reSIProcate/stack  9694
ParserCategory.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/HeaderFieldValue.hxx"
00006 #include "resip/stack/ParserCategory.hxx"
00007 #include "rutil/ParseBuffer.hxx"
00008 #include "resip/stack/SipMessage.hxx"
00009 #include "rutil/DataStream.hxx"
00010 #include "rutil/ParseBuffer.hxx"
00011 #include "rutil/compat.hxx"
00012 
00013 #include "resip/stack/UnknownParameter.hxx"
00014 #include "resip/stack/ExtensionParameter.hxx"
00015 
00016 #include <iostream>
00017 #include <cassert>
00018 
00019 #include "rutil/Logger.hxx"
00020 //#include "rutil/WinLeakCheck.hxx"  // not compatible with placement new used below
00021 
00022 #define RESIPROCATE_SUBSYSTEM Subsystem::SIP
00023 
00024 using namespace resip;
00025 using namespace std;
00026 
00027 const ParserCategory::ParameterTypeSet 
00028 ParserCategory::EmptyParameterTypeSet; 
00029 
00030 ParserCategory::ParserCategory(const HeaderFieldValue& headerFieldValue,
00031                                Headers::Type headerType,
00032                                PoolBase* pool)
00033     : LazyParser(headerFieldValue),
00034       mParameters(StlPoolAllocator<Parameter*, PoolBase>(pool)),
00035       mUnknownParameters(StlPoolAllocator<Parameter*, PoolBase>(pool)),
00036       mPool(pool),
00037       mHeaderType(headerType)
00038 {
00039 }
00040 
00041 ParserCategory::ParserCategory(const char* buf, 
00042                                  int length, 
00043                                  Headers::Type type,
00044                                  PoolBase* pool):
00045    LazyParser(buf, length),
00046    mParameters(StlPoolAllocator<Parameter*, PoolBase>(pool)),
00047    mUnknownParameters(StlPoolAllocator<Parameter*, PoolBase>(pool)),
00048    mPool(pool),
00049    mHeaderType(type)
00050 {}
00051 
00052 ParserCategory::ParserCategory(PoolBase* pool)
00053    : LazyParser(),
00054      mParameters(StlPoolAllocator<Parameter*, PoolBase>(pool)),
00055      mUnknownParameters(StlPoolAllocator<Parameter*, PoolBase>(pool)),
00056      mPool(pool),
00057      mHeaderType(Headers::NONE)
00058 {
00059 }
00060 
00061 ParserCategory::ParserCategory(const ParserCategory& rhs,
00062                                PoolBase* pool)
00063    : LazyParser(rhs),
00064      mParameters(StlPoolAllocator<Parameter*, PoolBase>(pool)),
00065      mUnknownParameters(StlPoolAllocator<Parameter*, PoolBase>(pool)),
00066      mPool(pool),
00067      mHeaderType(rhs.mHeaderType)
00068 {
00069    if (isParsed())
00070    {
00071       copyParametersFrom(rhs);
00072    }
00073 }
00074 
00075 ParserCategory&
00076 ParserCategory::operator=(const ParserCategory& rhs)
00077 {
00078    if (this != &rhs)
00079    {
00080       clear();
00081       mHeaderType = rhs.mHeaderType;
00082       LazyParser::operator=(rhs);
00083       if (rhs.isParsed())
00084       {
00085          copyParametersFrom(rhs);
00086       }
00087    }
00088    return *this;
00089 }
00090 
00091 void
00092 ParserCategory::clear()
00093 {
00094    //DebugLog(<<"ParserCategory::clear");
00095    LazyParser::clear();
00096 
00097    while(!mParameters.empty())
00098    {
00099       freeParameter(mParameters.back());
00100       mParameters.pop_back();
00101    }
00102 
00103    while(!mUnknownParameters.empty())
00104    {
00105       freeParameter(mUnknownParameters.back());
00106       mUnknownParameters.pop_back();
00107    }
00108 }
00109 
00110 void 
00111 ParserCategory::copyParametersFrom(const ParserCategory& other)
00112 {
00113    mParameters.reserve(other.mParameters.size());
00114    mUnknownParameters.reserve(other.mUnknownParameters.size());
00115    
00116    for (ParameterList::const_iterator it = other.mParameters.begin();
00117         it != other.mParameters.end(); it++)
00118    {
00119       mParameters.push_back((*it)->clone());
00120    }
00121    for (ParameterList::const_iterator it = other.mUnknownParameters.begin();
00122         it != other.mUnknownParameters.end(); it++)
00123    {
00124       mUnknownParameters.push_back((*it)->clone());
00125    }
00126 }
00127 
00128 ParserCategory::~ParserCategory()
00129 {
00130    clear();
00131 }
00132 
00133 const Data&
00134 ParserCategory::param(const ExtensionParameter& param) const
00135 {
00136    checkParsed();
00137    Parameter* p = getParameterByData(param.getName());
00138    if (!p)
00139    {
00140       InfoLog(<< "Referenced an unknown parameter " << param.getName());
00141       throw Exception("Missing unknown parameter", __FILE__, __LINE__);
00142    }
00143    return static_cast<UnknownParameter*>(p)->value();
00144 }
00145 
00146 Data&
00147 ParserCategory::param(const ExtensionParameter& param)
00148 {
00149    checkParsed();
00150    Parameter* p = getParameterByData(param.getName());
00151    if (!p)
00152    {
00153       p = new UnknownParameter(param.getName());
00154       mUnknownParameters.push_back(p);
00155    } 
00156    return static_cast<UnknownParameter*>(p)->value();
00157 }
00158 
00159 // removing non-present parameter is allowed      
00160 void
00161 ParserCategory::remove(const ParamBase& paramType)
00162 {
00163     checkParsed();
00164     removeParameterByEnum(paramType.getTypeNum());
00165 }
00166 
00167 void 
00168 ParserCategory::remove(const ExtensionParameter& param)
00169 {
00170    checkParsed();
00171    removeParameterByData(param.getName());
00172 }
00173 
00174 bool 
00175 ParserCategory::exists(const ExtensionParameter& param) const
00176 {
00177    checkParsed();
00178    return getParameterByData(param.getName()) != NULL;
00179 }
00180 
00181 void 
00182 ParserCategory::removeParametersExcept(const ParameterTypeSet& set)
00183 {
00184    checkParsed();
00185    for (ParameterList::iterator it = mParameters.begin();
00186         it != mParameters.end();)
00187    {
00188       if (set.find((*it)->getType()) == set.end())
00189       {
00190          freeParameter(*it);
00191          it = mParameters.erase(it);
00192       }
00193       else
00194       {
00195          ++it;
00196       }
00197    }
00198 }
00199 
00200 void 
00201 ParserCategory::clearUnknownParameters()
00202 {
00203    for (ParameterList::iterator it = mUnknownParameters.begin();
00204         it != mUnknownParameters.end(); it++)
00205    {
00206       freeParameter(*it);
00207    }   
00208    mUnknownParameters.clear();
00209 }
00210 
00211 void
00212 ParserCategory::parseParameters(ParseBuffer& pb)
00213 {
00214    while (!pb.eof() )
00215    {
00216       const char* start = pb.position();
00217       pb.skipWhitespace();
00218 
00219       if (  (!pb.eof() && *pb.position() == Symbols::SEMI_COLON[0]) )
00220       {
00221          // extract the key
00222          pb.skipChar();
00223          const char* keyStart = pb.skipWhitespace();
00224          static std::bitset<256> terminators1=Data::toBitset(" \t\r\n;=?>"); 
00225          const char* keyEnd = pb.skipToOneOf(terminators1);  
00226 
00227          if((int)(keyEnd-keyStart) != 0)
00228          {
00229             ParameterTypes::Type type = ParameterTypes::getType(keyStart, (unsigned int)(keyEnd - keyStart));
00230             static std::bitset<256> terminators2 = Data::toBitset(" \t\r\n;?>");
00231             Parameter* p;
00232             if (type == ParameterTypes::UNKNOWN || 
00233                !(p=createParam(type, pb, terminators2,getPool())))
00234             {
00235                mUnknownParameters.push_back(new (getPool()) UnknownParameter(keyStart, 
00236                                                                  int((keyEnd - keyStart)), pb, terminators2));
00237             }
00238             else
00239             {
00240                // invoke the particular factory
00241                mParameters.push_back(p);
00242             }
00243          }
00244       }
00245       else
00246       {
00247          pb.reset(start);
00248          return;
00249       }
00250    }
00251 }      
00252 
00253 Parameter* 
00254 ParserCategory::createParam(ParameterTypes::Type type, ParseBuffer& pb, const std::bitset<256>& terminators, PoolBase* pool)
00255 {
00256    return 0;
00257 }
00258 
00259 static Data up_Msgr("msgr");
00260 
00261 EncodeStream&
00262 ParserCategory::encodeParameters(EncodeStream& str) const
00263 {
00264     
00265    for (ParameterList::const_iterator it = mParameters.begin();
00266         it != mParameters.end(); it++)
00267    {
00268 #if 0
00269       // !cj! - may be wrong just hacking 
00270       // The goal of all this is not to add a tag if the tag is empty 
00271       ParameterTypes::Type type = (*it)->getType();
00272       
00273       if ( type ==  ParameterTypes::tag )
00274       {
00275          Parameter* p = (*it);
00276          DataParameter* d = dynamic_cast<DataParameter*>(p);
00277          
00278          Data& data = d->value();
00279          
00280          if ( !data.empty() )
00281          {
00282             str << Symbols::SEMI_COLON;
00283             // !ah! this is a TOTAL hack to work around an MSN bug that
00284             // !ah! requires a SPACE after the SEMI following the MIME type.
00285             if (it == mParameters.begin() && getParameterByData(up_Msgr))
00286             {
00287                str << Symbols::SPACE;
00288             }
00289 
00290             (*it)->encode(str);
00291          }
00292       }
00293       else
00294       {
00295          str << Symbols::SEMI_COLON;
00296          // !ah! this is a TOTAL hack to work around an MSN bug that
00297          // !ah! requires a SPACE after the SEMI following the MIME type.
00298          if (it == mParameters.begin() && getParameterByData(up_Msgr))
00299          {
00300             str << Symbols::SPACE;
00301          }
00302 
00303          (*it)->encode(str);
00304       }
00305       
00306 #else
00307       str << Symbols::SEMI_COLON;
00308       // !ah! this is a TOTAL hack to work around an MSN bug that
00309       // !ah! requires a SPACE after the SEMI following the MIME type.
00310       if (it == mParameters.begin() && getParameterByData(up_Msgr))
00311       {
00312          str << Symbols::SPACE;
00313       }
00314       
00315       (*it)->encode(str);
00316 #endif
00317    }
00318    for (ParameterList::const_iterator it = mUnknownParameters.begin();
00319         it != mUnknownParameters.end(); it++)
00320    {
00321       str << Symbols::SEMI_COLON;
00322       (*it)->encode(str);
00323    }
00324    return str;
00325 }
00326 
00327 EncodeStream&
00328 resip::operator<<(EncodeStream& stream, const ParserCategory& category)
00329 {
00330    category.checkParsed();
00331    return category.encode(stream);
00332 }
00333 
00334 Parameter* 
00335 ParserCategory::getParameterByEnum(ParameterTypes::Type type) const
00336 {
00337    for (ParameterList::const_iterator it = mParameters.begin();
00338         it != mParameters.end(); it++)
00339    {
00340       if ((*it)->getType() == type)
00341       {
00342          return *it;
00343       }
00344    }
00345    return 0;
00346 }
00347 
00348 void
00349 ParserCategory::setParameter(const Parameter* parameter)
00350 {
00351    assert(parameter);
00352 
00353    for (ParameterList::iterator it = mParameters.begin();
00354         it != mParameters.end(); it++)
00355    {
00356       if ((*it)->getType() == parameter->getType())
00357       {
00358          freeParameter(*it);
00359          mParameters.erase(it);
00360          mParameters.push_back(parameter->clone());
00361          return;
00362       }
00363    }
00364 
00365    // !dlb! kinda hacky -- what is the correct semantics here?
00366    // should be quietly add, quietly do nothing, throw?
00367    mParameters.push_back(parameter->clone());
00368 }
00369 
00370 void 
00371 ParserCategory::removeParameterByEnum(ParameterTypes::Type type)
00372 {
00373    // remove all instances
00374    for (ParameterList::iterator it = mParameters.begin();
00375         it != mParameters.end();)
00376    {
00377       if ((*it)->getType() == type)
00378       {
00379          freeParameter(*it);
00380          it = mParameters.erase(it);
00381       }
00382       else
00383       {
00384          ++it;
00385       }
00386    }
00387  }
00388 
00389 Parameter* 
00390 ParserCategory::getParameterByData(const Data& data) const
00391 {
00392    for (ParameterList::const_iterator it = mUnknownParameters.begin();
00393         it != mUnknownParameters.end(); it++)
00394    {
00395       if (isEqualNoCase((*it)->getName(), data))
00396       {
00397          return *it;
00398       }
00399    }
00400    return 0;
00401 }
00402 
00403 void 
00404 ParserCategory::removeParameterByData(const Data& data)
00405 {
00406    // remove all instances
00407    for (ParameterList::iterator it = mUnknownParameters.begin();
00408         it != mUnknownParameters.end();)
00409    {
00410       if ((*it)->getName() == data)
00411       {
00412          freeParameter(*it);
00413          it = mUnknownParameters.erase(it);
00414       }
00415       else
00416       {
00417          ++it;
00418       }
00419    }
00420 }
00421 
00422 Data
00423 ParserCategory::commutativeParameterHash() const
00424 {
00425    Data buffer;
00426    Data working;
00427 
00428    for (ParameterList::const_iterator i = mParameters.begin(); i != mParameters.end(); ++i)
00429    {
00430       if ((*i)->getType() != ParameterTypes::lr)
00431       {
00432          buffer.clear();
00433          {
00434             DataStream strm(buffer);
00435             (*i)->encode(strm);
00436          }
00437          working ^= buffer;
00438       }
00439    }
00440 
00441    buffer.clear();
00442    for (ParameterList::const_iterator i = mUnknownParameters.begin(); i != mUnknownParameters.end(); ++i)
00443    {
00444       UnknownParameter* p = static_cast<UnknownParameter*>(*i);
00445       buffer = p->getName();
00446       buffer += p->value();
00447       working ^= buffer;
00448    }
00449    
00450    return working;
00451 }
00452 
00453 const Data&
00454 ParserCategory::errorContext() const
00455 {
00456    return Headers::getHeaderName(mHeaderType);
00457 }
00458 
00459 /* ====================================================================
00460  * The Vovida Software License, Version 1.0 
00461  * 
00462  * Copyright (c) 2000 Vovida Networks, Inc.  All rights reserved.
00463  * 
00464  * Redistribution and use in source and binary forms, with or without
00465  * modification, are permitted provided that the following conditions
00466  * are met:
00467  * 
00468  * 1. Redistributions of source code must retain the above copyright
00469  *    notice, this list of conditions and the following disclaimer.
00470  * 
00471  * 2. Redistributions in binary form must reproduce the above copyright
00472  *    notice, this list of conditions and the following disclaimer in
00473  *    the documentation and/or other materials provided with the
00474  *    distribution.
00475  * 
00476  * 3. The names "VOCAL", "Vovida Open Communication Application Library",
00477  *    and "Vovida Open Communication Application Library (VOCAL)" must
00478  *    not be used to endorse or promote products derived from this
00479  *    software without prior written permission. For written
00480  *    permission, please contact vocal@vovida.org.
00481  *
00482  * 4. Products derived from this software may not be called "VOCAL", nor
00483  *    may "VOCAL" appear in their name, without prior written
00484  *    permission of Vovida Networks, Inc.
00485  * 
00486  * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
00487  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
00488  * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
00489  * NON-INFRINGEMENT ARE DISCLAIMED.  IN NO EVENT SHALL VOVIDA
00490  * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES
00491  * IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL,
00492  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
00493  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
00494  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
00495  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00496  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
00497  * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
00498  * DAMAGE.
00499  * 
00500  * ====================================================================
00501  * 
00502  * This software consists of voluntary contributions made by Vovida
00503  * Networks, Inc. and many individuals on behalf of Vovida Networks,
00504  * Inc.  For more information on Vovida Networks, Inc., please see
00505  * <http://www.vovida.org/>.
00506  *
00507  */
00508 
00509 /* Local Variables: */
00510 /* c-file-style: "ellemtel" */
00511 /* End: */