blob: 6eac9326a7fb3acb19b5f9bd2cccea3f3b9cae56 [file] [log] [blame]
Valentin Bartenev2686cb42013-03-20 10:36:57 +00001
2/*
3 * Copyright (C) Nginx, Inc.
4 * Copyright (C) Valentin V. Bartenev
5 */
6
7
8#include <ngx_config.h>
9#include <ngx_core.h>
10#include <ngx_http.h>
11#include <ngx_http_spdy_module.h>
12
13#include <zlib.h>
14
15
16#if (NGX_HAVE_LITTLE_ENDIAN && NGX_HAVE_NONALIGNED)
17
18#define ngx_str5cmp(m, c0, c1, c2, c3, c4) \
19 *(uint32_t *) m == (c3 << 24 | c2 << 16 | c1 << 8 | c0) \
20 && m[4] == c4
21
22#else
23
24#define ngx_str5cmp(m, c0, c1, c2, c3, c4) \
25 m[0] == c0 && m[1] == c1 && m[2] == c2 && m[3] == c3 && m[4] == c4
26
27#endif
28
29
30#if (NGX_HAVE_NONALIGNED)
31
32#define ngx_spdy_frame_parse_uint16(p) ntohs(*(uint16_t *) (p))
33#define ngx_spdy_frame_parse_uint32(p) ntohl(*(uint32_t *) (p))
34
35#else
36
37#define ngx_spdy_frame_parse_uint16(p) ((p)[0] << 8 | (p)[1])
38#define ngx_spdy_frame_parse_uint32(p) \
39 ((p)[0] << 24 | (p)[1] << 16 | (p)[2] << 8 | (p)[3])
40
41#endif
42
43#define ngx_spdy_frame_parse_sid(p) \
44 (ngx_spdy_frame_parse_uint32(p) & 0x7fffffff)
Valentin Bartenev449e8ee2014-01-31 19:17:26 +040045#define ngx_spdy_frame_parse_delta(p) \
46 (ngx_spdy_frame_parse_uint32(p) & 0x7fffffff)
Valentin Bartenev2686cb42013-03-20 10:36:57 +000047
48
49#define ngx_spdy_ctl_frame_check(h) \
Valentin Barteneva547f4a2014-04-07 19:27:56 +040050 (((h) & 0xffff0000) == ngx_spdy_ctl_frame_head(0))
Valentin Bartenev2686cb42013-03-20 10:36:57 +000051#define ngx_spdy_data_frame_check(h) \
52 (!((h) & (uint32_t) NGX_SPDY_CTL_BIT << 31))
53
Valentin Barteneva547f4a2014-04-07 19:27:56 +040054#define ngx_spdy_ctl_frame_type(h) ((h) & 0x0000ffff)
Valentin Bartenev2686cb42013-03-20 10:36:57 +000055#define ngx_spdy_frame_flags(p) ((p) >> 24)
56#define ngx_spdy_frame_length(p) ((p) & 0x00ffffff)
Valentin Bartenev449e8ee2014-01-31 19:17:26 +040057#define ngx_spdy_frame_id(p) ((p) & 0x00ffffff)
Valentin Bartenev2686cb42013-03-20 10:36:57 +000058
59
60#define NGX_SPDY_SKIP_HEADERS_BUFFER_SIZE 4096
61#define NGX_SPDY_CTL_FRAME_BUFFER_SIZE 16
62
63#define NGX_SPDY_PROTOCOL_ERROR 1
64#define NGX_SPDY_INVALID_STREAM 2
65#define NGX_SPDY_REFUSED_STREAM 3
66#define NGX_SPDY_UNSUPPORTED_VERSION 4
67#define NGX_SPDY_CANCEL 5
68#define NGX_SPDY_INTERNAL_ERROR 6
69#define NGX_SPDY_FLOW_CONTROL_ERROR 7
Valentin Bartenev449e8ee2014-01-31 19:17:26 +040070#define NGX_SPDY_STREAM_IN_USE 8
71#define NGX_SPDY_STREAM_ALREADY_CLOSED 9
72/* deprecated 10 */
73#define NGX_SPDY_FRAME_TOO_LARGE 11
Valentin Bartenev2686cb42013-03-20 10:36:57 +000074
75#define NGX_SPDY_SETTINGS_MAX_STREAMS 4
Valentin Bartenev449e8ee2014-01-31 19:17:26 +040076#define NGX_SPDY_SETTINGS_INIT_WINDOW 7
Valentin Bartenev2686cb42013-03-20 10:36:57 +000077
78#define NGX_SPDY_SETTINGS_FLAG_PERSIST 0x01
Valentin Bartenev449e8ee2014-01-31 19:17:26 +040079#define NGX_SPDY_SETTINGS_FLAG_PERSISTED 0x02
80
81#define NGX_SPDY_MAX_WINDOW NGX_MAX_INT32_VALUE
82#define NGX_SPDY_CONNECTION_WINDOW 65536
83#define NGX_SPDY_INIT_STREAM_WINDOW 65536
84#define NGX_SPDY_STREAM_WINDOW NGX_SPDY_MAX_WINDOW
Valentin Bartenev2686cb42013-03-20 10:36:57 +000085
86typedef struct {
87 ngx_uint_t hash;
88 u_char len;
89 u_char header[7];
90 ngx_int_t (*handler)(ngx_http_request_t *r);
91} ngx_http_spdy_request_header_t;
92
93
94static void ngx_http_spdy_read_handler(ngx_event_t *rev);
95static void ngx_http_spdy_write_handler(ngx_event_t *wev);
96static void ngx_http_spdy_handle_connection(ngx_http_spdy_connection_t *sc);
97
Roman Arutyunyan0b5f3292014-03-17 17:41:24 +040098static u_char *ngx_http_spdy_proxy_protocol(ngx_http_spdy_connection_t *sc,
99 u_char *pos, u_char *end);
Valentin Bartenev2686cb42013-03-20 10:36:57 +0000100static u_char *ngx_http_spdy_state_head(ngx_http_spdy_connection_t *sc,
101 u_char *pos, u_char *end);
102static u_char *ngx_http_spdy_state_syn_stream(ngx_http_spdy_connection_t *sc,
103 u_char *pos, u_char *end);
104static u_char *ngx_http_spdy_state_headers(ngx_http_spdy_connection_t *sc,
105 u_char *pos, u_char *end);
Valentin Bartenev2686cb42013-03-20 10:36:57 +0000106static u_char *ngx_http_spdy_state_headers_skip(ngx_http_spdy_connection_t *sc,
107 u_char *pos, u_char *end);
Valentin Bartenevef510792014-04-30 20:34:20 +0400108static u_char *ngx_http_spdy_state_headers_error(ngx_http_spdy_connection_t *sc,
109 u_char *pos, u_char *end);
Valentin Bartenev449e8ee2014-01-31 19:17:26 +0400110static u_char *ngx_http_spdy_state_window_update(ngx_http_spdy_connection_t *sc,
111 u_char *pos, u_char *end);
Valentin Bartenev2686cb42013-03-20 10:36:57 +0000112static u_char *ngx_http_spdy_state_data(ngx_http_spdy_connection_t *sc,
113 u_char *pos, u_char *end);
Valentin Bartenev449e8ee2014-01-31 19:17:26 +0400114static u_char *ngx_http_spdy_state_read_data(ngx_http_spdy_connection_t *sc,
115 u_char *pos, u_char *end);
Valentin Bartenev2686cb42013-03-20 10:36:57 +0000116static u_char *ngx_http_spdy_state_rst_stream(ngx_http_spdy_connection_t *sc,
117 u_char *pos, u_char *end);
118static u_char *ngx_http_spdy_state_ping(ngx_http_spdy_connection_t *sc,
119 u_char *pos, u_char *end);
120static u_char *ngx_http_spdy_state_skip(ngx_http_spdy_connection_t *sc,
121 u_char *pos, u_char *end);
122static u_char *ngx_http_spdy_state_settings(ngx_http_spdy_connection_t *sc,
123 u_char *pos, u_char *end);
Valentin Bartenev2686cb42013-03-20 10:36:57 +0000124static u_char *ngx_http_spdy_state_complete(ngx_http_spdy_connection_t *sc,
125 u_char *pos, u_char *end);
126static u_char *ngx_http_spdy_state_save(ngx_http_spdy_connection_t *sc,
127 u_char *pos, u_char *end, ngx_http_spdy_handler_pt handler);
Valentin Bartenevcf770dd2014-04-30 20:34:20 +0400128
129static u_char *ngx_http_spdy_state_inflate_error(
130 ngx_http_spdy_connection_t *sc, int rc);
Valentin Bartenev2686cb42013-03-20 10:36:57 +0000131static u_char *ngx_http_spdy_state_protocol_error(
132 ngx_http_spdy_connection_t *sc);
133static u_char *ngx_http_spdy_state_internal_error(
134 ngx_http_spdy_connection_t *sc);
135
Valentin Bartenev449e8ee2014-01-31 19:17:26 +0400136static ngx_int_t ngx_http_spdy_send_window_update(
137 ngx_http_spdy_connection_t *sc, ngx_uint_t sid, ngx_uint_t delta);
Valentin Bartenev2686cb42013-03-20 10:36:57 +0000138static ngx_int_t ngx_http_spdy_send_rst_stream(ngx_http_spdy_connection_t *sc,
139 ngx_uint_t sid, ngx_uint_t status, ngx_uint_t priority);
140static ngx_int_t ngx_http_spdy_send_settings(ngx_http_spdy_connection_t *sc);
141static ngx_int_t ngx_http_spdy_settings_frame_handler(
142 ngx_http_spdy_connection_t *sc, ngx_http_spdy_out_frame_t *frame);
143static ngx_http_spdy_out_frame_t *ngx_http_spdy_get_ctl_frame(
144 ngx_http_spdy_connection_t *sc, size_t size, ngx_uint_t priority);
145static ngx_int_t ngx_http_spdy_ctl_frame_handler(
146 ngx_http_spdy_connection_t *sc, ngx_http_spdy_out_frame_t *frame);
147
148static ngx_http_spdy_stream_t *ngx_http_spdy_create_stream(
149 ngx_http_spdy_connection_t *sc, ngx_uint_t id, ngx_uint_t priority);
150static ngx_http_spdy_stream_t *ngx_http_spdy_get_stream_by_id(
151 ngx_http_spdy_connection_t *sc, ngx_uint_t sid);
152#define ngx_http_spdy_streams_index_size(sscf) (sscf->streams_index_mask + 1)
153#define ngx_http_spdy_stream_index(sscf, sid) \
154 ((sid >> 1) & sscf->streams_index_mask)
155
156static ngx_int_t ngx_http_spdy_parse_header(ngx_http_request_t *r);
157static ngx_int_t ngx_http_spdy_alloc_large_header_buffer(ngx_http_request_t *r);
158
159static ngx_int_t ngx_http_spdy_handle_request_header(ngx_http_request_t *r);
160static ngx_int_t ngx_http_spdy_parse_method(ngx_http_request_t *r);
161static ngx_int_t ngx_http_spdy_parse_scheme(ngx_http_request_t *r);
Valentin Bartenev449e8ee2014-01-31 19:17:26 +0400162static ngx_int_t ngx_http_spdy_parse_host(ngx_http_request_t *r);
163static ngx_int_t ngx_http_spdy_parse_path(ngx_http_request_t *r);
Valentin Bartenev2686cb42013-03-20 10:36:57 +0000164static ngx_int_t ngx_http_spdy_parse_version(ngx_http_request_t *r);
165
166static ngx_int_t ngx_http_spdy_construct_request_line(ngx_http_request_t *r);
167static void ngx_http_spdy_run_request(ngx_http_request_t *r);
168static ngx_int_t ngx_http_spdy_init_request_body(ngx_http_request_t *r);
169
Valentin Bartenev449e8ee2014-01-31 19:17:26 +0400170static ngx_int_t ngx_http_spdy_terminate_stream(ngx_http_spdy_connection_t *sc,
171 ngx_http_spdy_stream_t *stream, ngx_uint_t status);
172
Valentin Bartenev92b82c82013-10-01 00:04:00 +0400173static void ngx_http_spdy_close_stream_handler(ngx_event_t *ev);
174
Valentin Bartenev2686cb42013-03-20 10:36:57 +0000175static void ngx_http_spdy_handle_connection_handler(ngx_event_t *rev);
176static void ngx_http_spdy_keepalive_handler(ngx_event_t *rev);
177static void ngx_http_spdy_finalize_connection(ngx_http_spdy_connection_t *sc,
178 ngx_int_t rc);
179
Valentin Bartenev449e8ee2014-01-31 19:17:26 +0400180static ngx_int_t ngx_http_spdy_adjust_windows(ngx_http_spdy_connection_t *sc,
181 ssize_t delta);
182
Valentin Bartenev2686cb42013-03-20 10:36:57 +0000183static void ngx_http_spdy_pool_cleanup(void *data);
184
185static void *ngx_http_spdy_zalloc(void *opaque, u_int items, u_int size);
186static void ngx_http_spdy_zfree(void *opaque, void *address);
187
188
Valentin Bartenev449e8ee2014-01-31 19:17:26 +0400189static const u_char ngx_http_spdy_dict[] = {
190 0x00, 0x00, 0x00, 0x07, 0x6f, 0x70, 0x74, 0x69, /* - - - - o p t i */
191 0x6f, 0x6e, 0x73, 0x00, 0x00, 0x00, 0x04, 0x68, /* o n s - - - - h */
192 0x65, 0x61, 0x64, 0x00, 0x00, 0x00, 0x04, 0x70, /* e a d - - - - p */
193 0x6f, 0x73, 0x74, 0x00, 0x00, 0x00, 0x03, 0x70, /* o s t - - - - p */
194 0x75, 0x74, 0x00, 0x00, 0x00, 0x06, 0x64, 0x65, /* u t - - - - d e */
195 0x6c, 0x65, 0x74, 0x65, 0x00, 0x00, 0x00, 0x05, /* l e t e - - - - */
196 0x74, 0x72, 0x61, 0x63, 0x65, 0x00, 0x00, 0x00, /* t r a c e - - - */
197 0x06, 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x00, /* - a c c e p t - */
198 0x00, 0x00, 0x0e, 0x61, 0x63, 0x63, 0x65, 0x70, /* - - - a c c e p */
199 0x74, 0x2d, 0x63, 0x68, 0x61, 0x72, 0x73, 0x65, /* t - c h a r s e */
200 0x74, 0x00, 0x00, 0x00, 0x0f, 0x61, 0x63, 0x63, /* t - - - - a c c */
201 0x65, 0x70, 0x74, 0x2d, 0x65, 0x6e, 0x63, 0x6f, /* e p t - e n c o */
202 0x64, 0x69, 0x6e, 0x67, 0x00, 0x00, 0x00, 0x0f, /* d i n g - - - - */
203 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x2d, 0x6c, /* a c c e p t - l */
204 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x00, /* a n g u a g e - */
205 0x00, 0x00, 0x0d, 0x61, 0x63, 0x63, 0x65, 0x70, /* - - - a c c e p */
206 0x74, 0x2d, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x73, /* t - r a n g e s */
207 0x00, 0x00, 0x00, 0x03, 0x61, 0x67, 0x65, 0x00, /* - - - - a g e - */
208 0x00, 0x00, 0x05, 0x61, 0x6c, 0x6c, 0x6f, 0x77, /* - - - a l l o w */
209 0x00, 0x00, 0x00, 0x0d, 0x61, 0x75, 0x74, 0x68, /* - - - - a u t h */
210 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, /* o r i z a t i o */
211 0x6e, 0x00, 0x00, 0x00, 0x0d, 0x63, 0x61, 0x63, /* n - - - - c a c */
212 0x68, 0x65, 0x2d, 0x63, 0x6f, 0x6e, 0x74, 0x72, /* h e - c o n t r */
213 0x6f, 0x6c, 0x00, 0x00, 0x00, 0x0a, 0x63, 0x6f, /* o l - - - - c o */
214 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, /* n n e c t i o n */
215 0x00, 0x00, 0x00, 0x0c, 0x63, 0x6f, 0x6e, 0x74, /* - - - - c o n t */
216 0x65, 0x6e, 0x74, 0x2d, 0x62, 0x61, 0x73, 0x65, /* e n t - b a s e */
217 0x00, 0x00, 0x00, 0x10, 0x63, 0x6f, 0x6e, 0x74, /* - - - - c o n t */
218 0x65, 0x6e, 0x74, 0x2d, 0x65, 0x6e, 0x63, 0x6f, /* e n t - e n c o */
219 0x64, 0x69, 0x6e, 0x67, 0x00, 0x00, 0x00, 0x10, /* d i n g - - - - */
220 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, /* c o n t e n t - */
221 0x6c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, /* l a n g u a g e */
222 0x00, 0x00, 0x00, 0x0e, 0x63, 0x6f, 0x6e, 0x74, /* - - - - c o n t */
223 0x65, 0x6e, 0x74, 0x2d, 0x6c, 0x65, 0x6e, 0x67, /* e n t - l e n g */
224 0x74, 0x68, 0x00, 0x00, 0x00, 0x10, 0x63, 0x6f, /* t h - - - - c o */
225 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x6c, 0x6f, /* n t e n t - l o */
226 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x00, 0x00, /* c a t i o n - - */
227 0x00, 0x0b, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, /* - - c o n t e n */
228 0x74, 0x2d, 0x6d, 0x64, 0x35, 0x00, 0x00, 0x00, /* t - m d 5 - - - */
229 0x0d, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, /* - c o n t e n t */
230 0x2d, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x00, 0x00, /* - r a n g e - - */
231 0x00, 0x0c, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, /* - - c o n t e n */
232 0x74, 0x2d, 0x74, 0x79, 0x70, 0x65, 0x00, 0x00, /* t - t y p e - - */
233 0x00, 0x04, 0x64, 0x61, 0x74, 0x65, 0x00, 0x00, /* - - d a t e - - */
234 0x00, 0x04, 0x65, 0x74, 0x61, 0x67, 0x00, 0x00, /* - - e t a g - - */
235 0x00, 0x06, 0x65, 0x78, 0x70, 0x65, 0x63, 0x74, /* - - e x p e c t */
236 0x00, 0x00, 0x00, 0x07, 0x65, 0x78, 0x70, 0x69, /* - - - - e x p i */
237 0x72, 0x65, 0x73, 0x00, 0x00, 0x00, 0x04, 0x66, /* r e s - - - - f */
238 0x72, 0x6f, 0x6d, 0x00, 0x00, 0x00, 0x04, 0x68, /* r o m - - - - h */
239 0x6f, 0x73, 0x74, 0x00, 0x00, 0x00, 0x08, 0x69, /* o s t - - - - i */
240 0x66, 0x2d, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x00, /* f - m a t c h - */
241 0x00, 0x00, 0x11, 0x69, 0x66, 0x2d, 0x6d, 0x6f, /* - - - i f - m o */
242 0x64, 0x69, 0x66, 0x69, 0x65, 0x64, 0x2d, 0x73, /* d i f i e d - s */
243 0x69, 0x6e, 0x63, 0x65, 0x00, 0x00, 0x00, 0x0d, /* i n c e - - - - */
244 0x69, 0x66, 0x2d, 0x6e, 0x6f, 0x6e, 0x65, 0x2d, /* i f - n o n e - */
245 0x6d, 0x61, 0x74, 0x63, 0x68, 0x00, 0x00, 0x00, /* m a t c h - - - */
246 0x08, 0x69, 0x66, 0x2d, 0x72, 0x61, 0x6e, 0x67, /* - i f - r a n g */
247 0x65, 0x00, 0x00, 0x00, 0x13, 0x69, 0x66, 0x2d, /* e - - - - i f - */
248 0x75, 0x6e, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x69, /* u n m o d i f i */
249 0x65, 0x64, 0x2d, 0x73, 0x69, 0x6e, 0x63, 0x65, /* e d - s i n c e */
250 0x00, 0x00, 0x00, 0x0d, 0x6c, 0x61, 0x73, 0x74, /* - - - - l a s t */
251 0x2d, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x69, 0x65, /* - m o d i f i e */
252 0x64, 0x00, 0x00, 0x00, 0x08, 0x6c, 0x6f, 0x63, /* d - - - - l o c */
253 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x00, 0x00, 0x00, /* a t i o n - - - */
254 0x0c, 0x6d, 0x61, 0x78, 0x2d, 0x66, 0x6f, 0x72, /* - m a x - f o r */
255 0x77, 0x61, 0x72, 0x64, 0x73, 0x00, 0x00, 0x00, /* w a r d s - - - */
256 0x06, 0x70, 0x72, 0x61, 0x67, 0x6d, 0x61, 0x00, /* - p r a g m a - */
257 0x00, 0x00, 0x12, 0x70, 0x72, 0x6f, 0x78, 0x79, /* - - - p r o x y */
258 0x2d, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, /* - a u t h e n t */
259 0x69, 0x63, 0x61, 0x74, 0x65, 0x00, 0x00, 0x00, /* i c a t e - - - */
260 0x13, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2d, 0x61, /* - p r o x y - a */
261 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, /* u t h o r i z a */
262 0x74, 0x69, 0x6f, 0x6e, 0x00, 0x00, 0x00, 0x05, /* t i o n - - - - */
263 0x72, 0x61, 0x6e, 0x67, 0x65, 0x00, 0x00, 0x00, /* r a n g e - - - */
264 0x07, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x72, /* - r e f e r e r */
265 0x00, 0x00, 0x00, 0x0b, 0x72, 0x65, 0x74, 0x72, /* - - - - r e t r */
266 0x79, 0x2d, 0x61, 0x66, 0x74, 0x65, 0x72, 0x00, /* y - a f t e r - */
267 0x00, 0x00, 0x06, 0x73, 0x65, 0x72, 0x76, 0x65, /* - - - s e r v e */
268 0x72, 0x00, 0x00, 0x00, 0x02, 0x74, 0x65, 0x00, /* r - - - - t e - */
269 0x00, 0x00, 0x07, 0x74, 0x72, 0x61, 0x69, 0x6c, /* - - - t r a i l */
270 0x65, 0x72, 0x00, 0x00, 0x00, 0x11, 0x74, 0x72, /* e r - - - - t r */
271 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x2d, 0x65, /* a n s f e r - e */
272 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x00, /* n c o d i n g - */
273 0x00, 0x00, 0x07, 0x75, 0x70, 0x67, 0x72, 0x61, /* - - - u p g r a */
274 0x64, 0x65, 0x00, 0x00, 0x00, 0x0a, 0x75, 0x73, /* d e - - - - u s */
275 0x65, 0x72, 0x2d, 0x61, 0x67, 0x65, 0x6e, 0x74, /* e r - a g e n t */
276 0x00, 0x00, 0x00, 0x04, 0x76, 0x61, 0x72, 0x79, /* - - - - v a r y */
277 0x00, 0x00, 0x00, 0x03, 0x76, 0x69, 0x61, 0x00, /* - - - - v i a - */
278 0x00, 0x00, 0x07, 0x77, 0x61, 0x72, 0x6e, 0x69, /* - - - w a r n i */
279 0x6e, 0x67, 0x00, 0x00, 0x00, 0x10, 0x77, 0x77, /* n g - - - - w w */
280 0x77, 0x2d, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, /* w - a u t h e n */
281 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x00, 0x00, /* t i c a t e - - */
282 0x00, 0x06, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, /* - - m e t h o d */
283 0x00, 0x00, 0x00, 0x03, 0x67, 0x65, 0x74, 0x00, /* - - - - g e t - */
284 0x00, 0x00, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, /* - - - s t a t u */
285 0x73, 0x00, 0x00, 0x00, 0x06, 0x32, 0x30, 0x30, /* s - - - - 2 0 0 */
286 0x20, 0x4f, 0x4b, 0x00, 0x00, 0x00, 0x07, 0x76, /* - O K - - - - v */
287 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x00, 0x00, /* e r s i o n - - */
288 0x00, 0x08, 0x48, 0x54, 0x54, 0x50, 0x2f, 0x31, /* - - H T T P - 1 */
289 0x2e, 0x31, 0x00, 0x00, 0x00, 0x03, 0x75, 0x72, /* - 1 - - - - u r */
290 0x6c, 0x00, 0x00, 0x00, 0x06, 0x70, 0x75, 0x62, /* l - - - - p u b */
291 0x6c, 0x69, 0x63, 0x00, 0x00, 0x00, 0x0a, 0x73, /* l i c - - - - s */
292 0x65, 0x74, 0x2d, 0x63, 0x6f, 0x6f, 0x6b, 0x69, /* e t - c o o k i */
293 0x65, 0x00, 0x00, 0x00, 0x0a, 0x6b, 0x65, 0x65, /* e - - - - k e e */
294 0x70, 0x2d, 0x61, 0x6c, 0x69, 0x76, 0x65, 0x00, /* p - a l i v e - */
295 0x00, 0x00, 0x06, 0x6f, 0x72, 0x69, 0x67, 0x69, /* - - - o r i g i */
296 0x6e, 0x31, 0x30, 0x30, 0x31, 0x30, 0x31, 0x32, /* n 1 0 0 1 0 1 2 */
297 0x30, 0x31, 0x32, 0x30, 0x32, 0x32, 0x30, 0x35, /* 0 1 2 0 2 2 0 5 */
298 0x32, 0x30, 0x36, 0x33, 0x30, 0x30, 0x33, 0x30, /* 2 0 6 3 0 0 3 0 */
299 0x32, 0x33, 0x30, 0x33, 0x33, 0x30, 0x34, 0x33, /* 2 3 0 3 3 0 4 3 */
300 0x30, 0x35, 0x33, 0x30, 0x36, 0x33, 0x30, 0x37, /* 0 5 3 0 6 3 0 7 */
301 0x34, 0x30, 0x32, 0x34, 0x30, 0x35, 0x34, 0x30, /* 4 0 2 4 0 5 4 0 */
302 0x36, 0x34, 0x30, 0x37, 0x34, 0x30, 0x38, 0x34, /* 6 4 0 7 4 0 8 4 */
303 0x30, 0x39, 0x34, 0x31, 0x30, 0x34, 0x31, 0x31, /* 0 9 4 1 0 4 1 1 */
304 0x34, 0x31, 0x32, 0x34, 0x31, 0x33, 0x34, 0x31, /* 4 1 2 4 1 3 4 1 */
305 0x34, 0x34, 0x31, 0x35, 0x34, 0x31, 0x36, 0x34, /* 4 4 1 5 4 1 6 4 */
306 0x31, 0x37, 0x35, 0x30, 0x32, 0x35, 0x30, 0x34, /* 1 7 5 0 2 5 0 4 */
307 0x35, 0x30, 0x35, 0x32, 0x30, 0x33, 0x20, 0x4e, /* 5 0 5 2 0 3 - N */
308 0x6f, 0x6e, 0x2d, 0x41, 0x75, 0x74, 0x68, 0x6f, /* o n - A u t h o */
309 0x72, 0x69, 0x74, 0x61, 0x74, 0x69, 0x76, 0x65, /* r i t a t i v e */
310 0x20, 0x49, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x61, /* - I n f o r m a */
311 0x74, 0x69, 0x6f, 0x6e, 0x32, 0x30, 0x34, 0x20, /* t i o n 2 0 4 - */
312 0x4e, 0x6f, 0x20, 0x43, 0x6f, 0x6e, 0x74, 0x65, /* N o - C o n t e */
313 0x6e, 0x74, 0x33, 0x30, 0x31, 0x20, 0x4d, 0x6f, /* n t 3 0 1 - M o */
314 0x76, 0x65, 0x64, 0x20, 0x50, 0x65, 0x72, 0x6d, /* v e d - P e r m */
315 0x61, 0x6e, 0x65, 0x6e, 0x74, 0x6c, 0x79, 0x34, /* a n e n t l y 4 */
316 0x30, 0x30, 0x20, 0x42, 0x61, 0x64, 0x20, 0x52, /* 0 0 - B a d - R */
317 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x34, 0x30, /* e q u e s t 4 0 */
318 0x31, 0x20, 0x55, 0x6e, 0x61, 0x75, 0x74, 0x68, /* 1 - U n a u t h */
319 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64, 0x34, 0x30, /* o r i z e d 4 0 */
320 0x33, 0x20, 0x46, 0x6f, 0x72, 0x62, 0x69, 0x64, /* 3 - F o r b i d */
321 0x64, 0x65, 0x6e, 0x34, 0x30, 0x34, 0x20, 0x4e, /* d e n 4 0 4 - N */
322 0x6f, 0x74, 0x20, 0x46, 0x6f, 0x75, 0x6e, 0x64, /* o t - F o u n d */
323 0x35, 0x30, 0x30, 0x20, 0x49, 0x6e, 0x74, 0x65, /* 5 0 0 - I n t e */
324 0x72, 0x6e, 0x61, 0x6c, 0x20, 0x53, 0x65, 0x72, /* r n a l - S e r */
325 0x76, 0x65, 0x72, 0x20, 0x45, 0x72, 0x72, 0x6f, /* v e r - E r r o */
326 0x72, 0x35, 0x30, 0x31, 0x20, 0x4e, 0x6f, 0x74, /* r 5 0 1 - N o t */
327 0x20, 0x49, 0x6d, 0x70, 0x6c, 0x65, 0x6d, 0x65, /* - I m p l e m e */
328 0x6e, 0x74, 0x65, 0x64, 0x35, 0x30, 0x33, 0x20, /* n t e d 5 0 3 - */
329 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x20, /* S e r v i c e - */
330 0x55, 0x6e, 0x61, 0x76, 0x61, 0x69, 0x6c, 0x61, /* U n a v a i l a */
331 0x62, 0x6c, 0x65, 0x4a, 0x61, 0x6e, 0x20, 0x46, /* b l e J a n - F */
332 0x65, 0x62, 0x20, 0x4d, 0x61, 0x72, 0x20, 0x41, /* e b - M a r - A */
333 0x70, 0x72, 0x20, 0x4d, 0x61, 0x79, 0x20, 0x4a, /* p r - M a y - J */
334 0x75, 0x6e, 0x20, 0x4a, 0x75, 0x6c, 0x20, 0x41, /* u n - J u l - A */
335 0x75, 0x67, 0x20, 0x53, 0x65, 0x70, 0x74, 0x20, /* u g - S e p t - */
336 0x4f, 0x63, 0x74, 0x20, 0x4e, 0x6f, 0x76, 0x20, /* O c t - N o v - */
337 0x44, 0x65, 0x63, 0x20, 0x30, 0x30, 0x3a, 0x30, /* D e c - 0 0 - 0 */
338 0x30, 0x3a, 0x30, 0x30, 0x20, 0x4d, 0x6f, 0x6e, /* 0 - 0 0 - M o n */
339 0x2c, 0x20, 0x54, 0x75, 0x65, 0x2c, 0x20, 0x57, /* - - T u e - - W */
340 0x65, 0x64, 0x2c, 0x20, 0x54, 0x68, 0x75, 0x2c, /* e d - - T h u - */
341 0x20, 0x46, 0x72, 0x69, 0x2c, 0x20, 0x53, 0x61, /* - F r i - - S a */
342 0x74, 0x2c, 0x20, 0x53, 0x75, 0x6e, 0x2c, 0x20, /* t - - S u n - - */
343 0x47, 0x4d, 0x54, 0x63, 0x68, 0x75, 0x6e, 0x6b, /* G M T c h u n k */
344 0x65, 0x64, 0x2c, 0x74, 0x65, 0x78, 0x74, 0x2f, /* e d - t e x t - */
345 0x68, 0x74, 0x6d, 0x6c, 0x2c, 0x69, 0x6d, 0x61, /* h t m l - i m a */
346 0x67, 0x65, 0x2f, 0x70, 0x6e, 0x67, 0x2c, 0x69, /* g e - p n g - i */
347 0x6d, 0x61, 0x67, 0x65, 0x2f, 0x6a, 0x70, 0x67, /* m a g e - j p g */
348 0x2c, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x2f, 0x67, /* - i m a g e - g */
349 0x69, 0x66, 0x2c, 0x61, 0x70, 0x70, 0x6c, 0x69, /* i f - a p p l i */
350 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, /* c a t i o n - x */
351 0x6d, 0x6c, 0x2c, 0x61, 0x70, 0x70, 0x6c, 0x69, /* m l - a p p l i */
352 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, /* c a t i o n - x */
353 0x68, 0x74, 0x6d, 0x6c, 0x2b, 0x78, 0x6d, 0x6c, /* h t m l - x m l */
354 0x2c, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x70, 0x6c, /* - t e x t - p l */
355 0x61, 0x69, 0x6e, 0x2c, 0x74, 0x65, 0x78, 0x74, /* a i n - t e x t */
356 0x2f, 0x6a, 0x61, 0x76, 0x61, 0x73, 0x63, 0x72, /* - j a v a s c r */
357 0x69, 0x70, 0x74, 0x2c, 0x70, 0x75, 0x62, 0x6c, /* i p t - p u b l */
358 0x69, 0x63, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, /* i c p r i v a t */
359 0x65, 0x6d, 0x61, 0x78, 0x2d, 0x61, 0x67, 0x65, /* e m a x - a g e */
360 0x3d, 0x67, 0x7a, 0x69, 0x70, 0x2c, 0x64, 0x65, /* - g z i p - d e */
361 0x66, 0x6c, 0x61, 0x74, 0x65, 0x2c, 0x73, 0x64, /* f l a t e - s d */
362 0x63, 0x68, 0x63, 0x68, 0x61, 0x72, 0x73, 0x65, /* c h c h a r s e */
363 0x74, 0x3d, 0x75, 0x74, 0x66, 0x2d, 0x38, 0x63, /* t - u t f - 8 c */
364 0x68, 0x61, 0x72, 0x73, 0x65, 0x74, 0x3d, 0x69, /* h a r s e t - i */
365 0x73, 0x6f, 0x2d, 0x38, 0x38, 0x35, 0x39, 0x2d, /* s o - 8 8 5 9 - */
366 0x31, 0x2c, 0x75, 0x74, 0x66, 0x2d, 0x2c, 0x2a, /* 1 - u t f - - - */
367 0x2c, 0x65, 0x6e, 0x71, 0x3d, 0x30, 0x2e /* - e n q - 0 - */
368};
Valentin Bartenev2686cb42013-03-20 10:36:57 +0000369
370
371static ngx_http_spdy_request_header_t ngx_http_spdy_request_headers[] = {
372 { 0, 6, "method", ngx_http_spdy_parse_method },
373 { 0, 6, "scheme", ngx_http_spdy_parse_scheme },
Valentin Bartenev449e8ee2014-01-31 19:17:26 +0400374 { 0, 4, "host", ngx_http_spdy_parse_host },
375 { 0, 4, "path", ngx_http_spdy_parse_path },
Valentin Bartenev2686cb42013-03-20 10:36:57 +0000376 { 0, 7, "version", ngx_http_spdy_parse_version },
377};
378
379#define NGX_SPDY_REQUEST_HEADERS \
380 (sizeof(ngx_http_spdy_request_headers) \
381 / sizeof(ngx_http_spdy_request_header_t))
382
383
384void
385ngx_http_spdy_init(ngx_event_t *rev)
386{
387 int rc;
388 ngx_connection_t *c;
389 ngx_pool_cleanup_t *cln;
390 ngx_http_connection_t *hc;
391 ngx_http_spdy_srv_conf_t *sscf;
392 ngx_http_spdy_main_conf_t *smcf;
393 ngx_http_spdy_connection_t *sc;
394
395 c = rev->data;
396 hc = c->data;
397
Valentin Bartenevd04a7142014-04-30 20:34:20 +0400398 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "init spdy request");
Valentin Bartenev2686cb42013-03-20 10:36:57 +0000399
400 c->log->action = "processing SPDY";
401
402 smcf = ngx_http_get_module_main_conf(hc->conf_ctx, ngx_http_spdy_module);
403
404 if (smcf->recv_buffer == NULL) {
405 smcf->recv_buffer = ngx_palloc(ngx_cycle->pool, smcf->recv_buffer_size);
406 if (smcf->recv_buffer == NULL) {
407 ngx_http_close_connection(c);
408 return;
409 }
410 }
411
412 sc = ngx_pcalloc(c->pool, sizeof(ngx_http_spdy_connection_t));
413 if (sc == NULL) {
414 ngx_http_close_connection(c);
415 return;
416 }
417
418 sc->connection = c;
419 sc->http_connection = hc;
420
Valentin Bartenev449e8ee2014-01-31 19:17:26 +0400421 sc->send_window = NGX_SPDY_CONNECTION_WINDOW;
422 sc->recv_window = NGX_SPDY_CONNECTION_WINDOW;
423
424 sc->init_window = NGX_SPDY_INIT_STREAM_WINDOW;
425
Valentin Bartenevd51d1682014-05-15 19:22:06 +0400426 sc->handler = hc->proxy_protocol ? ngx_http_spdy_proxy_protocol
427 : ngx_http_spdy_state_head;
Roman Arutyunyan0b5f3292014-03-17 17:41:24 +0400428
Valentin Bartenev2686cb42013-03-20 10:36:57 +0000429 sc->zstream_in.zalloc = ngx_http_spdy_zalloc;
430 sc->zstream_in.zfree = ngx_http_spdy_zfree;
431 sc->zstream_in.opaque = sc;
432
433 rc = inflateInit(&sc->zstream_in);
434 if (rc != Z_OK) {
435 ngx_log_error(NGX_LOG_ALERT, c->log, 0,
436 "inflateInit() failed: %d", rc);
437 ngx_http_close_connection(c);
438 return;
439 }
440
441 sc->zstream_out.zalloc = ngx_http_spdy_zalloc;
442 sc->zstream_out.zfree = ngx_http_spdy_zfree;
443 sc->zstream_out.opaque = sc;
444
445 sscf = ngx_http_get_module_srv_conf(hc->conf_ctx, ngx_http_spdy_module);
446
447 rc = deflateInit2(&sc->zstream_out, (int) sscf->headers_comp,
448 Z_DEFLATED, 11, 4, Z_DEFAULT_STRATEGY);
449
450 if (rc != Z_OK) {
451 ngx_log_error(NGX_LOG_ALERT, c->log, 0,
452 "deflateInit2() failed: %d", rc);
453 ngx_http_close_connection(c);
454 return;
455 }
456
457 rc = deflateSetDictionary(&sc->zstream_out, ngx_http_spdy_dict,
458 sizeof(ngx_http_spdy_dict));
459 if (rc != Z_OK) {
460 ngx_log_error(NGX_LOG_ALERT, c->log, 0,
461 "deflateSetDictionary() failed: %d", rc);
462 ngx_http_close_connection(c);
463 return;
464 }
465
466 sc->pool = ngx_create_pool(sscf->pool_size, sc->connection->log);
467 if (sc->pool == NULL) {
468 ngx_http_close_connection(c);
469 return;
470 }
471
472 cln = ngx_pool_cleanup_add(c->pool, sizeof(ngx_pool_cleanup_file_t));
473 if (cln == NULL) {
474 ngx_http_close_connection(c);
475 return;
476 }
477
478 cln->handler = ngx_http_spdy_pool_cleanup;
479 cln->data = sc;
480
481 sc->streams_index = ngx_pcalloc(sc->pool,
482 ngx_http_spdy_streams_index_size(sscf)
483 * sizeof(ngx_http_spdy_stream_t *));
484 if (sc->streams_index == NULL) {
485 ngx_http_close_connection(c);
486 return;
487 }
488
Valentin Bartenevd055f742014-01-22 04:58:19 +0400489 if (ngx_http_spdy_send_settings(sc) == NGX_ERROR) {
490 ngx_http_close_connection(c);
491 return;
492 }
493
Valentin Bartenev449e8ee2014-01-31 19:17:26 +0400494 if (ngx_http_spdy_send_window_update(sc, 0, NGX_SPDY_MAX_WINDOW
495 - sc->recv_window)
496 == NGX_ERROR)
497 {
498 ngx_http_close_connection(c);
499 return;
500 }
501
502 sc->recv_window = NGX_SPDY_MAX_WINDOW;
503
504 ngx_queue_init(&sc->waiting);
Valentin Bartenevabcbe542014-01-20 20:56:49 +0400505 ngx_queue_init(&sc->posted);
506
Valentin Bartenev2686cb42013-03-20 10:36:57 +0000507 c->data = sc;
508
509 rev->handler = ngx_http_spdy_read_handler;
510 c->write->handler = ngx_http_spdy_write_handler;
511
512 ngx_http_spdy_read_handler(rev);
513}
514
515
516static void
517ngx_http_spdy_read_handler(ngx_event_t *rev)
518{
519 u_char *p, *end;
520 size_t available;
521 ssize_t n;
522 ngx_connection_t *c;
523 ngx_http_spdy_main_conf_t *smcf;
524 ngx_http_spdy_connection_t *sc;
525
526 c = rev->data;
527 sc = c->data;
528
529 if (rev->timedout) {
530 ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT, "client timed out");
531 ngx_http_spdy_finalize_connection(sc, NGX_HTTP_REQUEST_TIME_OUT);
532 return;
533 }
534
535 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "spdy read handler");
536
537 sc->blocked = 1;
538
539 smcf = ngx_http_get_module_main_conf(sc->http_connection->conf_ctx,
540 ngx_http_spdy_module);
541
542 available = smcf->recv_buffer_size - 2 * NGX_SPDY_STATE_BUFFER_SIZE;
543
544 do {
545 p = smcf->recv_buffer;
546
547 ngx_memcpy(p, sc->buffer, NGX_SPDY_STATE_BUFFER_SIZE);
548 end = p + sc->buffer_used;
549
550 n = c->recv(c, end, available);
551
552 if (n == NGX_AGAIN) {
553 break;
554 }
555
Valentin Bartenev6ddb5782014-01-14 16:24:45 +0400556 if (n == 0 && (sc->incomplete || sc->processing)) {
Valentin Bartenev2686cb42013-03-20 10:36:57 +0000557 ngx_log_error(NGX_LOG_INFO, c->log, 0,
Valentin Bartenevd04a7142014-04-30 20:34:20 +0400558 "client prematurely closed connection");
Valentin Bartenev2686cb42013-03-20 10:36:57 +0000559 }
560
561 if (n == 0 || n == NGX_ERROR) {
562 ngx_http_spdy_finalize_connection(sc,
563 NGX_HTTP_CLIENT_CLOSED_REQUEST);
564 return;
565 }
566
567 end += n;
568
569 sc->buffer_used = 0;
Valentin Bartenev6ddb5782014-01-14 16:24:45 +0400570 sc->incomplete = 0;
Valentin Bartenev2686cb42013-03-20 10:36:57 +0000571
572 do {
573 p = sc->handler(sc, p, end);
574
575 if (p == NULL) {
576 return;
577 }
578
579 } while (p != end);
580
581 } while (rev->ready);
582
583 if (ngx_handle_read_event(rev, 0) != NGX_OK) {
584 ngx_http_spdy_finalize_connection(sc, NGX_HTTP_INTERNAL_SERVER_ERROR);
585 return;
586 }
587
Valentin Bartenev1ef55532014-01-15 17:16:38 +0400588 if (sc->last_out && ngx_http_spdy_send_output_queue(sc) == NGX_ERROR) {
589 ngx_http_spdy_finalize_connection(sc, NGX_HTTP_CLIENT_CLOSED_REQUEST);
590 return;
591 }
592
Valentin Bartenev2686cb42013-03-20 10:36:57 +0000593 sc->blocked = 0;
594
595 if (sc->processing) {
596 if (rev->timer_set) {
597 ngx_del_timer(rev);
598 }
599 return;
600 }
601
602 ngx_http_spdy_handle_connection(sc);
603}
604
605
606static void
607ngx_http_spdy_write_handler(ngx_event_t *wev)
608{
609 ngx_int_t rc;
Valentin Bartenevabcbe542014-01-20 20:56:49 +0400610 ngx_queue_t *q;
Valentin Bartenev2686cb42013-03-20 10:36:57 +0000611 ngx_connection_t *c;
Valentin Bartenevabcbe542014-01-20 20:56:49 +0400612 ngx_http_spdy_stream_t *stream;
Valentin Bartenev2686cb42013-03-20 10:36:57 +0000613 ngx_http_spdy_connection_t *sc;
614
615 c = wev->data;
616 sc = c->data;
617
618 if (wev->timedout) {
619 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0,
620 "spdy write event timed out");
621 ngx_http_spdy_finalize_connection(sc, NGX_HTTP_CLIENT_CLOSED_REQUEST);
622 return;
623 }
624
625 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "spdy write handler");
626
Valentin Bartenev75dad742013-12-26 17:03:16 +0400627 sc->blocked = 1;
Valentin Bartenev2686cb42013-03-20 10:36:57 +0000628
629 rc = ngx_http_spdy_send_output_queue(sc);
630
631 if (rc == NGX_ERROR) {
632 ngx_http_spdy_finalize_connection(sc, NGX_HTTP_CLIENT_CLOSED_REQUEST);
633 return;
634 }
635
Valentin Bartenevabcbe542014-01-20 20:56:49 +0400636 while (!ngx_queue_empty(&sc->posted)) {
637 q = ngx_queue_head(&sc->posted);
Valentin Bartenev2686cb42013-03-20 10:36:57 +0000638
Valentin Bartenevabcbe542014-01-20 20:56:49 +0400639 ngx_queue_remove(q);
Valentin Bartenev2686cb42013-03-20 10:36:57 +0000640
Valentin Bartenevabcbe542014-01-20 20:56:49 +0400641 stream = ngx_queue_data(q, ngx_http_spdy_stream_t, queue);
Valentin Bartenev2686cb42013-03-20 10:36:57 +0000642
Valentin Bartenev2686cb42013-03-20 10:36:57 +0000643 stream->handled = 0;
644
645 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0,
Valentin Bartenevd04a7142014-04-30 20:34:20 +0400646 "run spdy stream %ui", stream->id);
Valentin Bartenev2686cb42013-03-20 10:36:57 +0000647
648 wev = stream->request->connection->write;
649 wev->handler(wev);
650 }
651
652 sc->blocked = 0;
653
654 if (rc == NGX_AGAIN) {
655 return;
656 }
657
658 ngx_http_spdy_handle_connection(sc);
659}
660
661
662ngx_int_t
663ngx_http_spdy_send_output_queue(ngx_http_spdy_connection_t *sc)
664{
665 ngx_chain_t *cl;
666 ngx_event_t *wev;
667 ngx_connection_t *c;
668 ngx_http_core_loc_conf_t *clcf;
669 ngx_http_spdy_out_frame_t *out, *frame, *fn;
670
671 c = sc->connection;
672
673 if (c->error) {
674 return NGX_ERROR;
675 }
676
677 wev = c->write;
678
679 if (!wev->ready) {
680 return NGX_OK;
681 }
682
683 cl = NULL;
684 out = NULL;
685
686 for (frame = sc->last_out; frame; frame = fn) {
687 frame->last->next = cl;
688 cl = frame->first;
689
690 fn = frame->next;
691 frame->next = out;
692 out = frame;
693
694 ngx_log_debug5(NGX_LOG_DEBUG_HTTP, c->log, 0,
Valentin Bartenev3ddf9cc2014-01-22 04:58:19 +0400695 "spdy frame out: %p sid:%ui prio:%ui bl:%d len:%uz",
Valentin Bartenev2686cb42013-03-20 10:36:57 +0000696 out, out->stream ? out->stream->id : 0, out->priority,
Valentin Bartenev3ddf9cc2014-01-22 04:58:19 +0400697 out->blocked, out->length);
Valentin Bartenev2686cb42013-03-20 10:36:57 +0000698 }
699
700 cl = c->send_chain(c, cl, 0);
701
702 if (cl == NGX_CHAIN_ERROR) {
703 c->error = 1;
704
705 if (!sc->blocked) {
706 ngx_post_event(wev, &ngx_posted_events);
707 }
708
709 return NGX_ERROR;
710 }
711
712 clcf = ngx_http_get_module_loc_conf(sc->http_connection->conf_ctx,
713 ngx_http_core_module);
714
715 if (ngx_handle_write_event(wev, clcf->send_lowat) != NGX_OK) {
716 return NGX_ERROR; /* FIXME */
717 }
718
719 if (cl) {
720 ngx_add_timer(wev, clcf->send_timeout);
721
722 } else {
723 if (wev->timer_set) {
724 ngx_del_timer(wev);
725 }
726 }
727
Valentin Barteneve62156d2014-01-22 04:58:19 +0400728 for ( /* void */ ; out; out = fn) {
729 fn = out->next;
730
Valentin Bartenev2686cb42013-03-20 10:36:57 +0000731 if (out->handler(sc, out) != NGX_OK) {
732 out->blocked = 1;
733 out->priority = NGX_SPDY_HIGHEST_PRIORITY;
734 break;
735 }
736
737 ngx_log_debug4(NGX_LOG_DEBUG_HTTP, c->log, 0,
Valentin Bartenev3ddf9cc2014-01-22 04:58:19 +0400738 "spdy frame sent: %p sid:%ui bl:%d len:%uz",
Valentin Bartenev2686cb42013-03-20 10:36:57 +0000739 out, out->stream ? out->stream->id : 0,
Valentin Bartenev3ddf9cc2014-01-22 04:58:19 +0400740 out->blocked, out->length);
Valentin Bartenev2686cb42013-03-20 10:36:57 +0000741 }
742
743 frame = NULL;
744
745 for ( /* void */ ; out; out = fn) {
746 fn = out->next;
747 out->next = frame;
748 frame = out;
749 }
750
751 sc->last_out = frame;
752
753 return NGX_OK;
754}
755
756
757static void
758ngx_http_spdy_handle_connection(ngx_http_spdy_connection_t *sc)
759{
760 ngx_connection_t *c;
761 ngx_http_spdy_srv_conf_t *sscf;
762
763 if (sc->last_out || sc->processing) {
764 return;
765 }
766
767 c = sc->connection;
768
769 if (c->error) {
770 ngx_http_close_connection(c);
771 return;
772 }
773
774 if (c->buffered) {
775 return;
776 }
777
778 sscf = ngx_http_get_module_srv_conf(sc->http_connection->conf_ctx,
779 ngx_http_spdy_module);
Valentin Bartenev6ddb5782014-01-14 16:24:45 +0400780 if (sc->incomplete) {
Valentin Bartenev2686cb42013-03-20 10:36:57 +0000781 ngx_add_timer(c->read, sscf->recv_timeout);
782 return;
783 }
784
785 if (ngx_terminate || ngx_exiting) {
786 ngx_http_close_connection(c);
787 return;
788 }
789
790 ngx_destroy_pool(sc->pool);
791
792 sc->pool = NULL;
793 sc->free_ctl_frames = NULL;
794 sc->free_fake_connections = NULL;
795
796#if (NGX_HTTP_SSL)
797 if (c->ssl) {
798 ngx_ssl_free_buffer(c);
799 }
800#endif
801
802 c->destroyed = 1;
803 c->idle = 1;
804 ngx_reusable_connection(c, 1);
805
806 c->write->handler = ngx_http_empty_handler;
807 c->read->handler = ngx_http_spdy_keepalive_handler;
808
809 if (c->write->timer_set) {
810 ngx_del_timer(c->write);
811 }
812
813 ngx_add_timer(c->read, sscf->keepalive_timeout);
814}
815
816
817static u_char *
Roman Arutyunyan0b5f3292014-03-17 17:41:24 +0400818ngx_http_spdy_proxy_protocol(ngx_http_spdy_connection_t *sc, u_char *pos,
819 u_char *end)
820{
Valentin Bartenevd51d1682014-05-15 19:22:06 +0400821 ngx_log_t *log;
822
823 log = sc->connection->log;
824 log->action = "reading PROXY protocol";
825
Roman Arutyunyan0b5f3292014-03-17 17:41:24 +0400826 pos = ngx_proxy_protocol_parse(sc->connection, pos, end);
827
Valentin Bartenevd51d1682014-05-15 19:22:06 +0400828 log->action = "processing SPDY";
829
Roman Arutyunyan0b5f3292014-03-17 17:41:24 +0400830 if (pos == NULL) {
831 return ngx_http_spdy_state_protocol_error(sc);
832 }
833
Roman Arutyunyan0b5f3292014-03-17 17:41:24 +0400834 return ngx_http_spdy_state_complete(sc, pos, end);
835}
836
837
838static u_char *
Valentin Bartenev2686cb42013-03-20 10:36:57 +0000839ngx_http_spdy_state_head(ngx_http_spdy_connection_t *sc, u_char *pos,
840 u_char *end)
841{
Valentin Barteneva547f4a2014-04-07 19:27:56 +0400842 uint32_t head, flen;
843 ngx_uint_t type;
Valentin Bartenev2686cb42013-03-20 10:36:57 +0000844
845 if (end - pos < NGX_SPDY_FRAME_HEADER_SIZE) {
846 return ngx_http_spdy_state_save(sc, pos, end,
847 ngx_http_spdy_state_head);
848 }
849
850 head = ngx_spdy_frame_parse_uint32(pos);
851
852 pos += sizeof(uint32_t);
853
854 flen = ngx_spdy_frame_parse_uint32(pos);
855
856 sc->flags = ngx_spdy_frame_flags(flen);
857 sc->length = ngx_spdy_frame_length(flen);
858
859 pos += sizeof(uint32_t);
860
861 ngx_log_debug3(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0,
Valentin Bartenevd04a7142014-04-30 20:34:20 +0400862 "process spdy frame head:%08XD f:%Xd l:%uz",
Valentin Bartenev2686cb42013-03-20 10:36:57 +0000863 head, sc->flags, sc->length);
864
865 if (ngx_spdy_ctl_frame_check(head)) {
Valentin Barteneva547f4a2014-04-07 19:27:56 +0400866 type = ngx_spdy_ctl_frame_type(head);
867
868 switch (type) {
Valentin Bartenev2686cb42013-03-20 10:36:57 +0000869
870 case NGX_SPDY_SYN_STREAM:
871 return ngx_http_spdy_state_syn_stream(sc, pos, end);
872
873 case NGX_SPDY_SYN_REPLY:
Valentin Bartenevd04a7142014-04-30 20:34:20 +0400874 ngx_log_error(NGX_LOG_INFO, sc->connection->log, 0,
875 "client sent unexpected SYN_REPLY frame");
Valentin Bartenev2686cb42013-03-20 10:36:57 +0000876 return ngx_http_spdy_state_protocol_error(sc);
877
878 case NGX_SPDY_RST_STREAM:
879 return ngx_http_spdy_state_rst_stream(sc, pos, end);
880
881 case NGX_SPDY_SETTINGS:
Valentin Bartenev449e8ee2014-01-31 19:17:26 +0400882 return ngx_http_spdy_state_settings(sc, pos, end);
Valentin Bartenev2686cb42013-03-20 10:36:57 +0000883
884 case NGX_SPDY_PING:
885 return ngx_http_spdy_state_ping(sc, pos, end);
886
887 case NGX_SPDY_GOAWAY:
888 return ngx_http_spdy_state_skip(sc, pos, end); /* TODO */
889
890 case NGX_SPDY_HEADERS:
Valentin Bartenevd04a7142014-04-30 20:34:20 +0400891 ngx_log_error(NGX_LOG_INFO, sc->connection->log, 0,
892 "client sent unexpected HEADERS frame");
Valentin Bartenev2686cb42013-03-20 10:36:57 +0000893 return ngx_http_spdy_state_protocol_error(sc);
894
Valentin Bartenev449e8ee2014-01-31 19:17:26 +0400895 case NGX_SPDY_WINDOW_UPDATE:
896 return ngx_http_spdy_state_window_update(sc, pos, end);
897
Valentin Barteneva547f4a2014-04-07 19:27:56 +0400898 default:
899 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0,
900 "spdy control frame with unknown type %ui", type);
Valentin Bartenev2686cb42013-03-20 10:36:57 +0000901 return ngx_http_spdy_state_skip(sc, pos, end);
902 }
903 }
904
905 if (ngx_spdy_data_frame_check(head)) {
906 sc->stream = ngx_http_spdy_get_stream_by_id(sc, head);
907 return ngx_http_spdy_state_data(sc, pos, end);
908 }
909
Valentin Bartenevd04a7142014-04-30 20:34:20 +0400910 ngx_log_error(NGX_LOG_INFO, sc->connection->log, 0,
911 "client sent invalid frame");
Valentin Bartenev2686cb42013-03-20 10:36:57 +0000912
913 return ngx_http_spdy_state_protocol_error(sc);
914}
915
916
917static u_char *
918ngx_http_spdy_state_syn_stream(ngx_http_spdy_connection_t *sc, u_char *pos,
919 u_char *end)
920{
921 ngx_uint_t sid, prio;
922 ngx_http_spdy_stream_t *stream;
923 ngx_http_spdy_srv_conf_t *sscf;
924
925 if (end - pos < NGX_SPDY_SYN_STREAM_SIZE) {
926 return ngx_http_spdy_state_save(sc, pos, end,
927 ngx_http_spdy_state_syn_stream);
928 }
929
930 if (sc->length <= NGX_SPDY_SYN_STREAM_SIZE) {
Valentin Bartenevd04a7142014-04-30 20:34:20 +0400931 ngx_log_error(NGX_LOG_INFO, sc->connection->log, 0,
932 "client sent SYN_STREAM frame with incorrect length %uz",
933 sc->length);
934
Valentin Bartenev2686cb42013-03-20 10:36:57 +0000935 return ngx_http_spdy_state_protocol_error(sc);
936 }
937
938 sc->length -= NGX_SPDY_SYN_STREAM_SIZE;
939
940 sid = ngx_spdy_frame_parse_sid(pos);
Shigeki Ohtsu38a9a892014-02-04 14:06:23 +0900941 prio = pos[8] >> 5;
Valentin Bartenev2686cb42013-03-20 10:36:57 +0000942
943 pos += NGX_SPDY_SYN_STREAM_SIZE;
944
945 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0,
946 "spdy SYN_STREAM frame sid:%ui prio:%ui", sid, prio);
947
Valentin Barteneva57959b2014-04-21 18:59:53 +0400948 if (sid % 2 == 0 || sid <= sc->last_sid) {
949 ngx_log_error(NGX_LOG_INFO, sc->connection->log, 0,
950 "client sent SYN_STREAM frame "
951 "with invalid Stream-ID %ui", sid);
952
953 stream = ngx_http_spdy_get_stream_by_id(sc, sid);
954
955 if (stream) {
956 if (ngx_http_spdy_terminate_stream(sc, stream,
957 NGX_SPDY_PROTOCOL_ERROR)
958 != NGX_OK)
959 {
960 return ngx_http_spdy_state_internal_error(sc);
961 }
962 }
963
964 return ngx_http_spdy_state_protocol_error(sc);
965 }
966
967 sc->last_sid = sid;
968
Valentin Bartenev2686cb42013-03-20 10:36:57 +0000969 sscf = ngx_http_get_module_srv_conf(sc->http_connection->conf_ctx,
970 ngx_http_spdy_module);
971
972 if (sc->processing >= sscf->concurrent_streams) {
973
974 ngx_log_error(NGX_LOG_INFO, sc->connection->log, 0,
Valentin Bartenevd04a7142014-04-30 20:34:20 +0400975 "concurrent streams exceeded %ui", sc->processing);
Valentin Bartenev2686cb42013-03-20 10:36:57 +0000976
977 if (ngx_http_spdy_send_rst_stream(sc, sid, NGX_SPDY_REFUSED_STREAM,
978 prio)
979 != NGX_OK)
980 {
981 return ngx_http_spdy_state_internal_error(sc);
982 }
983
984 return ngx_http_spdy_state_headers_skip(sc, pos, end);
985 }
986
987 stream = ngx_http_spdy_create_stream(sc, sid, prio);
988 if (stream == NULL) {
989 return ngx_http_spdy_state_internal_error(sc);
990 }
991
992 stream->in_closed = (sc->flags & NGX_SPDY_FLAG_FIN) ? 1 : 0;
993
994 stream->request->request_length = NGX_SPDY_FRAME_HEADER_SIZE
995 + NGX_SPDY_SYN_STREAM_SIZE
996 + sc->length;
997
998 sc->stream = stream;
999
Valentin Bartenev2686cb42013-03-20 10:36:57 +00001000 return ngx_http_spdy_state_headers(sc, pos, end);
1001}
1002
1003
1004static u_char *
1005ngx_http_spdy_state_headers(ngx_http_spdy_connection_t *sc, u_char *pos,
1006 u_char *end)
1007{
1008 int z;
1009 size_t size;
1010 ngx_buf_t *buf;
1011 ngx_int_t rc;
Valentin Bartenev2686cb42013-03-20 10:36:57 +00001012 ngx_http_request_t *r;
1013
1014 size = end - pos;
1015
1016 if (size == 0) {
1017 return ngx_http_spdy_state_save(sc, pos, end,
1018 ngx_http_spdy_state_headers);
1019 }
1020
Valentin Bartenev57e5c3e2014-04-30 20:34:20 +04001021 if (size > sc->length) {
Valentin Bartenev2686cb42013-03-20 10:36:57 +00001022 size = sc->length;
Valentin Bartenev2686cb42013-03-20 10:36:57 +00001023 }
1024
1025 r = sc->stream->request;
1026
1027 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
Valentin Bartenevd04a7142014-04-30 20:34:20 +04001028 "process spdy header block %uz of %uz", size, sc->length);
Valentin Bartenev2686cb42013-03-20 10:36:57 +00001029
1030 buf = r->header_in;
1031
1032 sc->zstream_in.next_in = pos;
1033 sc->zstream_in.avail_in = size;
1034 sc->zstream_in.next_out = buf->last;
Valentin Bartenev3be925b2013-08-15 19:14:58 +04001035
1036 /* one byte is reserved for null-termination of the last header value */
Valentin Bartenev2686cb42013-03-20 10:36:57 +00001037 sc->zstream_in.avail_out = buf->end - buf->last - 1;
1038
1039 z = inflate(&sc->zstream_in, Z_NO_FLUSH);
1040
1041 if (z == Z_NEED_DICT) {
1042 z = inflateSetDictionary(&sc->zstream_in, ngx_http_spdy_dict,
1043 sizeof(ngx_http_spdy_dict));
Valentin Bartenevdfb9a5c2014-04-30 20:33:58 +04001044
Valentin Bartenevcf770dd2014-04-30 20:34:20 +04001045 if (z != Z_OK) {
1046 if (z == Z_DATA_ERROR) {
1047 ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
1048 "client sent SYN_STREAM frame with header "
1049 "block encoded using wrong dictionary: %ul",
1050 (u_long) sc->zstream_in.adler);
1051
1052 return ngx_http_spdy_state_protocol_error(sc);
1053 }
1054
1055 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
1056 "inflateSetDictionary() failed: %d", z);
1057
1058 return ngx_http_spdy_state_internal_error(sc);
Valentin Bartenev2686cb42013-03-20 10:36:57 +00001059 }
1060
1061 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1062 "spdy inflateSetDictionary(): %d", z);
1063
1064 z = sc->zstream_in.avail_in ? inflate(&sc->zstream_in, Z_NO_FLUSH)
1065 : Z_OK;
1066 }
1067
Valentin Bartenev2686cb42013-03-20 10:36:57 +00001068 ngx_log_debug5(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1069 "spdy inflate out: ni:%p no:%p ai:%ud ao:%ud rc:%d",
1070 sc->zstream_in.next_in, sc->zstream_in.next_out,
1071 sc->zstream_in.avail_in, sc->zstream_in.avail_out,
1072 z);
1073
Valentin Bartenev42b6d572014-11-07 17:19:12 +03001074 if (z != Z_OK) {
1075 return ngx_http_spdy_state_inflate_error(sc, z);
1076 }
1077
Valentin Bartenev2686cb42013-03-20 10:36:57 +00001078 sc->length -= sc->zstream_in.next_in - pos;
1079 pos = sc->zstream_in.next_in;
1080
1081 buf->last = sc->zstream_in.next_out;
1082
1083 if (r->headers_in.headers.part.elts == NULL) {
1084
1085 if (buf->last - buf->pos < NGX_SPDY_NV_NUM_SIZE) {
Valentin Bartenev042122a2014-03-26 17:43:39 +04001086
Valentin Bartenev57e5c3e2014-04-30 20:34:20 +04001087 if (sc->length == 0) {
Valentin Bartenevef510792014-04-30 20:34:20 +04001088 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1089 "premature end of spdy header block");
Valentin Bartenevdfb9a5c2014-04-30 20:33:58 +04001090
Valentin Bartenevef510792014-04-30 20:34:20 +04001091 return ngx_http_spdy_state_headers_error(sc, pos, end);
Valentin Bartenev042122a2014-03-26 17:43:39 +04001092 }
1093
Valentin Bartenev2686cb42013-03-20 10:36:57 +00001094 return ngx_http_spdy_state_save(sc, pos, end,
1095 ngx_http_spdy_state_headers);
1096 }
1097
Valentin Bartenev449e8ee2014-01-31 19:17:26 +04001098 sc->entries = ngx_spdy_frame_parse_uint32(buf->pos);
Valentin Bartenev2686cb42013-03-20 10:36:57 +00001099
1100 buf->pos += NGX_SPDY_NV_NUM_SIZE;
1101
1102 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
Valentin Bartenevd04a7142014-04-30 20:34:20 +04001103 "spdy header block has %ui entries",
Valentin Bartenev406c0612014-01-22 04:58:19 +04001104 sc->entries);
Valentin Bartenev2686cb42013-03-20 10:36:57 +00001105
Valentin Bartenev3925c1b2014-03-03 19:24:54 +04001106 if (ngx_list_init(&r->headers_in.headers, r->pool, 20,
Valentin Bartenev2686cb42013-03-20 10:36:57 +00001107 sizeof(ngx_table_elt_t))
1108 != NGX_OK)
1109 {
1110 ngx_http_spdy_close_stream(sc->stream,
1111 NGX_HTTP_INTERNAL_SERVER_ERROR);
Valentin Bartenevba890402014-04-30 20:34:20 +04001112 return ngx_http_spdy_state_headers_skip(sc, pos, end);
Valentin Bartenev2686cb42013-03-20 10:36:57 +00001113 }
1114
1115 if (ngx_array_init(&r->headers_in.cookies, r->pool, 2,
1116 sizeof(ngx_table_elt_t *))
1117 != NGX_OK)
1118 {
1119 ngx_http_spdy_close_stream(sc->stream,
1120 NGX_HTTP_INTERNAL_SERVER_ERROR);
Valentin Bartenevba890402014-04-30 20:34:20 +04001121 return ngx_http_spdy_state_headers_skip(sc, pos, end);
Valentin Bartenev2686cb42013-03-20 10:36:57 +00001122 }
1123 }
1124
Valentin Bartenev406c0612014-01-22 04:58:19 +04001125 while (sc->entries) {
Valentin Bartenev2686cb42013-03-20 10:36:57 +00001126
1127 rc = ngx_http_spdy_parse_header(r);
1128
1129 switch (rc) {
1130
1131 case NGX_DONE:
Valentin Bartenev406c0612014-01-22 04:58:19 +04001132 sc->entries--;
Valentin Bartenev2686cb42013-03-20 10:36:57 +00001133
1134 case NGX_OK:
1135 break;
1136
1137 case NGX_AGAIN:
1138
1139 if (sc->zstream_in.avail_in) {
1140
1141 rc = ngx_http_spdy_alloc_large_header_buffer(r);
1142
1143 if (rc == NGX_DECLINED) {
Valentin Bartenev2686cb42013-03-20 10:36:57 +00001144 ngx_http_finalize_request(r,
1145 NGX_HTTP_REQUEST_HEADER_TOO_LARGE);
Valentin Bartenevba890402014-04-30 20:34:20 +04001146 return ngx_http_spdy_state_headers_skip(sc, pos, end);
Valentin Bartenev2686cb42013-03-20 10:36:57 +00001147 }
1148
1149 if (rc != NGX_OK) {
1150 ngx_http_spdy_close_stream(sc->stream,
1151 NGX_HTTP_INTERNAL_SERVER_ERROR);
Valentin Bartenevba890402014-04-30 20:34:20 +04001152 return ngx_http_spdy_state_headers_skip(sc, pos, end);
Valentin Bartenev2686cb42013-03-20 10:36:57 +00001153 }
1154
Valentin Bartenev3be925b2013-08-15 19:14:58 +04001155 /* null-terminate the last processed header name or value */
1156 *buf->pos = '\0';
1157
Valentin Bartenev2686cb42013-03-20 10:36:57 +00001158 buf = r->header_in;
1159
1160 sc->zstream_in.next_out = buf->last;
Valentin Bartenev3be925b2013-08-15 19:14:58 +04001161
1162 /* one byte is reserved for null-termination */
Valentin Bartenev2686cb42013-03-20 10:36:57 +00001163 sc->zstream_in.avail_out = buf->end - buf->last - 1;
1164
1165 z = inflate(&sc->zstream_in, Z_NO_FLUSH);
1166
Valentin Bartenev42b6d572014-11-07 17:19:12 +03001167 ngx_log_debug5(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1168 "spdy inflate out: ni:%p no:%p ai:%ud ao:%ud rc:%d",
1169 sc->zstream_in.next_in, sc->zstream_in.next_out,
1170 sc->zstream_in.avail_in, sc->zstream_in.avail_out,
1171 z);
1172
Valentin Bartenev2686cb42013-03-20 10:36:57 +00001173 if (z != Z_OK) {
Valentin Bartenevcf770dd2014-04-30 20:34:20 +04001174 return ngx_http_spdy_state_inflate_error(sc, z);
Valentin Bartenev2686cb42013-03-20 10:36:57 +00001175 }
1176
1177 sc->length -= sc->zstream_in.next_in - pos;
1178 pos = sc->zstream_in.next_in;
1179
1180 buf->last = sc->zstream_in.next_out;
1181
1182 continue;
1183 }
1184
Valentin Bartenev57e5c3e2014-04-30 20:34:20 +04001185 if (sc->length == 0) {
Valentin Bartenev2686cb42013-03-20 10:36:57 +00001186 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
Valentin Bartenevd04a7142014-04-30 20:34:20 +04001187 "premature end of spdy header block");
Valentin Bartenevdfb9a5c2014-04-30 20:33:58 +04001188
Valentin Bartenevef510792014-04-30 20:34:20 +04001189 return ngx_http_spdy_state_headers_error(sc, pos, end);
Valentin Bartenev2686cb42013-03-20 10:36:57 +00001190 }
1191
1192 return ngx_http_spdy_state_save(sc, pos, end,
1193 ngx_http_spdy_state_headers);
1194
Valentin Bartenevef510792014-04-30 20:34:20 +04001195 case NGX_HTTP_PARSE_INVALID_HEADER:
Valentin Bartenev2686cb42013-03-20 10:36:57 +00001196 ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST);
Valentin Bartenevba890402014-04-30 20:34:20 +04001197 return ngx_http_spdy_state_headers_skip(sc, pos, end);
Valentin Bartenev2686cb42013-03-20 10:36:57 +00001198
Valentin Bartenevef510792014-04-30 20:34:20 +04001199 default: /* NGX_ERROR */
1200 return ngx_http_spdy_state_headers_error(sc, pos, end);
Valentin Bartenev2686cb42013-03-20 10:36:57 +00001201 }
1202
1203 /* a header line has been parsed successfully */
1204
1205 rc = ngx_http_spdy_handle_request_header(r);
1206
1207 if (rc != NGX_OK) {
1208 if (rc == NGX_HTTP_PARSE_INVALID_HEADER) {
Valentin Bartenevef510792014-04-30 20:34:20 +04001209 ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST);
1210 return ngx_http_spdy_state_headers_skip(sc, pos, end);
Valentin Bartenev2686cb42013-03-20 10:36:57 +00001211 }
1212
Valentin Bartenevef510792014-04-30 20:34:20 +04001213 if (rc != NGX_ABORT) {
1214 ngx_http_spdy_close_stream(sc->stream,
1215 NGX_HTTP_INTERNAL_SERVER_ERROR);
Valentin Bartenev2686cb42013-03-20 10:36:57 +00001216 }
1217
Valentin Bartenevba890402014-04-30 20:34:20 +04001218 return ngx_http_spdy_state_headers_skip(sc, pos, end);
Valentin Bartenev2686cb42013-03-20 10:36:57 +00001219 }
1220 }
1221
Valentin Bartenevde3c7a82014-03-26 18:01:11 +04001222 if (buf->pos != buf->last || sc->zstream_in.avail_in) {
Valentin Bartenevef510792014-04-30 20:34:20 +04001223 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1224 "incorrect number of spdy header block entries");
Valentin Bartenevdfb9a5c2014-04-30 20:33:58 +04001225
Valentin Bartenevef510792014-04-30 20:34:20 +04001226 return ngx_http_spdy_state_headers_error(sc, pos, end);
Valentin Bartenev2686cb42013-03-20 10:36:57 +00001227 }
1228
Valentin Bartenev57e5c3e2014-04-30 20:34:20 +04001229 if (sc->length) {
Valentin Bartenev2686cb42013-03-20 10:36:57 +00001230 return ngx_http_spdy_state_save(sc, pos, end,
1231 ngx_http_spdy_state_headers);
1232 }
1233
Valentin Bartenev3be925b2013-08-15 19:14:58 +04001234 /* null-terminate the last header value */
1235 *buf->pos = '\0';
1236
Valentin Bartenev2686cb42013-03-20 10:36:57 +00001237 ngx_http_spdy_run_request(r);
1238
1239 return ngx_http_spdy_state_complete(sc, pos, end);
1240}
1241
1242
1243static u_char *
Valentin Bartenev2686cb42013-03-20 10:36:57 +00001244ngx_http_spdy_state_headers_skip(ngx_http_spdy_connection_t *sc, u_char *pos,
1245 u_char *end)
1246{
1247 int n;
1248 size_t size;
1249 u_char buffer[NGX_SPDY_SKIP_HEADERS_BUFFER_SIZE];
1250
1251 if (sc->length == 0) {
1252 return ngx_http_spdy_state_complete(sc, pos, end);
1253 }
1254
1255 size = end - pos;
1256
1257 if (size == 0) {
1258 return ngx_http_spdy_state_save(sc, pos, end,
1259 ngx_http_spdy_state_headers_skip);
1260 }
1261
Valentin Bartenevd04a7142014-04-30 20:34:20 +04001262 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0,
1263 "spdy header block skip %uz of %uz", size, sc->length);
1264
Valentin Bartenev2686cb42013-03-20 10:36:57 +00001265 sc->zstream_in.next_in = pos;
1266 sc->zstream_in.avail_in = (size < sc->length) ? size : sc->length;
1267
1268 while (sc->zstream_in.avail_in) {
1269 sc->zstream_in.next_out = buffer;
1270 sc->zstream_in.avail_out = NGX_SPDY_SKIP_HEADERS_BUFFER_SIZE;
1271
1272 n = inflate(&sc->zstream_in, Z_NO_FLUSH);
1273
Valentin Bartenev42b6d572014-11-07 17:19:12 +03001274 ngx_log_debug5(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0,
1275 "spdy inflate out: ni:%p no:%p ai:%ud ao:%ud rc:%d",
1276 sc->zstream_in.next_in, sc->zstream_in.next_out,
1277 sc->zstream_in.avail_in, sc->zstream_in.avail_out,
1278 n);
1279
Valentin Bartenev2686cb42013-03-20 10:36:57 +00001280 if (n != Z_OK) {
Valentin Bartenevcf770dd2014-04-30 20:34:20 +04001281 return ngx_http_spdy_state_inflate_error(sc, n);
Valentin Bartenev2686cb42013-03-20 10:36:57 +00001282 }
1283 }
1284
1285 pos = sc->zstream_in.next_in;
1286
1287 if (size < sc->length) {
1288 sc->length -= size;
1289 return ngx_http_spdy_state_save(sc, pos, end,
1290 ngx_http_spdy_state_headers_skip);
1291 }
1292
1293 return ngx_http_spdy_state_complete(sc, pos, end);
1294}
1295
1296
1297static u_char *
Valentin Bartenevef510792014-04-30 20:34:20 +04001298ngx_http_spdy_state_headers_error(ngx_http_spdy_connection_t *sc, u_char *pos,
1299 u_char *end)
1300{
1301 ngx_http_spdy_stream_t *stream;
1302
1303 stream = sc->stream;
1304
1305 ngx_log_error(NGX_LOG_INFO, sc->connection->log, 0,
1306 "client sent SYN_STREAM frame for stream %ui "
1307 "with invalid header block", stream->id);
1308
1309 if (ngx_http_spdy_send_rst_stream(sc, stream->id, NGX_SPDY_PROTOCOL_ERROR,
1310 stream->priority)
1311 != NGX_OK)
1312 {
1313 return ngx_http_spdy_state_internal_error(sc);
1314 }
1315
1316 stream->out_closed = 1;
1317
1318 ngx_http_spdy_close_stream(stream, NGX_HTTP_BAD_REQUEST);
1319
1320 return ngx_http_spdy_state_headers_skip(sc, pos, end);
1321}
1322
1323
1324static u_char *
Valentin Bartenev449e8ee2014-01-31 19:17:26 +04001325ngx_http_spdy_state_window_update(ngx_http_spdy_connection_t *sc, u_char *pos,
1326 u_char *end)
1327{
1328 size_t delta;
1329 ngx_uint_t sid;
1330 ngx_event_t *wev;
1331 ngx_queue_t *q;
1332 ngx_http_spdy_stream_t *stream;
1333
1334 if (end - pos < NGX_SPDY_WINDOW_UPDATE_SIZE) {
1335 return ngx_http_spdy_state_save(sc, pos, end,
1336 ngx_http_spdy_state_window_update);
1337 }
1338
1339 if (sc->length != NGX_SPDY_WINDOW_UPDATE_SIZE) {
1340 ngx_log_error(NGX_LOG_INFO, sc->connection->log, 0,
1341 "client sent WINDOW_UPDATE frame "
1342 "with incorrect length %uz", sc->length);
1343
1344 return ngx_http_spdy_state_protocol_error(sc);
1345 }
1346
1347 sid = ngx_spdy_frame_parse_sid(pos);
1348
1349 pos += NGX_SPDY_SID_SIZE;
1350
1351 delta = ngx_spdy_frame_parse_delta(pos);
1352
1353 pos += NGX_SPDY_DELTA_SIZE;
1354
1355 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0,
1356 "spdy WINDOW_UPDATE sid:%ui delta:%ui", sid, delta);
1357
1358 if (sid) {
1359 stream = ngx_http_spdy_get_stream_by_id(sc, sid);
1360
1361 if (stream == NULL) {
Valentin Bartenevf79908a2014-04-21 19:21:17 +04001362 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0,
1363 "unknown spdy stream");
Valentin Bartenev449e8ee2014-01-31 19:17:26 +04001364
1365 return ngx_http_spdy_state_complete(sc, pos, end);
1366 }
1367
1368 if (stream->send_window > (ssize_t) (NGX_SPDY_MAX_WINDOW - delta)) {
1369
1370 ngx_log_error(NGX_LOG_INFO, sc->connection->log, 0,
1371 "client violated flow control for stream %ui: "
1372 "received WINDOW_UPDATE frame with delta %uz "
Valentin Bartenevd04a7142014-04-30 20:34:20 +04001373 "not allowed for window %z",
Valentin Bartenev449e8ee2014-01-31 19:17:26 +04001374 sid, delta, stream->send_window);
1375
1376 if (ngx_http_spdy_terminate_stream(sc, stream,
1377 NGX_SPDY_FLOW_CONTROL_ERROR)
1378 == NGX_ERROR)
1379 {
1380 return ngx_http_spdy_state_internal_error(sc);
1381 }
1382
1383 return ngx_http_spdy_state_complete(sc, pos, end);
1384 }
1385
1386 stream->send_window += delta;
1387
1388 if (stream->exhausted) {
1389 stream->exhausted = 0;
1390
1391 wev = stream->request->connection->write;
1392
1393 if (!wev->timer_set) {
1394 wev->delayed = 0;
1395 wev->handler(wev);
1396 }
1397 }
1398
1399 } else {
1400 sc->send_window += delta;
1401
1402 if (sc->send_window > NGX_SPDY_MAX_WINDOW) {
1403 ngx_log_error(NGX_LOG_INFO, sc->connection->log, 0,
1404 "client violated connection flow control: "
1405 "received WINDOW_UPDATE frame with delta %uz "
Valentin Bartenevd04a7142014-04-30 20:34:20 +04001406 "not allowed for window %uz",
Valentin Bartenev449e8ee2014-01-31 19:17:26 +04001407 delta, sc->send_window);
1408
1409 return ngx_http_spdy_state_protocol_error(sc);
1410 }
1411
1412 while (!ngx_queue_empty(&sc->waiting)) {
1413 q = ngx_queue_head(&sc->waiting);
1414
1415 ngx_queue_remove(q);
1416
1417 stream = ngx_queue_data(q, ngx_http_spdy_stream_t, queue);
1418
1419 stream->handled = 0;
1420
1421 wev = stream->request->connection->write;
1422
1423 if (!wev->timer_set) {
1424 wev->delayed = 0;
1425 wev->handler(wev);
1426
1427 if (sc->send_window == 0) {
1428 break;
1429 }
1430 }
1431 }
1432 }
1433
1434 return ngx_http_spdy_state_complete(sc, pos, end);
1435}
1436
1437
1438static u_char *
Valentin Bartenev2686cb42013-03-20 10:36:57 +00001439ngx_http_spdy_state_data(ngx_http_spdy_connection_t *sc, u_char *pos,
1440 u_char *end)
1441{
Valentin Bartenev449e8ee2014-01-31 19:17:26 +04001442 ngx_http_spdy_stream_t *stream;
1443
Valentin Bartenev449e8ee2014-01-31 19:17:26 +04001444 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0,
1445 "spdy DATA frame");
1446
1447 if (sc->length > sc->recv_window) {
1448 ngx_log_error(NGX_LOG_INFO, sc->connection->log, 0,
Valentin Bartenevd04a7142014-04-30 20:34:20 +04001449 "client violated connection flow control: "
1450 "received DATA frame length %uz, available window %uz",
Valentin Bartenev5d3f84e2014-04-08 20:12:30 +04001451 sc->length, sc->recv_window);
Valentin Bartenev449e8ee2014-01-31 19:17:26 +04001452
1453 return ngx_http_spdy_state_protocol_error(sc);
1454 }
1455
1456 sc->recv_window -= sc->length;
1457
1458 if (sc->recv_window < NGX_SPDY_MAX_WINDOW / 4) {
1459
1460 if (ngx_http_spdy_send_window_update(sc, 0,
1461 NGX_SPDY_MAX_WINDOW
1462 - sc->recv_window)
1463 == NGX_ERROR)
1464 {
1465 return ngx_http_spdy_state_internal_error(sc);
1466 }
1467
1468 sc->recv_window = NGX_SPDY_MAX_WINDOW;
1469 }
1470
Valentin Bartenev7da40e62014-04-09 18:15:32 +04001471 stream = sc->stream;
1472
Valentin Bartenev449e8ee2014-01-31 19:17:26 +04001473 if (stream == NULL) {
Valentin Bartenevd04a7142014-04-30 20:34:20 +04001474 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0,
1475 "unknown spdy stream");
1476
Valentin Bartenev449e8ee2014-01-31 19:17:26 +04001477 return ngx_http_spdy_state_skip(sc, pos, end);
1478 }
1479
1480 if (sc->length > stream->recv_window) {
1481 ngx_log_error(NGX_LOG_INFO, sc->connection->log, 0,
Valentin Bartenevd04a7142014-04-30 20:34:20 +04001482 "client violated flow control for stream %ui: "
1483 "received DATA frame length %uz, available window %uz",
Valentin Bartenev449e8ee2014-01-31 19:17:26 +04001484 stream->id, sc->length, stream->recv_window);
1485
1486 if (ngx_http_spdy_terminate_stream(sc, stream,
1487 NGX_SPDY_FLOW_CONTROL_ERROR)
1488 == NGX_ERROR)
1489 {
1490 return ngx_http_spdy_state_internal_error(sc);
1491 }
1492
1493 return ngx_http_spdy_state_skip(sc, pos, end);
1494 }
1495
1496 stream->recv_window -= sc->length;
1497
1498 if (stream->recv_window < NGX_SPDY_STREAM_WINDOW / 4) {
1499
1500 if (ngx_http_spdy_send_window_update(sc, stream->id,
1501 NGX_SPDY_STREAM_WINDOW
1502 - stream->recv_window)
1503 == NGX_ERROR)
1504 {
1505 return ngx_http_spdy_state_internal_error(sc);
1506 }
1507
1508 stream->recv_window = NGX_SPDY_STREAM_WINDOW;
1509 }
1510
1511 if (stream->in_closed) {
1512 ngx_log_error(NGX_LOG_INFO, sc->connection->log, 0,
Valentin Bartenevd04a7142014-04-30 20:34:20 +04001513 "client sent DATA frame for half-closed stream %ui",
Valentin Bartenev449e8ee2014-01-31 19:17:26 +04001514 stream->id);
1515
1516 if (ngx_http_spdy_terminate_stream(sc, stream,
1517 NGX_SPDY_STREAM_ALREADY_CLOSED)
1518 == NGX_ERROR)
1519 {
1520 return ngx_http_spdy_state_internal_error(sc);
1521 }
1522
1523 return ngx_http_spdy_state_skip(sc, pos, end);
1524 }
1525
1526 return ngx_http_spdy_state_read_data(sc, pos, end);
1527}
1528
1529
1530static u_char *
1531ngx_http_spdy_state_read_data(ngx_http_spdy_connection_t *sc, u_char *pos,
1532 u_char *end)
1533{
Valentin Bartenev2686cb42013-03-20 10:36:57 +00001534 size_t size;
1535 ssize_t n;
1536 ngx_buf_t *buf;
1537 ngx_int_t rc;
Valentin Bartenev2686cb42013-03-20 10:36:57 +00001538 ngx_temp_file_t *tf;
1539 ngx_http_request_t *r;
1540 ngx_http_spdy_stream_t *stream;
1541 ngx_http_request_body_t *rb;
1542 ngx_http_core_loc_conf_t *clcf;
1543
1544 stream = sc->stream;
1545
Valentin Bartenev2686cb42013-03-20 10:36:57 +00001546 if (stream == NULL) {
1547 return ngx_http_spdy_state_skip(sc, pos, end);
1548 }
1549
Valentin Bartenev2686cb42013-03-20 10:36:57 +00001550 if (stream->skip_data) {
1551
1552 if (sc->flags & NGX_SPDY_FLAG_FIN) {
1553 stream->in_closed = 1;
1554 }
1555
Valentin Bartenevd04a7142014-04-30 20:34:20 +04001556 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0,
1557 "skipping spdy DATA frame, reason: %d",
1558 stream->skip_data);
1559
Valentin Bartenev2686cb42013-03-20 10:36:57 +00001560 return ngx_http_spdy_state_skip(sc, pos, end);
1561 }
1562
1563 size = end - pos;
1564
Valentin Bartenev108e4d92014-04-07 19:27:56 +04001565 if (size > sc->length) {
Valentin Bartenev2686cb42013-03-20 10:36:57 +00001566 size = sc->length;
Valentin Bartenev2686cb42013-03-20 10:36:57 +00001567 }
1568
1569 r = stream->request;
1570
1571 if (r->request_body == NULL
1572 && ngx_http_spdy_init_request_body(r) != NGX_OK)
1573 {
1574 stream->skip_data = NGX_SPDY_DATA_INTERNAL_ERROR;
1575 return ngx_http_spdy_state_skip(sc, pos, end);
1576 }
1577
1578 rb = r->request_body;
1579 tf = rb->temp_file;
1580 buf = rb->buf;
1581
1582 if (size) {
1583 rb->rest += size;
1584
1585 if (r->headers_in.content_length_n != -1
1586 && r->headers_in.content_length_n < rb->rest)
1587 {
Valentin Bartenevd04a7142014-04-30 20:34:20 +04001588 ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
1589 "client intended to send body data "
1590 "larger than declared");
1591
Valentin Bartenev2686cb42013-03-20 10:36:57 +00001592 stream->skip_data = NGX_SPDY_DATA_ERROR;
1593 goto error;
1594
1595 } else {
1596 clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
1597
1598 if (clcf->client_max_body_size
1599 && clcf->client_max_body_size < rb->rest)
1600 {
1601 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
Valentin Bartenevd04a7142014-04-30 20:34:20 +04001602 "client intended to send "
1603 "too large chunked body: %O bytes", rb->rest);
Valentin Bartenev2686cb42013-03-20 10:36:57 +00001604
1605 stream->skip_data = NGX_SPDY_DATA_ERROR;
1606 goto error;
1607 }
1608 }
1609
Valentin Bartenevafb92a82014-03-28 20:05:07 +04001610 sc->length -= size;
1611
Valentin Bartenev2686cb42013-03-20 10:36:57 +00001612 if (tf) {
1613 buf->start = pos;
1614 buf->pos = pos;
1615
1616 pos += size;
1617
1618 buf->end = pos;
1619 buf->last = pos;
1620
1621 n = ngx_write_chain_to_temp_file(tf, rb->bufs);
1622
1623 /* TODO: n == 0 or not complete and level event */
1624
1625 if (n == NGX_ERROR) {
1626 stream->skip_data = NGX_SPDY_DATA_INTERNAL_ERROR;
1627 goto error;
1628 }
1629
1630 tf->offset += n;
1631
1632 } else {
1633 buf->last = ngx_cpymem(buf->last, pos, size);
1634 pos += size;
1635 }
1636
1637 r->request_length += size;
1638 }
1639
Valentin Bartenev108e4d92014-04-07 19:27:56 +04001640 if (sc->length) {
Valentin Bartenev2686cb42013-03-20 10:36:57 +00001641 return ngx_http_spdy_state_save(sc, pos, end,
Valentin Bartenev449e8ee2014-01-31 19:17:26 +04001642 ngx_http_spdy_state_read_data);
Valentin Bartenev2686cb42013-03-20 10:36:57 +00001643 }
1644
1645 if (sc->flags & NGX_SPDY_FLAG_FIN) {
1646
1647 stream->in_closed = 1;
1648
Valentin Bartenevac5a3cb2014-03-28 20:22:57 +04001649 if (r->headers_in.content_length_n < 0) {
1650 r->headers_in.content_length_n = rb->rest;
1651
1652 } else if (r->headers_in.content_length_n != rb->rest) {
1653 ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
1654 "client prematurely closed stream: "
Valentin Bartenevd04a7142014-04-30 20:34:20 +04001655 "only %O out of %O bytes of request body received",
Valentin Bartenevac5a3cb2014-03-28 20:22:57 +04001656 rb->rest, r->headers_in.content_length_n);
1657
1658 stream->skip_data = NGX_SPDY_DATA_ERROR;
1659 goto error;
1660 }
1661
Valentin Bartenev2686cb42013-03-20 10:36:57 +00001662 if (tf) {
1663 ngx_memzero(buf, sizeof(ngx_buf_t));
1664
1665 buf->in_file = 1;
1666 buf->file_last = tf->file.offset;
1667 buf->file = &tf->file;
1668
1669 rb->buf = NULL;
1670 }
1671
Valentin Bartenev2686cb42013-03-20 10:36:57 +00001672 if (rb->post_handler) {
Valentin Bartenev6ba03092013-10-01 00:00:57 +04001673 r->read_event_handler = ngx_http_block_reading;
Valentin Bartenev2686cb42013-03-20 10:36:57 +00001674 rb->post_handler(r);
1675 }
1676 }
1677
1678 return ngx_http_spdy_state_complete(sc, pos, end);
1679
1680error:
1681
1682 if (rb->post_handler) {
1683
1684 if (stream->skip_data == NGX_SPDY_DATA_ERROR) {
1685 rc = (r->headers_in.content_length_n == -1)
1686 ? NGX_HTTP_REQUEST_ENTITY_TOO_LARGE
1687 : NGX_HTTP_BAD_REQUEST;
1688
1689 } else {
1690 rc = NGX_HTTP_INTERNAL_SERVER_ERROR;
1691 }
1692
1693 ngx_http_finalize_request(r, rc);
1694 }
1695
1696 return ngx_http_spdy_state_skip(sc, pos, end);
1697}
1698
1699
1700static u_char *
1701ngx_http_spdy_state_rst_stream(ngx_http_spdy_connection_t *sc, u_char *pos,
1702 u_char *end)
1703{
1704 ngx_uint_t sid, status;
1705 ngx_event_t *ev;
1706 ngx_connection_t *fc;
Valentin Bartenev2686cb42013-03-20 10:36:57 +00001707 ngx_http_spdy_stream_t *stream;
1708
1709 if (end - pos < NGX_SPDY_RST_STREAM_SIZE) {
1710 return ngx_http_spdy_state_save(sc, pos, end,
1711 ngx_http_spdy_state_rst_stream);
1712 }
1713
1714 if (sc->length != NGX_SPDY_RST_STREAM_SIZE) {
Valentin Bartenev650984c2014-01-22 04:58:19 +04001715 ngx_log_error(NGX_LOG_INFO, sc->connection->log, 0,
1716 "client sent RST_STREAM frame with incorrect length %uz",
1717 sc->length);
1718
Valentin Bartenev2686cb42013-03-20 10:36:57 +00001719 return ngx_http_spdy_state_protocol_error(sc);
1720 }
1721
1722 sid = ngx_spdy_frame_parse_sid(pos);
1723
1724 pos += NGX_SPDY_SID_SIZE;
1725
1726 status = ngx_spdy_frame_parse_uint32(pos);
1727
1728 pos += sizeof(uint32_t);
1729
1730 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0,
1731 "spdy RST_STREAM sid:%ui st:%ui", sid, status);
1732
Valentin Bartenev650984c2014-01-22 04:58:19 +04001733 stream = ngx_http_spdy_get_stream_by_id(sc, sid);
Valentin Bartenevd04a7142014-04-30 20:34:20 +04001734
Valentin Bartenev650984c2014-01-22 04:58:19 +04001735 if (stream == NULL) {
1736 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0,
Valentin Bartenevd04a7142014-04-30 20:34:20 +04001737 "unknown spdy stream");
1738
Valentin Bartenev650984c2014-01-22 04:58:19 +04001739 return ngx_http_spdy_state_complete(sc, pos, end);
1740 }
1741
1742 stream->in_closed = 1;
1743 stream->out_closed = 1;
1744
1745 fc = stream->request->connection;
1746 fc->error = 1;
Valentin Bartenev2686cb42013-03-20 10:36:57 +00001747
1748 switch (status) {
1749
Valentin Bartenev2686cb42013-03-20 10:36:57 +00001750 case NGX_SPDY_CANCEL:
Valentin Bartenev650984c2014-01-22 04:58:19 +04001751 ngx_log_error(NGX_LOG_INFO, fc->log, 0,
1752 "client canceled stream %ui", sid);
Valentin Bartenev2686cb42013-03-20 10:36:57 +00001753 break;
1754
Valentin Bartenev650984c2014-01-22 04:58:19 +04001755 case NGX_SPDY_INTERNAL_ERROR:
1756 ngx_log_error(NGX_LOG_INFO, fc->log, 0,
Valentin Bartenevd04a7142014-04-30 20:34:20 +04001757 "client terminated stream %ui due to internal error",
Valentin Bartenev650984c2014-01-22 04:58:19 +04001758 sid);
1759 break;
Valentin Bartenev2686cb42013-03-20 10:36:57 +00001760
1761 default:
Valentin Bartenev650984c2014-01-22 04:58:19 +04001762 ngx_log_error(NGX_LOG_INFO, fc->log, 0,
1763 "client terminated stream %ui with status %ui",
1764 sid, status);
1765 break;
Valentin Bartenev2686cb42013-03-20 10:36:57 +00001766 }
1767
Valentin Bartenev650984c2014-01-22 04:58:19 +04001768 ev = fc->read;
1769 ev->handler(ev);
1770
Valentin Bartenev2686cb42013-03-20 10:36:57 +00001771 return ngx_http_spdy_state_complete(sc, pos, end);
1772}
1773
1774
1775static u_char *
1776ngx_http_spdy_state_ping(ngx_http_spdy_connection_t *sc, u_char *pos,
1777 u_char *end)
1778{
1779 u_char *p;
1780 ngx_buf_t *buf;
1781 ngx_http_spdy_out_frame_t *frame;
1782
1783 if (end - pos < NGX_SPDY_PING_SIZE) {
1784 return ngx_http_spdy_state_save(sc, pos, end,
1785 ngx_http_spdy_state_ping);
1786 }
1787
1788 if (sc->length != NGX_SPDY_PING_SIZE) {
Valentin Bartenevd04a7142014-04-30 20:34:20 +04001789 ngx_log_error(NGX_LOG_INFO, sc->connection->log, 0,
1790 "client sent PING frame with incorrect length %uz",
1791 sc->length);
1792
Valentin Bartenev2686cb42013-03-20 10:36:57 +00001793 return ngx_http_spdy_state_protocol_error(sc);
1794 }
1795
1796 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0,
1797 "spdy PING frame");
1798
1799 frame = ngx_http_spdy_get_ctl_frame(sc, NGX_SPDY_PING_SIZE,
1800 NGX_SPDY_HIGHEST_PRIORITY);
1801 if (frame == NULL) {
1802 return ngx_http_spdy_state_internal_error(sc);
1803 }
1804
1805 buf = frame->first->buf;
1806
1807 p = buf->pos;
1808
1809 p = ngx_spdy_frame_write_head(p, NGX_SPDY_PING);
1810 p = ngx_spdy_frame_write_flags_and_len(p, 0, NGX_SPDY_PING_SIZE);
1811
1812 p = ngx_cpymem(p, pos, NGX_SPDY_PING_SIZE);
1813
1814 buf->last = p;
1815
1816 ngx_http_spdy_queue_frame(sc, frame);
1817
1818 pos += NGX_SPDY_PING_SIZE;
1819
1820 return ngx_http_spdy_state_complete(sc, pos, end);
1821}
1822
1823
1824static u_char *
1825ngx_http_spdy_state_skip(ngx_http_spdy_connection_t *sc, u_char *pos,
1826 u_char *end)
1827{
1828 size_t size;
1829
1830 size = end - pos;
1831
Valentin Bartenevd04a7142014-04-30 20:34:20 +04001832 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0,
1833 "spdy frame skip %uz of %uz", size, sc->length);
1834
Valentin Bartenev2686cb42013-03-20 10:36:57 +00001835 if (size < sc->length) {
1836 sc->length -= size;
1837 return ngx_http_spdy_state_save(sc, end, end,
1838 ngx_http_spdy_state_skip);
1839 }
1840
1841 return ngx_http_spdy_state_complete(sc, pos + sc->length, end);
1842}
1843
1844
1845static u_char *
1846ngx_http_spdy_state_settings(ngx_http_spdy_connection_t *sc, u_char *pos,
1847 u_char *end)
1848{
Valentin Bartenev449e8ee2014-01-31 19:17:26 +04001849 ngx_uint_t fid, val;
1850
Valentin Bartenev406c0612014-01-22 04:58:19 +04001851 if (sc->entries == 0) {
Valentin Bartenev2686cb42013-03-20 10:36:57 +00001852
1853 if (end - pos < NGX_SPDY_SETTINGS_NUM_SIZE) {
1854 return ngx_http_spdy_state_save(sc, pos, end,
1855 ngx_http_spdy_state_settings);
1856 }
1857
Valentin Bartenev406c0612014-01-22 04:58:19 +04001858 sc->entries = ngx_spdy_frame_parse_uint32(pos);
Valentin Bartenev2686cb42013-03-20 10:36:57 +00001859
1860 pos += NGX_SPDY_SETTINGS_NUM_SIZE;
1861 sc->length -= NGX_SPDY_SETTINGS_NUM_SIZE;
1862
Valentin Bartenev406c0612014-01-22 04:58:19 +04001863 if (sc->length < sc->entries * NGX_SPDY_SETTINGS_PAIR_SIZE) {
Valentin Bartenevd04a7142014-04-30 20:34:20 +04001864 ngx_log_error(NGX_LOG_INFO, sc->connection->log, 0,
1865 "client sent SETTINGS frame with incorrect "
1866 "length %uz or number of entries %ui",
1867 sc->length, sc->entries);
1868
Valentin Bartenev2686cb42013-03-20 10:36:57 +00001869 return ngx_http_spdy_state_protocol_error(sc);
1870 }
1871
1872 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0,
Valentin Bartenevd04a7142014-04-30 20:34:20 +04001873 "spdy SETTINGS frame has %ui entries", sc->entries);
Valentin Bartenev2686cb42013-03-20 10:36:57 +00001874 }
1875
Valentin Bartenev406c0612014-01-22 04:58:19 +04001876 while (sc->entries) {
Valentin Bartenev2686cb42013-03-20 10:36:57 +00001877 if (end - pos < NGX_SPDY_SETTINGS_PAIR_SIZE) {
1878 return ngx_http_spdy_state_save(sc, pos, end,
1879 ngx_http_spdy_state_settings);
1880 }
1881
Valentin Bartenev406c0612014-01-22 04:58:19 +04001882 sc->entries--;
Valentin Bartenevd055f742014-01-22 04:58:19 +04001883 sc->length -= NGX_SPDY_SETTINGS_PAIR_SIZE;
Valentin Bartenev2686cb42013-03-20 10:36:57 +00001884
Valentin Bartenev449e8ee2014-01-31 19:17:26 +04001885 fid = ngx_spdy_frame_parse_uint32(pos);
Valentin Bartenev2686cb42013-03-20 10:36:57 +00001886
Valentin Bartenev449e8ee2014-01-31 19:17:26 +04001887 pos += NGX_SPDY_SETTINGS_FID_SIZE;
Valentin Bartenevd055f742014-01-22 04:58:19 +04001888
Valentin Bartenev449e8ee2014-01-31 19:17:26 +04001889 val = ngx_spdy_frame_parse_uint32(pos);
Valentin Bartenev2686cb42013-03-20 10:36:57 +00001890
Valentin Bartenev449e8ee2014-01-31 19:17:26 +04001891 pos += NGX_SPDY_SETTINGS_VAL_SIZE;
1892
1893 ngx_log_debug3(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0,
1894 "spdy SETTINGS entry fl:%ui id:%ui val:%ui",
1895 ngx_spdy_frame_flags(fid), ngx_spdy_frame_id(fid), val);
1896
1897 if (ngx_spdy_frame_flags(fid) == NGX_SPDY_SETTINGS_FLAG_PERSISTED) {
1898 continue;
1899 }
1900
1901 switch (ngx_spdy_frame_id(fid)) {
1902
1903 case NGX_SPDY_SETTINGS_INIT_WINDOW:
1904
1905 if (val > NGX_SPDY_MAX_WINDOW) {
1906 ngx_log_error(NGX_LOG_INFO, sc->connection->log, 0,
1907 "client sent SETTINGS frame with "
1908 "incorrect INIT_WINDOW value: %ui", val);
1909
1910 return ngx_http_spdy_state_protocol_error(sc);
1911 }
1912
1913 if (ngx_http_spdy_adjust_windows(sc, val - sc->init_window)
1914 != NGX_OK)
1915 {
1916 return ngx_http_spdy_state_internal_error(sc);
1917 }
1918
1919 sc->init_window = val;
1920
1921 continue;
1922 }
Valentin Bartenev2686cb42013-03-20 10:36:57 +00001923 }
1924
1925 return ngx_http_spdy_state_complete(sc, pos, end);
1926}
1927
1928
1929static u_char *
1930ngx_http_spdy_state_complete(ngx_http_spdy_connection_t *sc, u_char *pos,
1931 u_char *end)
1932{
Valentin Bartenevd04a7142014-04-30 20:34:20 +04001933 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0,
1934 "spdy frame complete pos:%p end:%p", pos, end);
1935
Valentin Barteneva785be72014-04-30 20:34:20 +04001936 if (pos > end) {
1937 ngx_log_error(NGX_LOG_ALERT, sc->connection->log, 0,
1938 "receive buffer overrun");
1939
1940 ngx_debug_point();
1941 return ngx_http_spdy_state_internal_error(sc);
1942 }
1943
Valentin Bartenev2686cb42013-03-20 10:36:57 +00001944 sc->handler = ngx_http_spdy_state_head;
Valentin Bartenevdfb9a5c2014-04-30 20:33:58 +04001945 sc->stream = NULL;
1946
Valentin Bartenev2686cb42013-03-20 10:36:57 +00001947 return pos;
1948}
1949
1950
1951static u_char *
1952ngx_http_spdy_state_save(ngx_http_spdy_connection_t *sc,
1953 u_char *pos, u_char *end, ngx_http_spdy_handler_pt handler)
1954{
Maxim Dounin062e7a02014-03-19 12:57:39 +04001955 size_t size;
1956
Valentin Bartenevd04a7142014-04-30 20:34:20 +04001957 ngx_log_debug3(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0,
1958 "spdy frame state save pos:%p end:%p handler:%p",
1959 pos, end, handler);
1960
Maxim Dounin062e7a02014-03-19 12:57:39 +04001961 size = end - pos;
1962
1963 if (size > NGX_SPDY_STATE_BUFFER_SIZE) {
Valentin Bartenev2686cb42013-03-20 10:36:57 +00001964 ngx_log_error(NGX_LOG_ALERT, sc->connection->log, 0,
Valentin Bartenevd04a7142014-04-30 20:34:20 +04001965 "state buffer overflow: %uz bytes required", size);
1966
Valentin Bartenev3f023a42014-04-30 20:34:20 +04001967 ngx_debug_point();
Valentin Bartenev2686cb42013-03-20 10:36:57 +00001968 return ngx_http_spdy_state_internal_error(sc);
1969 }
Valentin Bartenev2686cb42013-03-20 10:36:57 +00001970
1971 ngx_memcpy(sc->buffer, pos, NGX_SPDY_STATE_BUFFER_SIZE);
1972
Maxim Douninec1211d2014-03-19 19:30:09 +04001973 sc->buffer_used = size;
Valentin Bartenev2686cb42013-03-20 10:36:57 +00001974 sc->handler = handler;
Valentin Bartenev6ddb5782014-01-14 16:24:45 +04001975 sc->incomplete = 1;
Valentin Bartenev2686cb42013-03-20 10:36:57 +00001976
1977 return end;
1978}
1979
1980
1981static u_char *
Valentin Bartenevcf770dd2014-04-30 20:34:20 +04001982ngx_http_spdy_state_inflate_error(ngx_http_spdy_connection_t *sc, int rc)
1983{
1984 if (rc == Z_DATA_ERROR || rc == Z_STREAM_END) {
1985 ngx_log_error(NGX_LOG_INFO, sc->connection->log, 0,
1986 "client sent SYN_STREAM frame with "
1987 "corrupted header block, inflate() failed: %d", rc);
1988
1989 return ngx_http_spdy_state_protocol_error(sc);
1990 }
1991
1992 ngx_log_error(NGX_LOG_ERR, sc->connection->log, 0,
1993 "inflate() failed: %d", rc);
1994
1995 return ngx_http_spdy_state_internal_error(sc);
1996}
1997
1998
1999static u_char *
Valentin Bartenev2686cb42013-03-20 10:36:57 +00002000ngx_http_spdy_state_protocol_error(ngx_http_spdy_connection_t *sc)
2001{
2002 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0,
2003 "spdy state protocol error");
2004
Valentin Bartenevdfb9a5c2014-04-30 20:33:58 +04002005 if (sc->stream) {
Valentin Bartenev63ee6902014-05-15 19:18:26 +04002006 sc->stream->out_closed = 1;
Valentin Bartenevdfb9a5c2014-04-30 20:33:58 +04002007 ngx_http_spdy_close_stream(sc->stream, NGX_HTTP_BAD_REQUEST);
2008 }
2009
Valentin Bartenev2686cb42013-03-20 10:36:57 +00002010 ngx_http_spdy_finalize_connection(sc, NGX_HTTP_CLIENT_CLOSED_REQUEST);
Valentin Bartenevdfb9a5c2014-04-30 20:33:58 +04002011
Valentin Bartenev2686cb42013-03-20 10:36:57 +00002012 return NULL;
2013}
2014
2015
2016static u_char *
2017ngx_http_spdy_state_internal_error(ngx_http_spdy_connection_t *sc)
2018{
2019 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0,
2020 "spdy state internal error");
2021
Valentin Bartenevcf770dd2014-04-30 20:34:20 +04002022 if (sc->stream) {
2023 sc->stream->out_closed = 1;
2024 ngx_http_spdy_close_stream(sc->stream, NGX_HTTP_INTERNAL_SERVER_ERROR);
2025 }
2026
Valentin Bartenev2686cb42013-03-20 10:36:57 +00002027 ngx_http_spdy_finalize_connection(sc, NGX_HTTP_INTERNAL_SERVER_ERROR);
Valentin Bartenevcf770dd2014-04-30 20:34:20 +04002028
Valentin Bartenev2686cb42013-03-20 10:36:57 +00002029 return NULL;
2030}
2031
2032
2033static ngx_int_t
Valentin Bartenev449e8ee2014-01-31 19:17:26 +04002034ngx_http_spdy_send_window_update(ngx_http_spdy_connection_t *sc, ngx_uint_t sid,
2035 ngx_uint_t delta)
2036{
2037 u_char *p;
2038 ngx_buf_t *buf;
2039 ngx_http_spdy_out_frame_t *frame;
2040
2041 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0,
Valentin Bartenevd04a7142014-04-30 20:34:20 +04002042 "spdy send WINDOW_UPDATE sid:%ui delta:%ui", sid, delta);
Valentin Bartenev449e8ee2014-01-31 19:17:26 +04002043
2044 frame = ngx_http_spdy_get_ctl_frame(sc, NGX_SPDY_WINDOW_UPDATE_SIZE,
2045 NGX_SPDY_HIGHEST_PRIORITY);
2046 if (frame == NULL) {
2047 return NGX_ERROR;
2048 }
2049
2050 buf = frame->first->buf;
2051
2052 p = buf->pos;
2053
2054 p = ngx_spdy_frame_write_head(p, NGX_SPDY_WINDOW_UPDATE);
2055 p = ngx_spdy_frame_write_flags_and_len(p, 0, NGX_SPDY_WINDOW_UPDATE_SIZE);
2056
2057 p = ngx_spdy_frame_write_sid(p, sid);
2058 p = ngx_spdy_frame_aligned_write_uint32(p, delta);
2059
2060 buf->last = p;
2061
2062 ngx_http_spdy_queue_frame(sc, frame);
2063
2064 return NGX_OK;
2065}
2066
2067
2068static ngx_int_t
Valentin Bartenev2686cb42013-03-20 10:36:57 +00002069ngx_http_spdy_send_rst_stream(ngx_http_spdy_connection_t *sc, ngx_uint_t sid,
2070 ngx_uint_t status, ngx_uint_t priority)
2071{
2072 u_char *p;
2073 ngx_buf_t *buf;
2074 ngx_http_spdy_out_frame_t *frame;
2075
2076 if (sc->connection->error) {
2077 return NGX_OK;
2078 }
2079
2080 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0,
Valentin Bartenevd04a7142014-04-30 20:34:20 +04002081 "spdy send RST_STREAM sid:%ui st:%ui", sid, status);
Valentin Bartenev2686cb42013-03-20 10:36:57 +00002082
2083 frame = ngx_http_spdy_get_ctl_frame(sc, NGX_SPDY_RST_STREAM_SIZE,
2084 priority);
2085 if (frame == NULL) {
2086 return NGX_ERROR;
2087 }
2088
2089 buf = frame->first->buf;
2090
2091 p = buf->pos;
2092
2093 p = ngx_spdy_frame_write_head(p, NGX_SPDY_RST_STREAM);
2094 p = ngx_spdy_frame_write_flags_and_len(p, 0, NGX_SPDY_RST_STREAM_SIZE);
2095
2096 p = ngx_spdy_frame_write_sid(p, sid);
2097 p = ngx_spdy_frame_aligned_write_uint32(p, status);
2098
2099 buf->last = p;
2100
2101 ngx_http_spdy_queue_frame(sc, frame);
2102
2103 return NGX_OK;
2104}
2105
2106
2107#if 0
2108static ngx_int_t
2109ngx_http_spdy_send_goaway(ngx_http_spdy_connection_t *sc)
2110{
2111 u_char *p;
2112 ngx_buf_t *buf;
2113 ngx_http_spdy_out_frame_t *frame;
2114
2115 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0,
Valentin Bartenevd04a7142014-04-30 20:34:20 +04002116 "spdy send GOAWAY sid:%ui", sc->last_sid);
Valentin Bartenev2686cb42013-03-20 10:36:57 +00002117
2118 frame = ngx_http_spdy_get_ctl_frame(sc, NGX_SPDY_GOAWAY_SIZE,
2119 NGX_SPDY_HIGHEST_PRIORITY);
2120 if (frame == NULL) {
2121 return NGX_ERROR;
2122 }
2123
2124 buf = frame->first->buf;
2125
2126 p = buf->pos;
2127
2128 p = ngx_spdy_frame_write_head(p, NGX_SPDY_GOAWAY);
2129 p = ngx_spdy_frame_write_flags_and_len(p, 0, NGX_SPDY_GOAWAY_SIZE);
2130
2131 p = ngx_spdy_frame_write_sid(p, sc->last_sid);
2132
2133 buf->last = p;
2134
2135 ngx_http_spdy_queue_frame(sc, frame);
2136
2137 return NGX_OK;
2138}
2139#endif
2140
2141
2142static ngx_int_t
2143ngx_http_spdy_send_settings(ngx_http_spdy_connection_t *sc)
2144{
2145 u_char *p;
2146 ngx_buf_t *buf;
Valentin Bartenev2686cb42013-03-20 10:36:57 +00002147 ngx_chain_t *cl;
2148 ngx_http_spdy_srv_conf_t *sscf;
2149 ngx_http_spdy_out_frame_t *frame;
2150
2151 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0,
Valentin Bartenevd04a7142014-04-30 20:34:20 +04002152 "spdy send SETTINGS frame");
Valentin Bartenev2686cb42013-03-20 10:36:57 +00002153
Valentin Bartenev82a1ff32014-01-15 17:16:38 +04002154 frame = ngx_palloc(sc->pool, sizeof(ngx_http_spdy_out_frame_t));
Valentin Bartenev2686cb42013-03-20 10:36:57 +00002155 if (frame == NULL) {
2156 return NGX_ERROR;
2157 }
2158
Valentin Bartenev82a1ff32014-01-15 17:16:38 +04002159 cl = ngx_alloc_chain_link(sc->pool);
Valentin Bartenev2686cb42013-03-20 10:36:57 +00002160 if (cl == NULL) {
2161 return NGX_ERROR;
2162 }
2163
Valentin Bartenev82a1ff32014-01-15 17:16:38 +04002164 buf = ngx_create_temp_buf(sc->pool, NGX_SPDY_FRAME_HEADER_SIZE
2165 + NGX_SPDY_SETTINGS_NUM_SIZE
Valentin Bartenev449e8ee2014-01-31 19:17:26 +04002166 + 2 * NGX_SPDY_SETTINGS_PAIR_SIZE);
Valentin Bartenev2686cb42013-03-20 10:36:57 +00002167 if (buf == NULL) {
2168 return NGX_ERROR;
2169 }
2170
2171 buf->last_buf = 1;
2172
2173 cl->buf = buf;
2174 cl->next = NULL;
2175
2176 frame->first = cl;
2177 frame->last = cl;
2178 frame->handler = ngx_http_spdy_settings_frame_handler;
Valentin Bartenev2686cb42013-03-20 10:36:57 +00002179 frame->stream = NULL;
Valentin Bartenevb2b43ca2014-01-15 17:16:38 +04002180#if (NGX_DEBUG)
Valentin Bartenev449e8ee2014-01-31 19:17:26 +04002181 frame->length = NGX_SPDY_SETTINGS_NUM_SIZE
2182 + 2 * NGX_SPDY_SETTINGS_PAIR_SIZE;
Valentin Bartenev2686cb42013-03-20 10:36:57 +00002183#endif
2184 frame->priority = NGX_SPDY_HIGHEST_PRIORITY;
2185 frame->blocked = 0;
2186
2187 p = buf->pos;
2188
2189 p = ngx_spdy_frame_write_head(p, NGX_SPDY_SETTINGS);
2190 p = ngx_spdy_frame_write_flags_and_len(p, NGX_SPDY_FLAG_CLEAR_SETTINGS,
Valentin Bartenev449e8ee2014-01-31 19:17:26 +04002191 NGX_SPDY_SETTINGS_NUM_SIZE
2192 + 2 * NGX_SPDY_SETTINGS_PAIR_SIZE);
Valentin Bartenev2686cb42013-03-20 10:36:57 +00002193
Valentin Bartenev449e8ee2014-01-31 19:17:26 +04002194 p = ngx_spdy_frame_aligned_write_uint32(p, 2);
Valentin Bartenev2686cb42013-03-20 10:36:57 +00002195
2196 sscf = ngx_http_get_module_srv_conf(sc->http_connection->conf_ctx,
2197 ngx_http_spdy_module);
2198
Valentin Bartenev449e8ee2014-01-31 19:17:26 +04002199 p = ngx_spdy_frame_write_flags_and_id(p, 0, NGX_SPDY_SETTINGS_MAX_STREAMS);
Valentin Bartenev2686cb42013-03-20 10:36:57 +00002200 p = ngx_spdy_frame_aligned_write_uint32(p, sscf->concurrent_streams);
2201
Valentin Bartenev449e8ee2014-01-31 19:17:26 +04002202 p = ngx_spdy_frame_write_flags_and_id(p, 0, NGX_SPDY_SETTINGS_INIT_WINDOW);
2203 p = ngx_spdy_frame_aligned_write_uint32(p, NGX_SPDY_STREAM_WINDOW);
2204
Valentin Bartenev2686cb42013-03-20 10:36:57 +00002205 buf->last = p;
2206
2207 ngx_http_spdy_queue_frame(sc, frame);
2208
2209 return NGX_OK;
2210}
2211
2212
2213ngx_int_t
2214ngx_http_spdy_settings_frame_handler(ngx_http_spdy_connection_t *sc,
2215 ngx_http_spdy_out_frame_t *frame)
2216{
2217 ngx_buf_t *buf;
2218
2219 buf = frame->first->buf;
2220
2221 if (buf->pos != buf->last) {
2222 return NGX_AGAIN;
2223 }
2224
2225 ngx_free_chain(sc->pool, frame->first);
2226
2227 return NGX_OK;
2228}
2229
2230
2231static ngx_http_spdy_out_frame_t *
Valentin Bartenev3ddf9cc2014-01-22 04:58:19 +04002232ngx_http_spdy_get_ctl_frame(ngx_http_spdy_connection_t *sc, size_t length,
Valentin Bartenev2686cb42013-03-20 10:36:57 +00002233 ngx_uint_t priority)
2234{
2235 ngx_chain_t *cl;
2236 ngx_http_spdy_out_frame_t *frame;
2237
2238 frame = sc->free_ctl_frames;
2239
2240 if (frame) {
Valentin Barteneve62156d2014-01-22 04:58:19 +04002241 sc->free_ctl_frames = frame->next;
Valentin Bartenev2686cb42013-03-20 10:36:57 +00002242
2243 cl = frame->first;
2244 cl->buf->pos = cl->buf->start;
2245
2246 } else {
2247 frame = ngx_palloc(sc->pool, sizeof(ngx_http_spdy_out_frame_t));
2248 if (frame == NULL) {
2249 return NULL;
2250 }
2251
2252 cl = ngx_alloc_chain_link(sc->pool);
2253 if (cl == NULL) {
2254 return NULL;
2255 }
2256
2257 cl->buf = ngx_create_temp_buf(sc->pool,
2258 NGX_SPDY_CTL_FRAME_BUFFER_SIZE);
2259 if (cl->buf == NULL) {
2260 return NULL;
2261 }
2262
2263 cl->buf->last_buf = 1;
2264
2265 frame->first = cl;
2266 frame->last = cl;
2267 frame->handler = ngx_http_spdy_ctl_frame_handler;
Valentin Bartenevb2b43ca2014-01-15 17:16:38 +04002268 frame->stream = NULL;
Valentin Bartenev2686cb42013-03-20 10:36:57 +00002269 }
2270
Valentin Bartenev2686cb42013-03-20 10:36:57 +00002271#if (NGX_DEBUG)
Valentin Bartenev3ddf9cc2014-01-22 04:58:19 +04002272 if (length > NGX_SPDY_CTL_FRAME_BUFFER_SIZE - NGX_SPDY_FRAME_HEADER_SIZE) {
Valentin Bartenev2686cb42013-03-20 10:36:57 +00002273 ngx_log_error(NGX_LOG_ALERT, sc->pool->log, 0,
Valentin Bartenevd04a7142014-04-30 20:34:20 +04002274 "requested control frame is too large: %uz", length);
Valentin Bartenev2686cb42013-03-20 10:36:57 +00002275 return NULL;
2276 }
2277
Valentin Bartenev3ddf9cc2014-01-22 04:58:19 +04002278 frame->length = length;
Valentin Bartenev2686cb42013-03-20 10:36:57 +00002279#endif
2280
2281 frame->priority = priority;
2282 frame->blocked = 0;
2283
2284 return frame;
2285}
2286
2287
2288static ngx_int_t
2289ngx_http_spdy_ctl_frame_handler(ngx_http_spdy_connection_t *sc,
2290 ngx_http_spdy_out_frame_t *frame)
2291{
2292 ngx_buf_t *buf;
2293
2294 buf = frame->first->buf;
2295
2296 if (buf->pos != buf->last) {
2297 return NGX_AGAIN;
2298 }
2299
Valentin Barteneve62156d2014-01-22 04:58:19 +04002300 frame->next = sc->free_ctl_frames;
Valentin Bartenev2686cb42013-03-20 10:36:57 +00002301 sc->free_ctl_frames = frame;
2302
2303 return NGX_OK;
2304}
2305
2306
2307static ngx_http_spdy_stream_t *
2308ngx_http_spdy_create_stream(ngx_http_spdy_connection_t *sc, ngx_uint_t id,
2309 ngx_uint_t priority)
2310{
2311 ngx_log_t *log;
2312 ngx_uint_t index;
2313 ngx_event_t *rev, *wev;
2314 ngx_connection_t *fc;
2315 ngx_http_log_ctx_t *ctx;
2316 ngx_http_request_t *r;
2317 ngx_http_spdy_stream_t *stream;
2318 ngx_http_core_srv_conf_t *cscf;
2319 ngx_http_spdy_srv_conf_t *sscf;
2320
2321 fc = sc->free_fake_connections;
2322
2323 if (fc) {
2324 sc->free_fake_connections = fc->data;
2325
2326 rev = fc->read;
2327 wev = fc->write;
2328 log = fc->log;
2329 ctx = log->data;
2330
2331 } else {
2332 fc = ngx_palloc(sc->pool, sizeof(ngx_connection_t));
2333 if (fc == NULL) {
2334 return NULL;
2335 }
2336
2337 rev = ngx_palloc(sc->pool, sizeof(ngx_event_t));
2338 if (rev == NULL) {
2339 return NULL;
2340 }
2341
2342 wev = ngx_palloc(sc->pool, sizeof(ngx_event_t));
2343 if (wev == NULL) {
2344 return NULL;
2345 }
2346
2347 log = ngx_palloc(sc->pool, sizeof(ngx_log_t));
2348 if (log == NULL) {
2349 return NULL;
2350 }
2351
2352 ctx = ngx_palloc(sc->pool, sizeof(ngx_http_log_ctx_t));
2353 if (ctx == NULL) {
2354 return NULL;
2355 }
2356
2357 ctx->connection = fc;
2358 ctx->request = NULL;
2359 }
2360
2361 ngx_memcpy(log, sc->connection->log, sizeof(ngx_log_t));
2362
2363 log->data = ctx;
2364
2365 ngx_memzero(rev, sizeof(ngx_event_t));
2366
2367 rev->data = fc;
2368 rev->ready = 1;
Valentin Bartenev92b82c82013-10-01 00:04:00 +04002369 rev->handler = ngx_http_spdy_close_stream_handler;
Valentin Bartenev2686cb42013-03-20 10:36:57 +00002370 rev->log = log;
2371
2372 ngx_memcpy(wev, rev, sizeof(ngx_event_t));
2373
2374 wev->write = 1;
2375
2376 ngx_memcpy(fc, sc->connection, sizeof(ngx_connection_t));
2377
2378 fc->data = sc->http_connection;
2379 fc->read = rev;
2380 fc->write = wev;
2381 fc->sent = 0;
2382 fc->log = log;
2383 fc->buffered = 0;
2384 fc->sndlowat = 1;
Valentin Bartenev670d4282013-04-23 10:15:49 +00002385 fc->tcp_nodelay = NGX_TCP_NODELAY_DISABLED;
Valentin Bartenev2686cb42013-03-20 10:36:57 +00002386
2387 r = ngx_http_create_request(fc);
2388 if (r == NULL) {
2389 return NULL;
2390 }
2391
2392 r->valid_location = 1;
2393
2394 fc->data = r;
2395 sc->connection->requests++;
2396
2397 cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module);
2398
2399 r->header_in = ngx_create_temp_buf(r->pool,
2400 cscf->client_header_buffer_size);
2401 if (r->header_in == NULL) {
2402 ngx_http_free_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
2403 return NULL;
2404 }
2405
2406 r->headers_in.connection_type = NGX_HTTP_CONNECTION_CLOSE;
2407
2408 stream = ngx_pcalloc(r->pool, sizeof(ngx_http_spdy_stream_t));
2409 if (stream == NULL) {
2410 ngx_http_free_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
2411 return NULL;
2412 }
2413
2414 r->spdy_stream = stream;
2415
2416 stream->id = id;
2417 stream->request = r;
2418 stream->connection = sc;
Valentin Bartenev449e8ee2014-01-31 19:17:26 +04002419
2420 stream->send_window = sc->init_window;
2421 stream->recv_window = NGX_SPDY_STREAM_WINDOW;
2422
Valentin Bartenev2686cb42013-03-20 10:36:57 +00002423 stream->priority = priority;
2424
2425 sscf = ngx_http_get_module_srv_conf(r, ngx_http_spdy_module);
2426
2427 index = ngx_http_spdy_stream_index(sscf, id);
2428
2429 stream->index = sc->streams_index[index];
2430 sc->streams_index[index] = stream;
2431
2432 sc->processing++;
2433
2434 return stream;
2435}
2436
2437
2438static ngx_http_spdy_stream_t *
2439ngx_http_spdy_get_stream_by_id(ngx_http_spdy_connection_t *sc,
2440 ngx_uint_t sid)
2441{
2442 ngx_http_spdy_stream_t *stream;
2443 ngx_http_spdy_srv_conf_t *sscf;
2444
2445 sscf = ngx_http_get_module_srv_conf(sc->http_connection->conf_ctx,
2446 ngx_http_spdy_module);
2447
2448 stream = sc->streams_index[ngx_http_spdy_stream_index(sscf, sid)];
2449
2450 while (stream) {
2451 if (stream->id == sid) {
2452 return stream;
2453 }
2454
2455 stream = stream->index;
2456 }
2457
2458 return NULL;
2459}
2460
2461
2462static ngx_int_t
2463ngx_http_spdy_parse_header(ngx_http_request_t *r)
2464{
2465 u_char *p, *end, ch;
Valentin Bartenev0c05e5b2014-03-03 19:24:55 +04002466 ngx_uint_t hash;
Valentin Bartenev2686cb42013-03-20 10:36:57 +00002467 ngx_http_core_srv_conf_t *cscf;
2468
2469 enum {
2470 sw_name_len = 0,
2471 sw_name,
2472 sw_value_len,
2473 sw_value
2474 } state;
2475
2476 state = r->state;
2477
2478 p = r->header_in->pos;
2479 end = r->header_in->last;
2480
2481 switch (state) {
2482
2483 case sw_name_len:
2484
2485 if (end - p < NGX_SPDY_NV_NLEN_SIZE) {
2486 return NGX_AGAIN;
2487 }
2488
Valentin Bartenev0c05e5b2014-03-03 19:24:55 +04002489 r->lowcase_index = ngx_spdy_frame_parse_uint32(p);
Valentin Bartenev2686cb42013-03-20 10:36:57 +00002490
Valentin Bartenev0c05e5b2014-03-03 19:24:55 +04002491 if (r->lowcase_index == 0) {
Valentin Bartenevef510792014-04-30 20:34:20 +04002492 return NGX_ERROR;
Valentin Bartenev2686cb42013-03-20 10:36:57 +00002493 }
2494
Valentin Bartenev3be925b2013-08-15 19:14:58 +04002495 /* null-terminate the previous header value */
2496 *p = '\0';
2497
Valentin Bartenev2686cb42013-03-20 10:36:57 +00002498 p += NGX_SPDY_NV_NLEN_SIZE;
2499
Valentin Bartenev2686cb42013-03-20 10:36:57 +00002500 r->invalid_header = 0;
2501
2502 state = sw_name;
2503
2504 /* fall through */
2505
2506 case sw_name:
2507
Valentin Bartenev0c05e5b2014-03-03 19:24:55 +04002508 if ((ngx_uint_t) (end - p) < r->lowcase_index) {
Valentin Bartenev2686cb42013-03-20 10:36:57 +00002509 break;
2510 }
2511
2512 cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module);
2513
2514 r->header_name_start = p;
Valentin Bartenev0c05e5b2014-03-03 19:24:55 +04002515 r->header_name_end = p + r->lowcase_index;
Valentin Bartenev2686cb42013-03-20 10:36:57 +00002516
Valentin Bartenev449e8ee2014-01-31 19:17:26 +04002517 if (p[0] == ':') {
Valentin Bartenev449e8ee2014-01-31 19:17:26 +04002518 p++;
2519 }
2520
Valentin Bartenev2686cb42013-03-20 10:36:57 +00002521 hash = 0;
2522
2523 for ( /* void */ ; p != r->header_name_end; p++) {
2524
2525 ch = *p;
2526
2527 hash = ngx_hash(hash, ch);
2528
2529 if ((ch >= 'a' && ch <= 'z')
2530 || (ch == '-')
2531 || (ch >= '0' && ch <= '9')
2532 || (ch == '_' && cscf->underscores_in_headers))
2533 {
2534 continue;
2535 }
2536
2537 switch (ch) {
2538 case '\0':
2539 case LF:
2540 case CR:
2541 case ':':
Valentin Bartenevd04a7142014-04-30 20:34:20 +04002542 ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
2543 "client sent invalid header name: \"%*s\"",
2544 r->lowcase_index, r->header_name_start);
2545
Valentin Bartenevef510792014-04-30 20:34:20 +04002546 return NGX_HTTP_PARSE_INVALID_HEADER;
Valentin Bartenev2686cb42013-03-20 10:36:57 +00002547 }
2548
2549 if (ch >= 'A' && ch <= 'Z') {
Valentin Bartenevef510792014-04-30 20:34:20 +04002550 return NGX_ERROR;
Valentin Bartenev2686cb42013-03-20 10:36:57 +00002551 }
2552
2553 r->invalid_header = 1;
2554 }
2555
2556 r->header_hash = hash;
2557
2558 state = sw_value_len;
2559
2560 /* fall through */
2561
2562 case sw_value_len:
2563
2564 if (end - p < NGX_SPDY_NV_VLEN_SIZE) {
2565 break;
2566 }
2567
Valentin Bartenev0c05e5b2014-03-03 19:24:55 +04002568 r->lowcase_index = ngx_spdy_frame_parse_uint32(p);
Valentin Bartenev2686cb42013-03-20 10:36:57 +00002569
Valentin Bartenev3be925b2013-08-15 19:14:58 +04002570 /* null-terminate header name */
2571 *p = '\0';
2572
Valentin Bartenev2686cb42013-03-20 10:36:57 +00002573 p += NGX_SPDY_NV_VLEN_SIZE;
2574
Valentin Bartenev2686cb42013-03-20 10:36:57 +00002575 state = sw_value;
2576
2577 /* fall through */
2578
2579 case sw_value:
2580
Valentin Bartenev0c05e5b2014-03-03 19:24:55 +04002581 if ((ngx_uint_t) (end - p) < r->lowcase_index) {
Valentin Bartenev2686cb42013-03-20 10:36:57 +00002582 break;
2583 }
2584
2585 r->header_start = p;
2586
Valentin Bartenev0c05e5b2014-03-03 19:24:55 +04002587 while (r->lowcase_index--) {
Valentin Bartenev2686cb42013-03-20 10:36:57 +00002588 ch = *p;
2589
2590 if (ch == '\0') {
2591
2592 if (p == r->header_start) {
2593 return NGX_ERROR;
2594 }
2595
Valentin Bartenev0c05e5b2014-03-03 19:24:55 +04002596 r->header_end = p;
Valentin Bartenev2686cb42013-03-20 10:36:57 +00002597 r->header_in->pos = p + 1;
2598
Piotr Sikora12ca9c92014-07-08 02:17:44 -07002599 r->state = sw_value;
2600
Valentin Bartenev2686cb42013-03-20 10:36:57 +00002601 return NGX_OK;
2602 }
2603
2604 if (ch == CR || ch == LF) {
Valentin Bartenevd04a7142014-04-30 20:34:20 +04002605 ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
2606 "client sent header \"%*s\" with "
2607 "invalid value: \"%*s\\%c...\"",
2608 r->header_name_end - r->header_name_start,
2609 r->header_name_start,
2610 p - r->header_start,
2611 r->header_start,
2612 ch == CR ? 'r' : 'n');
2613
Valentin Bartenev2686cb42013-03-20 10:36:57 +00002614 return NGX_HTTP_PARSE_INVALID_HEADER;
2615 }
Valentin Bartenev0c05e5b2014-03-03 19:24:55 +04002616
2617 p++;
Valentin Bartenev2686cb42013-03-20 10:36:57 +00002618 }
2619
Valentin Bartenev0c05e5b2014-03-03 19:24:55 +04002620 r->header_end = p;
Valentin Bartenev2686cb42013-03-20 10:36:57 +00002621 r->header_in->pos = p;
2622
2623 r->state = 0;
2624
2625 return NGX_DONE;
2626 }
2627
2628 r->header_in->pos = p;
2629 r->state = state;
2630
2631 return NGX_AGAIN;
2632}
2633
2634
2635static ngx_int_t
2636ngx_http_spdy_alloc_large_header_buffer(ngx_http_request_t *r)
2637{
Valentin Bartenevd04a7142014-04-30 20:34:20 +04002638 u_char *old, *new, *p;
Valentin Bartenev2686cb42013-03-20 10:36:57 +00002639 size_t rest;
2640 ngx_buf_t *buf;
2641 ngx_http_spdy_stream_t *stream;
2642 ngx_http_core_srv_conf_t *cscf;
2643
2644 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
2645 "spdy alloc large header buffer");
2646
2647 stream = r->spdy_stream;
2648
2649 cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module);
2650
2651 if (stream->header_buffers
2652 == (ngx_uint_t) cscf->large_client_header_buffers.num)
2653 {
Valentin Bartenevd04a7142014-04-30 20:34:20 +04002654 ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
2655 "client sent too large request");
2656
Valentin Bartenev2686cb42013-03-20 10:36:57 +00002657 return NGX_DECLINED;
2658 }
2659
2660 rest = r->header_in->last - r->header_in->pos;
2661
Valentin Bartenevd04a7142014-04-30 20:34:20 +04002662 /*
Valentin Bartenev20d41492014-11-07 17:22:19 +03002663 * One more byte is needed for null-termination
2664 * and another one for further progress.
Valentin Bartenevd04a7142014-04-30 20:34:20 +04002665 */
Valentin Bartenev20d41492014-11-07 17:22:19 +03002666 if (rest > cscf->large_client_header_buffers.size - 2) {
Valentin Bartenevd04a7142014-04-30 20:34:20 +04002667 p = r->header_in->pos;
2668
2669 if (rest > NGX_MAX_ERROR_STR - 300) {
2670 rest = NGX_MAX_ERROR_STR - 300;
Valentin Bartenevd04a7142014-04-30 20:34:20 +04002671 }
2672
2673 ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
Maxim Douninfb969362014-11-07 17:38:55 +03002674 "client sent too long header name or value: \"%*s...\"",
Valentin Bartenevd04a7142014-04-30 20:34:20 +04002675 rest, p);
2676
Valentin Bartenev2686cb42013-03-20 10:36:57 +00002677 return NGX_DECLINED;
2678 }
2679
2680 buf = ngx_create_temp_buf(r->pool, cscf->large_client_header_buffers.size);
2681 if (buf == NULL) {
2682 return NGX_ERROR;
2683 }
2684
2685 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
Valentin Bartenevd04a7142014-04-30 20:34:20 +04002686 "spdy large header alloc: %p %uz",
Valentin Bartenev2686cb42013-03-20 10:36:57 +00002687 buf->pos, buf->end - buf->last);
2688
2689 old = r->header_in->pos;
2690 new = buf->pos;
2691
2692 if (rest) {
2693 buf->last = ngx_cpymem(new, old, rest);
2694 }
2695
Valentin Bartenev2686cb42013-03-20 10:36:57 +00002696 r->header_in = buf;
2697
2698 stream->header_buffers++;
2699
2700 return NGX_OK;
2701}
2702
2703
2704static ngx_int_t
2705ngx_http_spdy_handle_request_header(ngx_http_request_t *r)
2706{
2707 ngx_uint_t i;
2708 ngx_table_elt_t *h;
2709 ngx_http_core_srv_conf_t *cscf;
2710 ngx_http_spdy_request_header_t *sh;
2711
2712 if (r->invalid_header) {
2713 cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module);
2714
2715 if (cscf->ignore_invalid_headers) {
2716 ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
2717 "client sent invalid header: \"%*s\"",
2718 r->header_end - r->header_name_start,
2719 r->header_name_start);
2720 return NGX_OK;
2721 }
2722
Valentin Bartenev449e8ee2014-01-31 19:17:26 +04002723 }
2724
2725 if (r->header_name_start[0] == ':') {
Valentin Bartenev0c05e5b2014-03-03 19:24:55 +04002726 r->header_name_start++;
2727
Valentin Bartenev2686cb42013-03-20 10:36:57 +00002728 for (i = 0; i < NGX_SPDY_REQUEST_HEADERS; i++) {
2729 sh = &ngx_http_spdy_request_headers[i];
2730
2731 if (sh->hash != r->header_hash
Valentin Bartenev0c05e5b2014-03-03 19:24:55 +04002732 || sh->len != r->header_name_end - r->header_name_start
2733 || ngx_strncmp(sh->header, r->header_name_start, sh->len) != 0)
Valentin Bartenev2686cb42013-03-20 10:36:57 +00002734 {
2735 continue;
2736 }
2737
2738 return sh->handler(r);
2739 }
Valentin Bartenev449e8ee2014-01-31 19:17:26 +04002740
Valentin Bartenevd04a7142014-04-30 20:34:20 +04002741 ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
2742 "client sent invalid header name: \":%*s\"",
2743 r->header_end - r->header_name_start,
2744 r->header_name_start);
2745
Valentin Bartenevef510792014-04-30 20:34:20 +04002746 return NGX_HTTP_PARSE_INVALID_HEADER;
Valentin Bartenev2686cb42013-03-20 10:36:57 +00002747 }
2748
2749 h = ngx_list_push(&r->headers_in.headers);
2750 if (h == NULL) {
Valentin Bartenev2686cb42013-03-20 10:36:57 +00002751 return NGX_ERROR;
2752 }
2753
2754 h->hash = r->header_hash;
2755
Valentin Bartenev0c05e5b2014-03-03 19:24:55 +04002756 h->key.len = r->header_name_end - r->header_name_start;
Valentin Bartenev2686cb42013-03-20 10:36:57 +00002757 h->key.data = r->header_name_start;
Valentin Bartenev2686cb42013-03-20 10:36:57 +00002758
Valentin Bartenev0c05e5b2014-03-03 19:24:55 +04002759 h->value.len = r->header_end - r->header_start;
Valentin Bartenev2686cb42013-03-20 10:36:57 +00002760 h->value.data = r->header_start;
Valentin Bartenev2686cb42013-03-20 10:36:57 +00002761
2762 h->lowcase_key = h->key.data;
2763
2764 return NGX_OK;
2765}
2766
2767
2768void
Sergey Kandaurov3be6cc92013-05-23 15:47:58 +04002769ngx_http_spdy_request_headers_init(void)
Valentin Bartenev2686cb42013-03-20 10:36:57 +00002770{
2771 ngx_uint_t i;
2772 ngx_http_spdy_request_header_t *h;
2773
2774 for (i = 0; i < NGX_SPDY_REQUEST_HEADERS; i++) {
2775 h = &ngx_http_spdy_request_headers[i];
2776 h->hash = ngx_hash_key(h->header, h->len);
2777 }
2778}
2779
2780
2781static ngx_int_t
2782ngx_http_spdy_parse_method(ngx_http_request_t *r)
2783{
2784 size_t k, len;
2785 ngx_uint_t n;
2786 const u_char *p, *m;
2787
2788 /*
2789 * This array takes less than 256 sequential bytes,
2790 * and if typical CPU cache line size is 64 bytes,
2791 * it is prefetched for 4 load operations.
2792 */
2793 static const struct {
2794 u_char len;
2795 const u_char method[11];
2796 uint32_t value;
2797 } tests[] = {
2798 { 3, "GET", NGX_HTTP_GET },
2799 { 4, "POST", NGX_HTTP_POST },
2800 { 4, "HEAD", NGX_HTTP_HEAD },
2801 { 7, "OPTIONS", NGX_HTTP_OPTIONS },
2802 { 8, "PROPFIND", NGX_HTTP_PROPFIND },
2803 { 3, "PUT", NGX_HTTP_PUT },
2804 { 5, "MKCOL", NGX_HTTP_MKCOL },
2805 { 6, "DELETE", NGX_HTTP_DELETE },
2806 { 4, "COPY", NGX_HTTP_COPY },
2807 { 4, "MOVE", NGX_HTTP_MOVE },
2808 { 9, "PROPPATCH", NGX_HTTP_PROPPATCH },
2809 { 4, "LOCK", NGX_HTTP_LOCK },
2810 { 6, "UNLOCK", NGX_HTTP_UNLOCK },
2811 { 5, "PATCH", NGX_HTTP_PATCH },
2812 { 5, "TRACE", NGX_HTTP_TRACE }
2813 }, *test;
2814
2815 if (r->method_name.len) {
Valentin Bartenevd04a7142014-04-30 20:34:20 +04002816 ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
2817 "client sent duplicate :method header");
2818
Valentin Bartenev2686cb42013-03-20 10:36:57 +00002819 return NGX_HTTP_PARSE_INVALID_HEADER;
2820 }
2821
Valentin Bartenev0c05e5b2014-03-03 19:24:55 +04002822 len = r->header_end - r->header_start;
Valentin Bartenev2686cb42013-03-20 10:36:57 +00002823
2824 r->method_name.len = len;
2825 r->method_name.data = r->header_start;
2826
2827 test = tests;
2828 n = sizeof(tests) / sizeof(tests[0]);
2829
2830 do {
2831 if (len == test->len) {
2832 p = r->method_name.data;
2833 m = test->method;
2834 k = len;
2835
2836 do {
2837 if (*p++ != *m++) {
2838 goto next;
2839 }
2840 } while (--k);
2841
2842 r->method = test->value;
2843 return NGX_OK;
2844 }
2845
2846 next:
2847 test++;
2848
2849 } while (--n);
2850
2851 p = r->method_name.data;
2852
2853 do {
2854 if ((*p < 'A' || *p > 'Z') && *p != '_') {
2855 ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
Valentin Bartenevd04a7142014-04-30 20:34:20 +04002856 "client sent invalid method: \"%V\"",
2857 &r->method_name);
2858
Valentin Bartenevef510792014-04-30 20:34:20 +04002859 return NGX_HTTP_PARSE_INVALID_HEADER;
Valentin Bartenev2686cb42013-03-20 10:36:57 +00002860 }
2861
2862 p++;
2863
2864 } while (--len);
2865
2866 return NGX_OK;
2867}
2868
2869
2870static ngx_int_t
2871ngx_http_spdy_parse_scheme(ngx_http_request_t *r)
2872{
2873 if (r->schema_start) {
Valentin Bartenevd04a7142014-04-30 20:34:20 +04002874 ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
2875 "client sent duplicate :schema header");
2876
Valentin Bartenev2686cb42013-03-20 10:36:57 +00002877 return NGX_HTTP_PARSE_INVALID_HEADER;
2878 }
2879
2880 r->schema_start = r->header_start;
2881 r->schema_end = r->header_end;
2882
2883 return NGX_OK;
2884}
2885
2886
2887static ngx_int_t
Valentin Bartenev449e8ee2014-01-31 19:17:26 +04002888ngx_http_spdy_parse_host(ngx_http_request_t *r)
2889{
2890 ngx_table_elt_t *h;
2891
2892 if (r->headers_in.host) {
Valentin Bartenevd04a7142014-04-30 20:34:20 +04002893 ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
2894 "client sent duplicate :host header");
2895
Valentin Bartenev449e8ee2014-01-31 19:17:26 +04002896 return NGX_HTTP_PARSE_INVALID_HEADER;
2897 }
2898
2899 h = ngx_list_push(&r->headers_in.headers);
2900 if (h == NULL) {
Valentin Bartenev449e8ee2014-01-31 19:17:26 +04002901 return NGX_ERROR;
2902 }
2903
2904 r->headers_in.host = h;
2905
2906 h->hash = r->header_hash;
2907
Valentin Bartenev0c05e5b2014-03-03 19:24:55 +04002908 h->key.len = r->header_name_end - r->header_name_start;
2909 h->key.data = r->header_name_start;
Valentin Bartenev449e8ee2014-01-31 19:17:26 +04002910
Valentin Bartenev0c05e5b2014-03-03 19:24:55 +04002911 h->value.len = r->header_end - r->header_start;
Valentin Bartenev449e8ee2014-01-31 19:17:26 +04002912 h->value.data = r->header_start;
2913
2914 h->lowcase_key = h->key.data;
2915
2916 return NGX_OK;
2917}
2918
2919
2920static ngx_int_t
2921ngx_http_spdy_parse_path(ngx_http_request_t *r)
Valentin Bartenev2686cb42013-03-20 10:36:57 +00002922{
2923 if (r->unparsed_uri.len) {
Valentin Bartenevd04a7142014-04-30 20:34:20 +04002924 ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
2925 "client sent duplicate :path header");
2926
Valentin Bartenev2686cb42013-03-20 10:36:57 +00002927 return NGX_HTTP_PARSE_INVALID_HEADER;
2928 }
2929
2930 r->uri_start = r->header_start;
2931 r->uri_end = r->header_end;
2932
2933 if (ngx_http_parse_uri(r) != NGX_OK) {
Valentin Bartenevd04a7142014-04-30 20:34:20 +04002934 ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
2935 "client sent invalid URI: \"%*s\"",
2936 r->uri_end - r->uri_start, r->uri_start);
2937
Valentin Bartenevef510792014-04-30 20:34:20 +04002938 return NGX_HTTP_PARSE_INVALID_HEADER;
Valentin Bartenev2686cb42013-03-20 10:36:57 +00002939 }
2940
2941 if (ngx_http_process_request_uri(r) != NGX_OK) {
Valentin Bartenevef510792014-04-30 20:34:20 +04002942 /*
2943 * request has been finalized already
2944 * in ngx_http_process_request_uri()
2945 */
2946 return NGX_ABORT;
Valentin Bartenev2686cb42013-03-20 10:36:57 +00002947 }
2948
2949 return NGX_OK;
2950}
2951
2952
2953static ngx_int_t
2954ngx_http_spdy_parse_version(ngx_http_request_t *r)
2955{
2956 u_char *p, ch;
2957
2958 if (r->http_protocol.len) {
Valentin Bartenevd04a7142014-04-30 20:34:20 +04002959 ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
2960 "client sent duplicate :version header");
2961
Valentin Bartenev2686cb42013-03-20 10:36:57 +00002962 return NGX_HTTP_PARSE_INVALID_HEADER;
2963 }
2964
2965 p = r->header_start;
2966
Valentin Bartenev0c05e5b2014-03-03 19:24:55 +04002967 if (r->header_end - p < 8 || !(ngx_str5cmp(p, 'H', 'T', 'T', 'P', '/'))) {
Valentin Bartenevd04a7142014-04-30 20:34:20 +04002968 goto invalid;
Valentin Bartenev2686cb42013-03-20 10:36:57 +00002969 }
2970
2971 ch = *(p + 5);
2972
2973 if (ch < '1' || ch > '9') {
Valentin Bartenevd04a7142014-04-30 20:34:20 +04002974 goto invalid;
Valentin Bartenev2686cb42013-03-20 10:36:57 +00002975 }
2976
2977 r->http_major = ch - '0';
2978
2979 for (p += 6; p != r->header_end - 2; p++) {
2980
2981 ch = *p;
2982
Xiaochen Wangcd358e52014-02-11 20:54:16 +08002983 if (ch == '.') {
2984 break;
2985 }
2986
Valentin Bartenev2686cb42013-03-20 10:36:57 +00002987 if (ch < '0' || ch > '9') {
Valentin Bartenevd04a7142014-04-30 20:34:20 +04002988 goto invalid;
Valentin Bartenev2686cb42013-03-20 10:36:57 +00002989 }
2990
2991 r->http_major = r->http_major * 10 + ch - '0';
2992 }
2993
2994 if (*p != '.') {
Valentin Bartenevd04a7142014-04-30 20:34:20 +04002995 goto invalid;
Valentin Bartenev2686cb42013-03-20 10:36:57 +00002996 }
2997
2998 ch = *(p + 1);
2999
3000 if (ch < '0' || ch > '9') {
Valentin Bartenevd04a7142014-04-30 20:34:20 +04003001 goto invalid;
Valentin Bartenev2686cb42013-03-20 10:36:57 +00003002 }
3003
3004 r->http_minor = ch - '0';
3005
3006 for (p += 2; p != r->header_end; p++) {
3007
3008 ch = *p;
3009
3010 if (ch < '0' || ch > '9') {
Valentin Bartenevd04a7142014-04-30 20:34:20 +04003011 goto invalid;
Valentin Bartenev2686cb42013-03-20 10:36:57 +00003012 }
3013
3014 r->http_minor = r->http_minor * 10 + ch - '0';
3015 }
3016
Valentin Bartenev0c05e5b2014-03-03 19:24:55 +04003017 r->http_protocol.len = r->header_end - r->header_start;
Valentin Bartenev2686cb42013-03-20 10:36:57 +00003018 r->http_protocol.data = r->header_start;
3019 r->http_version = r->http_major * 1000 + r->http_minor;
3020
3021 return NGX_OK;
Valentin Bartenevd04a7142014-04-30 20:34:20 +04003022
3023invalid:
3024
3025 ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
3026 "client sent invalid http version: \"%*s\"",
3027 r->header_end - r->header_start, r->header_start);
3028
3029 return NGX_HTTP_PARSE_INVALID_HEADER;
Valentin Bartenev2686cb42013-03-20 10:36:57 +00003030}
3031
3032
3033static ngx_int_t
3034ngx_http_spdy_construct_request_line(ngx_http_request_t *r)
3035{
3036 u_char *p;
3037
3038 if (r->method_name.len == 0
3039 || r->unparsed_uri.len == 0
3040 || r->http_protocol.len == 0)
3041 {
3042 ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST);
3043 return NGX_ERROR;
3044 }
3045
3046 r->request_line.len = r->method_name.len + 1
3047 + r->unparsed_uri.len + 1
3048 + r->http_protocol.len;
3049
3050 p = ngx_pnalloc(r->pool, r->request_line.len + 1);
3051 if (p == NULL) {
Valentin Bartenevd9c25cd2014-04-30 02:16:21 +04003052 ngx_http_spdy_close_stream(r->spdy_stream,
3053 NGX_HTTP_INTERNAL_SERVER_ERROR);
Valentin Bartenev2686cb42013-03-20 10:36:57 +00003054 return NGX_ERROR;
3055 }
3056
3057 r->request_line.data = p;
3058
3059 p = ngx_cpymem(p, r->method_name.data, r->method_name.len);
3060
3061 *p++ = ' ';
3062
3063 p = ngx_cpymem(p, r->unparsed_uri.data, r->unparsed_uri.len);
3064
3065 *p++ = ' ';
3066
3067 ngx_memcpy(p, r->http_protocol.data, r->http_protocol.len + 1);
3068
3069 /* some modules expect the space character after method name */
3070 r->method_name.data = r->request_line.data;
3071
3072 return NGX_OK;
3073}
3074
3075
3076static void
3077ngx_http_spdy_run_request(ngx_http_request_t *r)
3078{
3079 ngx_uint_t i;
3080 ngx_list_part_t *part;
3081 ngx_table_elt_t *h;
3082 ngx_http_header_t *hh;
3083 ngx_http_core_main_conf_t *cmcf;
3084
3085 if (ngx_http_spdy_construct_request_line(r) != NGX_OK) {
3086 return;
3087 }
3088
3089 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
3090 "spdy http request line: \"%V\"", &r->request_line);
3091
3092 cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module);
3093
3094 part = &r->headers_in.headers.part;
3095 h = part->elts;
3096
3097 for (i = 0 ;; i++) {
3098
3099 if (i >= part->nelts) {
3100 if (part->next == NULL) {
3101 break;
3102 }
3103
3104 part = part->next;
3105 h = part->elts;
3106 i = 0;
3107 }
3108
3109 hh = ngx_hash_find(&cmcf->headers_in_hash, h[i].hash,
3110 h[i].lowcase_key, h[i].key.len);
3111
3112 if (hh && hh->handler(r, &h[i], hh->offset) != NGX_OK) {
3113 return;
3114 }
3115
3116 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
Valentin Bartenevd04a7142014-04-30 20:34:20 +04003117 "spdy http header: \"%V: %V\"", &h[i].key, &h[i].value);
Valentin Bartenev2686cb42013-03-20 10:36:57 +00003118 }
3119
3120 r->http_state = NGX_HTTP_PROCESS_REQUEST_STATE;
3121
3122 if (ngx_http_process_request_header(r) != NGX_OK) {
3123 return;
3124 }
3125
Valentin Bartenevb2cd5202014-04-07 19:27:56 +04003126 if (r->headers_in.content_length_n > 0 && r->spdy_stream->in_closed) {
3127 ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
3128 "client prematurely closed stream");
3129
3130 r->spdy_stream->skip_data = NGX_SPDY_DATA_ERROR;
3131
3132 ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST);
3133 return;
3134 }
3135
Valentin Bartenev2686cb42013-03-20 10:36:57 +00003136 ngx_http_process_request(r);
3137}
3138
3139
3140static ngx_int_t
3141ngx_http_spdy_init_request_body(ngx_http_request_t *r)
3142{
3143 ngx_buf_t *buf;
3144 ngx_temp_file_t *tf;
3145 ngx_http_request_body_t *rb;
3146 ngx_http_core_loc_conf_t *clcf;
3147
3148 rb = ngx_pcalloc(r->pool, sizeof(ngx_http_request_body_t));
3149 if (rb == NULL) {
3150 return NGX_ERROR;
3151 }
3152
3153 r->request_body = rb;
3154
3155 if (r->spdy_stream->in_closed) {
3156 return NGX_OK;
3157 }
3158
3159 rb->rest = r->headers_in.content_length_n;
3160
3161 clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
3162
3163 if (r->request_body_in_file_only
3164 || rb->rest > (off_t) clcf->client_body_buffer_size
3165 || rb->rest < 0)
3166 {
3167 tf = ngx_pcalloc(r->pool, sizeof(ngx_temp_file_t));
3168 if (tf == NULL) {
3169 return NGX_ERROR;
3170 }
3171
3172 tf->file.fd = NGX_INVALID_FILE;
3173 tf->file.log = r->connection->log;
3174 tf->path = clcf->client_body_temp_path;
3175 tf->pool = r->pool;
3176 tf->warn = "a client request body is buffered to a temporary file";
3177 tf->log_level = r->request_body_file_log_level;
3178 tf->persistent = r->request_body_in_persistent_file;
3179 tf->clean = r->request_body_in_clean_file;
3180
3181 if (r->request_body_file_group_access) {
3182 tf->access = 0660;
3183 }
3184
3185 rb->temp_file = tf;
3186
3187 if (r->spdy_stream->in_closed
3188 && ngx_create_temp_file(&tf->file, tf->path, tf->pool,
3189 tf->persistent, tf->clean, tf->access)
3190 != NGX_OK)
3191 {
3192 return NGX_ERROR;
3193 }
3194
3195 buf = ngx_calloc_buf(r->pool);
3196 if (buf == NULL) {
3197 return NGX_ERROR;
3198 }
3199
Valentin Bartenev2686cb42013-03-20 10:36:57 +00003200 } else {
3201
3202 if (rb->rest == 0) {
3203 return NGX_OK;
3204 }
3205
3206 buf = ngx_create_temp_buf(r->pool, (size_t) rb->rest);
3207 if (buf == NULL) {
3208 return NGX_ERROR;
3209 }
Valentin Bartenev2686cb42013-03-20 10:36:57 +00003210 }
3211
Valentin Bartenev32e167e2013-07-24 22:24:25 +04003212 rb->buf = buf;
3213
Valentin Bartenev2686cb42013-03-20 10:36:57 +00003214 rb->bufs = ngx_alloc_chain_link(r->pool);
3215 if (rb->bufs == NULL) {
3216 return NGX_ERROR;
3217 }
3218
3219 rb->bufs->buf = buf;
3220 rb->bufs->next = NULL;
3221
3222 rb->rest = 0;
3223
3224 return NGX_OK;
3225}
3226
3227
3228ngx_int_t
3229ngx_http_spdy_read_request_body(ngx_http_request_t *r,
3230 ngx_http_client_body_handler_pt post_handler)
3231{
3232 ngx_http_spdy_stream_t *stream;
3233
3234 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
3235 "spdy read request body");
3236
3237 stream = r->spdy_stream;
3238
3239 switch (stream->skip_data) {
3240
3241 case NGX_SPDY_DATA_DISCARD:
3242 post_handler(r);
3243 return NGX_OK;
3244
3245 case NGX_SPDY_DATA_ERROR:
3246 if (r->headers_in.content_length_n == -1) {
3247 return NGX_HTTP_REQUEST_ENTITY_TOO_LARGE;
3248 } else {
3249 return NGX_HTTP_BAD_REQUEST;
3250 }
3251
3252 case NGX_SPDY_DATA_INTERNAL_ERROR:
3253 return NGX_HTTP_INTERNAL_SERVER_ERROR;
3254 }
3255
3256 if (!r->request_body && ngx_http_spdy_init_request_body(r) != NGX_OK) {
3257 stream->skip_data = NGX_SPDY_DATA_INTERNAL_ERROR;
3258 return NGX_HTTP_INTERNAL_SERVER_ERROR;
3259 }
3260
3261 if (stream->in_closed) {
3262 post_handler(r);
3263 return NGX_OK;
3264 }
3265
3266 r->request_body->post_handler = post_handler;
3267
Valentin Bartenev6ba03092013-10-01 00:00:57 +04003268 r->read_event_handler = ngx_http_test_reading;
3269 r->write_event_handler = ngx_http_request_empty_handler;
3270
Valentin Bartenev2686cb42013-03-20 10:36:57 +00003271 return NGX_AGAIN;
3272}
3273
3274
Valentin Bartenev449e8ee2014-01-31 19:17:26 +04003275static ngx_int_t
3276ngx_http_spdy_terminate_stream(ngx_http_spdy_connection_t *sc,
3277 ngx_http_spdy_stream_t *stream, ngx_uint_t status)
3278{
3279 ngx_event_t *rev;
3280 ngx_connection_t *fc;
3281
3282 if (ngx_http_spdy_send_rst_stream(sc, stream->id, status,
3283 NGX_SPDY_HIGHEST_PRIORITY)
3284 == NGX_ERROR)
3285 {
3286 return NGX_ERROR;
3287 }
3288
3289 stream->out_closed = 1;
3290
3291 fc = stream->request->connection;
3292 fc->error = 1;
3293
3294 rev = fc->read;
3295 rev->handler(rev);
3296
3297 return NGX_OK;
3298}
3299
3300
Valentin Bartenev92b82c82013-10-01 00:04:00 +04003301static void
3302ngx_http_spdy_close_stream_handler(ngx_event_t *ev)
3303{
3304 ngx_connection_t *fc;
3305 ngx_http_request_t *r;
3306
3307 fc = ev->data;
3308 r = fc->data;
3309
3310 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
3311 "spdy close stream handler");
3312
3313 ngx_http_spdy_close_stream(r->spdy_stream, 0);
3314}
3315
3316
Valentin Bartenev2686cb42013-03-20 10:36:57 +00003317void
3318ngx_http_spdy_close_stream(ngx_http_spdy_stream_t *stream, ngx_int_t rc)
3319{
Valentin Bartenevdecaffa2014-11-21 22:51:49 +03003320 int tcp_nodelay;
Valentin Bartenev2686cb42013-03-20 10:36:57 +00003321 ngx_event_t *ev;
Valentin Bartenevdecaffa2014-11-21 22:51:49 +03003322 ngx_connection_t *c, *fc;
3323 ngx_http_core_loc_conf_t *clcf;
Valentin Bartenev2686cb42013-03-20 10:36:57 +00003324 ngx_http_spdy_stream_t **index, *s;
3325 ngx_http_spdy_srv_conf_t *sscf;
3326 ngx_http_spdy_connection_t *sc;
3327
3328 sc = stream->connection;
3329
Valentin Bartenevac8bb7a2014-01-14 16:24:45 +04003330 ngx_log_debug3(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0,
3331 "spdy close stream %ui, queued %ui, processing %ui",
3332 stream->id, stream->queued, sc->processing);
3333
3334 fc = stream->request->connection;
3335
3336 if (stream->queued) {
3337 fc->write->handler = ngx_http_spdy_close_stream_handler;
3338 return;
3339 }
Valentin Bartenev2686cb42013-03-20 10:36:57 +00003340
3341 if (!stream->out_closed) {
3342 if (ngx_http_spdy_send_rst_stream(sc, stream->id,
3343 NGX_SPDY_INTERNAL_ERROR,
3344 stream->priority)
3345 != NGX_OK)
3346 {
3347 sc->connection->error = 1;
3348 }
Valentin Bartenevdecaffa2014-11-21 22:51:49 +03003349
3350 } else {
3351 c = sc->connection;
3352
3353 if (c->tcp_nopush == NGX_TCP_NOPUSH_SET) {
3354 if (ngx_tcp_push(c->fd) == -1) {
3355 ngx_connection_error(c, ngx_socket_errno,
3356 ngx_tcp_push_n " failed");
3357 c->error = 1;
3358 tcp_nodelay = 0;
3359
3360 } else {
3361 c->tcp_nopush = NGX_TCP_NOPUSH_UNSET;
3362 tcp_nodelay = ngx_tcp_nodelay_and_tcp_nopush ? 1 : 0;
3363 }
3364
3365 } else {
3366 tcp_nodelay = 1;
3367 }
3368
3369 clcf = ngx_http_get_module_loc_conf(stream->request,
3370 ngx_http_core_module);
3371
3372 if (tcp_nodelay
3373 && clcf->tcp_nodelay
3374 && c->tcp_nodelay == NGX_TCP_NODELAY_UNSET)
3375 {
3376 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "tcp_nodelay");
3377
3378 if (setsockopt(c->fd, IPPROTO_TCP, TCP_NODELAY,
3379 (const void *) &tcp_nodelay, sizeof(int))
3380 == -1)
3381 {
3382#if (NGX_SOLARIS)
3383 /* Solaris returns EINVAL if a socket has been shut down */
3384 c->log_error = NGX_ERROR_IGNORE_EINVAL;
3385#endif
3386
3387 ngx_connection_error(c, ngx_socket_errno,
3388 "setsockopt(TCP_NODELAY) failed");
3389
3390 c->log_error = NGX_ERROR_INFO;
3391 c->error = 1;
3392
3393 } else {
3394 c->tcp_nodelay = NGX_TCP_NODELAY_SET;
3395 }
3396 }
Valentin Bartenev2686cb42013-03-20 10:36:57 +00003397 }
3398
Valentin Bartenev32bb39c2014-01-22 04:58:19 +04003399 if (sc->stream == stream) {
3400 sc->stream = NULL;
3401 }
3402
Valentin Bartenev2686cb42013-03-20 10:36:57 +00003403 sscf = ngx_http_get_module_srv_conf(sc->http_connection->conf_ctx,
3404 ngx_http_spdy_module);
3405
3406 index = sc->streams_index + ngx_http_spdy_stream_index(sscf, stream->id);
3407
3408 for ( ;; ) {
3409 s = *index;
3410
3411 if (s == NULL) {
3412 break;
3413 }
3414
3415 if (s == stream) {
3416 *index = s->index;
3417 break;
3418 }
3419
3420 index = &s->index;
3421 }
3422
Valentin Bartenev2686cb42013-03-20 10:36:57 +00003423 ngx_http_free_request(stream->request, rc);
3424
3425 ev = fc->read;
3426
3427 if (ev->active || ev->disabled) {
Valentin Bartenevc189eda2013-08-15 19:16:12 +04003428 ngx_log_error(NGX_LOG_ALERT, sc->connection->log, 0,
Valentin Bartenevd04a7142014-04-30 20:34:20 +04003429 "fake read event was activated");
Valentin Bartenev2686cb42013-03-20 10:36:57 +00003430 }
3431
3432 if (ev->timer_set) {
3433 ngx_del_timer(ev);
3434 }
3435
Valentin Bartenev37d24e72014-09-01 18:20:18 +04003436 if (ev->posted) {
Valentin Bartenev2686cb42013-03-20 10:36:57 +00003437 ngx_delete_posted_event(ev);
3438 }
3439
3440 ev = fc->write;
3441
3442 if (ev->active || ev->disabled) {
Valentin Bartenevc189eda2013-08-15 19:16:12 +04003443 ngx_log_error(NGX_LOG_ALERT, sc->connection->log, 0,
Valentin Bartenevd04a7142014-04-30 20:34:20 +04003444 "fake write event was activated");
Valentin Bartenev2686cb42013-03-20 10:36:57 +00003445 }
3446
3447 if (ev->timer_set) {
3448 ngx_del_timer(ev);
3449 }
3450
Valentin Bartenev37d24e72014-09-01 18:20:18 +04003451 if (ev->posted) {
Valentin Bartenev2686cb42013-03-20 10:36:57 +00003452 ngx_delete_posted_event(ev);
3453 }
3454
3455 fc->data = sc->free_fake_connections;
3456 sc->free_fake_connections = fc;
3457
3458 sc->processing--;
3459
3460 if (sc->processing || sc->blocked) {
3461 return;
3462 }
3463
3464 ev = sc->connection->read;
3465
3466 ev->handler = ngx_http_spdy_handle_connection_handler;
3467 ngx_post_event(ev, &ngx_posted_events);
3468}
3469
3470
3471static void
3472ngx_http_spdy_handle_connection_handler(ngx_event_t *rev)
3473{
3474 ngx_connection_t *c;
3475
3476 rev->handler = ngx_http_spdy_read_handler;
3477
3478 if (rev->ready) {
3479 ngx_http_spdy_read_handler(rev);
3480 return;
3481 }
3482
3483 c = rev->data;
3484
3485 ngx_http_spdy_handle_connection(c->data);
3486}
3487
3488
3489static void
3490ngx_http_spdy_keepalive_handler(ngx_event_t *rev)
3491{
3492 ngx_connection_t *c;
3493 ngx_http_spdy_srv_conf_t *sscf;
3494 ngx_http_spdy_connection_t *sc;
3495
3496 c = rev->data;
3497
3498 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "spdy keepalive handler");
3499
3500 if (rev->timedout || c->close) {
3501 ngx_http_close_connection(c);
3502 return;
3503 }
3504
3505#if (NGX_HAVE_KQUEUE)
3506
3507 if (ngx_event_flags & NGX_USE_KQUEUE_EVENT) {
3508 if (rev->pending_eof) {
3509 c->log->handler = NULL;
3510 ngx_log_error(NGX_LOG_INFO, c->log, rev->kq_errno,
3511 "kevent() reported that client %V closed "
3512 "keepalive connection", &c->addr_text);
3513#if (NGX_HTTP_SSL)
3514 if (c->ssl) {
3515 c->ssl->no_send_shutdown = 1;
3516 }
3517#endif
3518 ngx_http_close_connection(c);
3519 return;
3520 }
3521 }
3522
3523#endif
3524
3525 c->destroyed = 0;
3526 c->idle = 0;
3527 ngx_reusable_connection(c, 0);
3528
3529 sc = c->data;
3530
3531 sscf = ngx_http_get_module_srv_conf(sc->http_connection->conf_ctx,
3532 ngx_http_spdy_module);
3533
3534 sc->pool = ngx_create_pool(sscf->pool_size, sc->connection->log);
3535 if (sc->pool == NULL) {
3536 ngx_http_close_connection(c);
3537 return;
3538 }
3539
3540 sc->streams_index = ngx_pcalloc(sc->pool,
3541 ngx_http_spdy_streams_index_size(sscf)
3542 * sizeof(ngx_http_spdy_stream_t *));
3543 if (sc->streams_index == NULL) {
3544 ngx_http_close_connection(c);
3545 return;
3546 }
3547
3548 c->write->handler = ngx_http_spdy_write_handler;
3549
3550 rev->handler = ngx_http_spdy_read_handler;
3551 ngx_http_spdy_read_handler(rev);
3552}
3553
3554
3555static void
3556ngx_http_spdy_finalize_connection(ngx_http_spdy_connection_t *sc,
3557 ngx_int_t rc)
3558{
3559 ngx_uint_t i, size;
3560 ngx_event_t *ev;
3561 ngx_connection_t *c, *fc;
3562 ngx_http_request_t *r;
3563 ngx_http_spdy_stream_t *stream;
3564 ngx_http_spdy_srv_conf_t *sscf;
3565
3566 c = sc->connection;
3567
3568 if (!sc->processing) {
3569 ngx_http_close_connection(c);
3570 return;
3571 }
3572
3573 c->error = 1;
3574 c->read->handler = ngx_http_empty_handler;
Valentin Bartenev4f4963e2013-10-01 00:12:30 +04003575 c->write->handler = ngx_http_empty_handler;
Valentin Bartenev2686cb42013-03-20 10:36:57 +00003576
3577 sc->last_out = NULL;
3578
3579 sc->blocked = 1;
3580
3581 sscf = ngx_http_get_module_srv_conf(sc->http_connection->conf_ctx,
3582 ngx_http_spdy_module);
3583
3584 size = ngx_http_spdy_streams_index_size(sscf);
3585
3586 for (i = 0; i < size; i++) {
3587 stream = sc->streams_index[i];
3588
3589 while (stream) {
Valentin Bartenev75dad742013-12-26 17:03:16 +04003590 stream->handled = 0;
Valentin Bartenev2686cb42013-03-20 10:36:57 +00003591
Valentin Bartenev75dad742013-12-26 17:03:16 +04003592 r = stream->request;
Valentin Bartenev2686cb42013-03-20 10:36:57 +00003593 fc = r->connection;
Valentin Bartenev75dad742013-12-26 17:03:16 +04003594
Valentin Bartenev2686cb42013-03-20 10:36:57 +00003595 fc->error = 1;
3596
Valentin Bartenev00944562014-01-14 16:24:45 +04003597 if (stream->queued) {
Valentin Bartenev00944562014-01-14 16:24:45 +04003598 stream->queued = 0;
Valentin Bartenev7f545282013-12-10 20:27:33 +04003599
Valentin Bartenev2686cb42013-03-20 10:36:57 +00003600 ev = fc->write;
Valentin Bartenev7f545282013-12-10 20:27:33 +04003601 ev->delayed = 0;
Valentin Bartenev2686cb42013-03-20 10:36:57 +00003602
3603 } else {
3604 ev = fc->read;
3605 }
3606
3607 stream = stream->index;
3608
3609 ev->eof = 1;
3610 ev->handler(ev);
3611 }
3612 }
3613
3614 sc->blocked = 0;
3615
3616 if (sc->processing) {
3617 return;
3618 }
3619
3620 ngx_http_close_connection(c);
3621}
3622
3623
Valentin Bartenev449e8ee2014-01-31 19:17:26 +04003624static ngx_int_t
3625ngx_http_spdy_adjust_windows(ngx_http_spdy_connection_t *sc, ssize_t delta)
3626{
3627 ngx_uint_t i, size;
3628 ngx_event_t *wev;
3629 ngx_http_spdy_stream_t *stream, *sn;
3630 ngx_http_spdy_srv_conf_t *sscf;
3631
3632 sscf = ngx_http_get_module_srv_conf(sc->http_connection->conf_ctx,
3633 ngx_http_spdy_module);
3634
3635 size = ngx_http_spdy_streams_index_size(sscf);
3636
3637 for (i = 0; i < size; i++) {
3638
3639 for (stream = sc->streams_index[i]; stream; stream = sn) {
3640 sn = stream->index;
3641
3642 if (delta > 0
3643 && stream->send_window
3644 > (ssize_t) (NGX_SPDY_MAX_WINDOW - delta))
3645 {
3646 if (ngx_http_spdy_terminate_stream(sc, stream,
3647 NGX_SPDY_FLOW_CONTROL_ERROR)
3648 == NGX_ERROR)
3649 {
3650 return NGX_ERROR;
3651 }
3652
3653 continue;
3654 }
3655
3656 stream->send_window += delta;
3657
3658 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0,
3659 "spdy:%ui adjust window:%z",
3660 stream->id, stream->send_window);
3661
3662 if (stream->send_window > 0 && stream->exhausted) {
3663 stream->exhausted = 0;
3664
3665 wev = stream->request->connection->write;
3666
3667 if (!wev->timer_set) {
3668 wev->delayed = 0;
3669 wev->handler(wev);
3670 }
3671 }
3672 }
3673 }
3674
3675 return NGX_OK;
3676}
3677
3678
Valentin Bartenev2686cb42013-03-20 10:36:57 +00003679static void
3680ngx_http_spdy_pool_cleanup(void *data)
3681{
3682 ngx_http_spdy_connection_t *sc = data;
3683
3684 if (sc->pool) {
3685 ngx_destroy_pool(sc->pool);
3686 }
3687}
3688
3689
3690static void *
3691ngx_http_spdy_zalloc(void *opaque, u_int items, u_int size)
3692{
3693 ngx_http_spdy_connection_t *sc = opaque;
3694
3695 return ngx_palloc(sc->connection->pool, items * size);
3696}
3697
3698
3699static void
3700ngx_http_spdy_zfree(void *opaque, void *address)
3701{
3702#if 0
3703 ngx_http_spdy_connection_t *sc = opaque;
3704
3705 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0,
3706 "spdy zfree: %p", address);
3707#endif
3708}