Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependents: RPC_HTTP RPC_HTTP_WIZnetInterface RPC_HTTP rpc_over_http_TL_interrupter_gatePJ
Fork of HTTPServer by
Revision 0:7a2421e63e74, committed 2013-05-26
- Comitter:
- leihen
- Date:
- Sun May 26 20:13:28 2013 +0000
- Child:
- 1:6b7472d5e9ee
- Commit message:
- First draft, which does not actually handle a request.
; Framework is working though.
Changed in this revision
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/HTTPConnection.cpp Sun May 26 20:13:28 2013 +0000
@@ -0,0 +1,219 @@
+/* HTTPConnection.cpp */
+
+#include "mbed.h"
+#include "HTTPConnection.h"
+
+#include <vector>
+using std::vector;
+
+using std::string;
+
+#if (1 && !defined(TARGET_LPC11U24))
+#define INFO(x, ...) std::printf("[HttpConnection : INFO]"x"\r\n", ##__VA_ARGS__);
+#define WARN(x, ...) std::printf("[HttpConnection : WARN]"x"\r\n", ##__VA_ARGS__);
+#define ERR(x, ...) std::printf("[HttpConnection : ERR]"x"\r\n", ##__VA_ARGS__);
+#else
+#define INFO(x, ...)
+#define WARN(x, ...)
+#define ERR(x, ...)
+#endif
+
+
+
+
+HTTPConnection::HTTPConnection()
+{
+}
+
+
+HTTPConnection::~HTTPConnection()
+{
+ close();
+}
+
+void HTTPConnection::close()
+{
+ m_Msg.headers.clear();
+}
+
+int HTTPConnection::poll()
+{
+ static char buffer[256] = {};
+ static char echoHeader[256] = {};
+
+
+ int rcvd= 0;
+ INFO("[HTTPConnection]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(echoHeader,"HTTP/1.1 400 NOK\n\rContent-Length: %d\n\rContent-Type: text\n\rConnection: Close\n\r\n\r",strlen(buffer));
+ m_Tcp.set_blocking(true, 1500);
+ m_Tcp.send(echoHeader,strlen(echoHeader));
+ 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 !");
+ }
+ }
+ }
+ if (rcvd == 0) {
+ sprintf(echoHeader,"HTTP/1.1 200 OK\n\rContent-Length: %d\n\rContent-Type: text\n\rConnection: Close\n\r\n\r",strlen(buffer));
+ m_Tcp.set_blocking(true);
+ m_Tcp.send_all(echoHeader,strlen(echoHeader));
+ m_Tcp.send_all(buffer,strlen(buffer));
+
+ /// INSERT PRCESSING OF REQUESST HERE
+ /// END OF PROCESSING REQUEST
+
+ // Do not close the connection, it may be reused
+ }
+ INFO("Leaving poll function!");
+ return rcvd;
+}
+
+int HTTPConnection::receiveLine(char* szLine, int nMaxLen, int nTimeout, char cLineTerm)
+{
+ if ((szLine == NULL) || (nMaxLen == 0))
+ return -1;
+
+ m_Tcp.set_blocking(false);
+
+ 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_all( 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;
+ }
+ INFO("receiveLine : \"%s\".", szLine);
+
+ // 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(const char* buffer)
+{
+ if ((buffer == NULL) || (strlen(buffer) < 4)) {
+ ERR("Buffer content is invalid or too short.");
+ return -1;
+ }
+
+ vector<std::string> args;
+ args.clear();
+
+ // decompose string into a list of arguments
+ char s = 0; // current starting char
+ static char buff[255] = {};
+ for (int i = 0 ; i < strlen(buffer)+1 ; i++) {
+ if ((buffer[i] == ' ') || (buffer[i] == '\n') || (buffer[i] == 0)) {
+ // new arg found
+ strncpy(buff, &buffer[s], i-s);
+ buff[i-s] = 0;
+ INFO("Found argument \"%s\"", buff);
+ args.push_back(std::string(buff));
+ 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.");
+ }
+ }
+ args.clear();
+
+ return 1;
+}
+
+
+int HTTPConnection::parseHeader(const char *buffer)
+{
+ if ((strlen(buffer) <3) || (buffer == NULL))
+ return -1;
+
+ // decompose string into a touple of <field name> : <field value>
+ static char fieldname[256] = {};
+ static char fieldvalue[256] = {};
+ for (int i = 0 ; i < strlen(buffer)+1 ; i++) {
+ if (buffer[i] == ':') {
+ // touple found
+ strncpy(fieldname, buffer, i);
+ fieldname[i] = 0;
+ strcpy(fieldvalue, &buffer[i+1]);
+
+// m_Msg.headers[fieldname] = fieldvalue;
+
+ INFO("Header name=\"%s\" : value=\"%s\".", fieldname, fieldvalue);
+ return 0;
+ }
+ }
+
+ ERR("Did not recieve a valid header : \"%s\".", buffer);
+ return -1;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/HTTPConnection.h Sun May 26 20:13:28 2013 +0000
@@ -0,0 +1,69 @@
+/* HTTPConnection.h */
+#ifndef __HTTPConnection_H__
+#define __HTTPConnection_H__
+
+#include "mbed.h"
+#include "TCPSocketConnection.h"
+
+#include <string>
+#include <map>
+
+enum HTTPRequestType
+{
+ HTTP_RT_GET,
+ HTTP_RT_POST,
+ HTTP_RT_PUT,
+ HTTP_RT_OPTIONS,
+ HTTP_RT_HEAD,
+ HTTP_RT_DELETE,
+ HTTP_RT_TRACE,
+ HTTP_RT_CONNECT
+};
+
+struct HTTPMessage
+{
+ HTTPRequestType request;
+ std::string uri;
+ std::string version;
+ std::map<string, string> headers;
+};
+
+/** class HTTPConnection, encapsulates one connection being made throught the HTTPServer
+ *
+ */
+class HTTPConnection {
+ public:
+ /** public constructor
+ *
+ */
+ HTTPConnection ();
+ ~HTTPConnection();
+
+ /** function to close this connection. To be called from internally.
+ */
+ void close();
+
+ /** query if this connection is closed and can be deleted.
+ @returns true if connection is closed.
+ */
+ bool is_closed();
+
+ /**
+ Polling function
+ @returns -1 if connection is not required anymore. Can happen if a fault occured or if the connection is not needed anymore.
+ */
+ int poll();
+
+ protected:
+
+ TCPSocketConnection m_Tcp;
+
+ HTTPMessage m_Msg;
+ int parse(const char *buffer);
+ int parseHeader(const char *buffer);
+ int receiveHeaders(const char* buffer, int nBuffSize);
+ int receiveLine(char* szLine, int nMaxLen, int nTimeout = -1, char szLineTerm = '\n');
+
+};
+
+#endif // __HTTPConnection_H__
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/HTTPServer.cpp Sun May 26 20:13:28 2013 +0000
@@ -0,0 +1,118 @@
+#include "mbed.h"
+#include "HTTPServer.h"
+
+DigitalOut led1(LED1);
+DigitalOut led2(LED2);
+DigitalOut led3(LED3);
+DigitalOut led4(LED4);
+
+#if (1 && !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__);
+#else
+#define INFO(x, ...)
+#define WARN(x, ...)
+#define ERR(x, ...)
+#endif
+
+
+HTTPServer::HTTPServer(Serial* pDbg)
+{
+ m_pDbg = pDbg;
+ m_pSvr = NULL;
+ m_bServerListening = false;
+}
+
+HTTPServer::~HTTPServer()
+{
+ if (m_pSvr) {
+ delete m_pSvr;
+ m_pSvr = NULL;
+ m_bServerListening = false;
+ }
+}
+
+int HTTPServer::start(int port)
+{
+ // check if the start member was called already once
+ if (m_pSvr != NULL) {
+ 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();
+
+ // Bind the local server to the given port
+ if (m_pSvr->bind(port) < 0) {
+ ERR("Failed to bind to port %d\n", port);
+ return -1;
+ }
+ else {
+ INFO("Binding succeeded !\n");
+ }
+
+ // Listen to a maximum of 10 concurrent connections
+ if (m_pSvr->listen(1) < 0) {
+ ERR("Faild to listen !\n");
+ delete m_pSvr;
+ m_pSvr = NULL;
+ return -1;
+ }
+ else {
+ INFO("Listening\n");
+ m_bServerListening = true;
+ }
+
+ // set into non blocking operation
+ m_pSvr->set_blocking(false, 100);
+
+ return 0;
+}
+
+
+int HTTPServer::poll()
+{
+ INFO("Listening for new connection requests.");
+
+ // 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;
+
+ led4 = 1; // Indicate we are waiting for a new connection
+ 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");
+ led2 = 0;
+ m_bServerListening = false;
+ m_pSvr->close();
+ delete m_pSvr;
+ m_pSvr = NULL;
+ led4 = 0;
+ led3 = 1; // ERROR
+ led2 = 0;
+ led1 = 0;
+ return -1;
+ }
+ else {
+ led4 = 0;
+ // a new connection was received
+ INFO("Client (IP=%s) is connected !\n", Clnt.get_address());
+ // Start the main connection thread
+ led3 = 1;
+ led2 = 1;
+ HTTPConnection con;
+ int c = con.poll();
+ if (c == 0) {
+ }
+ led2 = 0;
+ led3 = 0;
+ }
+
+
+ INFO("Leaving polling thread");
+ return 0;
+}
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/HTTPServer.h Sun May 26 20:13:28 2013 +0000
@@ -0,0 +1,68 @@
+/* HTTPServer.cpp */
+#ifndef __HTTPSERVER_H__
+#define __HTTPSERVER_H__
+#include "mbed.h"
+#include "HTTPConnection.h"
+
+#include <TCPSocketConnection.h>
+#include <TCPSocketServer.h>
+
+/** Class HTTPServer for WiFly Interface Library
+ *
+ */
+ class HTTPServer
+ {
+
+ public:
+ HTTPServer(Serial* pDbg = NULL);
+ ~HTTPServer();
+/*
+ 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 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
+ */
+// template<typename T>
+// void addHandler(const char* path) //Template decl in header
+// { m_lpHandlers[path] = &T::inst; }
+
+ ///Starts listening
+ /**
+ 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
+ @returns : -1 if an unrecoverable error occured, or 0 if everything was ok.
+ */
+ int start(int port = 80);
+
+ /**
+ 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.
+ */
+ int poll();
+
+private:
+
+ TCPSocketServer* m_pSvr;
+ bool m_bServerListening;
+
+ Serial* m_pDbg;
+
+ };
+
+ #endif //__HTTPSERVER_H__
\ No newline at end of file
