📄 url.c
字号:
break; default: rv = strcmp(a->url_user, b->url_user); break; } if (rv) 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;}staticint url_tel_cmp_numbers(char const *A, char const *B){ short a, b; int rv; while (*A && *B) { #define UNHEX(a) (a - (a >= 'a' ? 'a' - 10 : (a >= 'A' ? 'A' - 10 : '0'))) /* Skip visual-separators */ do { a = *A++; if (a == '%' && IS_HEX(A[0]) && IS_HEX(A[1])) a = (UNHEX(A[0]) << 4) | UNHEX(A[1]), A +=2; } while (a == ' ' || a == '-' || a == '.' || a == '(' || a == ')'); if (isupper(a)) a = tolower(a); do { b = *B++; if (b == '%' && IS_HEX(B[0]) && IS_HEX(B[1])) b = (UNHEX(B[0]) << 4) | UNHEX(B[1]), B +=2; } while (b == ' ' || b == '-' || b == '.' || b == '(' || b == ')'); if (isupper(b)) b = tolower(b); if ((rv = a - b)) return rv; } return (int)*A - (int)*B;}/**Conservative comparison of urls. * * Compare all parts of URLs. * * @note * The @a a and @a b must be pointers to URL structures. * */int url_cmp_all(url_t const *a, url_t const *b){ int rv, url_type; if (!a || !b) return (a != NULL) - (b != NULL); if ((rv = a->url_type - b->url_type)) return rv; url_type = a->url_type; /* Or b->url_type, they are equal! */ if (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 ((rv = a->url_root - b->url_root)) return rv; if ((rv = host_cmp(a->url_host, b->url_host))) return rv; if (a->url_port != b->url_port) { char const *a_port; char const *b_port; if (url_type != url_sip && url_type != url_sips) a_port = b_port = url_port_default(url_type); else if (host_is_ip_address(a->url_host)) a_port = b_port = url_port_default(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; switch (url_type) { case url_tel: case url_modem: case url_fax: rv = url_tel_cmp_numbers(a->url_user, b->url_user); break; default: rv = strcmp(a->url_user, b->url_user); break; } if (rv) return rv; } 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; } if (a->url_params != b->url_params) { if (a->url_params == NULL) return -1; if (b->url_params == NULL) return +1; if ((rv = strcmp(a->url_params, b->url_params))) return rv; } if (a->url_headers != b->url_headers) { if (a->url_headers == NULL) return -1; if (b->url_headers == NULL) return +1; if ((rv = strcmp(a->url_headers, b->url_headers))) return rv; } if (a->url_headers != b->url_headers) { if (a->url_headers == NULL) return -1; if (b->url_headers == NULL) return +1; if ((rv = strcmp(a->url_headers, b->url_headers))) return rv; } if (a->url_fragment != b->url_fragment) { if (a->url_fragment == NULL) return -1; if (b->url_fragment == NULL) return +1; if ((rv = strcmp(a->url_fragment, b->url_fragment))) return rv; } 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: case url_msrps: 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_msrps: return "tls"; 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 && u->url_port[0]) return u->url_port; if (u->url_type == url_sips || u->url_type == url_sip) if (!host_is_ip_address(u->url_host)) return ""; 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, size_t n, char const *allow){ size_t i, j; for (i = 0, j = 0; i < n && s[i]; i++) { char c; if (s[i] == '%' && i + 2 < n && IS_HEX(s[i+1]) && IS_HEX(s[i+2])) {#define UNHEX(a) (a - (a >= 'a' ? 'a' - 10 : (a >= 'A' ? 'A' - 10 : '0'))) c = (UNHEX(s[i+1]) << 4) | UNHEX(s[i+2]);#undef UNHEX if (c != '%' && c > ' ' && c < '\177' && (!strchr(EXCLUDED, c) || strchr(allow, c))) { if (i != j) su_md5_iupdate(md5, s + j, i - j); su_md5_iupdate(md5, &c, 1); j = i + 3; } i += 2; } } if (i != j) su_md5_iupdate(md5, s + j, i - j);}/** Update MD5 sum with url-string contents */staticvoid url_string_update(su_md5_t *md5, char const *s){ size_t n, p; int have_authority = 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, 0, "+"); type = url_get_type(schema, at - schema); su_md5_iupdate(md5, schema, at - schema); have_authority = !url_type_is_opaque(type); s += n + 1; } else { su_md5_update(md5, "", 1); } if (type == url_sip || type == url_sips) { /* SIP URL may have /;? in user part but no path */ /* user-unreserved = "&" / "=" / "+" / "$" / "," / ";" / "?" / "/" */ /* Some #*@#* phones include unescaped # there, too */ n = strcspn(s, "@/;?#"); p = strcspn(s + n, "@"); if (s[n + p] == '@') { n += p; /* Ignore password in hash */ colon = memchr(s, ':', n); p = colon ? (size_t)(colon - s) : n; canon_update(md5, s, p, SIP_USER_UNRESERVED); s += n + 1; n = 0; } else su_md5_iupdate(md5, "", 1); /* user */ n += strcspn(s + n, "/;?#"); } else if (have_authority) { if (type == url_wv) { /* WV URL may have / in user part */ n = strcspn(s, "@;?#"); } else if (type != url_wv && s[0] == '/' && s[1] != '/') { /* foo:/bar */ su_md5_update(md5, "\0\0", 2); /* user, host */ su_md5_striupdate(md5, url_port_default(type)); return; } else if (s[0] == '/' && s[1] == '/') { /* We have authority, / / foo or foo */ s += 2; n = strcspn(s, "/?#@[]"); } else n = strcspn(s, "@;/?#"); if (s[n] == '@') { /* Ignore password in hash */ colon = type != url_unknown ? memchr(s, ':', n) : NULL; p = colon ? (size_t)(colon - s) : n; canon_update(md5, s, p, SIP_USER_UNRESERVED); s += n + 1; n = strcspn(s, "/;?#"); /* Until path, query or fragment */ } else { su_md5_iupdate(md5, "", 1); /* user */ n += strcspn(s + n, "/;?#"); /* Until path, query or fragment */ } } else /* if (!have_authority) */ { n = strcspn(s, ":/;?#"); /* Until pass, path, query or fragment */ canon_update(md5, s, n, ""); /* user */ su_md5_update(md5, "\0", 1); /* host, no port */ su_md5_striupdate(md5, url_port_default(type)); return; } if (n > 0 && s[0] == '[') { /* IPv6reference */ colon = memchr(s, ']', n); if (colon == NULL || ++colon == s + n || *colon != ':') colon = NULL; } else colon = memchr(s, ':', n); 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);}/** Convert a URL query to a header string. * * URL query is converted by replacing each "=" in header name "=" value * pair with semicolon (":"), and the "&" separating header-name-value pairs * with line feed ("\n"). The "body" pseudoheader is moved last in the * string. The %-escaping is removed. Note that if the @a query contains %00, * the resulting string will be truncated. * * @param home memory home used to alloate string (if NULL, malloc() it) * @param query query part from SIP URL * * The result string is allocated from @a home, and it can be used as * argument to msg_header_parse_str(), msg_header_add_str() or * SIPTAG_HEADER_STR(). * * @sa msg_header_add_str(), SIPTAG_HEADER_STR(), * sip_headers_as_url_query(), sip_url_query_as_taglist(), * @RFC3261 section 19.1.1 "Headers", #url_t, url_s#url_headers, * url_unescape(), url_unescape_to() * * @since New in @VERSION_1_12_4. */char *url_query_as_header_string(su_home_t *home, char const *query){ size_t i, j, n, b_start = 0, b_len = 0; char *s = su_strdup(home, query); if (!s) return NULL; for (i = 0, j = 0; s[i];) { n = strcspn(s + i, "="); if (!s[i + n]) break; if (n == 4 && strncasecmp(s + i, "body", 4) == 0) { if (b_start) break; b_start = i + n + 1, b_len = strcspn(s + b_start, "&"); i = b_start + b_len + 1; continue; } if (i != j) memmove(s + j, s + i, n); s[j + n] = ':'; i += n + 1, j += n + 1; n = strcspn(s + i, "&"); j += url_unescape_to(s + j, s + i, n); i += n; if (s[i]) { s[j++] = '\n', i++; } } if (s[i]) return (void)su_free(home, s), NULL; if (b_start) { s[j++] = '\n', s[j++] = '\n'; j += url_unescape_to(s + j, query + b_start, b_len); } s[j] = '\0'; assert(j <= i); return s;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -