HTTP Server, WebSocket support
Fork of HTTPD by
Revision 1:b724fdb741e7, committed 2017-06-15
- Comitter:
- dgriffin65
- Date:
- Thu Jun 15 20:17:24 2017 +0000
- Parent:
- 0:d18dff347122
- Commit message:
- Updated to mbed-os
Changed in this revision
--- 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;