Port of TI's CC3100 Websock camera demo. Using FreeRTOS, mbedTLS, also parts of Arducam for cams ov5642 and 0v2640. Can also use MT9D111. Work in progress. Be warned some parts maybe a bit flacky. This is for Seeed Arch max only, for an M3, see the demo for CM3 using the 0v5642 aducam mini.
HttpCore.cpp
00001 //***************************************************************************** 00002 // Copyright (C) 2014 Texas Instruments Incorporated 00003 // 00004 // All rights reserved. Property of Texas Instruments Incorporated. 00005 // Restricted rights to use, duplicate or disclose this code are 00006 // granted through contract. 00007 // The program may not be used without the written permission of 00008 // Texas Instruments Incorporated or against the terms and conditions 00009 // stipulated in the agreement under which this program has been supplied, 00010 // and under no circumstances can it be used with non-TI connectivity device. 00011 // 00012 //***************************************************************************** 00013 //***************************************************************************** 00014 // 00015 // Protocol Name - Hyper Text Transfer Protocol 00016 // Protocol Overview - The Hypertext Transfer Protocol (HTTP) is an application-level 00017 // protocol for distributed, collaborative, hypermedia information 00018 // systems. 00019 // Refer: https://www.ietf.org/rfc/rfc2616.txt 00020 //***************************************************************************** 00021 00022 00023 /** 00024 * @defgroup HttpCore 00025 * 00026 * @{ 00027 */ 00028 00029 #include "HttpHeaders.h" 00030 #include "HttpCore.h" 00031 #include "HttpSocket.h" 00032 #include "HttpResponse.h" 00033 #include "HttpRequest.h" 00034 #include "HttpAuth.h" 00035 #include "HttpDebug.h" 00036 #include "HttpDynamic.h" 00037 #include "HttpStatic.h" 00038 #include "httpserverapp.h" 00039 #include <string.h> 00040 #include "HttpConfig.h" 00041 #include "HttpString.h" 00042 #include "sha1_gen.h" 00043 #include "osi.h" 00044 #include "WebSockHandler.h" 00045 //#include <stdlib.h> 00046 00047 // Include CC3200 bridged networking stack headers 00048 #include "cc3100_simplelink.h" 00049 00050 using namespace mbed_cc3100; 00051 00052 cc3100 _cc3100Module_(NC, NC, PD_12, PD_13, PD_11, SPI(PC_3, PC_2, PB_10));//Seeed_Arch_Max irq, nHib, cs, mosi, miso, sck 00053 00054 OsiSyncObj_t g_WaitSyncObj; 00055 00056 int8_t ws_Flag = 0; 00057 00058 #define OSI_DELAY(x) osi_Sleep(x) 00059 00060 /** 00061 * @addtogroup HttpCore 00062 * @{ 00063 */ 00064 00065 00066 /** 00067 * This enumeration defines all possible states for a connection 00068 */ 00069 enum HttpConnectionState 00070 { 00071 /// Connection is inactive. The connection's socket should be INVALID_SOCKET_HANDLE 00072 Inactive, 00073 /// Waiting for packet(s) with the request method 00074 RequestMethod, 00075 /// Waiting for packet(s) with request headers 00076 RequestHeaders, 00077 /// Currently receiving a header which is too long - Drop it and continue waiting for more headers 00078 DropCurrentHeader, 00079 /// Done parsing headers, waiting for POST data pakcets 00080 RequestData, 00081 /// Request is at the hands of the content module (static and/or dynamic), waiting for response headers. 00082 Processing, 00083 /// Response headers have been sent. Sending response content. 00084 ResponseData, 00085 /// Response complete. Possibility of another request. 00086 ResponseComplete, 00087 /// WebSocket opening handshake from client 00088 WebSocketRequest, 00089 /// WebSocket opening handshake from server 00090 WebSocketResponse, 00091 /// WebSocket data packets received 00092 WebSocketDataRecv, 00093 /// Websocket data packets sent 00094 WebSocketDataSend 00095 }; 00096 00097 /** 00098 * This enumeration defines all possible request-handler modules 00099 */ 00100 enum HttpHandler 00101 { 00102 /// No module is going to process this request (use the default 404 error) 00103 None, 00104 /// The HttpStatic module is going to process this request 00105 HttpStatic, 00106 /// The HttpDynamic module is going to process this request 00107 HttpDynamic 00108 /// The websocket module is going to process this request 00109 }; 00110 00111 /** 00112 * This structure holds all information for an HTTP connection 00113 */ 00114 //#ifdef __CCS__ 00115 typedef struct HttpConnectionData 00116 //#endif 00117 //#ifdef __IAR_SYSTEMS_ICC__ 00118 //#pragma pack(1) 00119 //struct HttpConnectionData 00120 //#endif 00121 { 00122 /// The state of this connection 00123 enum HttpConnectionState connectionState; 00124 /// The data socket for this connection. Should be INVALID_SOCKET_HANDLE when in Inactive state 00125 int dataSocket; 00126 /// The current HTTP request on this connection 00127 struct HttpRequest request; 00128 /// Which handler is going to process the current request 00129 enum HttpHandler handler; 00130 /// An un-parsed chunk of header line 00131 UINT8 headerStart[HTTP_CORE_MAX_HEADER_LINE_LENGTH]; 00132 /// Amount of content left to be read in the request or sent in the response 00133 UINT32 uContentLeft; 00134 /// timeout count 00135 UINT32 timeout; 00136 /// If the headers will arrive in several packets the content will be buffered in the headers start buffer until a whole line is available 00137 UINT16 uSavedBufferSize; 00138 /// Check weather the authentication is done or not 00139 UINT8 HttpAuth; 00140 }HttpConnectionData; 00141 00142 /** 00143 * This structure holds all of the global state of the HTTP server 00144 */ 00145 //#ifdef __CCS__ 00146 //typedef struct __attribute__ ((__packed__)) HttpGlobalState 00147 //#elif __IAR_SYSTEMS_ICC__ 00148 //#pragma pack(1) 00149 struct HttpGlobalState 00150 //#endif 00151 { 00152 /// The listening socket 00153 int listenSocket; 00154 /// Number of active connections 00155 UINT16 uOpenConnections; 00156 /// All possible connections 00157 struct HttpConnectionData connections[HTTP_CORE_MAX_CONNECTIONS]; 00158 /// The packet-receive buffer 00159 UINT8 packetRecv[HTTP_CORE_MAX_PACKET_SIZE_RECEIVED]; 00160 /// Size of data in the packet-receive buffer 00161 int packetRecvSize; 00162 /// The packet-send buffer 00163 UINT8 packetSend[HTTP_CORE_MAX_PACKET_SIZE_SEND]; 00164 /// Size of data in the packet-send buffer 00165 UINT16 packetSendSize; 00166 }; 00167 00168 /// The global state of the HTTP server 00169 struct HttpGlobalState g_state; 00170 00171 00172 // Forward declarations for static functions 00173 static void HttpCore_InitWebServer(); 00174 static int HttpCore_HandleRequestPacket(UINT16 uConnection, struct HttpBlob packet); 00175 static int HttpCore_HandleMethodLine(UINT16 uConnection, struct HttpBlob line); 00176 static int HttpCore_HandleHeaderLine(UINT16 uConnection, struct HttpBlob line); 00177 static int WSCore_HandshakeRequest(UINT16 uConnection, struct HttpBlob line); 00178 static int WSCore_HandshakeResponse (UINT16 uConnection, struct HttpBlob line); 00179 static int WS_HandshakeHash(char *InKey, char *OutKey, char *EncOutKey); 00180 static int HttpCore_HandleRequestData(UINT16 uConnection, struct HttpBlob* pData); 00181 static void HttpCore_ProcessNotFound(UINT16 uConnection); 00182 static void RunHttpServer(void); 00183 00184 00185 00186 struct HttpBlob nullBlob = {NULL, 0}; 00187 00188 void HttpCloseServer() 00189 { 00190 if(g_state.listenSocket < 0) 00191 { 00192 HttpDebug("Closed Http Server \n\r"); 00193 return; 00194 } 00195 00196 if(CloseTCPServerSocket(g_state.listenSocket) >= 0) 00197 { 00198 g_state.listenSocket = -1; 00199 } 00200 HttpDebug("Closed Http Server \n\r"); 00201 } 00202 00203 void HttpServerInitAndRun(void * param) 00204 { 00205 // Initialize the server's global state 00206 HttpCore_InitWebServer(); 00207 00208 #ifdef HTTP_CORE_ENABLE_AUTH 00209 struct HttpBlob user,pass; 00210 user.pData = (UINT8*)"cc3100"; 00211 user.uLength= 6; 00212 pass.pData = (UINT8*)"admin"; 00213 pass.uLength = 5; 00214 00215 HttpAuth_Init(user, pass); 00216 #endif 00217 00218 HttpDebug("HttpServerApp Initialized \n\r"); 00219 00220 // Main loop of the server. Note: This is an infinite loop 00221 RunHttpServer(); 00222 } 00223 00224 void RunHttpServer() 00225 { 00226 int iRecvLen = 0, sock = -1, uConnection = 0; 00227 struct HttpBlob blob; 00228 00229 HttpDebug("Waiting for Client to connect\n\r"); 00230 00231 while(1) 00232 { 00233 // Create the listener socket for HTTP Server. 00234 if(g_state.listenSocket < 0) 00235 { 00236 sock = CreateTCPServerSocket(HTTP_CORE_SERVER_PORT); 00237 if(sock >= 0) 00238 { 00239 g_state.listenSocket = sock; 00240 } 00241 HttpDebug("\r\nHttp server socket %d \n\r", g_state.listenSocket); 00242 } 00243 00244 if(g_state.listenSocket >= 0) 00245 { 00246 if (g_state.uOpenConnections < HTTP_CORE_MAX_CONNECTIONS) 00247 { 00248 sock = CreateTCPClientSocket(g_state.listenSocket);//non blocking func 00249 if(sock >= 0 ) 00250 { 00251 for (uConnection = 0; uConnection < HTTP_CORE_MAX_CONNECTIONS; ++uConnection) 00252 { 00253 if (g_state.connections[uConnection].connectionState == Inactive) 00254 break; 00255 } 00256 if(uConnection != HTTP_CORE_MAX_CONNECTIONS) 00257 { 00258 g_state.connections[uConnection].dataSocket = sock; 00259 g_state.uOpenConnections++; 00260 g_state.connections[uConnection].connectionState = RequestMethod; 00261 HttpDebug("\r\nAccepting new connection number %d \n\r", uConnection); 00262 } 00263 } 00264 else if((sock != SL_EAGAIN) && (sock != SL_POOL_IS_EMPTY) && (sock != SL_INEXE) && (sock != SL_ENSOCK)) 00265 { 00266 HttpDebug("\r\n Http server socket error %d\n\r",sock); 00267 HttpCloseServer(); 00268 } 00269 else 00270 { 00271 HttpDebug("."); 00272 // HttpDebug("Http accept retry %d\n\r",sock); 00273 } 00274 } 00275 00276 if((g_state.uOpenConnections > 0) && 1) 00277 { 00278 for (uConnection = 0; uConnection < HTTP_CORE_MAX_CONNECTIONS; ++uConnection) 00279 { 00280 // if connection is open and in one of the receiving states, then add this socket to the set 00281 if (g_state.connections[uConnection].connectionState == RequestMethod || 00282 g_state.connections[uConnection].connectionState == RequestHeaders || 00283 g_state.connections[uConnection].connectionState == RequestData || 00284 g_state.connections[uConnection].connectionState == DropCurrentHeader|| 00285 g_state.connections[uConnection].connectionState == WebSocketDataRecv) 00286 { 00287 // This connection has data that can be received now 00288 00289 // Receive the data into the global packet-receive buffer 00290 memset(g_state.packetRecv, 0, HTTP_CORE_MAX_PACKET_SIZE_RECEIVED); 00291 iRecvLen = (int)_cc3100Module_._socket.recv(g_state.connections[uConnection].dataSocket, (char *)(g_state.packetRecv), HTTP_CORE_MAX_PACKET_SIZE_RECEIVED, 0);//blocking func with timeout 5sec 00292 if(iRecvLen > 0) 00293 { 00294 g_state.packetRecvSize = iRecvLen; 00295 HttpDebug("\r\n Http Client Data received %d\n\r",iRecvLen); 00296 g_state.connections[uConnection].timeout = 0; 00297 00298 blob.uLength = (UINT16)g_state.packetRecvSize; 00299 blob.pData = g_state.packetRecv; 00300 if (!HttpCore_HandleRequestPacket(uConnection, blob)) 00301 { 00302 HttpCore_CloseConnection(uConnection); 00303 } 00304 } 00305 else if((iRecvLen != SL_EAGAIN) && (iRecvLen != SL_POOL_IS_EMPTY)) 00306 // else if((iRecvLen == SL_EAGAIN) && (iRecvLen != SL_POOL_IS_EMPTY) && (ResponseComplete) && (!ws_Flag)) 00307 { 00308 // HttpDebug("\r\n Http Client close\n\r"); 00309 HttpCore_CloseConnection(uConnection); 00310 continue; 00311 } 00312 else 00313 { 00314 HttpDebug("*"); 00315 // HttpDebug("Http receive retry %d\n\r",iRecvLen); 00316 g_state.connections[uConnection].timeout++; 00317 if(g_state.connections[uConnection].connectionState != WebSocketDataRecv) 00318 { 00319 if(g_state.connections[uConnection].timeout >= 60) //60 sec timeout 00320 { 00321 HttpCore_CloseConnection(uConnection); 00322 } 00323 } 00324 continue; 00325 } 00326 } 00327 } 00328 } 00329 else if(g_state.uOpenConnections == 0) 00330 { 00331 /* wait 500ms */ 00332 wait_ms(500); 00333 } 00334 } 00335 } 00336 } 00337 00338 /** 00339 * Reset open connection after finishing HTPP transaction 00340 */ 00341 static void HttpCore_ResetConnection(UINT16 uConnection) 00342 { 00343 g_state.connections[uConnection].uContentLeft = 0; 00344 g_state.connections[uConnection].uSavedBufferSize = 0; 00345 g_state.connections[uConnection].handler = None; 00346 g_state.connections[uConnection].request.requestContent.pData = NULL; 00347 g_state.connections[uConnection].request.requestContent.uLength = 0; 00348 g_state.connections[uConnection].request.uFlags = 0; 00349 } 00350 00351 /** 00352 * Initialize the server's global state structure 00353 */ 00354 static void HttpCore_InitWebServer() 00355 { 00356 UINT16 uConnection; 00357 g_state.packetRecvSize = 0; 00358 g_state.packetSendSize = 0; 00359 g_state.uOpenConnections = 0; 00360 g_state.listenSocket = -1; 00361 00362 for (uConnection = 0; uConnection < HTTP_CORE_MAX_CONNECTIONS; ++uConnection) 00363 { 00364 g_state.connections[uConnection].connectionState = Inactive; 00365 g_state.connections[uConnection].dataSocket = -1; 00366 g_state.connections[uConnection].request.uConnection = uConnection; 00367 g_state.connections[uConnection].HttpAuth = 0; 00368 HttpCore_ResetConnection(uConnection); 00369 } 00370 00371 } 00372 00373 00374 /** 00375 * Close a connection and clean up its state 00376 */ 00377 void HttpCore_CloseConnection(UINT16 uConnection) 00378 { 00379 // HttpDebug("\r\nClose connection\n\r"); 00380 00381 if(CloseTCPClientSocket(g_state.connections[uConnection].dataSocket) >= 0) 00382 { 00383 g_state.connections[uConnection].connectionState = Inactive; 00384 g_state.connections[uConnection].dataSocket = -1; 00385 g_state.connections[uConnection].HttpAuth = 0; 00386 g_state.connections[uConnection].timeout = 0; 00387 HttpCore_ResetConnection(uConnection); 00388 if(g_state.uOpenConnections > 0) 00389 g_state.uOpenConnections--; 00390 00391 /* Clear send and receive size for this connection */ 00392 g_state.packetRecvSize = 0; 00393 g_state.packetSendSize = 0; 00394 } 00395 } 00396 00397 /** 00398 * Getting the next line in the HTTP headers section 00399 * 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 00400 * The input is the connection and the remaining blob of the received packet 00401 * 00402 * @return zero if the whole packet was handled, and need to wait for more data (pLine is not set to anything yet) 00403 * negative if some error occurred, and the connection should be closed. 00404 * 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 00405 */ 00406 static int HttpCore_GetNextLine(UINT16 uConnection, struct HttpBlob* pCurrentLocation, struct HttpBlob* pLine) 00407 { 00408 UINT16 uLength; 00409 UINT8* nextLocation; 00410 00411 // Keep a pointer to the connection state object 00412 struct HttpConnectionData* pConnection = &g_state.connections[uConnection]; 00413 00414 // search for the line delimiter in the received data 00415 nextLocation = HttpString_nextDelimiter(HTTP_HEADER_DELIMITER, sizeof(HTTP_HEADER_DELIMITER)-1, *pCurrentLocation); 00416 uLength = (UINT16)(nextLocation - pCurrentLocation->pData); 00417 00418 if (pConnection->uSavedBufferSize > 0) 00419 { 00420 // There is previous saved data for this line, so need to concatenate 00421 if ((pConnection->headerStart[pConnection->uSavedBufferSize - 1] == '\r') && (pCurrentLocation->pData[0] == '\n')) 00422 { 00423 // Handle special case where the headers were splitted exactly at the delimiter 00424 pConnection->headerStart[pConnection->uSavedBufferSize + 1] = pCurrentLocation->pData[0]; 00425 pLine->pData = pConnection->headerStart; 00426 // Account for the excessive \r in the buffer 00427 pLine->uLength = pConnection->uSavedBufferSize - 1; 00428 pConnection->uSavedBufferSize = 0; 00429 // Advance the current location past this line 00430 pCurrentLocation->pData += 1; 00431 pCurrentLocation->uLength -= 1; 00432 return 1; 00433 } 00434 else 00435 { 00436 // There is saved data, and the delimiter is not split between packets 00437 if (nextLocation == NULL) 00438 { 00439 // No line delimiter was found in the current packet 00440 if ((pConnection->uSavedBufferSize + pCurrentLocation->uLength) < HTTP_CORE_MAX_HEADER_LINE_LENGTH) 00441 { 00442 // There is enough space to append remaining header into saved buffer 00443 memcpy(pConnection->headerStart + pConnection->uSavedBufferSize, pCurrentLocation->pData, pCurrentLocation->uLength); 00444 pConnection->uSavedBufferSize += pCurrentLocation->uLength; 00445 return 0; 00446 } 00447 else 00448 // There is not enough space in the saved buffer. This header line will be discarded 00449 if (pConnection->connectionState == RequestMethod) 00450 { 00451 // Connection awaits to receive the the HTTP method line 00452 // The method line cannot be discarded, drop the connection 00453 return -1; 00454 } 00455 else 00456 { 00457 // Connection awaits to receive the next header line which is not the method 00458 // Clean saved buffer, and drop this header line 00459 pConnection->uSavedBufferSize = 0; 00460 pConnection->connectionState = DropCurrentHeader; 00461 return 0; 00462 } 00463 } 00464 else 00465 { 00466 // Header line delimiter was found in the current packet 00467 if ((pConnection->uSavedBufferSize + uLength) < HTTP_CORE_MAX_HEADER_LINE_LENGTH) 00468 { 00469 // This header length is of legal size 00470 // Concatenate data from the saved buffer and the current packet 00471 memcpy(pConnection->headerStart + pConnection->uSavedBufferSize, pCurrentLocation->pData, uLength); 00472 pConnection->uSavedBufferSize += uLength; 00473 pLine->pData = pConnection->headerStart; 00474 pLine->uLength = pConnection->uSavedBufferSize; 00475 pConnection->uSavedBufferSize = 0; 00476 } 00477 else 00478 { 00479 // There is not enough space in the saved buffer. This header line will be discarded 00480 if (pConnection->connectionState == RequestMethod) 00481 { 00482 // Connection awaits to receive the the HTTP method line 00483 // The method line cannot be discarded, drop the connection 00484 return -1; 00485 } 00486 // Return an epmty line since the header is too long 00487 pLine->pData = NULL; 00488 pLine->uLength = 0; 00489 } 00490 // Advance the current location past this line 00491 pCurrentLocation->pData += uLength + sizeof(HTTP_HEADER_DELIMITER)-1; 00492 pCurrentLocation->uLength -= uLength + sizeof(HTTP_HEADER_DELIMITER)-1; 00493 return 1; 00494 00495 } 00496 } 00497 } 00498 else 00499 { 00500 // There is no previously saved data for this line 00501 if (nextLocation == NULL) 00502 { 00503 // No line delimiter was found in the current packet 00504 if (pCurrentLocation->uLength < HTTP_CORE_MAX_HEADER_LINE_LENGTH) 00505 { 00506 // There is enough space to append remaining header into saved buffer 00507 memcpy(pConnection->headerStart, pCurrentLocation->pData, pCurrentLocation->uLength); 00508 pConnection->uSavedBufferSize = pCurrentLocation->uLength; 00509 return 0; 00510 } 00511 else 00512 // There is not enough space in the saved buffer 00513 // This header line will be discarded 00514 if (pConnection->connectionState == RequestMethod) 00515 { 00516 // Connection awaits to receive the the HTTP method line 00517 // The method line cannot be discarded, drop the connection 00518 return -1; 00519 } 00520 else 00521 { 00522 // Connection awaits to receive the next header line which is not the method 00523 // Clean saved buffer, and drop this header line 00524 pConnection->uSavedBufferSize = 0; 00525 pConnection->connectionState = DropCurrentHeader; 00526 return 0; 00527 } 00528 } 00529 else 00530 { 00531 // Header line delimiter was found in the current packet 00532 if (uLength < HTTP_CORE_MAX_HEADER_LINE_LENGTH) 00533 { 00534 // This header length is of legal size 00535 // The whole line is in the packet buffer 00536 pLine->pData = pCurrentLocation->pData; 00537 pLine->uLength = uLength; 00538 } 00539 else 00540 { 00541 // There is not enough space to append remaining header into saved buffer 00542 if (pConnection->connectionState == RequestMethod) 00543 { 00544 // Connection awaits to receive the HTTP method line 00545 // The method line cannot be discarded, drop the connection 00546 return -1; 00547 } 00548 // Return an epmty line since the header is too long 00549 pLine->pData = NULL; 00550 pLine->uLength = 0; 00551 pConnection->connectionState = DropCurrentHeader; 00552 } 00553 // Advance the current location past this line 00554 pCurrentLocation->pData += uLength + sizeof(HTTP_HEADER_DELIMITER)-1; 00555 pCurrentLocation->uLength -= uLength + sizeof(HTTP_HEADER_DELIMITER)-1; 00556 return 1; 00557 } 00558 } 00559 } 00560 00561 00562 /** 00563 * The main state machine to handle an HTTP transaction 00564 * Every received data packet for a connection is passed to this function for parsing and handling 00565 * 00566 * If there is an error the connection will be closed in the end of the transaction 00567 * It will also be closed if "connection: close" header is received or HTTP version is 1.0 00568 * 00569 * @return zero to close the connection 00570 * nonzero if packet was consumed successfully, and the connection can handle more data 00571 */ 00572 static int HttpCore_HandleRequestPacket(UINT16 uConnection, struct HttpBlob packet) 00573 { 00574 struct HttpBlob currentLocation, line = {0, NULL}; 00575 int ret; 00576 00577 currentLocation.pData = packet.pData; 00578 currentLocation.uLength = packet.uLength; 00579 00580 // when no more data is left and the HTTP transaction is not complete then return to wait for more data 00581 while (1) 00582 { 00583 if (g_state.connections[uConnection].connectionState == RequestMethod || 00584 g_state.connections[uConnection].connectionState == RequestHeaders || 00585 g_state.connections[uConnection].connectionState == DropCurrentHeader|| 00586 g_state.connections[uConnection].connectionState == WebSocketRequest|| 00587 g_state.connections[uConnection].connectionState == WebSocketResponse|| 00588 g_state.connections[uConnection].connectionState == WebSocketDataRecv) 00589 { 00590 // Parsing HTTP headers 00591 int result; 00592 00593 // Move to WebSockHandler.c if we are in the DataRecv state 00594 if(g_state.connections[uConnection].connectionState == WebSocketDataRecv) 00595 if(WSCore_DataRecv(uConnection, &packet)) 00596 return 1; 00597 00598 // Respond to websocket handshake 00599 if(g_state.connections[uConnection].connectionState == WebSocketResponse) 00600 WSCore_HandshakeResponse(uConnection, line); 00601 00602 // The received blob is empty, return to wait for more data 00603 if ((currentLocation.uLength < 1)) 00604 { 00605 return 1; 00606 } 00607 00608 // Get next header line if available 00609 result = HttpCore_GetNextLine(uConnection, ¤tLocation, &line); 00610 00611 if(result > 0) 00612 // HttpDebug("line: %.*s \n\r", line.uLength, line.pData); 00613 00614 // Method line is too long, or some other error 00615 if (result < 0) 00616 return 0; 00617 00618 // Whole packet was consumed, and no line-break found. Wait for more data 00619 if (result == 0) 00620 return 1; 00621 00622 // Otherwise a new and legal header line is found 00623 } 00624 00625 switch (g_state.connections[uConnection].connectionState) 00626 { 00627 case DropCurrentHeader: 00628 g_state.connections[uConnection].connectionState = RequestHeaders; 00629 break; 00630 case RequestMethod: 00631 HttpAssert((line.pData != NULL) && (line.uLength > 0)); 00632 // If there is an error, then return error to drop the connection 00633 if (!HttpCore_HandleMethodLine(uConnection, line)) 00634 return 0; 00635 break; 00636 case RequestHeaders: 00637 if (!HttpCore_HandleHeaderLine(uConnection, line)) 00638 return 0; 00639 break; 00640 case WebSocketRequest: 00641 if (!WSCore_HandshakeRequest(uConnection, line)) 00642 return 0; 00643 break; 00644 case RequestData: 00645 ret = HttpCore_HandleRequestData(uConnection, ¤tLocation); 00646 if (ret == 0) 00647 return 1; 00648 else 00649 if (ret < 0) 00650 return 0; 00651 break; 00652 case Processing: 00653 // All the request data was received - start final processing of the headers and post data if exists 00654 switch (g_state.connections[uConnection].handler) 00655 { 00656 #ifdef HTTP_CORE_ENABLE_STATIC 00657 case HttpStatic: 00658 if(!HttpStatic_ProcessRequest(&g_state.connections[uConnection].request)) 00659 return 0; 00660 break; 00661 #endif 00662 #ifdef HTTP_CORE_ENABLE_DYNAMIC 00663 case HttpDynamic: 00664 if(!HttpDynamic_ProcessRequest(&g_state.connections[uConnection].request)) 00665 return 0; 00666 break; 00667 #endif 00668 default: 00669 HttpCore_ProcessNotFound(uConnection); 00670 break; 00671 } 00672 break; 00673 case ResponseData: 00674 // This state should never be reached, it is set internally during the processing 00675 HttpDebug("Response data state in request handling main loop!\n\r"); 00676 HttpAssert(0); 00677 break; 00678 case ResponseComplete: 00679 if ((g_state.connections[uConnection].request.uFlags & HTTP_REQUEST_FLAG_CLOSE)!=0 || 00680 (g_state.connections[uConnection].request.uFlags & HTTP_REQUEST_1_1) == 0) 00681 { 00682 // Connection should be closed - either "Connection: close" was received or the HTTP version is 1.0 00683 // Return 0 to close the connection 00684 return 0; 00685 } 00686 // The current HTTP transaction is complete - reset state for the next transaction on this connection 00687 g_state.connections[uConnection].connectionState = RequestMethod; 00688 HttpCore_ResetConnection(uConnection); 00689 break; 00690 default: 00691 HttpDebug("Bad state in HttpCore!\n\r"); 00692 HttpAssert(0); 00693 break; 00694 } 00695 } 00696 } 00697 00698 /** 00699 * This function handles connection initial state 00700 * Parse the first header line as a method header 00701 * 00702 * Method line should be in the form: 00703 * GET /resource.html HTTP/1.1\r\n 00704 * 00705 * @return nonzero if success 00706 */ 00707 static int HttpCore_HandleMethodLine(UINT16 uConnection, struct HttpBlob line) 00708 { 00709 struct HttpBlob resource; 00710 UINT8* methodLocation; 00711 UINT8* versionLocation; 00712 UINT16 uMethodLength; 00713 UINT8 method = 0; 00714 00715 00716 //UINT8* hostLocation; 00717 00718 // Search for GET token in the input blob 00719 methodLocation = HttpString_nextToken(HTTP_METHOD_GET, sizeof(HTTP_METHOD_GET)-1, line); 00720 uMethodLength = sizeof(HTTP_METHOD_GET)-1; 00721 if (methodLocation == NULL) 00722 { 00723 // The method is not GET 00724 // Search for the POST token in the input blob 00725 methodLocation = HttpString_nextToken(HTTP_METHOD_POST, sizeof(HTTP_METHOD_POST)-1, line); 00726 uMethodLength = sizeof(HTTP_METHOD_POST)-1; 00727 g_state.connections[uConnection].request.uFlags |= HTTP_REQUEST_FLAG_METHOD_POST; 00728 method = POST; // This means POST 00729 } 00730 else 00731 { 00732 // Method is GET 00733 g_state.connections[uConnection].request.requestContent.uLength = 0; 00734 g_state.connections[uConnection].request.uFlags &= ~HTTP_REQUEST_FLAG_METHOD_POST; 00735 method = GET; //This means GET 00736 } 00737 if (methodLocation != line.pData) 00738 { 00739 methodLocation = HttpString_nextToken(HTTP_METHOD_POST, sizeof(HTTP_METHOD_POST)-1, line); 00740 uMethodLength = sizeof(HTTP_METHOD_POST)-1; 00741 g_state.connections[uConnection].request.uFlags |= HTTP_REQUEST_FLAG_METHOD_POST; 00742 if(methodLocation == NULL || methodLocation != line.pData) 00743 { 00744 // Header does not begin line with GET or POST as it should 00745 HttpDebug("Unsupported method\n\r"); 00746 return 0; 00747 } 00748 } 00749 00750 // Search for "HTTP/1.1" version token 00751 versionLocation = HttpString_nextToken(HTTP_VERSION_1P1, sizeof(HTTP_VERSION_1P1)-1, line); 00752 // Version is 1.1 00753 if (versionLocation != NULL) 00754 g_state.connections[uConnection].request.uFlags |= HTTP_REQUEST_1_1; 00755 else 00756 { 00757 // Search for "HTTP/1.1" version token 00758 versionLocation = HttpString_nextToken(HTTP_VERSION_1P0, sizeof(HTTP_VERSION_1P0)-1, line); 00759 // Version is 1.0 00760 if (versionLocation != NULL) 00761 g_state.connections[uConnection].request.uFlags &= ~HTTP_REQUEST_1_1; 00762 else 00763 { 00764 HttpDebug("Bad protocol version\n\r"); 00765 return 0; 00766 } 00767 } 00768 00769 HttpDebug("method Header: %.*s \n\r", line.uLength, line.pData); 00770 00771 // Find the URL part of the header 00772 resource.pData = methodLocation + uMethodLength + 1; 00773 resource.uLength = (UINT16)(versionLocation - (methodLocation + uMethodLength + 1) - 1); 00774 00775 // Determine which handler is supposed to handle this request 00776 // The handler functions are called according to a hardcoded priority - dynamic, static, default 00777 // The first handler that returns non zero will handle this request 00778 #ifdef HTTP_CORE_ENABLE_STATIC 00779 if (HttpStatic_InitRequest(uConnection, resource) != 0) 00780 g_state.connections[uConnection].handler = HttpStatic; 00781 else 00782 #endif 00783 #ifdef HTTP_CORE_ENABLE_DYNAMIC 00784 if (HttpDynamic_InitRequest(uConnection, resource,method) != 0) 00785 g_state.connections[uConnection].handler = HttpDynamic; 00786 else 00787 #endif 00788 g_state.connections[uConnection].handler = None; 00789 g_state.connections[uConnection].connectionState = RequestHeaders; 00790 return 1; 00791 } 00792 00793 /** 00794 * Handle The HTTP headers (after method) one by one 00795 * If an empty header is received then the headers section is complete 00796 * Searches for the headers tokens. If important data is found then it is saved in the connection object 00797 * 00798 * returns nonzero if sucessful 00799 */ 00800 static int HttpCore_HandleHeaderLine(UINT16 uConnection, struct HttpBlob line) 00801 { 00802 struct HttpBlob blobValue; 00803 UINT8* pFound; 00804 UINT32 length; 00805 00806 // NULL line is received when a header line is too long. 00807 if (line.pData == NULL){ 00808 HttpDebug("Header line is too long.\n\r"); 00809 return 1; 00810 } 00811 // Length is 0, this means than End-Of-Headers marker was reached 00812 // State of this connection is set to RequestData 00813 if (line.uLength == 0) 00814 { 00815 g_state.connections[uConnection].connectionState = RequestData; 00816 return 1; 00817 } 00818 00819 //Upgrade: websocket 00820 //if(g_state.connections[uConnection].request.uFlags == (~HTTP_REQUEST_FLAG_METHOD_POST)|HTTP_REQUEST_1_1) 00821 //{ 00822 if (HttpString_nextToken(WS_UPGRADE, sizeof(WS_UPGRADE)-1, line) == line.pData) 00823 { 00824 line.pData += sizeof(WS_UPGRADE)-1 + 1; 00825 line.uLength -= sizeof(WS_UPGRADE)-1 + 1; 00826 pFound = HttpString_nextToken(WS_WEBSOCKET, sizeof(WS_WEBSOCKET)-1, line); 00827 if (pFound != NULL) 00828 { 00829 g_state.connections[uConnection].connectionState = WebSocketRequest; 00830 return 1; 00831 } 00832 else 00833 return 0; 00834 } 00835 //} 00836 00837 // If "Accept-encoding" header then set or clear HTTP_REQUEST_FLAG_ACCEPT_GZIP flag 00838 if (HttpString_nextToken(HTTP_ACCEPT_ENCODING, sizeof(HTTP_ACCEPT_ENCODING)-1, line) == line.pData) 00839 { 00840 line.pData += sizeof(HTTP_ACCEPT_ENCODING)-1 + 2; 00841 line.uLength -= sizeof(HTTP_ACCEPT_ENCODING)-1 + 2; 00842 pFound = HttpString_nextToken(HTTP_GZIP, sizeof(HTTP_GZIP)-1, line); 00843 if (pFound != NULL) 00844 g_state.connections[uConnection].request.uFlags |= HTTP_REQUEST_FLAG_ACCEPT_GZIP; 00845 else 00846 g_state.connections[uConnection].request.uFlags &= ~HTTP_REQUEST_FLAG_ACCEPT_GZIP; 00847 return 1; 00848 } 00849 00850 // If "Content-Length" header then parse the lenght and set uContentLeft to it 00851 // GET and POST method behave the same 00852 if (HttpString_nextToken(HTTP_CONTENT_LENGTH, sizeof(HTTP_CONTENT_LENGTH)-1, line) == line.pData) 00853 { 00854 line.pData += sizeof(HTTP_CONTENT_LENGTH)-1 + 2; 00855 line.uLength -= sizeof(HTTP_CONTENT_LENGTH)-1 + 2; 00856 blobValue.pData = line.pData; 00857 blobValue.uLength = line.uLength - 2; 00858 length = HttpString_atou(blobValue); 00859 g_state.connections[uConnection].uContentLeft = length; 00860 // Set ignore flag 00861 if (g_state.connections[uConnection].uContentLeft > HTTP_CORE_MAX_HEADER_LINE_LENGTH) 00862 g_state.connections[uConnection].request.uFlags |= HTTP_REQUEST_CONTENT_IGNORED; 00863 // Prepare the request blob to buffer the content 00864 g_state.connections[uConnection].request.requestContent.pData = g_state.connections[uConnection].headerStart; 00865 g_state.connections[uConnection].request.requestContent.uLength = 0; 00866 return 1; 00867 } 00868 // If "Connection" header then look for "close" and set or clear HTTP_REQUEST_FLAG_CLOSE flag 00869 // The default behaviour for keep alive or no such header is to keep the connection open in http version 1.1 00870 // In http version 1.0 the default behavior is to always close the socket 00871 if (HttpString_nextToken(HTTP_CONNECTION_CLOSE, sizeof(HTTP_CONNECTION_CLOSE)-1, line) == line.pData) 00872 { 00873 line.pData += sizeof(HTTP_CONNECTION_CLOSE)-1 + 2; 00874 line.uLength -= sizeof(HTTP_CONNECTION_CLOSE)-1 + 2; 00875 pFound = HttpString_nextToken(HTTP_CLOSE, sizeof(HTTP_CLOSE)-1, line); 00876 if (pFound != 0) 00877 g_state.connections[uConnection].request.uFlags |= HTTP_REQUEST_FLAG_CLOSE; 00878 else 00879 g_state.connections[uConnection].request.uFlags &= ~HTTP_REQUEST_FLAG_CLOSE; 00880 return 1; 00881 } 00882 // If "Authorization" header the handle authentication 00883 if (HttpString_nextToken(HTTP_AUTHORIZATION, sizeof(HTTP_AUTHORIZATION)-1, line) == line.pData) 00884 { 00885 line.pData += sizeof(HTTP_AUTHORIZATION)-1 + 2; 00886 line.uLength -= sizeof(HTTP_AUTHORIZATION)-1 + 2; 00887 blobValue.pData = line.pData; 00888 blobValue.uLength = line.uLength; 00889 //TODO: handle the case when we don't support authentication 00890 #ifdef HTTP_CORE_ENABLE_AUTH 00891 HttpAuth_RequestAuthenticate(&g_state.connections[uConnection].request, blobValue); 00892 #endif 00893 return 1; 00894 } 00895 // None of the above mentioned headers was recognized so just ignore this header 00896 return 1; 00897 } 00898 00899 /** 00900 * Handle The WebSocket headers (after method) one by one 00901 * If an empty header is received then the headers section is complete 00902 * Searches for the headers tokens. If important data is found then it is saved in the connection object 00903 * 00904 * returns nonzero if sucessful 00905 */ 00906 static int WSCore_HandshakeRequest(UINT16 uConnection,struct HttpBlob line) 00907 { 00908 UINT8* pFound; 00909 UINT8 bRetVal = 1; 00910 static UINT16 Origin = 0; 00911 char *dataCopy = (char *)malloc(strlen((const char *)line.pData)); 00912 memset(dataCopy,'\0',strlen((const char *)line.pData)); 00913 memcpy(dataCopy,(const char *)line.pData,strlen((const char *)line.pData)); 00914 00915 // NULL line is received when a header line is too long. 00916 if (line.pData == NULL) 00917 { 00918 HttpDebug("Header line is too long.\n\r"); 00919 bRetVal = 0; 00920 goto exit; 00921 } 00922 00923 // Length is 0, this means than End-Of-Headers marker was reached 00924 // State of this connection is set to WebSocketResponse 00925 if (line.uLength == 0) 00926 { 00927 g_state.connections[uConnection].connectionState = WebSocketResponse; 00928 bRetVal = 1; 00929 goto exit; 00930 } 00931 ws_Flag = 1; 00932 //Connection: Upgrade 00933 if (HttpString_nextToken(WS_CONNECTION, sizeof(WS_CONNECTION)-1, line) == line.pData) 00934 { 00935 line.pData += sizeof(WS_CONNECTION) + 1; 00936 line.uLength -= sizeof(WS_CONNECTION) + 1; 00937 pFound = HttpString_nextToken(WS_UPGRADE, sizeof(WS_UPGRADE)-1, line); 00938 if (pFound != NULL) 00939 bRetVal = 1; 00940 else{ 00941 HttpDebug("WS_UPGRADE failed.\n\r"); 00942 bRetVal = 0; 00943 } 00944 goto exit; 00945 } 00946 00947 //host: IP address 00948 if (HttpString_nextToken(WS_HOST, sizeof(WS_HOST)-1, line) == line.pData) 00949 { 00950 line.pData += sizeof(WS_HOST) + 1; 00951 line.uLength -= sizeof(WS_HOST) + 1; 00952 bRetVal = 1; 00953 goto exit; 00954 } 00955 00956 //Sec-WebSocket-Key: "Client generated key" 00957 if (HttpString_nextToken(WS_KEY_REQUEST, sizeof(WS_KEY_REQUEST)-1, line) == line.pData) 00958 { 00959 memcpy(line.pData,dataCopy,strlen((const char *)line.pData)); 00960 // We increment twice to circumvent ':' and ' ' and point at the beginning of the key in base64 encoding 00961 line.pData += sizeof(WS_KEY_REQUEST) + 1; 00962 line.uLength -= sizeof(WS_KEY_REQUEST) + 1; 00963 memset(WS_KEY,'\0',WS_KEY_LENGTH+1); 00964 memcpy(WS_KEY,line.pData,WS_KEY_LENGTH); 00965 HttpDebug("key: %s \n\r", WS_KEY); 00966 if (WS_KEY != NULL) 00967 { 00968 bRetVal = 1; 00969 goto exit; 00970 } 00971 } 00972 00973 //Sec-WebSocket-Version = 13 00974 if (HttpString_nextToken(WS_VERSION_REQUEST, sizeof(WS_VERSION_REQUEST)-1, line) == line.pData) 00975 { 00976 line.pData += sizeof(WS_VERSION_REQUEST) + 1; 00977 line.uLength -= sizeof(WS_VERSION_REQUEST) + 1; 00978 pFound = HttpString_nextToken(WS_VERSION, sizeof(WS_VERSION)-1, line); 00979 if (pFound != NULL) 00980 { 00981 bRetVal = 1; 00982 goto exit; 00983 } 00984 } 00985 00986 //Sec-WebSocket-Extension - Later versions may support -TODO 00987 if (HttpString_nextToken(WS_EXTENSION, sizeof(WS_EXTENSION)-1, line) == line.pData) 00988 { 00989 line.pData += sizeof(WS_EXTENSION) + 1; 00990 line.uLength -= sizeof(WS_EXTENSION) + 1; 00991 bRetVal = 1; 00992 goto exit; 00993 } 00994 00995 //pragma field - TODO 00996 if (HttpString_nextToken(WS_PRAGMA, sizeof(WS_PRAGMA)-1, line) == line.pData) 00997 { 00998 line.pData += sizeof(WS_PRAGMA) + 1; 00999 line.uLength -= sizeof(WS_PRAGMA) + 1; 01000 bRetVal = 1; 01001 goto exit; 01002 } 01003 01004 //cache-control field - TODO 01005 if (HttpString_nextToken(WS_CACHE_CONTROL, sizeof(WS_CACHE_CONTROL)-1, line) == line.pData) 01006 { 01007 line.pData += sizeof(WS_CACHE_CONTROL) + 1; 01008 line.uLength -= sizeof(WS_CACHE_CONTROL) + 1; 01009 bRetVal = 1; 01010 goto exit; 01011 } 01012 01013 //Origin 01014 // If this header field doesn't exist, the client is not a browser. Flag will be set accordingly. 01015 // The server may block communication with an origin it does not validate by sending HTTP error code - Not implemented 01016 // If it doesn't recognise the origin it will accept data packets from anywhere 01017 if(Origin == 0) 01018 { 01019 if (HttpString_nextToken(WS_ORIGIN, sizeof(WS_ORIGIN)-1, line) == line.pData) 01020 { 01021 line.pData += sizeof(WS_ORIGIN) + 1; 01022 line.uLength -= sizeof(WS_ORIGIN) + 1; 01023 g_state.connections[uConnection].request.uFlags |= WS_REQUEST_BROWSER; 01024 WS_ORIGIN_NAME = (char *)realloc(WS_ORIGIN_NAME, line.uLength+1); 01025 if(WS_ORIGIN_NAME == NULL) 01026 { 01027 HttpDebug("WS_ORIGIN_NAME = NULL Error \n\r"); 01028 bRetVal = 0; 01029 goto exit; 01030 } 01031 memset(WS_ORIGIN_NAME,'\0',line.uLength+1); 01032 memcpy(WS_ORIGIN_NAME,line.pData,line.uLength); 01033 Origin = 1; 01034 } 01035 else 01036 { 01037 g_state.connections[uConnection].request.uFlags &= ~WS_REQUEST_BROWSER; 01038 HttpDebug("Non Browser Client\n"); 01039 } 01040 } 01041 exit: 01042 free(dataCopy); 01043 return bRetVal; 01044 //Sec-WebSocket-Protocol and Extensions not implemented - Optional 01045 01046 } 01047 01048 01049 /** 01050 * Handles request data for this transaction 01051 * Behaves the same for POST and GET methods - 01052 * If content length header was present then read the content for further processing 01053 * If the content is too long then ignore it 01054 * 01055 * @return 1 if successful, pData is updated to skip the handled data 01056 0 if all data is consumed and need to read more data 01057 * negative if an error occurs and the connection should be closed. 01058 */ 01059 static int HttpCore_HandleRequestData(UINT16 uConnection, struct HttpBlob* pData) 01060 { 01061 UINT32 uLengthToHandle; 01062 01063 if (g_state.connections[uConnection].uContentLeft == 0) 01064 { 01065 HttpDebug("Received content. Length=%d, content:\r\n%.*s \n\r", g_state.connections[uConnection].request.requestContent.uLength, g_state.connections[uConnection].request.requestContent.uLength, g_state.connections[uConnection].headerStart); 01066 g_state.connections[uConnection].connectionState = Processing; 01067 return 1; 01068 } 01069 01070 // Find minimum between the content left to handle and the current blob 01071 uLengthToHandle = g_state.connections[uConnection].uContentLeft; 01072 if (uLengthToHandle > pData->uLength) 01073 uLengthToHandle = pData->uLength; 01074 01075 // If no new data is received - return and wait for more 01076 if (uLengthToHandle == 0) 01077 return 0; 01078 01079 if ( (g_state.connections[uConnection].request.uFlags & HTTP_REQUEST_CONTENT_IGNORED) != 0) 01080 { 01081 // Ignore Content 01082 pData->pData += uLengthToHandle; 01083 pData->uLength -= (UINT16)uLengthToHandle; 01084 g_state.connections[uConnection].uContentLeft -= uLengthToHandle; 01085 } 01086 else 01087 { 01088 // Read content 01089 memcpy(g_state.connections[uConnection].headerStart + g_state.connections[uConnection].request.requestContent.uLength, pData->pData, uLengthToHandle); 01090 pData->pData += uLengthToHandle; 01091 pData->uLength -= (UINT16)uLengthToHandle; 01092 g_state.connections[uConnection].uContentLeft -= uLengthToHandle; 01093 g_state.connections[uConnection].request.requestContent.uLength += (UINT16)uLengthToHandle; 01094 } 01095 01096 return 1; 01097 } 01098 01099 /** 01100 * Returns HTTP 404 not found response 01101 */ 01102 static void HttpCore_ProcessNotFound(UINT16 uConnection) 01103 { 01104 // call HttpResponse_CannedError with 404 NOT_FOUND 01105 HttpResponse_CannedError(uConnection, HTTP_STATUS_ERROR_NOT_FOUND); 01106 } 01107 01108 /** 01109 * Sends the input blob over the connection socket 01110 */ 01111 static int HttpCore_SendPacket(UINT16 uConnection, struct HttpBlob buffer) 01112 { 01113 // Send the buffer over the data socket until all the buffer is sent 01114 while (buffer.uLength > 0) 01115 { 01116 int sent; 01117 01118 //Don't print more than what can be allocated 01119 //if(buffer.uLength < 32767) 01120 // HttpDebug("line: %.*s \n\r", buffer.uLength, buffer.pData); 01121 01122 if(buffer.uLength > HTTP_CORE_MAX_PACKET_SIZE_SEND) 01123 { 01124 if(buffer.pData != g_state.packetSend) 01125 { 01126 memcpy((void *)&g_state.packetSend[0],(void *)buffer.pData, HTTP_CORE_MAX_PACKET_SIZE_SEND); 01127 } 01128 else 01129 { 01130 HttpAssert(0); 01131 } 01132 sent = ClientSocketSend(g_state.connections[uConnection].dataSocket, (char*)g_state.packetSend, HTTP_CORE_MAX_PACKET_SIZE_SEND); 01133 if (sent <= 0) 01134 { 01135 Uart_Write((uint8_t*)"ClientSocketSend failed \n\r"); 01136 // Connection must be closed if send has failed 01137 return 0; 01138 } 01139 } 01140 else 01141 { 01142 if(buffer.pData != g_state.packetSend) 01143 { 01144 memcpy((void *)&g_state.packetSend[0],(void *)buffer.pData, buffer.uLength); 01145 } 01146 01147 sent = ClientSocketSend(g_state.connections[uConnection].dataSocket, (char*)g_state.packetSend, buffer.uLength); 01148 if (sent <= 0) 01149 { 01150 Uart_Write((uint8_t*)"ClientSocketSend failed \n\r"); 01151 // Connection must be closed if send has failed 01152 return 0; 01153 } 01154 } 01155 buffer.pData += sent; 01156 buffer.uLength -= (UINT16)sent; 01157 } 01158 return 1; 01159 } 01160 01161 /** 01162 * Add char to the response buffer 01163 */ 01164 void HttpResponse_AddCharToResponseHeaders(char ch) 01165 { 01166 //add char 01167 g_state.packetSend[g_state.packetSendSize] = ch; 01168 g_state.packetSendSize++; 01169 } 01170 01171 /** 01172 * Add UINT32 number to the response buffer 01173 */ 01174 static void HttpResponse_AddNumberToResponseHeaders(UINT32 num) 01175 { 01176 struct HttpBlob resource; 01177 resource.pData = g_state.packetSend + g_state.packetSendSize; 01178 resource.uLength = 0; 01179 HttpString_utoa(num, &resource); 01180 g_state.packetSendSize += resource.uLength; 01181 } 01182 01183 /** 01184 * Add a string to the response buffer 01185 */ 01186 void HttpResponse_AddStringToResponseHeaders(char * str, UINT16 len) 01187 { 01188 memcpy(g_state.packetSend + g_state.packetSendSize, str, len); 01189 g_state.packetSendSize += len; 01190 } 01191 01192 /** 01193 * Add header line to response buffer 01194 * Adds a line to the header with the provided name value pair 01195 * Precondition to this function is that g_state.packetSendSize and g_state.packetSend are correct 01196 */ 01197 static void HttpResponse_AddHeaderLine(char * headerName, UINT16 headerNameLen, char * headerValue, UINT16 headerValueLen) 01198 { 01199 HttpResponse_AddStringToResponseHeaders(headerName, headerNameLen); 01200 HttpResponse_AddCharToResponseHeaders(':'); 01201 HttpResponse_AddCharToResponseHeaders(' '); 01202 HttpResponse_AddStringToResponseHeaders(headerValue, headerValueLen); 01203 HttpResponse_AddStringToResponseHeaders(HTTP_HEADER_DELIMITER, sizeof(HTTP_HEADER_DELIMITER)-1); 01204 } 01205 01206 /** 01207 * Add Header line to response buffer 01208 * Adds a line to the header with the provided name value pair when the value is numeric 01209 * precondition to this function is that g_state.packetSendSize and g_state.packetSend are correct 01210 */ 01211 static void HttpResponse_AddHeaderLineNumValue(char * headerName, UINT16 uHeaderNameLen, UINT32 headerValue) 01212 { 01213 HttpResponse_AddStringToResponseHeaders(headerName, uHeaderNameLen); 01214 HttpResponse_AddCharToResponseHeaders(':'); 01215 HttpResponse_AddCharToResponseHeaders(' '); 01216 HttpResponse_AddNumberToResponseHeaders(headerValue); 01217 HttpResponse_AddStringToResponseHeaders(HTTP_HEADER_DELIMITER, sizeof(HTTP_HEADER_DELIMITER)-1); 01218 } 01219 01220 /** 01221 * Returns status string according to status code 01222 */ 01223 static void HttpStatusString(UINT16 uHttpStatus, struct HttpBlob* status) 01224 { 01225 switch (uHttpStatus) 01226 { 01227 case HTTP_STATUS_OK: 01228 HttpBlobSetConst(*status, HTTP_STATUS_OK_STR); 01229 break; 01230 case HTTP_STATUS_REDIRECT_PERMANENT: 01231 HttpBlobSetConst(*status, HTTP_STATUS_REDIRECT_PERMANENT_STR); 01232 break; 01233 case HTTP_STATUS_REDIRECT_TEMPORARY: 01234 HttpBlobSetConst(*status, HTTP_STATUS_REDIRECT_TEMPORARY_STR); 01235 break; 01236 case HTTP_STATUS_ERROR_UNAUTHORIZED: 01237 HttpBlobSetConst(*status, HTTP_STATUS_ERROR_UNAUTHORIZED_STR); 01238 break; 01239 case HTTP_STATUS_ERROR_NOT_FOUND: 01240 HttpBlobSetConst(*status, HTTP_STATUS_ERROR_NOT_FOUND_STR); 01241 break; 01242 case HTTP_STATUS_ERROR_NOT_ACCEPTED: 01243 HttpBlobSetConst(*status, HTTP_STATUS_ERROR_NOT_ACCEPTED_STR); 01244 break; 01245 case HTTP_STATUS_ERROR_INTERNAL: 01246 HttpBlobSetConst(*status, HTTP_STATUS_ERROR_INTERNAL_STR); 01247 break; 01248 default: 01249 HttpDebug("Unknown response status \n\r"); 01250 HttpAssert(0); 01251 break; 01252 } 01253 } 01254 01255 int HttpResponse_Headers(UINT16 uConnection, UINT16 uHttpStatus, UINT16 uFlags, UINT32 uContentLength, struct HttpBlob contentType, struct HttpBlob location) 01256 { 01257 struct HttpBlob status; 01258 struct HttpBlob packet; 01259 HttpAssert(g_state.packetSendSize == 0); 01260 HttpAssert(g_state.connections[uConnection].connectionState == Processing); 01261 01262 // Get status string according to uHttpStatus 01263 HttpStatusString(uHttpStatus, &status); 01264 01265 // 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" 01266 // For example: HTTP/1.1 200 OK\r\n 01267 01268 // Add http version to sent packet according to the version that was received in the request 01269 if ( (g_state.connections[uConnection].request.uFlags & HTTP_REQUEST_1_1) != 0) 01270 HttpResponse_AddStringToResponseHeaders(HTTP_VERSION_1P1, sizeof(HTTP_VERSION_1P1)-1); 01271 else 01272 HttpResponse_AddStringToResponseHeaders(HTTP_VERSION_1P0, sizeof(HTTP_VERSION_1P0)-1); 01273 HttpResponse_AddCharToResponseHeaders(' '); 01274 HttpResponse_AddNumberToResponseHeaders(uHttpStatus); 01275 HttpResponse_AddCharToResponseHeaders(' '); 01276 HttpResponse_AddStringToResponseHeaders((char*)status.pData, status.uLength); 01277 HttpResponse_AddStringToResponseHeaders(HTTP_HEADER_DELIMITER, sizeof(HTTP_HEADER_DELIMITER)-1); 01278 01279 01280 // Handle Authentication 01281 if (uHttpStatus == HTTP_STATUS_ERROR_UNAUTHORIZED) 01282 { 01283 #ifdef HTTP_CORE_ENABLE_AUTH 01284 HttpResponse_GetPacketSendBuffer(&packet); 01285 packet.pData = packet.pData + packet.uLength; 01286 packet.uLength = HTTP_CORE_MAX_PACKET_SIZE_SEND - packet.uLength; 01287 HttpAuth_ResponseAuthenticate(&g_state.connections[uConnection].request, &packet); 01288 if (packet.uLength > 0) 01289 g_state.packetSendSize += packet.uLength; 01290 #endif 01291 } 01292 01293 // Handle content type 01294 // e.g. "Content-Type: text/html\r\n" 01295 if ((contentType.pData != NULL) && (contentType.uLength > 0)) 01296 HttpResponse_AddHeaderLine(HTTP_CONTENT_TYPE, sizeof(HTTP_CONTENT_TYPE)-1, (char*)contentType.pData, contentType.uLength); 01297 01298 // Handle Content-length 01299 // e.g. "Content-Length: 562\r\n" 01300 if (uContentLength > 0) 01301 HttpResponse_AddHeaderLineNumValue(HTTP_CONTENT_LENGTH, sizeof(HTTP_CONTENT_LENGTH)-1, uContentLength); 01302 g_state.connections[uConnection].uContentLeft = uContentLength; 01303 01304 // Handle compression 01305 // e.g. "Content-Encoding: gzip\r\n" 01306 if ((uFlags & HTTP_RESPONSE_FLAG_COMPRESSED) != 0) 01307 HttpResponse_AddHeaderLine(HTTP_CONTENT_ENCODING, sizeof(HTTP_CONTENT_ENCODING)-1, HTTP_GZIP, sizeof(HTTP_GZIP)-1); 01308 01309 // Handle redirection/Location 01310 // e.g. "Location: /otherpage.html\r\n" 01311 if ((location.pData != NULL) && (location.uLength > 0)) 01312 HttpResponse_AddHeaderLine(HTTP_LOCATION, sizeof(HTTP_LOCATION)-1, (char*)location.pData, location.uLength); 01313 01314 // Add the end of headers marker (\r\n) 01315 HttpResponse_AddStringToResponseHeaders(HTTP_HEADER_DELIMITER, sizeof(HTTP_HEADER_DELIMITER)-1); 01316 01317 // Send all response headers over the connection socket 01318 packet.pData = g_state.packetSend; 01319 packet.uLength = g_state.packetSendSize; 01320 if(!HttpCore_SendPacket(uConnection, packet)) 01321 return 0; 01322 01323 g_state.packetSendSize = 0; 01324 01325 // advance state according to need to send content 01326 if (uContentLength > 0) 01327 g_state.connections[uConnection].connectionState = ResponseData; 01328 else 01329 g_state.connections[uConnection].connectionState = ResponseComplete; 01330 01331 /* 01332 Todo: add logic to send the header packet at any point in the middle, if there is not enough room left in it. 01333 */ 01334 return 1; 01335 } 01336 01337 void HttpResponse_GetPacketSendBuffer(struct HttpBlob* pPacketSendBuffer) 01338 { 01339 pPacketSendBuffer->pData = g_state.packetSend; 01340 pPacketSendBuffer->uLength = g_state.packetSendSize; 01341 } 01342 01343 int HttpResponse_Content(UINT16 uConnection, struct HttpBlob content) 01344 { 01345 HttpAssert(g_state.connections[uConnection].connectionState == ResponseData); 01346 HttpAssert(g_state.connections[uConnection].uContentLeft >= content.uLength); 01347 01348 // Send the specified content over the data socket 01349 if(!HttpCore_SendPacket(uConnection, content)) 01350 return 0; 01351 01352 // Update uContentLeft 01353 g_state.connections[uConnection].uContentLeft -= content.uLength; 01354 01355 // If no more content left to send then HTTP transaction is complete 01356 if (g_state.connections[uConnection].uContentLeft == 0) 01357 g_state.connections[uConnection].connectionState = ResponseComplete; 01358 01359 return 1; 01360 } 01361 01362 /* 01363 * This function creates a response handshake. 01364 * 1. Version 1.1 01365 * 2. Upgrade, connection 01366 * 3. SHA-1 algo for accept key 01367 * Send Packet 01368 * @ return : Non zero value if successful 01369 0 if failure 01370 */ 01371 int WSCore_HandshakeResponse(UINT16 uConnection, struct HttpBlob line) 01372 { 01373 UINT16 WS_STATUS_CODE = 101; 01374 char WS_HEADER[] = "Web Socket Protocol Handshake"; 01375 struct HttpBlob packet; 01376 char InKey[WS_KEY_LENGTH + sizeof(WS_MAGIC_STRING)+1]; 01377 char OutKey[WS_KEY_LENGTH + sizeof(WS_MAGIC_STRING) + 1]; 01378 char EncOutKey[WS_KEY_LENGTH + sizeof(WS_MAGIC_STRING) + 1];; 01379 01380 // InKey is the key client sent. It is concatenated with magic string stored in server. 01381 // OutKey is SHA-1 output of InKey 01382 // EncOutKey is OutKey after base64 encoding. 01383 memset(InKey,'\0',WS_KEY_LENGTH + sizeof(WS_MAGIC_STRING)+1); 01384 memcpy(InKey,(const char*)WS_KEY,strlen((const char*)WS_KEY)); 01385 memset(OutKey,'\0',WS_KEY_LENGTH + sizeof(WS_MAGIC_STRING) + 1); 01386 memset(EncOutKey,'\0',WS_KEY_LENGTH + sizeof(WS_MAGIC_STRING) + 1); 01387 strncat(InKey,WS_MAGIC_STRING, sizeof(WS_MAGIC_STRING)); 01388 01389 // The header field stating this is HTTP version 1.1. Version 1.0 is not supported by WebSockets 01390 // Status code 101 shows successful handshake. 01391 01392 // HTTP 1.1 101 Web Socket Protocol Handshake 01393 HttpResponse_AddStringToResponseHeaders(HTTP_VERSION_1P1, strlen(HTTP_VERSION_1P1)); 01394 HttpResponse_AddCharToResponseHeaders(' '); 01395 HttpResponse_AddNumberToResponseHeaders(WS_STATUS_CODE); 01396 HttpResponse_AddCharToResponseHeaders(' '); 01397 HttpResponse_AddStringToResponseHeaders(WS_HEADER, strlen(WS_HEADER)); 01398 HttpResponse_AddStringToResponseHeaders(HTTP_HEADER_DELIMITER, strlen(HTTP_HEADER_DELIMITER)); 01399 01400 // The Upgrade token tells the client we are moving to websocket protocol. 01401 HttpResponse_AddStringToResponseHeaders("Upgrade", strlen("Upgrade")); 01402 HttpResponse_AddCharToResponseHeaders(':'); 01403 HttpResponse_AddCharToResponseHeaders(' '); 01404 HttpResponse_AddStringToResponseHeaders(WS_WEBSOCKET, strlen(WS_WEBSOCKET)); 01405 HttpResponse_AddStringToResponseHeaders(HTTP_HEADER_DELIMITER, strlen(HTTP_HEADER_DELIMITER)); 01406 01407 // Connection: upgrade 01408 HttpResponse_AddStringToResponseHeaders("Connection", strlen("Connection")); 01409 HttpResponse_AddCharToResponseHeaders(':'); 01410 HttpResponse_AddCharToResponseHeaders(' '); 01411 HttpResponse_AddStringToResponseHeaders("Upgrade", strlen("Upgrade")); 01412 HttpResponse_AddStringToResponseHeaders(HTTP_HEADER_DELIMITER, strlen(HTTP_HEADER_DELIMITER)); 01413 01414 // This is where the client sent key is first sent to SHA-1 hash and then base 64 encoded. 01415 // The sent key must match what the client expects. Otherwise connection will be dropped immediately by client. 01416 HttpResponse_AddStringToResponseHeaders(WS_ACCEPT, strlen(WS_ACCEPT)); 01417 HttpResponse_AddCharToResponseHeaders(':'); 01418 HttpResponse_AddCharToResponseHeaders(' '); 01419 if(!WS_HandshakeHash(InKey,OutKey,EncOutKey)){ 01420 HttpDebug("WS_HandshakeHash failed\n\r"); 01421 return 0; 01422 } 01423 //CHANGE to KEY after SHA-1 Algorithm 01424 HttpResponse_AddStringToResponseHeaders(EncOutKey, strlen(EncOutKey)); 01425 HttpResponse_AddStringToResponseHeaders(HTTP_HEADER_DELIMITER, strlen(HTTP_HEADER_DELIMITER)); 01426 01427 // Server : CC3100 01428 // This field informs the client the server name 01429 HttpResponse_AddStringToResponseHeaders("Server", strlen("Server")); 01430 HttpResponse_AddCharToResponseHeaders(':'); 01431 HttpResponse_AddCharToResponseHeaders(' '); 01432 HttpResponse_AddStringToResponseHeaders("CC3100", strlen("CC3100")); 01433 HttpResponse_AddStringToResponseHeaders(HTTP_HEADER_DELIMITER, strlen(HTTP_HEADER_DELIMITER)); 01434 01435 // This is the same origin supplied by the client. The origin tells the server whether the client is a browser or not. 01436 // Use this header only on URL's that need to be accessed cross domain. Avoid using for entire domain. 01437 HttpResponse_AddStringToResponseHeaders("Access-Control-Allow-Origin", strlen("Access-Control-Allow-Origin")); 01438 HttpResponse_AddCharToResponseHeaders(':'); 01439 HttpResponse_AddCharToResponseHeaders(' '); 01440 HttpResponse_AddStringToResponseHeaders(WS_ORIGIN_NAME, strlen(WS_ORIGIN_NAME)); 01441 HttpResponse_AddStringToResponseHeaders(HTTP_HEADER_DELIMITER, strlen(HTTP_HEADER_DELIMITER)); 01442 01443 HttpResponse_AddStringToResponseHeaders("Access-Control-Allow-Credentials", strlen("Access-Control-Allow-Credentials")); 01444 HttpResponse_AddCharToResponseHeaders(':'); 01445 HttpResponse_AddCharToResponseHeaders(' '); 01446 HttpResponse_AddStringToResponseHeaders("true", strlen("true")); 01447 HttpResponse_AddStringToResponseHeaders(HTTP_HEADER_DELIMITER, strlen(HTTP_HEADER_DELIMITER)); 01448 01449 HttpResponse_AddStringToResponseHeaders("Access-Control-Allow-Headers", strlen("Access-Control-Allow-Headers")); 01450 HttpResponse_AddCharToResponseHeaders(':'); 01451 HttpResponse_AddCharToResponseHeaders(' '); 01452 HttpResponse_AddStringToResponseHeaders("content-type", strlen("content-type")); 01453 HttpResponse_AddStringToResponseHeaders(HTTP_HEADER_DELIMITER, strlen(HTTP_HEADER_DELIMITER)); 01454 01455 HttpResponse_AddStringToResponseHeaders("Access-Control-Allow-Headers", strlen("Access-Control-Allow-Headers")); 01456 HttpResponse_AddCharToResponseHeaders(':'); 01457 HttpResponse_AddCharToResponseHeaders(' '); 01458 HttpResponse_AddStringToResponseHeaders("authorization", strlen("authorization")); 01459 HttpResponse_AddStringToResponseHeaders(HTTP_HEADER_DELIMITER, strlen(HTTP_HEADER_DELIMITER)); 01460 01461 HttpResponse_AddStringToResponseHeaders("Access-Control-Allow-Headers", strlen("Access-Control-Allow-Headers")); 01462 HttpResponse_AddCharToResponseHeaders(':'); 01463 HttpResponse_AddCharToResponseHeaders(' '); 01464 HttpResponse_AddStringToResponseHeaders("x-websocket-version", strlen("x-websocket-version")); 01465 HttpResponse_AddStringToResponseHeaders(HTTP_HEADER_DELIMITER, strlen(HTTP_HEADER_DELIMITER)); 01466 01467 HttpResponse_AddStringToResponseHeaders("Access-Control-Allow-Headers", strlen("Access-Control-Allow-Headers")); 01468 HttpResponse_AddCharToResponseHeaders(':'); 01469 HttpResponse_AddCharToResponseHeaders(' '); 01470 HttpResponse_AddStringToResponseHeaders("x-websocket-protocol", strlen("x-websocket-protocol")); 01471 HttpResponse_AddStringToResponseHeaders(HTTP_HEADER_DELIMITER, strlen(HTTP_HEADER_DELIMITER)); 01472 01473 HttpResponse_AddStringToResponseHeaders("Access-Control-Allow-Headers", strlen("Access-Control-Allow-Headers")); 01474 HttpResponse_AddCharToResponseHeaders(':'); 01475 HttpResponse_AddCharToResponseHeaders(' '); 01476 HttpResponse_AddStringToResponseHeaders("x-websocket-extensions", strlen("x-websocket-extensions")); 01477 HttpResponse_AddStringToResponseHeaders(HTTP_HEADER_DELIMITER, strlen(HTTP_HEADER_DELIMITER)); 01478 01479 // Add the end of headers marker (\r\n) 01480 HttpResponse_AddStringToResponseHeaders(HTTP_HEADER_DELIMITER, sizeof(HTTP_HEADER_DELIMITER)-1); 01481 01482 // Send all response headers over the connection socket 01483 packet.pData = g_state.packetSend; 01484 packet.uLength = g_state.packetSendSize; 01485 if(!HttpCore_SendPacket(uConnection, packet)){ 01486 HttpDebug("HttpCore_SendPacket failed\n\r"); 01487 return 0; 01488 } 01489 g_state.packetSendSize = 0; 01490 01491 g_state.connections[uConnection].connectionState = WebSocketDataRecv; 01492 01493 sl_WebSocketHandshakeEvtHdlr(uConnection); 01494 01495 return 1; 01496 01497 //Advance to next state ie WebSocketDataResponse 01498 } 01499 01500 01501 /* 01502 * This function concatenates client generated key with websocket magic string 01503 * Performs SHA-1 algorithm on this string 01504 01505 * @return non zero if successful. 01506 0 if failure 01507 */ 01508 01509 int WS_HandshakeHash(char *InKey,char *OutKey, char *EncOutKey) 01510 { 01511 SHA1((unsigned char *)InKey, (unsigned char *)OutKey); 01512 ConvertToBase64(EncOutKey, OutKey, strlen(OutKey)); 01513 return 1; 01514 } 01515 01516 int WS_SendPacket(UINT16 uConnection) 01517 { 01518 struct HttpBlob packet; 01519 int retval; 01520 01521 // Send all response headers over the connection socket 01522 packet.pData = g_state.packetSend; 01523 packet.uLength = g_state.packetSendSize; 01524 retval = HttpCore_SendPacket(uConnection, packet); 01525 01526 g_state.packetSendSize = 0; 01527 01528 g_state.connections[uConnection].connectionState = WebSocketDataRecv; 01529 01530 return retval; 01531 01532 } 01533 01534 int HttpResponse_CannedRedirect(UINT16 uConnection, struct HttpBlob location, UINT16 bPermanent) 01535 { 01536 struct HttpBlob status; 01537 HttpStatusString((bPermanent==1? HTTP_STATUS_REDIRECT_PERMANENT:HTTP_STATUS_REDIRECT_TEMPORARY), &status); 01538 01539 if(!HttpResponse_Headers(uConnection, (bPermanent==1? HTTP_STATUS_REDIRECT_PERMANENT:HTTP_STATUS_REDIRECT_TEMPORARY), 0, 0, nullBlob, location)) 01540 return 0; 01541 else 01542 return 1; 01543 } 01544 01545 int HttpResponse_CannedError(UINT16 uConnection, UINT16 uHttpStatus) 01546 { 01547 struct HttpBlob status; 01548 HttpStatusString(uHttpStatus, &status); 01549 01550 if(!HttpResponse_Headers(uConnection, uHttpStatus, 0, status.uLength, nullBlob, nullBlob)) 01551 return 0; 01552 01553 if(!HttpResponse_Content(uConnection, status)) 01554 return 0; 01555 else 01556 return 1; 01557 } 01558 01559 01560 /// @} 01561
Generated on Tue Jul 12 2022 22:22:38 by 1.7.2