• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* ------------------------------------------------------------------
2  * Copyright (C) 1998-2009 PacketVideo
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
13  * express or implied.
14  * See the License for the specific language governing permissions
15  * and limitations under the License.
16  * -------------------------------------------------------------------
17  */
18 #include "http_parser.h"
19 #include "http_parser_internal.h"
20 #include "oscl_string_utils.h"
21 #include "oscl_string_containers.h"
22 
23 // Use default DLL entry point for Symbian
24 #include "oscl_dll.h"
25 
OSCL_DLL_ENTRY_POINT_DEFAULT()26 OSCL_DLL_ENTRY_POINT_DEFAULT()
27 
28 
29 // three inline functions for multiple class implementation
30 inline bool isLetter(const char c)
31 {
32     return ((c >= 65 && c <= 90) || (c >= 97 && c <= 122) || (c == 45)); // A-Z, or a-z or -
33 }
34 
isDigit(const char c)35 inline bool isDigit(const char c)
36 {
37     return (c >= 48 && c <= 57);
38 }
39 
isHexDigit(const char c)40 inline bool isHexDigit(const char c)
41 {
42     return (isDigit(c) || (c >= 65 && c <= 70) || (c >= 97 && c <= 102)); // 0-9, A-F or a-f
43 }
44 
45 
46 ////////////////////////////////////////////////////////////////////////////////////
47 ////// HTTPParser implementation ///////////////////////////////////////////////////
48 ////////////////////////////////////////////////////////////////////////////////////
49 
parse(const OsclRefCounterMemFrag & aInputDataStream,RefCountHTTPEntityUnit & aEntityUnit)50 OSCL_EXPORT_REF int32 HTTPParser::parse(const OsclRefCounterMemFrag &aInputDataStream, RefCountHTTPEntityUnit &aEntityUnit)
51 {
52     if (!iParserInput->push_back((OsclRefCounterMemFrag &)aInputDataStream)) // not a new data fragment
53         return PARSE_NEED_MORE_DATA;
54 
55     if (!aEntityUnit.empty()) aEntityUnit.clear();
56     if (!iHeader->isParsed()) return iHeader->parse(*iParserInput, aEntityUnit);
57 
58     return parseEntityBody(aEntityUnit);
59 }
60 
61 ////////////////////////////////////////////////////////////////////////////////////
doSanityCheckForResponseHeader()62 OSCL_EXPORT_REF int32 HTTPParser::doSanityCheckForResponseHeader()
63 {
64     if (!iHeader->isParsed()) return PARSE_HEADER_NOT_PARSED_YET;
65     return iHeader->doSanityCheckForResponseHeader();
66 }
67 
68 
69 ////////////////////////////////////////////////////////////////////////////////////
70 // assume aFieldKeyList has enough space to hold all parsed key list, if it is small, it will cause crash
71 // since we have no way to check the space
getFieldKeyListInHeader(StrPtrLen * & aFieldKeyList)72 OSCL_EXPORT_REF uint32 HTTPParser::getFieldKeyListInHeader(StrPtrLen *&aFieldKeyList)
73 {
74     return iHeader->getKeyValuesStore()->getCurrentKeyList(aFieldKeyList); // iHeader should be created successfully in factory method
75 }
76 
77 ////////////////////////////////////////////////////////////////////////////////////
getField(const StrCSumPtrLen & aNewFieldName,StrPtrLen & aNewFieldValue,uint32 index)78 OSCL_EXPORT_REF bool HTTPParser::getField(const StrCSumPtrLen &aNewFieldName, StrPtrLen &aNewFieldValue, uint32 index)
79 {
80     return iHeader->getField(aNewFieldName, aNewFieldValue, index);
81 }
82 
83 ////////////////////////////////////////////////////////////////////////////////////
getNumberOfFieldsByKey(const StrCSumPtrLen & aNewFieldName)84 OSCL_EXPORT_REF uint32 HTTPParser::getNumberOfFieldsByKey(const StrCSumPtrLen &aNewFieldName)
85 {
86     return iHeader->getNumberOfFieldsByKey(aNewFieldName);
87 }
88 
89 ////////////////////////////////////////////////////////////////////////////////////
getTotalFieldsInHeader()90 OSCL_EXPORT_REF uint32 HTTPParser::getTotalFieldsInHeader()
91 {
92     return iHeader->getNumFields();
93 }
94 
95 ////////////////////////////////////////////////////////////////////////////////////
getHTTPStatusCode()96 OSCL_EXPORT_REF uint32 HTTPParser::getHTTPStatusCode()
97 {
98     return iHeader->getStatusCode();
99 }
100 
101 ////////////////////////////////////////////////////////////////////////////////////
getContentInfo(HTTPContentInfo & aContentInfo)102 OSCL_EXPORT_REF void HTTPParser::getContentInfo(HTTPContentInfo &aContentInfo)
103 {
104     aContentInfo.clear();
105     if (iContentInfo) iContentInfo->get(aContentInfo);
106 }
107 
108 
109 ////////////////////////////////////////////////////////////////////////////////////
110 // reset the parser to parse a new HTTP response
reset()111 OSCL_EXPORT_REF void HTTPParser::reset()
112 {
113     if (iParserInput) iParserInput->clear();
114     if (iContentInfo) iContentInfo->clear();
115     if (iHeader) iHeader->reset();
116 
117     // delete iEntityBody
118     if (iEntityBody) OSCL_DELETE(iEntityBody);
119     iEntityBody = NULL;
120 }
121 
122 ////////////////////////////////////////////////////////////////////////////////////
123 // factory method
create()124 OSCL_EXPORT_REF HTTPParser* HTTPParser::create()
125 {
126     HTTPParser *parser = OSCL_NEW(HTTPParser, ());
127     if (!parser) return NULL;
128     if (!parser->construct())
129     {
130         OSCL_DELETE(parser);
131         return NULL;
132     }
133     return parser;
134 }
135 
136 ////////////////////////////////////////////////////////////////////////////////////
construct()137 bool HTTPParser::construct()
138 {
139     reset();
140 
141     // create the component objects
142     if ((iContentInfo = OSCL_NEW(HTTPContentInfoInternal, ())) == NULL) return false;
143     if ((iParserInput = HTTPParserInput::create()) == NULL) return false;
144     if ((iHeader = HTTPParserHeaderObject::create(iContentInfo)) == NULL) return false;
145     return true;
146 }
147 
148 ////////////////////////////////////////////////////////////////////////////////////
149 // destructor
~HTTPParser()150 OSCL_EXPORT_REF HTTPParser::~HTTPParser()
151 {
152     reset();
153 
154     // delete iParserInput
155     if (iParserInput) OSCL_DELETE(iParserInput);
156     iParserInput = NULL;
157 
158     // delete iContentInfo
159     if (iContentInfo) OSCL_DELETE(iContentInfo);
160     iContentInfo = NULL;
161 
162     // delete iHeader
163     if (iHeader) OSCL_DELETE(iHeader);
164     iHeader = NULL;
165 
166     // delete iEntityBody
167     if (iEntityBody) OSCL_DELETE(iEntityBody);
168     iEntityBody = NULL;
169 }
170 
171 ////////////////////////////////////////////////////////////////////////////////////
parseEntityBody(RefCountHTTPEntityUnit & aEntityUnit)172 int32 HTTPParser::parseEntityBody(RefCountHTTPEntityUnit &aEntityUnit)
173 {
174     if (!iHeader || !iHeader->isParsed()) return PARSE_HEADER_NOT_PARSED_YET;
175     if (iHeader->isWholeResponseParsed()) return PARSE_SUCCESS_END_OF_MESSAGE;
176 
177     if (!iEntityBody)
178     {
179         // create iEntityBody
180         // After parsing the header, we should get right content type, iContentType
181         if (iContentInfo->getContentType() == HTTP_CONTENT_NORMAL)
182             iEntityBody = OSCL_NEW(HTTPParserNormalContentObject, (iHeader->getKeyValuesStore(), iHeader->getAllocator(), iContentInfo));
183         else if (iContentInfo->getContentType() == HTTP_CONTENT_NULTIPART)
184             iEntityBody = OSCL_NEW(HTTPParserMultipartContentObject, (iHeader->getKeyValuesStore(), iHeader->getAllocator(), iContentInfo));
185         else if (iContentInfo->getContentType() == HTTP_CONTENT_CHUNKED_TRANSFER_ENCODING)
186             iEntityBody = OSCL_NEW(HTTPParserCTEContentObject, (iHeader->getKeyValuesStore(), iHeader->getAllocator(), iContentInfo));
187 
188         if (!iEntityBody) return PARSE_MEMORY_ALLOCATION_FAILURE;
189     }
190 
191     return iEntityBody->parse(*iParserInput, aEntityUnit);
192 }
193 
194 
195 /////////////////////////////////////////////////////////////////////////////////////
196 ////////// HTTPContentInfoInternal Implementation ///////////////////////////////////////////
197 /////////////////////////////////////////////////////////////////////////////////////
parseContentInfo(StringKeyValueStore & aKeyValueStore)198 bool HTTPContentInfoInternal::parseContentInfo(StringKeyValueStore &aKeyValueStore)
199 {
200     // Content-Length
201     StrCSumPtrLen contenLengthKey("Content-Length");
202     StrPtrLen contentLengthValue;
203     if (aKeyValueStore.getValueByKey(contenLengthKey, contentLengthValue))
204     {
205         // has content length
206         PV_atoi(contentLengthValue.c_str(), 'd', iContentLength);
207     }
208 
209     // Content-Type
210     StrCSumPtrLen contentTypeKey("Content-Type");
211     StrPtrLen contentTypeValue;
212     if (aKeyValueStore.getValueByKey(contentTypeKey, contentTypeValue))
213     {
214         // has content type
215         if (!parseContentType(contentTypeValue)) return false;
216     }
217 
218     // Content-Range
219     StrCSumPtrLen contentRangeKey("Content-Range");
220     StrPtrLen contentRangeValue;
221     if (aKeyValueStore.getValueByKey(contentRangeKey, contentRangeValue))
222     {
223         // has content type
224         parseContentRange(contentRangeValue);
225     }
226 
227     // check Chunked Transfer-Encoding, "Transfer-Encoding : chunked"
228     StrCSumPtrLen transferEncodingKey("Transfer-Encoding");
229     StrPtrLen transferEncodingValue;
230     if (aKeyValueStore.getValueByKey(transferEncodingKey, transferEncodingValue))
231     {
232         // has content type
233         verifyTransferEncoding(transferEncodingValue);
234     }
235     return true;
236 }
237 
238 /////////////////////////////////////////////////////////////////////////////////////
parseContentRange(const StrPtrLen & aContentRange)239 void HTTPContentInfoInternal::parseContentRange(const StrPtrLen &aContentRange)
240 {
241     char *ptr = (char *)aContentRange.c_str();
242     uint32 len = aContentRange.length();
243 
244     while (!isLetter(*ptr) && len > 0)
245     {
246         ptr++;
247         len--;
248     }
249     OSCL_FastString bytesString(_STRLIT_CHAR("bytes"));
250     if (len <= oscl_strlen(bytesString.get_cstr())) return;
251 
252     if (((ptr[0] | OSCL_ASCII_CASE_MAGIC_BIT) == 'b') &&
253             ((ptr[1] | OSCL_ASCII_CASE_MAGIC_BIT) == 'y') &&
254             ((ptr[2] | OSCL_ASCII_CASE_MAGIC_BIT) == 't') &&
255             ((ptr[3] | OSCL_ASCII_CASE_MAGIC_BIT) == 'e') &&
256             ((ptr[4] | OSCL_ASCII_CASE_MAGIC_BIT) == 's'))
257     {
258         // find "bytes"
259         ptr += 5;
260         if ((len -= 5) <= 0) return;
261 
262         // get the left side of the range
263         while (!isDigit(*ptr) && len > 0)
264         {
265             ptr++;
266             len--;
267         }
268         char *start_ptr = ptr;
269         uint32 start_len = len;
270         while (isDigit(*ptr) && len > 0)
271         {
272             ptr++;
273             len--;
274         }
275         PV_atoi(start_ptr, 'd', start_len - len, iContentRangeLeft);
276 
277         // get the right side of the range
278         while (!isDigit(*ptr) && len > 0)
279         {
280             ptr++;
281             len--;
282         }
283         start_ptr = ptr;
284         start_len = len;
285         while (isDigit(*ptr) && len > 0)
286         {
287             ptr++;
288             len--;
289         }
290         PV_atoi(start_ptr, 'd', start_len - len, iContentRangeRight);
291 
292         // get the content length
293         while (!isDigit(*ptr) && len > 0)
294         {
295             ptr++;
296             len--;
297         }
298         start_ptr = ptr;
299         start_len = len;
300         while (isDigit(*ptr) && len > 0)
301         {
302             ptr++;
303             len--;
304         }
305         PV_atoi(start_ptr, 'd', start_len - len, iContentLength);
306     }
307 }
308 
309 /////////////////////////////////////////////////////////////////////////////////////
parseContentType(const StrPtrLen & aContentType)310 bool HTTPContentInfoInternal::parseContentType(const StrPtrLen &aContentType)
311 {
312     // identify multipart content type and chunked transfer-encoding
313     // Content-type: multipart/byteranges; boundary=THIS_STRING_SEPARATES
314     char *ptr = (char *)aContentType.c_str();
315     uint32 len = aContentType.length();
316 
317     // eat non-letter characters
318     while (!isLetter(*ptr) && len > 0)
319     {
320         ptr++;
321         len--;
322     }
323     OSCL_FastString typeString(_STRLIT_CHAR("multipart/byteranges"));
324     if (len <= oscl_strlen(typeString.get_cstr())) return true;
325 
326     if (((ptr[0] | OSCL_ASCII_CASE_MAGIC_BIT) == 'm') &&
327             ((ptr[1] | OSCL_ASCII_CASE_MAGIC_BIT) == 'u') &&
328             ((ptr[2] | OSCL_ASCII_CASE_MAGIC_BIT) == 'l') &&
329             ((ptr[3] | OSCL_ASCII_CASE_MAGIC_BIT) == 't') &&
330             ((ptr[4] | OSCL_ASCII_CASE_MAGIC_BIT) == 'i') &&
331             ((ptr[5] | OSCL_ASCII_CASE_MAGIC_BIT) == 'p') &&
332             ((ptr[6] | OSCL_ASCII_CASE_MAGIC_BIT) == 'a') &&
333             ((ptr[7] | OSCL_ASCII_CASE_MAGIC_BIT) == 'r') &&
334             ((ptr[8] | OSCL_ASCII_CASE_MAGIC_BIT) == 't') &&
335             (ptr[9]                               == '/') &&
336             ((ptr[10] | OSCL_ASCII_CASE_MAGIC_BIT) == 'b') &&
337             ((ptr[11] | OSCL_ASCII_CASE_MAGIC_BIT) == 'y') &&
338             ((ptr[12] | OSCL_ASCII_CASE_MAGIC_BIT) == 't') &&
339             ((ptr[13] | OSCL_ASCII_CASE_MAGIC_BIT) == 'e') &&
340             ((ptr[14] | OSCL_ASCII_CASE_MAGIC_BIT) == 'r') &&
341             ((ptr[15] | OSCL_ASCII_CASE_MAGIC_BIT) == 'a') &&
342             ((ptr[16] | OSCL_ASCII_CASE_MAGIC_BIT) == 'n') &&
343             ((ptr[17] | OSCL_ASCII_CASE_MAGIC_BIT) == 'g') &&
344             ((ptr[18] | OSCL_ASCII_CASE_MAGIC_BIT) == 'e') &&
345             ((ptr[19] | OSCL_ASCII_CASE_MAGIC_BIT) == 's'))
346     {
347         // find "multipart/byteranges"
348         // constinue search "boundary"
349         ptr += 20;
350         if ((len -= 20) <= 8) return false;
351 
352         while (!isLetter(*ptr) && len > 0)
353         {
354             ptr++;
355             len--;
356         }
357         if (((ptr[0] | OSCL_ASCII_CASE_MAGIC_BIT) == 'b') &&
358                 ((ptr[1] | OSCL_ASCII_CASE_MAGIC_BIT) == 'o') &&
359                 ((ptr[2] | OSCL_ASCII_CASE_MAGIC_BIT) == 'u') &&
360                 ((ptr[3] | OSCL_ASCII_CASE_MAGIC_BIT) == 'n') &&
361                 ((ptr[4] | OSCL_ASCII_CASE_MAGIC_BIT) == 'd') &&
362                 ((ptr[5] | OSCL_ASCII_CASE_MAGIC_BIT) == 'a') &&
363                 ((ptr[6] | OSCL_ASCII_CASE_MAGIC_BIT) == 'r') &&
364                 ((ptr[7] | OSCL_ASCII_CASE_MAGIC_BIT) == 'y'))
365         {
366             // find "boundary"
367             ptr += 8;
368             if ((len -= 8) <= 0) return false;
369 
370             // find "="
371             while (*ptr != HTTP_CHAR_EQUAL && len > 0)
372             {
373                 ptr++;
374                 len--;
375             }
376             if (len <= 0) return false;
377             ptr++;
378 
379             while ((*ptr == HTTP_CHAR_SPACE || *ptr == HTTP_CHAR_TAB) && len > 0)
380             {
381                 ptr++;
382                 len--;
383             }
384             char *boundaryStartPtr = ptr;
385             uint32 start_len = (uint32)len;
386             while (!(*ptr == HTTP_CHAR_NULL || *ptr == HTTP_CHAR_SPACE || *ptr == HTTP_CHAR_TAB ||
387                      *ptr == HTTP_CHAR_CR   || *ptr == HTTP_CHAR_LF) && len > 0)
388             {
389                 ptr++;
390                 len--;
391             }
392             iContentType = HTTP_CONTENT_NULTIPART;
393             return copyBoundaryString(boundaryStartPtr, start_len - (uint32)len);
394         }
395     }
396     return true;
397 }
398 
399 /////////////////////////////////////////////////////////////////////////////////////
verifyTransferEncoding(const StrPtrLen & aTransferEncodingValue)400 void HTTPContentInfoInternal::verifyTransferEncoding(const StrPtrLen &aTransferEncodingValue)
401 {
402     char *ptr = (char *)aTransferEncodingValue.c_str();
403     uint32 len = aTransferEncodingValue.length();
404 
405     // eat non-letter characters
406     while (!isLetter(*ptr) && len > 0)
407     {
408         ptr++;
409         len--;
410     }
411     OSCL_FastString chunkedString(_STRLIT_CHAR("chunked"));
412     if (len < oscl_strlen(chunkedString.get_cstr())) return;
413 
414     if (((ptr[0] | OSCL_ASCII_CASE_MAGIC_BIT) == 'c') &&
415             ((ptr[1] | OSCL_ASCII_CASE_MAGIC_BIT) == 'h') &&
416             ((ptr[2] | OSCL_ASCII_CASE_MAGIC_BIT) == 'u') &&
417             ((ptr[3] | OSCL_ASCII_CASE_MAGIC_BIT) == 'n') &&
418             ((ptr[4] | OSCL_ASCII_CASE_MAGIC_BIT) == 'k') &&
419             ((ptr[5] | OSCL_ASCII_CASE_MAGIC_BIT) == 'e') &&
420             ((ptr[6] | OSCL_ASCII_CASE_MAGIC_BIT) == 'd'))
421     {
422         // find "chunked"
423         iContentType = HTTP_CONTENT_CHUNKED_TRANSFER_ENCODING;
424     }
425 }
426 
copyBoundaryString(const char * aBoundaryString,const uint32 aBoundaryStringLength)427 bool HTTPContentInfoInternal::copyBoundaryString(const char* aBoundaryString, const uint32 aBoundaryStringLength)
428 {
429     // allocate memory for boundary string
430     if (!iBoundaryBuffer) iBoundaryBuffer = new char[aBoundaryStringLength+1];
431     if (!iBoundaryBuffer) return false;
432     if (!aBoundaryString) return false;
433 
434     oscl_memcpy(iBoundaryBuffer, aBoundaryString, aBoundaryStringLength);
435     iBoundaryBuffer[aBoundaryStringLength] = HTTP_CHAR_NULL;
436     iBoundary.setPtrLen(iBoundaryBuffer, aBoundaryStringLength);
437     return true;
438 }
439 
440 ////////////////////////////////////////////////////////////////////////////////////
parseBoudaryLine(HTTPMemoryFragment & aInputLineData,bool & isFinalBoundary)441 bool HTTPContentInfoInternal::parseBoudaryLine(HTTPMemoryFragment &aInputLineData, bool &isFinalBoundary)
442 {
443     isFinalBoundary = false;
444 
445     // check boundary line : --BOUNDARY STRING
446     char *ptr = (char *)aInputLineData.getPtr();
447     int32 len = aInputLineData.getAvailableSpace();
448     while (*ptr != HTTP_CHAR_MINUS && len > 0)
449     {
450         ptr++;
451         len--;
452     }
453     if (len <= 0) return false; // this line is not boundary line
454     if (*(++ptr) != HTTP_CHAR_MINUS) return false; // not "--"
455     ptr++;
456     len -= 2;
457     if (len < iBoundary.length()) return false;
458     char *boundaryString = (char *)iBoundary.c_str();
459     int32 i = 0;
460     for (i = 0; i < iBoundary.length(); i++)
461     {
462         if (ptr[i] != boundaryString[i]) return false;
463     }
464 
465     // check the last "--" as the flag of final boundary string
466     ptr += iBoundary.length();
467     len -= iBoundary.length();
468     if (len >= 2)
469     {
470         if (*ptr == HTTP_CHAR_MINUS && *(ptr + 1) == HTTP_CHAR_MINUS)
471         {
472             isFinalBoundary = true;
473         }
474     }
475     return true;
476 }
477 
478 
479 /////////////////////////////////////////////////////////////////////////////////////
480 ////////// HTTPParserInput Implementation ///////////////////////////////////////////
481 /////////////////////////////////////////////////////////////////////////////////////
create()482 HTTPParserInput* HTTPParserInput::create()
483 {
484     HTTPParserInput *parserInput = OSCL_NEW(HTTPParserInput, ());
485     if (!parserInput) return NULL;
486     if (!parserInput->construct())
487     {
488         OSCL_DELETE(parserInput);
489         return NULL;
490     }
491     return parserInput;
492 }
493 
construct()494 bool HTTPParserInput::construct()
495 {
496     // create iLineBuffer
497     OsclMemAllocator alloc;
498     iLineBuffer = (char *)alloc.allocate(iLineBufferSize);
499     if (!iLineBuffer) return false;
500 
501     int32 err = 0;
502     OSCL_TRY(err,
503              iDataInQueue.reserve(DATA_QUEUE_VECTOR_RESERVE_SIZE);
504              iDataOutQueue.reserve(DATA_QUEUE_VECTOR_RESERVE_SIZE);
505             );
506     return (err == 0);
507 
508 }
509 
~HTTPParserInput()510 HTTPParserInput::~HTTPParserInput()
511 {
512     clear();
513     iDataInQueue.clear();
514     iDataOutQueue.clear();
515     if (iLineBuffer)
516     {
517         OsclMemAllocator alloc;
518         alloc.deallocate(iLineBuffer);
519         iLineBuffer = NULL;
520     }
521 }
522 
push_back(OsclRefCounterMemFrag & aFrag)523 bool HTTPParserInput::push_back(OsclRefCounterMemFrag &aFrag)
524 {
525     if (!aFrag.getMemFragPtr() || !aFrag.getRefCounter())  // empty fragment
526     {
527         return (!iDataInQueue.empty()); // true for iDataInQueue not being empty
528     }
529 
530     // check if this input is same to the previous one
531     if (!iDataInQueue.empty())
532     {
533         if ((uint8*)aFrag.getMemFragPtr() == (uint8*)iDataInQueue[iDataInQueue.size()-1].getMemFragPtr())
534         {
535             return true; // true for iDataInQueue not being empty
536         }
537     }
538 
539     // push into the data queue
540     int32 err = 0;
541     OSCL_TRY(err, iDataInQueue.push_back(aFrag););
542     if (err) return false;
543 
544     return true;
545 }
546 
547 /////////////////////////////////////////////////////////////////////////////////////
getNextCompleteLine(HTTPMemoryFragment & aHttpFrag,bool aHeaderParsed)548 bool HTTPParserInput::getNextCompleteLine(HTTPMemoryFragment &aHttpFrag, bool aHeaderParsed)
549 {
550     int32 offset = isNextLineAvailable(aHeaderParsed);
551     if (offset <= 0) return false;
552     aHttpFrag.bind(iHTTPMemFrag.getPtr(), offset);
553     return true;
554 }
555 
556 // aRequestDataSize==0 means no request size, the function needs to send out whatever amount of data it has,
557 // but with one input data fragment each time.
558 // return value: actual size, if aRequestDataSize > 0, actual size <= aRequestDataSize
559 // actual size = 0, => no data, -1 means error
getData(HTTPMemoryFragment & aHttpFrag,const uint32 aRequestDataSize)560 int32 HTTPParserInput::getData(HTTPMemoryFragment &aHttpFrag, const uint32 aRequestDataSize)
561 {
562     if (iDataInQueue.empty()) return 0;
563 
564     uint32 requestSize = (aRequestDataSize > 0 ? aRequestDataSize : 0xffffffff);
565     uint32 availableFragSize = iDataInQueue[0].getMemFragSize() - iDataInQueueMemFragOffset;
566     uint32 actualSize = OSCL_MIN(requestSize, availableFragSize);
567 
568     if (actualSize > 0)
569     {
570         // create the output fragments
571         uint8* fragStartPtr = (uint8*)iDataInQueue[0].getMemFragPtr() + iDataInQueueMemFragOffset;
572         aHttpFrag.bind((void *)fragStartPtr, actualSize);
573         if (!constructOutputFragment(actualSize, (void *)fragStartPtr, (iDataInQueueMemFragOffset == 0))) return -1;
574     }
575 
576     // check if iDataInQueue[0] needs to be removed and update iDataInQueueMemFragOffset
577     if (availableFragSize <= requestSize)
578     {
579         iDataInQueue.erase(iDataInQueue.begin());
580         iDataInQueueMemFragOffset = 0;
581     }
582     else
583     {
584         // updata iDataInQueueMemFragOffset
585         iDataInQueueMemFragOffset += actualSize;
586     }
587 
588     return (int32)actualSize;
589 }
590 
591 // This function is for parsing multipart content, specically for the final boundary string like --boundaryString--, which could
592 // has no "\r\n", so getNextCompleteLine may not work in this case
593 // In general, if iLineBuffer has data, then send out iLineBuffer, then check if input data queue has data, if it has, then send
594 // out the first buffer. Return false for no any data (both iLineBuffer and data queue are empty)
595 // Note that this function doesn't do "get" that means changing internal pointers, instead, only does "view"
viewAvailableInputData(HTTPMemoryFragment & aHttpFrag)596 bool HTTPParserInput::viewAvailableInputData(HTTPMemoryFragment &aHttpFrag)
597 {
598     if (iLineBufferOccupied == 0 && iDataInQueue.empty()) return false;
599 
600     if (iLineBufferOccupied)
601     {
602         aHttpFrag.bind(iLineBuffer, iLineBufferOccupied);
603     }
604     else   // iDataInQueue is not empty
605     {
606         int32 availableFragSize = iDataInQueue[0].getMemFragSize() - iDataInQueueMemFragOffset;
607         if (availableFragSize == 0) return false;
608         uint8* fragStartPtr = (uint8*)iDataInQueue[0].getMemFragPtr() + iDataInQueueMemFragOffset;
609         aHttpFrag.bind(fragStartPtr, availableFragSize);
610     }
611     return true;
612 }
613 
614 
615 /////////////////////////////////////////////////////////////////////////////////////
getOutputMemFrag(OsclRefCounterMemFrag & aMemFrag)616 bool HTTPParserInput::getOutputMemFrag(OsclRefCounterMemFrag &aMemFrag)
617 {
618     if (iDataOutQueue.empty()) return false;
619     iDataOutQueue[0].getRefCountMemFrag(aMemFrag);
620     iDataOutQueue.erase(iDataOutQueue.begin());
621     return true;
622 }
623 
624 /////////////////////////////////////////////////////////////////////////////////////
625 // pass ending CRLF
skipCRLF()626 void HTTPParserInput::skipCRLF()
627 {
628     if (iDataInQueue.empty()) return;
629     uint8* fragStartPtr = (uint8*)iDataInQueue[0].getMemFragPtr() + iDataInQueueMemFragOffset;
630     int32 availableFragSize = iDataInQueue[0].getMemFragSize() - iDataInQueueMemFragOffset;
631     while ((*fragStartPtr == HTTP_CHAR_CR || *fragStartPtr == HTTP_CHAR_LF) && availableFragSize > 0)
632     {
633         *fragStartPtr++;
634         availableFragSize--;
635         iDataInQueueMemFragOffset++;
636     }
637 }
638 
639 // return value: 0 => not available ; >0 means the offset of the next complete line from the current point
640 // -1 error
isNextLineAvailable(bool aHeaderParsed)641 int32 HTTPParserInput::isNextLineAvailable(bool aHeaderParsed)
642 {
643     if (iDataInQueue.empty()) return 0;
644 
645     while (iDataInQueue.size() > 0)
646     {
647         if (iDataInQueueMemFragOffset >= iDataInQueue[0].getMemFragSize())
648         {
649             // remove iDataInQueue[0], since it is copied to iDataOutQueue
650             iDataInQueue.erase(iDataInQueue.begin());
651             iDataInQueueMemFragOffset = 0;
652             iHTTPMemFrag.clear();
653             return 0;
654         }
655 
656         bool bNewData = (iDataInQueueMemFragOffset == 0);
657         iHTTPMemFrag.bind((void *)((uint8*)iDataInQueue[0].getMemFragPtr() + iDataInQueueMemFragOffset),
658                           iDataInQueue[0].getMemFragSize() - iDataInQueueMemFragOffset);
659 
660         int32 offset = checkNextLine(iHTTPMemFrag);
661         iDataInQueueMemFragOffset += offset;
662         if (offset > 0 && iLineBufferOccupied == 0)
663         {
664             // construct an output fragment
665             if (!constructOutputFragment(iDataInQueueMemFragOffset, NULL, bNewData)) return -1;
666             return offset;
667         }
668 
669         // copy to iLineBuffer to concatenate the line fragments
670         uint32 remaining_bytes = (offset > 0 ? offset : iHTTPMemFrag.getAvailableSpace());
671         HTTPMemoryFragment aFrag(iHTTPMemFrag.getPtr(), remaining_bytes);
672         if (assemblyLineFragments(aFrag)) return -1;
673 
674         if (offset > 0)
675         {
676             iHTTPMemFrag.bind(iLineBuffer, iLineBufferOccupied);
677             if (!constructOutputFragment(iDataInQueueMemFragOffset, NULL, bNewData)) return -1;
678             iLineBufferOccupied = 0;
679             return iHTTPMemFrag.getCapacity();
680         }
681 
682         if (!aHeaderParsed)
683         {
684             // save iDataInQueue[0]
685             if (!bNewData && !iDataOutQueue.empty()) iDataOutQueue.erase(&iDataOutQueue.back());
686             int32 err = 0;
687             OSCL_TRY(err, iDataOutQueue.push_back(iDataInQueue[0]););
688             if (err) return -1;
689         }
690         // remove iDataInQueue[0]
691         iDataInQueue.erase(iDataInQueue.begin());
692         iDataInQueueMemFragOffset = 0;
693         iHTTPMemFrag.clear();
694     }
695 
696     return 0;
697 }
698 
assemblyLineFragments(HTTPMemoryFragment & aFrag)699 int32 HTTPParserInput::assemblyLineFragments(HTTPMemoryFragment &aFrag)
700 {
701     if (aFrag.getCapacity() <= iLineBufferSize - iLineBufferOccupied)
702     {
703         oscl_memcpy(iLineBuffer + iLineBufferOccupied, (char*)aFrag.getPtr(), aFrag.getCapacity());
704     }
705     else
706     {
707         // realloc iLineBuffer
708         // aFrag.getCapacity()+iLineBufferOccupied>iLineBufferSize
709         iLineBufferSize = (aFrag.getCapacity() + iLineBufferOccupied) << 1;
710 
711         OsclMemAllocator alloc;
712         char *aNewLineBuffer = (char*)alloc.allocate(iLineBufferSize);
713         if (!aNewLineBuffer) return -1;
714         if (iLineBufferOccupied) oscl_memcpy(aNewLineBuffer, iLineBuffer, iLineBufferOccupied);
715         oscl_memcpy(aNewLineBuffer + iLineBufferOccupied, (char*)aFrag.getPtr(), aFrag.getCapacity());
716 
717         // deallocate iLineBuffer
718         alloc.deallocate(iLineBuffer);
719         iLineBuffer = aNewLineBuffer;
720     }
721     iLineBufferOccupied += aFrag.getCapacity();
722     return 0;
723 }
724 
725 /////////////////////////////////////////////////////////////////////////////////////
checkNextLine(HTTPMemoryFragment & aInputDataStream)726 int32 HTTPParserInput::checkNextLine(HTTPMemoryFragment &aInputDataStream)
727 {
728     char *ptr = (char *)aInputDataStream.getPtr(), *start_ptr = ptr;
729     int32 streamLength = aInputDataStream.getAvailableSpace();
730     while (streamLength > 1 && (*ptr != HTTP_CHAR_CR && *ptr != HTTP_CHAR_LF))
731     {
732         ptr++;
733         streamLength--;
734     }
735 
736     if (*ptr == HTTP_CHAR_CR || *ptr == HTTP_CHAR_LF)
737     {
738         if (streamLength > 1 &&
739                 (ptr[1] == HTTP_CHAR_CR || ptr[1] == HTTP_CHAR_LF) &&
740                 ptr[1] != ptr[0]) ptr++;    // avoid double CR or double LF, should treat it as different lines
741         // Note that double CR(CRLFCRLF) or double LF (CRLFCRLF, or LFLF) means end of HTTP header
742         return ptr - start_ptr + 1;
743     }
744 
745     return 0; // no complete key-value pair available
746 }
747 
748 /////////////////////////////////////////////////////////////////////////////////////
749 // if aNewMemFragPtr=NULL, no change to memory fragment pointer, existing fragment with larger length
constructOutputFragment(const uint32 aNewMemFragLen,const void * aNewMemFragPtr,const bool isNewFrag)750 bool HTTPParserInput::constructOutputFragment(const uint32 aNewMemFragLen, const void *aNewMemFragPtr, const bool isNewFrag)
751 {
752     if (isNewFrag || iDataOutQueue.empty())
753     {
754         RefCounterMemoryFragment refCountMemfrag(iDataInQueue[0].getMemFrag(), iDataInQueue[0].getRefCounter());
755         int32 err = 0;
756         OSCL_TRY(err, iDataOutQueue.push_back(refCountMemfrag););
757         if (err) return false;
758     }
759 
760     // update ptr and len of the memory fragment
761     iDataOutQueue.back().update(aNewMemFragLen);
762     if (aNewMemFragPtr) iDataOutQueue.back().update((void*)aNewMemFragPtr);
763     return true;
764 }
765 
empty()766 bool HTTPParserInput::empty()
767 {
768     if (iDataInQueue.empty()) return true;
769     if (iDataInQueue.size() > 1) return false;
770 
771     // iDataInQueue.size() = 1
772     if (iDataInQueueMemFragOffset == iDataInQueue[0].getMemFragSize()) return true;
773     return false;
774 }
775 
776 /////////////////////////////////////////////////////////////////////////////////////
777 ////////// HTTPParserBaseObject Implementation //////////////////////*/////////////
778 /////////////////////////////////////////////////////////////////////////////////////
parseHeaderFields(HTTPMemoryFragment & aInputLineData,const bool aReplaceOldValue)779 int32 HTTPParserBaseObject::parseHeaderFields(HTTPMemoryFragment &aInputLineData, const bool aReplaceOldValue)
780 {
781     // parse header fields
782     char *fieldKey;
783     uint32 fieldKeyLength;
784     char *fieldValue;
785     uint32 fieldValueLength = 0;
786     int32 status = getNextFieldKeyValuePair(aInputLineData, fieldKey, fieldKeyLength, fieldValue, fieldValueLength);
787     if (status == 1) return HTTPParser::PARSE_HEADER_AVAILABLE; // end of header
788     if (status < 0)
789     {
790         LOGINFO((0, "HTTPParserBaseObject::parseHeaderFields() : Syntax Error founded!!"));
791         return HTTPParser::PARSE_SYNTAX_ERROR;     // no divider characters found!
792     }
793 
794     // exception handling (no key or no value case)
795     if (fieldKeyLength == 0) return HTTPParser::PARSE_SUCCESS; // for no key, just ignore it
796     char spaceChar = HTTP_CHAR_SPACE;
797     if (fieldValueLength == 0)  // for no value, just set ''
798     {
799         fieldValue = &spaceChar;
800         fieldValueLength = 1;
801     }
802     if (status != 0) return HTTPParser::PARSE_SUCCESS; // just ignore
803 
804     // add a key-value pair(fieldKey, fieldValue) to store
805     return addKeyValuePairToStore(fieldKey, fieldKeyLength, fieldValue, fieldValueLength, aReplaceOldValue);
806 }
807 
addKeyValuePairToStore(const char * aFieldKey,const uint32 aFieldKeyLength,const char * aFieldValue,const uint32 aFieldValueLength,const bool aNeedReplaceOldValue)808 int32 HTTPParserBaseObject::addKeyValuePairToStore(const char *aFieldKey, const uint32 aFieldKeyLength,
809         const char *aFieldValue, const uint32 aFieldValueLength,
810         const bool aNeedReplaceOldValue)
811 {
812     if (aFieldKeyLength + aFieldValueLength < iKeyValueStore->getAvailableSize())
813     {
814         if (iKeyValueStore->addKeyValuePair(aFieldKey, aFieldKeyLength, aFieldValue, aFieldValueLength, aNeedReplaceOldValue) != 0)
815         {
816             return HTTPParser::PARSE_GENERAL_ERROR;
817         }
818     }
819     else
820     {
821         // not enough memory
822         if (!reallocKeyValueStore(aFieldKeyLength + aFieldValueLength)) return HTTPParser::PARSE_MEMORY_ALLOCATION_FAILURE;
823         // re-add key-value pair to store
824         if (iKeyValueStore->addKeyValuePair(aFieldKey, aFieldKeyLength, aFieldValue, aFieldValueLength, aNeedReplaceOldValue) ==
825                 StringKeyValueStore::StringKeyValueStore_Failure) return HTTPParser::PARSE_GENERAL_ERROR;
826     }
827     return HTTPParser::PARSE_SUCCESS;
828 }
829 
addKeyValuePairToStore(const StrCSumPtrLen & aNewKey,const StrPtrLen & aNewValue,const bool aNeedReplaceOldValue)830 int32 HTTPParserBaseObject::addKeyValuePairToStore(const StrCSumPtrLen &aNewKey,
831         const StrPtrLen &aNewValue,
832         const bool aNeedReplaceOldValue)
833 {
834     return addKeyValuePairToStore((char*)aNewKey.c_str(), aNewKey.length(),
835                                   (char*)aNewValue.c_str(), aNewValue.length(),
836                                   aNeedReplaceOldValue);
837 }
838 
839 
reallocKeyValueStore(const uint32 aCurrKeyValueSize)840 bool HTTPParserBaseObject::reallocKeyValueStore(const uint32 aCurrKeyValueSize)
841 {
842     // calculate the new KeyValueStore size
843     uint32 miniSize = iKeyValueStore->getCurrentMemoryUsage() + aCurrKeyValueSize;
844     uint32 aNewStoreSize = OSCL_MAX(miniSize, iKeyValueStore->getStoreSize()) << 1;
845 
846     // create a new store
847     StringKeyValueStore *aKeyValueStore = StringKeyValueStore::create(aNewStoreSize);
848     if (!aKeyValueStore) return false;
849     if (!aKeyValueStore->copy(*iKeyValueStore))
850     {
851         OSCL_DELETE(aKeyValueStore);
852         return false;
853     }
854     OSCL_DELETE(iKeyValueStore);
855     iKeyValueStore = aKeyValueStore;
856     return true;
857 
858 }
859 
constructEntityUnit(HTTPParserInput & aParserInput,RefCountHTTPEntityUnit & aEntityUnit)860 bool HTTPParserBaseObject::constructEntityUnit(HTTPParserInput &aParserInput, RefCountHTTPEntityUnit &aEntityUnit)
861 {
862     OsclRefCounterMemFrag entityUnit;
863     int32 err = 0;
864     OSCL_TRY(err, entityUnit = iEntityUnitAlloc->get(););
865     if (err) return false;
866 
867     // add memory fragments into the entity unit
868     HTTPEntityUnit* entityUnitFrag = OSCL_PLACEMENT_NEW(((uint8*) entityUnit.getMemFragPtr()), HTTPEntityUnit());
869     OsclRefCounterMemFrag memfrag;
870     while (aParserInput.getOutputMemFrag(memfrag))
871     {
872         if (!entityUnitFrag->addMemFrag(memfrag))
873         {
874             entityUnitFrag->~HTTPEntityUnit();
875             return false;
876         }
877     }
878     //if(entityUnitFrag->getNumFragments() == 0) { entityUnitFrag->~HTTPEntityUnit(); return false; } // no memory fragments
879     aEntityUnit = RefCountHTTPEntityUnit(*entityUnitFrag, entityUnit.getRefCounter()); // no memory fragments is possible
880     entityUnitFrag->~HTTPEntityUnit(); // destruct entityUnitFrag
881     return true;
882 }
883 
884 // return value: 0 normal, 1 end of header, 2 ignore, -1 error
getNextFieldKeyValuePair(HTTPMemoryFragment & aInputDataStream,char * & aFieldKey,uint32 & aFieldKeyLength,char * & aFieldValue,uint32 & aFieldValueLength)885 int32 HTTPParserBaseObject::getNextFieldKeyValuePair(HTTPMemoryFragment &aInputDataStream, char *&aFieldKey, uint32 &aFieldKeyLength,
886         char *&aFieldValue, uint32 &aFieldValueLength)
887 {
888     // get key
889     int32 status = parseNextValueItem(aInputDataStream, aFieldKey, aFieldKeyLength, true);
890     if (status != 0) return status; // end of header or error
891 
892     // get value
893     return parseNextValueItem(aInputDataStream, aFieldValue, aFieldValueLength, false);
894 }
895 
896 // return value: 0 normal,
897 //               1 end of header,
898 //               2 ignore (for CRLF, to handle CRLF split into separate fragments)
899 //              -1 error
parseNextValueItem(HTTPMemoryFragment & aInputDataStream,char * & valueItemPtr,uint32 & valueItemLength,const bool isKeyItem)900 int32 HTTPParserBaseObject::parseNextValueItem(HTTPMemoryFragment &aInputDataStream, char *&valueItemPtr, uint32 &valueItemLength, const bool isKeyItem)
901 {
902     char dividerChar0 = (isKeyItem ? HTTP_CHAR_COLON : HTTP_CHAR_CR);
903     char dividerChar1 = (isKeyItem ? HTTP_CHAR_COLON : HTTP_CHAR_LF);
904 
905     char *ptr = (char *)aInputDataStream.getPtr();
906     int32 len = aInputDataStream.getAvailableSpace();
907 
908     // eat all non-letter characters at the beginning
909     int32 status = getLineStartPoint(ptr, len, isKeyItem);
910     if (status == 2) return status; // ignore
911     if (status == 1)
912     {
913         aInputDataStream.update(ptr);    // Final CRLF, end of HTTP header
914         return 1;
915     }
916 
917     // search divider characters to identify the value item
918     valueItemPtr = ptr;
919     while (*ptr != dividerChar0 && *ptr != dividerChar1 && len > 0)
920     {
921         ptr++;    // assuming there is no case like "zzz key :"
922         len--;
923     }
924     if (len <= 0) return -1; // no divider chars
925 
926     char *end_ptr = ptr--;
927     while (*ptr == HTTP_CHAR_SPACE || *ptr == HTTP_CHAR_TAB) ptr--; // eat space or tab characater
928     valueItemLength = (ptr > valueItemPtr ? (ptr - valueItemPtr + 1) : 0); // ptr is the ending pointer for a value item
929 
930     ptr = end_ptr;
931     if (isKeyItem) ptr++;
932     else
933     {
934         saveEndingCRLF(ptr, len, iPrevCRLF);
935         if (len > 0 && (ptr[1] == HTTP_CHAR_CR || ptr[1] == HTTP_CHAR_LF)) ptr++; // pass CRLF at each line
936     }
937 
938     aInputDataStream.update(ptr);
939     return 0;
940 }
941 
942 // return value: 0 normal, 1 end of header, 2 ignore
getLineStartPoint(char * & ptr,int32 & len,const bool isKeyItem)943 int32 HTTPParserBaseObject::getLineStartPoint(char *&ptr, int32 &len, const bool isKeyItem)
944 {
945     if (isKeyItem)
946     {
947         while (!isLetter(*ptr) && (*ptr != HTTP_CHAR_CR && *ptr != HTTP_CHAR_LF) && len > 0)
948         {
949             iPrevCRLF = 0;
950             ptr++;
951             len--; // eat all non-letter characters except CRLF
952         }
953         if (*ptr == HTTP_CHAR_CR || *ptr == HTTP_CHAR_LF)  // key guarantees to have very first LETTER character
954         {
955             if (iPrevCRLF == 0)
956             {
957                 saveEndingCRLF(ptr, len, iPrevCRLF);
958                 if (len > 0 && (ptr[1] == HTTP_CHAR_CR || ptr[1] == HTTP_CHAR_LF)) ptr++;
959                 return 2; // save CRLF to iPrevCRLF, and ignore
960             }
961             else   // iPrevCRLF has something
962             {
963                 uint8 currCRLF = 0;
964                 saveEndingCRLF(ptr, len, currCRLF);
965                 if (len > 0 && (ptr[1] == HTTP_CHAR_CR || ptr[1] == HTTP_CHAR_LF)) ptr++;
966                 if (iPrevCRLF & currCRLF) return 1; // double CR or LF, end of HTTP header
967                 iPrevCRLF = currCRLF;
968                 return 2; // ignore
969             }
970         }
971     }
972     else
973     {
974         while ((*ptr == HTTP_CHAR_SPACE || *ptr == HTTP_CHAR_TAB) && len > 0)
975         {
976             ptr++;
977             len--;
978         } // eat space or tab character
979     }
980 
981     return 0;
982 }
983 
984 // aNeedReset=1, set aCRLF; aNeedReset=0, update aCRLF
saveEndingCRLF(char * ptr,uint32 len,uint8 & aCRLF,bool aNeedReset)985 void HTTPParserBaseObject::saveEndingCRLF(char *ptr, uint32 len, uint8& aCRLF, bool aNeedReset)
986 {
987     char *tmpPtr = ptr;
988     int32 tmpLen = (int32)len;
989     if (aNeedReset) aCRLF = 0;
990 
991     // get to CRLF point
992     while ((*tmpPtr != HTTP_CHAR_CR && *tmpPtr != HTTP_CHAR_LF) && tmpLen > 0)
993     {
994         tmpPtr++;
995         tmpLen--;
996     }
997 
998     while ((*tmpPtr == HTTP_CHAR_CR || *tmpPtr == HTTP_CHAR_LF) && tmpLen > 0)
999     {
1000         if (*tmpPtr == HTTP_CHAR_CR) aCRLF |= 0x2; // bit 1 = 1
1001         if (*tmpPtr == HTTP_CHAR_LF) aCRLF |= 0x1; // bit 0 = 1
1002         tmpPtr++;
1003         tmpLen--;
1004     }
1005 }
1006 
1007 
1008 /////////////////////////////////////////////////////////////////////////////////////
1009 ////////// HTTPParserHeaderObject Implementation ////////////////////////////////////
1010 /////////////////////////////////////////////////////////////////////////////////////
parse(HTTPParserInput & aParserInput,RefCountHTTPEntityUnit & aEntityUnit)1011 int32 HTTPParserHeaderObject::parse(HTTPParserInput &aParserInput, RefCountHTTPEntityUnit &aEntityUnit)
1012 {
1013     HTTPMemoryFragment aInputLineData;
1014 
1015     while (aParserInput.getNextCompleteLine(aInputLineData))
1016     {
1017         if (!iHeaderFirstLineParsed)
1018         {
1019             // parse the first line : Status-Line = HTTP-Version SP Status-Code SP Reason-Phrase CRLF
1020             int32 status = parseFirstLine(aInputLineData);
1021             if (status < 0) return status; // syntax error
1022             iHeaderFirstLineParsed = true;
1023         }
1024         else
1025         {
1026             int32 status = parseHeaderFields(aInputLineData);
1027             if (status == HTTPParser::PARSE_HEADER_AVAILABLE)
1028             {
1029                 iHeaderParsed = true;
1030                 // check content info
1031                 if (!iContentInfo->parseContentInfo(*iKeyValueStore)) return HTTPParser::PARSE_MEMORY_ALLOCATION_FAILURE;
1032                 // construct output entity unit
1033                 if (!constructEntityUnit(aParserInput, aEntityUnit)) return HTTPParser::PARSE_MEMORY_ALLOCATION_FAILURE;
1034                 if (!isGoodStatusCode())
1035                 {
1036                     LOGINFO((0, "HTTPParserHeaderObject::parse() : NOT GOOD STATUS CODE"));
1037                     return HTTPParser::PARSE_STATUS_LINE_SHOW_NOT_SUCCESSFUL;
1038                 }
1039                 if (checkResponseParsedComplete()) iResponseParsedComplete = true;
1040                 return HTTPParser::PARSE_HEADER_AVAILABLE;
1041             }
1042             if (status != HTTPParser::PARSE_SUCCESS) return status;
1043         }
1044 
1045     } // end of: while(iParserInput->getNextCompleteLine(aInputLineData))
1046 
1047     // check content info
1048     return HTTPParser::PARSE_NEED_MORE_DATA;
1049 }
1050 
1051 // return value: 0 => ok , or HTTPParser enum codes
parseFirstLine(HTTPMemoryFragment & aInputDataStream)1052 int32 HTTPParserHeaderObject::parseFirstLine(HTTPMemoryFragment &aInputDataStream)
1053 {
1054     // Status-Line = HTTP-Version SP Status-Code SP Reason-Phrase CRLF
1055     char *ptr = (char *)aInputDataStream.getPtr();
1056     int32 len = (int32)aInputDataStream.getAvailableSpace();
1057 
1058     while (!isLetter(*ptr) && len > 0)
1059     {
1060         ptr++;
1061         len--;
1062     }
1063     if (len < 8) return HTTPParser::PARSE_SYNTAX_ERROR;
1064 
1065     // check HTTP/1.x
1066     if (((ptr[0] | OSCL_ASCII_CASE_MAGIC_BIT) == 'h') &&
1067             ((ptr[1] | OSCL_ASCII_CASE_MAGIC_BIT) == 't') &&
1068             ((ptr[2] | OSCL_ASCII_CASE_MAGIC_BIT) == 't') &&
1069             ((ptr[3] | OSCL_ASCII_CASE_MAGIC_BIT) == 'p') &&
1070             (ptr[4]                              == '/'))
1071     {
1072         ptr += 5; // size of "http/"
1073         if (!checkHTTPVersion(ptr))
1074         {
1075             return HTTPParser::PARSE_HTTP_VERSION_NOT_SUPPORTED;
1076         }
1077 
1078         // ptr should be updated in checkHTTPVersion()
1079         while (!isDigit(*ptr) && len > 0)
1080         {
1081             ptr++;
1082             len--;
1083         }
1084         if (len <= 0) return 0; // no digital status code
1085         char *start_ptr = ptr;
1086         uint32 start_len = len;
1087         while (isDigit(*ptr) && len > 0)
1088         {
1089             ptr++;
1090             len--;
1091         }
1092         //if(len <= 0) return 1; // no Reason-Phrase
1093 
1094         // get status code
1095         PV_atoi(start_ptr, 'd', start_len - len, iStatusCode);
1096         saveEndingCRLF(ptr, len, iPrevCRLF);
1097         return 0;
1098     }
1099 
1100     // add first-line into the key-value store
1101     StrPtrLen firstLine = "Response-Line";
1102     addKeyValuePairToStore(firstLine.c_str(), firstLine.length(),
1103                            (char *)aInputDataStream.getPtr(), aInputDataStream.getAvailableSpace(),
1104                            true);
1105 
1106     return HTTPParser::PARSE_SYNTAX_ERROR; // looks like the status line has something we don't understand.
1107 }
1108 
checkHTTPVersion(char * & aPtr)1109 bool HTTPParserHeaderObject::checkHTTPVersion(char* &aPtr)
1110 {
1111     if (aPtr[0] == '1' && aPtr[0] == HTTP_CHAR_SPACE)
1112     {
1113         // support HTTP/1
1114         aPtr += 2;
1115         iHttpVersionNum = 0;
1116         return true;
1117     }
1118 
1119     if (aPtr[0] == '1' &&
1120             aPtr[1] == '.' &&
1121             (aPtr[2] == '0' || aPtr[2] == '1'))
1122     {
1123         iHttpVersionNum = (aPtr[2] == '0' ? 0 : 1);
1124         aPtr += 3;
1125         return true;
1126     }
1127 
1128     return false;
1129 }
1130 
1131 // This function gets complicated since a couple of new cases have been added
isGoodStatusCode()1132 bool HTTPParserHeaderObject::isGoodStatusCode()
1133 {
1134     if (iStatusCode < GOOD_HTTP_STATUS_CODE_START_FROM100 ||
1135             iStatusCode > GOOD_HTTP_STATUS_CODE_END_AT299) return false;
1136 
1137     // check 1xx code, 1xx code is only allowed in Http/1.1
1138     bool goodStatusCode = checkGood1xxCode();
1139     if (!goodStatusCode) return false;
1140 
1141     // check 2xx code, if 204 (no content) or 2xx code with content-length=0, then we need to error out
1142     goodStatusCode = checkGood2xxCode();
1143     return goodStatusCode;
1144 }
1145 
1146 // check 1xx code, 1xx code is only allowed in Http/1.1
checkGood1xxCode()1147 bool HTTPParserHeaderObject::checkGood1xxCode()
1148 {
1149     if (iHttpVersionNum == 0 &&
1150             (GOOD_HTTP_STATUS_CODE_START_FROM100 <= iStatusCode && iStatusCode < GOOD_HTTP_STATUS_CODE_START_FROM200))
1151     {
1152         return false;
1153     }
1154     return true;
1155 }
1156 
1157 // check 2xx code, if 2xx code with content-length=0, then we need to error out
checkGood2xxCode()1158 bool HTTPParserHeaderObject::checkGood2xxCode()
1159 {
1160     uint32 goodStatusCodeStart = GOOD_HTTP_STATUS_CODE_START_FROM200;
1161     if (GOOD_HTTP_STATUS_CODE_START_FROM200 <= iStatusCode && iStatusCode <= GOOD_HTTP_STATUS_CODE_END_AT299)
1162     {
1163         // for Http status code 204 (no content), error our right away
1164         if (iStatusCode == HTTP_STATUS_CODE_204_NO_CONTENT)
1165         {
1166             LOGINFO((0, "HTTPParserHeaderObject::checkGood2xxCode() : iStatusCode=HTTP_STATUS_CODE_204_NO_CONTENT"));
1167             return false;
1168         }
1169 
1170         // other 2xx code, check the zero or empty content-length
1171         StrCSumPtrLen contenLengthKey("Content-Length");
1172         StrPtrLen contentLengthValue;
1173         if (iKeyValueStore->getValueByKey(contenLengthKey, contentLengthValue))
1174         {
1175             // has Content-Length field
1176             uint32 aContentLength = 0;
1177             PV_atoi(contentLengthValue.c_str(), 'd', aContentLength);
1178 
1179             // check the empty Content-Length case
1180             char *ptr = (char *)contentLengthValue.c_str();
1181             if (aContentLength == 0 || ptr[0] == HTTP_CHAR_SPACE)
1182             {
1183                 LOGINFO((0, "HTTPParserHeaderObject::checkGood2xxCode() : zero or empty content length for 2xx code"));
1184                 return false;
1185             }
1186         }
1187     }
1188     return (goodStatusCodeStart <= iStatusCode && iStatusCode <= GOOD_HTTP_STATUS_CODE_END_AT299);
1189 }
1190 
doSanityCheckForResponseHeader()1191 int32 HTTPParserHeaderObject::doSanityCheckForResponseHeader()
1192 {
1193     // check Chunked Transfer Encoding supported for Http/1.1 only
1194     if (!checkChunkedTransferEncodingSupported()) return HTTPParser::PARSE_TRANSFER_ENCODING_NOT_SUPPORTED;
1195     return HTTPParser::PARSE_SUCCESS;
1196 }
1197 
1198 
1199 // check Chunked Transfer Encoding supported by Http/1.1 only
checkChunkedTransferEncodingSupported()1200 bool HTTPParserHeaderObject::checkChunkedTransferEncodingSupported()
1201 {
1202     StrCSumPtrLen transferEncodingKey("Transfer-Encoding");
1203     StrPtrLen transferEncodingValue;
1204     if (iKeyValueStore->getValueByKey(transferEncodingKey, transferEncodingValue))
1205     {
1206         LOGINFO((0, "HTTPParserHeaderObject::checkChunkedTransferEncodingSupported() : has Transfer-encoding field, HttpVersionNum=%d", iHttpVersionNum));
1207         // has Transfer-encoding field
1208         if (iHttpVersionNum == 0) return false;
1209     }
1210     return true;
1211 }
1212 
checkResponseParsedComplete()1213 bool HTTPParserHeaderObject::checkResponseParsedComplete()
1214 {
1215     // check "Content-Length"
1216     StrCSumPtrLen contentLengthKey = "Content-Length";
1217     StrPtrLen contentLengthValue;
1218 
1219     if (!getField(contentLengthKey, contentLengthValue)) return false; // no "Content-Length"
1220 
1221     // get "Content-Length" value
1222     uint32 contentLength = 0;
1223     PV_atoi(contentLengthValue.c_str(), 'd', contentLength);
1224     return (contentLength == 0);
1225 }
1226 
create(HTTPContentInfoInternal * aContentInfo)1227 HTTPParserHeaderObject *HTTPParserHeaderObject::create(HTTPContentInfoInternal *aContentInfo)
1228 {
1229     HTTPParserHeaderObject *header = OSCL_NEW(HTTPParserHeaderObject, ());
1230     if (!header) return NULL;
1231     if (!header->construct(aContentInfo))
1232     {
1233         OSCL_DELETE(header);
1234         return NULL;
1235     }
1236     return header;
1237 }
1238 
construct(HTTPContentInfoInternal * aContentInfo)1239 bool HTTPParserHeaderObject::construct(HTTPContentInfoInternal *aContentInfo)
1240 {
1241     reset();
1242     iContentInfo = aContentInfo;
1243 
1244     if ((iKeyValueStore = StringKeyValueStore::create()) == NULL) return false;
1245 
1246     iEntityUnitAlloc = OSCL_NEW(PVMFBufferPoolAllocator, ());
1247     if (!iEntityUnitAlloc) return false;
1248 
1249     int32 err = 0;
1250     OSCL_TRY(err, iEntityUnitAlloc->size(HTTP_ENTITY_UNIT_POOLNUM, sizeof(HTTPEntityUnit)));
1251     if (err) return false;
1252 
1253     return true;
1254 }
1255 
~HTTPParserHeaderObject()1256 HTTPParserHeaderObject::~HTTPParserHeaderObject()
1257 {
1258     reset();
1259 
1260     // delete iKeyValueStore
1261     if (iKeyValueStore) OSCL_DELETE(iKeyValueStore);
1262     iKeyValueStore = NULL;
1263 
1264     // delete iEntityUnitAlloc
1265     if (iEntityUnitAlloc) OSCL_DELETE(iEntityUnitAlloc);
1266     iEntityUnitAlloc = NULL;
1267 }
1268 
1269 
1270 /////////////////////////////////////////////////////////////////////////////////////
1271 ////////// HTTPParserEntityBodyObject Implementation ////////////////////////////////
1272 /////////////////////////////////////////////////////////////////////////////////////
parseEnityBodyChunkData(HTTPParserInput & aParserInput,RefCountHTTPEntityUnit & aEntityUnit)1273 int32 HTTPParserEntityBodyObject::parseEnityBodyChunkData(HTTPParserInput &aParserInput, RefCountHTTPEntityUnit &aEntityUnit)
1274 {
1275     int32 requestSize = iContentInfo->getContentRangeLength() - iCurrentChunkDataLength;
1276     HTTPMemoryFragment aFrag;
1277     int32 actualSize = 0;
1278     while (requestSize > 0)
1279     {
1280         if ((actualSize = aParserInput.getData(aFrag, requestSize)) <= 0) break;
1281         iCurrentChunkDataLength += actualSize;
1282         iNumChunks++;
1283         requestSize -= actualSize;
1284     }
1285     if (actualSize < 0) return HTTPParser::PARSE_MEMORY_ALLOCATION_FAILURE;
1286     if (actualSize == 0 && requestSize > 0) return HTTPParser::PARSE_NEED_MORE_DATA;
1287 
1288     // get complete chunk, and then construct output entity unit
1289     if (!constructEntityUnit(aParserInput, aEntityUnit)) return HTTPParser::PARSE_MEMORY_ALLOCATION_FAILURE;
1290 
1291     // pass ending CRLF for the chunk data for next chunk parsing
1292     aParserInput.skipCRLF();
1293     return HTTPParser::PARSE_SUCCESS;
1294 }
1295 
1296 /////////////////////////////////////////////////////////////////////////////////////
1297 ////////// HTTPParserNormalContentObject Implementation /////////////////////////////
1298 /////////////////////////////////////////////////////////////////////////////////////
parse(HTTPParserInput & aParserInput,RefCountHTTPEntityUnit & aEntityUnit)1299 int32 HTTPParserNormalContentObject::parse(HTTPParserInput &aParserInput, RefCountHTTPEntityUnit &aEntityUnit)
1300 {
1301     HTTPMemoryFragment aFrag;
1302     int32 actualSize = 0;
1303     if (iContentInfo->iContentLength == 0) iContentInfo->iContentLength = 0x7fffffff; // 0=>7fff ffff
1304     if (iCurrTotalLengthObtained == 0 && iContentInfo->iContentRangeLeft > 0) iCurrTotalLengthObtained = iContentInfo->iContentRangeLeft;
1305     int32 requestSize = (int32)iContentInfo->iContentLength - (int32)iCurrTotalLengthObtained;
1306     if (requestSize <= 0)
1307     {
1308         if (requestSize == 0) return HTTPParser::PARSE_SUCCESS_END_OF_MESSAGE;
1309         return HTTPParser::PARSE_SUCCESS_END_OF_MESSAGE_WITH_EXTRA_DATA;
1310     }
1311     while ((actualSize = aParserInput.getData(aFrag, requestSize)) > 0)
1312     {
1313         iCurrTotalLengthObtained += actualSize;
1314         if (requestSize > 0)
1315         {
1316             if ((requestSize -= actualSize) <= 0) break; // we don't need to process aFrag
1317         }
1318     }
1319     if (actualSize < 0) return HTTPParser::PARSE_MEMORY_ALLOCATION_FAILURE;
1320 
1321     // construct output entity unit
1322     if (!constructEntityUnit(aParserInput, aEntityUnit)) return HTTPParser::PARSE_MEMORY_ALLOCATION_FAILURE;
1323     if (iCurrTotalLengthObtained >= iContentInfo->iContentLength)
1324     {
1325         if (iCurrTotalLengthObtained > iContentInfo->iContentLength ||
1326                 !aParserInput.empty()) return HTTPParser::PARSE_SUCCESS_END_OF_MESSAGE_WITH_EXTRA_DATA;
1327         return HTTPParser::PARSE_SUCCESS_END_OF_MESSAGE;
1328     }
1329     if (actualSize == 0 && iContentInfo->iContentLength > iCurrTotalLengthObtained) return HTTPParser::PARSE_SUCCESS_END_OF_INPUT;
1330     return HTTPParser::PARSE_SUCCESS;
1331 }
1332 
1333 
1334 /////////////////////////////////////////////////////////////////////////////////////
1335 ////////// HTTPParserCTEContentObject Implementation /////////////////////////////
1336 /////////////////////////////////////////////////////////////////////////////////////
parse(HTTPParserInput & aParserInput,RefCountHTTPEntityUnit & aEntityUnit)1337 int32 HTTPParserCTEContentObject::parse(HTTPParserInput &aParserInput, RefCountHTTPEntityUnit &aEntityUnit)
1338 {
1339     // get CTE chunk length
1340     if (iContentInfo->iContentRangeRight == 0)
1341     {
1342         HTTPMemoryFragment aInputLineData;
1343         int32 chunkLength = -1;
1344         while (aParserInput.getNextCompleteLine(aInputLineData, true))  // true means header is already parsed
1345         {
1346             if (getCTEChunkLength(aInputLineData, chunkLength)) break;
1347         }
1348         if (chunkLength == -1) return HTTPParser::PARSE_NEED_MORE_DATA;
1349         if (chunkLength == 0)
1350         {
1351             if (!aParserInput.empty()) return HTTPParser::PARSE_SUCCESS_END_OF_MESSAGE_WITH_EXTRA_DATA;
1352             return HTTPParser::PARSE_SUCCESS_END_OF_MESSAGE;
1353         }
1354 
1355         iContentInfo->iContentRangeRight = chunkLength - 1;
1356         iContentInfo->iContentLength += chunkLength;
1357         aParserInput.clearOutputQueue();
1358     }
1359 
1360     // get CTE chunk data
1361     aParserInput.skipCRLF();
1362     int32 status = parseEnityBodyChunkData(aParserInput, aEntityUnit);
1363     if (status == HTTPParser::PARSE_SUCCESS) reset(); // for next chunk parsing
1364     return status;
1365 }
1366 
getCTEChunkLength(HTTPMemoryFragment & aInputLineData,int32 & aChunkSize)1367 bool HTTPParserCTEContentObject::getCTEChunkLength(HTTPMemoryFragment &aInputLineData, int32 &aChunkSize)
1368 {
1369     char *ptr = (char *)aInputLineData.getPtr();
1370     int32 len = (int32)aInputLineData.getAvailableSpace();
1371     while (!isHexDigit(*ptr) && len > 0)
1372     {
1373         ptr++;
1374         len--;
1375     }
1376     if (len <= 0) return false;
1377     char *start_ptr = ptr;
1378     int32 start_len = len;
1379     while (isHexDigit(*ptr) && len > 0)
1380     {
1381         ptr++;
1382         len--;
1383     }
1384     if (len <= 0) return false;
1385     uint32 chunkSize;
1386     PV_atoi(start_ptr, 'x', start_len - len, chunkSize);
1387     aChunkSize = (int32)chunkSize;
1388     return true;
1389 }
1390 
1391 /////////////////////////////////////////////////////////////////////////////////////
1392 ////////// HTTPParserMultipartContentObject Implementation /////////////////////////////
1393 /////////////////////////////////////////////////////////////////////////////////////
parse(HTTPParserInput & aParserInput,RefCountHTTPEntityUnit & aEntityUnit)1394 int32 HTTPParserMultipartContentObject::parse(HTTPParserInput &aParserInput, RefCountHTTPEntityUnit &aEntityUnit)
1395 {
1396     // parse boundary string and chunk header
1397     int32 status = parseChunkHeader(aParserInput);
1398     if (status != HTTPParser::PARSE_SUCCESS) return status;
1399 
1400     // get chunk data
1401 
1402     status = parseEnityBodyChunkData(aParserInput, aEntityUnit);
1403     if (status != HTTPParser::PARSE_SUCCESS) return status;
1404 
1405     reset(); // for next chunk parsing
1406     if (aParserInput.empty()) return HTTPParser::PARSE_SUCCESS_END_OF_INPUT;
1407     return HTTPParser::PARSE_SUCCESS;
1408 }
1409 
parseChunkHeader(HTTPParserInput & aParserInput)1410 int32 HTTPParserMultipartContentObject::parseChunkHeader(HTTPParserInput &aParserInput)
1411 {
1412     if (iHeaderInEntityBodyParsed) return HTTPParser::PARSE_SUCCESS;
1413 
1414     // parse boundary line
1415     if (!iBoudaryLineParsed)
1416     {
1417         int32 status = parseChunkBoundaryLine(aParserInput);
1418         if (status != HTTPParser::PARSE_SUCCESS) return status;
1419         if (!iBoudaryLineParsed) return HTTPParser::PARSE_NEED_MORE_DATA; // try next time
1420     }
1421 
1422     // parse chunk header
1423     HTTPMemoryFragment aInputLineData;
1424     while (aParserInput.getNextCompleteLine(aInputLineData))
1425     {
1426         if (!iBoudaryLineParsed)
1427         {
1428             return HTTPParser::PARSE_SYNTAX_ERROR;
1429         }
1430         int32 status = parseHeaderFields(aInputLineData, true); // true means replace the old field value with the new one
1431         if (status == HTTPParser::PARSE_HEADER_AVAILABLE)
1432         {
1433             iHeaderInEntityBodyParsed = true;
1434             iCounter++;
1435             // update content info
1436             if (!iContentInfo->parseContentInfo(*iKeyValueStore)) return HTTPParser::PARSE_MEMORY_ALLOCATION_FAILURE;
1437             aParserInput.clearOutputQueue();
1438             saveEndingCRLF((char *)aInputLineData.getPtr(), (int32)aInputLineData.getAvailableSpace(), iPrevCRLF);
1439             break;
1440         }
1441         if (status != HTTPParser::PARSE_SUCCESS) return status;
1442     }
1443     if (!iHeaderInEntityBodyParsed) return HTTPParser::PARSE_NEED_MORE_DATA;
1444 
1445     // check the extra CRLF
1446     if (needSkipCRLF()) aParserInput.skipCRLF();
1447     return HTTPParser::PARSE_SUCCESS;
1448 }
1449 
1450 
parseChunkBoundaryLine(HTTPParserInput & aParserInput)1451 int32 HTTPParserMultipartContentObject::parseChunkBoundaryLine(HTTPParserInput &aParserInput)
1452 {
1453     HTTPMemoryFragment aInputLineData;
1454     if (aParserInput.getNextCompleteLine(aInputLineData))
1455     {
1456 
1457         // parse boundary line : --BOUNDARY STRING
1458         bool isFinalBoundary = false;
1459         if (iContentInfo->parseBoudaryLine(aInputLineData, isFinalBoundary)) iBoudaryLineParsed = true;
1460         if (isFinalBoundary) return HTTPParser::PARSE_SUCCESS_END_OF_MESSAGE;
1461         saveEndingCRLF((char *)aInputLineData.getPtr(), (int32)aInputLineData.getAvailableSpace(), iPrevCRLF);
1462 
1463         if (!iBoudaryLineParsed)
1464         {
1465             if (aParserInput.getNextCompleteLine(aInputLineData))
1466             {
1467                 bool isFinalBoundary = false;
1468                 if (iContentInfo->parseBoudaryLine(aInputLineData, isFinalBoundary)) iBoudaryLineParsed = true;
1469             }
1470         }
1471     }
1472 
1473     if (!iBoudaryLineParsed)
1474     {
1475         // try to see whether it is final boundary line, like --boundaryString-- (no "\r\n")
1476         HTTPMemoryFragment frag;
1477         if (!aParserInput.viewAvailableInputData(frag)) return HTTPParser::PARSE_NEED_MORE_DATA;
1478 
1479         bool isFinalBoundary = false;
1480         iContentInfo->parseBoudaryLine(frag, isFinalBoundary);
1481         if (isFinalBoundary) return HTTPParser::PARSE_SUCCESS_END_OF_MESSAGE;
1482     }
1483     return HTTPParser::PARSE_SUCCESS;
1484 }
1485