• 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 #include "http_composer.h"
19 #include "http_parcom_internal.h"
20 #include "string_keyvalue_store.h"
21 #include "oscl_string_utils.h"
22 #include "oscl_string_containers.h"
23 
24 
25 ////////////////////////////////////////////////////////////////////////////////////
26 ////// HTTPComposer implementation /////////////////////////////////////////////////
27 ////////////////////////////////////////////////////////////////////////////////////
28 
reset(const bool aKeepAllSettingsExceptURI)29 OSCL_EXPORT_REF void HTTPComposer::reset(const bool aKeepAllSettingsExceptURI)
30 {
31     // reset URI
32     iURI.setPtrLen("", 0);
33     iHeaderLength     = 0;
34     iFirstLineLength  = 0;
35     iEntityBodyLength = 0;
36     if (aKeepAllSettingsExceptURI) return;
37 
38     // reset other stuff
39     iMethod  = HTTP_METHOD_GET;
40     iVersion = HTTP_V1_0;
41 
42     if (iKeyValueStore) iKeyValueStore->clear();
43 }
44 
45 ////////////////////////////////////////////////////////////////////////////////////
46 // factory method
create()47 OSCL_EXPORT_REF HTTPComposer* HTTPComposer::create()
48 {
49     HTTPComposer *composer = OSCL_NEW(HTTPComposer, ());
50     if (!composer) return NULL;
51     if (!composer->construct())
52     {
53         OSCL_DELETE(composer);
54         return NULL;
55     }
56     return composer;
57 }
58 
59 ////////////////////////////////////////////////////////////////////////////////////
construct()60 bool HTTPComposer::construct()
61 {
62     reset();
63     if ((iKeyValueStore = StringKeyValueStore::create()) == NULL) return false;
64     return true;
65 }
66 
67 ////////////////////////////////////////////////////////////////////////////////////
68 // destructor
~HTTPComposer()69 OSCL_EXPORT_REF HTTPComposer::~HTTPComposer()
70 {
71     reset();
72 
73     // delete iKeyValueStore
74     if (iKeyValueStore) OSCL_DELETE(iKeyValueStore);
75     iKeyValueStore = NULL;
76 }
77 
78 ////////////////////////////////////////////////////////////////////////////////////
setURI(const StrPtrLen aURI)79 OSCL_EXPORT_REF void HTTPComposer::setURI(const StrPtrLen aURI)
80 {
81     iURI = aURI;
82 
83     // get relative URI
84     const char *aServerAddPtr = oscl_strstr(((char*)aURI.c_str()), "//");
85     if (!aServerAddPtr) return;
86     aServerAddPtr += 2;
87     const char *aRelativeUriPtr = oscl_strstr(aServerAddPtr, "/");
88     if (!aRelativeUriPtr) return;
89     iRelativeURI = StrPtrLen(aRelativeUriPtr);
90 }
91 
92 ////////////////////////////////////////////////////////////////////////////////////
setField(const StrCSumPtrLen & aNewFieldName,const char * aNewFieldValue,const bool aNeedReplaceOldValue)93 OSCL_EXPORT_REF bool HTTPComposer::setField(const StrCSumPtrLen &aNewFieldName, const char *aNewFieldValue, const bool aNeedReplaceOldValue)
94 {
95     if (!iKeyValueStore) return false;
96 
97     if (aNewFieldValue)
98     {
99         return (iKeyValueStore->addKeyValuePair(aNewFieldName, aNewFieldValue, aNeedReplaceOldValue) ==
100                 StringKeyValueStore::StringKeyValueStore_Success);
101     }
102 
103     // remove this field
104     return iKeyValueStore->removeKeyValuePair(aNewFieldName);
105 }
106 
107 ////////////////////////////////////////////////////////////////////////////////////
setField(const StrCSumPtrLen & aNewFieldName,const StrPtrLen * aNewFieldValue,const bool aNeedReplaceOldValue)108 OSCL_EXPORT_REF bool HTTPComposer::setField(const StrCSumPtrLen &aNewFieldName, const StrPtrLen *aNewFieldValue, const bool aNeedReplaceOldValue)
109 {
110     if (!iKeyValueStore) return false;
111     if (!aNewFieldValue) return iKeyValueStore->removeKeyValuePair(aNewFieldName);
112     return (iKeyValueStore->addKeyValuePair(aNewFieldName, *aNewFieldValue, aNeedReplaceOldValue) ==
113             StringKeyValueStore::StringKeyValueStore_Success);
114 }
115 
116 
117 ////////////////////////////////////////////////////////////////////////////////////
getCurrentRequestLength(const bool usingAbsoluteURI)118 OSCL_EXPORT_REF int32 HTTPComposer::getCurrentRequestLength(const bool usingAbsoluteURI)
119 {
120     // sanity check
121     if (!usingAbsoluteURI && iRelativeURI.length() == 0) return COMPOSE_BAD_URI;
122 
123     // since iHeaderLength is updated for each setField, we only need to calculate the request-line length
124     // Request-line: Method SP Request-URI SP HTTP-Version CRLF
125     iFirstLineLength = oscl_strlen(HTTPMethodString[(uint32)iMethod]); // method
126     StrPtrLen *uriPtr = (usingAbsoluteURI ? (&iURI) : (&iRelativeURI));
127     iFirstLineLength += uriPtr->length(); // uri
128     iFirstLineLength += 8; // "HTTP/1.1" or "HTTP/1.0"
129     iFirstLineLength += 4; // 2 SPs + CRLF
130     iHeaderLength = iFirstLineLength;
131 
132     // header fields part
133     iHeaderLength += (iKeyValueStore->getTotalKeyValueLength() +
134                       iKeyValueStore->getNumberOfKeyValuePairs() * 4); // 4 => key:SPvalueCRLF, 1SP + ':' + CRLT
135 
136     iHeaderLength += 2; // final CRLF
137 
138     return (int32)(iHeaderLength + iEntityBodyLength);
139 }
140 
141 
142 ////////////////////////////////////////////////////////////////////////////////////
compose(OsclMemoryFragment & aComposedMessageBuffer,const bool usingAbsoluteURI,const uint32 aEntityBodyLength)143 OSCL_EXPORT_REF int32 HTTPComposer::compose(OsclMemoryFragment &aComposedMessageBuffer, const bool usingAbsoluteURI, const uint32 aEntityBodyLength)
144 {
145     HTTPMemoryFragment messageBuffer(aComposedMessageBuffer);
146 
147     // sanity check, all the list error codes will pop up here if there is an error
148     int32 status = santityCheckForCompose(messageBuffer, usingAbsoluteURI, aEntityBodyLength);
149     if (status != COMPOSE_SUCCESS) return status;
150     iEntityBodyLength = aEntityBodyLength;
151 
152     // compose the first request/status line
153     composeFirstLine(messageBuffer, usingAbsoluteURI);
154 
155     // compose the header part: general header + request header + entity header
156     composeHeaders(messageBuffer);
157 
158     // if there is an enity body, then it should be in place,
159     // then add NULL terminator for a string
160     if (messageBuffer.getAvailableSpace() > 0)
161     {
162         *((char*)messageBuffer.getPtr() + iEntityBodyLength) = HTTP_CHAR_NULL;
163         messageBuffer.update(1);
164     }
165 
166     return COMPOSE_SUCCESS;
167 }
168 
169 ////////////////////////////////////////////////////////////////////////////////////
170 // supporting function for compose()
santityCheckForCompose(HTTPMemoryFragment & aComposedMessageBuffer,const bool usingAbsoluteURI,const uint32 aEntityBodyLength)171 int32 HTTPComposer::santityCheckForCompose(HTTPMemoryFragment &aComposedMessageBuffer, const bool usingAbsoluteURI, const uint32 aEntityBodyLength)
172 {
173     // check URI
174     if (!usingAbsoluteURI && iRelativeURI.length() == 0) return COMPOSE_BAD_URI;
175 
176     // check input buffer size
177     if (!aComposedMessageBuffer.isSpaceEnough(getCurrentRequestLength(usingAbsoluteURI) + aEntityBodyLength))
178     {
179         return COMPOSE_BUFFER_TOO_SMALL;
180     }
181 
182     // check URI
183     if (iURI.length() == 0) return COMPOSE_URI_NOT_SET;
184 
185     // check content type and content length for entity body
186     if (aEntityBodyLength)
187     {
188         StrCSumPtrLen contentType("Content-Type");
189         if (!iKeyValueStore->isKeyValueAvailable(contentType)) // no "Content-Type" key
190             return COMPOSE_CONTENT_TYPE_NOT_SET_FOR_ENTITY_BODY;
191 
192         StrCSumPtrLen contentLengthKey("Content-Length");
193         StrPtrLen contentLengthValue;
194         if (!iKeyValueStore->getValueByKey(contentLengthKey, contentLengthValue)) // no "Content-Length" key
195             return COMPOSE_CONTENT_LENGTH_NOT_SET_FOR_ENTITY_BODY;
196 
197         uint32 contentLength;
198         PV_atoi(contentLengthValue.c_str(), 'd', contentLengthValue.length(), contentLength);
199         if (contentLength != aEntityBodyLength) return COMPOSE_CONTENT_LENGTH_NOT_MATCH_ENTITY_BODY_LENGTH;
200     }
201 
202     return COMPOSE_SUCCESS;
203 }
204 
205 ////////////////////////////////////////////////////////////////////////////////////
composeFirstLine(HTTPMemoryFragment & aComposedMessageBuffer,const bool usingAbsoluteURI)206 void HTTPComposer::composeFirstLine(HTTPMemoryFragment &aComposedMessageBuffer, const bool usingAbsoluteURI)
207 {
208     // Request-line: Method SP Request-URI SP HTTP-Version CRLF
209     char *ptr = (char *)aComposedMessageBuffer.getPtr();
210     oscl_memcpy(ptr, HTTPMethodString[(uint32)iMethod], oscl_strlen(HTTPMethodString[(uint32)iMethod]));
211     ptr += oscl_strlen(HTTPMethodString[iMethod]);
212     *ptr++ = HTTP_CHAR_SPACE;
213     StrPtrLen *uriPtr = (usingAbsoluteURI ? (&iURI) : (&iRelativeURI));
214     oscl_memcpy(ptr, uriPtr->c_str(), uriPtr->length());
215     ptr += uriPtr->length();
216     *ptr++ = HTTP_CHAR_SPACE;
217 
218     // HTTP version
219     OSCL_FastString versionString;
220     if (iVersion == HTTP_V1_1)
221     {
222         versionString.set((OSCL_String::chartype*)_STRLIT_CHAR("HTTP/1.1"), 8);
223     }
224     else
225     {
226         versionString.set((OSCL_String::chartype*)_STRLIT_CHAR("HTTP/1.0"), 8);
227     }
228     oscl_memcpy(ptr, versionString.get_cstr(), 8);
229     ptr += 8;
230     *ptr++ = HTTP_CHAR_CR;
231     *ptr++ = HTTP_CHAR_LF;
232 
233     OSCL_ASSERT(iFirstLineLength == (uint32)(ptr - (char*)aComposedMessageBuffer.getPtr()));
234     aComposedMessageBuffer.update(iFirstLineLength);
235 }
236 
237 ////////////////////////////////////////////////////////////////////////////////////
238 class CleanupObject
239 {
240         StrPtrLen *iKeyList;
241         StrPtrLen *iValueList;
242 
243     public:
CleanupObject(StrPtrLen * aKeyList=NULL,StrPtrLen * aValueList=NULL)244         CleanupObject(StrPtrLen *aKeyList = NULL, StrPtrLen *aValueList = NULL) :
245                 iKeyList(aKeyList), iValueList(aValueList)
246         {
247             ;
248         }
249 
250         //! Use destructor to do all the clean up work
~CleanupObject()251         ~CleanupObject()
252         {
253             if (iKeyList) OSCL_ARRAY_DELETE(iKeyList);
254             if (iValueList) OSCL_ARRAY_DELETE(iValueList);
255         }
256 
setKeyList(StrPtrLen * aKeyList)257         void setKeyList(StrPtrLen *aKeyList)
258         {
259             iKeyList = aKeyList;
260         }
setValueList(StrPtrLen * aValueList)261         void setValueList(StrPtrLen *aValueList)
262         {
263             iValueList = aValueList;
264         }
265 };
266 
composeHeaders(HTTPMemoryFragment & aComposedMessageBuffer)267 bool HTTPComposer::composeHeaders(HTTPMemoryFragment &aComposedMessageBuffer)
268 {
269     char *ptr = (char *)aComposedMessageBuffer.getPtr();
270     CleanupObject cleanup;
271 
272     uint32 numKeyValuePairs = iKeyValueStore->getNumberOfKeyValuePairs();
273     if (numKeyValuePairs > 0)
274     {
275         StrPtrLen *keyList = OSCL_ARRAY_NEW(StrPtrLen, numKeyValuePairs);
276         cleanup.setKeyList(keyList);
277         StrPtrLen *valueList = OSCL_ARRAY_NEW(StrPtrLen, numKeyValuePairs);
278         cleanup.setValueList(valueList);
279         if (!keyList || !valueList) return false; // let cleanup object to do automatic deallocation
280 
281         // get key list
282         uint32 numKeys = iKeyValueStore->getCurrentKeyList(keyList);
283         if (numKeys == 0)  return false;
284 
285         uint32 i, j, index = 0;
286         for (i = 0, j = 0; i < numKeyValuePairs && j < numKeys; j++)
287         {
288             index = 0;
289             while (iKeyValueStore->getValueByKey(keyList[j], valueList[i], index))
290             {
291                 // put key
292                 oscl_memcpy(ptr, keyList[j].c_str(), keyList[j].length()); // same field key
293                 ptr += keyList[j].length();
294                 *ptr++ = HTTP_CHAR_COLON;
295                 *ptr++ = HTTP_CHAR_SPACE;
296 
297                 // put value
298                 oscl_memcpy(ptr, valueList[i].c_str(), valueList[i].length()); // same field key
299                 ptr += valueList[i].length();
300                 *ptr++ = HTTP_CHAR_CR;
301                 *ptr++ = HTTP_CHAR_LF;
302                 index++;
303             }
304             i += index;
305         }
306     }
307 
308     // add final CRLF
309     *ptr++ = HTTP_CHAR_CR;
310     *ptr++ = HTTP_CHAR_LF;
311 
312     OSCL_ASSERT(iHeaderLength == (ptr - (char*)aComposedMessageBuffer.getPtr() + aComposedMessageBuffer.getLen()));
313     aComposedMessageBuffer.update(ptr);
314     return true;
315 }
316 
317