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_H_ 19 #define HTTP_PARSER_H_ 20 21 22 /////////////////////////////////////////////////////////////////////////////////////// 23 24 #include "oscl_base.h" 25 #include "oscl_mem.h" 26 #include "oscl_str_ptr_len.h" 27 #include "http_parser_external.h" // define struct HTTPContentInfo and class RefCountHTTPEntityUnit 28 29 // forward declarations 30 struct HTTPContentInfoInternal; 31 class HTTPParserInput; 32 class HTTPParserHeaderObject; 33 class HTTPParserEntityBodyObject; 34 35 class HTTPParser 36 { 37 38 public: 39 40 /** 41 * the sole parsing function to parse both HTTP header and entity body. Since the input data stream is a fragment of a complete 42 * HTTP response message (for client), the input data fragment is assumed arbitrary, i.e, its starting and ending position could 43 * be anywhere in a complete HTTP response message. Considering HTTP header could spread among multiple input data stream 44 * fragments, like the entity body case, parsing header and parsing entity body can be handled in a unified way. The output is 45 * entity unit which could be a complete HTTP header (FIRST entity unit), or a complete chunk of data for partial content, or the 46 * whole input data fragment. To avoid memory copy, we do inplace processing, i.e. the output entity unit is represented by a set 47 * of memory fragment pointers to point to the actual memory fragments inside the input data streams that may inlude the previous 48 * input data streams. Considering an entity unit may need one or mulitple input data fragments and an input data fragment could 49 * constain multiple entity units, the memory for an input data fragment can only be released after all the related entity units 50 * it has have been parsed and used. So the input data fragment needs to reference counted. Also the output entity unit needs to 51 * be reference counted. This lets the user not worry about how to release and re-use the existing memory fragment. Each time, 52 * user just need to create new memory fragment from a memory pool and pass it down to library in normal cases. Reference counter 53 * will automatically take care of memory deallocation. In the case where the previous input data fragment contains multiple entity 54 * units, user needs to input EMPTY fragment or the previous fragment again to let the library send out the next entity unit (since 55 * each time this function only sends out ONE enity unit if it has multiple). 56 * Return value: see the following enum. For PARSE_HEADER_AVAILABLE, user need to call getHTTPStatusCode() to get status code 57 * @param aInputDataStream, ref-counted input data fragment 58 * @param aEntityUnit, ref-counted output entity unit 59 * @return following PARSE_RETURN_CODES 60 * 61 * NOTE: as long as the return code is non-negative, user need to check the output entity unit to see whether there is something 62 * inside, and also user needs to do concatenation for the output fragments. 63 **/ 64 OSCL_IMPORT_REF int32 parse(const OsclRefCounterMemFrag &aInputDataStream, RefCountHTTPEntityUnit &aEntityUnit); 65 66 67 /** 68 * If http response header is available, status code is ok (though parse() already does some sanity check for status code), 69 * there still could be some headers that need further check, i.e. some headers are only supported in HTTP/1.1, such as Transfer-Encoding 70 * @return following PARSE_RETURN_CODES, list the unsupported items. 71 **/ 72 OSCL_IMPORT_REF int32 doSanityCheckForResponseHeader(); 73 74 75 // return codes for parse function 76 enum PARSE_RETURN_CODES 77 { 78 PARSE_SUCCESS = 0, // success with left over of the current input, don't send the new input next time 79 PARSE_SUCCESS_END_OF_INPUT = 1, // success with end of the current input 80 PARSE_SUCCESS_END_OF_MESSAGE = 2, // success with end of the message (get data with the size of content-length) 81 PARSE_SUCCESS_END_OF_MESSAGE_WITH_EXTRA_DATA = 3, // success with end of the message (get data with the size of content-length), but input has more extra data 82 83 PARSE_HEADER_AVAILABLE = 4, // HTTP header is parsed 84 PARSE_STATUS_LINE_SHOW_NOT_SUCCESSFUL = 5, // parse the first http status line, 85 // got status code >= 300, 3xx=>redirection, 4xx=>client error, 5xx=>server error 86 // note that this is return code when parser just finishes parsing the first line, 87 // user can continue calling parse function to get the complete http header 88 PARSE_NEED_MORE_DATA = 6, // no ouput, no entity units 89 90 // errors 91 PARSE_GENERAL_ERROR = -1, 92 PARSE_SYNTAX_ERROR = -2, // syntax is not understandable 93 PARSE_HTTP_VERSION_NOT_SUPPORTED = -3, // no HTTP version or HTTP version is different from 1.0 or 1.1. 94 PARSE_TRANSFER_ENCODING_NOT_SUPPORTED = -4, 95 PARSE_MEMORY_ALLOCATION_FAILURE = -5, // memory allocation for entity units 96 PARSE_HEADER_NOT_PARSED_YET = -6 // HTTP header hasn't been parsed yet, so shouldn't expect parsing entity body 97 }; 98 99 100 // After parsing HTTP header(parse() return PARSE_HEADER_AVAILABLE), use the following functions to get the related information 101 // get content info 102 OSCL_IMPORT_REF void getContentInfo(HTTPContentInfo &aContentInfo); 103 // get total fields inside the header 104 OSCL_IMPORT_REF uint32 getTotalFieldsInHeader(); 105 // get a list of all field keys inside the header 106 OSCL_IMPORT_REF uint32 getFieldKeyListInHeader(StrPtrLen *&aFieldKeyList); 107 // get the field value with the given field key, which can be retrieved from getFieldKeyListInHeader() 108 // There could be a case where one field key correponds to multiple field values, so input argument "index" is for 109 // getting which value for the given field key 110 OSCL_IMPORT_REF bool getField(const StrCSumPtrLen &aNewFieldName, StrPtrLen &aNewFieldValue, const uint32 index = 0); 111 // get the number of field key-value pairs with the same field key. 0 => no such key, 1 or more => number of key-value pairs 112 OSCL_IMPORT_REF uint32 getNumberOfFieldsByKey(const StrCSumPtrLen &aNewFieldName); 113 // get the status code, 1xx, 2xx, 3xx, 4xx, 5xx 114 OSCL_IMPORT_REF uint32 getHTTPStatusCode(); 115 ///////////////////////////////////////////////////////////////////////////////////////////// 116 117 // reset the parser to parse a new HTTP response 118 OSCL_IMPORT_REF void reset(); 119 120 // factory method 121 OSCL_IMPORT_REF static HTTPParser *create(); 122 123 // destructor 124 OSCL_IMPORT_REF ~HTTPParser(); 125 126 private: 127 int32 parseEntityBody(RefCountHTTPEntityUnit &aEntityUnit); 128 129 // called by create() to construct the parser 130 bool construct(); 131 132 // constructor HTTPParser()133 HTTPParser() 134 { 135 oscl_memset(this, 0, sizeof(HTTPParser)); 136 } 137 138 private: 139 // Basically, this parser is decomposed into the following objects. 140 // HTTPParserInput handles input data stream concatenation and fragment grouping for parsing and entity unit output 141 // HTTPContentInfo contains content type, content length and content range information and does infomation parsing. 142 // HTTPParserHeaderObject and HTTPParserEntityBodyObject handles header and entity body parsing 143 HTTPParserInput *iParserInput; 144 HTTPContentInfoInternal *iContentInfo; 145 HTTPParserHeaderObject *iHeader; 146 HTTPParserEntityBodyObject *iEntityBody; 147 }; 148 149 #endif // HTTP_PARSER_H_ 150 151