Web Server
[Libraries]

A simple Web Server. More...


Data Structures

struct  HtmlFormElement
 A structure that represents a key-value pair in an HTML form. More...
struct  HtmlForm
 A structure that represents a collection of HtmlFormElement structures. More...

Functions

int WebServer_SetActive (int active)
 Start the WebServer up, listening on port 80.
int WebServer_GetActive (void)
 Read the active state of the WebServer subsystem.
int WebServer_SetListenPort (int port)
 Set the port that the webserver should listen on for new connections.
int WebServer_GetListenPort (void)
 Get the port that the webserver is currently listening on.
int WebServer_Route (char *address, int(*handler)(char *requestType, char *address, char *requestBuffer, int requestMaxSize, void *socket, char *buffer, int len))
 Adds a route handler to the WebServer.
int WebServer_WriteResponseOkHTML (void *socket)
 Writes the HTTP OK message and sets the content type to HTML.
int WebServer_WriteResponseOkPlain (void *socket)
 Writes the HTTP OK message and sets the content type to plain text.
int WebServer_WriteHeader (int includeCSS, void *socket, char *buffer, int len)
 Writes the HTML header.
int WebServer_WriteBodyStart (char *reloadAddress, void *socket, char *buffer, int len)
 Writes the start of the BODY tag.
int WebServer_WriteBodyEnd (void *socket)
 Writes the end of the Body tag - and the final end of HTML tag.
bool WebServer_GetPostData (void *socket, char *requestBuffer, int maxSize)
 Set the data of an incoming HTTP POST request to the given buffer.
int WebServer_ParseFormElements (char *request, HtmlForm *form)
 Extract the elements of an HTML form into key/value pairs.

Detailed Description

A simple Web Server.

This Web Server implementation is based on the ServerSocket and Socket functions defined in Sockets. When started, a ServerSocket is opened and set to listen on port 80.

When the server receives a request, it checks the incoming address against a list of handlers. If the request address matches, the handler is invoked and checking stops. Users can add their own handlers to return custom information - see WebServer_Route(). Most of the rest of the WebServer system provides helpful functions for generating and parsing HTML.

There is a single default/test handler that will handle any requests that are not otherwise handled. This is about the simplest demo possible of how to write a handler - it simply prints out some text and a count of how pages it has served. There are more handler examples further down this page, and in the mcbuilder examples. Take a look at TestHandler() in webserver.c to see its source.

To access the web server type the IP address of your board into a web browser, optionally followed by the address of any handlers you've registered, ie 192.168.1.200/myhandler.


Function Documentation

int WebServer_GetActive ( void   ) 

Read the active state of the WebServer subsystem.

Returns:
State - 1/non-zero (on) or 0 (off).

Definition at line 170 of file webserver.c.

int WebServer_GetListenPort ( void   ) 

Get the port that the webserver is currently listening on.

Returns:
The port number.
Example
  int currentPort = WebServer_GetListenPort( );

Definition at line 204 of file webserver.c.

bool WebServer_GetPostData ( void *  socket,
char *  requestBuffer,
int  maxSize 
)

Set the data of an incoming HTTP POST request to the given buffer.

This is designed to be used from within a custom handler. An incoming HTTP request will have some number of lines of header information, and this function will read through them until getting to the body of the message. It will then store the contents of the body in the given buffer, null-terminating the end of the data.

It's usually convenient to set the POST data in the requestBuffer since it's already allocated.

Example

int MyRequestHandler( char* requestType, char* address, char* requestBuffer, 
                      int requestMaxSize, void* socket, char* buffer, int len )
{
  // ... other setup here ...

  if ( strncmp( requestType, "POST", 4 ) == 0 ) // if the request is indeed a POST
  {
    if( WebServer_GetPostData( socket, requestBuffer, requestMaxSize ) ) // set the POST data in the requestBuffer
    {
      // process the data in any way you like.
      // here, we're expecting a form and we want to grab the info out of it
      formElements = WebServer_ParseFormElements( requestBuffer, &form );
    }
  }

  // ... write out the response here ...
}
Parameters:
socket The socket from the incoming request
requestBuffer A pointer to the buffer to store the data in.
maxSize The maximum amount of data to be placed in the buffer.
Returns:
true on success, false on failure

Definition at line 496 of file webserver.c.

int WebServer_ParseFormElements ( char *  request,
HtmlForm form 
)

Extract the elements of an HTML form into key/value pairs.

This is designed to be used from within a custom handler. HTML forms can be sent via either the HTTP GET or POST methods. The request parameter must be set to the start of the form data, which is located in a different place for each method. In the GET case, we need to check if there are any form elements, as indicated by a ? after the URL address. In the POST case, we can use WebServer_GetPostData() to find the beginning of the POST data for us.

Note that the HtmlForm structure will simply point to the elements in the request buffer, so as soon as the buffer is deleted or out of scope, the form data is no longer valid.

Example

int MyRequestHandler( char* requestType, char* address, char* requestBuffer, 
                      int requestMaxSize, void* socket, char* buffer, int len )
{
  // ... other setup here ...
  
  int formElements = 0;
  HtmlForm form;
  form.count = 0;
  
  // determine the kind of request - GET or POST
  if ( strncmp( requestType, "GET", 3 ) == 0 )
  {
    char *p = strchr( requestBuffer, '?' ); // if GET, see if there's a ?
    if( p != NULL ) // if we didn't find a ?, there were no form elements
      formElements = WebServer_ParseFormElements( p+1, &form );
    // we have to send "p + 1" since the form data starts right after the ?
  }
  else if ( strncmp( requestType, "POST", 4 ) == 0 )
  {
    // make sure we're pointing at the POST data and if it looks good, process it
    if( WebServer_GetPostData( socket, requestBuffer, requestMaxSize ) )
      formElements = WebServer_ParseFormElements( requestBuffer, &form );
  }

  // ... write out the response here ...
}
Parameters:
request A pointer to the form data
form The HtmlForm structure to populate with elements
Returns:
The number of form elements found

Definition at line 582 of file webserver.c.

int WebServer_Route ( char *  address,
int(*)(char *requestType, char *address, char *requestBuffer, int requestMaxSize, void *socket, char *buffer, int len)  handler 
)

Adds a route handler to the WebServer.

This function binds an address fragment (e.g. "/", "/adcs", etc.) to a handler that will be called when the address matches. Matching ignores characters in the incoming address that are beyond the end of the address specified to this function. The first function to match the address will receive all the traffic and no more handlers will be checked. Thus if a handler is set up to match "/images" it will match "/images" and "/images/logo.png" and so on. Also if there is a subseqent handler set to match "/images/diagram" it will never be called since the prior handler will match the entire "/images" space. You can register your handlers prior to firing up the webserver system.

The handler will be called with the request type specified (usually "GET" or "POST"), the incoming address ( "/device/0", "/images/logo.png", etc.) A buffer (and max length) is passed in that can be used to receive the rest of the message if necessary. Then there will be the socket which will take the response and a helpful large buffer or specified length which can be used to build strings.

At the time the handler is called, only the first line of the request has been read. It is used to determine the request type and the address requested. If you need to process the request further its contents may be read into a buffer (the request buffer passed in is good once the request type address have been used since they're in there initially). The SocketReadLine( ) function is convenient to read a line of the request at a time.

The handler itself must first write the response using one of WebServer_WriteResponseOkHTML() for sending HTML or WebServer_WriteResponseOkPlain() for returning plain text. These send the appropriate HTTP header (for example "HTTP/1.0 200 OK\r\nContent-type:text/html\r\n\r\n"). All responses may be simply written to the Socket, but several helpers are provided to assist in the construction of simple web pages (for example WebServer_WriteHeader(), WebServer_WriteBodyStart(), etc.).

The handler should return non-zero if it handled the response appropriately or 0 if not, in which case the webserver will check for matches with other handlers that can handle it.

Parameters:
address An string specify the addresses to match.
handler pointer to a handler function that will be called when the address is matched.
Returns:
CONTROLLER_OK (=0) on success or the appropriate error if not
Here is an example of how to register a handler:
// now requests at MyBoardsIPAddress/my/handler will be handled by MyHandler
WebServer_Route( "/my/handler", MyHandler );

And here is an example handler, printing out some simple info in response to any request.

int MyHandler( char* requestType, char* address, char* requestBuffer, int requestMaxSize, 
                 void* socket, char* buffer, int len )
{
  (void)requestType;
  (void)address;
  WebServer_WriteResponseOkHTML( socket );
  WebServer_WriteHeader( true, socket, buffer, len );
  WebServer_WriteBodyStart( address, socket, buffer, len );
  snprintf( buffer, len, "<H1>TEST</H1>%d hits", WebServer->hits );
  SocketWrite( socket, buffer, strlen( buffer ) );
  WebServer_WriteBodyEnd( socket );
  return true;
}

Definition at line 269 of file webserver.c.

int WebServer_SetActive ( int  active  ) 

Start the WebServer up, listening on port 80.

See WebServer_Route() for info on how to register handlers for certain requests.

Parameters:
active An integer specifying the active state - 1 (on) or 0 (off).
Returns:
CONTROLLER_OK (0) on success or the appropriate error if not
Example
  // fire up the webserver
  WebServer_SetActive(true);

Definition at line 122 of file webserver.c.

int WebServer_SetListenPort ( int  port  ) 

Set the port that the webserver should listen on for new connections.

Note that this does not immediately take effect - because the webserver (if it's open) is already listening on a port, it will only take effect after it serves one last request on that port.

Parameters:
port The new port to listen on.
Returns:
0 on success.
Example
  // listen on a non-standard port for HTTP
  WebServer_SetListenPort(8080);

Definition at line 189 of file webserver.c.

int WebServer_WriteBodyEnd ( void *  socket  ) 

Writes the end of the Body tag - and the final end of HTML tag.

Should be preceded by writes to the socket with the content of the page - this is often the last thing done in a handler. See WebServer_Route() for a more complete example.

Parameters:
socket The socket to write to
Returns:
non-zero on success, zero on failure.
Example
  int MyRequestHandler( char* requestType, char* address, char* requestBuffer, 
                      int requestMaxSize, void* socket, char* buffer, int len )
  {
    // ... other code actually doing interesting things ...
    WebServer_WriteBodyEnd(socket); // now we're all done
    return 1;
  }

Definition at line 456 of file webserver.c.

int WebServer_WriteBodyStart ( char *  reloadAddress,
void *  socket,
char *  buffer,
int  len 
)

Writes the start of the BODY tag.

Should be preceded by a call to WebServer_WriteHeader(). Also writes a light grey background. You can optionally specify that you'd like the page to automatically refresh itself once a second by passing in the address to reload to reloadAddress. See WebServer_Route() for a more complete example.

Parameters:
reloadAddress A string signaling the address of a 1 second reload request. If it is NULL, no reload is requested.
socket The socket to write to.
buffer Helper buffer which the function can use. Should be at least 300 bytes. This is usually the buffer passed into your handler as buffer.
len Helper buffer length. Also usually passed into your handler as len.
Todo:
more parameterization of the tag
Example
  int MyRequestHandler( char* requestType, char* address, char* requestBuffer, 
                      int requestMaxSize, void* socket, char* buffer, int len )
  {
    // ... usually write out the OK response and the header first ...
    WebServer_WriteBodyStart(0, socket, buffer, len); // write the body start, with no reload
    // ... continue processing ...
  }

Definition at line 418 of file webserver.c.

int WebServer_WriteHeader ( int  includeCSS,
void *  socket,
char *  buffer,
int  len 
)

Writes the HTML header.

Should be preceded by a call to WebServer_WriteResponseOkHTML(). See WebServer_Route() for a more complete example.

Parameters:
includeCSS A flag signalling the inclusion of a very simple CSS header refining h1 and body text slightly.
socket The socket to write to
buffer Helper buffer which the function can use. Should be at least 300 bytes.
len Helper buffer length
Returns:
non-zero on success, zero on failure.
Todo:
more parameterization
Example
  int MyRequestHandler( char* requestType, char* address, char* requestBuffer, 
                      int requestMaxSize, void* socket, char* buffer, int len )
  {
    // ... usually write out the OK response first ...
    WebServer_WriteHeader(true, socket, buffer, len); // write the header, including simple CSS
    // ... continue processing ...
  }

Definition at line 377 of file webserver.c.

int WebServer_WriteResponseOkHTML ( void *  socket  ) 

Writes the HTTP OK message and sets the content type to HTML.

This will typically be the first thing you write out in your handler. Also see WebServer_WriteResponseOkPlain() to set your response type to plain text.

Parameters:
socket The socket to write to
Returns:
non-zero on success, zero on failure.
Example
  int MyRequestHandler( char* requestType, char* address, char* requestBuffer, 
                      int requestMaxSize, void* socket, char* buffer, int len )
  {
    WebServer_WriteResponseOkHTML(socket); // write the response out first
    // ... continue processing ...
  }

Definition at line 312 of file webserver.c.

int WebServer_WriteResponseOkPlain ( void *  socket  ) 

Writes the HTTP OK message and sets the content type to plain text.

This will typically be the first thing you write out in your handler. Also see WebServer_WriteResponseOkHTML() to set your response type to HTML.

Parameters:
socket The socket to write to.
Returns:
non-zero on success, zero on failure.
Example
  int MyRequestHandler( char* requestType, char* address, char* requestBuffer, 
                      int requestMaxSize, void* socket, char* buffer, int len )
  {
    WebServer_WriteResponseOkPlain(socket); // write the response out first
    // ... continue processing ...
  }

Definition at line 349 of file webserver.c.