- Main Page
- Related Pages
- Modules
- Data Structures
- Files

- File List
- Globals

# webserver.c

Go to the documentation of this file.

    00001 /*********************************************************************************
    00002
    00003  Copyright 2006-2008 MakingThings
    00004
    00005  Licensed under the Apache License,
    00006  Version 2.0 (the "License"); you may not use this file except in compliance
    00007  with the License. You may obtain a copy of the License at
    00008
    00009  http://www.apache.org/licenses/LICENSE-2.0
    00010
    00011  Unless required by applicable law or agreed to in writing, software distributed
    00012  under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
    00013  CONDITIONS OF ANY KIND, either express or implied. See the License for
    00014  the specific language governing permissions and limitations under the License.
    00015
    00016 *********************************************************************************/
    00017
    00018
    00019 /** \file webserver.c
    00020   Functions for implementing a WebServer on the Make Controller Board.
    00021 */
    00022
    00023 #include "config.h" // MakingThings.
    00024 #ifdef MAKE_CTRL_NETWORK
    00025
    00026 /* Standard includes. */
    00027 #include <stdio.h>
    00028 #include <string.h>
    00029 #include <stdlib.h>
    00030 #include <ctype.h>
    00031
    00032 #include "network.h"
    00033
    00034 #define HANDLERS_MAX        5
    00035 #define REQUEST_SIZE_MAX  256
    00036 #define RESPONSE_SIZE_MAX 1000
    00037 #define HTTP_OK "HTTP/1.0 200 OK\r\nContent-type: "
    00038 #define HTTP_CONTENT_HTML "text/html\r\n\r\n"
    00039 #define HTTP_CONTENT_PLAIN "text/plain\r\n\r\n"
    00040 #define HTTP_PORT   ( 80 )
    00041
    00042 #define HTML_OS_START \
    00043 "<BR>Make Magazine - MakingThings<BR><H1>MAKE Controller Kit</H1>"
    00044
    00045 void WebServerTask( void *p );
    00046
    00047 typedef struct WebServerHandlerS
    00048 {
    00049   char* address;
    00050   int (*handler)( char* requestType, char* address,  char* requestBuffer, int requestMaxSize, void* socket, char* buffer, int len );
    00051 } WebServerHandler;
    00052
    00053 typedef struct WebServerHandlersS
    00054 {
    00055   int count;
    00056   WebServerHandler handlers[ HANDLERS_MAX ];
    00057 } WebServerHandlers_;
    00058
    00059 WebServerHandlers_* WebServerHandlers = NULL;
    00060
    00061 typedef struct WebServerS
    00062 {
    00063   int hits;
    00064   void* serverTask;
    00065   void *serverSocket;
    00066   void *requestSocket;
    00067   int listenPort;
    00068   bool changeListenPort;
    00069   char request[ REQUEST_SIZE_MAX ];
    00070   char response[ RESPONSE_SIZE_MAX ];
    00071 } WebServer_;
    00072
    00073 WebServer_* WebServer = NULL;
    00074
    00075 #include "webserver.h"
    00076 #include "analogin.h"
    00077 #include "system.h"
    00078
    00079 #include "FreeRTOS.h"
    00080 #include "task.h"
    00081
    00082 int TestHandler( char* requestType, char* address, char* requestBuffer, int requestMaxSize, void* socket, char* buffer, int len );
    00083
    00084 static int WebServer_WriteResponseOk_( char* content, void* socket );
    00085
    00086
    00087 /** \defgroup webserver Web Server
    00088   A simple Web Server
    00089
    00090   This Web Server implementation is based on the \ref ServerSocket and \ref Socket functions defined
    00091   in \ref Sockets.  When started, a ServerSocket is opened and set to listen on port 80.
    00092
    00093   When the server receives a request, it checks the incoming address against a list of handlers.
    00094   If the request address matches, the handler is invoked and checking stops.  Users can add their own
    00095   handlers to return custom information - see WebServer_Route().  Most of the rest of the WebServer
    00096   system provides helpful functions for generating and parsing HTML.
    00097
    00098   There is a single default/test handler that will handle any requests that are not otherwise handled.  This
    00099   is about the simplest demo possible of how to write a handler - it simply prints out some text and a count
    00100   of how pages it has served.  There are more handler examples further down this page, and in the mcbuilder
    00101   examples.  Take a look at TestHandler() in webserver.c to see its source.
    00102
    00103   To access the web server type the IP address of your board into a web browser, optionally followed by
    00104   the address of any handlers you've registered, ie \b 192.168.1.200/myhandler.
    00105
    00106   \ingroup Libraries
    00107   @{
    00108 */
    00109
    00110 /**
    00111   Start the WebServer up, listening on port 80.
    00112   See WebServer_Route() for info on how to register handlers for certain requests.
    00113   @param active An integer specifying the active state - 1 (on) or 0 (off).
    00114   @return CONTROLLER_OK (0) on success or the appropriate error if not
    00115
    00116   \b Example
    00117   \code
    00118   // fire up the webserver
    00119   WebServer_SetActive(true);
    00120   \endcode
    00121 */
    00122 int WebServer_SetActive( int active )
    00123 {
    00124   if ( active )
    00125   {
    00126     if ( WebServer == NULL )
    00127     {
    00128       WebServer = MallocWait( sizeof( WebServer_ ), 100 );
    00129       WebServer->hits = 0;
    00130       WebServer->serverSocket = NULL;
    00131       WebServer->requestSocket = NULL;
    00132       WebServer->changeListenPort = false;
    00133       WebServer->listenPort = HTTP_PORT; // default to 80
    00134       #ifdef CROSSWORKS_BUILD
    00135       int stacksize = 800;
    00136       #else
    00137       int stacksize = 1800;
    00138       #endif // CROSSWORKS_BUILD
    00139       WebServer->serverTask = TaskCreate( WebServerTask, "WebServ", stacksize, NULL, 4 );
    00140       if ( WebServer->serverTask == NULL )
    00141       {
    00142         Free( WebServer );
    00143         WebServer = NULL;
    00144         return CONTROLLER_ERROR_CANT_START_TASK;
    00145       }
    00146     }
    00147   }
    00148   else
    00149   {
    00150     if( WebServer != NULL )
    00151     {
    00152       if ( WebServer->serverTask != NULL )
    00153         TaskDelete( WebServer->serverTask );
    00154       if ( WebServer->serverSocket != NULL )
    00155         ServerSocketClose( WebServer->serverSocket );
    00156       if ( WebServer->requestSocket != NULL )
    00157         SocketClose( WebServer->requestSocket );
    00158
    00159       Free( WebServer );
    00160       WebServer = NULL;
    00161     }
    00162   }
    00163   return CONTROLLER_OK;
    00164 }
    00165
    00166 /**
    00167   Read the active state of the WebServer subsystem.
    00168   @return State - 1/non-zero (on) or 0 (off).
    00169 */
    00170 int  WebServer_GetActive( void )
    00171 {
    00172   return ( WebServer != NULL ) ? 1 : 0;
    00173 }
    00174
    00175 /**
    00176   Set the port that the webserver should listen on for new connections.
    00177   Note that this does not immediately take effect - because the webserver
    00178   (if it's open) is already listening on a port, it will only take effect
    00179   after it serves one last request on that port.
    00180   @param port The new port to listen on.
    00181   @return 0 on success.
    00182
    00183   \b Example
    00184   \code
    00185   // listen on a non-standard port for HTTP
    00186   WebServer_SetListenPort(8080);
    00187   \endcode
    00188 */
    00189 int WebServer_SetListenPort( int port )
    00190 {
    00191   WebServer->listenPort = port;
    00192   return CONTROLLER_OK;
    00193 }
    00194
    00195 /**
    00196   Get the port that the webserver is currently listening on.
    00197   @return The port number.
    00198
    00199   \b Example
    00200   \code
    00201   int currentPort = WebServer_GetListenPort( );
    00202   \endcode
    00203 */
    00204 int WebServer_GetListenPort( void )
    00205 {
    00206   return WebServer->listenPort;
    00207 }
    00208
    00209 /**
    00210   Adds a route handler to the WebServer.
    00211
    00212   This function binds an address fragment (e.g. "/", "/adcs", etc.) to a handler
    00213   that will be called when the address matches.  Matching ignores characters in the
    00214   incoming address that are beyond the end of the address specified to this function.
    00215   The first function to match the address will receive all the traffic and no more
    00216   handlers will be checked.  Thus if a handler is set up to match "/images" it will match
    00217   "/images" and "/images/logo.png" and so on.  Also if there is a subseqent handler
    00218   set to match "/images/diagram" it will never be called since the prior handler
    00219   will match the entire "/images" space.  You can register your handlers prior to firing up
    00220   the webserver system.
    00221
    00222   The handler will be called with the request type specified (usually "GET" or  "POST"),
    00223   the incoming address ( "/device/0", "/images/logo.png", etc.) A buffer (and max length) is passed in that
    00224   can be used to receive the rest of the message if necessary. Then there will be
    00225   the socket which will take the response and a helpful large buffer or specified length
    00226   which can be used to build strings.
    00227
    00228   At the time the handler is called, only the first line of the request has been read.  It is used
    00229   to determine the request type and the address requested.  If you need to process the request further
    00230   its contents may be read into a buffer (the request buffer passed in is good once the request type
    00231   address have been used since they're in there initially).  The SocketReadLine( ) function is
    00232   convenient to read a line of the request at a time.
    00233
    00234   The handler itself must first write the response using one of WebServer_WriteResponseOkHTML() for
    00235   sending HTML or WebServer_WriteResponseOkPlain() for returning plain text.
    00236   These send the appropriate HTTP header (for example "HTTP/1.0 200 OK\r\nContent-type:text/html\r\n\r\n").
    00237   All responses may be simply written to the Socket, but several helpers are provided to assist in the
    00238   construction of simple web pages (for example WebServer_WriteHeader(), WebServer_WriteBodyStart(), etc.).
    00239
    00240   The handler should return non-zero if it handled the response appropriately or 0 if not, in which case
    00241   the webserver will check for matches with other handlers that can handle it.
    00242   @param address An string specify the addresses to match.
    00243   @param handler pointer to a handler function that will be called when the address is matched.
    00244   @return CONTROLLER_OK (=0) on success or the appropriate error if not
    00245
    00246   Here is an example of how to register a handler:
    00247   \code
    00248 // now requests at MyBoardsIPAddress/my/handler will be handled by MyHandler
    00249 WebServer_Route( "/my/handler", MyHandler );
    00250   \endcode
    00251
    00252   And here is an example handler, printing out some simple info in response to any request.
    00253   \code
    00254 int MyHandler( char* requestType, char* address, char* requestBuffer, int requestMaxSize,
    00255                  void* socket, char* buffer, int len )
    00256 {
    00257   (void)requestType;
    00258   (void)address;
    00259   WebServer_WriteResponseOkHTML( socket );
    00260   WebServer_WriteHeader( true, socket, buffer, len );
    00261   WebServer_WriteBodyStart( address, socket, buffer, len );
    00262   snprintf( buffer, len, "<H1>TEST</H1>%d hits", WebServer->hits );
    00263   SocketWrite( socket, buffer, strlen( buffer ) );
    00264   WebServer_WriteBodyEnd( socket );
    00265   return true;
    00266 }
    00267   \endcode
    00268 */
    00269 int WebServer_Route( char* address,
    00270                     int (*handler)( char* requestType, char* address, char* requestBuffer,
    00271                     int requestMaxSize, void* socket, char* buffer, int len ) )
    00272 {
    00273   if ( WebServerHandlers == NULL )
    00274   {
    00275     WebServerHandlers = MallocWait( sizeof( WebServerHandlers_ ), 100 );
    00276     if ( WebServerHandlers != NULL )
    00277       WebServerHandlers->count = 0;
    00278   }
    00279   if ( WebServerHandlers != NULL )
    00280   {
    00281     if ( WebServerHandlers->count < HANDLERS_MAX )
    00282     {
    00283       WebServerHandler* hp = &WebServerHandlers->handlers[ WebServerHandlers->count++ ];
    00284       hp->address = address;
    00285       hp->handler = handler;
    00286       return CONTROLLER_OK;
    00287     }
    00288    return CONTROLLER_ERROR_INSUFFICIENT_RESOURCES;
    00289   }
    00290
    00291   return CONTROLLER_ERROR_NOT_OPEN;
    00292 }
    00293
    00294
    00295 /**
    00296   Writes the HTTP OK message and sets the content type to HTML.
    00297   This will typically be the first thing you write out in your handler.
    00298   Also see WebServer_WriteResponseOkPlain() to set your response type to plain text.
    00299   @param socket The socket to write to
    00300   @return non-zero on success, zero on failure.
    00301
    00302   \b Example
    00303   \code
    00304   int MyRequestHandler( char* requestType, char* address, char* requestBuffer,
    00305                       int requestMaxSize, void* socket, char* buffer, int len )
    00306   {
    00307     WebServer_WriteResponseOkHTML(socket); // write the response out first
    00308     // ... continue processing ...
    00309   }
    00310   \endcode
    00311 */
    00312 int WebServer_WriteResponseOkHTML( void* socket )
    00313 {
    00314   //return WebServer_WriteResponseOk_( socket, HTTP_CONTENT_HTML );
    00315   int written = 0;
    00316   int ret = 0;
    00317   ret = SocketWrite( socket, HTTP_OK, strlen( HTTP_OK ) );
    00318   if( !ret )
    00319     return 0;
    00320   else
    00321     written += ret;
    00322
    00323   ret = SocketWrite( socket, HTTP_CONTENT_HTML, strlen( HTTP_CONTENT_HTML ) );
    00324   if( !ret )
    00325     return 0;
    00326   else
    00327     written += ret;
    00328
    00329   return written;
    00330 }
    00331
    00332 /**
    00333   Writes the HTTP OK message and sets the content type to plain text.
    00334   This will typically be the first thing you write out in your handler.
    00335   Also see WebServer_WriteResponseOkHTML() to set your response type to HTML.
    00336   @param socket The socket to write to.
    00337   @return non-zero on success, zero on failure.
    00338
    00339   \b Example
    00340   \code
    00341   int MyRequestHandler( char* requestType, char* address, char* requestBuffer,
    00342                       int requestMaxSize, void* socket, char* buffer, int len )
    00343   {
    00344     WebServer_WriteResponseOkPlain(socket); // write the response out first
    00345     // ... continue processing ...
    00346   }
    00347   \endcode
    00348 */
    00349 int WebServer_WriteResponseOkPlain( void* socket )
    00350 {
    00351   return WebServer_WriteResponseOk_( socket, HTTP_CONTENT_PLAIN );
    00352 }
    00353
    00354 /**
    00355   Writes the HTML header.
    00356   Should be preceded by a call to WebServer_WriteResponseOkHTML().
    00357   See WebServer_Route() for a more complete example.
    00358   @param includeCSS A flag signalling the inclusion of a very simple CSS header
    00359   refining h1 and body text slightly.
    00360   @param socket The socket to write to
    00361   @param buffer Helper buffer which the function can use.  Should be at least 300 bytes.
    00362   @param len Helper buffer length
    00363   @return non-zero on success, zero on failure.
    00364   \todo more parameterization
    00365
    00366   \b Example
    00367   \code
    00368   int MyRequestHandler( char* requestType, char* address, char* requestBuffer,
    00369                       int requestMaxSize, void* socket, char* buffer, int len )
    00370   {
    00371     // ... usually write out the OK response first ...
    00372     WebServer_WriteHeader(true, socket, buffer, len); // write the header, including simple CSS
    00373     // ... continue processing ...
    00374   }
    00375   \endcode
    00376 */
    00377 int WebServer_WriteHeader( int includeCSS, void* socket, char* buffer, int len )
    00378 {
    00379   (void)buffer;
    00380   (void)len;
    00381   char* headerStart = "<HTML>\r\n<HEAD>";
    00382   char* headerEnd = "\r\n</HEAD>";
    00383   char* style = "\r\n<STYLE type=\"text/css\"><!--\
    00384 body { font-family: Arial, Helvetica, sans-serif; } \
    00385 h1 { font-family: Arial, Helvetica, sans-serif; font-weight: bold; }\
    00386 --></STYLE>";
    00387
    00388   strcpy( buffer, headerStart );
    00389   if ( includeCSS )
    00390     strcat( buffer, style );
    00391   strcat( buffer, headerEnd );
    00392   return SocketWrite( socket, buffer, strlen( buffer ) );
    00393 }
    00394
    00395 /**
    00396   Writes the start of the BODY tag.
    00397   Should be preceded by a call to WebServer_WriteHeader().  Also writes a light grey background.
    00398   You can optionally specify that you'd like the page to automatically refresh itself once
    00399   a second by passing in the address to reload to \b reloadAddress.  See WebServer_Route() for a more complete example.
    00400   @param reloadAddress A string signaling the address of a 1 second reload request.  If it is NULL, no reload is requested.
    00401   @param socket The socket to write to.
    00402   @param buffer Helper buffer which the function can use.  Should be at least 300 bytes.  This is usually the buffer
    00403   passed into your handler as \b buffer.
    00404   @param len Helper buffer length.  Also usually passed into your handler as \b len.
    00405   \todo more parameterization of the tag
    00406
    00407   \b Example
    00408   \code
    00409   int MyRequestHandler( char* requestType, char* address, char* requestBuffer,
    00410                       int requestMaxSize, void* socket, char* buffer, int len )
    00411   {
    00412     // ... usually write out the OK response and the header first ...
    00413     WebServer_WriteBodyStart(0, socket, buffer, len); // write the body start, with no reload
    00414     // ... continue processing ...
    00415   }
    00416   \endcode
    00417 */
    00418 int WebServer_WriteBodyStart( char* reloadAddress, void* socket, char* buffer, int len )
    00419 {
    00420   (void)buffer;
    00421   (void)len;
    00422   char* bodyStart = "\r\n<BODY";
    00423   char* bodyEnd = " bgcolor=\"#eeeeee\">\r\n";
    00424
    00425   char* reloadStart = " onLoad=\"window.setTimeout(&quot;location.href='";
    00426   char* reloadEnd = "'&quot;,1000)\"";
    00427   strcpy( buffer, bodyStart );
    00428   if ( reloadAddress )
    00429   {
    00430     strcat( buffer, reloadStart  );
    00431     strcat( buffer, reloadAddress  );
    00432     strcat( buffer, reloadEnd  );
    00433   }
    00434   strcat( buffer, bodyEnd  );
    00435   return SocketWrite( socket, buffer, strlen( buffer ) );
    00436 }
    00437
    00438 /**
    00439   Writes the end of the Body tag - and the final end of HTML tag.
    00440   Should be preceded by writes to the socket with the content of the page -
    00441   this is often the last thing done in a handler.  See WebServer_Route() for a more complete example.
    00442   @param socket The socket to write to
    00443   @return non-zero on success, zero on failure.
    00444
    00445   \b Example
    00446   \code
    00447   int MyRequestHandler( char* requestType, char* address, char* requestBuffer,
    00448                       int requestMaxSize, void* socket, char* buffer, int len )
    00449   {
    00450     // ... other code actually doing interesting things ...
    00451     WebServer_WriteBodyEnd(socket); // now we're all done
    00452     return 1;
    00453   }
    00454   \endcode
    00455 */
    00456 int WebServer_WriteBodyEnd( void* socket )
    00457 {
    00458   char* bodyEnd = "\r\n</BODY>\r\n</HTML>";
    00459
    00460   return SocketWrite( socket, bodyEnd, strlen( bodyEnd ) );
    00461 }
    00462
    00463 /**
    00464   Set the data of an incoming HTTP POST request to the given buffer.
    00465   This is designed to be used from within a custom handler.  An incoming HTTP request will have some number of
    00466   lines of header information, and this function will read through them until getting to the body of the message.
    00467   It will then store the contents of the body in the given buffer, null-terminating the end of the data.
    00468
    00469   It's usually convenient to set the POST data in the requestBuffer since it's already allocated.
    00470
    00471   \b Example
    00472   \code
    00473 int MyRequestHandler( char* requestType, char* address, char* requestBuffer,
    00474                       int requestMaxSize, void* socket, char* buffer, int len )
    00475 {
    00476   // ... other setup here ...
    00477
    00478   if ( strncmp( requestType, "POST", 4 ) == 0 ) // if the request is indeed a POST
    00479   {
    00480     if( WebServer_GetPostData( socket, requestBuffer, requestMaxSize ) ) // set the POST data in the requestBuffer
    00481     {
    00482       // process the data in any way you like.
    00483       // here, we're expecting a form and we want to grab the info out of it
    00484       formElements = WebServer_ParseFormElements( requestBuffer, &form );
    00485     }
    00486   }
    00487
    00488   // ... write out the response here ...
    00489 }
    00490   \endcode
    00491   @param socket The socket from the incoming request
    00492   @param requestBuffer A pointer to the buffer to store the data in.
    00493   @param maxSize The maximum amount of data to be placed in the buffer.
    00494   @return true on success, false on failure
    00495 */
    00496 bool WebServer_GetPostData( void *socket, char *requestBuffer, int maxSize )
    00497 {
    00498   bool retval = false;
    00499   // keep reading lines of the HTTP header until we get CRLF which signifies the end of the
    00500   // header and the start of the body data.  If we see the contentlength along the way, keep that.
    00501   int contentLength = 0;
    00502   int bufferLength = 0;
    00503   while ( ( bufferLength = SocketReadLine( socket, requestBuffer, maxSize ) ) )
    00504   {
    00505     if ( strncmp( requestBuffer, "\r\n", 2 ) == 0 )
    00506       break;
    00507     if ( strncmp( requestBuffer, "Content-Length", 14 ) == 0 )
    00508       contentLength = atoi( &requestBuffer[ 15 ] );
    00509   }
    00510
    00511   // now we should be down to the HTTP POST data
    00512   // if there's any data, get up into it
    00513   if ( contentLength > 0 && bufferLength > 0 )
    00514   {
    00515     int bufferRead = 0;
    00516     int lengthToRead;
    00517     int avail = SocketBytesAvailable(socket);
    00518     if(avail > maxSize)
    00519       lengthToRead = maxSize - 1;
    00520     else
    00521       lengthToRead = avail;
    00522     char *rbp = requestBuffer;
    00523     // read all that the socket has to offer...may come in chunks, so keep going until there's none left
    00524     while ( ( bufferLength = SocketRead( socket, rbp, lengthToRead ) ) )
    00525     {
    00526       bufferRead += bufferLength;
    00527       rbp += bufferLength;
    00528       lengthToRead -= bufferLength;
    00529       if ( bufferRead >= contentLength )
    00530         break;
    00531     }
    00532     requestBuffer[ bufferRead ] = 0; // null-terminate the request
    00533     retval = true;
    00534   }
    00535   return retval;
    00536 }
    00537
    00538 /**
    00539   Extract the elements of an HTML form into key/value pairs.
    00540   This is designed to be used from within a custom handler.  HTML forms can be sent via either the HTTP GET
    00541   or POST methods.  The \b request parameter must be set to the start of the form data, which is
    00542   located in a different place for each method.  In the \b GET case, we need to check if there are any
    00543   form elements, as indicated by a \b ? after the URL address.  In the \b POST case, we can use
    00544   WebServer_GetPostData() to find the beginning of the POST data for us.
    00545
    00546   Note that the HtmlForm structure will simply point to the elements in the request buffer, so as soon as
    00547   the buffer is deleted or out of scope, the form data is no longer valid.
    00548
    00549   \b Example
    00550   \code
    00551 int MyRequestHandler( char* requestType, char* address, char* requestBuffer,
    00552                       int requestMaxSize, void* socket, char* buffer, int len )
    00553 {
    00554   // ... other setup here ...
    00555
    00556   int formElements = 0;
    00557   HtmlForm form;
    00558   form.count = 0;
    00559
    00560   // determine the kind of request - GET or POST
    00561   if ( strncmp( requestType, "GET", 3 ) == 0 )
    00562   {
    00563     char *p = strchr( requestBuffer, '?' ); // if GET, see if there's a ?
    00564     if( p != NULL ) // if we didn't find a ?, there were no form elements
    00565       formElements = WebServer_ParseFormElements( p+1, &form );
    00566     // we have to send "p + 1" since the form data starts right after the ?
    00567   }
    00568   else if ( strncmp( requestType, "POST", 4 ) == 0 )
    00569   {
    00570     // make sure we're pointing at the POST data and if it looks good, process it
    00571     if( WebServer_GetPostData( socket, requestBuffer, requestMaxSize ) )
    00572       formElements = WebServer_ParseFormElements( requestBuffer, &form );
    00573   }
    00574
    00575   // ... write out the response here ...
    00576 }
    00577   \endcode
    00578   @param request A pointer to the form data
    00579   @param form The HtmlForm structure to populate with elements
    00580   @return The number of form elements found
    00581 */
    00582 int WebServer_ParseFormElements( char *request, HtmlForm *form )
    00583 {
    00584   int count = 0;
    00585   bool cont = true;
    00586   char *p = request;
    00587   char* endp;
    00588
    00589   do
    00590   {
    00591     endp = strchr( p, '=' );
    00592     *endp = 0;
    00593     form->elements[form->count].key = p;
    00594
    00595     p = ++endp;
    00596     endp = strchr( p, '&' ); // look for the next element
    00597     if( endp == NULL ) // there is no next element, do this one and then be done
    00598     {
    00599       endp = strchr( p, 0 );
    00600       cont = false;
    00601     }
    00602     *endp = 0;
    00603
    00604     // if the value was empty, we'll either get the & if there are more elements, or 0 if we're at the end
    00605     if( *(p+1) == '&' || *(p+1) == 0 )
    00606       form->elements[form->count].value = 0;
    00607     else
    00608       form->elements[form->count].value = p;
    00609     p = ++endp;
    00610
    00611     form->count++;
    00612     count++;
    00613   } while( cont == true );
    00614
    00615   return count;
    00616 }
    00617
    00618 /** @}
    00619 */
    00620
    00621 int TestHandler( char* requestType, char* address, char* requestBuffer, int requestMaxSize, void* socket, char* buffer, int len )
    00622 {
    00623   (void)requestType;
    00624   (void)address;
    00625   (void)requestBuffer;
    00626   (void)requestMaxSize;
    00627   WebServer_WriteResponseOkHTML( socket );
    00628   WebServer_WriteHeader( true, socket, buffer, len );
    00629   WebServer_WriteBodyStart( address, socket, buffer, len );
    00630   snprintf( buffer, len, "<H1>Make Controller Web Server Test</H1> %d happy pages served...", WebServer->hits );
    00631   SocketWrite( socket, buffer, strlen( buffer ) );
    00632   WebServer_WriteBodyEnd( socket );
    00633   return true;
    00634 }
    00635
    00636 void WebServer_Demo( char* requestType, char* address, char* requestBuffer, int requestMaxSize, void* socket, char* buffer, int len );
    00637 static void WebServer_ProcessRequest( void* requestSocket );
    00638 static void WebServer_CreateServerSocket( void );
    00639 static char* WebServer_GetRequestAddress( char* request, int length, char** requestType );
    00640
    00641 void WebServer_ProcessRequest( void* requestSocket )
    00642 {
    00643   char* requestType = 0;
    00644   char* address = 0;
    00645   int i;
    00646   int responded;
    00647
    00648   SocketReadLine( requestSocket, WebServer->request, REQUEST_SIZE_MAX );
    00649   address = WebServer_GetRequestAddress( WebServer->request, REQUEST_SIZE_MAX, &requestType );
    00650
    00651   responded = false;
    00652   if ( WebServerHandlers != NULL )
    00653   {
    00654     for ( i = 0; i < WebServerHandlers->count; i++ )
    00655     {
    00656       WebServerHandler* hp = &WebServerHandlers->handlers[ i ];
    00657       if ( strncmp( hp->address, address, strlen( hp->address ) ) == 0 )
    00658       {
    00659         responded = (*hp->handler)( requestType, address, WebServer->request, REQUEST_SIZE_MAX, requestSocket, WebServer->response, RESPONSE_SIZE_MAX );
    00660         if ( responded )
    00661           break;
    00662       }
    00663     }
    00664   }
    00665   if(!responded)
    00666     TestHandler(requestType, address, WebServer->request, REQUEST_SIZE_MAX, requestSocket, WebServer->response, RESPONSE_SIZE_MAX);
    00667
    00668   SocketClose( requestSocket );
    00669 }
    00670
    00671 void WebServer_Demo( char* requestType, char* address, char* requestBuffer, int requestMaxSize, void* socket, char* buffer, int len )
    00672 {
    00673   (void)address;
    00674   char temp[100];
    00675
    00676   if( !WebServer_WriteResponseOkHTML( socket ) )
    00677     return;
    00678
    00679   if( !WebServer_WriteHeader( true, socket, buffer, len ) )
    00680     return;
    00681
    00682   if( !WebServer_WriteBodyStart( 0, socket, buffer, len ) )
    00683     return;
    00684
    00685   int formElements = 0;
    00686   HtmlForm form;
    00687   form.count = 0;
    00688
    00689   // if this request is an HTTP GET
    00690   if ( strncmp( requestType, "GET", 3 ) == 0 )
    00691   {
    00692     char *p = strchr( requestBuffer, '?' );
    00693     if( p != NULL ) // if we didn't find a ?, then there were no form elements
    00694       formElements = WebServer_ParseFormElements( p+1, &form );
    00695   }
    00696
    00697   // if this request is an HTTP POST
    00698   if ( strncmp( requestType, "POST", 4 ) == 0 )
    00699   {
    00700     // make sure we're pointing at the POST data and if it looks good, process it
    00701     if( WebServer_GetPostData( socket, requestBuffer, requestMaxSize ) )
    00702       formElements = WebServer_ParseFormElements( requestBuffer, &form ); // grab the data out of the form
    00703   }
    00704
    00705   strcat( buffer, "<form method=\"POST\">" );
    00706   strcat( buffer, "App LED 0: <input type=\"checkbox\" name=\"appled0\"><br>" );
    00707   strcat( buffer, "App LED 1: <input type=\"checkbox\" name=\"appled1\"><br>" );
    00708   strcat( buffer, "App LED 2: <input type=\"checkbox\" name=\"appled2\"><br>" );
    00709   strcat( buffer, "App LED 3: <input type=\"checkbox\" name=\"appled3\"><br>" );
    00710   strcat( buffer, "<p></p>" );
    00711   strcat( buffer, "<input type=\"submit\" value=\"Submit\">" );
    00712   strcat( buffer, "</form>" );
    00713
    00714   int i, j;
    00715   for( j = 0; j < 4; j++ )
    00716   {
    00717     int value = 0;
    00718     snprintf( temp, 100, "appled%d", j );
    00719     for( i = 0; i < formElements; i++ )
    00720     {
    00721       if( strcmp( temp, form.elements[i].key ) == 0 )
    00722         value = 1;
    00723     }
    00724     //AppLed_SetState( j, value );
    00725   }
    00726
    00727   // Write out the dynamically generated page.
    00728   if( !SocketWrite( socket, buffer, strlen( buffer ) ) )
    00729     return;
    00730
    00731   WebServer_WriteBodyEnd( socket );
    00732 }
    00733
    00734 void WebServerTask( void *p )
    00735 {
    00736   (void)p;
    00737
    00738   // Try to create a socket on the appropriate port
    00739   WebServer_CreateServerSocket();
    00740
    00741   while( 1 )
    00742   {
    00743     if(WebServer->changeListenPort == true)
    00744     {
    00745       WebServer_CreateServerSocket();
    00746       WebServer->changeListenPort = false;
    00747     }
    00748     /* Wait for connection. */
    00749     WebServer->requestSocket = ServerSocketAccept( WebServer->serverSocket );
    00750
    00751     if ( WebServer->requestSocket != NULL )
    00752     {
    00753       WebServer->hits++;
    00754       WebServer_ProcessRequest( WebServer->requestSocket );
    00755       WebServer->requestSocket = NULL;
    00756     }
    00757     Sleep( 5 );
    00758   }
    00759 }
    00760
    00761 /*
    00762   Create a new ServerSocket on the appropriate listenPort
    00763 */
    00764 static void WebServer_CreateServerSocket( )
    00765 {
    00766   if(WebServer->serverSocket)
    00767   {
    00768     SocketClose(WebServer->serverSocket);
    00769     WebServer->serverSocket = NULL;
    00770   }
    00771   while( WebServer->serverSocket == NULL )
    00772   {
    00773     WebServer->serverSocket = ServerSocket( WebServer->listenPort );
    00774     if ( WebServer->serverSocket == NULL )
    00775       Sleep( 1000 );
    00776   }
    00777 }
    00778
    00779 static int WebServer_WriteResponseOk_( char* contentType, void* socket )
    00780 {
    00781   int written = 0;
    00782   written += SocketWrite( socket, HTTP_OK, strlen( HTTP_OK ) );
    00783   written += SocketWrite( socket, contentType, strlen( contentType ) );
    00784   return written;
    00785 }
    00786
    00787 char* WebServer_GetRequestAddress( char* request, int length, char** requestType  )
    00788 {
    00789   char *last = request + length;
    00790   *requestType = NULL;
    00791   char* address = NULL;
    00792
    00793   // Skip any initial spaces
    00794   while( *request == ' ' )
    00795     request++;
    00796
    00797   if ( request > last )
    00798     return address;
    00799
    00800   *requestType = request;
    00801
    00802   // Skip the request type
    00803   while ( *request != ' ' )
    00804     request++;
    00805
    00806   if ( request > last )
    00807     return address;
    00808
    00809   // Skip any subsequent spaces
    00810   while( *request == ' ' )
    00811     request++;
    00812
    00813   if ( request > last )
    00814     return address;
    00815
    00816   address = request;
    00817
    00818   while( !isspace( *request ) )
    00819     request++;
    00820
    00821   if ( request < last )
    00822     *request = 0;
    00823
    00824   return address;
    00825 }
    00826
    00827 #ifdef OSC // Webserver OSC interface
    00828
    00829 /** \defgroup webserverosc Web Server - OSC
    00830   Configure the Web Server  via OSC.
    00831   \ingroup OSC
    00832
    00833   \section devices Devices
    00834     There is only one Web Server system, so a device index is not used.
    00835
    00836   \section properties Properties
    00837   The Web Server system has the following properties
    00838   - active
    00839   - listenport
    00840
    00841   \section details Property Details
    00842
    00843   \b Active
    00844
    00845   The \b active property sets whether the web server on the Make Controller is running or not.
    00846   The default web server does not really do anything too interesting, but provides a count of the
    00847   number of requests it has served.  You can access the web server by typing the board's IP address
    00848   into your favorite browser.  You can check the board's IP address in mchelper.
    00849
    00850   To turn the web server on, send the message
    00851   \code /webserver/active 1 \endcode
    00852   then enter the board's IP address into the address bar of your favorite web browser.  Send the message
    00853   \code /network/webserver 0 \endcode
    00854   to turn the webserver off.
    00855
    00856   <b> Listen Port </b>
    00857
    00858   The \b listenport property sets which port the web server should listen on for incoming requests.  By default
    00859   this is set to 80, the standard port for HTTP.
    00860
    00861   To listen on port 8080, send the message
    00862   \code /webserver/listenport 8080 \endcode
    00863
    00864   Note that the server will most likely already be listening on the previous port, and it won't update its port
    00865   until it serves that last request it's waiting for.
    00866 */
    00867
    00868 #include "osc.h"
    00869 static char* WebServerOsc_Name = "webserver";
    00870 static char* WebServerOsc_PropertyNames[] = { "active", "listenport", 0 }; // must have a trailing 0
    00871
    00872 int WebServerOsc_PropertySet( int value, int property );
    00873 int WebServerOsc_PropertyGet( int property );
    00874
    00875 const char* WebServerOsc_GetName( void )
    00876 {
    00877   return WebServerOsc_Name;
    00878 }
    00879
    00880 int WebServerOsc_ReceiveMessage( int channel, char* message, int length )
    00881 {
    00882   int status = Osc_IntReceiverHelper( channel, message, length,
    00883                                       WebServerOsc_Name,
    00884                                       WebServerOsc_PropertySet, WebServerOsc_PropertyGet,
    00885                                       WebServerOsc_PropertyNames );
    00886
    00887   if ( status != CONTROLLER_OK )
    00888     return Osc_SendError( channel, WebServerOsc_Name, status );
    00889   return CONTROLLER_OK;
    00890 }
    00891
    00892 // Set the index LED, property with the value
    00893 int WebServerOsc_PropertySet( int property, int value )
    00894 {
    00895   switch ( property )
    00896   {
    00897     case 0: // active
    00898       WebServer_SetActive( value );
    00899       break;
    00900     case 1: // listenport
    00901       if(value != WebServer_GetListenPort())
    00902       {
    00903         WebServer_SetListenPort( value );
    00904         WebServer->changeListenPort = true;
    00905       }
    00906       break;
    00907   }
    00908   return CONTROLLER_OK;
    00909 }
    00910
    00911 // Get the property
    00912 int WebServerOsc_PropertyGet( int property )
    00913 {
    00914   int value = 0;
    00915   switch ( property )
    00916   {
    00917     case 0: // active
    00918       value = WebServer_GetActive( );
    00919       break;
    00920     case 1: // listenport
    00921       value = WebServer_GetListenPort( );
    00922       break;
    00923   }
    00924   return value;
    00925 }
    00926
    00927 #endif // OSC
    00928
    00929 #endif // MAKE_CTRL_NETWORK
    00930

The Make Controller Kit is an open source project maintained by MakingThings.
MakingThings code is released under the Apache 2.0 license.
Bug tracker, development wiki and status can be found at http://dev.makingthings.com.
This document was last updated on 18 May 2009.