Annotation of embedaddon/nginx/src/http/ngx_http_spdy.c, revision 1.1.1.1
1.1 misho 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: } else {
2533:
2534: if (rb->rest == 0) {
2535: return NGX_OK;
2536: }
2537:
2538: buf = ngx_create_temp_buf(r->pool, (size_t) rb->rest);
2539: if (buf == NULL) {
2540: return NGX_ERROR;
2541: }
2542: }
2543:
2544: rb->buf = buf;
2545:
2546: rb->bufs = ngx_alloc_chain_link(r->pool);
2547: if (rb->bufs == NULL) {
2548: return NGX_ERROR;
2549: }
2550:
2551: rb->bufs->buf = buf;
2552: rb->bufs->next = NULL;
2553:
2554: rb->rest = 0;
2555:
2556: return NGX_OK;
2557: }
2558:
2559:
2560: ngx_int_t
2561: ngx_http_spdy_read_request_body(ngx_http_request_t *r,
2562: ngx_http_client_body_handler_pt post_handler)
2563: {
2564: ngx_http_spdy_stream_t *stream;
2565:
2566: ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
2567: "spdy read request body");
2568:
2569: stream = r->spdy_stream;
2570:
2571: switch (stream->skip_data) {
2572:
2573: case NGX_SPDY_DATA_DISCARD:
2574: post_handler(r);
2575: return NGX_OK;
2576:
2577: case NGX_SPDY_DATA_ERROR:
2578: if (r->headers_in.content_length_n == -1) {
2579: return NGX_HTTP_REQUEST_ENTITY_TOO_LARGE;
2580: } else {
2581: return NGX_HTTP_BAD_REQUEST;
2582: }
2583:
2584: case NGX_SPDY_DATA_INTERNAL_ERROR:
2585: return NGX_HTTP_INTERNAL_SERVER_ERROR;
2586: }
2587:
2588: if (!r->request_body && ngx_http_spdy_init_request_body(r) != NGX_OK) {
2589: stream->skip_data = NGX_SPDY_DATA_INTERNAL_ERROR;
2590: return NGX_HTTP_INTERNAL_SERVER_ERROR;
2591: }
2592:
2593: if (stream->in_closed) {
2594: post_handler(r);
2595: return NGX_OK;
2596: }
2597:
2598: r->request_body->post_handler = post_handler;
2599:
2600: return NGX_AGAIN;
2601: }
2602:
2603:
2604: void
2605: ngx_http_spdy_close_stream(ngx_http_spdy_stream_t *stream, ngx_int_t rc)
2606: {
2607: ngx_event_t *ev;
2608: ngx_connection_t *fc;
2609: ngx_http_spdy_stream_t **index, *s;
2610: ngx_http_spdy_srv_conf_t *sscf;
2611: ngx_http_spdy_connection_t *sc;
2612:
2613: sc = stream->connection;
2614:
2615: ngx_log_debug2(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0,
2616: "spdy close stream %ui, processing %ui",
2617: stream->id, sc->processing);
2618:
2619: if (!stream->out_closed) {
2620: if (ngx_http_spdy_send_rst_stream(sc, stream->id,
2621: NGX_SPDY_INTERNAL_ERROR,
2622: stream->priority)
2623: != NGX_OK)
2624: {
2625: sc->connection->error = 1;
2626: }
2627: }
2628:
2629: sscf = ngx_http_get_module_srv_conf(sc->http_connection->conf_ctx,
2630: ngx_http_spdy_module);
2631:
2632: index = sc->streams_index + ngx_http_spdy_stream_index(sscf, stream->id);
2633:
2634: for ( ;; ) {
2635: s = *index;
2636:
2637: if (s == NULL) {
2638: break;
2639: }
2640:
2641: if (s == stream) {
2642: *index = s->index;
2643: break;
2644: }
2645:
2646: index = &s->index;
2647: }
2648:
2649: fc = stream->request->connection;
2650:
2651: ngx_http_free_request(stream->request, rc);
2652:
2653: ev = fc->read;
2654:
2655: if (ev->active || ev->disabled) {
2656: ngx_del_event(ev, NGX_READ_EVENT, 0);
2657: }
2658:
2659: if (ev->timer_set) {
2660: ngx_del_timer(ev);
2661: }
2662:
2663: if (ev->prev) {
2664: ngx_delete_posted_event(ev);
2665: }
2666:
2667: ev = fc->write;
2668:
2669: if (ev->active || ev->disabled) {
2670: ngx_del_event(ev, NGX_WRITE_EVENT, 0);
2671: }
2672:
2673: if (ev->timer_set) {
2674: ngx_del_timer(ev);
2675: }
2676:
2677: if (ev->prev) {
2678: ngx_delete_posted_event(ev);
2679: }
2680:
2681: fc->data = sc->free_fake_connections;
2682: sc->free_fake_connections = fc;
2683:
2684: sc->processing--;
2685:
2686: if (sc->processing || sc->blocked) {
2687: return;
2688: }
2689:
2690: ev = sc->connection->read;
2691:
2692: ev->handler = ngx_http_spdy_handle_connection_handler;
2693: ngx_post_event(ev, &ngx_posted_events);
2694: }
2695:
2696:
2697: static void
2698: ngx_http_spdy_handle_connection_handler(ngx_event_t *rev)
2699: {
2700: ngx_connection_t *c;
2701:
2702: rev->handler = ngx_http_spdy_read_handler;
2703:
2704: if (rev->ready) {
2705: ngx_http_spdy_read_handler(rev);
2706: return;
2707: }
2708:
2709: c = rev->data;
2710:
2711: ngx_http_spdy_handle_connection(c->data);
2712: }
2713:
2714:
2715: static void
2716: ngx_http_spdy_keepalive_handler(ngx_event_t *rev)
2717: {
2718: ngx_connection_t *c;
2719: ngx_http_spdy_srv_conf_t *sscf;
2720: ngx_http_spdy_connection_t *sc;
2721:
2722: c = rev->data;
2723:
2724: ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "spdy keepalive handler");
2725:
2726: if (rev->timedout || c->close) {
2727: ngx_http_close_connection(c);
2728: return;
2729: }
2730:
2731: #if (NGX_HAVE_KQUEUE)
2732:
2733: if (ngx_event_flags & NGX_USE_KQUEUE_EVENT) {
2734: if (rev->pending_eof) {
2735: c->log->handler = NULL;
2736: ngx_log_error(NGX_LOG_INFO, c->log, rev->kq_errno,
2737: "kevent() reported that client %V closed "
2738: "keepalive connection", &c->addr_text);
2739: #if (NGX_HTTP_SSL)
2740: if (c->ssl) {
2741: c->ssl->no_send_shutdown = 1;
2742: }
2743: #endif
2744: ngx_http_close_connection(c);
2745: return;
2746: }
2747: }
2748:
2749: #endif
2750:
2751: c->destroyed = 0;
2752: c->idle = 0;
2753: ngx_reusable_connection(c, 0);
2754:
2755: sc = c->data;
2756:
2757: sscf = ngx_http_get_module_srv_conf(sc->http_connection->conf_ctx,
2758: ngx_http_spdy_module);
2759:
2760: sc->pool = ngx_create_pool(sscf->pool_size, sc->connection->log);
2761: if (sc->pool == NULL) {
2762: ngx_http_close_connection(c);
2763: return;
2764: }
2765:
2766: sc->streams_index = ngx_pcalloc(sc->pool,
2767: ngx_http_spdy_streams_index_size(sscf)
2768: * sizeof(ngx_http_spdy_stream_t *));
2769: if (sc->streams_index == NULL) {
2770: ngx_http_close_connection(c);
2771: return;
2772: }
2773:
2774: c->write->handler = ngx_http_spdy_write_handler;
2775:
2776: rev->handler = ngx_http_spdy_read_handler;
2777: ngx_http_spdy_read_handler(rev);
2778: }
2779:
2780:
2781: static void
2782: ngx_http_spdy_finalize_connection(ngx_http_spdy_connection_t *sc,
2783: ngx_int_t rc)
2784: {
2785: ngx_uint_t i, size;
2786: ngx_event_t *ev;
2787: ngx_connection_t *c, *fc;
2788: ngx_http_request_t *r;
2789: ngx_http_spdy_stream_t *stream;
2790: ngx_http_spdy_srv_conf_t *sscf;
2791:
2792: c = sc->connection;
2793:
2794: if (!sc->processing) {
2795: ngx_http_close_connection(c);
2796: return;
2797: }
2798:
2799: c->error = 1;
2800: c->read->handler = ngx_http_empty_handler;
2801:
2802: sc->last_out = NULL;
2803:
2804: sc->blocked = 1;
2805:
2806: sscf = ngx_http_get_module_srv_conf(sc->http_connection->conf_ctx,
2807: ngx_http_spdy_module);
2808:
2809: size = ngx_http_spdy_streams_index_size(sscf);
2810:
2811: for (i = 0; i < size; i++) {
2812: stream = sc->streams_index[i];
2813:
2814: while (stream) {
2815: r = stream->request;
2816:
2817: fc = r->connection;
2818: fc->error = 1;
2819:
2820: if (stream->waiting) {
2821: r->blocked -= stream->waiting;
2822: stream->waiting = 0;
2823: ev = fc->write;
2824:
2825: } else {
2826: ev = fc->read;
2827: }
2828:
2829: stream = stream->index;
2830:
2831: ev->eof = 1;
2832: ev->handler(ev);
2833: }
2834: }
2835:
2836: sc->blocked = 0;
2837:
2838: if (sc->processing) {
2839: return;
2840: }
2841:
2842: ngx_http_close_connection(c);
2843: }
2844:
2845:
2846: static void
2847: ngx_http_spdy_pool_cleanup(void *data)
2848: {
2849: ngx_http_spdy_connection_t *sc = data;
2850:
2851: if (sc->pool) {
2852: ngx_destroy_pool(sc->pool);
2853: }
2854: }
2855:
2856:
2857: static void *
2858: ngx_http_spdy_zalloc(void *opaque, u_int items, u_int size)
2859: {
2860: ngx_http_spdy_connection_t *sc = opaque;
2861:
2862: return ngx_palloc(sc->connection->pool, items * size);
2863: }
2864:
2865:
2866: static void
2867: ngx_http_spdy_zfree(void *opaque, void *address)
2868: {
2869: #if 0
2870: ngx_http_spdy_connection_t *sc = opaque;
2871:
2872: ngx_log_debug1(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0,
2873: "spdy zfree: %p", address);
2874: #endif
2875: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>