A simple web server that can be bound to either the EthernetInterface or the WiflyInterface.
Dependents: Smart-WiFly-WebServer WattEye X10Svr SSDP_Server
SW_HTTPServer.h@4:f34642902056, 2013-06-25 (annotated)
- Committer:
- WiredHome
- Date:
- Tue Jun 25 16:37:06 2013 +0000
- Revision:
- 4:f34642902056
- Parent:
- 3:17928786bdb5
- Child:
- 5:c9b27e718054
When a pointer to a buffer is passed in to the Wifly APIs that can modify that buffer, it will also pass the size of that buffer to avoid buffer overrun.
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
WiredHome | 1:54353af0d20a | 1 | |
WiredHome | 1:54353af0d20a | 2 | #ifndef SW_HTTPSERVER_H |
WiredHome | 1:54353af0d20a | 3 | #define SW_HTTPSERVER_H |
WiredHome | 1:54353af0d20a | 4 | #include "mbed.h" |
WiredHome | 1:54353af0d20a | 5 | //#include "MODSERIAL.h" // would like to hook in mod serial for higher performance, less blocking |
WiredHome | 1:54353af0d20a | 6 | #include "Wifly.h" |
WiredHome | 1:54353af0d20a | 7 | #include "TCPSocketServer.h" |
WiredHome | 1:54353af0d20a | 8 | #include "TCPSocketConnection.h" |
WiredHome | 1:54353af0d20a | 9 | |
WiredHome | 1:54353af0d20a | 10 | #ifdef MODSERIAL_H |
WiredHome | 1:54353af0d20a | 11 | #define PC MODSERIAL |
WiredHome | 1:54353af0d20a | 12 | #else |
WiredHome | 1:54353af0d20a | 13 | #define PC Serial |
WiredHome | 1:54353af0d20a | 14 | #endif |
WiredHome | 1:54353af0d20a | 15 | |
WiredHome | 3:17928786bdb5 | 16 | /// This is the default buffer size used to send files. You might |
WiredHome | 3:17928786bdb5 | 17 | /// size this to be a little less than the ethernet frame size |
WiredHome | 3:17928786bdb5 | 18 | #define FILESEND_BUF_SIZE 1200 |
WiredHome | 3:17928786bdb5 | 19 | |
WiredHome | 3:17928786bdb5 | 20 | |
WiredHome | 3:17928786bdb5 | 21 | /// MAX_HEADER_SIZE is the default size to contain the largest header. This is |
WiredHome | 3:17928786bdb5 | 22 | /// the size of the URL and query string, and also all the |
WiredHome | 3:17928786bdb5 | 23 | /// other header information about the client. This can be |
WiredHome | 3:17928786bdb5 | 24 | /// a couple of K, larger if you have big forms as it includes the |
WiredHome | 3:17928786bdb5 | 25 | /// form data that is submitted. |
WiredHome | 3:17928786bdb5 | 26 | #define MAX_HEADER_SIZE 1000 |
WiredHome | 3:17928786bdb5 | 27 | |
WiredHome | 1:54353af0d20a | 28 | /// HTTPServer is a simple web server using the WiFly module. |
WiredHome | 0:729320f63c5c | 29 | /// |
WiredHome | 3:17928786bdb5 | 30 | /// While simple, it is a capable, web server. The basic mode |
WiredHome | 3:17928786bdb5 | 31 | /// of operation is for it to serve static web pages from an available |
WiredHome | 3:17928786bdb5 | 32 | /// file system. |
WiredHome | 3:17928786bdb5 | 33 | /// |
WiredHome | 3:17928786bdb5 | 34 | /// The default page is index.htm (compile time defined) |
WiredHome | 3:17928786bdb5 | 35 | /// standard support to serve a number of standard file types; |
WiredHome | 3:17928786bdb5 | 36 | /// gif, jpg, jpeg, ico, png, zip, gz, tar, txt, pdf, htm, html |
WiredHome | 3:17928786bdb5 | 37 | /// (this list is also compile time defined) |
WiredHome | 3:17928786bdb5 | 38 | /// |
WiredHome | 3:17928786bdb5 | 39 | /// It can also serve dynamically generated pages, and therefore |
WiredHome | 3:17928786bdb5 | 40 | /// respond to form submission. Through the dynamic interface it is |
WiredHome | 3:17928786bdb5 | 41 | /// then quite easy to interact with the hardware, reading the inputs |
WiredHome | 3:17928786bdb5 | 42 | /// or signaling outputs. |
WiredHome | 3:17928786bdb5 | 43 | /// |
WiredHome | 3:17928786bdb5 | 44 | /// @code |
WiredHome | 3:17928786bdb5 | 45 | /// HTTPServer svr(&wifly, HTTP_SERVER_PORT, "/local/", 30, 10, &pc); |
WiredHome | 3:17928786bdb5 | 46 | /// svr.RegisterHandler("/dyn1", SimpleDynamicPage); |
WiredHome | 3:17928786bdb5 | 47 | /// while (true) |
WiredHome | 3:17928786bdb5 | 48 | /// { |
WiredHome | 3:17928786bdb5 | 49 | /// svr.Poll(); // this is non blocking process, but variable execution |
WiredHome | 3:17928786bdb5 | 50 | /// } |
WiredHome | 3:17928786bdb5 | 51 | /// @endcode |
WiredHome | 3:17928786bdb5 | 52 | /// |
WiredHome | 3:17928786bdb5 | 53 | /// This web server used nweb as a starting point, but expanded well beyond there. |
WiredHome | 0:729320f63c5c | 54 | /// http://www.ibm.com/developerworks/systems/library/es-nweb/sidefile1.html |
WiredHome | 0:729320f63c5c | 55 | /// |
WiredHome | 3:17928786bdb5 | 56 | /// @note This server uses a modified version of the mbed WiflyInterface - there |
WiredHome | 3:17928786bdb5 | 57 | /// were a number of performance issues identified and resolved in the local version. |
WiredHome | 0:729320f63c5c | 58 | /// |
WiredHome | 3:17928786bdb5 | 59 | /// Given: scheme://server:port/path?query_string#fragment_id |
WiredHome | 0:729320f63c5c | 60 | /// @li scheme is "http" |
WiredHome | 3:17928786bdb5 | 61 | /// @li server is whatever IP the server has |
WiredHome | 0:729320f63c5c | 62 | /// @li port is the registered port |
WiredHome | 0:729320f63c5c | 63 | /// @li /path is the reference to the file (actual or logical) on the server |
WiredHome | 0:729320f63c5c | 64 | /// @li query_string is any combination of name=value pairs |
WiredHome | 0:729320f63c5c | 65 | /// @li fragment_id is a reference to an anchor on the page |
WiredHome | 0:729320f63c5c | 66 | /// |
WiredHome | 3:17928786bdb5 | 67 | /// Features: |
WiredHome | 3:17928786bdb5 | 68 | /// @li Serves static pages from a file system. Many normal filetypes are |
WiredHome | 3:17928786bdb5 | 69 | /// supported. |
WiredHome | 3:17928786bdb5 | 70 | /// @li Compile time configurable for the "default" file, typically index.htm. |
WiredHome | 3:17928786bdb5 | 71 | /// @li Provides a registration interface for dynamically generated pages that |
WiredHome | 3:17928786bdb5 | 72 | /// can then interact with other hardware. |
WiredHome | 3:17928786bdb5 | 73 | /// @li Revised to be Non-blocking, however the execution time is variable |
WiredHome | 3:17928786bdb5 | 74 | /// depending on the actions being performed. |
WiredHome | 3:17928786bdb5 | 75 | /// |
WiredHome | 3:17928786bdb5 | 76 | /// Limitations: |
WiredHome | 3:17928786bdb5 | 77 | /// @li Supports only a single connection at a time. |
WiredHome | 3:17928786bdb5 | 78 | /// @li Rapid requests for page objects (e.g. embedded images) are lost. Still |
WiredHome | 3:17928786bdb5 | 79 | /// working to understand this issue. |
WiredHome | 3:17928786bdb5 | 80 | /// |
WiredHome | 3:17928786bdb5 | 81 | /// ToDo: |
WiredHome | 3:17928786bdb5 | 82 | /// @li A web page with served objects (img src=...) is rarely served properly. It |
WiredHome | 3:17928786bdb5 | 83 | /// might trace to forcing the connection to close, but not yet sure. |
WiredHome | 3:17928786bdb5 | 84 | /// Explore "Set Uart Rx Data Buffer" in WiFly manual 2.3.65 |
WiredHome | 3:17928786bdb5 | 85 | /// @li hunt down lengthy operations - there seems to be a long timeout somewhere. |
WiredHome | 3:17928786bdb5 | 86 | /// @li parse the header similar to the query string, and then make |
WiredHome | 2:a29c32190037 | 87 | /// those parameters accessible - perhaps like environment vars. |
WiredHome | 3:17928786bdb5 | 88 | /// @li move part of the POST method handler to the registered handler, so |
WiredHome | 0:729320f63c5c | 89 | /// it can decide if it should allocate the needed memory. |
WiredHome | 3:17928786bdb5 | 90 | /// @li Add password capability to some web pages |
WiredHome | 3:17928786bdb5 | 91 | /// @li transform the pc serial interface to a log interface, which might |
WiredHome | 0:729320f63c5c | 92 | /// be more useful. |
WiredHome | 3:17928786bdb5 | 93 | /// @li Add ability to put WiFly in AP mode and then configuration pages |
WiredHome | 2:a29c32190037 | 94 | /// to find and join a network. |
WiredHome | 3:17928786bdb5 | 95 | /// @li Add ability to change/update SW in the WiFly module |
WiredHome | 3:17928786bdb5 | 96 | /// @li Add ability to upload a new application to the mbed |
WiredHome | 2:a29c32190037 | 97 | /// |
WiredHome | 2:a29c32190037 | 98 | /// History: |
WiredHome | 2:a29c32190037 | 99 | /// @li 20130530 Initial version |
WiredHome | 2:a29c32190037 | 100 | /// @li 20130601 Renamed ip_process to Poll |
WiredHome | 3:17928786bdb5 | 101 | /// @li 20130617 Cleaned up some of the documentation changes |
WiredHome | 3:17928786bdb5 | 102 | /// @li 20130623 Make it non-blocking. "Poll" takes a variable amount |
WiredHome | 3:17928786bdb5 | 103 | /// of time, based on whether it is idle, or how much it |
WiredHome | 3:17928786bdb5 | 104 | /// has to do. |
WiredHome | 3:17928786bdb5 | 105 | /// @li It now survives overnight and still responds, so the problem with |
WiredHome | 3:17928786bdb5 | 106 | /// it going offline after long inactivity appears resolved. |
WiredHome | 0:729320f63c5c | 107 | /// |
WiredHome | 0:729320f63c5c | 108 | /// @note Copyright © 2013 by Smartware Computing, all rights reserved. |
WiredHome | 0:729320f63c5c | 109 | /// Individuals may use this application for evaluation or non-commercial |
WiredHome | 0:729320f63c5c | 110 | /// purposes. Within this restriction, changes may be made to this application |
WiredHome | 0:729320f63c5c | 111 | /// as long as this copyright notice is retained. The user shall make |
WiredHome | 0:729320f63c5c | 112 | /// clear that their work is a derived work, and not the original. |
WiredHome | 0:729320f63c5c | 113 | /// Users of this application and sources accept this application "as is" and |
WiredHome | 0:729320f63c5c | 114 | /// shall hold harmless Smartware Computing, for any undesired results while |
WiredHome | 0:729320f63c5c | 115 | /// using this application - whether real or imagined. |
WiredHome | 0:729320f63c5c | 116 | /// |
WiredHome | 0:729320f63c5c | 117 | /// @author David Smart, Smartware Computing |
WiredHome | 0:729320f63c5c | 118 | /// |
WiredHome | 0:729320f63c5c | 119 | class HTTPServer |
WiredHome | 0:729320f63c5c | 120 | { |
WiredHome | 0:729320f63c5c | 121 | public: |
WiredHome | 0:729320f63c5c | 122 | /** |
WiredHome | 3:17928786bdb5 | 123 | * name-value pairs for parameters |
WiredHome | 0:729320f63c5c | 124 | */ |
WiredHome | 3:17928786bdb5 | 125 | typedef struct NAMEVALUE { |
WiredHome | 0:729320f63c5c | 126 | char * name; |
WiredHome | 0:729320f63c5c | 127 | char * value; |
WiredHome | 0:729320f63c5c | 128 | } namevalue; |
WiredHome | 2:a29c32190037 | 129 | |
WiredHome | 2:a29c32190037 | 130 | /** |
WiredHome | 3:17928786bdb5 | 131 | * Indicates the purpose of the Handler callback |
WiredHome | 3:17928786bdb5 | 132 | * |
WiredHome | 3:17928786bdb5 | 133 | * Application code in a dynamic page uses this to determine the state |
WiredHome | 3:17928786bdb5 | 134 | * and therefore the needed operation to be performed. |
WiredHome | 3:17928786bdb5 | 135 | * |
WiredHome | 3:17928786bdb5 | 136 | * @code |
WiredHome | 3:17928786bdb5 | 137 | * bool SimpleDynamicPage(HTTPServer *svr, HTTPServer::CallBackType type, const char * path, const HTTPServer::namevalue *params, int paramcount) { |
WiredHome | 3:17928786bdb5 | 138 | * char buf[100]; |
WiredHome | 3:17928786bdb5 | 139 | * bool ret = false; |
WiredHome | 3:17928786bdb5 | 140 | * |
WiredHome | 3:17928786bdb5 | 141 | * switch (type) { |
WiredHome | 3:17928786bdb5 | 142 | * case HTTPServer::SEND_PAGE: |
WiredHome | 3:17928786bdb5 | 143 | * svr->header(200, "OK", "Content-Type: text/html\r\n"); |
WiredHome | 3:17928786bdb5 | 144 | * svr->send("<html><head><title>Dynamic Page</title></head>\r\n"); |
WiredHome | 3:17928786bdb5 | 145 | * svr->send("<body>\r\n"); |
WiredHome | 3:17928786bdb5 | 146 | * svr->send("This page was generated dynamically. Create your own name=value pairs on the URL " |
WiredHome | 3:17928786bdb5 | 147 | * "which uses the GET method.<br/>\r\n"); |
WiredHome | 3:17928786bdb5 | 148 | * sprintf(buf, "%d parameters passed to {%s}:<br/>\r\n", paramcount, path); |
WiredHome | 3:17928786bdb5 | 149 | * svr->send(buf); |
WiredHome | 3:17928786bdb5 | 150 | * for (int i=0; i<paramcount; i++) { |
WiredHome | 3:17928786bdb5 | 151 | * sprintf(buf, "%d: %s = %s<br/>\r\n", i, params[i].name, params[i].value); |
WiredHome | 3:17928786bdb5 | 152 | * svr->send(buf); |
WiredHome | 3:17928786bdb5 | 153 | * } |
WiredHome | 3:17928786bdb5 | 154 | * svr->send("<br/><a href='/'>back to main</a></body></html>\r\n"); |
WiredHome | 3:17928786bdb5 | 155 | * ret = true; |
WiredHome | 3:17928786bdb5 | 156 | * break; |
WiredHome | 3:17928786bdb5 | 157 | * case HTTPServer::CONTENT_LENGTH_REQUEST: |
WiredHome | 3:17928786bdb5 | 158 | * ret = true; |
WiredHome | 3:17928786bdb5 | 159 | * break; |
WiredHome | 3:17928786bdb5 | 160 | * case HTTPServer::DATA_TRANSFER: |
WiredHome | 3:17928786bdb5 | 161 | * ret = true; |
WiredHome | 3:17928786bdb5 | 162 | * break; |
WiredHome | 3:17928786bdb5 | 163 | * default: |
WiredHome | 3:17928786bdb5 | 164 | * ret = false; |
WiredHome | 3:17928786bdb5 | 165 | * break; |
WiredHome | 3:17928786bdb5 | 166 | * } |
WiredHome | 3:17928786bdb5 | 167 | * return ret; |
WiredHome | 3:17928786bdb5 | 168 | * } |
WiredHome | 3:17928786bdb5 | 169 | * @endcode |
WiredHome | 2:a29c32190037 | 170 | */ |
WiredHome | 3:17928786bdb5 | 171 | typedef enum CALLBACKTYPE { |
WiredHome | 3:17928786bdb5 | 172 | CONTENT_LENGTH_REQUEST, ///< ask the client if they wish to accept the data |
WiredHome | 3:17928786bdb5 | 173 | DATA_TRANSFER, ///< not currently used, may allow "chunking" the data to the client |
WiredHome | 3:17928786bdb5 | 174 | SEND_PAGE, ///< the activated method should now send the page |
WiredHome | 2:a29c32190037 | 175 | } CallBackType; |
WiredHome | 0:729320f63c5c | 176 | |
WiredHome | 0:729320f63c5c | 177 | /** |
WiredHome | 3:17928786bdb5 | 178 | * This is the prototype for custom handlers that are activated via a callback |
WiredHome | 0:729320f63c5c | 179 | * |
WiredHome | 3:17928786bdb5 | 180 | * This callback gets overloaded for a few purposes, which can be identified by the \see CallBackType parameter |
WiredHome | 2:a29c32190037 | 181 | * @li SEND_PAGE - the callback should now send the html page, using as many svr->send() as needed. |
WiredHome | 2:a29c32190037 | 182 | * When the callback returns, it should always indicate true. |
WiredHome | 2:a29c32190037 | 183 | * @li CONTENT_LENGTH_REQUEST - the server is asking the callback if it wants to receive the message, |
WiredHome | 2:a29c32190037 | 184 | * which may require significant memory. If the request is accepted, true should be returned. |
WiredHome | 2:a29c32190037 | 185 | * If the request is denied, false should be returned. |
WiredHome | 2:a29c32190037 | 186 | * |
WiredHome | 0:729320f63c5c | 187 | * @param svr is a handle to this class, so the callback has access to member functions |
WiredHome | 0:729320f63c5c | 188 | * @param params is a pointer to an array of name value pairs |
WiredHome | 0:729320f63c5c | 189 | * @paramcount is the number of parameters. |
WiredHome | 2:a29c32190037 | 190 | * @return true if command was accepted |
WiredHome | 0:729320f63c5c | 191 | */ |
WiredHome | 2:a29c32190037 | 192 | typedef bool (* Handler)(HTTPServer * svr, CallBackType type, const char *path, const namevalue *params, int paramcount); |
WiredHome | 0:729320f63c5c | 193 | |
WiredHome | 0:729320f63c5c | 194 | /** |
WiredHome | 0:729320f63c5c | 195 | * Create the HTTPServer object. |
WiredHome | 0:729320f63c5c | 196 | * |
WiredHome | 0:729320f63c5c | 197 | * @param wifly is the serial port with the wifly interface. |
WiredHome | 0:729320f63c5c | 198 | * @param port is the optional parameter for the port number to use, default is 80. |
WiredHome | 0:729320f63c5c | 199 | * @param webroot is a file system path to the root folder for the web space. |
WiredHome | 0:729320f63c5c | 200 | * @param maxparams defines the maximum number of parameters to a dynamic function (and the memory to support them). |
WiredHome | 0:729320f63c5c | 201 | * @param maxdynamicpages defines the maximum number of dynamic pages that can be registered. |
WiredHome | 0:729320f63c5c | 202 | * @param pc is the serial port for debug information (I should transform this to a log interface) |
WiredHome | 3:17928786bdb5 | 203 | * @param allocforheader is the memory allocation to support the largest expected header from a client |
WiredHome | 3:17928786bdb5 | 204 | * @param allocforfile is the memory allocation to support sending a file to the client. This is typically sized to fit |
WiredHome | 3:17928786bdb5 | 205 | * an ethernet frame. |
WiredHome | 0:729320f63c5c | 206 | */ |
WiredHome | 3:17928786bdb5 | 207 | HTTPServer(Wifly * wifly, int port = 80, const char * webroot = "/", int maxparams = 30, int maxdynamicpages = 10, PC * pc = NULL, |
WiredHome | 3:17928786bdb5 | 208 | int _allocforheader = MAX_HEADER_SIZE, int _allocforfile = FILESEND_BUF_SIZE); |
WiredHome | 0:729320f63c5c | 209 | |
WiredHome | 0:729320f63c5c | 210 | /** |
WiredHome | 3:17928786bdb5 | 211 | * Destructor, which can clean up memory. |
WiredHome | 0:729320f63c5c | 212 | */ |
WiredHome | 0:729320f63c5c | 213 | ~HTTPServer(); |
WiredHome | 0:729320f63c5c | 214 | |
WiredHome | 0:729320f63c5c | 215 | /** |
WiredHome | 3:17928786bdb5 | 216 | * The process to call whenever there is free time, as this basically does |
WiredHome | 0:729320f63c5c | 217 | * all the work to monitor for connections and handle replies. |
WiredHome | 2:a29c32190037 | 218 | * |
WiredHome | 2:a29c32190037 | 219 | * 20130601 Renamed from ip_process to Poll |
WiredHome | 0:729320f63c5c | 220 | */ |
WiredHome | 2:a29c32190037 | 221 | void Poll(); |
WiredHome | 0:729320f63c5c | 222 | |
WiredHome | 0:729320f63c5c | 223 | /** |
WiredHome | 3:17928786bdb5 | 224 | * Send typical header data, and some optional data back to the client. |
WiredHome | 3:17928786bdb5 | 225 | * |
WiredHome | 3:17928786bdb5 | 226 | * This forms and sends the typical header back to the client. It may also send |
WiredHome | 3:17928786bdb5 | 227 | * optional data (which must end with "\r\n"). It then sends the second newline |
WiredHome | 3:17928786bdb5 | 228 | * sequence that signals the end of the header. |
WiredHome | 0:729320f63c5c | 229 | * |
WiredHome | 0:729320f63c5c | 230 | * @param code is the optional return code; 200 = OK, if not provided then 404 = Not found is returned |
WiredHome | 0:729320f63c5c | 231 | * @param code_text is the text to align with the code (e.g. 404, "Not Found") |
WiredHome | 0:729320f63c5c | 232 | * @param content_type is a pointer to "Content-Type: text/html\r\n" (for example) |
WiredHome | 3:17928786bdb5 | 233 | * @param optional_text is a pointer to any other text that is part of the header, which must |
WiredHome | 3:17928786bdb5 | 234 | * have \r\n termination. |
WiredHome | 0:729320f63c5c | 235 | */ |
WiredHome | 0:729320f63c5c | 236 | void header(int code = 404, const char * code_text = "Not Found", const char * content_type = NULL, const char * optional_text = NULL); |
WiredHome | 0:729320f63c5c | 237 | |
WiredHome | 0:729320f63c5c | 238 | /** |
WiredHome | 0:729320f63c5c | 239 | * Send text to the client |
WiredHome | 0:729320f63c5c | 240 | * |
WiredHome | 3:17928786bdb5 | 241 | * This sends the specified text to the client. If the number of bytes is not set, |
WiredHome | 3:17928786bdb5 | 242 | * then it calculates the number of bytes as a string. For binary transfers, the |
WiredHome | 3:17928786bdb5 | 243 | * number of bytes to send is required for proper operation. |
WiredHome | 3:17928786bdb5 | 244 | * |
WiredHome | 0:729320f63c5c | 245 | * @param msg is the text string to send |
WiredHome | 0:729320f63c5c | 246 | * @param bytes is the number of bytes to send. If not set, then strlen is calculated. |
WiredHome | 0:729320f63c5c | 247 | */ |
WiredHome | 0:729320f63c5c | 248 | void send(const char * msg, int bytes = -1); |
WiredHome | 0:729320f63c5c | 249 | |
WiredHome | 0:729320f63c5c | 250 | /** |
WiredHome | 3:17928786bdb5 | 251 | * Send a referenced file to the client, including the header |
WiredHome | 3:17928786bdb5 | 252 | * |
WiredHome | 3:17928786bdb5 | 253 | * This sends a file from the filesystem to the client. It must be of a supported type |
WiredHome | 3:17928786bdb5 | 254 | * in order to properly create the header. |
WiredHome | 0:729320f63c5c | 255 | * |
WiredHome | 0:729320f63c5c | 256 | * @param filename is the fully qualified path and filename |
WiredHome | 3:17928786bdb5 | 257 | * @param filetype is the header information (e.g. "Content-Type: application/pdf") |
WiredHome | 0:729320f63c5c | 258 | * @return true if it thinks it sent ok, false otherwise. |
WiredHome | 0:729320f63c5c | 259 | */ |
WiredHome | 0:729320f63c5c | 260 | bool SendFile(const char * filename, const char * filetype); |
WiredHome | 0:729320f63c5c | 261 | |
WiredHome | 0:729320f63c5c | 262 | /** |
WiredHome | 0:729320f63c5c | 263 | * register a handler for a specific URL. |
WiredHome | 0:729320f63c5c | 264 | * |
WiredHome | 3:17928786bdb5 | 265 | * This api lets you register a dynamic handler in the web server. This is |
WiredHome | 3:17928786bdb5 | 266 | * most useful for interactive web pages, rather than simply serving static |
WiredHome | 3:17928786bdb5 | 267 | * pages. |
WiredHome | 3:17928786bdb5 | 268 | * |
WiredHome | 3:17928786bdb5 | 269 | * @code |
WiredHome | 3:17928786bdb5 | 270 | * |
WiredHome | 3:17928786bdb5 | 271 | * ... |
WiredHome | 3:17928786bdb5 | 272 | * svr.RegisterHandler("/dyn1", SimpleDynamicPage);svr.RegisterHandler("/dyn1", SimpleDynamicPage); |
WiredHome | 3:17928786bdb5 | 273 | * ... |
WiredHome | 3:17928786bdb5 | 274 | * |
WiredHome | 3:17928786bdb5 | 275 | * bool SimpleDynamicPage(HTTPServer *svr, HTTPServer::CallBackType type, const char * path, const HTTPServer::namevalue *params, int paramcount) { |
WiredHome | 3:17928786bdb5 | 276 | * char buf[100]; |
WiredHome | 3:17928786bdb5 | 277 | * bool ret = false; |
WiredHome | 3:17928786bdb5 | 278 | * |
WiredHome | 3:17928786bdb5 | 279 | * switch (type) { |
WiredHome | 3:17928786bdb5 | 280 | * case HTTPServer::SEND_PAGE: |
WiredHome | 3:17928786bdb5 | 281 | * svr->header(200, "OK", "Content-Type: text/html\r\n"); |
WiredHome | 3:17928786bdb5 | 282 | * svr->send("<html><head><title>Dynamic Page</title></head>\r\n"); |
WiredHome | 3:17928786bdb5 | 283 | * svr->send("<body>\r\n"); |
WiredHome | 3:17928786bdb5 | 284 | * svr->send("This page was generated dynamically. Create your own name=value pairs on the URL " |
WiredHome | 3:17928786bdb5 | 285 | * "which uses the GET method.<br/>\r\n"); |
WiredHome | 3:17928786bdb5 | 286 | * sprintf(buf, "%d parameters passed to {%s}:<br/>\r\n", paramcount, path); |
WiredHome | 3:17928786bdb5 | 287 | * svr->send(buf); |
WiredHome | 3:17928786bdb5 | 288 | * for (int i=0; i<paramcount; i++) { |
WiredHome | 3:17928786bdb5 | 289 | * sprintf(buf, "%d: %s = %s<br/>\r\n", i, params[i].name, params[i].value); |
WiredHome | 3:17928786bdb5 | 290 | * svr->send(buf); |
WiredHome | 3:17928786bdb5 | 291 | * } |
WiredHome | 3:17928786bdb5 | 292 | * svr->send("Stats:<br/>\r\n"); |
WiredHome | 3:17928786bdb5 | 293 | * sprintf(buf,"Free memory space: %d<br/>\r\n", Free()); |
WiredHome | 3:17928786bdb5 | 294 | * svr->send(buf); |
WiredHome | 3:17928786bdb5 | 295 | * sprintf(buf,"Max Header size: %d<br/>\r\n", svr->GetMaxHeaderSize()); |
WiredHome | 3:17928786bdb5 | 296 | * svr->send(buf); |
WiredHome | 3:17928786bdb5 | 297 | * svr->send("<br/><a href='/'>back to main</a></body></html>\r\n"); |
WiredHome | 3:17928786bdb5 | 298 | * ret = true; |
WiredHome | 3:17928786bdb5 | 299 | * break; |
WiredHome | 3:17928786bdb5 | 300 | * case HTTPServer::CONTENT_LENGTH_REQUEST: |
WiredHome | 3:17928786bdb5 | 301 | * ret = true; |
WiredHome | 3:17928786bdb5 | 302 | * break; |
WiredHome | 3:17928786bdb5 | 303 | * case HTTPServer::DATA_TRANSFER: |
WiredHome | 3:17928786bdb5 | 304 | * ret = true; |
WiredHome | 3:17928786bdb5 | 305 | * break; |
WiredHome | 3:17928786bdb5 | 306 | * default: |
WiredHome | 3:17928786bdb5 | 307 | * ret = false; |
WiredHome | 3:17928786bdb5 | 308 | * break; |
WiredHome | 3:17928786bdb5 | 309 | * } |
WiredHome | 3:17928786bdb5 | 310 | * return ret; |
WiredHome | 3:17928786bdb5 | 311 | * } |
WiredHome | 3:17928786bdb5 | 312 | * @endcode |
WiredHome | 3:17928786bdb5 | 313 | * |
WiredHome | 0:729320f63c5c | 314 | * @param path to register |
WiredHome | 0:729320f63c5c | 315 | * @param callback of type Handler |
WiredHome | 0:729320f63c5c | 316 | * @return true if successfully registered |
WiredHome | 0:729320f63c5c | 317 | */ |
WiredHome | 0:729320f63c5c | 318 | bool RegisterHandler(const char * path, Handler callback); |
WiredHome | 0:729320f63c5c | 319 | |
WiredHome | 0:729320f63c5c | 320 | /** |
WiredHome | 0:729320f63c5c | 321 | * determine if the named file is a supported type (e.g. .htm, .jpg, ...) |
WiredHome | 0:729320f63c5c | 322 | * |
WiredHome | 3:17928786bdb5 | 323 | * if you pass in a filename, it will attempt to extract the extension |
WiredHome | 3:17928786bdb5 | 324 | * and compare that to the list of supported file types. If it finds a |
WiredHome | 3:17928786bdb5 | 325 | * match, then it will return a pointer to the content-type string. |
WiredHome | 3:17928786bdb5 | 326 | * |
WiredHome | 3:17928786bdb5 | 327 | * @code |
WiredHome | 3:17928786bdb5 | 328 | * fType = GetSupportedType("mypix.jpg"); |
WiredHome | 3:17928786bdb5 | 329 | * if (fType) { |
WiredHome | 3:17928786bdb5 | 330 | * ... |
WiredHome | 3:17928786bdb5 | 331 | * @endcode |
WiredHome | 3:17928786bdb5 | 332 | * |
WiredHome | 0:729320f63c5c | 333 | * @param filename is the filename to test, based on the extension |
WiredHome | 0:729320f63c5c | 334 | * @return pointer to a Content-Type string if supported, or NULL if not. |
WiredHome | 0:729320f63c5c | 335 | */ |
WiredHome | 0:729320f63c5c | 336 | const char * GetSupportedType(const char * filename); |
WiredHome | 0:729320f63c5c | 337 | |
WiredHome | 0:729320f63c5c | 338 | /** |
WiredHome | 0:729320f63c5c | 339 | * search the available parameters for 'name' and if found, return the 'value' |
WiredHome | 0:729320f63c5c | 340 | * |
WiredHome | 3:17928786bdb5 | 341 | * After the querystring is parsed, the server maintains an array of |
WiredHome | 3:17928786bdb5 | 342 | * name=value pairs. This Get function will search for the passed in name |
WiredHome | 3:17928786bdb5 | 343 | * and provide access to the value. |
WiredHome | 3:17928786bdb5 | 344 | * |
WiredHome | 3:17928786bdb5 | 345 | * @code |
WiredHome | 3:17928786bdb5 | 346 | * BusOut leds(LED1,LED2,LED3,LED4); |
WiredHome | 3:17928786bdb5 | 347 | * ... |
WiredHome | 3:17928786bdb5 | 348 | * leds = atoi(svr->GetParameter("leds")); |
WiredHome | 3:17928786bdb5 | 349 | * @endcode |
WiredHome | 3:17928786bdb5 | 350 | * |
WiredHome | 0:729320f63c5c | 351 | * @param name is the name to search for |
WiredHome | 0:729320f63c5c | 352 | * @return pointer to the value, or NULL |
WiredHome | 0:729320f63c5c | 353 | */ |
WiredHome | 0:729320f63c5c | 354 | const char * GetParameter(const char * name); |
WiredHome | 0:729320f63c5c | 355 | |
WiredHome | 0:729320f63c5c | 356 | /** |
WiredHome | 3:17928786bdb5 | 357 | * Parse the text string into name=value parameters. |
WiredHome | 3:17928786bdb5 | 358 | * |
WiredHome | 3:17928786bdb5 | 359 | * This will directly modify the referenced string. If there is a |
WiredHome | 3:17928786bdb5 | 360 | * #fragment_id on the end of the string, it will be removed. |
WiredHome | 0:729320f63c5c | 361 | * |
WiredHome | 0:729320f63c5c | 362 | * @param pString is a pointer to the string. |
WiredHome | 0:729320f63c5c | 363 | */ |
WiredHome | 0:729320f63c5c | 364 | void ParseParameters(char * pString); |
WiredHome | 0:729320f63c5c | 365 | |
WiredHome | 0:729320f63c5c | 366 | /** |
WiredHome | 0:729320f63c5c | 367 | * Unescape string converts a coded string "in place" into a normal string |
WiredHome | 3:17928786bdb5 | 368 | * |
WiredHome | 3:17928786bdb5 | 369 | * A query string will have a number of characters replaced for communication |
WiredHome | 3:17928786bdb5 | 370 | * which includes spaces, quotes, question marks and more. Most of them |
WiredHome | 3:17928786bdb5 | 371 | * will be replaced with a %xx format, where xx is the hex code for the |
WiredHome | 3:17928786bdb5 | 372 | * character. Since the string will only get shorter when this happens |
WiredHome | 3:17928786bdb5 | 373 | * the operation is performed in place. |
WiredHome | 3:17928786bdb5 | 374 | * |
WiredHome | 0:729320f63c5c | 375 | * this "This%20is%20a%20question%3F%20and%20an%20answer." |
WiredHome | 3:17928786bdb5 | 376 | * |
WiredHome | 0:729320f63c5c | 377 | * becomes "This is a question? and an answer." |
WiredHome | 3:17928786bdb5 | 378 | * |
WiredHome | 0:729320f63c5c | 379 | * @note '+' is another form of space, so is converted to a space before the %xx |
WiredHome | 0:729320f63c5c | 380 | * |
WiredHome | 0:729320f63c5c | 381 | * @param encoded string to be converted |
WiredHome | 0:729320f63c5c | 382 | */ |
WiredHome | 0:729320f63c5c | 383 | void UnescapeString(char * encoded); |
WiredHome | 0:729320f63c5c | 384 | |
WiredHome | 0:729320f63c5c | 385 | /** |
WiredHome | 0:729320f63c5c | 386 | * Get the IP address of the remote node to which we are connected. |
WiredHome | 3:17928786bdb5 | 387 | * |
WiredHome | 3:17928786bdb5 | 388 | * This will get the IP address of the remote node to which we are |
WiredHome | 3:17928786bdb5 | 389 | * currently connected. This is written into the buffer in |
WiredHome | 3:17928786bdb5 | 390 | * "192.168.100.234" format. If the buffer size is note >= 16 bytes, |
WiredHome | 3:17928786bdb5 | 391 | * it will set the buffer to null. |
WiredHome | 3:17928786bdb5 | 392 | * |
WiredHome | 3:17928786bdb5 | 393 | * @note This switches the module into, and out of, command mode |
WiredHome | 3:17928786bdb5 | 394 | * which has quite a time penalty. |
WiredHome | 3:17928786bdb5 | 395 | * |
WiredHome | 3:17928786bdb5 | 396 | * @param str is the string to write the address into, which should be at |
WiredHome | 3:17928786bdb5 | 397 | * least as large as "192.168.100.203" (16-bytes). |
WiredHome | 4:f34642902056 | 398 | * @param strSize of the str buffer must be >=16, so it will not buffer overrun. |
WiredHome | 0:729320f63c5c | 399 | */ |
WiredHome | 4:f34642902056 | 400 | void GetRemoteAddr(char * str, int strSize); |
WiredHome | 0:729320f63c5c | 401 | |
WiredHome | 0:729320f63c5c | 402 | /** |
WiredHome | 3:17928786bdb5 | 403 | * This is used to force a connection to close |
WiredHome | 3:17928786bdb5 | 404 | * |
WiredHome | 3:17928786bdb5 | 405 | * This switches the module into command mode, performs the close, |
WiredHome | 3:17928786bdb5 | 406 | * then switches it back to data mode. So, this is a time-expensive |
WiredHome | 3:17928786bdb5 | 407 | * command. |
WiredHome | 0:729320f63c5c | 408 | */ |
WiredHome | 0:729320f63c5c | 409 | void close_connection(); |
WiredHome | 3:17928786bdb5 | 410 | |
WiredHome | 3:17928786bdb5 | 411 | /** |
WiredHome | 3:17928786bdb5 | 412 | * Get the size of the largest header. |
WiredHome | 3:17928786bdb5 | 413 | * |
WiredHome | 3:17928786bdb5 | 414 | * This is a diagnostic function, so you can resize the allocated |
WiredHome | 3:17928786bdb5 | 415 | * buffer for your application. With proper sizing, more of the |
WiredHome | 3:17928786bdb5 | 416 | * system memory is available for your application. |
WiredHome | 3:17928786bdb5 | 417 | * |
WiredHome | 3:17928786bdb5 | 418 | * @code |
WiredHome | 3:17928786bdb5 | 419 | * sprintf(buf,"Max Header size: %d<br/>\r\n", svr->GetMaxHeaderSize()); |
WiredHome | 3:17928786bdb5 | 420 | * svr->send(buf); |
WiredHome | 3:17928786bdb5 | 421 | * @endcode |
WiredHome | 3:17928786bdb5 | 422 | * |
WiredHome | 3:17928786bdb5 | 423 | * @returns size in bytes of the larger header measured. |
WiredHome | 3:17928786bdb5 | 424 | */ |
WiredHome | 3:17928786bdb5 | 425 | int GetMaxHeaderSize(); |
WiredHome | 3:17928786bdb5 | 426 | |
WiredHome | 3:17928786bdb5 | 427 | |
WiredHome | 3:17928786bdb5 | 428 | /** |
WiredHome | 3:17928786bdb5 | 429 | * Performance parameter |
WiredHome | 3:17928786bdb5 | 430 | */ |
WiredHome | 3:17928786bdb5 | 431 | typedef struct SW_PERFPARAM { |
WiredHome | 3:17928786bdb5 | 432 | unsigned long long TotalTime_us; |
WiredHome | 3:17928786bdb5 | 433 | unsigned long Samples; |
WiredHome | 3:17928786bdb5 | 434 | unsigned long MaxTime_us; |
WiredHome | 3:17928786bdb5 | 435 | } SW_PerformanceParam; |
WiredHome | 3:17928786bdb5 | 436 | |
WiredHome | 3:17928786bdb5 | 437 | /** |
WiredHome | 3:17928786bdb5 | 438 | * Performance metrics |
WiredHome | 3:17928786bdb5 | 439 | */ |
WiredHome | 3:17928786bdb5 | 440 | typedef struct SW_PERFDATA { |
WiredHome | 3:17928786bdb5 | 441 | SW_PerformanceParam Header; |
WiredHome | 3:17928786bdb5 | 442 | SW_PerformanceParam SendData; |
WiredHome | 3:17928786bdb5 | 443 | //SW_PerformanceParam SendFile; |
WiredHome | 3:17928786bdb5 | 444 | } SW_PerformanceData; |
WiredHome | 3:17928786bdb5 | 445 | |
WiredHome | 3:17928786bdb5 | 446 | /** |
WiredHome | 3:17928786bdb5 | 447 | * Get performance metrics from the web server. |
WiredHome | 3:17928786bdb5 | 448 | * |
WiredHome | 3:17928786bdb5 | 449 | * This is a diagnostic function, and gathers data on the internal |
WiredHome | 3:17928786bdb5 | 450 | * performance of the server, as it works various actions. |
WiredHome | 3:17928786bdb5 | 451 | * |
WiredHome | 3:17928786bdb5 | 452 | * @param p is a pointer to a SW_PerformanceData structure to be populated |
WiredHome | 3:17928786bdb5 | 453 | */ |
WiredHome | 3:17928786bdb5 | 454 | void GetPerformanceData(SW_PerformanceData * p); |
WiredHome | 3:17928786bdb5 | 455 | |
WiredHome | 3:17928786bdb5 | 456 | /** |
WiredHome | 3:17928786bdb5 | 457 | * Reset performance metrics. |
WiredHome | 3:17928786bdb5 | 458 | */ |
WiredHome | 3:17928786bdb5 | 459 | void ResetPerformanceData(); |
WiredHome | 0:729320f63c5c | 460 | |
WiredHome | 0:729320f63c5c | 461 | private: |
WiredHome | 0:729320f63c5c | 462 | Wifly * wifly; |
WiredHome | 0:729320f63c5c | 463 | char * webroot; |
WiredHome | 0:729320f63c5c | 464 | PC * pc; |
WiredHome | 0:729320f63c5c | 465 | TCPSocketServer * server; |
WiredHome | 0:729320f63c5c | 466 | TCPSocketConnection client; |
WiredHome | 0:729320f63c5c | 467 | char * rewriteWithDefaultFile(char * queryString); |
WiredHome | 0:729320f63c5c | 468 | char * rewritePrependWebroot(char * queryString); |
WiredHome | 0:729320f63c5c | 469 | int maxparams; |
WiredHome | 0:729320f63c5c | 470 | namevalue *params; |
WiredHome | 0:729320f63c5c | 471 | int paramcount; |
WiredHome | 3:17928786bdb5 | 472 | int maxheaderbytes; |
WiredHome | 3:17928786bdb5 | 473 | char * headerbuffer; |
WiredHome | 3:17928786bdb5 | 474 | int headerbuffersize; |
WiredHome | 0:729320f63c5c | 475 | |
WiredHome | 3:17928786bdb5 | 476 | Timer timer; // for performance metrics gathering |
WiredHome | 3:17928786bdb5 | 477 | /** |
WiredHome | 3:17928786bdb5 | 478 | * Records performance data |
WiredHome | 3:17928786bdb5 | 479 | * |
WiredHome | 3:17928786bdb5 | 480 | * This will take a pointer to a SW_PerformanceParam, and it will |
WiredHome | 3:17928786bdb5 | 481 | * take the time when the performance measurement started. It locally |
WiredHome | 3:17928786bdb5 | 482 | * accesses the current time to measure the elapsed. |
WiredHome | 3:17928786bdb5 | 483 | * |
WiredHome | 3:17928786bdb5 | 484 | * @param param is the performance parameter to update |
WiredHome | 3:17928786bdb5 | 485 | * @param value is the reference time. |
WiredHome | 3:17928786bdb5 | 486 | * @returns the current time which may be used as the reference time |
WiredHome | 3:17928786bdb5 | 487 | * for further measurements. |
WiredHome | 3:17928786bdb5 | 488 | */ |
WiredHome | 3:17928786bdb5 | 489 | int RecordPerformanceData(SW_PerformanceParam * param, int value); |
WiredHome | 3:17928786bdb5 | 490 | SW_PerformanceData perfData; |
WiredHome | 3:17928786bdb5 | 491 | |
WiredHome | 3:17928786bdb5 | 492 | typedef struct HANDLER { |
WiredHome | 0:729320f63c5c | 493 | char * path; |
WiredHome | 0:729320f63c5c | 494 | Handler callback; |
WiredHome | 0:729320f63c5c | 495 | } handler; |
WiredHome | 0:729320f63c5c | 496 | int maxdynamicpages; |
WiredHome | 0:729320f63c5c | 497 | handler *handlers; |
WiredHome | 0:729320f63c5c | 498 | int handlercount; |
WiredHome | 3:17928786bdb5 | 499 | |
WiredHome | 3:17928786bdb5 | 500 | char * queryType; |
WiredHome | 3:17928786bdb5 | 501 | char * queryString; |
WiredHome | 3:17928786bdb5 | 502 | char * hostString; |
WiredHome | 3:17928786bdb5 | 503 | char * contentLength; |
WiredHome | 3:17928786bdb5 | 504 | char * contentType; |
WiredHome | 3:17928786bdb5 | 505 | char * postQueryString; |
WiredHome | 0:729320f63c5c | 506 | |
WiredHome | 0:729320f63c5c | 507 | /** |
WiredHome | 0:729320f63c5c | 508 | * Extract the message from the record, by searching for the needle |
WiredHome | 0:729320f63c5c | 509 | * the string of interest follows the needle, and may be ' ' delimited |
WiredHome | 0:729320f63c5c | 510 | * Can damage haystack while processing it. |
WiredHome | 0:729320f63c5c | 511 | * |
WiredHome | 0:729320f63c5c | 512 | * @param haystack is the record to search |
WiredHome | 0:729320f63c5c | 513 | * @param needle is the text to search for, which precedes the text to return |
WiredHome | 0:729320f63c5c | 514 | * @param string is the text following the needle |
WiredHome | 0:729320f63c5c | 515 | * @return true if it extracted something successfully |
WiredHome | 0:729320f63c5c | 516 | */ |
WiredHome | 0:729320f63c5c | 517 | bool Extract(char * rec, char * needle, char ** string); |
WiredHome | 0:729320f63c5c | 518 | |
WiredHome | 3:17928786bdb5 | 519 | void SendResponse(); |
WiredHome | 3:17928786bdb5 | 520 | bool ParseHeader(char * bPtr); |
WiredHome | 3:17928786bdb5 | 521 | bool CheckDynamicHandlers(); |
WiredHome | 3:17928786bdb5 | 522 | |
WiredHome | 0:729320f63c5c | 523 | int HexCharToInt(char c); |
WiredHome | 0:729320f63c5c | 524 | char HexPairToChar(char * p); |
WiredHome | 0:729320f63c5c | 525 | }; |
WiredHome | 0:729320f63c5c | 526 | #endif //SW_HTTPSERVER_H |
WiredHome | 4:f34642902056 | 527 |