Groonga 3.0.9 Source Code Document
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
ngx_http_spdy.c
Go to the documentation of this file.
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 {
74  u_char len;
75  u_char header[7];
76  ngx_int_t (*handler)(ngx_http_request_t *r);
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(
114 static u_char *ngx_http_spdy_state_internal_error(
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(
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(
126 
127 static ngx_http_spdy_stream_t *ngx_http_spdy_create_stream(
129 static ngx_http_spdy_stream_t *ngx_http_spdy_get_stream_by_id(
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
200 {
201  int rc;
202  ngx_connection_t *c;
203  ngx_pool_cleanup_t *cln;
208 
209  c = rev->data;
210  hc = c->data;
211 
213  "init spdy request");
214 
215  c->log->action = "processing SPDY";
216 
218 
219  if (smcf->recv_buffer == NULL) {
221  if (smcf->recv_buffer == NULL) {
223  return;
224  }
225  }
226 
227  sc = ngx_pcalloc(c->pool, sizeof(ngx_http_spdy_connection_t));
228  if (sc == NULL) {
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) {
245  "inflateInit() failed: %d", rc);
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 
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) {
261  "deflateInit2() failed: %d", rc);
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) {
270  "deflateSetDictionary() failed: %d", rc);
272  return;
273  }
274 
275  sc->pool = ngx_create_pool(sscf->pool_size, sc->connection->log);
276  if (sc->pool == NULL) {
278  return;
279  }
280 
282  if (cln == NULL) {
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,
292  * sizeof(ngx_http_spdy_stream_t *));
293  if (sc->streams_index == NULL) {
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;
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 
332 
333  available = smcf->recv_buffer_size - 2 * NGX_SPDY_STATE_BUFFER_SIZE;
334 
335  do {
336  p = smcf->recv_buffer;
337 
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)) {
349  "client closed prematurely connection");
350  }
351 
352  if (n == 0 || n == NGX_ERROR) {
353  ngx_http_spdy_finalize_connection(sc,
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;
399 
400  c = wev->data;
401  sc = c->data;
402 
403  if (wev->timedout) {
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 
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 
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
456 {
457  ngx_chain_t *cl;
458  ngx_event_t *wev;
459  ngx_connection_t *c;
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 
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) {
499  }
500 
501  return NGX_ERROR;
502  }
503 
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;
524  break;
525  }
526 
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;
552 
553  if (sc->last_out || sc->processing) {
554  return;
555  }
556 
557  c = sc->connection;
558 
559  if (c->error) {
561  return;
562  }
563 
564  if (c->buffered) {
565  return;
566  }
567 
570  if (sc->waiting) {
571  ngx_add_timer(c->read, sscf->recv_timeout);
572  return;
573  }
574 
575  if (ngx_terminate || ngx_exiting) {
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) {
589  }
590 #endif
591 
592  c->destroyed = 1;
593  c->idle = 1;
595 
597  c->read->handler = ngx_http_spdy_keepalive_handler;
598 
599  if (c->write->timer_set) {
600  ngx_del_timer(c->write);
601  }
602 
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 
626  "spdy SETTINGS frame received, size: %uz", sc->length);
627 
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 
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 */
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;
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 
730 
731  sid = ngx_spdy_frame_parse_sid(pos);
732  prio = pos[8] >> 6;
733 
735 
737  "spdy SYN_STREAM frame sid:%ui prio:%ui", sid, prio);
738 
741 
742  if (sc->processing >= sscf->concurrent_streams) {
743 
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
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;
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 
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) {
821  "spdy inflateSetDictionary() failed: %d", z);
823  return ngx_http_spdy_state_protocol_error(sc);
824  }
825 
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) {
835  "spdy inflate() failed: %d", z);
837  return ngx_http_spdy_state_protocol_error(sc);
838  }
839 
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 
859 
860  buf->pos += NGX_SPDY_NV_NUM_SIZE;
861 
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  {
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  {
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 */
906  return ngx_http_spdy_state_headers_error(sc, pos, end);
907  }
908 
909  if (rc != NGX_OK) {
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) {
924  "spdy inflate() failed: %d", z);
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 */
940  "spdy again while last chunk");
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 
949 
950  /* TODO: improve error message */
952  "client sent invalid header line");
953 
955 
956  return ngx_http_spdy_state_headers_error(sc, pos, end);
957 
958  default: /* NGX_HTTP_PARSE_INVALID_HEADER */
959 
961  "client sent invalid HEADERS spdy frame");
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) {
973  "client sent invalid HEADERS spdy frame");
975  return ngx_http_spdy_state_protocol_error(sc);
976  }
977 
978  if (rc == NGX_HTTP_PARSE_INVALID_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 */
989  "end %ui %p %p", complete, buf->pos, buf->last);
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;
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;
1042 
1043  n = inflate(&sc->zstream_in, Z_NO_FLUSH);
1044 
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;
1080 
1081  stream = sc->stream;
1082 
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 {
1141 
1142  if (clcf->client_max_body_size
1143  && clcf->client_max_body_size < rb->rest)
1144  {
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)
1221 
1222  } else {
1224  }
1225 
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 
1262  "spdy RST_STREAM sid:%ui st:%ui", sid, status);
1263 
1264 
1265  switch (status) {
1266 
1268  /* TODO logging */
1269  return ngx_http_spdy_state_protocol_error(sc);
1270 
1272  /* TODO */
1273  break;
1274 
1276  /* TODO */
1277  break;
1278 
1280  /* TODO logging */
1281  return ngx_http_spdy_state_protocol_error(sc);
1282 
1283  case NGX_SPDY_CANCEL:
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 
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;
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 
1336  "spdy PING frame");
1337 
1338  frame = ngx_http_spdy_get_ctl_frame(sc, NGX_SPDY_PING_SIZE,
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 
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;
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 
1396 
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 
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) {
1421  continue;
1422  }
1423 
1425 
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) {
1471  "spdy state buffer overflow: "
1472  "%i bytes required", end - pos);
1473  return ngx_http_spdy_state_internal_error(sc);
1474  }
1475 #endif
1476 
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 {
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 {
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;
1518 
1519  if (sc->connection->error) {
1520  return NGX_OK;
1521  }
1522 
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 
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;
1557 
1559  "spdy create GOAWAY sid:%ui", sc->last_sid);
1560 
1561  frame = ngx_http_spdy_get_ctl_frame(sc, NGX_SPDY_GOAWAY_SIZE,
1563  if (frame == NULL) {
1564  return NGX_ERROR;
1565  }
1566 
1567  buf = frame->first->buf;
1568 
1569  p = buf->pos;
1570 
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;
1594 
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 
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;
1630 #endif
1632  frame->blocked = 0;
1633 
1634  p = buf->pos;
1635 
1639  + NGX_SPDY_SETTINGS_PAIR_SIZE);
1640 
1645 
1648 
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,
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 
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;
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,
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)
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,
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;
1764  ngx_http_request_t *r;
1765  ngx_http_spdy_stream_t *stream;
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;
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;
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 
1846 
1849  if (r->header_in == NULL) {
1851  return NULL;
1852  }
1853 
1855 
1856  stream = ngx_pcalloc(r->pool, sizeof(ngx_http_spdy_stream_t));
1857  if (stream == NULL) {
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 
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;
1888 
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;
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) {
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 
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 ':':
1981  }
1982 
1983  if (ch >= 'A' && ch <= 'Z') {
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) {
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;
2068 
2070  "spdy alloc large header buffer");
2071 
2072  stream = r->spdy_stream;
2073 
2075 
2076  if (stream->header_buffers
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 
2089  if (buf == NULL) {
2090  return NGX_ERROR;
2091  }
2092 
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;
2126 
2127  if (r->invalid_header) {
2129 
2130  if (cscf->ignore_invalid_headers) {
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
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,
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
2180 {
2181  ngx_uint_t i;
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) {
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 != '_') {
2263  "client sent invalid method");
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) {
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) {
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) {
2301  }
2302 
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) {
2318  }
2319 
2320  p = r->header_start;
2321 
2322  if (r->header_size < 8 || !(ngx_str5cmp(p, 'H', 'T', 'T', 'P', '/'))) {
2324  }
2325 
2326  ch = *(p + 5);
2327 
2328  if (ch < '1' || ch > '9') {
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') {
2340  }
2341 
2342  r->http_major = r->http_major * 10 + ch - '0';
2343  }
2344 
2345  if (*p != '.') {
2347  }
2348 
2349  ch = *(p + 1);
2350 
2351  if (ch < '0' || ch > '9') {
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') {
2363  }
2364 
2365  r->http_minor = r->http_minor * 10 + ch - '0';
2366  }
2367 
2368  r->http_protocol.len = r->header_size;
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  {
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) {
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 
2410 
2411  /* some modules expect the space character after method name */
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;
2426 
2427  if (ngx_http_spdy_construct_request_line(r) != NGX_OK) {
2428  return;
2429  }
2430 
2432  "spdy http request line: \"%V\"", &r->request_line);
2433 
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 
2459  "http header: \"%V: %V\"", &h[i].key, &h[i].value);
2460  }
2461 
2463 
2465  return;
2466  }
2467 
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;
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 
2494 
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";
2512 
2514  tf->access = 0660;
2515  }
2516 
2517  rb->temp_file = tf;
2518 
2519  if (r->spdy_stream->in_closed
2520  && ngx_create_temp_file(&tf->file, tf->path, tf->pool,
2521  tf->persistent, tf->clean, tf->access)
2522  != NGX_OK)
2523  {
2524  return NGX_ERROR;
2525  }
2526 
2527  buf = ngx_calloc_buf(r->pool);
2528  if (buf == NULL) {
2529  return NGX_ERROR;
2530  }
2531 
2532  if (rb->rest == 0) {
2533  buf->in_file = 1;
2534  buf->file = &tf->file;
2535  } else {
2536  rb->buf = buf;
2537  }
2538 
2539  } else {
2540 
2541  if (rb->rest == 0) {
2542  return NGX_OK;
2543  }
2544 
2545  buf = ngx_create_temp_buf(r->pool, (size_t) rb->rest);
2546  if (buf == NULL) {
2547  return NGX_ERROR;
2548  }
2549 
2550  rb->buf = buf;
2551  }
2552 
2553  rb->bufs = ngx_alloc_chain_link(r->pool);
2554  if (rb->bufs == NULL) {
2555  return NGX_ERROR;
2556  }
2557 
2558  rb->bufs->buf = buf;
2559  rb->bufs->next = NULL;
2560 
2561  rb->rest = 0;
2562 
2563  return NGX_OK;
2564 }
2565 
2566 
2567 ngx_int_t
2569  ngx_http_client_body_handler_pt post_handler)
2570 {
2571  ngx_http_spdy_stream_t *stream;
2572 
2574  "spdy read request body");
2575 
2576  stream = r->spdy_stream;
2577 
2578  switch (stream->skip_data) {
2579 
2580  case NGX_SPDY_DATA_DISCARD:
2581  post_handler(r);
2582  return NGX_OK;
2583 
2584  case NGX_SPDY_DATA_ERROR:
2585  if (r->headers_in.content_length_n == -1) {
2587  } else {
2588  return NGX_HTTP_BAD_REQUEST;
2589  }
2590 
2593  }
2594 
2595  if (!r->request_body && ngx_http_spdy_init_request_body(r) != NGX_OK) {
2596  stream->skip_data = NGX_SPDY_DATA_INTERNAL_ERROR;
2598  }
2599 
2600  if (stream->in_closed) {
2601  post_handler(r);
2602  return NGX_OK;
2603  }
2604 
2605  r->request_body->post_handler = post_handler;
2606 
2607  return NGX_AGAIN;
2608 }
2609 
2610 
2611 void
2612 ngx_http_spdy_close_stream(ngx_http_spdy_stream_t *stream, ngx_int_t rc)
2613 {
2614  ngx_event_t *ev;
2615  ngx_connection_t *fc;
2616  ngx_http_spdy_stream_t **index, *s;
2619 
2620  sc = stream->connection;
2621 
2623  "spdy close stream %ui, processing %ui",
2624  stream->id, sc->processing);
2625 
2626  if (!stream->out_closed) {
2627  if (ngx_http_spdy_send_rst_stream(sc, stream->id,
2629  stream->priority)
2630  != NGX_OK)
2631  {
2632  sc->connection->error = 1;
2633  }
2634  }
2635 
2638 
2639  index = sc->streams_index + ngx_http_spdy_stream_index(sscf, stream->id);
2640 
2641  for ( ;; ) {
2642  s = *index;
2643 
2644  if (s == NULL) {
2645  break;
2646  }
2647 
2648  if (s == stream) {
2649  *index = s->index;
2650  break;
2651  }
2652 
2653  index = &s->index;
2654  }
2655 
2656  fc = stream->request->connection;
2657 
2658  ngx_http_free_request(stream->request, rc);
2659 
2660  ev = fc->read;
2661 
2662  if (ev->active || ev->disabled) {
2663  ngx_del_event(ev, NGX_READ_EVENT, 0);
2664  }
2665 
2666  if (ev->timer_set) {
2667  ngx_del_timer(ev);
2668  }
2669 
2670  if (ev->prev) {
2672  }
2673 
2674  ev = fc->write;
2675 
2676  if (ev->active || ev->disabled) {
2678  }
2679 
2680  if (ev->timer_set) {
2681  ngx_del_timer(ev);
2682  }
2683 
2684  if (ev->prev) {
2686  }
2687 
2688  fc->data = sc->free_fake_connections;
2689  sc->free_fake_connections = fc;
2690 
2691  sc->processing--;
2692 
2693  if (sc->processing || sc->blocked) {
2694  return;
2695  }
2696 
2697  ev = sc->connection->read;
2698 
2699  ev->handler = ngx_http_spdy_handle_connection_handler;
2701 }
2702 
2703 
2704 static void
2705 ngx_http_spdy_handle_connection_handler(ngx_event_t *rev)
2706 {
2707  ngx_connection_t *c;
2708 
2709  rev->handler = ngx_http_spdy_read_handler;
2710 
2711  if (rev->ready) {
2712  ngx_http_spdy_read_handler(rev);
2713  return;
2714  }
2715 
2716  c = rev->data;
2717 
2718  ngx_http_spdy_handle_connection(c->data);
2719 }
2720 
2721 
2722 static void
2723 ngx_http_spdy_keepalive_handler(ngx_event_t *rev)
2724 {
2725  ngx_connection_t *c;
2728 
2729  c = rev->data;
2730 
2731  ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "spdy keepalive handler");
2732 
2733  if (rev->timedout || c->close) {
2735  return;
2736  }
2737 
2738 #if (NGX_HAVE_KQUEUE)
2739 
2741  if (rev->pending_eof) {
2742  c->log->handler = NULL;
2743  ngx_log_error(NGX_LOG_INFO, c->log, rev->kq_errno,
2744  "kevent() reported that client %V closed "
2745  "keepalive connection", &c->addr_text);
2746 #if (NGX_HTTP_SSL)
2747  if (c->ssl) {
2748  c->ssl->no_send_shutdown = 1;
2749  }
2750 #endif
2752  return;
2753  }
2754  }
2755 
2756 #endif
2757 
2758  c->destroyed = 0;
2759  c->idle = 0;
2761 
2762  sc = c->data;
2763 
2766 
2767  sc->pool = ngx_create_pool(sscf->pool_size, sc->connection->log);
2768  if (sc->pool == NULL) {
2770  return;
2771  }
2772 
2773  sc->streams_index = ngx_pcalloc(sc->pool,
2775  * sizeof(ngx_http_spdy_stream_t *));
2776  if (sc->streams_index == NULL) {
2778  return;
2779  }
2780 
2781  c->write->handler = ngx_http_spdy_write_handler;
2782 
2783  rev->handler = ngx_http_spdy_read_handler;
2784  ngx_http_spdy_read_handler(rev);
2785 }
2786 
2787 
2788 static void
2789 ngx_http_spdy_finalize_connection(ngx_http_spdy_connection_t *sc,
2790  ngx_int_t rc)
2791 {
2792  ngx_uint_t i, size;
2793  ngx_event_t *ev;
2794  ngx_connection_t *c, *fc;
2795  ngx_http_request_t *r;
2796  ngx_http_spdy_stream_t *stream;
2798 
2799  c = sc->connection;
2800 
2801  if (!sc->processing) {
2803  return;
2804  }
2805 
2806  c->error = 1;
2808 
2809  sc->last_out = NULL;
2810 
2811  sc->blocked = 1;
2812 
2815 
2816  size = ngx_http_spdy_streams_index_size(sscf);
2817 
2818  for (i = 0; i < size; i++) {
2819  stream = sc->streams_index[i];
2820 
2821  while (stream) {
2822  r = stream->request;
2823 
2824  fc = r->connection;
2825  fc->error = 1;
2826 
2827  if (stream->waiting) {
2828  r->blocked -= stream->waiting;
2829  stream->waiting = 0;
2830  ev = fc->write;
2831 
2832  } else {
2833  ev = fc->read;
2834  }
2835 
2836  stream = stream->index;
2837 
2838  ev->eof = 1;
2839  ev->handler(ev);
2840  }
2841  }
2842 
2843  sc->blocked = 0;
2844 
2845  if (sc->processing) {
2846  return;
2847  }
2848 
2850 }
2851 
2852 
2853 static void
2854 ngx_http_spdy_pool_cleanup(void *data)
2855 {
2856  ngx_http_spdy_connection_t *sc = data;
2857 
2858  if (sc->pool) {
2859  ngx_destroy_pool(sc->pool);
2860  }
2861 }
2862 
2863 
2864 static void *
2865 ngx_http_spdy_zalloc(void *opaque, u_int items, u_int size)
2866 {
2867  ngx_http_spdy_connection_t *sc = opaque;
2868 
2869  return ngx_palloc(sc->connection->pool, items * size);
2870 }
2871 
2872 
2873 static void
2874 ngx_http_spdy_zfree(void *opaque, void *address)
2875 {
2876 #if 0
2877  ngx_http_spdy_connection_t *sc = opaque;
2878 
2880  "spdy zfree: %p", address);
2881 #endif
2882 }