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("location.href='"; 00426 char* reloadEnd = "'",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.