int uri_parse(const char *uri_s, struct uri *uri) { const char *p, *q; uri_init(uri); /* Scheme, section 3.1. */ p = uri_s; if (!is_alpha_char(*p)) goto fail; q = p; while (is_alpha_char(*q) || is_digit_char(*q) || *q == '+' || *q == '-' || *q == '.') q++; if (*q != ':') goto fail; uri->scheme = mkstr(p, q); lowercase(uri->scheme); /* Authority, section 3.2. */ p = q + 1; if (*p == '/' && *(p + 1) == '/') { char *authority = NULL; p += 2; q = p; while (!(*q == '/' || *q == '?' || *q == '#' || *q == '\0')) q++; authority = mkstr(p, q); if (uri_parse_authority(uri, authority)) { free(authority); goto fail; } free(authority); p = q; } q = strchr(p, '\0'); uri->path = mkstr(p, q); return 0; fail: uri_free(uri); return -EINVAL; }
/* Parse a URI string into a struct URI. Any parts of the URI that are absent will become NULL entries in the structure, except for the port which will be -1. Returns NULL on error. See RFC 3986, section 3 for syntax. */ struct uri *uri_parse(struct uri *uri, const char *uri_s) { const char *p, *q; uri_init(uri); /* Scheme, section 3.1. */ p = uri_s; if (!is_alpha_char(*p)) goto fail; for (q = p; is_alpha_char(*q) || is_digit_char(*q) || *q == '+' || *q == '-' || *q == '.'; q++) ; if (*q != ':') goto fail; uri->scheme = mkstr(p, q); /* "An implementation should accept uppercase letters as equivalent to lowercase in scheme names (e.g., allow "HTTP" as well as "http") for the sake of robustness..." */ lowercase(uri->scheme); /* Authority, section 3.2. */ p = q + 1; if (*p == '/' && *(p + 1) == '/') { char *authority = NULL; p += 2; for (q = p; !(*q == '/' || *q == '?' || *q == '#' || *q == '\0'); q++) ; authority = mkstr(p, q); if (uri_parse_authority(uri, authority) == NULL) { free(authority); goto fail; } free(authority); p = q; } if (uri->port == -1) uri->port = scheme_default_port(uri->scheme); /* Path, section 3.3. We include the query and fragment in the path. The path is also not percent-decoded because we just pass it on to the origin server. */ q = strchr(p, '\0'); uri->path = mkstr(p, q); return uri; fail: uri_free(uri); return NULL; }
static const char *http_read_credentials(const char *s, struct http_credentials *credentials) { const char *p; char *scheme; credentials->scheme = AUTH_UNKNOWN; s = read_token(s, &scheme); if (s == NULL) return NULL; if (str_equal_i(scheme, "Basic")) { http_credentials_init_basic(credentials); } else if (str_equal_i(scheme, "Digest")) { http_credentials_init_digest(credentials); } else { free(scheme); return NULL; } free(scheme); while (is_space_char(*s)) s++; if (credentials->scheme == AUTH_BASIC) { p = s; /* Read base64. */ while (is_alpha_char(*p) || is_digit_char(*p) || *p == '+' || *p == '/' || *p == '=') p++; credentials->u.basic = mkstr(s, p); while (is_space_char(*p)) p++; s = p; } else if (credentials->scheme == AUTH_DIGEST) { char *name, *value; while (*s != '\0') { p = read_token(s, &name); if (p == NULL) goto bail; while (is_space_char(*p)) p++; /* It's not legal to combine multiple Authorization or Proxy-Authorization values. The productions are "Authorization" ":" credentials (section 14.8) "Proxy-Authorization" ":" credentials (section 14.34) Contrast this with WWW-Authenticate and Proxy-Authenticate and their handling in http_read_challenge. */ if (*p != '=') goto bail; p++; while (is_space_char(*p)) p++; p = read_token_or_quoted_string(p, &value); if (p == NULL) { free(name); goto bail; } if (str_equal_i(name, "username")) { if (credentials->u.digest.username != NULL) goto bail; credentials->u.digest.username = Strdup(value); } else if (str_equal_i(name, "realm")) { if (credentials->u.digest.realm != NULL) goto bail; credentials->u.digest.realm = Strdup(value); } else if (str_equal_i(name, "nonce")) { if (credentials->u.digest.nonce != NULL) goto bail; credentials->u.digest.nonce = Strdup(value); } else if (str_equal_i(name, "uri")) { if (credentials->u.digest.uri != NULL) goto bail; credentials->u.digest.uri = Strdup(value); } else if (str_equal_i(name, "response")) { if (credentials->u.digest.response != NULL) goto bail; credentials->u.digest.response = Strdup(value); } else if (str_equal_i(name, "algorithm")) { if (str_equal_i(value, "MD5")) credentials->u.digest.algorithm = ALGORITHM_MD5; else credentials->u.digest.algorithm = ALGORITHM_MD5; } else if (str_equal_i(name, "qop")) { if (str_equal_i(value, "auth")) credentials->u.digest.qop = QOP_AUTH; else if (str_equal_i(value, "auth-int")) credentials->u.digest.qop = QOP_AUTH_INT; else credentials->u.digest.qop = QOP_NONE; } else if (str_equal_i(name, "cnonce")) { if (credentials->u.digest.cnonce != NULL) goto bail; credentials->u.digest.cnonce = Strdup(value); } else if (str_equal_i(name, "nc")) { if (credentials->u.digest.nc != NULL) goto bail; credentials->u.digest.nc = Strdup(value); } free(name); free(value); while (is_space_char(*p)) p++; if (*p == ',') { p++; while (is_space_char(*p)) p++; if (*p == '\0') goto bail; } s = p; } } return s; bail: http_credentials_free(credentials); return NULL; }
bool is_symbol_char(char c) { return is_alpha_char(c); }