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
- Committer:
- WiredHome
- Date:
- 2018-06-10
- Revision:
- 53:e5d96abe5e9b
- Parent:
- 49:cd391662f254
- Child:
- 59:9a71ac02c782
File content as of revision 53:e5d96abe5e9b:
#ifndef SW_HTTPSERVER_H #define SW_HTTPSERVER_H #include "mbed.h" #include "TCPSocketServer.h" #include "TCPSocketConnection.h" #ifdef MODSERIAL_H #define PC MODSERIAL #else #define PC RawSerial #endif /// This is the default buffer size used to send files. You might size /// this to be equal or less than the payload size of 1460 bytes. /// For WiFly: see User Manual 3.6.1. #define FILESEND_BUF_SIZE 500 /// MAX_HEADER_SIZE is the default size to contain the largest header. /// This is the size of the URL and query string, and also all the /// other header information about the client. This can be /// a couple of K, larger if you have big forms as it includes the /// form data that is submitted. #define MAX_HEADER_SIZE 1000 /// HTTPServer is a simple web server leveraging a network interface. /// /// While simple, it is a capable, web server. The basic mode /// of operation is for it to serve static web pages from an available /// file system. /// /// The default page is index.htm (compile time defined) /// standard support to serve a number of standard file types; /// gif, jpg, jpeg, ico, png, zip, gz, tar, txt, pdf, htm, html /// (this list is also compile time defined) /// /// It can also serve dynamically generated pages, and therefore /// respond to form submission. Through the dynamic interface it is /// then quite easy to interact with the hardware, reading the inputs /// or signaling outputs. /// /// @code /// HTTPServer svr(HTTP_SERVER_PORT, "/local", 15, 30, 10, &pc); /// svr.RegisterHandler("/dyn1", SimpleDynamicPage); /// while (true) { /// svr.Poll(); // this is non blocking process, with variable execution /// } /// @endcode /// /// This web server used nweb as a starting point, but expanded well beyond that. /// http://nmon.sourceforge.net/pmwiki.php?n=Site.Nweb&cm_mc_uid=21286415979014862330090&cm_mc_sid_50200000=1486233009 /// /// Given: scheme://server:port/path?query_string#fragment_id /// @li scheme is "http" /// @li server 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 /// /// Features: /// @li Serves static pages from a file system. Many normal filetypes are /// supported. /// @li Compile time configurable for the "default" file, typically index.htm. /// @li Provides a registration interface for dynamically generated pages that /// can then interact with other hardware. /// @li Revised to be Non-blocking, however the execution time is variable /// depending on the actions being performed and can span hundreds of msec /// when using a WiFly module as the network interface. /// @li Support for filenames aliases, which permit using long filenames with /// the LocalFileSystem (which has an 8.3 constraint). /// /// Limitations: /// @li When used with Wifly network interface it supports only a single /// connection at a time. A web page with served objects (img src=...) /// is rarely served properly. It might trace to forcing the connection to /// close, but not yet sure. Explore "Set Uart Rx Data Buffer" in /// WiFly manual 2.3.65. This is a limitation of the Wifly module. /// No solution is forthcoming, so a crude workaround is to use javascript /// to load the images after the page loads. /// @li Rapid requests for page objects (e.g. embedded images) are lost. Still /// working to understand this issue. /// /// Improvements (TODO): /// @li Add hook for a custom 404 page, which might show a page, or might redirect. /// @li Combine the API for accessing parameters for the GET and POST, as they /// are normally [always?] mutually exclusive. /// @li Keep only the public functions public, make the rest private/protected. /// Add another interface for dynamic pages to give them access to private/protected /// functions. /// @li Try to reduce the size of the header buffer, since that is quite large. /// @li General clean-up, refactoring, de-duplication. /// @li Leverage mbed os, so one receive handler can spawn up to N response handlers. /// This may improve overall performance. /// @li Since some transactions can't be easily buffered (the stream may be too /// large, consider how to shuttle parts of the transaction back and forth /// between the user-code and the server. /// /// History (TO-Done): /// @li 20170408 Added another optional parameter to the constructor to control the /// blocking time when Poll() is called. /// @li 20140913 Removed the relationship to the Wifly module, which caused an API change /// in the constructor by elimination of the first parameter. /// @li 20140913 parses the header similar to the query string, and then makes /// those parameters accessible. /// @li 20140913 Added basic password capability to dynamic web pages. /// @li 20140913 move part of the POST method handler to the registered handler, so /// it can decide if it should allocate the needed memory. /// @li 20140201 hunted down several lengthy operations - the speed of the file system /// and the "close" operation which requires <delay 0.25s>$$$<delay>close\r. /// @li 20130530 Initial version /// @li 20130601 Renamed ip_process to Poll /// @li 20130617 Cleaned up some of the documentation changes /// @li 20130623 Make it non-blocking. "Poll" takes a variable amount /// of time, based on whether it is idle, or how much it /// has to do. /// @li 20130911 Lots of incremental changes along this way, this update /// refreshes the documentation. /// /// @note Copyright © 2014-2017 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 /// class HTTPServer { public: /** * name-value pairs for parameters */ typedef struct NAMEVALUE { char * name; char * value; } namevalue; /** * Indicates the purpose of the Handler callback * * Application code in a dynamic page uses this to determine the state * and therefore the needed operation to be performed. * * @code * bool SimpleDynamicPage(HTTPServer *svr, HTTPServer::CallBackType type, * const char * path, const HTTPServer::namevalue *queryParams, * int queryParamCount) { * char buf[100]; * bool ret = false; * * switch (type) { * case HTTPServer::SEND_PAGE: * svr->header(200, "OK", "Content-Type: text/html\r\n"); * svr->send("<html><head><title>Dynamic Page</title></head>\r\n"); * svr->send("<body>\r\n"); * svr->send("This page was generated dynamically. Create your own name=value pairs on the URL " * "which uses the GET method.<br/>\r\n"); * sprintf(buf, "%d parameters passed to {%s}:<br/>\r\n", queryParamCount, path); * svr->send(buf); * for (int i=0; i<queryParamCount; i++) { * sprintf(buf, "%d: %s = %s<br/>\r\n", i, queryParams[i].name, queryParams[i].value); * svr->send(buf); * } * svr->send("<br/><a href='/'>back to main</a></body></html>\r\n"); * ret = true; * break; * case HTTPServer::CONTENT_LENGTH_REQUEST: * ret = true; * break; * case HTTPServer::DATA_TRANSFER: * ret = true; * break; * default: * ret = false; * break; * } * return ret; * } * @endcode */ typedef enum CALLBACKTYPE { CONTENT_LENGTH_REQUEST, ///< ask the client if they wish to accept the data, typically from a POST event DATA_TRANSFER, ///< used when submitting a file via a form DATA_TRANSFER_END, ///< used when all data has been given to the client (may be used to close the file) SEND_PAGE, ///< the activated method should now send the page } CallBackType; typedef enum CALLBACKRESULTS { ACCEPT_ERROR, ///< client not accepting the request. ACCEPT_COMPLETE, ///< client accepted the request, the work is done. ACCEPT_CONTINUE, ///< client accepted the request, additional transactions to complete. } CallBackResults; /// This is the set of header codes that are generally recognized. Note that many are /// not supported, so may not be listed here. typedef enum HEADERCODES { // 1xx: Information //Continue = 100, ///< Server has received the headers, client should send the body. //Switching = 101, ///< Request to switch protocols - not supported. //Checkpoint = 102, ///< resume aborted PUT/POST - not supported. // 2xx: Successful OK = 200, ///< request is OK. //Created = 201, ///< The request has been fulfilled - not supported. //Accepted = 202, ///< The request has been accepted for processing - not supported. //Non_Auth = 203, ///< The request has been successfully processed - not supported. //No_Content = 204, ///< The request has been successfully processed, but is not returning any content //Reset_Content = 205, ///< The request has been successfully processed, but is not returning any content, // /// and requires that the requester reset the document view //Partial_Content = 206, /// The server is delivering only part of the resource due to a range header sent by the client // 3xx: Redirection //Multiple_Choices = 300, /// A link list. The user can select a link and go to that location. Maximum five addresses. Moved_Permanently = 301, ///< The requested page has moved to a new URL. //Found = 302, /// The requested page has moved temporarily to a new URL //See_Other = 303, /// The requested page can be found under a different URL //Not_Modified = 304, /// Indicates the requested page has not been modified since last requested // 306 Switch Proxy No longer used // 307 Temporary Redirect The requested page has moved temporarily to a new URL // 308 Resume Incomplete Used in the resumable requests proposal to resume aborted PUT or POST requests // 4xx: Client Error Bad_Request = 400, ///< The request cannot be fulfilled due to bad syntax Unauthorized = 401, ///< The request was a legal request, but the server is refusing to respond to it. For use when authentication is possible but has failed or not yet been provided // 402 Payment Required Reserved for future use // 403 Forbidden The request was a legal request, but the server is refusing to respond to it Not_Found = 404, ///< The requested page could not be found but may be available again in the future // Method Not Allowed 405 A request was made of a page using a request method not supported by that page // Not Acceptable 406 The server can only generate a response that is not accepted by the client // Proxy Auth Reqd 407 The client must first authenticate itself with the proxy Request_Timeout = 408, ///< The server timed out waiting for the request // 409 Conflict The request could not be completed because of a conflict in the request // 410 Gone The requested page is no longer available // 411 Length Required The "Content-Length" is not defined. The server will not accept the request without it // 412 Precondition Failed The precondition given in the request evaluated to false by the server // 413 Request Entity Too Large The server will not accept the request, because the request entity is too large // 414 Request-URI Too Long The server will not accept the request, because the URL is too long. Occurs when you convert a POST request to a GET request with a long query information Unsupported_Media_Type = 415, ///< The server will not accept the request, because the media type is not supported // 416 Requested Range Not Satisfiable The client has asked for a portion of the file, but the server cannot supply that portion // 417 Expectation Failed The server cannot meet the requirements of the Expect request-header field // 5xx: Server Error // Message: Description: Server_Error = 500, ///< A generic error message, given when no more specific message is suitable // 501 Not Implemented The server either does not recognize the request method, or it lacks the ability to fulfill the request // 502 Bad Gateway The server was acting as a gateway or proxy and received an invalid response from the upstream server // 503 Service Unavailable The server is currently unavailable (overloaded or down) // 504 Gateway Timeout The server was acting as a gateway or proxy and did not receive a timely response from the upstream server // 505 HTTP Version Not Supported The server does not support the HTTP protocol version used in the request // 511 Network Authentication Required The client needs to authenticate to gain network access } HeaderCodes; /** * This is the prototype for custom handlers that are activated via a callback * * This callback gets overloaded for a few purposes, which can be identified by the * \see CallBackType parameter. * * @li CONTENT_LENGTH_REQUEST - the server is asking the callback if it wants to receive the message, * which may require significant memory. If the request is accepted, true should be returned. * If the request is denied, false should be returned. * @li DATA_TRANSFER - the server is handing off a large body of data, which was accepted based * on the CONTENT_LENGTH_REQUEST callback. The data is now available for processing. * The callback should return true to continue the processing. * @li SEND_PAGE - the callback should now send the html page, using as many svr->send() as needed. * When the callback returns, it should always indicate true that it has sent the page. * * @note The queryParams pointer purpose depends on the callback type. * For CONTENT_LENGTH_REQUEST, the pointer points to the name=value pairs from the * header. * For DATA_TRANSFER, the pointer points to the start of the actual data. * For SEND_PAGE, ... <to be determined> * * @param[in] svr is a handle to this class, so the callback has access to member functions * @param[in] type is the callback type @see CallBackType * @param[in] path is the pointer to a large block of information being transferred. This pointer * references a dynamically managed resource, so any information of value must be * extracted from here, and not referenced into this memory space. * @param[in] queryParams is a pointer based on the callback type. * @param[in] count is the number of items - for type = CONTENT_LENGTH_REQUEST this is the number of * name=value pars in the queryParams parameter, and for the DATA_TRANSFER this is the * number of bytes being passed in the path parameters. * @return one of the @see CallBackResults signals indicating error or successes */ typedef CallBackResults (* Handler)(HTTPServer * svr, CallBackType type, char *path, const namevalue *queryParams, int queryParamCount); /** * Create the HTTPServer object. * * @param[in] port is the optional parameter for the port number to use, default is 80. * @param[in] webroot is a file system path to the root folder for the web space. If any trailing '/' * is included (e.g. "/web/path/") it will be removed (to "/web/path"). * @param[in] maxheaderParams defines the maximum number of parameters to extract from a header * (Host: 192..\r\nConnection: keep-alive\r\n...) * @param[in] maxqueryParams defines the maximum number of query parameters to a dynamic function * (and the memory to support them). * @param[in] maxdynamicpages defines the maximum number of dynamic pages that can be registered. * @param[in] blockingtime is the time that the Poll process will pause, waiting for input. * @param[in] pc is the serial port for debug information (I should transform this to a log interface) * @param[in] allocforheader is the memory allocation to support the largest expected header from a client * @param[in] allocforfile is the memory allocation to support sending a file to the client. This is * typically sized to fit an ethernet frame. */ HTTPServer(int port = 80, const char * webroot = "/", int maxheaderParams = 15, int maxqueryParams = 30, int maxdynamicpages = 10, int blockingtime = 10, PC * pc = NULL, int _allocforheader = MAX_HEADER_SIZE, int _allocforfile = FILESEND_BUF_SIZE ); /** * Destructor, which can clean up memory. */ ~HTTPServer(); /** * Get the path to the webroot, for applications that need to * reference the file system relative to that point. * * @note The returned value may not be exactly as set at instantiation * as trailing '/' were removed (unless the web root == "/"). * e.g. "/msc/web/" becomes "/msc/web" * * @returns pointer to the webroot string. */ const char * GetWebRoot() { return (const char *)webroot; }; /** * Search a haystack of name:value pairs for the needle. * * This is a case-sensitive search. If it cannot find an alias, * it returns the needle. * * This is used in the web server for conveniently mapping long filenames * to short filenames if you are using the LocalFileSystem which only * supports short filenames. * * @code * char * ptr; * namevalue list[] = { * {"/local/longfilename.ext", "/local/short.ext"}, * {"/local/verylongname2.ext", "/local/verylo~1.ext"}, * {NULL, NULL} * }; * * ptr = FindAlias(list, "/local/verylongname2.ext"); * // ptr now references "/local/verylo~1.ext" * @endcode * * @param[in] haystack is the NULL terminated namevalue pair list. * @param[in] needle is a pointer to the name to find. * @returns the alias (value) if the needle is found, otherwise * returns the needle. */ const char * FindAlias(const namevalue * haystack, const char * needle); /** * Register a list of filename aliases to webroot. * * Some uses of this could be on the LocalFileSystem, which only supports * an 8.3 naming convention. This API lets you register a list of * name:value pairs, where the name is the long filename and the * value is the corresponding short filename. * * @param[in] namevaluelist is a pointer to a NULL terminated long * to short filename list. */ void RegisterFilenameAliasList(const namevalue * namevaluelist); /** * The process to call whenever there is free time, as this basically does * all the work to monitor for connections and handle replies. * * Activate this API as often as you can, typically from the loop in main. * * @note This API will pause execution for the "blocking time" value configured * in the constructor. */ void Poll(); /** * Send typical header data, and some optional data back to the client. * * This forms and sends the typical header back to the client. It may also send * optional data (which must end with "\r\n"). It then sends the second newline * sequence that signals the end of the header. * * @code * svr->header(200, "OK", "Content-Type: text/html\r\n"); * ... * svr->header(200, "OK", "Content-Type: text/html\r\n", "SpecialParam: 13\r\n"); * svr->header("NextParam: 14\r\n"); * svr->header(""); // sends the final \r\n to end the header * @endcode * * @param[in] code is the optional return code; 200 = OK, if not provided then 404 = Not found is returned * @param[in] code_text is the text to align with the code (e.g. 404, "Not Found") * @param[in] content_type is a pointer to "Content-Type: text/html\r\n" (for example). The string * must have a \r\n termination. If this parameter is NULL, no alternate is substituted. * @param[in] optional_text is a pointer to any other text that is part of the header, which must * have \r\n termination. It is permissible to string several header items together, * each with the \r\n termination (which includes \r\n termination at the end). * If this parameter is NULL, a standard template response will be sent consisting * of "Max-age: 0\r\nServer: Smart_Server v0.2\r\nConnection: close\r\n\r\n" * If this parameter is not NULL, the user must call header(""), or ensure that * the termination double (\r\n\r\n) ends the optional_text. */ void header(HeaderCodes code = Not_Found, const char * code_text = "Not Found", const char * content_type = NULL, const char * optional_text = NULL); /** * Send a fragment of a header to the client. * * @code * ... * svr->header("NextParam: 14\r\n"); * svr->header(""); // sends the final \r\n to end the header * @endcode * * This API lets you send header information a fragment at a time. A fragment can be a single * line of text, or it can be several strung together with \r\n. * * @param[in] partialheader is a pointer to \r\n terminated text. If partial is a pointer to NULL, * then a terminating \r\n is sent, which ends the header record. */ void header(const char * partialheader); /** * Send text to the client * * This sends the specified text to the client. If the number of bytes is not set, * then it calculates the number of bytes as a string. For binary transfers, the * number of bytes to send is required for proper operation. * * @param[in] msg is the text string to send * @param[in] bytes is the number of bytes to send. If not set, then strlen is calculated. * @returns # of bytes sent, and < 0 for various error codes. */ int send(const char * msg, int bytes = -1); /** * Get the size of the file * * This returns the size of the file. If the specified file is not found, it returns zero. * * @param[in] filename is the file to read. * @returns the size of the file, or zero if the file was not found/opened. */ uint32_t FileSize(const char * filename); /** * Send a referenced file to the client, including the header * * This sends a file from the filesystem to the client. It must be of a supported type * in order to properly create the header. * * @param[in] filename is the fully qualified path and filename * @param[in] filetype is the header information (e.g. "Content-Type: application/pdf") * @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. * * This api lets you register a dynamic handler in the web server. This is * most useful for interactive web pages, rather than simply serving static * pages. * * @code * * ... * svr.RegisterHandler("/dyn1", SimpleDynamicPage); * ... * * HTTPServer::CallBackResults SimpleDynamicPage(HTTPServer *svr, HTTPServer::CallBackType type, char * path, * const HTTPServer::namevalue *queryParams, int queryParamCount) { * char buf[100]; * HTTPServer::CallBackResults ret = HTTPServer::ACCEPT_ERROR; * * switch (type) { * case HTTPServer::SEND_PAGE: * svr->header(HTTPServer::OK, "OK", "Content-Type: text/html\r\n"); * svr->send("<html><head><title>Dynamic Page</title></head>\r\n"); * svr->send("<body>\r\n"); * svr->send("This page was generated dynamically. Create your own name=value pairs on the URL " * "which uses the GET method.<br/>\r\n"); * sprintf(buf, "%d parameters passed to {%s}:<br/>\r\n", queryParamCount, path); * svr->send(buf); * for (int i=0; i<queryParamCount; i++) { * sprintf(buf, "%d: %s = %s<br/>\r\n", i, queryParams[i].name, queryParams[i].value); * svr->send(buf); * } * svr->send("Stats:<br/>\r\n"); * sprintf(buf,"Free memory space: %d<br/>\r\n", Free()); * svr->send(buf); * sprintf(buf,"Max Header size: %d<br/>\r\n", svr->GetMaxHeaderSize()); * svr->send(buf); * svr->send("<br/><a href='/'>back to main</a></body></html>\r\n"); * ret = HTTPServer::ACCEPT_COMPLETE; * break; * case HTTPServer::CONTENT_LENGTH_REQUEST: * ret = HTTPServer::ACCEPT_COMPLETE; * break; * case HTTPServer::DATA_TRANSFER: * ret = HTTPServer::ACCEPT_COMPLETE; * break; * default: * ret = HTTPServer::ACCEPT_ERROR; * break; * } * return ret; * } * @endcode * * @param[in] path to register * @param[in] 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 (htm, html, jpg, etc) * * if you pass in a filename, it will attempt to extract the extension * and compare that to the list of supported file types. If it finds a * match, then it will return a pointer to the content-type string. * * @code * fType = GetSupportedType("mypix.jpg"); * if (fType) { * ... * @endcode * * @param[in] 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 query parameters for 'name' and if found, return the 'value' * * After the querystring is parsed, the server maintains an array of * name=value pairs. This Get function will search for the passed in name * and provide access to the value. * * @code * BusOut leds(LED1,LED2,LED3,LED4); * ... * leds = atoi(svr->GetParameter("leds")); * @endcode * * @param[in] name is the name to search for * @return pointer to the value, or NULL */ const char * GetParameter(const char * name); /** * get a pointer to a name-value pair based on the index. * * @param[in] index is the item being referenced * @return pointer to the namevalue, or NULL */ const namevalue * GetParameter(int index); /** * Get the count of query parameters from the active transaction. * * @returns count of parameters. */ int GetParameterCount(void) { return queryParamCount; }; /** * search the available post parameters for 'name' and if found, return the 'value' * * After the post parameter string is parsed, the server maintains an array of * name=value pairs. This Get function will search for the passed in name * and provide access to the value. * * @code * BusOut leds(LED1,LED2,LED3,LED4); * ... * leds = atoi(svr->GetPostParameter("leds")); * @endcode * * @param[in] name is the name to search for * @return pointer to the value, or NULL */ const char * GetPostParameter(const char * name); /** * get a pointer to a post parameter name-value pair based on the index. * * @param[in] index is the item being referenced * @return pointer to the namevalue, or NULL */ namevalue * GetPostParameter(int index); /** * Get the count of post parameters from the active transaction. * * @returns count of parameters. */ int GetPostParameterCount(void) { return postParamCount; }; /** * 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, it will be removed. * * @param[in] qP is a pointer to a namevalue set * @param[in] qpCount is a pointer to a counter of what is in the set * @param[in] maxP is the maximum number of parameters for which space has been allocated. * @param[in,out] pName is a pointer to the string. * @returns The total number of items that have been parsed, * which can include a count from a url query string. */ int ParseParameters(namevalue * qP, int * qpCount, int maxP, char * pName); /** * Unescape string converts a coded string "in place" into a normal string. * * A query string will have a number of characters replaced for communication * which includes spaces, quotes, question marks and more. Most of them * will be replaced with a %xx format, where xx is the hex code for the * character. Since the string will only get shorter when this happens * the operation is performed in place. * * 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[in,out] encoded string to be converted */ void UnescapeString(char * encoded); /** * This is used to force a connection to close. * * @note When WiFly is the interface, this switches the module into * command mode, performs the close, and then switches it back to data mode. * So, this is a time-expensive command. * * @returns true if successful */ bool close_connection(); /** * Diagnostic to get the size of the largest header. * * This is a diagnostic function, so you can resize the allocated * buffer for your application. With proper sizing, more of the * system memory is available for your application. * * @code * sprintf(buf,"Max Header size: %d<br/>\r\n", svr->GetMaxHeaderSize()); * svr->send(buf); * @endcode * * @returns size in bytes of the larger header measured. */ int GetMaxHeaderSize(); /** * Get a value from the http header, if it exists. * * @param[in] hdr is the string to search for (e.g. "Content-Length") * @returns pointer to the value associated with that header. * @returns NULL if the header is not found. */ const char * GetHeaderValue(const char * hdr); /** * Performance parameter */ typedef struct SW_PERFPARAM { unsigned long long TotalTime_us; unsigned long Samples; unsigned long MaxTime_us; } SW_PerformanceParam; /** * Performance metrics */ typedef struct SW_PERFDATA { SW_PerformanceParam ConnectionAccepted; SW_PerformanceParam HeaderParsed; SW_PerformanceParam ResponseSent; SW_PerformanceParam ConnectionClosed; //SW_PerformanceParam SendFile; } SW_PerformanceData; /** * Get performance metrics from the web server. * * This is a diagnostic function, and gathers data on the internal * performance of the server, as it works various actions. * * @param[in] p is a pointer to a SW_PerformanceData structure to be populated */ void GetPerformanceData(SW_PerformanceData * p); /** * Reset performance metrics. */ void ResetPerformanceData(); /** * Get performance clock */ unsigned int GetPerformanceClock(); private: char * webroot; PC * pc; TCPSocketServer * server; TCPSocketConnection client; char * rewriteWithDefaultFile(char * queryString); char * rewritePrependWebroot(char * queryString); namevalue *queryParams; // Query Parameters from the URL this=that&sky=blue&... int maxqueryParams; int queryParamCount; namevalue *postParams; // Same as Query params, but for post method int maxPostParams; int postParamCount; namevalue *headerParams; // Header params Host: 192.168...\r\nConnection: keep-alive\r\n... int maxheaderParams; int headerParamCount; int maxheaderbytes; char * headerbuffer; int headerbuffersize; Timer PerformanceTimer; /** * Records performance data * * This will take a pointer to a SW_PerformanceParam, and it will * take the time when the performance measurement started. It locally * accesses the current time to measure the elapsed. * * @param[in] param is the performance parameter to update * @param[in] value is the reference time. * @returns the current time which may be used as the reference time * for further measurements. */ unsigned int RecordPerformanceData(SW_PerformanceParam * param, unsigned int value); SW_PerformanceData perfData; typedef struct HANDLER { char * path; Handler callback; } handler; int maxdynamicpages; handler *handlers; int handlercount; char * queryType; char * queryString; // the query string [and 'GET' data] passed on the URL (e.g. ?name1=value1&name2=value2...) char * postQueryString; // the post data const namevalue * filenameAliasList; // pointer to a filename alias list /** * Extract the parameter from the record, by searching for the needle in the haystack. * * The parameter of interest follows the needle, and may be ' ' delimited * Can damage haystack while processing it. * * @param[in] haystack is the record to search * @param[in] needle is the text to search for, which precedes the text to return * @param[out] string is the text following the needle * @return true if it extracted something successfully */ bool Extract(char * haystack, char * needle, char ** string); void SendResponse(); HTTPServer::CallBackResults ParseHeader(char * bPtr); bool CheckDynamicHandlers(); int HexCharToInt(char c); char HexPairToChar(char * p); #ifdef DEBUG void * MyMalloc(int x, int y); char toP(void * x); #endif }; #endif //SW_HTTPSERVER_H