reSIProcate
SIP stack, Dialog Usage Manager and related libraries
Loading...
Searching...
No Matches
Uri.cxx
Go to the documentation of this file.
1#if defined(HAVE_CONFIG_H)
2#include "config.h"
3#endif
4
5#include <ctype.h>
6#include <set>
7
14#include "resip/stack/Uri.hxx"
15#include "rutil/compat.hxx"
16#include "rutil/DataStream.hxx"
17#include "rutil/DnsUtil.hxx"
18#include "rutil/Logger.hxx"
19#include "rutil/ParseBuffer.hxx"
20//#include "rutil/WinLeakCheck.hxx" // not compatible with placement new used below
21
22using namespace resip;
23
24#define RESIPROCATE_SUBSYSTEM Subsystem::SIP
25#define HANDLE_CHARACTER_ESCAPING //undef for old behaviour
26
36
37const bool Uri::tablesMightBeInitialized(initAllTables());
38
40 : ParserCategory(pool),
41 mScheme(Data::Share, Symbols::DefaultSipScheme),
42 mPort(0),
43 mHostCanonicalized(false),
44 mIsBetweenAngleQuotes(false),
45 mIsBareAddrSpec(false)
46{
47}
48
50 ParserCategory(hfv, type, pool),
51 mPort(0),
52 mHostCanonicalized(false),
53 mIsBetweenAngleQuotes(false),
54 mIsBareAddrSpec(false)
55{}
56
57
58static const Data parseContext("Uri constructor");
59Uri::Uri(const Data& data)
61 mScheme(Symbols::DefaultSipScheme),
62 mPort(0),
63 mHostCanonicalized(false),
64 mIsBetweenAngleQuotes(false),
65 mIsBareAddrSpec(false)
66{
67 HeaderFieldValue hfv(data.data(), data.size());
68 // must copy because parse creates overlays
69 Uri tmp(hfv, Headers::UNKNOWN);
70 tmp.checkParsed();
71 *this = tmp;
72}
73
74Uri::Uri(const Uri& rhs,
75 PoolBase* pool)
76 : ParserCategory(rhs, pool),
77 mScheme(rhs.mScheme),
78 mHost(rhs.mHost),
79 mUser(rhs.mUser),
80 mUserParameters(rhs.mUserParameters),
81 mPort(rhs.mPort),
82 mPassword(rhs.mPassword),
83 mNetNs(rhs.mNetNs),
84 mPath(rhs.mPath),
85 mHostCanonicalized(rhs.mHostCanonicalized),
86 mCanonicalHost(rhs.mCanonicalHost),
87 mIsBetweenAngleQuotes(rhs.mIsBetweenAngleQuotes),
88 mIsBareAddrSpec(rhs.mIsBareAddrSpec),
89 mEmbeddedHeadersText(rhs.mEmbeddedHeadersText.get() ? new Data(*rhs.mEmbeddedHeadersText) : 0),
90 mEmbeddedHeaders(rhs.mEmbeddedHeaders.get() ? new SipMessage(*rhs.mEmbeddedHeaders) : 0),
91 mUserRaw(rhs.mUserRaw ? new Data(*rhs.mUserRaw) : nullptr)
92{}
93
94
96{}
97
98// RFC 3261 19.1.6
99#if 0 // deprecated
100Uri
101Uri::fromTel(const Uri& tel, const Data& host)
102{
104
105 Uri u;
106 u.scheme() = Symbols::Sip;
107 u.user() = tel.user();
108 u.host() = host;
109 u.param(p_user) = Symbols::Phone;
110
111 // need to sort the user parameters
112 if (!tel.userParameters().empty())
113 {
114 DebugLog(<< "Uri::fromTel: " << tel.userParameters());
115 Data isub;
116 Data postd;
117
118 int totalSize = 0;
119 std::set<Data> userParameters;
120
122 while (true)
123 {
124 const char* anchor = pb.position();
125 pb.skipToChar(Symbols::SEMI_COLON[0]);
126 Data param = pb.data(anchor);
127 // !dlb! not supposed to lowercase extension parameters
129 totalSize += param.size() + 1;
130
132 {
133 isub = param;
134 }
135 else if (param.prefix(Symbols::Postd))
136 {
137 postd = param;
138 }
139 else
140 {
141 userParameters.insert(param);
142 }
143 if (pb.eof())
144 {
145 break;
146 }
147 else
148 {
149 pb.skipChar();
150 }
151 }
152
153 u.userParameters().reserve(totalSize);
154 if (!isub.empty())
155 {
156 u.userParameters() = isub;
157 }
158 if (!postd.empty())
159 {
160 if (!u.userParameters().empty())
161 {
163 }
164 u.userParameters() += postd;
165 }
166
167 for(std::set<Data>::const_iterator i = userParameters.begin();
168 i != userParameters.end(); ++i)
169 {
170 DebugLog(<< "Adding param: " << *i);
171 if (!u.userParameters().empty())
172 {
174 }
175 u.userParameters() += *i;
176 }
177 }
178
179 return u;
180}
181#endif // deprecated
182
183Uri
184Uri::fromTel(const Uri& tel, const Uri& hostUri)
185{
187
188 Uri u(hostUri);
189 u.scheme() = Symbols::Sip;
190 u.user() = tel.user();
191 u.param(p_user) = Symbols::Phone;
192
193 // need to sort the user parameters
194 if (!tel.userParameters().empty())
195 {
196 DebugLog(<< "Uri::fromTel: " << tel.userParameters());
197 Data isub;
198 Data postd;
199
200 int totalSize = 0;
201 std::set<Data> userParameters;
202
204 while (true)
205 {
206 const char* anchor = pb.position();
208 Data param = pb.data(anchor);
209 // !dlb! not supposed to lowercase extension parameters
211 totalSize += (int)param.size() + 1;
212
214 {
215 isub = param;
216 }
217 else if (param.prefix(Symbols::Postd))
218 {
219 postd = param;
220 }
221 else
222 {
223 userParameters.insert(param);
224 }
225 if (pb.eof())
226 {
227 break;
228 }
229 else
230 {
231 pb.skipChar();
232 }
233 }
234
235 u.userParameters().reserve(totalSize);
236 if (!isub.empty())
237 {
238 u.userParameters() = isub;
239 }
240 if (!postd.empty())
241 {
242 if (!u.userParameters().empty())
243 {
245 }
246 u.userParameters() += postd;
247 }
248
249 for(std::set<Data>::const_iterator i = userParameters.begin();
250 i != userParameters.end(); ++i)
251 {
252 DebugLog(<< "Adding param: " << *i);
253 if (!u.userParameters().empty())
254 {
256 }
257 u.userParameters() += *i;
258 }
259 }
260
261 return u;
262}
263
264bool
266{
267 checkParsed();
268 int digits = 0;
269
270 if(mScheme != Symbols::Tel)
271 {
272 StackLog(<< "not a tel Uri");
273 return false;
274 }
275
276 if(mUser.size() < 4)
277 {
278 StackLog(<< "user part of Uri empty or too short for E.164");
279 return false;
280 }
281
282 // E.164 numbers must begin with a + and have at least
283 // 3 digits
284 if(mUser[0] != '+')
285 {
286 StackLog(<< "user part of Uri does not begin with `+' or too short");
287 return false;
288 }
289
290 // count the digits (skip the leading `+')
291 for(const char* i=user().begin() + 1; i!= user().end(); i++)
292 {
293 if (isdigit(static_cast< unsigned char >(*i)))
294 {
295 digits++;
296 }
297 else
298 {
299 if (*i != '-')
300 {
301 StackLog(<< "user part of Uri contains non-digit: " << *i);
302 return false; // Only digits and '-' permitted
303 }
304 }
305 }
306 if(digits > 15)
307 {
308 // E.164 only permits 15 digits in a phone number
309 StackLog(<< "user part of Uri contains more than 15 digits");
310 return false;
311 }
312
313 DebugLog(<< "is in E.164 format for ENUM: " << mUser);
314 return true;
315}
316
317std::vector<Data>
318Uri::getEnumLookups(const std::vector<Data>& suffixes) const
319{
320 std::vector<Data> results;
321 Data prefix;
322 if (isEnumSearchable())
323 {
324 // skip the leading +
325 for (const char* i=user().end()-1 ; i!= user().begin(); --i)
326 {
327 if (isdigit(static_cast< unsigned char >(*i)))
328 {
329 prefix += *i;
330 prefix += Symbols::DOT;
331 }
332 }
333 StackLog(<< "E.164 number reversed for ENUM query: " << prefix);
334 for (std::vector<Data>::const_iterator j=suffixes.begin(); j != suffixes.end(); ++j)
335 {
336 results.push_back(prefix + *j);
337 }
338 }
339 return results;
340}
341
342bool
344{
345 checkParsed();
346 return (mEmbeddedHeadersText.get() && !mEmbeddedHeadersText->empty()) || mEmbeddedHeaders.get() != 0;
347}
348
349void
351{
352 checkParsed();
353 mEmbeddedHeaders.reset();
354 mEmbeddedHeadersText.reset();
355}
356
357Uri&
359{
360 if (this != &rhs)
361 {
363 mScheme = rhs.mScheme;
364 mHost = rhs.mHost;
365 mPath = rhs.mPath;
368 mUser = rhs.mUser;
369 if (rhs.mUserRaw)
370 {
371 mUserRaw.reset(new Data(*rhs.mUserRaw));
372 }
373 else
374 {
375 mUserRaw.reset();
376 }
378 mPort = rhs.mPort;
379 mPassword = rhs.mPassword;
380 mNetNs = rhs.mNetNs;
381 if (rhs.mEmbeddedHeaders.get() != 0)
382 {
383 mEmbeddedHeaders.reset(new SipMessage(*rhs.mEmbeddedHeaders));
384 }
385 else if(rhs.mEmbeddedHeadersText.get() != 0)
386 {
387 if(!mEmbeddedHeadersText.get())
388 {
389 mEmbeddedHeadersText.reset(new Data(*rhs.mEmbeddedHeadersText));
390 }
391 else
392 {
393 // !bwc! Data::operator= is smart enough to handle this safely.
394 *mEmbeddedHeadersText = *rhs.mEmbeddedHeadersText;
395 }
396 }
397 }
398 return *this;
399}
400
406{
407 public:
411 OrderUnknownParameters() { notUsed=false; };
412
417
426 bool operator()(const Parameter* p1, const Parameter* p2) const
427 {
428 return dynamic_cast<const UnknownParameter*>(p1)->getName() < dynamic_cast<const UnknownParameter*>(p2)->getName();
429 }
430
431 private:
432 bool notUsed;
433};
434
436{
437 if (!param1 || !param2)
438 {
439 return false;
440 }
441
442 switch (param1->getType()) {
443 case ParameterTypes::user:
444 case ParameterTypes::method:
445 case ParameterTypes::maddr:
446 case ParameterTypes::transport:
447 case ParameterTypes::rinstance:
448 case ParameterTypes::comp:
449 case ParameterTypes::extension:
450 case ParameterTypes::wsSrcIp:
451 case ParameterTypes::sigcompId:
452 return isEqualNoCase(dynamic_cast<DataParameter*>(param1)->value(),
453 dynamic_cast<DataParameter*>(param2)->value());
454
455 case ParameterTypes::ttl:
456 case ParameterTypes::duration:
457 case ParameterTypes::wsSrcPort:
458 return dynamic_cast<UInt32Parameter*>(param1)->value() ==
459 dynamic_cast<UInt32Parameter*>(param2)->value();
460
461 case ParameterTypes::gr:
462 return isEqualNoCase(dynamic_cast<ExistsOrDataParameter*>(param1)->value(),
463 dynamic_cast<ExistsOrDataParameter*>(param2)->value());
464
465 case ParameterTypes::lr:
466 case ParameterTypes::ob:
467 // Exists parameters are equal.
468 return true;
469
470 default:
471 // Other parameters are not considered.
472 // Parameters may be added accordingly to RFCs.
473 return true;
474 }
475}
476
478{
479 if (!param1 || !param2)
480 {
481 return false;
482 }
483
484 switch (param1->getType()) {
485 case ParameterTypes::user:
486 case ParameterTypes::method:
487 case ParameterTypes::maddr:
488 case ParameterTypes::transport:
489 case ParameterTypes::rinstance:
490 case ParameterTypes::comp:
491 case ParameterTypes::extension:
492 case ParameterTypes::wsSrcIp:
493 case ParameterTypes::sigcompId:
494 return isLessThanNoCase(dynamic_cast<DataParameter*>(param1)->value(),
495 dynamic_cast<DataParameter*>(param2)->value());
496
497 case ParameterTypes::ttl:
498 case ParameterTypes::duration:
499 case ParameterTypes::wsSrcPort:
500 return dynamic_cast<UInt32Parameter*>(param1)->value() <
501 dynamic_cast<UInt32Parameter*>(param2)->value();
502
503 case ParameterTypes::gr:
504 return isLessThanNoCase(dynamic_cast<ExistsOrDataParameter*>(param1)->value(),
505 dynamic_cast<ExistsOrDataParameter*>(param2)->value());
506
507 case ParameterTypes::lr:
508 case ParameterTypes::ob:
509 // Exists parameters are equal.
510 return false;
511
512 default:
513 // Other parameters are not considered.
514 // Parameters may be added accordingly to RFCs.
515 return false;
516 }
517}
518
520{
521 return type == ParameterTypes::user ||
522 type == ParameterTypes::ttl ||
523 type == ParameterTypes::method ||
524 type == ParameterTypes::maddr ||
525 type == ParameterTypes::transport;
526}
527
535
536bool
537Uri::operator==(const Uri& other) const
538{
539 checkParsed();
540 other.checkParsed();
541
542 // compare hosts
545 {
546 // compare canonicalized IPV6 addresses
547
548 // update canonicalized if host changed
550 {
553 }
554
555 // update canonicalized if host changed
556 if (!other.mHostCanonicalized)
557 {
559 other.mHostCanonicalized=true;
560 }
561
562 if (mCanonicalHost != other.mCanonicalHost)
563 {
564 return false;
565 }
566 }
567 else
568 {
569 if (!isEqualNoCase(mHost, other.mHost))
570 {
571 return false;
572 }
573 }
574
575 // Case-sensitive user comparison for:
576 // - sip:/sips: per RFC 3261 sec 19.1.4.
577 // - urn: because the NID (case-insensitive per RFC 8141) is already
578 // normalized to lowercase by Uri::parse() (see comment there), so a
579 // plain compare here is correct: NID case differences have already
580 // been folded away, and NSS case is preserved and compared as-is.
581 // Known deviation: mUser also holds any rq-components/fragment
582 // (see the comment in Uri::parse()'s urn branch), which RFC 8141
583 // sec 3.1 explicitly excludes from URN equivalence -- so here
584 // "urn:example:nss?+rcomponent" != "urn:example:nss", where the RFC
585 // would consider them equivalent. Acceptable for SIP routing
586 // purposes (this is the same granularity used to compare the
587 // sip:/sips: user part above), but not a strict RFC 8141 comparison.
588 // Every other scheme defaults to case-insensitive.
589 bool userEqual;
592 {
593 userEqual = (mUser == other.mUser);
594 }
595 else
596 {
597 userEqual = isEqualNoCase(mUser, other.mUser);
598 }
599
600 if (isEqualNoCase(mScheme, other.mScheme) &&
601 userEqual &&
603 mPassword == other.mPassword &&
604 mPort == other.mPort &&
605 mNetNs == other.mNetNs &&
606 mPath == mPath)
607 {
608 for (ParameterList::const_iterator it = mParameters.begin(); it != mParameters.end(); ++it)
609 {
610 Parameter* otherParam = other.getParameterByEnum((*it)->getType());
611
612 if (Uri::isSignificantUriParameter((*it)->getType()) || otherParam)
613 {
614 if (!Uri::compareUriParametersEqual(*it, otherParam))
615 {
616 return false;
617 }
618 }
619 }
620
621 // now check the other way, sigh
622 for (ParameterList::const_iterator it = other.mParameters.begin(); it != other.mParameters.end(); ++it)
623 {
624 Parameter* param = getParameterByEnum((*it)->getType());
625
626 if (Uri::isSignificantUriParameter((*it)->getType()) || param)
627 {
629 {
630 return false;
631 }
632 }
633 }
634 }
635 else
636 {
637 return false;
638 }
639
640 OrderUnknownParameters orderUnknown;
641
642#if defined(__SUNPRO_CC) || defined(WIN32) || defined(__sun__)
643 // The Solaris Forte STL implementation does not support the
644 // notion of a list.sort() function taking a BinaryPredicate.
645 // The hacky workaround is to load the Parameter pointers into
646 // an STL set which does support an ordering function.
647
648 typedef std::set<Parameter*, OrderUnknownParameters> ParameterSet;
649 ParameterSet unA, unB;
650
651 for (ParameterList::const_iterator i = mUnknownParameters.begin();
652 i != mUnknownParameters.end(); ++i)
653 {
654 unA.insert(*i);
655 }
656 for (ParameterList::const_iterator i = other.mUnknownParameters.begin();
657 i != other.mUnknownParameters.end(); ++i)
658 {
659 unB.insert(*i);
660 }
661
662 ParameterSet::iterator a = unA.begin();
663 ParameterSet::iterator b = unB.begin();
664#else
665 // .dlb. more efficient to copy to vector for sorting?
666 // Uri comparison is expensive; consider caching? ugh
669
670 sort(unA.begin(), unA.end(), orderUnknown);
671 sort(unB.begin(), unB.end(), orderUnknown);
672
673 ParameterList::iterator a = unA.begin();
674 ParameterList::iterator b = unB.begin();
675#endif
676
677 while(a != unA.end() && b != unB.end())
678 {
679 if (orderUnknown(*a, *b))
680 {
681 ++a;
682 }
683 else if (orderUnknown(*b, *a))
684 {
685 ++b;
686 }
687 else
688 {
689 if (!isEqualNoCase(dynamic_cast<UnknownParameter*>(*a)->value(),
690 dynamic_cast<UnknownParameter*>(*b)->value()))
691 {
692 return false;
693 }
694 ++a;
695 ++b;
696 }
697 }
698 return true;
699}
700
701bool
702Uri::operator!=(const Uri& other) const
703{
704 return !(*this == other);
705}
706
707bool
708Uri::operator<(const Uri& other) const
709{
710 other.checkParsed();
711 checkParsed();
712 if (mUser < other.mUser)
713 {
714 return true;
715 }
716
717 if (mUser > other.mUser)
718 {
719 return false;
720 }
721
723 {
724 return true;
725 }
726
728 {
729 return false;
730 }
731
732 // !bwc! Canonicalize before we compare! Jeez...
734 {
736 {
738 }
739 else
740 {
743 }
745 }
746
747 if (!other.mHostCanonicalized)
748 {
750 {
752 }
753 else
754 {
755 other.mCanonicalHost = other.mHost;
757 }
758 other.mHostCanonicalized=true;
759 }
760
761 if (mCanonicalHost < other.mCanonicalHost)
762 {
763 return true;
764 }
765
766 if (mCanonicalHost > other.mCanonicalHost)
767 {
768 return false;
769 }
770
771 if (mPort < other.mPort)
772 {
773 return true;
774 }
775
776 if (mPort > other.mPort)
777 {
778 return false;
779 }
780
781 for (ParameterList::const_iterator it = mParameters.begin(); it != mParameters.end(); ++it)
782 {
783 Parameter* otherParam = other.getParameterByEnum((*it)->getType());
784
785 if (otherParam)
786 {
787 if (Uri::compareUriParametersLessThan(*it, otherParam)) {
788 return true;
789 }
790
791 if (Uri::compareUriParametersLessThan(otherParam, *it)) {
792 return false;
793 }
794 }
795 else if (Uri::isSignificantUriParameter((*it)->getType()))
796 {
797 return true; // Significant URI params should not be ignored.
798 }
799 }
800
801 // Sort unknown parameters from both URIs by their name using comparator class.
802 OrderUnknownParameters orderUnknown;
803
804#if defined(__SUNPRO_CC) || defined(WIN32) || defined(__sun__)
805 // The Solaris Forte STL implementation does not support the
806 // notion of a list.sort() function taking a BinaryPredicate.
807 // The hacky workaround is to load the Parameter pointers into
808 // an STL set which does support an ordering function.
809
810 typedef std::set<Parameter*, OrderUnknownParameters> ParameterSet;
811 ParameterSet thisUriParamList, otherUriParamList;
812
813 for (ParameterList::const_iterator i = mUnknownParameters.begin();
814 i != mUnknownParameters.end(); ++i)
815 {
816 thisUriParamList.insert(*i);
817 }
818 for (ParameterList::const_iterator i = other.mUnknownParameters.begin();
819 i != other.mUnknownParameters.end(); ++i)
820 {
821 otherUriParamList.insert(*i);
822 }
823#else
824 ParameterList thisUriParamList = mUnknownParameters;
825 ParameterList otherUriParamList = other.mUnknownParameters;
826
827 sort(thisUriParamList.begin(), thisUriParamList.end(), orderUnknown);
828 sort(otherUriParamList.begin(), otherUriParamList.end(), orderUnknown);
829#endif
830
831 auto thisUriParam = thisUriParamList.begin();
832 auto otherUriParam = otherUriParamList.begin();
833
834 // Iterate through unknown parameters of both URIs.
835 // Advance iterators to compare values of parameters with matching names.
836 while(thisUriParam != thisUriParamList.end() && otherUriParam != otherUriParamList.end())
837 {
838 if (orderUnknown(*thisUriParam, *otherUriParam))
839 {
840 // this < other param name.
841 ++thisUriParam;
842 }
843 else if (orderUnknown(*otherUriParam, *thisUriParam))
844 {
845 // other < this param name.
846 ++otherUriParam;
847 }
848 else
849 {
850 // this == other param name.
851 // Unknown parameter names are the same. Compare their values.
852 const Data& thisParamValue = dynamic_cast<UnknownParameter*>(*thisUriParam)->value();
853 const Data& otherParamValue = dynamic_cast<UnknownParameter*>(*otherUriParam)->value();
854
855 if (isLessThanNoCase(thisParamValue,
856 otherParamValue))
857 {
858 return true;
859 }
860
861 if (isLessThanNoCase(otherParamValue,
862 thisParamValue))
863 {
864 return false;
865 }
866
867 // Move iterators to the next position.
868 ++thisUriParam;
869 ++otherUriParam;
870 }
871 }
872
873 return false;
874}
875
876bool
877Uri::aorEqual(const resip::Uri& rhs) const
878{
879 checkParsed();
880 rhs.checkParsed();
881
883 {
885 {
887 }
888 else
889 {
892 }
894 }
895
896 if (!rhs.mHostCanonicalized)
897 {
899 {
901 }
902 else
903 {
904 rhs.mCanonicalHost = rhs.mHost;
906 }
907 rhs.mHostCanonicalized=true;
908 }
909
910 return (mUser == rhs.mUser) && (mCanonicalHost == rhs.mCanonicalHost) && (mPort == rhs.mPort) &&
911 isEqualNoCase(mScheme, rhs.mScheme) && (mNetNs == rhs.mNetNs);
912}
913
914void
915Uri::getAorInternal(bool dropScheme, bool addPort, Data& aor) const
916{
917 // The AOR is an identity/lookup key, so the user part is intentionally
918 // emitted in canonical (table-escaped) form and is NOT preserved verbatim
919 // the way encodeParsed()/getAorAsUri() preserve the sender's mUserRaw.
920 // Canonicalizing here keeps the key stable regardless of how a sender
921 // escaped it (e.g. "%23" vs a literal '#'), which matters because
922 // getAorNoPort() feeds auth key comparisons (DigestAuthenticator, etc.)
923 // and the registration DB is keyed on this form. Do not change this to
924 // preserve mUserRaw without auditing those key/identity paths.
925 checkParsed();
926 // canonicalize host
927
928 addPort = addPort && mPort!=0;
929
930 bool hostIsIpV6Address = DnsUtil::isIpV6Address(mHost);
932 {
933 if (hostIsIpV6Address)
934 {
936 }
937 else
938 {
941 }
942 mHostCanonicalized = true;
943 }
944
945 // !bwc! Maybe reintroduce caching of aor. (Would use a bool instead of the
946 // mOldX cruft)
947 // @:10000
948 aor.clear();
949 aor.reserve((dropScheme ? 0 : mScheme.size()+1)
950 + mUser.size() + mCanonicalHost.size() + 7);
951 if(!dropScheme)
952 {
953 aor += mScheme;
954 aor += ':';
955 }
956
957 if (!mUser.empty())
958 {
959#ifdef HANDLE_CHARACTER_ESCAPING
960 {
961 oDataStream str(aor);
963 {
965 }
966 else
967 {
969 }
970 }
971#else
972 aor += mUser;
973#endif
974 if(!mCanonicalHost.empty())
975 {
976 aor += Symbols::AT_SIGN;
977 }
978 }
979
980 if(hostIsIpV6Address && addPort)
981 {
982 aor += Symbols::LS_BRACKET;
983 aor += mCanonicalHost;
984 aor += Symbols::RS_BRACKET;
985 }
986 else
987 {
988 aor += mCanonicalHost;
989 }
990
991 if(addPort)
992 {
993 aor += Symbols::COLON;
994 aor += Data(mPort);
995 }
996}
997
998Data
999Uri::getAOR(bool addPort) const
1000{
1001 Data result;
1002 getAorInternal(false, addPort, result);
1003 return result;
1004}
1005
1006bool
1008{
1009 try
1010 {
1011 ParseBuffer pb(mUser);
1012 pb.assertNotEof();
1013 const char* anchor=pb.position();
1014 bool local=false;
1015 if(*pb.position()=='+')
1016 {
1017 // Might be a global phone number
1018 pb.skipChar();
1020 }
1021 else
1022 {
1024 local=true;
1025 }
1026
1027 Data dialString(pb.data(anchor));
1028 if(dialString.empty())
1029 {
1030 pb.fail(__FILE__, __LINE__, "Dial string is empty.");
1031 }
1032
1033 // ?bwc? More dial-string checking? For instance, +/ (or simply /) is not
1034 // a valid dial-string according to the BNF; the string must contain at
1035 // least one actual digit (or in the local number case, one hex digit or
1036 // '*' or '#'. Interestingly, this means that stuff like ///*/// is
1037 // valid)
1038
1039 // Dial string looks ok so far; now look for params (there must be a
1040 // phone-context param if this is a local number, otherwise there might
1041 // or might not be one)
1042 if(local || !pb.eof())
1043 {
1044 // The only thing that can be here is a ';'. If it does, we're going
1045 // to say it is good enough for us. If something in the parameter
1046 // string is malformed, it'll get caught when/if
1047 // getUserAsTelephoneSubscriber() is called.
1048 pb.skipChar(';');
1049 }
1050
1051 return true;
1052 }
1053 catch(ParseException& /*e*/)
1054 {
1055 return false;
1056 }
1057}
1058
1059Token
1061{
1062 // !bwc! Ugly. Someday, refactor all this lazy-parser stuff and make it
1063 // possible to control ownership explicitly.
1064 // Set this up as lazy-parsed, to prevent exceptions from being thrown.
1066 Token tempToken(temp, Headers::NONE);
1067 // tempToken does not own the HeaderFieldValue temp, and temp does not own
1068 // its buffer.
1069
1070 // Here's the voodoo; invoking operator= makes a deep copy of the stuff in
1071 // tempToken, with result owning the memory, and result is in the unparsed
1072 // state.
1073 Token result = tempToken;
1074 return result;
1075}
1076
1077void
1078Uri::setUserAsTelephoneSubscriber(const Token& telephoneSubscriber)
1079{
1080 mUser.clear();
1081 oDataStream str(mUser);
1082 str << telephoneSubscriber;
1083 mUserRaw.reset();
1084}
1085
1086Data
1088{
1089 Data result;
1090 getAorInternal(true, false, result);
1091 return result;
1092}
1093
1094Data
1096{
1097 Data result;
1098 getAorInternal(true, true, result);
1099 return result;
1100}
1101
1102Uri
1103Uri::getAorAsUri(TransportType transportTypeToRemoveDefaultPort) const
1104{
1105 //.dcm. -- tel conversion?
1106 checkParsed();
1107 Uri ret;
1108 ret.scheme() = mScheme;
1109 ret.user() = mUser;
1110 // Carry the as-received user bytes so a derived URI that reaches the wire
1111 // (e.g. a Route built from the AOR) preserves the sender's escaping too.
1112 if (mUserRaw)
1113 {
1114 ret.mUserRaw.reset(new Data(*mUserRaw));
1115 }
1116 ret.host() = mHost;
1117
1118 // Remove any default ports (if required)
1119 if(transportTypeToRemoveDefaultPort == UDP ||
1120 transportTypeToRemoveDefaultPort == TCP)
1121 {
1123 {
1124 ret.port() = mPort;
1125 }
1126 }
1127 else if (transportTypeToRemoveDefaultPort == TLS ||
1128 transportTypeToRemoveDefaultPort == DTLS)
1129 {
1131 {
1132 ret.port() = mPort;
1133 }
1134 }
1135 else
1136 {
1137 ret.port() = mPort;
1138 }
1139
1140 return ret;
1141}
1142
1143#ifdef HANDLE_CHARACTER_ESCAPING
1144// Decodes [start, pb.position()) into `user`, capturing the as-received
1145// bytes into `userRaw` (only if a '%' escape is present) so encodeParsed()
1146// can re-emit them verbatim instead of losing the sender's original
1147// escaping. Shared by the sip:/sips: and urn: user-parsing below -- both
1148// need the exact same "scan for '%', then dataUnescaped" dance.
1149static void
1151 Data& user, std::unique_ptr<Data>& userRaw)
1152{
1153 const char* userEnd = pb.position();
1154 bool userHasEscape = false;
1155 for (const char* p = start; p < userEnd; ++p)
1156 {
1157 if (*p == Symbols::PERCENT[0])
1158 {
1159 userHasEscape = true;
1160 break;
1161 }
1162 }
1163 pb.dataUnescaped(user, start);
1164 // Capture the as-received bytes only after the decode succeeds -- it can
1165 // throw on a malformed escape, and userRaw must never hold bytes that
1166 // fail to decode, so the encode-path re-decode cannot throw. userRaw
1167 // then always decodes back to the user just produced.
1168 if (userHasEscape)
1169 {
1170 userRaw.reset(new Data(start, (Data::size_type)(userEnd - start)));
1171 }
1172}
1173#endif
1174
1175void
1177{
1178 pb.skipWhitespace();
1179 const char* start = pb.position();
1180
1181 // Cleared up front so a path that sets no user part leaves no stale raw.
1182 mUserRaw.reset();
1183
1184 // Relative URLs (typically HTTP) start with a slash. These
1185 // are seen when parsing the WebSocket handshake.
1186 if (*pb.position() == Symbols::SLASH[0])
1187 {
1188 mScheme.clear();
1190 pb.data(mPath, start);
1192 {
1193 parseParameters(pb);
1194 }
1195 return;
1196 }
1197
1198 pb.skipToOneOf(":@");
1199
1200 pb.assertNotEof();
1201
1202 pb.data(mScheme, start);
1203 pb.skipChar(Symbols::COLON[0]);
1205
1206 // NID:NSS plus any rq-components ("?+"/"?=") and fragment ("#") is
1207 // captured as one opaque blob in mUser; no mUserParameters equivalent
1208 // (RFC 8141 has none).
1209 if (mScheme==Symbols::Urn)
1210 {
1211 const char* anchor = pb.position();
1213 {
1214 // Inside "<...>" the only terminator is '>' (SIP requires angle
1215 // brackets exactly to avoid ';'/'?'/',' clashing with NameAddr
1216 // params -- RFC 3261 sec 20 -- so within brackets those chars are
1217 // legal NSS content and must not be treated as delimiters).
1218 static std::bitset<256> delimiter=Data::toBitset("\r\n\t >");
1219 pb.skipToOneOf(delimiter);
1220 }
1221 else if (mIsBareAddrSpec)
1222 {
1223 // Bare (unbracketed) URI inside a header value (e.g. To/From
1224 // without "<...>"), flagged by NameAddr::parse(): stop at
1225 // ';'/'?'/',' too, since NameAddr parameters (";tag=...") may
1226 // follow directly and RFC 8141 gives no way to tell them apart
1227 // from NSS content here. Per RFC 3261 sec 20, a producer whose
1228 // NSS needs these characters must use "<...>" instead, where the
1229 // permissive rule above still applies.
1230 static std::bitset<256> delimiter=Data::toBitset("\r\n\t ;?,");
1231 pb.skipToOneOf(delimiter);
1232 }
1233 else
1234 {
1235 // Every other context: a Request-URI (RequestLine, never
1236 // bracketed but with nothing that can follow except whitespace
1237 // then SIP-Version), a standalone Uri built directly from a
1238 // string, or any other direct caller. ';'/'?'/',' here are legal
1239 // NSS content, same as the bracketed case above.
1241 }
1242#ifdef HANDLE_CHARACTER_ESCAPING
1243 // Decode %XX so user() returns the logical value, as for sip:/sips:.
1244 // But '#'/'?' are structural when unescaped (fragment/rq-components),
1245 // so a received "%23"/"%3F" (escaped data) and a literal "#"/"?"
1246 // (real separator) must not collapse to the same mUser and then
1247 // re-encode with the wrong form -- decodeUserPreservingEscapes()
1248 // keeps the as-received bytes in mUserRaw for that case.
1249 decodeUserPreservingEscapes(pb, anchor, mUser, mUserRaw);
1250#else
1251 pb.data(mUser, anchor);
1252#endif
1253 // RFC 8141 sec 2: NID = alphanum *(alphanum/"-") alphanum, 2-32
1254 // chars, and the NSS must be non-empty; sec 5.1: the NID must not be
1255 // "urn" itself (nonsensical/reserved). Reject anything else here so
1256 // a malformed urn: fails to parse instead of silently reaching the
1257 // application (e.g. DUM) looking like a well-formed one.
1259 if (sep == Data::npos)
1260 {
1261 pb.fail(__FILE__, __LINE__, "urn: missing NID:NSS separator.");
1262 }
1263 if (sep < 2 || sep > 32)
1264 {
1265 pb.fail(__FILE__, __LINE__, "urn: NID must be 2-32 characters.");
1266 }
1267 for (Data::size_type i = 0; i < sep; ++i)
1268 {
1269 const unsigned char c = (unsigned char)mUser[i];
1270 // Explicit ASCII range, not isalnum(): RFC 8141's NID ABNF is
1271 // ASCII-only, but isalnum() follows the process-wide C locale,
1272 // so a non-C locale (common in embedded/softswitch apps that
1273 // call setlocale() for logging/i18n) would accept 8-bit
1274 // characters here that RFC 8141 does not allow.
1275 const bool isAsciiAlnum = (c >= '0' && c <= '9') ||
1276 (c >= 'A' && c <= 'Z') ||
1277 (c >= 'a' && c <= 'z');
1278 if (!isAsciiAlnum && !(c == '-' && i > 0 && i < sep - 1))
1279 {
1280 pb.fail(__FILE__, __LINE__, "urn: NID has an invalid character.");
1281 }
1282 }
1283 if (sep + 1 >= mUser.size())
1284 {
1285 pb.fail(__FILE__, __LINE__, "urn: NSS must not be empty.");
1286 }
1288 {
1289 pb.fail(__FILE__, __LINE__, "urn: NID must not be \"urn\".");
1290 }
1291
1292 // RFC 8141 sec 2.2: the NID is case-insensitive. Normalize it to
1293 // lowercase here, the same way schemeLowercase() already normalizes
1294 // the scheme, so operator==, operator<, the hash function and
1295 // getAorInternal() all agree on urn: equality without needing a
1296 // urn-specific comparator.
1297 // NB: this only runs at parse() time, so a hand-built Uri (user()
1298 // set directly) is not validated/normalized -- same accepted
1299 // limitation as the scheme case-sensitivity noted on
1300 // getAorInternal()/encodeParsed().
1301 {
1302 Data nid(mUser.substr(0, sep));
1303 nid.lowercase();
1304 mUser = nid + mUser.substr(sep);
1305 }
1306 // mUserRaw is deliberately left untouched (still the exact bytes
1307 // received): the validation above runs on the decoded mUser, so a
1308 // NID could in principle hide a gratuitous, unnecessary %-escape
1309 // (e.g. "urn:EX%41MPLE:nss") that isn't reflected at the same byte
1310 // offset in mUserRaw -- rewriting mUserRaw's NID prefix in place,
1311 // like above, would silently corrupt it in that case. Leaving it
1312 // untouched is simpler and always correct: encodeParsed()'s
1313 // decodedUserRaw==mUser check already re-decodes mUserRaw and falls
1314 // back to escaping mUser fresh whenever they no longer match (e.g.
1315 // because of this normalization step here), which is exactly the
1316 // desired outcome whenever the NID's original casing has changed.
1317 return;
1318 }
1319
1320 if (mScheme==Symbols::Tel)
1321 {
1322 const char* anchor = pb.position();
1323 static std::bitset<256> delimiter=Data::toBitset("\r\n\t ;>");
1324 pb.skipToOneOf(delimiter);
1325 pb.data(mUser, anchor);
1326 if (!pb.eof() && *pb.position() == Symbols::SEMI_COLON[0])
1327 {
1328 anchor = pb.skipChar();
1330 pb.data(mUserParameters, anchor);
1331 }
1332 return;
1333 }
1334
1335 start = pb.position();
1336 static std::bitset<256> userPortOrPasswordDelim(Data::toBitset("@:\""));
1337 // stop at double-quote to prevent matching an '@' in a quoted string param.
1338 pb.skipToOneOf(userPortOrPasswordDelim);
1339 if (!pb.eof())
1340 {
1341 const char* atSign=0;
1342 if (*pb.position() == Symbols::COLON[0])
1343 {
1344 // Either a password, or a port
1345 const char* afterColon = pb.skipChar();
1346 pb.skipToOneOf("@\"");
1347 if(!pb.eof() && *pb.position() == Symbols::AT_SIGN[0])
1348 {
1349 atSign=pb.position();
1350 // password
1351#ifdef HANDLE_CHARACTER_ESCAPING
1352 pb.dataUnescaped(mPassword, afterColon);
1353#else
1354 pb.data(mPassword, afterColon);
1355#endif
1356 pb.reset(afterColon-1);
1357 }
1358 else
1359 {
1360 // port. No user part.
1361 pb.reset(start);
1362 }
1363 }
1364 else if(*pb.position() == Symbols::AT_SIGN[0])
1365 {
1366 atSign=pb.position();
1367 }
1368 else
1369 {
1370 // Only a hostpart
1371 pb.reset(start);
1372 }
1373
1374 if(atSign)
1375 {
1376#ifdef HANDLE_CHARACTER_ESCAPING
1377 // The range dataUnescaped decodes here is exactly [start, position),
1378 // i.e. up to ':' before a password, else '@' -- decodeUserPreservingEscapes()
1379 // scans it for an escape and keeps the as-received bytes in mUserRaw.
1380 decodeUserPreservingEscapes(pb, start, mUser, mUserRaw);
1381#else
1382 pb.data(mUser, start);
1383#endif
1384 pb.reset(atSign);
1385 start = pb.skipChar();
1386 }
1387 }
1388 else
1389 {
1390 pb.reset(start);
1391 }
1392
1393 if (pb.eof())
1394 {
1395 return;
1396 }
1397
1398 mHostCanonicalized=false;
1399 static std::bitset<256> hostDelimiter(Data::toBitset("\r\n\t :;?>"));
1400 if (*start == '[')
1401 {
1402 start = pb.skipChar();
1403 pb.skipToChar(']');
1404 pb.data(mHost, start);
1406 if (mCanonicalHost.empty())
1407 {
1408 // .bwc. So the V6 addy is garbage.
1409 throw ParseException("Unparsable V6 address (note, this might"
1410 " be unparsable because IPV6 support is not"
1411 " enabled)","Uri",__FILE__,
1412 __LINE__);
1413 }
1414 mHostCanonicalized = true;
1415 pb.skipChar();
1416 pb.skipToOneOf(hostDelimiter);
1417 }
1418 else
1419 {
1420 pb.skipToOneOf(hostDelimiter);
1421 pb.data(mHost, start);
1422 }
1423
1424 if (!pb.eof() && *pb.position() == ':')
1425 {
1426 start = pb.skipChar();
1427 mPort = pb.uInt32();
1428 }
1429 else
1430 {
1431 mPort = 0;
1432 }
1433
1434 parseParameters(pb);
1435
1436 if (!pb.eof() && *pb.position() == Symbols::QUESTION[0])
1437 {
1438 const char* anchor = pb.position();
1439
1441 {
1442 // Embedded headers will either end at the angle bracket (when Uri is in a NameAddr that uses angle
1443 // brackets) or at a semi-colon (when Uri is in a NameAddr that doesn't use angle brackets and has
1444 // NameAddr parameters following the embedded headers), or in Whitespace.
1445 // We used to just look for either of the 3 terminators, however to be more tolerant of endpoints
1446 // that do not properly escape ;'s in the embedded headers, we relax the rules, only when the uri
1447 // falls between angle quotes/brackets - in this case we will allow non-escaped semi-colons by only
1448 // looking for > and whitespace as a terminator.
1450 }
1451 else
1452 {
1454 }
1455
1456 if(!mEmbeddedHeadersText.get()) mEmbeddedHeadersText.reset(new Data);
1457 pb.data(*mEmbeddedHeadersText, anchor);
1458 }
1459}
1460
1463{
1464 return new Uri(*this);
1465}
1466
1468Uri::clone(void* location) const
1469{
1470 return new (location) Uri(*this);
1471}
1472
1475{
1476 return new (pool) Uri(*this);
1477}
1478
1479void Uri::setUriUserEncoding(unsigned char c, bool encode)
1480{
1482}
1483
1484void Uri::setUriPasswordEncoding(unsigned char c, bool encode)
1485{
1487}
1488
1489void Uri::setUriUrnEncoding(unsigned char c, bool encode)
1490{
1492}
1493
1494// should not encode user parameters unless its a tel?
1496Uri::encodeParsed(EncodeStream& str) const
1497{
1498 // Relative URIs may not have the scheme
1499 if (!mScheme.empty())
1500 {
1501 str << mScheme << Symbols::COLON;
1502 }
1503
1504 if (!mUser.empty())
1505 {
1506#ifdef HANDLE_CHARACTER_ESCAPING
1507 // urn: uses its own table (doesn't escape ':', '@', ';', '?', '#',
1508 // sub-delims -- RFC 8141); every other scheme uses the sip:/sips:
1509 // user table.
1512 if (mUserRaw)
1513 {
1514 // Emit the as-received bytes verbatim while they still decode (via the
1515 // same dataUnescaped as parse) to the current mUser, so the sender's
1516 // escaping (e.g. %23) survives regardless of the encoding table; a
1517 // post-parse edit breaks the match and falls back to table escaping.
1518 // Cost: re-decodes and compares on the encode path for every
1519 // %-containing user part (inline Data buffer avoids a heap alloc for
1520 // short values; unescaped users skip this branch).
1521 Data decodedUserRaw;
1522 ParseBuffer pb(mUserRaw->data(), mUserRaw->size());
1523 const char* anchor = pb.position();
1524 pb.skipToEnd();
1525 pb.dataUnescaped(decodedUserRaw, anchor);
1526 if (decodedUserRaw == mUser)
1527 {
1528 str << *mUserRaw;
1529 }
1530 else
1531 {
1532 mUser.escapeToStream(str, table);
1533 }
1534 }
1535 else
1536 {
1537 mUser.escapeToStream(str, table);
1538 }
1539#else
1540 str << mUser;
1541#endif
1542 if (!mUserParameters.empty())
1543 {
1545 }
1546 if (!mPassword.empty())
1547 {
1548 str << Symbols::COLON;
1549#ifdef HANDLE_CHARACTER_ESCAPING
1551#else
1552 str << mPassword;
1553#endif
1554 }
1555 }
1556 if (!mHost.empty())
1557 {
1558 if (!mUser.empty())
1559 {
1560 str << Symbols::AT_SIGN;
1561 }
1563 {
1564 str << '[' << mHost << ']';
1565 }
1566 else
1567 {
1568 str << mHost;
1569 }
1570 }
1571 if (mPort != 0)
1572 {
1573 str << Symbols::COLON << mPort;
1574 }
1575 if (!mPath.empty())
1576 {
1577 str << mPath;
1578 }
1579 encodeParameters(str);
1581
1582 return str;
1583}
1584
1587{
1588 checkParsed();
1589 if (mEmbeddedHeaders.get() == 0)
1590 {
1591 this->mEmbeddedHeaders.reset(new SipMessage());
1592 if (mEmbeddedHeadersText.get() && !mEmbeddedHeadersText->empty())
1593 {
1594 ParseBuffer pb(mEmbeddedHeadersText->data(), mEmbeddedHeadersText->size());
1595 this->parseEmbeddedHeaders(pb);
1596 }
1597 }
1598
1599 return *mEmbeddedHeaders;
1600}
1601
1602const SipMessage&
1604{
1605 Uri* ncthis = const_cast<Uri*>(this);
1606 return ncthis->embedded();
1607}
1608
1609static const Data bodyData("Body");
1610void
1612{
1613 DebugLog(<< "Uri::parseEmbeddedHeaders");
1614 if (!pb.eof() && *pb.position() == Symbols::QUESTION[0])
1615 {
1616 pb.skipChar();
1617 }
1618
1619 const char* anchor;
1620 Data headerName;
1621 Data headerContents;
1622
1623 bool first = true;
1624 while (!pb.eof())
1625 {
1626 if (first)
1627 {
1628 first = false;
1629 }
1630 else
1631 {
1633 }
1634
1635 anchor = pb.position();
1637 pb.data(headerName, anchor);
1638 // .dlb. in theory, need to decode header name
1639
1640 anchor = pb.skipChar(Symbols::EQUALS[0]);
1642 pb.data(headerContents, anchor);
1643
1644 unsigned int len;
1645 char* decodedContents = Embedded::decode(headerContents, len);
1646 mEmbeddedHeaders->addBuffer(decodedContents);
1647
1648 if (isEqualNoCase(bodyData, headerName))
1649 {
1650 mEmbeddedHeaders->setBody(decodedContents, len);
1651 }
1652 else
1653 {
1654 DebugLog(<< "Uri::parseEmbeddedHeaders(" << headerName << ", " << Data(decodedContents, len) << ")");
1655 mEmbeddedHeaders->addHeader(Headers::getType(headerName.data(), headerName.size()),
1656 headerName.data(), static_cast<uint32_t>(headerName.size()),
1657 decodedContents, len);
1658 }
1659 }
1660}
1661
1663Uri::encodeEmbeddedHeaders(EncodeStream& str) const
1664{
1665 if (mEmbeddedHeaders.get())
1666 {
1667 mEmbeddedHeaders->encodeEmbedded(str);
1668 }
1669 else if(mEmbeddedHeadersText.get())
1670 {
1671 // never decoded
1672 str << *mEmbeddedHeadersText;
1673 }
1674 return str;
1675}
1676
1677Data
1679{
1680 Data out;
1681 {
1682 oDataStream dataStream(out);
1683 this->encodeParsed(dataStream);
1684 }
1685 return out;
1686}
1687
1688ParameterTypes::Factory Uri::ParameterFactories[ParameterTypes::MAX_PARAMETER]={0};
1689
1690Parameter*
1691Uri::createParam(ParameterTypes::Type type, ParseBuffer& pb, const std::bitset<256>& terminators, PoolBase* pool)
1692{
1693 if(type > ParameterTypes::UNKNOWN && type < ParameterTypes::MAX_PARAMETER && ParameterFactories[type])
1694 {
1695 return ParameterFactories[type](type, pb, terminators, pool);
1696 }
1697 return 0;
1698}
1699
1700bool
1701Uri::exists(const Param<Uri>& paramType) const
1702{
1703 checkParsed();
1704 bool ret = getParameterByEnum(paramType.getTypeNum()) != NULL;
1705 return ret;
1706}
1707
1708void
1709Uri::remove(const Param<Uri>& paramType)
1710{
1711 checkParsed();
1712 removeParameterByEnum(paramType.getTypeNum());
1713}
1714
1715#define defineParam(_enum, _name, _type, _RFC_ref_ignored) \
1716_enum##_Param::DType& \
1717Uri::param(const _enum##_Param& paramType) \
1718{ \
1719 checkParsed(); \
1720 _enum##_Param::Type* p = \
1721 static_cast<_enum##_Param::Type*>(getParameterByEnum(paramType.getTypeNum())); \
1722 if (!p) \
1723 { \
1724 p = new _enum##_Param::Type(paramType.getTypeNum()); \
1725 mParameters.push_back(p); \
1726 } \
1727 return p->value(); \
1728} \
1729 \
1730const _enum##_Param::DType& \
1731Uri::param(const _enum##_Param& paramType) const \
1732{ \
1733 checkParsed(); \
1734 _enum##_Param::Type* p = \
1735 static_cast<_enum##_Param::Type*>(getParameterByEnum(paramType.getTypeNum())); \
1736 if (!p) \
1737 { \
1738 InfoLog(<< "Missing parameter " _name " " << ParameterTypes::ParameterNames[paramType.getTypeNum()]); \
1739 DebugLog(<< *this); \
1740 throw Exception("Missing parameter " _name, __FILE__, __LINE__); \
1741 } \
1742 return p->value(); \
1743}
1744
1745defineParam(ob,"ob",ExistsParameter,"RFC 5626");
1746defineParam(gr, "gr", ExistsOrDataParameter, "RFC 5627");
1747defineParam(comp, "comp", DataParameter, "RFC 3486");
1748defineParam(duration, "duration", UInt32Parameter, "RFC 4240");
1749defineParam(lr, "lr", ExistsParameter, "RFC 3261");
1750defineParam(maddr, "maddr", DataParameter, "RFC 3261");
1751defineParam(method, "method", DataParameter, "RFC 3261");
1752defineParam(transport, "transport", DataParameter, "RFC 3261");
1753defineParam(ttl, "ttl", UInt32Parameter, "RFC 3261");
1754defineParam(user, "user", DataParameter, "RFC 3261, 4967");
1755defineParam(extension, "ext", DataParameter, "RFC 3966"); // Token is used when ext is a user-parameter
1756defineParam(sigcompId, "sigcomp-id", QuotedDataParameter, "RFC 5049");
1757defineParam(rinstance, "rinstance", DataParameter, "proprietary (resip)");
1758defineParam(addTransport, "addTransport", ExistsParameter, "RESIP INTERNAL");
1759defineParam(wsSrcIp, "ws-src-ip", DataParameter, "RESIP INTERNAL (WebSocket)");
1760defineParam(wsSrcPort, "ws-src-port", UInt32Parameter, "RESIP INTERNAL (WebSocket)");
1761
1762#undef defineParam
1763
1765
1766/* ====================================================================
1767 * The Vovida Software License, Version 1.0
1768 *
1769 * Copyright (c) 2000 Vovida Networks, Inc. All rights reserved.
1770 *
1771 * Redistribution and use in source and binary forms, with or without
1772 * modification, are permitted provided that the following conditions
1773 * are met:
1774 *
1775 * 1. Redistributions of source code must retain the above copyright
1776 * notice, this list of conditions and the following disclaimer.
1777 *
1778 * 2. Redistributions in binary form must reproduce the above copyright
1779 * notice, this list of conditions and the following disclaimer in
1780 * the documentation and/or other materials provided with the
1781 * distribution.
1782 *
1783 * 3. The names "VOCAL", "Vovida Open Communication Application Library",
1784 * and "Vovida Open Communication Application Library (VOCAL)" must
1785 * not be used to endorse or promote products derived from this
1786 * software without prior written permission. For written
1787 * permission, please contact vocal@vovida.org.
1788 *
1789 * 4. Products derived from this software may not be called "VOCAL", nor
1790 * may "VOCAL" appear in their name, without prior written
1791 * permission of Vovida Networks, Inc.
1792 *
1793 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
1794 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1795 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
1796 * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL VOVIDA
1797 * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES
1798 * IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL,
1799 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
1800 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
1801 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
1802 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
1803 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
1804 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
1805 * DAMAGE.
1806 *
1807 * ====================================================================
1808 *
1809 * This software consists of voluntary contributions made by Vovida
1810 * Networks, Inc. and many individuals on behalf of Vovida Networks,
1811 * Inc. For more information on Vovida Networks, Inc., please see
1812 * <http://www.vovida.org/>.
1813 *
1814 */
#define defineParam(_enum, _name, _type, _RFC_ref_ignored)
Definition Auth.cxx:239
#define HashValueImp(type, ret)
Definition HashMap.hxx:24
static const Data sep("[]")
#define DebugLog(args_)
Definition Logger.hxx:128
#define StackLog(args_)
Definition Logger.hxx:125
#define resip_assert(x)
This file needs to work for both C and C++ code.
static void decodeUserPreservingEscapes(ParseBuffer &pb, const char *start, Data &user, std::unique_ptr< Data > &userRaw)
Definition Uri.cxx:1150
static const Data bodyData("Body")
static bool initAllTables()
Definition Uri.cxx:27
used as a comparator for sorting purposes
Definition Uri.cxx:406
bool operator()(const Parameter *p1, const Parameter *p2) const
used as a comparator for sorting purposes This does a straight Data comparison for name and returns t...
Definition Uri.cxx:426
OrderUnknownParameters()
constructor ; never called explicitly
Definition Uri.cxx:411
~OrderUnknownParameters()
empty destructor
Definition Uri.cxx:416
Generically represents miscellaneous parameter data.
An alternative to std::string, encapsulates an arbitrary buffer of bytes.
Definition Data.hxx:90
EncodeStream & escapeToStream(EncodeStream &str, Predicate shouldEscape) const
Performs escaping of this Data according to the indicated Predicate.
Definition Data.hxx:1147
const char * end() const noexcept
Returns a pointer to the end of the buffer used by the Data.
Definition Data.hxx:650
bool prefix(const Data &pre) const noexcept
Returns true if this Data starts with the bytes indicated by the passed-in Data.
Definition Data.cxx:1888
Data substr(size_type first, size_type count=Data::npos) const
Copies a portion of this Data into a new Data.
Definition Data.cxx:1932
bool empty() const noexcept
Checks whether the Data is empty.
Definition Data.hxx:591
Data & lowercase()
Converts this Data to lowercase.
Definition Data.cxx:1635
size_t size_type
Definition Data.hxx:94
size_type size() const noexcept
Returns the number of bytes in this Data.
Definition Data.hxx:599
static Data from(const T &x)
Converts from arbitrary other type to Data.
Definition Data.hxx:398
size_type find(const Data &match, size_type start=0) const
Finds a specified sequence of bytes in this Data.
Definition Data.cxx:1947
static const size_type npos
Represents an impossible position; returned to indicate failure to find.
Definition Data.hxx:887
Data & schemeLowercase()
Converts this Data to lowercase, assuming this Data only consists of scheme characters.
Definition Data.cxx:1661
const char * begin() const noexcept
Returns a pointer to the beginning of the buffer used by the Data.
Definition Data.hxx:642
Data & clear()
Clears the contents of this Data.
Definition Data.hxx:800
static std::bitset< 256 > toBitset(const resip::Data &chars)
Creates a bitset reflecting the contents of this data (as a set) ie.
Definition Data.cxx:2477
const char * data() const noexcept
Returns a pointer to the contents of this Data.
Definition Data.hxx:608
void reserve(size_type capacity)
Guarantees that the underlying buffer used by the Data is at least the number of bytes specified.
Definition Data.cxx:1049
static bool isIpV6Address(const Data &ipAddress)
Definition DnsUtil.cxx:386
static Data canonicalizeIpV6Address(const Data &ipV6Address)
Converts the printable form of an IPv6 address into consistent format so that string comparisons will...
Definition DnsUtil.cxx:427
static char * decode(const Data &input, unsigned int &decodedLength)
Definition Embedded.cxx:46
Represents various parameters that are indicated to be in effect merely by being present,...
static Type getType(const char *name, size_t len)
Definition Headers.cxx:351
void checkParsed() const
virtual ParameterTypes::Type getTypeNum() const =0
Parameter *(* Factory)(ParameterTypes::Type, ParseBuffer &, const std::bitset< 256 > &terminators, PoolBase *pool)
ParameterTypes::Type getType() const
Definition Parameter.cxx:16
Provides string-parsing functionality with protection from buffer overflow.
void dataUnescaped(Data &data, const char *start) const
uint32_t uInt32()
dcm! – merge these, ask about length checks
CurrentPosition skipToEnd()
CurrentPosition skipWhitespace()
CurrentPosition skipToChar(char c)
CurrentPosition position() const
static bool oneOf(char c, const char *cs)
void reset(const char *pos)
CurrentPosition skipChars(const char *cs)
void assertNotEof() const
CurrentPosition skipToOneOf(const char *cs)
CurrentPosition skipChar()
void fail(const char *file, unsigned int line, const Data &errmsg=Data::Empty) const
void data(Data &data, const char *start) const
make the passed in data share memory with the buffer (uses Data::Share)
static const char * Whitespace
BaseException used to indicate parse failures.
Base class for all SIP grammar elements that can have parameters.
Parameter * getParameterByEnum(ParameterTypes::Type type) const
ParameterList mUnknownParameters
ParserCategory & operator=(const ParserCategory &rhs)
void removeParameterByEnum(ParameterTypes::Type type)
void parseParameters(ParseBuffer &pb)
EncodeStream & encodeParameters(EncodeStream &str) const
Encodes parameters as they should appear on the wire.
std::vector< Parameter *, StlPoolAllocator< Parameter *, PoolBase > > ParameterList
Generically represents miscellaneous parameter data that is encoded using double quotes.
Represents a SIP message.
static const char * SEMI_COLON
Definition Symbols.hxx:30
static const char * Tel
Definition Symbols.hxx:64
static const char * Sips
Definition Symbols.hxx:63
static const int DefaultSipsPort
Definition Symbols.hxx:85
static const char * LS_BRACKET
Definition Symbols.hxx:39
static const char * Urn
Definition Symbols.hxx:65
static const char * DOT
Definition Symbols.hxx:19
static const char * PERCENT
Definition Symbols.hxx:44
static const char * COLON
Definition Symbols.hxx:15
static const char * RS_BRACKET
Definition Symbols.hxx:40
static const int DefaultSipPort
Definition Symbols.hxx:81
static const char * Isub
Definition Symbols.hxx:69
static const char * QUESTION
Definition Symbols.hxx:42
static const char * Phone
Definition Symbols.hxx:68
static const char * AT_SIGN
Definition Symbols.hxx:14
static const char * Sip
Definition Symbols.hxx:62
static const char * SLASH
Definition Symbols.hxx:32
static const char * Postd
Definition Symbols.hxx:70
static const char * RA_QUOTE
Definition Symbols.hxx:28
static const char * EQUALS
Definition Symbols.hxx:29
static const char * AMPERSAND
Definition Symbols.hxx:43
Represents the "token" element in the RFC 3261 grammar.
Definition Token.hxx:18
Generically represents unsigned 32-bit integer values conveyed by SIP parameters.
Generically used to represent any parameter that is not known by the implmentation.
Represents the "SIP-URI" and "SIPS-URI" elements in the RFC 3261 grammar.
Definition Uri.hxx:22
static EncodingTable & getGlobalNumberTable()
Definition Uri.hxx:296
virtual EncodeStream & encodeParsed(EncodeStream &str) const
Definition Uri.cxx:1496
static bool compareUriParametersEqual(Parameter *param1, Parameter *param2)
Compares two known URI parameters for equality.
Definition Uri.cxx:435
bool mHostCanonicalized
Definition Uri.hxx:348
bool aorEqual(const Uri &rhs) const
Definition Uri.cxx:877
Token getUserAsTelephoneSubscriber() const
Returns the user-part as a 'telephone-subscriber' grammar element (in other words,...
Definition Uri.cxx:1060
static void setUriUrnEncoding(unsigned char c, bool encode)
Definition Uri.cxx:1489
Data getAor() const
Definition Uri.cxx:1095
bool isEnumSearchable() const
Returns true if the uri can be converted into a string that can be used as an enum lookup.
Definition Uri.cxx:265
void parseEmbeddedHeaders(ParseBuffer &pb)
Definition Uri.cxx:1611
virtual void parse(ParseBuffer &pb)
Definition Uri.cxx:1176
bool mIsBareAddrSpec
Definition Uri.hxx:352
Data mUser
Definition Uri.hxx:340
virtual Parameter * createParam(ParameterTypes::Type type, ParseBuffer &pb, const std::bitset< 256 > &terminators, PoolBase *pool)
Definition Uri.cxx:1691
bool isUserRelevant() const
Checks if this URI's scheme has sip:/sips:/tel: user-part semantics, i.e.
Definition Uri.cxx:528
SipMessage & embedded()
Definition Uri.cxx:1586
std::vector< Data > getEnumLookups(const std::vector< Data > &suffixes) const
Return a vector of domains to do a NAPTR lookup for enum.
Definition Uri.cxx:318
bool mIsBetweenAngleQuotes
Definition Uri.hxx:351
static EncodingTable & getPasswordEncodingTable()
Definition Uri.hxx:257
Data mPath
Definition Uri.hxx:345
Data getAorNoPort() const
Definition Uri.cxx:1087
int & port()
Definition Uri.hxx:145
Data & scheme()
Definition Uri.hxx:143
void removeEmbedded()
Definition Uri.cxx:350
Data toString() const
Definition Uri.cxx:1678
bool operator<(const Uri &other) const
Definition Uri.cxx:708
bool hasEmbedded() const
Definition Uri.cxx:343
Data getAOR(bool addPort) const
Definition Uri.cxx:999
Data mCanonicalHost
cache for IPv6 host comparison
Definition Uri.hxx:349
Data mScheme
Definition Uri.hxx:338
bool exists(const Param< Uri > &paramType) const
Definition Uri.cxx:1701
EncodeStream & encodeEmbeddedHeaders(EncodeStream &str) const
Definition Uri.cxx:1663
Data mNetNs
Net namespace name scoping host and port.
Definition Uri.hxx:344
static void setUriPasswordEncoding(unsigned char c, bool encode)
Definition Uri.cxx:1484
static bool compareUriParametersLessThan(Parameter *param1, Parameter *param2)
Compares two URI parameters to determine if the first is less than the second.
Definition Uri.cxx:477
Data mUserParameters
Definition Uri.hxx:341
int mPort
Definition Uri.hxx:342
std::bitset< Uri::uriEncodingTableSize > EncodingTable
Definition Uri.hxx:245
Uri & operator=(const Uri &rhs)
Definition Uri.cxx:358
static EncodingTable & getUserEncodingTable()
Definition Uri.hxx:247
static EncodingTable & getUrnEncodingTable()
Encoding table for the NID:NSS (plus optional rq-components/fragment) of a urn: URI (RFC 8141: namest...
Definition Uri.hxx:273
Data & user()
Definition Uri.hxx:42
void getAorInternal(bool dropScheme, bool addPort, Data &aor) const
Definition Uri.cxx:915
static Uri fromTel(const Uri &, const Uri &hostUri)
Definition Uri.cxx:184
Data mPassword
Definition Uri.hxx:343
void remove(const Param< Uri > &paramType)
Definition Uri.cxx:1709
bool userIsTelephoneSubscriber() const
Returns true if the user appears to fit the BNF for the 'telephone-subscriber' element in the RFC 326...
Definition Uri.cxx:1007
Data mHost
Definition Uri.hxx:339
static EncodingTable & getLocalNumberTable()
Definition Uri.hxx:287
Data & host()
Definition Uri.hxx:40
virtual ParserCategory * clone() const
Definition Uri.cxx:1462
static void setUriUserEncoding(unsigned char c, bool encode)
Modifies the default URI encoding character sets.
Definition Uri.cxx:1479
Data & userParameters()
Definition Uri.hxx:44
bool operator==(const Uri &other) const
Definition Uri.cxx:537
Uri getAorAsUri(TransportType transportTypeToRemoveDefaultPort=UNKNOWN_TRANSPORT) const
Definition Uri.cxx:1103
static bool isSignificantUriParameter(const ParameterTypes::Type type) noexcept
Checks if the URI-parameter appearing in only one URI must not be ignored when comparing the URIs.
Definition Uri.cxx:519
void setUserAsTelephoneSubscriber(const Token &telephoneSubscriber)
Sets the user-part of this URI using the dial-string and parameters stored in telephoneSubscriber.
Definition Uri.cxx:1078
Uri(PoolBase *pool=0)
Definition Uri.cxx:39
bool operator!=(const Uri &other) const
Definition Uri.cxx:702
const Data & param(const ExtensionParameter &param) const
Const accessor for non-natively-supported parameter types.
An ostream that operates on an existing Data.
This file is used to handle compatibility fixes/tweaks so reSIProcate can function on multiple platfo...
dcm! – add UnusedChecking(_enum) below;
bool isEqualNoCase(const Data &left, const Data &right)
Definition Data.hxx:1116
bool isLessThanNoCase(const Data &left, const Data &right)
Definition Data.hxx:1127
static const Data parseContext("PrivacyCategory constructor")
unsigned int uint32_t
Definition Stun.hxx:34
TransportType
An enumeration of transport protocols.
static char * encode(char *buf, const char *data, unsigned int length)
Definition Stun.cxx:645
#define EncodeStream