A simple web server that can be bound to either the EthernetInterface or the WiflyInterface.

Dependents:   Smart-WiFly-WebServer WattEye X10Svr SSDP_Server

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?

UserRevisionLine numberNew 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