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

Dependents:   Smart-WiFly-WebServer WattEye X10Svr SSDP_Server

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