A Port of TI's Webserver for the CC3000
Embed:
(wiki syntax)
Show/hide line numbers
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