HTTP Server, WebSocket support

Fork of HTTPD by Suga koubou

Files at this revision

API Documentation at this revision

Comitter:
dgriffin65
Date:
Thu Jun 15 20:17:24 2017 +0000
Parent:
0:d18dff347122
Commit message:
Updated to mbed-os

Changed in this revision

HTTPD.cpp Show annotated file Show diff for this revision Revisions of this file
HTTPD.h Show annotated file Show diff for this revision Revisions of this file
HTTPD_req.cpp Show annotated file Show diff for this revision Revisions of this file
HTTPD_util.cpp Show annotated file Show diff for this revision Revisions of this file
HTTPD_ws.cpp Show annotated file Show diff for this revision Revisions of this file
--- a/HTTPD.cpp	Wed Nov 13 01:58:04 2013 +0000
+++ b/HTTPD.cpp	Thu Jun 15 20:17:24 2017 +0000
@@ -26,39 +26,46 @@
     _handler_count = 0;
 }
 
-int HTTPD::start (int port) {
+int HTTPD::start (NetworkStack *ns, int port) {
     int i;
 
+    m_ns = ns;
+    
     for (i = 0; i < HTTPD_MAX_CLIENTS; i ++) {
         _state[i].buf = new CircBuffer<char>(HTTPD_BUF_SIZE);
-        _state[i].thread = new Thread(child, (void*)i, osPriorityNormal, HTTPD_STACK_SIZE);
-        _state[i].client = new TCPSocketConnection;
+        _state[i].thread = new Thread(osPriorityNormal, HTTPD_STACK_SIZE);
+        _state[i].client = new TCPSocket();
+        _state[i].thread->start(callback(child, (void*)i));
     }
+    
 #ifdef HTTPD_ENABLE_CLOSER
     _state[HTTPD_MAX_CLIENTS].thread = new Thread(closer, (void*)HTTPD_MAX_CLIENTS, osPriorityNormal, 128);
-    _state[HTTPD_MAX_CLIENTS].client = new TCPSocketConnection;
+    _state[HTTPD_MAX_CLIENTS].client = new TCPSocket(m_ns);
 #endif
 
+    _server.open(m_ns);
     _server.bind(port);
+    _server.set_blocking(true);
     _server.listen();
-    _daemon = new Thread(daemon, NULL, osPriorityNormal, 256);
+    _daemon = new Thread(osPriorityNormal, HTTPD_STACK_SIZE);
+    _daemon->start(HTTPD::daemon);
     return 0;
 }
 
-void HTTPD::daemon (void const *args) {
+void HTTPD::daemon () {
     HTTPD *httpd = HTTPD::getInstance();
     int i, t = 0;
 
     INFO("Wait for new connection...\r\n");
     for (;;) {
         if (t >= 0) {
-            if (httpd->_server.accept(*httpd->_state[t].client) == 0) {
+            if (httpd->_server.accept(httpd->_state[t].client) == 0) {
                 INFO("accept %d\r\n", t);
                 httpd->_state[t].thread->signal_set(1);
             }
         } else {
 #ifdef HTTPD_ENABLE_CLOSER
-            if (httpd->_server.accept(*httpd->_state[HTTPD_MAX_CLIENTS].client) == 0) {
+            if (httpd->_server.accept(httpd->_state[HTTPD_MAX_CLIENTS].client) == 0) {
                 INFO("accept x\r\n");
                 httpd->_state[HTTPD_MAX_CLIENTS].thread->signal_set(1);
             }
@@ -82,19 +89,27 @@
 
     for (;;) {
         Thread::signal_wait(1);
-
         httpd->_state[id].mode = MODE_REQUEST;
         httpd->_state[id].buf->flush();
         httpd->_state[id].keepalive = 0;
-        INFO("Connection from %s\r\n", httpd->_state[id].client->get_address());
-        httpd->_state[id].client->set_blocking(false, HTTPD_TIMEOUT);
+        INFO("Connection from client\r\n");
+//      INFO("Connection from %s\r\n", httpd->_state[id].client->get_ip_address());
+
+        httpd->_state[id].client->set_blocking(false);
+        httpd->_state[id].client->set_timeout(HTTPD_TIMEOUT);
+        
         for (;;) {
-            if (! httpd->_state[id].client->is_connected()) break;
+            //if (! httpd->_state[id].client->is_connected()) break;
 
-            n = httpd->_state[id].client->receive(buf, sizeof(buf));
-            if (n < 0) break;
+            n = httpd->_state[id].client->recv(buf, sizeof(buf));
+            
+            if (n < 0 ) {
+                printf("HTTPD::child breaking n = %d\r\n", n);
+                break;
+            }
             buf[n] = 0;
-//            DBG("Recv %d '%s'", n, buf);
+            //DBG("Recv %d ", n);
+            DBG("Recv %d '%s'", n, buf);
 
             for (i = 0; i < n; i ++) {
                 httpd->recvData(id, buf[i]);
@@ -102,7 +117,8 @@
         }
 
         httpd->_state[id].client->close();
-        INFO("Close %s\r\n", httpd->_state[id].client->get_address());
+        INFO("Closed client connection\r\n");
+        //INFO("Close %s\r\n", httpd->_state[id].client->get_ip_address());
     }
 }
 
@@ -114,7 +130,8 @@
         Thread::signal_wait(1);
 
         httpd->_state[id].client->close();
-        INFO("Close %s\r\n", httpd->_state[id].client->get_address());
+        INFO("Closed client connection\r\n");
+        //INFO("Close %s\r\n", httpd->_state[id].client->get_ip_address());
     }
 }
 
--- a/HTTPD.h	Wed Nov 13 01:58:04 2013 +0000
+++ b/HTTPD.h	Thu Jun 15 20:17:24 2017 +0000
@@ -21,13 +21,14 @@
 
 #include "mbed.h"
 #include "rtos.h"
-#include "EthernetInterface.h"
+#include "NetworkStack.h"
+#include "EthInterface.h"
 #include "CBuffer.h"
 
-//#define DEBUG
+#define DEBUG
 
 #define HTTPD_PORT 80
-#define HTTPD_MAX_CLIENTS 2
+#define HTTPD_MAX_CLIENTS 5
 #define HTTPD_KEEPALIVE 10
 #define HTTPD_TIMEOUT 15000
 #define HTTPD_MAX_HANDLES 10
@@ -75,7 +76,7 @@
 
     struct STATE {
         Thread *thread;
-        TCPSocketConnection *client;
+        TCPSocket *client;
         volatile Request req;
         volatile Mode mode;
         CircBuffer <char>*buf;
@@ -97,7 +98,7 @@
 
     HTTPD ();
     
-    int start (int port = HTTPD_PORT);
+    int start (NetworkStack *ns, int port = HTTPD_PORT);
 
     // --- HTTPD_req.cpp ---
     void httpdError (int id, int err);
@@ -109,7 +110,14 @@
     char *getUri (int id);
     char *getFilename (int id);
     char *getQueryString (int id);
+    
+    TCPSocket *getClientSocket(int id) {
+        if (id >= HTTPD_MAX_CLIENTS) return NULL;
+        return _state[id].client;
+    }
     int send (int id, const char *body, int len, const char *header = NULL);
+    int sendstr (int id, const char *buf);
+    int hprintf(int id, const char* format, ...);
     int receive (int id, char *buf, int len);
     int attach (const char *uri, const char *dir);
     int attach (const char *uri, void (*funcCgi)(int id));
@@ -124,7 +132,9 @@
 private :
     static HTTPD *_inst;
     Thread *_daemon;
-    TCPSocketServer _server;
+    TCPServer _server;
+    
+    NetworkStack *m_ns;
 
 #ifdef HTTPD_ENABLE_CLOSER
     struct STATE _state[HTTPD_MAX_CLIENTS + 1];
@@ -140,7 +150,7 @@
 
     int _handler_count;
 
-    static void daemon (void const *arg);
+    static void daemon ();
     static void child (void const *arg);
     static void closer (void const *arg);
 
--- a/HTTPD_req.cpp	Wed Nov 13 01:58:04 2013 +0000
+++ b/HTTPD_req.cpp	Thu Jun 15 20:17:24 2017 +0000
@@ -37,7 +37,7 @@
     fp = fopen(file, "r");
     if (fp) {
         strcpy(buf, "HTTP/1.1 200 OK\r\n");
-        _state[id].client->send_all(buf, strlen(buf));
+        _state[id].client->send(buf, strlen(buf));
         {
             // file size
             i = ftell(fp);
@@ -47,22 +47,22 @@
         }
 
         strcpy(buf, "Server: GSwifi httpd\r\n");
-        _state[id].client->send_all(buf, strlen(buf));
+        _state[id].client->send(buf, strlen(buf));
         if (_state[id].keepalive) {
             strcpy(buf, "Connection: Keep-Alive\r\n");
         } else {
             strcpy(buf, "Connection: close\r\n");
         }
-        _state[id].client->send_all(buf, strlen(buf));
+        _state[id].client->send(buf, strlen(buf));
         sprintf(buf, "Content-Type: %s\r\n", mimetype(file));
-        _state[id].client->send_all(buf, strlen(buf));
+        _state[id].client->send(buf, strlen(buf));
         sprintf(buf, "Content-Length: %d\r\n\r\n", len);
-        _state[id].client->send_all(buf, strlen(buf));
+        _state[id].client->send(buf, strlen(buf));
 
         for (;;) {
             i = fread(buf, sizeof(char), sizeof(buf), fp);
             if (i <= 0) break;
-            _state[id].client->send_all(buf, i);
+            _state[id].client->send(buf, i);
 #if defined(TARGET_LPC1768) || defined(TARGET_LPC2368)
             if (feof(fp)) break;
 #endif
@@ -70,7 +70,7 @@
         fclose(fp);
         return 0;
     }
-
+    
     httpdError(id, 404);
     return -1;
 }
@@ -96,21 +96,20 @@
     DBG("httpd error: %d %d %s\r\n", id, err, msg);
     
     sprintf(buf, "HTTP/1.1 %d %s\r\n", err, msg);
-    _state[id].client->send_all(buf, strlen(buf));
+    _state[id].client->send(buf, strlen(buf));
     strcpy(buf, "Content-Type: text/html\r\n\r\n");
-    _state[id].client->send_all(buf, strlen(buf));
+    _state[id].client->send(buf, strlen(buf));
 
     sprintf(buf, "<html><head><title>%d %s</title></head>\r\n", err, msg);
-    _state[id].client->send_all(buf, strlen(buf));
+    _state[id].client->send(buf, strlen(buf));
     sprintf(buf, "<body><h1>%s</h1></body></html>\r\n", msg);
-    _state[id].client->send_all(buf, strlen(buf));
+    _state[id].client->send(buf, strlen(buf));
     wait_ms(100);
     _state[id].client->close();
-//    WARN("%d.%d.%d.%d ", _httpd[cid].host.getIp()[0], _httpd[cid].host.getIp()[1], _httpd[cid].host.getIp()[2], _httpd[cid].host.getIp()[3]);
-//    WARN("%s %s %d %d -\r\n", _httpd[cid].type == GSPROT_HTTPGET ? "GET" : "POST", _httpd[cid].uri, _httpd[cid].length, err);
+    //WARN("%d.%d.%d.%d ", _httpd[cid].host.getIp()[0], _httpd[cid].host.getIp()[1], _httpd[cid].host.getIp()[2], _httpd[cid].host.getIp()[3]);
+    //WARN("%s %s %d %d -\r\n", _httpd[cid].type == GSPROT_HTTPGET ? "GET" : "POST", _httpd[cid].uri, _httpd[cid].length, err);
 }
 
-
 void HTTPD::recvData (int id, char c) {
 
     switch (_state[id].mode) {
@@ -192,15 +191,15 @@
 
     if (_state[id].mode == MODE_ENTER) {
         int i = getHandler(_state[id].uri);
+        printf("handler = %d, uri = %s\r\n", i, _state[id].uri);
         if (i >= 0) { 
             if (_handler[i].dir) {
                 // file
                 httpdFile(id, _handler[i].dir);
-            } else
-            if (_handler[i].funcCgi) {
+            } else if (_handler[i].funcCgi) {
                 // cgi
                 _handler[i].funcCgi(id);
-//                _state[id].keepalive = 0;
+                _state[id].keepalive = 0;
             } else {
                 httpdError(id, 403);
             }
@@ -210,7 +209,7 @@
 
         if (_state[id].keepalive) {
             DBG("keepalive %d", _state[id].keepalive);
-            _state[id].keepalive --;
+            _state[id].keepalive--;
         } else {
             _state[id].client->close();
         }
--- a/HTTPD_util.cpp	Wed Nov 13 01:58:04 2013 +0000
+++ b/HTTPD_util.cpp	Thu Jun 15 20:17:24 2017 +0000
@@ -62,22 +62,46 @@
     char buf[HTTPD_CMD_SIZE];
 
     strcpy(buf, "HTTP/1.1 200 OK\r\n");
-    _state[id].client->send_all(buf, strlen(buf));
+    _state[id].client->send(buf, strlen(buf));
     strcpy(buf, "Server: GSwifi httpd\r\n");
-    _state[id].client->send_all(buf, strlen(buf));
+    _state[id].client->send(buf, strlen(buf));
     if (_state[id].keepalive) {
         strcpy(buf, "Connection: Keep-Alive\r\n");
     } else {
         strcpy(buf, "Connection: close\r\n");
     }
-    _state[id].client->send_all(buf, strlen(buf));
+    _state[id].client->send(buf, strlen(buf));
     if (header) {
-        _state[id].client->send_all((char*)header, strlen(header));
+        _state[id].client->send((char*)header, strlen(header));
     }
     sprintf(buf, "Content-Length: %d\r\n\r\n", len);
-    _state[id].client->send_all(buf, strlen(buf));
+    _state[id].client->send(buf, strlen(buf));
+
+    return _state[id].client->send((char*)body, len);
+}
+
+int HTTPD::sendstr (int id, const char *buf) {
+    return _state[id].client->send((char*)buf, strlen(buf));
+}
+
 
-    return _state[id].client->send_all((char*)body, len);
+int HTTPD::hprintf(int id, const char* format, ...) {
+    //FIX ME: This could result in memory overruns if the buffer size is exceeded
+    static Mutex _mtx;
+    static char  _buf[1024];
+
+    std::va_list arg;
+    
+    _mtx.lock();
+    
+    va_start(arg, format);
+    vsprintf(_buf, format, arg);
+    va_end(arg);
+
+    int r = _state[id].client->send(_buf, strlen(_buf));
+
+    _mtx.unlock();
+    return r;
 }
 
 int HTTPD::getHandler (const char *uri) {
--- a/HTTPD_ws.cpp	Wed Nov 13 01:58:04 2013 +0000
+++ b/HTTPD_ws.cpp	Thu Jun 15 20:17:24 2017 +0000
@@ -124,7 +124,7 @@
         for (i = 0; i < _state[id].length; i ++) {
             if (_state[id].buf->dequeue(&pong[i + 2]) == false) break;
         }
-        _state[id].client->send_all(pong, _state[id].length + 2);
+        _state[id].client->send(pong, _state[id].length + 2);
         }
         break;
     case 0x0a: // pong
@@ -143,22 +143,22 @@
     DBG("websocket accept: %d\r\n", id);
 
     strcpy(buf, "HTTP/1.1 101 Switching Protocols\r\n");
-    _state[id].client->send_all(buf, strlen(buf));
+    _state[id].client->send(buf, strlen(buf));
     strcpy(buf, "Upgrade: websocket\r\n");
-    _state[id].client->send_all(buf, strlen(buf));
+    _state[id].client->send(buf, strlen(buf));
     strcpy(buf, "Connection: Upgrade\r\n");
-    _state[id].client->send_all(buf, strlen(buf));
+    _state[id].client->send(buf, strlen(buf));
 
     strcpy(buf, "Sec-WebSocket-Accept: ");
-    _state[id].client->send_all(buf, strlen(buf));
+    _state[id].client->send(buf, strlen(buf));
     strcpy(buf, _state[id].websocket_key);
     strcat(buf, "258EAFA5-E914-47DA-95CA-C5AB0DC85B11");
     sha1(buf, strlen(buf), buf2);
     base64encode(buf2, 20, buf, sizeof(buf));
-    _state[id].client->send_all(buf, strlen(buf));
+    _state[id].client->send(buf, strlen(buf));
     strcpy(buf, "\r\n\r\n");
-    _state[id].client->send_all(buf, strlen(buf));
-    _state[id].client->set_blocking(true, HTTPD_TIMEOUT * 100);
+    _state[id].client->send(buf, strlen(buf));
+    //_state[id].client->set_blocking(true, HTTPD_TIMEOUT * 100);
     return 0;
 }
 
@@ -179,7 +179,7 @@
         memcpy(&tmp[i], mask, 4);
         i += 4;
     }
-    r = httpd->_state[id].client->send_all(tmp, i);
+    r = httpd->_state[id].client->send(tmp, i);
 
     if (r >= 0) {
         if (mask) {
@@ -187,9 +187,9 @@
             for (i = 0; i < len; i ++) {
                 tmp2[i] = buf[i] ^ mask[i & 0x03];
             }
-            r = httpd->_state[id].client->send_all(tmp2, len);
+            r = httpd->_state[id].client->send(tmp2, len);
         } else {
-            r = httpd->_state[id].client->send_all((char*)buf, len);
+            r = httpd->_state[id].client->send((char*)buf, len);
         }
     }
     return r;