TI's CC3100 websocket camera demo with Arducam mini ov5642 and freertos. Should work with other M3's. Work in progress test demo.

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