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 #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