Hiroaki Okoshi / Mbed OS http-webserver-example-mbed-os-5-odin-w2
Committer:
Hiroaki_Okoshi
Date:
Sat Oct 09 14:23:23 2021 +0000
Revision:
0:a21b8a29df03
Sample web server via WiFi program. for mbed os 5.15

Who changed what in which revision?

UserRevisionLine numberNew contents of line
Hiroaki_Okoshi 0:a21b8a29df03 1 /*
Hiroaki_Okoshi 0:a21b8a29df03 2 * PackageLicenseDeclared: Apache-2.0
Hiroaki_Okoshi 0:a21b8a29df03 3 * Copyright (c) 2017 ARM Limited
Hiroaki_Okoshi 0:a21b8a29df03 4 *
Hiroaki_Okoshi 0:a21b8a29df03 5 * Licensed under the Apache License, Version 2.0 (the "License");
Hiroaki_Okoshi 0:a21b8a29df03 6 * you may not use this file except in compliance with the License.
Hiroaki_Okoshi 0:a21b8a29df03 7 * You may obtain a copy of the License at
Hiroaki_Okoshi 0:a21b8a29df03 8 *
Hiroaki_Okoshi 0:a21b8a29df03 9 * http://www.apache.org/licenses/LICENSE-2.0
Hiroaki_Okoshi 0:a21b8a29df03 10 *
Hiroaki_Okoshi 0:a21b8a29df03 11 * Unless required by applicable law or agreed to in writing, software
Hiroaki_Okoshi 0:a21b8a29df03 12 * distributed under the License is distributed on an "AS IS" BASIS,
Hiroaki_Okoshi 0:a21b8a29df03 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
Hiroaki_Okoshi 0:a21b8a29df03 14 * See the License for the specific language governing permissions and
Hiroaki_Okoshi 0:a21b8a29df03 15 * limitations under the License.
Hiroaki_Okoshi 0:a21b8a29df03 16 */
Hiroaki_Okoshi 0:a21b8a29df03 17
Hiroaki_Okoshi 0:a21b8a29df03 18 #ifndef _HTTP_SERVER_
Hiroaki_Okoshi 0:a21b8a29df03 19 #define _HTTP_SERVER_
Hiroaki_Okoshi 0:a21b8a29df03 20
Hiroaki_Okoshi 0:a21b8a29df03 21 #include "mbed.h"
Hiroaki_Okoshi 0:a21b8a29df03 22 #include "http_request_parser.h"
Hiroaki_Okoshi 0:a21b8a29df03 23 #include "http_response.h"
Hiroaki_Okoshi 0:a21b8a29df03 24 #include "http_response_builder.h"
Hiroaki_Okoshi 0:a21b8a29df03 25
Hiroaki_Okoshi 0:a21b8a29df03 26 #ifndef HTTP_SERVER_MAX_CONCURRENT
Hiroaki_Okoshi 0:a21b8a29df03 27 #define HTTP_SERVER_MAX_CONCURRENT 5
Hiroaki_Okoshi 0:a21b8a29df03 28 #endif
Hiroaki_Okoshi 0:a21b8a29df03 29
Hiroaki_Okoshi 0:a21b8a29df03 30 typedef HttpResponse ParsedHttpRequest;
Hiroaki_Okoshi 0:a21b8a29df03 31
Hiroaki_Okoshi 0:a21b8a29df03 32 /**
Hiroaki_Okoshi 0:a21b8a29df03 33 * \brief HttpServer implements the logic for setting up an HTTP server.
Hiroaki_Okoshi 0:a21b8a29df03 34 */
Hiroaki_Okoshi 0:a21b8a29df03 35 class HttpServer {
Hiroaki_Okoshi 0:a21b8a29df03 36 public:
Hiroaki_Okoshi 0:a21b8a29df03 37 /**
Hiroaki_Okoshi 0:a21b8a29df03 38 * HttpRequest Constructor
Hiroaki_Okoshi 0:a21b8a29df03 39 *
Hiroaki_Okoshi 0:a21b8a29df03 40 * @param[in] network The network interface
Hiroaki_Okoshi 0:a21b8a29df03 41 */
Hiroaki_Okoshi 0:a21b8a29df03 42 HttpServer(NetworkInterface* network) {
Hiroaki_Okoshi 0:a21b8a29df03 43 _network = network;
Hiroaki_Okoshi 0:a21b8a29df03 44 }
Hiroaki_Okoshi 0:a21b8a29df03 45
Hiroaki_Okoshi 0:a21b8a29df03 46 ~HttpServer() {
Hiroaki_Okoshi 0:a21b8a29df03 47 for (size_t ix = 0; ix < HTTP_SERVER_MAX_CONCURRENT; ix++) {
Hiroaki_Okoshi 0:a21b8a29df03 48 if (socket_threads[ix]) {
Hiroaki_Okoshi 0:a21b8a29df03 49 delete socket_threads[ix];
Hiroaki_Okoshi 0:a21b8a29df03 50 }
Hiroaki_Okoshi 0:a21b8a29df03 51 }
Hiroaki_Okoshi 0:a21b8a29df03 52 }
Hiroaki_Okoshi 0:a21b8a29df03 53
Hiroaki_Okoshi 0:a21b8a29df03 54 /**
Hiroaki_Okoshi 0:a21b8a29df03 55 * Start running the server (it will run on it's own thread)
Hiroaki_Okoshi 0:a21b8a29df03 56 */
Hiroaki_Okoshi 0:a21b8a29df03 57 nsapi_error_t start(uint16_t port, Callback<void(ParsedHttpRequest* request, TCPSocket* socket)> a_handler) {
Hiroaki_Okoshi 0:a21b8a29df03 58 server = new TCPServer();
Hiroaki_Okoshi 0:a21b8a29df03 59
Hiroaki_Okoshi 0:a21b8a29df03 60 nsapi_error_t ret;
Hiroaki_Okoshi 0:a21b8a29df03 61
Hiroaki_Okoshi 0:a21b8a29df03 62 ret = server->open(_network);
Hiroaki_Okoshi 0:a21b8a29df03 63 if (ret != NSAPI_ERROR_OK) {
Hiroaki_Okoshi 0:a21b8a29df03 64 return ret;
Hiroaki_Okoshi 0:a21b8a29df03 65 }
Hiroaki_Okoshi 0:a21b8a29df03 66
Hiroaki_Okoshi 0:a21b8a29df03 67 ret = server->bind(port);
Hiroaki_Okoshi 0:a21b8a29df03 68 if (ret != NSAPI_ERROR_OK) {
Hiroaki_Okoshi 0:a21b8a29df03 69 return ret;
Hiroaki_Okoshi 0:a21b8a29df03 70 }
Hiroaki_Okoshi 0:a21b8a29df03 71
Hiroaki_Okoshi 0:a21b8a29df03 72 server->listen(HTTP_SERVER_MAX_CONCURRENT); // max. concurrent connections...
Hiroaki_Okoshi 0:a21b8a29df03 73
Hiroaki_Okoshi 0:a21b8a29df03 74 handler = a_handler;
Hiroaki_Okoshi 0:a21b8a29df03 75
Hiroaki_Okoshi 0:a21b8a29df03 76 main_thread.start(callback(this, &HttpServer::main));
Hiroaki_Okoshi 0:a21b8a29df03 77
Hiroaki_Okoshi 0:a21b8a29df03 78 return NSAPI_ERROR_OK;
Hiroaki_Okoshi 0:a21b8a29df03 79 }
Hiroaki_Okoshi 0:a21b8a29df03 80
Hiroaki_Okoshi 0:a21b8a29df03 81 private:
Hiroaki_Okoshi 0:a21b8a29df03 82
Hiroaki_Okoshi 0:a21b8a29df03 83 void receive_data() {
Hiroaki_Okoshi 0:a21b8a29df03 84 // UNSAFE: should Mutex around it or something
Hiroaki_Okoshi 0:a21b8a29df03 85 TCPSocket* socket = sockets.back();
Hiroaki_Okoshi 0:a21b8a29df03 86
Hiroaki_Okoshi 0:a21b8a29df03 87 // needs to keep running until the socket gets closed
Hiroaki_Okoshi 0:a21b8a29df03 88 while (1) {
Hiroaki_Okoshi 0:a21b8a29df03 89
Hiroaki_Okoshi 0:a21b8a29df03 90 ParsedHttpRequest* response = new ParsedHttpRequest();
Hiroaki_Okoshi 0:a21b8a29df03 91 HttpParser* parser = new HttpParser(response, HTTP_REQUEST);
Hiroaki_Okoshi 0:a21b8a29df03 92
Hiroaki_Okoshi 0:a21b8a29df03 93 // Set up a receive buffer (on the heap)
Hiroaki_Okoshi 0:a21b8a29df03 94 uint8_t* recv_buffer = (uint8_t*)malloc(HTTP_RECEIVE_BUFFER_SIZE);
Hiroaki_Okoshi 0:a21b8a29df03 95
Hiroaki_Okoshi 0:a21b8a29df03 96 // TCPSocket::recv is called until we don't have any data anymore
Hiroaki_Okoshi 0:a21b8a29df03 97 nsapi_size_or_error_t recv_ret;
Hiroaki_Okoshi 0:a21b8a29df03 98 while ((recv_ret = socket->recv(recv_buffer, HTTP_RECEIVE_BUFFER_SIZE)) > 0) {
Hiroaki_Okoshi 0:a21b8a29df03 99 // Pass the chunk into the http_parser
Hiroaki_Okoshi 0:a21b8a29df03 100 size_t nparsed = parser->execute((const char*)recv_buffer, recv_ret);
Hiroaki_Okoshi 0:a21b8a29df03 101 if (nparsed != recv_ret) {
Hiroaki_Okoshi 0:a21b8a29df03 102 printf("Parsing failed... parsed %d bytes, received %d bytes\n", nparsed, recv_ret);
Hiroaki_Okoshi 0:a21b8a29df03 103 recv_ret = -2101;
Hiroaki_Okoshi 0:a21b8a29df03 104 break;
Hiroaki_Okoshi 0:a21b8a29df03 105 }
Hiroaki_Okoshi 0:a21b8a29df03 106
Hiroaki_Okoshi 0:a21b8a29df03 107 if (response->is_message_complete()) {
Hiroaki_Okoshi 0:a21b8a29df03 108 break;
Hiroaki_Okoshi 0:a21b8a29df03 109 }
Hiroaki_Okoshi 0:a21b8a29df03 110 }
Hiroaki_Okoshi 0:a21b8a29df03 111 // error?
Hiroaki_Okoshi 0:a21b8a29df03 112 if (recv_ret <= 0) {
Hiroaki_Okoshi 0:a21b8a29df03 113 if (recv_ret < 0) {
Hiroaki_Okoshi 0:a21b8a29df03 114 printf("Error reading from socket %d\n", recv_ret);
Hiroaki_Okoshi 0:a21b8a29df03 115 }
Hiroaki_Okoshi 0:a21b8a29df03 116
Hiroaki_Okoshi 0:a21b8a29df03 117 // error = recv_ret;
Hiroaki_Okoshi 0:a21b8a29df03 118 delete response;
Hiroaki_Okoshi 0:a21b8a29df03 119 delete parser;
Hiroaki_Okoshi 0:a21b8a29df03 120 free(recv_buffer);
Hiroaki_Okoshi 0:a21b8a29df03 121
Hiroaki_Okoshi 0:a21b8a29df03 122 // q; should we always break out of the thread or only if NO_SOCKET ?
Hiroaki_Okoshi 0:a21b8a29df03 123 // should we delete socket here? the socket seems already gone...
Hiroaki_Okoshi 0:a21b8a29df03 124 if (recv_ret < -3000 || recv_ret == 0) {
Hiroaki_Okoshi 0:a21b8a29df03 125 return;
Hiroaki_Okoshi 0:a21b8a29df03 126 }
Hiroaki_Okoshi 0:a21b8a29df03 127 else {
Hiroaki_Okoshi 0:a21b8a29df03 128 continue;
Hiroaki_Okoshi 0:a21b8a29df03 129 }
Hiroaki_Okoshi 0:a21b8a29df03 130 }
Hiroaki_Okoshi 0:a21b8a29df03 131
Hiroaki_Okoshi 0:a21b8a29df03 132 // When done, call parser.finish()
Hiroaki_Okoshi 0:a21b8a29df03 133 parser->finish();
Hiroaki_Okoshi 0:a21b8a29df03 134
Hiroaki_Okoshi 0:a21b8a29df03 135 // Free the receive buffer
Hiroaki_Okoshi 0:a21b8a29df03 136 free(recv_buffer);
Hiroaki_Okoshi 0:a21b8a29df03 137
Hiroaki_Okoshi 0:a21b8a29df03 138 // Let user application handle the request, if user needs a handle to response they need to memcpy themselves
Hiroaki_Okoshi 0:a21b8a29df03 139 if (recv_ret > 0) {
Hiroaki_Okoshi 0:a21b8a29df03 140 handler(response, socket);
Hiroaki_Okoshi 0:a21b8a29df03 141 }
Hiroaki_Okoshi 0:a21b8a29df03 142
Hiroaki_Okoshi 0:a21b8a29df03 143 // Free the response and parser
Hiroaki_Okoshi 0:a21b8a29df03 144 delete response;
Hiroaki_Okoshi 0:a21b8a29df03 145 delete parser;
Hiroaki_Okoshi 0:a21b8a29df03 146 }
Hiroaki_Okoshi 0:a21b8a29df03 147 }
Hiroaki_Okoshi 0:a21b8a29df03 148
Hiroaki_Okoshi 0:a21b8a29df03 149 void main() {
Hiroaki_Okoshi 0:a21b8a29df03 150 while (1) {
Hiroaki_Okoshi 0:a21b8a29df03 151 TCPSocket* clt_sock = new TCPSocket(); // Q: when should these be cleared? When not connected anymore?
Hiroaki_Okoshi 0:a21b8a29df03 152 SocketAddress clt_addr;
Hiroaki_Okoshi 0:a21b8a29df03 153
Hiroaki_Okoshi 0:a21b8a29df03 154 nsapi_error_t accept_res = server->accept(clt_sock, &clt_addr);
Hiroaki_Okoshi 0:a21b8a29df03 155 if (accept_res == NSAPI_ERROR_OK) {
Hiroaki_Okoshi 0:a21b8a29df03 156 sockets.push_back(clt_sock); // so we can clear our disconnected sockets
Hiroaki_Okoshi 0:a21b8a29df03 157
Hiroaki_Okoshi 0:a21b8a29df03 158 // and start listening for events there
Hiroaki_Okoshi 0:a21b8a29df03 159 Thread* t = new Thread(osPriorityNormal, 2048);
Hiroaki_Okoshi 0:a21b8a29df03 160 t->start(callback(this, &HttpServer::receive_data));
Hiroaki_Okoshi 0:a21b8a29df03 161
Hiroaki_Okoshi 0:a21b8a29df03 162 socket_thread_metadata_t* m = new socket_thread_metadata_t();
Hiroaki_Okoshi 0:a21b8a29df03 163 m->socket = clt_sock;
Hiroaki_Okoshi 0:a21b8a29df03 164 m->thread = t;
Hiroaki_Okoshi 0:a21b8a29df03 165 socket_threads.push_back(m);
Hiroaki_Okoshi 0:a21b8a29df03 166 }
Hiroaki_Okoshi 0:a21b8a29df03 167 else {
Hiroaki_Okoshi 0:a21b8a29df03 168 delete clt_sock;
Hiroaki_Okoshi 0:a21b8a29df03 169 }
Hiroaki_Okoshi 0:a21b8a29df03 170
Hiroaki_Okoshi 0:a21b8a29df03 171 for (size_t ix = 0; ix < socket_threads.size(); ix++) {
Hiroaki_Okoshi 0:a21b8a29df03 172 if (socket_threads[ix]->thread->get_state() == Thread::Deleted) {
Hiroaki_Okoshi 0:a21b8a29df03 173 socket_threads[ix]->thread->terminate();
Hiroaki_Okoshi 0:a21b8a29df03 174 delete socket_threads[ix]->thread;
Hiroaki_Okoshi 0:a21b8a29df03 175 delete socket_threads[ix]->socket; // does this work on esp8266?
Hiroaki_Okoshi 0:a21b8a29df03 176 socket_threads.erase(socket_threads.begin() + ix); // what if there are two?
Hiroaki_Okoshi 0:a21b8a29df03 177 }
Hiroaki_Okoshi 0:a21b8a29df03 178 }
Hiroaki_Okoshi 0:a21b8a29df03 179
Hiroaki_Okoshi 0:a21b8a29df03 180 }
Hiroaki_Okoshi 0:a21b8a29df03 181 }
Hiroaki_Okoshi 0:a21b8a29df03 182
Hiroaki_Okoshi 0:a21b8a29df03 183 typedef struct {
Hiroaki_Okoshi 0:a21b8a29df03 184 TCPSocket* socket;
Hiroaki_Okoshi 0:a21b8a29df03 185 Thread* thread;
Hiroaki_Okoshi 0:a21b8a29df03 186 } socket_thread_metadata_t;
Hiroaki_Okoshi 0:a21b8a29df03 187
Hiroaki_Okoshi 0:a21b8a29df03 188 TCPServer* server;
Hiroaki_Okoshi 0:a21b8a29df03 189 NetworkInterface* _network;
Hiroaki_Okoshi 0:a21b8a29df03 190 Thread main_thread;
Hiroaki_Okoshi 0:a21b8a29df03 191 vector<TCPSocket*> sockets;
Hiroaki_Okoshi 0:a21b8a29df03 192 vector<socket_thread_metadata_t*> socket_threads;
Hiroaki_Okoshi 0:a21b8a29df03 193 Callback<void(ParsedHttpRequest* request, TCPSocket* socket)> handler;
Hiroaki_Okoshi 0:a21b8a29df03 194 };
Hiroaki_Okoshi 0:a21b8a29df03 195
Hiroaki_Okoshi 0:a21b8a29df03 196 #endif // _HTTP_SERVER