📄 url.c
字号:
case 't': case 'T': test_scheme(tel); break; case 'w': case 'W': test_scheme(wv); break; default: break; }#undef test_scheme if (len != span_unreserved(scheme)) return url_invalid; else return url_unknown;}/** * Decode a URL. * * This function decodes a (SIP) URL string to a url_t structure. * * @param url structure to store the parsing result * @param s NUL-terminated string to be parsed * * @note The parsed string @a s will be modified when parsing it. * * @retval 0 if successful, * @retval -1 otherwise. */staticint _url_d(url_t *url, char *s){ size_t n, p; char *s0, rest_c, *host, *user; int have_authority = 1; memset(url, 0, sizeof(*url)); if (strcmp(s, "*") == 0) { url->url_type = url_any; url->url_scheme = "*"; return 0; } s0 = s; n = strcspn(s, ":/?#"); if (n && s[n] == ':') { char *scheme; url->url_scheme = scheme = s; s[n] = '\0'; s = s + n + 1; if (!(scheme = url_canonize(scheme, scheme, SIZE_MAX, 0, "+"))) return -1; n = scheme - url->url_scheme; url->url_type = url_get_type(url->url_scheme, n); have_authority = !url_type_is_opaque(url->url_type); } else { url->url_type = url_unknown; } user = NULL, host = s; if (url->url_type == url_sip || url->url_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; user = s; host = s + n + 1; } n += strcspn(s + n, "/;?#"); } else if (have_authority) { if (url->url_type == url_wv) { /* WV URL may have / in user part */ n = strcspn(s, "@#?;"); if (s[n] == '@') { user = s; host = s + n + 1; n += strcspn(s + n, ";?#"); } } else if (host[0] == '/' && host[1] != '/') { /* foo:/bar or /bar - no authority, just path */ url->url_root = '/'; /* Absolute path */ host = NULL, n = 0; } else { if (host[0] == '/' && host[1] == '/') { /* We have authority, / / foo or foo */ host += 2; s += 2, url->url_root = '/'; n = strcspn(s, "/?#@[]"); } else n = strcspn(s, "@;/?#"); if (s[n] == '@') user = host, host = user + n + 1; n += strcspn(s + n, ";/?#"); /* Find path, query and/or fragment */ } } else /* !have_authority */ { user = host, host = NULL; if (url->url_type != url_invalid) n = strcspn(s, "/;?#"); /* Find params, query and/or fragment */ else n = strcspn(s, "#"); } rest_c = s[n]; s[n] = 0; s = rest_c ? s + n + 1 : NULL; if (user) { if (host) host[-1] = '\0'; url->url_user = user; if (url->url_type != url_unknown) { n = strcspn(user, ":"); if (user[n]) { user[n] = '\0'; url->url_password = user + n + 1; } } } if (host) { url->url_host = host; /* IPv6 (and in some cases, IPv4) addresses are quoted with [] */ if (host[0] == '[') { n = strcspn(host, "]"); if (host[n] && (host[n + 1] == '\0' || host[n + 1] == ':')) n++; else n = 0; } else { n = strcspn(host, ":"); } /* We allow empty host by default */ if (n == 0) switch (url->url_type) { case url_sip: case url_sips: case url_im: case url_pres: return -1; default: break; } if (host[n] == ':') { char *port = host + n + 1; url->url_port = port; switch (url->url_type) { case url_any: case url_sip: case url_sips: case url_http: case url_https: case url_ftp: case url_file: case url_rtsp: case url_rtspu: if (!url_canonize2(port, port, SIZE_MAX, 0, RESERVED_MASK)) return -1; /* Check that port is really numeric or wildcard */ /* Port can be *digit, empty string or "*" */ while (*port >= '0' && *port <= '9') port++; if (port != url->url_port ? port[0] != '\0' : (port[0] != '*' || port[1] != '\0')) return -1; } host[n] = 0; } } if (rest_c == '/') { url->url_path = s; n = strcspn(s, "?#"); rest_c = s[n]; s[n] = 0; s = rest_c ? s + n + 1 : NULL; } if (rest_c == ';') { url->url_params = s; n = strcspn(s, "?#"); rest_c = s[n]; s[n] = 0; s = rest_c ? s + n + 1 : NULL; } if (rest_c == '?') { url->url_headers = s; n = strcspn(s, "#"); rest_c = s[n]; s[n] = 0; s = rest_c ? s + n + 1 : NULL; } if (rest_c == '#') { url->url_fragment = s; rest_c = '\0'; } if (rest_c) return -1; return 0;}/* Unreserved things *//** * Decode a URL. * * This function decodes a URL string to a url_t structure. * * @param url structure to store the parsing result * @param s NUL-terminated string to be parsed * * @note The parsed string @a s will be modified when parsing it. * * @retval 0 if successful, * @retval -1 otherwise. */int url_d(url_t *url, char *s){ if (url == NULL || _url_d(url, s) < 0) return -1; /* Canonize URL */ /* scheme is canonized by _url_d() */ if (url->url_type == url_sip || url->url_type == url_sips) {# define SIP_USER_UNRESERVED "&=+$,;?/" s = (char *)url->url_user; if (s && !url_canonize(s, s, SIZE_MAX, 0, SIP_USER_UNRESERVED)) return -1; /* Having different charset in user and password does not make sense */ /* but that is how it is defined in RFC 3261 */# define SIP_PASS_UNRESERVED "&=+$," s = (char *)url->url_password; if (s && !url_canonize(s, s, SIZE_MAX, 0, SIP_PASS_UNRESERVED)) return -1; } else {# define USER_UNRESERVED "&=+$,;" s = (char *)url->url_user; if (s && !url_canonize(s, s, SIZE_MAX, 0, USER_UNRESERVED)) return -1;# define PASS_UNRESERVED "&=+$,;:" s = (char *)url->url_password; if (s && !url_canonize(s, s, SIZE_MAX, 0, PASS_UNRESERVED)) return -1; } s = (char *)url->url_host; if (s && !url_canonize2(s, s, SIZE_MAX, 0, RESERVED_MASK)) return -1; /* port is canonized by _url_d() */ s = (char *)url->url_path; if (s && !url_canonize(s, s, SIZE_MAX, /* Allow all URI characters but ? */ /* Allow unescaped /;?@, - but do not convert */ SYN33('/') | SYN33(';') | SYN33('=') | SYN33('@') | SYN33(','), /* Convert escaped :&+$ to unescaped */ ":&+$")) return -1; s = (char *)url->url_params; if (s && !url_canonize(s, s, SIZE_MAX, /* Allow all URI characters but ? */ /* Allow unescaped ;=@, - but do not convert */ SYN33(';') | SYN33('=') | SYN33('@') | SYN33(','), /* Convert escaped /:&+$ to unescaped */ "/:&+$")) return -1; /* Unhex alphanumeric and unreserved URI characters */ s = (char *)url->url_headers; if (s && !url_canonize3(s, s, SIZE_MAX, RESERVED_MASK)) return -1; /* Allow all URI characters (including reserved ones) */ s = (char *)url->url_fragment; if (s && !url_canonize2(s, s, SIZE_MAX, 0, URIC_MASK)) return -1; return 0;}/** Encode an URL. * * The function url_e() combines a URL from substrings in url_t structure * according the @ref url_syntax "URL syntax" presented above. The encoded * @a url is stored in a @a buffer of @a n bytes. * * @param buffer memory area to store the encoded @a url. * @param n size of @a buffer. * @param url URL to be encoded. * * @return * Return the number of bytes in the encoding. * * @note The function follows the convention set by C99 snprintf(). Even if * the result does not fit into the @a buffer and it is truncated, the * function returns the number of bytes in an untruncated encoding. */issize_t url_e(char buffer[], isize_t n, url_t const *url){ size_t i; char *b = buffer; size_t m = n; int do_copy = n > 0; if (url == NULL) return -1; if (URL_STRING_P(url)) { char const *u = (char *)url; i = strlen(u); if (!buffer) return i; if (i >= n) { memcpy(buffer, u, n - 2); buffer[n - 1] = '\0'; } else { memcpy(buffer, u, i + 1); } return i; } if (url->url_type == url_any) { if (b && m > 0) { if (m > 1) strcpy(b, "*"); else b[0] = '\0'; } return 1; } if (url->url_scheme && url->url_scheme[0]) { i = strlen(url->url_scheme) + 1; if (do_copy && (do_copy = i <= n)) { memcpy(b, url->url_scheme, i - 1); b[i - 1] = ':'; } b += i; n -= i; } if (url->url_root && (url->url_host || url->url_user)) { if (do_copy && (do_copy = 2 <= n)) memcpy(b, "//", 2); b += 2; n -= 2; } if (url->url_user) { i = strlen(url->url_user); if (do_copy && (do_copy = i <= n)) memcpy(b, url->url_user, i); b += i; n -= i; if (url->url_password) { if (do_copy && (do_copy = 1 <= n)) *b = ':'; b++; n--; i = strlen(url->url_password); if (do_copy && (do_copy = i <= n)) memcpy(b, url->url_password, i); b += i; n -= i; } if (url->url_host) { if (do_copy && (do_copy = 1 <= n)) *b = '@'; b++; n--; } } if (url->url_host) { i = strlen(url->url_host); if (do_copy && (do_copy = i <= n)) memcpy(b, url->url_host, i); b += i; n -= i; if (url->url_port) { i = strlen(url->url_port) + 1; if (do_copy && (do_copy = i <= n)) { b[0] = ':'; memcpy(b + 1, url->url_port, i - 1); } b += i; n -= i; } } if (url->url_path) { if (url->url_root) { if (do_copy && (do_copy = 1 <= n)) b[0] = '/'; b++, n--; } i = strlen(url->url_path); if (do_copy && (do_copy = i < n)) memcpy(b, url->url_path, i); b += i; n -= i; } { static char const sep[] = ";?#"; char const *pp[3]; size_t j; pp[0] = url->url_params; pp[1] = url->url_headers; pp[2] = url->url_fragment; for (j = 0; j < 3; j++) { char const *p = pp[j]; if (!p) continue; i = strlen(p) + 1; if (do_copy && (do_copy = i <= n)) { *b = sep[j]; memcpy(b + 1, p, i - 1); } b += i; n -= i; } } if (do_copy && (do_copy = 1 <= n)) *b = '\0'; else if (buffer && m > 0) buffer[m - 1] = '\0'; assert((size_t)(b - buffer) == (size_t)(m - n)); /* This follows the snprintf(C99) return value, * Number of characters written (excluding NUL) */ return b - buffer;}/** Calculate the length of URL when encoded. * */isize_t url_len(url_t const * url){ size_t rv = 0; if (url->url_scheme) rv += strlen(url->url_scheme) + 1; /* plus ':' */ if (url->url_user) { rv += strlen(url->url_user); if (url->url_password) rv += strlen(url->url_password) + 1; /* plus ':' */ rv += url->url_host != NULL; /* plus '@' */ } if (url->url_host) rv += strlen(url->url_host); if (url->url_port) rv += strlen(url->url_port) + 1; /* plus ':' */ if (url->url_path) rv += strlen(url->url_path) + 1; /* plus initial / */ if (url->url_params) rv += strlen(url->url_params) + 1; /* plus initial ; */ if (url->url_headers) rv += strlen(url->url_headers) + 1; /* plus '?' */ if (url->url_fragment) rv += strlen(url->url_fragment) + 1; /* plus '#' */ return rv;}/**@def URL_E(buf, end, url) * Encode an URL: use @a buf up to @a end. * @hideinitializer *//** * Calculate the size of strings associated with a #url_t sructure. * * @param url pointer to a #url_t structure or string * @return Number of bytes for URL */isize_t url_xtra(url_t const *url){ size_t xtra; if (URL_STRING_P(url)) { xtra = strlen((char const *)url) + 1; } else { size_t len_scheme, len_user, len_password, len_host, len_port, len_path, len_params, len_headers, len_fragment; len_scheme = (url->url_type <= url_unknown && url->url_scheme) ? strlen(url->url_scheme) + 1 : 0; len_user = url->url_user ? strlen(url->url_user) + 1 : 0; len_password = url->url_password ? strlen(url->url_password) + 1 : 0; len_host = url->url_host ? strlen(url->url_host) + 1 : 0; len_port = url->url_port ? strlen(url->url_port) + 1 : 0; len_path = url->url_path ? strlen(url->url_path) + 1 : 0; len_params = url->url_params ? strlen(url->url_params) + 1 : 0; len_headers = url->url_headers ? strlen(url->url_headers) + 1 : 0; len_fragment = url->url_fragment ? strlen(url->url_fragment) + 1 : 0; xtra = len_scheme + len_user + len_password + len_host + len_port + len_path + len_params + len_headers + len_fragment; } return xtra;}su_inlinechar *copy(char *buf, char *end, char const *src){#if HAVE_MEMCCPY char *b = memccpy(buf, src, '\0', end - buf); if (b) return b; else return end + strlen(src + (end - buf)) + 1;#else for (; buf < end && (*buf = *src); buf++, src++) ; if (buf >= end) while (*src++) buf++; return buf + 1;#endif}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -