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