📄 url.c
字号:
/** Test if param @a tag matches to parameter string @a p. */#define URL_PARAM_MATCH(p, tag) \ (strncasecmp(p, tag, strlen(tag)) == 0 && \ (p[strlen(tag)] == '\0' || p[strlen(tag)] == ';' || p[strlen(tag)] == '='))/** * Search for a parameter. * * This function searches for a parameter from a parameter list. * * If you want to test if there is parameter @b user=phone, * call this function like * @code if (url_param(url->url_param, "user=phone", NULL, 0)) * @endcode * * @param params URL parameter string (excluding first semicolon) * @param tag parameter name * @param value string to which the parameter value is copied * @param vlen length of string reserved for value * * @retval positive length of parameter value (including final NUL) if found * @retval zero if not found. */int url_param(char const *params, char const *tag, char value[], int vlen){ size_t n, tlen = strlen(tag), flen; char *p; if (!params) return 0; for (p = (char *)params; *p; p += n + 1) { n = strcspn(p, ";"); if (n < tlen) { if (p[n]) continue; else break; } if (strncasecmp(p, tag, tlen) == 0) { if (n == tlen) { if (vlen > 0) value[0] = '\0'; return 1; } if (p[tlen] != '=') continue; flen = n - tlen - 1; if (flen >= (size_t)vlen) return flen + 1; memcpy(value, p + tlen + 1, flen); value[flen] = '\0'; return flen + 1; } if (!p[n]) break; } return 0;}/** Check for a parameter. * * @deprecated * Bad grammar. Use url_has_param(). */int url_have_param(char const *params, char const *tag){ return url_param(params, tag, NULL, 0);}/** Check for a parameter. */int url_has_param(url_t const *url, char const *tag){ return url && url->url_params && url_param(url->url_params, tag, NULL, 0);}/** Add an parameter. */int url_param_add(su_home_t *h, url_t *url, char const *param){ /* XXX - should remove existing parameters? */ int n = url->url_params ? strlen(url->url_params) + 1: 0; int nn = strlen(param) + 1; char *s = su_alloc(h, n + nn); if (!s) return -1; if (url->url_params) strcpy(s, url->url_params)[n - 1] = ';'; strcpy(s + n, param); url->url_params = s; return 0;}int url_string_p(url_string_t const *url){ return URL_STRING_P(url);}int url_is_string(url_string_t const *url){ return URL_IS_STRING(url);}/** Strip transport-specific stuff. */staticint url_strip_transport2(url_t *url, int modify){ char *p, *d; size_t n; int semi; if (url->url_type != url_sip && url->url_type != url_sips) return 0; if (url->url_port != NULL) { if (!modify) return 1; url->url_port = NULL; } if (!url->url_params) return 0; for (d = p = (char *)url->url_params; *p; p += n + semi) { n = strcspn(p, ";"); semi = (p[n] != '\0'); if (modify && n == 0) continue; if (URL_PARAM_MATCH(p, "method")) continue; if (URL_PARAM_MATCH(p, "maddr")) continue; if (URL_PARAM_MATCH(p, "ttl")) continue; if (URL_PARAM_MATCH(p, "transport")) continue; if (p != d) { if (d != url->url_params) d++; if (p != d) { if (!modify) return 1; memcpy(d, p, n + 1); } } d += n; } if (d == p) return 0; else if (d + 1 == p) /* empty param */ return 0; else if (!modify) return 1; if (d != url->url_params) *d = '\0'; else url->url_params = NULL; return 1;}/** Strip transport-specific stuff. * * The function url_strip_transport() removes transport-specific parameters * from a SIP or SIPS URI. These parameters include: * - the port number * - "maddr=" parameter * - "transport=" parameter * - "ttl=" parameter * - "method=" parameter * * @note * The @a url must be a pointer to a URL structure. * * @note * If the parameter string contains empty parameters, they are stripped, too. * * @return * The function url_strip_transport() returns @e true, if the URL was * modified, @e false otherwise. */int url_strip_transport(url_t *url){ return url_strip_transport2(url, 1);}/** Check for transport-specific stuff. * * The function url_have_transport() tests if there are transport-specific * parameters in a SIP or SIPS URI. These parameters include: * - the port number * - "maddr=" parameters * - "transport=" parameters * * @note * The @a url must be a pointer to a URL structure. * * @return The function url_have_transport() returns @e true, if the URL * contains transport parameters, @e false otherwise. */int url_have_transport(url_t const *url){ return url_strip_transport2((url_t *)url, 0);}/** Compare two URLs. * * @note * The @a a and @a b must be pointers to URL structures. * * @note Currently, the url parameters are not compared. This is because the * url_cmp() is used to sort URLs: taking parameters into account makes that * impossible. */int url_cmp(url_t const *a, url_t const *b){ int rv; if ((a && a->url_type == url_any) || (b && b->url_type == url_any)) return 0; if (!a || !b) return (a != NULL) - (b != NULL); if ((rv = a->url_type - b->url_type)) { /* presence and instant messaging URLs match magically with SIP */ enum url_type_e a_type = a->url_type; enum url_type_e b_type = b->url_type; if (a_type == url_im || a_type == url_pres) a_type = url_sip; if (b_type == url_im || b_type == url_pres) b_type = url_sip; if (a_type != b_type) return rv; } if (a->url_type <= url_unknown && ((rv = !a->url_scheme - !b->url_scheme) || (a->url_scheme && b->url_scheme && (rv = strcasecmp(a->url_scheme, b->url_scheme))))) return rv; if (a->url_host != b->url_host && ((rv = !a->url_host - !b->url_host) || (rv = strcasecmp(a->url_host, b->url_host)))) return rv; if (a->url_port != b->url_port) { char const *a_port; char const *b_port; if (a->url_type != url_sip && a->url_type != url_sips) a_port = b_port = url_port_default(a->url_type); else if (host_is_ip_address(a->url_host)) a_port = b_port = url_port_default(a->url_type); else a_port = b_port = ""; if (a->url_port) a_port = a->url_port; if (b->url_port) b_port = b->url_port; if ((rv = strcmp(a_port, b_port))) return rv; } if (a->url_user != b->url_user) { if (a->url_user == NULL) return -1; if (b->url_user == NULL) return +1; if ((rv = strcmp(a->url_user, b->url_user))) return rv; }#if 0 if (a->url_path != b->url_path) { if (a->url_path == NULL) return -1; if (b->url_path == NULL) return +1; if ((rv = strcmp(a->url_path, b->url_path))) return rv; }#endif return 0;}/** Return default port number corresponding to the url type */char const *url_port_default(enum url_type_e url_type){ switch (url_type) { case url_sip: /* "sip:" */ return "5060"; case url_sips: /* "sips:" */ return "5061"; case url_http: /* "http:" */ return "80"; case url_https: /* "https:" */ return "443"; case url_ftp: /* "ftp:" */ case url_file: /* "file:" */ return "21"; case url_rtsp: /* "rtsp:" */ case url_rtspu: /* "rtspu:" */ return "554"; case url_mailto: /* "mailto:" */ return "25"; case url_any: /* "*" */ return "*"; case url_msrp: return "9999"; /* XXXX */ case url_tel: case url_fax: case url_modem: case url_im: case url_pres: case url_cid: case url_wv: default: /* Unknown scheme */ return ""; }}/** Return default transport name corresponding to the url type */char const *url_tport_default(enum url_type_e url_type){ switch (url_type) { case url_sip: return "*"; case url_sips: return "tls"; case url_http: return "tcp"; case url_https: return "tls"; case url_ftp: case url_file: return "tcp"; case url_rtsp: return "tcp"; case url_rtspu: return "udp"; case url_mailto: return "tcp"; case url_msrp: return "tcp"; case url_any: /* "*" */ case url_tel: case url_fax: case url_modem: case url_im: case url_pres: case url_cid: case url_wv: default: /* Unknown scheme */ return "*"; }}/** Return the URL port string */char const *url_port(url_t const *u){ if (!u) return ""; else if (u->url_port) return u->url_port; else return url_port_default(u->url_type);}/** Sanitize URL. * * The function url_sanitize() adds a scheme to an incomplete URL. It * modifies its parameter structure @a url. Currently, the function follows * simple heuristics: * * - URL with host name starting with @c ftp. is an FTP URL * - URL with host name starting with @c www. is an HTTP URL * - URL with host and path, e.g., @c host/foo;bar, is an HTTP URL * - URL with host name, no path is a SIP URL. * * @param url pointer to URL struct to be sanitized (IN/OUT) * * @return * The function url_sanitize() returns 0 if it considers URL to be * sane, and -1 otherwise. */int url_sanitize(url_t *url){ if (!url) return -1; else if (url->url_scheme != NULL) /* xyzzy */; else if (url->url_host == NULL) return -1; else if (strncasecmp(url->url_host, "ftp.", strlen("ftp.")) == 0) url->url_type = url_ftp, url->url_scheme = "ftp", url->url_root = '/'; else if (strncasecmp(url->url_host, "www.", strlen("www.")) == 0 || url->url_path) url->url_type = url_http, url->url_scheme = "http", url->url_root = '/'; else url->url_type = url_sip, url->url_scheme = "sip"; return 0;}#include <sofia-sip/su_md5.h>staticvoid canon_update(su_md5_t *md5, char const *s, int n, char const *allow){ char const *s0 = s, *b = s; for (;*s && s - s0 < n; s++) { char c; if (*s == '%' && IS_HEX(s[1]) && IS_HEX(s[2]) && s - s0 + 2 < n) {#define UNHEX(a) (a - (a >= 'a' ? 'a' - 10 : (a >= 'A' ? 'A' - 10 : '0'))) c = (UNHEX(s[1]) << 4) | UNHEX(s[2]);#undef UNHEX if (c != '%' && c > ' ' && c < '\177' && (!strchr(EXCLUDED, c) || strchr(allow, c))) { if (b != s) su_md5_iupdate(md5, b, s - b); su_md5_iupdate(md5, &c, 1); b = s + 3; } s += 2; } } if (b != s) su_md5_iupdate(md5, b, s - b);}/** Update MD5 sum with url-string contents */staticvoid url_string_update(su_md5_t *md5, char const *s){ int n; int hostpart = 1; enum url_type_e type = url_any; char const *at, *colon; char schema[48]; if (s == NULL || strlen(s) == 0 || strcmp(s, "*") == 0) { su_md5_update(md5, "*\0\0*", 4); return; } n = strcspn(s, ":/?#"); if (n >= sizeof schema) { su_md5_update(md5, ":", 1); } else if (n && s[n] == ':' ) { at = url_canonize(schema, s, n, "+"); type = url_get_type(schema, at - schema); su_md5_iupdate(md5, schema, at - schema); hostpart = !url_type_is_opaque(type); s += n + 1; } else { su_md5_update(md5, "", 1); } if (type == url_sip || type == url_sips) { n = strcspn(s, "@#"); /* Opaque part */ if (s[n] != '@') n = 0; n += strcspn(s + n, "/;?#"); } else if (!hostpart || s[0] != '/') { n = strcspn(s, "/;?#"); /* Opaque part */ } else if (s[1] == '/') { s += 2; n = strcspn(s, "/;?#"); /* Until path, query or fragment */ } else { /* foo:/bar */ su_md5_update(md5, "\0\0", 2); /* user, host */ su_md5_striupdate(md5, url_port_default(type)); return; } if (!hostpart) { char const *colon = memchr(s, ':', n); if (colon) n = colon - s; canon_update(md5, s, n, ""); /* user */ su_md5_update(md5, "\0", 1); /* host, no port */ su_md5_striupdate(md5, url_port_default(type)); return; } at = memchr(s, '@', n); if (at) { char const *allow = (type == url_sip || type == url_sips) ? SIP_USER_UNRESERVED : USER_UNRESERVED; colon = memchr(s, ':', at - s); /* Updated only user part */ if (colon) canon_update(md5, s, colon - s, allow); else canon_update(md5, s, at - s, allow); n = n - (at + 1 - s); s = at + 1; } else su_md5_iupdate(md5, "", 1); /* user */ colon = memchr(s, ':', n); /* XXX - IPv6! */ if (colon) { canon_update(md5, s, colon - s, ""); /* host */ canon_update(md5, colon + 1, (s + n) - (colon + 1), ""); } else { canon_update(md5, s, n, ""); /* host */ su_md5_strupdate(md5, url_port_default(type)); /* port */ } /* ignore parameters/path/headers.... */}/** Update md5 digest with contents of URL. * */void url_update(su_md5_t *md5, url_t const *url){ if (url_string_p((url_string_t *)url)) { url_string_update(md5, (char const *)url); } else { SU_MD5_STRI0UPDATE(md5, url->url_scheme); SU_MD5_STRI0UPDATE(md5, url->url_user); SU_MD5_STRI0UPDATE(md5, url->url_host); su_md5_striupdate(md5, URL_PORT(url)); /* XXX - parameters/path.... */ /* SU_MD5_STRI0UPDATE(md5, url->url_path); */ }}/** Calculate a digest from URL contents. */void url_digest(void *hash, int hsize, url_t const *url, char const *key){ su_md5_t md5[1]; uint8_t digest[SU_MD5_DIGEST_SIZE]; su_md5_init(md5); if (key) su_md5_strupdate(md5, key); url_update(md5, url); su_md5_digest(md5, digest); if (hsize > SU_MD5_DIGEST_SIZE) { memset((char *)hash + SU_MD5_DIGEST_SIZE, 0, hsize - SU_MD5_DIGEST_SIZE); hsize = SU_MD5_DIGEST_SIZE; } memcpy(hash, digest, hsize);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -