Groonga 3.0.9 Source Code Document
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
ngx_http_chunked_filter_module.c
Go to the documentation of this file.
1 
2 /*
3  * Copyright (C) Igor Sysoev
4  * Copyright (C) Nginx, Inc.
5  */
6 
7 
8 #include <ngx_config.h>
9 #include <ngx_core.h>
10 #include <ngx_http.h>
11 
12 
13 typedef struct {
17 
18 
19 static ngx_int_t ngx_http_chunked_filter_init(ngx_conf_t *cf);
20 
21 
22 static ngx_http_module_t ngx_http_chunked_filter_module_ctx = {
23  NULL, /* preconfiguration */
24  ngx_http_chunked_filter_init, /* postconfiguration */
25 
26  NULL, /* create main configuration */
27  NULL, /* init main configuration */
28 
29  NULL, /* create server configuration */
30  NULL, /* merge server configuration */
31 
32  NULL, /* create location configuration */
33  NULL /* merge location configuration */
34 };
35 
36 
39  &ngx_http_chunked_filter_module_ctx, /* module context */
40  NULL, /* module directives */
41  NGX_HTTP_MODULE, /* module type */
42  NULL, /* init master */
43  NULL, /* init module */
44  NULL, /* init process */
45  NULL, /* init thread */
46  NULL, /* exit thread */
47  NULL, /* exit process */
48  NULL, /* exit master */
50 };
51 
52 
53 static ngx_http_output_header_filter_pt ngx_http_next_header_filter;
54 static ngx_http_output_body_filter_pt ngx_http_next_body_filter;
55 
56 
57 static ngx_int_t
58 ngx_http_chunked_header_filter(ngx_http_request_t *r)
59 {
62 
66  || r != r->main
67  || (r->method & NGX_HTTP_HEAD))
68  {
69  return ngx_http_next_header_filter(r);
70  }
71 
72  if (r->headers_out.content_length_n == -1) {
74  r->keepalive = 0;
75 
76  } else {
78 
79  if (clcf->chunked_transfer_encoding) {
80  r->chunked = 1;
81 
82  ctx = ngx_pcalloc(r->pool,
84  if (ctx == NULL) {
85  return NGX_ERROR;
86  }
87 
88  ngx_http_set_ctx(r, ctx, ngx_http_chunked_filter_module);
89 
90  } else {
91  r->keepalive = 0;
92  }
93  }
94  }
95 
96  return ngx_http_next_header_filter(r);
97 }
98 
99 
100 static ngx_int_t
101 ngx_http_chunked_body_filter(ngx_http_request_t *r, ngx_chain_t *in)
102 {
103  u_char *chunk;
104  off_t size;
105  ngx_int_t rc;
106  ngx_buf_t *b;
107  ngx_chain_t *out, *cl, *tl, **ll;
109 
110  if (in == NULL || !r->chunked || r->header_only) {
111  return ngx_http_next_body_filter(r, in);
112  }
113 
114  ctx = ngx_http_get_module_ctx(r, ngx_http_chunked_filter_module);
115 
116  out = NULL;
117  ll = &out;
118 
119  size = 0;
120  cl = in;
121 
122  for ( ;; ) {
124  "http chunk: %d", ngx_buf_size(cl->buf));
125 
126  size += ngx_buf_size(cl->buf);
127 
128  if (cl->buf->flush
129  || cl->buf->sync
130  || ngx_buf_in_memory(cl->buf)
131  || cl->buf->in_file)
132  {
133  tl = ngx_alloc_chain_link(r->pool);
134  if (tl == NULL) {
135  return NGX_ERROR;
136  }
137 
138  tl->buf = cl->buf;
139  *ll = tl;
140  ll = &tl->next;
141  }
142 
143  if (cl->next == NULL) {
144  break;
145  }
146 
147  cl = cl->next;
148  }
149 
150  if (size) {
151  tl = ngx_chain_get_free_buf(r->pool, &ctx->free);
152  if (tl == NULL) {
153  return NGX_ERROR;
154  }
155 
156  b = tl->buf;
157  chunk = b->start;
158 
159  if (chunk == NULL) {
160  /* the "0000000000000000" is 64-bit hexadecimal string */
161 
162  chunk = ngx_palloc(r->pool, sizeof("0000000000000000" CRLF) - 1);
163  if (chunk == NULL) {
164  return NGX_ERROR;
165  }
166 
167  b->start = chunk;
168  b->end = chunk + sizeof("0000000000000000" CRLF) - 1;
169  }
170 
171  b->tag = (ngx_buf_tag_t) &ngx_http_chunked_filter_module;
172  b->memory = 0;
173  b->temporary = 1;
174  b->pos = chunk;
175  b->last = ngx_sprintf(chunk, "%xO" CRLF, size);
176 
177  tl->next = out;
178  out = tl;
179  }
180 
181  if (cl->buf->last_buf) {
182  tl = ngx_chain_get_free_buf(r->pool, &ctx->free);
183  if (tl == NULL) {
184  return NGX_ERROR;
185  }
186 
187  b = tl->buf;
188 
189  b->tag = (ngx_buf_tag_t) &ngx_http_chunked_filter_module;
190  b->temporary = 0;
191  b->memory = 1;
192  b->last_buf = 1;
193  b->pos = (u_char *) CRLF "0" CRLF CRLF;
194  b->last = b->pos + 7;
195 
196  cl->buf->last_buf = 0;
197 
198  *ll = tl;
199 
200  if (size == 0) {
201  b->pos += 2;
202  }
203 
204  } else if (size > 0) {
205  tl = ngx_chain_get_free_buf(r->pool, &ctx->free);
206  if (tl == NULL) {
207  return NGX_ERROR;
208  }
209 
210  b = tl->buf;
211 
212  b->tag = (ngx_buf_tag_t) &ngx_http_chunked_filter_module;
213  b->temporary = 0;
214  b->memory = 1;
215  b->pos = (u_char *) CRLF;
216  b->last = b->pos + 2;
217 
218  *ll = tl;
219 
220  } else {
221  *ll = NULL;
222  }
223 
224  rc = ngx_http_next_body_filter(r, out);
225 
226  ngx_chain_update_chains(r->pool, &ctx->free, &ctx->busy, &out,
227  (ngx_buf_tag_t) &ngx_http_chunked_filter_module);
228 
229  return rc;
230 }
231 
232 
233 static ngx_int_t
234 ngx_http_chunked_filter_init(ngx_conf_t *cf)
235 {
236  ngx_http_next_header_filter = ngx_http_top_header_filter;
237  ngx_http_top_header_filter = ngx_http_chunked_header_filter;
238 
239  ngx_http_next_body_filter = ngx_http_top_body_filter;
240  ngx_http_top_body_filter = ngx_http_chunked_body_filter;
241 
242  return NGX_OK;
243 }