A simple web server that can be bound to either the EthernetInterface or the WiflyInterface.
Dependents: Smart-WiFly-WebServer WattEye X10Svr SSDP_Server
Revision 22:55974de690c1, committed 2013-10-10
- Comitter:
- WiredHome
- Date:
- Thu Oct 10 13:44:07 2013 +0000
- Parent:
- 21:660143f20b04
- Child:
- 23:6963f45e950a
- Commit message:
- documentation updates.
Changed in this revision
SW_HTTPServer.cpp | Show annotated file Show diff for this revision Revisions of this file |
SW_HTTPServer.h | Show annotated file Show diff for this revision Revisions of this file |
--- a/SW_HTTPServer.cpp Thu Sep 26 23:47:50 2013 +0000 +++ b/SW_HTTPServer.cpp Thu Oct 10 13:44:07 2013 +0000 @@ -87,6 +87,8 @@ wifly = _wf; webroot = (char *)malloc(strlen(_webroot)+1); strcpy(webroot, _webroot); + if (strlen(webroot)>1 && webroot[strlen(webroot)-1] == '/') // remove trailing '/' + webroot[strlen(webroot)-1] = '\0'; maxqueryParams = _maxqueryParams; maxdynamicpages = _maxdynamicpages; headerParams = (namevalue *)malloc(maxheaderParams * sizeof(namevalue)); @@ -457,13 +459,17 @@ char * HTTPServer::rewritePrependWebroot(char * queryString) { - char * temp = (char *)mymalloc(strlen(webroot) + strlen(queryString) + 1); + char * temp = (char *)mymalloc(strlen(webroot) + strlen(queryString) + 2); // room for / if (temp) { *temp = '\0'; + char lastchar; strcpy(temp, webroot); - if (temp[strlen(temp)-1] == '/' && *queryString == '/') - temp[strlen(temp)-1] = '\0'; + lastchar = temp[strlen(temp)-1]; + if (lastchar != '/' && *queryString != '/') + strcat(temp, "/"); + else if (lastchar == '/' && *queryString == '/') + queryString++; strcat(temp, queryString); myfree(queryString); return temp; @@ -637,18 +643,26 @@ bool acceptIt = false; if (strcmp(queryType, "POST") == 0 && postBytes > 0 ) { if (postBytes) { + int ndxHandler = 0; bool regHandled = false; // Registered Dynamic Handler // Callback and ask if they want to accept this data - for (int i=0; i<handlercount; i++) { - if (strcmp(handlers[i].path, queryString) == 0) { - acceptIt = (*handlers[i].callback)(this, CONTENT_LENGTH_REQUEST, queryString, queryParams, queryParamCount); + for (ndxHandler=0; ndxHandler<handlercount; ndxHandler++) { + if (strcmp(handlers[ndxHandler].path, queryString) == 0) { + acceptIt = (*handlers[ndxHandler].callback)(this, CONTENT_LENGTH_REQUEST, queryString, queryParams, queryParamCount); regHandled = true; break; // we only execute the first one } } if (regHandled && acceptIt) { + // @todo need to refactor - if the thing is bigger than the buffer, + // then we can receive it a chunk at a time, and hand off + // the chunks to the callback. May need callbacks that + // are: START: extract the filename/object name, + // NEXT: a chunk of data, + // END: signals that all chunks were delivered. + // // If so, we'll make space for it postQueryString = (char *)mymalloc(postBytes + 1); if (postQueryString) { @@ -665,12 +679,22 @@ n = client.receive(offset, postBytes - len); if (n >=0) { offset[n] = '\0'; + //printf("HTTPd: %d of %d: [%s]\r\n", len, postBytes, offset); + } else if (n < 0) { + //printf("HTTPd: n=%d\r\n", n); + break; // no more data, before the plan } } if (len >= 0) { - UnescapeString(postQueryString); - ParseParameters(postQueryString); +// UnescapeString(postQueryString); +// ParseParameters(postQueryString); + // use the same handler as for the length check + acceptIt = (*handlers[ndxHandler].callback)(this, DATA_TRANSFER, postQueryString, NULL, 0); + } else { + pc->printf("HTTPd: len error.\r\n"); } + } else { + pc->printf("HTTPd: attempt to allocate %d failed.\r\n", postBytes+1); } } else { // Simply copy it to the bitbucket
--- a/SW_HTTPServer.h Thu Sep 26 23:47:50 2013 +0000 +++ b/SW_HTTPServer.h Thu Oct 10 13:44:07 2013 +0000 @@ -51,7 +51,7 @@ /// or signaling outputs. /// /// @code -/// HTTPServer svr(&wifly, HTTP_SERVER_PORT, "/local/", 15, 30, 10, &pc); +/// HTTPServer svr(&wifly, HTTP_SERVER_PORT, "/local", 15, 30, 10, &pc); /// svr.RegisterHandler("/dyn1", SimpleDynamicPage); /// while (true) /// { @@ -187,7 +187,7 @@ */ typedef enum CALLBACKTYPE { CONTENT_LENGTH_REQUEST, ///< ask the client if they wish to accept the data, typically from a POST event - DATA_TRANSFER, ///< not currently used, may allow "chunking" the data to the client + DATA_TRANSFER, ///< used when submitting a file via a form SEND_PAGE, ///< the activated method should now send the page } CallBackType; @@ -195,14 +195,23 @@ * This is the prototype for custom handlers that are activated via a callback * * This callback gets overloaded for a few purposes, which can be identified by the \see CallBackType parameter + * @li CONTENT_LENGTH_REQUEST - the server is asking the callback if it wants to receive the message, + * which may require significant memory. If the request is accepted, true should be returned. + * If the request is denied, false should be returned. + * @li DATA_TRANSFER - the server is handing off a large body of data, which was accepted based + * on the CONTENT_LENGTH_REQUEST callback. The data is now available for processing. + * The callback should return true to continue the processing. * @li SEND_PAGE - the callback should now send the html page, using as many svr->send() as needed. * When the callback returns, it should always indicate true. - * @li CONTENT_LENGTH_REQUEST - the server is asking the callback if it wants to receive the message, - * which may require significant memory. If the request is accepted, true should be returned. - * If the request is denied, false should be returned. + * + * @note The queryParams pointer purpose depends on the callback type. + * For CONTENT_LENGTH_REQUEST, the pointer points to the name=value pairs from the + * header. + * For DATA_TRANSFER, the pointer points to the start of the actual data. + * For SEND_PAGE, * * @param svr is a handle to this class, so the callback has access to member functions - * @param queryParams is a pointer to an array of name value pairs + * @param queryParams is a pointer based on the callback type. * @queryParamCount is the number of parameters. * @return true if command was accepted */ @@ -231,6 +240,20 @@ ~HTTPServer(); /** + * Get the path to the webroot, for applications that need to + * reference the file system relative to that point. + * + * @note The returned value may not be exactly as set at instantiation + * as trailing '/' were removed (unless the web root == "/"). + * e.g. "/msc/web/" becomes "/msc/web" + * + * @returns pointer to the webroot string. + */ + const char * GetWebRoot() { + return (const char *)webroot; + }; + + /** * The process to call whenever there is free time, as this basically does * all the work to monitor for connections and handle replies. *