A simple web server that can be bound to either the EthernetInterface or the WiflyInterface.
Dependents: Smart-WiFly-WebServer WattEye X10Svr SSDP_Server
Diff: SW_HTTPServer.h
- Revision:
- 0:729320f63c5c
- Child:
- 1:54353af0d20a
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/SW_HTTPServer.h Fri May 31 03:13:39 2013 +0000 @@ -0,0 +1,218 @@ +/// SW_HTTPServer is a simple web server using the WiFly module. +/// +/// Partially derived from nweb +/// http://www.ibm.com/developerworks/systems/library/es-nweb/sidefile1.html +/// +/// Uses a modified WiflyInterface - a number of performance issues +/// were identified and resolved in the local version. +/// +/// Also, if nothing visits its web page for a long time, it seems +/// to disable. Might be a sleep timer I'm not spotting. +/// +/// Given: scheme://domain:port/path?query_string#fragment_id +/// @li scheme is "http" +/// @li domain is whatever IP the server has +/// @li port is the registered port +/// @li /path is the reference to the file (actual or logical) on the server +/// @li query_string is any combination of name=value pairs +/// @li fragment_id is a reference to an anchor on the page +/// +/// @todo make it non-blocking. +/// @todo hunt down lengthy operations - there seems to be a long timeout somewhere. +/// @todo move part of the POST method handler to the registered handler, so +/// it can decide if it should allocate the needed memory. +/// @todo transform the pc serial interface to a log interface, which might +/// be more useful. +/// @todo parse the header similar to the query string, and then make +/// those parameters accessible - perhaps like environment vars. +/// +/// @note Copyright © 2013 by Smartware Computing, all rights reserved. +/// Individuals may use this application for evaluation or non-commercial +/// purposes. Within this restriction, changes may be made to this application +/// as long as this copyright notice is retained. The user shall make +/// clear that their work is a derived work, and not the original. +/// Users of this application and sources accept this application "as is" and +/// shall hold harmless Smartware Computing, for any undesired results while +/// using this application - whether real or imagined. +/// +/// @author David Smart, Smartware Computing +/// +#ifndef SW_HTTPSERVER_H +#define SW_HTTPSERVER_H +#include "mbed.h" +//#include "MODSERIAL.h" // would like to hook in mod serial for higher performance, less blocking +#include "Wifly.h" +#include "TCPSocketServer.h" +#include "TCPSocketConnection.h" + +#ifdef MODSERIAL_H +#define PC MODSERIAL +#else +#define PC Serial +#endif + + +class HTTPServer +{ +public: + /** + * namevalue pairs for parameters + */ + typedef struct { + char * name; + char * value; + } namevalue; + + /** + * callback prototype for custom handler + * + * @param svr is a handle to this class, so the callback has access to member functions + * @param params is a pointer to an array of name value pairs + * @paramcount is the number of parameters. + */ + typedef void (* Handler)(HTTPServer * svr, const char * path, const namevalue *params, int paramcount); + + /** + * Create the HTTPServer object. + * + * @param wifly is the serial port with the wifly interface. + * @param port is the optional parameter for the port number to use, default is 80. + * @param webroot is a file system path to the root folder for the web space. + * @param maxparams defines the maximum number of parameters to a dynamic function (and the memory to support them). + * @param maxdynamicpages defines the maximum number of dynamic pages that can be registered. + * @param pc is the serial port for debug information (I should transform this to a log interface) + */ + HTTPServer(Wifly * wifly, int port = 80, const char * webroot = "/", int maxparams = 30, int maxdynamicpages = 10, PC * pc = NULL); + + /** + * destructor, which can clean up a few things + */ + ~HTTPServer(); + + /** + * the process to call whenever there is free time, as this basically does + * all the work to monitor for connections and handle replies. + */ + void ip_process(); + + /** + * Send a header back to the client and automatically appends a "\r\n". Each parameter must + * send a "\r\n" as part of that string. + * + * @param code is the optional return code; 200 = OK, if not provided then 404 = Not found is returned + * @param code_text is the text to align with the code (e.g. 404, "Not Found") + * @param content_type is a pointer to "Content-Type: text/html\r\n" (for example) + * @param optional_text is a pointer to any other text that is part of the header + */ + void header(int code = 404, const char * code_text = "Not Found", const char * content_type = NULL, const char * optional_text = NULL); + + /** + * Send text to the client + * + * @param msg is the text string to send + * @param bytes is the number of bytes to send. If not set, then strlen is calculated. + */ + void send(const char * msg, int bytes = -1); + + /** + * Send a file to the client, including the header + * + * @param filename is the fully qualified path and filename + * @param filetype is the header information (e.g. "Content-Type: text/html") + * @return true if it thinks it sent ok, false otherwise. + */ + bool SendFile(const char * filename, const char * filetype); + + /** + * register a handler for a specific URL. + * + * @param path to register + * @param callback of type Handler + * @return true if successfully registered + */ + bool RegisterHandler(const char * path, Handler callback); + + /** + * determine if the named file is a supported type (e.g. .htm, .jpg, ...) + * + * @param filename is the filename to test, based on the extension + * @return pointer to a Content-Type string if supported, or NULL if not. + */ + const char * GetSupportedType(const char * filename); + + /** + * search the available parameters for 'name' and if found, return the 'value' + * + * @param name is the name to search for + * @return pointer to the value, or NULL + */ + const char * GetParameter(const char * name); + + /** + * parse the text string into name=value parameters. This will directly + * modify the referenced string. If there is a #fragment_id on the end + * of the string, that will be removed. + * + * @param pString is a pointer to the string. + */ + void ParseParameters(char * pString); + + /** + * Unescape string converts a coded string "in place" into a normal string + * this "This%20is%20a%20question%3F%20and%20an%20answer." + * becomes "This is a question? and an answer." + * @note '+' is another form of space, so is converted to a space before the %xx + * + * @param encoded string to be converted + */ + void UnescapeString(char * encoded); + + /** + * Get the IP address of the remote node to which we are connected. + * @caution this switches the module into, and out of, command mode + * which has quite a time penalty. + */ + void GetRemoteAddr(char * str, int size); + + /** + * used to force a connection to close + */ + void close_connection(); + +private: + Wifly * wifly; + char * webroot; + PC * pc; + Timer * timer; + TCPSocketServer * server; + TCPSocketConnection client; + char * rewriteWithDefaultFile(char * queryString); + char * rewritePrependWebroot(char * queryString); + int maxparams; + namevalue *params; + int paramcount; + + typedef struct { + char * path; + Handler callback; + } handler; + int maxdynamicpages; + handler *handlers; + int handlercount; + + /** + * Extract the message from the record, by searching for the needle + * the string of interest follows the needle, and may be ' ' delimited + * Can damage haystack while processing it. + * + * @param haystack is the record to search + * @param needle is the text to search for, which precedes the text to return + * @param string is the text following the needle + * @return true if it extracted something successfully + */ + bool Extract(char * rec, char * needle, char ** string); + + int HexCharToInt(char c); + char HexPairToChar(char * p); +}; +#endif //SW_HTTPSERVER_H