Mercurial > hg > nginx-quic
annotate src/http/modules/ngx_http_slice_filter_module.c @ 6699:9cf2dce316e5
Fixed log levels of configuration parsing errors.
All the errors that prevent loading configuration must be printed on the "emerg"
log level. Previously, nginx might silently fail to load configuration in some
cases as the default log level is "error".
author | Valentin Bartenev <vbart@nginx.com> |
---|---|
date | Tue, 20 Sep 2016 15:07:16 +0300 |
parents | 4f0f4f02c98f |
children | d16ba0ea3434 |
rev | line source |
---|---|
6317 | 1 |
2 /* | |
3 * Copyright (C) Roman Arutyunyan | |
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 { | |
14 size_t size; | |
15 } ngx_http_slice_loc_conf_t; | |
16 | |
17 | |
18 typedef struct { | |
19 off_t start; | |
20 off_t end; | |
21 ngx_str_t range; | |
22 ngx_str_t etag; | |
23 ngx_uint_t last; /* unsigned last:1; */ | |
24 } ngx_http_slice_ctx_t; | |
25 | |
26 | |
27 typedef struct { | |
28 off_t start; | |
29 off_t end; | |
30 off_t complete_length; | |
31 } ngx_http_slice_content_range_t; | |
32 | |
33 | |
34 static ngx_int_t ngx_http_slice_header_filter(ngx_http_request_t *r); | |
35 static ngx_int_t ngx_http_slice_body_filter(ngx_http_request_t *r, | |
36 ngx_chain_t *in); | |
37 static ngx_int_t ngx_http_slice_parse_content_range(ngx_http_request_t *r, | |
38 ngx_http_slice_content_range_t *cr); | |
39 static ngx_int_t ngx_http_slice_range_variable(ngx_http_request_t *r, | |
40 ngx_http_variable_value_t *v, uintptr_t data); | |
41 static off_t ngx_http_slice_get_start(ngx_http_request_t *r); | |
42 static void *ngx_http_slice_create_loc_conf(ngx_conf_t *cf); | |
43 static char *ngx_http_slice_merge_loc_conf(ngx_conf_t *cf, void *parent, | |
44 void *child); | |
45 static ngx_int_t ngx_http_slice_add_variables(ngx_conf_t *cf); | |
46 static ngx_int_t ngx_http_slice_init(ngx_conf_t *cf); | |
47 | |
48 | |
49 static ngx_command_t ngx_http_slice_filter_commands[] = { | |
50 | |
51 { ngx_string("slice"), | |
52 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, | |
53 ngx_conf_set_size_slot, | |
54 NGX_HTTP_LOC_CONF_OFFSET, | |
55 offsetof(ngx_http_slice_loc_conf_t, size), | |
56 NULL }, | |
57 | |
58 ngx_null_command | |
59 }; | |
60 | |
61 | |
62 static ngx_http_module_t ngx_http_slice_filter_module_ctx = { | |
63 ngx_http_slice_add_variables, /* preconfiguration */ | |
64 ngx_http_slice_init, /* postconfiguration */ | |
65 | |
66 NULL, /* create main configuration */ | |
67 NULL, /* init main configuration */ | |
68 | |
69 NULL, /* create server configuration */ | |
70 NULL, /* merge server configuration */ | |
71 | |
72 ngx_http_slice_create_loc_conf, /* create location configuration */ | |
73 ngx_http_slice_merge_loc_conf /* merge location configuration */ | |
74 }; | |
75 | |
76 | |
77 ngx_module_t ngx_http_slice_filter_module = { | |
78 NGX_MODULE_V1, | |
79 &ngx_http_slice_filter_module_ctx, /* module context */ | |
80 ngx_http_slice_filter_commands, /* module directives */ | |
81 NGX_HTTP_MODULE, /* module type */ | |
82 NULL, /* init master */ | |
83 NULL, /* init module */ | |
84 NULL, /* init process */ | |
85 NULL, /* init thread */ | |
86 NULL, /* exit thread */ | |
87 NULL, /* exit process */ | |
88 NULL, /* exit master */ | |
89 NGX_MODULE_V1_PADDING | |
90 }; | |
91 | |
92 | |
93 static ngx_str_t ngx_http_slice_range_name = ngx_string("slice_range"); | |
94 | |
95 static ngx_http_output_header_filter_pt ngx_http_next_header_filter; | |
96 static ngx_http_output_body_filter_pt ngx_http_next_body_filter; | |
97 | |
98 | |
99 static ngx_int_t | |
100 ngx_http_slice_header_filter(ngx_http_request_t *r) | |
101 { | |
102 off_t end; | |
103 ngx_int_t rc; | |
104 ngx_table_elt_t *h; | |
105 ngx_http_slice_ctx_t *ctx; | |
106 ngx_http_slice_loc_conf_t *slcf; | |
107 ngx_http_slice_content_range_t cr; | |
108 | |
109 ctx = ngx_http_get_module_ctx(r, ngx_http_slice_filter_module); | |
110 if (ctx == NULL) { | |
111 return ngx_http_next_header_filter(r); | |
112 } | |
113 | |
114 if (r->headers_out.status != NGX_HTTP_PARTIAL_CONTENT) { | |
115 if (r == r->main) { | |
116 ngx_http_set_ctx(r, NULL, ngx_http_slice_filter_module); | |
117 return ngx_http_next_header_filter(r); | |
118 } | |
119 | |
120 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
121 "unexpected status code %ui in slice response", | |
122 r->headers_out.status); | |
123 return NGX_ERROR; | |
124 } | |
125 | |
126 h = r->headers_out.etag; | |
127 | |
128 if (ctx->etag.len) { | |
129 if (h == NULL | |
130 || h->value.len != ctx->etag.len | |
131 || ngx_strncmp(h->value.data, ctx->etag.data, ctx->etag.len) | |
132 != 0) | |
133 { | |
134 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
135 "etag mismatch in slice response"); | |
136 return NGX_ERROR; | |
137 } | |
138 } | |
139 | |
140 if (h) { | |
141 ctx->etag = h->value; | |
142 } | |
143 | |
144 if (ngx_http_slice_parse_content_range(r, &cr) != NGX_OK) { | |
145 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
146 "invalid range in slice response"); | |
147 return NGX_ERROR; | |
148 } | |
149 | |
150 if (cr.complete_length == -1) { | |
151 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
152 "no complete length in slice response"); | |
153 return NGX_ERROR; | |
154 } | |
155 | |
156 ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
157 "http slice response range: %O-%O/%O", | |
158 cr.start, cr.end, cr.complete_length); | |
159 | |
160 slcf = ngx_http_get_module_loc_conf(r, ngx_http_slice_filter_module); | |
161 | |
162 end = ngx_min(cr.start + (off_t) slcf->size, cr.complete_length); | |
163 | |
164 if (cr.start != ctx->start || cr.end != end) { | |
165 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
166 "unexpected range in slice response: %O-%O", | |
167 cr.start, cr.end); | |
168 return NGX_ERROR; | |
169 } | |
170 | |
171 ctx->start = end; | |
172 | |
173 r->headers_out.status = NGX_HTTP_OK; | |
174 r->headers_out.status_line.len = 0; | |
175 r->headers_out.content_length_n = cr.complete_length; | |
176 r->headers_out.content_offset = cr.start; | |
177 r->headers_out.content_range->hash = 0; | |
178 r->headers_out.content_range = NULL; | |
179 | |
180 r->allow_ranges = 1; | |
181 r->subrequest_ranges = 1; | |
182 r->single_range = 1; | |
183 | |
184 rc = ngx_http_next_header_filter(r); | |
185 | |
186 if (r != r->main) { | |
187 return rc; | |
188 } | |
189 | |
190 if (r->headers_out.status == NGX_HTTP_PARTIAL_CONTENT) { | |
191 if (ctx->start + (off_t) slcf->size <= r->headers_out.content_offset) { | |
192 ctx->start = slcf->size | |
193 * (r->headers_out.content_offset / slcf->size); | |
194 } | |
195 | |
196 ctx->end = r->headers_out.content_offset | |
197 + r->headers_out.content_length_n; | |
198 | |
199 } else { | |
200 ctx->end = cr.complete_length; | |
201 } | |
202 | |
203 return rc; | |
204 } | |
205 | |
206 | |
207 static ngx_int_t | |
208 ngx_http_slice_body_filter(ngx_http_request_t *r, ngx_chain_t *in) | |
209 { | |
210 ngx_int_t rc; | |
211 ngx_chain_t *cl; | |
212 ngx_http_request_t *sr; | |
213 ngx_http_slice_ctx_t *ctx; | |
214 ngx_http_slice_loc_conf_t *slcf; | |
215 | |
216 ctx = ngx_http_get_module_ctx(r, ngx_http_slice_filter_module); | |
217 | |
218 if (ctx == NULL || r != r->main) { | |
219 return ngx_http_next_body_filter(r, in); | |
220 } | |
221 | |
222 for (cl = in; cl; cl = cl->next) { | |
223 if (cl->buf->last_buf) { | |
224 cl->buf->last_buf = 0; | |
6322
4f0f4f02c98f
Slice filter: terminate first slice with last_in_chain flag.
Roman Arutyunyan <arut@nginx.com>
parents:
6321
diff
changeset
|
225 cl->buf->last_in_chain = 1; |
6317 | 226 cl->buf->sync = 1; |
227 ctx->last = 1; | |
228 } | |
229 } | |
230 | |
231 rc = ngx_http_next_body_filter(r, in); | |
232 | |
233 if (rc == NGX_ERROR || !ctx->last) { | |
234 return rc; | |
235 } | |
236 | |
237 if (ctx->start >= ctx->end) { | |
238 ngx_http_set_ctx(r, NULL, ngx_http_slice_filter_module); | |
239 ngx_http_send_special(r, NGX_HTTP_LAST); | |
240 return rc; | |
241 } | |
242 | |
6321
bc9ea464e354
Slice filter: never run subrequests when main request is buffered.
Roman Arutyunyan <arut@nginx.com>
parents:
6317
diff
changeset
|
243 if (r->buffered) { |
bc9ea464e354
Slice filter: never run subrequests when main request is buffered.
Roman Arutyunyan <arut@nginx.com>
parents:
6317
diff
changeset
|
244 return rc; |
bc9ea464e354
Slice filter: never run subrequests when main request is buffered.
Roman Arutyunyan <arut@nginx.com>
parents:
6317
diff
changeset
|
245 } |
bc9ea464e354
Slice filter: never run subrequests when main request is buffered.
Roman Arutyunyan <arut@nginx.com>
parents:
6317
diff
changeset
|
246 |
6317 | 247 if (ngx_http_subrequest(r, &r->uri, &r->args, &sr, NULL, 0) != NGX_OK) { |
248 return NGX_ERROR; | |
249 } | |
250 | |
251 ngx_http_set_ctx(sr, ctx, ngx_http_slice_filter_module); | |
252 | |
253 slcf = ngx_http_get_module_loc_conf(r, ngx_http_slice_filter_module); | |
254 | |
255 ctx->range.len = ngx_sprintf(ctx->range.data, "bytes=%O-%O", ctx->start, | |
256 ctx->start + (off_t) slcf->size - 1) | |
257 - ctx->range.data; | |
258 | |
259 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
260 "http slice subrequest: \"%V\"", &ctx->range); | |
261 | |
262 return rc; | |
263 } | |
264 | |
265 | |
266 static ngx_int_t | |
267 ngx_http_slice_parse_content_range(ngx_http_request_t *r, | |
268 ngx_http_slice_content_range_t *cr) | |
269 { | |
270 off_t start, end, complete_length, cutoff, cutlim; | |
271 u_char *p; | |
272 ngx_table_elt_t *h; | |
273 | |
274 h = r->headers_out.content_range; | |
275 | |
276 if (h == NULL | |
277 || h->value.len < 7 | |
278 || ngx_strncmp(h->value.data, "bytes ", 6) != 0) | |
279 { | |
280 return NGX_ERROR; | |
281 } | |
282 | |
283 p = h->value.data + 6; | |
284 | |
285 cutoff = NGX_MAX_OFF_T_VALUE / 10; | |
286 cutlim = NGX_MAX_OFF_T_VALUE % 10; | |
287 | |
288 start = 0; | |
289 end = 0; | |
290 complete_length = 0; | |
291 | |
292 while (*p == ' ') { p++; } | |
293 | |
294 if (*p < '0' || *p > '9') { | |
295 return NGX_ERROR; | |
296 } | |
297 | |
298 while (*p >= '0' && *p <= '9') { | |
299 if (start >= cutoff && (start > cutoff || *p - '0' > cutlim)) { | |
300 return NGX_ERROR; | |
301 } | |
302 | |
303 start = start * 10 + *p++ - '0'; | |
304 } | |
305 | |
306 while (*p == ' ') { p++; } | |
307 | |
308 if (*p++ != '-') { | |
309 return NGX_ERROR; | |
310 } | |
311 | |
312 while (*p == ' ') { p++; } | |
313 | |
314 if (*p < '0' || *p > '9') { | |
315 return NGX_ERROR; | |
316 } | |
317 | |
318 while (*p >= '0' && *p <= '9') { | |
319 if (end >= cutoff && (end > cutoff || *p - '0' > cutlim)) { | |
320 return NGX_ERROR; | |
321 } | |
322 | |
323 end = end * 10 + *p++ - '0'; | |
324 } | |
325 | |
326 end++; | |
327 | |
328 while (*p == ' ') { p++; } | |
329 | |
330 if (*p++ != '/') { | |
331 return NGX_ERROR; | |
332 } | |
333 | |
334 while (*p == ' ') { p++; } | |
335 | |
336 if (*p != '*') { | |
337 if (*p < '0' || *p > '9') { | |
338 return NGX_ERROR; | |
339 } | |
340 | |
341 while (*p >= '0' && *p <= '9') { | |
342 if (complete_length >= cutoff | |
343 && (complete_length > cutoff || *p - '0' > cutlim)) | |
344 { | |
345 return NGX_ERROR; | |
346 } | |
347 | |
348 complete_length = complete_length * 10 + *p++ - '0'; | |
349 } | |
350 | |
351 } else { | |
352 complete_length = -1; | |
353 p++; | |
354 } | |
355 | |
356 while (*p == ' ') { p++; } | |
357 | |
358 if (*p != '\0') { | |
359 return NGX_ERROR; | |
360 } | |
361 | |
362 cr->start = start; | |
363 cr->end = end; | |
364 cr->complete_length = complete_length; | |
365 | |
366 return NGX_OK; | |
367 } | |
368 | |
369 | |
370 static ngx_int_t | |
371 ngx_http_slice_range_variable(ngx_http_request_t *r, | |
372 ngx_http_variable_value_t *v, uintptr_t data) | |
373 { | |
374 u_char *p; | |
375 ngx_http_slice_ctx_t *ctx; | |
376 ngx_http_slice_loc_conf_t *slcf; | |
377 | |
378 ctx = ngx_http_get_module_ctx(r, ngx_http_slice_filter_module); | |
379 | |
380 if (ctx == NULL) { | |
381 if (r != r->main || r->headers_out.status) { | |
382 v->not_found = 1; | |
383 return NGX_OK; | |
384 } | |
385 | |
386 slcf = ngx_http_get_module_loc_conf(r, ngx_http_slice_filter_module); | |
387 | |
388 if (slcf->size == 0) { | |
389 v->not_found = 1; | |
390 return NGX_OK; | |
391 } | |
392 | |
393 ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_slice_ctx_t)); | |
394 if (ctx == NULL) { | |
395 return NGX_ERROR; | |
396 } | |
397 | |
398 ngx_http_set_ctx(r, ctx, ngx_http_slice_filter_module); | |
399 | |
400 p = ngx_pnalloc(r->pool, sizeof("bytes=-") - 1 + 2 * NGX_OFF_T_LEN); | |
401 if (p == NULL) { | |
402 return NGX_ERROR; | |
403 } | |
404 | |
405 ctx->start = slcf->size * (ngx_http_slice_get_start(r) / slcf->size); | |
406 | |
407 ctx->range.data = p; | |
408 ctx->range.len = ngx_sprintf(p, "bytes=%O-%O", ctx->start, | |
409 ctx->start + (off_t) slcf->size - 1) | |
410 - p; | |
411 } | |
412 | |
413 v->data = ctx->range.data; | |
414 v->valid = 1; | |
415 v->not_found = 0; | |
416 v->no_cacheable = 1; | |
417 v->len = ctx->range.len; | |
418 | |
419 return NGX_OK; | |
420 } | |
421 | |
422 | |
423 static off_t | |
424 ngx_http_slice_get_start(ngx_http_request_t *r) | |
425 { | |
426 off_t start, cutoff, cutlim; | |
427 u_char *p; | |
428 ngx_table_elt_t *h; | |
429 | |
430 if (r->headers_in.if_range) { | |
431 return 0; | |
432 } | |
433 | |
434 h = r->headers_in.range; | |
435 | |
436 if (h == NULL | |
437 || h->value.len < 7 | |
438 || ngx_strncasecmp(h->value.data, (u_char *) "bytes=", 6) != 0) | |
439 { | |
440 return 0; | |
441 } | |
442 | |
443 p = h->value.data + 6; | |
444 | |
445 if (ngx_strchr(p, ',')) { | |
446 return 0; | |
447 } | |
448 | |
449 while (*p == ' ') { p++; } | |
450 | |
451 if (*p == '-') { | |
452 return 0; | |
453 } | |
454 | |
455 cutoff = NGX_MAX_OFF_T_VALUE / 10; | |
456 cutlim = NGX_MAX_OFF_T_VALUE % 10; | |
457 | |
458 start = 0; | |
459 | |
460 while (*p >= '0' && *p <= '9') { | |
461 if (start >= cutoff && (start > cutoff || *p - '0' > cutlim)) { | |
462 return 0; | |
463 } | |
464 | |
465 start = start * 10 + *p++ - '0'; | |
466 } | |
467 | |
468 return start; | |
469 } | |
470 | |
471 | |
472 static void * | |
473 ngx_http_slice_create_loc_conf(ngx_conf_t *cf) | |
474 { | |
475 ngx_http_slice_loc_conf_t *slcf; | |
476 | |
477 slcf = ngx_palloc(cf->pool, sizeof(ngx_http_slice_loc_conf_t)); | |
478 if (slcf == NULL) { | |
479 return NULL; | |
480 } | |
481 | |
482 slcf->size = NGX_CONF_UNSET_SIZE; | |
483 | |
484 return slcf; | |
485 } | |
486 | |
487 | |
488 static char * | |
489 ngx_http_slice_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) | |
490 { | |
491 ngx_http_slice_loc_conf_t *prev = parent; | |
492 ngx_http_slice_loc_conf_t *conf = child; | |
493 | |
494 ngx_conf_merge_size_value(conf->size, prev->size, 0); | |
495 | |
496 return NGX_CONF_OK; | |
497 } | |
498 | |
499 | |
500 static ngx_int_t | |
501 ngx_http_slice_add_variables(ngx_conf_t *cf) | |
502 { | |
503 ngx_http_variable_t *var; | |
504 | |
505 var = ngx_http_add_variable(cf, &ngx_http_slice_range_name, 0); | |
506 if (var == NULL) { | |
507 return NGX_ERROR; | |
508 } | |
509 | |
510 var->get_handler = ngx_http_slice_range_variable; | |
511 | |
512 return NGX_OK; | |
513 } | |
514 | |
515 | |
516 static ngx_int_t | |
517 ngx_http_slice_init(ngx_conf_t *cf) | |
518 { | |
519 ngx_http_next_header_filter = ngx_http_top_header_filter; | |
520 ngx_http_top_header_filter = ngx_http_slice_header_filter; | |
521 | |
522 ngx_http_next_body_filter = ngx_http_top_body_filter; | |
523 ngx_http_top_body_filter = ngx_http_slice_body_filter; | |
524 | |
525 return NGX_OK; | |
526 } |