This is a HTTP Server example using the new EthernetInterface and new mbed-rpc libraries.
Dependents: HTTP-RPCServerExample
Fork of HTTPServer by
Revision 4:d065642c32cc, committed 2013-05-28
- Comitter:
- leihen
- Date:
- Tue May 28 21:20:58 2013 +0000
- Parent:
- 3:d6224049b3bf
- Child:
- 5:dc88012caef1
- Commit message:
- Added parameter parsing from uri in http webrequest.
; Documentation updated.
Changed in this revision
--- a/HTTPConnection.cpp Tue May 28 01:56:14 2013 +0000 +++ b/HTTPConnection.cpp Tue May 28 21:20:58 2013 +0000 @@ -20,6 +20,20 @@ +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() { @@ -136,14 +150,16 @@ 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; } - vector<std::string> args; + 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; @@ -151,25 +167,25 @@ 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; } } - - if (args.at(0) == "GET") { - m_Msg.request = HTTP_RT_GET; - m_Msg.uri = args[1]; - m_Msg.version = args[2]; - } - else { - if (args.at(0) == "POST") { - m_Msg.request = HTTP_RT_GET; - m_Msg.uri = args[1]; - m_Msg.version = args[2]; - } - else { - INFO("unhandled message."); + + // 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(); @@ -180,6 +196,7 @@ 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; @@ -201,3 +218,49 @@ 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; +}
--- a/HTTPConnection.h Tue May 28 01:56:14 2013 +0000 +++ b/HTTPConnection.h Tue May 28 21:20:58 2013 +0000 @@ -45,7 +45,6 @@ HTTP_RT_CONNECT /*!< CONNECT request */ } HTTPRequestType; - /** class HTTPConnection, encapsulates one connection being made throught the HTTPServer * */ @@ -58,17 +57,21 @@ { /** Specifies the request type received */ - HTTPRequestType request; + HTTPRequestType request; /** The uri associated with the request. */ - std::string uri; + std::string uri; /** Contains the HTTP/1.1 or HTTP/1.0 version requested by client. */ - std::string version; + std::string version; /** Map of headers provided by the client in the form <HeaderName>:<HeaderValue> */ - std::map<std::string, std::string> headers; + 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. * */ @@ -99,11 +102,37 @@ 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__ \ No newline at end of file
--- a/HTTPFsRequestHandler.cpp Tue May 28 01:56:14 2013 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,86 +0,0 @@ -/* HTTPFsRequestHandler.cpp */ -#include "mbed.h" -#include "HTTPFsRequestHandler.h" - - - -#if (1 && !defined(TARGET_LPC11U24)) -#define INFO(x, ...) std::printf("[HTTPFsRequestHandler : DBG]"x"\r\n", ##__VA_ARGS__); -#define WARN(x, ...) std::printf("[HTTPFsRequestHandler : DBG]"x"\r\n", ##__VA_ARGS__); -#define ERR(x, ...) std::printf("[HTTPFsRequestHandler : DBG]"x"\r\n", ##__VA_ARGS__); -#else -#define INFO(x, ...) -#define WARN(x, ...) -#define ERR(x, ...) -#endif - - -#define MAX_BUFFERSIZE 128 -static char buffer[MAX_BUFFERSIZE]; - - -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; - - // Now replace the virtual root path with a mounted device path - std::map<const char*, const char*>::iterator it; - for (it = m_fsMap.begin() ; it != m_fsMap.end() ; it++) { - // find best match (if the given logical path is containted in the root - if (m_rootPath.find( it->second ) == 0) { - m_rootPath = it->first; - break; - } - } - - handleRequest(); -} - -HTTPFsRequestHandler::~HTTPFsRequestHandler() -{ -} - -int HTTPFsRequestHandler::handleGetRequest() -{ - INFO("Handling Get Request."); - int retval = 200; //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) { - // 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(buffer, 1, MAX_BUFFERSIZE , fp); - processResponse(cnt, buffer); - } - endResponse(); - fclose(fp); - } - else { - retval = 404; - ERR("Requested file was not found !"); - } - - return retval; -}
--- a/HTTPFsRequestHandler.h Tue May 28 01:56:14 2013 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,50 +0,0 @@ -/* HTTPFsRequestHandler.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 __HTTPFSREQUESTHANDLER_H__ -#define __HTTPFSREQUESTHANDLER_H__ - -#include "mbed.h" -#include "HTTPRequestHandler.h" - -#include <map> -#include <string> - -class HTTPFsRequestHandler : public HTTPRequestHandler -{ - std::string m_rootPath; - std::string m_localPath; - - public: - HTTPFsRequestHandler(const char* roottPath, const char* localPath, HTTPConnection::HTTPMessage& Msg, TCPSocketConnection& Tcp); - virtual ~HTTPFsRequestHandler(); - - 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(); - - static std::map<const char*, const char*> m_fsMap; - static void mount(const char* requestPath, const char* localPath) { m_fsMap[requestPath] = localPath; } -}; -#endif // __HTTPFSREQUESTHANDLER_H__ \ No newline at end of file
--- a/HTTPRequestHandler.cpp Tue May 28 01:56:14 2013 +0000 +++ b/HTTPRequestHandler.cpp Tue May 28 21:20:58 2013 +0000 @@ -35,13 +35,15 @@ err = handleGetRequest(); break; -// case HTTP_RT_POST: -// err = handlePostRequest(); -// break; + case HTTP_RT_POST: + INFO("Dispatching POST request."); + err = handlePostRequest(); + break; -// case HTTP_RT_PUT: -// err = handlePutRequest(); -// break; + case HTTP_RT_PUT: + INFO("Dispatching PUT request."); + err = handlePutRequest(); + break; default: INFO("Error in handleRequest, unhandled request type."); @@ -117,4 +119,3 @@ INFO("Ending Response !"); tcp.send("\r\n", 2); } -
--- a/HTTPRequestHandler.h Tue May 28 01:56:14 2013 +0000 +++ b/HTTPRequestHandler.h Tue May 28 21:20:58 2013 +0000 @@ -33,6 +33,7 @@ /** class HTTPRequestHandler is the base class for HTTP Handler request implementations. * */ + class HTTPRequestHandler { protected: @@ -49,8 +50,12 @@ virtual ~HTTPRequestHandler(); /** Handler function which will be used by the HTTPServer to serve requests. - * @param msg : Request Message information. - * @param tcp : The socket which represents the active connection to the client. + * 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(); @@ -74,18 +79,17 @@ void endResponse(); protected: - /** Handler function to serve GET requests + /** Handler function to serve GET requests. Download ressource from server from \c uri location. */ virtual int handleGetRequest() = 0; - /** Handler function to serve PUT requests + /** Handler function to serve PUT requests. Upload ressource to server to \c uri location. */ -// virtual int handlePutRequest() = 0; + virtual int handlePutRequest() = 0; - /** Handler function to serve POST requests + /** Handler function to serve POST requests. Send data to webserver. Can also be appended to uri. */ -// virtual int handlePostRequest() = 0; - + virtual int handlePostRequest() = 0; }; #endif // __HTTPREQUESTHANDLER_H__ \ No newline at end of file
--- a/HTTPServer.cpp Tue May 28 01:56:14 2013 +0000 +++ b/HTTPServer.cpp Tue May 28 21:20:58 2013 +0000 @@ -1,12 +1,16 @@ #include "mbed.h" #include "HTTPServer.h" +#define _DEBUG 1 + +#ifdef _DEBUG DigitalOut led1(LED1); DigitalOut led2(LED2); DigitalOut led3(LED3); DigitalOut led4(LED4); +#endif -#if (1 && !defined(TARGET_LPC11U24)) +#if (_DEBUG && !defined(TARGET_LPC11U24)) #define INFO(x, ...) if (m_pDbg) m_pDbg->printf("[HttpServer : DBG]"x"\r\n", ##__VA_ARGS__); else printf("[HttpServer : DBG]"x"\r\n", ##__VA_ARGS__); #define WARN(x, ...) if (m_pDbg) m_pDbg->printf("[HttpServer : WARN]"x"\r\n", ##__VA_ARGS__); else printf("[HttpServer : DBG]"x"\r\n", ##__VA_ARGS__); #define ERR(x, ...) if (m_pDbg) m_pDbg->printf("[HttpServer : ERR]"x"\r\n", ##__VA_ARGS__); else printf("[HttpServer : DBG]"x"\r\n", ##__VA_ARGS__); @@ -16,11 +20,13 @@ #define ERR(x, ...) #endif + +/* Constructor */ +/* initialize all members and set the standard error handler. */ HTTPServer::HTTPServer(Serial *dbg) { m_pDbg = dbg; m_pSvr = NULL; - m_bServerListening = false; m_pErrorHandler = StdErrorHandler; } @@ -29,17 +35,15 @@ if (m_pSvr) { delete m_pSvr; m_pSvr = NULL; - m_bServerListening = false; } } -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"; +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[512]; - + char echoHeader[256]; tcp.set_blocking(true, 1500); sprintf(echoHeader,"HTTP/1.1 404 Fail\r\nContent-Length: %d\r\nContent-Type: text/html\r\nServer: mbed embedded\r\n\n\r",strlen(szStdErrorPage)); tcp.send(echoHeader, strlen(echoHeader)); @@ -54,8 +58,6 @@ ERR("start function was already called, server is already in listening state."); return -1; } - - m_bServerListening = false; // Create a new server object m_pSvr = new TCPSocketServer(); @@ -78,7 +80,6 @@ } else { INFO("Listening\n"); - m_bServerListening = true; } // set into non blocking operation @@ -96,36 +97,47 @@ // If so , a new HTTPConnection is created and the connection thread is started. TCPSocketConnection Clnt; +#ifdef _DEBUG led4 = 1; // Indicate we are waiting for a new connection +#endif if (m_pSvr->accept(Clnt) < 0) { // an error occured ERR("There was an error, Accept returned with an error. Probably the connection to the router was lost. Shutting down server"); +#ifdef _DEBUG led2 = 0; - m_bServerListening = false; +#endif m_pSvr->close(); delete m_pSvr; m_pSvr = NULL; +#ifdef _DEBUG led4 = 0; led3 = 1; // ERROR led2 = 0; led1 = 0; +#endif return -1; } else { +#ifdef _DEBUG led4 = 0; +#endif // a new connection was received INFO("Client (IP=%s) is connected !\n", Clnt.get_address()); // Start the main connection thread +#ifdef _DEBUG led3 = 1; led2 = 1; +#endif HTTPConnection con; int c = con.poll(); if (c == 0) { // Handle the request HandleRequest(con.m_Msg, Clnt); } +#ifdef _DEBUG led2 = 0; led3 = 0; +#endif } INFO("Leaving polling thread"); @@ -137,12 +149,13 @@ 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) { - // handler found + // firts matching handler found, we just take it and we'll be happy localPath = msg.uri.substr(curpth.length()); break; } @@ -155,31 +168,12 @@ 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; } - } -/* -void HTTPServer::HandleRequest(HTTPConnection::HTTPMessage& msg, TCPSocketConnection& tcp) -{ - map<string, HTTPRequestHandlerFunction>::iterator it; - - it = m_pHandlers.find(msg.uri); - - if (it == m_pHandlers.end()) { - // There is no such handler, so return invalid - - m_pErrorHandler(msg, tcp); - INFO("Webrequest left unhandled."); - } - else { - // Handler was found so pass action to handler - INFO("Routing webrequest !"); - (it->second)(msg, tcp); - } -} -*/ \ No newline at end of file
--- a/HTTPServer.h Tue May 28 01:56:14 2013 +0000 +++ b/HTTPServer.h Tue May 28 21:20:58 2013 +0000 @@ -74,6 +74,11 @@ */ class HTTPServer { + + TCPSocketServer* m_pSvr; + bool m_bServerListening; + Serial* m_pDbg; + public: /** Constructor for HTTPServer objects. */ @@ -83,6 +88,9 @@ */ ~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 @@ -97,20 +105,21 @@ } }; - ///Adds a handler /** - Appends a handler to the handlers list - @param T : class which will be instanciated to serve these requests - @param path : requests starting with this path will be served using this handler + * 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 - handled by a handler from the handler list. - @param hdlFunc: Handler which serves an error condition. + * 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; } @@ -124,18 +133,30 @@ /** 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. + * @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(); - private: - static void StdErrorHandler(HTTPConnection::HTTPMessage&, TCPSocketConnection&); + 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); - TCPSocketServer* m_pSvr; - bool m_bServerListening; - - Serial* m_pDbg; - void HandleRequest(HTTPConnection::HTTPMessage& con, TCPSocketConnection&); + /** 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;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Handler/HTTPFsRequestHandler.cpp Tue May 28 21:20:58 2013 +0000 @@ -0,0 +1,97 @@ +/* HTTPFsRequestHandler.cpp */ +#include "mbed.h" +#include "HTTPFsRequestHandler.h" + + +#define _DEBUG 1 + +#if (_DEBUG && !defined(TARGET_LPC11U24)) +#define INFO(x, ...) std::printf("[HTTPFsRequestHandler : DBG]"x"\r\n", ##__VA_ARGS__); +#define WARN(x, ...) std::printf("[HTTPFsRequestHandler : DBG]"x"\r\n", ##__VA_ARGS__); +#define ERR(x, ...) std::printf("[HTTPFsRequestHandler : DBG]"x"\r\n", ##__VA_ARGS__); +#else +#define INFO(x, ...) +#define WARN(x, ...) +#define ERR(x, ...) +#endif + + +#define MAX_BUFFERSIZE 128 +static char buffer[MAX_BUFFERSIZE]; + + +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; + + // Now replace the virtual root path with a mounted device path + std::map<const char*, const char*>::iterator it; + for (it = m_fsMap.begin() ; it != m_fsMap.end() ; it++) { + // find best match (if the given logical path is containted in the root + if (m_rootPath.find( it->second ) == 0) { + m_rootPath = it->first; + break; + } + } + + handleRequest(); +} + +HTTPFsRequestHandler::~HTTPFsRequestHandler() +{ +} + +int HTTPFsRequestHandler::handleGetRequest() +{ + INFO("Handling Get Request."); + int retval = 200; //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) { + // 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(buffer, 1, MAX_BUFFERSIZE , fp); + processResponse(cnt, buffer); + } + endResponse(); + fclose(fp); + } + else { + retval = 404; + ERR("Requested file was not found !"); + } + + return retval; +} + +int HTTPFsRequestHandler::handlePostRequest() +{ + return 404; +} + +int HTTPFsRequestHandler::handlePutRequest() +{ + return 404; +} \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Handler/HTTPFsRequestHandler.h Tue May 28 21:20:58 2013 +0000 @@ -0,0 +1,81 @@ +/* HTTPFsRequestHandler.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 __HTTPFSREQUESTHANDLER_H__ +#define __HTTPFSREQUESTHANDLER_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 // __HTTPFSREQUESTHANDLER_H__ \ No newline at end of file