summaryrefslogtreecommitdiffstats
path: root/usr.sbin/nginx/src/http/ngx_http_parse.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr.sbin/nginx/src/http/ngx_http_parse.c')
-rw-r--r--usr.sbin/nginx/src/http/ngx_http_parse.c408
1 files changed, 408 insertions, 0 deletions
diff --git a/usr.sbin/nginx/src/http/ngx_http_parse.c b/usr.sbin/nginx/src/http/ngx_http_parse.c
index be750edd084..3c168aaf25b 100644
--- a/usr.sbin/nginx/src/http/ngx_http_parse.c
+++ b/usr.sbin/nginx/src/http/ngx_http_parse.c
@@ -1075,6 +1075,154 @@ header_done:
ngx_int_t
+ngx_http_parse_uri(ngx_http_request_t *r)
+{
+ u_char *p, ch;
+ enum {
+ sw_start = 0,
+ sw_after_slash_in_uri,
+ sw_check_uri,
+ sw_uri
+ } state;
+
+ state = sw_start;
+
+ for (p = r->uri_start; p != r->uri_end; p++) {
+
+ ch = *p;
+
+ switch (state) {
+
+ case sw_start:
+
+ if (ch != '/') {
+ return NGX_ERROR;
+ }
+
+ state = sw_after_slash_in_uri;
+ break;
+
+ /* check "/.", "//", "%", and "\" (Win32) in URI */
+ case sw_after_slash_in_uri:
+
+ if (usual[ch >> 5] & (1 << (ch & 0x1f))) {
+ state = sw_check_uri;
+ break;
+ }
+
+ switch (ch) {
+ case ' ':
+ r->space_in_uri = 1;
+ state = sw_check_uri;
+ break;
+ case '.':
+ r->complex_uri = 1;
+ state = sw_uri;
+ break;
+ case '%':
+ r->quoted_uri = 1;
+ state = sw_uri;
+ break;
+ case '/':
+ r->complex_uri = 1;
+ state = sw_uri;
+ break;
+#if (NGX_WIN32)
+ case '\\':
+ r->complex_uri = 1;
+ state = sw_uri;
+ break;
+#endif
+ case '?':
+ r->args_start = p + 1;
+ state = sw_uri;
+ break;
+ case '#':
+ r->complex_uri = 1;
+ state = sw_uri;
+ break;
+ case '+':
+ r->plus_in_uri = 1;
+ break;
+ default:
+ state = sw_check_uri;
+ break;
+ }
+ break;
+
+ /* check "/", "%" and "\" (Win32) in URI */
+ case sw_check_uri:
+
+ if (usual[ch >> 5] & (1 << (ch & 0x1f))) {
+ break;
+ }
+
+ switch (ch) {
+ case '/':
+#if (NGX_WIN32)
+ if (r->uri_ext == p) {
+ r->complex_uri = 1;
+ state = sw_uri;
+ break;
+ }
+#endif
+ r->uri_ext = NULL;
+ state = sw_after_slash_in_uri;
+ break;
+ case '.':
+ r->uri_ext = p + 1;
+ break;
+ case ' ':
+ r->space_in_uri = 1;
+ break;
+#if (NGX_WIN32)
+ case '\\':
+ r->complex_uri = 1;
+ state = sw_after_slash_in_uri;
+ break;
+#endif
+ case '%':
+ r->quoted_uri = 1;
+ state = sw_uri;
+ break;
+ case '?':
+ r->args_start = p + 1;
+ state = sw_uri;
+ break;
+ case '#':
+ r->complex_uri = 1;
+ state = sw_uri;
+ break;
+ case '+':
+ r->plus_in_uri = 1;
+ break;
+ }
+ break;
+
+ /* URI */
+ case sw_uri:
+
+ if (usual[ch >> 5] & (1 << (ch & 0x1f))) {
+ break;
+ }
+
+ switch (ch) {
+ case ' ':
+ r->space_in_uri = 1;
+ break;
+ case '#':
+ r->complex_uri = 1;
+ break;
+ }
+ break;
+ }
+ }
+
+ return NGX_OK;
+}
+
+
+ngx_int_t
ngx_http_parse_complex_uri(ngx_http_request_t *r, ngx_uint_t merge_slashes)
{
u_char c, ch, decoded, *p, *u;
@@ -1818,3 +1966,263 @@ ngx_http_split_args(ngx_http_request_t *r, ngx_str_t *uri, ngx_str_t *args)
args->len = 0;
}
}
+
+
+ngx_int_t
+ngx_http_parse_chunked(ngx_http_request_t *r, ngx_buf_t *b,
+ ngx_http_chunked_t *ctx)
+{
+ u_char *pos, ch, c;
+ ngx_int_t rc;
+ enum {
+ sw_chunk_start = 0,
+ sw_chunk_size,
+ sw_chunk_extension,
+ sw_chunk_extension_almost_done,
+ sw_chunk_data,
+ sw_after_data,
+ sw_after_data_almost_done,
+ sw_last_chunk_extension,
+ sw_last_chunk_extension_almost_done,
+ sw_trailer,
+ sw_trailer_almost_done,
+ sw_trailer_header,
+ sw_trailer_header_almost_done
+ } state;
+
+ state = ctx->state;
+
+ if (state == sw_chunk_data && ctx->size == 0) {
+ state = sw_after_data;
+ }
+
+ rc = NGX_AGAIN;
+
+ for (pos = b->pos; pos < b->last; pos++) {
+
+ ch = *pos;
+
+ ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+ "http chunked byte: %02Xd s:%d", ch, state);
+
+ switch (state) {
+
+ case sw_chunk_start:
+ if (ch >= '0' && ch <= '9') {
+ state = sw_chunk_size;
+ ctx->size = ch - '0';
+ break;
+ }
+
+ c = (u_char) (ch | 0x20);
+
+ if (c >= 'a' && c <= 'f') {
+ state = sw_chunk_size;
+ ctx->size = c - 'a' + 10;
+ break;
+ }
+
+ goto invalid;
+
+ case sw_chunk_size:
+ if (ch >= '0' && ch <= '9') {
+ ctx->size = ctx->size * 16 + (ch - '0');
+ break;
+ }
+
+ c = (u_char) (ch | 0x20);
+
+ if (c >= 'a' && c <= 'f') {
+ ctx->size = ctx->size * 16 + (c - 'a' + 10);
+ break;
+ }
+
+ if (ctx->size == 0) {
+
+ switch (ch) {
+ case CR:
+ state = sw_last_chunk_extension_almost_done;
+ break;
+ case LF:
+ state = sw_trailer;
+ break;
+ case ';':
+ case ' ':
+ case '\t':
+ state = sw_last_chunk_extension;
+ break;
+ default:
+ goto invalid;
+ }
+
+ break;
+ }
+
+ switch (ch) {
+ case CR:
+ state = sw_chunk_extension_almost_done;
+ break;
+ case LF:
+ state = sw_chunk_data;
+ break;
+ case ';':
+ case ' ':
+ case '\t':
+ state = sw_chunk_extension;
+ break;
+ default:
+ goto invalid;
+ }
+
+ break;
+
+ case sw_chunk_extension:
+ switch (ch) {
+ case CR:
+ state = sw_chunk_extension_almost_done;
+ break;
+ case LF:
+ state = sw_chunk_data;
+ }
+ break;
+
+ case sw_chunk_extension_almost_done:
+ if (ch == LF) {
+ state = sw_chunk_data;
+ break;
+ }
+ goto invalid;
+
+ case sw_chunk_data:
+ rc = NGX_OK;
+ goto data;
+
+ case sw_after_data:
+ switch (ch) {
+ case CR:
+ state = sw_after_data_almost_done;
+ break;
+ case LF:
+ state = sw_chunk_start;
+ }
+ break;
+
+ case sw_after_data_almost_done:
+ if (ch == LF) {
+ state = sw_chunk_start;
+ break;
+ }
+ goto invalid;
+
+ case sw_last_chunk_extension:
+ switch (ch) {
+ case CR:
+ state = sw_last_chunk_extension_almost_done;
+ break;
+ case LF:
+ state = sw_trailer;
+ }
+ break;
+
+ case sw_last_chunk_extension_almost_done:
+ if (ch == LF) {
+ state = sw_trailer;
+ break;
+ }
+ goto invalid;
+
+ case sw_trailer:
+ switch (ch) {
+ case CR:
+ state = sw_trailer_almost_done;
+ break;
+ case LF:
+ goto done;
+ default:
+ state = sw_trailer_header;
+ }
+ break;
+
+ case sw_trailer_almost_done:
+ if (ch == LF) {
+ goto done;
+ }
+ goto invalid;
+
+ case sw_trailer_header:
+ switch (ch) {
+ case CR:
+ state = sw_trailer_header_almost_done;
+ break;
+ case LF:
+ state = sw_trailer;
+ }
+ break;
+
+ case sw_trailer_header_almost_done:
+ if (ch == LF) {
+ state = sw_trailer;
+ break;
+ }
+ goto invalid;
+
+ }
+ }
+
+data:
+
+ ctx->state = state;
+ b->pos = pos;
+
+ switch (state) {
+
+ case sw_chunk_start:
+ ctx->length = 3 /* "0" LF LF */;
+ break;
+ case sw_chunk_size:
+ ctx->length = 2 /* LF LF */
+ + (ctx->size ? ctx->size + 4 /* LF "0" LF LF */ : 0);
+ break;
+ case sw_chunk_extension:
+ case sw_chunk_extension_almost_done:
+ ctx->length = 1 /* LF */ + ctx->size + 4 /* LF "0" LF LF */;
+ break;
+ case sw_chunk_data:
+ ctx->length = ctx->size + 4 /* LF "0" LF LF */;
+ break;
+ case sw_after_data:
+ case sw_after_data_almost_done:
+ ctx->length = 4 /* LF "0" LF LF */;
+ break;
+ case sw_last_chunk_extension:
+ case sw_last_chunk_extension_almost_done:
+ ctx->length = 2 /* LF LF */;
+ break;
+ case sw_trailer:
+ case sw_trailer_almost_done:
+ ctx->length = 1 /* LF */;
+ break;
+ case sw_trailer_header:
+ case sw_trailer_header_almost_done:
+ ctx->length = 2 /* LF LF */;
+ break;
+
+ }
+
+ if (ctx->size < 0 || ctx->length < 0) {
+ goto invalid;
+ }
+
+ return rc;
+
+done:
+
+ ctx->state = 0;
+ b->pos = pos + 1;
+
+ return NGX_DONE;
+
+invalid:
+
+ return NGX_ERROR;
+}