reSIProcate/stack  9694
Contents.cxx
Go to the documentation of this file.
00001 #include <vector>
00002 
00003 #if defined(HAVE_CONFIG_H)
00004 #include "config.h"
00005 #endif
00006 
00007 #include "resip/stack/Contents.hxx"
00008 #include "rutil/ParseBuffer.hxx"
00009 #include "rutil/Logger.hxx"
00010 #include "resip/stack/OctetContents.hxx"
00011 #include "rutil/WinLeakCheck.hxx"
00012 
00013 using namespace resip;
00014 using namespace std;
00015 
00016 #define RESIPROCATE_SUBSYSTEM Subsystem::CONTENTS
00017 
00018 H_ContentID resip::h_ContentID;
00019 H_ContentDescription resip::h_ContentDescription;
00020 
00021 Contents::Contents(const HeaderFieldValue& headerFieldValue,
00022                    const Mime& contentType) 
00023    : LazyParser(headerFieldValue),
00024       mType(contentType)
00025 {
00026    init();
00027 }
00028 
00029 Contents::Contents(const Mime& contentType) 
00030    : mType(contentType)
00031 {
00032    init();
00033 }
00034 
00035 Contents::Contents(const Contents& rhs) 
00036     : LazyParser(rhs)
00037 {
00038    init(rhs);
00039 }
00040 
00041 Contents::Contents(const Contents& rhs,HeaderFieldValue::CopyPaddingEnum e) 
00042     : LazyParser(rhs,e)
00043 {
00044    init(rhs);
00045 }
00046 
00047 Contents::Contents(const HeaderFieldValue& headerFieldValue,
00048                      HeaderFieldValue::CopyPaddingEnum e,
00049                      const Mime& contentsType)
00050     : LazyParser(headerFieldValue,e),
00051     mType(contentsType)
00052 {
00053    init();
00054 }
00055 
00056 
00057 Contents::~Contents()
00058 {
00059    freeMem();
00060 }
00061 
00062 static const Data errorContextData("Contents");
00063 const Data&
00064 Contents::errorContext() const
00065 {
00066    return errorContextData;
00067 }
00068 
00069 Contents& 
00070 Contents::operator=(const Contents& rhs) 
00071 {
00072    if (this != &rhs)
00073    {
00074       freeMem();
00075       LazyParser::operator=(rhs);
00076       init(rhs);
00077    }
00078 
00079    return *this;
00080 }
00081 
00082 void
00083 Contents::init(const Contents& orig)
00084 {
00085    mBufferList.clear();
00086    mType = orig.mType;
00087    if (orig.mDisposition)
00088    {
00089        mDisposition = new H_ContentDisposition::Type(*orig.mDisposition);
00090    }
00091    else
00092    {
00093       mDisposition = 0;
00094    }
00095    
00096    if (orig.mTransferEncoding)
00097    {
00098        mTransferEncoding = new H_ContentTransferEncoding::Type(*orig.mTransferEncoding);
00099    }
00100    else
00101    {
00102       mTransferEncoding = 0;
00103    }
00104    
00105    if (orig.mLanguages)
00106    {
00107        mLanguages = new H_ContentLanguages::Type(*orig.mLanguages);
00108    }
00109    else
00110    {
00111       mLanguages = 0;
00112    }
00113    
00114    if (orig.mId)
00115    {
00116        mId = new Token(*orig.mId);
00117    }
00118    else
00119    {
00120       mId = 0;
00121    }
00122    
00123    if (orig.mDescription)
00124    {
00125        mDescription = new StringCategory(*orig.mDescription);
00126    }
00127    else
00128    {
00129       mDescription = 0;
00130    }
00131    
00132    if(orig.mLength)
00133    {
00134       mLength = new StringCategory(*orig.mLength);
00135    }
00136    else
00137    {
00138       mLength = 0;
00139    }
00140 
00141    mVersion = orig.mVersion;
00142    mMinorVersion = orig.mMinorVersion;
00143 
00144 }
00145 
00146 Contents*
00147 Contents::createContents(const Mime& contentType, 
00148                          const Data& contents)
00149 {
00150   // !ass! why are we asserting that the Data doesn't own the buffer?
00151   // .dlb. because this method is to be called only within a multipart
00152   // !ass! HFV is an overlay -- then setting c->mIsMine to true ?? dlb Q
00153   // .dlb. we are telling the content that it owns its HFV, not the data that it
00154   // .dlb. owns its memory
00155   // .bwc. So, we are _violating_ _encapsulation_, to make an assertion that the 
00156   // Data is an intermediate instead of owning the buffer itself? What do we 
00157   // care how this buffer is owned? All we require is that the buffer doesn't 
00158   // get dealloced/modified while we're still around. The assertion might mean 
00159   // that the Data will not do either of these things, but it affords no 
00160   // protection from the actual owner doing so. We are no more protected with 
00161   // the assertion, so I am removing it.
00162 //   assert(!contents.mMine);
00163 
00164    HeaderFieldValue hfv(contents.data(), (unsigned int)contents.size());
00165 
00166 // !bwc! This padding stuff is now the responsibility of the Contents class.
00167 //   if(contentType.subType()=="sipfrag"||contentType.subType()=="external-body")
00168 //   {
00169 //      // .bwc. The parser for sipfrag requires padding at the end of the hfv.
00170 //      HeaderFieldValue* temp = hfv;
00171 //      hfv = new HeaderFieldValue(*temp,HeaderFieldValue::CopyPadding);
00172 //      delete temp;
00173 //   }
00174    
00175    Contents* c;
00176    if (ContentsFactoryBase::getFactoryMap().find(contentType) != ContentsFactoryBase::getFactoryMap().end())
00177    {
00178       c = ContentsFactoryBase::getFactoryMap()[contentType]->create(hfv, contentType);
00179    }
00180    else
00181    {
00182       c = new OctetContents(hfv, contentType);
00183    }
00184    return c;
00185 }
00186 
00187 bool
00188 Contents::exists(const HeaderBase& headerType) const
00189 {
00190    checkParsed();
00191    switch (headerType.getTypeNum())
00192    {
00193       case Headers::ContentType :
00194       {
00195          return true;
00196       }
00197       case Headers::ContentDisposition :
00198       {
00199          return mDisposition != 0;
00200       }
00201       case Headers::ContentTransferEncoding :
00202       {
00203          return mTransferEncoding != 0;
00204       }
00205       case Headers::ContentLanguage :
00206       {
00207          return mLanguages != 0;
00208       }
00209       default : return false;
00210    }
00211 }
00212 
00213 bool
00214 Contents::exists(const MIME_Header& type) const
00215 {
00216    if (&type == &h_ContentID)
00217    {
00218       return mId != 0;
00219    }
00220    
00221    if (&type == &h_ContentDescription)
00222    {
00223       return mDescription != 0;
00224    }
00225 
00226    assert(false);
00227    return false;
00228 }
00229 
00230 void
00231 Contents::remove(const HeaderBase& headerType)
00232 {
00233    switch (headerType.getTypeNum())
00234    {
00235       case Headers::ContentDisposition :
00236       {
00237          delete mDisposition;
00238          mDisposition = 0;
00239          break;
00240       }
00241       case Headers::ContentLanguage :
00242       {
00243          delete mLanguages;
00244          mLanguages = 0;
00245          break;
00246       }
00247       case Headers::ContentTransferEncoding :
00248       {
00249          delete mTransferEncoding;
00250          mTransferEncoding = 0;
00251          break;
00252       }
00253       default :
00254          ;
00255    }
00256 }
00257 
00258 void
00259 Contents::remove(const MIME_Header& type)
00260 {
00261    if (&type == &h_ContentID)
00262    {
00263       delete mId;
00264       mId = 0;
00265       return;
00266    }
00267     
00268    if (&type == &h_ContentDescription)
00269    {
00270       delete mDescription;
00271       mDescription = 0;
00272       return;
00273    }
00274 
00275    assert(false);
00276 }
00277 
00278 const H_ContentType::Type&
00279 Contents::header(const H_ContentType& headerType) const
00280 {
00281    return mType;
00282 }
00283 
00284 H_ContentType::Type&
00285 Contents::header(const H_ContentType& headerType)
00286 {
00287    return mType;
00288 }
00289 
00290 const H_ContentDisposition::Type&
00291 Contents::header(const H_ContentDisposition& headerType) const
00292 {
00293    checkParsed();
00294    if (mDisposition == 0)
00295    {
00296       ErrLog(<< "You called "
00297             "Contents::header(const H_ContentDisposition& headerType) _const_ "
00298             "without first calling exists(), and the header does not exist. Our"
00299             " behavior in this scenario is to implicitly create the header(using const_cast!); "
00300             "this is probably not what you want, but it is either this or "
00301             "assert/throw an exception. Since this has been the behavior for "
00302             "so long, we are not throwing here, _yet_. You need to fix your "
00303             "code, before we _do_ start throwing. This is why const-correctness"
00304             " should never be made a TODO item </rant>");
00305       Contents* ncthis = const_cast<Contents*>(this);
00306       ncthis->mDisposition = new H_ContentDisposition::Type;
00307    }
00308    return *mDisposition;
00309 }
00310 
00311 H_ContentDisposition::Type&
00312 Contents::header(const H_ContentDisposition& headerType)
00313 {
00314    checkParsed();
00315    if (mDisposition == 0)
00316    {
00317       mDisposition = new H_ContentDisposition::Type;
00318    }
00319    return *mDisposition;
00320 }
00321 
00322 const H_ContentTransferEncoding::Type&
00323 Contents::header(const H_ContentTransferEncoding& headerType) const
00324 {
00325    checkParsed();
00326    if (mTransferEncoding == 0)
00327    {
00328       ErrLog(<< "You called "
00329             "Contents::header(const H_ContentTransferEncoding& headerType) _const_ "
00330             "without first calling exists(), and the header does not exist. Our"
00331             " behavior in this scenario is to implicitly create the header(using const_cast!); "
00332             "this is probably not what you want, but it is either this or "
00333             "assert/throw an exception. Since this has been the behavior for "
00334             "so long, we are not throwing here, _yet_. You need to fix your "
00335             "code, before we _do_ start throwing. This is why const-correctness"
00336             " should never be made a TODO item </rant>");
00337       Contents* ncthis = const_cast<Contents*>(this);
00338       ncthis->mTransferEncoding = new H_ContentTransferEncoding::Type;
00339    }
00340    return *mTransferEncoding;
00341 }
00342 
00343 H_ContentTransferEncoding::Type&
00344 Contents::header(const H_ContentTransferEncoding& headerType)
00345 {
00346    checkParsed();
00347    if (mTransferEncoding == 0)
00348    {
00349       mTransferEncoding = new H_ContentTransferEncoding::Type;
00350    }
00351    return *mTransferEncoding;
00352 }
00353 
00354 const H_ContentLanguages::Type&
00355 Contents::header(const H_ContentLanguages& headerType) const 
00356 {
00357    checkParsed();
00358    if (mLanguages == 0)
00359    {
00360       ErrLog(<< "You called "
00361             "Contents::header(const H_ContentLanguages& headerType) _const_ "
00362             "without first calling exists(), and the header does not exist. Our"
00363             " behavior in this scenario is to implicitly create the header(using const_cast!); "
00364             "this is probably not what you want, but it is either this or "
00365             "assert/throw an exception. Since this has been the behavior for "
00366             "so long, we are not throwing here, _yet_. You need to fix your "
00367             "code, before we _do_ start throwing. This is why const-correctness"
00368             " should never be made a TODO item </rant>");
00369       Contents* ncthis = const_cast<Contents*>(this);
00370       ncthis->mLanguages = new H_ContentLanguages::Type;
00371    }
00372    return *mLanguages;
00373 }
00374 
00375 H_ContentLanguages::Type&
00376 Contents::header(const H_ContentLanguages& headerType)
00377 {
00378    checkParsed();
00379    if (mLanguages == 0)
00380    {
00381       mLanguages = new H_ContentLanguages::Type;
00382    }
00383    return *mLanguages;
00384 }
00385 
00386 const H_ContentDescription::Type&
00387 Contents::header(const H_ContentDescription& headerType) const
00388 {
00389    checkParsed();
00390    if (mDescription == 0)
00391    {
00392       ErrLog(<< "You called "
00393             "Contents::header(const H_ContentDescription& headerType) _const_ "
00394             "without first calling exists(), and the header does not exist. Our"
00395             " behavior in this scenario is to implicitly create the header(using const_cast!); "
00396             "this is probably not what you want, but it is either this or "
00397             "assert/throw an exception. Since this has been the behavior for "
00398             "so long, we are not throwing here, _yet_. You need to fix your "
00399             "code, before we _do_ start throwing. This is why const-correctness"
00400             " should never be made a TODO item </rant>");
00401       Contents* ncthis = const_cast<Contents*>(this);
00402       ncthis->mDescription = new H_ContentDescription::Type;
00403    }
00404    return *mDescription;
00405 }
00406 
00407 H_ContentDescription::Type&
00408 Contents::header(const H_ContentDescription& headerType)
00409 {
00410    checkParsed();
00411    if (mDescription == 0)
00412    {
00413       mDescription = new H_ContentDescription::Type;
00414    }
00415    return *mDescription;
00416 }
00417 
00418 const H_ContentID::Type&
00419 Contents::header(const H_ContentID& headerType) const
00420 {
00421    checkParsed();
00422    if (mId == 0)
00423    {
00424       ErrLog(<< "You called "
00425             "Contents::header(const H_ContentID& headerType) _const_ "
00426             "without first calling exists(), and the header does not exist. Our"
00427             " behavior in this scenario is to implicitly create the header(using const_cast!); "
00428             "this is probably not what you want, but it is either this or "
00429             "assert/throw an exception. Since this has been the behavior for "
00430             "so long, we are not throwing here, _yet_. You need to fix your "
00431             "code, before we _do_ start throwing. This is why const-correctness"
00432             " should never be made a TODO item </rant>");
00433       Contents* ncthis = const_cast<Contents*>(this);
00434       ncthis->mId = new H_ContentID::Type;
00435    }
00436    return *mId;
00437 }
00438 
00439 H_ContentID::Type&
00440 Contents::header(const H_ContentID& headerType)
00441 {
00442    checkParsed();
00443    if (mId == 0)
00444    {
00445       mId = new H_ContentID::Type;
00446    }
00447    return *mId;
00448 }
00449 
00450 // !dlb! headers except Content-Disposition may contain (comments)
00451 void
00452 Contents::preParseHeaders(ParseBuffer& pb)
00453 {
00454    const char* start = pb.position();
00455    Data all( start, pb.end()-start);
00456 
00457    Data headerName;
00458 
00459    try
00460    {
00461       
00462    while (!pb.eof())
00463    {
00464       const char* anchor = pb.skipWhitespace();
00465       pb.skipToOneOf(Symbols::COLON, ParseBuffer::Whitespace);
00466       pb.data(headerName, anchor);
00467 
00468       pb.skipWhitespace();
00469       pb.skipChar(Symbols::COLON[0]);
00470       anchor = pb.skipWhitespace();
00471       pb.skipToTermCRLF();
00472 
00473       Headers::Type type = Headers::getType(headerName.data(), (int)headerName.size());
00474       ParseBuffer subPb(anchor, pb.position() - anchor);
00475 
00476       switch (type)
00477       {
00478          case Headers::ContentType :
00479          {
00480             // already set
00481             break;
00482          }
00483          case Headers::ContentDisposition :
00484          {
00485             mDisposition = new H_ContentDisposition::Type;
00486             mDisposition->parse(subPb);
00487             break;
00488          }
00489          case Headers::ContentTransferEncoding :
00490          {
00491             mTransferEncoding = new H_ContentTransferEncoding::Type;
00492             mTransferEncoding->parse(subPb);
00493             break;
00494          }
00495          // !dlb! not sure this ever happens?
00496          case Headers::ContentLanguage :
00497          {
00498             if (mLanguages == 0)
00499             {
00500                mLanguages = new H_ContentLanguages::Type;
00501             }
00502 
00503             subPb.skipWhitespace();
00504             while (!subPb.eof() && *subPb.position() != Symbols::COMMA[0])
00505             {
00506                H_ContentLanguages::Type::value_type tmp;
00507                header(h_ContentLanguages).push_back(tmp);
00508                header(h_ContentLanguages).back().parse(subPb);
00509                subPb.skipLWS();
00510             }
00511             break;      // .kw. added -- this is needed, right?
00512          }
00513          default :
00514          {
00515             if (isEqualNoCase(headerName, "Content-Transfer-Encoding"))
00516             {
00517                mTransferEncoding = new StringCategory();
00518                mTransferEncoding->parse(subPb);
00519             }
00520             else if (isEqualNoCase(headerName, "Content-Description"))
00521             {
00522                mDescription = new StringCategory();
00523                mDescription->parse(subPb);
00524             }
00525             else if (isEqualNoCase(headerName, "Content-Id"))
00526             {
00527                mId = new Token();
00528                mId->parse(subPb);
00529             }
00530             // Some people put this in ...
00531             else if (isEqualNoCase(headerName, "Content-Length"))
00532             {
00533                mLength = new StringCategory();
00534                mLength->parse(subPb);
00535             }
00536             else if (isEqualNoCase(headerName, "MIME-Version"))
00537             {
00538                subPb.skipWhitespace();
00539                if (!subPb.eof() && *subPb.position() == Symbols::LPAREN[0])
00540                {
00541                   subPb.skipToEndQuote(Symbols::RPAREN[0]);
00542                   subPb.skipChar(Symbols::RPAREN[0]);
00543                }
00544                mVersion = subPb.integer();
00545 
00546                if (!subPb.eof() && *subPb.position() == Symbols::LPAREN[0])
00547                {
00548                   subPb.skipToEndQuote(Symbols::RPAREN[0]);
00549                   subPb.skipChar(Symbols::RPAREN[0]);
00550                }
00551                subPb.skipChar(Symbols::PERIOD[0]);
00552                
00553                if (!subPb.eof() && *subPb.position() == Symbols::LPAREN[0])
00554                {
00555                   subPb.skipToEndQuote(Symbols::RPAREN[0]);
00556                   subPb.skipChar(Symbols::RPAREN[0]);
00557                }
00558                
00559                mMinorVersion = subPb.integer();
00560             }
00561             else
00562             {
00563                // add to application headers someday
00564                std::cerr << "Unknown MIME Content- header: " << headerName << std::endl;
00565                ErrLog(<< "Unknown MIME Content- header: " << headerName);
00566                assert(false);
00567             }
00568          }
00569       }
00570    }
00571    }
00572    catch (ParseException &  e )
00573    {
00574       ErrLog( << "Some problem parsing contents: " << e );
00575       throw e;
00576    }
00577 }
00578 
00579 EncodeStream&
00580 Contents::encodeHeaders(EncodeStream& str) const
00581 {
00582    if (mVersion != 1 || mMinorVersion != 0)
00583    {
00584       str << "MIME-Version" << Symbols::COLON[0] << Symbols::SPACE[0]
00585           << mVersion << Symbols::PERIOD[0] << mMinorVersion 
00586           << Symbols::CRLF;
00587    }
00588 
00589    str << "Content-Type" << Symbols::COLON[0] << Symbols::SPACE[0]
00590        << mType 
00591        << Symbols::CRLF;
00592 
00593    if (exists(h_ContentDisposition))
00594    {
00595       str <<  "Content-Disposition" << Symbols::COLON[0] << Symbols::SPACE[0];
00596 
00597       header(h_ContentDisposition).encode(str);
00598       str << Symbols::CRLF;
00599    }
00600 
00601    if (exists(h_ContentLanguages))
00602    {
00603       str <<  "Content-Languages" << Symbols::COLON[0] << Symbols::SPACE[0];
00604 
00605       size_t count = 0;
00606       size_t size = header(h_ContentLanguages).size();
00607 
00608       for (H_ContentLanguages::Type::const_iterator 
00609               i = header(h_ContentLanguages).begin();
00610            i != header(h_ContentLanguages).end(); ++i)
00611       {
00612          i->encode(str);
00613 
00614          if (++count < size)
00615              str << Symbols::COMMA << Symbols::SPACE;
00616       }
00617       str << Symbols::CRLF;
00618    }
00619 
00620    if (mTransferEncoding)
00621    {
00622       str << "Content-Transfer-Encoding" << Symbols::COLON[0] << Symbols::SPACE[0]
00623           << *mTransferEncoding
00624           << Symbols::CRLF;
00625    }
00626 
00627    if (mId)
00628    {
00629       str << "Content-Id" << Symbols::COLON[0] << Symbols::SPACE[0]
00630           << *mId
00631           << Symbols::CRLF;
00632    }
00633 
00634    if (mDescription)
00635    {
00636       str << "Content-Description" << Symbols::COLON[0] << Symbols::SPACE[0]
00637           << *mDescription
00638           << Symbols::CRLF;
00639    }
00640 
00641    if (mLength)
00642    {
00643       str << "Content-Length" << Symbols::COLON[0] << Symbols::SPACE[0]
00644           <<  *mLength 
00645           << Symbols::CRLF;
00646    }
00647    
00648    str << Symbols::CRLF;
00649    return str;
00650 }
00651 
00652 Data
00653 Contents::getBodyData() const 
00654 {
00655    checkParsed();
00656    return Data::from(*this);
00657 }
00658 
00659 void
00660 Contents::addBuffer(char* buf)
00661 {
00662    mBufferList.push_back(buf);
00663 }
00664 
00665 /* ====================================================================
00666  * The Vovida Software License, Version 1.0 
00667  * 
00668  * Copyright (c) 2000-2005
00669  * 
00670  * Redistribution and use in source and binary forms, with or without
00671  * modification, are permitted provided that the following conditions
00672  * are met:
00673  * 
00674  * 1. Redistributions of source code must retain the above copyright
00675  *    notice, this list of conditions and the following disclaimer.
00676  * 
00677  * 2. Redistributions in binary form must reproduce the above copyright
00678  *    notice, this list of conditions and the following disclaimer in
00679  *    the documentation and/or other materials provided with the
00680  *    distribution.
00681  * 
00682  * 3. The names "VOCAL", "Vovida Open Communication Application Library",
00683  *    and "Vovida Open Communication Application Library (VOCAL)" must
00684  *    not be used to endorse or promote products derived from this
00685  *    software without prior written permission. For written
00686  *    permission, please contact vocal@vovida.org.
00687  *
00688  * 4. Products derived from this software may not be called "VOCAL", nor
00689  *    may "VOCAL" appear in their name, without prior written
00690  *    permission of Vovida Networks, Inc.
00691  * 
00692  * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
00693  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
00694  * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
00695  * NON-INFRINGEMENT ARE DISCLAIMED.  IN NO EVENT SHALL VOVIDA
00696  * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES
00697  * IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL,
00698  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
00699  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
00700  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
00701  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00702  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
00703  * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
00704  * DAMAGE.
00705  * 
00706  * ====================================================================
00707  * 
00708  * This software consists of voluntary contributions made by Vovida
00709  * Networks, Inc. and many individuals on behalf of Vovida Networks,
00710  * Inc.  For more information on Vovida Networks, Inc., please see
00711  * <http://www.vovida.org/>.
00712  *
00713  */