Web server based weather station using Sparkfun Weather Meters.

Dependencies:   FatFileSystem mbed WeatherMeters SDFileSystem

Committer:
AdamGreen
Date:
Sat Feb 25 03:28:05 2012 +0000
Revision:
1:c7958aa34fa1
Parent:
0:616601bde9fb
Use published libraries where possible.

Who changed what in which revision?

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