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 #ifndef HTTP_PARSER_INTERNAL_H_ 19 #define HTTP_PARSER_INTERNAL_H_ 20 21 #include "oscl_refcounter_memfrag.h" 22 #include "oscl_vector.h" 23 #include "http_parcom_internal.h" 24 #include "http_parser_external.h" 25 26 #ifndef PVMF_POOL_BUFFER_ALLOCATOR_H_INCLUDED 27 #include "pvmf_pool_buffer_allocator.h" 28 #endif 29 30 #ifndef PVLOGGER_H_INCLUDED 31 #include "pvlogger.h" 32 #endif 33 34 #ifndef STRING_KEYVALUE_STORE_H_INCLUDED 35 #include "string_keyvalue_store.h" 36 #endif 37 38 #define HTTP_ENTITY_UNIT_POOLNUM 4 39 #define DEFAULT_MAX_LINE_BUFFER_SIZE 512 40 #define DATA_QUEUE_VECTOR_RESERVE_SIZE 4 41 #define GOOD_HTTP_STATUS_CODE_START_FROM100 100 42 #define GOOD_HTTP_STATUS_CODE_START_FROM200 200 43 #define GOOD_HTTP_STATUS_CODE_END_AT299 299 44 #define HTTP_STATUS_CODE_204_NO_CONTENT 204 45 46 47 enum HTTPContentType 48 { 49 HTTP_CONTENT_NORMAL = 0, // no chunk header info 50 HTTP_CONTENT_NULTIPART, // for Content-Type : multipart/byteranges 51 HTTP_CONTENT_CHUNKED_TRANSFER_ENCODING // for Transfer-Encoding : chunked 52 }; 53 54 #define LOGINFO(m) PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG,iLogger,PVLOGMSG_INFO,m); 55 56 57 58 /////////////////////////////////////////////////////////////////////////////////////// 59 // HTTPContentInfoInternal object encapsulates content type/length/range infomation parsing happening 60 // on header parsing and entity body parsing 61 struct HTTPContentInfoInternal 62 { 63 uint32 iContentLength; // for "Content-Length" 64 uint32 iContentRangeLeft; // for "Content-Range" 65 uint32 iContentRangeRight; 66 67 // constructor HTTPContentInfoInternalHTTPContentInfoInternal68 HTTPContentInfoInternal() : iBoundaryBuffer(NULL) 69 { 70 clear(); 71 } 72 73 // ~destructor ~HTTPContentInfoInternalHTTPContentInfoInternal74 ~HTTPContentInfoInternal() 75 { 76 clear(); 77 if (iBoundaryBuffer) OSCL_ARRAY_DELETE(iBoundaryBuffer); 78 iBoundaryBuffer = NULL; 79 } 80 81 // clear clearHTTPContentInfoInternal82 void clear() 83 { 84 iContentLength = 0; 85 iContentRangeLeft = 0; 86 iContentRangeRight = 0; 87 88 iContentType = HTTP_CONTENT_NORMAL; 89 iBoundary.setPtrLen("", 0); 90 } 91 getHTTPContentInfoInternal92 void get(HTTPContentInfo &aContentInfo) 93 { 94 aContentInfo.iContentLength = iContentLength; 95 aContentInfo.iContentRangeLeft = iContentRangeLeft; 96 aContentInfo.iContentRangeRight = iContentRangeRight; 97 } 98 99 // operator "=" 100 HTTPContentInfoInternal &operator=(const HTTPContentInfoInternal& x) 101 { 102 iContentLength = x.iContentLength; 103 iContentRangeLeft = x.iContentRangeLeft; 104 iContentRangeRight = x.iContentRangeRight; 105 iContentType = x.iContentType; 106 return *this; 107 } 108 109 bool parseContentInfo(StringKeyValueStore &aKeyValueStore); getContentTypeHTTPContentInfoInternal110 uint32 getContentType() const 111 { 112 return (uint32)iContentType; 113 } 114 // range lengh = range right - range left getContentRangeLengthHTTPContentInfoInternal115 uint32 getContentRangeLength() const 116 { 117 return (iContentRangeRight == 0 ? 0 : iContentRangeRight - iContentRangeLeft + 1); 118 } 119 120 bool parseBoudaryLine(HTTPMemoryFragment &aInputLineData, bool &isFinalBoundary); 121 122 private: 123 void parseContentRange(const StrPtrLen &aContentRange); 124 bool parseContentType(const StrPtrLen &aContentType); 125 void verifyTransferEncoding(const StrPtrLen &aTransferEncodingValue); 126 bool copyBoundaryString(const char* aBoundaryString, const uint32 aBoundaryStringLength); 127 128 private: 129 HTTPContentType iContentType; 130 char *iBoundaryBuffer; 131 StrPtrLen iBoundary; // for "Content-Type : multipart/byteranges" 132 }; 133 134 135 /////////////////////////////////////////////////////////////////////////////////////// 136 // HTTPParserInput object hides fragment concatenation and grouping for header parsing and output generation 137 class HTTPParserInput 138 { 139 140 public: 141 // factory method 142 static HTTPParserInput *create(); 143 144 // destructor 145 ~HTTPParserInput(); 146 147 // clear clear()148 void clear() 149 { 150 iDataInQueue.clear(); 151 iDataOutQueue.clear(); 152 iHTTPMemFrag.clear(); 153 iDataInQueueMemFragOffset = 0; 154 iLineBufferOccupied = 0; 155 } 156 clearOutputQueue()157 void clearOutputQueue() 158 { 159 iDataOutQueue.clear(); 160 } 161 162 // add data 163 bool push_back(OsclRefCounterMemFrag &aFrag); 164 bool getNextCompleteLine(HTTPMemoryFragment &aHttpFrag, bool aHeaderParsed = false); 165 166 // aRequestDataSize==0 means no request size, the function needs to send out whatever amount of data it has, 167 // but with one input data fragment each time. 168 // return value: actual size, if aRequestDataSize > 0, actual size <= aRequestDataSize 169 // actual size = 0, => no data, -1 means error 170 int32 getData(HTTPMemoryFragment &aHttpFrag, const uint32 aRequestDataSize = 0); 171 bool getOutputMemFrag(OsclRefCounterMemFrag &aMemFrag); 172 173 // This function is for parsing multipart content, specically for the final boundary string like --boundaryString--, which could 174 // has no "\r\n", so getNextCompleteLine may not work in this case 175 // In general, if iLineBuffer has data, then send out iLineBuffer, then check if input data queue has data, if it has, then send 176 // out the first buffer. Return false for no any data (both iLineBuffer and data queue are empty) 177 // Note that this function doesn't do "get" (i.e. not changing internal pointers), instead, only does "view" 178 bool viewAvailableInputData(HTTPMemoryFragment &aHttpFrag); 179 bool empty(); 180 181 // pass ending CRLF 182 void skipCRLF(); 183 184 private: 185 186 // constructor HTTPParserInput()187 HTTPParserInput() : iLineBufferSize(DEFAULT_MAX_LINE_BUFFER_SIZE) 188 { 189 clear(); 190 } 191 192 // create iLineBuffer 193 bool construct(); 194 195 // return value: 0 => not available ; >0 means the offset of the next complete line from the current point 196 // -1 error 197 int32 isNextLineAvailable(bool aHeaderParsed); 198 // called by isNextLineAvailable() 199 int32 assemblyLineFragments(HTTPMemoryFragment &aFrag); 200 201 // if aNewMemFragPtr=NULL, no change to memory fragment pointer. isNewFrag=false means update the existing fragment 202 // from iDataOutQueue; if isNewFrag=true, get fragment from iDataInQueue 203 bool constructOutputFragment(const uint32 aNewMemFragLen, const void *aNewMemFragPtr = NULL, bool isNewFrag = false); 204 int32 checkNextLine(HTTPMemoryFragment &aInputDataStream); 205 206 private: 207 Oscl_Vector<OsclRefCounterMemFrag, OsclMemAllocator> iDataInQueue; 208 Oscl_Vector<RefCounterMemoryFragment, OsclMemAllocator> iDataOutQueue; // RefCounterMemoryFragment defined in http_parcom_internal.h 209 uint32 iDataInQueueMemFragOffset; 210 HTTPMemoryFragment iHTTPMemFrag; // hold the input data fragment being processed 211 char *iLineBuffer; // concatenate multiple fragments of each header line 212 uint32 iLineBufferSize; 213 uint32 iLineBufferOccupied; 214 }; 215 216 /////////////////////////////////////////////////////////////////////////////////////// 217 // HTTPParserBaseObject is the base class for header class and entity body class that still needs some kind of 218 // header parsing inside the entity body 219 220 #define LOGGER_TAG "datapath.sourcenode.protocolenginenode" // "protocolenginenode.protocolengine" 221 //#define LOGGER_TAG "protocolenginenode.protocolengine" 222 223 224 class HTTPParserBaseObject 225 { 226 public: 227 int32 parseHeaderFields(HTTPMemoryFragment &aInputLineData, const bool aReplaceOldValue = false); 228 bool constructEntityUnit(HTTPParserInput &aParserInput, RefCountHTTPEntityUnit &aEntityUnit); 229 void saveEndingCRLF(char *ptr, uint32 len, uint8& aCRLF, bool aNeedReset = true); 230 231 // constructor 232 HTTPParserBaseObject(StringKeyValueStore *aKeyValueStore = NULL, PVMFBufferPoolAllocator *aEntityUnitAlloc = NULL) : iKeyValueStore(aKeyValueStore)233 iKeyValueStore(aKeyValueStore), iEntityUnitAlloc(aEntityUnitAlloc), iPrevCRLF(0) 234 { 235 iLogger = PVLogger::GetLoggerObject(LOGGER_TAG); 236 } 237 238 protected: 239 // due to the fact that Key-Value store may increase size in the fly, create this method to 240 // to wrap up all the details 241 // return code comes from HTTPParser return code 242 int32 addKeyValuePairToStore(const char *aFieldKey, const uint32 aFieldKeyLength, 243 const char *aFieldValue, const uint32 aFieldValueLength, 244 const bool aNeedReplaceOldValue = false); 245 246 int32 addKeyValuePairToStore(const StrCSumPtrLen &aNewKey, 247 const StrPtrLen &aNewValue, 248 const bool aNeedReplaceOldValue = false); 249 250 private: 251 // return value: 0 normal, 1 end of header 252 int32 getNextFieldKeyValuePair(HTTPMemoryFragment &aInputDataStream, char *&aFieldKey, uint32 &aFieldKeyLength, 253 char *&aFieldValue, uint32 &aFieldValueLength); 254 // return value: 0 normal, 1 end of header, 2 ignore 255 int32 getLineStartPoint(char *&ptr, int32 &len, const bool isKeyItem); 256 // return value: 0 normal, 1 end of header 257 int32 parseNextValueItem(HTTPMemoryFragment &aInputDataStream, char *&valueItemPtr, uint32 &valueItemLength, const bool isKeyItem); 258 259 // called by addKeyValuePairToStore, increase the size of the current store 260 // due to not enough memory to hold new key-value pair 261 bool reallocKeyValueStore(const uint32 aCurrKeyValueSize); 262 263 protected: 264 StringKeyValueStore *iKeyValueStore; 265 PVMFBufferPoolAllocator *iEntityUnitAlloc; 266 uint8 iPrevCRLF; // bit0 -- LF , bit1 -- CR 267 PVLogger *iLogger; 268 }; 269 270 /////////////////////////////////////////////////////////////////////////////////////// 271 // HTTPParserHeaderObject encapsulates HTTP header parsing, basically parses every field inside the header and save it to 272 // key-value store, and also triggers content info parsing 273 class HTTPParserHeaderObject : public HTTPParserBaseObject 274 { 275 public: 276 int32 parse(HTTPParserInput &aParserInput, RefCountHTTPEntityUnit &aEntityUnit); isParsed()277 bool isParsed() const 278 { 279 return iHeaderParsed; 280 } 281 // query this case: parsing header completely means parsing the whole response completely 282 // in case of no http body with content-length setting to zero isWholeResponseParsed()283 bool isWholeResponseParsed() const 284 { 285 return iResponseParsedComplete; 286 } 287 // check if there are some unsupported headers 288 int32 doSanityCheckForResponseHeader(); 289 290 // The following "get" functions are for "get" functions of parser getStatusCode()291 uint32 getStatusCode() const 292 { 293 return iStatusCode; 294 } getNumFields()295 uint32 getNumFields() 296 { 297 return (iKeyValueStore == NULL ? 0 : iKeyValueStore->getNumberOfKeyValuePairs()); 298 } getFieldKeyList(StrPtrLen * & aFieldKeyList)299 uint32 getFieldKeyList(StrPtrLen *&aFieldKeyList) 300 { 301 return (iKeyValueStore == NULL ? 0 : iKeyValueStore->getCurrentKeyList(aFieldKeyList)); 302 } 303 bool getField(const StrCSumPtrLen &aNewFieldKey, StrPtrLen &aNewFieldValue, const uint32 index = 0) 304 { 305 return (iKeyValueStore == NULL ? false : iKeyValueStore->getValueByKey(aNewFieldKey, aNewFieldValue, index)); 306 } getNumberOfFieldsByKey(const StrCSumPtrLen & aNewFieldName)307 uint32 getNumberOfFieldsByKey(const StrCSumPtrLen &aNewFieldName) 308 { 309 return (iKeyValueStore == NULL ? 0 : iKeyValueStore->getNumberOfValuesByKey(aNewFieldName)); 310 } 311 /////////////////////////////////////////////////////////////////////////// 312 313 // get iKeyValueStore and iEntityUnitAlloc, will be used HTTPParserEntityBodyObject getKeyValuesStore()314 StringKeyValueStore *getKeyValuesStore() const 315 { 316 return iKeyValueStore; 317 } getAllocator()318 PVMFBufferPoolAllocator *getAllocator() const 319 { 320 return iEntityUnitAlloc; 321 } 322 323 // constructor HTTPParserHeaderObject()324 HTTPParserHeaderObject() 325 { 326 ; 327 } 328 329 // destructor 330 ~HTTPParserHeaderObject(); 331 332 // reset reset()333 void reset() 334 { 335 iStatusCode = 0; //200; 336 iHttpVersionNum = 0; 337 iHeaderParsed = false; 338 iHeaderFirstLineParsed = false; 339 iResponseParsedComplete = false; 340 if (iKeyValueStore) iKeyValueStore->clear(); 341 iPrevCRLF = 0; 342 } 343 344 // factory method, create iKeyValueStore and iEntityUnitAlloc 345 static HTTPParserHeaderObject *create(HTTPContentInfoInternal *aContentInfo); 346 347 private: 348 // return value: 0 => ok , 1 => data not enough -1 => syntax error 349 int32 parseFirstLine(HTTPMemoryFragment &aInputDataStream); 350 bool construct(HTTPContentInfoInternal *aContentInfo); 351 bool isGoodStatusCode(); 352 bool checkGood1xxCode(); 353 bool checkGood2xxCode(); 354 bool checkHTTPVersion(char* &aPtr); 355 bool checkResponseParsedComplete(); 356 bool checkChunkedTransferEncodingSupported(); 357 358 private: 359 HTTPContentInfoInternal *iContentInfo; 360 uint32 iStatusCode; 361 uint32 iHttpVersionNum; 362 bool iHeaderParsed; 363 bool iHeaderFirstLineParsed; 364 bool iResponseParsedComplete; 365 }; 366 367 /////////////////////////////////////////////////////////////////////////////////////// 368 // HTTPParserEntityBodyObject encapsulates HTTP entity body parsing. Here we support three types of entity body, 369 // normal body without any internal headers (usually in HTTP 1.0), multipart/byteranges used in pv fasttrack download 370 // and chunked transfer encoding, both having internal headers. To handle these three types of content, the following 371 // classes are designed to remove conditional using polymorphism, or remove type code with class, i.e. derived classes 372 // implement the interface defined in the base class, parse(). 373 class HTTPParserEntityBodyObject : public HTTPParserBaseObject 374 { 375 public: 376 virtual int32 parse(HTTPParserInput &aParserInput, RefCountHTTPEntityUnit &aEntityUnit) = 0; 377 378 // constructor HTTPParserEntityBodyObject(StringKeyValueStore * aKeyValueStore,PVMFBufferPoolAllocator * aEntityUnitAlloc,HTTPContentInfoInternal * aContentInfo)379 HTTPParserEntityBodyObject(StringKeyValueStore *aKeyValueStore, 380 PVMFBufferPoolAllocator *aEntityUnitAlloc, 381 HTTPContentInfoInternal *aContentInfo) : 382 HTTPParserBaseObject(aKeyValueStore, aEntityUnitAlloc), 383 iContentInfo(aContentInfo), 384 iCurrentChunkDataLength(0), 385 iNumChunks(0), 386 iCounter(0) 387 { 388 ; 389 } 390 ~HTTPParserEntityBodyObject()391 virtual ~HTTPParserEntityBodyObject() 392 { 393 ; 394 } 395 396 protected: 397 // used in HTTPParserCTEContentObject and HTTPParserMultipartContentObject 398 int32 parseEnityBodyChunkData(HTTPParserInput &aParserInput, RefCountHTTPEntityUnit &aEntityUnit); 399 400 protected: 401 HTTPContentInfoInternal *iContentInfo; 402 uint32 iCurrentChunkDataLength; 403 uint32 iNumChunks; 404 uint32 iCounter; // for debugging purpose 405 }; 406 407 /////////////////////////////////////////////////////////////////////////////////////// 408 class HTTPParserNormalContentObject : public HTTPParserEntityBodyObject 409 { 410 public: 411 int32 parse(HTTPParserInput &aParserInput, RefCountHTTPEntityUnit &aEntityUnit); 412 413 // constructor HTTPParserNormalContentObject(StringKeyValueStore * aKeyValueStore,PVMFBufferPoolAllocator * aEntityUnitAlloc,HTTPContentInfoInternal * aContentInfo)414 HTTPParserNormalContentObject(StringKeyValueStore *aKeyValueStore, 415 PVMFBufferPoolAllocator *aEntityUnitAlloc, 416 HTTPContentInfoInternal *aContentInfo) : 417 HTTPParserEntityBodyObject(aKeyValueStore, aEntityUnitAlloc, aContentInfo), 418 iCurrTotalLengthObtained(0) 419 { 420 ; 421 } ~HTTPParserNormalContentObject()422 virtual ~HTTPParserNormalContentObject() 423 { 424 ; 425 } 426 427 private: 428 uint32 iCurrTotalLengthObtained; 429 }; 430 431 /////////////////////////////////////////////////////////////////////////////////////// 432 // CTE = Chunked Transfer Encoding 433 class HTTPParserCTEContentObject : public HTTPParserEntityBodyObject 434 { 435 public: 436 int32 parse(HTTPParserInput &aParserInput, RefCountHTTPEntityUnit &aEntityUnit); 437 438 // constructor HTTPParserCTEContentObject(StringKeyValueStore * aKeyValueStore,PVMFBufferPoolAllocator * aEntityUnitAlloc,HTTPContentInfoInternal * aContentInfo)439 HTTPParserCTEContentObject(StringKeyValueStore *aKeyValueStore, 440 PVMFBufferPoolAllocator *aEntityUnitAlloc, 441 HTTPContentInfoInternal *aContentInfo) : 442 HTTPParserEntityBodyObject(aKeyValueStore, aEntityUnitAlloc, aContentInfo) 443 { 444 ; 445 } 446 ~HTTPParserCTEContentObject()447 virtual ~HTTPParserCTEContentObject() 448 { 449 ; 450 } 451 private: 452 bool getCTEChunkLength(HTTPMemoryFragment &aInputLineData, int32 &aChunkSize); 453 // reset for next chunk parsing reset()454 void reset() 455 { 456 iCurrentChunkDataLength = 0; 457 if (iContentInfo) 458 { 459 iContentInfo->iContentRangeLeft = 0; 460 iContentInfo->iContentRangeRight = 0; 461 } 462 } 463 }; 464 465 /////////////////////////////////////////////////////////////////////////////////////// 466 class HTTPParserMultipartContentObject : public HTTPParserEntityBodyObject 467 { 468 public: 469 int32 parse(HTTPParserInput &aParserInput, RefCountHTTPEntityUnit &aEntityUnit); 470 471 // constructor HTTPParserMultipartContentObject(StringKeyValueStore * aKeyValueStore,PVMFBufferPoolAllocator * aEntityUnitAlloc,HTTPContentInfoInternal * aContentInfo)472 HTTPParserMultipartContentObject(StringKeyValueStore *aKeyValueStore, 473 PVMFBufferPoolAllocator *aEntityUnitAlloc, 474 HTTPContentInfoInternal *aContentInfo) : 475 HTTPParserEntityBodyObject(aKeyValueStore, aEntityUnitAlloc, aContentInfo) 476 { 477 reset(); 478 } 479 ~HTTPParserMultipartContentObject()480 virtual ~HTTPParserMultipartContentObject() 481 { 482 ; 483 } 484 private: reset()485 void reset() 486 { 487 iBoudaryLineParsed = iHeaderInEntityBodyParsed = false; 488 iCurrentChunkDataLength = 0; 489 iNumChunks = 0; 490 } 491 needSkipCRLF()492 bool needSkipCRLF() 493 { 494 // iPrevCRLF&0x3!=0x3 means iPrevCRLF hasn't got complete CRLF (i.e.both CR and LF) 495 return ((iNumChunks == 0) && ((iPrevCRLF&0x3) != 0x3)); 496 } 497 498 int32 parseChunkHeader(HTTPParserInput &aParserInput); 499 int32 parseChunkBoundaryLine(HTTPParserInput &aParserInput); 500 501 private: 502 bool iBoudaryLineParsed; 503 bool iHeaderInEntityBodyParsed; 504 505 }; 506 507 508 #endif // HTTP_PARSER_INTERNAL_H_ 509 510