NetBurner 3.5.0
PDF Version
 
HTML Processing

Introduction

The Web Server will process all content in a project's "html" folder. If you are using any of the html examples or the application wizard, the html folder will have been created for you. If adding html and web server functionality to a project without a html folder, simply create one, and add the corresponding StartHttp() or StartHttps() function call to your application to start web server services.

You can add whatever content you wish to the html folder: HTML, CSS, java script, java, images, etc. The NetBurner tools will automatically compile and link them into the application image that you download into your NetBurner device. You can use whatever web development tools you wish to create content, or write content with a text editor. The content in the html folder can be static pages or take advantage of dynamic content using function callback and variable tags. Static content can also be delivered from the onboard EFFS-STD file system and the external EFFS-FAT file system used by flash cards.

Note
When using NBEclipse, you can view web content source by right-clicking on the file and selecting Open With -> Text Editor

The function StartHttp() with no parameters will default to port 80. To use a different port number add a parameter, such as StartHttp(2000). Similarly, StartHttps() will default to port 443. The function can have up to 2 parameters, one for HTTPS and one for HTTP. StartHttps(527) changes the HTTPS port number. StartHttps(442, 80) enables both HTTPS and HTTP on the standard ports.



Dynamic Content

Dynamic content is generated at run-time on your NetBurner device. For example, you can a web page for an instrument in which the content changes to match the current state of the instrument, such as gauges, light indicators, and switches. Or you can provide a graph showing data by creating an image or using any of the advanced tool such as Bootstrap. There are many examples of this in the \nburn\examples\web folder.

Dynamic content can be created in a number of ways:

  • Function callback tags in HTML code to call a C/C++ function in real time as the web page is being rendered, such as CPPCALL
  • Variable tags in HTML code to insert application variable values in real time as the web page is being rendered, such as VARIABLE
  • Languages such as Javascript that runs in the browser
  • A HTTP GET request handler that will be called when a web page is requested from the web browser
  • A HTTP POST handler that will be called when a web page FORM post data to the web browser
  • Web Sockets for two-way communication
  • Web content can be delivered from multiple sources: content compiled into the application, generated by application code, internal file system (EFFS-STD in on-chip memory), or an external file system (EFFS-FAT) such as microSD flash cards.



HTML Tags

You can think of web server operation as receiving a request from a web browser for a file, and responding by sending that file as a data stream back to the browser. One method to create dynamic content is to embed a "tag" in the HTML source code file so that when the web server encounters it while streaming the content to the web browser, it takes some type of action in real-time. The NetBurner web server uses a number of tags to accomplish real-time dynamic content.

Tag Description
CPPCALL Call a C++ function in the application without parameters
VARIABLE() Call a C++ function with parameters
VARIABLE Insert the value of an application variable


The tags are used inside a HTML comment so they do not interfere with standard HTML processing. For example, a function callback could be used to format and display client information from the web browser:
Client Info: <!--CPPCALL webShowClientInfo -->

Warning
The space characters in the HTML comment block are important. there should be no space between "!--" and CPPCALL, and there must be a space between the end of the function name and "-->": <!--CPPCALL YourFunctionName -->

Configuration System Tags

While the previously mentioned tags can be used to display and/or modify any type of system configuration or application variables, the CONFIG tags are another option and can greatly simplify the interface. The CONFIG tags are designed to operate on the variables in the Configuration Record, which holds system configuration variables as well as any application variables in the AppData leaf of the configuration tree structure.

Tag Description
CONFIGVALUE Display a configuration or application variable value.
CONFIGINPUT Display a configuration or application variable value and create a HTML "<input>" field. The current variable value will be displayed.
CONFIGTABLE Create a table of the object and all sub-objects


The CPPCALL Tag

When the web server encounters a CPPCALL tag, it executes the corresponding C++ function in the application code. The function is passed the file descriptor to the open TCP socket and a pointer to the URL of the web page. The function then has control and can do whatever is desired by the application: create web content, perform operations such as controlling hardware, change software options, etc.

Note
The FUNCTIONCALL tag is is a 2.x tools tag and deprecated. The difference is the CPPCALL does not require extern "C" declarations in application source code to prevent C++ name mangling.


The screen shot below shows the usage for CPPCALL, VARIABLE and VARIABLE(x, y) tags:




The CPPCALL function signature is:

void YourFunctionName( int sock, PCSTR url )
{
// add code here
}

For example, to display the IP address and port number of the client that made the web page request:
HTML Code:

<html>
<body>
Client Address: <!--CPPCALL webShowClientInfo -->
</body>
</html>


The corresponding C++ function in the application:

void webShowClientInfo( int sock, PCSTR url )
{
IPADDR localIP = GetSocketLocalAddr(socket);
uint32_t remotePort = GetSocketRemotePort(socket);
localIP.fdprint(socket); // Write IP address
fdprintf(sock, ": %d<br>\r\n", remotePort);} // Write port number
}
Used to hold and manipulate IPv4 and IPv6 addresses in dual stack mode.
Definition ipv6_addr.h:41
void fdprint(int fd, bool bCompact=true, bool bShowV4Raw=false) const
Print the IP address to the specified file descriptor.
int fdprintf(int fc, const char *format,...)
printf to a file descriptor
IPADDR GetSocketLocalAddr(int fd)
Returns the IP address of the local interface associated with the connection.
Definition tcp.h:652
uint16_t GetSocketRemotePort(int fd)
Returns the port number of the remote host associated with the connection.


The VARIABLE Tag

The VARIABLE tag has two uses:

  1. Simply inserting a variable or expression
  2. Calling an application function with variable parameters (essentially a CPPCALL with function parameters)

To display a variable the format is: <!--VARIABLE <name> -->
Where <name> is the name of the application variable or an expression. For example, the system time tick variable, TimeTick can be displayed with <!--VARIABLE TimeTick -->
Or you can display the time in seconds with the equation: <!--VARIABLE TimeTick/TICKS_PER_SECOND -->
The VARIABLE tag is processed during the compilation of the application by parsing the text between “<!—VARIABLE” and the trailing “ -->”, then the NetBurner tools automatically convert it into a function call with a signature that contains a file descriptor and variable. For example, WriteHtmlVariable( fd, TimeTick/TICKS_PER_SECOND );
The following parameter types are available and defined in \nburn\include\htmlfiles.h:

void WriteHtmlVariable(int fd, char c);
void WriteHtmlVariable(int fd, int i);
void WriteHtmlVariable(int fd, short i);
void WriteHtmlVariable(int fd, long i);
void WriteHtmlVariable(int fd, uint8_t b);
void WriteHtmlVariable(int fd, uint16_t w);
void WriteHtmlVariable(int fd, unsigned long dw);
void WriteHtmlVariable(int fd, const char *);
void WriteHtmlVariable(int fd, MACADR ip);
Used to store and manipulate MAC addresses.
Definition nettypes.h:69


The INCLUDE Tag and htmlvar.h Header File

The functions that are created from the VARIABLE tags are located in an auto-generated file named htmldata.cpp. Since these functions reference the variable names, there must be a way for the linker to resolve them. For example, to display TimeTick the application would need to include <nbrtos.h>, otherwise a linker error will occur.

Include files for the HTML code/files to enable linking can be handled two ways:

  1. An include HTML tag, <INCLUDE headername.h> in the HTML code
  2. Create a header file in the project with the name "htmlvar.h". The tools will automatically look for a file of this name if <INCLUDE> tags are not detected in the HTML source files.

Example of a HTML file using the INCLUDE tag with a user defined header file name:

<html>
<body>
<!--INCLUDE myIncludeFile.h -->
Value = <!--VARIABLE MyVar --><br>
</body>
</html>


Example of htmlvar.h header file that exposes two variables, the <nbrtos.h> header file, and a function that takes an integer parameter:

#ifndef HTMLVARS_H_
#define HTMLVARS_H_
#include <nbrtos.h> // For access to TimeTick
extern int gIntVal;
extern char gStrVal[];
const char *FooWithParameters(int fd, int v);
#endif /*HTMLVARS_H_*/
NetBurner Real-Time Operating System (NBRTOS) API.


The VARIABLE() Tag With Parameters

If you need to specify a function callback but need to pass a parameter, the CPPCALL tag will not work because the function signature parameters are fixed as the socket file descriptor and URL. In this case we can use the VARIABLE tag to achieve the functionality of calling a function with a variable.

The include file (e.g. htmlvar.h) must specify the function definition in the format below. In this case we are passing an integer value ‘v’. The first parameter must always be the socket file descriptor: const char * myIntFunction(int fd,int v);

The HTML source code then uses the VARIABLE tag with the function definition. In this example we are passing the integer value of TimeTick. <!--VARIABLE MyIntFunction(fd,TimeTick) -->

When the application is compiled, the function definition will be created as: WriteHtmlVariable( fd, MyFunction(fd,TimeTick) );

This function returns an empty string, which will have no effect on the web page. An example of what a function might do is shown below:

const char *FooWithParameters(int fd, int v)
{
fdprintf(fd, "This function was called with parameter v = %d\r\n", v);
return "\0"; // Return a const char * here of zero length so it will
not print anything
}


Extending the VARIABLE Tag

The VARIABLE functionality can be extended to support user defined types, such as displaying a user defined structure or class. Let’s say you have a structure you want to display on a web page called myStruct:

struct my_struct {
int i;
char buf[80];
uint32_t dVal;
} MY_STRUCT;
MY_STRUCT myStruct;


In your include file add the function definition: void WriteHtmlVariable(int fd, MY_STRUCT myStruct);

Now you can display it on the web page with the VARIABLE tag: <!--VARIABLE myStruct -->

Which will compile to: WriteHtmlVariable( fd, myStruct );

Note that you still have to write the implementation of the above function. The function below is the source code for the MAC address type already defined by the system:

void WriteHtmlVariable(int fd, MACADR ma)
{
PBYTE lpb = ( PBYTE ) &ma;
for (int I = 0; I < 5; i++)
{
fd_writehex( fd, lpb[i] );
write(fd,":",1);
}
fd_writehex( fd, lpb[6] );
}
int write(int fd, const char *buf, int nbytes)
Write data to the stream associated with a file descriptor (fd). Can be used to write data to stdio,...


The CONFIGVALUE Tag



HTTP GET Request Handler

When you click on a link or enter an address in the URL field of a web browser, it sends a GET request to the web server. At its most basic level a GET request is the word "GET" and the requested file name. A GET handler is a mechanism by which an application can take control of the GET request instead of it being handled by the normal web server processing. For example, if an application implemented a GET handler for a HTML page named "showstatus.html", the GET handler could create whatever type of status output it wanted instead of the web server delivering a file named "showstatus.html".

A GET handler is also useful for URL encoding. Two common methods for delivering data from a client (eg. web browser) to a web server are URL encoding and HTML forms using a POST submission. URL encoding involves sending data to the web server by adding it to the end of the URL. For example, an e-commerce application might store product information such as: http://www.store.com/orderform?type=order123. The data sent to the web server to be processed "type=order123" in the URL. Everything following the "?" character is ignored by the browser, so your application can store information there. Another advantage of this method is that the application can be stateful, meaning multiple users can access the same application and each user’s session is maintained by the data encoding in the URL.

When a web browser requests something from a web server, such as an HTML page or image, it makes a GET request. The web server normally handles static web pages and dynamic web pages with the CPPCALL and VARIABLE tags, but your application can intercept the request and take control of the processing using a callback function object called CallBackFunctionPageHandler. When you declare the instance of the object you specify the name of the request to intercept and a pointer to the function in your application to process the request. For example, to take control of processing for a HTML page named setcookie.html:

To create a HTTP GET handler:

  1. Create an application callback function to process the GET request
  2. Create a CallBackFunctionPageHandler declaration to specify the URL mask, application callback function, and additional configuration parameters

A GET handler consists of a callback function to handle the actual processing, and a page handler declaration specify the conditions in which the callback function should be executed. The callback function sends an HTML header to identify the content, in this case it is HTML, determines if the system seconds timer is odd or even, then sends the appropriate HTML file as a response. Note that OddEven.html does not exist as a file. The GET request for OddEven.html is intercepted by the callback.

The callback has the function signature: ‘int callbackGetOddEven(int sock, HTTP_Request &pHttpRequest)’

The page handler declaration has the signature:

CallBackFunctionPageHandler(const char *pUrl,
http_gethandlerfunc *pFunction,
int accessGroup = 0,
bool beforeFiles = false)
Implements the HtmlPageHandler class as a function pointer callback for GET requests.
Definition http.h:181
HTTP_RequestTypes
HTTP request types for HTTP page handler callback functions.
Definition http.h:35
int http_gethandlerfunc(int sock, HTTP_Request &pd)
Implements the HtmlPageHandler class as a function pointer callback for GET requests.
Definition http.h:171
@ tGet
GET request.
Definition http.h:37



/*---------------------------------------------------------------------------------------
* Callback to intercept a GET request for URL OddEven.html. The purpose of this callback
* example is to demonstrate how to add custom processing and send an existing HTML file.
* The URL OddEven.html does not exist as a file. If the page is requested by a browser,
* this callback function is executed, which does some processing and decides which web
* page file to send to the browser based on the current system seconds timer value.
*
* - Sends a HTML header to the browser to specify the content that follows is HTML
* - Reads the system seconds timer, and sends the file odd.html or even.html
* - A return value of 1 tells the system the HTML request was handled by the callback
*
* Notes:
* - HTTP_Request is a structure containing detailed information of the request
*--------------------------------------------------------------------------------------*/
int callbackGetOddEven(int sock, HTTP_Request &pHttpRequest)
{
// Send the web page header telling the browser we are sending HTML content
//----- Add custom processing here -----
// Display message to serial terminal showing requested URL
iprintf("Executing GET request callback function: callbackGetOddEven\r\n");
iprintf("Request URL: %s, from: %I\r\n", pHttpRequest.pURL, pHttpRequest.client_IPaddr);
if ( (Secs % 2) == 0)
SendFileFragment("even.html", sock);
else
SendFileFragment("odd.html", sock);
// Notify system we handled the GET request
return 1;
}
/*
* Declare the callback function. Parameters:
* OddEven.html URL to intercept
* callbackGetOddEven Pointer to the callback function
* tGet HTTP Request Type (ref HTTP_RequestTypes)
* 0 User Access Group, 0 = no password
* true When to call (beforeFiles parameter):
* true: Always called for the specified URL
* false: Only called if the if the requested URL cannot be satisfied elsewhere
*/
CallBackFunctionPageHandler getHandlerOddEven("OddEven.html", callbackGetOddEven, tGet, 0, true);
void SendHTMLHeader(int sock)
Send a HTML response header.
int32_t SendFileFragment(char const *name, int32_t fd, PCSTR url=NULL)
Send a file fragment without a header.
HTTP Request Structure.
Definition http.h:69
PSTR pURL
Request URL.
Definition http.h:70
IPADDR client_IPaddr
IP address of client.
Definition http.h:82


A key component is the CallBackFunctionPageHandler declaration. Lets look at each parameter:

pURL: is the URL name to match. In this case it is fully defined as "OddEven.html", but wildcards can also be used. Although not very useful in this case, it could have been "Odd*", which would result in the callback being executed for anything beginning with "Odd".

pFunction: is a pointer to the function callback.

tGet: is the request type, in this case it is a GET, which has a request type of tGet.

accessGroup: is used for security/password access. Not the subject of this example, so a 0 for no access restriction is used.

beforeFiles: refers to the html content in the html folder of the project. If true, the callback will be executed without the web server first checking to see if a file by that name exists. If false, if a file by the pURL name is found, it will be sent to the client first.



HTTP Form POST Handler

You have probably encountered forms many times on the web, such as e-commerce and feedback forms. The format is typically some number of text fields, check boxes, radio buttons, combo boxes and a submit button. When you click on the submit button, the data from the form is sent to the web server as a HTTP POST. The web server then parses the data and takes appropriate action.

A form is declared in HTML by the <form> tag. User input is controlled by various <input> tags. For example, the web page below creates a form with a text field. NetBurner tags such as CPPCALL, VARIABLE and CONFIG tags can be used to populate input fields with their current value.

To create a HTTP POST form handler:

  1. Create a HTML web page with a form
  2. Create a corresponding application callback function to process the posted data
  3. Create a HtmlPostVariableListCallback declaration to specify the matching callback mask and attach the application callback function


The example below creates a HTML page with four input fields, and a POST handler callback function to process them.




HTML Code:

<html>
<title>HTML Post Example</title>
<body>
<img src="images/netburner-logo.gif">
<h1><font face=arial>HTML Form Post Example, Second Form</font></h1>
<br>
<form action="form2" method=post>
Enter data to post var0: <input type="text" name="Var0" value="Var0"><br><br>
Enter data to post var1: <input type="text" name="Var1" value="Var1"><br><br>
Enter data to post var2: <input type="text" name="Var2" value="Var2"><br><br>
Enter data to post var3: <input type="text" name="Var3" value="Var3"><br><br>
<br><input type="submit" value="Submit"><br>
</form>
</body>
</html>


Corresponding Application Source Code:

/*
* Callback function for Form2. This function will be called once for each variable
* in the form.
*/
void form2PostCallBack(int sock, PostEvents event, const char * pName, const char * pValue)
{
// Received a call back with an event, check for event type
switch (event)
{
// Called at the beginning of the post before any data is sent
case eStartingPost:
for (int i = 0; i < numVars; i++)
strVar[i][0] = '\0';
form2ParseError = false;
break;
// Called once for each variable in the form
case eVariable:
if (strcmp("Var0", pName) == 0)
{
strncpy(strVar[0], pValue, varLen - 1);
iprintf("strVar0 set to: \"%s\"\r\n", strVar[0]);
}
else if (strcmp("Var1", pName) == 0)
{
strncpy(strVar[1], pValue, varLen - 1);
iprintf("strVar1 set to: \"%s\"\r\n", strVar[1]);
}
else if (strcmp("Var2", pName) == 0)
{
strncpy(strVar[2], pValue, varLen - 1);
iprintf("strVar2 set to: \"%s\"\r\n", strVar[2]);
}
else if (strcmp("Var3", pName) == 0)
{
strncpy(strVar[3], pValue, varLen - 1);
iprintf("strVar3 set to: \"%s\"\r\n", strVar[3]);
}
else
{
iprintf("*** Error: Form variable name not found\r\n");
form2ParseError = true;
}
break;
//Called back with a file handle if the post had a file
case eFile:
break; //No file type here so we do nothing
// Called back when the post is complete. You should send your response here.
case eEndOfPost:
{
iprintf("Variable Summary:\r\n");
for (int i = 0; i < numVars; i++)
iprintf(" Var%d = \"%s\" \r\n", i, strVar[i]);
if (form2ParseError)
iprintf("*** Error: Form variable name not found\r\n");
RedirectResponse(sock, "complete.html");
}
break;
} //switch
}
// Create a global static post handling object that responds to the specified html page.
// A separate post handler can be created for each form in your application.
HtmlPostVariableListCallback postForm2("form2*", form2PostCallBack);
Implements the HtmlPostVariableListHandler class as a function pointer callback for HTTP POST submiss...
Definition httppost.h:130
void RedirectResponse(int sock, PCSTR new_page)
Redirect a HTTP request to a different page.


When a post is submitted the callback post handler will be executed a number times for the following events:

Event Description
eStartingPost Occurs once at the first event of a post
eVariable Occurs once for each variable in the form
eFile Occurs if a file is being posted
eEndOfPost Occurs once at the end of post processing


In this example the following events will occur:

  • eStartingPost is called first and enables the application to initialize the array.
  • eVariable is called once for each variable (input field). In this example it will be called 4 times. The callback function must parse for the input field name on each call.
  • eFile is called. Since we are not posting a file no action is taken.
  • eEndOfPost is called last. In this example it is used to print a summary of the input field values


The HtmlPostVariableListCallback declaration is used to specify the URL name and mask, as well as a pointer to the post handler callback. Full URL names can be specified with and multiple callback functions, or a wildcard can be used and the post handler callback must parse the URL information to determine the correct action.