|
reSIProcate/stack
9694
|
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 */
1.7.5.1