A Port of TI's Webserver for the CC3000

Dependencies:   mbed

Committer:
dflet
Date:
Mon Sep 16 18:37:14 2013 +0000
Revision:
2:e6a185df9e4c
Parent:
0:6ad60d78b315
ADC and Leds now work on board and config.html page.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
dflet 0:6ad60d78b315 1 /*****************************************************************************
dflet 0:6ad60d78b315 2 *
dflet 0:6ad60d78b315 3 * HttpCore.c
dflet 0:6ad60d78b315 4 * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/
dflet 0:6ad60d78b315 5 *
dflet 0:6ad60d78b315 6 * Redistribution and use in source and binary forms, with or without
dflet 0:6ad60d78b315 7 * modification, are permitted provided that the following conditions
dflet 0:6ad60d78b315 8 * are met:
dflet 0:6ad60d78b315 9 *
dflet 0:6ad60d78b315 10 * Redistributions of source code must retain the above copyright
dflet 0:6ad60d78b315 11 * notice, this list of conditions and the following disclaimer.
dflet 0:6ad60d78b315 12 *
dflet 0:6ad60d78b315 13 * Redistributions in binary form must reproduce the above copyright
dflet 0:6ad60d78b315 14 * notice, this list of conditions and the following disclaimer in the
dflet 0:6ad60d78b315 15 * documentation and/or other materials provided with the
dflet 0:6ad60d78b315 16 * distribution.
dflet 0:6ad60d78b315 17 *
dflet 0:6ad60d78b315 18 * Neither the name of Texas Instruments Incorporated nor the names of
dflet 0:6ad60d78b315 19 * its contributors may be used to endorse or promote products derived
dflet 0:6ad60d78b315 20 * from this software without specific prior written permission.
dflet 0:6ad60d78b315 21 *
dflet 0:6ad60d78b315 22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
dflet 0:6ad60d78b315 23 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
dflet 0:6ad60d78b315 24 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
dflet 0:6ad60d78b315 25 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
dflet 0:6ad60d78b315 26 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
dflet 0:6ad60d78b315 27 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
dflet 0:6ad60d78b315 28 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
dflet 0:6ad60d78b315 29 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
dflet 0:6ad60d78b315 30 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
dflet 0:6ad60d78b315 31 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
dflet 0:6ad60d78b315 32 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
dflet 0:6ad60d78b315 33 *
dflet 0:6ad60d78b315 34 *****************************************************************************/
dflet 0:6ad60d78b315 35 #include "mbed.h"
dflet 0:6ad60d78b315 36 #include "Common.h"
dflet 0:6ad60d78b315 37 #include "HttpHeaders.h"
dflet 0:6ad60d78b315 38 #include "HttpCore.h"
dflet 0:6ad60d78b315 39 #include "HttpResponse.h"
dflet 0:6ad60d78b315 40 #include "HttpRequest.h"
dflet 0:6ad60d78b315 41 #include "HttpAuth.h"
dflet 0:6ad60d78b315 42 #include "HttpDebug.h"
dflet 0:6ad60d78b315 43 #include "HttpDynamic.h"
dflet 0:6ad60d78b315 44 #include "HttpStatic.h"
dflet 0:6ad60d78b315 45 #include <string.h>
dflet 0:6ad60d78b315 46 #include "HttpConfig.h"
dflet 0:6ad60d78b315 47
dflet 0:6ad60d78b315 48 // Include CC3000 bridged networking stack headers
dflet 0:6ad60d78b315 49 #include "cc3000_common.h"
dflet 0:6ad60d78b315 50 #include "socket.h"
dflet 0:6ad60d78b315 51 #include "netapp.h"
dflet 0:6ad60d78b315 52 #include "FlashDB.h"
dflet 0:6ad60d78b315 53
dflet 0:6ad60d78b315 54 /**
dflet 0:6ad60d78b315 55 * @addtogroup HttpCore
dflet 0:6ad60d78b315 56 * @{
dflet 0:6ad60d78b315 57 */
dflet 0:6ad60d78b315 58
dflet 0:6ad60d78b315 59
dflet 0:6ad60d78b315 60 /**
dflet 0:6ad60d78b315 61 * This enumeration defines all possible states for a connection
dflet 0:6ad60d78b315 62 */
dflet 0:6ad60d78b315 63 enum HttpConnectionState
dflet 0:6ad60d78b315 64 {
dflet 0:6ad60d78b315 65 /// Connection is inactive. The connection's socket should be INVALID_SOCKET_HANDLE
dflet 0:6ad60d78b315 66 Inactive,
dflet 0:6ad60d78b315 67 /// Waiting for packet(s) with the request method
dflet 0:6ad60d78b315 68 RequestMethod,
dflet 0:6ad60d78b315 69 /// Waiting for packet(s) with request headers
dflet 0:6ad60d78b315 70 RequestHeaders,
dflet 0:6ad60d78b315 71 /// Currently receiving a header which is too long - Drop it and continue waiting for more headers
dflet 0:6ad60d78b315 72 DropCurrentHeader,
dflet 0:6ad60d78b315 73 /// Done parsing headers, waiting for POST data pakcets
dflet 0:6ad60d78b315 74 RequestData,
dflet 0:6ad60d78b315 75 /// Request is at the hands of the content module (static and/or dynamic), waiting for response headers.
dflet 0:6ad60d78b315 76 Processing,
dflet 0:6ad60d78b315 77 /// Response headers have been sent. Sending response content.
dflet 0:6ad60d78b315 78 ResponseData,
dflet 0:6ad60d78b315 79 /// Response complete. Possibility of another request.
dflet 0:6ad60d78b315 80 ResponseComplete
dflet 0:6ad60d78b315 81 };
dflet 0:6ad60d78b315 82
dflet 0:6ad60d78b315 83 /**
dflet 0:6ad60d78b315 84 * This enumeration defines all possible request-handler modules
dflet 0:6ad60d78b315 85 */
dflet 0:6ad60d78b315 86 enum HttpHandler
dflet 0:6ad60d78b315 87 {
dflet 0:6ad60d78b315 88 /// No module is going to process this request (use the default 404 error)
dflet 0:6ad60d78b315 89 None,
dflet 0:6ad60d78b315 90 /// The HttpStatic module is going to process this request
dflet 0:6ad60d78b315 91 HttpStatic,
dflet 0:6ad60d78b315 92 /// The HttpDynamic module is going to process this request
dflet 0:6ad60d78b315 93 HttpDynamic
dflet 0:6ad60d78b315 94 };
dflet 0:6ad60d78b315 95
dflet 0:6ad60d78b315 96 /**
dflet 0:6ad60d78b315 97 * This structure holds all information for an HTTP connection
dflet 0:6ad60d78b315 98 */
dflet 0:6ad60d78b315 99 //#ifdef __CCS__
dflet 0:6ad60d78b315 100 //struct __attribute__ ((__packed__)) HttpConnectionData
dflet 0:6ad60d78b315 101 //#elif __IAR_SYSTEMS_ICC__
dflet 0:6ad60d78b315 102 //#pragma pack(1)
dflet 0:6ad60d78b315 103 struct HttpConnectionData
dflet 0:6ad60d78b315 104 //#endif
dflet 0:6ad60d78b315 105 {
dflet 0:6ad60d78b315 106 /// The state of this connection
dflet 0:6ad60d78b315 107 enum HttpConnectionState connectionState;
dflet 0:6ad60d78b315 108 /// The data socket for this connection. Should be INVALID_SOCKET_HANDLE when in Inactive state
dflet 0:6ad60d78b315 109 SOCKET dataSocket;
dflet 0:6ad60d78b315 110 /// The current HTTP request on this connection
dflet 0:6ad60d78b315 111 struct HttpRequest request;
dflet 0:6ad60d78b315 112 /// Which handler is going to process the current request
dflet 0:6ad60d78b315 113 enum HttpHandler handler;
dflet 0:6ad60d78b315 114 /// An un-parsed chunk of header line
dflet 0:6ad60d78b315 115 uint8 headerStart[HTTP_CORE_MAX_HEADER_LINE_LENGTH];
dflet 0:6ad60d78b315 116 /// Amount of content left to be read in the request or sent in the response
dflet 0:6ad60d78b315 117 uint32 uContentLeft;
dflet 0:6ad60d78b315 118 /// If the headers will arrive in several packets the content will be buffered in the headers start buffer until a whole line is available
dflet 0:6ad60d78b315 119 uint16 uSavedBufferSize;
dflet 0:6ad60d78b315 120 /// Check weather the authentication is done or not
dflet 0:6ad60d78b315 121 uint8 HttpAuth;
dflet 0:6ad60d78b315 122 };
dflet 0:6ad60d78b315 123
dflet 0:6ad60d78b315 124 /**
dflet 0:6ad60d78b315 125 * This structure holds all of the global state of the HTTP server
dflet 0:6ad60d78b315 126 */
dflet 0:6ad60d78b315 127 //#ifdef __CCS__
dflet 0:6ad60d78b315 128 //struct __attribute__ ((__packed__)) HttpGlobalState
dflet 0:6ad60d78b315 129 //#elif __IAR_SYSTEMS_ICC__
dflet 0:6ad60d78b315 130 //#pragma pack(1)
dflet 0:6ad60d78b315 131 struct HttpGlobalState
dflet 0:6ad60d78b315 132 //#endif
dflet 0:6ad60d78b315 133 {
dflet 0:6ad60d78b315 134 /// The listening socket
dflet 0:6ad60d78b315 135 SOCKET listenSocket;
dflet 0:6ad60d78b315 136 /// Number of active connections
dflet 0:6ad60d78b315 137 uint16 uOpenConnections;
dflet 0:6ad60d78b315 138 /// All possible connections
dflet 0:6ad60d78b315 139 struct HttpConnectionData connections[HTTP_CORE_MAX_CONNECTIONS];
dflet 0:6ad60d78b315 140 /// The packet-receive buffer
dflet 0:6ad60d78b315 141 uint8 packetRecv[HTTP_CORE_MAX_PACKET_SIZE_RECEIVED];
dflet 0:6ad60d78b315 142 /// Size of data in the packet-receive buffer
dflet 0:6ad60d78b315 143 int packetRecvSize;
dflet 0:6ad60d78b315 144 /// The packet-send buffer
dflet 0:6ad60d78b315 145 uint8 packetSend[HTTP_CORE_MAX_PACKET_SIZE_SEND];
dflet 0:6ad60d78b315 146 /// Size of data in the packet-send buffer
dflet 0:6ad60d78b315 147 uint16 packetSendSize;
dflet 0:6ad60d78b315 148 };
dflet 0:6ad60d78b315 149
dflet 0:6ad60d78b315 150 /// The global state of the HTTP server
dflet 0:6ad60d78b315 151 __no_init struct HttpGlobalState g_state;
dflet 0:6ad60d78b315 152
dflet 0:6ad60d78b315 153 // Forward declarations for static functions
dflet 0:6ad60d78b315 154 static void HttpCore_InitWebServer();
dflet 0:6ad60d78b315 155 static void HttpCore_CloseConnection(uint16 uConnection);
dflet 0:6ad60d78b315 156 static int HttpCore_HandleRequestPacket(uint16 uConnection, struct HttpBlob packet);
dflet 0:6ad60d78b315 157 static int HttpCore_HandleMethodLine(uint16 uConnection, struct HttpBlob line);
dflet 0:6ad60d78b315 158 static int HttpCore_HandleHeaderLine(uint16 uConnection, struct HttpBlob line);
dflet 0:6ad60d78b315 159 static int HttpCore_HandleRequestData(uint16 uConnection, struct HttpBlob* pData);
dflet 0:6ad60d78b315 160 static void HttpCore_ProcessNotFound(uint16 uConnection);
dflet 0:6ad60d78b315 161
dflet 0:6ad60d78b315 162 struct HttpBlob nullBlob = {NULL, 0};
dflet 0:6ad60d78b315 163
dflet 0:6ad60d78b315 164 extern volatile char runSmartConfig;
dflet 0:6ad60d78b315 165 extern char DevServname[];
dflet 0:6ad60d78b315 166 extern unsigned char mDNSSend;
dflet 0:6ad60d78b315 167 extern char CheckSocket;
dflet 0:6ad60d78b315 168 extern signed char sd[];
dflet 0:6ad60d78b315 169
dflet 0:6ad60d78b315 170 #define MAX_SENT_DATA 912
dflet 0:6ad60d78b315 171
dflet 0:6ad60d78b315 172 /**
dflet 0:6ad60d78b315 173 * Detect all error conditions from a sockets API return value, such as accpet()
dflet 0:6ad60d78b315 174 * Note: This is different in Windows and CC3000
dflet 0:6ad60d78b315 175 * Returns nonzero if valid socket, or zero if invalid socket
dflet 0:6ad60d78b315 176 */
dflet 0:6ad60d78b315 177 static int HttpIsValidSocket(SOCKET sock)
dflet 0:6ad60d78b315 178 {
dflet 0:6ad60d78b315 179 #if (defined(WIN32) && !defined(HTTP_WEB_SERVER_ON_BRIDGE))
dflet 0:6ad60d78b315 180 // The CC3000 API returns an int, and might return CC3000_INVALID_SOCKET
dflet 0:6ad60d78b315 181 if ((sock == INVALID_SOCKET) ||
dflet 0:6ad60d78b315 182 (sock == CC3000_INVALID_SOCKET))
dflet 0:6ad60d78b315 183 return 0;
dflet 0:6ad60d78b315 184 #else
dflet 0:6ad60d78b315 185 if (sock < 0)
dflet 0:6ad60d78b315 186 return 0;
dflet 0:6ad60d78b315 187 #endif
dflet 0:6ad60d78b315 188 return 1;
dflet 0:6ad60d78b315 189 }
dflet 0:6ad60d78b315 190
dflet 0:6ad60d78b315 191 void HttpCloseServer()
dflet 0:6ad60d78b315 192 {
dflet 0:6ad60d78b315 193 closesocket(g_state.listenSocket);
dflet 0:6ad60d78b315 194 }
dflet 0:6ad60d78b315 195
dflet 0:6ad60d78b315 196 void HttpServerInitAndRun()
dflet 0:6ad60d78b315 197 {
dflet 0:6ad60d78b315 198 uint16 uConnection;
dflet 0:6ad60d78b315 199 sockaddr_in addr;
dflet 0:6ad60d78b315 200 sockaddr_in clientAddr;
dflet 0:6ad60d78b315 201 socklen_t addrLen = sizeof(clientAddr);
dflet 0:6ad60d78b315 202 struct HttpBlob blob;
dflet 0:6ad60d78b315 203 fd_set readsds, errorsds;
dflet 0:6ad60d78b315 204 int ret = 0;
dflet 0:6ad60d78b315 205 SOCKET maxFD;
dflet 0:6ad60d78b315 206 timeval timeout;
dflet 0:6ad60d78b315 207 signed char curSocket;
dflet 0:6ad60d78b315 208 int optval, optlen;
dflet 0:6ad60d78b315 209
dflet 0:6ad60d78b315 210 memset(&timeout, 0, sizeof(timeval));
dflet 0:6ad60d78b315 211 timeout.tv_sec = 1;
dflet 0:6ad60d78b315 212 timeout.tv_usec = 0;
dflet 0:6ad60d78b315 213
dflet 0:6ad60d78b315 214 // Initialize the server's global state
dflet 0:6ad60d78b315 215 HttpCore_InitWebServer();
dflet 0:6ad60d78b315 216
dflet 0:6ad60d78b315 217 // Create the listener socket for HTTP Server.
dflet 0:6ad60d78b315 218 g_state.listenSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
dflet 0:6ad60d78b315 219 if(g_state.listenSocket == INVALID_SOCKET)
dflet 0:6ad60d78b315 220 {
dflet 0:6ad60d78b315 221 HttpDebug("Failed to create listen socket");
dflet 0:6ad60d78b315 222 printf("Failed to create listen socket\r\n");
dflet 0:6ad60d78b315 223 return;
dflet 0:6ad60d78b315 224 }
dflet 0:6ad60d78b315 225
dflet 0:6ad60d78b315 226 memset(&addr, 0, sizeof(addr));
dflet 0:6ad60d78b315 227 #ifdef _WINSOCKAPI_
dflet 0:6ad60d78b315 228 addr.sin_family = AF_INET;
dflet 0:6ad60d78b315 229 #else
dflet 0:6ad60d78b315 230 addr.sin_family = htons(AF_INET);
dflet 0:6ad60d78b315 231 #endif
dflet 0:6ad60d78b315 232 addr.sin_port = htons(HTTP_CORE_SERVER_PORT);
dflet 0:6ad60d78b315 233 if (bind(g_state.listenSocket, (const sockaddr*)&addr, sizeof(addr)) != 0)
dflet 0:6ad60d78b315 234 {
dflet 0:6ad60d78b315 235 HttpDebug("bind() fail");
dflet 0:6ad60d78b315 236 printf("bind() fail\r\n");
dflet 0:6ad60d78b315 237 return;
dflet 0:6ad60d78b315 238 }
dflet 0:6ad60d78b315 239 if (listen(g_state.listenSocket, 10) != 0)
dflet 0:6ad60d78b315 240 {
dflet 0:6ad60d78b315 241 HttpDebug("listen() fail");
dflet 0:6ad60d78b315 242 printf("listen() fail\r\n");
dflet 0:6ad60d78b315 243 return;
dflet 0:6ad60d78b315 244 }
dflet 0:6ad60d78b315 245
dflet 0:6ad60d78b315 246 #ifdef HTTP_CORE_ENABLE_AUTH
dflet 0:6ad60d78b315 247 struct HttpBlob user,pass;
dflet 0:6ad60d78b315 248 user.pData = (uint8*)"cc3000";
dflet 0:6ad60d78b315 249 user.uLength= 6;
dflet 0:6ad60d78b315 250 pass.pData = (uint8*)"admin";
dflet 0:6ad60d78b315 251 pass.uLength = 5;
dflet 0:6ad60d78b315 252 int count;
dflet 0:6ad60d78b315 253
dflet 0:6ad60d78b315 254 HttpAuth_Init(user, pass);
dflet 0:6ad60d78b315 255 #endif
dflet 0:6ad60d78b315 256
dflet 0:6ad60d78b315 257 g_state.uOpenConnections = 0;
dflet 0:6ad60d78b315 258
dflet 0:6ad60d78b315 259 // Main loop of the server. Note: This is an infinite loop
dflet 0:6ad60d78b315 260 while (1)
dflet 0:6ad60d78b315 261 {
dflet 0:6ad60d78b315 262 //printf("Server Loop...\r\n");
dflet 0:6ad60d78b315 263 // Check if button is pressed for smart config
dflet 0:6ad60d78b315 264 if(runSmartConfig == 1)
dflet 0:6ad60d78b315 265 {
dflet 0:6ad60d78b315 266 // Button is pressed for smart config. Close all active connections
dflet 0:6ad60d78b315 267 for(uConnection = 0; uConnection < HTTP_CORE_MAX_CONNECTIONS; ++uConnection)
dflet 0:6ad60d78b315 268 {
dflet 0:6ad60d78b315 269 if (g_state.connections[uConnection].connectionState != Inactive)
dflet 0:6ad60d78b315 270 {
dflet 0:6ad60d78b315 271 HttpCore_CloseConnection(uConnection);
dflet 0:6ad60d78b315 272 }
dflet 0:6ad60d78b315 273 }
dflet 0:6ad60d78b315 274
dflet 0:6ad60d78b315 275 // Close listening socket
dflet 0:6ad60d78b315 276 HttpCloseServer();
dflet 0:6ad60d78b315 277 break;
dflet 0:6ad60d78b315 278 }
dflet 0:6ad60d78b315 279 if( mDNSSend ==1)
dflet 0:6ad60d78b315 280 {
dflet 0:6ad60d78b315 281 mdnsAdvertiser(1,DevServname, strlen(DevServname));
dflet 0:6ad60d78b315 282 mDNSSend =0;
dflet 0:6ad60d78b315 283 }
dflet 0:6ad60d78b315 284
dflet 0:6ad60d78b315 285 // Client socket is closed, close socket
dflet 0:6ad60d78b315 286 if(CheckSocket == 1)
dflet 0:6ad60d78b315 287 {
dflet 0:6ad60d78b315 288 for(count = 0; count<9 ; count++)
dflet 0:6ad60d78b315 289 {
dflet 0:6ad60d78b315 290 if(sd[count] == 1)
dflet 0:6ad60d78b315 291 {
dflet 0:6ad60d78b315 292 HttpCore_CloseConnection(count);
dflet 0:6ad60d78b315 293 sd[count] = 0;
dflet 0:6ad60d78b315 294 }
dflet 0:6ad60d78b315 295 }
dflet 0:6ad60d78b315 296 for(uConnection = 0; uConnection < HTTP_CORE_MAX_CONNECTIONS; ++uConnection)
dflet 0:6ad60d78b315 297 {
dflet 0:6ad60d78b315 298 if (g_state.connections[uConnection].connectionState != Inactive)
dflet 0:6ad60d78b315 299 {
dflet 0:6ad60d78b315 300 // Check for socket timeouts
dflet 0:6ad60d78b315 301 curSocket = getsockopt(g_state.connections[uConnection].dataSocket, SOL_SOCKET, SOCKOPT_RECV_NONBLOCK , &optval, (socklen_t*)&optlen);
dflet 0:6ad60d78b315 302 if (curSocket == -57)
dflet 0:6ad60d78b315 303 {
dflet 0:6ad60d78b315 304 HttpCore_CloseConnection(uConnection);
dflet 0:6ad60d78b315 305 }
dflet 0:6ad60d78b315 306 }
dflet 0:6ad60d78b315 307 }
dflet 0:6ad60d78b315 308 CheckSocket = 0;
dflet 0:6ad60d78b315 309 }
dflet 0:6ad60d78b315 310
dflet 0:6ad60d78b315 311 SOCKET newsock;
dflet 0:6ad60d78b315 312
dflet 0:6ad60d78b315 313 newsock = accept(g_state.listenSocket, (sockaddr*)&clientAddr, &addrLen);
dflet 0:6ad60d78b315 314
dflet 0:6ad60d78b315 315 // If new connection is returned - initialize the new connection object
dflet 0:6ad60d78b315 316 if (HttpIsValidSocket(newsock))
dflet 0:6ad60d78b315 317 {
dflet 0:6ad60d78b315 318 if (g_state.uOpenConnections >= HTTP_CORE_MAX_CONNECTIONS)
dflet 0:6ad60d78b315 319 {
dflet 0:6ad60d78b315 320 //check if sockets are are available
dflet 0:6ad60d78b315 321 for(uConnection = 0; uConnection < HTTP_CORE_MAX_CONNECTIONS; ++uConnection)
dflet 0:6ad60d78b315 322 {
dflet 0:6ad60d78b315 323 if (g_state.connections[uConnection].connectionState != Inactive)
dflet 0:6ad60d78b315 324 {
dflet 0:6ad60d78b315 325 //Check for Socket Timeout
dflet 0:6ad60d78b315 326 curSocket = getsockopt(g_state.connections[uConnection].dataSocket, SOL_SOCKET, SOCKOPT_RECV_NONBLOCK , &optval, (socklen_t*)&optlen);
dflet 0:6ad60d78b315 327 if (curSocket == -57)
dflet 0:6ad60d78b315 328 {
dflet 0:6ad60d78b315 329 HttpCore_CloseConnection(uConnection);
dflet 0:6ad60d78b315 330 }
dflet 0:6ad60d78b315 331 }
dflet 0:6ad60d78b315 332 }
dflet 0:6ad60d78b315 333 }
dflet 0:6ad60d78b315 334
dflet 0:6ad60d78b315 335 if(g_state.uOpenConnections < HTTP_CORE_MAX_CONNECTIONS)
dflet 0:6ad60d78b315 336 {
dflet 0:6ad60d78b315 337 for (uConnection = 0; uConnection < HTTP_CORE_MAX_CONNECTIONS; ++uConnection)
dflet 0:6ad60d78b315 338 if (g_state.connections[uConnection].connectionState == Inactive)
dflet 0:6ad60d78b315 339 break;
dflet 0:6ad60d78b315 340
dflet 0:6ad60d78b315 341 g_state.connections[uConnection].dataSocket = newsock;
dflet 0:6ad60d78b315 342 g_state.uOpenConnections++;
dflet 0:6ad60d78b315 343 g_state.connections[uConnection].connectionState = RequestMethod;
dflet 0:6ad60d78b315 344 HttpDebug("Accepting new connection number %d", uConnection);
dflet 0:6ad60d78b315 345 printf("Accepting new connection number %i\r\n", uConnection);
dflet 0:6ad60d78b315 346 }
dflet 0:6ad60d78b315 347 }
dflet 0:6ad60d78b315 348
dflet 0:6ad60d78b315 349
dflet 0:6ad60d78b315 350
dflet 0:6ad60d78b315 351
dflet 0:6ad60d78b315 352 // Nothing more to do if no open connections
dflet 0:6ad60d78b315 353 if (g_state.uOpenConnections == 0)
dflet 0:6ad60d78b315 354 continue;
dflet 0:6ad60d78b315 355
dflet 0:6ad60d78b315 356 // Receive data on all open connections, and handle the new data
dflet 0:6ad60d78b315 357 maxFD = (SOCKET)-1;
dflet 0:6ad60d78b315 358 // Select only the active connections
dflet 0:6ad60d78b315 359 FD_ZERO(&readsds);
dflet 0:6ad60d78b315 360 FD_ZERO(&errorsds);
dflet 0:6ad60d78b315 361 for (uConnection = 0; uConnection < HTTP_CORE_MAX_CONNECTIONS; ++uConnection)
dflet 0:6ad60d78b315 362 {
dflet 0:6ad60d78b315 363 // if connection is open and in one of the receiving states, then add this socket to the set
dflet 0:6ad60d78b315 364 if (g_state.connections[uConnection].connectionState == RequestMethod ||
dflet 0:6ad60d78b315 365 g_state.connections[uConnection].connectionState == RequestHeaders ||
dflet 0:6ad60d78b315 366 g_state.connections[uConnection].connectionState == RequestData ||
dflet 0:6ad60d78b315 367 g_state.connections[uConnection].connectionState == DropCurrentHeader)
dflet 0:6ad60d78b315 368 {
dflet 0:6ad60d78b315 369 FD_SET(g_state.connections[uConnection].dataSocket, &readsds);
dflet 0:6ad60d78b315 370 FD_SET(g_state.connections[uConnection].dataSocket, &errorsds);
dflet 0:6ad60d78b315 371 // Calculate the maximum socket number
dflet 0:6ad60d78b315 372 if (maxFD <= g_state.connections[uConnection].dataSocket)
dflet 0:6ad60d78b315 373 maxFD = g_state.connections[uConnection].dataSocket + 1;
dflet 0:6ad60d78b315 374 }
dflet 0:6ad60d78b315 375 }
dflet 0:6ad60d78b315 376
dflet 0:6ad60d78b315 377 ret = select(maxFD, &readsds, NULL, &errorsds, &timeout);
dflet 0:6ad60d78b315 378
dflet 0:6ad60d78b315 379 // Nothing more to do if no packet received
dflet 0:6ad60d78b315 380 if (ret == 0)
dflet 0:6ad60d78b315 381 {
dflet 0:6ad60d78b315 382 continue;
dflet 0:6ad60d78b315 383 }
dflet 0:6ad60d78b315 384
dflet 0:6ad60d78b315 385 for (uConnection = 0; uConnection < HTTP_CORE_MAX_CONNECTIONS; ++uConnection)
dflet 0:6ad60d78b315 386 {
dflet 0:6ad60d78b315 387 // Skip inactive connections
dflet 0:6ad60d78b315 388 if (g_state.connections[uConnection].connectionState == Inactive)
dflet 0:6ad60d78b315 389 continue;
dflet 0:6ad60d78b315 390
dflet 0:6ad60d78b315 391 // Close connections that were select()ed for error
dflet 0:6ad60d78b315 392 if (FD_ISSET(g_state.connections[uConnection].dataSocket, &errorsds))
dflet 0:6ad60d78b315 393 {
dflet 0:6ad60d78b315 394 HttpCore_CloseConnection(uConnection);
dflet 0:6ad60d78b315 395 continue;
dflet 0:6ad60d78b315 396 }
dflet 0:6ad60d78b315 397
dflet 0:6ad60d78b315 398 // Skip connections that were not select()ed for reading
dflet 0:6ad60d78b315 399 if (!FD_ISSET(g_state.connections[uConnection].dataSocket, &readsds))
dflet 0:6ad60d78b315 400 continue;
dflet 0:6ad60d78b315 401
dflet 0:6ad60d78b315 402 // This connection has data that can be received now
dflet 0:6ad60d78b315 403
dflet 0:6ad60d78b315 404 // Receive the data into the global packet-receive buffer
dflet 0:6ad60d78b315 405 memset(g_state.packetRecv, 0, HTTP_CORE_MAX_PACKET_SIZE_RECEIVED);
dflet 0:6ad60d78b315 406 g_state.packetRecvSize = recv(g_state.connections[uConnection].dataSocket, (char *)(g_state.packetRecv), HTTP_CORE_MAX_PACKET_SIZE_RECEIVED, 0);
dflet 0:6ad60d78b315 407
dflet 0:6ad60d78b315 408 // Detect and handle errors
dflet 0:6ad60d78b315 409 if (g_state.packetRecvSize <= 0)
dflet 0:6ad60d78b315 410 {
dflet 0:6ad60d78b315 411 HttpDebug("HTTP Connection recv error. connection=%d, error = %d", uConnection, g_state.packetRecvSize);
dflet 0:6ad60d78b315 412 printf("HTTP Connection recv error. connection=%i, error = %i\r\n", uConnection, g_state.packetRecvSize);
dflet 0:6ad60d78b315 413 HttpCore_CloseConnection(uConnection);
dflet 0:6ad60d78b315 414 continue;
dflet 0:6ad60d78b315 415 }
dflet 0:6ad60d78b315 416
dflet 0:6ad60d78b315 417 blob.uLength = (uint16)g_state.packetRecvSize;
dflet 0:6ad60d78b315 418 blob.pData = g_state.packetRecv;
dflet 0:6ad60d78b315 419 if (!HttpCore_HandleRequestPacket(uConnection, blob))
dflet 0:6ad60d78b315 420 HttpCore_CloseConnection(uConnection);
dflet 0:6ad60d78b315 421 }
dflet 0:6ad60d78b315 422 }
dflet 0:6ad60d78b315 423 }
dflet 0:6ad60d78b315 424
dflet 0:6ad60d78b315 425 /**
dflet 0:6ad60d78b315 426 * Reset open connection after finishing HTPP transaction
dflet 0:6ad60d78b315 427 */
dflet 0:6ad60d78b315 428 static void HttpCore_ResetConnection(uint16 uConnection)
dflet 0:6ad60d78b315 429 {
dflet 0:6ad60d78b315 430 g_state.connections[uConnection].uContentLeft = 0;
dflet 0:6ad60d78b315 431 g_state.connections[uConnection].uSavedBufferSize = 0;
dflet 0:6ad60d78b315 432 g_state.connections[uConnection].handler = None;
dflet 0:6ad60d78b315 433 g_state.connections[uConnection].request.requestContent.pData = NULL;
dflet 0:6ad60d78b315 434 g_state.connections[uConnection].request.requestContent.uLength = 0;
dflet 0:6ad60d78b315 435 g_state.connections[uConnection].request.uFlags = 0;
dflet 0:6ad60d78b315 436 }
dflet 0:6ad60d78b315 437
dflet 0:6ad60d78b315 438 /**
dflet 0:6ad60d78b315 439 * Initialize the server's global state structure
dflet 0:6ad60d78b315 440 */
dflet 0:6ad60d78b315 441 static void HttpCore_InitWebServer()
dflet 0:6ad60d78b315 442 {
dflet 0:6ad60d78b315 443 uint16 uConnection;
dflet 0:6ad60d78b315 444 g_state.packetRecvSize = 0;
dflet 0:6ad60d78b315 445 g_state.packetSendSize = 0;
dflet 0:6ad60d78b315 446 g_state.uOpenConnections = 0;
dflet 0:6ad60d78b315 447 g_state.listenSocket = INVALID_SOCKET;
dflet 0:6ad60d78b315 448
dflet 0:6ad60d78b315 449 for (uConnection = 0; uConnection < HTTP_CORE_MAX_CONNECTIONS; ++uConnection)
dflet 0:6ad60d78b315 450 {
dflet 0:6ad60d78b315 451 g_state.connections[uConnection].connectionState = Inactive;
dflet 0:6ad60d78b315 452 g_state.connections[uConnection].dataSocket = INVALID_SOCKET;
dflet 0:6ad60d78b315 453 g_state.connections[uConnection].request.uConnection = uConnection;
dflet 0:6ad60d78b315 454 g_state.connections[uConnection].HttpAuth = 0;
dflet 0:6ad60d78b315 455 HttpCore_ResetConnection(uConnection);
dflet 0:6ad60d78b315 456 }
dflet 0:6ad60d78b315 457
dflet 0:6ad60d78b315 458 FlashDB_Init();
dflet 0:6ad60d78b315 459 }
dflet 0:6ad60d78b315 460
dflet 0:6ad60d78b315 461
dflet 0:6ad60d78b315 462 /**
dflet 0:6ad60d78b315 463 * Close a connection and clean up its state
dflet 0:6ad60d78b315 464 */
dflet 0:6ad60d78b315 465 static void HttpCore_CloseConnection(uint16 uConnection)
dflet 0:6ad60d78b315 466 {
dflet 0:6ad60d78b315 467 HttpDebug("Close connection");
dflet 0:6ad60d78b315 468 printf("Close connection\r\n");
dflet 0:6ad60d78b315 469
dflet 0:6ad60d78b315 470 closesocket(g_state.connections[uConnection].dataSocket);
dflet 0:6ad60d78b315 471
dflet 0:6ad60d78b315 472 g_state.connections[uConnection].connectionState = Inactive;
dflet 0:6ad60d78b315 473 g_state.connections[uConnection].dataSocket = INVALID_SOCKET;
dflet 0:6ad60d78b315 474 g_state.connections[uConnection].HttpAuth = 0;
dflet 0:6ad60d78b315 475 HttpCore_ResetConnection(uConnection);
dflet 0:6ad60d78b315 476 if(g_state.uOpenConnections > 0)
dflet 0:6ad60d78b315 477 g_state.uOpenConnections--;
dflet 0:6ad60d78b315 478 }
dflet 0:6ad60d78b315 479
dflet 0:6ad60d78b315 480 /**
dflet 0:6ad60d78b315 481 * Getting the next line in the HTTP headers section
dflet 0:6ad60d78b315 482 * This function is called to get the header lines one by one until an empty line is encountered which means the end of the header section
dflet 0:6ad60d78b315 483 * The input is the connection and the remaining blob of the received packet
dflet 0:6ad60d78b315 484 *
dflet 0:6ad60d78b315 485 * @return zero if the whole packet was handled, and need to wait for more data (pLine is not set to anything yet)
dflet 0:6ad60d78b315 486 * negative if some error occurred, and the connection should be closed.
dflet 0:6ad60d78b315 487 * positive if successful. In this case pCurrentLocation is advanced to skip the line and pLine returns the next line, or NULL and 0 if it should be discarded
dflet 0:6ad60d78b315 488 */
dflet 0:6ad60d78b315 489 static int HttpCore_GetNextLine(uint16 uConnection, struct HttpBlob* pCurrentLocation, struct HttpBlob* pLine)
dflet 0:6ad60d78b315 490 {
dflet 0:6ad60d78b315 491 uint16 uLength;
dflet 0:6ad60d78b315 492 uint8* nextLocation;
dflet 0:6ad60d78b315 493 // Keep a pointer to the connection state object
dflet 0:6ad60d78b315 494 struct HttpConnectionData* pConnection = &g_state.connections[uConnection];
dflet 0:6ad60d78b315 495
dflet 0:6ad60d78b315 496 // search for the line delimiter in the received data
dflet 0:6ad60d78b315 497 nextLocation = HttpString_nextToken(HTTP_HEADER_DELIMITER, sizeof(HTTP_HEADER_DELIMITER)-1, *pCurrentLocation);
dflet 0:6ad60d78b315 498 uLength = (uint16)(nextLocation - pCurrentLocation->pData);
dflet 0:6ad60d78b315 499
dflet 0:6ad60d78b315 500 if (pConnection->uSavedBufferSize > 0)
dflet 0:6ad60d78b315 501 {
dflet 0:6ad60d78b315 502 // There is previous saved data for this line, so need to concatenate
dflet 0:6ad60d78b315 503 if ((pConnection->headerStart[pConnection->uSavedBufferSize - 1] == '\r') && (pCurrentLocation->pData[0] == '\n'))
dflet 0:6ad60d78b315 504 {
dflet 0:6ad60d78b315 505 // Handle special case where the headers were splitted exactly at the delimiter
dflet 0:6ad60d78b315 506 pConnection->headerStart[pConnection->uSavedBufferSize + 1] = pCurrentLocation->pData[0];
dflet 0:6ad60d78b315 507 pLine->pData = pConnection->headerStart;
dflet 0:6ad60d78b315 508 // Account for the excessive \r in the buffer
dflet 0:6ad60d78b315 509 pLine->uLength = pConnection->uSavedBufferSize - 1;
dflet 0:6ad60d78b315 510 pConnection->uSavedBufferSize = 0;
dflet 0:6ad60d78b315 511 // Advance the current location past this line
dflet 0:6ad60d78b315 512 pCurrentLocation->pData += 1;
dflet 0:6ad60d78b315 513 pCurrentLocation->uLength -= 1;
dflet 0:6ad60d78b315 514 return 1;
dflet 0:6ad60d78b315 515 }
dflet 0:6ad60d78b315 516 else
dflet 0:6ad60d78b315 517 {
dflet 0:6ad60d78b315 518 // There is saved data, and the delimiter is not split between packets
dflet 0:6ad60d78b315 519 if (nextLocation == NULL)
dflet 0:6ad60d78b315 520 {
dflet 0:6ad60d78b315 521 // No line delimiter was found in the current packet
dflet 0:6ad60d78b315 522 if ((pConnection->uSavedBufferSize + pCurrentLocation->uLength) < HTTP_CORE_MAX_HEADER_LINE_LENGTH)
dflet 0:6ad60d78b315 523 {
dflet 0:6ad60d78b315 524 // There is enough space to append remaining header into saved buffer
dflet 0:6ad60d78b315 525 memcpy(pConnection->headerStart + pConnection->uSavedBufferSize, pCurrentLocation->pData, pCurrentLocation->uLength);
dflet 0:6ad60d78b315 526 pConnection->uSavedBufferSize += pCurrentLocation->uLength;
dflet 0:6ad60d78b315 527 return 0;
dflet 0:6ad60d78b315 528 }
dflet 0:6ad60d78b315 529 else
dflet 0:6ad60d78b315 530 // There is not enough space in the saved buffer. This header line will be discarded
dflet 0:6ad60d78b315 531 if (pConnection->connectionState == RequestMethod)
dflet 0:6ad60d78b315 532 {
dflet 0:6ad60d78b315 533 // Connection awaits to receive the the HTTP method line
dflet 0:6ad60d78b315 534 // The method line cannot be discarded, drop the connection
dflet 0:6ad60d78b315 535 return -1;
dflet 0:6ad60d78b315 536 }
dflet 0:6ad60d78b315 537 else
dflet 0:6ad60d78b315 538 {
dflet 0:6ad60d78b315 539 // Connection awaits to receive the next header line which is not the method
dflet 0:6ad60d78b315 540 // Clean saved buffer, and drop this header line
dflet 0:6ad60d78b315 541 pConnection->uSavedBufferSize = 0;
dflet 0:6ad60d78b315 542 pConnection->connectionState = DropCurrentHeader;
dflet 0:6ad60d78b315 543 return 0;
dflet 0:6ad60d78b315 544 }
dflet 0:6ad60d78b315 545 }
dflet 0:6ad60d78b315 546 else
dflet 0:6ad60d78b315 547 {
dflet 0:6ad60d78b315 548 // Header line delimiter was found in the current packet
dflet 0:6ad60d78b315 549 if ((pConnection->uSavedBufferSize + uLength) < HTTP_CORE_MAX_HEADER_LINE_LENGTH)
dflet 0:6ad60d78b315 550 {
dflet 0:6ad60d78b315 551 // This header length is of legal size
dflet 0:6ad60d78b315 552 // Concatenate data from the saved buffer and the current packet
dflet 0:6ad60d78b315 553 memcpy(pConnection->headerStart + pConnection->uSavedBufferSize, pCurrentLocation->pData, uLength);
dflet 0:6ad60d78b315 554 pConnection->uSavedBufferSize += uLength;
dflet 0:6ad60d78b315 555 pLine->pData = pConnection->headerStart;
dflet 0:6ad60d78b315 556 pLine->uLength = pConnection->uSavedBufferSize;
dflet 0:6ad60d78b315 557 pConnection->uSavedBufferSize = 0;
dflet 0:6ad60d78b315 558 }
dflet 0:6ad60d78b315 559 else
dflet 0:6ad60d78b315 560 {
dflet 0:6ad60d78b315 561 // There is not enough space in the saved buffer. This header line will be discarded
dflet 0:6ad60d78b315 562 if (pConnection->connectionState == RequestMethod)
dflet 0:6ad60d78b315 563 {
dflet 0:6ad60d78b315 564 // Connection awaits to receive the the HTTP method line
dflet 0:6ad60d78b315 565 // The method line cannot be discarded, drop the connection
dflet 0:6ad60d78b315 566 return -1;
dflet 0:6ad60d78b315 567 }
dflet 0:6ad60d78b315 568 // Return an epmty line since the header is too long
dflet 0:6ad60d78b315 569 pLine->pData = NULL;
dflet 0:6ad60d78b315 570 pLine->uLength = 0;
dflet 0:6ad60d78b315 571 }
dflet 0:6ad60d78b315 572 // Advance the current location past this line
dflet 0:6ad60d78b315 573 pCurrentLocation->pData += uLength + sizeof(HTTP_HEADER_DELIMITER)-1;
dflet 0:6ad60d78b315 574 pCurrentLocation->uLength -= uLength + sizeof(HTTP_HEADER_DELIMITER)-1;
dflet 0:6ad60d78b315 575 return 1;
dflet 0:6ad60d78b315 576
dflet 0:6ad60d78b315 577 }
dflet 0:6ad60d78b315 578 }
dflet 0:6ad60d78b315 579 }
dflet 0:6ad60d78b315 580 else
dflet 0:6ad60d78b315 581 {
dflet 0:6ad60d78b315 582 // There is no previously saved data for this line
dflet 0:6ad60d78b315 583 if (nextLocation == NULL)
dflet 0:6ad60d78b315 584 {
dflet 0:6ad60d78b315 585 // No line delimiter was found in the current packet
dflet 0:6ad60d78b315 586 if (pCurrentLocation->uLength < HTTP_CORE_MAX_HEADER_LINE_LENGTH)
dflet 0:6ad60d78b315 587 {
dflet 0:6ad60d78b315 588 // There is enough space to append remaining header into saved buffer
dflet 0:6ad60d78b315 589 memcpy(pConnection->headerStart, pCurrentLocation->pData, pCurrentLocation->uLength);
dflet 0:6ad60d78b315 590 pConnection->uSavedBufferSize = pCurrentLocation->uLength;
dflet 0:6ad60d78b315 591 return 0;
dflet 0:6ad60d78b315 592 }
dflet 0:6ad60d78b315 593 else
dflet 0:6ad60d78b315 594 // There is not enough space in the saved buffer
dflet 0:6ad60d78b315 595 // This header line will be discarded
dflet 0:6ad60d78b315 596 if (pConnection->connectionState == RequestMethod)
dflet 0:6ad60d78b315 597 {
dflet 0:6ad60d78b315 598 // Connection awaits to receive the the HTTP method line
dflet 0:6ad60d78b315 599 // The method line cannot be discarded, drop the connection
dflet 0:6ad60d78b315 600 return -1;
dflet 0:6ad60d78b315 601 }
dflet 0:6ad60d78b315 602 else
dflet 0:6ad60d78b315 603 {
dflet 0:6ad60d78b315 604 // Connection awaits to receive the next header line which is not the method
dflet 0:6ad60d78b315 605 // Clean saved buffer, and drop this header line
dflet 0:6ad60d78b315 606 pConnection->uSavedBufferSize = 0;
dflet 0:6ad60d78b315 607 pConnection->connectionState = DropCurrentHeader;
dflet 0:6ad60d78b315 608 return 0;
dflet 0:6ad60d78b315 609 }
dflet 0:6ad60d78b315 610 }
dflet 0:6ad60d78b315 611 else
dflet 0:6ad60d78b315 612 {
dflet 0:6ad60d78b315 613 // Header line delimiter was found in the current packet
dflet 0:6ad60d78b315 614 if (uLength < HTTP_CORE_MAX_HEADER_LINE_LENGTH)
dflet 0:6ad60d78b315 615 {
dflet 0:6ad60d78b315 616 // This header length is of legal size
dflet 0:6ad60d78b315 617 // The whole line is in the packet buffer
dflet 0:6ad60d78b315 618 pLine->pData = pCurrentLocation->pData;
dflet 0:6ad60d78b315 619 pLine->uLength = uLength;
dflet 0:6ad60d78b315 620 }
dflet 0:6ad60d78b315 621 else
dflet 0:6ad60d78b315 622 {
dflet 0:6ad60d78b315 623 // There is not enough space to append remaining header into saved buffer
dflet 0:6ad60d78b315 624 if (pConnection->connectionState == RequestMethod)
dflet 0:6ad60d78b315 625 {
dflet 0:6ad60d78b315 626 // Connection awaits to receive the HTTP method line
dflet 0:6ad60d78b315 627 // The method line cannot be discarded, drop the connection
dflet 0:6ad60d78b315 628 return -1;
dflet 0:6ad60d78b315 629 }
dflet 0:6ad60d78b315 630 // Return an epmty line since the header is too long
dflet 0:6ad60d78b315 631 pLine->pData = NULL;
dflet 0:6ad60d78b315 632 pLine->uLength = 0;
dflet 0:6ad60d78b315 633 pConnection->connectionState = DropCurrentHeader;
dflet 0:6ad60d78b315 634 }
dflet 0:6ad60d78b315 635 // Advance the current location past this line
dflet 0:6ad60d78b315 636 pCurrentLocation->pData += uLength + sizeof(HTTP_HEADER_DELIMITER)-1;
dflet 0:6ad60d78b315 637 pCurrentLocation->uLength -= uLength + sizeof(HTTP_HEADER_DELIMITER)-1;
dflet 0:6ad60d78b315 638 return 1;
dflet 0:6ad60d78b315 639 }
dflet 0:6ad60d78b315 640 }
dflet 0:6ad60d78b315 641 }
dflet 0:6ad60d78b315 642
dflet 0:6ad60d78b315 643
dflet 0:6ad60d78b315 644 /**
dflet 0:6ad60d78b315 645 * The main state machine to handle an HTTP transaction
dflet 0:6ad60d78b315 646 * Every received data packet for a connection is passed to this function for parsing and handling
dflet 0:6ad60d78b315 647 *
dflet 0:6ad60d78b315 648 * If there is an error the connection will be closed in the end of the transaction
dflet 0:6ad60d78b315 649 * It will also be closed if "connection: close" header is received or HTTP version is 1.0
dflet 0:6ad60d78b315 650 *
dflet 0:6ad60d78b315 651 * @return zero to close the connection
dflet 0:6ad60d78b315 652 * nonzero if packet was consumed successfully, and the connection can handle more data
dflet 0:6ad60d78b315 653 */
dflet 0:6ad60d78b315 654 static int HttpCore_HandleRequestPacket(uint16 uConnection, struct HttpBlob packet)
dflet 0:6ad60d78b315 655 {
dflet 0:6ad60d78b315 656 struct HttpBlob currentLocation, line;
dflet 0:6ad60d78b315 657 int ret;
dflet 0:6ad60d78b315 658
dflet 0:6ad60d78b315 659 currentLocation.pData = packet.pData;
dflet 0:6ad60d78b315 660 currentLocation.uLength = packet.uLength;
dflet 0:6ad60d78b315 661
dflet 0:6ad60d78b315 662 // when no more data is left and the HTTP transaction is not complete then return to wait for more data
dflet 0:6ad60d78b315 663 while (1)
dflet 0:6ad60d78b315 664 {
dflet 0:6ad60d78b315 665 if (g_state.connections[uConnection].connectionState == RequestMethod ||
dflet 0:6ad60d78b315 666 g_state.connections[uConnection].connectionState == RequestHeaders ||
dflet 0:6ad60d78b315 667 g_state.connections[uConnection].connectionState == DropCurrentHeader)
dflet 0:6ad60d78b315 668 {
dflet 0:6ad60d78b315 669 // Parsing HTTP headers
dflet 0:6ad60d78b315 670 int result;
dflet 0:6ad60d78b315 671
dflet 0:6ad60d78b315 672 // The received blob is empty, return to wait for more data
dflet 0:6ad60d78b315 673 if (currentLocation.uLength < 1)
dflet 0:6ad60d78b315 674 {
dflet 0:6ad60d78b315 675 return 1;
dflet 0:6ad60d78b315 676 }
dflet 0:6ad60d78b315 677
dflet 0:6ad60d78b315 678 // Get next header line if available
dflet 0:6ad60d78b315 679 result = HttpCore_GetNextLine(uConnection, &currentLocation, &line);
dflet 0:6ad60d78b315 680
dflet 0:6ad60d78b315 681 // Method line is too long, or some other error
dflet 0:6ad60d78b315 682 if (result < 0)
dflet 0:6ad60d78b315 683 return 0;
dflet 0:6ad60d78b315 684
dflet 0:6ad60d78b315 685 // Whole packet was consumed, and no line-break found. Wait for more data
dflet 0:6ad60d78b315 686 if (result == 0)
dflet 0:6ad60d78b315 687 return 1;
dflet 0:6ad60d78b315 688
dflet 0:6ad60d78b315 689 // Otherwise a new and legal header line is found
dflet 0:6ad60d78b315 690 }
dflet 0:6ad60d78b315 691
dflet 0:6ad60d78b315 692 switch (g_state.connections[uConnection].connectionState)
dflet 0:6ad60d78b315 693 {
dflet 0:6ad60d78b315 694 case DropCurrentHeader:
dflet 0:6ad60d78b315 695 g_state.connections[uConnection].connectionState = RequestHeaders;
dflet 0:6ad60d78b315 696 break;
dflet 0:6ad60d78b315 697 case RequestMethod:
dflet 0:6ad60d78b315 698 //HttpAssert((line.pData != NULL) && (line.uLength > 0));
dflet 0:6ad60d78b315 699 // If there is an error, then return error to drop the connection
dflet 0:6ad60d78b315 700 if (!HttpCore_HandleMethodLine(uConnection, line))
dflet 0:6ad60d78b315 701 return 0;
dflet 0:6ad60d78b315 702 break;
dflet 0:6ad60d78b315 703 case RequestHeaders:
dflet 0:6ad60d78b315 704 if (!HttpCore_HandleHeaderLine(uConnection, line))
dflet 0:6ad60d78b315 705 return 0;
dflet 0:6ad60d78b315 706 break;
dflet 0:6ad60d78b315 707 case RequestData:
dflet 0:6ad60d78b315 708 ret = HttpCore_HandleRequestData(uConnection, &currentLocation);
dflet 0:6ad60d78b315 709 if (ret == 0)
dflet 0:6ad60d78b315 710 return 1;
dflet 0:6ad60d78b315 711 else
dflet 0:6ad60d78b315 712 if (ret < 0)
dflet 0:6ad60d78b315 713 return 0;
dflet 0:6ad60d78b315 714 break;
dflet 0:6ad60d78b315 715 case Processing:
dflet 0:6ad60d78b315 716 // All the request data was received - start final processing of the headers and post data if exists
dflet 0:6ad60d78b315 717 switch (g_state.connections[uConnection].handler)
dflet 0:6ad60d78b315 718 {
dflet 0:6ad60d78b315 719 #ifdef HTTP_CORE_ENABLE_STATIC
dflet 0:6ad60d78b315 720 case HttpStatic:
dflet 0:6ad60d78b315 721 HttpStatic_ProcessRequest(&g_state.connections[uConnection].request);
dflet 0:6ad60d78b315 722 break;
dflet 0:6ad60d78b315 723 #endif
dflet 0:6ad60d78b315 724 #ifdef HTTP_CORE_ENABLE_DYNAMIC
dflet 0:6ad60d78b315 725 case HttpDynamic:
dflet 0:6ad60d78b315 726 HttpDynamic_ProcessRequest(&g_state.connections[uConnection].request);
dflet 0:6ad60d78b315 727 break;
dflet 0:6ad60d78b315 728 #endif
dflet 0:6ad60d78b315 729 default:
dflet 0:6ad60d78b315 730 HttpCore_ProcessNotFound(uConnection);
dflet 0:6ad60d78b315 731 break;
dflet 0:6ad60d78b315 732 }
dflet 0:6ad60d78b315 733 break;
dflet 0:6ad60d78b315 734 case ResponseData:
dflet 0:6ad60d78b315 735 // This state should never be reached, it is set internally during the processing
dflet 0:6ad60d78b315 736 HttpDebug("Response data state in request handling main loop!");
dflet 0:6ad60d78b315 737 printf("Response data state in request handling main loop!\r\n");
dflet 0:6ad60d78b315 738 HttpAssert(0);
dflet 0:6ad60d78b315 739 break;
dflet 0:6ad60d78b315 740 case ResponseComplete:
dflet 0:6ad60d78b315 741 if ((g_state.connections[uConnection].request.uFlags & HTTP_REQUEST_FLAG_CLOSE)!=0 ||
dflet 0:6ad60d78b315 742 (g_state.connections[uConnection].request.uFlags & HTTP_REQUEST_1_1) == 0)
dflet 0:6ad60d78b315 743 {
dflet 0:6ad60d78b315 744 // Connection should be closed - either "Connection: close" was received or the HTTP version is 1.0
dflet 0:6ad60d78b315 745 // Return 0 to close the connection
dflet 0:6ad60d78b315 746 return 0;
dflet 0:6ad60d78b315 747 }
dflet 0:6ad60d78b315 748 // The current HTTP transaction is complete - reset state for the next transaction on this connection
dflet 0:6ad60d78b315 749 g_state.connections[uConnection].connectionState = RequestMethod;
dflet 0:6ad60d78b315 750 HttpCore_ResetConnection(uConnection);
dflet 0:6ad60d78b315 751 break;
dflet 0:6ad60d78b315 752 default:
dflet 0:6ad60d78b315 753 HttpDebug("Bad state in HttpCore!");
dflet 0:6ad60d78b315 754 printf("Bad state in HttpCore!\r\n");
dflet 0:6ad60d78b315 755 //HttpAssert(0);
dflet 0:6ad60d78b315 756 break;
dflet 0:6ad60d78b315 757 }
dflet 0:6ad60d78b315 758 }
dflet 0:6ad60d78b315 759 }
dflet 0:6ad60d78b315 760
dflet 0:6ad60d78b315 761 /**
dflet 0:6ad60d78b315 762 * This function handles connection initial state
dflet 0:6ad60d78b315 763 * Parse the first header line as a method header
dflet 0:6ad60d78b315 764 *
dflet 0:6ad60d78b315 765 * Method line should be in the form:
dflet 0:6ad60d78b315 766 * GET /resource.html HTTP/1.1\r\n
dflet 0:6ad60d78b315 767 *
dflet 0:6ad60d78b315 768 * @return nonzero if success
dflet 0:6ad60d78b315 769 */
dflet 0:6ad60d78b315 770 static int HttpCore_HandleMethodLine(uint16 uConnection, struct HttpBlob line)
dflet 0:6ad60d78b315 771 {
dflet 0:6ad60d78b315 772 struct HttpBlob resource;
dflet 0:6ad60d78b315 773 uint8* methodLocation;
dflet 0:6ad60d78b315 774 uint8* versionLocation;
dflet 0:6ad60d78b315 775 uint16 uMethodLength;
dflet 0:6ad60d78b315 776 // Search for GET token in the input blob
dflet 0:6ad60d78b315 777 methodLocation = HttpString_nextToken(HTTP_METHOD_GET, sizeof(HTTP_METHOD_GET)-1, line);
dflet 0:6ad60d78b315 778 uMethodLength = sizeof(HTTP_METHOD_GET)-1;
dflet 0:6ad60d78b315 779 if (methodLocation == NULL)
dflet 0:6ad60d78b315 780 {
dflet 0:6ad60d78b315 781 // The method is not GET
dflet 0:6ad60d78b315 782 // Search for the POST token in the input blob
dflet 0:6ad60d78b315 783 methodLocation = HttpString_nextToken(HTTP_METHOD_POST, sizeof(HTTP_METHOD_POST)-1, line);
dflet 0:6ad60d78b315 784 uMethodLength = sizeof(HTTP_METHOD_POST)-1;
dflet 0:6ad60d78b315 785 g_state.connections[uConnection].request.uFlags |= HTTP_REQUEST_FLAG_METHOD_POST;
dflet 0:6ad60d78b315 786 }
dflet 0:6ad60d78b315 787 else
dflet 0:6ad60d78b315 788 {
dflet 0:6ad60d78b315 789 // Method is GET
dflet 0:6ad60d78b315 790 g_state.connections[uConnection].request.requestContent.uLength = 0;
dflet 0:6ad60d78b315 791 g_state.connections[uConnection].request.uFlags &= ~HTTP_REQUEST_FLAG_METHOD_POST;
dflet 0:6ad60d78b315 792 }
dflet 0:6ad60d78b315 793 if (methodLocation != line.pData)
dflet 0:6ad60d78b315 794 {
dflet 0:6ad60d78b315 795 methodLocation = HttpString_nextToken(HTTP_METHOD_POST, sizeof(HTTP_METHOD_POST)-1, line);
dflet 0:6ad60d78b315 796 uMethodLength = sizeof(HTTP_METHOD_POST)-1;
dflet 0:6ad60d78b315 797 g_state.connections[uConnection].request.uFlags |= HTTP_REQUEST_FLAG_METHOD_POST;
dflet 0:6ad60d78b315 798 if(methodLocation == NULL || methodLocation != line.pData)
dflet 0:6ad60d78b315 799 {
dflet 0:6ad60d78b315 800 // Header does not begin line with GET or POST as it should
dflet 0:6ad60d78b315 801 HttpDebug("Unsupported method");
dflet 0:6ad60d78b315 802 printf("Unsupported method\r\n");
dflet 0:6ad60d78b315 803 return 0;
dflet 0:6ad60d78b315 804 }
dflet 0:6ad60d78b315 805 }
dflet 0:6ad60d78b315 806
dflet 0:6ad60d78b315 807 // Search for "HTTP/1.1" version token
dflet 0:6ad60d78b315 808 versionLocation = HttpString_nextToken(HTTP_VERSION_1P1, sizeof(HTTP_VERSION_1P1)-1, line);
dflet 0:6ad60d78b315 809 // Version is 1.1
dflet 0:6ad60d78b315 810 if (versionLocation != NULL)
dflet 0:6ad60d78b315 811 g_state.connections[uConnection].request.uFlags |= HTTP_REQUEST_1_1;
dflet 0:6ad60d78b315 812 else
dflet 0:6ad60d78b315 813 {
dflet 0:6ad60d78b315 814 // Search for "HTTP/1.1" version token
dflet 0:6ad60d78b315 815 versionLocation = HttpString_nextToken(HTTP_VERSION_1P0, sizeof(HTTP_VERSION_1P0)-1, line);
dflet 0:6ad60d78b315 816 // Version is 1.0
dflet 0:6ad60d78b315 817 if (versionLocation != NULL)
dflet 0:6ad60d78b315 818 g_state.connections[uConnection].request.uFlags &= ~HTTP_REQUEST_1_1;
dflet 0:6ad60d78b315 819 else
dflet 0:6ad60d78b315 820 {
dflet 0:6ad60d78b315 821 HttpDebug("Bad protocol version");
dflet 0:6ad60d78b315 822 printf("Bad protocol version\r\n");
dflet 0:6ad60d78b315 823 return 0;
dflet 0:6ad60d78b315 824 }
dflet 0:6ad60d78b315 825 }
dflet 0:6ad60d78b315 826
dflet 0:6ad60d78b315 827 HttpDebug("method Header: %.*s", line.uLength, line.pData);
dflet 0:6ad60d78b315 828 //printf("method Header: %i , %c\r\n", line.uLength, line.pData);
dflet 0:6ad60d78b315 829 // Find the URL part of the header
dflet 0:6ad60d78b315 830 resource.pData = methodLocation + uMethodLength + 1;
dflet 0:6ad60d78b315 831 resource.uLength = (uint16)(versionLocation - (methodLocation + uMethodLength + 1) - 1);
dflet 0:6ad60d78b315 832
dflet 0:6ad60d78b315 833 // Determine which handler is supposed to handle this request
dflet 0:6ad60d78b315 834 // The handler functions are called according to a hardcoded priority - dynamic, static, default
dflet 0:6ad60d78b315 835 // The first handler that returns non zero will handle this request
dflet 0:6ad60d78b315 836 #ifdef HTTP_CORE_ENABLE_DYNAMIC
dflet 0:6ad60d78b315 837 if (HttpDynamic_InitRequest(uConnection, resource) != 0)
dflet 0:6ad60d78b315 838 g_state.connections[uConnection].handler = HttpDynamic;
dflet 0:6ad60d78b315 839 else
dflet 0:6ad60d78b315 840 #endif
dflet 0:6ad60d78b315 841 #ifdef HTTP_CORE_ENABLE_STATIC
dflet 0:6ad60d78b315 842 if (HttpStatic_InitRequest(uConnection, resource) != 0)
dflet 0:6ad60d78b315 843 g_state.connections[uConnection].handler = HttpStatic;
dflet 0:6ad60d78b315 844 else
dflet 0:6ad60d78b315 845 #endif
dflet 0:6ad60d78b315 846 g_state.connections[uConnection].handler = None;
dflet 0:6ad60d78b315 847 g_state.connections[uConnection].connectionState = RequestHeaders;
dflet 0:6ad60d78b315 848 return 1;
dflet 0:6ad60d78b315 849 }
dflet 0:6ad60d78b315 850
dflet 0:6ad60d78b315 851 /**
dflet 0:6ad60d78b315 852 * Handle The HTTP headers (after method) one by one
dflet 0:6ad60d78b315 853 * If an empty header is received then the headers section is complete
dflet 0:6ad60d78b315 854 * Searches for the headers tokens. If important data is found then it is saved in the connection object
dflet 0:6ad60d78b315 855 *
dflet 0:6ad60d78b315 856 * returns nonzero if sucessful
dflet 0:6ad60d78b315 857 */
dflet 0:6ad60d78b315 858 static int HttpCore_HandleHeaderLine(uint16 uConnection, struct HttpBlob line)
dflet 0:6ad60d78b315 859 {
dflet 0:6ad60d78b315 860 struct HttpBlob blobValue;
dflet 0:6ad60d78b315 861 uint8* pFound;
dflet 0:6ad60d78b315 862 uint32 length;
dflet 0:6ad60d78b315 863
dflet 0:6ad60d78b315 864 // NULL line is received when a header line is too long.
dflet 0:6ad60d78b315 865 if (line.pData == NULL)
dflet 0:6ad60d78b315 866 return 1;
dflet 0:6ad60d78b315 867
dflet 0:6ad60d78b315 868 // Length is 0, this means than End-Of-Headers marker was reached
dflet 0:6ad60d78b315 869 // State of this connection is set to RequestData
dflet 0:6ad60d78b315 870 if (line.uLength == 0)
dflet 0:6ad60d78b315 871 {
dflet 0:6ad60d78b315 872 g_state.connections[uConnection].connectionState = RequestData;
dflet 0:6ad60d78b315 873 return 1;
dflet 0:6ad60d78b315 874 }
dflet 0:6ad60d78b315 875
dflet 0:6ad60d78b315 876 // If "Accept-encoding" header then set or clear HTTP_REQUEST_FLAG_ACCEPT_GZIP flag
dflet 0:6ad60d78b315 877 if (HttpString_nextToken(HTTP_ACCEPT_ENCODING, sizeof(HTTP_ACCEPT_ENCODING)-1, line))
dflet 0:6ad60d78b315 878 {
dflet 0:6ad60d78b315 879 line.pData += sizeof(HTTP_ACCEPT_ENCODING)-1 + 2;
dflet 0:6ad60d78b315 880 line.uLength -= sizeof(HTTP_ACCEPT_ENCODING)-1 + 2;
dflet 0:6ad60d78b315 881 pFound = HttpString_nextToken(HTTP_GZIP, sizeof(HTTP_GZIP)-1, line);
dflet 0:6ad60d78b315 882 if (pFound != NULL)
dflet 0:6ad60d78b315 883 g_state.connections[uConnection].request.uFlags |= HTTP_REQUEST_FLAG_ACCEPT_GZIP;
dflet 0:6ad60d78b315 884 else
dflet 0:6ad60d78b315 885 g_state.connections[uConnection].request.uFlags &= ~HTTP_REQUEST_FLAG_ACCEPT_GZIP;
dflet 0:6ad60d78b315 886 return 1;
dflet 0:6ad60d78b315 887 }
dflet 0:6ad60d78b315 888
dflet 0:6ad60d78b315 889 // If "Content-Length" header then parse the lenght and set uContentLeft to it
dflet 0:6ad60d78b315 890 // GET and POST method behave the same
dflet 0:6ad60d78b315 891 if (HttpString_nextToken(HTTP_CONTENT_LENGTH, sizeof(HTTP_CONTENT_LENGTH)-1, line) == line.pData)
dflet 0:6ad60d78b315 892 {
dflet 0:6ad60d78b315 893 line.pData += sizeof(HTTP_CONTENT_LENGTH)-1 + 2;
dflet 0:6ad60d78b315 894 line.uLength -= sizeof(HTTP_CONTENT_LENGTH)-1 + 2;
dflet 0:6ad60d78b315 895 blobValue.pData = line.pData;
dflet 0:6ad60d78b315 896 blobValue.uLength = line.uLength - 2;
dflet 0:6ad60d78b315 897 length = HttpString_atou(blobValue);
dflet 0:6ad60d78b315 898 g_state.connections[uConnection].uContentLeft = length;
dflet 0:6ad60d78b315 899 // Set ignore flag
dflet 0:6ad60d78b315 900 if (g_state.connections[uConnection].uContentLeft > HTTP_CORE_MAX_HEADER_LINE_LENGTH)
dflet 0:6ad60d78b315 901 g_state.connections[uConnection].request.uFlags |= HTTP_REQUEST_CONTENT_IGNORED;
dflet 0:6ad60d78b315 902 // Prepare the request blob to buffer the content
dflet 0:6ad60d78b315 903 g_state.connections[uConnection].request.requestContent.pData = g_state.connections[uConnection].headerStart;
dflet 0:6ad60d78b315 904 g_state.connections[uConnection].request.requestContent.uLength = 0;
dflet 0:6ad60d78b315 905 return 1;
dflet 0:6ad60d78b315 906 }
dflet 0:6ad60d78b315 907 // If "Connection" header then look for "close" and set or clear HTTP_REQUEST_FLAG_CLOSE flag
dflet 0:6ad60d78b315 908 // The default behaviour for keep alive or no such header is to keep the connection open in http version 1.1
dflet 0:6ad60d78b315 909 // In http version 1.0 the default behavior is to always close the socket
dflet 0:6ad60d78b315 910 if (HttpString_nextToken(HTTP_CONNECTION_CLOSE, sizeof(HTTP_CONNECTION_CLOSE)-1, line) == line.pData)
dflet 0:6ad60d78b315 911 {
dflet 0:6ad60d78b315 912 line.pData += sizeof(HTTP_CONNECTION_CLOSE)-1 + 2;
dflet 0:6ad60d78b315 913 line.uLength -= sizeof(HTTP_CONNECTION_CLOSE)-1 + 2;
dflet 0:6ad60d78b315 914 pFound = HttpString_nextToken(HTTP_CLOSE, sizeof(HTTP_CLOSE)-1, line);
dflet 0:6ad60d78b315 915 if (pFound != 0)
dflet 0:6ad60d78b315 916 g_state.connections[uConnection].request.uFlags |= HTTP_REQUEST_FLAG_CLOSE;
dflet 0:6ad60d78b315 917 else
dflet 0:6ad60d78b315 918 g_state.connections[uConnection].request.uFlags &= ~HTTP_REQUEST_FLAG_CLOSE;
dflet 0:6ad60d78b315 919 return 1;
dflet 0:6ad60d78b315 920 }
dflet 0:6ad60d78b315 921 // If "Authorization" header the handle authentication
dflet 0:6ad60d78b315 922 if (HttpString_nextToken(HTTP_AUTHORIZATION, sizeof(HTTP_AUTHORIZATION)-1, line) == line.pData)
dflet 0:6ad60d78b315 923 {
dflet 0:6ad60d78b315 924 line.pData += sizeof(HTTP_AUTHORIZATION)-1 + 2;
dflet 0:6ad60d78b315 925 line.uLength -= sizeof(HTTP_AUTHORIZATION)-1 + 2;
dflet 0:6ad60d78b315 926 blobValue.pData = line.pData;
dflet 0:6ad60d78b315 927 blobValue.uLength = line.uLength;
dflet 0:6ad60d78b315 928 //TODO: handle the case when we don't support authentication
dflet 0:6ad60d78b315 929 #ifdef HTTP_CORE_ENABLE_AUTH
dflet 0:6ad60d78b315 930 HttpAuth_RequestAuthenticate(&g_state.connections[uConnection].request, blobValue);
dflet 0:6ad60d78b315 931 #endif
dflet 0:6ad60d78b315 932 return 1;
dflet 0:6ad60d78b315 933 }
dflet 0:6ad60d78b315 934 // None of the above mentioned headers was recognized so just ignore this header
dflet 0:6ad60d78b315 935 return 1;
dflet 0:6ad60d78b315 936 }
dflet 0:6ad60d78b315 937
dflet 0:6ad60d78b315 938 /**
dflet 0:6ad60d78b315 939 * Handles request data for this transaction
dflet 0:6ad60d78b315 940 * Behaves the same for POST and GET methods -
dflet 0:6ad60d78b315 941 * If content length header was present then read the content for further processing
dflet 0:6ad60d78b315 942 * If the content is too long then ignore it
dflet 0:6ad60d78b315 943 *
dflet 0:6ad60d78b315 944 * @return 1 if successful, pData is updated to skip the handled data
dflet 0:6ad60d78b315 945 0 if all data is consumed and need to read more data
dflet 0:6ad60d78b315 946 * negative if an error occurs and the connection should be closed.
dflet 0:6ad60d78b315 947 */
dflet 0:6ad60d78b315 948 static int HttpCore_HandleRequestData(uint16 uConnection, struct HttpBlob* pData)
dflet 0:6ad60d78b315 949 {
dflet 0:6ad60d78b315 950 uint32 uLengthToHandle;
dflet 0:6ad60d78b315 951
dflet 0:6ad60d78b315 952 if (g_state.connections[uConnection].uContentLeft == 0)
dflet 0:6ad60d78b315 953 {
dflet 0:6ad60d78b315 954 HttpDebug("Received content. Length=%d, content:\r\n%.*s", g_state.connections[uConnection].request.requestContent.uLength, g_state.connections[uConnection].request.requestContent.uLength, g_state.connections[uConnection].headerStart);
dflet 0:6ad60d78b315 955 g_state.connections[uConnection].connectionState = Processing;
dflet 0:6ad60d78b315 956 return 1;
dflet 0:6ad60d78b315 957 }
dflet 0:6ad60d78b315 958
dflet 0:6ad60d78b315 959 // Find minimum between the content left to handle and the current blob
dflet 0:6ad60d78b315 960 uLengthToHandle = g_state.connections[uConnection].uContentLeft;
dflet 0:6ad60d78b315 961 if (uLengthToHandle > pData->uLength)
dflet 0:6ad60d78b315 962 uLengthToHandle = pData->uLength;
dflet 0:6ad60d78b315 963
dflet 0:6ad60d78b315 964 // If no new data is received - return and wait for more
dflet 0:6ad60d78b315 965 if (uLengthToHandle == 0)
dflet 0:6ad60d78b315 966 return 0;
dflet 0:6ad60d78b315 967
dflet 0:6ad60d78b315 968 if ( (g_state.connections[uConnection].request.uFlags & HTTP_REQUEST_CONTENT_IGNORED) != 0)
dflet 0:6ad60d78b315 969 {
dflet 0:6ad60d78b315 970 // Ignore Content
dflet 0:6ad60d78b315 971 pData->pData += uLengthToHandle;
dflet 0:6ad60d78b315 972 pData->uLength -= (uint16)uLengthToHandle;
dflet 0:6ad60d78b315 973 g_state.connections[uConnection].uContentLeft -= uLengthToHandle;
dflet 0:6ad60d78b315 974 }
dflet 0:6ad60d78b315 975 else
dflet 0:6ad60d78b315 976 {
dflet 0:6ad60d78b315 977 // Read content
dflet 0:6ad60d78b315 978 memcpy(g_state.connections[uConnection].headerStart + g_state.connections[uConnection].request.requestContent.uLength, pData->pData, uLengthToHandle);
dflet 0:6ad60d78b315 979 pData->pData += uLengthToHandle;
dflet 0:6ad60d78b315 980 pData->uLength -= (uint16)uLengthToHandle;
dflet 0:6ad60d78b315 981 g_state.connections[uConnection].uContentLeft -= uLengthToHandle;
dflet 0:6ad60d78b315 982 g_state.connections[uConnection].request.requestContent.uLength += (uint16)uLengthToHandle;
dflet 0:6ad60d78b315 983 }
dflet 0:6ad60d78b315 984
dflet 0:6ad60d78b315 985 return 1;
dflet 0:6ad60d78b315 986 }
dflet 0:6ad60d78b315 987
dflet 0:6ad60d78b315 988 /**
dflet 0:6ad60d78b315 989 * Returns HTTP 404 not found response
dflet 0:6ad60d78b315 990 */
dflet 0:6ad60d78b315 991 static void HttpCore_ProcessNotFound(uint16 uConnection)
dflet 0:6ad60d78b315 992 {
dflet 0:6ad60d78b315 993 // call HttpResponse_CannedError with 404 NOT_FOUND
dflet 0:6ad60d78b315 994 HttpResponse_CannedError(uConnection, HTTP_STATUS_ERROR_NOT_FOUND);
dflet 0:6ad60d78b315 995 }
dflet 0:6ad60d78b315 996
dflet 0:6ad60d78b315 997 /**
dflet 0:6ad60d78b315 998 * Sends the input blob over the connection socket
dflet 0:6ad60d78b315 999 */
dflet 0:6ad60d78b315 1000 static int HttpCore_SendPacket(uint16 uConnection, struct HttpBlob buffer)
dflet 0:6ad60d78b315 1001 {
dflet 0:6ad60d78b315 1002 // Send the buffer over the data socket until all the buffer is sent
dflet 0:6ad60d78b315 1003 while (buffer.uLength > 0)
dflet 0:6ad60d78b315 1004 {
dflet 0:6ad60d78b315 1005 int sent;
dflet 0:6ad60d78b315 1006 if(buffer.uLength > MAX_SENT_DATA)
dflet 0:6ad60d78b315 1007 {
dflet 0:6ad60d78b315 1008 sent = send(g_state.connections[uConnection].dataSocket, (char*)buffer.pData, MAX_SENT_DATA, 0);
dflet 0:6ad60d78b315 1009 if (sent <= 0)
dflet 0:6ad60d78b315 1010 {
dflet 0:6ad60d78b315 1011 printf("Send failed...\r\n");
dflet 0:6ad60d78b315 1012 // Connection must be closed if send has failed
dflet 0:6ad60d78b315 1013 return 0;
dflet 0:6ad60d78b315 1014 }
dflet 0:6ad60d78b315 1015 }
dflet 0:6ad60d78b315 1016 else
dflet 0:6ad60d78b315 1017 {
dflet 0:6ad60d78b315 1018 sent = send(g_state.connections[uConnection].dataSocket, (char*)buffer.pData, buffer.uLength, 0);
dflet 0:6ad60d78b315 1019 if (sent <= 0)
dflet 0:6ad60d78b315 1020 {
dflet 0:6ad60d78b315 1021 printf("Send failed...\r\n");
dflet 0:6ad60d78b315 1022 // Connection must be closed if send has failed
dflet 0:6ad60d78b315 1023 return 0;
dflet 0:6ad60d78b315 1024 }
dflet 0:6ad60d78b315 1025 }
dflet 0:6ad60d78b315 1026 buffer.pData += sent;
dflet 0:6ad60d78b315 1027 buffer.uLength -= (uint16)sent;
dflet 0:6ad60d78b315 1028 }
dflet 0:6ad60d78b315 1029 return 1;
dflet 0:6ad60d78b315 1030 }
dflet 0:6ad60d78b315 1031
dflet 0:6ad60d78b315 1032 /**
dflet 0:6ad60d78b315 1033 * Add char to the response buffer
dflet 0:6ad60d78b315 1034 */
dflet 0:6ad60d78b315 1035 static void HttpResponse_AddCharToResponseHeaders(char ch)
dflet 0:6ad60d78b315 1036 {
dflet 0:6ad60d78b315 1037 //add char
dflet 0:6ad60d78b315 1038 g_state.packetSend[g_state.packetSendSize] = ch;
dflet 0:6ad60d78b315 1039 g_state.packetSendSize++;
dflet 0:6ad60d78b315 1040 }
dflet 0:6ad60d78b315 1041
dflet 0:6ad60d78b315 1042 /**
dflet 0:6ad60d78b315 1043 * Add uint32 number to the response buffer
dflet 0:6ad60d78b315 1044 */
dflet 0:6ad60d78b315 1045 static void HttpResponse_AddNumberToResponseHeaders(uint32 num)
dflet 0:6ad60d78b315 1046 {
dflet 0:6ad60d78b315 1047 struct HttpBlob resource;
dflet 0:6ad60d78b315 1048 resource.pData = g_state.packetSend + g_state.packetSendSize;
dflet 0:6ad60d78b315 1049 resource.uLength = 0;
dflet 0:6ad60d78b315 1050 HttpString_utoa(num, &resource);
dflet 0:6ad60d78b315 1051 g_state.packetSendSize += resource.uLength;
dflet 0:6ad60d78b315 1052 }
dflet 0:6ad60d78b315 1053
dflet 0:6ad60d78b315 1054
dflet 0:6ad60d78b315 1055 /**
dflet 0:6ad60d78b315 1056 * Add a string to the response buffer
dflet 0:6ad60d78b315 1057 */
dflet 0:6ad60d78b315 1058 static void HttpResponse_AddStringToResponseHeaders(char * str, uint16 len)
dflet 0:6ad60d78b315 1059 {
dflet 0:6ad60d78b315 1060 memcpy(g_state.packetSend + g_state.packetSendSize, str, len);
dflet 0:6ad60d78b315 1061 g_state.packetSendSize += len;
dflet 0:6ad60d78b315 1062 }
dflet 0:6ad60d78b315 1063
dflet 0:6ad60d78b315 1064 /**
dflet 0:6ad60d78b315 1065 * Add header line to response buffer
dflet 0:6ad60d78b315 1066 * Adds a line to the header with the provided name value pair
dflet 0:6ad60d78b315 1067 * Precondition to this function is that g_state.packetSendSize and g_state.packetSend are correct
dflet 0:6ad60d78b315 1068 */
dflet 0:6ad60d78b315 1069 static void HttpResponse_AddHeaderLine(char * headerName, uint16 headerNameLen, char * headerValue, uint16 headerValueLen)
dflet 0:6ad60d78b315 1070 {
dflet 0:6ad60d78b315 1071 HttpResponse_AddStringToResponseHeaders(headerName, headerNameLen);
dflet 0:6ad60d78b315 1072 HttpResponse_AddCharToResponseHeaders(':');
dflet 0:6ad60d78b315 1073 HttpResponse_AddCharToResponseHeaders(' ');
dflet 0:6ad60d78b315 1074 HttpResponse_AddStringToResponseHeaders(headerValue, headerValueLen);
dflet 0:6ad60d78b315 1075 HttpResponse_AddStringToResponseHeaders(HTTP_HEADER_DELIMITER, sizeof(HTTP_HEADER_DELIMITER)-1);
dflet 0:6ad60d78b315 1076 }
dflet 0:6ad60d78b315 1077
dflet 0:6ad60d78b315 1078 /**
dflet 0:6ad60d78b315 1079 * Add Header line to response buffer
dflet 0:6ad60d78b315 1080 * Adds a line to the header with the provided name value pair when the value is numeric
dflet 0:6ad60d78b315 1081 * precondition to this function is that g_state.packetSendSize and g_state.packetSend are correct
dflet 0:6ad60d78b315 1082 */
dflet 0:6ad60d78b315 1083 static void HttpResponse_AddHeaderLineNumValue(char * headerName, uint16 uHeaderNameLen, uint32 headerValue)
dflet 0:6ad60d78b315 1084 {
dflet 0:6ad60d78b315 1085 HttpResponse_AddStringToResponseHeaders(headerName, uHeaderNameLen);
dflet 0:6ad60d78b315 1086 HttpResponse_AddCharToResponseHeaders(':');
dflet 0:6ad60d78b315 1087 HttpResponse_AddCharToResponseHeaders(' ');
dflet 0:6ad60d78b315 1088 HttpResponse_AddNumberToResponseHeaders(headerValue);
dflet 0:6ad60d78b315 1089 HttpResponse_AddStringToResponseHeaders(HTTP_HEADER_DELIMITER, sizeof(HTTP_HEADER_DELIMITER)-1);
dflet 0:6ad60d78b315 1090 }
dflet 0:6ad60d78b315 1091
dflet 0:6ad60d78b315 1092 /**
dflet 0:6ad60d78b315 1093 * Returns status string according to status code
dflet 0:6ad60d78b315 1094 */
dflet 0:6ad60d78b315 1095 static void HttpStatusString(uint16 uHttpStatus, struct HttpBlob* status)
dflet 0:6ad60d78b315 1096 {
dflet 0:6ad60d78b315 1097 switch (uHttpStatus)
dflet 0:6ad60d78b315 1098 {
dflet 0:6ad60d78b315 1099 case HTTP_STATUS_OK:
dflet 0:6ad60d78b315 1100 HttpBlobSetConst(*status, HTTP_STATUS_OK_STR);
dflet 0:6ad60d78b315 1101 break;
dflet 0:6ad60d78b315 1102 case HTTP_STATUS_REDIRECT_PERMANENT:
dflet 0:6ad60d78b315 1103 HttpBlobSetConst(*status, HTTP_STATUS_REDIRECT_PERMANENT_STR);
dflet 0:6ad60d78b315 1104 break;
dflet 0:6ad60d78b315 1105 case HTTP_STATUS_REDIRECT_TEMPORARY:
dflet 0:6ad60d78b315 1106 HttpBlobSetConst(*status, HTTP_STATUS_REDIRECT_TEMPORARY_STR);
dflet 0:6ad60d78b315 1107 break;
dflet 0:6ad60d78b315 1108 case HTTP_STATUS_ERROR_UNAUTHORIZED:
dflet 0:6ad60d78b315 1109 HttpBlobSetConst(*status, HTTP_STATUS_ERROR_UNAUTHORIZED_STR);
dflet 0:6ad60d78b315 1110 break;
dflet 0:6ad60d78b315 1111 case HTTP_STATUS_ERROR_NOT_FOUND:
dflet 0:6ad60d78b315 1112 HttpBlobSetConst(*status, HTTP_STATUS_ERROR_NOT_FOUND_STR);
dflet 0:6ad60d78b315 1113 break;
dflet 0:6ad60d78b315 1114 case HTTP_STATUS_ERROR_NOT_ACCEPTED:
dflet 0:6ad60d78b315 1115 HttpBlobSetConst(*status, HTTP_STATUS_ERROR_NOT_ACCEPTED_STR);
dflet 0:6ad60d78b315 1116 break;
dflet 0:6ad60d78b315 1117 case HTTP_STATUS_ERROR_INTERNAL:
dflet 0:6ad60d78b315 1118 HttpBlobSetConst(*status, HTTP_STATUS_ERROR_INTERNAL_STR);
dflet 0:6ad60d78b315 1119 break;
dflet 0:6ad60d78b315 1120 default:
dflet 0:6ad60d78b315 1121 HttpDebug("Unknown response status");
dflet 0:6ad60d78b315 1122 printf("Unknown response status\r\n");
dflet 0:6ad60d78b315 1123 //HttpAssert(0);
dflet 0:6ad60d78b315 1124 break;
dflet 0:6ad60d78b315 1125 }
dflet 0:6ad60d78b315 1126 }
dflet 0:6ad60d78b315 1127
dflet 0:6ad60d78b315 1128 void HttpResponse_Headers(uint16 uConnection, uint16 uHttpStatus, uint16 uFlags, uint32 uContentLength, struct HttpBlob contentType, struct HttpBlob location)
dflet 0:6ad60d78b315 1129 {
dflet 0:6ad60d78b315 1130 //printf("ResponseHeaders...\r\n");
dflet 0:6ad60d78b315 1131 struct HttpBlob status;
dflet 0:6ad60d78b315 1132 struct HttpBlob packet;
dflet 0:6ad60d78b315 1133 //HttpAssert(g_state.packetSendSize == 0);
dflet 0:6ad60d78b315 1134 //HttpAssert(g_state.connections[uConnection].connectionState == Processing);
dflet 0:6ad60d78b315 1135
dflet 0:6ad60d78b315 1136 // Get status string according to uHttpStatus
dflet 0:6ad60d78b315 1137 HttpStatusString(uHttpStatus, &status);
dflet 0:6ad60d78b315 1138
dflet 0:6ad60d78b315 1139 // Build the response status line in the packet-send buffer: "HTTP/1.1 " followed by the status number as string, a space, the status string, and "\r\n"
dflet 0:6ad60d78b315 1140 // For example: HTTP/1.1 200 OK\r\n
dflet 0:6ad60d78b315 1141
dflet 0:6ad60d78b315 1142 // Add http version to sent packet according to the version that was received in the request
dflet 0:6ad60d78b315 1143 if ( (g_state.connections[uConnection].request.uFlags & HTTP_REQUEST_1_1) != 0)
dflet 0:6ad60d78b315 1144 HttpResponse_AddStringToResponseHeaders(HTTP_VERSION_1P1, sizeof(HTTP_VERSION_1P1)-1);
dflet 0:6ad60d78b315 1145 else
dflet 0:6ad60d78b315 1146 HttpResponse_AddStringToResponseHeaders(HTTP_VERSION_1P0, sizeof(HTTP_VERSION_1P0)-1);
dflet 0:6ad60d78b315 1147 HttpResponse_AddCharToResponseHeaders(' ');
dflet 0:6ad60d78b315 1148 HttpResponse_AddNumberToResponseHeaders(uHttpStatus);
dflet 0:6ad60d78b315 1149 HttpResponse_AddCharToResponseHeaders(' ');
dflet 0:6ad60d78b315 1150 HttpResponse_AddStringToResponseHeaders((char*)status.pData, status.uLength);
dflet 0:6ad60d78b315 1151 HttpResponse_AddStringToResponseHeaders(HTTP_HEADER_DELIMITER, sizeof(HTTP_HEADER_DELIMITER)-1);
dflet 0:6ad60d78b315 1152
dflet 0:6ad60d78b315 1153
dflet 0:6ad60d78b315 1154 // Handle Authentication
dflet 0:6ad60d78b315 1155 if (uHttpStatus == HTTP_STATUS_ERROR_UNAUTHORIZED)
dflet 0:6ad60d78b315 1156 {
dflet 0:6ad60d78b315 1157 #ifdef HTTP_CORE_ENABLE_AUTH
dflet 0:6ad60d78b315 1158 HttpResponse_GetPacketSendBuffer(&packet);
dflet 0:6ad60d78b315 1159 packet.pData = packet.pData + packet.uLength;
dflet 0:6ad60d78b315 1160 packet.uLength = HTTP_CORE_MAX_PACKET_SIZE_SEND - packet.uLength;
dflet 0:6ad60d78b315 1161 HttpAuth_ResponseAuthenticate(&g_state.connections[uConnection].request, &packet);
dflet 0:6ad60d78b315 1162 if (packet.uLength > 0)
dflet 0:6ad60d78b315 1163 g_state.packetSendSize += packet.uLength;
dflet 0:6ad60d78b315 1164 //printf("packet.uLength...%i\r\n",g_state.packetSendSize);
dflet 0:6ad60d78b315 1165 #endif
dflet 0:6ad60d78b315 1166 }
dflet 0:6ad60d78b315 1167 //printf("Auth complete, now Handle content type...\r\n");
dflet 0:6ad60d78b315 1168 // Handle content type
dflet 0:6ad60d78b315 1169 // e.g. "Content-Type: text/html\r\n"
dflet 0:6ad60d78b315 1170 if ((contentType.pData != NULL) && (contentType.uLength > 0))
dflet 0:6ad60d78b315 1171 HttpResponse_AddHeaderLine(HTTP_CONTENT_TYPE, sizeof(HTTP_CONTENT_TYPE)-1, (char*)contentType.pData, contentType.uLength);
dflet 0:6ad60d78b315 1172
dflet 0:6ad60d78b315 1173 // Handle Content-length
dflet 0:6ad60d78b315 1174 // e.g. "Content-Length: 562\r\n"
dflet 0:6ad60d78b315 1175 //printf("Handle content-length...%i\r\n",uContentLength);
dflet 0:6ad60d78b315 1176 if (uContentLength > 0)
dflet 0:6ad60d78b315 1177 HttpResponse_AddHeaderLineNumValue(HTTP_CONTENT_LENGTH, sizeof(HTTP_CONTENT_LENGTH)-1, uContentLength);
dflet 0:6ad60d78b315 1178 g_state.connections[uConnection].uContentLeft = uContentLength;
dflet 0:6ad60d78b315 1179
dflet 0:6ad60d78b315 1180 // Handle compression
dflet 0:6ad60d78b315 1181 // e.g. "Content-Encoding: gzip\r\n"
dflet 0:6ad60d78b315 1182 //printf("Handle compression...\r\n");
dflet 0:6ad60d78b315 1183 if ((uFlags & HTTP_RESPONSE_FLAG_COMPRESSED) != 0)
dflet 0:6ad60d78b315 1184 HttpResponse_AddHeaderLine(HTTP_CONTENT_ENCODING, sizeof(HTTP_CONTENT_ENCODING)-1, HTTP_GZIP, sizeof(HTTP_GZIP)-1);
dflet 0:6ad60d78b315 1185
dflet 0:6ad60d78b315 1186 // Handle redirection/Location
dflet 0:6ad60d78b315 1187 // e.g. "Location: /otherpage.html\r\n"
dflet 0:6ad60d78b315 1188 //printf("Handle redirection/Location...\r\n");
dflet 0:6ad60d78b315 1189 if ((location.pData != NULL) && (location.uLength > 0))
dflet 0:6ad60d78b315 1190 HttpResponse_AddHeaderLine(HTTP_LOCATION, sizeof(HTTP_LOCATION)-1, (char*)location.pData, location.uLength);
dflet 0:6ad60d78b315 1191
dflet 0:6ad60d78b315 1192 // Add the end of headers marker (\r\n)
dflet 0:6ad60d78b315 1193 HttpResponse_AddStringToResponseHeaders(HTTP_HEADER_DELIMITER, sizeof(HTTP_HEADER_DELIMITER)-1);
dflet 0:6ad60d78b315 1194
dflet 0:6ad60d78b315 1195 // Send all response headers over the connection socket
dflet 0:6ad60d78b315 1196 //printf("Send all response headers...\r\n");
dflet 0:6ad60d78b315 1197 packet.pData = g_state.packetSend;
dflet 0:6ad60d78b315 1198 packet.uLength = g_state.packetSendSize;
dflet 0:6ad60d78b315 1199 //printf("packet.uLength...%i\r\n",packet.uLength);
dflet 0:6ad60d78b315 1200 if (!HttpCore_SendPacket(uConnection, packet)){
dflet 0:6ad60d78b315 1201 //printf("Send all response headers failed...\r\n");
dflet 0:6ad60d78b315 1202 return;
dflet 0:6ad60d78b315 1203 }
dflet 0:6ad60d78b315 1204 g_state.packetSendSize = 0;
dflet 0:6ad60d78b315 1205 //printf("Send all response headers complete...\r\n");
dflet 0:6ad60d78b315 1206 // advance state according to need to send content
dflet 0:6ad60d78b315 1207 if (uContentLength > 0)
dflet 0:6ad60d78b315 1208 g_state.connections[uConnection].connectionState = ResponseData;
dflet 0:6ad60d78b315 1209 else
dflet 0:6ad60d78b315 1210 g_state.connections[uConnection].connectionState = ResponseComplete;
dflet 0:6ad60d78b315 1211 /*
dflet 0:6ad60d78b315 1212 Todo: add logic to send the header packet at any point in the middle, if there is not enough room left in it.
dflet 0:6ad60d78b315 1213 */
dflet 0:6ad60d78b315 1214 printf("Finished send...\r\n");
dflet 0:6ad60d78b315 1215 }
dflet 0:6ad60d78b315 1216
dflet 0:6ad60d78b315 1217 void HttpResponse_GetPacketSendBuffer(struct HttpBlob* pPacketSendBuffer)
dflet 0:6ad60d78b315 1218 {
dflet 0:6ad60d78b315 1219 pPacketSendBuffer->pData = g_state.packetSend;
dflet 0:6ad60d78b315 1220 pPacketSendBuffer->uLength = g_state.packetSendSize;
dflet 0:6ad60d78b315 1221 }
dflet 0:6ad60d78b315 1222
dflet 0:6ad60d78b315 1223 void HttpResponse_Content(uint16 uConnection, struct HttpBlob content)
dflet 0:6ad60d78b315 1224 {
dflet 0:6ad60d78b315 1225 //HttpAssert(g_state.connections[uConnection].connectionState == ResponseData);
dflet 0:6ad60d78b315 1226 //HttpAssert(g_state.connections[uConnection].uContentLeft >= content.uLength);
dflet 0:6ad60d78b315 1227
dflet 0:6ad60d78b315 1228 // Send the specified content over the data socket
dflet 0:6ad60d78b315 1229 HttpCore_SendPacket(uConnection, content);
dflet 0:6ad60d78b315 1230
dflet 0:6ad60d78b315 1231 // Update uContentLeft
dflet 0:6ad60d78b315 1232 g_state.connections[uConnection].uContentLeft -= content.uLength;
dflet 0:6ad60d78b315 1233
dflet 0:6ad60d78b315 1234 // If no more content left to send then HTTP transaction is complete
dflet 0:6ad60d78b315 1235 if (g_state.connections[uConnection].uContentLeft == 0)
dflet 0:6ad60d78b315 1236 g_state.connections[uConnection].connectionState = ResponseComplete;
dflet 0:6ad60d78b315 1237 }
dflet 0:6ad60d78b315 1238
dflet 0:6ad60d78b315 1239 void HttpResponse_CannedRedirect(uint16 uConnection, struct HttpBlob location, uint16 bPermanent)
dflet 0:6ad60d78b315 1240 {
dflet 0:6ad60d78b315 1241 struct HttpBlob status;
dflet 0:6ad60d78b315 1242 HttpStatusString((bPermanent==1? HTTP_STATUS_REDIRECT_PERMANENT:HTTP_STATUS_REDIRECT_TEMPORARY), &status);
dflet 0:6ad60d78b315 1243
dflet 0:6ad60d78b315 1244 HttpResponse_Headers(uConnection, (bPermanent==1? HTTP_STATUS_REDIRECT_PERMANENT:HTTP_STATUS_REDIRECT_TEMPORARY), 0, 0, nullBlob, location);
dflet 0:6ad60d78b315 1245 }
dflet 0:6ad60d78b315 1246
dflet 0:6ad60d78b315 1247 void HttpResponse_CannedError(uint16 uConnection, uint16 uHttpStatus)
dflet 0:6ad60d78b315 1248 {
dflet 0:6ad60d78b315 1249 struct HttpBlob status;
dflet 0:6ad60d78b315 1250 HttpStatusString(uHttpStatus, &status);
dflet 0:6ad60d78b315 1251
dflet 0:6ad60d78b315 1252 HttpResponse_Headers(uConnection, uHttpStatus, 0, status.uLength, nullBlob, nullBlob);
dflet 0:6ad60d78b315 1253 HttpResponse_Content(uConnection, status);
dflet 0:6ad60d78b315 1254 }
dflet 0:6ad60d78b315 1255
dflet 0:6ad60d78b315 1256
dflet 0:6ad60d78b315 1257 /// @}
dflet 0:6ad60d78b315 1258