Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Fork of SW_HTTPServer by
SW_HTTPServer.h@0:729320f63c5c, 2013-05-31 (annotated)
- Committer:
- WiredHome
- Date:
- Fri May 31 03:13:39 2013 +0000
- Revision:
- 0:729320f63c5c
- Child:
- 1:54353af0d20a
First viable version of the Smartware HTTP Server. It handles static and dynamic pages, GET and POST methods.
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
WiredHome | 0:729320f63c5c | 1 | /// SW_HTTPServer is a simple web server using the WiFly module. |
WiredHome | 0:729320f63c5c | 2 | /// |
WiredHome | 0:729320f63c5c | 3 | /// Partially derived from nweb |
WiredHome | 0:729320f63c5c | 4 | /// http://www.ibm.com/developerworks/systems/library/es-nweb/sidefile1.html |
WiredHome | 0:729320f63c5c | 5 | /// |
WiredHome | 0:729320f63c5c | 6 | /// Uses a modified WiflyInterface - a number of performance issues |
WiredHome | 0:729320f63c5c | 7 | /// were identified and resolved in the local version. |
WiredHome | 0:729320f63c5c | 8 | /// |
WiredHome | 0:729320f63c5c | 9 | /// Also, if nothing visits its web page for a long time, it seems |
WiredHome | 0:729320f63c5c | 10 | /// to disable. Might be a sleep timer I'm not spotting. |
WiredHome | 0:729320f63c5c | 11 | /// |
WiredHome | 0:729320f63c5c | 12 | /// Given: scheme://domain:port/path?query_string#fragment_id |
WiredHome | 0:729320f63c5c | 13 | /// @li scheme is "http" |
WiredHome | 0:729320f63c5c | 14 | /// @li domain is whatever IP the server has |
WiredHome | 0:729320f63c5c | 15 | /// @li port is the registered port |
WiredHome | 0:729320f63c5c | 16 | /// @li /path is the reference to the file (actual or logical) on the server |
WiredHome | 0:729320f63c5c | 17 | /// @li query_string is any combination of name=value pairs |
WiredHome | 0:729320f63c5c | 18 | /// @li fragment_id is a reference to an anchor on the page |
WiredHome | 0:729320f63c5c | 19 | /// |
WiredHome | 0:729320f63c5c | 20 | /// @todo make it non-blocking. |
WiredHome | 0:729320f63c5c | 21 | /// @todo hunt down lengthy operations - there seems to be a long timeout somewhere. |
WiredHome | 0:729320f63c5c | 22 | /// @todo move part of the POST method handler to the registered handler, so |
WiredHome | 0:729320f63c5c | 23 | /// it can decide if it should allocate the needed memory. |
WiredHome | 0:729320f63c5c | 24 | /// @todo transform the pc serial interface to a log interface, which might |
WiredHome | 0:729320f63c5c | 25 | /// be more useful. |
WiredHome | 0:729320f63c5c | 26 | /// @todo parse the header similar to the query string, and then make |
WiredHome | 0:729320f63c5c | 27 | /// those parameters accessible - perhaps like environment vars. |
WiredHome | 0:729320f63c5c | 28 | /// |
WiredHome | 0:729320f63c5c | 29 | /// @note Copyright © 2013 by Smartware Computing, all rights reserved. |
WiredHome | 0:729320f63c5c | 30 | /// Individuals may use this application for evaluation or non-commercial |
WiredHome | 0:729320f63c5c | 31 | /// purposes. Within this restriction, changes may be made to this application |
WiredHome | 0:729320f63c5c | 32 | /// as long as this copyright notice is retained. The user shall make |
WiredHome | 0:729320f63c5c | 33 | /// clear that their work is a derived work, and not the original. |
WiredHome | 0:729320f63c5c | 34 | /// Users of this application and sources accept this application "as is" and |
WiredHome | 0:729320f63c5c | 35 | /// shall hold harmless Smartware Computing, for any undesired results while |
WiredHome | 0:729320f63c5c | 36 | /// using this application - whether real or imagined. |
WiredHome | 0:729320f63c5c | 37 | /// |
WiredHome | 0:729320f63c5c | 38 | /// @author David Smart, Smartware Computing |
WiredHome | 0:729320f63c5c | 39 | /// |
WiredHome | 0:729320f63c5c | 40 | #ifndef SW_HTTPSERVER_H |
WiredHome | 0:729320f63c5c | 41 | #define SW_HTTPSERVER_H |
WiredHome | 0:729320f63c5c | 42 | #include "mbed.h" |
WiredHome | 0:729320f63c5c | 43 | //#include "MODSERIAL.h" // would like to hook in mod serial for higher performance, less blocking |
WiredHome | 0:729320f63c5c | 44 | #include "Wifly.h" |
WiredHome | 0:729320f63c5c | 45 | #include "TCPSocketServer.h" |
WiredHome | 0:729320f63c5c | 46 | #include "TCPSocketConnection.h" |
WiredHome | 0:729320f63c5c | 47 | |
WiredHome | 0:729320f63c5c | 48 | #ifdef MODSERIAL_H |
WiredHome | 0:729320f63c5c | 49 | #define PC MODSERIAL |
WiredHome | 0:729320f63c5c | 50 | #else |
WiredHome | 0:729320f63c5c | 51 | #define PC Serial |
WiredHome | 0:729320f63c5c | 52 | #endif |
WiredHome | 0:729320f63c5c | 53 | |
WiredHome | 0:729320f63c5c | 54 | |
WiredHome | 0:729320f63c5c | 55 | class HTTPServer |
WiredHome | 0:729320f63c5c | 56 | { |
WiredHome | 0:729320f63c5c | 57 | public: |
WiredHome | 0:729320f63c5c | 58 | /** |
WiredHome | 0:729320f63c5c | 59 | * namevalue pairs for parameters |
WiredHome | 0:729320f63c5c | 60 | */ |
WiredHome | 0:729320f63c5c | 61 | typedef struct { |
WiredHome | 0:729320f63c5c | 62 | char * name; |
WiredHome | 0:729320f63c5c | 63 | char * value; |
WiredHome | 0:729320f63c5c | 64 | } namevalue; |
WiredHome | 0:729320f63c5c | 65 | |
WiredHome | 0:729320f63c5c | 66 | /** |
WiredHome | 0:729320f63c5c | 67 | * callback prototype for custom handler |
WiredHome | 0:729320f63c5c | 68 | * |
WiredHome | 0:729320f63c5c | 69 | * @param svr is a handle to this class, so the callback has access to member functions |
WiredHome | 0:729320f63c5c | 70 | * @param params is a pointer to an array of name value pairs |
WiredHome | 0:729320f63c5c | 71 | * @paramcount is the number of parameters. |
WiredHome | 0:729320f63c5c | 72 | */ |
WiredHome | 0:729320f63c5c | 73 | typedef void (* Handler)(HTTPServer * svr, const char * path, const namevalue *params, int paramcount); |
WiredHome | 0:729320f63c5c | 74 | |
WiredHome | 0:729320f63c5c | 75 | /** |
WiredHome | 0:729320f63c5c | 76 | * Create the HTTPServer object. |
WiredHome | 0:729320f63c5c | 77 | * |
WiredHome | 0:729320f63c5c | 78 | * @param wifly is the serial port with the wifly interface. |
WiredHome | 0:729320f63c5c | 79 | * @param port is the optional parameter for the port number to use, default is 80. |
WiredHome | 0:729320f63c5c | 80 | * @param webroot is a file system path to the root folder for the web space. |
WiredHome | 0:729320f63c5c | 81 | * @param maxparams defines the maximum number of parameters to a dynamic function (and the memory to support them). |
WiredHome | 0:729320f63c5c | 82 | * @param maxdynamicpages defines the maximum number of dynamic pages that can be registered. |
WiredHome | 0:729320f63c5c | 83 | * @param pc is the serial port for debug information (I should transform this to a log interface) |
WiredHome | 0:729320f63c5c | 84 | */ |
WiredHome | 0:729320f63c5c | 85 | HTTPServer(Wifly * wifly, int port = 80, const char * webroot = "/", int maxparams = 30, int maxdynamicpages = 10, PC * pc = NULL); |
WiredHome | 0:729320f63c5c | 86 | |
WiredHome | 0:729320f63c5c | 87 | /** |
WiredHome | 0:729320f63c5c | 88 | * destructor, which can clean up a few things |
WiredHome | 0:729320f63c5c | 89 | */ |
WiredHome | 0:729320f63c5c | 90 | ~HTTPServer(); |
WiredHome | 0:729320f63c5c | 91 | |
WiredHome | 0:729320f63c5c | 92 | /** |
WiredHome | 0:729320f63c5c | 93 | * the process to call whenever there is free time, as this basically does |
WiredHome | 0:729320f63c5c | 94 | * all the work to monitor for connections and handle replies. |
WiredHome | 0:729320f63c5c | 95 | */ |
WiredHome | 0:729320f63c5c | 96 | void ip_process(); |
WiredHome | 0:729320f63c5c | 97 | |
WiredHome | 0:729320f63c5c | 98 | /** |
WiredHome | 0:729320f63c5c | 99 | * Send a header back to the client and automatically appends a "\r\n". Each parameter must |
WiredHome | 0:729320f63c5c | 100 | * send a "\r\n" as part of that string. |
WiredHome | 0:729320f63c5c | 101 | * |
WiredHome | 0:729320f63c5c | 102 | * @param code is the optional return code; 200 = OK, if not provided then 404 = Not found is returned |
WiredHome | 0:729320f63c5c | 103 | * @param code_text is the text to align with the code (e.g. 404, "Not Found") |
WiredHome | 0:729320f63c5c | 104 | * @param content_type is a pointer to "Content-Type: text/html\r\n" (for example) |
WiredHome | 0:729320f63c5c | 105 | * @param optional_text is a pointer to any other text that is part of the header |
WiredHome | 0:729320f63c5c | 106 | */ |
WiredHome | 0:729320f63c5c | 107 | void header(int code = 404, const char * code_text = "Not Found", const char * content_type = NULL, const char * optional_text = NULL); |
WiredHome | 0:729320f63c5c | 108 | |
WiredHome | 0:729320f63c5c | 109 | /** |
WiredHome | 0:729320f63c5c | 110 | * Send text to the client |
WiredHome | 0:729320f63c5c | 111 | * |
WiredHome | 0:729320f63c5c | 112 | * @param msg is the text string to send |
WiredHome | 0:729320f63c5c | 113 | * @param bytes is the number of bytes to send. If not set, then strlen is calculated. |
WiredHome | 0:729320f63c5c | 114 | */ |
WiredHome | 0:729320f63c5c | 115 | void send(const char * msg, int bytes = -1); |
WiredHome | 0:729320f63c5c | 116 | |
WiredHome | 0:729320f63c5c | 117 | /** |
WiredHome | 0:729320f63c5c | 118 | * Send a file to the client, including the header |
WiredHome | 0:729320f63c5c | 119 | * |
WiredHome | 0:729320f63c5c | 120 | * @param filename is the fully qualified path and filename |
WiredHome | 0:729320f63c5c | 121 | * @param filetype is the header information (e.g. "Content-Type: text/html") |
WiredHome | 0:729320f63c5c | 122 | * @return true if it thinks it sent ok, false otherwise. |
WiredHome | 0:729320f63c5c | 123 | */ |
WiredHome | 0:729320f63c5c | 124 | bool SendFile(const char * filename, const char * filetype); |
WiredHome | 0:729320f63c5c | 125 | |
WiredHome | 0:729320f63c5c | 126 | /** |
WiredHome | 0:729320f63c5c | 127 | * register a handler for a specific URL. |
WiredHome | 0:729320f63c5c | 128 | * |
WiredHome | 0:729320f63c5c | 129 | * @param path to register |
WiredHome | 0:729320f63c5c | 130 | * @param callback of type Handler |
WiredHome | 0:729320f63c5c | 131 | * @return true if successfully registered |
WiredHome | 0:729320f63c5c | 132 | */ |
WiredHome | 0:729320f63c5c | 133 | bool RegisterHandler(const char * path, Handler callback); |
WiredHome | 0:729320f63c5c | 134 | |
WiredHome | 0:729320f63c5c | 135 | /** |
WiredHome | 0:729320f63c5c | 136 | * determine if the named file is a supported type (e.g. .htm, .jpg, ...) |
WiredHome | 0:729320f63c5c | 137 | * |
WiredHome | 0:729320f63c5c | 138 | * @param filename is the filename to test, based on the extension |
WiredHome | 0:729320f63c5c | 139 | * @return pointer to a Content-Type string if supported, or NULL if not. |
WiredHome | 0:729320f63c5c | 140 | */ |
WiredHome | 0:729320f63c5c | 141 | const char * GetSupportedType(const char * filename); |
WiredHome | 0:729320f63c5c | 142 | |
WiredHome | 0:729320f63c5c | 143 | /** |
WiredHome | 0:729320f63c5c | 144 | * search the available parameters for 'name' and if found, return the 'value' |
WiredHome | 0:729320f63c5c | 145 | * |
WiredHome | 0:729320f63c5c | 146 | * @param name is the name to search for |
WiredHome | 0:729320f63c5c | 147 | * @return pointer to the value, or NULL |
WiredHome | 0:729320f63c5c | 148 | */ |
WiredHome | 0:729320f63c5c | 149 | const char * GetParameter(const char * name); |
WiredHome | 0:729320f63c5c | 150 | |
WiredHome | 0:729320f63c5c | 151 | /** |
WiredHome | 0:729320f63c5c | 152 | * parse the text string into name=value parameters. This will directly |
WiredHome | 0:729320f63c5c | 153 | * modify the referenced string. If there is a #fragment_id on the end |
WiredHome | 0:729320f63c5c | 154 | * of the string, that will be removed. |
WiredHome | 0:729320f63c5c | 155 | * |
WiredHome | 0:729320f63c5c | 156 | * @param pString is a pointer to the string. |
WiredHome | 0:729320f63c5c | 157 | */ |
WiredHome | 0:729320f63c5c | 158 | void ParseParameters(char * pString); |
WiredHome | 0:729320f63c5c | 159 | |
WiredHome | 0:729320f63c5c | 160 | /** |
WiredHome | 0:729320f63c5c | 161 | * Unescape string converts a coded string "in place" into a normal string |
WiredHome | 0:729320f63c5c | 162 | * this "This%20is%20a%20question%3F%20and%20an%20answer." |
WiredHome | 0:729320f63c5c | 163 | * becomes "This is a question? and an answer." |
WiredHome | 0:729320f63c5c | 164 | * @note '+' is another form of space, so is converted to a space before the %xx |
WiredHome | 0:729320f63c5c | 165 | * |
WiredHome | 0:729320f63c5c | 166 | * @param encoded string to be converted |
WiredHome | 0:729320f63c5c | 167 | */ |
WiredHome | 0:729320f63c5c | 168 | void UnescapeString(char * encoded); |
WiredHome | 0:729320f63c5c | 169 | |
WiredHome | 0:729320f63c5c | 170 | /** |
WiredHome | 0:729320f63c5c | 171 | * Get the IP address of the remote node to which we are connected. |
WiredHome | 0:729320f63c5c | 172 | * @caution this switches the module into, and out of, command mode |
WiredHome | 0:729320f63c5c | 173 | * which has quite a time penalty. |
WiredHome | 0:729320f63c5c | 174 | */ |
WiredHome | 0:729320f63c5c | 175 | void GetRemoteAddr(char * str, int size); |
WiredHome | 0:729320f63c5c | 176 | |
WiredHome | 0:729320f63c5c | 177 | /** |
WiredHome | 0:729320f63c5c | 178 | * used to force a connection to close |
WiredHome | 0:729320f63c5c | 179 | */ |
WiredHome | 0:729320f63c5c | 180 | void close_connection(); |
WiredHome | 0:729320f63c5c | 181 | |
WiredHome | 0:729320f63c5c | 182 | private: |
WiredHome | 0:729320f63c5c | 183 | Wifly * wifly; |
WiredHome | 0:729320f63c5c | 184 | char * webroot; |
WiredHome | 0:729320f63c5c | 185 | PC * pc; |
WiredHome | 0:729320f63c5c | 186 | Timer * timer; |
WiredHome | 0:729320f63c5c | 187 | TCPSocketServer * server; |
WiredHome | 0:729320f63c5c | 188 | TCPSocketConnection client; |
WiredHome | 0:729320f63c5c | 189 | char * rewriteWithDefaultFile(char * queryString); |
WiredHome | 0:729320f63c5c | 190 | char * rewritePrependWebroot(char * queryString); |
WiredHome | 0:729320f63c5c | 191 | int maxparams; |
WiredHome | 0:729320f63c5c | 192 | namevalue *params; |
WiredHome | 0:729320f63c5c | 193 | int paramcount; |
WiredHome | 0:729320f63c5c | 194 | |
WiredHome | 0:729320f63c5c | 195 | typedef struct { |
WiredHome | 0:729320f63c5c | 196 | char * path; |
WiredHome | 0:729320f63c5c | 197 | Handler callback; |
WiredHome | 0:729320f63c5c | 198 | } handler; |
WiredHome | 0:729320f63c5c | 199 | int maxdynamicpages; |
WiredHome | 0:729320f63c5c | 200 | handler *handlers; |
WiredHome | 0:729320f63c5c | 201 | int handlercount; |
WiredHome | 0:729320f63c5c | 202 | |
WiredHome | 0:729320f63c5c | 203 | /** |
WiredHome | 0:729320f63c5c | 204 | * Extract the message from the record, by searching for the needle |
WiredHome | 0:729320f63c5c | 205 | * the string of interest follows the needle, and may be ' ' delimited |
WiredHome | 0:729320f63c5c | 206 | * Can damage haystack while processing it. |
WiredHome | 0:729320f63c5c | 207 | * |
WiredHome | 0:729320f63c5c | 208 | * @param haystack is the record to search |
WiredHome | 0:729320f63c5c | 209 | * @param needle is the text to search for, which precedes the text to return |
WiredHome | 0:729320f63c5c | 210 | * @param string is the text following the needle |
WiredHome | 0:729320f63c5c | 211 | * @return true if it extracted something successfully |
WiredHome | 0:729320f63c5c | 212 | */ |
WiredHome | 0:729320f63c5c | 213 | bool Extract(char * rec, char * needle, char ** string); |
WiredHome | 0:729320f63c5c | 214 | |
WiredHome | 0:729320f63c5c | 215 | int HexCharToInt(char c); |
WiredHome | 0:729320f63c5c | 216 | char HexPairToChar(char * p); |
WiredHome | 0:729320f63c5c | 217 | }; |
WiredHome | 0:729320f63c5c | 218 | #endif //SW_HTTPSERVER_H |