Coverage Report

Created: 2025-06-13 06:12

/src/resiprocate/resip/stack/Uri.hxx
Line
Count
Source (jump to first uncovered line)
1
#if !defined(RESIP_URI_HXX)
2
#define RESIP_URI_HXX 
3
4
#include <bitset>
5
#include "rutil/ResipAssert.h"
6
7
#include "resip/stack/ParserCategory.hxx"
8
#include "resip/stack/Token.hxx"
9
#include "rutil/TransportType.hxx"
10
#include "rutil/HeapInstanceCounter.hxx"
11
12
namespace resip
13
{
14
class SipMessage;
15
16
/**
17
   @ingroup sip_grammar
18
   @brief Represents the "SIP-URI" and "SIPS-URI" elements in the RFC 3261 
19
      grammar. Also can be made to represent other URI types (like tel URIs)
20
*/
21
class Uri : public ParserCategory
22
{
23
   public:
24
      RESIP_HeapCount(Uri);
25
      
26
      static const size_t uriEncodingTableSize = 256;
27
28
      Uri(PoolBase* pool=0);
29
      Uri(const HeaderFieldValue& hfv, Headers::Type type, PoolBase* pool=0);
30
      Uri(const Uri& orig,
31
         PoolBase* pool=0);
32
      explicit Uri(const Data& data);
33
34
      ~Uri();
35
      
36
      // convert from a tel scheme to sip scheme, adds user=phone param
37
      //static Uri fromTel(const Uri&, const Data& host);  // deprecate...
38
      static Uri fromTel(const Uri&, const Uri& hostUri);
39
40
0
      Data& host() {checkParsed(); mHostCanonicalized=false; return mHost;}
41
0
      const Data& host() const {checkParsed(); return mHost;}
42
0
      Data& user() {checkParsed(); return mUser;}
43
0
      const Data& user() const {checkParsed(); return mUser;}
44
0
      Data& userParameters() {checkParsed(); return mUserParameters;}
45
0
      const Data& userParameters() const {checkParsed(); return mUserParameters;}
46
0
      Data& opaque() {checkParsed(); return mHost;}
47
0
      const Data& opaque() const {checkParsed(); return mHost;}
48
0
      Data& path() {checkParsed(); return mPath;}
49
0
      const Data& path() const {checkParsed(); return mPath;}
50
51
      // Returns user@host[:port] (no scheme)
52
      Data getAor() const;
53
      // Returns user@host (no scheme or port)
54
      Data getAorNoPort() const;
55
56
      // Actually returns the AOR; <scheme>:<user>@<host>
57
      Data getAorNoReally() const
58
0
      {
59
0
         return getAOR(false);
60
0
      }
61
62
      // Returns the AOR, optionally adding the port
63
      Data getAOR(bool addPort) const;
64
65
      //strips all paramters - if transport type is specified (ie. not UNKNOWN_TRANSPORT),
66
      //and the default port for the transport is on the Aor, then it is removed
67
      Uri getAorAsUri(TransportType transportTypeToRemoveDefaultPort = UNKNOWN_TRANSPORT) const;
68
      
69
70
      /**
71
         Returns true if the user appears to fit the BNF for the 
72
         'telephone-subscriber' element in the RFC 3261 (and by extension, RFC 
73
         3966) grammar. This is important because 'telephone-subscriber' can 
74
         have parameters, which you could then access easily through the
75
         getUserAsTelephoneSubscriber() and setUserAsTelephoneSubscriber() 
76
         calls.
77
      */
78
      bool userIsTelephoneSubscriber() const;
79
80
      /**
81
         Returns the user-part as a 'telephone-subscriber' grammar element (in 
82
         other words, this parses the user-part into a dial string and 
83
         parameters, with the dial-string accessible with Token::value(), and 
84
         the parameters accessible with the various Token::param() and 
85
         Token::exists() interfaces). 
86
         
87
         For example, suppose the following is in the Request-URI:
88
         
89
         sip:5555551234;phone-context=+86\@example.com;user=dialstring
90
         
91
         The user-part of this SIP URI is "5555551234;phone-context=+86", and it
92
         fits the BNF for the 'telephone-subscriber' grammar element. To access 
93
         the 'phone-context' parameter, do something like the following:
94
95
         @code
96
            Uri& reqUri(sip.header(h_RequestLine).uri());
97
98
            // !bwc! May add native support for this param later
99
            static ExtensionParameter p_phoneContext("phone-context");
100
            Data phoneContextValue;
101
102
            if(reqUri.isWellFormed())
103
            {
104
               if(reqUri.exists(p_phoneContext))
105
               {
106
                  // Phone context as URI param
107
                  phoneContextValue=reqUri.param(p_phoneContext);
108
               }
109
               else if(reqUri.scheme()=="sip" || reqUri.scheme()=="sips")
110
               {
111
                  // Might have phone-context as a user param (only happens 
112
                  // in a sip or sips URI)
113
                  // Technically, this userIsTelephoneSubscriber() check is 
114
                  // required: 
115
                  // sip:bob;phone-context=+86@example.com doesn't have a 
116
                  // phone-context param according to the BNF in 3261. But, 
117
                  // interop may require you to parse this as if it did have 
118
                  // such a param.
119
                  if(reqUri.userIsTelephoneSubscriber())
120
                  {
121
                     Token telSub(reqUri.getUserAsTelephoneSubscriber());
122
                     if(telSub.isWellFormed() && telSub.exists(p_phoneContext))
123
                     {
124
                        // Phone context as user param
125
                        phoneContextValue=telSub.param(p_phoneContext);
126
                     }
127
                  }
128
               }
129
            }
130
         @endcode
131
      */
132
      Token getUserAsTelephoneSubscriber() const;
133
134
      /**
135
         Sets the user-part of this URI using the dial-string and parameters 
136
         stored in telephoneSubscriber.
137
         @param telephoneSubscriber The user-part, as a 'telephone-subscriber'
138
            grammar element.
139
      */
140
      void setUserAsTelephoneSubscriber(const Token& telephoneSubscriber);
141
142
143
0
      Data& scheme() {checkParsed(); return mScheme;}
144
0
      const Data& scheme() const {checkParsed(); return mScheme;}
145
0
      int& port() {checkParsed(); return mPort;}
146
0
      int port() const {checkParsed(); return mPort;}
147
0
      Data& password() {checkParsed(); return mPassword;}
148
0
      const Data& password() const {checkParsed(); return mPassword;}
149
150
0
      Data& netNs() {return(mNetNs);}
151
0
      const Data& netNs() const {return(mNetNs);}
152
153
      Data toString() const;
154
155
      /** Returns true if the uri can be converted into a string that can be
156
          used as an enum lookup */
157
      bool isEnumSearchable() const;
158
159
      /** Return a vector of domains to do a NAPTR lookup for enum */
160
      std::vector<Data> getEnumLookups(const std::vector<Data>& suffixes) const;
161
162
      /** Modifies the default URI encoding character sets */
163
      static void setUriUserEncoding(unsigned char c, bool encode);
164
      static void setUriPasswordEncoding(unsigned char c, bool encode);
165
      
166
      bool hasEmbedded() const;
167
      SipMessage& embedded();
168
      const SipMessage& embedded() const;
169
170
      void removeEmbedded();
171
172
      virtual void parse(ParseBuffer& pb);
173
      virtual ParserCategory* clone() const;
174
      virtual ParserCategory* clone(void* location) const;
175
      virtual ParserCategory* clone(PoolBase* pool) const;
176
      virtual EncodeStream& encodeParsed(EncodeStream& str) const;
177
      
178
      // parse the headers into this as SipMessage
179
      void parseEmbeddedHeaders(ParseBuffer& pb);
180
      EncodeStream& encodeEmbeddedHeaders(EncodeStream& str) const;
181
182
      Uri& operator=(const Uri& rhs);
183
      bool operator==(const Uri& other) const;
184
      bool operator!=(const Uri& other) const;
185
      bool operator<(const Uri& other) const;
186
      
187
      bool aorEqual(const Uri& rhs) const;
188
5.96k
      void setIsBetweenAngleQuotes(bool value) { mIsBetweenAngleQuotes = value; }
189
190
      /**
191
         @brief Compares two known URI parameters for equality.
192
         @param param1 The first parameter to compare.
193
         @param param2 The second parameter to compare.
194
         @return `true` if the parameters are equal; otherwise, `false`.
195
      */
196
      static bool compareUriParametersEqual(Parameter* param1, Parameter* param2);
197
198
      /**
199
         @brief Compares two URI parameters to determine if the first is less
200
                than the second.
201
         @param param1 The first parameter to compare.
202
         @param param2 The second parameter to compare.
203
         @return `true` if the first parameter is less than the second;
204
                 otherwise, `false`.
205
      */
206
      static bool compareUriParametersLessThan(Parameter* param1, Parameter* param2);
207
208
      /**
209
         @brief Checks if the URI-parameter appearing in only one URI must not
210
                be ignored when comparing the URIs.
211
         @param type The type of the parameter to check.
212
         @return `true` if such a parameter must not be ignored;
213
                 otherwise, `false`.
214
         @note Follows RFC 3261 section 19.1.4.
215
      */
216
      static bool isSignificantUriParameter(const ParameterTypes::Type type) noexcept;
217
218
      typedef std::bitset<Uri::uriEncodingTableSize> EncodingTable;
219
220
      static EncodingTable& getUserEncodingTable()
221
2
      {
222
2
         static EncodingTable userEncodingTable(
223
2
               Data::toBitset("abcdefghijklmnopqrstuvwxyz"
224
2
                              "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
225
2
                              "0123456789"
226
2
                              "-_.!~*\\()&=+$,;?/").flip());
227
2
         return userEncodingTable;
228
2
      }
229
230
      static EncodingTable& getPasswordEncodingTable()
231
2
      {
232
2
         static EncodingTable passwordEncodingTable(
233
2
               Data::toBitset("abcdefghijklmnopqrstuvwxyz"
234
2
                              "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
235
2
                              "0123456789"
236
2
                              "-_.!~*\\()&=+$").flip());
237
2
         return passwordEncodingTable;
238
2
      }
239
240
      static EncodingTable& getLocalNumberTable()
241
2
      {
242
         // ?bwc? 'p' and 'w' are allowed in 2806, but have been removed in 
243
         // 3966. Should we support these or not?
244
2
         static EncodingTable localNumberTable(
245
2
               Data::toBitset("*#-.()0123456789ABCDEFpw"));
246
2
         return localNumberTable;
247
2
      }
248
249
      static EncodingTable& getGlobalNumberTable()
250
2
      {
251
2
         static EncodingTable globalNumberTable(
252
2
               Data::toBitset("-.()0123456789"));
253
2
         return globalNumberTable;
254
2
      }
255
256
      // Inform the compiler that overloads of these may be found in
257
      // ParserCategory, too.
258
      using ParserCategory::exists;
259
      using ParserCategory::remove;
260
      using ParserCategory::param;
261
262
      virtual Parameter* createParam(ParameterTypes::Type type, ParseBuffer& pb, const std::bitset<256>& terminators, PoolBase* pool);
263
      bool exists(const Param<Uri>& paramType) const;
264
      void remove(const Param<Uri>& paramType);
265
266
#define defineParam(_enum, _name, _type, _RFC_ref_ignored)                      \
267
      const _enum##_Param::DType& param(const _enum##_Param& paramType) const;  \
268
      _enum##_Param::DType& param(const _enum##_Param& paramType); \
269
      friend class _enum##_Param
270
271
      defineParam(ob,"ob",ExistsParameter,"RFC 5626");
272
      defineParam(gr, "gr", ExistsOrDataParameter, "RFC 5627");
273
      defineParam(comp, "comp", DataParameter, "RFC 3486");
274
      defineParam(duration, "duration", UInt32Parameter, "RFC 4240");
275
      defineParam(lr, "lr", ExistsParameter, "RFC 3261");
276
      defineParam(maddr, "maddr", DataParameter, "RFC 3261");
277
      defineParam(method, "method", DataParameter, "RFC 3261");
278
      defineParam(transport, "transport", DataParameter, "RFC 3261");
279
      defineParam(ttl, "ttl", UInt32Parameter, "RFC 3261");
280
      defineParam(user, "user", DataParameter, "RFC 3261, 4967");
281
      defineParam(extension, "ext", DataParameter, "RFC 3966"); // Token is used when ext is a user-parameter
282
      defineParam(sigcompId, "sigcomp-id", QuotedDataParameter, "RFC 5049");
283
      defineParam(rinstance, "rinstance", DataParameter, "proprietary (resip)");
284
      defineParam(addTransport, "addTransport", ExistsParameter, "RESIP INTERNAL");
285
      defineParam(wsSrcIp, "ws-src-ip", DataParameter, "RESIP INTERNAL (WebSocket)");
286
      defineParam(wsSrcPort, "ws-src-port", UInt32Parameter, "RESIP INTERNAL (WebSocket)");
287
288
#undef defineParam
289
290
   protected:
291
      Data mScheme;
292
      Data mHost;
293
      Data mUser;
294
      Data mUserParameters;
295
      int mPort;
296
      Data mPassword;
297
      Data mNetNs;  ///< Net namespace name scoping host and port
298
      Data mPath;
299
300
      void getAorInternal(bool dropScheme, bool addPort, Data& aor) const;
301
      mutable bool mHostCanonicalized;
302
      mutable Data mCanonicalHost;  ///< cache for IPv6 host comparison
303
304
      bool mIsBetweenAngleQuotes;
305
306
   private:
307
      std::unique_ptr<Data> mEmbeddedHeadersText;
308
      std::unique_ptr<SipMessage> mEmbeddedHeaders;
309
310
      static ParameterTypes::Factory ParameterFactories[ParameterTypes::MAX_PARAMETER];
311
312
      /** 
313
         Dummy static initialization variable, for ensuring that the encoding 
314
         tables are initialized sometime during static initialization, 
315
         preventing the scenario where multiple threads try to runtime init the 
316
         same table at the same time.
317
         @note Prior to static initialization of this bool, it could be either 
318
            true or false; you should not be using this variable to check 
319
            whether the tables are initialized. Just call the getXTable() 
320
            accessor function; it will init the table if it is not already.
321
      */
322
      static const bool tablesMightBeInitialized;
323
324
};
325
326
}
327
328
#include "rutil/HashMap.hxx"
329
330
HashValue(resip::Uri);
331
332
#endif
333
334
/* ====================================================================
335
 * The Vovida Software License, Version 1.0 
336
 * 
337
 * Copyright (c) 2000 Vovida Networks, Inc.  All rights reserved.
338
 * 
339
 * Redistribution and use in source and binary forms, with or without
340
 * modification, are permitted provided that the following conditions
341
 * are met:
342
 * 
343
 * 1. Redistributions of source code must retain the above copyright
344
 *    notice, this list of conditions and the following disclaimer.
345
 * 
346
 * 2. Redistributions in binary form must reproduce the above copyright
347
 *    notice, this list of conditions and the following disclaimer in
348
 *    the documentation and/or other materials provided with the
349
 *    distribution.
350
 * 
351
 * 3. The names "VOCAL", "Vovida Open Communication Application Library",
352
 *    and "Vovida Open Communication Application Library (VOCAL)" must
353
 *    not be used to endorse or promote products derived from this
354
 *    software without prior written permission. For written
355
 *    permission, please contact vocal@vovida.org.
356
 *
357
 * 4. Products derived from this software may not be called "VOCAL", nor
358
 *    may "VOCAL" appear in their name, without prior written
359
 *    permission of Vovida Networks, Inc.
360
 * 
361
 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
362
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
363
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
364
 * NON-INFRINGEMENT ARE DISCLAIMED.  IN NO EVENT SHALL VOVIDA
365
 * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES
366
 * IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL,
367
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
368
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
369
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
370
 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
371
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
372
 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
373
 * DAMAGE.
374
 * 
375
 * ====================================================================
376
 * 
377
 * This software consists of voluntary contributions made by Vovida
378
 * Networks, Inc. and many individuals on behalf of Vovida Networks,
379
 * Inc.  For more information on Vovida Networks, Inc., please see
380
 * <http://www.vovida.org/>.
381
 *
382
 */