0
|
1
|
|
2 /*
|
|
3 * Copyright (C) Igor Sysoev
|
|
4 */
|
|
5
|
|
6
|
|
7 #include <ngx_config.h>
|
|
8 #include <ngx_core.h>
|
|
9 #include <ngx_http.h>
|
|
10 #include <ngx_http_proxy_handler.h>
|
|
11
|
|
12
|
|
13 int ngx_http_proxy_parse_status_line(ngx_http_proxy_ctx_t *p)
|
|
14 {
|
|
15 u_char ch;
|
|
16 u_char *pos;
|
|
17 enum {
|
|
18 sw_start = 0,
|
|
19 sw_H,
|
|
20 sw_HT,
|
|
21 sw_HTT,
|
|
22 sw_HTTP,
|
|
23 sw_first_major_digit,
|
|
24 sw_major_digit,
|
|
25 sw_first_minor_digit,
|
|
26 sw_minor_digit,
|
|
27 sw_status,
|
|
28 sw_space_after_status,
|
|
29 sw_status_text,
|
|
30 sw_almost_done,
|
|
31 sw_done
|
|
32 } state;
|
|
33
|
|
34 state = p->parse_state;
|
|
35 pos = p->header_in->pos;
|
|
36
|
|
37 while (pos < p->header_in->last && state < sw_done) {
|
|
38 ch = *pos++;
|
|
39
|
|
40 switch (state) {
|
|
41
|
|
42 /* "HTTP/" */
|
|
43 case sw_start:
|
|
44 switch (ch) {
|
|
45 case 'H':
|
|
46 state = sw_H;
|
|
47 break;
|
|
48 default:
|
|
49 return NGX_HTTP_PROXY_PARSE_NO_HEADER;
|
|
50 }
|
|
51 break;
|
|
52
|
|
53 case sw_H:
|
|
54 switch (ch) {
|
|
55 case 'T':
|
|
56 state = sw_HT;
|
|
57 break;
|
|
58 default:
|
|
59 return NGX_HTTP_PROXY_PARSE_NO_HEADER;
|
|
60 }
|
|
61 break;
|
|
62
|
|
63 case sw_HT:
|
|
64 switch (ch) {
|
|
65 case 'T':
|
|
66 state = sw_HTT;
|
|
67 break;
|
|
68 default:
|
|
69 return NGX_HTTP_PROXY_PARSE_NO_HEADER;
|
|
70 }
|
|
71 break;
|
|
72
|
|
73 case sw_HTT:
|
|
74 switch (ch) {
|
|
75 case 'P':
|
|
76 state = sw_HTTP;
|
|
77 break;
|
|
78 default:
|
|
79 return NGX_HTTP_PROXY_PARSE_NO_HEADER;
|
|
80 }
|
|
81 break;
|
|
82
|
|
83 case sw_HTTP:
|
|
84 switch (ch) {
|
|
85 case '/':
|
|
86 state = sw_first_major_digit;
|
|
87 break;
|
|
88 default:
|
|
89 return NGX_HTTP_PROXY_PARSE_NO_HEADER;
|
|
90 }
|
|
91 break;
|
|
92
|
|
93 /* the first digit of major HTTP version */
|
|
94 case sw_first_major_digit:
|
|
95 if (ch < '1' || ch > '9') {
|
|
96 return NGX_HTTP_PROXY_PARSE_NO_HEADER;
|
|
97 }
|
|
98
|
|
99 state = sw_major_digit;
|
|
100 break;
|
|
101
|
|
102 /* the major HTTP version or dot */
|
|
103 case sw_major_digit:
|
|
104 if (ch == '.') {
|
|
105 state = sw_first_minor_digit;
|
|
106 break;
|
|
107 }
|
|
108
|
|
109 if (ch < '0' || ch > '9') {
|
|
110 return NGX_HTTP_PROXY_PARSE_NO_HEADER;
|
|
111 }
|
|
112
|
|
113 break;
|
|
114
|
|
115 /* the first digit of minor HTTP version */
|
|
116 case sw_first_minor_digit:
|
|
117 if (ch < '0' || ch > '9') {
|
|
118 return NGX_HTTP_PROXY_PARSE_NO_HEADER;
|
|
119 }
|
|
120
|
|
121 state = sw_minor_digit;
|
|
122 break;
|
|
123
|
|
124 /* the minor HTTP version or the end of the request line */
|
|
125 case sw_minor_digit:
|
|
126 if (ch == ' ') {
|
|
127 state = sw_status;
|
|
128 break;
|
|
129 }
|
|
130
|
|
131 if (ch < '0' || ch > '9') {
|
|
132 return NGX_HTTP_PROXY_PARSE_NO_HEADER;
|
|
133 }
|
|
134
|
|
135 break;
|
|
136
|
|
137 /* HTTP status code */
|
|
138 case sw_status:
|
|
139 if (ch < '0' || ch > '9') {
|
|
140 return NGX_HTTP_PROXY_PARSE_NO_HEADER;
|
|
141 }
|
|
142
|
|
143 p->status = p->status * 10 + ch - '0';
|
|
144
|
|
145 if (++p->status_count == 3) {
|
|
146 state = sw_space_after_status;
|
|
147 p->status_start = pos - 3;
|
|
148 }
|
|
149
|
|
150 break;
|
|
151
|
|
152 /* space or end of line */
|
|
153 case sw_space_after_status:
|
|
154 switch (ch) {
|
|
155 case ' ':
|
|
156 state = sw_status_text;
|
|
157 break;
|
|
158 case CR:
|
|
159 state = sw_almost_done;
|
|
160 break;
|
|
161 case LF:
|
|
162 state = sw_done;
|
|
163 break;
|
|
164 default:
|
|
165 return NGX_HTTP_PROXY_PARSE_NO_HEADER;
|
|
166 }
|
|
167 break;
|
|
168
|
|
169 /* any text until end of line */
|
|
170 case sw_status_text:
|
|
171 switch (ch) {
|
|
172 case CR:
|
|
173 state = sw_almost_done;
|
|
174
|
|
175 break;
|
|
176 case LF:
|
|
177 state = sw_done;
|
|
178 break;
|
|
179 }
|
|
180 break;
|
|
181
|
|
182 /* end of request line */
|
|
183 case sw_almost_done:
|
|
184 p->status_end = pos - 2;
|
|
185 switch (ch) {
|
|
186 case LF:
|
|
187 state = sw_done;
|
|
188 break;
|
|
189 default:
|
|
190 return NGX_HTTP_PROXY_PARSE_NO_HEADER;
|
|
191 }
|
|
192 break;
|
|
193
|
|
194 /* suppress warning */
|
|
195 case sw_done:
|
|
196 break;
|
|
197 }
|
|
198 }
|
|
199
|
|
200 p->header_in->pos = pos;
|
|
201
|
|
202 if (state == sw_done) {
|
|
203 if (p->status_end == NULL) {
|
|
204 p->status_end = pos - 1;
|
|
205 }
|
|
206
|
|
207 p->parse_state = sw_start;
|
|
208 return NGX_OK;
|
|
209 }
|
|
210
|
|
211 p->parse_state = state;
|
|
212 return NGX_AGAIN;
|
|
213 }
|