http

Committer:
reeml3
Date:
Mon Apr 15 18:12:24 2019 +0000
Revision:
1:ce6ccd14af4c
Parent:
0:a49e37a83a7a
http

Who changed what in which revision?

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