Webserver example for Nuvoton NuMaker boards and mbed OS 5.15 - HTTP 1.1 and multi-threaded.

Dependencies:   mbed-http

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers http_server.h Source File

http_server.h

00001 /*
00002  * PackageLicenseDeclared: Apache-2.0
00003  * Copyright (c) 2017 ARM Limited
00004  *
00005  * Licensed under the Apache License, Version 2.0 (the "License");
00006  * you may not use this file except in compliance with the License.
00007  * You may obtain a copy of the License at
00008  *
00009  *     http://www.apache.org/licenses/LICENSE-2.0
00010  *
00011  * Unless required by applicable law or agreed to in writing, software
00012  * distributed under the License is distributed on an "AS IS" BASIS,
00013  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00014  * See the License for the specific language governing permissions and
00015  * limitations under the License.
00016  */
00017 
00018 #ifndef _HTTP_SERVER_
00019 #define _HTTP_SERVER_
00020 
00021 #include "mbed.h"
00022 #include "http_request_parser.h"
00023 #include "http_response.h"
00024 #include "http_response_builder.h"
00025 
00026 #ifndef HTTP_SERVER_MAX_CONCURRENT
00027 #define HTTP_SERVER_MAX_CONCURRENT      5
00028 #endif
00029 
00030 typedef HttpResponse ParsedHttpRequest;
00031 
00032 /**
00033  * \brief HttpServer implements the logic for setting up an HTTP server.
00034  */
00035 class HttpServer {
00036 public:
00037     /**
00038      * HttpRequest Constructor
00039      *
00040      * @param[in] network The network interface
00041     */
00042     HttpServer(NetworkInterface* network) {
00043         _network = network;
00044     }
00045 
00046     ~HttpServer() {
00047         for (size_t ix = 0; ix < HTTP_SERVER_MAX_CONCURRENT; ix++) {
00048             if (socket_threads[ix]) {
00049                 delete socket_threads[ix];
00050             }
00051         }
00052     }
00053 
00054     /**
00055      * Start running the server (it will run on it's own thread)
00056      */
00057     nsapi_error_t start(uint16_t port, Callback<void(ParsedHttpRequest* request, TCPSocket* socket)> a_handler) {
00058         server = new TCPSocket();
00059 
00060         nsapi_error_t ret;
00061 
00062         ret = server->open(_network);
00063         if (ret != NSAPI_ERROR_OK) {
00064             return ret;
00065         }
00066 
00067         ret = server->bind(port);
00068         if (ret != NSAPI_ERROR_OK) {
00069             return ret;
00070         }
00071 
00072         server->listen(HTTP_SERVER_MAX_CONCURRENT); // max. concurrent connections...
00073 
00074         handler = a_handler;
00075 
00076         main_thread.start(callback(this, &HttpServer::main));
00077 
00078         return NSAPI_ERROR_OK;
00079     }
00080 
00081 private:
00082 
00083     void receive_data() {
00084         // UNSAFE: should Mutex around it or something
00085         TCPSocket* socket = sockets.back();
00086 
00087         // needs to keep running until the socket gets closed
00088         while (1) {
00089 
00090             ParsedHttpRequest* response = new ParsedHttpRequest();
00091             HttpParser* parser = new HttpParser(response, HTTP_REQUEST);
00092 
00093             // Set up a receive buffer (on the heap)
00094             uint8_t* recv_buffer = (uint8_t*)malloc(HTTP_RECEIVE_BUFFER_SIZE);
00095 
00096             // TCPSocket::recv is called until we don't have any data anymore
00097             nsapi_size_or_error_t recv_ret;
00098             while ((recv_ret = socket->recv(recv_buffer, HTTP_RECEIVE_BUFFER_SIZE)) > 0) {
00099                 // Pass the chunk into the http_parser
00100                 size_t nparsed = parser->execute((const char*)recv_buffer, recv_ret);
00101                 if (nparsed != recv_ret) {
00102                     printf("Parsing failed... parsed %d bytes, received %d bytes\n", nparsed, recv_ret);
00103                     recv_ret = -2101;
00104                     break;
00105                 }
00106 
00107                 if (response->is_message_complete()) {
00108                     break;
00109                 }
00110             }
00111             // error?
00112             if (recv_ret <= 0) {
00113                 if (recv_ret < 0) {
00114                     printf("Error reading from socket %d\n", recv_ret);
00115                 }
00116 
00117                 // error = recv_ret;
00118                 delete response;
00119                 delete parser;
00120                 free(recv_buffer);
00121 
00122                 // q; should we always break out of the thread or only if NO_SOCKET ?
00123                 // should we delete socket here? the socket seems already gone...
00124                 if (recv_ret < -3000 || recv_ret == 0) {
00125                     return;
00126                 }
00127                 else {
00128                     continue;
00129                 }
00130             }
00131 
00132             // When done, call parser.finish()
00133             parser->finish();
00134 
00135             // Free the receive buffer
00136             free(recv_buffer);
00137 
00138             // Let user application handle the request, if user needs a handle to response they need to memcpy themselves
00139             if (recv_ret > 0) {
00140                 handler(response, socket);
00141             }
00142 
00143             // Free the response and parser
00144             delete response;
00145             delete parser;
00146         }
00147     }
00148 
00149     void main() {
00150         while (1) {
00151             TCPSocket* clt_sock; // = new TCPSocket(); // Q: when should these be cleared? When not connected anymore?
00152             //SocketAddress clt_addr;
00153             nsapi_error_t accept_res;
00154             
00155             //nsapi_error_t accept_res = server->accept(clt_sock, &clt_addr);
00156             clt_sock = server->accept(&accept_res);
00157             if (accept_res == NSAPI_ERROR_OK) {
00158                 sockets.push_back(clt_sock); // so we can clear our disconnected sockets
00159 
00160                 // and start listening for events there
00161                 Thread* t = new Thread(osPriorityNormal, 2048);
00162                 t->start(callback(this, &HttpServer::receive_data));
00163 
00164                 socket_thread_metadata_t* m = new socket_thread_metadata_t();
00165                 m->socket = clt_sock;
00166                 m->thread = t;
00167                 socket_threads.push_back(m);
00168             }
00169             else {
00170                 //delete clt_sock;
00171             }
00172 
00173             for (size_t ix = 0; ix < socket_threads.size(); ix++) {
00174                 if (socket_threads[ix]->thread->get_state() == Thread::Deleted) {
00175                     socket_threads[ix]->thread->terminate();
00176                     delete socket_threads[ix]->thread;
00177                     //delete socket_threads[ix]->socket; // does this work on esp8266?
00178                     socket_threads[ix]->socket->close();
00179                     socket_threads.erase(socket_threads.begin() + ix); // what if there are two?
00180                 }
00181             }
00182 
00183         }
00184     }
00185 
00186     typedef struct {
00187         TCPSocket* socket;
00188         Thread*    thread;
00189     } socket_thread_metadata_t;
00190 
00191     TCPSocket* server;
00192     NetworkInterface* _network;
00193     Thread main_thread;
00194     vector<TCPSocket*> sockets;
00195     vector<socket_thread_metadata_t*> socket_threads;
00196     Callback<void(ParsedHttpRequest* request, TCPSocket* socket)> handler;
00197 };
00198 
00199 #endif // _HTTP_SERVER