src/http/ngx_http_spdy.c - nginx-1.7.10

Global variables defined

Data types defined

Functions defined

Macros defined

Source code


  1. /*
  2. * Copyright (C) Nginx, Inc.
  3. * Copyright (C) Valentin V. Bartenev
  4. */


  5. #include <ngx_config.h>
  6. #include <ngx_core.h>
  7. #include <ngx_http.h>
  8. #include <ngx_http_spdy_module.h>

  9. #include <zlib.h>


  10. #if (NGX_HAVE_LITTLE_ENDIAN && NGX_HAVE_NONALIGNED)

  11. #define ngx_str5cmp(m, c0, c1, c2, c3, c4)                                    \
  12.     *(uint32_t *) m == (c3 << 24 | c2 << 16 | c1 << 8 | c0)                   \
  13.         && m[4] == c4

  14. #else

  15. #define ngx_str5cmp(m, c0, c1, c2, c3, c4)                                    \
  16.     m[0] == c0 && m[1] == c1 && m[2] == c2 && m[3] == c3 && m[4] == c4

  17. #endif


  18. #if (NGX_HAVE_NONALIGNED)

  19. #define ngx_spdy_frame_parse_uint16(p)  ntohs(*(uint16_t *) (p))
  20. #define ngx_spdy_frame_parse_uint32(p)  ntohl(*(uint32_t *) (p))

  21. #else

  22. #define ngx_spdy_frame_parse_uint16(p) ((p)[0] << 8 | (p)[1])
  23. #define ngx_spdy_frame_parse_uint32(p)                                        \
  24.     ((p)[0] << 24 | (p)[1] << 16 | (p)[2] << 8 | (p)[3])

  25. #endif

  26. #define ngx_spdy_frame_parse_sid(p)                                           \
  27.     (ngx_spdy_frame_parse_uint32(p) & 0x7fffffff)
  28. #define ngx_spdy_frame_parse_delta(p)                                         \
  29.     (ngx_spdy_frame_parse_uint32(p) & 0x7fffffff)


  30. #define ngx_spdy_ctl_frame_check(h)                                           \
  31.     (((h) & 0xffff0000) == ngx_spdy_ctl_frame_head(0))
  32. #define ngx_spdy_data_frame_check(h)                                          \
  33.     (!((h) & (uint32_t) NGX_SPDY_CTL_BIT << 31))

  34. #define ngx_spdy_ctl_frame_type(h)   ((h) & 0x0000ffff)
  35. #define ngx_spdy_frame_flags(p)      ((p) >> 24)
  36. #define ngx_spdy_frame_length(p)     ((p) & 0x00ffffff)
  37. #define ngx_spdy_frame_id(p)         ((p) & 0x00ffffff)


  38. #define NGX_SPDY_SKIP_HEADERS_BUFFER_SIZE  4096
  39. #define NGX_SPDY_CTL_FRAME_BUFFER_SIZE     16

  40. #define NGX_SPDY_PROTOCOL_ERROR            1
  41. #define NGX_SPDY_INVALID_STREAM            2
  42. #define NGX_SPDY_REFUSED_STREAM            3
  43. #define NGX_SPDY_UNSUPPORTED_VERSION       4
  44. #define NGX_SPDY_CANCEL                    5
  45. #define NGX_SPDY_INTERNAL_ERROR            6
  46. #define NGX_SPDY_FLOW_CONTROL_ERROR        7
  47. #define NGX_SPDY_STREAM_IN_USE             8
  48. #define NGX_SPDY_STREAM_ALREADY_CLOSED     9
  49. /* deprecated                              10 */
  50. #define NGX_SPDY_FRAME_TOO_LARGE           11

  51. #define NGX_SPDY_SETTINGS_MAX_STREAMS      4
  52. #define NGX_SPDY_SETTINGS_INIT_WINDOW      7

  53. #define NGX_SPDY_SETTINGS_FLAG_PERSIST     0x01
  54. #define NGX_SPDY_SETTINGS_FLAG_PERSISTED   0x02

  55. #define NGX_SPDY_MAX_WINDOW                NGX_MAX_INT32_VALUE
  56. #define NGX_SPDY_CONNECTION_WINDOW         65536
  57. #define NGX_SPDY_INIT_STREAM_WINDOW        65536
  58. #define NGX_SPDY_STREAM_WINDOW             NGX_SPDY_MAX_WINDOW

  59. typedef struct {
  60.     ngx_uint_t    hash;
  61.     u_char        len;
  62.     u_char        header[7];
  63.     ngx_int_t   (*handler)(ngx_http_request_t *r);
  64. } ngx_http_spdy_request_header_t;


  65. static void ngx_http_spdy_read_handler(ngx_event_t *rev);
  66. static void ngx_http_spdy_write_handler(ngx_event_t *wev);
  67. static void ngx_http_spdy_handle_connection(ngx_http_spdy_connection_t *sc);

  68. static u_char *ngx_http_spdy_proxy_protocol(ngx_http_spdy_connection_t *sc,
  69.     u_char *pos, u_char *end);
  70. static u_char *ngx_http_spdy_state_head(ngx_http_spdy_connection_t *sc,
  71.     u_char *pos, u_char *end);
  72. static u_char *ngx_http_spdy_state_syn_stream(ngx_http_spdy_connection_t *sc,
  73.     u_char *pos, u_char *end);
  74. static u_char *ngx_http_spdy_state_headers(ngx_http_spdy_connection_t *sc,
  75.     u_char *pos, u_char *end);
  76. static u_char *ngx_http_spdy_state_headers_skip(ngx_http_spdy_connection_t *sc,
  77.     u_char *pos, u_char *end);
  78. static u_char *ngx_http_spdy_state_headers_error(ngx_http_spdy_connection_t *sc,
  79.     u_char *pos, u_char *end);
  80. static u_char *ngx_http_spdy_state_window_update(ngx_http_spdy_connection_t *sc,
  81.     u_char *pos, u_char *end);
  82. static u_char *ngx_http_spdy_state_data(ngx_http_spdy_connection_t *sc,
  83.     u_char *pos, u_char *end);
  84. static u_char *ngx_http_spdy_state_read_data(ngx_http_spdy_connection_t *sc,
  85.     u_char *pos, u_char *end);
  86. static u_char *ngx_http_spdy_state_rst_stream(ngx_http_spdy_connection_t *sc,
  87.     u_char *pos, u_char *end);
  88. static u_char *ngx_http_spdy_state_ping(ngx_http_spdy_connection_t *sc,
  89.     u_char *pos, u_char *end);
  90. static u_char *ngx_http_spdy_state_skip(ngx_http_spdy_connection_t *sc,
  91.     u_char *pos, u_char *end);
  92. static u_char *ngx_http_spdy_state_settings(ngx_http_spdy_connection_t *sc,
  93.     u_char *pos, u_char *end);
  94. static u_char *ngx_http_spdy_state_complete(ngx_http_spdy_connection_t *sc,
  95.     u_char *pos, u_char *end);
  96. static u_char *ngx_http_spdy_state_save(ngx_http_spdy_connection_t *sc,
  97.     u_char *pos, u_char *end, ngx_http_spdy_handler_pt handler);

  98. static u_char *ngx_http_spdy_state_inflate_error(
  99.     ngx_http_spdy_connection_t *sc, int rc);
  100. static u_char *ngx_http_spdy_state_protocol_error(
  101.     ngx_http_spdy_connection_t *sc);
  102. static u_char *ngx_http_spdy_state_internal_error(
  103.     ngx_http_spdy_connection_t *sc);

  104. static ngx_int_t ngx_http_spdy_send_window_update(
  105.     ngx_http_spdy_connection_t *sc, ngx_uint_t sid, ngx_uint_t delta);
  106. static ngx_int_t ngx_http_spdy_send_rst_stream(ngx_http_spdy_connection_t *sc,
  107.     ngx_uint_t sid, ngx_uint_t status, ngx_uint_t priority);
  108. static ngx_int_t ngx_http_spdy_send_settings(ngx_http_spdy_connection_t *sc);
  109. static ngx_int_t ngx_http_spdy_settings_frame_handler(
  110.     ngx_http_spdy_connection_t *sc, ngx_http_spdy_out_frame_t *frame);
  111. static ngx_http_spdy_out_frame_t *ngx_http_spdy_get_ctl_frame(
  112.     ngx_http_spdy_connection_t *sc, size_t size, ngx_uint_t priority);
  113. static ngx_int_t ngx_http_spdy_ctl_frame_handler(
  114.     ngx_http_spdy_connection_t *sc, ngx_http_spdy_out_frame_t *frame);

  115. static ngx_http_spdy_stream_t *ngx_http_spdy_create_stream(
  116.     ngx_http_spdy_connection_t *sc, ngx_uint_t id, ngx_uint_t priority);
  117. static ngx_http_spdy_stream_t *ngx_http_spdy_get_stream_by_id(
  118.     ngx_http_spdy_connection_t *sc, ngx_uint_t sid);
  119. #define ngx_http_spdy_streams_index_size(sscf)  (sscf->streams_index_mask + 1)
  120. #define ngx_http_spdy_stream_index(sscf, sid)                                 \
  121.     ((sid >> 1) & sscf->streams_index_mask)

  122. static ngx_int_t ngx_http_spdy_parse_header(ngx_http_request_t *r);
  123. static ngx_int_t ngx_http_spdy_alloc_large_header_buffer(ngx_http_request_t *r);

  124. static ngx_int_t ngx_http_spdy_handle_request_header(ngx_http_request_t *r);
  125. static ngx_int_t ngx_http_spdy_parse_method(ngx_http_request_t *r);
  126. static ngx_int_t ngx_http_spdy_parse_scheme(ngx_http_request_t *r);
  127. static ngx_int_t ngx_http_spdy_parse_host(ngx_http_request_t *r);
  128. static ngx_int_t ngx_http_spdy_parse_path(ngx_http_request_t *r);
  129. static ngx_int_t ngx_http_spdy_parse_version(ngx_http_request_t *r);

  130. static ngx_int_t ngx_http_spdy_construct_request_line(ngx_http_request_t *r);
  131. static void ngx_http_spdy_run_request(ngx_http_request_t *r);
  132. static ngx_int_t ngx_http_spdy_init_request_body(ngx_http_request_t *r);

  133. static ngx_int_t ngx_http_spdy_terminate_stream(ngx_http_spdy_connection_t *sc,
  134.     ngx_http_spdy_stream_t *stream, ngx_uint_t status);

  135. static void ngx_http_spdy_close_stream_handler(ngx_event_t *ev);

  136. static void ngx_http_spdy_handle_connection_handler(ngx_event_t *rev);
  137. static void ngx_http_spdy_keepalive_handler(ngx_event_t *rev);
  138. static void ngx_http_spdy_finalize_connection(ngx_http_spdy_connection_t *sc,
  139.     ngx_int_t rc);

  140. static ngx_int_t ngx_http_spdy_adjust_windows(ngx_http_spdy_connection_t *sc,
  141.     ssize_t delta);

  142. static void ngx_http_spdy_pool_cleanup(void *data);

  143. static void *ngx_http_spdy_zalloc(void *opaque, u_int items, u_int size);
  144. static void ngx_http_spdy_zfree(void *opaque, void *address);


  145. static const u_char ngx_http_spdy_dict[] = {
  146.     0x00, 0x00, 0x00, 0x07, 0x6f, 0x70, 0x74, 0x69,   /* - - - - o p t i */
  147.     0x6f, 0x6e, 0x73, 0x00, 0x00, 0x00, 0x04, 0x68,   /* o n s - - - - h */
  148.     0x65, 0x61, 0x64, 0x00, 0x00, 0x00, 0x04, 0x70,   /* e a d - - - - p */
  149.     0x6f, 0x73, 0x74, 0x00, 0x00, 0x00, 0x03, 0x70,   /* o s t - - - - p */
  150.     0x75, 0x74, 0x00, 0x00, 0x00, 0x06, 0x64, 0x65,   /* u t - - - - d e */
  151.     0x6c, 0x65, 0x74, 0x65, 0x00, 0x00, 0x00, 0x05,   /* l e t e - - - - */
  152.     0x74, 0x72, 0x61, 0x63, 0x65, 0x00, 0x00, 0x00,   /* t r a c e - - - */
  153.     0x06, 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x00,   /* - a c c e p t - */
  154.     0x00, 0x00, 0x0e, 0x61, 0x63, 0x63, 0x65, 0x70,   /* - - - a c c e p */
  155.     0x74, 0x2d, 0x63, 0x68, 0x61, 0x72, 0x73, 0x65,   /* t - c h a r s e */
  156.     0x74, 0x00, 0x00, 0x00, 0x0f, 0x61, 0x63, 0x63,   /* t - - - - a c c */
  157.     0x65, 0x70, 0x74, 0x2d, 0x65, 0x6e, 0x63, 0x6f,   /* e p t - e n c o */
  158.     0x64, 0x69, 0x6e, 0x67, 0x00, 0x00, 0x00, 0x0f,   /* d i n g - - - - */
  159.     0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x2d, 0x6c,   /* a c c e p t - l */
  160.     0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x00,   /* a n g u a g e - */
  161.     0x00, 0x00, 0x0d, 0x61, 0x63, 0x63, 0x65, 0x70,   /* - - - a c c e p */
  162.     0x74, 0x2d, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x73,   /* t - r a n g e s */
  163.     0x00, 0x00, 0x00, 0x03, 0x61, 0x67, 0x65, 0x00,   /* - - - - a g e - */
  164.     0x00, 0x00, 0x05, 0x61, 0x6c, 0x6c, 0x6f, 0x77,   /* - - - a l l o w */
  165.     0x00, 0x00, 0x00, 0x0d, 0x61, 0x75, 0x74, 0x68,   /* - - - - a u t h */
  166.     0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f,   /* o r i z a t i o */
  167.     0x6e, 0x00, 0x00, 0x00, 0x0d, 0x63, 0x61, 0x63,   /* n - - - - c a c */
  168.     0x68, 0x65, 0x2d, 0x63, 0x6f, 0x6e, 0x74, 0x72,   /* h e - c o n t r */
  169.     0x6f, 0x6c, 0x00, 0x00, 0x00, 0x0a, 0x63, 0x6f,   /* o l - - - - c o */
  170.     0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e,   /* n n e c t i o n */
  171.     0x00, 0x00, 0x00, 0x0c, 0x63, 0x6f, 0x6e, 0x74,   /* - - - - c o n t */
  172.     0x65, 0x6e, 0x74, 0x2d, 0x62, 0x61, 0x73, 0x65,   /* e n t - b a s e */
  173.     0x00, 0x00, 0x00, 0x10, 0x63, 0x6f, 0x6e, 0x74,   /* - - - - c o n t */
  174.     0x65, 0x6e, 0x74, 0x2d, 0x65, 0x6e, 0x63, 0x6f,   /* e n t - e n c o */
  175.     0x64, 0x69, 0x6e, 0x67, 0x00, 0x00, 0x00, 0x10,   /* d i n g - - - - */
  176.     0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d,   /* c o n t e n t - */
  177.     0x6c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65,   /* l a n g u a g e */
  178.     0x00, 0x00, 0x00, 0x0e, 0x63, 0x6f, 0x6e, 0x74,   /* - - - - c o n t */
  179.     0x65, 0x6e, 0x74, 0x2d, 0x6c, 0x65, 0x6e, 0x67,   /* e n t - l e n g */
  180.     0x74, 0x68, 0x00, 0x00, 0x00, 0x10, 0x63, 0x6f,   /* t h - - - - c o */
  181.     0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x6c, 0x6f,   /* n t e n t - l o */
  182.     0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x00, 0x00,   /* c a t i o n - - */
  183.     0x00, 0x0b, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e,   /* - - c o n t e n */
  184.     0x74, 0x2d, 0x6d, 0x64, 0x35, 0x00, 0x00, 0x00,   /* t - m d 5 - - - */
  185.     0x0d, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74,   /* - c o n t e n t */
  186.     0x2d, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x00, 0x00,   /* - r a n g e - - */
  187.     0x00, 0x0c, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e,   /* - - c o n t e n */
  188.     0x74, 0x2d, 0x74, 0x79, 0x70, 0x65, 0x00, 0x00,   /* t - t y p e - - */
  189.     0x00, 0x04, 0x64, 0x61, 0x74, 0x65, 0x00, 0x00,   /* - - d a t e - - */
  190.     0x00, 0x04, 0x65, 0x74, 0x61, 0x67, 0x00, 0x00,   /* - - e t a g - - */
  191.     0x00, 0x06, 0x65, 0x78, 0x70, 0x65, 0x63, 0x74,   /* - - e x p e c t */
  192.     0x00, 0x00, 0x00, 0x07, 0x65, 0x78, 0x70, 0x69,   /* - - - - e x p i */
  193.     0x72, 0x65, 0x73, 0x00, 0x00, 0x00, 0x04, 0x66,   /* r e s - - - - f */
  194.     0x72, 0x6f, 0x6d, 0x00, 0x00, 0x00, 0x04, 0x68,   /* r o m - - - - h */
  195.     0x6f, 0x73, 0x74, 0x00, 0x00, 0x00, 0x08, 0x69,   /* o s t - - - - i */
  196.     0x66, 0x2d, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x00,   /* f - m a t c h - */
  197.     0x00, 0x00, 0x11, 0x69, 0x66, 0x2d, 0x6d, 0x6f,   /* - - - i f - m o */
  198.     0x64, 0x69, 0x66, 0x69, 0x65, 0x64, 0x2d, 0x73,   /* d i f i e d - s */
  199.     0x69, 0x6e, 0x63, 0x65, 0x00, 0x00, 0x00, 0x0d,   /* i n c e - - - - */
  200.     0x69, 0x66, 0x2d, 0x6e, 0x6f, 0x6e, 0x65, 0x2d,   /* i f - n o n e - */
  201.     0x6d, 0x61, 0x74, 0x63, 0x68, 0x00, 0x00, 0x00,   /* m a t c h - - - */
  202.     0x08, 0x69, 0x66, 0x2d, 0x72, 0x61, 0x6e, 0x67,   /* - i f - r a n g */
  203.     0x65, 0x00, 0x00, 0x00, 0x13, 0x69, 0x66, 0x2d,   /* e - - - - i f - */
  204.     0x75, 0x6e, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x69,   /* u n m o d i f i */
  205.     0x65, 0x64, 0x2d, 0x73, 0x69, 0x6e, 0x63, 0x65,   /* e d - s i n c e */
  206.     0x00, 0x00, 0x00, 0x0d, 0x6c, 0x61, 0x73, 0x74,   /* - - - - l a s t */
  207.     0x2d, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x69, 0x65,   /* - m o d i f i e */
  208.     0x64, 0x00, 0x00, 0x00, 0x08, 0x6c, 0x6f, 0x63,   /* d - - - - l o c */
  209.     0x61, 0x74, 0x69, 0x6f, 0x6e, 0x00, 0x00, 0x00,   /* a t i o n - - - */
  210.     0x0c, 0x6d, 0x61, 0x78, 0x2d, 0x66, 0x6f, 0x72,   /* - m a x - f o r */
  211.     0x77, 0x61, 0x72, 0x64, 0x73, 0x00, 0x00, 0x00,   /* w a r d s - - - */
  212.     0x06, 0x70, 0x72, 0x61, 0x67, 0x6d, 0x61, 0x00,   /* - p r a g m a - */
  213.     0x00, 0x00, 0x12, 0x70, 0x72, 0x6f, 0x78, 0x79,   /* - - - p r o x y */
  214.     0x2d, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74,   /* - a u t h e n t */
  215.     0x69, 0x63, 0x61, 0x74, 0x65, 0x00, 0x00, 0x00,   /* i c a t e - - - */
  216.     0x13, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2d, 0x61,   /* - p r o x y - a */
  217.     0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61,   /* u t h o r i z a */
  218.     0x74, 0x69, 0x6f, 0x6e, 0x00, 0x00, 0x00, 0x05,   /* t i o n - - - - */
  219.     0x72, 0x61, 0x6e, 0x67, 0x65, 0x00, 0x00, 0x00,   /* r a n g e - - - */
  220.     0x07, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x72,   /* - r e f e r e r */
  221.     0x00, 0x00, 0x00, 0x0b, 0x72, 0x65, 0x74, 0x72,   /* - - - - r e t r */
  222.     0x79, 0x2d, 0x61, 0x66, 0x74, 0x65, 0x72, 0x00,   /* y - a f t e r - */
  223.     0x00, 0x00, 0x06, 0x73, 0x65, 0x72, 0x76, 0x65,   /* - - - s e r v e */
  224.     0x72, 0x00, 0x00, 0x00, 0x02, 0x74, 0x65, 0x00,   /* r - - - - t e - */
  225.     0x00, 0x00, 0x07, 0x74, 0x72, 0x61, 0x69, 0x6c,   /* - - - t r a i l */
  226.     0x65, 0x72, 0x00, 0x00, 0x00, 0x11, 0x74, 0x72,   /* e r - - - - t r */
  227.     0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x2d, 0x65,   /* a n s f e r - e */
  228.     0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x00,   /* n c o d i n g - */
  229.     0x00, 0x00, 0x07, 0x75, 0x70, 0x67, 0x72, 0x61,   /* - - - u p g r a */
  230.     0x64, 0x65, 0x00, 0x00, 0x00, 0x0a, 0x75, 0x73,   /* d e - - - - u s */
  231.     0x65, 0x72, 0x2d, 0x61, 0x67, 0x65, 0x6e, 0x74,   /* e r - a g e n t */
  232.     0x00, 0x00, 0x00, 0x04, 0x76, 0x61, 0x72, 0x79,   /* - - - - v a r y */
  233.     0x00, 0x00, 0x00, 0x03, 0x76, 0x69, 0x61, 0x00,   /* - - - - v i a - */
  234.     0x00, 0x00, 0x07, 0x77, 0x61, 0x72, 0x6e, 0x69,   /* - - - w a r n i */
  235.     0x6e, 0x67, 0x00, 0x00, 0x00, 0x10, 0x77, 0x77,   /* n g - - - - w w */
  236.     0x77, 0x2d, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e,   /* w - a u t h e n */
  237.     0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x00, 0x00,   /* t i c a t e - - */
  238.     0x00, 0x06, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64,   /* - - m e t h o d */
  239.     0x00, 0x00, 0x00, 0x03, 0x67, 0x65, 0x74, 0x00,   /* - - - - g e t - */
  240.     0x00, 0x00, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75,   /* - - - s t a t u */
  241.     0x73, 0x00, 0x00, 0x00, 0x06, 0x32, 0x30, 0x30,   /* s - - - - 2 0 0 */
  242.     0x20, 0x4f, 0x4b, 0x00, 0x00, 0x00, 0x07, 0x76,   /* - O K - - - - v */
  243.     0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x00, 0x00,   /* e r s i o n - - */
  244.     0x00, 0x08, 0x48, 0x54, 0x54, 0x50, 0x2f, 0x31,   /* - - H T T P - 1 */
  245.     0x2e, 0x31, 0x00, 0x00, 0x00, 0x03, 0x75, 0x72,   /* - 1 - - - - u r */
  246.     0x6c, 0x00, 0x00, 0x00, 0x06, 0x70, 0x75, 0x62,   /* l - - - - p u b */
  247.     0x6c, 0x69, 0x63, 0x00, 0x00, 0x00, 0x0a, 0x73,   /* l i c - - - - s */
  248.     0x65, 0x74, 0x2d, 0x63, 0x6f, 0x6f, 0x6b, 0x69,   /* e t - c o o k i */
  249.     0x65, 0x00, 0x00, 0x00, 0x0a, 0x6b, 0x65, 0x65,   /* e - - - - k e e */
  250.     0x70, 0x2d, 0x61, 0x6c, 0x69, 0x76, 0x65, 0x00,   /* p - a l i v e - */
  251.     0x00, 0x00, 0x06, 0x6f, 0x72, 0x69, 0x67, 0x69,   /* - - - o r i g i */
  252.     0x6e, 0x31, 0x30, 0x30, 0x31, 0x30, 0x31, 0x32,   /* n 1 0 0 1 0 1 2 */
  253.     0x30, 0x31, 0x32, 0x30, 0x32, 0x32, 0x30, 0x35,   /* 0 1 2 0 2 2 0 5 */
  254.     0x32, 0x30, 0x36, 0x33, 0x30, 0x30, 0x33, 0x30,   /* 2 0 6 3 0 0 3 0 */
  255.     0x32, 0x33, 0x30, 0x33, 0x33, 0x30, 0x34, 0x33,   /* 2 3 0 3 3 0 4 3 */
  256.     0x30, 0x35, 0x33, 0x30, 0x36, 0x33, 0x30, 0x37,   /* 0 5 3 0 6 3 0 7 */
  257.     0x34, 0x30, 0x32, 0x34, 0x30, 0x35, 0x34, 0x30,   /* 4 0 2 4 0 5 4 0 */
  258.     0x36, 0x34, 0x30, 0x37, 0x34, 0x30, 0x38, 0x34,   /* 6 4 0 7 4 0 8 4 */
  259.     0x30, 0x39, 0x34, 0x31, 0x30, 0x34, 0x31, 0x31,   /* 0 9 4 1 0 4 1 1 */
  260.     0x34, 0x31, 0x32, 0x34, 0x31, 0x33, 0x34, 0x31,   /* 4 1 2 4 1 3 4 1 */
  261.     0x34, 0x34, 0x31, 0x35, 0x34, 0x31, 0x36, 0x34,   /* 4 4 1 5 4 1 6 4 */
  262.     0x31, 0x37, 0x35, 0x30, 0x32, 0x35, 0x30, 0x34,   /* 1 7 5 0 2 5 0 4 */
  263.     0x35, 0x30, 0x35, 0x32, 0x30, 0x33, 0x20, 0x4e,   /* 5 0 5 2 0 3 - N */
  264.     0x6f, 0x6e, 0x2d, 0x41, 0x75, 0x74, 0x68, 0x6f,   /* o n - A u t h o */
  265.     0x72, 0x69, 0x74, 0x61, 0x74, 0x69, 0x76, 0x65,   /* r i t a t i v e */
  266.     0x20, 0x49, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x61,   /* - I n f o r m a */
  267.     0x74, 0x69, 0x6f, 0x6e, 0x32, 0x30, 0x34, 0x20,   /* t i o n 2 0 4 - */
  268.     0x4e, 0x6f, 0x20, 0x43, 0x6f, 0x6e, 0x74, 0x65,   /* N o - C o n t e */
  269.     0x6e, 0x74, 0x33, 0x30, 0x31, 0x20, 0x4d, 0x6f,   /* n t 3 0 1 - M o */
  270.     0x76, 0x65, 0x64, 0x20, 0x50, 0x65, 0x72, 0x6d,   /* v e d - P e r m */
  271.     0x61, 0x6e, 0x65, 0x6e, 0x74, 0x6c, 0x79, 0x34,   /* a n e n t l y 4 */
  272.     0x30, 0x30, 0x20, 0x42, 0x61, 0x64, 0x20, 0x52,   /* 0 0 - B a d - R */
  273.     0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x34, 0x30,   /* e q u e s t 4 0 */
  274.     0x31, 0x20, 0x55, 0x6e, 0x61, 0x75, 0x74, 0x68,   /* 1 - U n a u t h */
  275.     0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64, 0x34, 0x30,   /* o r i z e d 4 0 */
  276.     0x33, 0x20, 0x46, 0x6f, 0x72, 0x62, 0x69, 0x64,   /* 3 - F o r b i d */
  277.     0x64, 0x65, 0x6e, 0x34, 0x30, 0x34, 0x20, 0x4e,   /* d e n 4 0 4 - N */
  278.     0x6f, 0x74, 0x20, 0x46, 0x6f, 0x75, 0x6e, 0x64,   /* o t - F o u n d */
  279.     0x35, 0x30, 0x30, 0x20, 0x49, 0x6e, 0x74, 0x65,   /* 5 0 0 - I n t e */
  280.     0x72, 0x6e, 0x61, 0x6c, 0x20, 0x53, 0x65, 0x72,   /* r n a l - S e r */
  281.     0x76, 0x65, 0x72, 0x20, 0x45, 0x72, 0x72, 0x6f,   /* v e r - E r r o */
  282.     0x72, 0x35, 0x30, 0x31, 0x20, 0x4e, 0x6f, 0x74,   /* r 5 0 1 - N o t */
  283.     0x20, 0x49, 0x6d, 0x70, 0x6c, 0x65, 0x6d, 0x65,   /* - I m p l e m e */
  284.     0x6e, 0x74, 0x65, 0x64, 0x35, 0x30, 0x33, 0x20,   /* n t e d 5 0 3 - */
  285.     0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x20,   /* S e r v i c e - */
  286.     0x55, 0x6e, 0x61, 0x76, 0x61, 0x69, 0x6c, 0x61,   /* U n a v a i l a */
  287.     0x62, 0x6c, 0x65, 0x4a, 0x61, 0x6e, 0x20, 0x46,   /* b l e J a n - F */
  288.     0x65, 0x62, 0x20, 0x4d, 0x61, 0x72, 0x20, 0x41,   /* e b - M a r - A */
  289.     0x70, 0x72, 0x20, 0x4d, 0x61, 0x79, 0x20, 0x4a,   /* p r - M a y - J */
  290.     0x75, 0x6e, 0x20, 0x4a, 0x75, 0x6c, 0x20, 0x41,   /* u n - J u l - A */
  291.     0x75, 0x67, 0x20, 0x53, 0x65, 0x70, 0x74, 0x20,   /* u g - S e p t - */
  292.     0x4f, 0x63, 0x74, 0x20, 0x4e, 0x6f, 0x76, 0x20,   /* O c t - N o v - */
  293.     0x44, 0x65, 0x63, 0x20, 0x30, 0x30, 0x3a, 0x30,   /* D e c - 0 0 - 0 */
  294.     0x30, 0x3a, 0x30, 0x30, 0x20, 0x4d, 0x6f, 0x6e,   /* 0 - 0 0 - M o n */
  295.     0x2c, 0x20, 0x54, 0x75, 0x65, 0x2c, 0x20, 0x57,   /* - - T u e - - W */
  296.     0x65, 0x64, 0x2c, 0x20, 0x54, 0x68, 0x75, 0x2c,   /* e d - - T h u - */
  297.     0x20, 0x46, 0x72, 0x69, 0x2c, 0x20, 0x53, 0x61,   /* - F r i - - S a */
  298.     0x74, 0x2c, 0x20, 0x53, 0x75, 0x6e, 0x2c, 0x20,   /* t - - S u n - - */
  299.     0x47, 0x4d, 0x54, 0x63, 0x68, 0x75, 0x6e, 0x6b,   /* G M T c h u n k */
  300.     0x65, 0x64, 0x2c, 0x74, 0x65, 0x78, 0x74, 0x2f,   /* e d - t e x t - */
  301.     0x68, 0x74, 0x6d, 0x6c, 0x2c, 0x69, 0x6d, 0x61,   /* h t m l - i m a */
  302.     0x67, 0x65, 0x2f, 0x70, 0x6e, 0x67, 0x2c, 0x69,   /* g e - p n g - i */
  303.     0x6d, 0x61, 0x67, 0x65, 0x2f, 0x6a, 0x70, 0x67,   /* m a g e - j p g */
  304.     0x2c, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x2f, 0x67,   /* - i m a g e - g */
  305.     0x69, 0x66, 0x2c, 0x61, 0x70, 0x70, 0x6c, 0x69,   /* i f - a p p l i */
  306.     0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78,   /* c a t i o n - x */
  307.     0x6d, 0x6c, 0x2c, 0x61, 0x70, 0x70, 0x6c, 0x69,   /* m l - a p p l i */
  308.     0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78,   /* c a t i o n - x */
  309.     0x68, 0x74, 0x6d, 0x6c, 0x2b, 0x78, 0x6d, 0x6c,   /* h t m l - x m l */
  310.     0x2c, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x70, 0x6c,   /* - t e x t - p l */
  311.     0x61, 0x69, 0x6e, 0x2c, 0x74, 0x65, 0x78, 0x74,   /* a i n - t e x t */
  312.     0x2f, 0x6a, 0x61, 0x76, 0x61, 0x73, 0x63, 0x72,   /* - j a v a s c r */
  313.     0x69, 0x70, 0x74, 0x2c, 0x70, 0x75, 0x62, 0x6c,   /* i p t - p u b l */
  314.     0x69, 0x63, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74,   /* i c p r i v a t */
  315.     0x65, 0x6d, 0x61, 0x78, 0x2d, 0x61, 0x67, 0x65,   /* e m a x - a g e */
  316.     0x3d, 0x67, 0x7a, 0x69, 0x70, 0x2c, 0x64, 0x65,   /* - g z i p - d e */
  317.     0x66, 0x6c, 0x61, 0x74, 0x65, 0x2c, 0x73, 0x64,   /* f l a t e - s d */
  318.     0x63, 0x68, 0x63, 0x68, 0x61, 0x72, 0x73, 0x65,   /* c h c h a r s e */
  319.     0x74, 0x3d, 0x75, 0x74, 0x66, 0x2d, 0x38, 0x63,   /* t - u t f - 8 c */
  320.     0x68, 0x61, 0x72, 0x73, 0x65, 0x74, 0x3d, 0x69,   /* h a r s e t - i */
  321.     0x73, 0x6f, 0x2d, 0x38, 0x38, 0x35, 0x39, 0x2d,   /* s o - 8 8 5 9 - */
  322.     0x31, 0x2c, 0x75, 0x74, 0x66, 0x2d, 0x2c, 0x2a,   /* 1 - u t f - - - */
  323.     0x2c, 0x65, 0x6e, 0x71, 0x3d, 0x30, 0x2e          /* - e n q - 0 -   */
  324. };


  325. static ngx_http_spdy_request_header_t ngx_http_spdy_request_headers[] = {
  326.     { 0, 6, "method", ngx_http_spdy_parse_method },
  327.     { 0, 6, "scheme", ngx_http_spdy_parse_scheme },
  328.     { 0, 4, "host", ngx_http_spdy_parse_host },
  329.     { 0, 4, "path", ngx_http_spdy_parse_path },
  330.     { 0, 7, "version", ngx_http_spdy_parse_version },
  331. };

  332. #define NGX_SPDY_REQUEST_HEADERS                                              \
  333.     (sizeof(ngx_http_spdy_request_headers)                                    \
  334.      / sizeof(ngx_http_spdy_request_header_t))


  335. void
  336. ngx_http_spdy_init(ngx_event_t *rev)
  337. {
  338.     int                          rc;
  339.     ngx_connection_t            *c;
  340.     ngx_pool_cleanup_t          *cln;
  341.     ngx_http_connection_t       *hc;
  342.     ngx_http_spdy_srv_conf_t    *sscf;
  343.     ngx_http_spdy_main_conf_t   *smcf;
  344.     ngx_http_spdy_connection_t  *sc;

  345.     c = rev->data;
  346.     hc = c->data;

  347.     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "init spdy request");

  348.     c->log->action = "processing SPDY";

  349.     smcf = ngx_http_get_module_main_conf(hc->conf_ctx, ngx_http_spdy_module);

  350.     if (smcf->recv_buffer == NULL) {
  351.         smcf->recv_buffer = ngx_palloc(ngx_cycle->pool, smcf->recv_buffer_size);
  352.         if (smcf->recv_buffer == NULL) {
  353.             ngx_http_close_connection(c);
  354.             return;
  355.         }
  356.     }

  357.     sc = ngx_pcalloc(c->pool, sizeof(ngx_http_spdy_connection_t));
  358.     if (sc == NULL) {
  359.         ngx_http_close_connection(c);
  360.         return;
  361.     }

  362.     sc->connection = c;
  363.     sc->http_connection = hc;

  364.     sc->send_window = NGX_SPDY_CONNECTION_WINDOW;
  365.     sc->recv_window = NGX_SPDY_CONNECTION_WINDOW;

  366.     sc->init_window = NGX_SPDY_INIT_STREAM_WINDOW;

  367.     sc->handler = hc->proxy_protocol ? ngx_http_spdy_proxy_protocol
  368.                                      : ngx_http_spdy_state_head;

  369.     sc->zstream_in.zalloc = ngx_http_spdy_zalloc;
  370.     sc->zstream_in.zfree = ngx_http_spdy_zfree;
  371.     sc->zstream_in.opaque = sc;

  372.     rc = inflateInit(&sc->zstream_in);
  373.     if (rc != Z_OK) {
  374.         ngx_log_error(NGX_LOG_ALERT, c->log, 0,
  375.                       "inflateInit() failed: %d", rc);
  376.         ngx_http_close_connection(c);
  377.         return;
  378.     }

  379.     sc->zstream_out.zalloc = ngx_http_spdy_zalloc;
  380.     sc->zstream_out.zfree = ngx_http_spdy_zfree;
  381.     sc->zstream_out.opaque = sc;

  382.     sscf = ngx_http_get_module_srv_conf(hc->conf_ctx, ngx_http_spdy_module);

  383.     rc = deflateInit2(&sc->zstream_out, (int) sscf->headers_comp,
  384.                       Z_DEFLATED, 11, 4, Z_DEFAULT_STRATEGY);

  385.     if (rc != Z_OK) {
  386.         ngx_log_error(NGX_LOG_ALERT, c->log, 0,
  387.                       "deflateInit2() failed: %d", rc);
  388.         ngx_http_close_connection(c);
  389.         return;
  390.     }

  391.     rc = deflateSetDictionary(&sc->zstream_out, ngx_http_spdy_dict,
  392.                               sizeof(ngx_http_spdy_dict));
  393.     if (rc != Z_OK) {
  394.         ngx_log_error(NGX_LOG_ALERT, c->log, 0,
  395.                       "deflateSetDictionary() failed: %d", rc);
  396.         ngx_http_close_connection(c);
  397.         return;
  398.     }

  399.     sc->pool = ngx_create_pool(sscf->pool_size, sc->connection->log);
  400.     if (sc->pool == NULL) {
  401.         ngx_http_close_connection(c);
  402.         return;
  403.     }

  404.     cln = ngx_pool_cleanup_add(c->pool, sizeof(ngx_pool_cleanup_file_t));
  405.     if (cln == NULL) {
  406.         ngx_http_close_connection(c);
  407.         return;
  408.     }

  409.     cln->handler = ngx_http_spdy_pool_cleanup;
  410.     cln->data = sc;

  411.     sc->streams_index = ngx_pcalloc(sc->pool,
  412.                                     ngx_http_spdy_streams_index_size(sscf)
  413.                                     * sizeof(ngx_http_spdy_stream_t *));
  414.     if (sc->streams_index == NULL) {
  415.         ngx_http_close_connection(c);
  416.         return;
  417.     }

  418.     if (ngx_http_spdy_send_settings(sc) == NGX_ERROR) {
  419.         ngx_http_close_connection(c);
  420.         return;
  421.     }

  422.     if (ngx_http_spdy_send_window_update(sc, 0, NGX_SPDY_MAX_WINDOW
  423.                                                 - sc->recv_window)
  424.         == NGX_ERROR)
  425.     {
  426.         ngx_http_close_connection(c);
  427.         return;
  428.     }

  429.     sc->recv_window = NGX_SPDY_MAX_WINDOW;

  430.     ngx_queue_init(&sc->waiting);
  431.     ngx_queue_init(&sc->posted);

  432.     c->data = sc;

  433.     rev->handler = ngx_http_spdy_read_handler;
  434.     c->write->handler = ngx_http_spdy_write_handler;

  435.     ngx_http_spdy_read_handler(rev);
  436. }


  437. static void
  438. ngx_http_spdy_read_handler(ngx_event_t *rev)
  439. {
  440.     u_char                      *p, *end;
  441.     size_t                       available;
  442.     ssize_t                      n;
  443.     ngx_connection_t            *c;
  444.     ngx_http_spdy_main_conf_t   *smcf;
  445.     ngx_http_spdy_connection_t  *sc;

  446.     c = rev->data;
  447.     sc = c->data;

  448.     if (rev->timedout) {
  449.         ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT, "client timed out");
  450.         ngx_http_spdy_finalize_connection(sc, NGX_HTTP_REQUEST_TIME_OUT);
  451.         return;
  452.     }

  453.     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "spdy read handler");

  454.     sc->blocked = 1;

  455.     smcf = ngx_http_get_module_main_conf(sc->http_connection->conf_ctx,
  456.                                          ngx_http_spdy_module);

  457.     available = smcf->recv_buffer_size - 2 * NGX_SPDY_STATE_BUFFER_SIZE;

  458.     do {
  459.         p = smcf->recv_buffer;

  460.         ngx_memcpy(p, sc->buffer, NGX_SPDY_STATE_BUFFER_SIZE);
  461.         end = p + sc->buffer_used;

  462.         n = c->recv(c, end, available);

  463.         if (n == NGX_AGAIN) {
  464.             break;
  465.         }

  466.         if (n == 0 && (sc->incomplete || sc->processing)) {
  467.             ngx_log_error(NGX_LOG_INFO, c->log, 0,
  468.                           "client prematurely closed connection");
  469.         }

  470.         if (n == 0 || n == NGX_ERROR) {
  471.             ngx_http_spdy_finalize_connection(sc,
  472.                                               NGX_HTTP_CLIENT_CLOSED_REQUEST);
  473.             return;
  474.         }

  475.         end += n;

  476.         sc->buffer_used = 0;
  477.         sc->incomplete = 0;

  478.         do {
  479.             p = sc->handler(sc, p, end);

  480.             if (p == NULL) {
  481.                 return;
  482.             }

  483.         } while (p != end);

  484.     } while (rev->ready);

  485.     if (ngx_handle_read_event(rev, 0) != NGX_OK) {
  486.         ngx_http_spdy_finalize_connection(sc, NGX_HTTP_INTERNAL_SERVER_ERROR);
  487.         return;
  488.     }

  489.     if (sc->last_out && ngx_http_spdy_send_output_queue(sc) == NGX_ERROR) {
  490.         ngx_http_spdy_finalize_connection(sc, NGX_HTTP_CLIENT_CLOSED_REQUEST);
  491.         return;
  492.     }

  493.     sc->blocked = 0;

  494.     if (sc->processing) {
  495.         if (rev->timer_set) {
  496.             ngx_del_timer(rev);
  497.         }
  498.         return;
  499.     }

  500.     ngx_http_spdy_handle_connection(sc);
  501. }


  502. static void
  503. ngx_http_spdy_write_handler(ngx_event_t *wev)
  504. {
  505.     ngx_int_t                    rc;
  506.     ngx_queue_t                 *q;
  507.     ngx_connection_t            *c;
  508.     ngx_http_spdy_stream_t      *stream;
  509.     ngx_http_spdy_connection_t  *sc;

  510.     c = wev->data;
  511.     sc = c->data;

  512.     if (wev->timedout) {
  513.         ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0,
  514.                        "spdy write event timed out");
  515.         ngx_http_spdy_finalize_connection(sc, NGX_HTTP_CLIENT_CLOSED_REQUEST);
  516.         return;
  517.     }

  518.     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "spdy write handler");

  519.     sc->blocked = 1;

  520.     rc = ngx_http_spdy_send_output_queue(sc);

  521.     if (rc == NGX_ERROR) {
  522.         ngx_http_spdy_finalize_connection(sc, NGX_HTTP_CLIENT_CLOSED_REQUEST);
  523.         return;
  524.     }

  525.     while (!ngx_queue_empty(&sc->posted)) {
  526.         q = ngx_queue_head(&sc->posted);

  527.         ngx_queue_remove(q);

  528.         stream = ngx_queue_data(q, ngx_http_spdy_stream_t, queue);

  529.         stream->handled = 0;

  530.         ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0,
  531.                        "run spdy stream %ui", stream->id);

  532.         wev = stream->request->connection->write;
  533.         wev->handler(wev);
  534.     }

  535.     sc->blocked = 0;

  536.     if (rc == NGX_AGAIN) {
  537.         return;
  538.     }

  539.     ngx_http_spdy_handle_connection(sc);
  540. }


  541. ngx_int_t
  542. ngx_http_spdy_send_output_queue(ngx_http_spdy_connection_t *sc)
  543. {
  544.     ngx_chain_t                *cl;
  545.     ngx_event_t                *wev;
  546.     ngx_connection_t           *c;
  547.     ngx_http_core_loc_conf_t   *clcf;
  548.     ngx_http_spdy_out_frame_t  *out, *frame, *fn;

  549.     c = sc->connection;

  550.     if (c->error) {
  551.         return NGX_ERROR;
  552.     }

  553.     wev = c->write;

  554.     if (!wev->ready) {
  555.         return NGX_OK;
  556.     }

  557.     cl = NULL;
  558.     out = NULL;

  559.     for (frame = sc->last_out; frame; frame = fn) {
  560.         frame->last->next = cl;
  561.         cl = frame->first;

  562.         fn = frame->next;
  563.         frame->next = out;
  564.         out = frame;

  565.         ngx_log_debug5(NGX_LOG_DEBUG_HTTP, c->log, 0,
  566.                        "spdy frame out: %p sid:%ui prio:%ui bl:%d len:%uz",
  567.                        out, out->stream ? out->stream->id : 0, out->priority,
  568.                        out->blocked, out->length);
  569.     }

  570.     cl = c->send_chain(c, cl, 0);

  571.     if (cl == NGX_CHAIN_ERROR) {
  572.         c->error = 1;

  573.         if (!sc->blocked) {
  574.             ngx_post_event(wev, &ngx_posted_events);
  575.         }

  576.         return NGX_ERROR;
  577.     }

  578.     clcf = ngx_http_get_module_loc_conf(sc->http_connection->conf_ctx,
  579.                                         ngx_http_core_module);

  580.     if (ngx_handle_write_event(wev, clcf->send_lowat) != NGX_OK) {
  581.         return NGX_ERROR; /* FIXME */
  582.     }

  583.     if (cl) {
  584.         ngx_add_timer(wev, clcf->send_timeout);

  585.     } else {
  586.         if (wev->timer_set) {
  587.             ngx_del_timer(wev);
  588.         }
  589.     }

  590.     for ( /* void */ ; out; out = fn) {
  591.         fn = out->next;

  592.         if (out->handler(sc, out) != NGX_OK) {
  593.             out->blocked = 1;
  594.             out->priority = NGX_SPDY_HIGHEST_PRIORITY;
  595.             break;
  596.         }

  597.         ngx_log_debug4(NGX_LOG_DEBUG_HTTP, c->log, 0,
  598.                        "spdy frame sent: %p sid:%ui bl:%d len:%uz",
  599.                        out, out->stream ? out->stream->id : 0,
  600.                        out->blocked, out->length);
  601.     }

  602.     frame = NULL;

  603.     for ( /* void */ ; out; out = fn) {
  604.         fn = out->next;
  605.         out->next = frame;
  606.         frame = out;
  607.     }

  608.     sc->last_out = frame;

  609.     return NGX_OK;
  610. }


  611. static void
  612. ngx_http_spdy_handle_connection(ngx_http_spdy_connection_t *sc)
  613. {
  614.     ngx_connection_t          *c;
  615.     ngx_http_spdy_srv_conf_t  *sscf;

  616.     if (sc->last_out || sc->processing) {
  617.         return;
  618.     }

  619.     c = sc->connection;

  620.     if (c->error) {
  621.         ngx_http_close_connection(c);
  622.         return;
  623.     }

  624.     if (c->buffered) {
  625.         return;
  626.     }

  627.     sscf = ngx_http_get_module_srv_conf(sc->http_connection->conf_ctx,
  628.                                         ngx_http_spdy_module);
  629.     if (sc->incomplete) {
  630.         ngx_add_timer(c->read, sscf->recv_timeout);
  631.         return;
  632.     }

  633.     if (ngx_terminate || ngx_exiting) {
  634.         ngx_http_close_connection(c);
  635.         return;
  636.     }

  637.     ngx_destroy_pool(sc->pool);

  638.     sc->pool = NULL;
  639.     sc->free_ctl_frames = NULL;
  640.     sc->free_fake_connections = NULL;

  641. #if (NGX_HTTP_SSL)
  642.     if (c->ssl) {
  643.         ngx_ssl_free_buffer(c);
  644.     }
  645. #endif

  646.     c->destroyed = 1;
  647.     c->idle = 1;
  648.     ngx_reusable_connection(c, 1);

  649.     c->write->handler = ngx_http_empty_handler;
  650.     c->read->handler = ngx_http_spdy_keepalive_handler;

  651.     if (c->write->timer_set) {
  652.         ngx_del_timer(c->write);
  653.     }

  654.     ngx_add_timer(c->read, sscf->keepalive_timeout);
  655. }


  656. static u_char *
  657. ngx_http_spdy_proxy_protocol(ngx_http_spdy_connection_t *sc, u_char *pos,
  658.     u_char *end)
  659. {
  660.     ngx_log_t  *log;

  661.     log = sc->connection->log;
  662.     log->action = "reading PROXY protocol";

  663.     pos = ngx_proxy_protocol_parse(sc->connection, pos, end);

  664.     log->action = "processing SPDY";

  665.     if (pos == NULL) {
  666.         return ngx_http_spdy_state_protocol_error(sc);
  667.     }

  668.     return ngx_http_spdy_state_complete(sc, pos, end);
  669. }


  670. static u_char *
  671. ngx_http_spdy_state_head(ngx_http_spdy_connection_t *sc, u_char *pos,
  672.     u_char *end)
  673. {
  674.     uint32_t    head, flen;
  675.     ngx_uint_t  type;

  676.     if (end - pos < NGX_SPDY_FRAME_HEADER_SIZE) {
  677.         return ngx_http_spdy_state_save(sc, pos, end,
  678.                                         ngx_http_spdy_state_head);
  679.     }

  680.     head = ngx_spdy_frame_parse_uint32(pos);

  681.     pos += sizeof(uint32_t);

  682.     flen = ngx_spdy_frame_parse_uint32(pos);

  683.     sc->flags = ngx_spdy_frame_flags(flen);
  684.     sc->length = ngx_spdy_frame_length(flen);

  685.     pos += sizeof(uint32_t);

  686.     ngx_log_debug3(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0,
  687.                    "process spdy frame head:%08XD f:%Xd l:%uz",
  688.                    head, sc->flags, sc->length);

  689.     if (ngx_spdy_ctl_frame_check(head)) {
  690.         type = ngx_spdy_ctl_frame_type(head);

  691.         switch (type) {

  692.         case NGX_SPDY_SYN_STREAM:
  693.             return ngx_http_spdy_state_syn_stream(sc, pos, end);

  694.         case NGX_SPDY_SYN_REPLY:
  695.             ngx_log_error(NGX_LOG_INFO, sc->connection->log, 0,
  696.                           "client sent unexpected SYN_REPLY frame");
  697.             return ngx_http_spdy_state_protocol_error(sc);

  698.         case NGX_SPDY_RST_STREAM:
  699.             return ngx_http_spdy_state_rst_stream(sc, pos, end);

  700.         case NGX_SPDY_SETTINGS:
  701.             return ngx_http_spdy_state_settings(sc, pos, end);

  702.         case NGX_SPDY_PING:
  703.             return ngx_http_spdy_state_ping(sc, pos, end);

  704.         case NGX_SPDY_GOAWAY:
  705.             return ngx_http_spdy_state_skip(sc, pos, end); /* TODO */

  706.         case NGX_SPDY_HEADERS:
  707.             ngx_log_error(NGX_LOG_INFO, sc->connection->log, 0,
  708.                           "client sent unexpected HEADERS frame");
  709.             return ngx_http_spdy_state_protocol_error(sc);

  710.         case NGX_SPDY_WINDOW_UPDATE:
  711.             return ngx_http_spdy_state_window_update(sc, pos, end);

  712.         default:
  713.             ngx_log_debug1(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0,
  714.                            "spdy control frame with unknown type %ui", type);
  715.             return ngx_http_spdy_state_skip(sc, pos, end);
  716.         }
  717.     }

  718.     if (ngx_spdy_data_frame_check(head)) {
  719.         sc->stream = ngx_http_spdy_get_stream_by_id(sc, head);
  720.         return ngx_http_spdy_state_data(sc, pos, end);
  721.     }

  722.     ngx_log_error(NGX_LOG_INFO, sc->connection->log, 0,
  723.                   "client sent invalid frame");

  724.     return ngx_http_spdy_state_protocol_error(sc);
  725. }


  726. static u_char *
  727. ngx_http_spdy_state_syn_stream(ngx_http_spdy_connection_t *sc, u_char *pos,
  728.     u_char *end)
  729. {
  730.     ngx_uint_t                 sid, prio;
  731.     ngx_http_spdy_stream_t    *stream;
  732.     ngx_http_spdy_srv_conf_t  *sscf;

  733.     if (end - pos < NGX_SPDY_SYN_STREAM_SIZE) {
  734.         return ngx_http_spdy_state_save(sc, pos, end,
  735.                                         ngx_http_spdy_state_syn_stream);
  736.     }

  737.     if (sc->length <= NGX_SPDY_SYN_STREAM_SIZE) {
  738.         ngx_log_error(NGX_LOG_INFO, sc->connection->log, 0,
  739.                       "client sent SYN_STREAM frame with incorrect length %uz",
  740.                       sc->length);

  741.         return ngx_http_spdy_state_protocol_error(sc);
  742.     }

  743.     sc->length -= NGX_SPDY_SYN_STREAM_SIZE;

  744.     sid = ngx_spdy_frame_parse_sid(pos);
  745.     prio = pos[8] >> 5;

  746.     pos += NGX_SPDY_SYN_STREAM_SIZE;

  747.     ngx_log_debug2(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0,
  748.                    "spdy SYN_STREAM frame sid:%ui prio:%ui", sid, prio);

  749.     if (sid % 2 == 0 || sid <= sc->last_sid) {
  750.         ngx_log_error(NGX_LOG_INFO, sc->connection->log, 0,
  751.                       "client sent SYN_STREAM frame "
  752.                       "with invalid Stream-ID %ui", sid);

  753.         stream = ngx_http_spdy_get_stream_by_id(sc, sid);

  754.         if (stream) {
  755.             if (ngx_http_spdy_terminate_stream(sc, stream,
  756.                                                NGX_SPDY_PROTOCOL_ERROR)
  757.                 != NGX_OK)
  758.             {
  759.                 return ngx_http_spdy_state_internal_error(sc);
  760.             }
  761.         }

  762.         return ngx_http_spdy_state_protocol_error(sc);
  763.     }

  764.     sc->last_sid = sid;

  765.     sscf = ngx_http_get_module_srv_conf(sc->http_connection->conf_ctx,
  766.                                         ngx_http_spdy_module);

  767.     if (sc->processing >= sscf->concurrent_streams) {

  768.         ngx_log_error(NGX_LOG_INFO, sc->connection->log, 0,
  769.                       "concurrent streams exceeded %ui", sc->processing);

  770.         if (ngx_http_spdy_send_rst_stream(sc, sid, NGX_SPDY_REFUSED_STREAM,
  771.                                           prio)
  772.             != NGX_OK)
  773.         {
  774.             return ngx_http_spdy_state_internal_error(sc);
  775.         }

  776.         return ngx_http_spdy_state_headers_skip(sc, pos, end);
  777.     }

  778.     stream = ngx_http_spdy_create_stream(sc, sid, prio);
  779.     if (stream == NULL) {
  780.         return ngx_http_spdy_state_internal_error(sc);
  781.     }

  782.     stream->in_closed = (sc->flags & NGX_SPDY_FLAG_FIN) ? 1 : 0;

  783.     stream->request->request_length = NGX_SPDY_FRAME_HEADER_SIZE
  784.                                       + NGX_SPDY_SYN_STREAM_SIZE
  785.                                       + sc->length;

  786.     sc->stream = stream;

  787.     return ngx_http_spdy_state_headers(sc, pos, end);
  788. }


  789. static u_char *
  790. ngx_http_spdy_state_headers(ngx_http_spdy_connection_t *sc, u_char *pos,
  791.     u_char *end)
  792. {
  793.     int                  z;
  794.     size_t               size;
  795.     ngx_buf_t           *buf;
  796.     ngx_int_t            rc;
  797.     ngx_http_request_t  *r;

  798.     size = end - pos;

  799.     if (size == 0) {
  800.         return ngx_http_spdy_state_save(sc, pos, end,
  801.                                         ngx_http_spdy_state_headers);
  802.     }

  803.     if (size > sc->length) {
  804.         size = sc->length;
  805.     }

  806.     r = sc->stream->request;

  807.     ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  808.                    "process spdy header block %uz of %uz", size, sc->length);

  809.     buf = r->header_in;

  810.     sc->zstream_in.next_in = pos;
  811.     sc->zstream_in.avail_in = size;
  812.     sc->zstream_in.next_out = buf->last;

  813.     /* one byte is reserved for null-termination of the last header value */
  814.     sc->zstream_in.avail_out = buf->end - buf->last - 1;

  815.     z = inflate(&sc->zstream_in, Z_NO_FLUSH);

  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.             if (z == Z_DATA_ERROR) {
  821.                 ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
  822.                               "client sent SYN_STREAM frame with header "
  823.                               "block encoded using wrong dictionary: %ul",
  824.                               (u_long) sc->zstream_in.adler);

  825.                 return ngx_http_spdy_state_protocol_error(sc);
  826.             }

  827.             ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  828.                           "inflateSetDictionary() failed: %d", z);

  829.             return ngx_http_spdy_state_internal_error(sc);
  830.         }

  831.         ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  832.                        "spdy inflateSetDictionary(): %d", z);

  833.         z = sc->zstream_in.avail_in ? inflate(&sc->zstream_in, Z_NO_FLUSH)
  834.                                     : Z_OK;
  835.     }

  836.     ngx_log_debug5(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  837.                    "spdy inflate out: ni:%p no:%p ai:%ud ao:%ud rc:%d",
  838.                    sc->zstream_in.next_in, sc->zstream_in.next_out,
  839.                    sc->zstream_in.avail_in, sc->zstream_in.avail_out,
  840.                    z);

  841.     if (z != Z_OK) {
  842.         return ngx_http_spdy_state_inflate_error(sc, z);
  843.     }

  844.     sc->length -= sc->zstream_in.next_in - pos;
  845.     pos = sc->zstream_in.next_in;

  846.     buf->last = sc->zstream_in.next_out;

  847.     if (r->headers_in.headers.part.elts == NULL) {

  848.         if (buf->last - buf->pos < NGX_SPDY_NV_NUM_SIZE) {

  849.             if (sc->length == 0) {
  850.                 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  851.                                "premature end of spdy header block");

  852.                 return ngx_http_spdy_state_headers_error(sc, pos, end);
  853.             }

  854.             return ngx_http_spdy_state_save(sc, pos, end,
  855.                                             ngx_http_spdy_state_headers);
  856.         }

  857.         sc->entries = ngx_spdy_frame_parse_uint32(buf->pos);

  858.         buf->pos += NGX_SPDY_NV_NUM_SIZE;

  859.         ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  860.                        "spdy header block has %ui entries",
  861.                        sc->entries);

  862.         if (ngx_list_init(&r->headers_in.headers, r->pool, 20,
  863.                           sizeof(ngx_table_elt_t))
  864.             != NGX_OK)
  865.         {
  866.             ngx_http_spdy_close_stream(sc->stream,
  867.                                        NGX_HTTP_INTERNAL_SERVER_ERROR);
  868.             return ngx_http_spdy_state_headers_skip(sc, pos, end);
  869.         }

  870.         if (ngx_array_init(&r->headers_in.cookies, r->pool, 2,
  871.                            sizeof(ngx_table_elt_t *))
  872.             != NGX_OK)
  873.         {
  874.             ngx_http_spdy_close_stream(sc->stream,
  875.                                        NGX_HTTP_INTERNAL_SERVER_ERROR);
  876.             return ngx_http_spdy_state_headers_skip(sc, pos, end);
  877.         }
  878.     }

  879.     while (sc->entries) {

  880.         rc = ngx_http_spdy_parse_header(r);

  881.         switch (rc) {

  882.         case NGX_DONE:
  883.             sc->entries--;

  884.         case NGX_OK:
  885.             break;

  886.         case NGX_AGAIN:

  887.             if (sc->zstream_in.avail_in) {

  888.                 rc = ngx_http_spdy_alloc_large_header_buffer(r);

  889.                 if (rc == NGX_DECLINED) {
  890.                     ngx_http_finalize_request(r,
  891.                                             NGX_HTTP_REQUEST_HEADER_TOO_LARGE);
  892.                     return ngx_http_spdy_state_headers_skip(sc, pos, end);
  893.                 }

  894.                 if (rc != NGX_OK) {
  895.                     ngx_http_spdy_close_stream(sc->stream,
  896.                                                NGX_HTTP_INTERNAL_SERVER_ERROR);
  897.                     return ngx_http_spdy_state_headers_skip(sc, pos, end);
  898.                 }

  899.                 /* null-terminate the last processed header name or value */
  900.                 *buf->pos = '\0';

  901.                 buf = r->header_in;

  902.                 sc->zstream_in.next_out = buf->last;

  903.                 /* one byte is reserved for null-termination */
  904.                 sc->zstream_in.avail_out = buf->end - buf->last - 1;

  905.                 z = inflate(&sc->zstream_in, Z_NO_FLUSH);

  906.                 ngx_log_debug5(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  907.                            "spdy inflate out: ni:%p no:%p ai:%ud ao:%ud rc:%d",
  908.                            sc->zstream_in.next_in, sc->zstream_in.next_out,
  909.                            sc->zstream_in.avail_in, sc->zstream_in.avail_out,
  910.                            z);

  911.                 if (z != Z_OK) {
  912.                     return ngx_http_spdy_state_inflate_error(sc, z);
  913.                 }

  914.                 sc->length -= sc->zstream_in.next_in - pos;
  915.                 pos = sc->zstream_in.next_in;

  916.                 buf->last = sc->zstream_in.next_out;

  917.                 continue;
  918.             }

  919.             if (sc->length == 0) {
  920.                 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  921.                                "premature end of spdy header block");

  922.                 return ngx_http_spdy_state_headers_error(sc, pos, end);
  923.             }

  924.             return ngx_http_spdy_state_save(sc, pos, end,
  925.                                             ngx_http_spdy_state_headers);

  926.         case NGX_HTTP_PARSE_INVALID_HEADER:
  927.             ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST);
  928.             return ngx_http_spdy_state_headers_skip(sc, pos, end);

  929.         default: /* NGX_ERROR */
  930.             return ngx_http_spdy_state_headers_error(sc, pos, end);
  931.         }

  932.         /* a header line has been parsed successfully */

  933.         rc = ngx_http_spdy_handle_request_header(r);

  934.         if (rc != NGX_OK) {
  935.             if (rc == NGX_HTTP_PARSE_INVALID_HEADER) {
  936.                 ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST);
  937.                 return ngx_http_spdy_state_headers_skip(sc, pos, end);
  938.             }

  939.             if (rc != NGX_ABORT) {
  940.                 ngx_http_spdy_close_stream(sc->stream,
  941.                                            NGX_HTTP_INTERNAL_SERVER_ERROR);
  942.             }

  943.             return ngx_http_spdy_state_headers_skip(sc, pos, end);
  944.         }
  945.     }

  946.     if (buf->pos != buf->last || sc->zstream_in.avail_in) {
  947.         ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  948.                        "incorrect number of spdy header block entries");

  949.         return ngx_http_spdy_state_headers_error(sc, pos, end);
  950.     }

  951.     if (sc->length) {
  952.         return ngx_http_spdy_state_save(sc, pos, end,
  953.                                         ngx_http_spdy_state_headers);
  954.     }

  955.     /* null-terminate the last header value */
  956.     *buf->pos = '\0';

  957.     ngx_http_spdy_run_request(r);

  958.     return ngx_http_spdy_state_complete(sc, pos, end);
  959. }


  960. static u_char *
  961. ngx_http_spdy_state_headers_skip(ngx_http_spdy_connection_t *sc, u_char *pos,
  962.     u_char *end)
  963. {
  964.     int     n;
  965.     size_t  size;
  966.     u_char  buffer[NGX_SPDY_SKIP_HEADERS_BUFFER_SIZE];

  967.     if (sc->length == 0) {
  968.         return ngx_http_spdy_state_complete(sc, pos, end);
  969.     }

  970.     size = end - pos;

  971.     if (size == 0) {
  972.         return ngx_http_spdy_state_save(sc, pos, end,
  973.                                         ngx_http_spdy_state_headers_skip);
  974.     }

  975.     ngx_log_debug2(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0,
  976.                    "spdy header block skip %uz of %uz", size, sc->length);

  977.     sc->zstream_in.next_in = pos;
  978.     sc->zstream_in.avail_in = (size < sc->length) ? size : sc->length;

  979.     while (sc->zstream_in.avail_in) {
  980.         sc->zstream_in.next_out = buffer;
  981.         sc->zstream_in.avail_out = NGX_SPDY_SKIP_HEADERS_BUFFER_SIZE;

  982.         n = inflate(&sc->zstream_in, Z_NO_FLUSH);

  983.         ngx_log_debug5(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0,
  984.                        "spdy inflate out: ni:%p no:%p ai:%ud ao:%ud rc:%d",
  985.                        sc->zstream_in.next_in, sc->zstream_in.next_out,
  986.                        sc->zstream_in.avail_in, sc->zstream_in.avail_out,
  987.                        n);

  988.         if (n != Z_OK) {
  989.             return ngx_http_spdy_state_inflate_error(sc, n);
  990.         }
  991.     }

  992.     pos = sc->zstream_in.next_in;

  993.     if (size < sc->length) {
  994.         sc->length -= size;
  995.         return ngx_http_spdy_state_save(sc, pos, end,
  996.                                         ngx_http_spdy_state_headers_skip);
  997.     }

  998.     return ngx_http_spdy_state_complete(sc, pos, end);
  999. }


  1000. static u_char *
  1001. ngx_http_spdy_state_headers_error(ngx_http_spdy_connection_t *sc, u_char *pos,
  1002.     u_char *end)
  1003. {
  1004.     ngx_http_spdy_stream_t  *stream;

  1005.     stream = sc->stream;

  1006.     ngx_log_error(NGX_LOG_INFO, sc->connection->log, 0,
  1007.                   "client sent SYN_STREAM frame for stream %ui "
  1008.                   "with invalid header block", stream->id);

  1009.     if (ngx_http_spdy_send_rst_stream(sc, stream->id, NGX_SPDY_PROTOCOL_ERROR,
  1010.                                       stream->priority)
  1011.         != NGX_OK)
  1012.     {
  1013.         return ngx_http_spdy_state_internal_error(sc);
  1014.     }

  1015.     stream->out_closed = 1;

  1016.     ngx_http_spdy_close_stream(stream, NGX_HTTP_BAD_REQUEST);

  1017.     return ngx_http_spdy_state_headers_skip(sc, pos, end);
  1018. }


  1019. static u_char *
  1020. ngx_http_spdy_state_window_update(ngx_http_spdy_connection_t *sc, u_char *pos,
  1021.     u_char *end)
  1022. {
  1023.     size_t                   delta;
  1024.     ngx_uint_t               sid;
  1025.     ngx_event_t             *wev;
  1026.     ngx_queue_t             *q;
  1027.     ngx_http_spdy_stream_t  *stream;

  1028.     if (end - pos < NGX_SPDY_WINDOW_UPDATE_SIZE) {
  1029.         return ngx_http_spdy_state_save(sc, pos, end,
  1030.                                         ngx_http_spdy_state_window_update);
  1031.     }

  1032.     if (sc->length != NGX_SPDY_WINDOW_UPDATE_SIZE) {
  1033.         ngx_log_error(NGX_LOG_INFO, sc->connection->log, 0,
  1034.                       "client sent WINDOW_UPDATE frame "
  1035.                       "with incorrect length %uz", sc->length);

  1036.         return ngx_http_spdy_state_protocol_error(sc);
  1037.     }

  1038.     sid = ngx_spdy_frame_parse_sid(pos);

  1039.     pos += NGX_SPDY_SID_SIZE;

  1040.     delta = ngx_spdy_frame_parse_delta(pos);

  1041.     pos += NGX_SPDY_DELTA_SIZE;

  1042.     ngx_log_debug2(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0,
  1043.                    "spdy WINDOW_UPDATE sid:%ui delta:%ui", sid, delta);

  1044.     if (sid) {
  1045.         stream = ngx_http_spdy_get_stream_by_id(sc, sid);

  1046.         if (stream == NULL) {
  1047.             ngx_log_debug0(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0,
  1048.                            "unknown spdy stream");

  1049.             return ngx_http_spdy_state_complete(sc, pos, end);
  1050.         }

  1051.         if (stream->send_window > (ssize_t) (NGX_SPDY_MAX_WINDOW - delta)) {

  1052.             ngx_log_error(NGX_LOG_INFO, sc->connection->log, 0,
  1053.                           "client violated flow control for stream %ui: "
  1054.                           "received WINDOW_UPDATE frame with delta %uz "
  1055.                           "not allowed for window %z",
  1056.                           sid, delta, stream->send_window);

  1057.             if (ngx_http_spdy_terminate_stream(sc, stream,
  1058.                                                NGX_SPDY_FLOW_CONTROL_ERROR)
  1059.                 == NGX_ERROR)
  1060.             {
  1061.                 return ngx_http_spdy_state_internal_error(sc);
  1062.             }

  1063.             return ngx_http_spdy_state_complete(sc, pos, end);
  1064.         }

  1065.         stream->send_window += delta;

  1066.         if (stream->exhausted) {
  1067.             stream->exhausted = 0;

  1068.             wev = stream->request->connection->write;

  1069.             if (!wev->timer_set) {
  1070.                 wev->delayed = 0;
  1071.                 wev->handler(wev);
  1072.             }
  1073.         }

  1074.     } else {
  1075.         sc->send_window += delta;

  1076.         if (sc->send_window > NGX_SPDY_MAX_WINDOW) {
  1077.             ngx_log_error(NGX_LOG_INFO, sc->connection->log, 0,
  1078.                           "client violated connection flow control: "
  1079.                           "received WINDOW_UPDATE frame with delta %uz "
  1080.                           "not allowed for window %uz",
  1081.                           delta, sc->send_window);

  1082.             return ngx_http_spdy_state_protocol_error(sc);
  1083.         }

  1084.         while (!ngx_queue_empty(&sc->waiting)) {
  1085.             q = ngx_queue_head(&sc->waiting);

  1086.             ngx_queue_remove(q);

  1087.             stream = ngx_queue_data(q, ngx_http_spdy_stream_t, queue);

  1088.             stream->handled = 0;

  1089.             wev = stream->request->connection->write;

  1090.             if (!wev->timer_set) {
  1091.                 wev->delayed = 0;
  1092.                 wev->handler(wev);

  1093.                 if (sc->send_window == 0) {
  1094.                     break;
  1095.                 }
  1096.             }
  1097.         }
  1098.     }

  1099.     return ngx_http_spdy_state_complete(sc, pos, end);
  1100. }


  1101. static u_char *
  1102. ngx_http_spdy_state_data(ngx_http_spdy_connection_t *sc, u_char *pos,
  1103.     u_char *end)
  1104. {
  1105.     ngx_http_spdy_stream_t  *stream;

  1106.     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0,
  1107.                    "spdy DATA frame");

  1108.     if (sc->length > sc->recv_window) {
  1109.         ngx_log_error(NGX_LOG_INFO, sc->connection->log, 0,
  1110.                       "client violated connection flow control: "
  1111.                       "received DATA frame length %uz, available window %uz",
  1112.                       sc->length, sc->recv_window);

  1113.         return ngx_http_spdy_state_protocol_error(sc);
  1114.     }

  1115.     sc->recv_window -= sc->length;

  1116.     if (sc->recv_window < NGX_SPDY_MAX_WINDOW / 4) {

  1117.         if (ngx_http_spdy_send_window_update(sc, 0,
  1118.                                              NGX_SPDY_MAX_WINDOW
  1119.                                              - sc->recv_window)
  1120.             == NGX_ERROR)
  1121.         {
  1122.             return ngx_http_spdy_state_internal_error(sc);
  1123.         }

  1124.         sc->recv_window = NGX_SPDY_MAX_WINDOW;
  1125.     }

  1126.     stream = sc->stream;

  1127.     if (stream == NULL) {
  1128.         ngx_log_debug0(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0,
  1129.                        "unknown spdy stream");

  1130.         return ngx_http_spdy_state_skip(sc, pos, end);
  1131.     }

  1132.     if (sc->length > stream->recv_window) {
  1133.         ngx_log_error(NGX_LOG_INFO, sc->connection->log, 0,
  1134.                       "client violated flow control for stream %ui: "
  1135.                       "received DATA frame length %uz, available window %uz",
  1136.                       stream->id, sc->length, stream->recv_window);

  1137.         if (ngx_http_spdy_terminate_stream(sc, stream,
  1138.                                            NGX_SPDY_FLOW_CONTROL_ERROR)
  1139.             == NGX_ERROR)
  1140.         {
  1141.             return ngx_http_spdy_state_internal_error(sc);
  1142.         }

  1143.         return ngx_http_spdy_state_skip(sc, pos, end);
  1144.     }

  1145.     stream->recv_window -= sc->length;

  1146.     if (stream->recv_window < NGX_SPDY_STREAM_WINDOW / 4) {

  1147.         if (ngx_http_spdy_send_window_update(sc, stream->id,
  1148.                                              NGX_SPDY_STREAM_WINDOW
  1149.                                              - stream->recv_window)
  1150.             == NGX_ERROR)
  1151.         {
  1152.             return ngx_http_spdy_state_internal_error(sc);
  1153.         }

  1154.         stream->recv_window = NGX_SPDY_STREAM_WINDOW;
  1155.     }

  1156.     if (stream->in_closed) {
  1157.         ngx_log_error(NGX_LOG_INFO, sc->connection->log, 0,
  1158.                       "client sent DATA frame for half-closed stream %ui",
  1159.                       stream->id);

  1160.         if (ngx_http_spdy_terminate_stream(sc, stream,
  1161.                                            NGX_SPDY_STREAM_ALREADY_CLOSED)
  1162.             == NGX_ERROR)
  1163.         {
  1164.             return ngx_http_spdy_state_internal_error(sc);
  1165.         }

  1166.         return ngx_http_spdy_state_skip(sc, pos, end);
  1167.     }

  1168.     return ngx_http_spdy_state_read_data(sc, pos, end);
  1169. }


  1170. static u_char *
  1171. ngx_http_spdy_state_read_data(ngx_http_spdy_connection_t *sc, u_char *pos,
  1172.     u_char *end)
  1173. {
  1174.     size_t                     size;
  1175.     ssize_t                    n;
  1176.     ngx_buf_t                 *buf;
  1177.     ngx_int_t                  rc;
  1178.     ngx_temp_file_t           *tf;
  1179.     ngx_http_request_t        *r;
  1180.     ngx_http_spdy_stream_t    *stream;
  1181.     ngx_http_request_body_t   *rb;
  1182.     ngx_http_core_loc_conf_t  *clcf;

  1183.     stream = sc->stream;

  1184.     if (stream == NULL) {
  1185.         return ngx_http_spdy_state_skip(sc, pos, end);
  1186.     }

  1187.     if (stream->skip_data) {

  1188.         if (sc->flags & NGX_SPDY_FLAG_FIN) {
  1189.             stream->in_closed = 1;
  1190.         }

  1191.         ngx_log_debug1(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0,
  1192.                        "skipping spdy DATA frame, reason: %d",
  1193.                        stream->skip_data);

  1194.         return ngx_http_spdy_state_skip(sc, pos, end);
  1195.     }

  1196.     size = end - pos;

  1197.     if (size > sc->length) {
  1198.         size = sc->length;
  1199.     }

  1200.     r = stream->request;

  1201.     if (r->request_body == NULL
  1202.         && ngx_http_spdy_init_request_body(r) != NGX_OK)
  1203.     {
  1204.         stream->skip_data = NGX_SPDY_DATA_INTERNAL_ERROR;
  1205.         return ngx_http_spdy_state_skip(sc, pos, end);
  1206.     }

  1207.     rb = r->request_body;
  1208.     tf = rb->temp_file;
  1209.     buf = rb->buf;

  1210.     if (size) {
  1211.         rb->rest += size;

  1212.         if (r->headers_in.content_length_n != -1
  1213.             && r->headers_in.content_length_n < rb->rest)
  1214.         {
  1215.             ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
  1216.                           "client intended to send body data "
  1217.                           "larger than declared");

  1218.             stream->skip_data = NGX_SPDY_DATA_ERROR;
  1219.             goto error;

  1220.         } else {
  1221.             clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);

  1222.             if (clcf->client_max_body_size
  1223.                 && clcf->client_max_body_size < rb->rest)
  1224.             {
  1225.                 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  1226.                               "client intended to send "
  1227.                               "too large chunked body: %O bytes", rb->rest);

  1228.                 stream->skip_data = NGX_SPDY_DATA_ERROR;
  1229.                 goto error;
  1230.             }
  1231.         }

  1232.         sc->length -= size;

  1233.         if (tf) {
  1234.             buf->start = pos;
  1235.             buf->pos = pos;

  1236.             pos += size;

  1237.             buf->end = pos;
  1238.             buf->last = pos;

  1239.             n = ngx_write_chain_to_temp_file(tf, rb->bufs);

  1240.             /* TODO: n == 0 or not complete and level event */

  1241.             if (n == NGX_ERROR) {
  1242.                 stream->skip_data = NGX_SPDY_DATA_INTERNAL_ERROR;
  1243.                 goto error;
  1244.             }

  1245.             tf->offset += n;

  1246.         } else {
  1247.             buf->last = ngx_cpymem(buf->last, pos, size);
  1248.             pos += size;
  1249.         }

  1250.         r->request_length += size;
  1251.     }

  1252.     if (sc->length) {
  1253.         return ngx_http_spdy_state_save(sc, pos, end,
  1254.                                         ngx_http_spdy_state_read_data);
  1255.     }

  1256.     if (sc->flags & NGX_SPDY_FLAG_FIN) {

  1257.         stream->in_closed = 1;

  1258.         if (r->headers_in.content_length_n < 0) {
  1259.             r->headers_in.content_length_n = rb->rest;

  1260.         } else if (r->headers_in.content_length_n != rb->rest) {
  1261.             ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
  1262.                           "client prematurely closed stream: "
  1263.                           "only %O out of %O bytes of request body received",
  1264.                           rb->rest, r->headers_in.content_length_n);

  1265.             stream->skip_data = NGX_SPDY_DATA_ERROR;
  1266.             goto error;
  1267.         }

  1268.         if (tf) {
  1269.             ngx_memzero(buf, sizeof(ngx_buf_t));

  1270.             buf->in_file = 1;
  1271.             buf->file_last = tf->file.offset;
  1272.             buf->file = &tf->file;

  1273.             rb->buf = NULL;
  1274.         }

  1275.         if (rb->post_handler) {
  1276.             r->read_event_handler = ngx_http_block_reading;
  1277.             rb->post_handler(r);
  1278.         }
  1279.     }

  1280.     return ngx_http_spdy_state_complete(sc, pos, end);

  1281. error:

  1282.     if (rb->post_handler) {

  1283.         if (stream->skip_data == NGX_SPDY_DATA_ERROR) {
  1284.             rc = (r->headers_in.content_length_n == -1)
  1285.                  ? NGX_HTTP_REQUEST_ENTITY_TOO_LARGE
  1286.                  : NGX_HTTP_BAD_REQUEST;

  1287.         } else {
  1288.             rc = NGX_HTTP_INTERNAL_SERVER_ERROR;
  1289.         }

  1290.         ngx_http_finalize_request(r, rc);
  1291.     }

  1292.     return ngx_http_spdy_state_skip(sc, pos, end);
  1293. }


  1294. static u_char *
  1295. ngx_http_spdy_state_rst_stream(ngx_http_spdy_connection_t *sc, u_char *pos,
  1296.     u_char *end)
  1297. {
  1298.     ngx_uint_t               sid, status;
  1299.     ngx_event_t             *ev;
  1300.     ngx_connection_t        *fc;
  1301.     ngx_http_spdy_stream_t  *stream;

  1302.     if (end - pos < NGX_SPDY_RST_STREAM_SIZE) {
  1303.         return ngx_http_spdy_state_save(sc, pos, end,
  1304.                                         ngx_http_spdy_state_rst_stream);
  1305.     }

  1306.     if (sc->length != NGX_SPDY_RST_STREAM_SIZE) {
  1307.         ngx_log_error(NGX_LOG_INFO, sc->connection->log, 0,
  1308.                       "client sent RST_STREAM frame with incorrect length %uz",
  1309.                       sc->length);

  1310.         return ngx_http_spdy_state_protocol_error(sc);
  1311.     }

  1312.     sid = ngx_spdy_frame_parse_sid(pos);

  1313.     pos += NGX_SPDY_SID_SIZE;

  1314.     status = ngx_spdy_frame_parse_uint32(pos);

  1315.     pos += sizeof(uint32_t);

  1316.     ngx_log_debug2(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0,
  1317.                    "spdy RST_STREAM sid:%ui st:%ui", sid, status);

  1318.     stream = ngx_http_spdy_get_stream_by_id(sc, sid);

  1319.     if (stream == NULL) {
  1320.         ngx_log_debug0(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0,
  1321.                        "unknown spdy stream");

  1322.         return ngx_http_spdy_state_complete(sc, pos, end);
  1323.     }

  1324.     stream->in_closed = 1;
  1325.     stream->out_closed = 1;

  1326.     fc = stream->request->connection;
  1327.     fc->error = 1;

  1328.     switch (status) {

  1329.     case NGX_SPDY_CANCEL:
  1330.         ngx_log_error(NGX_LOG_INFO, fc->log, 0,
  1331.                       "client canceled stream %ui", sid);
  1332.         break;

  1333.     case NGX_SPDY_INTERNAL_ERROR:
  1334.         ngx_log_error(NGX_LOG_INFO, fc->log, 0,
  1335.                       "client terminated stream %ui due to internal error",
  1336.                       sid);
  1337.         break;

  1338.     default:
  1339.         ngx_log_error(NGX_LOG_INFO, fc->log, 0,
  1340.                       "client terminated stream %ui with status %ui",
  1341.                       sid, status);
  1342.         break;
  1343.     }

  1344.     ev = fc->read;
  1345.     ev->handler(ev);

  1346.     return ngx_http_spdy_state_complete(sc, pos, end);
  1347. }


  1348. static u_char *
  1349. ngx_http_spdy_state_ping(ngx_http_spdy_connection_t *sc, u_char *pos,
  1350.     u_char *end)
  1351. {
  1352.     u_char                     *p;
  1353.     ngx_buf_t                  *buf;
  1354.     ngx_http_spdy_out_frame_t  *frame;

  1355.     if (end - pos < NGX_SPDY_PING_SIZE) {
  1356.         return ngx_http_spdy_state_save(sc, pos, end,
  1357.                                         ngx_http_spdy_state_ping);
  1358.     }

  1359.     if (sc->length != NGX_SPDY_PING_SIZE) {
  1360.         ngx_log_error(NGX_LOG_INFO, sc->connection->log, 0,
  1361.                       "client sent PING frame with incorrect length %uz",
  1362.                       sc->length);

  1363.         return ngx_http_spdy_state_protocol_error(sc);
  1364.     }

  1365.     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0,
  1366.                    "spdy PING frame");

  1367.     frame = ngx_http_spdy_get_ctl_frame(sc, NGX_SPDY_PING_SIZE,
  1368.                                         NGX_SPDY_HIGHEST_PRIORITY);
  1369.     if (frame == NULL) {
  1370.         return ngx_http_spdy_state_internal_error(sc);
  1371.     }

  1372.     buf = frame->first->buf;

  1373.     p = buf->pos;

  1374.     p = ngx_spdy_frame_write_head(p, NGX_SPDY_PING);
  1375.     p = ngx_spdy_frame_write_flags_and_len(p, 0, NGX_SPDY_PING_SIZE);

  1376.     p = ngx_cpymem(p, pos, NGX_SPDY_PING_SIZE);

  1377.     buf->last = p;

  1378.     ngx_http_spdy_queue_frame(sc, frame);

  1379.     pos += NGX_SPDY_PING_SIZE;

  1380.     return ngx_http_spdy_state_complete(sc, pos, end);
  1381. }


  1382. static u_char *
  1383. ngx_http_spdy_state_skip(ngx_http_spdy_connection_t *sc, u_char *pos,
  1384.     u_char *end)
  1385. {
  1386.     size_t  size;

  1387.     size = end - pos;

  1388.     ngx_log_debug2(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0,
  1389.                    "spdy frame skip %uz of %uz", size, sc->length);

  1390.     if (size < sc->length) {
  1391.         sc->length -= size;
  1392.         return ngx_http_spdy_state_save(sc, end, end,
  1393.                                         ngx_http_spdy_state_skip);
  1394.     }

  1395.     return ngx_http_spdy_state_complete(sc, pos + sc->length, end);
  1396. }


  1397. static u_char *
  1398. ngx_http_spdy_state_settings(ngx_http_spdy_connection_t *sc, u_char *pos,
  1399.     u_char *end)
  1400. {
  1401.     ngx_uint_t  fid, val;

  1402.     if (sc->entries == 0) {

  1403.         if (end - pos < NGX_SPDY_SETTINGS_NUM_SIZE) {
  1404.             return ngx_http_spdy_state_save(sc, pos, end,
  1405.                                             ngx_http_spdy_state_settings);
  1406.         }

  1407.         sc->entries = ngx_spdy_frame_parse_uint32(pos);

  1408.         pos += NGX_SPDY_SETTINGS_NUM_SIZE;
  1409.         sc->length -= NGX_SPDY_SETTINGS_NUM_SIZE;

  1410.         if (sc->length < sc->entries * NGX_SPDY_SETTINGS_PAIR_SIZE) {
  1411.             ngx_log_error(NGX_LOG_INFO, sc->connection->log, 0,
  1412.                           "client sent SETTINGS frame with incorrect "
  1413.                           "length %uz or number of entries %ui",
  1414.                           sc->length, sc->entries);

  1415.             return ngx_http_spdy_state_protocol_error(sc);
  1416.         }

  1417.         ngx_log_debug1(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0,
  1418.                        "spdy SETTINGS frame has %ui entries", sc->entries);
  1419.     }

  1420.     while (sc->entries) {
  1421.         if (end - pos < NGX_SPDY_SETTINGS_PAIR_SIZE) {
  1422.             return ngx_http_spdy_state_save(sc, pos, end,
  1423.                                             ngx_http_spdy_state_settings);
  1424.         }

  1425.         sc->entries--;
  1426.         sc->length -= NGX_SPDY_SETTINGS_PAIR_SIZE;

  1427.         fid = ngx_spdy_frame_parse_uint32(pos);

  1428.         pos += NGX_SPDY_SETTINGS_FID_SIZE;

  1429.         val = ngx_spdy_frame_parse_uint32(pos);

  1430.         pos += NGX_SPDY_SETTINGS_VAL_SIZE;

  1431.         ngx_log_debug3(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0,
  1432.                        "spdy SETTINGS entry fl:%ui id:%ui val:%ui",
  1433.                        ngx_spdy_frame_flags(fid), ngx_spdy_frame_id(fid), val);

  1434.         if (ngx_spdy_frame_flags(fid) == NGX_SPDY_SETTINGS_FLAG_PERSISTED) {
  1435.             continue;
  1436.         }

  1437.         switch (ngx_spdy_frame_id(fid)) {

  1438.         case NGX_SPDY_SETTINGS_INIT_WINDOW:

  1439.             if (val > NGX_SPDY_MAX_WINDOW) {
  1440.                 ngx_log_error(NGX_LOG_INFO, sc->connection->log, 0,
  1441.                               "client sent SETTINGS frame with "
  1442.                               "incorrect INIT_WINDOW value: %ui", val);

  1443.                 return ngx_http_spdy_state_protocol_error(sc);
  1444.             }

  1445.             if (ngx_http_spdy_adjust_windows(sc, val - sc->init_window)
  1446.                 != NGX_OK)
  1447.             {
  1448.                 return ngx_http_spdy_state_internal_error(sc);
  1449.             }

  1450.             sc->init_window = val;

  1451.             continue;
  1452.         }
  1453.     }

  1454.     return ngx_http_spdy_state_complete(sc, pos, end);
  1455. }


  1456. static u_char *
  1457. ngx_http_spdy_state_complete(ngx_http_spdy_connection_t *sc, u_char *pos,
  1458.     u_char *end)
  1459. {
  1460.     ngx_log_debug2(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0,
  1461.                    "spdy frame complete pos:%p end:%p", pos, end);

  1462.     if (pos > end) {
  1463.         ngx_log_error(NGX_LOG_ALERT, sc->connection->log, 0,
  1464.                       "receive buffer overrun");

  1465.         ngx_debug_point();
  1466.         return ngx_http_spdy_state_internal_error(sc);
  1467.     }

  1468.     sc->handler = ngx_http_spdy_state_head;
  1469.     sc->stream = NULL;

  1470.     return pos;
  1471. }


  1472. static u_char *
  1473. ngx_http_spdy_state_save(ngx_http_spdy_connection_t *sc,
  1474.     u_char *pos, u_char *end, ngx_http_spdy_handler_pt handler)
  1475. {
  1476.     size_t  size;

  1477.     ngx_log_debug3(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0,
  1478.                    "spdy frame state save pos:%p end:%p handler:%p",
  1479.                    pos, end, handler);

  1480.     size = end - pos;

  1481.     if (size > NGX_SPDY_STATE_BUFFER_SIZE) {
  1482.         ngx_log_error(NGX_LOG_ALERT, sc->connection->log, 0,
  1483.                       "state buffer overflow: %uz bytes required", size);

  1484.         ngx_debug_point();
  1485.         return ngx_http_spdy_state_internal_error(sc);
  1486.     }

  1487.     ngx_memcpy(sc->buffer, pos, NGX_SPDY_STATE_BUFFER_SIZE);

  1488.     sc->buffer_used = size;
  1489.     sc->handler = handler;
  1490.     sc->incomplete = 1;

  1491.     return end;
  1492. }


  1493. static u_char *
  1494. ngx_http_spdy_state_inflate_error(ngx_http_spdy_connection_t *sc, int rc)
  1495. {
  1496.     if (rc == Z_DATA_ERROR || rc == Z_STREAM_END) {
  1497.         ngx_log_error(NGX_LOG_INFO, sc->connection->log, 0,
  1498.                       "client sent SYN_STREAM frame with "
  1499.                       "corrupted header block, inflate() failed: %d", rc);

  1500.         return ngx_http_spdy_state_protocol_error(sc);
  1501.     }

  1502.     ngx_log_error(NGX_LOG_ERR, sc->connection->log, 0,
  1503.                   "inflate() failed: %d", rc);

  1504.     return ngx_http_spdy_state_internal_error(sc);
  1505. }


  1506. static u_char *
  1507. ngx_http_spdy_state_protocol_error(ngx_http_spdy_connection_t *sc)
  1508. {
  1509.     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0,
  1510.                    "spdy state protocol error");

  1511.     if (sc->stream) {
  1512.         sc->stream->out_closed = 1;
  1513.         ngx_http_spdy_close_stream(sc->stream, NGX_HTTP_BAD_REQUEST);
  1514.     }

  1515.     ngx_http_spdy_finalize_connection(sc, NGX_HTTP_CLIENT_CLOSED_REQUEST);

  1516.     return NULL;
  1517. }


  1518. static u_char *
  1519. ngx_http_spdy_state_internal_error(ngx_http_spdy_connection_t *sc)
  1520. {
  1521.     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0,
  1522.                    "spdy state internal error");

  1523.     if (sc->stream) {
  1524.         sc->stream->out_closed = 1;
  1525.         ngx_http_spdy_close_stream(sc->stream, NGX_HTTP_INTERNAL_SERVER_ERROR);
  1526.     }

  1527.     ngx_http_spdy_finalize_connection(sc, NGX_HTTP_INTERNAL_SERVER_ERROR);

  1528.     return NULL;
  1529. }


  1530. static ngx_int_t
  1531. ngx_http_spdy_send_window_update(ngx_http_spdy_connection_t *sc, ngx_uint_t sid,
  1532.     ngx_uint_t delta)
  1533. {
  1534.     u_char                     *p;
  1535.     ngx_buf_t                  *buf;
  1536.     ngx_http_spdy_out_frame_t  *frame;

  1537.     ngx_log_debug2(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0,
  1538.                    "spdy send WINDOW_UPDATE sid:%ui delta:%ui", sid, delta);

  1539.     frame = ngx_http_spdy_get_ctl_frame(sc, NGX_SPDY_WINDOW_UPDATE_SIZE,
  1540.                                         NGX_SPDY_HIGHEST_PRIORITY);
  1541.     if (frame == NULL) {
  1542.         return NGX_ERROR;
  1543.     }

  1544.     buf = frame->first->buf;

  1545.     p = buf->pos;

  1546.     p = ngx_spdy_frame_write_head(p, NGX_SPDY_WINDOW_UPDATE);
  1547.     p = ngx_spdy_frame_write_flags_and_len(p, 0, NGX_SPDY_WINDOW_UPDATE_SIZE);

  1548.     p = ngx_spdy_frame_write_sid(p, sid);
  1549.     p = ngx_spdy_frame_aligned_write_uint32(p, delta);

  1550.     buf->last = p;

  1551.     ngx_http_spdy_queue_frame(sc, frame);

  1552.     return NGX_OK;
  1553. }


  1554. static ngx_int_t
  1555. ngx_http_spdy_send_rst_stream(ngx_http_spdy_connection_t *sc, ngx_uint_t sid,
  1556.     ngx_uint_t status, ngx_uint_t priority)
  1557. {
  1558.     u_char                     *p;
  1559.     ngx_buf_t                  *buf;
  1560.     ngx_http_spdy_out_frame_t  *frame;

  1561.     if (sc->connection->error) {
  1562.         return NGX_OK;
  1563.     }

  1564.     ngx_log_debug2(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0,
  1565.                    "spdy send RST_STREAM sid:%ui st:%ui", sid, status);

  1566.     frame = ngx_http_spdy_get_ctl_frame(sc, NGX_SPDY_RST_STREAM_SIZE,
  1567.                                         priority);
  1568.     if (frame == NULL) {
  1569.         return NGX_ERROR;
  1570.     }

  1571.     buf = frame->first->buf;

  1572.     p = buf->pos;

  1573.     p = ngx_spdy_frame_write_head(p, NGX_SPDY_RST_STREAM);
  1574.     p = ngx_spdy_frame_write_flags_and_len(p, 0, NGX_SPDY_RST_STREAM_SIZE);

  1575.     p = ngx_spdy_frame_write_sid(p, sid);
  1576.     p = ngx_spdy_frame_aligned_write_uint32(p, status);

  1577.     buf->last = p;

  1578.     ngx_http_spdy_queue_frame(sc, frame);

  1579.     return NGX_OK;
  1580. }


  1581. #if 0
  1582. static ngx_int_t
  1583. ngx_http_spdy_send_goaway(ngx_http_spdy_connection_t *sc)
  1584. {
  1585.     u_char                     *p;
  1586.     ngx_buf_t                  *buf;
  1587.     ngx_http_spdy_out_frame_t  *frame;

  1588.     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0,
  1589.                    "spdy send GOAWAY sid:%ui", sc->last_sid);

  1590.     frame = ngx_http_spdy_get_ctl_frame(sc, NGX_SPDY_GOAWAY_SIZE,
  1591.                                         NGX_SPDY_HIGHEST_PRIORITY);
  1592.     if (frame == NULL) {
  1593.         return NGX_ERROR;
  1594.     }

  1595.     buf = frame->first->buf;

  1596.     p = buf->pos;

  1597.     p = ngx_spdy_frame_write_head(p, NGX_SPDY_GOAWAY);
  1598.     p = ngx_spdy_frame_write_flags_and_len(p, 0, NGX_SPDY_GOAWAY_SIZE);

  1599.     p = ngx_spdy_frame_write_sid(p, sc->last_sid);

  1600.     buf->last = p;

  1601.     ngx_http_spdy_queue_frame(sc, frame);

  1602.     return NGX_OK;
  1603. }
  1604. #endif


  1605. static ngx_int_t
  1606. ngx_http_spdy_send_settings(ngx_http_spdy_connection_t *sc)
  1607. {
  1608.     u_char                     *p;
  1609.     ngx_buf_t                  *buf;
  1610.     ngx_chain_t                *cl;
  1611.     ngx_http_spdy_srv_conf_t   *sscf;
  1612.     ngx_http_spdy_out_frame_t  *frame;

  1613.     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0,
  1614.                    "spdy send SETTINGS frame");

  1615.     frame = ngx_palloc(sc->pool, sizeof(ngx_http_spdy_out_frame_t));
  1616.     if (frame == NULL) {
  1617.         return NGX_ERROR;
  1618.     }

  1619.     cl = ngx_alloc_chain_link(sc->pool);
  1620.     if (cl == NULL) {
  1621.         return NGX_ERROR;
  1622.     }

  1623.     buf = ngx_create_temp_buf(sc->pool, NGX_SPDY_FRAME_HEADER_SIZE
  1624.                                         + NGX_SPDY_SETTINGS_NUM_SIZE
  1625.                                         + 2 * NGX_SPDY_SETTINGS_PAIR_SIZE);
  1626.     if (buf == NULL) {
  1627.         return NGX_ERROR;
  1628.     }

  1629.     buf->last_buf = 1;

  1630.     cl->buf = buf;
  1631.     cl->next = NULL;

  1632.     frame->first = cl;
  1633.     frame->last = cl;
  1634.     frame->handler = ngx_http_spdy_settings_frame_handler;
  1635.     frame->stream = NULL;
  1636. #if (NGX_DEBUG)
  1637.     frame->length = NGX_SPDY_SETTINGS_NUM_SIZE
  1638.                     + 2 * NGX_SPDY_SETTINGS_PAIR_SIZE;
  1639. #endif
  1640.     frame->priority = NGX_SPDY_HIGHEST_PRIORITY;
  1641.     frame->blocked = 0;

  1642.     p = buf->pos;

  1643.     p = ngx_spdy_frame_write_head(p, NGX_SPDY_SETTINGS);
  1644.     p = ngx_spdy_frame_write_flags_and_len(p, NGX_SPDY_FLAG_CLEAR_SETTINGS,
  1645.                                            NGX_SPDY_SETTINGS_NUM_SIZE
  1646.                                            + 2 * NGX_SPDY_SETTINGS_PAIR_SIZE);

  1647.     p = ngx_spdy_frame_aligned_write_uint32(p, 2);

  1648.     sscf = ngx_http_get_module_srv_conf(sc->http_connection->conf_ctx,
  1649.                                         ngx_http_spdy_module);

  1650.     p = ngx_spdy_frame_write_flags_and_id(p, 0, NGX_SPDY_SETTINGS_MAX_STREAMS);
  1651.     p = ngx_spdy_frame_aligned_write_uint32(p, sscf->concurrent_streams);

  1652.     p = ngx_spdy_frame_write_flags_and_id(p, 0, NGX_SPDY_SETTINGS_INIT_WINDOW);
  1653.     p = ngx_spdy_frame_aligned_write_uint32(p, NGX_SPDY_STREAM_WINDOW);

  1654.     buf->last = p;

  1655.     ngx_http_spdy_queue_frame(sc, frame);

  1656.     return NGX_OK;
  1657. }


  1658. ngx_int_t
  1659. ngx_http_spdy_settings_frame_handler(ngx_http_spdy_connection_t *sc,
  1660.     ngx_http_spdy_out_frame_t *frame)
  1661. {
  1662.     ngx_buf_t  *buf;

  1663.     buf = frame->first->buf;

  1664.     if (buf->pos != buf->last) {
  1665.         return NGX_AGAIN;
  1666.     }

  1667.     ngx_free_chain(sc->pool, frame->first);

  1668.     return NGX_OK;
  1669. }


  1670. static ngx_http_spdy_out_frame_t *
  1671. ngx_http_spdy_get_ctl_frame(ngx_http_spdy_connection_t *sc, size_t length,
  1672.     ngx_uint_t priority)
  1673. {
  1674.     ngx_chain_t                *cl;
  1675.     ngx_http_spdy_out_frame_t  *frame;

  1676.     frame = sc->free_ctl_frames;

  1677.     if (frame) {
  1678.         sc->free_ctl_frames = frame->next;

  1679.         cl = frame->first;
  1680.         cl->buf->pos = cl->buf->start;

  1681.     } else {
  1682.         frame = ngx_palloc(sc->pool, sizeof(ngx_http_spdy_out_frame_t));
  1683.         if (frame == NULL) {
  1684.             return NULL;
  1685.         }

  1686.         cl = ngx_alloc_chain_link(sc->pool);
  1687.         if (cl == NULL) {
  1688.             return NULL;
  1689.         }

  1690.         cl->buf = ngx_create_temp_buf(sc->pool,
  1691.                                       NGX_SPDY_CTL_FRAME_BUFFER_SIZE);
  1692.         if (cl->buf == NULL) {
  1693.             return NULL;
  1694.         }

  1695.         cl->buf->last_buf = 1;

  1696.         frame->first = cl;
  1697.         frame->last = cl;
  1698.         frame->handler = ngx_http_spdy_ctl_frame_handler;
  1699.         frame->stream = NULL;
  1700.     }

  1701. #if (NGX_DEBUG)
  1702.     if (length > NGX_SPDY_CTL_FRAME_BUFFER_SIZE - NGX_SPDY_FRAME_HEADER_SIZE) {
  1703.         ngx_log_error(NGX_LOG_ALERT, sc->pool->log, 0,
  1704.                       "requested control frame is too large: %uz", length);
  1705.         return NULL;
  1706.     }

  1707.     frame->length = length;
  1708. #endif

  1709.     frame->priority = priority;
  1710.     frame->blocked = 0;

  1711.     return frame;
  1712. }


  1713. static ngx_int_t
  1714. ngx_http_spdy_ctl_frame_handler(ngx_http_spdy_connection_t *sc,
  1715.     ngx_http_spdy_out_frame_t *frame)
  1716. {
  1717.     ngx_buf_t  *buf;

  1718.     buf = frame->first->buf;

  1719.     if (buf->pos != buf->last) {
  1720.         return NGX_AGAIN;
  1721.     }

  1722.     frame->next = sc->free_ctl_frames;
  1723.     sc->free_ctl_frames = frame;

  1724.     return NGX_OK;
  1725. }


  1726. static ngx_http_spdy_stream_t *
  1727. ngx_http_spdy_create_stream(ngx_http_spdy_connection_t *sc, ngx_uint_t id,
  1728.     ngx_uint_t priority)
  1729. {
  1730.     ngx_log_t                 *log;
  1731.     ngx_uint_t                 index;
  1732.     ngx_event_t               *rev, *wev;
  1733.     ngx_connection_t          *fc;
  1734.     ngx_http_log_ctx_t        *ctx;
  1735.     ngx_http_request_t        *r;
  1736.     ngx_http_spdy_stream_t    *stream;
  1737.     ngx_http_core_srv_conf_t  *cscf;
  1738.     ngx_http_spdy_srv_conf_t  *sscf;

  1739.     fc = sc->free_fake_connections;

  1740.     if (fc) {
  1741.         sc->free_fake_connections = fc->data;

  1742.         rev = fc->read;
  1743.         wev = fc->write;
  1744.         log = fc->log;
  1745.         ctx = log->data;

  1746.     } else {
  1747.         fc = ngx_palloc(sc->pool, sizeof(ngx_connection_t));
  1748.         if (fc == NULL) {
  1749.             return NULL;
  1750.         }

  1751.         rev = ngx_palloc(sc->pool, sizeof(ngx_event_t));
  1752.         if (rev == NULL) {
  1753.             return NULL;
  1754.         }

  1755.         wev = ngx_palloc(sc->pool, sizeof(ngx_event_t));
  1756.         if (wev == NULL) {
  1757.             return NULL;
  1758.         }

  1759.         log = ngx_palloc(sc->pool, sizeof(ngx_log_t));
  1760.         if (log == NULL) {
  1761.             return NULL;
  1762.         }

  1763.         ctx = ngx_palloc(sc->pool, sizeof(ngx_http_log_ctx_t));
  1764.         if (ctx == NULL) {
  1765.             return NULL;
  1766.         }

  1767.         ctx->connection = fc;
  1768.         ctx->request = NULL;
  1769.     }

  1770.     ngx_memcpy(log, sc->connection->log, sizeof(ngx_log_t));

  1771.     log->data = ctx;

  1772.     ngx_memzero(rev, sizeof(ngx_event_t));

  1773.     rev->data = fc;
  1774.     rev->ready = 1;
  1775.     rev->handler = ngx_http_spdy_close_stream_handler;
  1776.     rev->log = log;

  1777.     ngx_memcpy(wev, rev, sizeof(ngx_event_t));

  1778.     wev->write = 1;

  1779.     ngx_memcpy(fc, sc->connection, sizeof(ngx_connection_t));

  1780.     fc->data = sc->http_connection;
  1781.     fc->read = rev;
  1782.     fc->write = wev;
  1783.     fc->sent = 0;
  1784.     fc->log = log;
  1785.     fc->buffered = 0;
  1786.     fc->sndlowat = 1;
  1787.     fc->tcp_nodelay = NGX_TCP_NODELAY_DISABLED;

  1788.     r = ngx_http_create_request(fc);
  1789.     if (r == NULL) {
  1790.         return NULL;
  1791.     }

  1792.     r->valid_location = 1;

  1793.     fc->data = r;
  1794.     sc->connection->requests++;

  1795.     cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module);

  1796.     r->header_in = ngx_create_temp_buf(r->pool,
  1797.                                        cscf->client_header_buffer_size);
  1798.     if (r->header_in == NULL) {
  1799.         ngx_http_free_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
  1800.         return NULL;
  1801.     }

  1802.     r->headers_in.connection_type = NGX_HTTP_CONNECTION_CLOSE;

  1803.     stream = ngx_pcalloc(r->pool, sizeof(ngx_http_spdy_stream_t));
  1804.     if (stream == NULL) {
  1805.         ngx_http_free_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
  1806.         return NULL;
  1807.     }

  1808.     r->spdy_stream = stream;

  1809.     stream->id = id;
  1810.     stream->request = r;
  1811.     stream->connection = sc;

  1812.     stream->send_window = sc->init_window;
  1813.     stream->recv_window = NGX_SPDY_STREAM_WINDOW;

  1814.     stream->priority = priority;

  1815.     sscf = ngx_http_get_module_srv_conf(r, ngx_http_spdy_module);

  1816.     index = ngx_http_spdy_stream_index(sscf, id);

  1817.     stream->index = sc->streams_index[index];
  1818.     sc->streams_index[index] = stream;

  1819.     sc->processing++;

  1820.     return stream;
  1821. }


  1822. static ngx_http_spdy_stream_t *
  1823. ngx_http_spdy_get_stream_by_id(ngx_http_spdy_connection_t *sc,
  1824.     ngx_uint_t sid)
  1825. {
  1826.     ngx_http_spdy_stream_t    *stream;
  1827.     ngx_http_spdy_srv_conf_t  *sscf;

  1828.     sscf = ngx_http_get_module_srv_conf(sc->http_connection->conf_ctx,
  1829.                                         ngx_http_spdy_module);

  1830.     stream = sc->streams_index[ngx_http_spdy_stream_index(sscf, sid)];

  1831.     while (stream) {
  1832.         if (stream->id == sid) {
  1833.             return stream;
  1834.         }

  1835.         stream = stream->index;
  1836.     }

  1837.     return NULL;
  1838. }


  1839. static ngx_int_t
  1840. ngx_http_spdy_parse_header(ngx_http_request_t *r)
  1841. {
  1842.     u_char                     *p, *end, ch;
  1843.     ngx_uint_t                  hash;
  1844.     ngx_http_core_srv_conf_t   *cscf;

  1845.     enum {
  1846.         sw_name_len = 0,
  1847.         sw_name,
  1848.         sw_value_len,
  1849.         sw_value
  1850.     } state;

  1851.     state = r->state;

  1852.     p = r->header_in->pos;
  1853.     end = r->header_in->last;

  1854.     switch (state) {

  1855.     case sw_name_len:

  1856.         if (end - p < NGX_SPDY_NV_NLEN_SIZE) {
  1857.             return NGX_AGAIN;
  1858.         }

  1859.         r->lowcase_index = ngx_spdy_frame_parse_uint32(p);

  1860.         if (r->lowcase_index == 0) {
  1861.             return NGX_ERROR;
  1862.         }

  1863.         /* null-terminate the previous header value */
  1864.         *p = '\0';

  1865.         p += NGX_SPDY_NV_NLEN_SIZE;

  1866.         r->invalid_header = 0;

  1867.         state = sw_name;

  1868.         /* fall through */

  1869.     case sw_name:

  1870.         if ((ngx_uint_t) (end - p) < r->lowcase_index) {
  1871.             break;
  1872.         }

  1873.         cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module);

  1874.         r->header_name_start = p;
  1875.         r->header_name_end = p + r->lowcase_index;

  1876.         if (p[0] == ':') {
  1877.             p++;
  1878.         }

  1879.         hash = 0;

  1880.         for ( /* void */ ; p != r->header_name_end; p++) {

  1881.             ch = *p;

  1882.             hash = ngx_hash(hash, ch);

  1883.             if ((ch >= 'a' && ch <= 'z')
  1884.                 || (ch == '-')
  1885.                 || (ch >= '0' && ch <= '9')
  1886.                 || (ch == '_' && cscf->underscores_in_headers))
  1887.             {
  1888.                 continue;
  1889.             }

  1890.             switch (ch) {
  1891.             case '\0':
  1892.             case LF:
  1893.             case CR:
  1894.             case ':':
  1895.                 ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
  1896.                               "client sent invalid header name: \"%*s\"",
  1897.                               r->lowcase_index, r->header_name_start);

  1898.                 return NGX_HTTP_PARSE_INVALID_HEADER;
  1899.             }

  1900.             if (ch >= 'A' && ch <= 'Z') {
  1901.                 return NGX_ERROR;
  1902.             }

  1903.             r->invalid_header = 1;
  1904.         }

  1905.         r->header_hash = hash;

  1906.         state = sw_value_len;

  1907.         /* fall through */

  1908.     case sw_value_len:

  1909.         if (end - p < NGX_SPDY_NV_VLEN_SIZE) {
  1910.             break;
  1911.         }

  1912.         r->lowcase_index = ngx_spdy_frame_parse_uint32(p);

  1913.         /* null-terminate header name */
  1914.         *p = '\0';

  1915.         p += NGX_SPDY_NV_VLEN_SIZE;

  1916.         state = sw_value;

  1917.         /* fall through */

  1918.     case sw_value:

  1919.         if ((ngx_uint_t) (end - p) < r->lowcase_index) {
  1920.             break;
  1921.         }

  1922.         r->header_start = p;

  1923.         while (r->lowcase_index--) {
  1924.             ch = *p;

  1925.             if (ch == '\0') {

  1926.                 if (p == r->header_start) {
  1927.                     return NGX_ERROR;
  1928.                 }

  1929.                 r->header_end = p;
  1930.                 r->header_in->pos = p + 1;

  1931.                 r->state = sw_value;

  1932.                 return NGX_OK;
  1933.             }

  1934.             if (ch == CR || ch == LF) {
  1935.                 ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
  1936.                               "client sent header \"%*s\" with "
  1937.                               "invalid value: \"%*s\\%c...\"",
  1938.                               r->header_name_end - r->header_name_start,
  1939.                               r->header_name_start,
  1940.                               p - r->header_start,
  1941.                               r->header_start,
  1942.                               ch == CR ? 'r' : 'n');

  1943.                 return NGX_HTTP_PARSE_INVALID_HEADER;
  1944.             }

  1945.             p++;
  1946.         }

  1947.         r->header_end = p;
  1948.         r->header_in->pos = p;

  1949.         r->state = 0;

  1950.         return NGX_DONE;
  1951.     }

  1952.     r->header_in->pos = p;
  1953.     r->state = state;

  1954.     return NGX_AGAIN;
  1955. }


  1956. static ngx_int_t
  1957. ngx_http_spdy_alloc_large_header_buffer(ngx_http_request_t *r)
  1958. {
  1959.     u_char                    *old, *new, *p;
  1960.     size_t                     rest;
  1961.     ngx_buf_t                 *buf;
  1962.     ngx_http_spdy_stream_t    *stream;
  1963.     ngx_http_core_srv_conf_t  *cscf;

  1964.     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  1965.                    "spdy alloc large header buffer");

  1966.     stream = r->spdy_stream;

  1967.     cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module);

  1968.     if (stream->header_buffers
  1969.         == (ngx_uint_t) cscf->large_client_header_buffers.num)
  1970.     {
  1971.         ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
  1972.                       "client sent too large request");

  1973.         return NGX_DECLINED;
  1974.     }

  1975.     rest = r->header_in->last - r->header_in->pos;

  1976.     /*
  1977.      * One more byte is needed for null-termination
  1978.      * and another one for further progress.
  1979.      */
  1980.     if (rest > cscf->large_client_header_buffers.size - 2) {
  1981.         p = r->header_in->pos;

  1982.         if (rest > NGX_MAX_ERROR_STR - 300) {
  1983.             rest = NGX_MAX_ERROR_STR - 300;
  1984.         }

  1985.         ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
  1986.                       "client sent too long header name or value: \"%*s...\"",
  1987.                       rest, p);

  1988.         return NGX_DECLINED;
  1989.     }

  1990.     buf = ngx_create_temp_buf(r->pool, cscf->large_client_header_buffers.size);
  1991.     if (buf == NULL) {
  1992.         return NGX_ERROR;
  1993.     }

  1994.     ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  1995.                    "spdy large header alloc: %p %uz",
  1996.                    buf->pos, buf->end - buf->last);

  1997.     old = r->header_in->pos;
  1998.     new = buf->pos;

  1999.     if (rest) {
  2000.         buf->last = ngx_cpymem(new, old, rest);
  2001.     }

  2002.     r->header_in = buf;

  2003.     stream->header_buffers++;

  2004.     return NGX_OK;
  2005. }


  2006. static ngx_int_t
  2007. ngx_http_spdy_handle_request_header(ngx_http_request_t *r)
  2008. {
  2009.     ngx_uint_t                       i;
  2010.     ngx_table_elt_t                 *h;
  2011.     ngx_http_core_srv_conf_t        *cscf;
  2012.     ngx_http_spdy_request_header_t  *sh;

  2013.     if (r->invalid_header) {
  2014.         cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module);

  2015.         if (cscf->ignore_invalid_headers) {
  2016.             ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
  2017.                           "client sent invalid header: \"%*s\"",
  2018.                           r->header_end - r->header_name_start,
  2019.                           r->header_name_start);
  2020.             return NGX_OK;
  2021.         }

  2022.     }

  2023.     if (r->header_name_start[0] == ':') {
  2024.         r->header_name_start++;

  2025.         for (i = 0; i < NGX_SPDY_REQUEST_HEADERS; i++) {
  2026.             sh = &ngx_http_spdy_request_headers[i];

  2027.             if (sh->hash != r->header_hash
  2028.                 || sh->len != r->header_name_end - r->header_name_start
  2029.                 || ngx_strncmp(sh->header, r->header_name_start, sh->len) != 0)
  2030.             {
  2031.                 continue;
  2032.             }

  2033.             return sh->handler(r);
  2034.         }

  2035.         ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
  2036.                       "client sent invalid header name: \":%*s\"",
  2037.                       r->header_end - r->header_name_start,
  2038.                       r->header_name_start);

  2039.         return NGX_HTTP_PARSE_INVALID_HEADER;
  2040.     }

  2041.     h = ngx_list_push(&r->headers_in.headers);
  2042.     if (h == NULL) {
  2043.         return NGX_ERROR;
  2044.     }

  2045.     h->hash = r->header_hash;

  2046.     h->key.len = r->header_name_end - r->header_name_start;
  2047.     h->key.data = r->header_name_start;

  2048.     h->value.len = r->header_end - r->header_start;
  2049.     h->value.data = r->header_start;

  2050.     h->lowcase_key = h->key.data;

  2051.     return NGX_OK;
  2052. }


  2053. void
  2054. ngx_http_spdy_request_headers_init(void)
  2055. {
  2056.     ngx_uint_t                       i;
  2057.     ngx_http_spdy_request_header_t  *h;

  2058.     for (i = 0; i < NGX_SPDY_REQUEST_HEADERS; i++) {
  2059.         h = &ngx_http_spdy_request_headers[i];
  2060.         h->hash = ngx_hash_key(h->header, h->len);
  2061.     }
  2062. }


  2063. static ngx_int_t
  2064. ngx_http_spdy_parse_method(ngx_http_request_t *r)
  2065. {
  2066.     size_t         k, len;
  2067.     ngx_uint_t     n;
  2068.     const u_char  *p, *m;

  2069.     /*
  2070.      * This array takes less than 256 sequential bytes,
  2071.      * and if typical CPU cache line size is 64 bytes,
  2072.      * it is prefetched for 4 load operations.
  2073.      */
  2074.     static const struct {
  2075.         u_char            len;
  2076.         const u_char      method[11];
  2077.         uint32_t          value;
  2078.     } tests[] = {
  2079.         { 3, "GET",       NGX_HTTP_GET },
  2080.         { 4, "POST",      NGX_HTTP_POST },
  2081.         { 4, "HEAD",      NGX_HTTP_HEAD },
  2082.         { 7, "OPTIONS",   NGX_HTTP_OPTIONS },
  2083.         { 8, "PROPFIND"NGX_HTTP_PROPFIND },
  2084.         { 3, "PUT",       NGX_HTTP_PUT },
  2085.         { 5, "MKCOL",     NGX_HTTP_MKCOL },
  2086.         { 6, "DELETE",    NGX_HTTP_DELETE },
  2087.         { 4, "COPY",      NGX_HTTP_COPY },
  2088.         { 4, "MOVE",      NGX_HTTP_MOVE },
  2089.         { 9, "PROPPATCH", NGX_HTTP_PROPPATCH },
  2090.         { 4, "LOCK",      NGX_HTTP_LOCK },
  2091.         { 6, "UNLOCK",    NGX_HTTP_UNLOCK },
  2092.         { 5, "PATCH",     NGX_HTTP_PATCH },
  2093.         { 5, "TRACE",     NGX_HTTP_TRACE }
  2094.     }, *test;

  2095.     if (r->method_name.len) {
  2096.         ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
  2097.                       "client sent duplicate :method header");

  2098.         return NGX_HTTP_PARSE_INVALID_HEADER;
  2099.     }

  2100.     len = r->header_end - r->header_start;

  2101.     r->method_name.len = len;
  2102.     r->method_name.data = r->header_start;

  2103.     test = tests;
  2104.     n = sizeof(tests) / sizeof(tests[0]);

  2105.     do {
  2106.         if (len == test->len) {
  2107.             p = r->method_name.data;
  2108.             m = test->method;
  2109.             k = len;

  2110.             do {
  2111.                 if (*p++ != *m++) {
  2112.                     goto next;
  2113.                 }
  2114.             } while (--k);

  2115.             r->method = test->value;
  2116.             return NGX_OK;
  2117.         }

  2118.     next:
  2119.         test++;

  2120.     } while (--n);

  2121.     p = r->method_name.data;

  2122.     do {
  2123.         if ((*p < 'A' || *p > 'Z') && *p != '_') {
  2124.             ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
  2125.                           "client sent invalid method: \"%V\"",
  2126.                           &r->method_name);

  2127.             return NGX_HTTP_PARSE_INVALID_HEADER;
  2128.         }

  2129.         p++;

  2130.     } while (--len);

  2131.     return NGX_OK;
  2132. }


  2133. static ngx_int_t
  2134. ngx_http_spdy_parse_scheme(ngx_http_request_t *r)
  2135. {
  2136.     if (r->schema_start) {
  2137.         ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
  2138.                       "client sent duplicate :schema header");

  2139.         return NGX_HTTP_PARSE_INVALID_HEADER;
  2140.     }

  2141.     r->schema_start = r->header_start;
  2142.     r->schema_end = r->header_end;

  2143.     return NGX_OK;
  2144. }


  2145. static ngx_int_t
  2146. ngx_http_spdy_parse_host(ngx_http_request_t *r)
  2147. {
  2148.     ngx_table_elt_t  *h;

  2149.     if (r->headers_in.host) {
  2150.         ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
  2151.                       "client sent duplicate :host header");

  2152.         return NGX_HTTP_PARSE_INVALID_HEADER;
  2153.     }

  2154.     h = ngx_list_push(&r->headers_in.headers);
  2155.     if (h == NULL) {
  2156.         return NGX_ERROR;
  2157.     }

  2158.     r->headers_in.host = h;

  2159.     h->hash = r->header_hash;

  2160.     h->key.len = r->header_name_end - r->header_name_start;
  2161.     h->key.data = r->header_name_start;

  2162.     h->value.len = r->header_end - r->header_start;
  2163.     h->value.data = r->header_start;

  2164.     h->lowcase_key = h->key.data;

  2165.     return NGX_OK;
  2166. }


  2167. static ngx_int_t
  2168. ngx_http_spdy_parse_path(ngx_http_request_t *r)
  2169. {
  2170.     if (r->unparsed_uri.len) {
  2171.         ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
  2172.                       "client sent duplicate :path header");

  2173.         return NGX_HTTP_PARSE_INVALID_HEADER;
  2174.     }

  2175.     r->uri_start = r->header_start;
  2176.     r->uri_end = r->header_end;

  2177.     if (ngx_http_parse_uri(r) != NGX_OK) {
  2178.         ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
  2179.                       "client sent invalid URI: \"%*s\"",
  2180.                       r->uri_end - r->uri_start, r->uri_start);

  2181.         return NGX_HTTP_PARSE_INVALID_HEADER;
  2182.     }

  2183.     if (ngx_http_process_request_uri(r) != NGX_OK) {
  2184.         /*
  2185.          * request has been finalized already
  2186.          * in ngx_http_process_request_uri()
  2187.          */
  2188.         return NGX_ABORT;
  2189.     }

  2190.     return NGX_OK;
  2191. }


  2192. static ngx_int_t
  2193. ngx_http_spdy_parse_version(ngx_http_request_t *r)
  2194. {
  2195.     u_char  *p, ch;

  2196.     if (r->http_protocol.len) {
  2197.         ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
  2198.                       "client sent duplicate :version header");

  2199.         return NGX_HTTP_PARSE_INVALID_HEADER;
  2200.     }

  2201.     p = r->header_start;

  2202.     if (r->header_end - p < 8 || !(ngx_str5cmp(p, 'H', 'T', 'T', 'P', '/'))) {
  2203.         goto invalid;
  2204.     }

  2205.     ch = *(p + 5);

  2206.     if (ch < '1' || ch > '9') {
  2207.         goto invalid;
  2208.     }

  2209.     r->http_major = ch - '0';

  2210.     for (p += 6; p != r->header_end - 2; p++) {

  2211.         ch = *p;

  2212.         if (ch == '.') {
  2213.             break;
  2214.         }

  2215.         if (ch < '0' || ch > '9') {
  2216.             goto invalid;
  2217.         }

  2218.         r->http_major = r->http_major * 10 + ch - '0';
  2219.     }

  2220.     if (*p != '.') {
  2221.         goto invalid;
  2222.     }

  2223.     ch = *(p + 1);

  2224.     if (ch < '0' || ch > '9') {
  2225.         goto invalid;
  2226.     }

  2227.     r->http_minor = ch - '0';

  2228.     for (p += 2; p != r->header_end; p++) {

  2229.         ch = *p;

  2230.         if (ch < '0' || ch > '9') {
  2231.             goto invalid;
  2232.         }

  2233.         r->http_minor = r->http_minor * 10 + ch - '0';
  2234.     }

  2235.     r->http_protocol.len = r->header_end - r->header_start;
  2236.     r->http_protocol.data = r->header_start;
  2237.     r->http_version = r->http_major * 1000 + r->http_minor;

  2238.     return NGX_OK;

  2239. invalid:

  2240.     ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
  2241.                   "client sent invalid http version: \"%*s\"",
  2242.                   r->header_end - r->header_start, r->header_start);

  2243.     return NGX_HTTP_PARSE_INVALID_HEADER;
  2244. }


  2245. static ngx_int_t
  2246. ngx_http_spdy_construct_request_line(ngx_http_request_t *r)
  2247. {
  2248.     u_char  *p;

  2249.     if (r->method_name.len == 0
  2250.         || r->unparsed_uri.len == 0
  2251.         || r->http_protocol.len == 0)
  2252.     {
  2253.         ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST);
  2254.         return NGX_ERROR;
  2255.     }

  2256.     r->request_line.len = r->method_name.len + 1
  2257.                           + r->unparsed_uri.len + 1
  2258.                           + r->http_protocol.len;

  2259.     p = ngx_pnalloc(r->pool, r->request_line.len + 1);
  2260.     if (p == NULL) {
  2261.         ngx_http_spdy_close_stream(r->spdy_stream,
  2262.                                    NGX_HTTP_INTERNAL_SERVER_ERROR);
  2263.         return NGX_ERROR;
  2264.     }

  2265.     r->request_line.data = p;

  2266.     p = ngx_cpymem(p, r->method_name.data, r->method_name.len);

  2267.     *p++ = ' ';

  2268.     p = ngx_cpymem(p, r->unparsed_uri.data, r->unparsed_uri.len);

  2269.     *p++ = ' ';

  2270.     ngx_memcpy(p, r->http_protocol.data, r->http_protocol.len + 1);

  2271.     /* some modules expect the space character after method name */
  2272.     r->method_name.data = r->request_line.data;

  2273.     return NGX_OK;
  2274. }


  2275. static void
  2276. ngx_http_spdy_run_request(ngx_http_request_t *r)
  2277. {
  2278.     ngx_uint_t                  i;
  2279.     ngx_list_part_t            *part;
  2280.     ngx_table_elt_t            *h;
  2281.     ngx_http_header_t          *hh;
  2282.     ngx_http_core_main_conf_t  *cmcf;

  2283.     if (ngx_http_spdy_construct_request_line(r) != NGX_OK) {
  2284.         return;
  2285.     }

  2286.     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  2287.                    "spdy http request line: \"%V\"", &r->request_line);

  2288.     cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module);

  2289.     part = &r->headers_in.headers.part;
  2290.     h = part->elts;

  2291.     for (i = 0 ;; i++) {

  2292.         if (i >= part->nelts) {
  2293.             if (part->next == NULL) {
  2294.                 break;
  2295.             }

  2296.             part = part->next;
  2297.             h = part->elts;
  2298.             i = 0;
  2299.         }

  2300.         hh = ngx_hash_find(&cmcf->headers_in_hash, h[i].hash,
  2301.                            h[i].lowcase_key, h[i].key.len);

  2302.         if (hh && hh->handler(r, &h[i], hh->offset) != NGX_OK) {
  2303.             return;
  2304.         }

  2305.         ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  2306.                        "spdy http header: \"%V: %V\"", &h[i].key, &h[i].value);
  2307.     }

  2308.     r->http_state = NGX_HTTP_PROCESS_REQUEST_STATE;

  2309.     if (ngx_http_process_request_header(r) != NGX_OK) {
  2310.         return;
  2311.     }

  2312.     if (r->headers_in.content_length_n > 0 && r->spdy_stream->in_closed) {
  2313.         ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
  2314.                       "client prematurely closed stream");

  2315.         r->spdy_stream->skip_data = NGX_SPDY_DATA_ERROR;

  2316.         ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST);
  2317.         return;
  2318.     }

  2319.     ngx_http_process_request(r);
  2320. }


  2321. static ngx_int_t
  2322. ngx_http_spdy_init_request_body(ngx_http_request_t *r)
  2323. {
  2324.     ngx_buf_t                 *buf;
  2325.     ngx_temp_file_t           *tf;
  2326.     ngx_http_request_body_t   *rb;
  2327.     ngx_http_core_loc_conf_t  *clcf;

  2328.     rb = ngx_pcalloc(r->pool, sizeof(ngx_http_request_body_t));
  2329.     if (rb == NULL) {
  2330.         return NGX_ERROR;
  2331.     }

  2332.     r->request_body = rb;

  2333.     if (r->spdy_stream->in_closed) {
  2334.         return NGX_OK;
  2335.     }

  2336.     rb->rest = r->headers_in.content_length_n;

  2337.     clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);

  2338.     if (r->request_body_in_file_only
  2339.         || rb->rest > (off_t) clcf->client_body_buffer_size
  2340.         || rb->rest < 0)
  2341.     {
  2342.         tf = ngx_pcalloc(r->pool, sizeof(ngx_temp_file_t));
  2343.         if (tf == NULL) {
  2344.             return NGX_ERROR;
  2345.         }

  2346.         tf->file.fd = NGX_INVALID_FILE;
  2347.         tf->file.log = r->connection->log;
  2348.         tf->path = clcf->client_body_temp_path;
  2349.         tf->pool = r->pool;
  2350.         tf->warn = "a client request body is buffered to a temporary file";
  2351.         tf->log_level = r->request_body_file_log_level;
  2352.         tf->persistent = r->request_body_in_persistent_file;
  2353.         tf->clean = r->request_body_in_clean_file;

  2354.         if (r->request_body_file_group_access) {
  2355.             tf->access = 0660;
  2356.         }

  2357.         rb->temp_file = tf;

  2358.         if (r->spdy_stream->in_closed
  2359.             && ngx_create_temp_file(&tf->file, tf->path, tf->pool,
  2360.                                     tf->persistent, tf->clean, tf->access)
  2361.                != NGX_OK)
  2362.         {
  2363.             return NGX_ERROR;
  2364.         }

  2365.         buf = ngx_calloc_buf(r->pool);
  2366.         if (buf == NULL) {
  2367.             return NGX_ERROR;
  2368.         }

  2369.     } else {

  2370.         if (rb->rest == 0) {
  2371.             return NGX_OK;
  2372.         }

  2373.         buf = ngx_create_temp_buf(r->pool, (size_t) rb->rest);
  2374.         if (buf == NULL) {
  2375.             return NGX_ERROR;
  2376.         }
  2377.     }

  2378.     rb->buf = buf;

  2379.     rb->bufs = ngx_alloc_chain_link(r->pool);
  2380.     if (rb->bufs == NULL) {
  2381.         return NGX_ERROR;
  2382.     }

  2383.     rb->bufs->buf = buf;
  2384.     rb->bufs->next = NULL;

  2385.     rb->rest = 0;

  2386.     return NGX_OK;
  2387. }


  2388. ngx_int_t
  2389. ngx_http_spdy_read_request_body(ngx_http_request_t *r,
  2390.     ngx_http_client_body_handler_pt post_handler)
  2391. {
  2392.     ngx_http_spdy_stream_t  *stream;

  2393.     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  2394.                    "spdy read request body");

  2395.     stream = r->spdy_stream;

  2396.     switch (stream->skip_data) {

  2397.     case NGX_SPDY_DATA_DISCARD:
  2398.         post_handler(r);
  2399.         return NGX_OK;

  2400.     case NGX_SPDY_DATA_ERROR:
  2401.         if (r->headers_in.content_length_n == -1) {
  2402.             return NGX_HTTP_REQUEST_ENTITY_TOO_LARGE;
  2403.         } else {
  2404.             return NGX_HTTP_BAD_REQUEST;
  2405.         }

  2406.     case NGX_SPDY_DATA_INTERNAL_ERROR:
  2407.         return NGX_HTTP_INTERNAL_SERVER_ERROR;
  2408.     }

  2409.     if (!r->request_body && ngx_http_spdy_init_request_body(r) != NGX_OK) {
  2410.         stream->skip_data = NGX_SPDY_DATA_INTERNAL_ERROR;
  2411.         return NGX_HTTP_INTERNAL_SERVER_ERROR;
  2412.     }

  2413.     if (stream->in_closed) {
  2414.         post_handler(r);
  2415.         return NGX_OK;
  2416.     }

  2417.     r->request_body->post_handler = post_handler;

  2418.     r->read_event_handler = ngx_http_test_reading;
  2419.     r->write_event_handler = ngx_http_request_empty_handler;

  2420.     return NGX_AGAIN;
  2421. }


  2422. static ngx_int_t
  2423. ngx_http_spdy_terminate_stream(ngx_http_spdy_connection_t *sc,
  2424.     ngx_http_spdy_stream_t *stream, ngx_uint_t status)
  2425. {
  2426.     ngx_event_t       *rev;
  2427.     ngx_connection_t  *fc;

  2428.     if (ngx_http_spdy_send_rst_stream(sc, stream->id, status,
  2429.                                       NGX_SPDY_HIGHEST_PRIORITY)
  2430.         == NGX_ERROR)
  2431.     {
  2432.         return NGX_ERROR;
  2433.     }

  2434.     stream->out_closed = 1;

  2435.     fc = stream->request->connection;
  2436.     fc->error = 1;

  2437.     rev = fc->read;
  2438.     rev->handler(rev);

  2439.     return NGX_OK;
  2440. }


  2441. static void
  2442. ngx_http_spdy_close_stream_handler(ngx_event_t *ev)
  2443. {
  2444.     ngx_connection_t    *fc;
  2445.     ngx_http_request_t  *r;

  2446.     fc = ev->data;
  2447.     r = fc->data;

  2448.     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  2449.                    "spdy close stream handler");

  2450.     ngx_http_spdy_close_stream(r->spdy_stream, 0);
  2451. }


  2452. void
  2453. ngx_http_spdy_close_stream(ngx_http_spdy_stream_t *stream, ngx_int_t rc)
  2454. {
  2455.     int                           tcp_nodelay;
  2456.     ngx_event_t                  *ev;
  2457.     ngx_connection_t             *c, *fc;
  2458.     ngx_http_core_loc_conf_t     *clcf;
  2459.     ngx_http_spdy_stream_t      **index, *s;
  2460.     ngx_http_spdy_srv_conf_t     *sscf;
  2461.     ngx_http_spdy_connection_t   *sc;

  2462.     sc = stream->connection;

  2463.     ngx_log_debug3(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0,
  2464.                    "spdy close stream %ui, queued %ui, processing %ui",
  2465.                    stream->id, stream->queued, sc->processing);

  2466.     fc = stream->request->connection;

  2467.     if (stream->queued) {
  2468.         fc->write->handler = ngx_http_spdy_close_stream_handler;
  2469.         return;
  2470.     }

  2471.     if (!stream->out_closed) {
  2472.         if (ngx_http_spdy_send_rst_stream(sc, stream->id,
  2473.                                           NGX_SPDY_INTERNAL_ERROR,
  2474.                                           stream->priority)
  2475.             != NGX_OK)
  2476.         {
  2477.             sc->connection->error = 1;
  2478.         }

  2479.     } else {
  2480.         c = sc->connection;

  2481.         if (c->tcp_nopush == NGX_TCP_NOPUSH_SET) {
  2482.             if (ngx_tcp_push(c->fd) == -1) {
  2483.                 ngx_connection_error(c, ngx_socket_errno,
  2484.                                      ngx_tcp_push_n " failed");
  2485.                 c->error = 1;
  2486.                 tcp_nodelay = 0;

  2487.             } else {
  2488.                 c->tcp_nopush = NGX_TCP_NOPUSH_UNSET;
  2489.                 tcp_nodelay = ngx_tcp_nodelay_and_tcp_nopush ? 1 : 0;
  2490.             }

  2491.         } else {
  2492.             tcp_nodelay = 1;
  2493.         }

  2494.         clcf = ngx_http_get_module_loc_conf(stream->request,
  2495.                                             ngx_http_core_module);

  2496.         if (tcp_nodelay
  2497.             && clcf->tcp_nodelay
  2498.             && c->tcp_nodelay == NGX_TCP_NODELAY_UNSET)
  2499.         {
  2500.             ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "tcp_nodelay");

  2501.             if (setsockopt(c->fd, IPPROTO_TCP, TCP_NODELAY,
  2502.                            (const void *) &tcp_nodelay, sizeof(int))
  2503.                 == -1)
  2504.             {
  2505. #if (NGX_SOLARIS)
  2506.                 /* Solaris returns EINVAL if a socket has been shut down */
  2507.                 c->log_error = NGX_ERROR_IGNORE_EINVAL;
  2508. #endif

  2509.                 ngx_connection_error(c, ngx_socket_errno,
  2510.                                      "setsockopt(TCP_NODELAY) failed");

  2511.                 c->log_error = NGX_ERROR_INFO;
  2512.                 c->error = 1;

  2513.             } else {
  2514.                 c->tcp_nodelay = NGX_TCP_NODELAY_SET;
  2515.             }
  2516.         }
  2517.     }

  2518.     if (sc->stream == stream) {
  2519.         sc->stream = NULL;
  2520.     }

  2521.     sscf = ngx_http_get_module_srv_conf(sc->http_connection->conf_ctx,
  2522.                                         ngx_http_spdy_module);

  2523.     index = sc->streams_index + ngx_http_spdy_stream_index(sscf, stream->id);

  2524.     for ( ;; ) {
  2525.         s = *index;

  2526.         if (s == NULL) {
  2527.             break;
  2528.         }

  2529.         if (s == stream) {
  2530.             *index = s->index;
  2531.             break;
  2532.         }

  2533.         index = &s->index;
  2534.     }

  2535.     ngx_http_free_request(stream->request, rc);

  2536.     ev = fc->read;

  2537.     if (ev->active || ev->disabled) {
  2538.         ngx_log_error(NGX_LOG_ALERT, sc->connection->log, 0,
  2539.                       "fake read event was activated");
  2540.     }

  2541.     if (ev->timer_set) {
  2542.         ngx_del_timer(ev);
  2543.     }

  2544.     if (ev->posted) {
  2545.         ngx_delete_posted_event(ev);
  2546.     }

  2547.     ev = fc->write;

  2548.     if (ev->active || ev->disabled) {
  2549.         ngx_log_error(NGX_LOG_ALERT, sc->connection->log, 0,
  2550.                       "fake write event was activated");
  2551.     }

  2552.     if (ev->timer_set) {
  2553.         ngx_del_timer(ev);
  2554.     }

  2555.     if (ev->posted) {
  2556.         ngx_delete_posted_event(ev);
  2557.     }

  2558.     fc->data = sc->free_fake_connections;
  2559.     sc->free_fake_connections = fc;

  2560.     sc->processing--;

  2561.     if (sc->processing || sc->blocked) {
  2562.         return;
  2563.     }

  2564.     ev = sc->connection->read;

  2565.     ev->handler = ngx_http_spdy_handle_connection_handler;
  2566.     ngx_post_event(ev, &ngx_posted_events);
  2567. }


  2568. static void
  2569. ngx_http_spdy_handle_connection_handler(ngx_event_t *rev)
  2570. {
  2571.     ngx_connection_t  *c;

  2572.     rev->handler = ngx_http_spdy_read_handler;

  2573.     if (rev->ready) {
  2574.         ngx_http_spdy_read_handler(rev);
  2575.         return;
  2576.     }

  2577.     c = rev->data;

  2578.     ngx_http_spdy_handle_connection(c->data);
  2579. }


  2580. static void
  2581. ngx_http_spdy_keepalive_handler(ngx_event_t *rev)
  2582. {
  2583.     ngx_connection_t            *c;
  2584.     ngx_http_spdy_srv_conf_t    *sscf;
  2585.     ngx_http_spdy_connection_t  *sc;

  2586.     c = rev->data;

  2587.     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "spdy keepalive handler");

  2588.     if (rev->timedout || c->close) {
  2589.         ngx_http_close_connection(c);
  2590.         return;
  2591.     }

  2592. #if (NGX_HAVE_KQUEUE)

  2593.     if (ngx_event_flags & NGX_USE_KQUEUE_EVENT) {
  2594.         if (rev->pending_eof) {
  2595.             c->log->handler = NULL;
  2596.             ngx_log_error(NGX_LOG_INFO, c->log, rev->kq_errno,
  2597.                           "kevent() reported that client %V closed "
  2598.                           "keepalive connection", &c->addr_text);
  2599. #if (NGX_HTTP_SSL)
  2600.             if (c->ssl) {
  2601.                 c->ssl->no_send_shutdown = 1;
  2602.             }
  2603. #endif
  2604.             ngx_http_close_connection(c);
  2605.             return;
  2606.         }
  2607.     }

  2608. #endif

  2609.     c->destroyed = 0;
  2610.     c->idle = 0;
  2611.     ngx_reusable_connection(c, 0);

  2612.     sc = c->data;

  2613.     sscf = ngx_http_get_module_srv_conf(sc->http_connection->conf_ctx,
  2614.                                         ngx_http_spdy_module);

  2615.     sc->pool = ngx_create_pool(sscf->pool_size, sc->connection->log);
  2616.     if (sc->pool == NULL) {
  2617.         ngx_http_close_connection(c);
  2618.         return;
  2619.     }

  2620.     sc->streams_index = ngx_pcalloc(sc->pool,
  2621.                                     ngx_http_spdy_streams_index_size(sscf)
  2622.                                     * sizeof(ngx_http_spdy_stream_t *));
  2623.     if (sc->streams_index == NULL) {
  2624.         ngx_http_close_connection(c);
  2625.         return;
  2626.     }

  2627.     c->write->handler = ngx_http_spdy_write_handler;

  2628.     rev->handler = ngx_http_spdy_read_handler;
  2629.     ngx_http_spdy_read_handler(rev);
  2630. }


  2631. static void
  2632. ngx_http_spdy_finalize_connection(ngx_http_spdy_connection_t *sc,
  2633.     ngx_int_t rc)
  2634. {
  2635.     ngx_uint_t                 i, size;
  2636.     ngx_event_t               *ev;
  2637.     ngx_connection_t          *c, *fc;
  2638.     ngx_http_request_t        *r;
  2639.     ngx_http_spdy_stream_t    *stream;
  2640.     ngx_http_spdy_srv_conf_t  *sscf;

  2641.     c = sc->connection;

  2642.     if (!sc->processing) {
  2643.         ngx_http_close_connection(c);
  2644.         return;
  2645.     }

  2646.     c->error = 1;
  2647.     c->read->handler = ngx_http_empty_handler;
  2648.     c->write->handler = ngx_http_empty_handler;

  2649.     sc->last_out = NULL;

  2650.     sc->blocked = 1;

  2651.     sscf = ngx_http_get_module_srv_conf(sc->http_connection->conf_ctx,
  2652.                                         ngx_http_spdy_module);

  2653.     size = ngx_http_spdy_streams_index_size(sscf);

  2654.     for (i = 0; i < size; i++) {
  2655.         stream = sc->streams_index[i];

  2656.         while (stream) {
  2657.             stream->handled = 0;

  2658.             r = stream->request;
  2659.             fc = r->connection;

  2660.             fc->error = 1;

  2661.             if (stream->queued) {
  2662.                 stream->queued = 0;

  2663.                 ev = fc->write;
  2664.                 ev->delayed = 0;

  2665.             } else {
  2666.                 ev = fc->read;
  2667.             }

  2668.             stream = stream->index;

  2669.             ev->eof = 1;
  2670.             ev->handler(ev);
  2671.         }
  2672.     }

  2673.     sc->blocked = 0;

  2674.     if (sc->processing) {
  2675.         return;
  2676.     }

  2677.     ngx_http_close_connection(c);
  2678. }


  2679. static ngx_int_t
  2680. ngx_http_spdy_adjust_windows(ngx_http_spdy_connection_t *sc, ssize_t delta)
  2681. {
  2682.     ngx_uint_t                 i, size;
  2683.     ngx_event_t               *wev;
  2684.     ngx_http_spdy_stream_t    *stream, *sn;
  2685.     ngx_http_spdy_srv_conf_t  *sscf;

  2686.     sscf = ngx_http_get_module_srv_conf(sc->http_connection->conf_ctx,
  2687.                                         ngx_http_spdy_module);

  2688.     size = ngx_http_spdy_streams_index_size(sscf);

  2689.     for (i = 0; i < size; i++) {

  2690.         for (stream = sc->streams_index[i]; stream; stream = sn) {
  2691.             sn = stream->index;

  2692.             if (delta > 0
  2693.                 && stream->send_window
  2694.                       > (ssize_t) (NGX_SPDY_MAX_WINDOW - delta))
  2695.             {
  2696.                 if (ngx_http_spdy_terminate_stream(sc, stream,
  2697.                                                    NGX_SPDY_FLOW_CONTROL_ERROR)
  2698.                     == NGX_ERROR)
  2699.                 {
  2700.                     return NGX_ERROR;
  2701.                 }

  2702.                 continue;
  2703.             }

  2704.             stream->send_window += delta;

  2705.             ngx_log_debug2(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0,
  2706.                            "spdy:%ui adjust window:%z",
  2707.                            stream->id, stream->send_window);

  2708.             if (stream->send_window > 0 && stream->exhausted) {
  2709.                 stream->exhausted = 0;

  2710.                 wev = stream->request->connection->write;

  2711.                 if (!wev->timer_set) {
  2712.                     wev->delayed = 0;
  2713.                     wev->handler(wev);
  2714.                 }
  2715.             }
  2716.         }
  2717.     }

  2718.     return NGX_OK;
  2719. }


  2720. static void
  2721. ngx_http_spdy_pool_cleanup(void *data)
  2722. {
  2723.     ngx_http_spdy_connection_t  *sc = data;

  2724.     if (sc->pool) {
  2725.         ngx_destroy_pool(sc->pool);
  2726.     }
  2727. }


  2728. static void *
  2729. ngx_http_spdy_zalloc(void *opaque, u_int items, u_int size)
  2730. {
  2731.     ngx_http_spdy_connection_t *sc = opaque;

  2732.     return ngx_palloc(sc->connection->pool, items * size);
  2733. }


  2734. static void
  2735. ngx_http_spdy_zfree(void *opaque, void *address)
  2736. {
  2737. #if 0
  2738.     ngx_http_spdy_connection_t *sc = opaque;

  2739.     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0,
  2740.                    "spdy zfree: %p", address);
  2741. #endif
  2742. }