| /* | |
| * Copyright (C) Igor Sysoev | |
| */ | |
| #include <ngx_config.h> | |
| #include <ngx_core.h> | |
| #include <ngx_http.h> | |
| #include <ngx_http_proxy_handler.h> | |
| int ngx_http_proxy_parse_status_line(ngx_http_proxy_ctx_t *p) | |
| { | |
| u_char ch; | |
| u_char *pos; | |
| enum { | |
| sw_start = 0, | |
| sw_H, | |
| sw_HT, | |
| sw_HTT, | |
| sw_HTTP, | |
| sw_first_major_digit, | |
| sw_major_digit, | |
| sw_first_minor_digit, | |
| sw_minor_digit, | |
| sw_status, | |
| sw_space_after_status, | |
| sw_status_text, | |
| sw_almost_done, | |
| sw_done | |
| } state; | |
| state = p->parse_state; | |
| pos = p->header_in->pos; | |
| while (pos < p->header_in->last && state < sw_done) { | |
| ch = *pos++; | |
| switch (state) { | |
| /* "HTTP/" */ | |
| case sw_start: | |
| switch (ch) { | |
| case 'H': | |
| state = sw_H; | |
| break; | |
| default: | |
| return NGX_HTTP_PROXY_PARSE_NO_HEADER; | |
| } | |
| break; | |
| case sw_H: | |
| switch (ch) { | |
| case 'T': | |
| state = sw_HT; | |
| break; | |
| default: | |
| return NGX_HTTP_PROXY_PARSE_NO_HEADER; | |
| } | |
| break; | |
| case sw_HT: | |
| switch (ch) { | |
| case 'T': | |
| state = sw_HTT; | |
| break; | |
| default: | |
| return NGX_HTTP_PROXY_PARSE_NO_HEADER; | |
| } | |
| break; | |
| case sw_HTT: | |
| switch (ch) { | |
| case 'P': | |
| state = sw_HTTP; | |
| break; | |
| default: | |
| return NGX_HTTP_PROXY_PARSE_NO_HEADER; | |
| } | |
| break; | |
| case sw_HTTP: | |
| switch (ch) { | |
| case '/': | |
| state = sw_first_major_digit; | |
| break; | |
| default: | |
| return NGX_HTTP_PROXY_PARSE_NO_HEADER; | |
| } | |
| break; | |
| /* the first digit of major HTTP version */ | |
| case sw_first_major_digit: | |
| if (ch < '1' || ch > '9') { | |
| return NGX_HTTP_PROXY_PARSE_NO_HEADER; | |
| } | |
| state = sw_major_digit; | |
| break; | |
| /* the major HTTP version or dot */ | |
| case sw_major_digit: | |
| if (ch == '.') { | |
| state = sw_first_minor_digit; | |
| break; | |
| } | |
| if (ch < '0' || ch > '9') { | |
| return NGX_HTTP_PROXY_PARSE_NO_HEADER; | |
| } | |
| break; | |
| /* the first digit of minor HTTP version */ | |
| case sw_first_minor_digit: | |
| if (ch < '0' || ch > '9') { | |
| return NGX_HTTP_PROXY_PARSE_NO_HEADER; | |
| } | |
| state = sw_minor_digit; | |
| break; | |
| /* the minor HTTP version or the end of the request line */ | |
| case sw_minor_digit: | |
| if (ch == ' ') { | |
| state = sw_status; | |
| break; | |
| } | |
| if (ch < '0' || ch > '9') { | |
| return NGX_HTTP_PROXY_PARSE_NO_HEADER; | |
| } | |
| break; | |
| /* HTTP status code */ | |
| case sw_status: | |
| if (ch < '0' || ch > '9') { | |
| return NGX_HTTP_PROXY_PARSE_NO_HEADER; | |
| } | |
| p->status = p->status * 10 + ch - '0'; | |
| if (++p->status_count == 3) { | |
| state = sw_space_after_status; | |
| p->status_start = pos - 3; | |
| } | |
| break; | |
| /* space or end of line */ | |
| case sw_space_after_status: | |
| switch (ch) { | |
| case ' ': | |
| state = sw_status_text; | |
| break; | |
| case '.': /* IIS may send 403.1, 403.2, etc */ | |
| state = sw_status_text; | |
| break; | |
| case CR: | |
| state = sw_almost_done; | |
| break; | |
| case LF: | |
| state = sw_done; | |
| break; | |
| default: | |
| return NGX_HTTP_PROXY_PARSE_NO_HEADER; | |
| } | |
| break; | |
| /* any text until end of line */ | |
| case sw_status_text: | |
| switch (ch) { | |
| case CR: | |
| state = sw_almost_done; | |
| break; | |
| case LF: | |
| state = sw_done; | |
| break; | |
| } | |
| break; | |
| /* end of request line */ | |
| case sw_almost_done: | |
| p->status_end = pos - 2; | |
| switch (ch) { | |
| case LF: | |
| state = sw_done; | |
| break; | |
| default: | |
| return NGX_HTTP_PROXY_PARSE_NO_HEADER; | |
| } | |
| break; | |
| /* suppress warning */ | |
| case sw_done: | |
| break; | |
| } | |
| } | |
| p->header_in->pos = pos; | |
| if (state == sw_done) { | |
| if (p->status_end == NULL) { | |
| p->status_end = pos - 1; | |
| } | |
| p->parse_state = sw_start; | |
| return NGX_OK; | |
| } | |
| p->parse_state = state; | |
| return NGX_AGAIN; | |
| } |