/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 | | */ |