• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* ------------------------------------------------------------------
2  * Copyright (C) 1998-2009 PacketVideo
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
13  * express or implied.
14  * See the License for the specific language governing permissions
15  * and limitations under the License.
16  * -------------------------------------------------------------------
17  */
18 #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