Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
HttpCore.cpp
00001 /***************************************************************************** 00002 * 00003 * HttpCore.c 00004 * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/ 00005 * 00006 * Redistribution and use in source and binary forms, with or without 00007 * modification, are permitted provided that the following conditions 00008 * are met: 00009 * 00010 * Redistributions of source code must retain the above copyright 00011 * notice, this list of conditions and the following disclaimer. 00012 * 00013 * Redistributions in binary form must reproduce the above copyright 00014 * notice, this list of conditions and the following disclaimer in the 00015 * documentation and/or other materials provided with the 00016 * distribution. 00017 * 00018 * Neither the name of Texas Instruments Incorporated nor the names of 00019 * its contributors may be used to endorse or promote products derived 00020 * from this software without specific prior written permission. 00021 * 00022 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 00023 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 00024 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 00025 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 00026 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 00027 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 00028 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 00029 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 00030 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 00031 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 00032 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 00033 * 00034 *****************************************************************************/ 00035 #include "mbed.h" 00036 #include "Common.h" 00037 #include "HttpHeaders.h" 00038 #include "HttpCore.h" 00039 #include "HttpResponse.h" 00040 #include "HttpRequest.h" 00041 #include "HttpAuth.h" 00042 #include "HttpDebug.h" 00043 #include "HttpDynamic.h" 00044 #include "HttpStatic.h" 00045 #include <string.h> 00046 #include "HttpConfig.h" 00047 00048 // Include CC3000 bridged networking stack headers 00049 #include "cc3000_common.h" 00050 #include "socket.h" 00051 #include "netapp.h" 00052 #include "FlashDB.h" 00053 00054 /** 00055 * @addtogroup HttpCore 00056 * @{ 00057 */ 00058 00059 00060 /** 00061 * This enumeration defines all possible states for a connection 00062 */ 00063 enum HttpConnectionState 00064 { 00065 /// Connection is inactive. The connection's socket should be INVALID_SOCKET_HANDLE 00066 Inactive, 00067 /// Waiting for packet(s) with the request method 00068 RequestMethod, 00069 /// Waiting for packet(s) with request headers 00070 RequestHeaders, 00071 /// Currently receiving a header which is too long - Drop it and continue waiting for more headers 00072 DropCurrentHeader, 00073 /// Done parsing headers, waiting for POST data pakcets 00074 RequestData, 00075 /// Request is at the hands of the content module (static and/or dynamic), waiting for response headers. 00076 Processing, 00077 /// Response headers have been sent. Sending response content. 00078 ResponseData, 00079 /// Response complete. Possibility of another request. 00080 ResponseComplete 00081 }; 00082 00083 /** 00084 * This enumeration defines all possible request-handler modules 00085 */ 00086 enum HttpHandler 00087 { 00088 /// No module is going to process this request (use the default 404 error) 00089 None, 00090 /// The HttpStatic module is going to process this request 00091 HttpStatic, 00092 /// The HttpDynamic module is going to process this request 00093 HttpDynamic 00094 }; 00095 00096 /** 00097 * This structure holds all information for an HTTP connection 00098 */ 00099 //#ifdef __CCS__ 00100 //struct __attribute__ ((__packed__)) HttpConnectionData 00101 //#elif __IAR_SYSTEMS_ICC__ 00102 //#pragma pack(1) 00103 struct HttpConnectionData 00104 //#endif 00105 { 00106 /// The state of this connection 00107 enum HttpConnectionState connectionState; 00108 /// The data socket for this connection. Should be INVALID_SOCKET_HANDLE when in Inactive state 00109 SOCKET dataSocket; 00110 /// The current HTTP request on this connection 00111 struct HttpRequest request; 00112 /// Which handler is going to process the current request 00113 enum HttpHandler handler; 00114 /// An un-parsed chunk of header line 00115 uint8 headerStart[HTTP_CORE_MAX_HEADER_LINE_LENGTH]; 00116 /// Amount of content left to be read in the request or sent in the response 00117 uint32 uContentLeft; 00118 /// If the headers will arrive in several packets the content will be buffered in the headers start buffer until a whole line is available 00119 uint16 uSavedBufferSize; 00120 /// Check weather the authentication is done or not 00121 uint8 HttpAuth; 00122 }; 00123 00124 /** 00125 * This structure holds all of the global state of the HTTP server 00126 */ 00127 //#ifdef __CCS__ 00128 //struct __attribute__ ((__packed__)) HttpGlobalState 00129 //#elif __IAR_SYSTEMS_ICC__ 00130 //#pragma pack(1) 00131 struct HttpGlobalState 00132 //#endif 00133 { 00134 /// The listening socket 00135 SOCKET listenSocket; 00136 /// Number of active connections 00137 uint16 uOpenConnections; 00138 /// All possible connections 00139 struct HttpConnectionData connections[HTTP_CORE_MAX_CONNECTIONS]; 00140 /// The packet-receive buffer 00141 uint8 packetRecv[HTTP_CORE_MAX_PACKET_SIZE_RECEIVED]; 00142 /// Size of data in the packet-receive buffer 00143 int packetRecvSize; 00144 /// The packet-send buffer 00145 uint8 packetSend[HTTP_CORE_MAX_PACKET_SIZE_SEND]; 00146 /// Size of data in the packet-send buffer 00147 uint16 packetSendSize; 00148 }; 00149 00150 /// The global state of the HTTP server 00151 __no_init struct HttpGlobalState g_state; 00152 00153 // Forward declarations for static functions 00154 static void HttpCore_InitWebServer(); 00155 static void HttpCore_CloseConnection(uint16 uConnection); 00156 static int HttpCore_HandleRequestPacket(uint16 uConnection, struct HttpBlob packet); 00157 static int HttpCore_HandleMethodLine(uint16 uConnection, struct HttpBlob line); 00158 static int HttpCore_HandleHeaderLine(uint16 uConnection, struct HttpBlob line); 00159 static int HttpCore_HandleRequestData(uint16 uConnection, struct HttpBlob* pData); 00160 static void HttpCore_ProcessNotFound(uint16 uConnection); 00161 00162 struct HttpBlob nullBlob = {NULL, 0}; 00163 00164 extern volatile char runSmartConfig; 00165 extern char DevServname[]; 00166 extern unsigned char mDNSSend; 00167 extern char CheckSocket; 00168 extern signed char sd[]; 00169 00170 #define MAX_SENT_DATA 912 00171 00172 /** 00173 * Detect all error conditions from a sockets API return value, such as accpet() 00174 * Note: This is different in Windows and CC3000 00175 * Returns nonzero if valid socket, or zero if invalid socket 00176 */ 00177 static int HttpIsValidSocket(SOCKET sock) 00178 { 00179 #if (defined(WIN32) && !defined(HTTP_WEB_SERVER_ON_BRIDGE)) 00180 // The CC3000 API returns an int, and might return CC3000_INVALID_SOCKET 00181 if ((sock == INVALID_SOCKET) || 00182 (sock == CC3000_INVALID_SOCKET)) 00183 return 0; 00184 #else 00185 if (sock < 0) 00186 return 0; 00187 #endif 00188 return 1; 00189 } 00190 00191 void HttpCloseServer() 00192 { 00193 closesocket(g_state.listenSocket); 00194 } 00195 00196 void HttpServerInitAndRun() 00197 { 00198 uint16 uConnection; 00199 sockaddr_in addr; 00200 sockaddr_in clientAddr; 00201 socklen_t addrLen = sizeof(clientAddr); 00202 struct HttpBlob blob; 00203 fd_set readsds, errorsds; 00204 int ret = 0; 00205 SOCKET maxFD; 00206 timeval timeout; 00207 signed char curSocket; 00208 int optval, optlen; 00209 00210 memset(&timeout, 0, sizeof(timeval)); 00211 timeout.tv_sec = 1; 00212 timeout.tv_usec = 0; 00213 00214 // Initialize the server's global state 00215 HttpCore_InitWebServer(); 00216 00217 // Create the listener socket for HTTP Server. 00218 g_state.listenSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 00219 if(g_state.listenSocket == INVALID_SOCKET) 00220 { 00221 HttpDebug("Failed to create listen socket"); 00222 printf("Failed to create listen socket\r\n"); 00223 return; 00224 } 00225 00226 memset(&addr, 0, sizeof(addr)); 00227 #ifdef _WINSOCKAPI_ 00228 addr.sin_family = AF_INET; 00229 #else 00230 addr.sin_family = htons(AF_INET); 00231 #endif 00232 addr.sin_port = htons(HTTP_CORE_SERVER_PORT); 00233 if (bind(g_state.listenSocket, (const sockaddr*)&addr, sizeof(addr)) != 0) 00234 { 00235 HttpDebug("bind() fail"); 00236 printf("bind() fail\r\n"); 00237 return; 00238 } 00239 if (listen(g_state.listenSocket, 10) != 0) 00240 { 00241 HttpDebug("listen() fail"); 00242 printf("listen() fail\r\n"); 00243 return; 00244 } 00245 00246 #ifdef HTTP_CORE_ENABLE_AUTH 00247 struct HttpBlob user,pass; 00248 user.pData = (uint8*)"cc3000"; 00249 user.uLength= 6; 00250 pass.pData = (uint8*)"admin"; 00251 pass.uLength = 5; 00252 int count; 00253 00254 HttpAuth_Init(user, pass); 00255 #endif 00256 00257 g_state.uOpenConnections = 0; 00258 00259 // Main loop of the server. Note: This is an infinite loop 00260 while (1) 00261 { 00262 //printf("Server Loop...\r\n"); 00263 // Check if button is pressed for smart config 00264 if(runSmartConfig == 1) 00265 { 00266 // Button is pressed for smart config. Close all active connections 00267 for(uConnection = 0; uConnection < HTTP_CORE_MAX_CONNECTIONS; ++uConnection) 00268 { 00269 if (g_state.connections[uConnection].connectionState != Inactive) 00270 { 00271 HttpCore_CloseConnection(uConnection); 00272 } 00273 } 00274 00275 // Close listening socket 00276 HttpCloseServer(); 00277 break; 00278 } 00279 if( mDNSSend ==1) 00280 { 00281 mdnsAdvertiser(1,DevServname, strlen(DevServname)); 00282 mDNSSend =0; 00283 } 00284 00285 // Client socket is closed, close socket 00286 if(CheckSocket == 1) 00287 { 00288 for(count = 0; count<9 ; count++) 00289 { 00290 if(sd[count] == 1) 00291 { 00292 HttpCore_CloseConnection(count); 00293 sd[count] = 0; 00294 } 00295 } 00296 for(uConnection = 0; uConnection < HTTP_CORE_MAX_CONNECTIONS; ++uConnection) 00297 { 00298 if (g_state.connections[uConnection].connectionState != Inactive) 00299 { 00300 // Check for socket timeouts 00301 curSocket = getsockopt(g_state.connections[uConnection].dataSocket, SOL_SOCKET, SOCKOPT_RECV_NONBLOCK , &optval, (socklen_t*)&optlen); 00302 if (curSocket == -57) 00303 { 00304 HttpCore_CloseConnection(uConnection); 00305 } 00306 } 00307 } 00308 CheckSocket = 0; 00309 } 00310 00311 SOCKET newsock; 00312 00313 newsock = accept(g_state.listenSocket, (sockaddr*)&clientAddr, &addrLen); 00314 00315 // If new connection is returned - initialize the new connection object 00316 if (HttpIsValidSocket(newsock)) 00317 { 00318 if (g_state.uOpenConnections >= HTTP_CORE_MAX_CONNECTIONS) 00319 { 00320 //check if sockets are are available 00321 for(uConnection = 0; uConnection < HTTP_CORE_MAX_CONNECTIONS; ++uConnection) 00322 { 00323 if (g_state.connections[uConnection].connectionState != Inactive) 00324 { 00325 //Check for Socket Timeout 00326 curSocket = getsockopt(g_state.connections[uConnection].dataSocket, SOL_SOCKET, SOCKOPT_RECV_NONBLOCK , &optval, (socklen_t*)&optlen); 00327 if (curSocket == -57) 00328 { 00329 HttpCore_CloseConnection(uConnection); 00330 } 00331 } 00332 } 00333 } 00334 00335 if(g_state.uOpenConnections < HTTP_CORE_MAX_CONNECTIONS) 00336 { 00337 for (uConnection = 0; uConnection < HTTP_CORE_MAX_CONNECTIONS; ++uConnection) 00338 if (g_state.connections[uConnection].connectionState == Inactive) 00339 break; 00340 00341 g_state.connections[uConnection].dataSocket = newsock; 00342 g_state.uOpenConnections++; 00343 g_state.connections[uConnection].connectionState = RequestMethod; 00344 HttpDebug("Accepting new connection number %d", uConnection); 00345 printf("Accepting new connection number %i\r\n", uConnection); 00346 } 00347 } 00348 00349 00350 00351 00352 // Nothing more to do if no open connections 00353 if (g_state.uOpenConnections == 0) 00354 continue; 00355 00356 // Receive data on all open connections, and handle the new data 00357 maxFD = (SOCKET)-1; 00358 // Select only the active connections 00359 FD_ZERO(&readsds); 00360 FD_ZERO(&errorsds); 00361 for (uConnection = 0; uConnection < HTTP_CORE_MAX_CONNECTIONS; ++uConnection) 00362 { 00363 // if connection is open and in one of the receiving states, then add this socket to the set 00364 if (g_state.connections[uConnection].connectionState == RequestMethod || 00365 g_state.connections[uConnection].connectionState == RequestHeaders || 00366 g_state.connections[uConnection].connectionState == RequestData || 00367 g_state.connections[uConnection].connectionState == DropCurrentHeader) 00368 { 00369 FD_SET(g_state.connections[uConnection].dataSocket, &readsds); 00370 FD_SET(g_state.connections[uConnection].dataSocket, &errorsds); 00371 // Calculate the maximum socket number 00372 if (maxFD <= g_state.connections[uConnection].dataSocket) 00373 maxFD = g_state.connections[uConnection].dataSocket + 1; 00374 } 00375 } 00376 00377 ret = select(maxFD, &readsds, NULL, &errorsds, &timeout); 00378 00379 // Nothing more to do if no packet received 00380 if (ret == 0) 00381 { 00382 continue; 00383 } 00384 00385 for (uConnection = 0; uConnection < HTTP_CORE_MAX_CONNECTIONS; ++uConnection) 00386 { 00387 // Skip inactive connections 00388 if (g_state.connections[uConnection].connectionState == Inactive) 00389 continue; 00390 00391 // Close connections that were select()ed for error 00392 if (FD_ISSET(g_state.connections[uConnection].dataSocket, &errorsds)) 00393 { 00394 HttpCore_CloseConnection(uConnection); 00395 continue; 00396 } 00397 00398 // Skip connections that were not select()ed for reading 00399 if (!FD_ISSET(g_state.connections[uConnection].dataSocket, &readsds)) 00400 continue; 00401 00402 // This connection has data that can be received now 00403 00404 // Receive the data into the global packet-receive buffer 00405 memset(g_state.packetRecv, 0, HTTP_CORE_MAX_PACKET_SIZE_RECEIVED); 00406 g_state.packetRecvSize = recv(g_state.connections[uConnection].dataSocket, (char *)(g_state.packetRecv), HTTP_CORE_MAX_PACKET_SIZE_RECEIVED, 0); 00407 00408 // Detect and handle errors 00409 if (g_state.packetRecvSize <= 0) 00410 { 00411 HttpDebug("HTTP Connection recv error. connection=%d, error = %d", uConnection, g_state.packetRecvSize); 00412 printf("HTTP Connection recv error. connection=%i, error = %i\r\n", uConnection, g_state.packetRecvSize); 00413 HttpCore_CloseConnection(uConnection); 00414 continue; 00415 } 00416 00417 blob.uLength = (uint16)g_state.packetRecvSize; 00418 blob.pData = g_state.packetRecv; 00419 if (!HttpCore_HandleRequestPacket(uConnection, blob)) 00420 HttpCore_CloseConnection(uConnection); 00421 } 00422 } 00423 } 00424 00425 /** 00426 * Reset open connection after finishing HTPP transaction 00427 */ 00428 static void HttpCore_ResetConnection(uint16 uConnection) 00429 { 00430 g_state.connections[uConnection].uContentLeft = 0; 00431 g_state.connections[uConnection].uSavedBufferSize = 0; 00432 g_state.connections[uConnection].handler = None; 00433 g_state.connections[uConnection].request.requestContent.pData = NULL; 00434 g_state.connections[uConnection].request.requestContent.uLength = 0; 00435 g_state.connections[uConnection].request.uFlags = 0; 00436 } 00437 00438 /** 00439 * Initialize the server's global state structure 00440 */ 00441 static void HttpCore_InitWebServer() 00442 { 00443 uint16 uConnection; 00444 g_state.packetRecvSize = 0; 00445 g_state.packetSendSize = 0; 00446 g_state.uOpenConnections = 0; 00447 g_state.listenSocket = INVALID_SOCKET; 00448 00449 for (uConnection = 0; uConnection < HTTP_CORE_MAX_CONNECTIONS; ++uConnection) 00450 { 00451 g_state.connections[uConnection].connectionState = Inactive; 00452 g_state.connections[uConnection].dataSocket = INVALID_SOCKET; 00453 g_state.connections[uConnection].request.uConnection = uConnection; 00454 g_state.connections[uConnection].HttpAuth = 0; 00455 HttpCore_ResetConnection(uConnection); 00456 } 00457 00458 FlashDB_Init(); 00459 } 00460 00461 00462 /** 00463 * Close a connection and clean up its state 00464 */ 00465 static void HttpCore_CloseConnection(uint16 uConnection) 00466 { 00467 HttpDebug("Close connection"); 00468 printf("Close connection\r\n"); 00469 00470 closesocket(g_state.connections[uConnection].dataSocket); 00471 00472 g_state.connections[uConnection].connectionState = Inactive; 00473 g_state.connections[uConnection].dataSocket = INVALID_SOCKET; 00474 g_state.connections[uConnection].HttpAuth = 0; 00475 HttpCore_ResetConnection(uConnection); 00476 if(g_state.uOpenConnections > 0) 00477 g_state.uOpenConnections--; 00478 } 00479 00480 /** 00481 * Getting the next line in the HTTP headers section 00482 * 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 00483 * The input is the connection and the remaining blob of the received packet 00484 * 00485 * @return zero if the whole packet was handled, and need to wait for more data (pLine is not set to anything yet) 00486 * negative if some error occurred, and the connection should be closed. 00487 * 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 00488 */ 00489 static int HttpCore_GetNextLine(uint16 uConnection, struct HttpBlob* pCurrentLocation, struct HttpBlob* pLine) 00490 { 00491 uint16 uLength; 00492 uint8* nextLocation; 00493 // Keep a pointer to the connection state object 00494 struct HttpConnectionData* pConnection = &g_state.connections[uConnection]; 00495 00496 // search for the line delimiter in the received data 00497 nextLocation = HttpString_nextToken(HTTP_HEADER_DELIMITER, sizeof(HTTP_HEADER_DELIMITER)-1, *pCurrentLocation); 00498 uLength = (uint16)(nextLocation - pCurrentLocation->pData); 00499 00500 if (pConnection->uSavedBufferSize > 0) 00501 { 00502 // There is previous saved data for this line, so need to concatenate 00503 if ((pConnection->headerStart[pConnection->uSavedBufferSize - 1] == '\r') && (pCurrentLocation->pData[0] == '\n')) 00504 { 00505 // Handle special case where the headers were splitted exactly at the delimiter 00506 pConnection->headerStart[pConnection->uSavedBufferSize + 1] = pCurrentLocation->pData[0]; 00507 pLine->pData = pConnection->headerStart; 00508 // Account for the excessive \r in the buffer 00509 pLine->uLength = pConnection->uSavedBufferSize - 1; 00510 pConnection->uSavedBufferSize = 0; 00511 // Advance the current location past this line 00512 pCurrentLocation->pData += 1; 00513 pCurrentLocation->uLength -= 1; 00514 return 1; 00515 } 00516 else 00517 { 00518 // There is saved data, and the delimiter is not split between packets 00519 if (nextLocation == NULL) 00520 { 00521 // No line delimiter was found in the current packet 00522 if ((pConnection->uSavedBufferSize + pCurrentLocation->uLength) < HTTP_CORE_MAX_HEADER_LINE_LENGTH) 00523 { 00524 // There is enough space to append remaining header into saved buffer 00525 memcpy(pConnection->headerStart + pConnection->uSavedBufferSize, pCurrentLocation->pData, pCurrentLocation->uLength); 00526 pConnection->uSavedBufferSize += pCurrentLocation->uLength; 00527 return 0; 00528 } 00529 else 00530 // There is not enough space in the saved buffer. This header line will be discarded 00531 if (pConnection->connectionState == RequestMethod) 00532 { 00533 // Connection awaits to receive the the HTTP method line 00534 // The method line cannot be discarded, drop the connection 00535 return -1; 00536 } 00537 else 00538 { 00539 // Connection awaits to receive the next header line which is not the method 00540 // Clean saved buffer, and drop this header line 00541 pConnection->uSavedBufferSize = 0; 00542 pConnection->connectionState = DropCurrentHeader; 00543 return 0; 00544 } 00545 } 00546 else 00547 { 00548 // Header line delimiter was found in the current packet 00549 if ((pConnection->uSavedBufferSize + uLength) < HTTP_CORE_MAX_HEADER_LINE_LENGTH) 00550 { 00551 // This header length is of legal size 00552 // Concatenate data from the saved buffer and the current packet 00553 memcpy(pConnection->headerStart + pConnection->uSavedBufferSize, pCurrentLocation->pData, uLength); 00554 pConnection->uSavedBufferSize += uLength; 00555 pLine->pData = pConnection->headerStart; 00556 pLine->uLength = pConnection->uSavedBufferSize; 00557 pConnection->uSavedBufferSize = 0; 00558 } 00559 else 00560 { 00561 // There is not enough space in the saved buffer. This header line will be discarded 00562 if (pConnection->connectionState == RequestMethod) 00563 { 00564 // Connection awaits to receive the the HTTP method line 00565 // The method line cannot be discarded, drop the connection 00566 return -1; 00567 } 00568 // Return an epmty line since the header is too long 00569 pLine->pData = NULL; 00570 pLine->uLength = 0; 00571 } 00572 // Advance the current location past this line 00573 pCurrentLocation->pData += uLength + sizeof(HTTP_HEADER_DELIMITER)-1; 00574 pCurrentLocation->uLength -= uLength + sizeof(HTTP_HEADER_DELIMITER)-1; 00575 return 1; 00576 00577 } 00578 } 00579 } 00580 else 00581 { 00582 // There is no previously saved data for this line 00583 if (nextLocation == NULL) 00584 { 00585 // No line delimiter was found in the current packet 00586 if (pCurrentLocation->uLength < HTTP_CORE_MAX_HEADER_LINE_LENGTH) 00587 { 00588 // There is enough space to append remaining header into saved buffer 00589 memcpy(pConnection->headerStart, pCurrentLocation->pData, pCurrentLocation->uLength); 00590 pConnection->uSavedBufferSize = pCurrentLocation->uLength; 00591 return 0; 00592 } 00593 else 00594 // There is not enough space in the saved buffer 00595 // This header line will be discarded 00596 if (pConnection->connectionState == RequestMethod) 00597 { 00598 // Connection awaits to receive the the HTTP method line 00599 // The method line cannot be discarded, drop the connection 00600 return -1; 00601 } 00602 else 00603 { 00604 // Connection awaits to receive the next header line which is not the method 00605 // Clean saved buffer, and drop this header line 00606 pConnection->uSavedBufferSize = 0; 00607 pConnection->connectionState = DropCurrentHeader; 00608 return 0; 00609 } 00610 } 00611 else 00612 { 00613 // Header line delimiter was found in the current packet 00614 if (uLength < HTTP_CORE_MAX_HEADER_LINE_LENGTH) 00615 { 00616 // This header length is of legal size 00617 // The whole line is in the packet buffer 00618 pLine->pData = pCurrentLocation->pData; 00619 pLine->uLength = uLength; 00620 } 00621 else 00622 { 00623 // There is not enough space to append remaining header into saved buffer 00624 if (pConnection->connectionState == RequestMethod) 00625 { 00626 // Connection awaits to receive the HTTP method line 00627 // The method line cannot be discarded, drop the connection 00628 return -1; 00629 } 00630 // Return an epmty line since the header is too long 00631 pLine->pData = NULL; 00632 pLine->uLength = 0; 00633 pConnection->connectionState = DropCurrentHeader; 00634 } 00635 // Advance the current location past this line 00636 pCurrentLocation->pData += uLength + sizeof(HTTP_HEADER_DELIMITER)-1; 00637 pCurrentLocation->uLength -= uLength + sizeof(HTTP_HEADER_DELIMITER)-1; 00638 return 1; 00639 } 00640 } 00641 } 00642 00643 00644 /** 00645 * The main state machine to handle an HTTP transaction 00646 * Every received data packet for a connection is passed to this function for parsing and handling 00647 * 00648 * If there is an error the connection will be closed in the end of the transaction 00649 * It will also be closed if "connection: close" header is received or HTTP version is 1.0 00650 * 00651 * @return zero to close the connection 00652 * nonzero if packet was consumed successfully, and the connection can handle more data 00653 */ 00654 static int HttpCore_HandleRequestPacket(uint16 uConnection, struct HttpBlob packet) 00655 { 00656 struct HttpBlob currentLocation, line; 00657 int ret; 00658 00659 currentLocation.pData = packet.pData; 00660 currentLocation.uLength = packet.uLength; 00661 00662 // when no more data is left and the HTTP transaction is not complete then return to wait for more data 00663 while (1) 00664 { 00665 if (g_state.connections[uConnection].connectionState == RequestMethod || 00666 g_state.connections[uConnection].connectionState == RequestHeaders || 00667 g_state.connections[uConnection].connectionState == DropCurrentHeader) 00668 { 00669 // Parsing HTTP headers 00670 int result; 00671 00672 // The received blob is empty, return to wait for more data 00673 if (currentLocation.uLength < 1) 00674 { 00675 return 1; 00676 } 00677 00678 // Get next header line if available 00679 result = HttpCore_GetNextLine(uConnection, ¤tLocation, &line); 00680 00681 // Method line is too long, or some other error 00682 if (result < 0) 00683 return 0; 00684 00685 // Whole packet was consumed, and no line-break found. Wait for more data 00686 if (result == 0) 00687 return 1; 00688 00689 // Otherwise a new and legal header line is found 00690 } 00691 00692 switch (g_state.connections[uConnection].connectionState) 00693 { 00694 case DropCurrentHeader: 00695 g_state.connections[uConnection].connectionState = RequestHeaders; 00696 break; 00697 case RequestMethod: 00698 //HttpAssert((line.pData != NULL) && (line.uLength > 0)); 00699 // If there is an error, then return error to drop the connection 00700 if (!HttpCore_HandleMethodLine(uConnection, line)) 00701 return 0; 00702 break; 00703 case RequestHeaders: 00704 if (!HttpCore_HandleHeaderLine(uConnection, line)) 00705 return 0; 00706 break; 00707 case RequestData: 00708 ret = HttpCore_HandleRequestData(uConnection, ¤tLocation); 00709 if (ret == 0) 00710 return 1; 00711 else 00712 if (ret < 0) 00713 return 0; 00714 break; 00715 case Processing: 00716 // All the request data was received - start final processing of the headers and post data if exists 00717 switch (g_state.connections[uConnection].handler) 00718 { 00719 #ifdef HTTP_CORE_ENABLE_STATIC 00720 case HttpStatic: 00721 HttpStatic_ProcessRequest(&g_state.connections[uConnection].request); 00722 break; 00723 #endif 00724 #ifdef HTTP_CORE_ENABLE_DYNAMIC 00725 case HttpDynamic: 00726 HttpDynamic_ProcessRequest(&g_state.connections[uConnection].request); 00727 break; 00728 #endif 00729 default: 00730 HttpCore_ProcessNotFound(uConnection); 00731 break; 00732 } 00733 break; 00734 case ResponseData: 00735 // This state should never be reached, it is set internally during the processing 00736 HttpDebug("Response data state in request handling main loop!"); 00737 printf("Response data state in request handling main loop!\r\n"); 00738 HttpAssert(0); 00739 break; 00740 case ResponseComplete: 00741 if ((g_state.connections[uConnection].request.uFlags & HTTP_REQUEST_FLAG_CLOSE)!=0 || 00742 (g_state.connections[uConnection].request.uFlags & HTTP_REQUEST_1_1) == 0) 00743 { 00744 // Connection should be closed - either "Connection: close" was received or the HTTP version is 1.0 00745 // Return 0 to close the connection 00746 return 0; 00747 } 00748 // The current HTTP transaction is complete - reset state for the next transaction on this connection 00749 g_state.connections[uConnection].connectionState = RequestMethod; 00750 HttpCore_ResetConnection(uConnection); 00751 break; 00752 default: 00753 HttpDebug("Bad state in HttpCore!"); 00754 printf("Bad state in HttpCore!\r\n"); 00755 //HttpAssert(0); 00756 break; 00757 } 00758 } 00759 } 00760 00761 /** 00762 * This function handles connection initial state 00763 * Parse the first header line as a method header 00764 * 00765 * Method line should be in the form: 00766 * GET /resource.html HTTP/1.1\r\n 00767 * 00768 * @return nonzero if success 00769 */ 00770 static int HttpCore_HandleMethodLine(uint16 uConnection, struct HttpBlob line) 00771 { 00772 struct HttpBlob resource; 00773 uint8* methodLocation; 00774 uint8* versionLocation; 00775 uint16 uMethodLength; 00776 // Search for GET token in the input blob 00777 methodLocation = HttpString_nextToken(HTTP_METHOD_GET, sizeof(HTTP_METHOD_GET)-1, line); 00778 uMethodLength = sizeof(HTTP_METHOD_GET)-1; 00779 if (methodLocation == NULL) 00780 { 00781 // The method is not GET 00782 // Search for the POST token in the input blob 00783 methodLocation = HttpString_nextToken(HTTP_METHOD_POST, sizeof(HTTP_METHOD_POST)-1, line); 00784 uMethodLength = sizeof(HTTP_METHOD_POST)-1; 00785 g_state.connections[uConnection].request.uFlags |= HTTP_REQUEST_FLAG_METHOD_POST; 00786 } 00787 else 00788 { 00789 // Method is GET 00790 g_state.connections[uConnection].request.requestContent.uLength = 0; 00791 g_state.connections[uConnection].request.uFlags &= ~HTTP_REQUEST_FLAG_METHOD_POST; 00792 } 00793 if (methodLocation != line.pData) 00794 { 00795 methodLocation = HttpString_nextToken(HTTP_METHOD_POST, sizeof(HTTP_METHOD_POST)-1, line); 00796 uMethodLength = sizeof(HTTP_METHOD_POST)-1; 00797 g_state.connections[uConnection].request.uFlags |= HTTP_REQUEST_FLAG_METHOD_POST; 00798 if(methodLocation == NULL || methodLocation != line.pData) 00799 { 00800 // Header does not begin line with GET or POST as it should 00801 HttpDebug("Unsupported method"); 00802 printf("Unsupported method\r\n"); 00803 return 0; 00804 } 00805 } 00806 00807 // Search for "HTTP/1.1" version token 00808 versionLocation = HttpString_nextToken(HTTP_VERSION_1P1, sizeof(HTTP_VERSION_1P1)-1, line); 00809 // Version is 1.1 00810 if (versionLocation != NULL) 00811 g_state.connections[uConnection].request.uFlags |= HTTP_REQUEST_1_1; 00812 else 00813 { 00814 // Search for "HTTP/1.1" version token 00815 versionLocation = HttpString_nextToken(HTTP_VERSION_1P0, sizeof(HTTP_VERSION_1P0)-1, line); 00816 // Version is 1.0 00817 if (versionLocation != NULL) 00818 g_state.connections[uConnection].request.uFlags &= ~HTTP_REQUEST_1_1; 00819 else 00820 { 00821 HttpDebug("Bad protocol version"); 00822 printf("Bad protocol version\r\n"); 00823 return 0; 00824 } 00825 } 00826 00827 HttpDebug("method Header: %.*s", line.uLength, line.pData); 00828 //printf("method Header: %i , %c\r\n", line.uLength, line.pData); 00829 // Find the URL part of the header 00830 resource.pData = methodLocation + uMethodLength + 1; 00831 resource.uLength = (uint16)(versionLocation - (methodLocation + uMethodLength + 1) - 1); 00832 00833 // Determine which handler is supposed to handle this request 00834 // The handler functions are called according to a hardcoded priority - dynamic, static, default 00835 // The first handler that returns non zero will handle this request 00836 #ifdef HTTP_CORE_ENABLE_DYNAMIC 00837 if (HttpDynamic_InitRequest(uConnection, resource) != 0) 00838 g_state.connections[uConnection].handler = HttpDynamic; 00839 else 00840 #endif 00841 #ifdef HTTP_CORE_ENABLE_STATIC 00842 if (HttpStatic_InitRequest(uConnection, resource) != 0) 00843 g_state.connections[uConnection].handler = HttpStatic; 00844 else 00845 #endif 00846 g_state.connections[uConnection].handler = None; 00847 g_state.connections[uConnection].connectionState = RequestHeaders; 00848 return 1; 00849 } 00850 00851 /** 00852 * Handle The HTTP headers (after method) one by one 00853 * If an empty header is received then the headers section is complete 00854 * Searches for the headers tokens. If important data is found then it is saved in the connection object 00855 * 00856 * returns nonzero if sucessful 00857 */ 00858 static int HttpCore_HandleHeaderLine(uint16 uConnection, struct HttpBlob line) 00859 { 00860 struct HttpBlob blobValue; 00861 uint8* pFound; 00862 uint32 length; 00863 00864 // NULL line is received when a header line is too long. 00865 if (line.pData == NULL) 00866 return 1; 00867 00868 // Length is 0, this means than End-Of-Headers marker was reached 00869 // State of this connection is set to RequestData 00870 if (line.uLength == 0) 00871 { 00872 g_state.connections[uConnection].connectionState = RequestData; 00873 return 1; 00874 } 00875 00876 // If "Accept-encoding" header then set or clear HTTP_REQUEST_FLAG_ACCEPT_GZIP flag 00877 if (HttpString_nextToken(HTTP_ACCEPT_ENCODING, sizeof(HTTP_ACCEPT_ENCODING)-1, line)) 00878 { 00879 line.pData += sizeof(HTTP_ACCEPT_ENCODING)-1 + 2; 00880 line.uLength -= sizeof(HTTP_ACCEPT_ENCODING)-1 + 2; 00881 pFound = HttpString_nextToken(HTTP_GZIP, sizeof(HTTP_GZIP)-1, line); 00882 if (pFound != NULL) 00883 g_state.connections[uConnection].request.uFlags |= HTTP_REQUEST_FLAG_ACCEPT_GZIP; 00884 else 00885 g_state.connections[uConnection].request.uFlags &= ~HTTP_REQUEST_FLAG_ACCEPT_GZIP; 00886 return 1; 00887 } 00888 00889 // If "Content-Length" header then parse the lenght and set uContentLeft to it 00890 // GET and POST method behave the same 00891 if (HttpString_nextToken(HTTP_CONTENT_LENGTH, sizeof(HTTP_CONTENT_LENGTH)-1, line) == line.pData) 00892 { 00893 line.pData += sizeof(HTTP_CONTENT_LENGTH)-1 + 2; 00894 line.uLength -= sizeof(HTTP_CONTENT_LENGTH)-1 + 2; 00895 blobValue.pData = line.pData; 00896 blobValue.uLength = line.uLength - 2; 00897 length = HttpString_atou(blobValue); 00898 g_state.connections[uConnection].uContentLeft = length; 00899 // Set ignore flag 00900 if (g_state.connections[uConnection].uContentLeft > HTTP_CORE_MAX_HEADER_LINE_LENGTH) 00901 g_state.connections[uConnection].request.uFlags |= HTTP_REQUEST_CONTENT_IGNORED; 00902 // Prepare the request blob to buffer the content 00903 g_state.connections[uConnection].request.requestContent.pData = g_state.connections[uConnection].headerStart; 00904 g_state.connections[uConnection].request.requestContent.uLength = 0; 00905 return 1; 00906 } 00907 // If "Connection" header then look for "close" and set or clear HTTP_REQUEST_FLAG_CLOSE flag 00908 // The default behaviour for keep alive or no such header is to keep the connection open in http version 1.1 00909 // In http version 1.0 the default behavior is to always close the socket 00910 if (HttpString_nextToken(HTTP_CONNECTION_CLOSE, sizeof(HTTP_CONNECTION_CLOSE)-1, line) == line.pData) 00911 { 00912 line.pData += sizeof(HTTP_CONNECTION_CLOSE)-1 + 2; 00913 line.uLength -= sizeof(HTTP_CONNECTION_CLOSE)-1 + 2; 00914 pFound = HttpString_nextToken(HTTP_CLOSE, sizeof(HTTP_CLOSE)-1, line); 00915 if (pFound != 0) 00916 g_state.connections[uConnection].request.uFlags |= HTTP_REQUEST_FLAG_CLOSE; 00917 else 00918 g_state.connections[uConnection].request.uFlags &= ~HTTP_REQUEST_FLAG_CLOSE; 00919 return 1; 00920 } 00921 // If "Authorization" header the handle authentication 00922 if (HttpString_nextToken(HTTP_AUTHORIZATION, sizeof(HTTP_AUTHORIZATION)-1, line) == line.pData) 00923 { 00924 line.pData += sizeof(HTTP_AUTHORIZATION)-1 + 2; 00925 line.uLength -= sizeof(HTTP_AUTHORIZATION)-1 + 2; 00926 blobValue.pData = line.pData; 00927 blobValue.uLength = line.uLength; 00928 //TODO: handle the case when we don't support authentication 00929 #ifdef HTTP_CORE_ENABLE_AUTH 00930 HttpAuth_RequestAuthenticate(&g_state.connections[uConnection].request, blobValue); 00931 #endif 00932 return 1; 00933 } 00934 // None of the above mentioned headers was recognized so just ignore this header 00935 return 1; 00936 } 00937 00938 /** 00939 * Handles request data for this transaction 00940 * Behaves the same for POST and GET methods - 00941 * If content length header was present then read the content for further processing 00942 * If the content is too long then ignore it 00943 * 00944 * @return 1 if successful, pData is updated to skip the handled data 00945 0 if all data is consumed and need to read more data 00946 * negative if an error occurs and the connection should be closed. 00947 */ 00948 static int HttpCore_HandleRequestData(uint16 uConnection, struct HttpBlob* pData) 00949 { 00950 uint32 uLengthToHandle; 00951 00952 if (g_state.connections[uConnection].uContentLeft == 0) 00953 { 00954 HttpDebug("Received content. Length=%d, content:\r\n%.*s", g_state.connections[uConnection].request.requestContent.uLength, g_state.connections[uConnection].request.requestContent.uLength, g_state.connections[uConnection].headerStart); 00955 g_state.connections[uConnection].connectionState = Processing; 00956 return 1; 00957 } 00958 00959 // Find minimum between the content left to handle and the current blob 00960 uLengthToHandle = g_state.connections[uConnection].uContentLeft; 00961 if (uLengthToHandle > pData->uLength) 00962 uLengthToHandle = pData->uLength; 00963 00964 // If no new data is received - return and wait for more 00965 if (uLengthToHandle == 0) 00966 return 0; 00967 00968 if ( (g_state.connections[uConnection].request.uFlags & HTTP_REQUEST_CONTENT_IGNORED) != 0) 00969 { 00970 // Ignore Content 00971 pData->pData += uLengthToHandle; 00972 pData->uLength -= (uint16)uLengthToHandle; 00973 g_state.connections[uConnection].uContentLeft -= uLengthToHandle; 00974 } 00975 else 00976 { 00977 // Read content 00978 memcpy(g_state.connections[uConnection].headerStart + g_state.connections[uConnection].request.requestContent.uLength, pData->pData, uLengthToHandle); 00979 pData->pData += uLengthToHandle; 00980 pData->uLength -= (uint16)uLengthToHandle; 00981 g_state.connections[uConnection].uContentLeft -= uLengthToHandle; 00982 g_state.connections[uConnection].request.requestContent.uLength += (uint16)uLengthToHandle; 00983 } 00984 00985 return 1; 00986 } 00987 00988 /** 00989 * Returns HTTP 404 not found response 00990 */ 00991 static void HttpCore_ProcessNotFound(uint16 uConnection) 00992 { 00993 // call HttpResponse_CannedError with 404 NOT_FOUND 00994 HttpResponse_CannedError(uConnection, HTTP_STATUS_ERROR_NOT_FOUND); 00995 } 00996 00997 /** 00998 * Sends the input blob over the connection socket 00999 */ 01000 static int HttpCore_SendPacket(uint16 uConnection, struct HttpBlob buffer) 01001 { 01002 // Send the buffer over the data socket until all the buffer is sent 01003 while (buffer.uLength > 0) 01004 { 01005 int sent; 01006 if(buffer.uLength > MAX_SENT_DATA) 01007 { 01008 sent = send(g_state.connections[uConnection].dataSocket, (char*)buffer.pData, MAX_SENT_DATA, 0); 01009 if (sent <= 0) 01010 { 01011 printf("Send failed...\r\n"); 01012 // Connection must be closed if send has failed 01013 return 0; 01014 } 01015 } 01016 else 01017 { 01018 sent = send(g_state.connections[uConnection].dataSocket, (char*)buffer.pData, buffer.uLength, 0); 01019 if (sent <= 0) 01020 { 01021 printf("Send failed...\r\n"); 01022 // Connection must be closed if send has failed 01023 return 0; 01024 } 01025 } 01026 buffer.pData += sent; 01027 buffer.uLength -= (uint16)sent; 01028 } 01029 return 1; 01030 } 01031 01032 /** 01033 * Add char to the response buffer 01034 */ 01035 static void HttpResponse_AddCharToResponseHeaders(char ch) 01036 { 01037 //add char 01038 g_state.packetSend[g_state.packetSendSize] = ch; 01039 g_state.packetSendSize++; 01040 } 01041 01042 /** 01043 * Add uint32 number to the response buffer 01044 */ 01045 static void HttpResponse_AddNumberToResponseHeaders(uint32 num) 01046 { 01047 struct HttpBlob resource; 01048 resource.pData = g_state.packetSend + g_state.packetSendSize; 01049 resource.uLength = 0; 01050 HttpString_utoa(num, &resource); 01051 g_state.packetSendSize += resource.uLength; 01052 } 01053 01054 01055 /** 01056 * Add a string to the response buffer 01057 */ 01058 static void HttpResponse_AddStringToResponseHeaders(char * str, uint16 len) 01059 { 01060 memcpy(g_state.packetSend + g_state.packetSendSize, str, len); 01061 g_state.packetSendSize += len; 01062 } 01063 01064 /** 01065 * Add header line to response buffer 01066 * Adds a line to the header with the provided name value pair 01067 * Precondition to this function is that g_state.packetSendSize and g_state.packetSend are correct 01068 */ 01069 static void HttpResponse_AddHeaderLine(char * headerName, uint16 headerNameLen, char * headerValue, uint16 headerValueLen) 01070 { 01071 HttpResponse_AddStringToResponseHeaders(headerName, headerNameLen); 01072 HttpResponse_AddCharToResponseHeaders(':'); 01073 HttpResponse_AddCharToResponseHeaders(' '); 01074 HttpResponse_AddStringToResponseHeaders(headerValue, headerValueLen); 01075 HttpResponse_AddStringToResponseHeaders(HTTP_HEADER_DELIMITER, sizeof(HTTP_HEADER_DELIMITER)-1); 01076 } 01077 01078 /** 01079 * Add Header line to response buffer 01080 * Adds a line to the header with the provided name value pair when the value is numeric 01081 * precondition to this function is that g_state.packetSendSize and g_state.packetSend are correct 01082 */ 01083 static void HttpResponse_AddHeaderLineNumValue(char * headerName, uint16 uHeaderNameLen, uint32 headerValue) 01084 { 01085 HttpResponse_AddStringToResponseHeaders(headerName, uHeaderNameLen); 01086 HttpResponse_AddCharToResponseHeaders(':'); 01087 HttpResponse_AddCharToResponseHeaders(' '); 01088 HttpResponse_AddNumberToResponseHeaders(headerValue); 01089 HttpResponse_AddStringToResponseHeaders(HTTP_HEADER_DELIMITER, sizeof(HTTP_HEADER_DELIMITER)-1); 01090 } 01091 01092 /** 01093 * Returns status string according to status code 01094 */ 01095 static void HttpStatusString(uint16 uHttpStatus, struct HttpBlob* status) 01096 { 01097 switch (uHttpStatus) 01098 { 01099 case HTTP_STATUS_OK: 01100 HttpBlobSetConst(*status, HTTP_STATUS_OK_STR); 01101 break; 01102 case HTTP_STATUS_REDIRECT_PERMANENT: 01103 HttpBlobSetConst(*status, HTTP_STATUS_REDIRECT_PERMANENT_STR); 01104 break; 01105 case HTTP_STATUS_REDIRECT_TEMPORARY: 01106 HttpBlobSetConst(*status, HTTP_STATUS_REDIRECT_TEMPORARY_STR); 01107 break; 01108 case HTTP_STATUS_ERROR_UNAUTHORIZED: 01109 HttpBlobSetConst(*status, HTTP_STATUS_ERROR_UNAUTHORIZED_STR); 01110 break; 01111 case HTTP_STATUS_ERROR_NOT_FOUND: 01112 HttpBlobSetConst(*status, HTTP_STATUS_ERROR_NOT_FOUND_STR); 01113 break; 01114 case HTTP_STATUS_ERROR_NOT_ACCEPTED: 01115 HttpBlobSetConst(*status, HTTP_STATUS_ERROR_NOT_ACCEPTED_STR); 01116 break; 01117 case HTTP_STATUS_ERROR_INTERNAL: 01118 HttpBlobSetConst(*status, HTTP_STATUS_ERROR_INTERNAL_STR); 01119 break; 01120 default: 01121 HttpDebug("Unknown response status"); 01122 printf("Unknown response status\r\n"); 01123 //HttpAssert(0); 01124 break; 01125 } 01126 } 01127 01128 void HttpResponse_Headers(uint16 uConnection, uint16 uHttpStatus, uint16 uFlags, uint32 uContentLength, struct HttpBlob contentType, struct HttpBlob location) 01129 { 01130 //printf("ResponseHeaders...\r\n"); 01131 struct HttpBlob status; 01132 struct HttpBlob packet; 01133 //HttpAssert(g_state.packetSendSize == 0); 01134 //HttpAssert(g_state.connections[uConnection].connectionState == Processing); 01135 01136 // Get status string according to uHttpStatus 01137 HttpStatusString(uHttpStatus, &status); 01138 01139 // 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" 01140 // For example: HTTP/1.1 200 OK\r\n 01141 01142 // Add http version to sent packet according to the version that was received in the request 01143 if ( (g_state.connections[uConnection].request.uFlags & HTTP_REQUEST_1_1) != 0) 01144 HttpResponse_AddStringToResponseHeaders(HTTP_VERSION_1P1, sizeof(HTTP_VERSION_1P1)-1); 01145 else 01146 HttpResponse_AddStringToResponseHeaders(HTTP_VERSION_1P0, sizeof(HTTP_VERSION_1P0)-1); 01147 HttpResponse_AddCharToResponseHeaders(' '); 01148 HttpResponse_AddNumberToResponseHeaders(uHttpStatus); 01149 HttpResponse_AddCharToResponseHeaders(' '); 01150 HttpResponse_AddStringToResponseHeaders((char*)status.pData, status.uLength); 01151 HttpResponse_AddStringToResponseHeaders(HTTP_HEADER_DELIMITER, sizeof(HTTP_HEADER_DELIMITER)-1); 01152 01153 01154 // Handle Authentication 01155 if (uHttpStatus == HTTP_STATUS_ERROR_UNAUTHORIZED) 01156 { 01157 #ifdef HTTP_CORE_ENABLE_AUTH 01158 HttpResponse_GetPacketSendBuffer(&packet); 01159 packet.pData = packet.pData + packet.uLength; 01160 packet.uLength = HTTP_CORE_MAX_PACKET_SIZE_SEND - packet.uLength; 01161 HttpAuth_ResponseAuthenticate(&g_state.connections[uConnection].request, &packet); 01162 if (packet.uLength > 0) 01163 g_state.packetSendSize += packet.uLength; 01164 //printf("packet.uLength...%i\r\n",g_state.packetSendSize); 01165 #endif 01166 } 01167 //printf("Auth complete, now Handle content type...\r\n"); 01168 // Handle content type 01169 // e.g. "Content-Type: text/html\r\n" 01170 if ((contentType.pData != NULL) && (contentType.uLength > 0)) 01171 HttpResponse_AddHeaderLine(HTTP_CONTENT_TYPE, sizeof(HTTP_CONTENT_TYPE)-1, (char*)contentType.pData, contentType.uLength); 01172 01173 // Handle Content-length 01174 // e.g. "Content-Length: 562\r\n" 01175 //printf("Handle content-length...%i\r\n",uContentLength); 01176 if (uContentLength > 0) 01177 HttpResponse_AddHeaderLineNumValue(HTTP_CONTENT_LENGTH, sizeof(HTTP_CONTENT_LENGTH)-1, uContentLength); 01178 g_state.connections[uConnection].uContentLeft = uContentLength; 01179 01180 // Handle compression 01181 // e.g. "Content-Encoding: gzip\r\n" 01182 //printf("Handle compression...\r\n"); 01183 if ((uFlags & HTTP_RESPONSE_FLAG_COMPRESSED) != 0) 01184 HttpResponse_AddHeaderLine(HTTP_CONTENT_ENCODING, sizeof(HTTP_CONTENT_ENCODING)-1, HTTP_GZIP, sizeof(HTTP_GZIP)-1); 01185 01186 // Handle redirection/Location 01187 // e.g. "Location: /otherpage.html\r\n" 01188 //printf("Handle redirection/Location...\r\n"); 01189 if ((location.pData != NULL) && (location.uLength > 0)) 01190 HttpResponse_AddHeaderLine(HTTP_LOCATION, sizeof(HTTP_LOCATION)-1, (char*)location.pData, location.uLength); 01191 01192 // Add the end of headers marker (\r\n) 01193 HttpResponse_AddStringToResponseHeaders(HTTP_HEADER_DELIMITER, sizeof(HTTP_HEADER_DELIMITER)-1); 01194 01195 // Send all response headers over the connection socket 01196 //printf("Send all response headers...\r\n"); 01197 packet.pData = g_state.packetSend; 01198 packet.uLength = g_state.packetSendSize; 01199 //printf("packet.uLength...%i\r\n",packet.uLength); 01200 if (!HttpCore_SendPacket(uConnection, packet)){ 01201 //printf("Send all response headers failed...\r\n"); 01202 return; 01203 } 01204 g_state.packetSendSize = 0; 01205 //printf("Send all response headers complete...\r\n"); 01206 // advance state according to need to send content 01207 if (uContentLength > 0) 01208 g_state.connections[uConnection].connectionState = ResponseData; 01209 else 01210 g_state.connections[uConnection].connectionState = ResponseComplete; 01211 /* 01212 Todo: add logic to send the header packet at any point in the middle, if there is not enough room left in it. 01213 */ 01214 printf("Finished send...\r\n"); 01215 } 01216 01217 void HttpResponse_GetPacketSendBuffer(struct HttpBlob* pPacketSendBuffer) 01218 { 01219 pPacketSendBuffer->pData = g_state.packetSend; 01220 pPacketSendBuffer->uLength = g_state.packetSendSize; 01221 } 01222 01223 void HttpResponse_Content(uint16 uConnection, struct HttpBlob content) 01224 { 01225 //HttpAssert(g_state.connections[uConnection].connectionState == ResponseData); 01226 //HttpAssert(g_state.connections[uConnection].uContentLeft >= content.uLength); 01227 01228 // Send the specified content over the data socket 01229 HttpCore_SendPacket(uConnection, content); 01230 01231 // Update uContentLeft 01232 g_state.connections[uConnection].uContentLeft -= content.uLength; 01233 01234 // If no more content left to send then HTTP transaction is complete 01235 if (g_state.connections[uConnection].uContentLeft == 0) 01236 g_state.connections[uConnection].connectionState = ResponseComplete; 01237 } 01238 01239 void HttpResponse_CannedRedirect(uint16 uConnection, struct HttpBlob location, uint16 bPermanent) 01240 { 01241 struct HttpBlob status; 01242 HttpStatusString((bPermanent==1? HTTP_STATUS_REDIRECT_PERMANENT:HTTP_STATUS_REDIRECT_TEMPORARY), &status); 01243 01244 HttpResponse_Headers(uConnection, (bPermanent==1? HTTP_STATUS_REDIRECT_PERMANENT:HTTP_STATUS_REDIRECT_TEMPORARY), 0, 0, nullBlob, location); 01245 } 01246 01247 void HttpResponse_CannedError(uint16 uConnection, uint16 uHttpStatus) 01248 { 01249 struct HttpBlob status; 01250 HttpStatusString(uHttpStatus, &status); 01251 01252 HttpResponse_Headers(uConnection, uHttpStatus, 0, status.uLength, nullBlob, nullBlob); 01253 HttpResponse_Content(uConnection, status); 01254 } 01255 01256 01257 /// @} 01258
Generated on Wed Jul 13 2022 13:30:51 by
1.7.2