Annotation of embedaddon/nginx/src/http/ngx_http_spdy_filter_module.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 <nginx.h>
12: #include <ngx_http_spdy_module.h>
13:
14: #include <zlib.h>
15:
16:
17: #define NGX_SPDY_WRITE_BUFFERED NGX_HTTP_WRITE_BUFFERED
18:
19: #define ngx_http_spdy_nv_nsize(h) (NGX_SPDY_NV_NLEN_SIZE + sizeof(h) - 1)
20: #define ngx_http_spdy_nv_vsize(h) (NGX_SPDY_NV_VLEN_SIZE + sizeof(h) - 1)
21:
22: #define ngx_http_spdy_nv_write_num ngx_spdy_frame_write_uint16
23: #define ngx_http_spdy_nv_write_nlen ngx_spdy_frame_write_uint16
24: #define ngx_http_spdy_nv_write_vlen ngx_spdy_frame_write_uint16
25:
26: #define ngx_http_spdy_nv_write_name(p, h) \
27: ngx_cpymem(ngx_http_spdy_nv_write_nlen(p, sizeof(h) - 1), h, sizeof(h) - 1)
28:
29: #define ngx_http_spdy_nv_write_val(p, h) \
30: ngx_cpymem(ngx_http_spdy_nv_write_vlen(p, sizeof(h) - 1), h, sizeof(h) - 1)
31:
32: static ngx_inline ngx_int_t ngx_http_spdy_filter_send(
33: ngx_connection_t *fc, ngx_http_spdy_stream_t *stream);
34:
35: static ngx_http_spdy_out_frame_t *ngx_http_spdy_filter_get_data_frame(
36: ngx_http_spdy_stream_t *stream, size_t len, ngx_uint_t flags,
37: ngx_chain_t *first, ngx_chain_t *last);
38:
39: static ngx_int_t ngx_http_spdy_syn_frame_handler(
40: ngx_http_spdy_connection_t *sc, ngx_http_spdy_out_frame_t *frame);
41: static ngx_int_t ngx_http_spdy_data_frame_handler(
42: ngx_http_spdy_connection_t *sc, ngx_http_spdy_out_frame_t *frame);
43: static ngx_inline void ngx_http_spdy_handle_frame(
44: ngx_http_spdy_stream_t *stream, ngx_http_spdy_out_frame_t *frame);
45: static ngx_inline void ngx_http_spdy_handle_stream(
46: ngx_http_spdy_connection_t *sc, ngx_http_spdy_stream_t *stream);
47:
48: static void ngx_http_spdy_filter_cleanup(void *data);
49:
50: static ngx_int_t ngx_http_spdy_filter_init(ngx_conf_t *cf);
51:
52:
53: static ngx_http_module_t ngx_http_spdy_filter_module_ctx = {
54: NULL, /* preconfiguration */
55: ngx_http_spdy_filter_init, /* postconfiguration */
56:
57: NULL, /* create main configuration */
58: NULL, /* init main configuration */
59:
60: NULL, /* create server configuration */
61: NULL, /* merge server configuration */
62:
63: NULL, /* create location configuration */
64: NULL /* merge location configuration */
65: };
66:
67:
68: ngx_module_t ngx_http_spdy_filter_module = {
69: NGX_MODULE_V1,
70: &ngx_http_spdy_filter_module_ctx, /* module context */
71: NULL, /* module directives */
72: NGX_HTTP_MODULE, /* module type */
73: NULL, /* init master */
74: NULL, /* init module */
75: NULL, /* init process */
76: NULL, /* init thread */
77: NULL, /* exit thread */
78: NULL, /* exit process */
79: NULL, /* exit master */
80: NGX_MODULE_V1_PADDING
81: };
82:
83:
84: static ngx_http_output_header_filter_pt ngx_http_next_header_filter;
85: static ngx_http_output_body_filter_pt ngx_http_next_body_filter;
86:
87:
88: static ngx_int_t
89: ngx_http_spdy_header_filter(ngx_http_request_t *r)
90: {
91: int rc;
92: size_t len;
93: u_char *p, *buf, *last;
94: ngx_buf_t *b;
95: ngx_str_t host;
96: ngx_uint_t i, j, count, port;
97: ngx_chain_t *cl;
98: ngx_list_part_t *part, *pt;
99: ngx_table_elt_t *header, *h;
100: ngx_connection_t *c;
101: ngx_http_cleanup_t *cln;
102: ngx_http_core_loc_conf_t *clcf;
103: ngx_http_core_srv_conf_t *cscf;
104: ngx_http_spdy_stream_t *stream;
105: ngx_http_spdy_out_frame_t *frame;
106: ngx_http_spdy_connection_t *sc;
107: struct sockaddr_in *sin;
108: #if (NGX_HAVE_INET6)
109: struct sockaddr_in6 *sin6;
110: #endif
111: u_char addr[NGX_SOCKADDR_STRLEN];
112:
113: if (!r->spdy_stream) {
114: return ngx_http_next_header_filter(r);
115: }
116:
117: ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
118: "spdy header filter");
119:
120: if (r->header_sent) {
121: return NGX_OK;
122: }
123:
124: r->header_sent = 1;
125:
126: if (r != r->main) {
127: return NGX_OK;
128: }
129:
130: c = r->connection;
131:
132: if (r->method == NGX_HTTP_HEAD) {
133: r->header_only = 1;
134: }
135:
136: switch (r->headers_out.status) {
137:
138: case NGX_HTTP_OK:
139: case NGX_HTTP_PARTIAL_CONTENT:
140: break;
141:
142: case NGX_HTTP_NOT_MODIFIED:
143: r->header_only = 1;
144: break;
145:
146: case NGX_HTTP_NO_CONTENT:
147: r->header_only = 1;
148:
149: ngx_str_null(&r->headers_out.content_type);
150:
151: r->headers_out.content_length = NULL;
152: r->headers_out.content_length_n = -1;
153:
154: /* fall through */
155:
156: default:
157: r->headers_out.last_modified_time = -1;
158: r->headers_out.last_modified = NULL;
159: }
160:
161: len = NGX_SPDY_NV_NUM_SIZE
162: + ngx_http_spdy_nv_nsize("version")
163: + ngx_http_spdy_nv_vsize("HTTP/1.1")
164: + ngx_http_spdy_nv_nsize("status")
165: + ngx_http_spdy_nv_vsize("418");
166:
167: clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
168:
169: if (r->headers_out.server == NULL) {
170: len += ngx_http_spdy_nv_nsize("server");
171: len += clcf->server_tokens ? ngx_http_spdy_nv_vsize(NGINX_VER)
172: : ngx_http_spdy_nv_vsize("nginx");
173: }
174:
175: if (r->headers_out.date == NULL) {
176: len += ngx_http_spdy_nv_nsize("date")
177: + ngx_http_spdy_nv_vsize("Wed, 31 Dec 1986 10:00:00 GMT");
178: }
179:
180: if (r->headers_out.content_type.len) {
181: len += ngx_http_spdy_nv_nsize("content-type")
182: + NGX_SPDY_NV_VLEN_SIZE + r->headers_out.content_type.len;
183:
184: if (r->headers_out.content_type_len == r->headers_out.content_type.len
185: && r->headers_out.charset.len)
186: {
187: len += sizeof("; charset=") - 1 + r->headers_out.charset.len;
188: }
189: }
190:
191: if (r->headers_out.content_length == NULL
192: && r->headers_out.content_length_n >= 0)
193: {
194: len += ngx_http_spdy_nv_nsize("content-length")
195: + NGX_SPDY_NV_VLEN_SIZE + NGX_OFF_T_LEN;
196: }
197:
198: if (r->headers_out.last_modified == NULL
199: && r->headers_out.last_modified_time != -1)
200: {
201: len += ngx_http_spdy_nv_nsize("last-modified")
202: + ngx_http_spdy_nv_vsize("Wed, 31 Dec 1986 10:00:00 GMT");
203: }
204:
205: if (r->headers_out.location
206: && r->headers_out.location->value.len
207: && r->headers_out.location->value.data[0] == '/')
208: {
209: r->headers_out.location->hash = 0;
210:
211: if (clcf->server_name_in_redirect) {
212: cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module);
213: host = cscf->server_name;
214:
215: } else if (r->headers_in.server.len) {
216: host = r->headers_in.server;
217:
218: } else {
219: host.len = NGX_SOCKADDR_STRLEN;
220: host.data = addr;
221:
222: if (ngx_connection_local_sockaddr(c, &host, 0) != NGX_OK) {
223: return NGX_ERROR;
224: }
225: }
226:
227: switch (c->local_sockaddr->sa_family) {
228:
229: #if (NGX_HAVE_INET6)
230: case AF_INET6:
231: sin6 = (struct sockaddr_in6 *) c->local_sockaddr;
232: port = ntohs(sin6->sin6_port);
233: break;
234: #endif
235: #if (NGX_HAVE_UNIX_DOMAIN)
236: case AF_UNIX:
237: port = 0;
238: break;
239: #endif
240: default: /* AF_INET */
241: sin = (struct sockaddr_in *) c->local_sockaddr;
242: port = ntohs(sin->sin_port);
243: break;
244: }
245:
246: len += ngx_http_spdy_nv_nsize("location")
247: + ngx_http_spdy_nv_vsize("https://")
248: + host.len
249: + r->headers_out.location->value.len;
250:
251: if (clcf->port_in_redirect) {
252:
253: #if (NGX_HTTP_SSL)
254: if (c->ssl)
255: port = (port == 443) ? 0 : port;
256: else
257: #endif
258: port = (port == 80) ? 0 : port;
259:
260: } else {
261: port = 0;
262: }
263:
264: if (port) {
265: len += sizeof(":65535") - 1;
266: }
267:
268: } else {
269: ngx_str_null(&host);
270: port = 0;
271: }
272:
273: part = &r->headers_out.headers.part;
274: header = part->elts;
275:
276: for (i = 0; /* void */; i++) {
277:
278: if (i >= part->nelts) {
279: if (part->next == NULL) {
280: break;
281: }
282:
283: part = part->next;
284: header = part->elts;
285: i = 0;
286: }
287:
288: if (header[i].hash == 0) {
289: continue;
290: }
291:
292: len += NGX_SPDY_NV_NLEN_SIZE + header[i].key.len
293: + NGX_SPDY_NV_VLEN_SIZE + header[i].value.len;
294: }
295:
296: buf = ngx_alloc(len, r->pool->log);
297: if (buf == NULL) {
298: return NGX_ERROR;
299: }
300:
301: last = buf + NGX_SPDY_NV_NUM_SIZE;
302:
303: last = ngx_http_spdy_nv_write_name(last, "version");
304: last = ngx_http_spdy_nv_write_val(last, "HTTP/1.1");
305:
306: last = ngx_http_spdy_nv_write_name(last, "status");
307: last = ngx_spdy_frame_write_uint16(last, 3);
308: last = ngx_sprintf(last, "%03ui", r->headers_out.status);
309:
310: count = 2;
311:
312: if (r->headers_out.server == NULL) {
313: last = ngx_http_spdy_nv_write_name(last, "server");
314: last = clcf->server_tokens
315: ? ngx_http_spdy_nv_write_val(last, NGINX_VER)
316: : ngx_http_spdy_nv_write_val(last, "nginx");
317:
318: count++;
319: }
320:
321: if (r->headers_out.date == NULL) {
322: last = ngx_http_spdy_nv_write_name(last, "date");
323:
324: last = ngx_http_spdy_nv_write_vlen(last, ngx_cached_http_time.len);
325:
326: last = ngx_cpymem(last, ngx_cached_http_time.data,
327: ngx_cached_http_time.len);
328:
329: count++;
330: }
331:
332: if (r->headers_out.content_type.len) {
333:
334: last = ngx_http_spdy_nv_write_name(last, "content-type");
335:
336: p = last + NGX_SPDY_NV_VLEN_SIZE;
337:
338: last = ngx_cpymem(p, r->headers_out.content_type.data,
339: r->headers_out.content_type.len);
340:
341: if (r->headers_out.content_type_len == r->headers_out.content_type.len
342: && r->headers_out.charset.len)
343: {
344: last = ngx_cpymem(last, "; charset=", sizeof("; charset=") - 1);
345:
346: last = ngx_cpymem(last, r->headers_out.charset.data,
347: r->headers_out.charset.len);
348:
349: /* update r->headers_out.content_type for possible logging */
350:
351: r->headers_out.content_type.len = last - p;
352: r->headers_out.content_type.data = p;
353: }
354:
355: (void) ngx_http_spdy_nv_write_vlen(p - NGX_SPDY_NV_VLEN_SIZE,
356: r->headers_out.content_type.len);
357:
358: count++;
359: }
360:
361: if (r->headers_out.content_length == NULL
362: && r->headers_out.content_length_n >= 0)
363: {
364: last = ngx_http_spdy_nv_write_name(last, "content-length");
365:
366: p = last + NGX_SPDY_NV_VLEN_SIZE;
367:
368: last = ngx_sprintf(p, "%O", r->headers_out.content_length_n);
369:
370: (void) ngx_http_spdy_nv_write_vlen(p - NGX_SPDY_NV_VLEN_SIZE,
371: last - p);
372:
373: count++;
374: }
375:
376: if (r->headers_out.last_modified == NULL
377: && r->headers_out.last_modified_time != -1)
378: {
379: last = ngx_http_spdy_nv_write_name(last, "last-modified");
380:
381: p = last + NGX_SPDY_NV_VLEN_SIZE;
382:
383: last = ngx_http_time(p, r->headers_out.last_modified_time);
384:
385: (void) ngx_http_spdy_nv_write_vlen(p - NGX_SPDY_NV_VLEN_SIZE,
386: last - p);
387:
388: count++;
389: }
390:
391: if (host.data) {
392:
393: last = ngx_http_spdy_nv_write_name(last, "location");
394:
395: p = last + NGX_SPDY_NV_VLEN_SIZE;
396:
397: last = ngx_cpymem(p, "http", sizeof("http") - 1);
398:
399: #if (NGX_HTTP_SSL)
400: if (c->ssl) {
401: *last++ ='s';
402: }
403: #endif
404:
405: *last++ = ':'; *last++ = '/'; *last++ = '/';
406:
407: last = ngx_cpymem(last, host.data, host.len);
408:
409: if (port) {
410: last = ngx_sprintf(last, ":%ui", port);
411: }
412:
413: last = ngx_cpymem(last, r->headers_out.location->value.data,
414: r->headers_out.location->value.len);
415:
416: /* update r->headers_out.location->value for possible logging */
417:
418: r->headers_out.location->value.len = last - p;
419: r->headers_out.location->value.data = p;
420: ngx_str_set(&r->headers_out.location->key, "location");
421:
422: (void) ngx_http_spdy_nv_write_vlen(p - NGX_SPDY_NV_VLEN_SIZE,
423: r->headers_out.location->value.len);
424:
425: count++;
426: }
427:
428: part = &r->headers_out.headers.part;
429: header = part->elts;
430:
431: for (i = 0; /* void */; i++) {
432:
433: if (i >= part->nelts) {
434: if (part->next == NULL) {
435: break;
436: }
437:
438: part = part->next;
439: header = part->elts;
440: i = 0;
441: }
442:
443: if (header[i].hash == 0 || header[i].hash == 2) {
444: continue;
445: }
446:
447: if ((header[i].key.len == 6
448: && ngx_strncasecmp(header[i].key.data,
449: (u_char *) "status", 6) == 0)
450: || (header[i].key.len == 7
451: && ngx_strncasecmp(header[i].key.data,
452: (u_char *) "version", 7) == 0))
453: {
454: header[i].hash = 0;
455: continue;
456: }
457:
458: last = ngx_http_spdy_nv_write_nlen(last, header[i].key.len);
459:
460: ngx_strlow(last, header[i].key.data, header[i].key.len);
461: last += header[i].key.len;
462:
463: p = last + NGX_SPDY_NV_VLEN_SIZE;
464:
465: last = ngx_cpymem(p, header[i].value.data, header[i].value.len);
466:
467: pt = part;
468: h = header;
469:
470: for (j = i + 1; /* void */; j++) {
471:
472: if (j >= pt->nelts) {
473: if (pt->next == NULL) {
474: break;
475: }
476:
477: pt = pt->next;
478: h = pt->elts;
479: j = 0;
480: }
481:
482: if (h[j].hash == 0 || h[j].hash == 2
483: || h[j].key.len != header[i].key.len
484: || ngx_strncasecmp(header[i].key.data, h[j].key.data,
485: header[i].key.len))
486: {
487: continue;
488: }
489:
490: *last++ = '\0';
491:
492: last = ngx_cpymem(last, h[j].value.data, h[j].value.len);
493:
494: h[j].hash = 2;
495: }
496:
497: (void) ngx_http_spdy_nv_write_vlen(p - NGX_SPDY_NV_VLEN_SIZE,
498: last - p);
499:
500: count++;
501: }
502:
503: (void) ngx_spdy_frame_write_uint16(buf, count);
504:
505: stream = r->spdy_stream;
506: sc = stream->connection;
507:
508: len = last - buf;
509:
510: b = ngx_create_temp_buf(r->pool, NGX_SPDY_FRAME_HEADER_SIZE
511: + NGX_SPDY_SYN_REPLY_SIZE
512: + deflateBound(&sc->zstream_out, len));
513: if (b == NULL) {
514: ngx_free(buf);
515: return NGX_ERROR;
516: }
517:
518: b->last += NGX_SPDY_FRAME_HEADER_SIZE + NGX_SPDY_SYN_REPLY_SIZE;
519:
520: sc->zstream_out.next_in = buf;
521: sc->zstream_out.avail_in = len;
522: sc->zstream_out.next_out = b->last;
523: sc->zstream_out.avail_out = b->end - b->last;
524:
525: rc = deflate(&sc->zstream_out, Z_SYNC_FLUSH);
526:
527: ngx_free(buf);
528:
529: if (rc != Z_OK) {
530: ngx_log_error(NGX_LOG_ALERT, c->log, 0,
531: "spdy deflate() failed: %d", rc);
532: return NGX_ERROR;
533: }
534:
535: ngx_log_debug5(NGX_LOG_DEBUG_HTTP, c->log, 0,
536: "spdy deflate out: ni:%p no:%p ai:%ud ao:%ud rc:%d",
537: sc->zstream_out.next_in, sc->zstream_out.next_out,
538: sc->zstream_out.avail_in, sc->zstream_out.avail_out,
539: rc);
540:
541: b->last = sc->zstream_out.next_out;
542:
543: p = b->pos;
544: p = ngx_spdy_frame_write_head(p, NGX_SPDY_SYN_REPLY);
545:
546: len = b->last - b->pos;
547:
548: r->header_size = len;
549:
550: if (r->header_only) {
551: b->last_buf = 1;
552: p = ngx_spdy_frame_write_flags_and_len(p, NGX_SPDY_FLAG_FIN,
553: len - NGX_SPDY_FRAME_HEADER_SIZE);
554: } else {
555: p = ngx_spdy_frame_write_flags_and_len(p, 0,
556: len - NGX_SPDY_FRAME_HEADER_SIZE);
557: }
558:
559: (void) ngx_spdy_frame_write_sid(p, stream->id);
560:
561: cl = ngx_alloc_chain_link(r->pool);
562: if (cl == NULL) {
563: return NGX_ERROR;
564: }
565:
566: cl->buf = b;
567: cl->next = NULL;
568:
569: frame = ngx_palloc(r->pool, sizeof(ngx_http_spdy_out_frame_t));
570: if (frame == NULL) {
571: return NGX_ERROR;
572: }
573:
574: frame->first = cl;
575: frame->last = cl;
576: frame->handler = ngx_http_spdy_syn_frame_handler;
577: frame->free = NULL;
578: frame->stream = stream;
579: frame->size = len;
580: frame->priority = stream->priority;
581: frame->blocked = 1;
582: frame->fin = r->header_only;
583:
584: ngx_log_debug3(NGX_LOG_DEBUG_HTTP, stream->request->connection->log, 0,
585: "spdy:%ui create SYN_REPLY frame %p: size:%uz",
586: stream->id, frame, frame->size);
587:
588: ngx_http_spdy_queue_blocked_frame(sc, frame);
589:
590: r->blocked++;
591:
592: cln = ngx_http_cleanup_add(r, 0);
593: if (cln == NULL) {
594: return NGX_ERROR;
595: }
596:
597: cln->handler = ngx_http_spdy_filter_cleanup;
598: cln->data = stream;
599:
600: stream->waiting = 1;
601:
602: return ngx_http_spdy_filter_send(c, stream);
603: }
604:
605:
606: static ngx_int_t
607: ngx_http_spdy_body_filter(ngx_http_request_t *r, ngx_chain_t *in)
608: {
609: off_t size;
610: ngx_buf_t *b;
611: ngx_chain_t *cl, *ll, *out, **ln;
612: ngx_http_spdy_stream_t *stream;
613: ngx_http_spdy_out_frame_t *frame;
614:
615: stream = r->spdy_stream;
616:
617: if (stream == NULL) {
618: return ngx_http_next_body_filter(r, in);
619: }
620:
621: ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
622: "spdy body filter \"%V?%V\"", &r->uri, &r->args);
623:
624: if (in == NULL || r->header_only) {
625:
626: if (stream->waiting) {
627: return NGX_AGAIN;
628: }
629:
630: r->connection->buffered &= ~NGX_SPDY_WRITE_BUFFERED;
631:
632: return NGX_OK;
633: }
634:
635: size = 0;
636: ln = &out;
637: ll = in;
638:
639: for ( ;; ) {
640: b = ll->buf;
641: #if 1
642: if (ngx_buf_size(b) == 0 && !ngx_buf_special(b)) {
643: ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
644: "zero size buf in spdy body filter "
645: "t:%d r:%d f:%d %p %p-%p %p %O-%O",
646: b->temporary,
647: b->recycled,
648: b->in_file,
649: b->start,
650: b->pos,
651: b->last,
652: b->file,
653: b->file_pos,
654: b->file_last);
655:
656: ngx_debug_point();
657: return NGX_ERROR;
658: }
659: #endif
660: cl = ngx_alloc_chain_link(r->pool);
661: if (cl == NULL) {
662: return NGX_ERROR;
663: }
664:
665: size += ngx_buf_size(b);
666: cl->buf = b;
667:
668: *ln = cl;
669: ln = &cl->next;
670:
671: if (ll->next == NULL) {
672: break;
673: }
674:
675: ll = ll->next;
676: }
677:
678: if (size > NGX_SPDY_MAX_FRAME_SIZE) {
679: ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
680: "FIXME: chain too big in spdy filter: %O", size);
681: return NGX_ERROR;
682: }
683:
684: frame = ngx_http_spdy_filter_get_data_frame(stream, (size_t) size,
685: b->last_buf, out, cl);
686: if (frame == NULL) {
687: return NGX_ERROR;
688: }
689:
690: ngx_http_spdy_queue_frame(stream->connection, frame);
691:
692: stream->waiting++;
693:
694: r->main->blocked++;
695:
696: return ngx_http_spdy_filter_send(r->connection, stream);
697: }
698:
699:
700: static ngx_http_spdy_out_frame_t *
701: ngx_http_spdy_filter_get_data_frame(ngx_http_spdy_stream_t *stream,
702: size_t len, ngx_uint_t fin, ngx_chain_t *first, ngx_chain_t *last)
703: {
704: u_char *p;
705: ngx_buf_t *buf;
706: ngx_uint_t flags;
707: ngx_chain_t *cl;
708: ngx_http_spdy_out_frame_t *frame;
709:
710:
711: frame = stream->free_frames;
712:
713: if (frame) {
714: stream->free_frames = frame->free;
715:
716: } else {
717: frame = ngx_palloc(stream->request->pool,
718: sizeof(ngx_http_spdy_out_frame_t));
719: if (frame == NULL) {
720: return NULL;
721: }
722: }
723:
724: ngx_log_debug4(NGX_LOG_DEBUG_HTTP, stream->request->connection->log, 0,
725: "spdy:%ui create DATA frame %p: len:%uz fin:%ui",
726: stream->id, frame, len, fin);
727:
728: if (len || fin) {
729:
730: flags = fin ? NGX_SPDY_FLAG_FIN : 0;
731:
732: cl = ngx_chain_get_free_buf(stream->request->pool,
733: &stream->free_data_headers);
734: if (cl == NULL) {
735: return NULL;
736: }
737:
738: buf = cl->buf;
739:
740: if (buf->start) {
741: p = buf->start;
742: buf->pos = p;
743:
744: p += sizeof(uint32_t);
745:
746: (void) ngx_spdy_frame_write_flags_and_len(p, flags, len);
747:
748: } else {
749: p = ngx_palloc(stream->request->pool, NGX_SPDY_FRAME_HEADER_SIZE);
750: if (p == NULL) {
751: return NULL;
752: }
753:
754: buf->pos = p;
755: buf->start = p;
756:
757: p = ngx_spdy_frame_write_sid(p, stream->id);
758: p = ngx_spdy_frame_write_flags_and_len(p, flags, len);
759:
760: buf->last = p;
761: buf->end = p;
762:
763: buf->tag = (ngx_buf_tag_t) &ngx_http_spdy_filter_module;
764: buf->memory = 1;
765: }
766:
767: cl->next = first;
768: first = cl;
769: }
770:
771: frame->first = first;
772: frame->last = last;
773: frame->handler = ngx_http_spdy_data_frame_handler;
774: frame->free = NULL;
775: frame->stream = stream;
776: frame->size = NGX_SPDY_FRAME_HEADER_SIZE + len;
777: frame->priority = stream->priority;
778: frame->blocked = 0;
779: frame->fin = fin;
780:
781: return frame;
782: }
783:
784:
785: static ngx_inline ngx_int_t
786: ngx_http_spdy_filter_send(ngx_connection_t *fc, ngx_http_spdy_stream_t *stream)
787: {
788: if (ngx_http_spdy_send_output_queue(stream->connection) == NGX_ERROR) {
789: fc->error = 1;
790: return NGX_ERROR;
791: }
792:
793: if (stream->waiting) {
794: fc->buffered |= NGX_SPDY_WRITE_BUFFERED;
795: fc->write->delayed = 1;
796: return NGX_AGAIN;
797: }
798:
799: fc->buffered &= ~NGX_SPDY_WRITE_BUFFERED;
800:
801: return NGX_OK;
802: }
803:
804:
805: static ngx_int_t
806: ngx_http_spdy_syn_frame_handler(ngx_http_spdy_connection_t *sc,
807: ngx_http_spdy_out_frame_t *frame)
808: {
809: ngx_buf_t *buf;
810: ngx_http_spdy_stream_t *stream;
811:
812: buf = frame->first->buf;
813:
814: if (buf->pos != buf->last) {
815: return NGX_AGAIN;
816: }
817:
818: stream = frame->stream;
819:
820: ngx_log_debug2(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0,
821: "spdy:%ui SYN_REPLY frame %p was sent", stream->id, frame);
822:
823: ngx_free_chain(stream->request->pool, frame->first);
824:
825: ngx_http_spdy_handle_frame(stream, frame);
826:
827: ngx_http_spdy_handle_stream(sc, stream);
828:
829: return NGX_OK;
830: }
831:
832:
833: static ngx_int_t
834: ngx_http_spdy_data_frame_handler(ngx_http_spdy_connection_t *sc,
835: ngx_http_spdy_out_frame_t *frame)
836: {
837: ngx_chain_t *cl, *ln;
838: ngx_http_spdy_stream_t *stream;
839:
840: stream = frame->stream;
841:
842: cl = frame->first;
843:
844: if (cl->buf->tag == (ngx_buf_tag_t) &ngx_http_spdy_filter_module) {
845:
846: if (cl->buf->pos != cl->buf->last) {
847: ngx_log_debug2(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0,
848: "spdy:%ui DATA frame %p was sent partially",
849: stream->id, frame);
850:
851: return NGX_AGAIN;
852: }
853:
854: ln = cl->next;
855:
856: cl->next = stream->free_data_headers;
857: stream->free_data_headers = cl;
858:
859: if (cl == frame->last) {
860: goto done;
861: }
862:
863: cl = ln;
864: }
865:
866: for ( ;; ) {
867: if (ngx_buf_size(cl->buf) != 0) {
868:
869: if (cl != frame->first) {
870: frame->first = cl;
871: ngx_http_spdy_handle_stream(sc, stream);
872: }
873:
874: ngx_log_debug2(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0,
875: "spdy:%ui DATA frame %p was sent partially",
876: stream->id, frame);
877:
878: return NGX_AGAIN;
879: }
880:
881: ln = cl->next;
882:
883: ngx_free_chain(stream->request->pool, cl);
884:
885: if (cl == frame->last) {
886: goto done;
887: }
888:
889: cl = ln;
890: }
891:
892: done:
893:
894: ngx_log_debug2(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0,
895: "spdy:%ui DATA frame %p was sent", stream->id, frame);
896:
897: stream->request->header_size += NGX_SPDY_FRAME_HEADER_SIZE;
898:
899: ngx_http_spdy_handle_frame(stream, frame);
900:
901: ngx_http_spdy_handle_stream(sc, stream);
902:
903: return NGX_OK;
904: }
905:
906:
907: static ngx_inline void
908: ngx_http_spdy_handle_frame(ngx_http_spdy_stream_t *stream,
909: ngx_http_spdy_out_frame_t *frame)
910: {
911: ngx_http_request_t *r;
912:
913: r = stream->request;
914:
915: r->connection->sent += frame->size;
916: r->blocked--;
917:
918: if (frame->fin) {
919: stream->out_closed = 1;
920: }
921:
922: frame->free = stream->free_frames;
923: stream->free_frames = frame;
924:
925: stream->waiting--;
926: }
927:
928:
929: static ngx_inline void
930: ngx_http_spdy_handle_stream(ngx_http_spdy_connection_t *sc,
931: ngx_http_spdy_stream_t *stream)
932: {
933: ngx_connection_t *fc;
934:
935: fc = stream->request->connection;
936:
937: fc->write->delayed = 0;
938:
939: if (stream->handled) {
940: return;
941: }
942:
943: if (sc->blocked == 2) {
944: stream->handled = 1;
945:
946: stream->next = sc->last_stream;
947: sc->last_stream = stream;
948: }
949: }
950:
951:
952: static void
953: ngx_http_spdy_filter_cleanup(void *data)
954: {
955: ngx_http_spdy_stream_t *stream = data;
956:
957: ngx_http_request_t *r;
958: ngx_http_spdy_out_frame_t *frame, **fn;
959:
960: if (stream->waiting == 0) {
961: return;
962: }
963:
964: r = stream->request;
965:
966: fn = &stream->connection->last_out;
967:
968: for ( ;; ) {
969: frame = *fn;
970:
971: if (frame == NULL) {
972: break;
973: }
974:
975: if (frame->stream == stream && !frame->blocked) {
976:
977: stream->waiting--;
978: r->blocked--;
979:
980: *fn = frame->next;
981: continue;
982: }
983:
984: fn = &frame->next;
985: }
986: }
987:
988:
989: static ngx_int_t
990: ngx_http_spdy_filter_init(ngx_conf_t *cf)
991: {
992: ngx_http_next_header_filter = ngx_http_top_header_filter;
993: ngx_http_top_header_filter = ngx_http_spdy_header_filter;
994:
995: ngx_http_next_body_filter = ngx_http_top_body_filter;
996: ngx_http_top_body_filter = ngx_http_spdy_body_filter;
997:
998: return NGX_OK;
999: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>