diff options
-rw-r--r-- | src/nxt_controller.c | 38 | ||||
-rw-r--r-- | src/nxt_http_parse.c | 327 | ||||
-rw-r--r-- | src/nxt_http_parse.h | 83 | ||||
-rw-r--r-- | test/nxt_http_parse_unit_test.c | 199 |
4 files changed, 395 insertions, 252 deletions
diff --git a/src/nxt_controller.c b/src/nxt_controller.c index c8522573..e31e2e15 100644 --- a/src/nxt_controller.c +++ b/src/nxt_controller.c @@ -51,7 +51,7 @@ static void nxt_controller_conn_close(nxt_task_t *task, void *obj, void *data); static void nxt_controller_conn_free(nxt_task_t *task, void *obj, void *data); static nxt_int_t nxt_controller_request_content_length(void *ctx, - nxt_str_t *name, nxt_str_t *value, uintptr_t data); + nxt_http_field_t *field, uintptr_t data, nxt_log_t *log); static void nxt_controller_process_request(nxt_task_t *task, nxt_event_conn_t *c, nxt_controller_request_t *r); @@ -61,14 +61,14 @@ static nxt_buf_t *nxt_controller_response_body(nxt_controller_response_t *resp, nxt_mem_pool_t *pool); -static nxt_http_fields_t nxt_controller_request_fields[] = { +static nxt_http_fields_hash_entry_t nxt_controller_request_fields[] = { { nxt_string("Content-Length"), &nxt_controller_request_content_length, 0 }, { nxt_null_string, NULL, 0 } }; -static nxt_http_fields_hash_t *nxt_controller_request_fields_hash; +static nxt_http_fields_hash_t *nxt_controller_fields_hash; static nxt_controller_conf_t nxt_controller_conf; @@ -90,13 +90,13 @@ nxt_controller_start(nxt_task_t *task, nxt_runtime_t *rt) static const nxt_str_t json = nxt_string("{ \"sockets\": {}, \"applications\": {} }"); - hash = nxt_http_fields_hash(nxt_controller_request_fields, rt->mem_pool); - + hash = nxt_http_fields_hash_create(nxt_controller_request_fields, + rt->mem_pool); if (nxt_slow_path(hash == NULL)) { return NXT_ERROR; } - nxt_controller_request_fields_hash = hash; + nxt_controller_fields_hash = hash; if (nxt_listen_event(task, rt->controller_socket) == NULL) { return NXT_ERROR; @@ -215,8 +215,12 @@ nxt_controller_conn_init(nxt_task_t *task, void *obj, void *data) return; } - r->parser.hash = nxt_controller_request_fields_hash; - r->parser.ctx = r; + if (nxt_slow_path(nxt_http_parse_request_init(&r->parser, c->mem_pool) + != NXT_OK)) + { + nxt_controller_conn_free(task, c, NULL); + return; + } b = nxt_buf_mem_alloc(c->mem_pool, 1024, 0); if (nxt_slow_path(b == NULL)) { @@ -292,6 +296,14 @@ nxt_controller_conn_read(nxt_task_t *task, void *obj, void *data) return; } + rc = nxt_http_fields_process(r->parser.fields, nxt_controller_fields_hash, + r, task->log); + + if (nxt_slow_path(rc != NXT_OK)) { + nxt_controller_conn_close(task, c, r); + return; + } + preread = nxt_buf_mem_used_size(&b->mem); nxt_debug(task, "controller request header parsing complete, " @@ -508,24 +520,24 @@ nxt_controller_conn_free(nxt_task_t *task, void *obj, void *data) static nxt_int_t -nxt_controller_request_content_length(void *ctx, nxt_str_t *name, - nxt_str_t *value, uintptr_t data) +nxt_controller_request_content_length(void *ctx, nxt_http_field_t *field, + uintptr_t data, nxt_log_t *log) { off_t length; nxt_controller_request_t *r; r = ctx; - length = nxt_off_t_parse(value->start, value->length); + length = nxt_off_t_parse(field->value.start, field->value.length); if (nxt_fast_path(length > 0)) { - /* TODO length too big */ + nxt_log_error(NXT_LOG_ERR, log, "Content-Length is too big"); r->length = length; return NXT_OK; } - /* TODO logging (task?) */ + nxt_log_error(NXT_LOG_ERR, log, "Content-Length is invalid"); return NXT_ERROR; } diff --git a/src/nxt_http_parse.c b/src/nxt_http_parse.c index 9424dc8b..3e74461b 100644 --- a/src/nxt_http_parse.c +++ b/src/nxt_http_parse.c @@ -8,29 +8,29 @@ typedef struct { - nxt_http_field_handler_t handler; - uintptr_t data; + nxt_http_fields_hash_entry_t *entry; + union { - uint8_t str[8]; - uint64_t ui64; + uint8_t str[8]; + uint64_t ui64; } key[]; -} nxt_http_fields_hash_entry_t; - - -#define nxt_http_fields_hash_next_entry(entry, n) \ - ((nxt_http_fields_hash_entry_t *) ((u_char *) (entry) \ - + sizeof(nxt_http_fields_hash_entry_t) \ - + n * 8)) +} nxt_http_fields_hash_elt_t; struct nxt_http_fields_hash_s { size_t min_length; size_t max_length; void *long_fields; - nxt_http_fields_hash_entry_t *entries[]; + nxt_http_fields_hash_elt_t *elts[]; }; +#define nxt_http_fields_hash_next_elt(elt, n) \ + ((nxt_http_fields_hash_elt_t *) ((u_char *) (elt) \ + + sizeof(nxt_http_fields_hash_elt_t) \ + + n * 8)) + + static nxt_int_t nxt_http_parse_unusual_target(nxt_http_request_parse_t *rp, u_char **pos, u_char *end); static nxt_int_t nxt_http_parse_request_line(nxt_http_request_parse_t *rp, @@ -43,10 +43,9 @@ static u_char *nxt_http_lookup_field_end(u_char *p, u_char *end); static nxt_int_t nxt_http_parse_field_end(nxt_http_request_parse_t *rp, u_char **pos, u_char *end); -static nxt_http_fields_hash_entry_t *nxt_http_fields_hash_lookup( - nxt_http_fields_hash_t *hash, uint64_t *key, nxt_str_t *value); -static nxt_http_fields_hash_entry_t *nxt_http_header_fields_hash_lookup_long( - nxt_http_fields_hash_t *hash, nxt_str_t *value); + +static nxt_http_fields_hash_entry_t *nxt_http_fields_hash_lookup_long( + nxt_http_fields_hash_t *hash, nxt_http_field_t *field); typedef enum { @@ -427,7 +426,7 @@ nxt_http_parse_field_name(nxt_http_request_parse_t *rp, u_char **pos, p = *pos; size = end - p; - i = rp->offset; + i = rp->field.name.length; #define nxt_http_parse_field_name_step \ { \ @@ -438,7 +437,7 @@ nxt_http_parse_field_name(nxt_http_request_parse_t *rp, u_char **pos, goto name_end; \ } \ \ - rp->field_name_key.str[i % 32] = c; \ + rp->field.key.str[i % 32] = c; \ i++; \ } @@ -460,7 +459,7 @@ nxt_http_parse_field_name(nxt_http_request_parse_t *rp, u_char **pos, #undef nxt_http_parse_field_name_step - rp->offset = i; + rp->field.name.length = i; rp->handler = &nxt_http_parse_field_name; return NXT_AGAIN; @@ -474,10 +473,8 @@ name_end: *pos = &p[i] + 1; - rp->field_name.start = p; - rp->field_name.length = i; - - rp->offset = 0; + rp->field.name.length = i; + rp->field.name.start = p; return nxt_http_parse_field_value(rp, pos, end); } @@ -486,8 +483,6 @@ name_end: return NXT_ERROR; } - rp->field_name.length = 0; - return nxt_http_parse_field_end(rp, pos, end); } @@ -516,13 +511,13 @@ nxt_http_parse_field_value(nxt_http_request_parse_t *rp, u_char **pos, *pos = p; - p += rp->offset; + p += rp->field.value.length; for ( ;; ) { p = nxt_http_lookup_field_end(p, end); if (nxt_slow_path(p == end)) { - rp->offset = p - *pos; + rp->field.value.length = p - *pos; rp->handler = &nxt_http_parse_field_value; return NXT_AGAIN; } @@ -544,10 +539,8 @@ nxt_http_parse_field_value(nxt_http_request_parse_t *rp, u_char **pos, } } - rp->offset = 0; - - rp->field_value.start = *pos; - rp->field_value.length = p - *pos; + rp->field.value.length = p - *pos; + rp->field.value.start = *pos; *pos = p; @@ -624,9 +617,8 @@ static nxt_int_t nxt_http_parse_field_end(nxt_http_request_parse_t *rp, u_char **pos, u_char *end) { - u_char *p; - nxt_int_t rc; - nxt_http_fields_hash_entry_t *entry; + u_char *p; + nxt_http_field_t *field; p = *pos; @@ -642,21 +634,16 @@ nxt_http_parse_field_end(nxt_http_request_parse_t *rp, u_char **pos, if (nxt_fast_path(*p == '\n')) { *pos = p + 1; - if (rp->field_name.length != 0) { - entry = nxt_http_fields_hash_lookup(rp->hash, - rp->field_name_key.ui64, - &rp->field_name); + if (rp->field.name.length != 0) { + field = nxt_list_add(rp->fields); - if (entry != NULL) { - rc = entry->handler(rp->ctx, &rp->field_name, &rp->field_value, - entry->data); - - if (nxt_slow_path(rc != NXT_OK)) { - return NXT_ERROR; - } + if (nxt_slow_path(field == NULL)) { + return NXT_ERROR; } - nxt_memzero(rp->field_name_key.str, 32); + *field = rp->field; + + nxt_memzero(&rp->field, sizeof(nxt_http_field_t)); rp->handler = &nxt_http_parse_field_name; return NXT_OK; @@ -669,85 +656,175 @@ nxt_http_parse_field_end(nxt_http_request_parse_t *rp, u_char **pos, } -static nxt_http_fields_hash_entry_t * -nxt_http_fields_hash_lookup(nxt_http_fields_hash_t *hash, uint64_t *key, - nxt_str_t *value) +nxt_http_fields_hash_t * +nxt_http_fields_hash_create(nxt_http_fields_hash_entry_t *entries, + nxt_mem_pool_t *mp) { - nxt_http_fields_hash_entry_t *entry; + size_t min_length, max_length, length, size; + nxt_uint_t i, j, n; + nxt_http_fields_hash_t *hash; + nxt_http_fields_hash_elt_t *elt; - if (hash == NULL || value->length < hash->min_length) { + min_length = 32 + 1; + max_length = 0; + + for (i = 0; entries[i].handler != NULL; i++) { + length = entries[i].name.length; + + if (length > 32) { + /* TODO */ + return NULL; + } + + min_length = nxt_min(length, min_length); + max_length = nxt_max(length, max_length); + } + + size = sizeof(nxt_http_fields_hash_t); + + if (min_length <= 32) { + size += (max_length - min_length + 1) + * sizeof(nxt_http_fields_hash_elt_t *); + } + + hash = nxt_mem_zalloc(mp, size); + if (nxt_slow_path(hash == NULL)) { return NULL; } - if (value->length > hash->max_length) { - if (value->length > 32 && hash->long_fields != NULL) { - return nxt_http_header_fields_hash_lookup_long(hash, value); + hash->min_length = min_length; + hash->max_length = max_length; + + for (i = 0; entries[i].handler != NULL; i++) { + length = entries[i].name.length; + elt = hash->elts[length - min_length]; + + if (elt != NULL) { + continue; + } + + n = 1; + + for (j = i + 1; entries[j].handler != NULL; j++) { + if (length == entries[j].name.length) { + n++; + } + } + + size = sizeof(nxt_http_fields_hash_elt_t) + nxt_align_size(length, 8); + + elt = nxt_mem_zalloc(mp, n * size + + sizeof(nxt_http_fields_hash_elt_t)); + + if (nxt_slow_path(elt == NULL)) { + return NULL; } + hash->elts[length - min_length] = elt; + + for (j = i; entries[j].handler != NULL; j++) { + if (length != entries[j].name.length) { + continue; + } + + elt->entry = &entries[j]; + + nxt_memcpy_lowcase(elt->key->str, entries[j].name.start, length); + + n--; + + if (n == 0) { + break; + } + + elt = (nxt_http_fields_hash_elt_t *) ((u_char *) elt + size); + } + } + + return hash; +} + + +nxt_http_fields_hash_entry_t * +nxt_http_fields_hash_lookup(nxt_http_fields_hash_t *hash, + nxt_http_field_t *field) +{ + nxt_http_fields_hash_elt_t *elt; + + if (field->name.length < hash->min_length) { return NULL; } - entry = hash->entries[value->length - hash->min_length]; + if (field->name.length > hash->max_length) { + + if (field->name.length > 32 && hash->long_fields != NULL) { + return nxt_http_fields_hash_lookup_long(hash, field); + } - if (entry == NULL) { return NULL; } - switch ((value->length + 7) / 8) { + elt = hash->elts[field->name.length - hash->min_length]; + + if (elt == NULL) { + return NULL; + } + + switch ((field->name.length + 7) / 8) { case 1: do { - if (entry->key[0].ui64 == key[0]) { - return entry; + if (elt->key[0].ui64 == field->key.ui64[0]) { + return elt->entry; } - entry = nxt_http_fields_hash_next_entry(entry, 1); + elt = nxt_http_fields_hash_next_elt(elt, 1); - } while (entry->handler != NULL); + } while (elt->entry != NULL); break; case 2: do { - if (entry->key[0].ui64 == key[0] - && entry->key[1].ui64 == key[1]) + if (elt->key[0].ui64 == field->key.ui64[0] + && elt->key[1].ui64 == field->key.ui64[1]) { - return entry; + return elt->entry; } - entry = nxt_http_fields_hash_next_entry(entry, 2); + elt = nxt_http_fields_hash_next_elt(elt, 2); - } while (entry->handler != NULL); + } while (elt->entry != NULL); break; case 3: do { - if (entry->key[0].ui64 == key[0] - && entry->key[1].ui64 == key[1] - && entry->key[2].ui64 == key[2]) + if (elt->key[0].ui64 == field->key.ui64[0] + && elt->key[1].ui64 == field->key.ui64[1] + && elt->key[2].ui64 == field->key.ui64[2]) { - return entry; + return elt->entry; } - entry = nxt_http_fields_hash_next_entry(entry, 3); + elt = nxt_http_fields_hash_next_elt(elt, 3); - } while (entry->handler != NULL); + } while (elt->entry != NULL); break; case 4: do { - if (entry->key[0].ui64 == key[0] - && entry->key[1].ui64 == key[1] - && entry->key[2].ui64 == key[2] - && entry->key[3].ui64 == key[3]) + if (elt->key[0].ui64 == field->key.ui64[0] + && elt->key[1].ui64 == field->key.ui64[1] + && elt->key[2].ui64 == field->key.ui64[2] + && elt->key[3].ui64 == field->key.ui64[3]) { - return entry; + return elt->entry; } - entry = nxt_http_fields_hash_next_entry(entry, 4); + elt = nxt_http_fields_hash_next_elt(elt, 4); - } while (entry->handler != NULL); + } while (elt->entry != NULL); break; @@ -760,98 +837,34 @@ nxt_http_fields_hash_lookup(nxt_http_fields_hash_t *hash, uint64_t *key, static nxt_http_fields_hash_entry_t * -nxt_http_header_fields_hash_lookup_long(nxt_http_fields_hash_t *hash, - nxt_str_t *value) +nxt_http_fields_hash_lookup_long(nxt_http_fields_hash_t *hash, + nxt_http_field_t *field) { /* TODO */ return NULL; } -nxt_http_fields_hash_t * -nxt_http_fields_hash(nxt_http_fields_t *fields, nxt_mem_pool_t *mp) +nxt_int_t +nxt_http_fields_process(nxt_list_t *fields, nxt_http_fields_hash_t *hash, + void *ctx, nxt_log_t *log) { - size_t min_length, max_length, length, size; - nxt_uint_t i, j, n; - nxt_http_fields_hash_t *hash; + nxt_int_t rc; + nxt_http_field_t *field; nxt_http_fields_hash_entry_t *entry; - min_length = 32 + 1; - max_length = 0; - - for (i = 0; fields[i].handler != NULL; i++) { - length = fields[i].name.length; - - if (length > 32) { - /* TODO */ - return NULL; - } - - min_length = nxt_min(length, min_length); - max_length = nxt_max(length, max_length); - } - - size = sizeof(nxt_http_fields_hash_t); - - if (min_length <= 32) { - size += (max_length - min_length + 1) - * sizeof(nxt_http_fields_hash_entry_t *); - } - - hash = nxt_mem_zalloc(mp, size); - if (nxt_slow_path(hash == NULL)) { - return NULL; - } - - hash->min_length = min_length; - hash->max_length = max_length; - - for (i = 0; fields[i].handler != NULL; i++) { - length = fields[i].name.length; - entry = hash->entries[length - min_length]; + nxt_list_each(field, fields) { + entry = nxt_http_fields_hash_lookup(hash, field); if (entry != NULL) { - continue; - } - - n = 1; + rc = entry->handler(ctx, field, entry->data, log); - for (j = i + 1; fields[j].handler != NULL; j++) { - if (length == fields[j].name.length) { - n++; + if (rc != NXT_OK) { + return rc; } } - size = sizeof(nxt_http_fields_hash_entry_t) + nxt_align_size(length, 8); - - entry = nxt_mem_zalloc(mp, n * size - + sizeof(nxt_http_fields_hash_entry_t)); - - if (nxt_slow_path(entry == NULL)) { - return NULL; - } - - hash->entries[length - min_length] = entry; - - for (j = i; fields[j].handler != NULL; j++) { - if (length != fields[j].name.length) { - continue; - } - - entry->handler = fields[j].handler; - entry->data = fields[j].data; - - nxt_memcpy_lowcase(entry->key->str, fields[j].name.start, length); - - n--; + } nxt_list_loop; - if (n == 0) { - break; - } - - entry = (nxt_http_fields_hash_entry_t *) ((u_char *) entry + size); - } - } - - return hash; + return NXT_OK; } diff --git a/src/nxt_http_parse.h b/src/nxt_http_parse.h index 2376855e..4cf3dc3c 100644 --- a/src/nxt_http_parse.h +++ b/src/nxt_http_parse.h @@ -11,64 +11,87 @@ typedef struct nxt_http_request_parse_s nxt_http_request_parse_t; typedef struct nxt_http_fields_hash_s nxt_http_fields_hash_t; -typedef nxt_int_t (*nxt_http_field_handler_t)(void *ctx, nxt_str_t *name, - nxt_str_t *value, uintptr_t data); - typedef union { - u_char str[8]; - uint64_t ui64; + u_char str[8]; + uint64_t ui64; } nxt_http_ver_t; -struct nxt_http_request_parse_s { - nxt_int_t (*handler)(nxt_http_request_parse_t *rp, - u_char **pos, u_char *end); +typedef struct { + union { + uint8_t str[32]; + uint64_t ui64[4]; + } key; - size_t offset; + nxt_str_t name; + nxt_str_t value; +} nxt_http_field_t; - nxt_str_t method; - u_char *target_start; - u_char *target_end; - u_char *exten_start; - u_char *args_start; +struct nxt_http_request_parse_s { + nxt_int_t (*handler)(nxt_http_request_parse_t *rp, + u_char **pos, u_char *end); - nxt_http_ver_t version; + size_t offset; - union { - uint8_t str[32]; - uint64_t ui64[4]; - } field_name_key; + nxt_str_t method; + + u_char *target_start; + u_char *target_end; + u_char *exten_start; + u_char *args_start; - nxt_str_t field_name; - nxt_str_t field_value; + nxt_http_ver_t version; - nxt_http_fields_hash_t *hash; - void *ctx; + nxt_http_field_t field; + nxt_list_t *fields; /* target with "/." */ - unsigned complex_target:1; + unsigned complex_target:1; /* target with "%" */ - unsigned quoted_target:1; + unsigned quoted_target:1; /* target with " " */ - unsigned space_in_target:1; + unsigned space_in_target:1; /* target with "+" */ - unsigned plus_in_target:1; + unsigned plus_in_target:1; }; +typedef nxt_int_t (*nxt_http_field_handler_t)(void *ctx, + nxt_http_field_t *field, + uintptr_t data, nxt_log_t *log); + + typedef struct { nxt_str_t name; nxt_http_field_handler_t handler; uintptr_t data; -} nxt_http_fields_t; +} nxt_http_fields_hash_entry_t; + + +nxt_inline nxt_int_t +nxt_http_parse_request_init(nxt_http_request_parse_t *rp, nxt_mem_pool_t *mp) +{ + rp->fields = nxt_list_create(mp, 8, sizeof(nxt_http_field_t)); + if (nxt_slow_path(rp->fields == NULL)){ + return NXT_ERROR; + } + + return NXT_OK; +} nxt_int_t nxt_http_parse_request(nxt_http_request_parse_t *rp, nxt_buf_mem_t *b); -nxt_http_fields_hash_t *nxt_http_fields_hash(nxt_http_fields_t *fields, - nxt_mem_pool_t *mp); + +nxt_http_fields_hash_t *nxt_http_fields_hash_create( + nxt_http_fields_hash_entry_t *entries, nxt_mem_pool_t *mp); +nxt_http_fields_hash_entry_t *nxt_http_fields_hash_lookup( + nxt_http_fields_hash_t *hash, nxt_http_field_t *field); + +nxt_int_t nxt_http_fields_process(nxt_list_t *fields, + nxt_http_fields_hash_t *hash, void *ctx, nxt_log_t *log); #endif /* _NXT_HTTP_PARSER_H_INCLUDED_ */ diff --git a/test/nxt_http_parse_unit_test.c b/test/nxt_http_parse_unit_test.c index 2bc974db..f2b5ac96 100644 --- a/test/nxt_http_parse_unit_test.c +++ b/test/nxt_http_parse_unit_test.c @@ -25,8 +25,15 @@ typedef struct { } nxt_http_parse_unit_test_request_line_t; +typedef struct { + nxt_http_fields_hash_entry_t *entries; + nxt_int_t result; +} nxt_http_parse_unit_test_fields_t; + + typedef union { void *pointer; + nxt_http_parse_unit_test_fields_t fields; nxt_http_parse_unit_test_request_line_t request_line; } nxt_http_parse_unit_test_data_t; @@ -50,11 +57,26 @@ static nxt_int_t nxt_http_parse_unit_test_bench(nxt_thread_t *thr, static nxt_int_t nxt_http_parse_unit_test_request_line( nxt_http_request_parse_t *rp, nxt_http_parse_unit_test_data_t *data, nxt_str_t *request, nxt_log_t *log); +static nxt_int_t nxt_http_parse_unit_test_fields( + nxt_http_request_parse_t *rp, nxt_http_parse_unit_test_data_t *data, + nxt_str_t *request, nxt_log_t *log); + + +static nxt_int_t nxt_http_unit_test_header_return(void *ctx, nxt_http_field_t *field, + uintptr_t data, nxt_log_t *log); + + +static nxt_http_fields_hash_entry_t nxt_http_unit_test_fields[] = { + { nxt_string("X-Bad-Header"), + &nxt_http_unit_test_header_return, + (uintptr_t) NXT_ERROR }, -static nxt_int_t nxt_http_unit_test_header_return(void *ctx, nxt_str_t *name, - nxt_str_t *value, uintptr_t data); -static nxt_int_t nxt_http_unit_test_header_dump(void *ctx, nxt_str_t *name, - nxt_str_t *value, uintptr_t data); + { nxt_string("X-Good-Header"), + &nxt_http_unit_test_header_return, + (uintptr_t) NXT_OK }, + + { nxt_null_string, NULL, 0 } +}; static nxt_http_parse_unit_test_case_t nxt_http_unit_test_cases[] = { @@ -269,36 +291,57 @@ static nxt_http_parse_unit_test_case_t nxt_http_unit_test_cases[] = { }, { nxt_string("GET / HTTP/1.1\r\n" + "X-Unknown-Header: value\r\n" + "X-Good-Header: value\r\n\r\n"), + NXT_DONE, + &nxt_http_parse_unit_test_fields, + { .fields = { + nxt_http_unit_test_fields, + NXT_OK + }} + }, + { + nxt_string("GET / HTTP/1.1\r\n" + "X-Good-Header: value\r\n" + "X-Unknown-Header: value\r\n" "X-Bad-Header: value\r\n\r\n"), - NXT_ERROR, - NULL, { NULL } + NXT_DONE, + &nxt_http_parse_unit_test_fields, + { .fields = { + nxt_http_unit_test_fields, + NXT_ERROR + }} }, }; -static nxt_http_fields_t nxt_http_unit_test_headers[] = { - { nxt_string("X-Bad-Header"), - &nxt_http_unit_test_header_return, - (uintptr_t) NXT_ERROR }, - - { nxt_null_string, NULL, 0 } -}; - - -static nxt_http_fields_t nxt_http_unit_test_bench_headers[] = { - { nxt_string("Host"), &nxt_http_unit_test_header_dump, 0 }, - { nxt_string("User-Agent"), &nxt_http_unit_test_header_dump, 0 }, - { nxt_string("Accept-Encoding"), &nxt_http_unit_test_header_dump, 0 }, - { nxt_string("Accept-Language"), &nxt_http_unit_test_header_dump, 0 }, - { nxt_string("Connection"), &nxt_http_unit_test_header_dump, 0 }, - { nxt_string("Content-Length"), &nxt_http_unit_test_header_dump, 0 }, - { nxt_string("Content-Type"), &nxt_http_unit_test_header_dump, 0 }, - { nxt_string("If-Modified-Since"), &nxt_http_unit_test_header_dump, 0 }, - { nxt_string("If-Match"), &nxt_http_unit_test_header_dump, 0 }, - { nxt_string("Date"), &nxt_http_unit_test_header_dump, 0 }, - { nxt_string("Upgrade"), &nxt_http_unit_test_header_dump, 0 }, - { nxt_string("X-Forwarded-For"), &nxt_http_unit_test_header_dump, 0 }, - { nxt_string("X-Request-ID"), &nxt_http_unit_test_header_dump, 0 }, +static nxt_http_fields_hash_entry_t nxt_http_unit_test_bench_fields[] = { + { nxt_string("Host"), + &nxt_http_unit_test_header_return, NXT_OK }, + { nxt_string("User-Agent"), + &nxt_http_unit_test_header_return, NXT_OK }, + { nxt_string("Accept-Encoding"), + &nxt_http_unit_test_header_return, NXT_OK }, + { nxt_string("Accept-Language"), + &nxt_http_unit_test_header_return, NXT_OK }, + { nxt_string("Connection"), + &nxt_http_unit_test_header_return, NXT_OK }, + { nxt_string("Content-Length"), + &nxt_http_unit_test_header_return, NXT_OK }, + { nxt_string("Content-Type"), + &nxt_http_unit_test_header_return, NXT_OK }, + { nxt_string("If-Modified-Since"), + &nxt_http_unit_test_header_return, NXT_OK }, + { nxt_string("If-Match"), + &nxt_http_unit_test_header_return, NXT_OK }, + { nxt_string("Date"), + &nxt_http_unit_test_header_return, NXT_OK }, + { nxt_string("Upgrade"), + &nxt_http_unit_test_header_return, NXT_OK }, + { nxt_string("X-Forwarded-For"), + &nxt_http_unit_test_header_return, NXT_OK }, + { nxt_string("X-Request-ID"), + &nxt_http_unit_test_header_return, NXT_OK }, { nxt_null_string, NULL, 0 } }; @@ -387,30 +430,26 @@ nxt_http_parse_unit_test(nxt_thread_t *thr) { nxt_int_t rc; nxt_uint_t i; - nxt_mem_pool_t *pool; + nxt_mem_pool_t *mp; nxt_http_fields_hash_t *hash; nxt_http_request_parse_t rp; nxt_http_parse_unit_test_case_t *test; nxt_thread_time_update(thr); - pool = nxt_mem_pool_create(512); - if (pool == NULL) { - return NXT_ERROR; - } - - hash = nxt_http_fields_hash(nxt_http_unit_test_headers, pool); - - if (hash == NULL) { - return NXT_ERROR; - } - for (i = 0; i < nxt_nitems(nxt_http_unit_test_cases); i++) { test = &nxt_http_unit_test_cases[i]; nxt_memzero(&rp, sizeof(nxt_http_request_parse_t)); - rp.hash = hash; + mp = nxt_mem_pool_create(512); + if (mp == NULL) { + return NXT_ERROR; + } + + if (nxt_http_parse_request_init(&rp, mp) != NXT_OK) { + return NXT_ERROR; + } rc = nxt_http_parse_unit_test_run(&rp, &test->request); @@ -428,12 +467,18 @@ nxt_http_parse_unit_test(nxt_thread_t *thr) { return NXT_ERROR; } + + nxt_mem_pool_destroy(mp); } nxt_log_error(NXT_LOG_NOTICE, thr->log, "http parse unit test passed"); - hash = nxt_http_fields_hash(nxt_http_unit_test_bench_headers, pool); + mp = nxt_mem_pool_create(512); + if (mp == NULL) { + return NXT_ERROR; + } + hash = nxt_http_fields_hash_create(nxt_http_unit_test_bench_fields, mp); if (hash == NULL) { return NXT_ERROR; } @@ -452,7 +497,7 @@ nxt_http_parse_unit_test(nxt_thread_t *thr) return NXT_ERROR; } - nxt_mem_pool_destroy(pool); + nxt_mem_pool_destroy(mp); return NXT_OK; } @@ -486,6 +531,7 @@ nxt_http_parse_unit_test_bench(nxt_thread_t *thr, nxt_str_t *request, nxt_nsec_t start, end; nxt_uint_t i; nxt_buf_mem_t buf; + nxt_mem_pool_t *mp; nxt_http_request_parse_t rp; nxt_log_error(NXT_LOG_NOTICE, thr->log, @@ -502,14 +548,34 @@ nxt_http_parse_unit_test_bench(nxt_thread_t *thr, nxt_str_t *request, for (i = 0; nxt_fast_path(i < n); i++) { nxt_memzero(&rp, sizeof(nxt_http_request_parse_t)); + mp = nxt_mem_pool_create(512); + if (nxt_slow_path(mp == NULL)) { + return NXT_ERROR; + } + + if (nxt_slow_path(nxt_http_parse_request_init(&rp, mp) != NXT_OK)) { + return NXT_ERROR; + } + buf.pos = buf.start; buf.free = buf.end; if (nxt_slow_path(nxt_http_parse_request(&rp, &buf) != NXT_DONE)) { - nxt_log_alert(thr->log, "http parse unit %s request bench failed", - name); + nxt_log_alert(thr->log, "http parse unit %s request bench failed " + "while parsing", name); return NXT_ERROR; } + + if (nxt_slow_path(nxt_http_fields_process(rp.fields, hash, NULL, + thr->log) + != NXT_OK)) + { + nxt_log_alert(thr->log, "http parse unit %s request bench failed " + "while fields processing", name); + return NXT_ERROR; + } + + nxt_mem_pool_destroy(mp); } nxt_thread_time_update(thr); @@ -627,16 +693,45 @@ nxt_http_parse_unit_test_request_line(nxt_http_request_parse_t *rp, static nxt_int_t -nxt_http_unit_test_header_return(void *ctx, nxt_str_t *name, nxt_str_t *value, - uintptr_t data) +nxt_http_parse_unit_test_fields(nxt_http_request_parse_t *rp, + nxt_http_parse_unit_test_data_t *data, nxt_str_t *request, nxt_log_t *log) { - return (nxt_int_t) data; + nxt_int_t rc; + nxt_mem_pool_t *mp; + nxt_http_fields_hash_t *hash; + + nxt_http_parse_unit_test_fields_t *test = &data->fields; + + mp = nxt_mem_pool_create(256); + if (mp == NULL) { + return NXT_ERROR; + } + + hash = nxt_http_fields_hash_create(test->entries, mp); + if (hash == NULL) { + nxt_log_alert(log, "unable to create hash"); + return NXT_ERROR; + } + + rc = nxt_http_fields_process(rp->fields, hash, NULL, log); + + if (rc != test->result) { + nxt_log_alert(log, "http parse unit test hash failed:\n" + " - request:\n\"%V\"\n" + " - result: %i (expected: %i)", + request, rc, test->result); + return NXT_ERROR; + } + + nxt_mem_pool_destroy(mp); + + return NXT_OK; } static nxt_int_t -nxt_http_unit_test_header_dump(void *ctx, nxt_str_t *name, nxt_str_t *value, - uintptr_t data) +nxt_http_unit_test_header_return(void *ctx, nxt_http_field_t *field, + uintptr_t data, nxt_log_t *log) { - return NXT_OK; + return (nxt_int_t) data; } |