Home | History | Annotate | Download | only in src
      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
     68     HTTPContentInfoInternal() : iBoundaryBuffer(NULL)
     69     {
     70         clear();
     71     }
     72 
     73     // ~destructor
     74     ~HTTPContentInfoInternal()
     75     {
     76         clear();
     77         if (iBoundaryBuffer) OSCL_ARRAY_DELETE(iBoundaryBuffer);
     78         iBoundaryBuffer = NULL;
     79     }
     80 
     81     // clear
     82     void clear()
     83     {
     84         iContentLength     = 0;
     85         iContentRangeLeft  = 0;
     86         iContentRangeRight = 0;
     87 
     88         iContentType = HTTP_CONTENT_NORMAL;
     89         iBoundary.setPtrLen("", 0);
     90     }
     91 
     92     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);
    110     uint32 getContentType() const
    111     {
    112         return (uint32)iContentType;
    113     }
    114     // range lengh = range right - range left
    115     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
    148         void clear()
    149         {
    150             iDataInQueue.clear();
    151             iDataOutQueue.clear();
    152             iHTTPMemFrag.clear();
    153             iDataInQueueMemFragOffset = 0;
    154             iLineBufferOccupied = 0;
    155         }
    156 
    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
    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) :
    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);
    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
    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
    291         uint32 getStatusCode() const
    292         {
    293             return iStatusCode;
    294         }
    295         uint32 getNumFields()
    296         {
    297             return (iKeyValueStore == NULL ? 0 : iKeyValueStore->getNumberOfKeyValuePairs());
    298         }
    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         }
    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
    314         StringKeyValueStore *getKeyValuesStore() const
    315         {
    316             return iKeyValueStore;
    317         }
    318         PVMFBufferPoolAllocator *getAllocator() const
    319         {
    320             return iEntityUnitAlloc;
    321         }
    322 
    323         // constructor
    324         HTTPParserHeaderObject()
    325         {
    326             ;
    327         }
    328 
    329         // destructor
    330         ~HTTPParserHeaderObject();
    331 
    332         // 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
    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 
    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
    414         HTTPParserNormalContentObject(StringKeyValueStore *aKeyValueStore,
    415                                       PVMFBufferPoolAllocator *aEntityUnitAlloc,
    416                                       HTTPContentInfoInternal *aContentInfo) :
    417                 HTTPParserEntityBodyObject(aKeyValueStore, aEntityUnitAlloc, aContentInfo),
    418                 iCurrTotalLengthObtained(0)
    419         {
    420             ;
    421         }
    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
    439         HTTPParserCTEContentObject(StringKeyValueStore *aKeyValueStore,
    440                                    PVMFBufferPoolAllocator *aEntityUnitAlloc,
    441                                    HTTPContentInfoInternal *aContentInfo) :
    442                 HTTPParserEntityBodyObject(aKeyValueStore, aEntityUnitAlloc, aContentInfo)
    443         {
    444             ;
    445         }
    446 
    447         virtual ~HTTPParserCTEContentObject()
    448         {
    449             ;
    450         }
    451     private:
    452         bool getCTEChunkLength(HTTPMemoryFragment &aInputLineData, int32 &aChunkSize);
    453         // reset for next chunk parsing
    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
    472         HTTPParserMultipartContentObject(StringKeyValueStore *aKeyValueStore,
    473                                          PVMFBufferPoolAllocator *aEntityUnitAlloc,
    474                                          HTTPContentInfoInternal *aContentInfo) :
    475                 HTTPParserEntityBodyObject(aKeyValueStore, aEntityUnitAlloc, aContentInfo)
    476         {
    477             reset();
    478         }
    479 
    480         virtual ~HTTPParserMultipartContentObject()
    481         {
    482             ;
    483         }
    484     private:
    485         void reset()
    486         {
    487             iBoudaryLineParsed = iHeaderInEntityBodyParsed = false;
    488             iCurrentChunkDataLength = 0;
    489             iNumChunks = 0;
    490         }
    491 
    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