comparison src/http/modules/ngx_http_range_filter_module.c @ 4035:c2a91088b0c0

Now if total size of all ranges is greater than source response size, then nginx disables ranges and returns just the source response. This fix should not affect well-behaving applications but will defeat DoS attempts exploiting malicious byte ranges.
author Igor Sysoev <igor@sysoev.ru>
date Fri, 26 Aug 2011 09:42:50 +0000
parents dd1570b6f237
children 20c7c73d3efa
comparison
equal deleted inserted replaced
4034:e2c075e774b6 4035:c2a91088b0c0
144 144
145 static ngx_int_t 145 static ngx_int_t
146 ngx_http_range_header_filter(ngx_http_request_t *r) 146 ngx_http_range_header_filter(ngx_http_request_t *r)
147 { 147 {
148 time_t if_range; 148 time_t if_range;
149 ngx_int_t rc;
150 ngx_http_range_filter_ctx_t *ctx; 149 ngx_http_range_filter_ctx_t *ctx;
151 150
152 if (r->http_version < NGX_HTTP_VERSION_10 151 if (r->http_version < NGX_HTTP_VERSION_10
153 || r->headers_out.status != NGX_HTTP_OK 152 || r->headers_out.status != NGX_HTTP_OK
154 || r != r->main 153 || r != r->main
190 != NGX_OK) 189 != NGX_OK)
191 { 190 {
192 return NGX_ERROR; 191 return NGX_ERROR;
193 } 192 }
194 193
195 rc = ngx_http_range_parse(r, ctx); 194 switch (ngx_http_range_parse(r, ctx)) {
196 195
197 if (rc == NGX_OK) { 196 case NGX_OK:
198
199 ngx_http_set_ctx(r, ctx, ngx_http_range_body_filter_module); 197 ngx_http_set_ctx(r, ctx, ngx_http_range_body_filter_module);
200 198
201 r->headers_out.status = NGX_HTTP_PARTIAL_CONTENT; 199 r->headers_out.status = NGX_HTTP_PARTIAL_CONTENT;
202 r->headers_out.status_line.len = 0; 200 r->headers_out.status_line.len = 0;
203 201
204 if (ctx->ranges.nelts == 1) { 202 if (ctx->ranges.nelts == 1) {
205 return ngx_http_range_singlepart_header(r, ctx); 203 return ngx_http_range_singlepart_header(r, ctx);
206 } 204 }
207 205
208 return ngx_http_range_multipart_header(r, ctx); 206 return ngx_http_range_multipart_header(r, ctx);
209 } 207
210 208 case NGX_HTTP_RANGE_NOT_SATISFIABLE:
211 if (rc == NGX_HTTP_RANGE_NOT_SATISFIABLE) {
212 return ngx_http_range_not_satisfiable(r); 209 return ngx_http_range_not_satisfiable(r);
213 } 210
214 211 case NGX_ERROR:
215 /* rc == NGX_ERROR */ 212 return NGX_ERROR;
216 213
217 return rc; 214 default: /* NGX_DECLINED */
215 break;
216 }
218 217
219 next_filter: 218 next_filter:
220 219
221 r->headers_out.accept_ranges = ngx_list_push(&r->headers_out.headers); 220 r->headers_out.accept_ranges = ngx_list_push(&r->headers_out.headers);
222 if (r->headers_out.accept_ranges == NULL) { 221 if (r->headers_out.accept_ranges == NULL) {
233 232
234 ngx_int_t 233 ngx_int_t
235 ngx_http_range_parse(ngx_http_request_t *r, ngx_http_range_filter_ctx_t *ctx) 234 ngx_http_range_parse(ngx_http_request_t *r, ngx_http_range_filter_ctx_t *ctx)
236 { 235 {
237 u_char *p; 236 u_char *p;
238 off_t start, end; 237 off_t start, end, size;
239 ngx_uint_t suffix; 238 ngx_uint_t suffix;
240 ngx_http_range_t *range; 239 ngx_http_range_t *range;
241 240
242 p = r->headers_in.range->value.data + 6; 241 p = r->headers_in.range->value.data + 6;
242 size = 0;
243 243
244 for ( ;; ) { 244 for ( ;; ) {
245 start = 0; 245 start = 0;
246 end = 0; 246 end = 0;
247 suffix = 0; 247 suffix = 0;
275 return NGX_ERROR; 275 return NGX_ERROR;
276 } 276 }
277 277
278 range->start = start; 278 range->start = start;
279 range->end = r->headers_out.content_length_n; 279 range->end = r->headers_out.content_length_n;
280 size += range->end - start;
280 281
281 if (*p++ != ',') { 282 if (*p++ != ',') {
282 return NGX_OK; 283 break;
283 } 284 }
284 285
285 continue; 286 continue;
286 } 287 }
287 288
329 330
330 } else { 331 } else {
331 range->end = end + 1; 332 range->end = end + 1;
332 } 333 }
333 334
335 size += range->end - start;
336
334 if (*p++ != ',') { 337 if (*p++ != ',') {
335 return NGX_OK; 338 break;
336 } 339 }
337 } 340 }
341
342 if (size > r->headers_out.content_length_n) {
343 return NGX_DECLINED;
344 }
345
346 return NGX_OK;
338 } 347 }
339 348
340 349
341 static ngx_int_t 350 static ngx_int_t
342 ngx_http_range_singlepart_header(ngx_http_request_t *r, 351 ngx_http_range_singlepart_header(ngx_http_request_t *r,