Port of TI's CC3100 Websock camera demo. Using FreeRTOS, mbedTLS, also parts of Arducam for cams ov5642 and 0v2640. Can also use MT9D111. Work in progress. Be warned some parts maybe a bit flacky. This is for Seeed Arch max only, for an M3, see the demo for CM3 using the 0v5642 aducam mini.

Dependencies:   mbed

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers HttpCore.cpp Source File

HttpCore.cpp

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