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 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 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 //////////////////////////////////////////////////////////////////////////////////// 60 bool HTTPComposer::construct() 61 { 62 reset(); 63 if ((iKeyValueStore = StringKeyValueStore::create()) == NULL) return false; 64 return true; 65 } 66 67 //////////////////////////////////////////////////////////////////////////////////// 68 // destructor 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 //////////////////////////////////////////////////////////////////////////////////// 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 //////////////////////////////////////////////////////////////////////////////////// 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 //////////////////////////////////////////////////////////////////////////////////// 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 //////////////////////////////////////////////////////////////////////////////////// 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 //////////////////////////////////////////////////////////////////////////////////// 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() 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 //////////////////////////////////////////////////////////////////////////////////// 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: 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 251 ~CleanupObject() 252 { 253 if (iKeyList) OSCL_ARRAY_DELETE(iKeyList); 254 if (iValueList) OSCL_ARRAY_DELETE(iValueList); 255 } 256 257 void setKeyList(StrPtrLen *aKeyList) 258 { 259 iKeyList = aKeyList; 260 } 261 void setValueList(StrPtrLen *aValueList) 262 { 263 iValueList = aValueList; 264 } 265 }; 266 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