reSIProcate/stack  9694
MultipartMixedContents.cxx
Go to the documentation of this file.
00001 #if defined(HAVE_CONFIG_H)
00002 #include "config.h"
00003 #endif
00004 
00005 #include "resip/stack/MultipartMixedContents.hxx"
00006 #include "resip/stack/SipMessage.hxx"
00007 #include "rutil/Logger.hxx"
00008 #include "rutil/Random.hxx"
00009 #include "rutil/BaseException.hxx"
00010 #include "rutil/ParseBuffer.hxx"
00011 #include "rutil/WinLeakCheck.hxx"
00012 
00013 using namespace resip;
00014 using namespace std;
00015 
00016 #define RESIPROCATE_SUBSYSTEM Subsystem::CONTENTS
00017 
00018 bool 
00019 MultipartMixedContents::init()
00020 {
00021    static ContentsFactory<MultipartMixedContents> factory;
00022    (void)factory;
00023    return true;
00024 }
00025 
00026 MultipartMixedContents::MultipartMixedContents()
00027    : Contents(getStaticType()),
00028      mContents()
00029 {
00030    setBoundary();
00031 }
00032 
00033 MultipartMixedContents::MultipartMixedContents(const Mime& contentsType)
00034    : Contents(contentsType),
00035      mContents()
00036 {
00037    if (!mType.exists(p_boundary))
00038    {
00039       setBoundary();
00040    }
00041 }
00042 
00043 MultipartMixedContents::MultipartMixedContents(const HeaderFieldValue& hfv, const Mime& contentsType)
00044    : Contents(hfv, contentsType),
00045      mContents()
00046 {
00047    if (!mType.exists(p_boundary))
00048    {
00049       setBoundary();
00050    }
00051 }
00052 
00053 MultipartMixedContents::MultipartMixedContents(const MultipartMixedContents& rhs)
00054    : Contents(rhs),
00055      mContents()
00056 {
00057    vector<Contents*>::const_iterator j;
00058 
00059    // .bwc. Don't trigger a parse of the original by calling parts()
00060    const vector<Contents*>& list = rhs.mContents;
00061    
00062    for ( j = list.begin(); 
00063          j != list.end(); ++j)
00064    {
00065       assert( *j );
00066       mContents.push_back( (*j)->clone() );
00067    }
00068 }
00069 
00070 void
00071 MultipartMixedContents::setBoundary()
00072 {
00073    Data boundaryToken = Random::getRandomHex(8);
00074    mType.param(p_boundary) = boundaryToken;
00075 }
00076 
00077 void
00078 MultipartMixedContents::setBoundary(const Data& boundary)
00079 {
00080     mType.param(p_boundary) = boundary;
00081 }
00082 
00083 void
00084 MultipartMixedContents::clear()
00085 {
00086    for (vector<Contents*>::iterator i = mContents.begin(); 
00087         i != mContents.end(); ++i)
00088    {
00089       delete *i;
00090    }
00091 }
00092 
00093 MultipartMixedContents::~MultipartMixedContents()
00094 {
00095    clear();
00096 }
00097 
00098 MultipartMixedContents&
00099 MultipartMixedContents::operator=(const MultipartMixedContents& rhs)
00100 {
00101    if (this != &rhs)
00102    {
00103       Contents::operator=(rhs);
00104       clear();
00105       
00106       for (vector<Contents*>::iterator i = mContents.begin(); 
00107            i != mContents.end(); ++i)
00108       {
00109          mContents.push_back( (*i)->clone() );
00110       }
00111    }
00112    return *this;
00113 }
00114 
00115 Contents* 
00116 MultipartMixedContents::clone() const
00117 {
00118    return new MultipartMixedContents(*this);
00119 }
00120 
00121 const Mime& 
00122 MultipartMixedContents::getStaticType() 
00123 {
00124    static Mime type("multipart","mixed");
00125    return type;
00126 }
00127 
00128 EncodeStream& 
00129 MultipartMixedContents::encodeParsed(EncodeStream& str) const
00130 {
00131    const Data& boundaryToken = mType.param(p_boundary);
00132    Data boundary(boundaryToken.size() + 2, Data::Preallocate);
00133    boundary = Symbols::DASHDASH;
00134    boundary += boundaryToken;
00135    boundary.replace("\"", ""); // remove quotes
00136 
00137    assert( mContents.size() > 0 );
00138    
00139    bool first = true;
00140    for (vector<Contents*>::const_iterator i = mContents.begin(); 
00141         i != mContents.end(); ++i)
00142    {
00143       if (!first)
00144       {
00145          str << Symbols::CRLF;
00146       }
00147       else
00148       {
00149          first = false;
00150       }
00151       str << boundary << Symbols::CRLF;
00152       (*i)->encodeHeaders(str);
00153       (*i)->encode(str);
00154    }
00155 
00156    str << Symbols::CRLF << boundary << Symbols::DASHDASH;
00157    return str;
00158 }
00159 
00160 // The boundary delimiter MUST occur at the beginning of a line, i.e., following
00161 // a CRLF, and the initial CRLF is considered to be attached to the boundary
00162 // delimiter line rather than part of the preceding part.
00163 void 
00164 MultipartMixedContents::parse(ParseBuffer& pb)
00165 {
00166    const Data& boundaryToken = mType.param(p_boundary);
00167    
00168    Data boundary(boundaryToken.size() + 4, Data::Preallocate);
00169    boundary += Symbols::CRLF;
00170    boundary += Symbols::DASHDASH;
00171    boundary += boundaryToken;
00172 
00173    Data boundaryNoCRLF(boundaryToken.size() + 2, Data::Preallocate);
00174    boundaryNoCRLF += Symbols::DASHDASH;
00175    boundaryNoCRLF += boundaryToken;
00176 
00177    pb.skipToChars(boundaryNoCRLF);
00178    pb.skipN((int)boundaryNoCRLF.size());
00179    pb.assertNotEof();
00180 
00181    do
00182    {
00183       // skip over boundary
00184  
00185       if( pb.eof() || *pb.position() != Symbols::CR[0] )
00186       {
00187          throw Exception("Invalid line ending, missing CR",__FILE__,__LINE__);
00188       }
00189       pb.skipChar();
00190       if( pb.eof() || *pb.position() != Symbols::LF[0] )
00191       {
00192          throw Exception("Invalid line ending, missing LF",__FILE__,__LINE__);
00193       }
00194       pb.skipChar();
00195       
00196       pb.assertNotEof();
00197 
00198       const char* headerStart = pb.position();
00199 
00200       // pull out contents type only
00201       pb.skipToChars("Content-Type");
00202       if (pb.eof())
00203       {
00204          pb.reset(headerStart);
00205          pb.skipToChars("CONTENT-TYPE");
00206       }
00207       pb.assertNotEof();
00208 
00209       pb.skipToChar(Symbols::COLON[0]);
00210       pb.skipChar();
00211       pb.assertNotEof();
00212       
00213       pb.skipWhitespace();
00214       const char* typeStart = pb.position();
00215       pb.assertNotEof();
00216       
00217       // determine contents-type header buffer
00218       pb.skipToTermCRLF();
00219       pb.assertNotEof();
00220 
00221       ParseBuffer subPb(typeStart, pb.position() - typeStart);
00222       Mime contentType;
00223       contentType.parse(subPb);
00224       
00225       pb.assertNotEof();
00226 
00227       // determine body start
00228       pb.reset(typeStart);
00229       const char* bodyStart = pb.skipToChars(Symbols::CRLFCRLF);
00230       pb.assertNotEof();
00231       bodyStart += 4;
00232 
00233       // determine contents body buffer
00234       pb.skipToChars(boundary);
00235       pb.assertNotEof();
00236       Data tmp;
00237       pb.data(tmp, bodyStart);
00238       // create contents against body
00239       mContents.push_back(createContents(contentType, tmp));
00240       // pre-parse headers
00241       ParseBuffer headersPb(headerStart, bodyStart-4-headerStart);
00242       mContents.back()->preParseHeaders(headersPb);
00243 
00244       pb.skipN((int)boundary.size());
00245 
00246       const char* loc = pb.position();
00247       pb.skipChar();
00248       pb.skipChar();
00249       Data next;
00250       pb.data(next, loc);
00251 
00252       if ( next == Symbols::DASHDASH )
00253       {
00254          break;
00255       }
00256       pb.reset( loc );
00257    }
00258    while ( !pb.eof() );
00259 
00260 }
00261 
00262 /* ====================================================================
00263  * The Vovida Software License, Version 1.0 
00264  * 
00265  * Copyright (c) 2000 Vovida Networks, Inc.  All rights reserved.
00266  * 
00267  * Redistribution and use in source and binary forms, with or without
00268  * modification, are permitted provided that the following conditions
00269  * are met:
00270  * 
00271  * 1. Redistributions of source code must retain the above copyright
00272  *    notice, this list of conditions and the following disclaimer.
00273  * 
00274  * 2. Redistributions in binary form must reproduce the above copyright
00275  *    notice, this list of conditions and the following disclaimer in
00276  *    the documentation and/or other materials provided with the
00277  *    distribution.
00278  * 
00279  * 3. The names "VOCAL", "Vovida Open Communication Application Library",
00280  *    and "Vovida Open Communication Application Library (VOCAL)" must
00281  *    not be used to endorse or promote products derived from this
00282  *    software without prior written permission. For written
00283  *    permission, please contact vocal@vovida.org.
00284  *
00285  * 4. Products derived from this software may not be called "VOCAL", nor
00286  *    may "VOCAL" appear in their name, without prior written
00287  *    permission of Vovida Networks, Inc.
00288  * 
00289  * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
00290  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
00291  * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
00292  * NON-INFRINGEMENT ARE DISCLAIMED.  IN NO EVENT SHALL VOVIDA
00293  * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES
00294  * IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL,
00295  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
00296  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
00297  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
00298  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00299  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
00300  * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
00301  * DAMAGE.
00302  * 
00303  * ====================================================================
00304  * 
00305  * This software consists of voluntary contributions made by Vovida
00306  * Networks, Inc. and many individuals on behalf of Vovida Networks,
00307  * Inc.  For more information on Vovida Networks, Inc., please see
00308  * <http://www.vovida.org/>.
00309  *
00310  */