Dependencies:   FatFileSystem mbed WeatherMeters SDFileSystem

Committer:
dcoban
Date:
Tue Apr 03 18:43:13 2012 +0000
Revision:
0:1a61c61d0845

        

Who changed what in which revision?

UserRevisionLine numberNew contents of line
dcoban 0:1a61c61d0845 1 /* Copyright 2011 Adam Green (http://mbed.org/users/AdamGreen/)
dcoban 0:1a61c61d0845 2
dcoban 0:1a61c61d0845 3 Licensed under the Apache License, Version 2.0 (the "License");
dcoban 0:1a61c61d0845 4 you may not use this file except in compliance with the License.
dcoban 0:1a61c61d0845 5 You may obtain a copy of the License at
dcoban 0:1a61c61d0845 6
dcoban 0:1a61c61d0845 7 http://www.apache.org/licenses/LICENSE-2.0
dcoban 0:1a61c61d0845 8
dcoban 0:1a61c61d0845 9 Unless required by applicable law or agreed to in writing, software
dcoban 0:1a61c61d0845 10 distributed under the License is distributed on an "AS IS" BASIS,
dcoban 0:1a61c61d0845 11 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
dcoban 0:1a61c61d0845 12 See the License for the specific language governing permissions and
dcoban 0:1a61c61d0845 13 limitations under the License.
dcoban 0:1a61c61d0845 14 */
dcoban 0:1a61c61d0845 15 /* Implementation of HTTP Server functionality. */
dcoban 0:1a61c61d0845 16 #include "HTTPServer.h"
dcoban 0:1a61c61d0845 17 #include "network.h"
dcoban 0:1a61c61d0845 18 #include "debug.h"
dcoban 0:1a61c61d0845 19
dcoban 0:1a61c61d0845 20
dcoban 0:1a61c61d0845 21 // HTTP_TRACE to 1/0 to enable/disable logging for the HTTP server.
dcoban 0:1a61c61d0845 22 #define HTTP_TRACE 0
dcoban 0:1a61c61d0845 23 #if HTTP_TRACE
dcoban 0:1a61c61d0845 24 #define TRACE printf
dcoban 0:1a61c61d0845 25 #else
dcoban 0:1a61c61d0845 26 static void __trace(...)
dcoban 0:1a61c61d0845 27 {
dcoban 0:1a61c61d0845 28 return;
dcoban 0:1a61c61d0845 29 }
dcoban 0:1a61c61d0845 30 #define TRACE __trace
dcoban 0:1a61c61d0845 31 #endif // HTTP_TRACE
dcoban 0:1a61c61d0845 32
dcoban 0:1a61c61d0845 33
dcoban 0:1a61c61d0845 34
dcoban 0:1a61c61d0845 35 // Maximum size of buffer to be allocated on the stack for building filename
dcoban 0:1a61c61d0845 36 // from URI that can be used in mbed fopen() call.
dcoban 0:1a61c61d0845 37 #define HTTP_MAX_FILENAME 64
dcoban 0:1a61c61d0845 38
dcoban 0:1a61c61d0845 39 // Maximum size of a request line to be buffered.
dcoban 0:1a61c61d0845 40 #define HTTP_MAX_REQUEST_LINE 128
dcoban 0:1a61c61d0845 41
dcoban 0:1a61c61d0845 42
dcoban 0:1a61c61d0845 43 // Utility macro to determine the element count of an array.
dcoban 0:1a61c61d0845 44 #define ARRAYSIZE(X) (sizeof(X)/sizeof(X[0]))
dcoban 0:1a61c61d0845 45
dcoban 0:1a61c61d0845 46
dcoban 0:1a61c61d0845 47
dcoban 0:1a61c61d0845 48 // Default filenames to be used when the requested URI is "/"
dcoban 0:1a61c61d0845 49 static const char* g_DefaultFilenames[] =
dcoban 0:1a61c61d0845 50 {
dcoban 0:1a61c61d0845 51 "/index.html",
dcoban 0:1a61c61d0845 52 "/index.htm"
dcoban 0:1a61c61d0845 53 };
dcoban 0:1a61c61d0845 54
dcoban 0:1a61c61d0845 55
dcoban 0:1a61c61d0845 56
dcoban 0:1a61c61d0845 57 // Static-Scope Function Prototypes.
dcoban 0:1a61c61d0845 58 static void NetworkPrintRemoteAddress(tcp_pcb* pPCB);
dcoban 0:1a61c61d0845 59
dcoban 0:1a61c61d0845 60
dcoban 0:1a61c61d0845 61
dcoban 0:1a61c61d0845 62 // Structure used to represent each header to be sent. It includes both a
dcoban 0:1a61c61d0845 63 // pointer to the constant string and the length of the constant string so
dcoban 0:1a61c61d0845 64 // that a memcpy() can be used for moving into buffer instead of strcpy().
dcoban 0:1a61c61d0845 65 struct SHeader
dcoban 0:1a61c61d0845 66 {
dcoban 0:1a61c61d0845 67 // Header string.
dcoban 0:1a61c61d0845 68 const char* pHeaderString;
dcoban 0:1a61c61d0845 69 // Length of header string, not including the NULL terminator.
dcoban 0:1a61c61d0845 70 unsigned int HeaderLength;
dcoban 0:1a61c61d0845 71 };
dcoban 0:1a61c61d0845 72
dcoban 0:1a61c61d0845 73
dcoban 0:1a61c61d0845 74 // Structure which stores information about each HTTP client connection.
dcoban 0:1a61c61d0845 75 class CHTTPContext : protected IHTTPRequestHandlerContext
dcoban 0:1a61c61d0845 76 {
dcoban 0:1a61c61d0845 77 public:
dcoban 0:1a61c61d0845 78 // Constructors/Destructors
dcoban 0:1a61c61d0845 79 CHTTPContext(CHTTPServer* pHTTPServer, tcp_pcb* pPCB);
dcoban 0:1a61c61d0845 80 ~CHTTPContext();
dcoban 0:1a61c61d0845 81
dcoban 0:1a61c61d0845 82 // IHTTPRequestHandlerContext methods.
dcoban 0:1a61c61d0845 83 virtual int BeginRequestHeaders();
dcoban 0:1a61c61d0845 84 virtual void WriteRequestHeader(const char* pHeaderName,
dcoban 0:1a61c61d0845 85 const char* pHeaderValue);
dcoban 0:1a61c61d0845 86 virtual void EndRequestHeaders();
dcoban 0:1a61c61d0845 87 virtual int BeginRequestContent(size_t ContentSize);
dcoban 0:1a61c61d0845 88 virtual void WriteRequestContentBlock(const void* pBlockBuffer,
dcoban 0:1a61c61d0845 89 size_t BlockBufferSize);
dcoban 0:1a61c61d0845 90 virtual void EndRequestContent();
dcoban 0:1a61c61d0845 91 virtual const char* GetStatusLine(size_t* pStatusLineLength);
dcoban 0:1a61c61d0845 92 virtual const char* GetResponseHeaders(size_t* pResponseHeaderLength);
dcoban 0:1a61c61d0845 93 virtual int BeginResponseContent();
dcoban 0:1a61c61d0845 94 virtual size_t ReadResponseContentBlock(char* pBuffer,
dcoban 0:1a61c61d0845 95 size_t BytesToRead);
dcoban 0:1a61c61d0845 96 virtual void EndResponseContent();
dcoban 0:1a61c61d0845 97 virtual void Release();
dcoban 0:1a61c61d0845 98
dcoban 0:1a61c61d0845 99 CHTTPServer* Server() { return m_pHTTPServer; }
dcoban 0:1a61c61d0845 100 CHTTPContext* GetNext() { return m_pNext; }
dcoban 0:1a61c61d0845 101 void RemovedFromWaitingList(CHTTPContext* pPrev)
dcoban 0:1a61c61d0845 102 {
dcoban 0:1a61c61d0845 103 if (pPrev)
dcoban 0:1a61c61d0845 104 {
dcoban 0:1a61c61d0845 105 pPrev->m_pNext = this->m_pNext;
dcoban 0:1a61c61d0845 106 }
dcoban 0:1a61c61d0845 107 m_pNext = NULL;
dcoban 0:1a61c61d0845 108 m_WaitingForBuffer = 0;
dcoban 0:1a61c61d0845 109 }
dcoban 0:1a61c61d0845 110 void AddToWaitingList(CHTTPContext* pPrev)
dcoban 0:1a61c61d0845 111 {
dcoban 0:1a61c61d0845 112 if (pPrev)
dcoban 0:1a61c61d0845 113 {
dcoban 0:1a61c61d0845 114 assert ( !pPrev->m_pNext );
dcoban 0:1a61c61d0845 115 pPrev->m_pNext = this;
dcoban 0:1a61c61d0845 116 }
dcoban 0:1a61c61d0845 117 m_WaitingForBuffer = 1;
dcoban 0:1a61c61d0845 118 }
dcoban 0:1a61c61d0845 119 int IsWaitingForBuffer() { return m_WaitingForBuffer; }
dcoban 0:1a61c61d0845 120
dcoban 0:1a61c61d0845 121 void CloseConnection();
dcoban 0:1a61c61d0845 122 void FreeContext(int ForcedFree);
dcoban 0:1a61c61d0845 123 void BufferAvailable();
dcoban 0:1a61c61d0845 124
dcoban 0:1a61c61d0845 125 protected:
dcoban 0:1a61c61d0845 126 // Static methods for lwIP callbacks.
dcoban 0:1a61c61d0845 127 static err_t HTTPRecv(void* pvArg, tcp_pcb* pPCB, pbuf* pBuf, err_t err);
dcoban 0:1a61c61d0845 128 static err_t HTTPSent(void* pvArg, tcp_pcb* pPCB, u16_t SendCount);
dcoban 0:1a61c61d0845 129 static void HTTPError(void* pvArg, err_t Error);
dcoban 0:1a61c61d0845 130 static err_t HTTPPoll(void* pvArg, tcp_pcb* pPCB);
dcoban 0:1a61c61d0845 131
dcoban 0:1a61c61d0845 132 // Protected helper methods.
dcoban 0:1a61c61d0845 133 void ProcessRequestData(pbuf* pBuf);
dcoban 0:1a61c61d0845 134 void BufferRequestLines(pbuf* pBuf);
dcoban 0:1a61c61d0845 135 void ProcessRequestContent(pbuf* pBuf);
dcoban 0:1a61c61d0845 136 void ParseRequestLine();
dcoban 0:1a61c61d0845 137 void ParseFirstRequestLine();
dcoban 0:1a61c61d0845 138 void ParseHeaderRequestLine();
dcoban 0:1a61c61d0845 139 void StartRequestHandler(const char* pURI);
dcoban 0:1a61c61d0845 140 void StartGetRequest(const char* pURI);
dcoban 0:1a61c61d0845 141 void StartHeadRequest(const char* pURI);
dcoban 0:1a61c61d0845 142 void StartPostRequest(const char* pURI);
dcoban 0:1a61c61d0845 143 void StartBadRequest(const char* pRequest);
dcoban 0:1a61c61d0845 144 void OpenFile(const char* pURI);
dcoban 0:1a61c61d0845 145 void PrepareResponse();
dcoban 0:1a61c61d0845 146 void PrepareResponseHeaders();
dcoban 0:1a61c61d0845 147 void ReadContent();
dcoban 0:1a61c61d0845 148 void SendResponse();
dcoban 0:1a61c61d0845 149 int WriteData();
dcoban 0:1a61c61d0845 150
dcoban 0:1a61c61d0845 151 // States used to track the HTTP request parsing progress.
dcoban 0:1a61c61d0845 152 enum EParseState {
dcoban 0:1a61c61d0845 153 STATE_FIRST_LINE,
dcoban 0:1a61c61d0845 154 STATE_HEADERS,
dcoban 0:1a61c61d0845 155 STATE_CONTENT,
dcoban 0:1a61c61d0845 156 STATE_DONE
dcoban 0:1a61c61d0845 157 };
dcoban 0:1a61c61d0845 158
dcoban 0:1a61c61d0845 159 // Type of HTTP request that has been made by the client.
dcoban 0:1a61c61d0845 160 enum ERequestType
dcoban 0:1a61c61d0845 161 {
dcoban 0:1a61c61d0845 162 TYPE_GET_0_9,
dcoban 0:1a61c61d0845 163 TYPE_GET_1_0,
dcoban 0:1a61c61d0845 164 TYPE_HEAD,
dcoban 0:1a61c61d0845 165 TYPE_POST,
dcoban 0:1a61c61d0845 166 TYPE_BAD_REQUEST
dcoban 0:1a61c61d0845 167 };
dcoban 0:1a61c61d0845 168
dcoban 0:1a61c61d0845 169 // Pointer to parent HTTP Server object.
dcoban 0:1a61c61d0845 170 CHTTPServer* m_pHTTPServer;
dcoban 0:1a61c61d0845 171 // Pointer to the tcp_pcb 'socket' for this context.
dcoban 0:1a61c61d0845 172 tcp_pcb* m_pPCB;
dcoban 0:1a61c61d0845 173 // The next context in the buffer waiting queue.
dcoban 0:1a61c61d0845 174 CHTTPContext* m_pNext;
dcoban 0:1a61c61d0845 175 // Handle of file to be sent to the client.
dcoban 0:1a61c61d0845 176 FILE* m_pFile;
dcoban 0:1a61c61d0845 177 // Pointer to the request handler context. May point to self for
dcoban 0:1a61c61d0845 178 // default GET/HEAD request handling.
dcoban 0:1a61c61d0845 179 IHTTPRequestHandlerContext* m_pRequestHandlerContext;
dcoban 0:1a61c61d0845 180 // Content-Type description header field.
dcoban 0:1a61c61d0845 181 const char* m_pContentType;
dcoban 0:1a61c61d0845 182 // HTML text to be sent back in response to error.
dcoban 0:1a61c61d0845 183 const char* m_pErrorHTML;
dcoban 0:1a61c61d0845 184 // Queue of buffers used by this context. BufferQueueHead and
dcoban 0:1a61c61d0845 185 // BufferQueueTail track the current buffers being written and/or
dcoban 0:1a61c61d0845 186 // waiting for acknowledgment from remote machine.
dcoban 0:1a61c61d0845 187 SBuffer* m_BufferQueue[2];
dcoban 0:1a61c61d0845 188 // Array of pointers to constant header strings to be sent before response
dcoban 0:1a61c61d0845 189 // content. Status Line, Server:, Other Headers, /r/n
dcoban 0:1a61c61d0845 190 SHeader m_HeaderArray[4];
dcoban 0:1a61c61d0845 191 // The length of the m_pContentType string.
dcoban 0:1a61c61d0845 192 size_t m_ContentTypeLength;
dcoban 0:1a61c61d0845 193 // The length of the m_pErrorHTML string.
dcoban 0:1a61c61d0845 194 size_t m_ErrorHTMLLength;
dcoban 0:1a61c61d0845 195 // The current read offset into the m_pErrorHTML string.
dcoban 0:1a61c61d0845 196 size_t m_ErrorHTMLOffset;
dcoban 0:1a61c61d0845 197 // UNDONE: Many of these fields could be packed into a single field to save memory.
dcoban 0:1a61c61d0845 198 // Are we waiting for a buffer already?
dcoban 0:1a61c61d0845 199 int m_WaitingForBuffer;
dcoban 0:1a61c61d0845 200 // Are we in the process of closing down the connection?
dcoban 0:1a61c61d0845 201 int m_ClosingConnection;
dcoban 0:1a61c61d0845 202 // Should request headers be sent to handler?
dcoban 0:1a61c61d0845 203 int m_SendRequestHeadersToHandler;
dcoban 0:1a61c61d0845 204 // Should request content be sent to handler?
dcoban 0:1a61c61d0845 205 int m_SendRequestContentToHandler;
dcoban 0:1a61c61d0845 206 // Content-Length of request content body.
dcoban 0:1a61c61d0845 207 unsigned int m_RequestContentLength;
dcoban 0:1a61c61d0845 208 // The current state of the request parsing code.
dcoban 0:1a61c61d0845 209 EParseState m_ParseState;
dcoban 0:1a61c61d0845 210 // The type of request being made by the client.
dcoban 0:1a61c61d0845 211 ERequestType m_RequestType;
dcoban 0:1a61c61d0845 212 // UNDONE: Check for memory savings across these structures.
dcoban 0:1a61c61d0845 213 // Offset into m_LineBuffer where next character should be placed.
dcoban 0:1a61c61d0845 214 unsigned short m_LineBufferOffset;
dcoban 0:1a61c61d0845 215 // Offset into current header being sent to client.
dcoban 0:1a61c61d0845 216 unsigned short m_HeaderOffset;
dcoban 0:1a61c61d0845 217 // Head and tail indices for SentBufferQueue.
dcoban 0:1a61c61d0845 218 // Head is the buffer currently being written.
dcoban 0:1a61c61d0845 219 unsigned char m_BufferQueueHead;
dcoban 0:1a61c61d0845 220 // Tail is the buffer currently in the process of being acknowledged.
dcoban 0:1a61c61d0845 221 unsigned char m_BufferQueueTail;
dcoban 0:1a61c61d0845 222 // Number of tcp_write() retries attempted so far.
dcoban 0:1a61c61d0845 223 unsigned char m_RetryCount;
dcoban 0:1a61c61d0845 224 // Current index into HeaderArray[] of next header to be sent to client.
dcoban 0:1a61c61d0845 225 unsigned char m_HeaderIndex;
dcoban 0:1a61c61d0845 226 // Each line of the request is buffered here.
dcoban 0:1a61c61d0845 227 char m_LineBuffer[HTTP_MAX_REQUEST_LINE+1];
dcoban 0:1a61c61d0845 228 };
dcoban 0:1a61c61d0845 229
dcoban 0:1a61c61d0845 230
dcoban 0:1a61c61d0845 231 CHTTPContext::CHTTPContext(CHTTPServer* pHTTPServer, tcp_pcb* pPCB)
dcoban 0:1a61c61d0845 232 {
dcoban 0:1a61c61d0845 233 m_pHTTPServer = pHTTPServer;
dcoban 0:1a61c61d0845 234 m_pPCB = pPCB;
dcoban 0:1a61c61d0845 235 m_pNext = NULL;
dcoban 0:1a61c61d0845 236 m_pFile = NULL;
dcoban 0:1a61c61d0845 237 m_pRequestHandlerContext = NULL;
dcoban 0:1a61c61d0845 238 m_pContentType = NULL;
dcoban 0:1a61c61d0845 239 m_pErrorHTML = NULL;
dcoban 0:1a61c61d0845 240 memset(m_BufferQueue, 0, sizeof(m_BufferQueue));
dcoban 0:1a61c61d0845 241 memset(m_HeaderArray, 0, sizeof(m_HeaderArray));
dcoban 0:1a61c61d0845 242 m_ContentTypeLength = 0;
dcoban 0:1a61c61d0845 243 m_ErrorHTMLLength = 0;
dcoban 0:1a61c61d0845 244 m_ErrorHTMLOffset = 0;
dcoban 0:1a61c61d0845 245 m_WaitingForBuffer = 0;
dcoban 0:1a61c61d0845 246 m_ClosingConnection = 0;
dcoban 0:1a61c61d0845 247 m_SendRequestHeadersToHandler = 0;
dcoban 0:1a61c61d0845 248 m_SendRequestContentToHandler = 0;
dcoban 0:1a61c61d0845 249 m_RequestContentLength = 0;
dcoban 0:1a61c61d0845 250 m_ParseState = STATE_FIRST_LINE;
dcoban 0:1a61c61d0845 251 m_RequestType = TYPE_BAD_REQUEST;
dcoban 0:1a61c61d0845 252 m_LineBufferOffset = 0;
dcoban 0:1a61c61d0845 253 m_HeaderOffset = 0;
dcoban 0:1a61c61d0845 254 m_BufferQueueHead = 0;
dcoban 0:1a61c61d0845 255 m_BufferQueueTail = 0;
dcoban 0:1a61c61d0845 256 m_RetryCount = 0;
dcoban 0:1a61c61d0845 257 m_HeaderIndex = 0;
dcoban 0:1a61c61d0845 258 m_LineBuffer[0] = '\0';
dcoban 0:1a61c61d0845 259
dcoban 0:1a61c61d0845 260 // Associate this context with the lwIP PCB object.
dcoban 0:1a61c61d0845 261 tcp_arg(pPCB, this);
dcoban 0:1a61c61d0845 262
dcoban 0:1a61c61d0845 263 // Setup the callbacks to be called whenever any activity occurs on this new
dcoban 0:1a61c61d0845 264 // client PCB.
dcoban 0:1a61c61d0845 265 tcp_recv(pPCB, HTTPRecv);
dcoban 0:1a61c61d0845 266 tcp_sent(pPCB, HTTPSent);
dcoban 0:1a61c61d0845 267 tcp_err(pPCB, HTTPError);
dcoban 0:1a61c61d0845 268
dcoban 0:1a61c61d0845 269 // There might be scenarios where the application can't queue up more work
dcoban 0:1a61c61d0845 270 // for this client PCB (due to things like out of memory) so that activity
dcoban 0:1a61c61d0845 271 // could cease on this PCB when there were no more calls to functions like
dcoban 0:1a61c61d0845 272 // HTTPSent(). To make sure this doesn't happen, have lwIP callback into
dcoban 0:1a61c61d0845 273 // the HTTPPoll() function every 4 iterations of the coarse TCP timer (2
dcoban 0:1a61c61d0845 274 // seconds). HTTPPoll() can take care of retrying any previously failed
dcoban 0:1a61c61d0845 275 // operations.
dcoban 0:1a61c61d0845 276 tcp_poll(pPCB, HTTPPoll, 4);
dcoban 0:1a61c61d0845 277 }
dcoban 0:1a61c61d0845 278
dcoban 0:1a61c61d0845 279
dcoban 0:1a61c61d0845 280 // Destructor
dcoban 0:1a61c61d0845 281 CHTTPContext::~CHTTPContext()
dcoban 0:1a61c61d0845 282 {
dcoban 0:1a61c61d0845 283 // Make sure that everything was cleaned up before destructor was called.
dcoban 0:1a61c61d0845 284 assert ( NULL == m_pFile );
dcoban 0:1a61c61d0845 285 assert ( NULL == m_pPCB );
dcoban 0:1a61c61d0845 286 assert ( NULL == m_pRequestHandlerContext );
dcoban 0:1a61c61d0845 287 }
dcoban 0:1a61c61d0845 288
dcoban 0:1a61c61d0845 289
dcoban 0:1a61c61d0845 290 int CHTTPContext::BeginRequestHeaders()
dcoban 0:1a61c61d0845 291 {
dcoban 0:1a61c61d0845 292 // This context already parses out the Content-Length header that it needs.
dcoban 0:1a61c61d0845 293 return 0;
dcoban 0:1a61c61d0845 294 }
dcoban 0:1a61c61d0845 295
dcoban 0:1a61c61d0845 296 void CHTTPContext::WriteRequestHeader(const char* pHeaderName,
dcoban 0:1a61c61d0845 297 const char* pHeaderValue)
dcoban 0:1a61c61d0845 298 {
dcoban 0:1a61c61d0845 299 static const int ShouldNotBeCalled = 0;
dcoban 0:1a61c61d0845 300
dcoban 0:1a61c61d0845 301 (void)pHeaderName;
dcoban 0:1a61c61d0845 302 (void)pHeaderValue;
dcoban 0:1a61c61d0845 303
dcoban 0:1a61c61d0845 304 assert ( ShouldNotBeCalled );
dcoban 0:1a61c61d0845 305 }
dcoban 0:1a61c61d0845 306
dcoban 0:1a61c61d0845 307 void CHTTPContext::EndRequestHeaders()
dcoban 0:1a61c61d0845 308 {
dcoban 0:1a61c61d0845 309 static const int ShouldNotBeCalled = 0;
dcoban 0:1a61c61d0845 310
dcoban 0:1a61c61d0845 311 assert ( ShouldNotBeCalled );
dcoban 0:1a61c61d0845 312 }
dcoban 0:1a61c61d0845 313
dcoban 0:1a61c61d0845 314 int CHTTPContext::BeginRequestContent(size_t ContentSize)
dcoban 0:1a61c61d0845 315 {
dcoban 0:1a61c61d0845 316 (void)ContentSize;
dcoban 0:1a61c61d0845 317
dcoban 0:1a61c61d0845 318 // Only processing GET and HEAD requests so don't care about content sent
dcoban 0:1a61c61d0845 319 // in request.
dcoban 0:1a61c61d0845 320 return 0;
dcoban 0:1a61c61d0845 321 }
dcoban 0:1a61c61d0845 322
dcoban 0:1a61c61d0845 323 void CHTTPContext::WriteRequestContentBlock(const void* pBlockBuffer,
dcoban 0:1a61c61d0845 324 size_t BlockBufferSize)
dcoban 0:1a61c61d0845 325 {
dcoban 0:1a61c61d0845 326 static const int ShouldNotBeCalled = 0;
dcoban 0:1a61c61d0845 327
dcoban 0:1a61c61d0845 328 (void)pBlockBuffer;
dcoban 0:1a61c61d0845 329 (void)BlockBufferSize;
dcoban 0:1a61c61d0845 330
dcoban 0:1a61c61d0845 331 assert ( ShouldNotBeCalled );
dcoban 0:1a61c61d0845 332 }
dcoban 0:1a61c61d0845 333
dcoban 0:1a61c61d0845 334 void CHTTPContext::EndRequestContent()
dcoban 0:1a61c61d0845 335 {
dcoban 0:1a61c61d0845 336 static const int ShouldNotBeCalled = 0;
dcoban 0:1a61c61d0845 337
dcoban 0:1a61c61d0845 338 assert ( ShouldNotBeCalled );
dcoban 0:1a61c61d0845 339 }
dcoban 0:1a61c61d0845 340
dcoban 0:1a61c61d0845 341 const char* CHTTPContext::GetStatusLine(size_t* pStatusLineLength)
dcoban 0:1a61c61d0845 342 {
dcoban 0:1a61c61d0845 343 static const char Ok[] = "HTTP/1.0 200 OK\r\n";
dcoban 0:1a61c61d0845 344 static const char NotFound[] = "HTTP/1.0 404 Not Found\r\n";
dcoban 0:1a61c61d0845 345 static const char BadRequest[] = "HTTP/1.0 400 Bad Request\r\n";
dcoban 0:1a61c61d0845 346 static const char NotImplemented[] = "HTTP/1.0 501 Not Implemented\r\n";
dcoban 0:1a61c61d0845 347
dcoban 0:1a61c61d0845 348 switch (m_RequestType)
dcoban 0:1a61c61d0845 349 {
dcoban 0:1a61c61d0845 350 case TYPE_HEAD:
dcoban 0:1a61c61d0845 351 case TYPE_GET_1_0:
dcoban 0:1a61c61d0845 352 if (m_pFile)
dcoban 0:1a61c61d0845 353 {
dcoban 0:1a61c61d0845 354 *pStatusLineLength = sizeof(Ok) - 1;
dcoban 0:1a61c61d0845 355 return Ok;
dcoban 0:1a61c61d0845 356 }
dcoban 0:1a61c61d0845 357 else
dcoban 0:1a61c61d0845 358 {
dcoban 0:1a61c61d0845 359 *pStatusLineLength = sizeof(NotFound) - 1;
dcoban 0:1a61c61d0845 360 return NotFound;
dcoban 0:1a61c61d0845 361 }
dcoban 0:1a61c61d0845 362 break;
dcoban 0:1a61c61d0845 363 case TYPE_GET_0_9:
dcoban 0:1a61c61d0845 364 // Shouldn't get called for such a request.
dcoban 0:1a61c61d0845 365 assert ( TYPE_GET_0_9 != m_RequestType );
dcoban 0:1a61c61d0845 366 return NULL;
dcoban 0:1a61c61d0845 367 case TYPE_BAD_REQUEST:
dcoban 0:1a61c61d0845 368 *pStatusLineLength = sizeof(BadRequest) - 1;
dcoban 0:1a61c61d0845 369 return BadRequest;
dcoban 0:1a61c61d0845 370 default:
dcoban 0:1a61c61d0845 371 // This server has no default handling for any other type of request.
dcoban 0:1a61c61d0845 372 *pStatusLineLength = sizeof(NotImplemented) - 1;
dcoban 0:1a61c61d0845 373 return NotImplemented;
dcoban 0:1a61c61d0845 374 }
dcoban 0:1a61c61d0845 375 }
dcoban 0:1a61c61d0845 376
dcoban 0:1a61c61d0845 377 const char* CHTTPContext::GetResponseHeaders(size_t* pResponseHeaderLength)
dcoban 0:1a61c61d0845 378 {
dcoban 0:1a61c61d0845 379 // Additional error text will be returned as HTML text.
dcoban 0:1a61c61d0845 380 static const char ContentTypeHTML[] = "Content-type: text/html\r\n";
dcoban 0:1a61c61d0845 381 static const char NotImplementedHTML[] = "<html>"
dcoban 0:1a61c61d0845 382 "<body><h2>501: Not Implemented.</h2></body>"
dcoban 0:1a61c61d0845 383 "</html>\r\n";
dcoban 0:1a61c61d0845 384 static const char BadRequestHTML[] = "<html>"
dcoban 0:1a61c61d0845 385 "<body><h2>400: Bad Request.</h2></body>"
dcoban 0:1a61c61d0845 386 "</html>\r\n";
dcoban 0:1a61c61d0845 387
dcoban 0:1a61c61d0845 388 switch (m_RequestType)
dcoban 0:1a61c61d0845 389 {
dcoban 0:1a61c61d0845 390 case TYPE_HEAD:
dcoban 0:1a61c61d0845 391 case TYPE_GET_1_0:
dcoban 0:1a61c61d0845 392 *pResponseHeaderLength = m_ContentTypeLength;
dcoban 0:1a61c61d0845 393 return m_pContentType;
dcoban 0:1a61c61d0845 394 case TYPE_GET_0_9:
dcoban 0:1a61c61d0845 395 // Shouldn't get called for such a request.
dcoban 0:1a61c61d0845 396 assert ( TYPE_GET_0_9 != m_RequestType );
dcoban 0:1a61c61d0845 397 return NULL;
dcoban 0:1a61c61d0845 398 case TYPE_BAD_REQUEST:
dcoban 0:1a61c61d0845 399 // Will send error back as HTML text.
dcoban 0:1a61c61d0845 400 m_pErrorHTML = BadRequestHTML;
dcoban 0:1a61c61d0845 401 m_ErrorHTMLLength = sizeof(BadRequestHTML) - 1;
dcoban 0:1a61c61d0845 402 *pResponseHeaderLength = sizeof(ContentTypeHTML) - 1;
dcoban 0:1a61c61d0845 403 return ContentTypeHTML;
dcoban 0:1a61c61d0845 404 default:
dcoban 0:1a61c61d0845 405 // This server has no default handling for any other type of request.
dcoban 0:1a61c61d0845 406 m_pErrorHTML = NotImplementedHTML;
dcoban 0:1a61c61d0845 407 m_ErrorHTMLLength = sizeof(NotImplementedHTML) - 1;
dcoban 0:1a61c61d0845 408 *pResponseHeaderLength = sizeof(ContentTypeHTML) - 1;
dcoban 0:1a61c61d0845 409 return ContentTypeHTML;
dcoban 0:1a61c61d0845 410 }
dcoban 0:1a61c61d0845 411 }
dcoban 0:1a61c61d0845 412
dcoban 0:1a61c61d0845 413 int CHTTPContext::BeginResponseContent()
dcoban 0:1a61c61d0845 414 {
dcoban 0:1a61c61d0845 415 // Have response content to send back so return 1;
dcoban 0:1a61c61d0845 416 assert ( m_pFile || m_pErrorHTML );
dcoban 0:1a61c61d0845 417 return 1;
dcoban 0:1a61c61d0845 418 }
dcoban 0:1a61c61d0845 419
dcoban 0:1a61c61d0845 420 size_t CHTTPContext::ReadResponseContentBlock(char* pBuffer,
dcoban 0:1a61c61d0845 421 size_t BytesToRead)
dcoban 0:1a61c61d0845 422 {
dcoban 0:1a61c61d0845 423 if (m_pFile)
dcoban 0:1a61c61d0845 424 {
dcoban 0:1a61c61d0845 425 // Read content from file.
dcoban 0:1a61c61d0845 426 return fread(pBuffer, 1, BytesToRead, m_pFile);
dcoban 0:1a61c61d0845 427 }
dcoban 0:1a61c61d0845 428 else
dcoban 0:1a61c61d0845 429 {
dcoban 0:1a61c61d0845 430 // Read content from HTML text for error.
dcoban 0:1a61c61d0845 431 size_t BytesLeft = m_ErrorHTMLLength - m_ErrorHTMLOffset;
dcoban 0:1a61c61d0845 432
dcoban 0:1a61c61d0845 433 if (BytesToRead > BytesLeft)
dcoban 0:1a61c61d0845 434 {
dcoban 0:1a61c61d0845 435 BytesToRead = BytesLeft;
dcoban 0:1a61c61d0845 436 }
dcoban 0:1a61c61d0845 437 memcpy(pBuffer, &m_pErrorHTML[m_ErrorHTMLOffset], BytesToRead);
dcoban 0:1a61c61d0845 438 m_ErrorHTMLOffset += BytesToRead;
dcoban 0:1a61c61d0845 439
dcoban 0:1a61c61d0845 440 return BytesToRead;
dcoban 0:1a61c61d0845 441 }
dcoban 0:1a61c61d0845 442 }
dcoban 0:1a61c61d0845 443
dcoban 0:1a61c61d0845 444 void CHTTPContext::EndResponseContent()
dcoban 0:1a61c61d0845 445 {
dcoban 0:1a61c61d0845 446 if (m_pFile)
dcoban 0:1a61c61d0845 447 {
dcoban 0:1a61c61d0845 448 fclose(m_pFile);
dcoban 0:1a61c61d0845 449 m_pFile = NULL;
dcoban 0:1a61c61d0845 450 }
dcoban 0:1a61c61d0845 451 }
dcoban 0:1a61c61d0845 452
dcoban 0:1a61c61d0845 453 void CHTTPContext::Release()
dcoban 0:1a61c61d0845 454 {
dcoban 0:1a61c61d0845 455 // Just make sure that any files are closed.
dcoban 0:1a61c61d0845 456 EndResponseContent();
dcoban 0:1a61c61d0845 457
dcoban 0:1a61c61d0845 458 return;
dcoban 0:1a61c61d0845 459 }
dcoban 0:1a61c61d0845 460
dcoban 0:1a61c61d0845 461
dcoban 0:1a61c61d0845 462 /* Called by lwIP whenever data is sent to an active connection. The main task
dcoban 0:1a61c61d0845 463 of this callback is to acknowledge application receipt of the data, parse
dcoban 0:1a61c61d0845 464 the received data to determine which file is being requested by the client,
dcoban 0:1a61c61d0845 465 open the requested file, and start sending it back to the remote client.
dcoban 0:1a61c61d0845 466
dcoban 0:1a61c61d0845 467 Parameters:
dcoban 0:1a61c61d0845 468 pvArg is the value set on the active PCB through the call to tcp_arg in
dcoban 0:1a61c61d0845 469 HTTPAccept() which is a pointer to the HTTP context for this
dcoban 0:1a61c61d0845 470 connection.
dcoban 0:1a61c61d0845 471 pPCB is a pointer to the PCB that has just received some data from the
dcoban 0:1a61c61d0845 472 client.
dcoban 0:1a61c61d0845 473 pBuf is a pointer to a PBUF which contains a linked list of the data
dcoban 0:1a61c61d0845 474 received from the remote client.
dcoban 0:1a61c61d0845 475 err is passed in from the lwIP stack to indicate if an error occurred.
dcoban 0:1a61c61d0845 476
dcoban 0:1a61c61d0845 477 Returns:
dcoban 0:1a61c61d0845 478 ERR_ABRT if we end up aborting the connection and ERR_OK otherwise.
dcoban 0:1a61c61d0845 479 */
dcoban 0:1a61c61d0845 480 err_t CHTTPContext::HTTPRecv(void* pvArg, tcp_pcb* pPCB, pbuf* pBuf, err_t err)
dcoban 0:1a61c61d0845 481 {
dcoban 0:1a61c61d0845 482 CHTTPContext* pHTTPContext = (CHTTPContext*)pvArg;
dcoban 0:1a61c61d0845 483
dcoban 0:1a61c61d0845 484 // Validate parameters.
dcoban 0:1a61c61d0845 485 assert ( pPCB );
dcoban 0:1a61c61d0845 486 assert ( ERR_OK == err );
dcoban 0:1a61c61d0845 487
dcoban 0:1a61c61d0845 488 // If the client has closed their end then pBuf will be NULL so the server
dcoban 0:1a61c61d0845 489 // should shutdown its end as well.
dcoban 0:1a61c61d0845 490 if (!pBuf)
dcoban 0:1a61c61d0845 491 {
dcoban 0:1a61c61d0845 492 TRACE("HTTP: Closing as client closed its end for connection: ");
dcoban 0:1a61c61d0845 493 NetworkPrintRemoteAddress(pPCB);
dcoban 0:1a61c61d0845 494 TRACE("\r\n");
dcoban 0:1a61c61d0845 495
dcoban 0:1a61c61d0845 496 pHTTPContext->CloseConnection();
dcoban 0:1a61c61d0845 497 pHTTPContext->FreeContext(TRUE);
dcoban 0:1a61c61d0845 498
dcoban 0:1a61c61d0845 499 return ERR_OK;
dcoban 0:1a61c61d0845 500 }
dcoban 0:1a61c61d0845 501
dcoban 0:1a61c61d0845 502 // Let lwIP know that the HTTP application has received the data.
dcoban 0:1a61c61d0845 503 tcp_recved(pPCB, pBuf->tot_len);
dcoban 0:1a61c61d0845 504
dcoban 0:1a61c61d0845 505 // Just return if we have already freed the client context from a close
dcoban 0:1a61c61d0845 506 // attempt.
dcoban 0:1a61c61d0845 507 if (!pvArg)
dcoban 0:1a61c61d0845 508 {
dcoban 0:1a61c61d0845 509 TRACE("HTTP: Ignoring HTTPRecv() as client context was already freed for: ");
dcoban 0:1a61c61d0845 510 NetworkPrintRemoteAddress(pPCB);
dcoban 0:1a61c61d0845 511 TRACE("\r\n");
dcoban 0:1a61c61d0845 512 goto Error;
dcoban 0:1a61c61d0845 513 }
dcoban 0:1a61c61d0845 514
dcoban 0:1a61c61d0845 515 // The PCB shouldn't change out underneath this object!
dcoban 0:1a61c61d0845 516 assert ( pPCB == pHTTPContext->m_pPCB );
dcoban 0:1a61c61d0845 517
dcoban 0:1a61c61d0845 518 pHTTPContext->ProcessRequestData(pBuf);
dcoban 0:1a61c61d0845 519
dcoban 0:1a61c61d0845 520 Error:
dcoban 0:1a61c61d0845 521 // Release the pbuf as the application no longer requires any of its data
dcoban 0:1a61c61d0845 522 pbuf_free(pBuf);
dcoban 0:1a61c61d0845 523
dcoban 0:1a61c61d0845 524 return ERR_OK;
dcoban 0:1a61c61d0845 525 }
dcoban 0:1a61c61d0845 526
dcoban 0:1a61c61d0845 527
dcoban 0:1a61c61d0845 528 /* Called by lwIP whenever sent data is acknowledged by the remote machine.
dcoban 0:1a61c61d0845 529 The main task of this callback is to update the byte count of unacknowledged
dcoban 0:1a61c61d0845 530 bytes and send more data once the previously sent data has been acknowledged.
dcoban 0:1a61c61d0845 531
dcoban 0:1a61c61d0845 532 Parameters:
dcoban 0:1a61c61d0845 533 pvArg is the value set on the active PCB through the call to tcp_arg in
dcoban 0:1a61c61d0845 534 HTTPAccept() which is a pointer to the HTTP context for this
dcoban 0:1a61c61d0845 535 connection.
dcoban 0:1a61c61d0845 536 pPCB is a pointer to the PCB that has just received acknowledgement from
dcoban 0:1a61c61d0845 537 the remote client of sent data.
dcoban 0:1a61c61d0845 538 AcknowledgeCount is the number of bytes that the remote client has
dcoban 0:1a61c61d0845 539 acknowledged receipt of.
dcoban 0:1a61c61d0845 540
dcoban 0:1a61c61d0845 541 Returns:
dcoban 0:1a61c61d0845 542 ERR_ABRT if we end up aborting the connection and ERR_OK otherwise.
dcoban 0:1a61c61d0845 543 */
dcoban 0:1a61c61d0845 544 err_t CHTTPContext::HTTPSent(void* pvArg, tcp_pcb* pPCB, u16_t AcknowledgeCount)
dcoban 0:1a61c61d0845 545 {
dcoban 0:1a61c61d0845 546 CHTTPContext* pHTTPContext = (CHTTPContext*)pvArg;
dcoban 0:1a61c61d0845 547
dcoban 0:1a61c61d0845 548 // Validate parameters.
dcoban 0:1a61c61d0845 549 assert ( pvArg );
dcoban 0:1a61c61d0845 550 assert ( pPCB );
dcoban 0:1a61c61d0845 551 assert ( AcknowledgeCount );
dcoban 0:1a61c61d0845 552
dcoban 0:1a61c61d0845 553 // Loop through all of the buffers in the sent state to update their
dcoban 0:1a61c61d0845 554 // unacknowledged count since this acknowledgment can span buffers.
dcoban 0:1a61c61d0845 555 while (AcknowledgeCount > 0)
dcoban 0:1a61c61d0845 556 {
dcoban 0:1a61c61d0845 557 SBuffer* pSentBuffer = pHTTPContext->m_BufferQueue[pHTTPContext->m_BufferQueueTail];
dcoban 0:1a61c61d0845 558
dcoban 0:1a61c61d0845 559 // We should have a buffer in the sent state if we are getting back
dcoban 0:1a61c61d0845 560 // acknowledgments from the remote machine.
dcoban 0:1a61c61d0845 561 assert ( pSentBuffer );
dcoban 0:1a61c61d0845 562
dcoban 0:1a61c61d0845 563 // Update outstanding byte count for this buffer.
dcoban 0:1a61c61d0845 564 if (AcknowledgeCount >= pSentBuffer->UnacknowledgedBytes)
dcoban 0:1a61c61d0845 565 {
dcoban 0:1a61c61d0845 566 // This callback acknowledges all of the data in the buffer at the
dcoban 0:1a61c61d0845 567 // tail of the queue and possibly spans into the next buffer as
dcoban 0:1a61c61d0845 568 // well. It is also possible that there is still more data to be
dcoban 0:1a61c61d0845 569 // written from this buffer.
dcoban 0:1a61c61d0845 570 AcknowledgeCount -= pSentBuffer->UnacknowledgedBytes;
dcoban 0:1a61c61d0845 571 pSentBuffer->UnacknowledgedBytes = 0;
dcoban 0:1a61c61d0845 572
dcoban 0:1a61c61d0845 573 if (0 == pSentBuffer->BytesToWrite)
dcoban 0:1a61c61d0845 574 {
dcoban 0:1a61c61d0845 575 // Free the buffer which might cause another client context to be
dcoban 0:1a61c61d0845 576 // invoked if it was waiting for a buffer.
dcoban 0:1a61c61d0845 577 pHTTPContext->m_BufferQueue[pHTTPContext->m_BufferQueueTail] = NULL;
dcoban 0:1a61c61d0845 578 pHTTPContext->m_BufferQueueTail = (pHTTPContext->m_BufferQueueTail + 1) & 1;
dcoban 0:1a61c61d0845 579 pHTTPContext->m_pHTTPServer->FreeBuffer(pSentBuffer);
dcoban 0:1a61c61d0845 580
dcoban 0:1a61c61d0845 581 // Check to see if this context is in the closing state and all sent
dcoban 0:1a61c61d0845 582 // buffers are now free.
dcoban 0:1a61c61d0845 583 if (pHTTPContext->m_ClosingConnection &&
dcoban 0:1a61c61d0845 584 !pHTTPContext->m_BufferQueue[pHTTPContext->m_BufferQueueTail])
dcoban 0:1a61c61d0845 585 {
dcoban 0:1a61c61d0845 586 // Free the context and return immediately since the context is
dcoban 0:1a61c61d0845 587 // no longer valid.
dcoban 0:1a61c61d0845 588 assert ( !pHTTPContext->m_BufferQueue[0] );
dcoban 0:1a61c61d0845 589 assert ( !pHTTPContext->m_BufferQueue[1] );
dcoban 0:1a61c61d0845 590 assert ( !pHTTPContext->m_WaitingForBuffer );
dcoban 0:1a61c61d0845 591
dcoban 0:1a61c61d0845 592 pHTTPContext->FreeContext(FALSE);
dcoban 0:1a61c61d0845 593 return ERR_OK;
dcoban 0:1a61c61d0845 594 }
dcoban 0:1a61c61d0845 595 }
dcoban 0:1a61c61d0845 596 else
dcoban 0:1a61c61d0845 597 {
dcoban 0:1a61c61d0845 598 // We still have data to write from this buffer so there should
dcoban 0:1a61c61d0845 599 // no more bytes to acknowledge in another buffer.
dcoban 0:1a61c61d0845 600 assert ( 0 == AcknowledgeCount );
dcoban 0:1a61c61d0845 601 }
dcoban 0:1a61c61d0845 602 }
dcoban 0:1a61c61d0845 603 else
dcoban 0:1a61c61d0845 604 {
dcoban 0:1a61c61d0845 605 // This callback is just acknowledging a portion of the data in
dcoban 0:1a61c61d0845 606 // this buffer.
dcoban 0:1a61c61d0845 607 pSentBuffer->UnacknowledgedBytes -= AcknowledgeCount;
dcoban 0:1a61c61d0845 608 AcknowledgeCount = 0;
dcoban 0:1a61c61d0845 609 }
dcoban 0:1a61c61d0845 610 }
dcoban 0:1a61c61d0845 611
dcoban 0:1a61c61d0845 612 // Attempt to send more response data to this client.
dcoban 0:1a61c61d0845 613 pHTTPContext->SendResponse();
dcoban 0:1a61c61d0845 614
dcoban 0:1a61c61d0845 615 return ERR_OK;
dcoban 0:1a61c61d0845 616 }
dcoban 0:1a61c61d0845 617
dcoban 0:1a61c61d0845 618
dcoban 0:1a61c61d0845 619 /* Called by lwIP every 2 seconds (4 iterations of the tcp_slowtmr) as
dcoban 0:1a61c61d0845 620 specified in the tcp_poll() call in HTTPInit(). Can be used to retry
dcoban 0:1a61c61d0845 621 sending of response data or closing of the PCB.
dcoban 0:1a61c61d0845 622
dcoban 0:1a61c61d0845 623 Parameters:
dcoban 0:1a61c61d0845 624 pvArg is the value set on the active PCB through the call to tcp_arg in
dcoban 0:1a61c61d0845 625 HTTPAccept() which is a pointer to the HTTP context for this
dcoban 0:1a61c61d0845 626 connection. It will be NULL if we have previously failed to close
dcoban 0:1a61c61d0845 627 the PCB.
dcoban 0:1a61c61d0845 628 pPCB is a pointer to the low level lwIP API socket object for this
dcoban 0:1a61c61d0845 629 connection.
dcoban 0:1a61c61d0845 630
dcoban 0:1a61c61d0845 631 Returns:
dcoban 0:1a61c61d0845 632 ERR_ABRT if we end up aborting the connection and ERR_OK otherwise.
dcoban 0:1a61c61d0845 633 */
dcoban 0:1a61c61d0845 634 err_t CHTTPContext::HTTPPoll(void* pvArg, tcp_pcb* pPCB)
dcoban 0:1a61c61d0845 635 {
dcoban 0:1a61c61d0845 636 CHTTPContext* pHTTPContext = (CHTTPContext*)pvArg;
dcoban 0:1a61c61d0845 637
dcoban 0:1a61c61d0845 638 // Validate parameters.
dcoban 0:1a61c61d0845 639 assert ( pPCB );
dcoban 0:1a61c61d0845 640
dcoban 0:1a61c61d0845 641 // Check to see if we need to retry closing the PCB.
dcoban 0:1a61c61d0845 642 if (!pHTTPContext)
dcoban 0:1a61c61d0845 643 {
dcoban 0:1a61c61d0845 644 err_t CloseResult;
dcoban 0:1a61c61d0845 645
dcoban 0:1a61c61d0845 646 TRACE("HTTP: Retrying close for connection to: ");
dcoban 0:1a61c61d0845 647 NetworkPrintRemoteAddress(pPCB);
dcoban 0:1a61c61d0845 648 TRACE("\r\n");
dcoban 0:1a61c61d0845 649
dcoban 0:1a61c61d0845 650 CloseResult = tcp_close(pPCB);
dcoban 0:1a61c61d0845 651 if (ERR_OK != CloseResult)
dcoban 0:1a61c61d0845 652 {
dcoban 0:1a61c61d0845 653 // This is the second failed attempt to close the PCB, force an
dcoban 0:1a61c61d0845 654 // abort.
dcoban 0:1a61c61d0845 655 tcp_abort(pPCB);
dcoban 0:1a61c61d0845 656 return ERR_ABRT;
dcoban 0:1a61c61d0845 657 }
dcoban 0:1a61c61d0845 658 else
dcoban 0:1a61c61d0845 659 {
dcoban 0:1a61c61d0845 660 return ERR_OK;
dcoban 0:1a61c61d0845 661 }
dcoban 0:1a61c61d0845 662 }
dcoban 0:1a61c61d0845 663
dcoban 0:1a61c61d0845 664 // Close the connection if the client hasn't sent its request within the polling interval.
dcoban 0:1a61c61d0845 665 if (STATE_DONE != pHTTPContext->m_ParseState)
dcoban 0:1a61c61d0845 666 {
dcoban 0:1a61c61d0845 667 TRACE("HTTP: Closing connection due to no HTTP request from connection to: ");
dcoban 0:1a61c61d0845 668 NetworkPrintRemoteAddress(pPCB);
dcoban 0:1a61c61d0845 669 TRACE("\r\n");
dcoban 0:1a61c61d0845 670
dcoban 0:1a61c61d0845 671 pHTTPContext->CloseConnection();
dcoban 0:1a61c61d0845 672 pHTTPContext->FreeContext(TRUE);
dcoban 0:1a61c61d0845 673
dcoban 0:1a61c61d0845 674 return ERR_OK;
dcoban 0:1a61c61d0845 675 }
dcoban 0:1a61c61d0845 676
dcoban 0:1a61c61d0845 677 // If we have unacknowledged bytes outstanding then we will still
dcoban 0:1a61c61d0845 678 // receive a HTTPSent() callback from lwIP so no need to retry data sends
dcoban 0:1a61c61d0845 679 // from here.
dcoban 0:1a61c61d0845 680 // NOTE: This version will wait forever for a request from the client.
dcoban 0:1a61c61d0845 681 if (!pHTTPContext->m_BufferQueue[pHTTPContext->m_BufferQueueTail] &&
dcoban 0:1a61c61d0845 682 pHTTPContext->m_BufferQueue[pHTTPContext->m_BufferQueueHead])
dcoban 0:1a61c61d0845 683 {
dcoban 0:1a61c61d0845 684 if (pHTTPContext->m_RetryCount++ > 8)
dcoban 0:1a61c61d0845 685 {
dcoban 0:1a61c61d0845 686 // We have already retried sending the data 8 times, so close
dcoban 0:1a61c61d0845 687 // the connection.
dcoban 0:1a61c61d0845 688 TRACE("HTTP: Failed multiple retries to send data for connection to: ");
dcoban 0:1a61c61d0845 689 NetworkPrintRemoteAddress(pPCB);
dcoban 0:1a61c61d0845 690 TRACE("\r\n");
dcoban 0:1a61c61d0845 691
dcoban 0:1a61c61d0845 692 pHTTPContext->CloseConnection();
dcoban 0:1a61c61d0845 693 }
dcoban 0:1a61c61d0845 694 else
dcoban 0:1a61c61d0845 695 {
dcoban 0:1a61c61d0845 696 // Retry sending the response data again.
dcoban 0:1a61c61d0845 697 TRACE("HTTP: Retrying to send data for connection to: ");
dcoban 0:1a61c61d0845 698 NetworkPrintRemoteAddress(pPCB);
dcoban 0:1a61c61d0845 699 TRACE("\r\n");
dcoban 0:1a61c61d0845 700
dcoban 0:1a61c61d0845 701 pHTTPContext->SendResponse();
dcoban 0:1a61c61d0845 702 }
dcoban 0:1a61c61d0845 703 }
dcoban 0:1a61c61d0845 704
dcoban 0:1a61c61d0845 705 return ERR_OK;
dcoban 0:1a61c61d0845 706 }
dcoban 0:1a61c61d0845 707
dcoban 0:1a61c61d0845 708
dcoban 0:1a61c61d0845 709 /* Called by lwIP whenever the PCB is closed or reset by the remote client.
dcoban 0:1a61c61d0845 710 Gives the application the opportunity to free up the context object.
dcoban 0:1a61c61d0845 711
dcoban 0:1a61c61d0845 712 Parameters:
dcoban 0:1a61c61d0845 713 pvArg is the value set on the active PCB through the call to tcp_arg in
dcoban 0:1a61c61d0845 714 HTTPAccept() which is a pointer to the HTTP context for this
dcoban 0:1a61c61d0845 715 connection.
dcoban 0:1a61c61d0845 716 Error is the error that caused the connection to be shutdown. It can be
dcoban 0:1a61c61d0845 717 set to ERR_ABRT or ERR_RST.
dcoban 0:1a61c61d0845 718
dcoban 0:1a61c61d0845 719 Returns:
dcoban 0:1a61c61d0845 720 Nothing.
dcoban 0:1a61c61d0845 721 */
dcoban 0:1a61c61d0845 722 void CHTTPContext::HTTPError(void* pvArg, err_t Error)
dcoban 0:1a61c61d0845 723 {
dcoban 0:1a61c61d0845 724 CHTTPContext* pHTTPContext = (CHTTPContext*)pvArg;
dcoban 0:1a61c61d0845 725
dcoban 0:1a61c61d0845 726 // Unused parameters.
dcoban 0:1a61c61d0845 727 (void)Error;
dcoban 0:1a61c61d0845 728
dcoban 0:1a61c61d0845 729 TRACE("HTTP: Forcing connection context to be freed.\r\n");
dcoban 0:1a61c61d0845 730
dcoban 0:1a61c61d0845 731 // Free the context if it is non-NULL.
dcoban 0:1a61c61d0845 732 if (pHTTPContext)
dcoban 0:1a61c61d0845 733 {
dcoban 0:1a61c61d0845 734 pHTTPContext->FreeContext(TRUE);
dcoban 0:1a61c61d0845 735 }
dcoban 0:1a61c61d0845 736 }
dcoban 0:1a61c61d0845 737
dcoban 0:1a61c61d0845 738
dcoban 0:1a61c61d0845 739 /* Attempts to close the PCB connection. The context is placed into a closing
dcoban 0:1a61c61d0845 740 state where it waits for the data written to be acknowledged by the remote
dcoban 0:1a61c61d0845 741 machine before freeing up its memory.
dcoban 0:1a61c61d0845 742
dcoban 0:1a61c61d0845 743 Parameters:
dcoban 0:1a61c61d0845 744 None.
dcoban 0:1a61c61d0845 745 Returns:
dcoban 0:1a61c61d0845 746 Nothing.
dcoban 0:1a61c61d0845 747 */
dcoban 0:1a61c61d0845 748 void CHTTPContext::CloseConnection()
dcoban 0:1a61c61d0845 749 {
dcoban 0:1a61c61d0845 750 err_t CloseResult = ERR_MEM;
dcoban 0:1a61c61d0845 751
dcoban 0:1a61c61d0845 752 // Validate parameters.
dcoban 0:1a61c61d0845 753 assert ( m_pPCB );
dcoban 0:1a61c61d0845 754
dcoban 0:1a61c61d0845 755 TRACE("HTTP: Closing connection to: ");
dcoban 0:1a61c61d0845 756 NetworkPrintRemoteAddress(m_pPCB);
dcoban 0:1a61c61d0845 757 TRACE("\r\n");
dcoban 0:1a61c61d0845 758
dcoban 0:1a61c61d0845 759 // Flag the context as being in the closing state.
dcoban 0:1a61c61d0845 760 m_ClosingConnection = 1;
dcoban 0:1a61c61d0845 761
dcoban 0:1a61c61d0845 762 // Have no more data to send so no need for poll callback unless the
dcoban 0:1a61c61d0845 763 // tcp_close() below should fail and require retrying.
dcoban 0:1a61c61d0845 764 tcp_poll(m_pPCB, NULL, 0);
dcoban 0:1a61c61d0845 765
dcoban 0:1a61c61d0845 766 // Atempt to close the connection.
dcoban 0:1a61c61d0845 767 CloseResult = tcp_close(m_pPCB);
dcoban 0:1a61c61d0845 768 if (ERR_OK != CloseResult)
dcoban 0:1a61c61d0845 769 {
dcoban 0:1a61c61d0845 770 // Close wasn't successful so re-enable the HTTPPoll() callback.
dcoban 0:1a61c61d0845 771 tcp_poll(m_pPCB, HTTPPoll, 4);
dcoban 0:1a61c61d0845 772 }
dcoban 0:1a61c61d0845 773 }
dcoban 0:1a61c61d0845 774
dcoban 0:1a61c61d0845 775
dcoban 0:1a61c61d0845 776 /* Frees up the resources used by the context.
dcoban 0:1a61c61d0845 777
dcoban 0:1a61c61d0845 778 Parameters:
dcoban 0:1a61c61d0845 779 ForcedFree indicates whether a shutdown is being forced and therefore it is
dcoban 0:1a61c61d0845 780 OK to free the buffers even though they might indicate they still have
dcoban 0:1a61c61d0845 781 outstanding data.
dcoban 0:1a61c61d0845 782
dcoban 0:1a61c61d0845 783 Returns:
dcoban 0:1a61c61d0845 784 Nothing.
dcoban 0:1a61c61d0845 785 */
dcoban 0:1a61c61d0845 786 void CHTTPContext::FreeContext(int ForcedFree)
dcoban 0:1a61c61d0845 787 {
dcoban 0:1a61c61d0845 788 size_t i;
dcoban 0:1a61c61d0845 789
dcoban 0:1a61c61d0845 790 if (m_pPCB)
dcoban 0:1a61c61d0845 791 {
dcoban 0:1a61c61d0845 792 TRACE("HTTP: Freeing context for connection to: ");
dcoban 0:1a61c61d0845 793 NetworkPrintRemoteAddress(m_pPCB);
dcoban 0:1a61c61d0845 794 TRACE("\r\n");
dcoban 0:1a61c61d0845 795 }
dcoban 0:1a61c61d0845 796 else
dcoban 0:1a61c61d0845 797 {
dcoban 0:1a61c61d0845 798 TRACE("HTTP: Freeing connection due to unexpected close.\r\n");
dcoban 0:1a61c61d0845 799 }
dcoban 0:1a61c61d0845 800
dcoban 0:1a61c61d0845 801 // Free the HTTP context record and any resources it owned.
dcoban 0:1a61c61d0845 802 if (m_WaitingForBuffer)
dcoban 0:1a61c61d0845 803 {
dcoban 0:1a61c61d0845 804 m_pHTTPServer->RemoveWaitingContext(this);
dcoban 0:1a61c61d0845 805 }
dcoban 0:1a61c61d0845 806 for (i = 0 ; i < ARRAYSIZE(m_BufferQueue) ; i++)
dcoban 0:1a61c61d0845 807 {
dcoban 0:1a61c61d0845 808 SBuffer* pBuffer = m_BufferQueue[i];
dcoban 0:1a61c61d0845 809 if (pBuffer)
dcoban 0:1a61c61d0845 810 {
dcoban 0:1a61c61d0845 811 if (ForcedFree)
dcoban 0:1a61c61d0845 812 {
dcoban 0:1a61c61d0845 813 // 0 out the counts if we are forcing a free.
dcoban 0:1a61c61d0845 814 pBuffer->BytesToWrite = 0;
dcoban 0:1a61c61d0845 815 pBuffer->UnacknowledgedBytes = 0;
dcoban 0:1a61c61d0845 816 }
dcoban 0:1a61c61d0845 817
dcoban 0:1a61c61d0845 818 // Free the buffer.
dcoban 0:1a61c61d0845 819 m_pHTTPServer->FreeBuffer(m_BufferQueue[i]);
dcoban 0:1a61c61d0845 820 m_BufferQueue[i] = NULL;
dcoban 0:1a61c61d0845 821 }
dcoban 0:1a61c61d0845 822 }
dcoban 0:1a61c61d0845 823 if (m_pRequestHandlerContext)
dcoban 0:1a61c61d0845 824 {
dcoban 0:1a61c61d0845 825 m_pRequestHandlerContext->Release();
dcoban 0:1a61c61d0845 826 m_pRequestHandlerContext = NULL;
dcoban 0:1a61c61d0845 827 }
dcoban 0:1a61c61d0845 828
dcoban 0:1a61c61d0845 829 // Clear the callbacks for the PCB as we are getting ready to close it.
dcoban 0:1a61c61d0845 830 if (m_pPCB)
dcoban 0:1a61c61d0845 831 {
dcoban 0:1a61c61d0845 832 // Keep the polling callback enabled incase the previous tcp_close()
dcoban 0:1a61c61d0845 833 // attempt failed.
dcoban 0:1a61c61d0845 834 tcp_arg(m_pPCB, NULL);
dcoban 0:1a61c61d0845 835 tcp_accept(m_pPCB, NULL);
dcoban 0:1a61c61d0845 836 tcp_recv(m_pPCB, NULL);
dcoban 0:1a61c61d0845 837 tcp_sent(m_pPCB, NULL);
dcoban 0:1a61c61d0845 838 tcp_err(m_pPCB, NULL);
dcoban 0:1a61c61d0845 839 m_pPCB = NULL;
dcoban 0:1a61c61d0845 840 }
dcoban 0:1a61c61d0845 841
dcoban 0:1a61c61d0845 842 delete this;
dcoban 0:1a61c61d0845 843 }
dcoban 0:1a61c61d0845 844
dcoban 0:1a61c61d0845 845
dcoban 0:1a61c61d0845 846 /* Processes the HTTP request data as it comes in from the client.
dcoban 0:1a61c61d0845 847
dcoban 0:1a61c61d0845 848 Parameters:
dcoban 0:1a61c61d0845 849 pBuf points to the buffer of inbound TCP/IP data from the connection.
dcoban 0:1a61c61d0845 850
dcoban 0:1a61c61d0845 851 Returns:
dcoban 0:1a61c61d0845 852 Nothing.
dcoban 0:1a61c61d0845 853 */
dcoban 0:1a61c61d0845 854 void CHTTPContext::ProcessRequestData(pbuf* pBuf)
dcoban 0:1a61c61d0845 855 {
dcoban 0:1a61c61d0845 856 // Validate parameters.
dcoban 0:1a61c61d0845 857 assert ( pBuf );
dcoban 0:1a61c61d0845 858
dcoban 0:1a61c61d0845 859 switch (m_ParseState)
dcoban 0:1a61c61d0845 860 {
dcoban 0:1a61c61d0845 861 case STATE_FIRST_LINE:
dcoban 0:1a61c61d0845 862 case STATE_HEADERS:
dcoban 0:1a61c61d0845 863 BufferRequestLines(pBuf);
dcoban 0:1a61c61d0845 864 break;
dcoban 0:1a61c61d0845 865 case STATE_CONTENT:
dcoban 0:1a61c61d0845 866 ProcessRequestContent(pBuf);
dcoban 0:1a61c61d0845 867 break;
dcoban 0:1a61c61d0845 868 case STATE_DONE:
dcoban 0:1a61c61d0845 869 // We should have received everything already so discard data and
dcoban 0:1a61c61d0845 870 // return.
dcoban 0:1a61c61d0845 871 return;
dcoban 0:1a61c61d0845 872 }
dcoban 0:1a61c61d0845 873
dcoban 0:1a61c61d0845 874 if (STATE_DONE == m_ParseState)
dcoban 0:1a61c61d0845 875 {
dcoban 0:1a61c61d0845 876 // Let the application interface know that we are done sending it
dcoban 0:1a61c61d0845 877 // the request content.
dcoban 0:1a61c61d0845 878 if (m_SendRequestContentToHandler)
dcoban 0:1a61c61d0845 879 {
dcoban 0:1a61c61d0845 880 m_pRequestHandlerContext->EndRequestContent();
dcoban 0:1a61c61d0845 881 }
dcoban 0:1a61c61d0845 882
dcoban 0:1a61c61d0845 883 // And prepare response headers and content to send back to client.
dcoban 0:1a61c61d0845 884 PrepareResponse();
dcoban 0:1a61c61d0845 885
dcoban 0:1a61c61d0845 886 // Attempt to allocate a buffer and fill it in with header and data
dcoban 0:1a61c61d0845 887 // content.
dcoban 0:1a61c61d0845 888 ReadContent();
dcoban 0:1a61c61d0845 889
dcoban 0:1a61c61d0845 890 // Attempt to send first segments of response data.
dcoban 0:1a61c61d0845 891 SendResponse();
dcoban 0:1a61c61d0845 892 }
dcoban 0:1a61c61d0845 893 }
dcoban 0:1a61c61d0845 894
dcoban 0:1a61c61d0845 895
dcoban 0:1a61c61d0845 896 /* Buffers up the HTTP requests a line at a time and then processes it once
dcoban 0:1a61c61d0845 897 a complete line has been buffered.
dcoban 0:1a61c61d0845 898
dcoban 0:1a61c61d0845 899 Parameters:
dcoban 0:1a61c61d0845 900 pBuf points to the buffer of inbound TCP/IP data from the connection.
dcoban 0:1a61c61d0845 901
dcoban 0:1a61c61d0845 902 Returns:
dcoban 0:1a61c61d0845 903 Nothing.
dcoban 0:1a61c61d0845 904 */
dcoban 0:1a61c61d0845 905 void CHTTPContext::BufferRequestLines(pbuf* pBuf)
dcoban 0:1a61c61d0845 906 {
dcoban 0:1a61c61d0845 907 // Validate parameters.
dcoban 0:1a61c61d0845 908 assert ( pBuf );
dcoban 0:1a61c61d0845 909
dcoban 0:1a61c61d0845 910 // Loop through all chunks in the pbuf list and parse its content a line
dcoban 0:1a61c61d0845 911 // at a time.
dcoban 0:1a61c61d0845 912 while (pBuf)
dcoban 0:1a61c61d0845 913 {
dcoban 0:1a61c61d0845 914 char* pCurr = (char*)pBuf->payload;
dcoban 0:1a61c61d0845 915 u16_t BytesLeft = pBuf->len;
dcoban 0:1a61c61d0845 916
dcoban 0:1a61c61d0845 917 // Loop through the characters in this chunk.
dcoban 0:1a61c61d0845 918 while (BytesLeft)
dcoban 0:1a61c61d0845 919 {
dcoban 0:1a61c61d0845 920 char CurrChar = *pCurr;
dcoban 0:1a61c61d0845 921
dcoban 0:1a61c61d0845 922 if ('\n' == CurrChar)
dcoban 0:1a61c61d0845 923 {
dcoban 0:1a61c61d0845 924 // Have encountered end of line.
dcoban 0:1a61c61d0845 925 m_LineBuffer[m_LineBufferOffset] = '\0';
dcoban 0:1a61c61d0845 926
dcoban 0:1a61c61d0845 927 ParseRequestLine();
dcoban 0:1a61c61d0845 928
dcoban 0:1a61c61d0845 929 // Reset pointer to start buffering next line.
dcoban 0:1a61c61d0845 930 m_LineBufferOffset = 0;
dcoban 0:1a61c61d0845 931 }
dcoban 0:1a61c61d0845 932 else if ('\r' != CurrChar &&
dcoban 0:1a61c61d0845 933 m_LineBufferOffset < ARRAYSIZE(m_LineBuffer)-1)
dcoban 0:1a61c61d0845 934 {
dcoban 0:1a61c61d0845 935 // Copy character into line buffer. Above conditional protects
dcoban 0:1a61c61d0845 936 // from buffer overflow on the write and leaves room for NULL
dcoban 0:1a61c61d0845 937 // terminator.
dcoban 0:1a61c61d0845 938 m_LineBuffer[m_LineBufferOffset++] = CurrChar;
dcoban 0:1a61c61d0845 939 }
dcoban 0:1a61c61d0845 940
dcoban 0:1a61c61d0845 941 // Advance to the next character in this chunk.
dcoban 0:1a61c61d0845 942 pCurr++;
dcoban 0:1a61c61d0845 943 BytesLeft--;
dcoban 0:1a61c61d0845 944 }
dcoban 0:1a61c61d0845 945
dcoban 0:1a61c61d0845 946 // Advance to the next chunk in the pbuf list.
dcoban 0:1a61c61d0845 947 pBuf = pBuf->next;
dcoban 0:1a61c61d0845 948 }
dcoban 0:1a61c61d0845 949 }
dcoban 0:1a61c61d0845 950
dcoban 0:1a61c61d0845 951
dcoban 0:1a61c61d0845 952 /* Processes the HTTP request content data as it comes in from the client.
dcoban 0:1a61c61d0845 953
dcoban 0:1a61c61d0845 954 Parameters:
dcoban 0:1a61c61d0845 955 pBuf points to the buffer of inbound TCP/IP data from the connection.
dcoban 0:1a61c61d0845 956
dcoban 0:1a61c61d0845 957 Returns:
dcoban 0:1a61c61d0845 958 Nothing.
dcoban 0:1a61c61d0845 959 */
dcoban 0:1a61c61d0845 960 void CHTTPContext::ProcessRequestContent(pbuf* pBuf)
dcoban 0:1a61c61d0845 961 {
dcoban 0:1a61c61d0845 962 // Validate parameters.
dcoban 0:1a61c61d0845 963 assert ( pBuf );
dcoban 0:1a61c61d0845 964
dcoban 0:1a61c61d0845 965 while (pBuf && m_RequestContentLength > 0);
dcoban 0:1a61c61d0845 966 {
dcoban 0:1a61c61d0845 967 size_t BytesToWrite = pBuf->len;
dcoban 0:1a61c61d0845 968 if (BytesToWrite > m_RequestContentLength)
dcoban 0:1a61c61d0845 969 {
dcoban 0:1a61c61d0845 970 // Make sure that we don't send the application interface more
dcoban 0:1a61c61d0845 971 // content than we told it we would send.
dcoban 0:1a61c61d0845 972 BytesToWrite = m_RequestContentLength;
dcoban 0:1a61c61d0845 973 }
dcoban 0:1a61c61d0845 974 if (m_SendRequestContentToHandler)
dcoban 0:1a61c61d0845 975 {
dcoban 0:1a61c61d0845 976 // Only send the application interface the request content if
dcoban 0:1a61c61d0845 977 // it has indicated that it wants to receive the data.
dcoban 0:1a61c61d0845 978 m_pRequestHandlerContext->WriteRequestContentBlock(pBuf->payload, BytesToWrite);
dcoban 0:1a61c61d0845 979 }
dcoban 0:1a61c61d0845 980 m_RequestContentLength -= BytesToWrite;
dcoban 0:1a61c61d0845 981
dcoban 0:1a61c61d0845 982 // Advance to next chunk in the pbuf list.
dcoban 0:1a61c61d0845 983 pBuf = pBuf->next;
dcoban 0:1a61c61d0845 984 }
dcoban 0:1a61c61d0845 985
dcoban 0:1a61c61d0845 986 if (0 == m_RequestContentLength)
dcoban 0:1a61c61d0845 987 {
dcoban 0:1a61c61d0845 988 // Have finished receiving the request content so advance to the next
dcoban 0:1a61c61d0845 989 // state where response data is sent to the client.
dcoban 0:1a61c61d0845 990 m_ParseState = STATE_DONE;
dcoban 0:1a61c61d0845 991 }
dcoban 0:1a61c61d0845 992 }
dcoban 0:1a61c61d0845 993
dcoban 0:1a61c61d0845 994
dcoban 0:1a61c61d0845 995 /* Attempts to parse the current line in m_LineBuffer.
dcoban 0:1a61c61d0845 996
dcoban 0:1a61c61d0845 997 Parameters:
dcoban 0:1a61c61d0845 998 None.
dcoban 0:1a61c61d0845 999
dcoban 0:1a61c61d0845 1000 Returns:
dcoban 0:1a61c61d0845 1001 Nothing.
dcoban 0:1a61c61d0845 1002 */
dcoban 0:1a61c61d0845 1003 void CHTTPContext::ParseRequestLine()
dcoban 0:1a61c61d0845 1004 {
dcoban 0:1a61c61d0845 1005 switch(m_ParseState)
dcoban 0:1a61c61d0845 1006 {
dcoban 0:1a61c61d0845 1007 case STATE_FIRST_LINE:
dcoban 0:1a61c61d0845 1008 ParseFirstRequestLine();
dcoban 0:1a61c61d0845 1009 break;
dcoban 0:1a61c61d0845 1010 case STATE_HEADERS:
dcoban 0:1a61c61d0845 1011 ParseHeaderRequestLine();
dcoban 0:1a61c61d0845 1012 break;
dcoban 0:1a61c61d0845 1013 default:
dcoban 0:1a61c61d0845 1014 assert ( FALSE );
dcoban 0:1a61c61d0845 1015 break;
dcoban 0:1a61c61d0845 1016 }
dcoban 0:1a61c61d0845 1017 }
dcoban 0:1a61c61d0845 1018
dcoban 0:1a61c61d0845 1019
dcoban 0:1a61c61d0845 1020 /* Attempts to parse the first request line found in m_LineBuffer which should
dcoban 0:1a61c61d0845 1021 contain the request method, URI, etc.
dcoban 0:1a61c61d0845 1022
dcoban 0:1a61c61d0845 1023 Parameters:
dcoban 0:1a61c61d0845 1024 None.
dcoban 0:1a61c61d0845 1025
dcoban 0:1a61c61d0845 1026 Returns:
dcoban 0:1a61c61d0845 1027 Nothing.
dcoban 0:1a61c61d0845 1028 */
dcoban 0:1a61c61d0845 1029 void CHTTPContext::ParseFirstRequestLine()
dcoban 0:1a61c61d0845 1030 {
dcoban 0:1a61c61d0845 1031 static const char GetMethod[] = "GET ";
dcoban 0:1a61c61d0845 1032 static const char HeadMethod[] = "HEAD ";
dcoban 0:1a61c61d0845 1033 static const char PostMethod[] = "POST ";
dcoban 0:1a61c61d0845 1034 const char* pURIStart = NULL;
dcoban 0:1a61c61d0845 1035 const char* pURISrc = NULL;
dcoban 0:1a61c61d0845 1036 char* pURIDest = NULL;
dcoban 0:1a61c61d0845 1037 char UnescapedChar = 0;
dcoban 0:1a61c61d0845 1038 int CharsToEscape = 0;
dcoban 0:1a61c61d0845 1039
dcoban 0:1a61c61d0845 1040 // Advance to next state.
dcoban 0:1a61c61d0845 1041 m_ParseState = STATE_HEADERS;
dcoban 0:1a61c61d0845 1042
dcoban 0:1a61c61d0845 1043 // This is the first line which indicates method being requested
dcoban 0:1a61c61d0845 1044 // (ie. GET, HEAD, POST).
dcoban 0:1a61c61d0845 1045 if (0 == strncmp(m_LineBuffer, GetMethod, sizeof(GetMethod)-1))
dcoban 0:1a61c61d0845 1046 {
dcoban 0:1a61c61d0845 1047 // Assume a HTTP/1.0 GET request for now. Will know later if we
dcoban 0:1a61c61d0845 1048 // need to downgrade it to a 0.9 request when version isn't sent.
dcoban 0:1a61c61d0845 1049 m_RequestType = TYPE_GET_1_0;
dcoban 0:1a61c61d0845 1050 pURISrc = &m_LineBuffer[sizeof(GetMethod)-1];
dcoban 0:1a61c61d0845 1051 }
dcoban 0:1a61c61d0845 1052 else if (0 == strncmp(m_LineBuffer, HeadMethod, sizeof(HeadMethod)-1))
dcoban 0:1a61c61d0845 1053 {
dcoban 0:1a61c61d0845 1054 m_RequestType = TYPE_HEAD;
dcoban 0:1a61c61d0845 1055 pURISrc = &m_LineBuffer[sizeof(HeadMethod)-1];
dcoban 0:1a61c61d0845 1056 }
dcoban 0:1a61c61d0845 1057 else if (0 == strncmp(m_LineBuffer, PostMethod, sizeof(PostMethod)-1))
dcoban 0:1a61c61d0845 1058 {
dcoban 0:1a61c61d0845 1059 m_RequestType = TYPE_POST;
dcoban 0:1a61c61d0845 1060 pURISrc = &m_LineBuffer[sizeof(PostMethod)-1];
dcoban 0:1a61c61d0845 1061 }
dcoban 0:1a61c61d0845 1062 else
dcoban 0:1a61c61d0845 1063 {
dcoban 0:1a61c61d0845 1064 // Don't recognize this method so mark it as bad.
dcoban 0:1a61c61d0845 1065 m_RequestType = TYPE_BAD_REQUEST;
dcoban 0:1a61c61d0845 1066
dcoban 0:1a61c61d0845 1067 // See if the application recognizes and wants to handle it by sending
dcoban 0:1a61c61d0845 1068 // it the full request line.
dcoban 0:1a61c61d0845 1069 StartBadRequest(m_LineBuffer);
dcoban 0:1a61c61d0845 1070 return;
dcoban 0:1a61c61d0845 1071 }
dcoban 0:1a61c61d0845 1072
dcoban 0:1a61c61d0845 1073 // Skip additional whitespace that might precede URI even though there
dcoban 0:1a61c61d0845 1074 // shouldn't be any just to be lenient.
dcoban 0:1a61c61d0845 1075 while (' ' == *pURISrc)
dcoban 0:1a61c61d0845 1076 {
dcoban 0:1a61c61d0845 1077 pURISrc++;
dcoban 0:1a61c61d0845 1078 }
dcoban 0:1a61c61d0845 1079 pURIStart = pURISrc;
dcoban 0:1a61c61d0845 1080 pURIDest = (char*)(void*)pURISrc;
dcoban 0:1a61c61d0845 1081
dcoban 0:1a61c61d0845 1082 // Save away the URI character by character until whitespace or end
dcoban 0:1a61c61d0845 1083 // of line is encountered.
dcoban 0:1a61c61d0845 1084 while(' ' != *pURISrc &&
dcoban 0:1a61c61d0845 1085 '\0' != *pURISrc)
dcoban 0:1a61c61d0845 1086 {
dcoban 0:1a61c61d0845 1087 char CurrChar = *pURISrc;
dcoban 0:1a61c61d0845 1088
dcoban 0:1a61c61d0845 1089 // Unescape % HEX HEX portions of the URI
dcoban 0:1a61c61d0845 1090 if ('%' == CurrChar)
dcoban 0:1a61c61d0845 1091 {
dcoban 0:1a61c61d0845 1092 CharsToEscape = 2;
dcoban 0:1a61c61d0845 1093 UnescapedChar = 0;
dcoban 0:1a61c61d0845 1094 }
dcoban 0:1a61c61d0845 1095 else if (CharsToEscape)
dcoban 0:1a61c61d0845 1096 {
dcoban 0:1a61c61d0845 1097 UnescapedChar <<= 4;
dcoban 0:1a61c61d0845 1098
dcoban 0:1a61c61d0845 1099 if (CurrChar >= 'a' && CurrChar <= 'f')
dcoban 0:1a61c61d0845 1100 {
dcoban 0:1a61c61d0845 1101 CurrChar = (CurrChar - 'a') + 10;
dcoban 0:1a61c61d0845 1102 }
dcoban 0:1a61c61d0845 1103 else if (CurrChar >= 'A' && CurrChar <= 'F')
dcoban 0:1a61c61d0845 1104 {
dcoban 0:1a61c61d0845 1105 CurrChar = (CurrChar - 'A') + 10;
dcoban 0:1a61c61d0845 1106 }
dcoban 0:1a61c61d0845 1107 else if (CurrChar >= '0' && CurrChar <= '9')
dcoban 0:1a61c61d0845 1108 {
dcoban 0:1a61c61d0845 1109 CurrChar = CurrChar - '0';
dcoban 0:1a61c61d0845 1110 }
dcoban 0:1a61c61d0845 1111 else
dcoban 0:1a61c61d0845 1112 {
dcoban 0:1a61c61d0845 1113 // Not a hex digit.
dcoban 0:1a61c61d0845 1114 CurrChar = 0;
dcoban 0:1a61c61d0845 1115 }
dcoban 0:1a61c61d0845 1116
dcoban 0:1a61c61d0845 1117 UnescapedChar |= (CurrChar & 0xF);
dcoban 0:1a61c61d0845 1118
dcoban 0:1a61c61d0845 1119 if (0 == --CharsToEscape)
dcoban 0:1a61c61d0845 1120 {
dcoban 0:1a61c61d0845 1121 *pURIDest++ = UnescapedChar;
dcoban 0:1a61c61d0845 1122 }
dcoban 0:1a61c61d0845 1123 }
dcoban 0:1a61c61d0845 1124 else
dcoban 0:1a61c61d0845 1125 {
dcoban 0:1a61c61d0845 1126 *pURIDest++ = CurrChar;
dcoban 0:1a61c61d0845 1127 }
dcoban 0:1a61c61d0845 1128 pURISrc++;
dcoban 0:1a61c61d0845 1129 }
dcoban 0:1a61c61d0845 1130
dcoban 0:1a61c61d0845 1131 if (' ' != *pURISrc)
dcoban 0:1a61c61d0845 1132 {
dcoban 0:1a61c61d0845 1133 // Protocol string didn't follow URI so must be a HTTP/0.9 request.
dcoban 0:1a61c61d0845 1134 if (TYPE_GET_1_0 == m_RequestType)
dcoban 0:1a61c61d0845 1135 {
dcoban 0:1a61c61d0845 1136 m_RequestType = TYPE_GET_0_9;
dcoban 0:1a61c61d0845 1137 // This will have been the last request line for a v0.9 request so
dcoban 0:1a61c61d0845 1138 // advance to the finished state.
dcoban 0:1a61c61d0845 1139 m_ParseState = STATE_DONE;
dcoban 0:1a61c61d0845 1140 }
dcoban 0:1a61c61d0845 1141 else
dcoban 0:1a61c61d0845 1142 {
dcoban 0:1a61c61d0845 1143 m_RequestType = TYPE_BAD_REQUEST;
dcoban 0:1a61c61d0845 1144
dcoban 0:1a61c61d0845 1145 // See if the application recognizes and wants to handle it by sending
dcoban 0:1a61c61d0845 1146 // it the full request line.
dcoban 0:1a61c61d0845 1147 StartBadRequest(m_LineBuffer);
dcoban 0:1a61c61d0845 1148 return;
dcoban 0:1a61c61d0845 1149 }
dcoban 0:1a61c61d0845 1150 }
dcoban 0:1a61c61d0845 1151 *pURIDest = '\0';
dcoban 0:1a61c61d0845 1152
dcoban 0:1a61c61d0845 1153 StartRequestHandler(pURIStart);
dcoban 0:1a61c61d0845 1154 }
dcoban 0:1a61c61d0845 1155
dcoban 0:1a61c61d0845 1156
dcoban 0:1a61c61d0845 1157 /* Attempts to parse the header request lines until a blank request line is
dcoban 0:1a61c61d0845 1158 encountered which indicates that start of the content.
dcoban 0:1a61c61d0845 1159
dcoban 0:1a61c61d0845 1160 Parameters:
dcoban 0:1a61c61d0845 1161 None.
dcoban 0:1a61c61d0845 1162
dcoban 0:1a61c61d0845 1163 Returns:
dcoban 0:1a61c61d0845 1164 Nothing.
dcoban 0:1a61c61d0845 1165 */
dcoban 0:1a61c61d0845 1166 void CHTTPContext::ParseHeaderRequestLine()
dcoban 0:1a61c61d0845 1167 {
dcoban 0:1a61c61d0845 1168 static const char ContentLengthName[] = "Content-Length";
dcoban 0:1a61c61d0845 1169 char* pName = m_LineBuffer;
dcoban 0:1a61c61d0845 1170 char* pValue = NULL;
dcoban 0:1a61c61d0845 1171 char* pCurr = m_LineBuffer;
dcoban 0:1a61c61d0845 1172
dcoban 0:1a61c61d0845 1173 if ('\0' == m_LineBuffer[0])
dcoban 0:1a61c61d0845 1174 {
dcoban 0:1a61c61d0845 1175 // Let the request handler know that we have reached the last header.
dcoban 0:1a61c61d0845 1176 if (m_SendRequestHeadersToHandler)
dcoban 0:1a61c61d0845 1177 {
dcoban 0:1a61c61d0845 1178 m_pRequestHandlerContext->EndRequestHeaders();
dcoban 0:1a61c61d0845 1179 }
dcoban 0:1a61c61d0845 1180
dcoban 0:1a61c61d0845 1181 if (m_RequestContentLength)
dcoban 0:1a61c61d0845 1182 {
dcoban 0:1a61c61d0845 1183 // Determine if the request handler is interested in any request
dcoban 0:1a61c61d0845 1184 // content data that might follow the headers.
dcoban 0:1a61c61d0845 1185 m_ParseState = STATE_CONTENT;
dcoban 0:1a61c61d0845 1186 m_SendRequestContentToHandler = m_pRequestHandlerContext->BeginRequestContent(m_RequestContentLength);
dcoban 0:1a61c61d0845 1187 }
dcoban 0:1a61c61d0845 1188 else
dcoban 0:1a61c61d0845 1189 {
dcoban 0:1a61c61d0845 1190 // There is no request content from the client so server can start
dcoban 0:1a61c61d0845 1191 // to send its response now.
dcoban 0:1a61c61d0845 1192 m_ParseState = STATE_DONE;
dcoban 0:1a61c61d0845 1193 }
dcoban 0:1a61c61d0845 1194
dcoban 0:1a61c61d0845 1195 return;
dcoban 0:1a61c61d0845 1196 }
dcoban 0:1a61c61d0845 1197
dcoban 0:1a61c61d0845 1198 // Find the colon character which terminates the field name. A whitespace
dcoban 0:1a61c61d0845 1199 // character at the beginning of a header line indicates a line
dcoban 0:1a61c61d0845 1200 // continuation so handle that as well.
dcoban 0:1a61c61d0845 1201 while (':' != *pCurr &&
dcoban 0:1a61c61d0845 1202 ' ' != *pCurr &&
dcoban 0:1a61c61d0845 1203 '\t' != *pCurr )
dcoban 0:1a61c61d0845 1204 {
dcoban 0:1a61c61d0845 1205 pCurr++;
dcoban 0:1a61c61d0845 1206 }
dcoban 0:1a61c61d0845 1207 *pCurr++ = '\0';
dcoban 0:1a61c61d0845 1208
dcoban 0:1a61c61d0845 1209 // Skip over whitespace to find start of value.
dcoban 0:1a61c61d0845 1210 while (' ' == *pCurr ||
dcoban 0:1a61c61d0845 1211 '\t' == *pCurr)
dcoban 0:1a61c61d0845 1212 {
dcoban 0:1a61c61d0845 1213 pCurr++;
dcoban 0:1a61c61d0845 1214 }
dcoban 0:1a61c61d0845 1215 pValue = pCurr;
dcoban 0:1a61c61d0845 1216
dcoban 0:1a61c61d0845 1217 // Check for the Content-Length field which tells the server if it should
dcoban 0:1a61c61d0845 1218 // expect the request to have a content body.
dcoban 0:1a61c61d0845 1219 if (0 == strcasecmp(pName, ContentLengthName))
dcoban 0:1a61c61d0845 1220 {
dcoban 0:1a61c61d0845 1221 m_RequestContentLength = strtoul(pValue, NULL, 10);
dcoban 0:1a61c61d0845 1222 }
dcoban 0:1a61c61d0845 1223
dcoban 0:1a61c61d0845 1224 // Send the header to request handler context interface if it has requested
dcoban 0:1a61c61d0845 1225 // the server to do so.
dcoban 0:1a61c61d0845 1226 if (m_SendRequestHeadersToHandler)
dcoban 0:1a61c61d0845 1227 {
dcoban 0:1a61c61d0845 1228 m_pRequestHandlerContext->WriteRequestHeader(pName, pValue);
dcoban 0:1a61c61d0845 1229 }
dcoban 0:1a61c61d0845 1230 }
dcoban 0:1a61c61d0845 1231
dcoban 0:1a61c61d0845 1232
dcoban 0:1a61c61d0845 1233 /* Kicks off the process of handling client specified request.
dcoban 0:1a61c61d0845 1234
dcoban 0:1a61c61d0845 1235 Parameters:
dcoban 0:1a61c61d0845 1236 pURI is the name of the URI being requested.
dcoban 0:1a61c61d0845 1237
dcoban 0:1a61c61d0845 1238 Returns:
dcoban 0:1a61c61d0845 1239 Nothing.
dcoban 0:1a61c61d0845 1240 */
dcoban 0:1a61c61d0845 1241 void CHTTPContext::StartRequestHandler(const char* pURI)
dcoban 0:1a61c61d0845 1242 {
dcoban 0:1a61c61d0845 1243 // Start request by first letting application provider a handler and if it
dcoban 0:1a61c61d0845 1244 // doesn't use this object's default request handler interface instead.
dcoban 0:1a61c61d0845 1245 switch (m_RequestType)
dcoban 0:1a61c61d0845 1246 {
dcoban 0:1a61c61d0845 1247 case TYPE_GET_0_9:
dcoban 0:1a61c61d0845 1248 case TYPE_GET_1_0:
dcoban 0:1a61c61d0845 1249 StartGetRequest(pURI);
dcoban 0:1a61c61d0845 1250 break;
dcoban 0:1a61c61d0845 1251 case TYPE_HEAD:
dcoban 0:1a61c61d0845 1252 StartHeadRequest(pURI);
dcoban 0:1a61c61d0845 1253 break;
dcoban 0:1a61c61d0845 1254 case TYPE_POST:
dcoban 0:1a61c61d0845 1255 StartPostRequest(pURI);
dcoban 0:1a61c61d0845 1256 break;
dcoban 0:1a61c61d0845 1257 default:
dcoban 0:1a61c61d0845 1258 assert ( FALSE );
dcoban 0:1a61c61d0845 1259 break;
dcoban 0:1a61c61d0845 1260 }
dcoban 0:1a61c61d0845 1261
dcoban 0:1a61c61d0845 1262 // Should have a request handler now: either from application or this
dcoban 0:1a61c61d0845 1263 // context object.
dcoban 0:1a61c61d0845 1264 assert ( m_pRequestHandlerContext );
dcoban 0:1a61c61d0845 1265
dcoban 0:1a61c61d0845 1266 // Ask the request handler interface if it wants each request header sent
dcoban 0:1a61c61d0845 1267 // to it. There will be no header for HTTP/0.9 GET request which skips the
dcoban 0:1a61c61d0845 1268 // header state.
dcoban 0:1a61c61d0845 1269 if (STATE_HEADERS == m_ParseState)
dcoban 0:1a61c61d0845 1270 {
dcoban 0:1a61c61d0845 1271 m_SendRequestHeadersToHandler = m_pRequestHandlerContext->BeginRequestHeaders();
dcoban 0:1a61c61d0845 1272 }
dcoban 0:1a61c61d0845 1273 }
dcoban 0:1a61c61d0845 1274
dcoban 0:1a61c61d0845 1275
dcoban 0:1a61c61d0845 1276 /* Handles GET requests by first allowing the application to handler it via a
dcoban 0:1a61c61d0845 1277 register request handler. If it doesn't want to handle the request then the
dcoban 0:1a61c61d0845 1278 server will attempt to satisfy the request from the file system that was
dcoban 0:1a61c61d0845 1279 registers at bind time.
dcoban 0:1a61c61d0845 1280
dcoban 0:1a61c61d0845 1281 Parameters:
dcoban 0:1a61c61d0845 1282 pURI is the name of the URI being requested.
dcoban 0:1a61c61d0845 1283
dcoban 0:1a61c61d0845 1284 Returns:
dcoban 0:1a61c61d0845 1285 Nothing.
dcoban 0:1a61c61d0845 1286 */
dcoban 0:1a61c61d0845 1287 void CHTTPContext::StartGetRequest(const char* pURI)
dcoban 0:1a61c61d0845 1288 {
dcoban 0:1a61c61d0845 1289 // Load the requested file if possible or the file not found
dcoban 0:1a61c61d0845 1290 // content if requested file was not found.
dcoban 0:1a61c61d0845 1291 TRACE("HTTP: GET '%s' from: ", pURI);
dcoban 0:1a61c61d0845 1292 NetworkPrintRemoteAddress(m_pPCB);
dcoban 0:1a61c61d0845 1293 TRACE("\r\n");
dcoban 0:1a61c61d0845 1294
dcoban 0:1a61c61d0845 1295 if (m_pHTTPServer->m_pRequestHandler)
dcoban 0:1a61c61d0845 1296 {
dcoban 0:1a61c61d0845 1297 // First let the application attempt to handle the GET request.
dcoban 0:1a61c61d0845 1298 m_pRequestHandlerContext = m_pHTTPServer->m_pRequestHandler->HandleGetRequest(pURI);
dcoban 0:1a61c61d0845 1299 }
dcoban 0:1a61c61d0845 1300 if (!m_pRequestHandlerContext)
dcoban 0:1a61c61d0845 1301 {
dcoban 0:1a61c61d0845 1302 // The application doesn't want to handle the GET request so use the
dcoban 0:1a61c61d0845 1303 // default server behaviour.
dcoban 0:1a61c61d0845 1304 OpenFile(pURI);
dcoban 0:1a61c61d0845 1305 m_pRequestHandlerContext = this;
dcoban 0:1a61c61d0845 1306 }
dcoban 0:1a61c61d0845 1307 }
dcoban 0:1a61c61d0845 1308
dcoban 0:1a61c61d0845 1309
dcoban 0:1a61c61d0845 1310 /* Handles HEAD requests by first allowing the application to handler it via a
dcoban 0:1a61c61d0845 1311 register request handler. If it doesn't want to handle the request then the
dcoban 0:1a61c61d0845 1312 server will attempt to satisfy the request from the file system that was
dcoban 0:1a61c61d0845 1313 registers at bind time.
dcoban 0:1a61c61d0845 1314
dcoban 0:1a61c61d0845 1315 Parameters:
dcoban 0:1a61c61d0845 1316 pURI is the name of the URI being requested.
dcoban 0:1a61c61d0845 1317
dcoban 0:1a61c61d0845 1318 Returns:
dcoban 0:1a61c61d0845 1319 Nothing.
dcoban 0:1a61c61d0845 1320 */
dcoban 0:1a61c61d0845 1321 void CHTTPContext::StartHeadRequest(const char* pURI)
dcoban 0:1a61c61d0845 1322 {
dcoban 0:1a61c61d0845 1323 // Load the requested file if possible or the file not found
dcoban 0:1a61c61d0845 1324 // content if requested file was not found.
dcoban 0:1a61c61d0845 1325 TRACE("HTTP: HEAD '%s' from: ", pURI);
dcoban 0:1a61c61d0845 1326 NetworkPrintRemoteAddress(m_pPCB);
dcoban 0:1a61c61d0845 1327 TRACE("\r\n");
dcoban 0:1a61c61d0845 1328
dcoban 0:1a61c61d0845 1329 if (m_pHTTPServer->m_pRequestHandler)
dcoban 0:1a61c61d0845 1330 {
dcoban 0:1a61c61d0845 1331 // First let the application attempt to handle the HEAD request.
dcoban 0:1a61c61d0845 1332 m_pRequestHandlerContext = m_pHTTPServer->m_pRequestHandler->HandleHeadRequest(pURI);
dcoban 0:1a61c61d0845 1333 }
dcoban 0:1a61c61d0845 1334
dcoban 0:1a61c61d0845 1335 if (!m_pRequestHandlerContext)
dcoban 0:1a61c61d0845 1336 {
dcoban 0:1a61c61d0845 1337 // The application doesn't want to handle the HEAD request so use the
dcoban 0:1a61c61d0845 1338 // default server behaviour.
dcoban 0:1a61c61d0845 1339 OpenFile(pURI);
dcoban 0:1a61c61d0845 1340 m_pRequestHandlerContext = this;
dcoban 0:1a61c61d0845 1341 }
dcoban 0:1a61c61d0845 1342 }
dcoban 0:1a61c61d0845 1343
dcoban 0:1a61c61d0845 1344
dcoban 0:1a61c61d0845 1345 /* Handles POST requests by allowing the application to handler it via a
dcoban 0:1a61c61d0845 1346 registered request handler. If it doesn't want to handle the request then
dcoban 0:1a61c61d0845 1347 the server will treat it as an unimplemented request.
dcoban 0:1a61c61d0845 1348
dcoban 0:1a61c61d0845 1349 Parameters:
dcoban 0:1a61c61d0845 1350 pURI is the name of the URI being requested.
dcoban 0:1a61c61d0845 1351
dcoban 0:1a61c61d0845 1352 Returns:
dcoban 0:1a61c61d0845 1353 Nothing.
dcoban 0:1a61c61d0845 1354 */
dcoban 0:1a61c61d0845 1355 void CHTTPContext::StartPostRequest(const char* pURI)
dcoban 0:1a61c61d0845 1356 {
dcoban 0:1a61c61d0845 1357 // Load the requested file if possible or the file not found
dcoban 0:1a61c61d0845 1358 // content if requested file was not found.
dcoban 0:1a61c61d0845 1359 TRACE("HTTP: POST '%s' from: ", pURI);
dcoban 0:1a61c61d0845 1360 NetworkPrintRemoteAddress(m_pPCB);
dcoban 0:1a61c61d0845 1361 TRACE("\r\n");
dcoban 0:1a61c61d0845 1362
dcoban 0:1a61c61d0845 1363 if (m_pHTTPServer->m_pRequestHandler)
dcoban 0:1a61c61d0845 1364 {
dcoban 0:1a61c61d0845 1365 // First let the application attempt to handle the POST request.
dcoban 0:1a61c61d0845 1366 m_pRequestHandlerContext = m_pHTTPServer->m_pRequestHandler->HandlePostRequest(pURI);
dcoban 0:1a61c61d0845 1367 }
dcoban 0:1a61c61d0845 1368
dcoban 0:1a61c61d0845 1369 if (!m_pRequestHandlerContext)
dcoban 0:1a61c61d0845 1370 {
dcoban 0:1a61c61d0845 1371 // The application doesn't want to handle the POST request.
dcoban 0:1a61c61d0845 1372 m_pRequestHandlerContext = this;
dcoban 0:1a61c61d0845 1373 }
dcoban 0:1a61c61d0845 1374 }
dcoban 0:1a61c61d0845 1375
dcoban 0:1a61c61d0845 1376
dcoban 0:1a61c61d0845 1377 /* Handles unknown/bad HTTP client requests by sending back an appropriate
dcoban 0:1a61c61d0845 1378 error response.
dcoban 0:1a61c61d0845 1379
dcoban 0:1a61c61d0845 1380 Parameters:
dcoban 0:1a61c61d0845 1381 pRequest is the complete request line which wasn't recognized by the server.
dcoban 0:1a61c61d0845 1382
dcoban 0:1a61c61d0845 1383 Returns:
dcoban 0:1a61c61d0845 1384 Nothing.
dcoban 0:1a61c61d0845 1385 */
dcoban 0:1a61c61d0845 1386 void CHTTPContext::StartBadRequest(const char* pRequest)
dcoban 0:1a61c61d0845 1387 {
dcoban 0:1a61c61d0845 1388 if (m_pHTTPServer->m_pRequestHandler)
dcoban 0:1a61c61d0845 1389 {
dcoban 0:1a61c61d0845 1390 // First let the application attempt to handle this request instead.
dcoban 0:1a61c61d0845 1391 m_pRequestHandlerContext = m_pHTTPServer->m_pRequestHandler->HandleBadRequest(pRequest);
dcoban 0:1a61c61d0845 1392 }
dcoban 0:1a61c61d0845 1393 if (!m_pRequestHandlerContext)
dcoban 0:1a61c61d0845 1394 {
dcoban 0:1a61c61d0845 1395 // The application doesn't want to handle the bad request so just
dcoban 0:1a61c61d0845 1396 // return an appropriate bad request response.
dcoban 0:1a61c61d0845 1397 m_pRequestHandlerContext = this;
dcoban 0:1a61c61d0845 1398 }
dcoban 0:1a61c61d0845 1399
dcoban 0:1a61c61d0845 1400 // Ask the request handler interface if it wants each request header sent
dcoban 0:1a61c61d0845 1401 // to it.
dcoban 0:1a61c61d0845 1402 m_SendRequestHeadersToHandler = m_pRequestHandlerContext->BeginRequestHeaders();
dcoban 0:1a61c61d0845 1403 }
dcoban 0:1a61c61d0845 1404
dcoban 0:1a61c61d0845 1405
dcoban 0:1a61c61d0845 1406 /* Called from HTTPRecv() to open the specified file that has been requested by
dcoban 0:1a61c61d0845 1407 the HTTP client. In addition to opening the specified file, it will also
dcoban 0:1a61c61d0845 1408 fill in the headers to match the content being sent vack. It also handles
dcoban 0:1a61c61d0845 1409 sending back the correct header if the requested file isn't found.
dcoban 0:1a61c61d0845 1410
dcoban 0:1a61c61d0845 1411 Parameters:
dcoban 0:1a61c61d0845 1412 pURI is the name of the URI being requested.
dcoban 0:1a61c61d0845 1413
dcoban 0:1a61c61d0845 1414 Returns:
dcoban 0:1a61c61d0845 1415 Nothing.
dcoban 0:1a61c61d0845 1416 */
dcoban 0:1a61c61d0845 1417 void CHTTPContext::OpenFile(const char* pURI)
dcoban 0:1a61c61d0845 1418 {
dcoban 0:1a61c61d0845 1419 static const char NotFoundHTML[] = "<html>"
dcoban 0:1a61c61d0845 1420 "<body><h2>404: File not found.</h2></body>"
dcoban 0:1a61c61d0845 1421 "</html>\r\n";
dcoban 0:1a61c61d0845 1422 // The content types supported by this HTTP server.
dcoban 0:1a61c61d0845 1423 static const char ContentHTML[] = "Content-type: text/html\r\n";
dcoban 0:1a61c61d0845 1424 static const char ContentGIF[] = "Content-type: image/gif\r\n";
dcoban 0:1a61c61d0845 1425 static const char ContentPNG[] = "Content-type: image/png\r\n";
dcoban 0:1a61c61d0845 1426 static const char ContentJPG[] = "Content-type: image/jpeg\r\n";
dcoban 0:1a61c61d0845 1427 static const char ContentBMP[] = "Content-type: image/bmp\r\n";
dcoban 0:1a61c61d0845 1428 static const char ContentICO[] = "Content-type: image/x-icon\r\n";
dcoban 0:1a61c61d0845 1429 static const char ContentStream[] = "Content-type: application/octet-stream\r\n";
dcoban 0:1a61c61d0845 1430 static const char ContentJScript[] = "Content-type: application/x-javascript\r\n";
dcoban 0:1a61c61d0845 1431 static const char ContentCSS[] = "Content-type: text/css\r\n";
dcoban 0:1a61c61d0845 1432 static const char ContentFlash[] = "Content-type: application/x-shockwave-flash\r\n";
dcoban 0:1a61c61d0845 1433 static const char ContentXML[] = "Content-type: text/xml\r\n";
dcoban 0:1a61c61d0845 1434 static const char ContentDefault[] = "Content-type: text/plain\r\n";
dcoban 0:1a61c61d0845 1435
dcoban 0:1a61c61d0845 1436 // Table used to map file extensions to above content type headers.
dcoban 0:1a61c61d0845 1437 #define CONTENT_HEADER(X) X, sizeof(X)-1
dcoban 0:1a61c61d0845 1438 static const struct
dcoban 0:1a61c61d0845 1439 {
dcoban 0:1a61c61d0845 1440 // File extension.
dcoban 0:1a61c61d0845 1441 const char* pExtension;
dcoban 0:1a61c61d0845 1442 // Content header to be used for this file extension type.
dcoban 0:1a61c61d0845 1443 const char* pContentHeader;
dcoban 0:1a61c61d0845 1444 // Length of pContentHeader string without NULL terminator.
dcoban 0:1a61c61d0845 1445 unsigned int ContentHeaderLength;
dcoban 0:1a61c61d0845 1446 } ContentMapping[] =
dcoban 0:1a61c61d0845 1447 {
dcoban 0:1a61c61d0845 1448 {".html", CONTENT_HEADER(ContentHTML)},
dcoban 0:1a61c61d0845 1449 {".htm", CONTENT_HEADER(ContentHTML)},
dcoban 0:1a61c61d0845 1450 {".gif", CONTENT_HEADER(ContentGIF)},
dcoban 0:1a61c61d0845 1451 {".png", CONTENT_HEADER(ContentPNG)},
dcoban 0:1a61c61d0845 1452 {".jpg", CONTENT_HEADER(ContentJPG)},
dcoban 0:1a61c61d0845 1453 {".bmp", CONTENT_HEADER(ContentBMP)},
dcoban 0:1a61c61d0845 1454 {".ico", CONTENT_HEADER(ContentICO)},
dcoban 0:1a61c61d0845 1455 {".class", CONTENT_HEADER(ContentStream)},
dcoban 0:1a61c61d0845 1456 {".cls", CONTENT_HEADER(ContentStream)},
dcoban 0:1a61c61d0845 1457 {".js", CONTENT_HEADER(ContentJScript)},
dcoban 0:1a61c61d0845 1458 {".css", CONTENT_HEADER(ContentCSS)},
dcoban 0:1a61c61d0845 1459 {".swf", CONTENT_HEADER(ContentFlash)},
dcoban 0:1a61c61d0845 1460 {".xml", CONTENT_HEADER(ContentXML)}
dcoban 0:1a61c61d0845 1461 };
dcoban 0:1a61c61d0845 1462 // Local variables.
dcoban 0:1a61c61d0845 1463 size_t i;
dcoban 0:1a61c61d0845 1464 char LocalFilename[HTTP_MAX_FILENAME+1];
dcoban 0:1a61c61d0845 1465
dcoban 0:1a61c61d0845 1466 // Attempt to open the file.
dcoban 0:1a61c61d0845 1467 if (0 == strcmp(pURI, "/"))
dcoban 0:1a61c61d0845 1468 {
dcoban 0:1a61c61d0845 1469 // Iterate through the list of default root filenames.
dcoban 0:1a61c61d0845 1470 for (i = 0 ; !m_pFile && i < ARRAYSIZE(g_DefaultFilenames) ; i++)
dcoban 0:1a61c61d0845 1471 {
dcoban 0:1a61c61d0845 1472 snprintf(LocalFilename, ARRAYSIZE(LocalFilename), "/%s%s", m_pHTTPServer->m_pRootPathname, g_DefaultFilenames[i]);
dcoban 0:1a61c61d0845 1473 m_pFile = fopen(LocalFilename, "r");
dcoban 0:1a61c61d0845 1474 }
dcoban 0:1a61c61d0845 1475 }
dcoban 0:1a61c61d0845 1476 else
dcoban 0:1a61c61d0845 1477 {
dcoban 0:1a61c61d0845 1478 // Attempt to open the specified URI.
dcoban 0:1a61c61d0845 1479 snprintf(LocalFilename, ARRAYSIZE(LocalFilename), "/%s%s", m_pHTTPServer->m_pRootPathname, pURI);
dcoban 0:1a61c61d0845 1480 m_pFile = fopen(LocalFilename, "r");
dcoban 0:1a61c61d0845 1481 }
dcoban 0:1a61c61d0845 1482
dcoban 0:1a61c61d0845 1483 // Setup the content type field based on whether the file was found or not.
dcoban 0:1a61c61d0845 1484 if (!m_pFile)
dcoban 0:1a61c61d0845 1485 {
dcoban 0:1a61c61d0845 1486 // The file open failed so return a 404 error with HTML.
dcoban 0:1a61c61d0845 1487 m_pContentType = ContentHTML;
dcoban 0:1a61c61d0845 1488 m_ContentTypeLength = sizeof(ContentHTML) - 1;
dcoban 0:1a61c61d0845 1489 m_pErrorHTML = NotFoundHTML;
dcoban 0:1a61c61d0845 1490 m_ErrorHTMLLength = sizeof(NotFoundHTML) - 1;
dcoban 0:1a61c61d0845 1491 }
dcoban 0:1a61c61d0845 1492 else
dcoban 0:1a61c61d0845 1493 {
dcoban 0:1a61c61d0845 1494 const char* pExtension;
dcoban 0:1a61c61d0845 1495
dcoban 0:1a61c61d0845 1496 // Configure the content type header based on filename extension.
dcoban 0:1a61c61d0845 1497 pExtension = strrchr(LocalFilename, '.');
dcoban 0:1a61c61d0845 1498 for (i = 0 ; pExtension && i < ARRAYSIZE(ContentMapping) ; i++)
dcoban 0:1a61c61d0845 1499 {
dcoban 0:1a61c61d0845 1500 if (0 == strcmp(pExtension, ContentMapping[i].pExtension))
dcoban 0:1a61c61d0845 1501 {
dcoban 0:1a61c61d0845 1502 m_pContentType = ContentMapping[i].pContentHeader;
dcoban 0:1a61c61d0845 1503 m_ContentTypeLength = ContentMapping[i].ContentHeaderLength;
dcoban 0:1a61c61d0845 1504 break;
dcoban 0:1a61c61d0845 1505 }
dcoban 0:1a61c61d0845 1506 }
dcoban 0:1a61c61d0845 1507
dcoban 0:1a61c61d0845 1508 // If the type couldn't be found default to plain.
dcoban 0:1a61c61d0845 1509 if (!m_pContentType)
dcoban 0:1a61c61d0845 1510 {
dcoban 0:1a61c61d0845 1511 m_pContentType = ContentDefault;
dcoban 0:1a61c61d0845 1512 m_ContentTypeLength = sizeof(ContentDefault) - 1;
dcoban 0:1a61c61d0845 1513 }
dcoban 0:1a61c61d0845 1514 }
dcoban 0:1a61c61d0845 1515 }
dcoban 0:1a61c61d0845 1516
dcoban 0:1a61c61d0845 1517
dcoban 0:1a61c61d0845 1518 /* Prepares the headers and content to be sent back to the HTTP client as a
dcoban 0:1a61c61d0845 1519 response to its latest request. It then starts sending out the first set of
dcoban 0:1a61c61d0845 1520 response packets.
dcoban 0:1a61c61d0845 1521
dcoban 0:1a61c61d0845 1522 Parameters:
dcoban 0:1a61c61d0845 1523 None.
dcoban 0:1a61c61d0845 1524
dcoban 0:1a61c61d0845 1525 Returns:
dcoban 0:1a61c61d0845 1526 Nothing.
dcoban 0:1a61c61d0845 1527 */
dcoban 0:1a61c61d0845 1528 void CHTTPContext::PrepareResponse()
dcoban 0:1a61c61d0845 1529 {
dcoban 0:1a61c61d0845 1530 assert ( STATE_DONE == m_ParseState );
dcoban 0:1a61c61d0845 1531
dcoban 0:1a61c61d0845 1532 PrepareResponseHeaders();
dcoban 0:1a61c61d0845 1533
dcoban 0:1a61c61d0845 1534 if (!m_pRequestHandlerContext->BeginResponseContent())
dcoban 0:1a61c61d0845 1535 {
dcoban 0:1a61c61d0845 1536 // The application has no content to send so release it.
dcoban 0:1a61c61d0845 1537 m_pRequestHandlerContext->Release();
dcoban 0:1a61c61d0845 1538 m_pRequestHandlerContext = NULL;
dcoban 0:1a61c61d0845 1539 }
dcoban 0:1a61c61d0845 1540 }
dcoban 0:1a61c61d0845 1541
dcoban 0:1a61c61d0845 1542
dcoban 0:1a61c61d0845 1543 /* Prepares the headers and content to be sent back to the HTTP client as a
dcoban 0:1a61c61d0845 1544 response to its latest request. It then starts sending out the first set of
dcoban 0:1a61c61d0845 1545 response packets.
dcoban 0:1a61c61d0845 1546
dcoban 0:1a61c61d0845 1547 Parameters:
dcoban 0:1a61c61d0845 1548 None.
dcoban 0:1a61c61d0845 1549
dcoban 0:1a61c61d0845 1550 Returns:
dcoban 0:1a61c61d0845 1551 Nothing.
dcoban 0:1a61c61d0845 1552 */
dcoban 0:1a61c61d0845 1553 void CHTTPContext::PrepareResponseHeaders()
dcoban 0:1a61c61d0845 1554 {
dcoban 0:1a61c61d0845 1555 static const char BlankLine[] = "\r\n";
dcoban 0:1a61c61d0845 1556 const char* pStatusLine = NULL;
dcoban 0:1a61c61d0845 1557 const char* pExtraHeaders = NULL;
dcoban 0:1a61c61d0845 1558 size_t StatusLineLength = 0;
dcoban 0:1a61c61d0845 1559 size_t ExtraHeadersLength = 0;
dcoban 0:1a61c61d0845 1560 size_t i = 0;
dcoban 0:1a61c61d0845 1561
dcoban 0:1a61c61d0845 1562 if (TYPE_GET_0_9 == m_RequestType)
dcoban 0:1a61c61d0845 1563 {
dcoban 0:1a61c61d0845 1564 // Don't return any headers for a HTTP/0.9 GET request.
dcoban 0:1a61c61d0845 1565 m_HeaderArray[0].pHeaderString = NULL;
dcoban 0:1a61c61d0845 1566 m_HeaderArray[0].HeaderLength = 0;
dcoban 0:1a61c61d0845 1567 return;
dcoban 0:1a61c61d0845 1568 }
dcoban 0:1a61c61d0845 1569
dcoban 0:1a61c61d0845 1570 // Prepare the response status.
dcoban 0:1a61c61d0845 1571 pStatusLine = m_pRequestHandlerContext->GetStatusLine(&StatusLineLength);
dcoban 0:1a61c61d0845 1572
dcoban 0:1a61c61d0845 1573 // Application must return a status line.
dcoban 0:1a61c61d0845 1574 assert ( pStatusLine && StatusLineLength > 0 );
dcoban 0:1a61c61d0845 1575
dcoban 0:1a61c61d0845 1576 m_HeaderArray[0].pHeaderString = pStatusLine;
dcoban 0:1a61c61d0845 1577 m_HeaderArray[0].HeaderLength = StatusLineLength;
dcoban 0:1a61c61d0845 1578
dcoban 0:1a61c61d0845 1579 // The second header returned will always be the server type, no
dcoban 0:1a61c61d0845 1580 // matter what response we send back.
dcoban 0:1a61c61d0845 1581 m_HeaderArray[1].pHeaderString = m_pHTTPServer->m_ServerHeader;
dcoban 0:1a61c61d0845 1582 m_HeaderArray[1].HeaderLength = m_pHTTPServer->m_ServerHeaderLength;
dcoban 0:1a61c61d0845 1583
dcoban 0:1a61c61d0845 1584 // Find out what other headers the application would like to send back to
dcoban 0:1a61c61d0845 1585 // the HTTP client.
dcoban 0:1a61c61d0845 1586 pExtraHeaders = m_pRequestHandlerContext->GetResponseHeaders(&ExtraHeadersLength);
dcoban 0:1a61c61d0845 1587 if (pExtraHeaders)
dcoban 0:1a61c61d0845 1588 {
dcoban 0:1a61c61d0845 1589 m_HeaderArray[2].pHeaderString = pExtraHeaders;
dcoban 0:1a61c61d0845 1590 m_HeaderArray[2].HeaderLength = ExtraHeadersLength;
dcoban 0:1a61c61d0845 1591 i = 3;
dcoban 0:1a61c61d0845 1592 }
dcoban 0:1a61c61d0845 1593 else
dcoban 0:1a61c61d0845 1594 {
dcoban 0:1a61c61d0845 1595 // Won't be using all of the elements of m_HeaderArray.
dcoban 0:1a61c61d0845 1596 i = 2;
dcoban 0:1a61c61d0845 1597 }
dcoban 0:1a61c61d0845 1598
dcoban 0:1a61c61d0845 1599 // Finally send the blank line header which separates the headers from the
dcoban 0:1a61c61d0845 1600 // entity body.
dcoban 0:1a61c61d0845 1601 m_HeaderArray[i].pHeaderString = BlankLine;
dcoban 0:1a61c61d0845 1602 m_HeaderArray[i].HeaderLength = sizeof(BlankLine) -1;
dcoban 0:1a61c61d0845 1603 }
dcoban 0:1a61c61d0845 1604
dcoban 0:1a61c61d0845 1605 /* Attempts to allocate a SBuffer object for reading the data into. If such a
dcoban 0:1a61c61d0845 1606 buffer is available then read HTTP headers and file data into the buffer.
dcoban 0:1a61c61d0845 1607 If the buffer can't be allocated, then add this client to a queue to be
dcoban 0:1a61c61d0845 1608 processed later.
dcoban 0:1a61c61d0845 1609
dcoban 0:1a61c61d0845 1610 Parameters:
dcoban 0:1a61c61d0845 1611 None.
dcoban 0:1a61c61d0845 1612
dcoban 0:1a61c61d0845 1613 Returns:
dcoban 0:1a61c61d0845 1614 Nothing.
dcoban 0:1a61c61d0845 1615 */
dcoban 0:1a61c61d0845 1616 void CHTTPContext::ReadContent()
dcoban 0:1a61c61d0845 1617 {
dcoban 0:1a61c61d0845 1618 // Local variables.
dcoban 0:1a61c61d0845 1619 SBuffer* pWriteBuffer = m_BufferQueue[m_BufferQueueHead];
dcoban 0:1a61c61d0845 1620 unsigned int BytesLeftInBuffer;
dcoban 0:1a61c61d0845 1621 char* pData;
dcoban 0:1a61c61d0845 1622 unsigned int i;
dcoban 0:1a61c61d0845 1623
dcoban 0:1a61c61d0845 1624
dcoban 0:1a61c61d0845 1625 // Return now if there is already a buffer filled with data in the process
dcoban 0:1a61c61d0845 1626 // of being written out to the connection. Also return if there is no more
dcoban 0:1a61c61d0845 1627 // data to be sent to this client.
dcoban 0:1a61c61d0845 1628 if (pWriteBuffer ||
dcoban 0:1a61c61d0845 1629 (m_HeaderIndex >= ARRAYSIZE(m_HeaderArray) &&
dcoban 0:1a61c61d0845 1630 !m_pRequestHandlerContext))
dcoban 0:1a61c61d0845 1631 {
dcoban 0:1a61c61d0845 1632 return;
dcoban 0:1a61c61d0845 1633 }
dcoban 0:1a61c61d0845 1634
dcoban 0:1a61c61d0845 1635 // Attempt to allocate a new SBuffer.
dcoban 0:1a61c61d0845 1636 pWriteBuffer = m_pHTTPServer->AllocateBuffer(this);
dcoban 0:1a61c61d0845 1637 if (!pWriteBuffer)
dcoban 0:1a61c61d0845 1638 {
dcoban 0:1a61c61d0845 1639 // There is no buffer available at this time. Will be called back
dcoban 0:1a61c61d0845 1640 // later when one becomes available.
dcoban 0:1a61c61d0845 1641 return;
dcoban 0:1a61c61d0845 1642 }
dcoban 0:1a61c61d0845 1643 assert ( 0 == pWriteBuffer->BytesToWrite );
dcoban 0:1a61c61d0845 1644 assert ( 0 == pWriteBuffer->UnacknowledgedBytes );
dcoban 0:1a61c61d0845 1645
dcoban 0:1a61c61d0845 1646 // Buffer is free. Now fill it with headers and file data.
dcoban 0:1a61c61d0845 1647 BytesLeftInBuffer = sizeof(pWriteBuffer->Data);
dcoban 0:1a61c61d0845 1648 pData = pWriteBuffer->Data;
dcoban 0:1a61c61d0845 1649 pWriteBuffer->pWrite = pData;
dcoban 0:1a61c61d0845 1650
dcoban 0:1a61c61d0845 1651 // Copy remaining headers into free buffer.
dcoban 0:1a61c61d0845 1652 for (i = m_HeaderIndex ;
dcoban 0:1a61c61d0845 1653 i < ARRAYSIZE(m_HeaderArray) ;
dcoban 0:1a61c61d0845 1654 i++)
dcoban 0:1a61c61d0845 1655 {
dcoban 0:1a61c61d0845 1656 unsigned int BytesToCopy;
dcoban 0:1a61c61d0845 1657 unsigned int HeaderBytesLeft;
dcoban 0:1a61c61d0845 1658
dcoban 0:1a61c61d0845 1659 assert ( i == m_HeaderIndex );
dcoban 0:1a61c61d0845 1660
dcoban 0:1a61c61d0845 1661 if (!m_HeaderArray[i].pHeaderString)
dcoban 0:1a61c61d0845 1662 {
dcoban 0:1a61c61d0845 1663 // Not all (or any) of the headers were used so mark as done and
dcoban 0:1a61c61d0845 1664 // no need to copy any more so break out of loop.
dcoban 0:1a61c61d0845 1665 m_HeaderIndex = ARRAYSIZE(m_HeaderArray);
dcoban 0:1a61c61d0845 1666 break;
dcoban 0:1a61c61d0845 1667 }
dcoban 0:1a61c61d0845 1668
dcoban 0:1a61c61d0845 1669 // Determine how many bytes are to be copied.
dcoban 0:1a61c61d0845 1670 HeaderBytesLeft = m_HeaderArray[i].HeaderLength -
dcoban 0:1a61c61d0845 1671 m_HeaderOffset;
dcoban 0:1a61c61d0845 1672 if (HeaderBytesLeft > BytesLeftInBuffer)
dcoban 0:1a61c61d0845 1673 {
dcoban 0:1a61c61d0845 1674 BytesToCopy = BytesLeftInBuffer;
dcoban 0:1a61c61d0845 1675 }
dcoban 0:1a61c61d0845 1676 else
dcoban 0:1a61c61d0845 1677 {
dcoban 0:1a61c61d0845 1678 BytesToCopy = HeaderBytesLeft;
dcoban 0:1a61c61d0845 1679 }
dcoban 0:1a61c61d0845 1680
dcoban 0:1a61c61d0845 1681 // Perform the copy.
dcoban 0:1a61c61d0845 1682 memcpy(pData,
dcoban 0:1a61c61d0845 1683 m_HeaderArray[i].pHeaderString + m_HeaderOffset,
dcoban 0:1a61c61d0845 1684 BytesToCopy);
dcoban 0:1a61c61d0845 1685
dcoban 0:1a61c61d0845 1686 // Update buffer information.
dcoban 0:1a61c61d0845 1687 pData += BytesToCopy;
dcoban 0:1a61c61d0845 1688 BytesLeftInBuffer -= BytesToCopy;
dcoban 0:1a61c61d0845 1689 HeaderBytesLeft -= BytesToCopy;
dcoban 0:1a61c61d0845 1690 if (0 == HeaderBytesLeft)
dcoban 0:1a61c61d0845 1691 {
dcoban 0:1a61c61d0845 1692 // Advance to next header.
dcoban 0:1a61c61d0845 1693 m_HeaderIndex++;
dcoban 0:1a61c61d0845 1694 m_HeaderOffset = 0;
dcoban 0:1a61c61d0845 1695 }
dcoban 0:1a61c61d0845 1696 else
dcoban 0:1a61c61d0845 1697 {
dcoban 0:1a61c61d0845 1698 // Advance offset within this header and exit since buffer is full.
dcoban 0:1a61c61d0845 1699 assert ( 0 == BytesLeftInBuffer );
dcoban 0:1a61c61d0845 1700
dcoban 0:1a61c61d0845 1701 m_HeaderOffset += BytesToCopy;
dcoban 0:1a61c61d0845 1702 break;
dcoban 0:1a61c61d0845 1703 }
dcoban 0:1a61c61d0845 1704 }
dcoban 0:1a61c61d0845 1705
dcoban 0:1a61c61d0845 1706 // Copy file data into buffer for sending.
dcoban 0:1a61c61d0845 1707 if (m_pRequestHandlerContext)
dcoban 0:1a61c61d0845 1708 {
dcoban 0:1a61c61d0845 1709 size_t BytesRead;
dcoban 0:1a61c61d0845 1710
dcoban 0:1a61c61d0845 1711 BytesRead = m_pRequestHandlerContext->ReadResponseContentBlock(pData, BytesLeftInBuffer);
dcoban 0:1a61c61d0845 1712 if (BytesRead < BytesLeftInBuffer)
dcoban 0:1a61c61d0845 1713 {
dcoban 0:1a61c61d0845 1714 // Must have hit end of file, so close it.
dcoban 0:1a61c61d0845 1715 m_pRequestHandlerContext->EndResponseContent();
dcoban 0:1a61c61d0845 1716 m_pRequestHandlerContext->Release();
dcoban 0:1a61c61d0845 1717 m_pRequestHandlerContext = NULL;
dcoban 0:1a61c61d0845 1718 }
dcoban 0:1a61c61d0845 1719 pData += BytesRead;
dcoban 0:1a61c61d0845 1720 BytesLeftInBuffer -= BytesRead;
dcoban 0:1a61c61d0845 1721 }
dcoban 0:1a61c61d0845 1722
dcoban 0:1a61c61d0845 1723 // Update the buffer valid byte count.
dcoban 0:1a61c61d0845 1724 pWriteBuffer->BytesToWrite = ARRAYSIZE(pWriteBuffer->Data) -
dcoban 0:1a61c61d0845 1725 BytesLeftInBuffer;
dcoban 0:1a61c61d0845 1726
dcoban 0:1a61c61d0845 1727 // Update the client context to indicate that it now has a buffer ready to
dcoban 0:1a61c61d0845 1728 // be written out to the client connection.
dcoban 0:1a61c61d0845 1729 m_BufferQueue[m_BufferQueueHead] = pWriteBuffer;
dcoban 0:1a61c61d0845 1730 }
dcoban 0:1a61c61d0845 1731
dcoban 0:1a61c61d0845 1732
dcoban 0:1a61c61d0845 1733 /* Attempts to send HTTP client data already read into buffer and also reads
dcoban 0:1a61c61d0845 1734 in more data to the buffer for sending as necessary. This data will be
dcoban 0:1a61c61d0845 1735 composed of HTTP headers and file data.
dcoban 0:1a61c61d0845 1736
dcoban 0:1a61c61d0845 1737 Parameters:
dcoban 0:1a61c61d0845 1738 None.
dcoban 0:1a61c61d0845 1739
dcoban 0:1a61c61d0845 1740 Returns:
dcoban 0:1a61c61d0845 1741 Nothing.
dcoban 0:1a61c61d0845 1742 */
dcoban 0:1a61c61d0845 1743 void CHTTPContext::SendResponse()
dcoban 0:1a61c61d0845 1744 {
dcoban 0:1a61c61d0845 1745 int ConnectionClosed;
dcoban 0:1a61c61d0845 1746
dcoban 0:1a61c61d0845 1747 // Attempt to send any data still in write buffer.
dcoban 0:1a61c61d0845 1748 ConnectionClosed = WriteData();
dcoban 0:1a61c61d0845 1749
dcoban 0:1a61c61d0845 1750 // Return now if the connection was closed.
dcoban 0:1a61c61d0845 1751 if (ConnectionClosed)
dcoban 0:1a61c61d0845 1752 {
dcoban 0:1a61c61d0845 1753 return;
dcoban 0:1a61c61d0845 1754 }
dcoban 0:1a61c61d0845 1755
dcoban 0:1a61c61d0845 1756 // Read in more content if possible.
dcoban 0:1a61c61d0845 1757 ReadContent();
dcoban 0:1a61c61d0845 1758
dcoban 0:1a61c61d0845 1759 // UNDONE: Once I have a performance test available, try removing this to see if it has any impact on performance.
dcoban 0:1a61c61d0845 1760 // Also want to wait for DMA based driver.
dcoban 0:1a61c61d0845 1761 // Attempt to send data that was just read into buffer.
dcoban 0:1a61c61d0845 1762 WriteData();
dcoban 0:1a61c61d0845 1763 }
dcoban 0:1a61c61d0845 1764
dcoban 0:1a61c61d0845 1765
dcoban 0:1a61c61d0845 1766 /* Sends any remaining response data to the HTTP client and closes the
dcoban 0:1a61c61d0845 1767 connection once the data has been sent.
dcoban 0:1a61c61d0845 1768
dcoban 0:1a61c61d0845 1769 Parameters:
dcoban 0:1a61c61d0845 1770 None.
dcoban 0:1a61c61d0845 1771
dcoban 0:1a61c61d0845 1772 Returns:
dcoban 0:1a61c61d0845 1773 1 if the last chunk was sent and the connection closed and 0 otherwise.
dcoban 0:1a61c61d0845 1774 */
dcoban 0:1a61c61d0845 1775 int CHTTPContext::WriteData()
dcoban 0:1a61c61d0845 1776 {
dcoban 0:1a61c61d0845 1777 // Local variables.
dcoban 0:1a61c61d0845 1778 err_t WriteResult = ERR_MEM;
dcoban 0:1a61c61d0845 1779 size_t BytesToWrite;
dcoban 0:1a61c61d0845 1780 size_t SendBufferSize;
dcoban 0:1a61c61d0845 1781 SBuffer* pWriteBuffer = m_BufferQueue[m_BufferQueueHead];
dcoban 0:1a61c61d0845 1782
dcoban 0:1a61c61d0845 1783 // Just return if there isn't a write buffer with data to send.
dcoban 0:1a61c61d0845 1784 if (!pWriteBuffer)
dcoban 0:1a61c61d0845 1785 {
dcoban 0:1a61c61d0845 1786 return 0;
dcoban 0:1a61c61d0845 1787 }
dcoban 0:1a61c61d0845 1788
dcoban 0:1a61c61d0845 1789 // Don't try to send more bytes than what the connection will accept.
dcoban 0:1a61c61d0845 1790 BytesToWrite = pWriteBuffer->BytesToWrite;
dcoban 0:1a61c61d0845 1791 SendBufferSize = tcp_sndbuf(m_pPCB);
dcoban 0:1a61c61d0845 1792 if (BytesToWrite > SendBufferSize)
dcoban 0:1a61c61d0845 1793 {
dcoban 0:1a61c61d0845 1794 BytesToWrite = SendBufferSize;
dcoban 0:1a61c61d0845 1795 }
dcoban 0:1a61c61d0845 1796
dcoban 0:1a61c61d0845 1797 // Keep attempting to send response data and shrinking the write until it
dcoban 0:1a61c61d0845 1798 // succeeds or it shrinks down to 0 bytes.
dcoban 0:1a61c61d0845 1799 while (BytesToWrite > 0)
dcoban 0:1a61c61d0845 1800 {
dcoban 0:1a61c61d0845 1801 // Attempt to write the response data out to the PCB.
dcoban 0:1a61c61d0845 1802 WriteResult = tcp_write(m_pPCB,
dcoban 0:1a61c61d0845 1803 pWriteBuffer->pWrite,
dcoban 0:1a61c61d0845 1804 BytesToWrite,
dcoban 0:1a61c61d0845 1805 0);
dcoban 0:1a61c61d0845 1806 if (ERR_OK == WriteResult)
dcoban 0:1a61c61d0845 1807 {
dcoban 0:1a61c61d0845 1808 // Write was successful so update buffer descriptors in the context
dcoban 0:1a61c61d0845 1809 // objects.
dcoban 0:1a61c61d0845 1810 pWriteBuffer->pWrite += BytesToWrite;
dcoban 0:1a61c61d0845 1811 pWriteBuffer->BytesToWrite -= BytesToWrite;
dcoban 0:1a61c61d0845 1812 pWriteBuffer->UnacknowledgedBytes += BytesToWrite;
dcoban 0:1a61c61d0845 1813
dcoban 0:1a61c61d0845 1814 // Successfully queued up data for sending so reset retry count.
dcoban 0:1a61c61d0845 1815 m_RetryCount = 0;
dcoban 0:1a61c61d0845 1816 break;
dcoban 0:1a61c61d0845 1817 }
dcoban 0:1a61c61d0845 1818 else if (ERR_MEM == WriteResult)
dcoban 0:1a61c61d0845 1819 {
dcoban 0:1a61c61d0845 1820 // Failed to perform the write due to out of memory error.
dcoban 0:1a61c61d0845 1821 // Check to see if the send queue if full. If not, half the write
dcoban 0:1a61c61d0845 1822 // size and try again.
dcoban 0:1a61c61d0845 1823 if (0 == tcp_sndqueuelen(m_pPCB))
dcoban 0:1a61c61d0845 1824 {
dcoban 0:1a61c61d0845 1825 break;
dcoban 0:1a61c61d0845 1826 }
dcoban 0:1a61c61d0845 1827 // UNDONE: Rather than half it, subtract the size of a MSS.
dcoban 0:1a61c61d0845 1828 BytesToWrite >>= 1;
dcoban 0:1a61c61d0845 1829 }
dcoban 0:1a61c61d0845 1830 else
dcoban 0:1a61c61d0845 1831 {
dcoban 0:1a61c61d0845 1832 // Received unexpected error.
dcoban 0:1a61c61d0845 1833 break;
dcoban 0:1a61c61d0845 1834 }
dcoban 0:1a61c61d0845 1835 }
dcoban 0:1a61c61d0845 1836
dcoban 0:1a61c61d0845 1837 if (0 == pWriteBuffer->BytesToWrite)
dcoban 0:1a61c61d0845 1838 {
dcoban 0:1a61c61d0845 1839 // There are no more bytes to write from the buffer so advance the
dcoban 0:1a61c61d0845 1840 // header pointer to the next item in the buffer queue.
dcoban 0:1a61c61d0845 1841 m_BufferQueueHead = (m_BufferQueueHead + 1) & 1;
dcoban 0:1a61c61d0845 1842
dcoban 0:1a61c61d0845 1843 // If there are no more bytes to send and the client has finished sending
dcoban 0:1a61c61d0845 1844 // its request then we should attempt to close the connection.
dcoban 0:1a61c61d0845 1845 if (m_HeaderIndex >= ARRAYSIZE(m_HeaderArray) &&
dcoban 0:1a61c61d0845 1846 !m_pRequestHandlerContext &&
dcoban 0:1a61c61d0845 1847 STATE_DONE == m_ParseState)
dcoban 0:1a61c61d0845 1848 {
dcoban 0:1a61c61d0845 1849 TRACE("HTTP: Response send completed to: ");
dcoban 0:1a61c61d0845 1850 NetworkPrintRemoteAddress(m_pPCB);
dcoban 0:1a61c61d0845 1851 TRACE("\r\n");
dcoban 0:1a61c61d0845 1852 CloseConnection();
dcoban 0:1a61c61d0845 1853
dcoban 0:1a61c61d0845 1854 return 1;
dcoban 0:1a61c61d0845 1855 }
dcoban 0:1a61c61d0845 1856 }
dcoban 0:1a61c61d0845 1857
dcoban 0:1a61c61d0845 1858 return 0;
dcoban 0:1a61c61d0845 1859 }
dcoban 0:1a61c61d0845 1860
dcoban 0:1a61c61d0845 1861
dcoban 0:1a61c61d0845 1862 /* Called for a context which was waiting for a buffer when a buffer is freed
dcoban 0:1a61c61d0845 1863 by another connection.
dcoban 0:1a61c61d0845 1864
dcoban 0:1a61c61d0845 1865 Parameters:
dcoban 0:1a61c61d0845 1866 None.
dcoban 0:1a61c61d0845 1867
dcoban 0:1a61c61d0845 1868 Returns:
dcoban 0:1a61c61d0845 1869 Nothing.
dcoban 0:1a61c61d0845 1870 */
dcoban 0:1a61c61d0845 1871 void CHTTPContext::BufferAvailable()
dcoban 0:1a61c61d0845 1872 {
dcoban 0:1a61c61d0845 1873 // Allow the context to allocate the buffer and fill it in with data.
dcoban 0:1a61c61d0845 1874 ReadContent();
dcoban 0:1a61c61d0845 1875
dcoban 0:1a61c61d0845 1876 // Allow the context to send the data that was just read into the
dcoban 0:1a61c61d0845 1877 // buffer.
dcoban 0:1a61c61d0845 1878 SendResponse();
dcoban 0:1a61c61d0845 1879
dcoban 0:1a61c61d0845 1880 // Tell lwIP to send the segments for this PCB as it normally only
dcoban 0:1a61c61d0845 1881 // queues up segments automatically for the PCB whose callback is
dcoban 0:1a61c61d0845 1882 // currently being called.
dcoban 0:1a61c61d0845 1883 tcp_output(m_pPCB);
dcoban 0:1a61c61d0845 1884 }
dcoban 0:1a61c61d0845 1885
dcoban 0:1a61c61d0845 1886
dcoban 0:1a61c61d0845 1887
dcoban 0:1a61c61d0845 1888 /* Constructor */
dcoban 0:1a61c61d0845 1889 CHTTPServer::CHTTPServer()
dcoban 0:1a61c61d0845 1890 {
dcoban 0:1a61c61d0845 1891 m_pHTTPListenPCB = NULL;
dcoban 0:1a61c61d0845 1892 m_pContextWaitingHead = NULL;
dcoban 0:1a61c61d0845 1893 m_pContextWaitingTail = NULL;
dcoban 0:1a61c61d0845 1894 m_pRootPathname = NULL;
dcoban 0:1a61c61d0845 1895 m_pRequestHandler = NULL;
dcoban 0:1a61c61d0845 1896 m_ServerHeaderLength = 0;;
dcoban 0:1a61c61d0845 1897 m_ServerHeader[0] = '\0';
dcoban 0:1a61c61d0845 1898 memset(m_BufferPool, 0, sizeof(m_BufferPool));
dcoban 0:1a61c61d0845 1899 }
dcoban 0:1a61c61d0845 1900
dcoban 0:1a61c61d0845 1901
dcoban 0:1a61c61d0845 1902 /* Attach IRequestHandler to the HTTP server to allow application to add
dcoban 0:1a61c61d0845 1903 custom GET/POST handling.
dcoban 0:1a61c61d0845 1904
dcoban 0:1a61c61d0845 1905 Parameters:
dcoban 0:1a61c61d0845 1906 pHandler is a pointer to the application specific request handler object
dcoban 0:1a61c61d0845 1907 to be used by the HTTP server when it receives GET/POST requests.
dcoban 0:1a61c61d0845 1908
dcoban 0:1a61c61d0845 1909 Returns:
dcoban 0:1a61c61d0845 1910 Returns 0 on successful attachment and a positive value otherwise.
dcoban 0:1a61c61d0845 1911 */
dcoban 0:1a61c61d0845 1912 int CHTTPServer::AttachRequestHandler(IHTTPRequestHandler* pHandler)
dcoban 0:1a61c61d0845 1913 {
dcoban 0:1a61c61d0845 1914 m_pRequestHandler = pHandler;
dcoban 0:1a61c61d0845 1915
dcoban 0:1a61c61d0845 1916 return 0;
dcoban 0:1a61c61d0845 1917 }
dcoban 0:1a61c61d0845 1918
dcoban 0:1a61c61d0845 1919
dcoban 0:1a61c61d0845 1920 /* Initializes the HTTP server using the raw lwIP APIs. This consists of
dcoban 0:1a61c61d0845 1921 creating a PCB (low level lwIP socket), binding it to port 80 and then
dcoban 0:1a61c61d0845 1922 listening for connections on this port. When subsequent connection comes
dcoban 0:1a61c61d0845 1923 into the HTTP server, a callback will be made into the HTTPAccept()
dcoban 0:1a61c61d0845 1924 function that is registered here as well.
dcoban 0:1a61c61d0845 1925
dcoban 0:1a61c61d0845 1926 Parameters:
dcoban 0:1a61c61d0845 1927 pRootPathame is the pathname of the default root directory from which the
dcoban 0:1a61c61d0845 1928 HTTP GET requests are satisfied.
dcoban 0:1a61c61d0845 1929 pServerName is the name of the server to be returned to the HTTP client
dcoban 0:1a61c61d0845 1930 in the Server header.
dcoban 0:1a61c61d0845 1931 BindPort is the TCP/IP port to which the HTTP server should listen for
dcoban 0:1a61c61d0845 1932 incoming requests. The default port for HTTP would be 80.
dcoban 0:1a61c61d0845 1933
dcoban 0:1a61c61d0845 1934 Returns:
dcoban 0:1a61c61d0845 1935 0 on success and a positive error code otherwise.
dcoban 0:1a61c61d0845 1936 */
dcoban 0:1a61c61d0845 1937 int CHTTPServer::Bind(const char* pRootPathname,
dcoban 0:1a61c61d0845 1938 const char* pServerName,
dcoban 0:1a61c61d0845 1939 unsigned short BindPort)
dcoban 0:1a61c61d0845 1940 {
dcoban 0:1a61c61d0845 1941 int Return = 1;
dcoban 0:1a61c61d0845 1942 tcp_pcb* pcb = NULL;
dcoban 0:1a61c61d0845 1943 int Length = -1;
dcoban 0:1a61c61d0845 1944 err_t Result;
dcoban 0:1a61c61d0845 1945
dcoban 0:1a61c61d0845 1946 // Validate parameters.
dcoban 0:1a61c61d0845 1947 assert ( pRootPathname && pServerName );
dcoban 0:1a61c61d0845 1948
dcoban 0:1a61c61d0845 1949 // Create server header string.
dcoban 0:1a61c61d0845 1950 Length = snprintf(m_ServerHeader, ARRAYSIZE(m_ServerHeader), "Server: %s\r\n", pServerName);
dcoban 0:1a61c61d0845 1951 if (Length < 0 || Length >= (int)ARRAYSIZE(m_ServerHeader))
dcoban 0:1a61c61d0845 1952 {
dcoban 0:1a61c61d0845 1953 printf("error: '%s' is too long for the HTTP server name string.\r\n", pServerName);
dcoban 0:1a61c61d0845 1954 goto Error;
dcoban 0:1a61c61d0845 1955 }
dcoban 0:1a61c61d0845 1956 m_ServerHeaderLength = (size_t)Length;
dcoban 0:1a61c61d0845 1957
dcoban 0:1a61c61d0845 1958 // Save away root directory name.
dcoban 0:1a61c61d0845 1959 m_pRootPathname = pRootPathname;
dcoban 0:1a61c61d0845 1960
dcoban 0:1a61c61d0845 1961 // Create the PCB (low level lwIP socket) for the HTTP server to listen to
dcoban 0:1a61c61d0845 1962 // on well known HTTP port 80.
dcoban 0:1a61c61d0845 1963 pcb = tcp_new();
dcoban 0:1a61c61d0845 1964 if (!pcb)
dcoban 0:1a61c61d0845 1965 {
dcoban 0:1a61c61d0845 1966 printf("error: Failed to create new connection for HTTP server to listen upon.\r\n");
dcoban 0:1a61c61d0845 1967 goto Error;
dcoban 0:1a61c61d0845 1968 }
dcoban 0:1a61c61d0845 1969
dcoban 0:1a61c61d0845 1970 // Bind the PCB to port 80.
dcoban 0:1a61c61d0845 1971 Result = tcp_bind(pcb, IP_ADDR_ANY, BindPort);
dcoban 0:1a61c61d0845 1972 if (ERR_OK != Result)
dcoban 0:1a61c61d0845 1973 {
dcoban 0:1a61c61d0845 1974 printf("error: HTTP server failed to bind to port %d.\r\n", BindPort);
dcoban 0:1a61c61d0845 1975 goto Error;
dcoban 0:1a61c61d0845 1976 }
dcoban 0:1a61c61d0845 1977
dcoban 0:1a61c61d0845 1978 // Listen on this PCB.
dcoban 0:1a61c61d0845 1979 m_pHTTPListenPCB = tcp_listen(pcb);
dcoban 0:1a61c61d0845 1980 if (!m_pHTTPListenPCB)
dcoban 0:1a61c61d0845 1981 {
dcoban 0:1a61c61d0845 1982 printf("error: HTTP server failed to listen on port %d.\r\n", BindPort);
dcoban 0:1a61c61d0845 1983 goto Error;
dcoban 0:1a61c61d0845 1984 }
dcoban 0:1a61c61d0845 1985
dcoban 0:1a61c61d0845 1986 // pcb was freed by successful tcp_listen() call.
dcoban 0:1a61c61d0845 1987 pcb = NULL;
dcoban 0:1a61c61d0845 1988
dcoban 0:1a61c61d0845 1989 // When connections come in on port 80, we want lwIP to call our
dcoban 0:1a61c61d0845 1990 // HTTPAccept() function to handle the connection.
dcoban 0:1a61c61d0845 1991 tcp_arg(m_pHTTPListenPCB, this);
dcoban 0:1a61c61d0845 1992 tcp_accept(m_pHTTPListenPCB, HTTPAccept);
dcoban 0:1a61c61d0845 1993
dcoban 0:1a61c61d0845 1994 // Return to the main program since there is nothing left to do until a
dcoban 0:1a61c61d0845 1995 // client tries to make a connection on port 80, at which time lwIP will
dcoban 0:1a61c61d0845 1996 // get the connection packet from the Ethernet driver and make the callback
dcoban 0:1a61c61d0845 1997 // into HTTPAccept().
dcoban 0:1a61c61d0845 1998
dcoban 0:1a61c61d0845 1999 Return = 0;
dcoban 0:1a61c61d0845 2000 Error:
dcoban 0:1a61c61d0845 2001 if (pcb)
dcoban 0:1a61c61d0845 2002 {
dcoban 0:1a61c61d0845 2003 tcp_close(pcb);
dcoban 0:1a61c61d0845 2004 }
dcoban 0:1a61c61d0845 2005 return Return;
dcoban 0:1a61c61d0845 2006 }
dcoban 0:1a61c61d0845 2007
dcoban 0:1a61c61d0845 2008
dcoban 0:1a61c61d0845 2009 /* Called by lwIP whenever a connection is made on the PCB which is listening
dcoban 0:1a61c61d0845 2010 on port 80 for HTTP requests. The main task of this callback is to create
dcoban 0:1a61c61d0845 2011 any necessary state to track this unique HTTP client connection and then
dcoban 0:1a61c61d0845 2012 setup the callbacks to be called when activity occurs on this client
dcoban 0:1a61c61d0845 2013 connection.
dcoban 0:1a61c61d0845 2014
dcoban 0:1a61c61d0845 2015 Parameters:
dcoban 0:1a61c61d0845 2016 pvArg is the value set on the listening PCB through the call to tcp_arg in
dcoban 0:1a61c61d0845 2017 HTTPInit() which is a pointer to the intitialized network object.
dcoban 0:1a61c61d0845 2018 pNewPCB is a pointer to the new PCB that was just allocated by the lwIP
dcoban 0:1a61c61d0845 2019 stack for this new client connection on port 80.
dcoban 0:1a61c61d0845 2020 err is passed in from the lwIP stack to indicate if an error occurred.
dcoban 0:1a61c61d0845 2021
dcoban 0:1a61c61d0845 2022 Returns:
dcoban 0:1a61c61d0845 2023 ERR_MEM if we don't have enough memory for this connection and ERR_OK
dcoban 0:1a61c61d0845 2024 otherwise.
dcoban 0:1a61c61d0845 2025 */
dcoban 0:1a61c61d0845 2026 err_t CHTTPServer::HTTPAccept(void* pvArg, tcp_pcb* pNewPCB, err_t err)
dcoban 0:1a61c61d0845 2027 {
dcoban 0:1a61c61d0845 2028 CHTTPServer* pHTTPServer = (CHTTPServer*)pvArg;
dcoban 0:1a61c61d0845 2029 CHTTPContext* pHTTPContext = NULL;
dcoban 0:1a61c61d0845 2030 (void)err;
dcoban 0:1a61c61d0845 2031
dcoban 0:1a61c61d0845 2032 // Validate parameters.
dcoban 0:1a61c61d0845 2033 assert ( pvArg );
dcoban 0:1a61c61d0845 2034 assert ( pNewPCB );
dcoban 0:1a61c61d0845 2035
dcoban 0:1a61c61d0845 2036 // Let user know that we have just accepted a new connection.
dcoban 0:1a61c61d0845 2037 TRACE("HTTP: Accepting client connection from: ");
dcoban 0:1a61c61d0845 2038 NetworkPrintRemoteAddress(pNewPCB);
dcoban 0:1a61c61d0845 2039 TRACE("\r\n");
dcoban 0:1a61c61d0845 2040
dcoban 0:1a61c61d0845 2041 // Let the lwIP stack know that the HTTP application has successfuly
dcoban 0:1a61c61d0845 2042 // received the client connection on the listening PCB.
dcoban 0:1a61c61d0845 2043 tcp_accepted(pHTTPServer->m_pHTTPListenPCB);
dcoban 0:1a61c61d0845 2044
dcoban 0:1a61c61d0845 2045 // UNDONE: Remove this new call and use a pool instead.
dcoban 0:1a61c61d0845 2046 // Allocate memory to track context for this client connection and
dcoban 0:1a61c61d0845 2047 // associate with the PCB.
dcoban 0:1a61c61d0845 2048 pHTTPContext = new CHTTPContext(pHTTPServer, pNewPCB);
dcoban 0:1a61c61d0845 2049 if (!pHTTPContext)
dcoban 0:1a61c61d0845 2050 {
dcoban 0:1a61c61d0845 2051 TRACE("HTTP: Failed to allocate client context for: ");
dcoban 0:1a61c61d0845 2052 NetworkPrintRemoteAddress(pNewPCB);
dcoban 0:1a61c61d0845 2053 TRACE("\r\n");
dcoban 0:1a61c61d0845 2054
dcoban 0:1a61c61d0845 2055 // lwIP will shutdown this connection when it get back a return value
dcoban 0:1a61c61d0845 2056 // other than ERR_OK.
dcoban 0:1a61c61d0845 2057 return ERR_MEM;
dcoban 0:1a61c61d0845 2058 }
dcoban 0:1a61c61d0845 2059
dcoban 0:1a61c61d0845 2060 return ERR_OK;
dcoban 0:1a61c61d0845 2061 }
dcoban 0:1a61c61d0845 2062
dcoban 0:1a61c61d0845 2063
dcoban 0:1a61c61d0845 2064 /* Removes the specified context from the linked list of waiting contexts.
dcoban 0:1a61c61d0845 2065
dcoban 0:1a61c61d0845 2066 Parameters:
dcoban 0:1a61c61d0845 2067 pHTTPContext is a pointer to the context object for the client connection
dcoban 0:1a61c61d0845 2068 to be removed.
dcoban 0:1a61c61d0845 2069
dcoban 0:1a61c61d0845 2070 Returns:
dcoban 0:1a61c61d0845 2071 Nothing.
dcoban 0:1a61c61d0845 2072 */
dcoban 0:1a61c61d0845 2073 void CHTTPServer::RemoveWaitingContext(CHTTPContext* pHTTPContext)
dcoban 0:1a61c61d0845 2074 {
dcoban 0:1a61c61d0845 2075 // Find this node in the waiting queue and remove it.
dcoban 0:1a61c61d0845 2076 CHTTPContext* pPrev = NULL;
dcoban 0:1a61c61d0845 2077 CHTTPContext* pCurr = m_pContextWaitingHead;
dcoban 0:1a61c61d0845 2078 while(pCurr)
dcoban 0:1a61c61d0845 2079 {
dcoban 0:1a61c61d0845 2080 CHTTPContext* pNext = pCurr->GetNext();
dcoban 0:1a61c61d0845 2081
dcoban 0:1a61c61d0845 2082 if (pCurr == pHTTPContext)
dcoban 0:1a61c61d0845 2083 {
dcoban 0:1a61c61d0845 2084 // Found this context. Now remove it and exit loop.
dcoban 0:1a61c61d0845 2085 pCurr->RemovedFromWaitingList(pPrev);
dcoban 0:1a61c61d0845 2086 if (!pPrev)
dcoban 0:1a61c61d0845 2087 {
dcoban 0:1a61c61d0845 2088 // This node was at the head so update the head pointer.
dcoban 0:1a61c61d0845 2089 m_pContextWaitingHead = pNext;
dcoban 0:1a61c61d0845 2090 }
dcoban 0:1a61c61d0845 2091 if (!pNext)
dcoban 0:1a61c61d0845 2092 {
dcoban 0:1a61c61d0845 2093 // This node was at the tail so reset the tail to previous node.
dcoban 0:1a61c61d0845 2094 m_pContextWaitingTail = pPrev;
dcoban 0:1a61c61d0845 2095 }
dcoban 0:1a61c61d0845 2096 break;
dcoban 0:1a61c61d0845 2097 }
dcoban 0:1a61c61d0845 2098 pPrev = pCurr;
dcoban 0:1a61c61d0845 2099 pCurr = pNext;
dcoban 0:1a61c61d0845 2100 }
dcoban 0:1a61c61d0845 2101 // We should always find this context in the list.
dcoban 0:1a61c61d0845 2102 assert ( pCurr == pHTTPContext );
dcoban 0:1a61c61d0845 2103 }
dcoban 0:1a61c61d0845 2104
dcoban 0:1a61c61d0845 2105
dcoban 0:1a61c61d0845 2106 /* Attempts to allocate a SBuffer object into which content can be placed for
dcoban 0:1a61c61d0845 2107 sending back to the HTTP client. If it fails to find a free buffer in the
dcoban 0:1a61c61d0845 2108 server's pool then it will add the client context to a queue and return
dcoban 0:1a61c61d0845 2109 NULL.
dcoban 0:1a61c61d0845 2110
dcoban 0:1a61c61d0845 2111 Parameters:
dcoban 0:1a61c61d0845 2112 pHTTPContext is a pointer to the context asking for a buffer object.
dcoban 0:1a61c61d0845 2113
dcoban 0:1a61c61d0845 2114 Returns:
dcoban 0:1a61c61d0845 2115 A pointer to a free SBuffer object or NULL if none are free.
dcoban 0:1a61c61d0845 2116 */
dcoban 0:1a61c61d0845 2117 SBuffer* CHTTPServer::AllocateBuffer(CHTTPContext* pHTTPContext)
dcoban 0:1a61c61d0845 2118 {
dcoban 0:1a61c61d0845 2119 CHTTPContext* pPrev = NULL;
dcoban 0:1a61c61d0845 2120
dcoban 0:1a61c61d0845 2121 // Validate parameters.
dcoban 0:1a61c61d0845 2122 assert ( pHTTPContext );
dcoban 0:1a61c61d0845 2123
dcoban 0:1a61c61d0845 2124 // Local variables.
dcoban 0:1a61c61d0845 2125 size_t i;
dcoban 0:1a61c61d0845 2126
dcoban 0:1a61c61d0845 2127 // Just return NULL if this context is already waiting for a buffer.
dcoban 0:1a61c61d0845 2128 if (pHTTPContext->IsWaitingForBuffer())
dcoban 0:1a61c61d0845 2129 {
dcoban 0:1a61c61d0845 2130 return NULL;
dcoban 0:1a61c61d0845 2131 }
dcoban 0:1a61c61d0845 2132
dcoban 0:1a61c61d0845 2133 // Search for a free buffer in the pool.
dcoban 0:1a61c61d0845 2134 for (i = 0 ; i < ARRAYSIZE(m_BufferPool) ; i++)
dcoban 0:1a61c61d0845 2135 {
dcoban 0:1a61c61d0845 2136 // A buffer is free if it has no bytes left to write to the connection
dcoban 0:1a61c61d0845 2137 // and the remote machine has acknowledged all previously written bytes
dcoban 0:1a61c61d0845 2138 // from this buffer.
dcoban 0:1a61c61d0845 2139 SBuffer* pBuffer = &(m_BufferPool[i]);
dcoban 0:1a61c61d0845 2140
dcoban 0:1a61c61d0845 2141 if (0 == pBuffer->BytesToWrite &&
dcoban 0:1a61c61d0845 2142 0 == pBuffer->UnacknowledgedBytes)
dcoban 0:1a61c61d0845 2143 {
dcoban 0:1a61c61d0845 2144 return pBuffer;
dcoban 0:1a61c61d0845 2145 }
dcoban 0:1a61c61d0845 2146 }
dcoban 0:1a61c61d0845 2147
dcoban 0:1a61c61d0845 2148 // Get here if there wasn't a free buffer in the pool so add this context
dcoban 0:1a61c61d0845 2149 // to the queue to be serviced later.
dcoban 0:1a61c61d0845 2150 assert (!pHTTPContext->GetNext());
dcoban 0:1a61c61d0845 2151 if (m_pContextWaitingTail)
dcoban 0:1a61c61d0845 2152 {
dcoban 0:1a61c61d0845 2153 // Add to end of list.
dcoban 0:1a61c61d0845 2154 pPrev = m_pContextWaitingTail;
dcoban 0:1a61c61d0845 2155 m_pContextWaitingTail = pHTTPContext;
dcoban 0:1a61c61d0845 2156 }
dcoban 0:1a61c61d0845 2157 else
dcoban 0:1a61c61d0845 2158 {
dcoban 0:1a61c61d0845 2159 // Adding entry to empty queue.
dcoban 0:1a61c61d0845 2160 assert (!m_pContextWaitingHead);
dcoban 0:1a61c61d0845 2161
dcoban 0:1a61c61d0845 2162 m_pContextWaitingHead = pHTTPContext;
dcoban 0:1a61c61d0845 2163 m_pContextWaitingTail = pHTTPContext;
dcoban 0:1a61c61d0845 2164 }
dcoban 0:1a61c61d0845 2165 pHTTPContext->AddToWaitingList(pPrev);
dcoban 0:1a61c61d0845 2166
dcoban 0:1a61c61d0845 2167 // Let calling context know that it will have to wait until later for a
dcoban 0:1a61c61d0845 2168 // buffer.
dcoban 0:1a61c61d0845 2169 return NULL;
dcoban 0:1a61c61d0845 2170 }
dcoban 0:1a61c61d0845 2171
dcoban 0:1a61c61d0845 2172
dcoban 0:1a61c61d0845 2173 /* Frees a SBuffer object back into the server's pool. If there is a client
dcoban 0:1a61c61d0845 2174 context waiting in the queue, then callback into the context and let
dcoban 0:1a61c61d0845 2175 it use the buffer now that it is free.
dcoban 0:1a61c61d0845 2176
dcoban 0:1a61c61d0845 2177 Parameters:
dcoban 0:1a61c61d0845 2178 pBuffer is a pointer to the buffer to be freed.
dcoban 0:1a61c61d0845 2179
dcoban 0:1a61c61d0845 2180 Returns:
dcoban 0:1a61c61d0845 2181 Nothing.
dcoban 0:1a61c61d0845 2182 */
dcoban 0:1a61c61d0845 2183 void CHTTPServer::FreeBuffer(SBuffer* pBuffer)
dcoban 0:1a61c61d0845 2184 {
dcoban 0:1a61c61d0845 2185 // Validate parameters.
dcoban 0:1a61c61d0845 2186 assert ( pBuffer );
dcoban 0:1a61c61d0845 2187
dcoban 0:1a61c61d0845 2188 // The SBuffer shouldn't be in use when this routine is called.
dcoban 0:1a61c61d0845 2189 assert ( 0 == pBuffer->BytesToWrite );
dcoban 0:1a61c61d0845 2190 assert ( 0 == pBuffer->UnacknowledgedBytes );
dcoban 0:1a61c61d0845 2191
dcoban 0:1a61c61d0845 2192 // See if there are other client connection waiting for a buffer to become
dcoban 0:1a61c61d0845 2193 // free. If so, give it an apportunity to make use of this one.
dcoban 0:1a61c61d0845 2194 if (m_pContextWaitingHead)
dcoban 0:1a61c61d0845 2195 {
dcoban 0:1a61c61d0845 2196 CHTTPContext* pHTTPContext = m_pContextWaitingHead;
dcoban 0:1a61c61d0845 2197
dcoban 0:1a61c61d0845 2198 // Remove the context from the waiting list.
dcoban 0:1a61c61d0845 2199 m_pContextWaitingHead = pHTTPContext->GetNext();
dcoban 0:1a61c61d0845 2200 if (!m_pContextWaitingHead)
dcoban 0:1a61c61d0845 2201 {
dcoban 0:1a61c61d0845 2202 // We just emptied the list so clear tail pointer as well.
dcoban 0:1a61c61d0845 2203 assert ( m_pContextWaitingTail == pHTTPContext );
dcoban 0:1a61c61d0845 2204
dcoban 0:1a61c61d0845 2205 m_pContextWaitingTail = NULL;
dcoban 0:1a61c61d0845 2206 }
dcoban 0:1a61c61d0845 2207
dcoban 0:1a61c61d0845 2208 // Let context know that it is no longer in a list.
dcoban 0:1a61c61d0845 2209 pHTTPContext->RemovedFromWaitingList(NULL);
dcoban 0:1a61c61d0845 2210 pHTTPContext->BufferAvailable();
dcoban 0:1a61c61d0845 2211 }
dcoban 0:1a61c61d0845 2212 }
dcoban 0:1a61c61d0845 2213
dcoban 0:1a61c61d0845 2214
dcoban 0:1a61c61d0845 2215 /* Prints out the remote machine IP address and port number.
dcoban 0:1a61c61d0845 2216
dcoban 0:1a61c61d0845 2217 Parameters:
dcoban 0:1a61c61d0845 2218 pPCB is a pointer to the TCP protocol control block.
dcoban 0:1a61c61d0845 2219
dcoban 0:1a61c61d0845 2220 Returns:
dcoban 0:1a61c61d0845 2221 Nothing.
dcoban 0:1a61c61d0845 2222 */
dcoban 0:1a61c61d0845 2223 static void NetworkPrintRemoteAddress(tcp_pcb* pPCB)
dcoban 0:1a61c61d0845 2224 {
dcoban 0:1a61c61d0845 2225 // Validate paramters.
dcoban 0:1a61c61d0845 2226 assert ( pPCB );
dcoban 0:1a61c61d0845 2227
dcoban 0:1a61c61d0845 2228 if (HTTP_TRACE)
dcoban 0:1a61c61d0845 2229 {
dcoban 0:1a61c61d0845 2230 SNetwork_PrintAddress(&pPCB->remote_ip);
dcoban 0:1a61c61d0845 2231 printf(":%u", pPCB->remote_port);
dcoban 0:1a61c61d0845 2232 }
dcoban 0:1a61c61d0845 2233 }