diff --git a/include/re_uri.h b/include/re_uri.h index 4b9871beb..1ac03c516 100644 --- a/include/re_uri.h +++ b/include/re_uri.h @@ -43,3 +43,6 @@ int uri_param_escape(struct re_printf *pf, const struct pl *pl); int uri_param_unescape(struct re_printf *pf, const struct pl *pl); int uri_header_escape(struct re_printf *pf, const struct pl *pl); int uri_header_unescape(struct re_printf *pf, const struct pl *pl); +int uri_display_name_escape(struct re_printf *pf, const struct pl *pl); +int uri_escape(struct re_printf *pf, const char *uri); +int uri_escape_pl(struct re_printf *pf, const struct pl *pl); diff --git a/src/sip/ctrans.c b/src/sip/ctrans.c index 10b5f28d0..886280102 100644 --- a/src/sip/ctrans.c +++ b/src/sip/ctrans.c @@ -59,7 +59,8 @@ static bool route_handler(const struct sip_hdr *hdr, const struct sip_msg *msg, void *arg) { (void)msg; - return 0 != mbuf_printf(arg, "Route: %r\r\n", &hdr->val); + return 0 != mbuf_printf(arg, "Route: %H\r\n", uri_escape_pl, + &hdr->val); } diff --git a/src/sip/dialog.c b/src/sip/dialog.c index e605e17c3..ebf009e91 100644 --- a/src/sip/dialog.c +++ b/src/sip/dialog.c @@ -113,16 +113,21 @@ int sip_dialog_alloc(struct sip_dialog **dlgp, } for (i=0; imb, "Route: <%s;lr>\r\n", routev[i]); + err |= mbuf_printf(dlg->mb, "Route: <%H;lr>\r\n", uri_escape, + routev[i]); if (i == 0) rend = dlg->mb->pos - 2; } - err |= mbuf_printf(dlg->mb, "To: <%s>\r\n", to_uri); + err |= mbuf_printf(dlg->mb, "To: <%H>\r\n", uri_escape, to_uri); dlg->cpos = dlg->mb->pos; - err |= mbuf_printf(dlg->mb, "From: %s%s%s<%s>;tag=%016llx\r\n", - from_name ? "\"" : "", from_name, - from_name ? "\" " : "", - from_uri, ltag); + err |= mbuf_printf(dlg->mb, "From: "); + if (from_name) { + pl_set_str(&pl, from_name); + err |= mbuf_printf(dlg->mb, "\"%H\" ", uri_display_name_escape, + &pl); + } + err |= mbuf_printf(dlg->mb, "<%H>", uri_escape, from_uri); + err |= mbuf_printf(dlg->mb, ";tag=%016llx\r\n", ltag); if (err) goto out; @@ -156,7 +161,7 @@ static bool record_route_handler(const struct sip_hdr *hdr, struct route_enc *renc = arg; (void)msg; - if (mbuf_printf(renc->mb, "Route: %r\r\n", &hdr->val)) + if (mbuf_printf(renc->mb, "Route: %H\r\n", uri_escape_pl, &hdr->val)) return true; if (!renc->end) diff --git a/src/sip/request.c b/src/sip/request.c index 3e16721c4..02bacf683 100644 --- a/src/sip/request.c +++ b/src/sip/request.c @@ -189,7 +189,8 @@ static int request(struct sip_request *req, enum sip_transp tp, goto out; mbuf_set_pos(mbs, 0); - err = mbuf_printf(mb, "%s %s SIP/2.0\r\n", req->met, req->uri); + err = mbuf_printf(mb, "%s ", req->met); + err |= mbuf_printf(mb, "%H SIP/2.0\r\n", uri_escape, req->uri); err |= mbuf_printf(mb, "Via: SIP/2.0/%s %J;branch=%s;rport\r\n", sip_transp_name(tp), &laddr, branch); err |= mbuf_write_mem(mb, mbuf_buf(mbs), mbuf_get_left(mbs)); diff --git a/src/uri/uri.c b/src/uri/uri.c index 11d623728..3812de85e 100644 --- a/src/uri/uri.c +++ b/src/uri/uri.c @@ -49,11 +49,9 @@ int uri_encode(struct re_printf *pf, const struct uri *uri) /* The IPv6 address is delimited by '[' and ']' */ switch (uri->af) { -#ifdef HAVE_INET6 case AF_INET6: err = re_hprintf(pf, "[%r]", &uri->host); break; -#endif default: err = re_hprintf(pf, "%r", &uri->host); @@ -271,3 +269,82 @@ int uri_headers_apply(const struct pl *pl, uri_apply_h *ah, void *arg) return err; } + + +/** + * Escape SIP URI + * + * @param pf Print function to encode into + * @param uri URI + * + * @return 0 if success, otherwise errorcode + */ +int uri_escape(struct re_printf *pf, const char *uri) +{ + struct pl pl; + pl_set_str(&pl, uri); + return uri_escape_pl(pf, &pl); +} + + +/** + * Escape SIP URI + * + * @param pf Print function to encode into + * @param pl URI + * + * @return 0 if success, otherwise errorcode + */ +int uri_escape_pl(struct re_printf *pf, const struct pl *pl) +{ + int err; + struct uri uri; + + if (!pl) + return 0; + + err = uri_decode(&uri, pl); + if (err) + return err; + + if (!pl_isset(&uri.scheme) || !pl_isset(&uri.host)) + return EINVAL; + + err = re_hprintf(pf, "%r:", &uri.scheme); + if (err) + return err; + + if (pl_isset(&uri.user)) { + err = re_hprintf(pf, "%H", uri_user_escape, &uri.user); + + if (pl_isset(&uri.password)) + err |= re_hprintf(pf, ":%H", uri_password_escape, + &uri.password); + + err |= pf->vph("@", 1, pf->arg); + if (err) + return err; + } + + /* The IPv6 address is delimited by '[' and ']' */ + switch (uri.af) { + + case AF_INET6: + err = re_hprintf(pf, "[%r]", &uri.host); + break; + + default: + err = re_hprintf(pf, "%r", &uri.host); + break; + } + if (err) + return err; + + if (uri.port) + err = re_hprintf(pf, ":%u", uri.port); + + err |= re_hprintf(pf, "%r%r%r", &uri.path, &uri.params, + &uri.headers); + + return err; +} diff --git a/src/uri/uric.c b/src/uri/uric.c index 1d97dfe70..f59e0849a 100644 --- a/src/uri/uric.c +++ b/src/uri/uric.c @@ -40,7 +40,7 @@ static bool is_mark(int c) static bool is_unreserved(char c) { - return isalnum(c) || is_mark(c); + return isalnum((unsigned char)c) || is_mark(c); } @@ -120,6 +120,33 @@ static bool is_param_unreserved(char c) } +static bool is_token_non_alphanum(int c) +{ + switch (c) { + + case '-': + case '.': + case '!': + case '%': + case '*': + case '_': + case '+': + case '`': + case '\'': + case '~': + return true; + default: + return false; + } +} + + +static bool is_token(char c) +{ + return isalnum((unsigned char)c) || is_token_non_alphanum(c); +} + + static bool is_paramchar(char c) { return is_param_unreserved(c) || is_unreserved(c); @@ -147,7 +174,7 @@ static int comp_escape(struct re_printf *pf, const struct pl *pl, esc_h *eh) err = pf->vph(&c, 1, pf->arg); } else { - err = re_hprintf(pf, "%%%02X", c); + err = re_hprintf(pf, "%%%W", &c, 1); } } @@ -304,3 +331,17 @@ int uri_header_unescape(struct re_printf *pf, const struct pl *pl) { return comp_unescape(pf, pl, is_hvalue); } + + +/** + * Escape display name + * + * @param pf Print function + * @param pl String to escape + * + * @return 0 if success, otherwise errorcode + */ +int uri_display_name_escape(struct re_printf *pf, const struct pl *pl) +{ + return comp_escape(pf, pl, is_token); +} diff --git a/test/uri.c b/test/uri.c index 83c4785c4..fb2a8062f 100644 --- a/test/uri.c +++ b/test/uri.c @@ -178,7 +178,8 @@ int test_uri_user(void) } uriv[] = { {"alice%40atlanta.com", "alice@atlanta.com"}, {"project%20x", "project x"}, - {"*21%23", "*21#"} + {"*21%23", "*21#"}, + {"*21%23%C3%A4%E2%82%AC%40%20", "*21#รค\xE2\x82\xAC@ "} }; struct mbuf mbe, mbd; int err = EINVAL;