/* * Copyright (C) Nginx, Inc. * Copyright (C) Valentin V. Bartenev */ #ifndef _NGX_HTTP_SPDY_H_INCLUDED_ #define _NGX_HTTP_SPDY_H_INCLUDED_ #include #include #include #include #define NGX_SPDY_VERSION 3 #define NGX_SPDY_NPN_ADVERTISE "\x08spdy/3.1" #define NGX_SPDY_NPN_NEGOTIATED "spdy/3.1" #define NGX_SPDY_STATE_BUFFER_SIZE 16 #define NGX_SPDY_CTL_BIT 1 #define NGX_SPDY_SYN_STREAM 1 #define NGX_SPDY_SYN_REPLY 2 #define NGX_SPDY_RST_STREAM 3 #define NGX_SPDY_SETTINGS 4 #define NGX_SPDY_PING 6 #define NGX_SPDY_GOAWAY 7 #define NGX_SPDY_HEADERS 8 #define NGX_SPDY_WINDOW_UPDATE 9 #define NGX_SPDY_FRAME_HEADER_SIZE 8 #define NGX_SPDY_SID_SIZE 4 #define NGX_SPDY_DELTA_SIZE 4 #define NGX_SPDY_SYN_STREAM_SIZE 10 #define NGX_SPDY_SYN_REPLY_SIZE 4 #define NGX_SPDY_RST_STREAM_SIZE 8 #define NGX_SPDY_PING_SIZE 4 #define NGX_SPDY_GOAWAY_SIZE 8 #define NGX_SPDY_WINDOW_UPDATE_SIZE 8 #define NGX_SPDY_NV_NUM_SIZE 4 #define NGX_SPDY_NV_NLEN_SIZE 4 #define NGX_SPDY_NV_VLEN_SIZE 4 #define NGX_SPDY_SETTINGS_NUM_SIZE 4 #define NGX_SPDY_SETTINGS_FID_SIZE 4 #define NGX_SPDY_SETTINGS_VAL_SIZE 4 #define NGX_SPDY_SETTINGS_PAIR_SIZE \ (NGX_SPDY_SETTINGS_FID_SIZE + NGX_SPDY_SETTINGS_VAL_SIZE) #define NGX_SPDY_HIGHEST_PRIORITY 0 #define NGX_SPDY_LOWEST_PRIORITY 7 #define NGX_SPDY_FLAG_FIN 0x01 #define NGX_SPDY_FLAG_UNIDIRECTIONAL 0x02 #define NGX_SPDY_FLAG_CLEAR_SETTINGS 0x01 #define NGX_SPDY_MAX_FRAME_SIZE ((1 << 24) - 1) #define NGX_SPDY_DATA_DISCARD 1 #define NGX_SPDY_DATA_ERROR 2 #define NGX_SPDY_DATA_INTERNAL_ERROR 3 typedef struct ngx_http_spdy_connection_s ngx_http_spdy_connection_t; typedef struct ngx_http_spdy_out_frame_s ngx_http_spdy_out_frame_t; typedef u_char *(*ngx_http_spdy_handler_pt) (ngx_http_spdy_connection_t *sc, u_char *pos, u_char *end); struct ngx_http_spdy_connection_s { ngx_connection_t *connection; ngx_http_connection_t *http_connection; ngx_uint_t processing; size_t send_window; size_t recv_window; size_t init_window; ngx_queue_t waiting; u_char buffer[NGX_SPDY_STATE_BUFFER_SIZE]; size_t buffer_used; ngx_http_spdy_handler_pt handler; z_stream zstream_in; z_stream zstream_out; ngx_pool_t *pool; ngx_http_spdy_out_frame_t *free_ctl_frames; ngx_connection_t *free_fake_connections; ngx_http_spdy_stream_t **streams_index; ngx_http_spdy_out_frame_t *last_out; ngx_queue_t posted; ngx_http_spdy_stream_t *stream; ngx_uint_t entries; size_t length; u_char flags; ngx_uint_t last_sid; unsigned blocked:1; unsigned incomplete:1; }; struct ngx_http_spdy_stream_s { ngx_uint_t id; ngx_http_request_t *request; ngx_http_spdy_connection_t *connection; ngx_http_spdy_stream_t *index; ngx_uint_t header_buffers; ngx_uint_t queued; /* * A change to SETTINGS_INITIAL_WINDOW_SIZE could cause the * send_window to become negative, hence it's signed. */ ssize_t send_window; size_t recv_window; ngx_http_spdy_out_frame_t *free_frames; ngx_chain_t *free_data_headers; ngx_chain_t *free_bufs; ngx_queue_t queue; unsigned priority:3; unsigned handled:1; unsigned blocked:1; unsigned exhausted:1; unsigned in_closed:1; unsigned out_closed:1; unsigned skip_data:2; }; struct ngx_http_spdy_out_frame_s { ngx_http_spdy_out_frame_t *next; ngx_chain_t *first; ngx_chain_t *last; ngx_int_t (*handler)(ngx_http_spdy_connection_t *sc, ngx_http_spdy_out_frame_t *frame); ngx_http_spdy_stream_t *stream; size_t length; ngx_uint_t priority; unsigned blocked:1; unsigned fin:1; }; static ngx_inline void ngx_http_spdy_queue_frame(ngx_http_spdy_connection_t *sc, ngx_http_spdy_out_frame_t *frame) { ngx_http_spdy_out_frame_t **out; for (out = &sc->last_out; *out; out = &(*out)->next) { /* * NB: higher values represent lower priorities. */ if (frame->priority >= (*out)->priority) { break; } } frame->next = *out; *out = frame; } static ngx_inline void ngx_http_spdy_queue_blocked_frame(ngx_http_spdy_connection_t *sc, ngx_http_spdy_out_frame_t *frame) { ngx_http_spdy_out_frame_t **out; for (out = &sc->last_out; *out; out = &(*out)->next) { if ((*out)->blocked) { break; } } frame->next = *out; *out = frame; } void ngx_http_spdy_init(ngx_event_t *rev); void ngx_http_spdy_request_headers_init(void); ngx_int_t ngx_http_spdy_read_request_body(ngx_http_request_t *r, ngx_http_client_body_handler_pt post_handler); void ngx_http_spdy_close_stream(ngx_http_spdy_stream_t *stream, ngx_int_t rc); ngx_int_t ngx_http_spdy_send_output_queue(ngx_http_spdy_connection_t *sc); #define ngx_spdy_frame_aligned_write_uint16(p, s) \ (*(uint16_t *) (p) = htons((uint16_t) (s)), (p) + sizeof(uint16_t)) #define ngx_spdy_frame_aligned_write_uint32(p, s) \ (*(uint32_t *) (p) = htonl((uint32_t) (s)), (p) + sizeof(uint32_t)) #if (NGX_HAVE_NONALIGNED) #define ngx_spdy_frame_write_uint16 ngx_spdy_frame_aligned_write_uint16 #define ngx_spdy_frame_write_uint32 ngx_spdy_frame_aligned_write_uint32 #else #define ngx_spdy_frame_write_uint16(p, s) \ ((p)[0] = (u_char) (s) >> 8, (p)[1] = (u_char) (s), (p) + sizeof(uint16_t)) #define ngx_spdy_frame_write_uint32(p, s) \ ((p)[0] = (u_char) (s) >> 24, \ (p)[1] = (u_char) (s) >> 16, \ (p)[2] = (u_char) (s) >> 8, \ (p)[3] = (u_char) (s), (p) + sizeof(uint32_t)) #endif #define ngx_spdy_ctl_frame_head(t) \ ((uint32_t) NGX_SPDY_CTL_BIT << 31 | NGX_SPDY_VERSION << 16 | (t)) #define ngx_spdy_frame_write_head(p, t) \ ngx_spdy_frame_aligned_write_uint32(p, ngx_spdy_ctl_frame_head(t)) #define ngx_spdy_frame_write_flags_and_len(p, f, l) \ ngx_spdy_frame_aligned_write_uint32(p, (f) << 24 | (l)) #define ngx_spdy_frame_write_flags_and_id(p, f, i) \ ngx_spdy_frame_aligned_write_uint32(p, (f) << 24 | (i)) #define ngx_spdy_frame_write_sid ngx_spdy_frame_aligned_write_uint32 #define ngx_spdy_frame_write_window ngx_spdy_frame_aligned_write_uint32 #endif /* _NGX_HTTP_SPDY_H_INCLUDED_ */