Annotation of embedaddon/nginx/src/http/ngx_http_spdy.c, revision 1.1

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

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>