diff options
author | Max Romanov <max.romanov@nginx.com> | 2017-07-05 13:31:45 +0300 |
---|---|---|
committer | Max Romanov <max.romanov@nginx.com> | 2017-07-05 13:31:45 +0300 |
commit | f3107f3896c199a5bc166f57ccd9fef2823ccdaf (patch) | |
tree | 1bb2388940d3ad1be08ababfecd270c65289cf26 | |
parent | f05d674126f3ec3f147f645231a1357e4a0784bf (diff) | |
download | unit-f3107f3896c199a5bc166f57ccd9fef2823ccdaf.tar.gz unit-f3107f3896c199a5bc166f57ccd9fef2823ccdaf.tar.bz2 |
Complex target parser copied from NGINX.
nxt_app_request_header_t fields renamed:
- 'path' renamed to 'target'.
- 'path_no_query' renamed to 'path' and contains parsed value.
-rw-r--r-- | src/nginext/nxt_go_port.c | 17 | ||||
-rw-r--r-- | src/nxt_application.c | 16 | ||||
-rw-r--r-- | src/nxt_application.h | 4 | ||||
-rw-r--r-- | src/nxt_controller.c | 9 | ||||
-rw-r--r-- | src/nxt_go.c | 9 | ||||
-rw-r--r-- | src/nxt_http_parse.c | 337 | ||||
-rw-r--r-- | src/nxt_http_parse.h | 7 | ||||
-rw-r--r-- | src/nxt_php_sapi.c | 38 | ||||
-rw-r--r-- | src/nxt_python_wsgi.c | 30 |
9 files changed, 413 insertions, 54 deletions
diff --git a/src/nginext/nxt_go_port.c b/src/nginext/nxt_go_port.c index 00d13a38..47e46f02 100644 --- a/src/nginext/nxt_go_port.c +++ b/src/nginext/nxt_go_port.c @@ -41,22 +41,27 @@ nxt_go_data_handler(nxt_port_msg_t *port_msg, size_t size) h = &ctx->r.header; nxt_go_ctx_read_str(ctx, &h->method); + nxt_go_ctx_read_str(ctx, &h->target); nxt_go_ctx_read_str(ctx, &h->path); - h->path_no_query = h->path; nxt_go_ctx_read_size(ctx, &s); if (s > 0) { s--; - h->query.start = h->path.start + s; - h->query.length = h->path.length - s; + h->query.start = h->target.start + s; + h->query.length = h->target.length - s; - if (s > 0) { - h->path_no_query.length = s - 1; + if (h->path.start == NULL) { + h->path.start = h->target.start; + h->path.length = s - 1; } } + if (h->path.start == NULL) { + h->path = h->target; + } + nxt_go_new_request(r, port_msg->stream, nxt_go_str(&h->method), - nxt_go_str(&h->path)); + nxt_go_str(&h->target)); nxt_go_ctx_read_str(ctx, &h->version); diff --git a/src/nxt_application.c b/src/nxt_application.c index d7393de7..37e2577c 100644 --- a/src/nxt_application.c +++ b/src/nxt_application.c @@ -477,19 +477,11 @@ nxt_app_http_req_parse(nxt_task_t *task, nxt_app_parse_ctx_t *ctx, h->method = p->method; - h->path.start = p->target_start; - h->path.length = p->target_end - p->target_start; + h->target.start = p->target_start; + h->target.length = p->target_end - p->target_start; - h->path_no_query = h->path; - - if (p->args_start != NULL) { - h->query.start = p->args_start; - h->query.length = p->target_end - p->args_start; - - if (p->args_start > p->target_start) { - h->path_no_query.length = p->args_start - p->target_start - 1; - } - } + h->path = p->path; + h->query = p->args; if (h->parsed_content_length == 0) { b->done = 1; diff --git a/src/nxt_application.h b/src/nxt_application.h index fe36ea4d..9d8b1054 100644 --- a/src/nxt_application.h +++ b/src/nxt_application.h @@ -17,10 +17,10 @@ typedef struct { typedef struct { nxt_str_t method; + nxt_str_t target; + nxt_str_t version; nxt_str_t path; - nxt_str_t path_no_query; nxt_str_t query; - nxt_str_t version; nxt_list_t *fields; diff --git a/src/nxt_controller.c b/src/nxt_controller.c index 6898be6d..a3c0af17 100644 --- a/src/nxt_controller.c +++ b/src/nxt_controller.c @@ -554,14 +554,7 @@ nxt_controller_process_request(nxt_task_t *task, nxt_conn_t *c, static const nxt_str_t empty_obj = nxt_string("{}"); - path.start = req->parser.target_start; - - if (req->parser.args_start != NULL) { - path.length = req->parser.args_start - path.start; - - } else { - path.length = req->parser.target_end - path.start; - } + path = req->parser.path; if (path.length > 1 && path.start[path.length - 1] == '/') { path.length--; diff --git a/src/nxt_go.c b/src/nxt_go.c index 703974ba..4c77de0d 100644 --- a/src/nxt_go.c +++ b/src/nxt_go.c @@ -158,11 +158,16 @@ nxt_go_prepare_msg(nxt_task_t *task, nxt_app_request_t *r, nxt_app_wmsg_t *wmsg) /* TODO error handle, async mmap buffer assignment */ NXT_WRITE(&h->method); - NXT_WRITE(&h->path); + NXT_WRITE(&h->target); + if (h->path.start == h->target.start) { + NXT_WRITE(&eof); + } else { + NXT_WRITE(&h->path); + } if (h->query.start != NULL) { RC(nxt_app_msg_write_size(task, wmsg, - h->query.start - h->path.start + 1)); + h->query.start - h->target.start + 1)); } else { RC(nxt_app_msg_write_size(task, wmsg, 0)); } diff --git a/src/nxt_http_parse.c b/src/nxt_http_parse.c index abdb23fa..946c8da2 100644 --- a/src/nxt_http_parse.c +++ b/src/nxt_http_parse.c @@ -49,6 +49,8 @@ static void nxt_http_fields_hash_lookup(nxt_http_fields_hash_t *hash, static void nxt_http_fields_hash_lookup_long(nxt_http_fields_hash_t *hash, nxt_http_field_t *field); +static nxt_int_t nxt_http_parse_complex_target(nxt_http_request_parse_t *rp); + typedef enum { NXT_HTTP_TARGET_SPACE = 1, /* \s */ @@ -349,10 +351,39 @@ space_after_target: } *pos = p + 1; + + } else { + *pos = p + 10; + } + + if (rp->complex_target != 0 || rp->quoted_target != 0) { + rc = nxt_http_parse_complex_target(rp); + + if (nxt_slow_path(rc != NXT_OK)) { + return rc; + } + return nxt_http_parse_field_name(rp, pos, end); } - *pos = p + 10; + rp->path.start = rp->target_start; + + if (rp->args_start != NULL) { + rp->path.length = rp->args_start - rp->target_start - 1; + + rp->args.start = rp->args_start; + rp->args.length = rp->target_end - rp->args_start; + + } else { + rp->path.length = rp->target_end - rp->target_start; + } + + if (rp->exten_start) { + rp->exten.length = rp->path.start + rp->path.length - + rp->exten_start; + rp->exten.start = rp->exten_start; + } + return nxt_http_parse_field_name(rp, pos, end); } @@ -885,3 +916,307 @@ nxt_http_fields_process(nxt_list_t *fields, void *ctx, nxt_log_t *log) return NXT_OK; } + + +#define \ +nxt_http_is_normal(c) \ + (nxt_fast_path((nxt_http_normal[c / 8] & (1 << (c & 7))) != 0)) + + +static const uint8_t nxt_http_normal[32] nxt_aligned(32) = { + + /* \0 \r \n */ + 0xfe, 0xdb, 0xff, 0xff, /* 1111 1110 1101 1011 1111 1111 1111 1111 */ + + /* '&%$ #"! /.-, |*)( 7654 3210 ?>=< ;:98 */ + 0xd6, 0x37, 0xff, 0x7f, /* 1101 0110 0011 0111 1111 1111 0111 1111 */ + + /* GFED CBA@ ONML KJIH WVUT SRQP _^]\ [ZYX */ + 0xff, 0xff, 0xff, 0xff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ + + /* gfed cba` onml kjih wvut srqp ~}| {zyx */ + 0xff, 0xff, 0xff, 0xff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ + + 0xff, 0xff, 0xff, 0xff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ + 0xff, 0xff, 0xff, 0xff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ + 0xff, 0xff, 0xff, 0xff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ + 0xff, 0xff, 0xff, 0xff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ +}; + + +static nxt_int_t +nxt_http_parse_complex_target(nxt_http_request_parse_t *rp) +{ + u_char *p, *u, c, ch, high; + enum { + sw_normal = 0, + sw_slash, + sw_dot, + sw_dot_dot, + sw_quoted, + sw_quoted_second, + } state, saved_state; + + nxt_prefetch(nxt_http_normal); + + state = sw_normal; + saved_state = sw_normal; + p = rp->target_start; + + u = nxt_mp_alloc(rp->mem_pool, rp->target_end - p + 1); + + if (nxt_slow_path(u == NULL)) { + return NXT_ERROR; + } + + rp->path.length = 0; + rp->path.start = u; + + high = '\0'; + rp->exten_start = NULL; + rp->args_start = NULL; + + while (p < rp->target_end) { + + ch = *p++; + + again: + + switch (state) { + + case sw_normal: + + if (nxt_http_is_normal(ch)) { + *u++ = ch; + continue; + } + + switch (ch) { + case '/': + rp->exten_start = NULL; + state = sw_slash; + *u++ = ch; + continue; + case '%': + saved_state = state; + state = sw_quoted; + continue; + case '?': + rp->args_start = p; + goto args; + case '#': + goto done; + case '.': + rp->exten_start = u + 1; + *u++ = ch; + continue; + case '+': + rp->plus_in_target = 1; + /* Fall through. */ + default: + *u++ = ch; + continue; + } + + break; + + case sw_slash: + + if (nxt_http_is_normal(ch)) { + state = sw_normal; + *u++ = ch; + continue; + } + + switch (ch) { + case '/': + continue; + case '.': + state = sw_dot; + *u++ = ch; + continue; + case '%': + saved_state = state; + state = sw_quoted; + continue; + case '?': + rp->args_start = p; + goto args; + case '#': + goto done; + case '+': + rp->plus_in_target = 1; + /* Fall through. */ + default: + state = sw_normal; + *u++ = ch; + continue; + } + + break; + + case sw_dot: + + if (nxt_http_is_normal(ch)) { + state = sw_normal; + *u++ = ch; + continue; + } + + switch (ch) { + case '/': + state = sw_slash; + u--; + continue; + case '.': + state = sw_dot_dot; + *u++ = ch; + continue; + case '%': + saved_state = state; + state = sw_quoted; + continue; + case '?': + rp->args_start = p; + goto args; + case '#': + goto done; + case '+': + rp->plus_in_target = 1; + /* Fall through. */ + default: + state = sw_normal; + *u++ = ch; + continue; + } + + break; + + case sw_dot_dot: + + if (nxt_http_is_normal(ch)) { + state = sw_normal; + *u++ = ch; + continue; + } + + switch (ch) { + case '/': + state = sw_slash; + u -= 5; + for ( ;; ) { + if (u < rp->path.start) { + return NXT_ERROR; + } + if (*u == '/') { + u++; + break; + } + u--; + } + break; + + case '%': + saved_state = state; + state = sw_quoted; + continue; + case '?': + rp->args_start = p; + goto args; + case '#': + goto done; + case '+': + rp->plus_in_target = 1; + /* Fall through. */ + default: + state = sw_normal; + *u++ = ch; + continue; + } + + break; + + case sw_quoted: + rp->quoted_target = 1; + + if (ch >= '0' && ch <= '9') { + high = (u_char) (ch - '0'); + state = sw_quoted_second; + continue; + } + + c = (u_char) (ch | 0x20); + if (c >= 'a' && c <= 'f') { + high = (u_char) (c - 'a' + 10); + state = sw_quoted_second; + continue; + } + + return NXT_ERROR; + + case sw_quoted_second: + if (ch >= '0' && ch <= '9') { + ch = (u_char) ((high << 4) + ch - '0'); + + if (ch == '%' || ch == '#') { + state = sw_normal; + *u++ = ch; + continue; + + } else if (ch == '\0') { + return NXT_ERROR; + } + + state = saved_state; + goto again; + } + + c = (u_char) (ch | 0x20); + if (c >= 'a' && c <= 'f') { + ch = (u_char) ((high << 4) + c - 'a' + 10); + + if (ch == '?') { + state = sw_normal; + *u++ = ch; + continue; + + } else if (ch == '+') { + rp->plus_in_target = 1; + } + + state = saved_state; + goto again; + } + + return NXT_ERROR; + } + } + + if (state >= sw_quoted) { + return NXT_ERROR; + } + +args: + + for (/* void */; p < rp->target_end; p++) { + if (*p == '#') { + break; + } + } + + if (rp->args_start != NULL) { + rp->args.length = p - rp->args_start; + rp->args.start = rp->args_start; + } + +done: + + rp->path.length = u - rp->path.start; + + if (rp->exten_start) { + rp->exten.length = u - rp->exten_start; + rp->exten.start = rp->exten_start; + } + + return NXT_OK; +} diff --git a/src/nxt_http_parse.h b/src/nxt_http_parse.h index da8c4ce6..2baa36ce 100644 --- a/src/nxt_http_parse.h +++ b/src/nxt_http_parse.h @@ -32,6 +32,10 @@ struct nxt_http_request_parse_s { u_char *exten_start; u_char *args_start; + nxt_str_t path; + nxt_str_t args; + nxt_str_t exten; + nxt_http_ver_t version; union { @@ -45,6 +49,7 @@ struct nxt_http_request_parse_s { nxt_http_fields_hash_t *fields_hash; nxt_list_t *fields; + nxt_mp_t *mem_pool; /* target with "/." */ unsigned complex_target:1; @@ -80,6 +85,8 @@ struct nxt_http_field_s { nxt_inline nxt_int_t nxt_http_parse_request_init(nxt_http_request_parse_t *rp, nxt_mp_t *mp) { + rp->mem_pool = mp; + rp->fields = nxt_list_create(mp, 8, sizeof(nxt_http_field_t)); if (nxt_slow_path(rp->fields == NULL)){ return NXT_ERROR; diff --git a/src/nxt_php_sapi.c b/src/nxt_php_sapi.c index 28b6f406..b57d5c8f 100644 --- a/src/nxt_php_sapi.c +++ b/src/nxt_php_sapi.c @@ -244,28 +244,33 @@ nxt_php_read_request(nxt_task_t *task, nxt_app_rmsg_t *rmsg, h = &ctx->r.header; nxt_app_msg_read_str(task, rmsg, &h->method); + nxt_app_msg_read_str(task, rmsg, &h->target); nxt_app_msg_read_str(task, rmsg, &h->path); - h->path_no_query = h->path; nxt_app_msg_read_size(task, rmsg, &s); if (s > 0) { s--; - h->query.start = h->path.start + s; - h->query.length = h->path.length - s; + h->query.start = h->target.start + s; + h->query.length = h->target.length - s; - if (s > 0) { - h->path_no_query.length = s - 1; + if (h->path.start == NULL) { + h->path.start = h->target.start; + h->path.length = s - 1; } } + if (h->path.start == NULL) { + h->path = h->target; + } + if (nxt_php_path.start == NULL) { - if (h->path_no_query.start[h->path_no_query.length - 1] == '/') { + if (h->path.start[h->path.length - 1] == '/') { script_name = nxt_php_index_name; } else { script_name.length = 0; } - ctx->script.length = nxt_php_root.length + h->path_no_query.length + + ctx->script.length = nxt_php_root.length + h->path.length + script_name.length; ctx->script.start = nxt_mp_nget(ctx->mem_pool, ctx->script.length + 1); @@ -275,8 +280,8 @@ nxt_php_read_request(nxt_task_t *task, nxt_app_rmsg_t *rmsg, nxt_memcpy(p, nxt_php_root.start, nxt_php_root.length); p += nxt_php_root.length; - nxt_memcpy(p, h->path_no_query.start, h->path_no_query.length); - p += h->path_no_query.length; + nxt_memcpy(p, h->path.start, h->path.length); + p += h->path.length; if (script_name.length > 0) { nxt_memcpy(p, script_name.start, script_name.length); @@ -331,11 +336,16 @@ nxt_php_prepare_msg(nxt_task_t *task, nxt_app_request_t *r, /* TODO error handle, async mmap buffer assignment */ NXT_WRITE(&h->method); - NXT_WRITE(&h->path); + NXT_WRITE(&h->target); + if (h->path.start == h->target.start) { + NXT_WRITE(&eof); + } else { + NXT_WRITE(&h->path); + } if (h->query.start != NULL) { RC(nxt_app_msg_write_size(task, wmsg, - h->query.start - h->path.start + 1)); + h->query.start - h->target.start + 1)); } else { RC(nxt_app_msg_write_size(task, wmsg, 0)); } @@ -401,7 +411,7 @@ nxt_php_run(nxt_task_t *task, nxt_php_read_request(task, rmsg, &run_ctx); SG(server_context) = &run_ctx; - SG(request_info).request_uri = (char *) h->path.start; + SG(request_info).request_uri = (char *) h->target.start; SG(request_info).request_method = (char *) h->method.start; SG(request_info).proto_num = 1001; @@ -729,8 +739,8 @@ nxt_php_register_variables(zval *track_vars_array TSRMLS_DC) h->method.length, track_vars_array TSRMLS_CC); php_register_variable_safe((char *) "REQUEST_URI", - (char *) h->path.start, - h->path.length, track_vars_array TSRMLS_CC); + (char *) h->target.start, + h->target.length, track_vars_array TSRMLS_CC); if (h->query.start != NULL) { php_register_variable_safe((char *) "QUERY_STRING", diff --git a/src/nxt_python_wsgi.c b/src/nxt_python_wsgi.c index 70253b2c..9995e80b 100644 --- a/src/nxt_python_wsgi.c +++ b/src/nxt_python_wsgi.c @@ -420,11 +420,16 @@ nxt_python_prepare_msg(nxt_task_t *task, nxt_app_request_t *r, /* TODO error handle, async mmap buffer assignment */ NXT_WRITE(&h->method); - NXT_WRITE(&h->path); + NXT_WRITE(&h->target); + if (h->path.start == h->target.start) { + NXT_WRITE(&eof); + } else { + NXT_WRITE(&h->path); + } if (h->query.start != NULL) { RC(nxt_app_msg_write_size(task, wmsg, - h->query.start - h->path.start + 1)); + h->query.start - h->target.start + 1)); } else { RC(nxt_app_msg_write_size(task, wmsg, 0)); } @@ -763,7 +768,7 @@ nxt_python_get_environ(nxt_task_t *task, nxt_app_rmsg_t *rmsg) size_t s; PyObject *environ; nxt_int_t rc; - nxt_str_t n, v, path_no_query, query; + nxt_str_t n, v, target, path, query; environ = PyDict_Copy(nxt_py_environ_ptyp); @@ -787,22 +792,29 @@ nxt_python_get_environ(nxt_task_t *task, nxt_app_rmsg_t *rmsg) NXT_READ("REQUEST_METHOD"); NXT_READ("REQUEST_URI"); - path_no_query = v; // assume no query + target = v; + RC(nxt_app_msg_read_str(task, rmsg, &path)); + RC(nxt_app_msg_read_size(task, rmsg, &s)); // query length + 1 if (s > 0) { s--; - query.start = path_no_query.start + s; - query.length = path_no_query.length - s; + query.start = target.start + s; + query.length = target.length - s; RC(nxt_python_add_env(task, environ, "QUERY_STRING", &query)); - if (s > 0) { - path_no_query.length = s - 1; + if (path.start == NULL) { + path.start = target.start; + path.length = s - 1; } } - RC(nxt_python_add_env(task, environ, "PATH_INFO", &path_no_query)); + if (path.start == NULL) { + path = target; + } + + RC(nxt_python_add_env(task, environ, "PATH_INFO", &path)); NXT_READ("SERVER_PROTOCOL"); |