Mercurial > hg > ngx_http_bytes_filter_module
comparison ngx_http_bytes_filter_module.c @ 1:6b995d5251ec
Implement bytes= argument parsing.
The only known problem is that it doesn't reject 'bytes=-' as invalid (suffix
byte range specification must contain suffix length per RFC 2616).
author | Maxim Dounin <mdounin@mdounin.ru> |
---|---|
date | Sat, 28 Jun 2008 20:20:50 +0400 |
parents | 8aec31ab4d52 |
children | 13a2fbcc8bc4 |
comparison
equal
deleted
inserted
replaced
0:8aec31ab4d52 | 1:6b995d5251ec |
---|---|
80 | 80 |
81 | 81 |
82 static ngx_int_t | 82 static ngx_int_t |
83 ngx_http_bytes_header_filter(ngx_http_request_t *r) | 83 ngx_http_bytes_header_filter(ngx_http_request_t *r) |
84 { | 84 { |
85 u_char *p; | 85 u_char *p, *last; |
86 off_t start, end; | |
87 ngx_uint_t suffix, bad; | |
88 ngx_http_bytes_t *range; | |
86 ngx_http_bytes_conf_t *conf; | 89 ngx_http_bytes_conf_t *conf; |
87 ngx_http_bytes_ctx_t *ctx; | 90 ngx_http_bytes_ctx_t *ctx; |
91 enum { | |
92 sw_start = 0, | |
93 sw_first_byte_pos, | |
94 sw_first_byte_pos_n, | |
95 sw_last_byte_pos, | |
96 sw_last_byte_pos_n, | |
97 sw_done | |
98 } state = 0; | |
88 | 99 |
89 conf = ngx_http_get_module_loc_conf(r, ngx_http_bytes_filter_module); | 100 conf = ngx_http_get_module_loc_conf(r, ngx_http_bytes_filter_module); |
90 | 101 |
91 if (!conf->enable || r->args.len == 0) { | 102 if (!conf->enable || r->args.len == 0) { |
92 return ngx_http_next_header_filter(r); | 103 return ngx_http_next_header_filter(r); |
100 | 111 |
101 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | 112 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, |
102 "bytes header filter: r %p", r); | 113 "bytes header filter: r %p", r); |
103 | 114 |
104 p += sizeof("bytes=") - 1; | 115 p += sizeof("bytes=") - 1; |
116 last = r->args.data + r->args.len; | |
105 | 117 |
106 /* create context */ | 118 /* create context */ |
107 | 119 |
108 ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_bytes_ctx_t)); | 120 ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_bytes_ctx_t)); |
109 if (ctx == NULL) { | 121 if (ctx == NULL) { |
119 /* | 131 /* |
120 * bytes= contain ranges compatible with RFC 2616, "14.35.1 Byte Ranges", | 132 * bytes= contain ranges compatible with RFC 2616, "14.35.1 Byte Ranges", |
121 * but no whitespaces permitted | 133 * but no whitespaces permitted |
122 */ | 134 */ |
123 | 135 |
124 #if 0 | 136 bad = 0; |
125 for ( ;; ) { | 137 |
126 start = 0; | 138 while (p < last) { |
127 end = 0; | 139 |
128 suffix = 0; | 140 switch (state) { |
129 | 141 |
130 if (*p != '-') { | 142 case sw_start: |
143 case sw_first_byte_pos: | |
144 if (*p == '-') { | |
145 p++; | |
146 suffix = 1; | |
147 state = sw_last_byte_pos; | |
148 break; | |
149 } | |
150 suffix = 0; | |
151 start = 0; | |
152 state = sw_first_byte_pos_n; | |
153 | |
154 /* fall through */ | |
155 | |
156 case sw_first_byte_pos_n: | |
157 if (*p == '-') { | |
158 p++; | |
159 state = sw_last_byte_pos; | |
160 break; | |
161 } | |
131 if (*p < '0' || *p > '9') { | 162 if (*p < '0' || *p > '9') { |
132 break; | 163 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, |
133 } | 164 "bytes header filter: unexpected char '%c'" |
134 | 165 " (expected first-byte-pos)", *p); |
135 while (*p >= '0' && *p <= '9') { | 166 bad = 1; |
136 start = start * 10 + *p++ - '0'; | 167 break; |
137 } | 168 } |
138 | 169 start = start * 10 + *p - '0'; |
139 if (*p != '-') { | |
140 break; | |
141 } | |
142 | |
143 if (*p == ',' || *p == '\0') { | |
144 /* no last-byte-pos, assume end of file */ | |
145 end = len - 1; | |
146 } | |
147 | |
148 } else { | |
149 suffix = 1; | |
150 p++; | 170 p++; |
171 break; | |
172 | |
173 case sw_last_byte_pos: | |
174 if (*p == ',' || *p == '&' || *p == ';') { | |
175 /* no last byte pos, assume end of file */ | |
176 end = r->headers_out.content_length_n - 1; | |
177 state = sw_done; | |
178 break; | |
179 } | |
180 end = 0; | |
181 state = sw_last_byte_pos_n; | |
182 | |
183 /* fall though */ | |
184 | |
185 case sw_last_byte_pos_n: | |
186 if (*p == ',' || *p == '&' || *p == ';') { | |
187 state = sw_done; | |
188 break; | |
189 } | |
190 if (*p < '0' || *p > '9') { | |
191 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
192 "bytes header filter: unexpected char '%c'" | |
193 " (expected last-byte-pos)", *p); | |
194 bad = 1; | |
195 break; | |
196 } | |
197 end = end * 10 + *p - '0'; | |
198 p++; | |
199 break; | |
200 | |
201 case sw_done: | |
202 range = ngx_array_push(&ctx->ranges); | |
203 if (range == NULL) { | |
204 return NGX_ERROR; | |
205 } | |
206 | |
207 if (suffix) { | |
208 start = r->headers_out.content_length_n - end; | |
209 end = r->headers_out.content_length_n - 1; | |
210 } | |
211 | |
212 /* note: range->end isn't inclusive, while last-byte-pos is */ | |
213 | |
214 range->start = start; | |
215 range->end = end + 1; | |
216 | |
217 if (*p == ',') { | |
218 p++; | |
219 state = sw_first_byte_pos; | |
220 break; | |
221 } | |
222 | |
223 goto done; | |
224 | |
151 } | 225 } |
152 } | 226 |
153 #endif | 227 if (bad) { |
154 | 228 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, |
155 /* ... */ | 229 "bytes header filter: invalid range specification"); |
230 return ngx_http_next_header_filter(r); | |
231 } | |
232 } | |
233 | |
234 switch (state) { | |
235 | |
236 case sw_last_byte_pos: | |
237 end = r->headers_out.content_length_n - 1; | |
238 | |
239 /* fall through */ | |
240 | |
241 case sw_last_byte_pos_n: | |
242 range = ngx_array_push(&ctx->ranges); | |
243 if (range == NULL) { | |
244 return NGX_ERROR; | |
245 } | |
246 | |
247 if (suffix) { | |
248 start = r->headers_out.content_length_n - end; | |
249 end = r->headers_out.content_length_n - 1; | |
250 } | |
251 | |
252 range->start = start; | |
253 range->end = end + 1; | |
254 | |
255 break; | |
256 | |
257 default: | |
258 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
259 "bytes header filter: invalid range specification"); | |
260 return ngx_http_next_header_filter(r); | |
261 | |
262 } | |
263 | |
264 done: | |
265 /* ... fix content-length */ | |
156 | 266 |
157 ngx_http_set_ctx(r, ctx, ngx_http_bytes_filter_module); | 267 ngx_http_set_ctx(r, ctx, ngx_http_bytes_filter_module); |
158 | 268 |
159 return ngx_http_next_header_filter(r); | 269 return ngx_http_next_header_filter(r); |
160 } | 270 } |
161 | 271 |
162 | 272 |
163 static ngx_int_t | 273 static ngx_int_t |
164 ngx_http_bytes_body_filter(ngx_http_request_t *r, ngx_chain_t *in) | 274 ngx_http_bytes_body_filter(ngx_http_request_t *r, ngx_chain_t *in) |
165 { | 275 { |
276 ngx_uint_t i; | |
166 ngx_http_bytes_ctx_t *ctx; | 277 ngx_http_bytes_ctx_t *ctx; |
278 ngx_http_bytes_t *range; | |
167 | 279 |
168 ctx = ngx_http_get_module_ctx(r, ngx_http_bytes_filter_module); | 280 ctx = ngx_http_get_module_ctx(r, ngx_http_bytes_filter_module); |
169 | 281 |
170 if (ctx == NULL) { | 282 if (ctx == NULL) { |
171 return ngx_http_next_body_filter(r, in); | 283 return ngx_http_next_body_filter(r, in); |
172 } | 284 } |
173 | 285 |
174 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | 286 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, |
175 "bytes body filter: r %p, in %p", r, in); | 287 "bytes body filter: r %p, in %p", r, in); |
288 | |
289 range = ctx->ranges.elts; | |
290 | |
291 for (i = 0; i < ctx->ranges.nelts; i++) { | |
292 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
293 "bytes body filter: %O-%O", range->start, range->end); | |
294 range++; | |
295 } | |
176 | 296 |
177 return ngx_http_next_body_filter(r, in); | 297 return ngx_http_next_body_filter(r, in); |
178 } | 298 } |
179 | 299 |
180 | 300 |