Mercurial > hg > nginx
annotate src/http/modules/ngx_http_flv_module.c @ 4247:b79dbadb3d5e stable-1.0
Merging r4147, r4148, r4149, r4150, r4207:
Fixes of combination of error_page and return directives:
*) Fix for incorrect 201 replies from dav module.
Replies with 201 code contain body, and we should clearly indicate it's
empty if it's empty. Before 0.8.32 chunked was explicitly disabled for
201 replies and as a result empty body was indicated by connection close
(not perfect, but worked). Since 0.8.32 chunked is enabled, and this
causes incorrect responses from dav module when HTTP/1.1 is used: with
"Transfer-Encoding: chunked" but no chunks at all.
Fix is to actually return empty body in special response handler instead
of abusing r->header_only flag.
See here for initial report:
http://mailman.nginx.org/pipermail/nginx-ru/2010-October/037535.html
*) Fix for double content when return is used in error_page handler.
Test case:
location / {
error_page 405 /nope;
return 405;
}
location /nope {
return 200;
}
This is expected to return 405 with empty body, but in 0.8.42+ will return
builtin 405 error page as well (though not counted in Content-Length, thus
breaking protocol).
Fix is to use status provided by rewrite script execution in case
it's less than NGX_HTTP_BAD_REQUEST even if r->error_status set. This
check is in line with one in ngx_http_script_return_code().
Note that this patch also changes behaviour for "return 302 ..." and
"rewrite ... redirect" used as error handler. E.g.
location / {
error_page 405 /redirect;
return 405;
}
location /redirect {
rewrite ^ http://example.com/;
}
will actually return redirect to "http://example.com/" instead of builtin
405 error page with meaningless Location header. This looks like correct
change and it's in line with what happens on e.g. directory redirects
in error handlers.
*) Fix for "return 202" not discarding body.
Big POST (not fully preread) to a
location / {
return 202;
}
resulted in incorrect behaviour due to "return" code path not calling
ngx_http_discard_request_body(). The same applies to all "return" used
with 2xx/3xx codes except 201 and 204, and to all "return ... text" uses.
Fix is to add ngx_http_discard_request_body() call to
ngx_http_send_response() function where it looks appropriate.
Discard body call from emtpy gif module removed as it's now redundant.
Reported by Pyry Hakulinen, see
http://mailman.nginx.org/pipermail/nginx/2011-August/028503.html
*) Incorrect special case for "return 204" removed.
The special case in question leads to replies without body in
configuration like
location / { error_page 404 /zero; return 404; }
location /zero { return 204; }
while replies with empty body are expected per protocol specs.
Correct one will look like
if (status == NGX_HTTP_NO_CONTENT) {
rc = ngx_http_send_header(r);
if (rc == NGX_ERROR || r->header_only) {
return rc;
}
return ngx_http_send_special(r, NGX_HTTP_LAST);
}
though it looks like it's better to drop this special case at all.
*) Clear old Location header (if any) while adding a new one.
This prevents incorrect behaviour when another redirect is issued within
error_page 302 handler.
author | Igor Sysoev <igor@sysoev.ru> |
---|---|
date | Tue, 01 Nov 2011 13:45:33 +0000 |
parents | 84905c7b2aa7 |
children | 2f8e9469b436 |
rev | line source |
---|---|
753 | 1 |
2 /* | |
3 * Copyright (C) Igor Sysoev | |
4 */ | |
5 | |
6 #include <ngx_config.h> | |
7 #include <ngx_core.h> | |
8 #include <ngx_http.h> | |
9 | |
10 | |
11 static char *ngx_http_flv(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); | |
12 | |
13 static ngx_command_t ngx_http_flv_commands[] = { | |
14 | |
15 { ngx_string("flv"), | |
16 NGX_HTTP_LOC_CONF|NGX_CONF_NOARGS, | |
17 ngx_http_flv, | |
18 0, | |
19 0, | |
20 NULL }, | |
21 | |
22 ngx_null_command | |
23 }; | |
24 | |
25 | |
26 static u_char ngx_flv_header[] = "FLV\x1\x1\0\0\0\x9\0\0\0\x9"; | |
27 | |
28 | |
29 static ngx_http_module_t ngx_http_flv_module_ctx = { | |
30 NULL, /* preconfiguration */ | |
31 NULL, /* postconfiguration */ | |
32 | |
33 NULL, /* create main configuration */ | |
34 NULL, /* init main configuration */ | |
35 | |
36 NULL, /* create server configuration */ | |
37 NULL, /* merge server configuration */ | |
38 | |
39 NULL, /* create location configuration */ | |
40 NULL /* merge location configuration */ | |
41 }; | |
42 | |
43 | |
44 ngx_module_t ngx_http_flv_module = { | |
45 NGX_MODULE_V1, | |
46 &ngx_http_flv_module_ctx, /* module context */ | |
47 ngx_http_flv_commands, /* module directives */ | |
48 NGX_HTTP_MODULE, /* module type */ | |
49 NULL, /* init master */ | |
50 NULL, /* init module */ | |
51 NULL, /* init process */ | |
52 NULL, /* init thread */ | |
53 NULL, /* exit thread */ | |
54 NULL, /* exit process */ | |
55 NULL, /* exit master */ | |
56 NGX_MODULE_V1_PADDING | |
57 }; | |
58 | |
59 | |
60 static ngx_int_t | |
61 ngx_http_flv_handler(ngx_http_request_t *r) | |
62 { | |
2415 | 63 u_char *last; |
753 | 64 off_t start, len; |
774
589841f06b87
previous commit broke two modules
Igor Sysoev <igor@sysoev.ru>
parents:
764
diff
changeset
|
65 size_t root; |
753 | 66 ngx_int_t rc; |
764
761a94247118
do not send flv header for full file
Igor Sysoev <igor@sysoev.ru>
parents:
754
diff
changeset
|
67 ngx_uint_t level, i; |
2415 | 68 ngx_str_t path, value; |
753 | 69 ngx_log_t *log; |
70 ngx_buf_t *b; | |
71 ngx_chain_t out[2]; | |
1454 | 72 ngx_open_file_info_t of; |
753 | 73 ngx_http_core_loc_conf_t *clcf; |
74 | |
75 if (!(r->method & (NGX_HTTP_GET|NGX_HTTP_HEAD))) { | |
76 return NGX_HTTP_NOT_ALLOWED; | |
77 } | |
78 | |
79 if (r->uri.data[r->uri.len - 1] == '/') { | |
80 return NGX_DECLINED; | |
81 } | |
82 | |
1370
cc114c85be0f
rename ngx_http_discard_body() to ngx_http_discard_request_body()
Igor Sysoev <igor@sysoev.ru>
parents:
1048
diff
changeset
|
83 rc = ngx_http_discard_request_body(r); |
753 | 84 |
1374 | 85 if (rc != NGX_OK) { |
753 | 86 return rc; |
87 } | |
88 | |
1454 | 89 last = ngx_http_map_uri_to_path(r, &path, &root, 0); |
90 if (last == NULL) { | |
753 | 91 return NGX_HTTP_INTERNAL_SERVER_ERROR; |
92 } | |
93 | |
94 log = r->connection->log; | |
95 | |
1454 | 96 path.len = last - path.data; |
753 | 97 |
1454 | 98 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0, |
99 "http flv filename: \"%V\"", &path); | |
100 | |
101 clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); | |
753 | 102 |
2068
75a8d34459c5
ngx_memzero() ngx_open_file_info_t
Igor Sysoev <igor@sysoev.ru>
parents:
2063
diff
changeset
|
103 ngx_memzero(&of, sizeof(ngx_open_file_info_t)); |
75a8d34459c5
ngx_memzero() ngx_open_file_info_t
Igor Sysoev <igor@sysoev.ru>
parents:
2063
diff
changeset
|
104 |
3178 | 105 of.read_ahead = clcf->read_ahead; |
2129 | 106 of.directio = clcf->directio; |
1767
c42431762903
open_file_cache_retest > open_file_cache_valid
Igor Sysoev <igor@sysoev.ru>
parents:
1696
diff
changeset
|
107 of.valid = clcf->open_file_cache_valid; |
1772 | 108 of.min_uses = clcf->open_file_cache_min_uses; |
1454 | 109 of.errors = clcf->open_file_cache_errors; |
1457 | 110 of.events = clcf->open_file_cache_events; |
1560
25ee6eee7573
style fix: remove trailing spaces
Igor Sysoev <igor@sysoev.ru>
parents:
1553
diff
changeset
|
111 |
1799 | 112 if (ngx_open_cached_file(clcf->open_file_cache, &path, &of, r->pool) |
113 != NGX_OK) | |
114 { | |
1454 | 115 switch (of.err) { |
116 | |
117 case 0: | |
118 return NGX_HTTP_INTERNAL_SERVER_ERROR; | |
119 | |
120 case NGX_ENOENT: | |
121 case NGX_ENOTDIR: | |
122 case NGX_ENAMETOOLONG: | |
123 | |
753 | 124 level = NGX_LOG_ERR; |
125 rc = NGX_HTTP_NOT_FOUND; | |
1454 | 126 break; |
753 | 127 |
1454 | 128 case NGX_EACCES: |
129 | |
753 | 130 level = NGX_LOG_ERR; |
131 rc = NGX_HTTP_FORBIDDEN; | |
1454 | 132 break; |
753 | 133 |
1454 | 134 default: |
135 | |
753 | 136 level = NGX_LOG_CRIT; |
137 rc = NGX_HTTP_INTERNAL_SERVER_ERROR; | |
1454 | 138 break; |
753 | 139 } |
140 | |
141 if (rc != NGX_HTTP_NOT_FOUND || clcf->log_not_found) { | |
1454 | 142 ngx_log_error(level, log, of.err, |
2756
09cab3f8d92e
*) of.test_only to not open file if only stat() is enough
Igor Sysoev <igor@sysoev.ru>
parents:
2721
diff
changeset
|
143 "%s \"%s\" failed", of.failed, path.data); |
753 | 144 } |
145 | |
146 return rc; | |
147 } | |
148 | |
1454 | 149 if (!of.is_file) { |
753 | 150 |
1696 | 151 if (ngx_close_file(of.fd) == NGX_FILE_ERROR) { |
753 | 152 ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, |
153 ngx_close_file_n " \"%s\" failed", path.data); | |
154 } | |
155 | |
156 return NGX_DECLINED; | |
157 } | |
158 | |
2444
aee735f41627
set r->root_tested for non-error_page response only
Igor Sysoev <igor@sysoev.ru>
parents:
2415
diff
changeset
|
159 r->root_tested = !r->error_page; |
2087
c8039b26a949
always test root existence for access_log with variables
Igor Sysoev <igor@sysoev.ru>
parents:
2086
diff
changeset
|
160 |
753 | 161 start = 0; |
1454 | 162 len = of.size; |
764
761a94247118
do not send flv header for full file
Igor Sysoev <igor@sysoev.ru>
parents:
754
diff
changeset
|
163 i = 1; |
753 | 164 |
165 if (r->args.len) { | |
166 | |
2415 | 167 if (ngx_http_arg(r, (u_char *) "start", 5, &value) == NGX_OK) { |
2086
22d36702c654
allow several values in query string
Igor Sysoev <igor@sysoev.ru>
parents:
2068
diff
changeset
|
168 |
2415 | 169 start = ngx_atoof(value.data, value.len); |
753 | 170 |
171 if (start == NGX_ERROR || start >= len) { | |
172 start = 0; | |
173 } | |
174 | |
764
761a94247118
do not send flv header for full file
Igor Sysoev <igor@sysoev.ru>
parents:
754
diff
changeset
|
175 if (start) { |
761a94247118
do not send flv header for full file
Igor Sysoev <igor@sysoev.ru>
parents:
754
diff
changeset
|
176 len = sizeof(ngx_flv_header) - 1 + len - start; |
761a94247118
do not send flv header for full file
Igor Sysoev <igor@sysoev.ru>
parents:
754
diff
changeset
|
177 i = 0; |
761a94247118
do not send flv header for full file
Igor Sysoev <igor@sysoev.ru>
parents:
754
diff
changeset
|
178 } |
753 | 179 } |
180 } | |
181 | |
182 log->action = "sending flv to client"; | |
183 | |
184 r->headers_out.status = NGX_HTTP_OK; | |
764
761a94247118
do not send flv header for full file
Igor Sysoev <igor@sysoev.ru>
parents:
754
diff
changeset
|
185 r->headers_out.content_length_n = len; |
1454 | 186 r->headers_out.last_modified_time = of.mtime; |
753 | 187 |
188 if (ngx_http_set_content_type(r) != NGX_OK) { | |
754
4ac89c5aa10d
style fix: remove trailing spaces
Igor Sysoev <igor@sysoev.ru>
parents:
753
diff
changeset
|
189 return NGX_HTTP_INTERNAL_SERVER_ERROR; |
753 | 190 } |
191 | |
764
761a94247118
do not send flv header for full file
Igor Sysoev <igor@sysoev.ru>
parents:
754
diff
changeset
|
192 if (i == 0) { |
761a94247118
do not send flv header for full file
Igor Sysoev <igor@sysoev.ru>
parents:
754
diff
changeset
|
193 b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t)); |
761a94247118
do not send flv header for full file
Igor Sysoev <igor@sysoev.ru>
parents:
754
diff
changeset
|
194 if (b == NULL) { |
761a94247118
do not send flv header for full file
Igor Sysoev <igor@sysoev.ru>
parents:
754
diff
changeset
|
195 return NGX_HTTP_INTERNAL_SERVER_ERROR; |
761a94247118
do not send flv header for full file
Igor Sysoev <igor@sysoev.ru>
parents:
754
diff
changeset
|
196 } |
753 | 197 |
764
761a94247118
do not send flv header for full file
Igor Sysoev <igor@sysoev.ru>
parents:
754
diff
changeset
|
198 b->pos = ngx_flv_header; |
761a94247118
do not send flv header for full file
Igor Sysoev <igor@sysoev.ru>
parents:
754
diff
changeset
|
199 b->last = ngx_flv_header + sizeof(ngx_flv_header) - 1; |
761a94247118
do not send flv header for full file
Igor Sysoev <igor@sysoev.ru>
parents:
754
diff
changeset
|
200 b->memory = 1; |
753 | 201 |
764
761a94247118
do not send flv header for full file
Igor Sysoev <igor@sysoev.ru>
parents:
754
diff
changeset
|
202 out[0].buf = b; |
761a94247118
do not send flv header for full file
Igor Sysoev <igor@sysoev.ru>
parents:
754
diff
changeset
|
203 out[0].next = &out[1]; |
761a94247118
do not send flv header for full file
Igor Sysoev <igor@sysoev.ru>
parents:
754
diff
changeset
|
204 } |
753 | 205 |
781
836f099aa5cb
allow ranges for full flv files
Igor Sysoev <igor@sysoev.ru>
parents:
774
diff
changeset
|
206 |
753 | 207 b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t)); |
208 if (b == NULL) { | |
209 return NGX_HTTP_INTERNAL_SERVER_ERROR; | |
210 } | |
211 | |
212 b->file = ngx_pcalloc(r->pool, sizeof(ngx_file_t)); | |
213 if (b->file == NULL) { | |
214 return NGX_HTTP_INTERNAL_SERVER_ERROR; | |
215 } | |
216 | |
2122
d090fa684433
allow range for partial flv response
Igor Sysoev <igor@sysoev.ru>
parents:
2087
diff
changeset
|
217 r->allow_ranges = 1; |
d090fa684433
allow range for partial flv response
Igor Sysoev <igor@sysoev.ru>
parents:
2087
diff
changeset
|
218 |
753 | 219 rc = ngx_http_send_header(r); |
220 | |
221 if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) { | |
222 return rc; | |
223 } | |
224 | |
225 b->file_pos = start; | |
1454 | 226 b->file_last = of.size; |
753 | 227 |
228 b->in_file = b->file_last ? 1: 0; | |
229 b->last_buf = 1; | |
230 b->last_in_chain = 1; | |
231 | |
1696 | 232 b->file->fd = of.fd; |
753 | 233 b->file->name = path; |
234 b->file->log = log; | |
2231
8564129d49b6
*) handle unaligned file part for directio
Igor Sysoev <igor@sysoev.ru>
parents:
2129
diff
changeset
|
235 b->file->directio = of.is_directio; |
753 | 236 |
237 out[1].buf = b; | |
238 out[1].next = NULL; | |
239 | |
764
761a94247118
do not send flv header for full file
Igor Sysoev <igor@sysoev.ru>
parents:
754
diff
changeset
|
240 return ngx_http_output_filter(r, &out[i]); |
753 | 241 } |
242 | |
243 | |
244 static char * | |
245 ngx_http_flv(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) | |
246 { | |
247 ngx_http_core_loc_conf_t *clcf; | |
248 | |
249 clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module); | |
250 clcf->handler = ngx_http_flv_handler; | |
251 | |
252 return NGX_CONF_OK; | |
253 } |