Re: [reSIProcate-users] ExtensionHeader and comma-separated addr-spec
- From: "Alfred E. Heggestad" <aeh@xxxxxx>
- Date: Wed, 03 Sep 2008 16:57:50 +0200
Hi
please find attached a patch against resiprocate r8218 which adds the
`History-Info' header as defined in RFC 4244
/alfred
Byron Campen wrote:
Yeah; the code lives in MsgHeaderScanner. Not easy to re-use. Your
best bet is to add native support for the header you're working with.
Doing this is somewhat tricky, see
http://www.resiprocate.org/Adding_a_new_header
Best regards,
Byron Campen
Hi Byron
many thanks for your code example, you are right that we also need to
care about quoted commas.
but surely there must be a function in resip that does exactly this?
doesn't all multivalue headers with the NameAddr spec also need to
parse the buffer like this? For example the Contact header should
follow the same syntax.
it would be great for application developers to have access to this
general parsing function (if it exist), so that they can avoid
reimplementing low-level parsing code every time!
/alfred
Byron Campen wrote:
Yikes! That code will blow up in your face. Let me be more explicit:
You'll need to tokenize the stuff contained in s.value(), keeping
in mind to be wary of a quoted strings (since ',' can appear in a
quoted string). Here's some code that should work (although keep in
mind I just wrote this off the seat of my pants; testing is good)
ParseBuffer pb(s.value());
while(!pb.eof())
{
const char* start=pb.position();
pb.skipToOneOf(",\"");
while(!pb.eof() && *pb.position() == '\"')
{
// Quoted string, skip over it, and try again
pb.skipToEndQuote('\"');
pb.skipToOneOf(",\"");
}
// We should either be at a ',' or the end of the buffer
NameAddr na(pb.data(start)); // or new NameAddr, whatever it
is you need.
if(!pb.eof())
{
pb.skipChar(',');
}
}
Best regards,
Byron Campen
Hi Byron
many thanks for your advice!
I ended up using ParseBuffer as you mentioned, and managed to get
the following
piece of code working:
for (StringCategories::iterator i = sc.begin(); i !=
sc.end(); ++i) {
const StringCategory &s = *i;
/* One Foo header can contain many
nameaddr values, so we must parse it */
ParseBuffer pb(s.value());
for (int i=0; !pb.eof() && i<32; i++) {
NameAddr na;
stringstream ss;
na.parse(pb);
ss << na;
printf("Foo %d: \"%s\"\n", i, ss.str().c_str());
}
}
/alfred
Byron Campen wrote:
Comma doesn't mean anything special in an extension header.
(see RFC 3261 BNF for more on this) As an example, the following is
a valid, _single-value_, extension-header:
*snip*
UnknownHeaderWithUnusualValue: ;;,,;;,;
*snip*
You'll need to parse them out yourself, and ParseBuffer will
probably be the tool you'll need to tokenize based on commas.
Best regards,
Byron Campen
Hi
I am facing a problem where I need to parse multiple comma-separated
addresses from an extension header. The problem is that if there are
multiple addr-spec values in one header, the parser is not able
to split the values.
Consider the following code example:
const ExtensionHeader h_fooHeader("P-FooHeader");
if (msg->exists(h_fooHeader)) {
StringCategories &sc = msg->header(h_fooHeader);
for (StringCategories::iterator i = sc.begin();
i != sc.end(); ++i) {
const StringCategory &s = *i;
const Data foo(s.value());
printf("got foo-header: %s\n", foo.c_str());
}
}
this code works for SIP messages like:
P-FooHeader: <sip:foo@xxxxxxxxxxx>;param=1
P-FooHeader: <sip:bar@xxxxxxxxxxx>;param=2
which will print out the two header entries.
But this code is not working for SIP messages like this:
P-FooHeader: <sip:foo@xxxxxxxxxxx>;param=1,
<sip:baz@xxxxxxxxxxx>;param=0
P-FooHeader: <sip:bar@xxxxxxxxxxx>;param=2
For my extension header I would like to parse and validate that the
content (Addr-Spec) is correct. For this I assume that NameAddr is
the
best class to use.
How can I put the content of a StringCategory value into a new
NameAddr value, and iterate over all address fields inside the value?
I have looked at the documentation, but it does not mention this
special case. Are there any places in the code where similar stuff
is done?
Thanks in advance for any help!
/alfred
_______________________________________________
resiprocate-users mailing list
resiprocate-users@xxxxxxxxxxxxxxx
List Archive: http://list.resiprocate.org/archive/resiprocate-users/
Index: resip/stack/Headers.hxx
===================================================================
--- resip/stack/Headers.hxx (revisjon 8218)
+++ resip/stack/Headers.hxx (arbeidskopi)
@@ -201,6 +201,7 @@
defineMultiHeader(PAssociatedUri, "P-Associated-URI", NameAddr, "RFC 3455");
defineMultiHeader(ServiceRoute, "Service-Route", NameAddr, "RFC 3608");
defineHeader(RemotePartyId, "Remote-Party-ID", NameAddr, "draft-ietf-sip-privacy-04"); // ?bwc? Not in 3323, should we keep?
+defineMultiHeader(HistoryInfo, "History-Info", NameAddr, "RFC 4244");
//====================
// StringCategory:
Index: resip/stack/HeaderTypes.hxx
===================================================================
--- resip/stack/HeaderTypes.hxx (revisjon 8218)
+++ resip/stack/HeaderTypes.hxx (arbeidskopi)
@@ -126,6 +126,7 @@
defineHeader(AnswerMode, "Answer-Mode", Token, "draft-ietf-answermode-01"),
defineHeader(PrivAnswerMode, "Priv-Answer-Mode", Token, "draft-ietf-answermode-01"),
defineHeader(RemotePartyId, "Remote-Party-ID", NameAddr, "draft-ietf-sip-privacy-04"), // ?bwc? Not in 3323, should we keep?
+ defineMultiHeader(HistoryInfo, "History-Info", NameAddr, "RFC 4244"),
defineMultiHeader(RESIP_DO_NOT_USE, "ShouldNotSeeThis", StringCategory, "N/A"),
MAX_HEADERS,
Index: resip/stack/SipMessage.hxx
===================================================================
--- resip/stack/SipMessage.hxx (revisjon 8218)
+++ resip/stack/SipMessage.hxx (arbeidskopi)
@@ -256,6 +256,8 @@
defineMultiHeader(Via, "Via", Via, "RFC 3261");
defineHeader(RAck, "RAck", RAckCategory, "RFC 3262");
+ defineMultiHeader(HistoryInfo, "History-Info", NameAddr, "RFC 4244");
+
// unknown header interface
const StringCategories& header(const ExtensionHeader& symbol) const;
StringCategories& header(const ExtensionHeader& symbol);
Index: resip/stack/HeaderHash.cxx
===================================================================
--- resip/stack/HeaderHash.cxx (revisjon 8218)
+++ resip/stack/HeaderHash.cxx (arbeidskopi)
@@ -1,4 +1,4 @@
-/* C++ code produced by gperf version 3.0.1 */
+/* C++ code produced by gperf version 3.0.3 */
/* Command-line: gperf -D -E -L C++ -t -k '*' --compare-strncmp -Z HeaderHash HeaderHash.gperf */
#if !((' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \
@@ -64,9 +64,9 @@
431, 431, 431, 431, 431, 431, 431, 431, 431, 431,
431, 431, 431, 431, 431, 431, 431, 431, 431, 431,
431, 431, 431, 431, 431, 431, 431, 0, 55, 15,
- 0, 30, 35, 10, 5, 25, 5, 70, 40, 75,
- 0, 5, 0, 25, 10, 50, 0, 10, 45, 0,
- 60, 20, 50, 431, 431, 431, 431, 431, 431, 431,
+ 0, 30, 35, 10, 0, 25, 5, 70, 40, 75,
+ 0, 5, 0, 25, 10, 50, 0, 10, 45, 15,
+ 60, 20, 25, 431, 431, 431, 431, 431, 431, 431,
431, 431, 431, 431, 431, 431, 431, 431, 431, 431,
431, 431, 431, 431, 431, 431, 431, 431, 431, 431,
431, 431, 431, 431, 431, 431, 431, 431, 431, 431,
@@ -169,7 +169,7 @@
{
enum
{
- TOTAL_KEYWORDS = 103,
+ TOTAL_KEYWORDS = 104,
MIN_WORD_LENGTH = 1,
MAX_WORD_LENGTH = 25,
MIN_HASH_VALUE = 1,
@@ -180,12 +180,12 @@
{
#line 20 "HeaderHash.gperf"
{"t", Headers::To},
+#line 91 "HeaderHash.gperf"
+ {"path", Headers::Path},
#line 26 "HeaderHash.gperf"
{"o", Headers::Event},
#line 36 "HeaderHash.gperf"
{"to", Headers::To},
-#line 91 "HeaderHash.gperf"
- {"path", Headers::Path},
#line 22 "HeaderHash.gperf"
{"r", Headers::ReferTo},
#line 16 "HeaderHash.gperf"
@@ -212,18 +212,18 @@
{"v", Headers::Via},
#line 18 "HeaderHash.gperf"
{"s", Headers::Subject},
-#line 75 "HeaderHash.gperf"
- {"warning", Headers::Warning},
#line 23 "HeaderHash.gperf"
{"b", Headers::ReferredBy},
+#line 82 "HeaderHash.gperf"
+ {"hide", Headers::UNKNOWN},
#line 34 "HeaderHash.gperf"
{"route", Headers::Route},
#line 24 "HeaderHash.gperf"
{"x", Headers::SessionExpires},
-#line 82 "HeaderHash.gperf"
- {"hide", Headers::UNKNOWN},
#line 38 "HeaderHash.gperf"
{"accept", Headers::Accept},
+#line 75 "HeaderHash.gperf"
+ {"warning", Headers::Warning},
#line 19 "HeaderHash.gperf"
{"k", Headers::Supported},
#line 37 "HeaderHash.gperf"
@@ -232,14 +232,14 @@
{"m", Headers::Contact},
#line 47 "HeaderHash.gperf"
{"content-id", Headers::ContentId},
-#line 43 "HeaderHash.gperf"
- {"allow", Headers::Allow},
#line 95 "HeaderHash.gperf"
{"rack", Headers::RAck},
#line 96 "HeaderHash.gperf"
{"reason", Headers::Reason},
#line 58 "HeaderHash.gperf"
{"priority", Headers::Priority},
+#line 43 "HeaderHash.gperf"
+ {"allow", Headers::Allow},
#line 83 "HeaderHash.gperf"
{"identity", Headers::Identity},
#line 39 "HeaderHash.gperf"
@@ -254,6 +254,10 @@
{"supported", Headers::Supported},
#line 80 "HeaderHash.gperf"
{"encryption", Headers::UNKNOWN},
+#line 57 "HeaderHash.gperf"
+ {"organization", Headers::Organization},
+#line 78 "HeaderHash.gperf"
+ {"authorization", Headers::Authorization},
#line 106 "HeaderHash.gperf"
{"rseq", Headers::RSeq},
#line 94 "HeaderHash.gperf"
@@ -270,8 +274,6 @@
{"refer-to",Headers::ReferTo},
#line 32 "HeaderHash.gperf"
{"from", Headers::From},
-#line 76 "HeaderHash.gperf"
- {"www-authenticate",Headers::WWWAuthenticate},
#line 62 "HeaderHash.gperf"
{"record-route", Headers::RecordRoute},
#line 100 "HeaderHash.gperf"
@@ -280,16 +282,12 @@
{"error-info", Headers::ErrorInfo},
#line 54 "HeaderHash.gperf"
{"in-reply-to", Headers::InReplyTo},
-#line 57 "HeaderHash.gperf"
- {"organization", Headers::Organization},
#line 93 "HeaderHash.gperf"
{"target-dialog", Headers::TargetDialog},
+#line 30 "HeaderHash.gperf"
+ {"content-length", Headers::ContentLength},
#line 64 "HeaderHash.gperf"
{"require", Headers::Require},
-#line 78 "HeaderHash.gperf"
- {"authorization", Headers::Authorization},
-#line 30 "HeaderHash.gperf"
- {"content-length", Headers::ContentLength},
#line 74 "HeaderHash.gperf"
{"user-agent", Headers::UserAgent},
#line 48 "HeaderHash.gperf"
@@ -304,6 +302,8 @@
{"content-language", Headers::ContentLanguage},
#line 45 "HeaderHash.gperf"
{"call-info", Headers::CallInfo},
+#line 76 "HeaderHash.gperf"
+ {"www-authenticate",Headers::WWWAuthenticate},
#line 35 "HeaderHash.gperf"
{"subject", Headers::Subject},
#line 41 "HeaderHash.gperf"
@@ -316,42 +316,46 @@
{"replaces",Headers::Replaces},
#line 112 "HeaderHash.gperf"
{"min-se", Headers::MinSE},
+#line 115 "HeaderHash.gperf"
+ {"history-info", Headers::HistoryInfo},
+#line 44 "HeaderHash.gperf"
+ {"authentication-info", Headers::AuthenticationInfo},
#line 88 "HeaderHash.gperf"
{"p-called-party-id", Headers::PCalledPartyId},
#line 101 "HeaderHash.gperf"
{"p-called-party-id", Headers::PCalledPartyId},
-#line 44 "HeaderHash.gperf"
- {"authentication-info", Headers::AuthenticationInfo},
-#line 71 "HeaderHash.gperf"
- {"answer-mode", Headers::AnswerMode},
#line 31 "HeaderHash.gperf"
{"expires", Headers::Expires},
+#line 60 "HeaderHash.gperf"
+ {"proxy-authorization", Headers::ProxyAuthorization},
#line 114 "HeaderHash.gperf"
{"remote-party-id", Headers::RemotePartyId},
#line 59 "HeaderHash.gperf"
{"proxy-authenticate", Headers::ProxyAuthenticate},
+#line 71 "HeaderHash.gperf"
+ {"answer-mode", Headers::AnswerMode},
#line 87 "HeaderHash.gperf"
{"p-associated-uri", Headers::PAssociatedUri},
#line 102 "HeaderHash.gperf"
{"p-associated-uri", Headers::PAssociatedUri},
+#line 68 "HeaderHash.gperf"
+ {"sip-if-match", Headers::SIPIfMatch},
#line 113 "HeaderHash.gperf"
{"refer-sub", Headers::ReferSub},
#line 98 "HeaderHash.gperf"
{"referred-by",Headers::ReferredBy},
-#line 68 "HeaderHash.gperf"
- {"sip-if-match", Headers::SIPIfMatch},
#line 61 "HeaderHash.gperf"
{"proxy-require", Headers::ProxyRequire},
-#line 60 "HeaderHash.gperf"
- {"proxy-authorization", Headers::ProxyAuthorization},
+#line 46 "HeaderHash.gperf"
+ {"content-disposition", Headers::ContentDisposition},
+#line 89 "HeaderHash.gperf"
+ {"p-media-authorization", Headers::PMediaAuthorization},
+#line 70 "HeaderHash.gperf"
+ {"timestamp", Headers::Timestamp},
#line 79 "HeaderHash.gperf"
{"allow-events", Headers::AllowEvents},
-#line 46 "HeaderHash.gperf"
- {"content-disposition", Headers::ContentDisposition},
#line 33 "HeaderHash.gperf"
{"max-forwards", Headers::MaxForwards},
-#line 70 "HeaderHash.gperf"
- {"timestamp", Headers::Timestamp},
#line 103 "HeaderHash.gperf"
{"service-route", Headers::ServiceRoute},
#line 110 "HeaderHash.gperf"
@@ -360,16 +364,14 @@
{"p-preferred-identity", Headers::PPreferredIdentity},
#line 107 "HeaderHash.gperf"
{"security-client", Headers::SecurityClient},
-#line 89 "HeaderHash.gperf"
- {"p-media-authorization", Headers::PMediaAuthorization},
#line 86 "HeaderHash.gperf"
{"p-asserted-identity", Headers::PAssertedIdentity},
#line 51 "HeaderHash.gperf"
{"content-transfer-encoding", Headers::ContentTransferEncoding},
+#line 105 "HeaderHash.gperf"
+ {"response-key", Headers::UNKNOWN},
#line 72 "HeaderHash.gperf"
{"priv-answer-mode", Headers::PrivAnswerMode},
-#line 105 "HeaderHash.gperf"
- {"response-key", Headers::UNKNOWN},
#line 55 "HeaderHash.gperf"
{"min-expires", Headers::MinExpires},
#line 109 "HeaderHash.gperf"
@@ -388,60 +390,60 @@
static short lookup[] =
{
- -1, 0, -1, -1, -1, -1, 1, 2,
- -1, 3, -1, 4, -1, -1, -1, -1,
+ -1, 0, -1, -1, 1, -1, 2, 3,
+ -1, -1, -1, 4, -1, -1, -1, -1,
5, -1, -1, -1, -1, 6, -1, -1,
-1, -1, 7, -1, -1, -1, -1, 8,
- -1, -1, 9, -1, 10, -1, -1, -147,
- -1, 13, 14, -92, -2, -1, 15, -1,
- -1, -1, -1, 16, 17, -1, -1, -1,
- 18, -1, -1, -1, 19, 20, -1, -1,
- 21, -1, 22, -1, -1, -1, -1, 23,
+ -1, -1, 9, -1, 10, -1, -1, -148,
+ -1, 13, 14, -93, -2, -1, 15, -1,
+ -1, -1, -1, 16, -1, -1, -1, -1,
+ 17, -1, -1, 18, 19, 20, -1, -1,
+ -1, -1, 21, 22, -1, -1, -1, 23,
-1, 24, -1, -1, 25, -1, -1, -1,
-1, -1, -1, -1, -1, 26, -1, -1,
- -1, -1, 27, -1, -1, -1, -1, -1,
- -1, -1, -1, 28, -1, 29, -1, 30,
- -1, -1, -1, -1, 31, 32, 33, -1,
- 34, 35, 36, 37, -1, -1, -1, 38,
- -1, -1, 39, 40, 41, -1, 42, 43,
- 44, 45, -1, 46, -1, -1, -1, -1,
- -1, 47, -1, 48, 49, 50, 51, 52,
- -1, -1, -1, 53, 54, 55, 56, 57,
- -1, -1, -1, 58, 59, -1, -1, -1,
- 60, -1, -1, -1, -1, -1, 61, -1,
- -1, 62, -1, -1, 63, -1, -1, 64,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, 27, -1, 28, -1, 29,
+ -1, 30, -1, -1, 31, 32, 33, -1,
+ 34, 35, 36, 37, -1, 38, 39, 40,
+ -1, -1, 41, 42, 43, -1, 44, 45,
+ 46, 47, -1, -1, -1, -1, -1, -1,
+ -1, 48, -1, 49, 50, 51, -1, 52,
+ 53, -1, -1, 54, -1, -1, 55, 56,
+ -1, -1, -1, 57, 58, -1, -1, -1,
+ 59, -1, -1, -1, -1, -1, 60, -1,
+ -1, 61, -1, 62, 63, -1, -1, 64,
-1, -1, 65, -1, -1, 66, -1, 67,
- -1, -1, 68, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -304, -1, 71,
- -34, -2, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, 72, 73, -1, -1, -1,
- -1, -1, -1, -1, 74, -1, -1, -1,
- -1, -1, -1, -1, 75, -1, -1, -1,
- -1, -1, -1, -1, -341, -27, -2, 78,
- -1, 79, 80, -1, -1, -1, -1, -1,
- 81, 82, -1, -1, 83, -1, 84, -1,
- -1, 85, -1, -1, -1, -1, -1, -1,
- 86, -1, -1, -1, -1, -1, -1, -1,
- -1, -380, -1, 89, -16, -2, -1, -1,
- -1, -1, -1, -1, -1, 90, 91, -1,
- -1, 92, -1, -1, -1, -1, -1, 93,
- 94, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, 95, -1, -1, -1, -1,
- -1, -1, -1, -1, 96, -1, -1, -1,
+ -1, -1, 68, 69, -1, -1, -1, -1,
+ -1, -1, 70, -1, -1, -303, -33, -2,
-1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, 73, -1, -1, -1,
+ -1, -1, -1, 74, 75, -1, -1, 76,
+ -1, -1, 77, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -347, 80, -1, 81,
+ -1, 82, -26, -2, -1, -1, -1, -1,
+ 83, -1, -1, -1, -1, -1, 84, -1,
+ 85, -1, -1, -1, -1, -1, -1, -1,
+ 86, -1, -1, 87, -1, -1, -1, -1,
+ 88, -381, -1, 91, -15, -2, -1, -1,
+ -1, -1, -1, -1, -1, 92, -1, -1,
+ -1, 93, -1, -1, -1, -1, -1, 94,
-1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, 97, -1, -1, 98,
- -1, -1, -1, -1, -1, -1, 99, -1,
- -1, -1, -1, -1, -1, -1, -1, 100,
+ -1, -1, -1, 95, -1, -1, -1, 96,
+ -1, -1, -1, -1, 97, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, 101, -1,
+ -1, -1, -1, -1, 98, -1, -1, 99,
+ -1, -1, -1, -1, -1, -1, 100, -1,
+ -1, -1, -1, -1, -1, -1, -1, 101,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 102, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, 102
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 103
};
if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
@@ -478,6 +480,6 @@
}
return 0;
}
-#line 115 "HeaderHash.gperf"
+#line 116 "HeaderHash.gperf"
}
Index: resip/stack/Headers.cxx
===================================================================
--- resip/stack/Headers.cxx (revisjon 8218)
+++ resip/stack/Headers.cxx (arbeidskopi)
@@ -213,6 +213,7 @@
defineMultiHeader(PAssociatedUri, "P-Associated-URI", NameAddr, "RFC 3455");
defineMultiHeader(ServiceRoute, "Service-Route", NameAddr, "RFC 3608");
defineHeader(RemotePartyId, "Remote-Party-ID", NameAddr, "draft-ietf-sip-privacy-04"); // ?bwc? Not in 3323, should we keep?
+defineMultiHeader(HistoryInfo, "History-Info", NameAddr, "RFC 4244");
//====================
// String:
Index: resip/stack/SipMessage.cxx
===================================================================
--- resip/stack/SipMessage.cxx (revisjon 8218)
+++ resip/stack/SipMessage.cxx (arbeidskopi)
@@ -1466,6 +1466,7 @@
defineMultiHeader(Via, "Via", Via, "RFC 3261");
defineHeader(RAck, "RAck", RAckCategory, "RFC 3262");
defineHeader(RemotePartyId, "Remote-Party-ID", NameAddr, "draft-ietf-sip-privacy-04"); // ?bwc? Not in 3323, should we keep?
+defineMultiHeader(HistoryInfo, "History-Info", NameAddr, "RFC 4244");
#endif
Index: resip/stack/HeaderHash.gperf
===================================================================
--- resip/stack/HeaderHash.gperf (revisjon 8218)
+++ resip/stack/HeaderHash.gperf (arbeidskopi)
@@ -112,5 +112,6 @@
min-se, Headers::MinSE
refer-sub, Headers::ReferSub
remote-party-id, Headers::RemotePartyId
+history-info, Headers::HistoryInfo
%%
}