nginxtra 1.2.8.8 → 1.4.0.8

Sign up to get free protection for your applications and to get access to all the features.
Files changed (89) hide show
  1. data/bin/nginxtra +1 -1
  2. data/bin/nginxtra_rails +1 -1
  3. data/lib/nginxtra/version.rb +1 -1
  4. data/vendor/nginx/CHANGES +202 -63
  5. data/vendor/nginx/CHANGES.ru +208 -66
  6. data/vendor/nginx/auto/lib/md5/conf +3 -3
  7. data/vendor/nginx/auto/lib/perl/conf +3 -1
  8. data/vendor/nginx/auto/lib/perl/make +21 -16
  9. data/vendor/nginx/auto/lib/sha1/conf +1 -1
  10. data/vendor/nginx/auto/modules +25 -4
  11. data/vendor/nginx/auto/options +7 -1
  12. data/vendor/nginx/auto/sources +15 -1
  13. data/vendor/nginx/auto/unix +14 -0
  14. data/vendor/nginx/src/core/nginx.h +2 -2
  15. data/vendor/nginx/src/core/ngx_array.c +1 -7
  16. data/vendor/nginx/src/core/ngx_array.h +2 -2
  17. data/vendor/nginx/src/core/ngx_connection.c +13 -7
  18. data/vendor/nginx/src/core/ngx_connection.h +1 -2
  19. data/vendor/nginx/src/core/ngx_core.h +1 -2
  20. data/vendor/nginx/src/core/ngx_crypt.c +37 -0
  21. data/vendor/nginx/src/core/ngx_cycle.h +1 -1
  22. data/vendor/nginx/src/core/ngx_inet.c +219 -48
  23. data/vendor/nginx/src/core/ngx_inet.h +1 -1
  24. data/vendor/nginx/src/event/modules/ngx_devpoll_module.c +7 -1
  25. data/vendor/nginx/src/event/modules/ngx_eventport_module.c +1 -1
  26. data/vendor/nginx/src/event/ngx_event.c +5 -1
  27. data/vendor/nginx/src/event/ngx_event.h +1 -0
  28. data/vendor/nginx/src/event/ngx_event_connect.c +1 -1
  29. data/vendor/nginx/src/event/ngx_event_openssl.c +135 -9
  30. data/vendor/nginx/src/event/ngx_event_openssl.h +9 -0
  31. data/vendor/nginx/src/event/ngx_event_openssl_stapling.c +1749 -0
  32. data/vendor/nginx/src/http/modules/ngx_http_addition_filter_module.c +1 -0
  33. data/vendor/nginx/src/http/modules/ngx_http_chunked_filter_module.c +1 -0
  34. data/vendor/nginx/src/http/modules/ngx_http_fastcgi_module.c +5 -0
  35. data/vendor/nginx/src/http/modules/ngx_http_flv_module.c +4 -0
  36. data/vendor/nginx/src/http/modules/ngx_http_geo_module.c +7 -8
  37. data/vendor/nginx/src/http/modules/ngx_http_geoip_module.c +10 -12
  38. data/vendor/nginx/src/http/modules/ngx_http_gunzip_filter_module.c +677 -0
  39. data/vendor/nginx/src/http/modules/ngx_http_gzip_filter_module.c +3 -0
  40. data/vendor/nginx/src/http/modules/ngx_http_gzip_static_module.c +36 -10
  41. data/vendor/nginx/src/http/modules/ngx_http_headers_filter_module.c +31 -13
  42. data/vendor/nginx/src/http/modules/ngx_http_image_filter_module.c +13 -0
  43. data/vendor/nginx/src/http/modules/ngx_http_limit_conn_module.c +18 -2
  44. data/vendor/nginx/src/http/modules/ngx_http_limit_req_module.c +19 -2
  45. data/vendor/nginx/src/http/modules/ngx_http_map_module.c +1 -1
  46. data/vendor/nginx/src/http/modules/ngx_http_memcached_module.c +60 -8
  47. data/vendor/nginx/src/http/modules/ngx_http_mp4_module.c +4 -8
  48. data/vendor/nginx/src/http/modules/ngx_http_not_modified_filter_module.c +126 -29
  49. data/vendor/nginx/src/http/modules/ngx_http_proxy_module.c +59 -301
  50. data/vendor/nginx/src/http/modules/ngx_http_range_filter_module.c +34 -6
  51. data/vendor/nginx/src/http/modules/ngx_http_realip_module.c +13 -12
  52. data/vendor/nginx/src/http/modules/ngx_http_scgi_module.c +30 -11
  53. data/vendor/nginx/src/http/modules/ngx_http_ssi_filter_module.c +1 -0
  54. data/vendor/nginx/src/http/modules/ngx_http_ssl_module.c +155 -4
  55. data/vendor/nginx/src/http/modules/ngx_http_ssl_module.h +6 -0
  56. data/vendor/nginx/src/http/modules/ngx_http_static_module.c +4 -0
  57. data/vendor/nginx/src/http/modules/ngx_http_stub_status_module.c +90 -3
  58. data/vendor/nginx/src/http/modules/ngx_http_sub_filter_module.c +1 -0
  59. data/vendor/nginx/src/http/modules/ngx_http_upstream_ip_hash_module.c +5 -0
  60. data/vendor/nginx/src/http/modules/ngx_http_upstream_least_conn_module.c +5 -0
  61. data/vendor/nginx/src/http/modules/ngx_http_uwsgi_module.c +14 -1
  62. data/vendor/nginx/src/http/modules/ngx_http_xslt_filter_module.c +1 -0
  63. data/vendor/nginx/src/http/modules/perl/Makefile.PL +4 -2
  64. data/vendor/nginx/src/http/modules/perl/nginx.pm +1 -1
  65. data/vendor/nginx/src/http/modules/perl/nginx.xs +36 -3
  66. data/vendor/nginx/src/http/ngx_http.c +24 -1
  67. data/vendor/nginx/src/http/ngx_http.h +26 -2
  68. data/vendor/nginx/src/http/ngx_http_core_module.c +136 -10
  69. data/vendor/nginx/src/http/ngx_http_core_module.h +37 -13
  70. data/vendor/nginx/src/http/ngx_http_header_filter_module.c +9 -2
  71. data/vendor/nginx/src/http/ngx_http_parse.c +404 -0
  72. data/vendor/nginx/src/http/ngx_http_request.c +840 -517
  73. data/vendor/nginx/src/http/ngx_http_request.h +37 -25
  74. data/vendor/nginx/src/http/ngx_http_request_body.c +585 -156
  75. data/vendor/nginx/src/http/ngx_http_spdy.c +2882 -0
  76. data/vendor/nginx/src/http/ngx_http_spdy.h +235 -0
  77. data/vendor/nginx/src/http/ngx_http_spdy_filter_module.c +999 -0
  78. data/vendor/nginx/src/http/ngx_http_spdy_module.c +351 -0
  79. data/vendor/nginx/src/http/ngx_http_spdy_module.h +36 -0
  80. data/vendor/nginx/src/http/ngx_http_special_response.c +3 -1
  81. data/vendor/nginx/src/http/ngx_http_upstream.c +415 -26
  82. data/vendor/nginx/src/http/ngx_http_upstream.h +11 -1
  83. data/vendor/nginx/src/http/ngx_http_upstream_round_robin.c +2 -45
  84. data/vendor/nginx/src/http/ngx_http_upstream_round_robin.h +0 -2
  85. data/vendor/nginx/src/http/ngx_http_variables.c +72 -12
  86. data/vendor/nginx/src/mail/ngx_mail.h +2 -2
  87. data/vendor/nginx/src/mail/ngx_mail_auth_http_module.c +35 -25
  88. data/vendor/nginx/src/mail/ngx_mail_core_module.c +5 -1
  89. metadata +9 -2
@@ -0,0 +1,2882 @@
1
+
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)
45
+
46
+
47
+ #define ngx_spdy_ctl_frame_check(h) \
48
+ (((h) & 0xffffff00) == ngx_spdy_ctl_frame_head(0))
49
+ #define ngx_spdy_data_frame_check(h) \
50
+ (!((h) & (uint32_t) NGX_SPDY_CTL_BIT << 31))
51
+
52
+ #define ngx_spdy_ctl_frame_type(h) ((h) & 0x000000ff)
53
+ #define ngx_spdy_frame_flags(p) ((p) >> 24)
54
+ #define ngx_spdy_frame_length(p) ((p) & 0x00ffffff)
55
+
56
+
57
+ #define NGX_SPDY_SKIP_HEADERS_BUFFER_SIZE 4096
58
+ #define NGX_SPDY_CTL_FRAME_BUFFER_SIZE 16
59
+
60
+ #define NGX_SPDY_PROTOCOL_ERROR 1
61
+ #define NGX_SPDY_INVALID_STREAM 2
62
+ #define NGX_SPDY_REFUSED_STREAM 3
63
+ #define NGX_SPDY_UNSUPPORTED_VERSION 4
64
+ #define NGX_SPDY_CANCEL 5
65
+ #define NGX_SPDY_INTERNAL_ERROR 6
66
+ #define NGX_SPDY_FLOW_CONTROL_ERROR 7
67
+
68
+ #define NGX_SPDY_SETTINGS_MAX_STREAMS 4
69
+
70
+ #define NGX_SPDY_SETTINGS_FLAG_PERSIST 0x01
71
+
72
+ typedef struct {
73
+ ngx_uint_t hash;
74
+ u_char len;
75
+ u_char header[7];
76
+ ngx_int_t (*handler)(ngx_http_request_t *r);
77
+ } ngx_http_spdy_request_header_t;
78
+
79
+
80
+ static void ngx_http_spdy_read_handler(ngx_event_t *rev);
81
+ static void ngx_http_spdy_write_handler(ngx_event_t *wev);
82
+ static void ngx_http_spdy_handle_connection(ngx_http_spdy_connection_t *sc);
83
+
84
+ static u_char *ngx_http_spdy_state_detect_settings(
85
+ ngx_http_spdy_connection_t *sc, u_char *pos, u_char *end);
86
+ static u_char *ngx_http_spdy_state_head(ngx_http_spdy_connection_t *sc,
87
+ u_char *pos, u_char *end);
88
+ static u_char *ngx_http_spdy_state_syn_stream(ngx_http_spdy_connection_t *sc,
89
+ u_char *pos, u_char *end);
90
+ static u_char *ngx_http_spdy_state_headers(ngx_http_spdy_connection_t *sc,
91
+ u_char *pos, u_char *end);
92
+ static u_char *ngx_http_spdy_state_headers_error(ngx_http_spdy_connection_t *sc,
93
+ u_char *pos, u_char *end);
94
+ static u_char *ngx_http_spdy_state_headers_skip(ngx_http_spdy_connection_t *sc,
95
+ u_char *pos, u_char *end);
96
+ static u_char *ngx_http_spdy_state_data(ngx_http_spdy_connection_t *sc,
97
+ u_char *pos, u_char *end);
98
+ static u_char *ngx_http_spdy_state_rst_stream(ngx_http_spdy_connection_t *sc,
99
+ u_char *pos, u_char *end);
100
+ static u_char *ngx_http_spdy_state_ping(ngx_http_spdy_connection_t *sc,
101
+ u_char *pos, u_char *end);
102
+ static u_char *ngx_http_spdy_state_skip(ngx_http_spdy_connection_t *sc,
103
+ u_char *pos, u_char *end);
104
+ static u_char *ngx_http_spdy_state_settings(ngx_http_spdy_connection_t *sc,
105
+ u_char *pos, u_char *end);
106
+ static u_char *ngx_http_spdy_state_noop(ngx_http_spdy_connection_t *sc,
107
+ u_char *pos, u_char *end);
108
+ static u_char *ngx_http_spdy_state_complete(ngx_http_spdy_connection_t *sc,
109
+ u_char *pos, u_char *end);
110
+ static u_char *ngx_http_spdy_state_save(ngx_http_spdy_connection_t *sc,
111
+ u_char *pos, u_char *end, ngx_http_spdy_handler_pt handler);
112
+ static u_char *ngx_http_spdy_state_protocol_error(
113
+ ngx_http_spdy_connection_t *sc);
114
+ static u_char *ngx_http_spdy_state_internal_error(
115
+ ngx_http_spdy_connection_t *sc);
116
+
117
+ static ngx_int_t ngx_http_spdy_send_rst_stream(ngx_http_spdy_connection_t *sc,
118
+ ngx_uint_t sid, ngx_uint_t status, ngx_uint_t priority);
119
+ static ngx_int_t ngx_http_spdy_send_settings(ngx_http_spdy_connection_t *sc);
120
+ static ngx_int_t ngx_http_spdy_settings_frame_handler(
121
+ ngx_http_spdy_connection_t *sc, ngx_http_spdy_out_frame_t *frame);
122
+ static ngx_http_spdy_out_frame_t *ngx_http_spdy_get_ctl_frame(
123
+ ngx_http_spdy_connection_t *sc, size_t size, ngx_uint_t priority);
124
+ static ngx_int_t ngx_http_spdy_ctl_frame_handler(
125
+ ngx_http_spdy_connection_t *sc, ngx_http_spdy_out_frame_t *frame);
126
+
127
+ static ngx_http_spdy_stream_t *ngx_http_spdy_create_stream(
128
+ ngx_http_spdy_connection_t *sc, ngx_uint_t id, ngx_uint_t priority);
129
+ static ngx_http_spdy_stream_t *ngx_http_spdy_get_stream_by_id(
130
+ ngx_http_spdy_connection_t *sc, ngx_uint_t sid);
131
+ #define ngx_http_spdy_streams_index_size(sscf) (sscf->streams_index_mask + 1)
132
+ #define ngx_http_spdy_stream_index(sscf, sid) \
133
+ ((sid >> 1) & sscf->streams_index_mask)
134
+
135
+ static ngx_int_t ngx_http_spdy_parse_header(ngx_http_request_t *r);
136
+ static ngx_int_t ngx_http_spdy_alloc_large_header_buffer(ngx_http_request_t *r);
137
+
138
+ static ngx_int_t ngx_http_spdy_handle_request_header(ngx_http_request_t *r);
139
+ static ngx_int_t ngx_http_spdy_parse_method(ngx_http_request_t *r);
140
+ static ngx_int_t ngx_http_spdy_parse_scheme(ngx_http_request_t *r);
141
+ static ngx_int_t ngx_http_spdy_parse_url(ngx_http_request_t *r);
142
+ static ngx_int_t ngx_http_spdy_parse_version(ngx_http_request_t *r);
143
+
144
+ static ngx_int_t ngx_http_spdy_construct_request_line(ngx_http_request_t *r);
145
+ static void ngx_http_spdy_run_request(ngx_http_request_t *r);
146
+ static ngx_int_t ngx_http_spdy_init_request_body(ngx_http_request_t *r);
147
+
148
+ static void ngx_http_spdy_handle_connection_handler(ngx_event_t *rev);
149
+ static void ngx_http_spdy_keepalive_handler(ngx_event_t *rev);
150
+ static void ngx_http_spdy_finalize_connection(ngx_http_spdy_connection_t *sc,
151
+ ngx_int_t rc);
152
+
153
+ static void ngx_http_spdy_pool_cleanup(void *data);
154
+
155
+ static void *ngx_http_spdy_zalloc(void *opaque, u_int items, u_int size);
156
+ static void ngx_http_spdy_zfree(void *opaque, void *address);
157
+
158
+
159
+ static const u_char ngx_http_spdy_dict[] =
160
+ "options" "get" "head" "post" "put" "delete" "trace"
161
+ "accept" "accept-charset" "accept-encoding" "accept-language"
162
+ "authorization" "expect" "from" "host"
163
+ "if-modified-since" "if-match" "if-none-match" "if-range"
164
+ "if-unmodifiedsince" "max-forwards" "proxy-authorization"
165
+ "range" "referer" "te" "user-agent"
166
+ "100" "101" "200" "201" "202" "203" "204" "205" "206"
167
+ "300" "301" "302" "303" "304" "305" "306" "307"
168
+ "400" "401" "402" "403" "404" "405" "406" "407" "408" "409" "410"
169
+ "411" "412" "413" "414" "415" "416" "417"
170
+ "500" "501" "502" "503" "504" "505"
171
+ "accept-ranges" "age" "etag" "location" "proxy-authenticate" "public"
172
+ "retry-after" "server" "vary" "warning" "www-authenticate" "allow"
173
+ "content-base" "content-encoding" "cache-control" "connection" "date"
174
+ "trailer" "transfer-encoding" "upgrade" "via" "warning"
175
+ "content-language" "content-length" "content-location"
176
+ "content-md5" "content-range" "content-type" "etag" "expires"
177
+ "last-modified" "set-cookie"
178
+ "Monday" "Tuesday" "Wednesday" "Thursday" "Friday" "Saturday" "Sunday"
179
+ "Jan" "Feb" "Mar" "Apr" "May" "Jun" "Jul" "Aug" "Sep" "Oct" "Nov" "Dec"
180
+ "chunked" "text/html" "image/png" "image/jpg" "image/gif"
181
+ "application/xml" "application/xhtml" "text/plain" "public" "max-age"
182
+ "charset=iso-8859-1" "utf-8" "gzip" "deflate" "HTTP/1.1" "status"
183
+ "version" "url";
184
+
185
+
186
+ static ngx_http_spdy_request_header_t ngx_http_spdy_request_headers[] = {
187
+ { 0, 6, "method", ngx_http_spdy_parse_method },
188
+ { 0, 6, "scheme", ngx_http_spdy_parse_scheme },
189
+ { 0, 3, "url", ngx_http_spdy_parse_url },
190
+ { 0, 7, "version", ngx_http_spdy_parse_version },
191
+ };
192
+
193
+ #define NGX_SPDY_REQUEST_HEADERS \
194
+ (sizeof(ngx_http_spdy_request_headers) \
195
+ / sizeof(ngx_http_spdy_request_header_t))
196
+
197
+
198
+ void
199
+ ngx_http_spdy_init(ngx_event_t *rev)
200
+ {
201
+ int rc;
202
+ ngx_connection_t *c;
203
+ ngx_pool_cleanup_t *cln;
204
+ ngx_http_connection_t *hc;
205
+ ngx_http_spdy_srv_conf_t *sscf;
206
+ ngx_http_spdy_main_conf_t *smcf;
207
+ ngx_http_spdy_connection_t *sc;
208
+
209
+ c = rev->data;
210
+ hc = c->data;
211
+
212
+ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0,
213
+ "init spdy request");
214
+
215
+ c->log->action = "processing SPDY";
216
+
217
+ smcf = ngx_http_get_module_main_conf(hc->conf_ctx, ngx_http_spdy_module);
218
+
219
+ if (smcf->recv_buffer == NULL) {
220
+ smcf->recv_buffer = ngx_palloc(ngx_cycle->pool, smcf->recv_buffer_size);
221
+ if (smcf->recv_buffer == NULL) {
222
+ ngx_http_close_connection(c);
223
+ return;
224
+ }
225
+ }
226
+
227
+ sc = ngx_pcalloc(c->pool, sizeof(ngx_http_spdy_connection_t));
228
+ if (sc == NULL) {
229
+ ngx_http_close_connection(c);
230
+ return;
231
+ }
232
+
233
+ sc->connection = c;
234
+ sc->http_connection = hc;
235
+
236
+ sc->handler = ngx_http_spdy_state_detect_settings;
237
+
238
+ sc->zstream_in.zalloc = ngx_http_spdy_zalloc;
239
+ sc->zstream_in.zfree = ngx_http_spdy_zfree;
240
+ sc->zstream_in.opaque = sc;
241
+
242
+ rc = inflateInit(&sc->zstream_in);
243
+ if (rc != Z_OK) {
244
+ ngx_log_error(NGX_LOG_ALERT, c->log, 0,
245
+ "inflateInit() failed: %d", rc);
246
+ ngx_http_close_connection(c);
247
+ return;
248
+ }
249
+
250
+ sc->zstream_out.zalloc = ngx_http_spdy_zalloc;
251
+ sc->zstream_out.zfree = ngx_http_spdy_zfree;
252
+ sc->zstream_out.opaque = sc;
253
+
254
+ sscf = ngx_http_get_module_srv_conf(hc->conf_ctx, ngx_http_spdy_module);
255
+
256
+ rc = deflateInit2(&sc->zstream_out, (int) sscf->headers_comp,
257
+ Z_DEFLATED, 11, 4, Z_DEFAULT_STRATEGY);
258
+
259
+ if (rc != Z_OK) {
260
+ ngx_log_error(NGX_LOG_ALERT, c->log, 0,
261
+ "deflateInit2() failed: %d", rc);
262
+ ngx_http_close_connection(c);
263
+ return;
264
+ }
265
+
266
+ rc = deflateSetDictionary(&sc->zstream_out, ngx_http_spdy_dict,
267
+ sizeof(ngx_http_spdy_dict));
268
+ if (rc != Z_OK) {
269
+ ngx_log_error(NGX_LOG_ALERT, c->log, 0,
270
+ "deflateSetDictionary() failed: %d", rc);
271
+ ngx_http_close_connection(c);
272
+ return;
273
+ }
274
+
275
+ sc->pool = ngx_create_pool(sscf->pool_size, sc->connection->log);
276
+ if (sc->pool == NULL) {
277
+ ngx_http_close_connection(c);
278
+ return;
279
+ }
280
+
281
+ cln = ngx_pool_cleanup_add(c->pool, sizeof(ngx_pool_cleanup_file_t));
282
+ if (cln == NULL) {
283
+ ngx_http_close_connection(c);
284
+ return;
285
+ }
286
+
287
+ cln->handler = ngx_http_spdy_pool_cleanup;
288
+ cln->data = sc;
289
+
290
+ sc->streams_index = ngx_pcalloc(sc->pool,
291
+ ngx_http_spdy_streams_index_size(sscf)
292
+ * sizeof(ngx_http_spdy_stream_t *));
293
+ if (sc->streams_index == NULL) {
294
+ ngx_http_close_connection(c);
295
+ return;
296
+ }
297
+
298
+ c->data = sc;
299
+
300
+ rev->handler = ngx_http_spdy_read_handler;
301
+ c->write->handler = ngx_http_spdy_write_handler;
302
+
303
+ ngx_http_spdy_read_handler(rev);
304
+ }
305
+
306
+
307
+ static void
308
+ ngx_http_spdy_read_handler(ngx_event_t *rev)
309
+ {
310
+ u_char *p, *end;
311
+ size_t available;
312
+ ssize_t n;
313
+ ngx_connection_t *c;
314
+ ngx_http_spdy_main_conf_t *smcf;
315
+ ngx_http_spdy_connection_t *sc;
316
+
317
+ c = rev->data;
318
+ sc = c->data;
319
+
320
+ if (rev->timedout) {
321
+ ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT, "client timed out");
322
+ ngx_http_spdy_finalize_connection(sc, NGX_HTTP_REQUEST_TIME_OUT);
323
+ return;
324
+ }
325
+
326
+ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "spdy read handler");
327
+
328
+ sc->blocked = 1;
329
+
330
+ smcf = ngx_http_get_module_main_conf(sc->http_connection->conf_ctx,
331
+ ngx_http_spdy_module);
332
+
333
+ available = smcf->recv_buffer_size - 2 * NGX_SPDY_STATE_BUFFER_SIZE;
334
+
335
+ do {
336
+ p = smcf->recv_buffer;
337
+
338
+ ngx_memcpy(p, sc->buffer, NGX_SPDY_STATE_BUFFER_SIZE);
339
+ end = p + sc->buffer_used;
340
+
341
+ n = c->recv(c, end, available);
342
+
343
+ if (n == NGX_AGAIN) {
344
+ break;
345
+ }
346
+
347
+ if (n == 0 && (sc->waiting || sc->processing)) {
348
+ ngx_log_error(NGX_LOG_INFO, c->log, 0,
349
+ "client closed prematurely connection");
350
+ }
351
+
352
+ if (n == 0 || n == NGX_ERROR) {
353
+ ngx_http_spdy_finalize_connection(sc,
354
+ NGX_HTTP_CLIENT_CLOSED_REQUEST);
355
+ return;
356
+ }
357
+
358
+ end += n;
359
+
360
+ sc->buffer_used = 0;
361
+ sc->waiting = 0;
362
+
363
+ do {
364
+ p = sc->handler(sc, p, end);
365
+
366
+ if (p == NULL) {
367
+ return;
368
+ }
369
+
370
+ } while (p != end);
371
+
372
+ } while (rev->ready);
373
+
374
+ if (ngx_handle_read_event(rev, 0) != NGX_OK) {
375
+ ngx_http_spdy_finalize_connection(sc, NGX_HTTP_INTERNAL_SERVER_ERROR);
376
+ return;
377
+ }
378
+
379
+ sc->blocked = 0;
380
+
381
+ if (sc->processing) {
382
+ if (rev->timer_set) {
383
+ ngx_del_timer(rev);
384
+ }
385
+ return;
386
+ }
387
+
388
+ ngx_http_spdy_handle_connection(sc);
389
+ }
390
+
391
+
392
+ static void
393
+ ngx_http_spdy_write_handler(ngx_event_t *wev)
394
+ {
395
+ ngx_int_t rc;
396
+ ngx_connection_t *c;
397
+ ngx_http_spdy_stream_t *stream, *s, *sn;
398
+ ngx_http_spdy_connection_t *sc;
399
+
400
+ c = wev->data;
401
+ sc = c->data;
402
+
403
+ if (wev->timedout) {
404
+ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0,
405
+ "spdy write event timed out");
406
+ ngx_http_spdy_finalize_connection(sc, NGX_HTTP_CLIENT_CLOSED_REQUEST);
407
+ return;
408
+ }
409
+
410
+ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "spdy write handler");
411
+
412
+ sc->blocked = 2;
413
+
414
+ rc = ngx_http_spdy_send_output_queue(sc);
415
+
416
+ if (rc == NGX_ERROR) {
417
+ ngx_http_spdy_finalize_connection(sc, NGX_HTTP_CLIENT_CLOSED_REQUEST);
418
+ return;
419
+ }
420
+
421
+ stream = NULL;
422
+
423
+ for (s = sc->last_stream; s; s = sn) {
424
+ sn = s->next;
425
+ s->next = stream;
426
+ stream = s;
427
+ }
428
+
429
+ sc->last_stream = NULL;
430
+
431
+ sc->blocked = 1;
432
+
433
+ for ( /* void */ ; stream; stream = sn) {
434
+ sn = stream->next;
435
+ stream->handled = 0;
436
+
437
+ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0,
438
+ "spdy run stream %ui", stream->id);
439
+
440
+ wev = stream->request->connection->write;
441
+ wev->handler(wev);
442
+ }
443
+
444
+ sc->blocked = 0;
445
+
446
+ if (rc == NGX_AGAIN) {
447
+ return;
448
+ }
449
+
450
+ ngx_http_spdy_handle_connection(sc);
451
+ }
452
+
453
+
454
+ ngx_int_t
455
+ ngx_http_spdy_send_output_queue(ngx_http_spdy_connection_t *sc)
456
+ {
457
+ ngx_chain_t *cl;
458
+ ngx_event_t *wev;
459
+ ngx_connection_t *c;
460
+ ngx_http_core_loc_conf_t *clcf;
461
+ ngx_http_spdy_out_frame_t *out, *frame, *fn;
462
+
463
+ c = sc->connection;
464
+
465
+ if (c->error) {
466
+ return NGX_ERROR;
467
+ }
468
+
469
+ wev = c->write;
470
+
471
+ if (!wev->ready) {
472
+ return NGX_OK;
473
+ }
474
+
475
+ cl = NULL;
476
+ out = NULL;
477
+
478
+ for (frame = sc->last_out; frame; frame = fn) {
479
+ frame->last->next = cl;
480
+ cl = frame->first;
481
+
482
+ fn = frame->next;
483
+ frame->next = out;
484
+ out = frame;
485
+
486
+ ngx_log_debug5(NGX_LOG_DEBUG_HTTP, c->log, 0,
487
+ "spdy frame out: %p sid:%ui prio:%ui bl:%ui size:%uz",
488
+ out, out->stream ? out->stream->id : 0, out->priority,
489
+ out->blocked, out->size);
490
+ }
491
+
492
+ cl = c->send_chain(c, cl, 0);
493
+
494
+ if (cl == NGX_CHAIN_ERROR) {
495
+ c->error = 1;
496
+
497
+ if (!sc->blocked) {
498
+ ngx_post_event(wev, &ngx_posted_events);
499
+ }
500
+
501
+ return NGX_ERROR;
502
+ }
503
+
504
+ clcf = ngx_http_get_module_loc_conf(sc->http_connection->conf_ctx,
505
+ ngx_http_core_module);
506
+
507
+ if (ngx_handle_write_event(wev, clcf->send_lowat) != NGX_OK) {
508
+ return NGX_ERROR; /* FIXME */
509
+ }
510
+
511
+ if (cl) {
512
+ ngx_add_timer(wev, clcf->send_timeout);
513
+
514
+ } else {
515
+ if (wev->timer_set) {
516
+ ngx_del_timer(wev);
517
+ }
518
+ }
519
+
520
+ for ( /* void */ ; out; out = out->next) {
521
+ if (out->handler(sc, out) != NGX_OK) {
522
+ out->blocked = 1;
523
+ out->priority = NGX_SPDY_HIGHEST_PRIORITY;
524
+ break;
525
+ }
526
+
527
+ ngx_log_debug4(NGX_LOG_DEBUG_HTTP, c->log, 0,
528
+ "spdy frame sent: %p sid:%ui bl:%ui size:%uz",
529
+ out, out->stream ? out->stream->id : 0,
530
+ out->blocked, out->size);
531
+ }
532
+
533
+ frame = NULL;
534
+
535
+ for ( /* void */ ; out; out = fn) {
536
+ fn = out->next;
537
+ out->next = frame;
538
+ frame = out;
539
+ }
540
+
541
+ sc->last_out = frame;
542
+
543
+ return NGX_OK;
544
+ }
545
+
546
+
547
+ static void
548
+ ngx_http_spdy_handle_connection(ngx_http_spdy_connection_t *sc)
549
+ {
550
+ ngx_connection_t *c;
551
+ ngx_http_spdy_srv_conf_t *sscf;
552
+
553
+ if (sc->last_out || sc->processing) {
554
+ return;
555
+ }
556
+
557
+ c = sc->connection;
558
+
559
+ if (c->error) {
560
+ ngx_http_close_connection(c);
561
+ return;
562
+ }
563
+
564
+ if (c->buffered) {
565
+ return;
566
+ }
567
+
568
+ sscf = ngx_http_get_module_srv_conf(sc->http_connection->conf_ctx,
569
+ ngx_http_spdy_module);
570
+ if (sc->waiting) {
571
+ ngx_add_timer(c->read, sscf->recv_timeout);
572
+ return;
573
+ }
574
+
575
+ if (ngx_terminate || ngx_exiting) {
576
+ ngx_http_close_connection(c);
577
+ return;
578
+ }
579
+
580
+ ngx_destroy_pool(sc->pool);
581
+
582
+ sc->pool = NULL;
583
+ sc->free_ctl_frames = NULL;
584
+ sc->free_fake_connections = NULL;
585
+
586
+ #if (NGX_HTTP_SSL)
587
+ if (c->ssl) {
588
+ ngx_ssl_free_buffer(c);
589
+ }
590
+ #endif
591
+
592
+ c->destroyed = 1;
593
+ c->idle = 1;
594
+ ngx_reusable_connection(c, 1);
595
+
596
+ c->write->handler = ngx_http_empty_handler;
597
+ c->read->handler = ngx_http_spdy_keepalive_handler;
598
+
599
+ if (c->write->timer_set) {
600
+ ngx_del_timer(c->write);
601
+ }
602
+
603
+ ngx_add_timer(c->read, sscf->keepalive_timeout);
604
+ }
605
+
606
+
607
+ static u_char *
608
+ ngx_http_spdy_state_detect_settings(ngx_http_spdy_connection_t *sc,
609
+ u_char *pos, u_char *end)
610
+ {
611
+ if (end - pos < NGX_SPDY_FRAME_HEADER_SIZE) {
612
+ return ngx_http_spdy_state_save(sc, pos, end,
613
+ ngx_http_spdy_state_detect_settings);
614
+ }
615
+
616
+ /*
617
+ * Since this is the first frame in a buffer,
618
+ * then it is properly aligned
619
+ */
620
+
621
+ if (*(uint32_t *) pos == htonl(ngx_spdy_ctl_frame_head(NGX_SPDY_SETTINGS)))
622
+ {
623
+ sc->length = ngx_spdy_frame_length(htonl(((uint32_t *) pos)[1]));
624
+
625
+ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0,
626
+ "spdy SETTINGS frame received, size: %uz", sc->length);
627
+
628
+ pos += NGX_SPDY_FRAME_HEADER_SIZE;
629
+
630
+ return ngx_http_spdy_state_settings(sc, pos, end);
631
+ }
632
+
633
+ ngx_http_spdy_send_settings(sc);
634
+
635
+ return ngx_http_spdy_state_head(sc, pos, end);
636
+ }
637
+
638
+
639
+ static u_char *
640
+ ngx_http_spdy_state_head(ngx_http_spdy_connection_t *sc, u_char *pos,
641
+ u_char *end)
642
+ {
643
+ uint32_t head, flen;
644
+
645
+ if (end - pos < NGX_SPDY_FRAME_HEADER_SIZE) {
646
+ return ngx_http_spdy_state_save(sc, pos, end,
647
+ ngx_http_spdy_state_head);
648
+ }
649
+
650
+ head = ngx_spdy_frame_parse_uint32(pos);
651
+
652
+ pos += sizeof(uint32_t);
653
+
654
+ flen = ngx_spdy_frame_parse_uint32(pos);
655
+
656
+ sc->flags = ngx_spdy_frame_flags(flen);
657
+ sc->length = ngx_spdy_frame_length(flen);
658
+
659
+ pos += sizeof(uint32_t);
660
+
661
+ ngx_log_debug3(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0,
662
+ "spdy process frame head:%08Xd f:%ui l:%ui",
663
+ head, sc->flags, sc->length);
664
+
665
+ if (ngx_spdy_ctl_frame_check(head)) {
666
+ switch (ngx_spdy_ctl_frame_type(head)) {
667
+
668
+ case NGX_SPDY_SYN_STREAM:
669
+ return ngx_http_spdy_state_syn_stream(sc, pos, end);
670
+
671
+ case NGX_SPDY_SYN_REPLY:
672
+ return ngx_http_spdy_state_protocol_error(sc);
673
+
674
+ case NGX_SPDY_RST_STREAM:
675
+ return ngx_http_spdy_state_rst_stream(sc, pos, end);
676
+
677
+ case NGX_SPDY_SETTINGS:
678
+ return ngx_http_spdy_state_skip(sc, pos, end);
679
+
680
+ case NGX_SPDY_NOOP:
681
+ return ngx_http_spdy_state_noop(sc, pos, end);
682
+
683
+ case NGX_SPDY_PING:
684
+ return ngx_http_spdy_state_ping(sc, pos, end);
685
+
686
+ case NGX_SPDY_GOAWAY:
687
+ return ngx_http_spdy_state_skip(sc, pos, end); /* TODO */
688
+
689
+ case NGX_SPDY_HEADERS:
690
+ return ngx_http_spdy_state_protocol_error(sc);
691
+
692
+ default: /* TODO logging */
693
+ return ngx_http_spdy_state_skip(sc, pos, end);
694
+ }
695
+ }
696
+
697
+ if (ngx_spdy_data_frame_check(head)) {
698
+ sc->stream = ngx_http_spdy_get_stream_by_id(sc, head);
699
+ return ngx_http_spdy_state_data(sc, pos, end);
700
+ }
701
+
702
+
703
+ /* TODO version & type check */
704
+ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0,
705
+ "spdy unknown frame");
706
+
707
+ return ngx_http_spdy_state_protocol_error(sc);
708
+ }
709
+
710
+
711
+ static u_char *
712
+ ngx_http_spdy_state_syn_stream(ngx_http_spdy_connection_t *sc, u_char *pos,
713
+ u_char *end)
714
+ {
715
+ ngx_uint_t sid, prio;
716
+ ngx_http_spdy_stream_t *stream;
717
+ ngx_http_spdy_srv_conf_t *sscf;
718
+
719
+ if (end - pos < NGX_SPDY_SYN_STREAM_SIZE) {
720
+ return ngx_http_spdy_state_save(sc, pos, end,
721
+ ngx_http_spdy_state_syn_stream);
722
+ }
723
+
724
+ if (sc->length <= NGX_SPDY_SYN_STREAM_SIZE) {
725
+ /* TODO logging */
726
+ return ngx_http_spdy_state_protocol_error(sc);
727
+ }
728
+
729
+ sc->length -= NGX_SPDY_SYN_STREAM_SIZE;
730
+
731
+ sid = ngx_spdy_frame_parse_sid(pos);
732
+ prio = pos[8] >> 6;
733
+
734
+ pos += NGX_SPDY_SYN_STREAM_SIZE;
735
+
736
+ ngx_log_debug2(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0,
737
+ "spdy SYN_STREAM frame sid:%ui prio:%ui", sid, prio);
738
+
739
+ sscf = ngx_http_get_module_srv_conf(sc->http_connection->conf_ctx,
740
+ ngx_http_spdy_module);
741
+
742
+ if (sc->processing >= sscf->concurrent_streams) {
743
+
744
+ ngx_log_error(NGX_LOG_INFO, sc->connection->log, 0,
745
+ "spdy concurrent streams excessed %ui", sc->processing);
746
+
747
+ if (ngx_http_spdy_send_rst_stream(sc, sid, NGX_SPDY_REFUSED_STREAM,
748
+ prio)
749
+ != NGX_OK)
750
+ {
751
+ return ngx_http_spdy_state_internal_error(sc);
752
+ }
753
+
754
+ return ngx_http_spdy_state_headers_skip(sc, pos, end);
755
+ }
756
+
757
+ stream = ngx_http_spdy_create_stream(sc, sid, prio);
758
+ if (stream == NULL) {
759
+ return ngx_http_spdy_state_internal_error(sc);
760
+ }
761
+
762
+ stream->in_closed = (sc->flags & NGX_SPDY_FLAG_FIN) ? 1 : 0;
763
+
764
+ stream->request->request_length = NGX_SPDY_FRAME_HEADER_SIZE
765
+ + NGX_SPDY_SYN_STREAM_SIZE
766
+ + sc->length;
767
+
768
+ sc->stream = stream;
769
+
770
+ sc->last_sid = sid;
771
+
772
+ return ngx_http_spdy_state_headers(sc, pos, end);
773
+ }
774
+
775
+
776
+ static u_char *
777
+ ngx_http_spdy_state_headers(ngx_http_spdy_connection_t *sc, u_char *pos,
778
+ u_char *end)
779
+ {
780
+ int z;
781
+ size_t size;
782
+ ngx_buf_t *buf;
783
+ ngx_int_t rc;
784
+ ngx_uint_t complete;
785
+ ngx_http_request_t *r;
786
+
787
+ size = end - pos;
788
+
789
+ if (size == 0) {
790
+ return ngx_http_spdy_state_save(sc, pos, end,
791
+ ngx_http_spdy_state_headers);
792
+ }
793
+
794
+ if (size >= sc->length) {
795
+ size = sc->length;
796
+ complete = 1;
797
+
798
+ } else {
799
+ complete = 0;
800
+ }
801
+
802
+ r = sc->stream->request;
803
+
804
+ ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
805
+ "spdy process HEADERS %uz of %uz", size, sc->length);
806
+
807
+ buf = r->header_in;
808
+
809
+ sc->zstream_in.next_in = pos;
810
+ sc->zstream_in.avail_in = size;
811
+ sc->zstream_in.next_out = buf->last;
812
+ sc->zstream_in.avail_out = buf->end - buf->last - 1;
813
+
814
+ z = inflate(&sc->zstream_in, Z_NO_FLUSH);
815
+
816
+ if (z == Z_NEED_DICT) {
817
+ z = inflateSetDictionary(&sc->zstream_in, ngx_http_spdy_dict,
818
+ sizeof(ngx_http_spdy_dict));
819
+ if (z != Z_OK) {
820
+ ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
821
+ "spdy inflateSetDictionary() failed: %d", z);
822
+ ngx_http_spdy_close_stream(sc->stream, 0);
823
+ return ngx_http_spdy_state_protocol_error(sc);
824
+ }
825
+
826
+ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
827
+ "spdy inflateSetDictionary(): %d", z);
828
+
829
+ z = sc->zstream_in.avail_in ? inflate(&sc->zstream_in, Z_NO_FLUSH)
830
+ : Z_OK;
831
+ }
832
+
833
+ if (z != Z_OK) {
834
+ ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
835
+ "spdy inflate() failed: %d", z);
836
+ ngx_http_spdy_close_stream(sc->stream, 0);
837
+ return ngx_http_spdy_state_protocol_error(sc);
838
+ }
839
+
840
+ ngx_log_debug5(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
841
+ "spdy inflate out: ni:%p no:%p ai:%ud ao:%ud rc:%d",
842
+ sc->zstream_in.next_in, sc->zstream_in.next_out,
843
+ sc->zstream_in.avail_in, sc->zstream_in.avail_out,
844
+ z);
845
+
846
+ sc->length -= sc->zstream_in.next_in - pos;
847
+ pos = sc->zstream_in.next_in;
848
+
849
+ buf->last = sc->zstream_in.next_out;
850
+
851
+ if (r->headers_in.headers.part.elts == NULL) {
852
+
853
+ if (buf->last - buf->pos < NGX_SPDY_NV_NUM_SIZE) {
854
+ return ngx_http_spdy_state_save(sc, pos, end,
855
+ ngx_http_spdy_state_headers);
856
+ }
857
+
858
+ sc->headers = ngx_spdy_frame_parse_uint16(buf->pos);
859
+
860
+ buf->pos += NGX_SPDY_NV_NUM_SIZE;
861
+
862
+ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
863
+ "spdy headers count: %ui", sc->headers);
864
+
865
+ if (ngx_list_init(&r->headers_in.headers, r->pool, sc->headers + 3,
866
+ sizeof(ngx_table_elt_t))
867
+ != NGX_OK)
868
+ {
869
+ ngx_http_spdy_close_stream(sc->stream,
870
+ NGX_HTTP_INTERNAL_SERVER_ERROR);
871
+ return ngx_http_spdy_state_headers_error(sc, pos, end);
872
+ }
873
+
874
+ if (ngx_array_init(&r->headers_in.cookies, r->pool, 2,
875
+ sizeof(ngx_table_elt_t *))
876
+ != NGX_OK)
877
+ {
878
+ ngx_http_spdy_close_stream(sc->stream,
879
+ NGX_HTTP_INTERNAL_SERVER_ERROR);
880
+ return ngx_http_spdy_state_headers_error(sc, pos, end);
881
+ }
882
+ }
883
+
884
+ while (sc->headers) {
885
+
886
+ rc = ngx_http_spdy_parse_header(r);
887
+
888
+ switch (rc) {
889
+
890
+ case NGX_DONE:
891
+ sc->headers--;
892
+
893
+ case NGX_OK:
894
+ break;
895
+
896
+ case NGX_AGAIN:
897
+
898
+ if (sc->zstream_in.avail_in) {
899
+
900
+ rc = ngx_http_spdy_alloc_large_header_buffer(r);
901
+
902
+ if (rc == NGX_DECLINED) {
903
+ /* TODO logging */
904
+ ngx_http_finalize_request(r,
905
+ NGX_HTTP_REQUEST_HEADER_TOO_LARGE);
906
+ return ngx_http_spdy_state_headers_error(sc, pos, end);
907
+ }
908
+
909
+ if (rc != NGX_OK) {
910
+ ngx_http_spdy_close_stream(sc->stream,
911
+ NGX_HTTP_INTERNAL_SERVER_ERROR);
912
+ return ngx_http_spdy_state_headers_error(sc, pos, end);
913
+ }
914
+
915
+ buf = r->header_in;
916
+
917
+ sc->zstream_in.next_out = buf->last;
918
+ sc->zstream_in.avail_out = buf->end - buf->last - 1;
919
+
920
+ z = inflate(&sc->zstream_in, Z_NO_FLUSH);
921
+
922
+ if (z != Z_OK) {
923
+ ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
924
+ "spdy inflate() failed: %d", z);
925
+ ngx_http_spdy_close_stream(sc->stream, 0);
926
+ return ngx_http_spdy_state_protocol_error(sc);
927
+ }
928
+
929
+ sc->length -= sc->zstream_in.next_in - pos;
930
+ pos = sc->zstream_in.next_in;
931
+
932
+ buf->last = sc->zstream_in.next_out;
933
+
934
+ continue;
935
+ }
936
+
937
+ if (complete) {
938
+ /* TODO: improve error message */
939
+ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
940
+ "spdy again while last chunk");
941
+ ngx_http_spdy_close_stream(sc->stream, 0);
942
+ return ngx_http_spdy_state_protocol_error(sc);
943
+ }
944
+
945
+ return ngx_http_spdy_state_save(sc, pos, end,
946
+ ngx_http_spdy_state_headers);
947
+
948
+ case NGX_HTTP_PARSE_INVALID_REQUEST:
949
+
950
+ /* TODO: improve error message */
951
+ ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
952
+ "client sent invalid header line");
953
+
954
+ ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST);
955
+
956
+ return ngx_http_spdy_state_headers_error(sc, pos, end);
957
+
958
+ default: /* NGX_HTTP_PARSE_INVALID_HEADER */
959
+
960
+ ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
961
+ "client sent invalid HEADERS spdy frame");
962
+ ngx_http_spdy_close_stream(sc->stream, NGX_HTTP_BAD_REQUEST);
963
+ return ngx_http_spdy_state_protocol_error(sc);
964
+ }
965
+
966
+ /* a header line has been parsed successfully */
967
+
968
+ rc = ngx_http_spdy_handle_request_header(r);
969
+
970
+ if (rc != NGX_OK) {
971
+ if (rc == NGX_HTTP_PARSE_INVALID_HEADER) {
972
+ ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
973
+ "client sent invalid HEADERS spdy frame");
974
+ ngx_http_spdy_close_stream(sc->stream, NGX_HTTP_BAD_REQUEST);
975
+ return ngx_http_spdy_state_protocol_error(sc);
976
+ }
977
+
978
+ if (rc == NGX_HTTP_PARSE_INVALID_REQUEST) {
979
+ ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST);
980
+ }
981
+
982
+ return ngx_http_spdy_state_headers_error(sc, pos, end);
983
+ }
984
+ }
985
+
986
+ if (buf->pos != buf->last) {
987
+ /* TODO: improve error message */
988
+ ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
989
+ "end %ui %p %p", complete, buf->pos, buf->last);
990
+ ngx_http_spdy_close_stream(sc->stream, NGX_HTTP_BAD_REQUEST);
991
+ return ngx_http_spdy_state_protocol_error(sc);
992
+ }
993
+
994
+ if (!complete) {
995
+ return ngx_http_spdy_state_save(sc, pos, end,
996
+ ngx_http_spdy_state_headers);
997
+ }
998
+
999
+ ngx_http_spdy_run_request(r);
1000
+
1001
+ return ngx_http_spdy_state_complete(sc, pos, end);
1002
+ }
1003
+
1004
+
1005
+ static u_char *
1006
+ ngx_http_spdy_state_headers_error(ngx_http_spdy_connection_t *sc, u_char *pos,
1007
+ u_char *end)
1008
+ {
1009
+ if (sc->connection->error) {
1010
+ return ngx_http_spdy_state_internal_error(sc);
1011
+ }
1012
+
1013
+ return ngx_http_spdy_state_headers_skip(sc, pos, end);
1014
+ }
1015
+
1016
+
1017
+ static u_char *
1018
+ ngx_http_spdy_state_headers_skip(ngx_http_spdy_connection_t *sc, u_char *pos,
1019
+ u_char *end)
1020
+ {
1021
+ int n;
1022
+ size_t size;
1023
+ u_char buffer[NGX_SPDY_SKIP_HEADERS_BUFFER_SIZE];
1024
+
1025
+ if (sc->length == 0) {
1026
+ return ngx_http_spdy_state_complete(sc, pos, end);
1027
+ }
1028
+
1029
+ size = end - pos;
1030
+
1031
+ if (size == 0) {
1032
+ return ngx_http_spdy_state_save(sc, pos, end,
1033
+ ngx_http_spdy_state_headers_skip);
1034
+ }
1035
+
1036
+ sc->zstream_in.next_in = pos;
1037
+ sc->zstream_in.avail_in = (size < sc->length) ? size : sc->length;
1038
+
1039
+ while (sc->zstream_in.avail_in) {
1040
+ sc->zstream_in.next_out = buffer;
1041
+ sc->zstream_in.avail_out = NGX_SPDY_SKIP_HEADERS_BUFFER_SIZE;
1042
+
1043
+ n = inflate(&sc->zstream_in, Z_NO_FLUSH);
1044
+
1045
+ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0,
1046
+ "spdy inflate(): %d", n);
1047
+
1048
+ if (n != Z_OK) {
1049
+ /* TODO: logging */
1050
+ return ngx_http_spdy_state_protocol_error(sc);
1051
+ }
1052
+ }
1053
+
1054
+ pos = sc->zstream_in.next_in;
1055
+
1056
+ if (size < sc->length) {
1057
+ sc->length -= size;
1058
+ return ngx_http_spdy_state_save(sc, pos, end,
1059
+ ngx_http_spdy_state_headers_skip);
1060
+ }
1061
+
1062
+ return ngx_http_spdy_state_complete(sc, pos, end);
1063
+ }
1064
+
1065
+
1066
+ static u_char *
1067
+ ngx_http_spdy_state_data(ngx_http_spdy_connection_t *sc, u_char *pos,
1068
+ u_char *end)
1069
+ {
1070
+ size_t size;
1071
+ ssize_t n;
1072
+ ngx_buf_t *buf;
1073
+ ngx_int_t rc;
1074
+ ngx_uint_t complete;
1075
+ ngx_temp_file_t *tf;
1076
+ ngx_http_request_t *r;
1077
+ ngx_http_spdy_stream_t *stream;
1078
+ ngx_http_request_body_t *rb;
1079
+ ngx_http_core_loc_conf_t *clcf;
1080
+
1081
+ stream = sc->stream;
1082
+
1083
+ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0,
1084
+ "spdy DATA frame");
1085
+
1086
+ if (stream == NULL) {
1087
+ return ngx_http_spdy_state_skip(sc, pos, end);
1088
+ }
1089
+
1090
+ if (stream->in_closed) {
1091
+ /* TODO log */
1092
+ return ngx_http_spdy_state_protocol_error(sc);
1093
+ }
1094
+
1095
+ if (stream->skip_data) {
1096
+
1097
+ if (sc->flags & NGX_SPDY_FLAG_FIN) {
1098
+ stream->in_closed = 1;
1099
+ }
1100
+
1101
+ /* TODO log and accounting */
1102
+ return ngx_http_spdy_state_skip(sc, pos, end);
1103
+ }
1104
+
1105
+ size = end - pos;
1106
+
1107
+ if (size >= sc->length) {
1108
+ size = sc->length;
1109
+ complete = 1;
1110
+
1111
+ } else {
1112
+ sc->length -= size;
1113
+ complete = 0;
1114
+ }
1115
+
1116
+ r = stream->request;
1117
+
1118
+ if (r->request_body == NULL
1119
+ && ngx_http_spdy_init_request_body(r) != NGX_OK)
1120
+ {
1121
+ stream->skip_data = NGX_SPDY_DATA_INTERNAL_ERROR;
1122
+ return ngx_http_spdy_state_skip(sc, pos, end);
1123
+ }
1124
+
1125
+ rb = r->request_body;
1126
+ tf = rb->temp_file;
1127
+ buf = rb->buf;
1128
+
1129
+ if (size) {
1130
+ rb->rest += size;
1131
+
1132
+ if (r->headers_in.content_length_n != -1
1133
+ && r->headers_in.content_length_n < rb->rest)
1134
+ {
1135
+ /* TODO logging */
1136
+ stream->skip_data = NGX_SPDY_DATA_ERROR;
1137
+ goto error;
1138
+
1139
+ } else {
1140
+ clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
1141
+
1142
+ if (clcf->client_max_body_size
1143
+ && clcf->client_max_body_size < rb->rest)
1144
+ {
1145
+ ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
1146
+ "client intended to send too large chunked "
1147
+ "body: %O bytes",
1148
+ rb->rest);
1149
+
1150
+ stream->skip_data = NGX_SPDY_DATA_ERROR;
1151
+ goto error;
1152
+ }
1153
+ }
1154
+
1155
+ if (tf) {
1156
+ buf->start = pos;
1157
+ buf->pos = pos;
1158
+
1159
+ pos += size;
1160
+
1161
+ buf->end = pos;
1162
+ buf->last = pos;
1163
+
1164
+ n = ngx_write_chain_to_temp_file(tf, rb->bufs);
1165
+
1166
+ /* TODO: n == 0 or not complete and level event */
1167
+
1168
+ if (n == NGX_ERROR) {
1169
+ stream->skip_data = NGX_SPDY_DATA_INTERNAL_ERROR;
1170
+ goto error;
1171
+ }
1172
+
1173
+ tf->offset += n;
1174
+
1175
+ } else {
1176
+ buf->last = ngx_cpymem(buf->last, pos, size);
1177
+ pos += size;
1178
+ }
1179
+
1180
+ r->request_length += size;
1181
+ }
1182
+
1183
+ if (!complete) {
1184
+ return ngx_http_spdy_state_save(sc, pos, end,
1185
+ ngx_http_spdy_state_data);
1186
+ }
1187
+
1188
+ if (sc->flags & NGX_SPDY_FLAG_FIN) {
1189
+
1190
+ stream->in_closed = 1;
1191
+
1192
+ if (tf) {
1193
+ ngx_memzero(buf, sizeof(ngx_buf_t));
1194
+
1195
+ buf->in_file = 1;
1196
+ buf->file_last = tf->file.offset;
1197
+ buf->file = &tf->file;
1198
+
1199
+ rb->buf = NULL;
1200
+ }
1201
+
1202
+ if (r->headers_in.content_length_n < 0) {
1203
+ r->headers_in.content_length_n = rb->rest;
1204
+ }
1205
+
1206
+ if (rb->post_handler) {
1207
+ rb->post_handler(r);
1208
+ }
1209
+ }
1210
+
1211
+ return ngx_http_spdy_state_complete(sc, pos, end);
1212
+
1213
+ error:
1214
+
1215
+ if (rb->post_handler) {
1216
+
1217
+ if (stream->skip_data == NGX_SPDY_DATA_ERROR) {
1218
+ rc = (r->headers_in.content_length_n == -1)
1219
+ ? NGX_HTTP_REQUEST_ENTITY_TOO_LARGE
1220
+ : NGX_HTTP_BAD_REQUEST;
1221
+
1222
+ } else {
1223
+ rc = NGX_HTTP_INTERNAL_SERVER_ERROR;
1224
+ }
1225
+
1226
+ ngx_http_finalize_request(r, rc);
1227
+ }
1228
+
1229
+ return ngx_http_spdy_state_skip(sc, pos, end);
1230
+ }
1231
+
1232
+
1233
+ static u_char *
1234
+ ngx_http_spdy_state_rst_stream(ngx_http_spdy_connection_t *sc, u_char *pos,
1235
+ u_char *end)
1236
+ {
1237
+ ngx_uint_t sid, status;
1238
+ ngx_event_t *ev;
1239
+ ngx_connection_t *fc;
1240
+ ngx_http_request_t *r;
1241
+ ngx_http_spdy_stream_t *stream;
1242
+
1243
+ if (end - pos < NGX_SPDY_RST_STREAM_SIZE) {
1244
+ return ngx_http_spdy_state_save(sc, pos, end,
1245
+ ngx_http_spdy_state_rst_stream);
1246
+ }
1247
+
1248
+ if (sc->length != NGX_SPDY_RST_STREAM_SIZE) {
1249
+ /* TODO logging */
1250
+ return ngx_http_spdy_state_protocol_error(sc);
1251
+ }
1252
+
1253
+ sid = ngx_spdy_frame_parse_sid(pos);
1254
+
1255
+ pos += NGX_SPDY_SID_SIZE;
1256
+
1257
+ status = ngx_spdy_frame_parse_uint32(pos);
1258
+
1259
+ pos += sizeof(uint32_t);
1260
+
1261
+ ngx_log_debug2(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0,
1262
+ "spdy RST_STREAM sid:%ui st:%ui", sid, status);
1263
+
1264
+
1265
+ switch (status) {
1266
+
1267
+ case NGX_SPDY_PROTOCOL_ERROR:
1268
+ /* TODO logging */
1269
+ return ngx_http_spdy_state_protocol_error(sc);
1270
+
1271
+ case NGX_SPDY_INVALID_STREAM:
1272
+ /* TODO */
1273
+ break;
1274
+
1275
+ case NGX_SPDY_REFUSED_STREAM:
1276
+ /* TODO */
1277
+ break;
1278
+
1279
+ case NGX_SPDY_UNSUPPORTED_VERSION:
1280
+ /* TODO logging */
1281
+ return ngx_http_spdy_state_protocol_error(sc);
1282
+
1283
+ case NGX_SPDY_CANCEL:
1284
+ case NGX_SPDY_INTERNAL_ERROR:
1285
+ stream = ngx_http_spdy_get_stream_by_id(sc, sid);
1286
+ if (stream == NULL) {
1287
+ /* TODO false cancel */
1288
+ break;
1289
+ }
1290
+
1291
+ stream->in_closed = 1;
1292
+ stream->out_closed = 1;
1293
+
1294
+ r = stream->request;
1295
+
1296
+ fc = r->connection;
1297
+ fc->error = 1;
1298
+
1299
+ ev = fc->read;
1300
+ ev->handler(ev);
1301
+
1302
+ break;
1303
+
1304
+ case NGX_SPDY_FLOW_CONTROL_ERROR:
1305
+ /* TODO logging */
1306
+ return ngx_http_spdy_state_protocol_error(sc);
1307
+
1308
+ default:
1309
+ /* TODO */
1310
+ return ngx_http_spdy_state_protocol_error(sc);
1311
+ }
1312
+
1313
+ return ngx_http_spdy_state_complete(sc, pos, end);
1314
+ }
1315
+
1316
+
1317
+ static u_char *
1318
+ ngx_http_spdy_state_ping(ngx_http_spdy_connection_t *sc, u_char *pos,
1319
+ u_char *end)
1320
+ {
1321
+ u_char *p;
1322
+ ngx_buf_t *buf;
1323
+ ngx_http_spdy_out_frame_t *frame;
1324
+
1325
+ if (end - pos < NGX_SPDY_PING_SIZE) {
1326
+ return ngx_http_spdy_state_save(sc, pos, end,
1327
+ ngx_http_spdy_state_ping);
1328
+ }
1329
+
1330
+ if (sc->length != NGX_SPDY_PING_SIZE) {
1331
+ /* TODO logging */
1332
+ return ngx_http_spdy_state_protocol_error(sc);
1333
+ }
1334
+
1335
+ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0,
1336
+ "spdy PING frame");
1337
+
1338
+ frame = ngx_http_spdy_get_ctl_frame(sc, NGX_SPDY_PING_SIZE,
1339
+ NGX_SPDY_HIGHEST_PRIORITY);
1340
+ if (frame == NULL) {
1341
+ return ngx_http_spdy_state_internal_error(sc);
1342
+ }
1343
+
1344
+ buf = frame->first->buf;
1345
+
1346
+ p = buf->pos;
1347
+
1348
+ p = ngx_spdy_frame_write_head(p, NGX_SPDY_PING);
1349
+ p = ngx_spdy_frame_write_flags_and_len(p, 0, NGX_SPDY_PING_SIZE);
1350
+
1351
+ p = ngx_cpymem(p, pos, NGX_SPDY_PING_SIZE);
1352
+
1353
+ buf->last = p;
1354
+
1355
+ ngx_http_spdy_queue_frame(sc, frame);
1356
+
1357
+ pos += NGX_SPDY_PING_SIZE;
1358
+
1359
+ return ngx_http_spdy_state_complete(sc, pos, end);
1360
+ }
1361
+
1362
+
1363
+ static u_char *
1364
+ ngx_http_spdy_state_skip(ngx_http_spdy_connection_t *sc, u_char *pos,
1365
+ u_char *end)
1366
+ {
1367
+ size_t size;
1368
+
1369
+ size = end - pos;
1370
+
1371
+ if (size < sc->length) {
1372
+ sc->length -= size;
1373
+ return ngx_http_spdy_state_save(sc, end, end,
1374
+ ngx_http_spdy_state_skip);
1375
+ }
1376
+
1377
+ return ngx_http_spdy_state_complete(sc, pos + sc->length, end);
1378
+ }
1379
+
1380
+
1381
+ static u_char *
1382
+ ngx_http_spdy_state_settings(ngx_http_spdy_connection_t *sc, u_char *pos,
1383
+ u_char *end)
1384
+ {
1385
+ ngx_uint_t v;
1386
+ ngx_http_spdy_srv_conf_t *sscf;
1387
+
1388
+ if (sc->headers == 0) {
1389
+
1390
+ if (end - pos < NGX_SPDY_SETTINGS_NUM_SIZE) {
1391
+ return ngx_http_spdy_state_save(sc, pos, end,
1392
+ ngx_http_spdy_state_settings);
1393
+ }
1394
+
1395
+ sc->headers = ngx_spdy_frame_parse_uint32(pos);
1396
+
1397
+ pos += NGX_SPDY_SETTINGS_NUM_SIZE;
1398
+ sc->length -= NGX_SPDY_SETTINGS_NUM_SIZE;
1399
+
1400
+ if (sc->length < sc->headers * NGX_SPDY_SETTINGS_PAIR_SIZE) {
1401
+ /* TODO logging */
1402
+ return ngx_http_spdy_state_protocol_error(sc);
1403
+ }
1404
+
1405
+ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0,
1406
+ "spdy SETTINGS frame consists of %ui entries",
1407
+ sc->headers);
1408
+ }
1409
+
1410
+ while (sc->headers) {
1411
+ if (end - pos < NGX_SPDY_SETTINGS_PAIR_SIZE) {
1412
+ return ngx_http_spdy_state_save(sc, pos, end,
1413
+ ngx_http_spdy_state_settings);
1414
+ }
1415
+
1416
+ sc->headers--;
1417
+
1418
+ if (pos[0] != NGX_SPDY_SETTINGS_MAX_STREAMS) {
1419
+ pos += NGX_SPDY_SETTINGS_PAIR_SIZE;
1420
+ sc->length -= NGX_SPDY_SETTINGS_PAIR_SIZE;
1421
+ continue;
1422
+ }
1423
+
1424
+ v = ngx_spdy_frame_parse_uint32(pos + NGX_SPDY_SETTINGS_IDF_SIZE);
1425
+
1426
+ sscf = ngx_http_get_module_srv_conf(sc->http_connection->conf_ctx,
1427
+ ngx_http_spdy_module);
1428
+
1429
+ if (v != sscf->concurrent_streams) {
1430
+ ngx_http_spdy_send_settings(sc);
1431
+ }
1432
+
1433
+ return ngx_http_spdy_state_skip(sc, pos, end);
1434
+ }
1435
+
1436
+ ngx_http_spdy_send_settings(sc);
1437
+
1438
+ return ngx_http_spdy_state_complete(sc, pos, end);
1439
+ }
1440
+
1441
+
1442
+ static u_char *
1443
+ ngx_http_spdy_state_noop(ngx_http_spdy_connection_t *sc, u_char *pos,
1444
+ u_char *end)
1445
+ {
1446
+ if (sc->length) {
1447
+ /* TODO logging */
1448
+ return ngx_http_spdy_state_protocol_error(sc);
1449
+ }
1450
+
1451
+ return ngx_http_spdy_state_complete(sc, pos, end);
1452
+ }
1453
+
1454
+
1455
+ static u_char *
1456
+ ngx_http_spdy_state_complete(ngx_http_spdy_connection_t *sc, u_char *pos,
1457
+ u_char *end)
1458
+ {
1459
+ sc->handler = ngx_http_spdy_state_head;
1460
+ return pos;
1461
+ }
1462
+
1463
+
1464
+ static u_char *
1465
+ ngx_http_spdy_state_save(ngx_http_spdy_connection_t *sc,
1466
+ u_char *pos, u_char *end, ngx_http_spdy_handler_pt handler)
1467
+ {
1468
+ #if (NGX_DEBUG)
1469
+ if (end - pos > NGX_SPDY_STATE_BUFFER_SIZE) {
1470
+ ngx_log_error(NGX_LOG_ALERT, sc->connection->log, 0,
1471
+ "spdy state buffer overflow: "
1472
+ "%i bytes required", end - pos);
1473
+ return ngx_http_spdy_state_internal_error(sc);
1474
+ }
1475
+ #endif
1476
+
1477
+ ngx_memcpy(sc->buffer, pos, NGX_SPDY_STATE_BUFFER_SIZE);
1478
+
1479
+ sc->buffer_used = end - pos;
1480
+ sc->handler = handler;
1481
+ sc->waiting = 1;
1482
+
1483
+ return end;
1484
+ }
1485
+
1486
+
1487
+ static u_char *
1488
+ ngx_http_spdy_state_protocol_error(ngx_http_spdy_connection_t *sc)
1489
+ {
1490
+ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0,
1491
+ "spdy state protocol error");
1492
+
1493
+ /* TODO */
1494
+ ngx_http_spdy_finalize_connection(sc, NGX_HTTP_CLIENT_CLOSED_REQUEST);
1495
+ return NULL;
1496
+ }
1497
+
1498
+
1499
+ static u_char *
1500
+ ngx_http_spdy_state_internal_error(ngx_http_spdy_connection_t *sc)
1501
+ {
1502
+ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0,
1503
+ "spdy state internal error");
1504
+
1505
+ /* TODO */
1506
+ ngx_http_spdy_finalize_connection(sc, NGX_HTTP_INTERNAL_SERVER_ERROR);
1507
+ return NULL;
1508
+ }
1509
+
1510
+
1511
+ static ngx_int_t
1512
+ ngx_http_spdy_send_rst_stream(ngx_http_spdy_connection_t *sc, ngx_uint_t sid,
1513
+ ngx_uint_t status, ngx_uint_t priority)
1514
+ {
1515
+ u_char *p;
1516
+ ngx_buf_t *buf;
1517
+ ngx_http_spdy_out_frame_t *frame;
1518
+
1519
+ if (sc->connection->error) {
1520
+ return NGX_OK;
1521
+ }
1522
+
1523
+ ngx_log_debug2(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0,
1524
+ "spdy write RST_STREAM sid:%ui st:%ui", sid, status);
1525
+
1526
+ frame = ngx_http_spdy_get_ctl_frame(sc, NGX_SPDY_RST_STREAM_SIZE,
1527
+ priority);
1528
+ if (frame == NULL) {
1529
+ return NGX_ERROR;
1530
+ }
1531
+
1532
+ buf = frame->first->buf;
1533
+
1534
+ p = buf->pos;
1535
+
1536
+ p = ngx_spdy_frame_write_head(p, NGX_SPDY_RST_STREAM);
1537
+ p = ngx_spdy_frame_write_flags_and_len(p, 0, NGX_SPDY_RST_STREAM_SIZE);
1538
+
1539
+ p = ngx_spdy_frame_write_sid(p, sid);
1540
+ p = ngx_spdy_frame_aligned_write_uint32(p, status);
1541
+
1542
+ buf->last = p;
1543
+
1544
+ ngx_http_spdy_queue_frame(sc, frame);
1545
+
1546
+ return NGX_OK;
1547
+ }
1548
+
1549
+
1550
+ #if 0
1551
+ static ngx_int_t
1552
+ ngx_http_spdy_send_goaway(ngx_http_spdy_connection_t *sc)
1553
+ {
1554
+ u_char *p;
1555
+ ngx_buf_t *buf;
1556
+ ngx_http_spdy_out_frame_t *frame;
1557
+
1558
+ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0,
1559
+ "spdy create GOAWAY sid:%ui", sc->last_sid);
1560
+
1561
+ frame = ngx_http_spdy_get_ctl_frame(sc, NGX_SPDY_GOAWAY_SIZE,
1562
+ NGX_SPDY_HIGHEST_PRIORITY);
1563
+ if (frame == NULL) {
1564
+ return NGX_ERROR;
1565
+ }
1566
+
1567
+ buf = frame->first->buf;
1568
+
1569
+ p = buf->pos;
1570
+
1571
+ p = ngx_spdy_frame_write_head(p, NGX_SPDY_GOAWAY);
1572
+ p = ngx_spdy_frame_write_flags_and_len(p, 0, NGX_SPDY_GOAWAY_SIZE);
1573
+
1574
+ p = ngx_spdy_frame_write_sid(p, sc->last_sid);
1575
+
1576
+ buf->last = p;
1577
+
1578
+ ngx_http_spdy_queue_frame(sc, frame);
1579
+
1580
+ return NGX_OK;
1581
+ }
1582
+ #endif
1583
+
1584
+
1585
+ static ngx_int_t
1586
+ ngx_http_spdy_send_settings(ngx_http_spdy_connection_t *sc)
1587
+ {
1588
+ u_char *p;
1589
+ ngx_buf_t *buf;
1590
+ ngx_pool_t *pool;
1591
+ ngx_chain_t *cl;
1592
+ ngx_http_spdy_srv_conf_t *sscf;
1593
+ ngx_http_spdy_out_frame_t *frame;
1594
+
1595
+ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0,
1596
+ "spdy create SETTINGS frame");
1597
+
1598
+ pool = sc->connection->pool;
1599
+
1600
+ frame = ngx_palloc(pool, sizeof(ngx_http_spdy_out_frame_t));
1601
+ if (frame == NULL) {
1602
+ return NGX_ERROR;
1603
+ }
1604
+
1605
+ cl = ngx_alloc_chain_link(pool);
1606
+ if (cl == NULL) {
1607
+ return NGX_ERROR;
1608
+ }
1609
+
1610
+ buf = ngx_create_temp_buf(pool, NGX_SPDY_FRAME_HEADER_SIZE
1611
+ + NGX_SPDY_SETTINGS_NUM_SIZE
1612
+ + NGX_SPDY_SETTINGS_PAIR_SIZE);
1613
+ if (buf == NULL) {
1614
+ return NGX_ERROR;
1615
+ }
1616
+
1617
+ buf->last_buf = 1;
1618
+
1619
+ cl->buf = buf;
1620
+ cl->next = NULL;
1621
+
1622
+ frame->first = cl;
1623
+ frame->last = cl;
1624
+ frame->handler = ngx_http_spdy_settings_frame_handler;
1625
+ #if (NGX_DEBUG)
1626
+ frame->stream = NULL;
1627
+ frame->size = NGX_SPDY_FRAME_HEADER_SIZE
1628
+ + NGX_SPDY_SETTINGS_NUM_SIZE
1629
+ + NGX_SPDY_SETTINGS_PAIR_SIZE;
1630
+ #endif
1631
+ frame->priority = NGX_SPDY_HIGHEST_PRIORITY;
1632
+ frame->blocked = 0;
1633
+
1634
+ p = buf->pos;
1635
+
1636
+ p = ngx_spdy_frame_write_head(p, NGX_SPDY_SETTINGS);
1637
+ p = ngx_spdy_frame_write_flags_and_len(p, NGX_SPDY_FLAG_CLEAR_SETTINGS,
1638
+ NGX_SPDY_SETTINGS_NUM_SIZE
1639
+ + NGX_SPDY_SETTINGS_PAIR_SIZE);
1640
+
1641
+ p = ngx_spdy_frame_aligned_write_uint32(p, 1);
1642
+ p = ngx_spdy_frame_aligned_write_uint32(p,
1643
+ NGX_SPDY_SETTINGS_MAX_STREAMS << 24
1644
+ | NGX_SPDY_SETTINGS_FLAG_PERSIST);
1645
+
1646
+ sscf = ngx_http_get_module_srv_conf(sc->http_connection->conf_ctx,
1647
+ ngx_http_spdy_module);
1648
+
1649
+ p = ngx_spdy_frame_aligned_write_uint32(p, sscf->concurrent_streams);
1650
+
1651
+ buf->last = p;
1652
+
1653
+ ngx_http_spdy_queue_frame(sc, frame);
1654
+
1655
+ return NGX_OK;
1656
+ }
1657
+
1658
+
1659
+ ngx_int_t
1660
+ ngx_http_spdy_settings_frame_handler(ngx_http_spdy_connection_t *sc,
1661
+ ngx_http_spdy_out_frame_t *frame)
1662
+ {
1663
+ ngx_buf_t *buf;
1664
+
1665
+ buf = frame->first->buf;
1666
+
1667
+ if (buf->pos != buf->last) {
1668
+ return NGX_AGAIN;
1669
+ }
1670
+
1671
+ ngx_free_chain(sc->pool, frame->first);
1672
+
1673
+ return NGX_OK;
1674
+ }
1675
+
1676
+
1677
+ static ngx_http_spdy_out_frame_t *
1678
+ ngx_http_spdy_get_ctl_frame(ngx_http_spdy_connection_t *sc, size_t size,
1679
+ ngx_uint_t priority)
1680
+ {
1681
+ ngx_chain_t *cl;
1682
+ ngx_http_spdy_out_frame_t *frame;
1683
+
1684
+ frame = sc->free_ctl_frames;
1685
+
1686
+ if (frame) {
1687
+ sc->free_ctl_frames = frame->free;
1688
+
1689
+ cl = frame->first;
1690
+ cl->buf->pos = cl->buf->start;
1691
+
1692
+ } else {
1693
+ frame = ngx_palloc(sc->pool, sizeof(ngx_http_spdy_out_frame_t));
1694
+ if (frame == NULL) {
1695
+ return NULL;
1696
+ }
1697
+
1698
+ cl = ngx_alloc_chain_link(sc->pool);
1699
+ if (cl == NULL) {
1700
+ return NULL;
1701
+ }
1702
+
1703
+ cl->buf = ngx_create_temp_buf(sc->pool,
1704
+ NGX_SPDY_CTL_FRAME_BUFFER_SIZE);
1705
+ if (cl->buf == NULL) {
1706
+ return NULL;
1707
+ }
1708
+
1709
+ cl->buf->last_buf = 1;
1710
+
1711
+ frame->first = cl;
1712
+ frame->last = cl;
1713
+ frame->handler = ngx_http_spdy_ctl_frame_handler;
1714
+ }
1715
+
1716
+ frame->free = NULL;
1717
+
1718
+ #if (NGX_DEBUG)
1719
+ if (size > NGX_SPDY_CTL_FRAME_BUFFER_SIZE - NGX_SPDY_FRAME_HEADER_SIZE) {
1720
+ ngx_log_error(NGX_LOG_ALERT, sc->pool->log, 0,
1721
+ "requested control frame is too big: %z", size);
1722
+ return NULL;
1723
+ }
1724
+
1725
+ frame->stream = NULL;
1726
+ frame->size = size;
1727
+ #endif
1728
+
1729
+ frame->priority = priority;
1730
+ frame->blocked = 0;
1731
+
1732
+ return frame;
1733
+ }
1734
+
1735
+
1736
+ static ngx_int_t
1737
+ ngx_http_spdy_ctl_frame_handler(ngx_http_spdy_connection_t *sc,
1738
+ ngx_http_spdy_out_frame_t *frame)
1739
+ {
1740
+ ngx_buf_t *buf;
1741
+
1742
+ buf = frame->first->buf;
1743
+
1744
+ if (buf->pos != buf->last) {
1745
+ return NGX_AGAIN;
1746
+ }
1747
+
1748
+ frame->free = sc->free_ctl_frames;
1749
+ sc->free_ctl_frames = frame;
1750
+
1751
+ return NGX_OK;
1752
+ }
1753
+
1754
+
1755
+ static ngx_http_spdy_stream_t *
1756
+ ngx_http_spdy_create_stream(ngx_http_spdy_connection_t *sc, ngx_uint_t id,
1757
+ ngx_uint_t priority)
1758
+ {
1759
+ ngx_log_t *log;
1760
+ ngx_uint_t index;
1761
+ ngx_event_t *rev, *wev;
1762
+ ngx_connection_t *fc;
1763
+ ngx_http_log_ctx_t *ctx;
1764
+ ngx_http_request_t *r;
1765
+ ngx_http_spdy_stream_t *stream;
1766
+ ngx_http_core_srv_conf_t *cscf;
1767
+ ngx_http_spdy_srv_conf_t *sscf;
1768
+
1769
+ fc = sc->free_fake_connections;
1770
+
1771
+ if (fc) {
1772
+ sc->free_fake_connections = fc->data;
1773
+
1774
+ rev = fc->read;
1775
+ wev = fc->write;
1776
+ log = fc->log;
1777
+ ctx = log->data;
1778
+
1779
+ } else {
1780
+ fc = ngx_palloc(sc->pool, sizeof(ngx_connection_t));
1781
+ if (fc == NULL) {
1782
+ return NULL;
1783
+ }
1784
+
1785
+ rev = ngx_palloc(sc->pool, sizeof(ngx_event_t));
1786
+ if (rev == NULL) {
1787
+ return NULL;
1788
+ }
1789
+
1790
+ wev = ngx_palloc(sc->pool, sizeof(ngx_event_t));
1791
+ if (wev == NULL) {
1792
+ return NULL;
1793
+ }
1794
+
1795
+ log = ngx_palloc(sc->pool, sizeof(ngx_log_t));
1796
+ if (log == NULL) {
1797
+ return NULL;
1798
+ }
1799
+
1800
+ ctx = ngx_palloc(sc->pool, sizeof(ngx_http_log_ctx_t));
1801
+ if (ctx == NULL) {
1802
+ return NULL;
1803
+ }
1804
+
1805
+ ctx->connection = fc;
1806
+ ctx->request = NULL;
1807
+ }
1808
+
1809
+ ngx_memcpy(log, sc->connection->log, sizeof(ngx_log_t));
1810
+
1811
+ log->data = ctx;
1812
+
1813
+ ngx_memzero(rev, sizeof(ngx_event_t));
1814
+
1815
+ rev->data = fc;
1816
+ rev->ready = 1;
1817
+ rev->handler = ngx_http_empty_handler;
1818
+ rev->log = log;
1819
+
1820
+ ngx_memcpy(wev, rev, sizeof(ngx_event_t));
1821
+
1822
+ wev->write = 1;
1823
+
1824
+ ngx_memcpy(fc, sc->connection, sizeof(ngx_connection_t));
1825
+
1826
+ fc->data = sc->http_connection;
1827
+ fc->read = rev;
1828
+ fc->write = wev;
1829
+ fc->sent = 0;
1830
+ fc->log = log;
1831
+ fc->buffered = 0;
1832
+ fc->sndlowat = 1;
1833
+ fc->tcp_nodelay = NGX_TCP_NODELAY_DISABLED;
1834
+
1835
+ r = ngx_http_create_request(fc);
1836
+ if (r == NULL) {
1837
+ return NULL;
1838
+ }
1839
+
1840
+ r->valid_location = 1;
1841
+
1842
+ fc->data = r;
1843
+ sc->connection->requests++;
1844
+
1845
+ cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module);
1846
+
1847
+ r->header_in = ngx_create_temp_buf(r->pool,
1848
+ cscf->client_header_buffer_size);
1849
+ if (r->header_in == NULL) {
1850
+ ngx_http_free_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
1851
+ return NULL;
1852
+ }
1853
+
1854
+ r->headers_in.connection_type = NGX_HTTP_CONNECTION_CLOSE;
1855
+
1856
+ stream = ngx_pcalloc(r->pool, sizeof(ngx_http_spdy_stream_t));
1857
+ if (stream == NULL) {
1858
+ ngx_http_free_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
1859
+ return NULL;
1860
+ }
1861
+
1862
+ r->spdy_stream = stream;
1863
+
1864
+ stream->id = id;
1865
+ stream->request = r;
1866
+ stream->connection = sc;
1867
+ stream->priority = priority;
1868
+
1869
+ sscf = ngx_http_get_module_srv_conf(r, ngx_http_spdy_module);
1870
+
1871
+ index = ngx_http_spdy_stream_index(sscf, id);
1872
+
1873
+ stream->index = sc->streams_index[index];
1874
+ sc->streams_index[index] = stream;
1875
+
1876
+ sc->processing++;
1877
+
1878
+ return stream;
1879
+ }
1880
+
1881
+
1882
+ static ngx_http_spdy_stream_t *
1883
+ ngx_http_spdy_get_stream_by_id(ngx_http_spdy_connection_t *sc,
1884
+ ngx_uint_t sid)
1885
+ {
1886
+ ngx_http_spdy_stream_t *stream;
1887
+ ngx_http_spdy_srv_conf_t *sscf;
1888
+
1889
+ sscf = ngx_http_get_module_srv_conf(sc->http_connection->conf_ctx,
1890
+ ngx_http_spdy_module);
1891
+
1892
+ stream = sc->streams_index[ngx_http_spdy_stream_index(sscf, sid)];
1893
+
1894
+ while (stream) {
1895
+ if (stream->id == sid) {
1896
+ return stream;
1897
+ }
1898
+
1899
+ stream = stream->index;
1900
+ }
1901
+
1902
+ return NULL;
1903
+ }
1904
+
1905
+
1906
+ static ngx_int_t
1907
+ ngx_http_spdy_parse_header(ngx_http_request_t *r)
1908
+ {
1909
+ u_char *p, *end, ch;
1910
+ ngx_uint_t len, hash;
1911
+ ngx_http_core_srv_conf_t *cscf;
1912
+
1913
+ enum {
1914
+ sw_name_len = 0,
1915
+ sw_name,
1916
+ sw_value_len,
1917
+ sw_value
1918
+ } state;
1919
+
1920
+ state = r->state;
1921
+
1922
+ p = r->header_in->pos;
1923
+ end = r->header_in->last;
1924
+
1925
+ switch (state) {
1926
+
1927
+ case sw_name_len:
1928
+
1929
+ if (end - p < NGX_SPDY_NV_NLEN_SIZE) {
1930
+ return NGX_AGAIN;
1931
+ }
1932
+
1933
+ len = ngx_spdy_frame_parse_uint16(p);
1934
+
1935
+ if (!len) {
1936
+ return NGX_HTTP_PARSE_INVALID_HEADER;
1937
+ }
1938
+
1939
+ p += NGX_SPDY_NV_NLEN_SIZE;
1940
+
1941
+ r->header_name_end = p + len;
1942
+ r->lowcase_index = len;
1943
+ r->invalid_header = 0;
1944
+
1945
+ state = sw_name;
1946
+
1947
+ /* fall through */
1948
+
1949
+ case sw_name:
1950
+
1951
+ if (r->header_name_end > end) {
1952
+ break;
1953
+ }
1954
+
1955
+ cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module);
1956
+
1957
+ r->header_name_start = p;
1958
+
1959
+ hash = 0;
1960
+
1961
+ for ( /* void */ ; p != r->header_name_end; p++) {
1962
+
1963
+ ch = *p;
1964
+
1965
+ hash = ngx_hash(hash, ch);
1966
+
1967
+ if ((ch >= 'a' && ch <= 'z')
1968
+ || (ch == '-')
1969
+ || (ch >= '0' && ch <= '9')
1970
+ || (ch == '_' && cscf->underscores_in_headers))
1971
+ {
1972
+ continue;
1973
+ }
1974
+
1975
+ switch (ch) {
1976
+ case '\0':
1977
+ case LF:
1978
+ case CR:
1979
+ case ':':
1980
+ return NGX_HTTP_PARSE_INVALID_REQUEST;
1981
+ }
1982
+
1983
+ if (ch >= 'A' && ch <= 'Z') {
1984
+ return NGX_HTTP_PARSE_INVALID_HEADER;
1985
+ }
1986
+
1987
+ r->invalid_header = 1;
1988
+ }
1989
+
1990
+ r->header_hash = hash;
1991
+
1992
+ state = sw_value_len;
1993
+
1994
+ /* fall through */
1995
+
1996
+ case sw_value_len:
1997
+
1998
+ if (end - p < NGX_SPDY_NV_VLEN_SIZE) {
1999
+ break;
2000
+ }
2001
+
2002
+ len = ngx_spdy_frame_parse_uint16(p);
2003
+
2004
+ if (!len) {
2005
+ return NGX_ERROR;
2006
+ }
2007
+
2008
+ p += NGX_SPDY_NV_VLEN_SIZE;
2009
+
2010
+ r->header_end = p + len;
2011
+
2012
+ state = sw_value;
2013
+
2014
+ /* fall through */
2015
+
2016
+ case sw_value:
2017
+
2018
+ if (r->header_end > end) {
2019
+ break;
2020
+ }
2021
+
2022
+ r->header_start = p;
2023
+
2024
+ for ( /* void */ ; p != r->header_end; p++) {
2025
+
2026
+ ch = *p;
2027
+
2028
+ if (ch == '\0') {
2029
+
2030
+ if (p == r->header_start) {
2031
+ return NGX_ERROR;
2032
+ }
2033
+
2034
+ r->header_size = p - r->header_start;
2035
+ r->header_in->pos = p + 1;
2036
+
2037
+ return NGX_OK;
2038
+ }
2039
+
2040
+ if (ch == CR || ch == LF) {
2041
+ return NGX_HTTP_PARSE_INVALID_HEADER;
2042
+ }
2043
+ }
2044
+
2045
+ r->header_size = p - r->header_start;
2046
+ r->header_in->pos = p;
2047
+
2048
+ r->state = 0;
2049
+
2050
+ return NGX_DONE;
2051
+ }
2052
+
2053
+ r->header_in->pos = p;
2054
+ r->state = state;
2055
+
2056
+ return NGX_AGAIN;
2057
+ }
2058
+
2059
+
2060
+ static ngx_int_t
2061
+ ngx_http_spdy_alloc_large_header_buffer(ngx_http_request_t *r)
2062
+ {
2063
+ u_char *old, *new;
2064
+ size_t rest;
2065
+ ngx_buf_t *buf;
2066
+ ngx_http_spdy_stream_t *stream;
2067
+ ngx_http_core_srv_conf_t *cscf;
2068
+
2069
+ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
2070
+ "spdy alloc large header buffer");
2071
+
2072
+ stream = r->spdy_stream;
2073
+
2074
+ cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module);
2075
+
2076
+ if (stream->header_buffers
2077
+ == (ngx_uint_t) cscf->large_client_header_buffers.num)
2078
+ {
2079
+ return NGX_DECLINED;
2080
+ }
2081
+
2082
+ rest = r->header_in->last - r->header_in->pos;
2083
+
2084
+ if (rest >= cscf->large_client_header_buffers.size) {
2085
+ return NGX_DECLINED;
2086
+ }
2087
+
2088
+ buf = ngx_create_temp_buf(r->pool, cscf->large_client_header_buffers.size);
2089
+ if (buf == NULL) {
2090
+ return NGX_ERROR;
2091
+ }
2092
+
2093
+ ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
2094
+ "spdy large header alloc: %p %uz",
2095
+ buf->pos, buf->end - buf->last);
2096
+
2097
+ old = r->header_in->pos;
2098
+ new = buf->pos;
2099
+
2100
+ if (rest) {
2101
+ buf->last = ngx_cpymem(new, old, rest);
2102
+ }
2103
+
2104
+ if (r->header_name_end > old) {
2105
+ r->header_name_end = new + (r->header_name_end - old);
2106
+
2107
+ } else if (r->header_end > old) {
2108
+ r->header_end = new + (r->header_end - old);
2109
+ }
2110
+
2111
+ r->header_in = buf;
2112
+
2113
+ stream->header_buffers++;
2114
+
2115
+ return NGX_OK;
2116
+ }
2117
+
2118
+
2119
+ static ngx_int_t
2120
+ ngx_http_spdy_handle_request_header(ngx_http_request_t *r)
2121
+ {
2122
+ ngx_uint_t i;
2123
+ ngx_table_elt_t *h;
2124
+ ngx_http_core_srv_conf_t *cscf;
2125
+ ngx_http_spdy_request_header_t *sh;
2126
+
2127
+ if (r->invalid_header) {
2128
+ cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module);
2129
+
2130
+ if (cscf->ignore_invalid_headers) {
2131
+ ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
2132
+ "client sent invalid header: \"%*s\"",
2133
+ r->header_end - r->header_name_start,
2134
+ r->header_name_start);
2135
+ return NGX_OK;
2136
+ }
2137
+
2138
+ } else {
2139
+ for (i = 0; i < NGX_SPDY_REQUEST_HEADERS; i++) {
2140
+ sh = &ngx_http_spdy_request_headers[i];
2141
+
2142
+ if (sh->hash != r->header_hash
2143
+ || sh->len != r->lowcase_index
2144
+ || ngx_strncmp(sh->header, r->header_name_start,
2145
+ r->lowcase_index)
2146
+ != 0)
2147
+ {
2148
+ continue;
2149
+ }
2150
+
2151
+ return sh->handler(r);
2152
+ }
2153
+ }
2154
+
2155
+ h = ngx_list_push(&r->headers_in.headers);
2156
+ if (h == NULL) {
2157
+ ngx_http_spdy_close_stream(r->spdy_stream,
2158
+ NGX_HTTP_INTERNAL_SERVER_ERROR);
2159
+ return NGX_ERROR;
2160
+ }
2161
+
2162
+ h->hash = r->header_hash;
2163
+
2164
+ h->key.len = r->lowcase_index;
2165
+ h->key.data = r->header_name_start;
2166
+ h->key.data[h->key.len] = '\0';
2167
+
2168
+ h->value.len = r->header_size;
2169
+ h->value.data = r->header_start;
2170
+ h->value.data[h->value.len] = '\0';
2171
+
2172
+ h->lowcase_key = h->key.data;
2173
+
2174
+ return NGX_OK;
2175
+ }
2176
+
2177
+
2178
+ void
2179
+ ngx_http_spdy_request_headers_init()
2180
+ {
2181
+ ngx_uint_t i;
2182
+ ngx_http_spdy_request_header_t *h;
2183
+
2184
+ for (i = 0; i < NGX_SPDY_REQUEST_HEADERS; i++) {
2185
+ h = &ngx_http_spdy_request_headers[i];
2186
+ h->hash = ngx_hash_key(h->header, h->len);
2187
+ }
2188
+ }
2189
+
2190
+
2191
+ static ngx_int_t
2192
+ ngx_http_spdy_parse_method(ngx_http_request_t *r)
2193
+ {
2194
+ size_t k, len;
2195
+ ngx_uint_t n;
2196
+ const u_char *p, *m;
2197
+
2198
+ /*
2199
+ * This array takes less than 256 sequential bytes,
2200
+ * and if typical CPU cache line size is 64 bytes,
2201
+ * it is prefetched for 4 load operations.
2202
+ */
2203
+ static const struct {
2204
+ u_char len;
2205
+ const u_char method[11];
2206
+ uint32_t value;
2207
+ } tests[] = {
2208
+ { 3, "GET", NGX_HTTP_GET },
2209
+ { 4, "POST", NGX_HTTP_POST },
2210
+ { 4, "HEAD", NGX_HTTP_HEAD },
2211
+ { 7, "OPTIONS", NGX_HTTP_OPTIONS },
2212
+ { 8, "PROPFIND", NGX_HTTP_PROPFIND },
2213
+ { 3, "PUT", NGX_HTTP_PUT },
2214
+ { 5, "MKCOL", NGX_HTTP_MKCOL },
2215
+ { 6, "DELETE", NGX_HTTP_DELETE },
2216
+ { 4, "COPY", NGX_HTTP_COPY },
2217
+ { 4, "MOVE", NGX_HTTP_MOVE },
2218
+ { 9, "PROPPATCH", NGX_HTTP_PROPPATCH },
2219
+ { 4, "LOCK", NGX_HTTP_LOCK },
2220
+ { 6, "UNLOCK", NGX_HTTP_UNLOCK },
2221
+ { 5, "PATCH", NGX_HTTP_PATCH },
2222
+ { 5, "TRACE", NGX_HTTP_TRACE }
2223
+ }, *test;
2224
+
2225
+ if (r->method_name.len) {
2226
+ return NGX_HTTP_PARSE_INVALID_HEADER;
2227
+ }
2228
+
2229
+ len = r->header_size;
2230
+
2231
+ r->method_name.len = len;
2232
+ r->method_name.data = r->header_start;
2233
+
2234
+ test = tests;
2235
+ n = sizeof(tests) / sizeof(tests[0]);
2236
+
2237
+ do {
2238
+ if (len == test->len) {
2239
+ p = r->method_name.data;
2240
+ m = test->method;
2241
+ k = len;
2242
+
2243
+ do {
2244
+ if (*p++ != *m++) {
2245
+ goto next;
2246
+ }
2247
+ } while (--k);
2248
+
2249
+ r->method = test->value;
2250
+ return NGX_OK;
2251
+ }
2252
+
2253
+ next:
2254
+ test++;
2255
+
2256
+ } while (--n);
2257
+
2258
+ p = r->method_name.data;
2259
+
2260
+ do {
2261
+ if ((*p < 'A' || *p > 'Z') && *p != '_') {
2262
+ ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
2263
+ "client sent invalid method");
2264
+ return NGX_HTTP_PARSE_INVALID_REQUEST;
2265
+ }
2266
+
2267
+ p++;
2268
+
2269
+ } while (--len);
2270
+
2271
+ return NGX_OK;
2272
+ }
2273
+
2274
+
2275
+ static ngx_int_t
2276
+ ngx_http_spdy_parse_scheme(ngx_http_request_t *r)
2277
+ {
2278
+ if (r->schema_start) {
2279
+ return NGX_HTTP_PARSE_INVALID_HEADER;
2280
+ }
2281
+
2282
+ r->schema_start = r->header_start;
2283
+ r->schema_end = r->header_end;
2284
+
2285
+ return NGX_OK;
2286
+ }
2287
+
2288
+
2289
+ static ngx_int_t
2290
+ ngx_http_spdy_parse_url(ngx_http_request_t *r)
2291
+ {
2292
+ if (r->unparsed_uri.len) {
2293
+ return NGX_HTTP_PARSE_INVALID_HEADER;
2294
+ }
2295
+
2296
+ r->uri_start = r->header_start;
2297
+ r->uri_end = r->header_end;
2298
+
2299
+ if (ngx_http_parse_uri(r) != NGX_OK) {
2300
+ return NGX_HTTP_PARSE_INVALID_REQUEST;
2301
+ }
2302
+
2303
+ if (ngx_http_process_request_uri(r) != NGX_OK) {
2304
+ return NGX_ERROR;
2305
+ }
2306
+
2307
+ return NGX_OK;
2308
+ }
2309
+
2310
+
2311
+ static ngx_int_t
2312
+ ngx_http_spdy_parse_version(ngx_http_request_t *r)
2313
+ {
2314
+ u_char *p, ch;
2315
+
2316
+ if (r->http_protocol.len) {
2317
+ return NGX_HTTP_PARSE_INVALID_HEADER;
2318
+ }
2319
+
2320
+ p = r->header_start;
2321
+
2322
+ if (r->header_size < 8 || !(ngx_str5cmp(p, 'H', 'T', 'T', 'P', '/'))) {
2323
+ return NGX_HTTP_PARSE_INVALID_REQUEST;
2324
+ }
2325
+
2326
+ ch = *(p + 5);
2327
+
2328
+ if (ch < '1' || ch > '9') {
2329
+ return NGX_HTTP_PARSE_INVALID_REQUEST;
2330
+ }
2331
+
2332
+ r->http_major = ch - '0';
2333
+
2334
+ for (p += 6; p != r->header_end - 2; p++) {
2335
+
2336
+ ch = *p;
2337
+
2338
+ if (ch < '0' || ch > '9') {
2339
+ return NGX_HTTP_PARSE_INVALID_REQUEST;
2340
+ }
2341
+
2342
+ r->http_major = r->http_major * 10 + ch - '0';
2343
+ }
2344
+
2345
+ if (*p != '.') {
2346
+ return NGX_HTTP_PARSE_INVALID_REQUEST;
2347
+ }
2348
+
2349
+ ch = *(p + 1);
2350
+
2351
+ if (ch < '0' || ch > '9') {
2352
+ return NGX_HTTP_PARSE_INVALID_REQUEST;
2353
+ }
2354
+
2355
+ r->http_minor = ch - '0';
2356
+
2357
+ for (p += 2; p != r->header_end; p++) {
2358
+
2359
+ ch = *p;
2360
+
2361
+ if (ch < '0' || ch > '9') {
2362
+ return NGX_HTTP_PARSE_INVALID_REQUEST;
2363
+ }
2364
+
2365
+ r->http_minor = r->http_minor * 10 + ch - '0';
2366
+ }
2367
+
2368
+ r->http_protocol.len = r->header_size;
2369
+ r->http_protocol.data = r->header_start;
2370
+ r->http_version = r->http_major * 1000 + r->http_minor;
2371
+
2372
+ return NGX_OK;
2373
+ }
2374
+
2375
+
2376
+ static ngx_int_t
2377
+ ngx_http_spdy_construct_request_line(ngx_http_request_t *r)
2378
+ {
2379
+ u_char *p;
2380
+
2381
+ if (r->method_name.len == 0
2382
+ || r->unparsed_uri.len == 0
2383
+ || r->http_protocol.len == 0)
2384
+ {
2385
+ ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST);
2386
+ return NGX_ERROR;
2387
+ }
2388
+
2389
+ r->request_line.len = r->method_name.len + 1
2390
+ + r->unparsed_uri.len + 1
2391
+ + r->http_protocol.len;
2392
+
2393
+ p = ngx_pnalloc(r->pool, r->request_line.len + 1);
2394
+ if (p == NULL) {
2395
+ ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
2396
+ return NGX_ERROR;
2397
+ }
2398
+
2399
+ r->request_line.data = p;
2400
+
2401
+ p = ngx_cpymem(p, r->method_name.data, r->method_name.len);
2402
+
2403
+ *p++ = ' ';
2404
+
2405
+ p = ngx_cpymem(p, r->unparsed_uri.data, r->unparsed_uri.len);
2406
+
2407
+ *p++ = ' ';
2408
+
2409
+ ngx_memcpy(p, r->http_protocol.data, r->http_protocol.len + 1);
2410
+
2411
+ /* some modules expect the space character after method name */
2412
+ r->method_name.data = r->request_line.data;
2413
+
2414
+ return NGX_OK;
2415
+ }
2416
+
2417
+
2418
+ static void
2419
+ ngx_http_spdy_run_request(ngx_http_request_t *r)
2420
+ {
2421
+ ngx_uint_t i;
2422
+ ngx_list_part_t *part;
2423
+ ngx_table_elt_t *h;
2424
+ ngx_http_header_t *hh;
2425
+ ngx_http_core_main_conf_t *cmcf;
2426
+
2427
+ if (ngx_http_spdy_construct_request_line(r) != NGX_OK) {
2428
+ return;
2429
+ }
2430
+
2431
+ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
2432
+ "spdy http request line: \"%V\"", &r->request_line);
2433
+
2434
+ cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module);
2435
+
2436
+ part = &r->headers_in.headers.part;
2437
+ h = part->elts;
2438
+
2439
+ for (i = 0 ;; i++) {
2440
+
2441
+ if (i >= part->nelts) {
2442
+ if (part->next == NULL) {
2443
+ break;
2444
+ }
2445
+
2446
+ part = part->next;
2447
+ h = part->elts;
2448
+ i = 0;
2449
+ }
2450
+
2451
+ hh = ngx_hash_find(&cmcf->headers_in_hash, h[i].hash,
2452
+ h[i].lowcase_key, h[i].key.len);
2453
+
2454
+ if (hh && hh->handler(r, &h[i], hh->offset) != NGX_OK) {
2455
+ return;
2456
+ }
2457
+
2458
+ ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
2459
+ "http header: \"%V: %V\"", &h[i].key, &h[i].value);
2460
+ }
2461
+
2462
+ r->http_state = NGX_HTTP_PROCESS_REQUEST_STATE;
2463
+
2464
+ if (ngx_http_process_request_header(r) != NGX_OK) {
2465
+ return;
2466
+ }
2467
+
2468
+ ngx_http_process_request(r);
2469
+ }
2470
+
2471
+
2472
+ static ngx_int_t
2473
+ ngx_http_spdy_init_request_body(ngx_http_request_t *r)
2474
+ {
2475
+ ngx_buf_t *buf;
2476
+ ngx_temp_file_t *tf;
2477
+ ngx_http_request_body_t *rb;
2478
+ ngx_http_core_loc_conf_t *clcf;
2479
+
2480
+ rb = ngx_pcalloc(r->pool, sizeof(ngx_http_request_body_t));
2481
+ if (rb == NULL) {
2482
+ return NGX_ERROR;
2483
+ }
2484
+
2485
+ r->request_body = rb;
2486
+
2487
+ if (r->spdy_stream->in_closed) {
2488
+ return NGX_OK;
2489
+ }
2490
+
2491
+ rb->rest = r->headers_in.content_length_n;
2492
+
2493
+ clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
2494
+
2495
+ if (r->request_body_in_file_only
2496
+ || rb->rest > (off_t) clcf->client_body_buffer_size
2497
+ || rb->rest < 0)
2498
+ {
2499
+ tf = ngx_pcalloc(r->pool, sizeof(ngx_temp_file_t));
2500
+ if (tf == NULL) {
2501
+ return NGX_ERROR;
2502
+ }
2503
+
2504
+ tf->file.fd = NGX_INVALID_FILE;
2505
+ tf->file.log = r->connection->log;
2506
+ tf->path = clcf->client_body_temp_path;
2507
+ tf->pool = r->pool;
2508
+ tf->warn = "a client request body is buffered to a temporary file";
2509
+ tf->log_level = r->request_body_file_log_level;
2510
+ tf->persistent = r->request_body_in_persistent_file;
2511
+ tf->clean = r->request_body_in_clean_file;
2512
+
2513
+ if (r->request_body_file_group_access) {
2514
+ tf->access = 0660;
2515
+ }
2516
+
2517
+ rb->temp_file = tf;
2518
+
2519
+ if (r->spdy_stream->in_closed
2520
+ && ngx_create_temp_file(&tf->file, tf->path, tf->pool,
2521
+ tf->persistent, tf->clean, tf->access)
2522
+ != NGX_OK)
2523
+ {
2524
+ return NGX_ERROR;
2525
+ }
2526
+
2527
+ buf = ngx_calloc_buf(r->pool);
2528
+ if (buf == NULL) {
2529
+ return NGX_ERROR;
2530
+ }
2531
+
2532
+ if (rb->rest == 0) {
2533
+ buf->in_file = 1;
2534
+ buf->file = &tf->file;
2535
+ } else {
2536
+ rb->buf = buf;
2537
+ }
2538
+
2539
+ } else {
2540
+
2541
+ if (rb->rest == 0) {
2542
+ return NGX_OK;
2543
+ }
2544
+
2545
+ buf = ngx_create_temp_buf(r->pool, (size_t) rb->rest);
2546
+ if (buf == NULL) {
2547
+ return NGX_ERROR;
2548
+ }
2549
+
2550
+ rb->buf = buf;
2551
+ }
2552
+
2553
+ rb->bufs = ngx_alloc_chain_link(r->pool);
2554
+ if (rb->bufs == NULL) {
2555
+ return NGX_ERROR;
2556
+ }
2557
+
2558
+ rb->bufs->buf = buf;
2559
+ rb->bufs->next = NULL;
2560
+
2561
+ rb->rest = 0;
2562
+
2563
+ return NGX_OK;
2564
+ }
2565
+
2566
+
2567
+ ngx_int_t
2568
+ ngx_http_spdy_read_request_body(ngx_http_request_t *r,
2569
+ ngx_http_client_body_handler_pt post_handler)
2570
+ {
2571
+ ngx_http_spdy_stream_t *stream;
2572
+
2573
+ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
2574
+ "spdy read request body");
2575
+
2576
+ stream = r->spdy_stream;
2577
+
2578
+ switch (stream->skip_data) {
2579
+
2580
+ case NGX_SPDY_DATA_DISCARD:
2581
+ post_handler(r);
2582
+ return NGX_OK;
2583
+
2584
+ case NGX_SPDY_DATA_ERROR:
2585
+ if (r->headers_in.content_length_n == -1) {
2586
+ return NGX_HTTP_REQUEST_ENTITY_TOO_LARGE;
2587
+ } else {
2588
+ return NGX_HTTP_BAD_REQUEST;
2589
+ }
2590
+
2591
+ case NGX_SPDY_DATA_INTERNAL_ERROR:
2592
+ return NGX_HTTP_INTERNAL_SERVER_ERROR;
2593
+ }
2594
+
2595
+ if (!r->request_body && ngx_http_spdy_init_request_body(r) != NGX_OK) {
2596
+ stream->skip_data = NGX_SPDY_DATA_INTERNAL_ERROR;
2597
+ return NGX_HTTP_INTERNAL_SERVER_ERROR;
2598
+ }
2599
+
2600
+ if (stream->in_closed) {
2601
+ post_handler(r);
2602
+ return NGX_OK;
2603
+ }
2604
+
2605
+ r->request_body->post_handler = post_handler;
2606
+
2607
+ return NGX_AGAIN;
2608
+ }
2609
+
2610
+
2611
+ void
2612
+ ngx_http_spdy_close_stream(ngx_http_spdy_stream_t *stream, ngx_int_t rc)
2613
+ {
2614
+ ngx_event_t *ev;
2615
+ ngx_connection_t *fc;
2616
+ ngx_http_spdy_stream_t **index, *s;
2617
+ ngx_http_spdy_srv_conf_t *sscf;
2618
+ ngx_http_spdy_connection_t *sc;
2619
+
2620
+ sc = stream->connection;
2621
+
2622
+ ngx_log_debug2(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0,
2623
+ "spdy close stream %ui, processing %ui",
2624
+ stream->id, sc->processing);
2625
+
2626
+ if (!stream->out_closed) {
2627
+ if (ngx_http_spdy_send_rst_stream(sc, stream->id,
2628
+ NGX_SPDY_INTERNAL_ERROR,
2629
+ stream->priority)
2630
+ != NGX_OK)
2631
+ {
2632
+ sc->connection->error = 1;
2633
+ }
2634
+ }
2635
+
2636
+ sscf = ngx_http_get_module_srv_conf(sc->http_connection->conf_ctx,
2637
+ ngx_http_spdy_module);
2638
+
2639
+ index = sc->streams_index + ngx_http_spdy_stream_index(sscf, stream->id);
2640
+
2641
+ for ( ;; ) {
2642
+ s = *index;
2643
+
2644
+ if (s == NULL) {
2645
+ break;
2646
+ }
2647
+
2648
+ if (s == stream) {
2649
+ *index = s->index;
2650
+ break;
2651
+ }
2652
+
2653
+ index = &s->index;
2654
+ }
2655
+
2656
+ fc = stream->request->connection;
2657
+
2658
+ ngx_http_free_request(stream->request, rc);
2659
+
2660
+ ev = fc->read;
2661
+
2662
+ if (ev->active || ev->disabled) {
2663
+ ngx_del_event(ev, NGX_READ_EVENT, 0);
2664
+ }
2665
+
2666
+ if (ev->timer_set) {
2667
+ ngx_del_timer(ev);
2668
+ }
2669
+
2670
+ if (ev->prev) {
2671
+ ngx_delete_posted_event(ev);
2672
+ }
2673
+
2674
+ ev = fc->write;
2675
+
2676
+ if (ev->active || ev->disabled) {
2677
+ ngx_del_event(ev, NGX_WRITE_EVENT, 0);
2678
+ }
2679
+
2680
+ if (ev->timer_set) {
2681
+ ngx_del_timer(ev);
2682
+ }
2683
+
2684
+ if (ev->prev) {
2685
+ ngx_delete_posted_event(ev);
2686
+ }
2687
+
2688
+ fc->data = sc->free_fake_connections;
2689
+ sc->free_fake_connections = fc;
2690
+
2691
+ sc->processing--;
2692
+
2693
+ if (sc->processing || sc->blocked) {
2694
+ return;
2695
+ }
2696
+
2697
+ ev = sc->connection->read;
2698
+
2699
+ ev->handler = ngx_http_spdy_handle_connection_handler;
2700
+ ngx_post_event(ev, &ngx_posted_events);
2701
+ }
2702
+
2703
+
2704
+ static void
2705
+ ngx_http_spdy_handle_connection_handler(ngx_event_t *rev)
2706
+ {
2707
+ ngx_connection_t *c;
2708
+
2709
+ rev->handler = ngx_http_spdy_read_handler;
2710
+
2711
+ if (rev->ready) {
2712
+ ngx_http_spdy_read_handler(rev);
2713
+ return;
2714
+ }
2715
+
2716
+ c = rev->data;
2717
+
2718
+ ngx_http_spdy_handle_connection(c->data);
2719
+ }
2720
+
2721
+
2722
+ static void
2723
+ ngx_http_spdy_keepalive_handler(ngx_event_t *rev)
2724
+ {
2725
+ ngx_connection_t *c;
2726
+ ngx_http_spdy_srv_conf_t *sscf;
2727
+ ngx_http_spdy_connection_t *sc;
2728
+
2729
+ c = rev->data;
2730
+
2731
+ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "spdy keepalive handler");
2732
+
2733
+ if (rev->timedout || c->close) {
2734
+ ngx_http_close_connection(c);
2735
+ return;
2736
+ }
2737
+
2738
+ #if (NGX_HAVE_KQUEUE)
2739
+
2740
+ if (ngx_event_flags & NGX_USE_KQUEUE_EVENT) {
2741
+ if (rev->pending_eof) {
2742
+ c->log->handler = NULL;
2743
+ ngx_log_error(NGX_LOG_INFO, c->log, rev->kq_errno,
2744
+ "kevent() reported that client %V closed "
2745
+ "keepalive connection", &c->addr_text);
2746
+ #if (NGX_HTTP_SSL)
2747
+ if (c->ssl) {
2748
+ c->ssl->no_send_shutdown = 1;
2749
+ }
2750
+ #endif
2751
+ ngx_http_close_connection(c);
2752
+ return;
2753
+ }
2754
+ }
2755
+
2756
+ #endif
2757
+
2758
+ c->destroyed = 0;
2759
+ c->idle = 0;
2760
+ ngx_reusable_connection(c, 0);
2761
+
2762
+ sc = c->data;
2763
+
2764
+ sscf = ngx_http_get_module_srv_conf(sc->http_connection->conf_ctx,
2765
+ ngx_http_spdy_module);
2766
+
2767
+ sc->pool = ngx_create_pool(sscf->pool_size, sc->connection->log);
2768
+ if (sc->pool == NULL) {
2769
+ ngx_http_close_connection(c);
2770
+ return;
2771
+ }
2772
+
2773
+ sc->streams_index = ngx_pcalloc(sc->pool,
2774
+ ngx_http_spdy_streams_index_size(sscf)
2775
+ * sizeof(ngx_http_spdy_stream_t *));
2776
+ if (sc->streams_index == NULL) {
2777
+ ngx_http_close_connection(c);
2778
+ return;
2779
+ }
2780
+
2781
+ c->write->handler = ngx_http_spdy_write_handler;
2782
+
2783
+ rev->handler = ngx_http_spdy_read_handler;
2784
+ ngx_http_spdy_read_handler(rev);
2785
+ }
2786
+
2787
+
2788
+ static void
2789
+ ngx_http_spdy_finalize_connection(ngx_http_spdy_connection_t *sc,
2790
+ ngx_int_t rc)
2791
+ {
2792
+ ngx_uint_t i, size;
2793
+ ngx_event_t *ev;
2794
+ ngx_connection_t *c, *fc;
2795
+ ngx_http_request_t *r;
2796
+ ngx_http_spdy_stream_t *stream;
2797
+ ngx_http_spdy_srv_conf_t *sscf;
2798
+
2799
+ c = sc->connection;
2800
+
2801
+ if (!sc->processing) {
2802
+ ngx_http_close_connection(c);
2803
+ return;
2804
+ }
2805
+
2806
+ c->error = 1;
2807
+ c->read->handler = ngx_http_empty_handler;
2808
+
2809
+ sc->last_out = NULL;
2810
+
2811
+ sc->blocked = 1;
2812
+
2813
+ sscf = ngx_http_get_module_srv_conf(sc->http_connection->conf_ctx,
2814
+ ngx_http_spdy_module);
2815
+
2816
+ size = ngx_http_spdy_streams_index_size(sscf);
2817
+
2818
+ for (i = 0; i < size; i++) {
2819
+ stream = sc->streams_index[i];
2820
+
2821
+ while (stream) {
2822
+ r = stream->request;
2823
+
2824
+ fc = r->connection;
2825
+ fc->error = 1;
2826
+
2827
+ if (stream->waiting) {
2828
+ r->blocked -= stream->waiting;
2829
+ stream->waiting = 0;
2830
+ ev = fc->write;
2831
+
2832
+ } else {
2833
+ ev = fc->read;
2834
+ }
2835
+
2836
+ stream = stream->index;
2837
+
2838
+ ev->eof = 1;
2839
+ ev->handler(ev);
2840
+ }
2841
+ }
2842
+
2843
+ sc->blocked = 0;
2844
+
2845
+ if (sc->processing) {
2846
+ return;
2847
+ }
2848
+
2849
+ ngx_http_close_connection(c);
2850
+ }
2851
+
2852
+
2853
+ static void
2854
+ ngx_http_spdy_pool_cleanup(void *data)
2855
+ {
2856
+ ngx_http_spdy_connection_t *sc = data;
2857
+
2858
+ if (sc->pool) {
2859
+ ngx_destroy_pool(sc->pool);
2860
+ }
2861
+ }
2862
+
2863
+
2864
+ static void *
2865
+ ngx_http_spdy_zalloc(void *opaque, u_int items, u_int size)
2866
+ {
2867
+ ngx_http_spdy_connection_t *sc = opaque;
2868
+
2869
+ return ngx_palloc(sc->connection->pool, items * size);
2870
+ }
2871
+
2872
+
2873
+ static void
2874
+ ngx_http_spdy_zfree(void *opaque, void *address)
2875
+ {
2876
+ #if 0
2877
+ ngx_http_spdy_connection_t *sc = opaque;
2878
+
2879
+ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0,
2880
+ "spdy zfree: %p", address);
2881
+ #endif
2882
+ }