HTTPServer
Revision 0:caf5feddac47, committed 2017-09-16
- Comitter:
- jphuc96
- Date:
- Sat Sep 16 02:39:55 2017 +0000
- Commit message:
- v1
Changed in this revision
diff -r 000000000000 -r caf5feddac47 HTTPConnection.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/HTTPConnection.cpp Sat Sep 16 02:39:55 2017 +0000 @@ -0,0 +1,264 @@ +/* HTTPConnection.cpp */ + +#include "mbed.h" +#include "HTTPConnection.h" +#define DEBUG +#include "hl_debug.h" + +#include <vector> +using std::vector; + +using std::string; + + + +const struct HTTPRequestConfig { + const char* request_string; + HTTPRequestType request_type; +} g_requestConfig[] = { + { "GET", HTTP_RT_GET }, + { "POST", HTTP_RT_POST}, + { "PUT", HTTP_RT_PUT}, + { "OPTIONS",HTTP_RT_OPTIONS}, + { "HEAD", HTTP_RT_HEAD}, + { "DELETE", HTTP_RT_DELETE}, + { "TRACE", HTTP_RT_TRACE}, + { "CONNECT",HTTP_RT_CONNECT} +}; + + +HTTPConnection::HTTPConnection(TCPSocketConnection& clnt) : m_Tcp(clnt) +{ +} + + +HTTPConnection::~HTTPConnection() +{ + close(); +} + +void HTTPConnection::close() +{ + m_Msg.headers.clear(); +} + +int HTTPConnection::poll() +{ + static char buffer[256] = {}; + + + int rcvd= 0; + INFO("Waiting for new data in connection"); + // Try receiving request line + rcvd = receiveLine(buffer, 255, 3000); + if (rcvd == -1) { + // there was an error, probably the connection was closed, so close this connection as well + INFO("No more data available. Will close this connection now."); + close(); + return -1; + } + + // The Request has not yet been received so try it + rcvd = parse(buffer); + if (rcvd == -1) { + // Invalid content received, so close the connection + INFO("Invalid message received, so sending negative response and closing connection !"); + sprintf(buffer,"HTTP/1.1 400 BadRequest\n\rContent-Length: %d\n\rContent-Type: text\n\r\n\r\n\r",0); + m_Tcp.set_blocking(true, 1500); + m_Tcp.send(buffer,strlen(buffer)); + close(); + rcvd = -1; + return -1; + } + // The request has been received, try receive the body + while(rcvd > 0) { + rcvd = receiveLine((char*)buffer, 255, 3000); + // First check if we received an empty line. This would indicate the end of the message or message body. + if (rcvd < 0) { + // there was an empty line, so we can start with performing the request + INFO("Request Header was received completely. Performing request."); + rcvd = 0; + break; + } + else { + // add message body + if (parseHeader(buffer) == 0) { + } + else { + WARN("Invalid message header received !"); + } + } + } + INFO("Leaving poll function!"); + return rcvd; +} + +int HTTPConnection::receiveLine(char* szLine, int nMaxLen, int nTimeout, char cLineTerm) +{ + if ((szLine == NULL) || (nMaxLen == 0)) + return -1; + + szLine[0] = 0; + m_Tcp.set_blocking(false); + + if (!m_Tcp.is_connected()) { + error("NOT COnnected anymore"); + return -1; + } + Timer tm; + int i; + + // Try to receive up to the max number of characters + for (i = 0 ; i < nMaxLen-1 ; i++) { + int c; + c = m_Tcp.receive( szLine + i, 1 ); + // Check that - if no character was currently received - the timeout period is reached. + if ((c == 0) || (c==-1)) { + // no character was read, so check if operation timed out + if (tm.read_ms() > nTimeout) { + // Operation timed out + INFO("Timeout occured in function 'receiveLine'."); + return -1; + } + } + + // Check if line terminating character was received + if (szLine[i] == cLineTerm) + { + break; + } + } + // Terminate with \0 + szLine[i] = 0; + + // Trim for '\r' linefeed at the end + if( (i >0) && (szLine[i-1] == '\r')) { + i--; + szLine[i] = 0; + } + + // return number of characters received in the line or return -2 if an empty line was received + if ((i == 0) || ((i==1) &&(szLine[0] == '\r'))) + { + // empty line received, so return -2 + return -2; + } + return i; +} + +int HTTPConnection::parse(char* buffer) +{ + // Check if buffer is invalid or its content not long enough. + if ((buffer == NULL) || (strlen(buffer) < 4)) { + ERR("Buffer content is invalid or too short."); + return -1; + } + + std::vector<std::string> args; + args.clear(); + + int argno = 0; + // decompose string into a list of arguments + char s = 0; // current starting char + int nLen = strlen(buffer)+1; + for (int i = 0 ; i < nLen ; i++) { + if ((buffer[i] == ' ') || (buffer[i] == '\n') || (buffer[i] == 0)) { + // new arg found + buffer[i] = 0; + if (argno++ == 1) { + // its the uri + // parse the uri args + parseUriArgs(&buffer[s], m_Msg.args); + } + INFO("Found argument \"%s\"", &buffer[s]); + args.push_back(&buffer[s]); + s = i+1; + } + } + + // store the uri and the HTTP version + m_Msg.uri = args[1]; + m_Msg.version = args[2]; + + // Find matching request type + for (int i = 0 ; i < sizeof(g_requestConfig)/sizeof(struct HTTPRequestConfig) ; i++) { + if (args.at(0) == g_requestConfig[i].request_string) { + m_Msg.request = g_requestConfig[i].request_type; + } + } + args.clear(); + + return 1; +} + + +int HTTPConnection::parseHeader(char *buffer) +{ + // Check if the buffer is invalid or if the content is too short to be meaningful + if ((strlen(buffer) <3) || (buffer == NULL)) + return -1; + + // decompose string into a touple of <field name> : <field value> + int value_start = 0; + int buflen = strlen(buffer)+1; + for (int i = 0 ; i < buflen ; i++) { + if (buffer[i] == ':') { + // touple found + buffer[i] = 0; + value_start = i+1; + m_Msg.headers[buffer] = &buffer[value_start]; + + INFO("Header name=\"%s\" : value=\"%s\".", buffer, &buffer[value_start]); + return 0; + } + } + + ERR("Did not recieve a valid header : \"%s\".", buffer); + return -1; +} + +int HTTPConnection::parseUriArgs(char *buffer, map<string,string>&args) +{ + // Check if the buffer is invalid or if the content is too short to be meaningful + if ((strlen(buffer) <3) || (buffer == NULL)) + return -1; + + int args_start = -1; + int value_start = -1; + int buflen = strlen(buffer) +1; + const char* argname = NULL; + const char* valuename = NULL; + for (int i = 0; i < buflen ; i++) { + if (args_start == -1) { // args section not yet found + if (buffer[i] == '?') { // starts with a question mark, so got it + buffer[i] = 0; + args_start = i; // set the start of the args section + INFO("Argument section found !"); + } + } + else { // search arg-value touples + if (argname == NULL) { // arg-name found ? + if (buffer[i] == '=') { + // yes, separate the arg-name + buffer[i] = 0; + argname = &buffer[args_start]; + value_start = i+1; + INFO("Argument name %s", argname); + } + } + else { // search for end of value + if ((buffer[i] == '&') || (buffer[i] == 0) || (buffer[i] == '\r') || (buffer[i] == '\n')) { + buffer[i] = 0; + valuename = &buffer[value_start]; + INFO("Argument value %s", valuename); + args[argname] = valuename; + // reset all indicators + argname = NULL; + valuename = NULL; + } + } + } + } + + return 0; +}
diff -r 000000000000 -r caf5feddac47 HTTPConnection.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/HTTPConnection.h Sat Sep 16 02:39:55 2017 +0000 @@ -0,0 +1,139 @@ +/* HTTPConnection.h */ +/* +Copyright (c) 2013 Henry Leinen (henry[dot]leinen [at] online [dot] de) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ +#ifndef __HTTPConnection_H__ +#define __HTTPConnection_H__ + +#include "mbed.h" +#include "TCPSocketConnection.h" + +#include <string> +#include <map> + +class HTTPServer; + +/** Type HTTPRequestType enumerates request types +*/ +typedef enum +{ + HTTP_RT_GET, /*!< GET request */ + HTTP_RT_POST, /*!< POST request */ + HTTP_RT_PUT, /*!< PUT request */ + HTTP_RT_OPTIONS, /*!< OPTIONS request */ + HTTP_RT_HEAD, /*!< HEAD request */ + HTTP_RT_DELETE, /*!< DELETE request */ + HTTP_RT_TRACE, /*!< TRACE request */ + HTTP_RT_CONNECT /*!< CONNECT request */ +} HTTPRequestType; + +/** class HTTPConnection, encapsulates one connection being made throught the HTTPServer + * + */ +class HTTPConnection { + public: + + /** HTTPMessage contains all the details of the request received by external HTTP client. + */ + typedef struct + { + /** Specifies the request type received + */ + HTTPRequestType request; + /** The uri associated with the request. + */ + std::string uri; + /** Contains the HTTP/1.1 or HTTP/1.0 version requested by client. + */ + std::string version; + /** Map of headers provided by the client in the form <HeaderName>:<HeaderValue> + */ + std::map<std::string, std::string> headers; + /** Map of arguments that came with the uri string + */ + std::map<std::string, std::string> args; + } HTTPMessage; + + /** Public constructor for HTTPConnection objects. + * + */ + HTTPConnection (TCPSocketConnection& clnt); + + /** Destructor for HTTPConnection objects. + * + */ + ~HTTPConnection(); + + /** Query if this connection is already closed and can be deleted. + @returns true, if connection is closed. + */ + bool is_closed(); + + /** Polling function for the connection. + * @returns -1 if connection is not required anymore. In the current version of this library this should be the normal case. This may change in future versions. + */ + int poll(); + + protected: + + /** Function to close this connection. To be called from internally. + */ + void close(); + + friend class HTTPServer; + + TCPSocketConnection m_Tcp; + HTTPMessage m_Msg; + + /** parse a HTTP request line from the content of the buffer. + * @param buffer : the request received from the client in the form <RequestType> <uri> <Http Version> + * @returns -1 if the request is invalid or 0 if the request is valid + */ + int parse(char *buffer); + + /** parses the received string in \c buffer for HTTP request headers. + * @param buffer : buffer which contains the string to parse for headers. + * @returns -1 in case of an error, otherwise returns 0 + */ + int parseHeader(char *buffer); + int receiveHeaders(const char* buffer, int nBuffSize); + + /** Function which receives a line from the current Socket + * @param szline : will contain one line received from the socket + * @param nMaxLen : the size of the buffer. If the line is longer than the buffer the line is cropped at the end. + * @param nTimeout : if the timeout elapses, only the portion that has been received within this time will be returned. + * @param szLineTerm : the \c end-of-line character to be used to detect the end of the line. + * @returns -1 in case of an error or timeout, -2 in case of an empty line or the number of received characters. + */ + int receiveLine(char* szLine, int nMaxLen, int nTimeout = -1, char szLineTerm = '\n'); + + + /** parse the receoved \c uri_string for arguments which will be stored in the \c args map. + * @parse uri_string : the uri string which was received from the client. + * @parse args : the args map which will receive the argument:value touples from the \c uri_string. + * @returns -1 if an error occured, otherwise returns 0. + */ + int parseUriArgs(char *uri_string, map<string,string>& args); + +}; + +#endif // __HTTPConnection_H__ +
diff -r 000000000000 -r caf5feddac47 HTTPRequestHandler.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/HTTPRequestHandler.cpp Sat Sep 16 02:39:55 2017 +0000 @@ -0,0 +1,176 @@ +/* HTTPRequestHandler.cpp */ +#include "mbed.h" +#include "HTTPRequestHandler.h" +#define DEBUG +#include "hl_debug.h" +#include <ctype.h> + + +static char buffer[128]; + + +const char hdrStandard[] = "DNT: 1\r\n" + "MaxAge: 0\r\n" + "Connection: Keep-Alive\r\n" + "Content-Type: text/html\r\n" + "Server: mbed embedded\r\n" + "Accessible: 1\r\n" + "\r\n"; + + +static int _stricmp(const char* a, const char* b) +{ + int la = strlen(a); + int lb = strlen(b); + for (int i = 0 ; i < min(la, lb) ; i++) { + if (tolower((int)a[i]) != tolower((int)b[i])) + return i; + } + return 0; +} + + +static const struct mapping_t { + const char* key; + const char* value; +} fileTypeMapping[] = { + {".gif", "Content-Type: image/gif\r\n" }, + {".jpg", "Content-Type: image/jpeg\r\n" }, + {".jpeg","Content-Type: image/jpeg\r\n" }, + {".ico", "Content-Type: image/x-icon\r\n"}, + {".png", "Content-Type: image/png\r\n" }, + {".zip", "Content-Type: image/zip\r\n" }, + {".gz", "Content-Type: image/gz\r\n" }, + {".tar", "Content-Type: image/tar\r\n" }, + {".txt", "Content-Type: plain/text\r\n" }, + {".pdf", "Content-Type: application/pdf\r\n" }, + {".htm", "Content-Type: text/html\r\n" }, + {".html","Content-Type: text/html\r\n" }, + {".css", "Content-Type: text/css\r\n" }, + {".js", "Content-Type: text/javascript\r\n"}}; + +HTTPRequestHandler::HTTPRequestHandler(HTTPConnection::HTTPMessage& Msg, TCPSocketConnection& Tcp) + : msg(Msg), tcp(Tcp) +{ + msg = Msg; + tcp = Tcp; + +} + +HTTPRequestHandler::~HTTPRequestHandler() +{ +} + +void HTTPRequestHandler::getStandardHeaders(HTTPHeaders& header, const char* fext) +{ + header.clear(); + header["DNT"] = "1"; + header["MaxAge"] = "0"; + header["Connection"] = "Keep-Alive"; + header["Server"] = "mbed Embedded"; + if (fext == NULL) + header["Content-Type"] = "text/html"; + else { + for (int i = 0 ; i < sizeof(fileTypeMapping)/sizeof(struct mapping_t) ;i++) { + if (_stricmp(fileTypeMapping[i].key, fext) == 0) { + header["Content-Type"] = fileTypeMapping[i].value; + break; + } + } + } +} + +void HTTPRequestHandler::handleRequest() +{ + int err = 0; + + switch (msg.request) { + case HTTP_RT_GET: + INFO("Dispatching GET Request."); + err = handleGetRequest(); + break; + + case HTTP_RT_POST: + INFO("Dispatching POST request."); + err = handlePostRequest(); + break; + + case HTTP_RT_PUT: + INFO("Dispatching PUT request."); + err = handlePutRequest(); + break; + + default: + INFO("Error in handleRequest, unhandled request type."); + err = HTTP_NotImplemented; + break; + } + + // if any of these functions returns a negative number, call the error handler + if (err > 0) { + handleError(err); + } +} + +static const char* szErrorPage = "<HTML><HEAD><META content=\"text/html\" http-equiv=Content-Type></HEAD><BODY><h1>Error</h1><P>HTTPServer Error<P></BODY></HTML>\r\n\r\n"; + +void HTTPRequestHandler::handleError(int errorCode, HTTPHeaders* header) +{ + INFO("Handling error !"); + tcp.set_blocking(false, 1500); + sprintf(buffer,"HTTP/1.1 %d Error\r\n", errorCode); + tcp.send(buffer, strlen(buffer)); + sprintf(buffer, "Content-Length: %d\r\n", strlen(szErrorPage)); + tcp.send(buffer, strlen(buffer)); + if (header == NULL) { + sprintf(buffer, "Content-Type: text/html\r\nServer: mbed embedded\r\n\n\r"); + tcp.send(buffer, strlen(buffer)); + } + else { + for ( map<const char*, const char*>::iterator cIter = header->begin() ; cIter != header->end() ; cIter ++) { + tcp.send((char*)cIter->first, strlen(cIter->first)); + tcp.send(": ", 2); + tcp.send((char*)cIter->second, strlen(cIter->second)); + tcp.send("\r\n",2); + } + tcp.send("\r\n",2); + } + tcp.send((char*)szErrorPage, strlen(szErrorPage)); +} + + +void HTTPRequestHandler::startResponse(int returnCode, long nLen, HTTPHeaders* header) +{ + INFO("Starting response (%ld bytes in total)!", nLen); + tcp.set_blocking(false, 1500); + sprintf(buffer, "HTTP/1.1 %d OK\r\n", returnCode); + tcp.send(buffer, strlen(buffer)); + sprintf(buffer, "Content-Length: %ld\r\n", nLen); // Add 2 chars for the terminating CR+LF + tcp.send(buffer, strlen(buffer)); + INFO("Sending standard headers !"); + if (header == NULL) { + tcp.send_all((char*)hdrStandard, strlen(hdrStandard)); + } + else { + for ( map<const char*, const char*>::iterator cIter = header->begin() ; cIter != header->end() ; cIter ++) { + tcp.send_all((char*)cIter->first, strlen(cIter->first)); + tcp.send_all(": ", 2); + tcp.send_all((char*)cIter->second, strlen(cIter->second)); + tcp.send_all("\r\n\r\n",2); + } + tcp.send_all("\r\n", 2); + } + INFO("Proceeding !"); + // other content must be sent using the 'processResponse' function +} + +void HTTPRequestHandler::processResponse(int nLen, char* body) +{ + INFO("Processing Response (%d bytes)!\n",nLen); + tcp.send_all(body, nLen); +} + +void HTTPRequestHandler::endResponse() +{ + INFO("Ending Response !"); +}
diff -r 000000000000 -r caf5feddac47 HTTPRequestHandler.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/HTTPRequestHandler.h Sat Sep 16 02:39:55 2017 +0000 @@ -0,0 +1,139 @@ +/* HTTPRequestHandler.h */ +/* +Copyright (c) 2013 Henry Leinen (henry[dot]leinen [at] online [dot] de) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ +#ifndef __HTTPREQUESTHANDLER_H__ +#define __HTTPREQUESTHANDLER_H__ + +#include "mbed.h" +#include "HTTPConnection.h" + +#include <map> + +typedef std::map<const char*,const char*> HTTPHeaders; + +typedef enum { + HTTP_Continue = 100, // 100 + HTTP_SwitchingProtocols = 101, // 101 + HTTP_Ok = 200, // 200 + HTTP_Created = 201, // 201 + HTTP_Accepted = 202, // 202 + HTTP_NonAuthoritativeInformation = 203, // 203 + HTTP_NoContent = 204, // 204 + HTTP_ResetContent = 205, // 205 + HTTP_PartialContent = 206, // 206 + HTTP_MultipleChoices = 300, // 300 + HTTP_MovedPermanently = 301, // 301 + HTTP_Found = 302, // 302 + HTTP_SeeOther = 303, // 303 + HTTP_NotModified = 304, // 304 + HTTP_UseProxy = 305, // 305 + HTTP_TemporaryRedirect = 307, // 307 + HTTP_BadRequest = 400, // 400 + HTTP_Unauthorized = 401, // 401 + HTTP_PaymentRequired = 402, // 402 + HTTP_Forbidden = 403, // 403 + HTTP_NotFound = 404, // 404 + HTTP_MethodNotAllowed = 405, // 405 + HTTP_NotAcceptable = 406, // 406 + HTTP_ProxyAuthRequired = 407, // 407 + HTTP_RequestTimeOut = 408, // 408 + HTTP_Conflict = 409, // 409 + HTTP_Gone = 410, // 410 + HTTP_LengthRequired = 411, // 411 + HTTP_PreconditionFailed = 412, // 412 + HTTP_RequestEntityTooLarge = 413, // 413 + HTTP_RequestURITooLarge = 414, // 414 + HTTP_UnsupportedMediaType = 415, // 415 + HTTP_RequestedRangeNotSatisfiable = 416, // 416 + HTTP_ExpectationFailed = 417, // 417 + HTTP_InternalServerError = 500, // 500 + HTTP_NotImplemented = 501, // 501 + HTTP_BadGateway = 502, // 502 + HTTP_ServiceUnavailable = 503, // 503 + HTTP_GatewayTimeout = 504, // 504 + HTTP_HTTPVersionNotSupported = 505, // 505 +} HTTPResponseCode; + +/** class HTTPRequestHandler is the base class for HTTP Handler request implementations. +* +*/ +class HTTPRequestHandler +{ + protected: + HTTPConnection::HTTPMessage& msg; + TCPSocketConnection& tcp; + + public: + /** Constructor for HTTPRequestHandler objects. + */ + HTTPRequestHandler(HTTPConnection::HTTPMessage&, TCPSocketConnection&); + + /** Destructor for HTTPRequestHandler objects. + */ + virtual ~HTTPRequestHandler(); + + /** Handler function which will be used by the HTTPServer to serve requests. + * The default version of this function will dispatch respective handler member + * functions according to the request type given in the HTTPMessage object. + * The list of possible functions dispatched is : + * * handleGetRequest + * * handlePostRequest + * * handlePutRequest + */ + virtual void handleRequest(); + + /** Handler function which will handle errors and return errors correctly + * @param errorCode : The error code returned by the HTTP Server to represent the error condition. + * @param msg : Request Message information. + * @param tcp : The socket which represents the active connection to the client. + */ + virtual void handleError(int errorCode, HTTPHeaders* header = NULL); + + /** Function sends the response header which consists of the return code and the headers section + * the response header also contains the length (in bytes) of the body. You need to send the body + * right after calling this function. Please note that you do not need to consider the terminating + * CR+LF after your last CR+LF. This will be sent automatically once \c endResponse is called. Also + * the Length given in \c nLen does not need to consider this additional chars. It will also be + * automatically added in \c startResponse. if you need to change the headers, please do NOT + * specify the \c Content-Length Header. This is done automatically be the function. + */ + void startResponse(int returnCode, long nLen, HTTPHeaders* header = NULL); + void processResponse(int nLen, char* body ); + void endResponse(); + + protected: + /** Handler function to serve GET requests. Download ressource from server from \c uri location. + */ + virtual int handleGetRequest() = 0; + + /** Handler function to serve PUT requests. Upload ressource to server to \c uri location. + */ + virtual int handlePutRequest() = 0; + + /** Handler function to serve POST requests. Send data to webserver. Can also be appended to uri. + */ + virtual int handlePostRequest() = 0; + + void getStandardHeaders(HTTPHeaders& header, const char* fext = NULL); +}; + +#endif // __HTTPREQUESTHANDLER_H__
diff -r 000000000000 -r caf5feddac47 HTTPServer.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/HTTPServer.cpp Sat Sep 16 02:39:55 2017 +0000 @@ -0,0 +1,153 @@ +#include "mbed.h" +#include "HTTPServer.h" +#define DEBUG +#include "hl_debug.h" + + + +/* Constructor */ +/* initialize all members and set the standard error handler. */ +HTTPServer::HTTPServer() + : m_pEthernet(NULL) +{ + m_pErrorHandler = StdErrorHandler; +} + +HTTPServer::~HTTPServer() +{ + if (m_pEthernet == NULL) { + INFO("Deleting EthernetInterface Object.\n"); + delete m_pEthernet; + } +} + +static const char* szStdErrorPage = "<HTML><HEAD><META content=\"text/html\" http-equiv=Content-Type></HEAD><BODY><h1>Error 404</h1><P>This resource is not available<P></BODY></HTML>\r\n\r\n"; + +void HTTPServer::StdErrorHandler(HTTPConnection::HTTPMessage& msg, TCPSocketConnection& tcp) +{ + char echoHeader[256]; + tcp.set_blocking(true, 1500); + sprintf(echoHeader,"HTTP/1.0 404 Fail\r\nConnection: close\r\nContent-Length: %d\r\nContent-Type: text/html\r\nServer: mbed embedded\r\n\n\r",strlen(szStdErrorPage)); + tcp.send(echoHeader, strlen(echoHeader)); + tcp.send((char*)szStdErrorPage, strlen(szStdErrorPage)); +} + + +bool HTTPServer::start(int port, EthernetInterface* pEthernet) +{ + // If no ethernet interface is provided, instantiate own on the heap. This has to be deleted later in the destructor. + // If a valid pointer to an thernet interface is proveded, we can simply use it. + if (pEthernet == NULL) { + INFO("Creating EthernetInterface object\n"); + m_pEthernet = new EthernetInterface(); + + if (m_pEthernet == NULL) { + ERR("Out of memory, unable to instantiate an EthernetInterface object."); + return false; + } + + // Initiaize the network + INFO("Initializing network\n"); + if (m_pEthernet->init() != 0) { + ERR("Failed to initialize the ethernet interface !"); + delete m_pEthernet; + m_pEthernet = NULL; + return false; + } + + // Connect to the network using DHCP + INFO("Connecting to the network using DHCP..."); + if (m_pEthernet->connect() != 0) { + ERR("Failed to connect to the ethernet !"); + delete m_pEthernet; + m_pEthernet = NULL; + return false; + } + + INFO("Connected IP %s", m_pEthernet->getIPAddress()); + + } else { + // In the case that the ethernet interface is provided, it is assumed that a connection has already been created. + INFO("Using connection IP %s", pEthernet->getIPAddress()); + } + + INFO("Binding to port %d...", port); + if (m_Svr.bind(port) < 0) { + ERR("Failed to bind to port !\n"); + error("Binding"); + return false; + } + + INFO("Listening ..."); + if (m_Svr.listen(1) < 0) { + ERR("Failed to listen !\n"); + error("Listening"); + return false; + } + + INFO("Connected !"); + // set into non blocking operation + m_Svr.set_blocking(false, 100); + + return true; +} + + +int HTTPServer::poll(bool blocking) +{ + // This thread basically checks if there is a new incoming connection. + // If so , a new HTTPConnection is created and the connection thread is started. + TCPSocketConnection Clnt; + if (m_Svr.accept(Clnt) < 0) { + return -1; + } + + // a new connection was received + INFO("Client (IP=%s) is connected !\n", Clnt.get_address()); + HTTPConnection con(Clnt); + int c = con.poll(); + if (c == 0) { + // Handle the request + INFO("Handling request !"); + HandleRequest(con.m_Msg, Clnt); + } + if (c == -1) { +// break; + } + + INFO("Leaving polling thread"); + return 0; +} + +void HTTPServer::HandleRequest(HTTPConnection::HTTPMessage& msg, TCPSocketConnection& tcp) +{ + std::string localPath; + std::map<std::string, HTTPRequestHandler*(*)(const char*, const char*, HTTPConnection::HTTPMessage&, TCPSocketConnection&), handlersComp>::const_iterator it; + + // Iterate through registered handlers and check if the handler's path is a subset of the requested uri. + for (it = m_lpHandlers.begin() ; it != m_lpHandlers.end() ; it++) { + // check if this entries' path is fully contained at the beginning of the requested path + std::string curpth = it->first; + + if (msg.uri.find(curpth) == 0) { + // firts matching handler found, we just take it and we'll be happy + localPath = msg.uri.substr(curpth.length()); + break; + } + } + + if (it == m_lpHandlers.end()) { + // There is no such handler, so return invalid + + m_pErrorHandler(msg, tcp); + INFO("Webrequest left unhandled."); + } else { + // Valid handler was found + INFO("Routing webrequest !"); + // Instantiate the handler object (handling will be done from withing the object's constructor + HTTPRequestHandler *phdl = (*it->second)(it->first.c_str(), localPath.c_str(), msg, tcp); + // now we can delete the object, because handling is completed. + if (phdl != NULL) + delete phdl; + } +}
diff -r 000000000000 -r caf5feddac47 HTTPServer.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/HTTPServer.h Sat Sep 16 02:39:55 2017 +0000 @@ -0,0 +1,212 @@ +/* HTTPServer.cpp */ +/* +Copyright (c) 2013 Henry Leinen (henry[dot]leinen [at] online [dot] de) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ +#ifndef __HTTPSERVER_H__ +#define __HTTPSERVER_H__ +#include "mbed.h" +#include "EthernetInterface.h" +#include "HTTPConnection.h" +#include "HTTPRequestHandler.h" +#include "RpcHandler.h" + +#include <map> +using std::map; +#include <string> +using std::string; + +#include <TCPSocketConnection.h> +#include <TCPSocketServer.h> + +/** Typedefinition for a handler function +*/ +typedef void (*HTTPRequestHandlerFunction)(HTTPConnection::HTTPMessage&, TCPSocketConnection&); + + +/** Class HTTPServer for use with <a href="http://mbed.org/users/samux/code/WiflyInterface/">WiflyInterface</a>. +* This class is a simple implementation of an HTTP Server for use with the WiFly interface. +* The class will listen for incoming connections on the (configurable) HTTP port. For each +* incoming connection, one request will be processed. +* After instantiating this class, add all required handlers using the \c addHandler function, +* replace the default error handler using \c addErrorHandler if needed and call the \c start +* method to initialize the class. +* You need to continuously poll for any new incoming connections after one request has been +* served using the \c poll member function. +* +* \b Example: +* @code +* #include "mbed.h" +* #include "HTTPServer.h" +* #include "LocalFileSystem.h" +* +* LocalFileSystem local("local"); +* +* void main(void) +* { +* HTTPServer svr; +* svr.mount("/local/", "/"); +* svr.addHandler<HTTPFsRequestHandler>( "/" ); +* svr.start(); +* while(1) +* { +* if (svr.poll() < 0) +* exit(0); +* } +* } +* @endcode +* +* An alternate approach e.g. if you need to perform additional tasks using the EthernetInterface +* there is the possibility to provide the EthernetInterface object in an initialized and connected +* state. __NOTE: You should choose this scenario for compatibility reasons.___ +* +* \b Example2: +* @code +* #include "mbed.h" +* #include "HTTPServer.h" +* #include "EthernetInterface.h" +* #include "LocalFileSystem.h" +* +* LocalFileSystem local("local"); +* EthernetInterface eth; +* +* void main(void) +* { +* HTTPServer svr; +* // Initialize the ethernet interface +* if (eth.init() != 0) { +* printf("Initialization of EthernetInterface failed !"); +* exit(0); +* } +* // Connect using DHCP +* if (eth.connect() !=0) { +* printf("Failed to connect using DHCP !"); +* exit(0); +* } +* +* // Moint the local file system and provide a handler for 'root'. +* svr.mount("/local/", "/"); +* svr.addHandler<HTTPFsRequestHandler>( "/" ); +* // Start the server on port 80, providing our own ethernet interface object. +* svr.start(80, ð); +* while(1) +* { +* if (svr.poll() < 0) +* exit(0); +* } +* } +* @endcode +* +*/ +class HTTPServer +{ + TCPSocketServer m_Svr; + bool m_bServerListening; + EthernetInterface* m_pEthernet; + + public: + /** Constructor for HTTPServer objects. + */ + HTTPServer(); + + /** Destructor for HTTPServer objects. + */ + ~HTTPServer(); + + /** + * Structure which will allow to order the stored handlers according to their associated path. + */ + struct handlersComp //Used to order handlers in the right way + { + bool operator() (const string& handler1, const string& handler2) const + { + //The first handler is longer than the second one + if (handler1.length() > handler2.length()) + return true; //Returns true if handler1 is to appear before handler2 + else if (handler1.length() < handler2.length()) + return false; + else //To avoid the == case, sort now by address + return ((&handler1)>(&handler2)); + } + }; + + /** + * Adds a request handler to the handlers list. You will have to use one of the existing implementations. + * With each handler a \c uri or \c path is associated. Whenever a request is received the server will + * walk through all registered handlers and check which \c path is matching. + * @param T : class which will be instanciated to serve these requests for the associated \b path. + * @param path : request uri starting with this \c path will be served using this handler. + */ + template<typename T> + void addHandler(const char* path) + { m_lpHandlers[path] = &T::create; } + + /** + * Replaces the standard error Handler. The error Handler will be called everytime a request is not + * matching any of the registered \c paths or \c uris. + * @param hdlFunc: User specified handler function which will be used in error conditions. + */ + void addErrorHandler(HTTPRequestHandlerFunction hdlFunc) + { m_pErrorHandler = hdlFunc!=NULL ?hdlFunc : StdErrorHandler; } + + /** Binds server to a specific port and starts listening. This member prepares the internal variables and the server socket + * and terminates after successfull initialization + * @param port : port on which to listen for incoming connections + * @param pEthernet : a pointer to an existing EthernetInterface object or NULL if the HTTPServer shall allocate the object. _Please note that for compatibility reasons + * your should consider to create the EthernetInterface as a static variable. Otherwise the the object will be created on the heap._ + * @returns : false if an unrecoverable error occured or if the ethernet interface was not set or not initialized correctly, or true if everything was ok. + */ + bool start(int port = 80, EthernetInterface* pEthernet = NULL); + + /** Performs the regular polling of the server component. Needs to be called cyclically. + * The function will internally check whether new connections are requested by a client and will also poll all existing client connections. + * @param blocking : if true, + * @returns -1 if there was a problem. If 0 is returned, the latest request was served successfully and the server is + * ready for processing the next request. Simply call \c poll as long as you want to serve new incoming requests. + */ + int poll(bool blocking = true); + + private: + + /** The standard error handler function. + * @param msg : Request message data. + * @param tcp : Socket to be used for responding. + */ + static void StdErrorHandler(HTTPConnection::HTTPMessage& msg, TCPSocketConnection& tcp); + + /** Internal function which processes a request and which will try to find the matching handler function + * for the given request. Please note that the function will search through the list of handlers, iterating + * from longest to shortest \c paths. If the registered \c path is a subset of the request the associated + * handler is considered as being a match. + * @param msg : Request message data. Contains the requested logical \c uri. + * @param tcp : Socket to be used for communication with the client. + */ + void HandleRequest(HTTPConnection::HTTPMessage& msg, TCPSocketConnection& tcp); + + /** Map of handler objects. Can be any object derived from \ref HTTPRequestHeader. Use the \ref addHandler function + * to register new handler objects. + */ + map<string, HTTPRequestHandler* (*)(const char*, const char*, HTTPConnection::HTTPMessage&, TCPSocketConnection&), handlersComp> m_lpHandlers; + HTTPRequestHandlerFunction m_pErrorHandler; + + }; + + #endif //__HTTPSERVER_H__ + \ No newline at end of file
diff -r 000000000000 -r caf5feddac47 Handler/FsHandler.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Handler/FsHandler.cpp Sat Sep 16 02:39:55 2017 +0000 @@ -0,0 +1,126 @@ +/* FsHandler.cpp */ +#include "mbed.h" +#include "FsHandler.h" +#define DEBUG +#include "hl_debug.h" + + + +static int matchstrings(const char* one, const char* two) +{ + int m = 0; + + for (m = 0; m < min(strlen(one), strlen(two)) ; m++) { + if (one[m] != two[m]) + return m; + } + return m; +} + +std::map<const char*, const char*> HTTPFsRequestHandler::m_fsMap; + +HTTPFsRequestHandler::HTTPFsRequestHandler(const char* rootPath, const char* localPath, HTTPConnection::HTTPMessage& Msg, TCPSocketConnection& Tcp) + : HTTPRequestHandler(Msg, Tcp) +{ + m_rootPath = rootPath; + m_localPath = localPath; + + string myPath = m_rootPath + m_localPath; + + // Now replace the virtual root path with a mounted device path + std::map<const char*, const char*>::iterator it; + const char *bestMatch = NULL; + const char *bestMatchExchange = NULL; + int match_ind = -1; + for (it = m_fsMap.begin() ; it != m_fsMap.end() ; it++) { + // find best match (if the given logical path is containted in the root + int s = matchstrings(myPath.c_str(), it->second); + INFO("Matching Root %s with handler %s results in %d identical characters\n", myPath.c_str(), it->second, s); + if ((s == strlen(it->second)) && (s > match_ind)) { + match_ind = s; + bestMatch = it->first; + bestMatchExchange = it->second; + } + } + + if (bestMatch != NULL) { + m_rootPath = bestMatch; + m_localPath = string(myPath).substr(strlen(bestMatchExchange)); + } + + handleRequest(); +} + +HTTPFsRequestHandler::~HTTPFsRequestHandler() +{ +} + +int HTTPFsRequestHandler::handleGetRequest() +{ + HTTPHeaders headers; + + if (m_localPath.length() > 4) + getStandardHeaders(headers, m_localPath.substr(m_localPath.length()-4).c_str()); + else + getStandardHeaders(headers); + + INFO("Handling Get Request (root = %s, local = %s).", m_rootPath.c_str(), m_localPath.c_str()); + int retval = 0; //success + std::string reqPath; + + // Check if we received a directory with the local bath + if ((m_localPath.length() == 0) || (m_localPath.substr( m_localPath.length()-1, 1) == "/")) { + // yes, we shall append the default page name + m_localPath += "index.html"; + } + + reqPath = m_rootPath + m_localPath; + + INFO("Mapping \"%s\" to \"%s\"", msg.uri.c_str(), reqPath.c_str()); + + FILE *fp = fopen(reqPath.c_str(), "r"); + if (fp != NULL) { + char * pBuffer = NULL; + int sz = 8192; + while( pBuffer == NULL) { + sz /= 2; + pBuffer = (char*)malloc(sz); + if (sz < 128) + error ("OutOfMemory"); + } + + // File was found and can be returned + + // first determine the size + fseek(fp, 0, SEEK_END); + long size = ftell(fp); + fseek(fp, 0, SEEK_SET); + + startResponse(200, size); + while(!feof(fp) && !ferror(fp)) { + int cnt = fread(pBuffer, 1, sz , fp); + if (cnt < 0) + cnt = 0; + processResponse(cnt, pBuffer); + } + delete pBuffer; + endResponse(); + fclose(fp); + } + else { + retval = 404; + ERR("Requested file was not found !"); + } + + return retval; +} + +int HTTPFsRequestHandler::handlePostRequest() +{ + return 404; +} + +int HTTPFsRequestHandler::handlePutRequest() +{ + return 404; +}
diff -r 000000000000 -r caf5feddac47 Handler/FsHandler.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Handler/FsHandler.h Sat Sep 16 02:39:55 2017 +0000 @@ -0,0 +1,81 @@ +/* FsHandler.h */ +/* +Copyright (c) 2013 Henry Leinen (henry[dot]leinen [at] online [dot] de) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ +#ifndef __FSHANDLER_H__ +#define __FSHANDLER_H__ + +#include "mbed.h" +#include "HTTPRequestHandler.h" + +#include <map> +#include <string> + +/** class HTTPFsRequestHandler serves requests with file-system objects +*/ +class HTTPFsRequestHandler : public HTTPRequestHandler +{ + std::string m_rootPath; + std::string m_localPath; + + public: + /** constructor for HTTPFsRequestHandler object and stores the request related data locally. + * the request handling will be initiated from within the constructor. + * @param rootPath : The path under which the handler was registered. + * @param localPath : The path which is relative to the registered file system root. + * @param Msg : Message request information that comes with the request. + * @param Tcp : The socket connection for communicating with the client. + */ + HTTPFsRequestHandler(const char* rootPath, const char* localPath, HTTPConnection::HTTPMessage& Msg, TCPSocketConnection& Tcp); + + /** Destructor + */ + virtual ~HTTPFsRequestHandler(); + + /** static creation function for this object. + */ + static inline HTTPRequestHandler* create(const char* rootPath, const char* localPath, HTTPConnection::HTTPMessage& msg, TCPSocketConnection& tcp) { return new HTTPFsRequestHandler(rootPath, localPath, msg, tcp); } + + /** Handler function to serve GET requests + */ + virtual int handleGetRequest(); + + /** Handler function to serve PUT requests + */ + virtual int handlePutRequest(); + + /** Handler function to serve POST requests + */ + virtual int handlePostRequest(); + + /** Map to register different file system types and associate them with different root paths + */ + static std::map<const char*, const char*> m_fsMap; + + /** static function to register a new file system type with a logical root path + */ + static void mount(const char* requestPath, const char* localPath) { m_fsMap[requestPath] = localPath; } + + /** Parse a uri string for uri file name and argument:value pairs + */ + int parseUriArgs(string uri, map<string, string>& args); +}; +#endif // __FSHANDLER_H__
diff -r 000000000000 -r caf5feddac47 Handler/RpcHandler.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Handler/RpcHandler.cpp Sat Sep 16 02:39:55 2017 +0000 @@ -0,0 +1,76 @@ +/* FsHandler.cpp */ +#include "mbed.h" +#include "RpcHandler.h" +#include "mbed_rpc.h" + + +#define DEBUG 1 +#include "hl_debug.h" + +RPC rpc("rpc"); + + +HTTPRpcRequestHandler::HTTPRpcRequestHandler(const char* rootPath, const char* localPath, HTTPConnection::HTTPMessage& Msg, TCPSocketConnection& Tcp) + : HTTPRequestHandler(Msg, Tcp) +{ + m_rootPath = rootPath; + m_localPath = localPath; + + handleRequest(); +} + + +HTTPRpcRequestHandler::~HTTPRpcRequestHandler() +{ +} + + +int HTTPRpcRequestHandler::handleGetRequest() +{ + char outBuf[256] = {}; + bool retval = false; + int err = 404; + string rpc_args(""); + + INFO("Handling RPC Get Requesst."); + // This version of the RPC handler does only accept native RPC commands in the format + // /<class>/<method> <argument1> [<argument2> [<argument3> ...]] + // So we can simply pass our local pathg to our rpc + + // Append missing slash if needed + if (m_localPath.c_str()[0] != '/') { + rpc_args = "/"; + } + // replace the HTTP strings with ascii strings + for (int i = 0 ; i < m_localPath.length() ; i++) { + if (m_localPath.substr(i,3) == "%20") { + rpc_args += " "; + i+=2; + } + else { + rpc_args += m_localPath.substr(i,1); + } + } + INFO("RPC to %s", rpc_args.c_str()); + retval = rpc.call(rpc_args.c_str(),outBuf); + INFO("RPC Request returned %d with args : %s", retval==true ? 200 : 0, outBuf); + if (retval) { + // No error + startResponse(200, strlen(outBuf)); + processResponse(strlen(outBuf), outBuf); + endResponse(); + err = 0; + } + + return err; +} + +int HTTPRpcRequestHandler::handlePutRequest() +{ + return 404; +} + +int HTTPRpcRequestHandler::handlePostRequest() +{ + return 404; +} \ No newline at end of file
diff -r 000000000000 -r caf5feddac47 Handler/RpcHandler.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Handler/RpcHandler.h Sat Sep 16 02:39:55 2017 +0000 @@ -0,0 +1,68 @@ +/* RpcHandler.h */ +/* +Copyright (c) 2013 Henry Leinen (henry[dot]leinen [at] online [dot] de) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ +#ifndef __RPCHANDLER_H__ +#define __RPCHANDLER_H__ + +#include "mbed.h" +#include "HTTPRequestHandler.h" + +class HTTPRpcRequestHandler : public HTTPRequestHandler +{ + std::string m_rootPath; + std::string m_localPath; + + public: + /** constructor for HTTPRpcRequestHandler object and stores the request related data locally. + * the request handling will be initiated from within the constructor. + * @param rootPath : The path under which the handler was registered. + * @param localPath : The path which is relative to the registered file system root. + * @param Msg : Message request information that comes with the request. + * @param Tcp : The socket connection for communicating with the client. + */ + HTTPRpcRequestHandler(const char* rootPath, const char* localPath, HTTPConnection::HTTPMessage& Msg, TCPSocketConnection& Tcp); + + /** Destructor + */ + virtual ~HTTPRpcRequestHandler(); + + /** static creation function for this object. + */ + static inline HTTPRequestHandler* create(const char* rootPath, const char* localPath, HTTPConnection::HTTPMessage& msg, TCPSocketConnection& tcp) { return new HTTPRpcRequestHandler(rootPath, localPath, msg, tcp); } + + /** Handler function to serve GET requests + */ + virtual int handleGetRequest(); + + /** Handler function to serve PUT requests + */ + virtual int handlePutRequest(); + + /** Handler function to serve POST requests + */ + virtual int handlePostRequest(); + + /** Parse a uri string for uri file name and argument:value pairs + */ +// int parseUriArgs(string uri, string map<string, string>& args); +}; +#endif // __RPCHANDLER_H__
diff -r 000000000000 -r caf5feddac47 hl_debug.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hl_debug.h Sat Sep 16 02:39:55 2017 +0000 @@ -0,0 +1,16 @@ +#ifndef __DEBUG_H__ +#define __DEBUG_H__ + + +#ifdef DEBUG +#define INFO(x, ...) std::printf("[INFO: %s:%d]"x"\r\n", __FILE__, __LINE__, ##__VA_ARGS__); +#define WARN(x, ...) std::printf("[WARN: %s:%d]"x"\r\n", __FILE__, __LINE__, ##__VA_ARGS__); +#define ERR(x, ...) std::printf("[ERR: %s:%d]"x"\r\n", __FILE__, __LINE__, ##__VA_ARGS__); +#else +#define INFO(x, ...) +#define WARN(x, ...) +#define ERR(x, ...) +#endif + + +#endif // __DEBUG_H__#ifndef __DEBUG_H__