h2o_iovec_vector_t h2o_extract_push_path_from_link_header(h2o_mem_pool_t *pool, const char *value, size_t value_len, h2o_iovec_t base_path, const h2o_url_scheme_t *input_scheme, h2o_iovec_t input_authority, const h2o_url_scheme_t *base_scheme, h2o_iovec_t *base_authority) { h2o_iovec_vector_t paths_to_push = {}; h2o_iovec_t iter = h2o_iovec_init(value, value_len), token_value; const char *token; size_t token_len; /* extract URL values from Link: </pushed.css>; rel=preload */ do { if ((token = h2o_next_token(&iter, ';', &token_len, NULL)) == NULL) break; /* first element should be <URL> */ if (!(token_len >= 2 && token[0] == '<' && token[token_len - 1] == '>')) break; h2o_iovec_t url = h2o_iovec_init(token + 1, token_len - 2); /* find rel=preload */ int preload = 0, nopush = 0; while ((token = h2o_next_token(&iter, ';', &token_len, &token_value)) != NULL && !h2o_memis(token, token_len, H2O_STRLIT(","))) { if (h2o_lcstris(token, token_len, H2O_STRLIT("rel")) && h2o_lcstris(token_value.base, token_value.len, H2O_STRLIT("preload"))) { preload++; } else if (h2o_lcstris(token, token_len, H2O_STRLIT("nopush"))) { nopush++; } } if (!nopush && preload) push_one_path(pool, &paths_to_push, &url, base_path, input_scheme, input_authority, base_scheme, base_authority); } while (token != NULL); return paths_to_push; }
h2o_iovec_t h2o_extract_push_path_from_link_header(h2o_mem_pool_t *pool, const char *value, size_t value_len, const h2o_url_scheme_t *base_scheme, h2o_iovec_t *base_authority, h2o_iovec_t *base_path) { h2o_iovec_t url; h2o_url_t parsed, resolved; { /* extract URL value from: Link: </pushed.css>; rel=preload */ h2o_iovec_t iter = h2o_iovec_init(value, value_len), token_value; const char *token; size_t token_len; /* first element should be <URL> */ if ((token = h2o_next_token(&iter, ';', &token_len, NULL)) == NULL) goto None; if (!(token_len >= 2 && token[0] == '<' && token[token_len - 1] == '>')) goto None; url = h2o_iovec_init(token + 1, token_len - 2); /* find rel=preload */ while ((token = h2o_next_token(&iter, ';', &token_len, &token_value)) != NULL) { if (h2o_lcstris(token, token_len, H2O_STRLIT("rel")) && h2o_lcstris(token_value.base, token_value.len, H2O_STRLIT("preload"))) break; } if (token == NULL) goto None; } /* check the authority, and extract absolute path */ if (h2o_url_parse_relative(url.base, url.len, &parsed) != 0) goto None; /* return the URL found in Link header, if it is an absolute path-only URL */ if (parsed.scheme == NULL && parsed.authority.base == NULL && url.len != 0 && url.base[0] == '/') return h2o_strdup(pool, url.base, url.len); /* check scheme and authority if given URL contains either of the two */ h2o_url_t base = {base_scheme, *base_authority, {}, *base_path, 65535}; h2o_url_resolve(pool, &base, &parsed, &resolved); if (base.scheme != resolved.scheme) goto None; if (parsed.authority.base != NULL && !h2o_lcstris(base.authority.base, base.authority.len, resolved.authority.base, resolved.authority.len)) goto None; return resolved.path; None: return (h2o_iovec_t){}; }
static void test_next_token(void) { h2o_iovec_t iter; const char *token; size_t token_len; #define NEXT() \ if ((token = h2o_next_token(&iter, ',', &token_len, NULL)) == NULL) { \ ok(0); \ return; \ } iter = h2o_iovec_init(H2O_STRLIT("public, max-age=86400, must-revalidate")); NEXT(); ok(h2o_memis(token, token_len, H2O_STRLIT("public"))); NEXT(); ok(h2o_memis(token, token_len, H2O_STRLIT("max-age=86400"))); NEXT(); ok(h2o_memis(token, token_len, H2O_STRLIT("must-revalidate"))); token = h2o_next_token(&iter, ',', &token_len, NULL); ok(token == NULL); iter = h2o_iovec_init(H2O_STRLIT(" public ,max-age=86400 ,")); NEXT(); ok(h2o_memis(token, token_len, H2O_STRLIT("public"))); NEXT(); ok(h2o_memis(token, token_len, H2O_STRLIT("max-age=86400"))); token = h2o_next_token(&iter, ',', &token_len, NULL); ok(token == NULL); iter = h2o_iovec_init(H2O_STRLIT("")); token = h2o_next_token(&iter, ',', &token_len, NULL); ok(token == NULL); iter = h2o_iovec_init(H2O_STRLIT(", ,a, ")); NEXT(); ok(token_len == 0); NEXT(); ok(token_len == 0); NEXT(); ok(h2o_memis(token, token_len, H2O_STRLIT("a"))); token = h2o_next_token(&iter, ',', &token_len, NULL); ok(token == NULL); #undef NEXT }
static void test_next_token2(void) { h2o_iovec_t iter, value; const char *name; size_t name_len; #define NEXT() \ if ((name = h2o_next_token(&iter, ',', &name_len, &value)) == NULL) { \ ok(0); \ return; \ } iter = h2o_iovec_init(H2O_STRLIT("public, max-age=86400, must-revalidate")); NEXT(); ok(h2o_memis(name, name_len, H2O_STRLIT("public"))); ok(value.base == NULL); ok(value.len == 0); NEXT(); ok(h2o_memis(name, name_len, H2O_STRLIT("max-age"))); ok(h2o_memis(value.base, value.len, H2O_STRLIT("86400"))); NEXT(); ok(h2o_memis(name, name_len, H2O_STRLIT("must-revalidate"))); ok(value.base == NULL); ok(value.len == 0); name = h2o_next_token(&iter, ',', &name_len, &value); ok(name == NULL); iter = h2o_iovec_init(H2O_STRLIT("public, max-age = 86400 = c , must-revalidate=")); NEXT(); ok(h2o_memis(name, name_len, H2O_STRLIT("public"))); ok(value.base == NULL); ok(value.len == 0); NEXT(); ok(h2o_memis(name, name_len, H2O_STRLIT("max-age"))); ok(h2o_memis(value.base, value.len, H2O_STRLIT("86400 = c"))); NEXT(); ok(h2o_memis(name, name_len, H2O_STRLIT("must-revalidate"))); name = h2o_next_token(&iter, ',', &name_len, &value); ok(h2o_memis(value.base, value.len, H2O_STRLIT(""))); #undef NEXT }
void h2o_cache_digests_load_header(h2o_cache_digests_t **digests, const char *value, size_t len) { h2o_iovec_t iter = h2o_iovec_init(value, len); const char *token; size_t token_len; do { const char *gcs_base64; size_t gcs_base64_len; int reset = 0, validators = 0, complete = 0, skip = 0; h2o_iovec_t token_value; if ((gcs_base64 = h2o_next_token(&iter, ';', &gcs_base64_len, NULL)) == NULL) return; while ((token = h2o_next_token(&iter, ';', &token_len, &token_value)) != NULL && !h2o_memis(token, token_len, H2O_STRLIT(","))) { if (h2o_lcstris(token, token_len, H2O_STRLIT("reset"))) { reset = 1; } else if (h2o_lcstris(token, token_len, H2O_STRLIT("validators"))) { validators = 1; } else if (h2o_lcstris(token, token_len, H2O_STRLIT("complete"))) { complete = 1; } else { skip = 1; } } if (reset && *digests != NULL) { h2o_cache_digests_destroy(*digests); *digests = NULL; } if (skip) { /* not supported for the time being */ } else { load_digest(digests, gcs_base64, gcs_base64_len, validators, complete); } } while (token != NULL); }
static void test_next_token3(void) { h2o_iovec_t iter, value; const char *name; size_t name_len; #define NEXT() \ if ((name = h2o_next_token(&iter, ';', &name_len, &value)) == NULL) { \ ok(0); \ return; \ } iter = h2o_iovec_init(H2O_STRLIT("</foo.css>; rel=preload; xxx=,</bar.js>, </zzz.js>")); NEXT(); ok(h2o_memis(name, name_len, H2O_STRLIT("</foo.css>"))); ok(value.base == NULL); ok(value.len == 0); NEXT(); ok(h2o_memis(name, name_len, H2O_STRLIT("rel"))); ok(h2o_memis(value.base, value.len, H2O_STRLIT("preload"))); NEXT(); ok(h2o_memis(name, name_len, H2O_STRLIT("xxx"))); ok(value.base != NULL); /* xxx _has_ a value! */ ok(value.len == 0); NEXT(); ok(h2o_memis(name, name_len, H2O_STRLIT(","))); ok(value.base == NULL); ok(value.len == 0); NEXT(); ok(h2o_memis(name, name_len, H2O_STRLIT("</bar.js>"))); ok(value.base == NULL); ok(value.len == 0); NEXT(); ok(h2o_memis(name, name_len, H2O_STRLIT(","))); ok(value.base == NULL); ok(value.len == 0); NEXT(); ok(h2o_memis(name, name_len, H2O_STRLIT("</zzz.js>"))); ok(value.base == NULL); ok(value.len == 0); name = h2o_next_token(&iter, ',', &name_len, &value); ok(name == NULL); #undef NEXT }
int h2o_get_compressible_types(const h2o_headers_t *headers) { size_t header_index; int compressible_types = 0; for (header_index = 0; header_index != headers->size; ++header_index) { const h2o_header_t *header = headers->entries + header_index; if (H2O_UNLIKELY(header->name == &H2O_TOKEN_ACCEPT_ENCODING->buf)) { h2o_iovec_t iter = h2o_iovec_init(header->value.base, header->value.len); const char *token = NULL; size_t token_len = 0; while ((token = h2o_next_token(&iter, ',', &token_len, NULL)) != NULL) { if (h2o_lcstris(token, token_len, H2O_STRLIT("gzip"))) compressible_types |= H2O_COMPRESSIBLE_GZIP; else if (h2o_lcstris(token, token_len, H2O_STRLIT("br"))) compressible_types |= H2O_COMPRESSIBLE_BROTLI; } } } return compressible_types; }