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