1 Jeff Trawick <[email protected]> |
|
2 Subject [PATCH] byterange patch for 2.2.20 |
|
3 Date Thu, 08 Sep 2011 15:16:11 GMT |
|
4 |
|
5 Here's what I have at present: |
|
6 http://people.apache.org/~trawick/2.2.20-byterange-fixes.txt |
|
7 |
|
8 (compiled-in max ranges, uses same AP_ symbol as 2.2.21 even though |
|
9 the compiled-in version isn't the same type of "DEFAULT") |
|
10 |
|
11 --- modules/http/byterange_filter.c.orig 2011-09-08 11:03:54.000000000 -0400 |
|
12 +++ modules/http/byterange_filter.c 2011-09-08 11:02:36.000000000 -0400 |
|
13 @@ -55,6 +55,10 @@ |
|
14 #include <unistd.h> |
|
15 #endif |
|
16 |
|
17 +#ifndef AP_DEFAULT_MAX_RANGES |
|
18 +#define AP_DEFAULT_MAX_RANGES 200 |
|
19 +#endif |
|
20 + |
|
21 static int ap_set_byterange(request_rec *r, apr_off_t clength, |
|
22 apr_array_header_t **indexes); |
|
23 |
|
24 @@ -83,8 +87,6 @@ |
|
25 apr_bucket *first = NULL, *last = NULL, *out_first = NULL, *e; |
|
26 apr_uint64_t pos = 0, off_first = 0, off_last = 0; |
|
27 apr_status_t rv; |
|
28 - const char *s; |
|
29 - apr_size_t len; |
|
30 apr_uint64_t start64, end64; |
|
31 apr_off_t pofft = 0; |
|
32 |
|
33 @@ -136,44 +138,10 @@ |
|
34 if (e == first) { |
|
35 if (off_first != start64) { |
|
36 rv = apr_bucket_split(copy, (apr_size_t)(start64 - off_first)); |
|
37 - if (rv == APR_ENOTIMPL) { |
|
38 - rv = apr_bucket_read(copy, &s, &len, APR_BLOCK_READ); |
|
39 - if (rv != APR_SUCCESS) { |
|
40 - apr_brigade_cleanup(bbout); |
|
41 - return rv; |
|
42 - } |
|
43 - /* |
|
44 - * The read above might have morphed copy in a bucket |
|
45 - * of shorter length. So read and delete until we reached |
|
46 - * the correct bucket for splitting. |
|
47 - */ |
|
48 - while (start64 - off_first > (apr_uint64_t)copy->length) { |
|
49 - apr_bucket *tmp = APR_BUCKET_NEXT(copy); |
|
50 - off_first += (apr_uint64_t)copy->length; |
|
51 - APR_BUCKET_REMOVE(copy); |
|
52 - apr_bucket_destroy(copy); |
|
53 - copy = tmp; |
|
54 - rv = apr_bucket_read(copy, &s, &len, APR_BLOCK_READ); |
|
55 - if (rv != APR_SUCCESS) { |
|
56 - apr_brigade_cleanup(bbout); |
|
57 - return rv; |
|
58 - } |
|
59 - } |
|
60 - if (start64 > off_first) { |
|
61 - rv = apr_bucket_split(copy, (apr_size_t)(start64 - off_first)); |
|
62 if (rv != APR_SUCCESS) { |
|
63 apr_brigade_cleanup(bbout); |
|
64 return rv; |
|
65 } |
|
66 - } |
|
67 - else { |
|
68 - copy = APR_BUCKET_PREV(copy); |
|
69 - } |
|
70 - } |
|
71 - else if (rv != APR_SUCCESS) { |
|
72 - apr_brigade_cleanup(bbout); |
|
73 - return rv; |
|
74 - } |
|
75 out_first = APR_BUCKET_NEXT(copy); |
|
76 APR_BUCKET_REMOVE(copy); |
|
77 apr_bucket_destroy(copy); |
|
78 @@ -189,38 +157,10 @@ |
|
79 } |
|
80 if (end64 - off_last != (apr_uint64_t)e->length) { |
|
81 rv = apr_bucket_split(copy, (apr_size_t)(end64 + 1 - off_last)); |
|
82 - if (rv == APR_ENOTIMPL) { |
|
83 - rv = apr_bucket_read(copy, &s, &len, APR_BLOCK_READ); |
|
84 if (rv != APR_SUCCESS) { |
|
85 apr_brigade_cleanup(bbout); |
|
86 return rv; |
|
87 } |
|
88 - /* |
|
89 - * The read above might have morphed copy in a bucket |
|
90 - * of shorter length. So read until we reached |
|
91 - * the correct bucket for splitting. |
|
92 - */ |
|
93 - while (end64 + 1 - off_last > (apr_uint64_t)copy->length) { |
|
94 - off_last += (apr_uint64_t)copy->length; |
|
95 - copy = APR_BUCKET_NEXT(copy); |
|
96 - rv = apr_bucket_read(copy, &s, &len, APR_BLOCK_READ); |
|
97 - if (rv != APR_SUCCESS) { |
|
98 - apr_brigade_cleanup(bbout); |
|
99 - return rv; |
|
100 - } |
|
101 - } |
|
102 - if (end64 < off_last + (apr_uint64_t)copy->length - 1) { |
|
103 - rv = apr_bucket_split(copy, end64 + 1 - off_last); |
|
104 - if (rv != APR_SUCCESS) { |
|
105 - apr_brigade_cleanup(bbout); |
|
106 - return rv; |
|
107 - } |
|
108 - } |
|
109 - } |
|
110 - else if (rv != APR_SUCCESS) { |
|
111 - apr_brigade_cleanup(bbout); |
|
112 - return rv; |
|
113 - } |
|
114 copy = APR_BUCKET_NEXT(copy); |
|
115 if (copy != APR_BRIGADE_SENTINEL(bbout)) { |
|
116 APR_BUCKET_REMOVE(copy); |
|
117 @@ -243,6 +183,20 @@ |
|
118 apr_off_t end; |
|
119 } indexes_t; |
|
120 |
|
121 +static apr_status_t send_416(ap_filter_t *f, apr_bucket_brigade *tmpbb) |
|
122 +{ |
|
123 + apr_bucket *e; |
|
124 + conn_rec *c = f->r->connection; |
|
125 + ap_remove_output_filter(f); |
|
126 + f->r->status = HTTP_OK; |
|
127 + e = ap_bucket_error_create(HTTP_RANGE_NOT_SATISFIABLE, NULL, |
|
128 + f->r->pool, c->bucket_alloc); |
|
129 + APR_BRIGADE_INSERT_TAIL(tmpbb, e); |
|
130 + e = apr_bucket_eos_create(c->bucket_alloc); |
|
131 + APR_BRIGADE_INSERT_TAIL(tmpbb, e); |
|
132 + return ap_pass_brigade(f->next, tmpbb); |
|
133 +} |
|
134 + |
|
135 AP_CORE_DECLARE_NONSTD(apr_status_t) ap_byterange_filter(ap_filter_t *f, |
|
136 apr_bucket_brigade *bb) |
|
137 { |
|
138 @@ -290,17 +244,23 @@ |
|
139 num_ranges = ap_set_byterange(r, clength, &indexes); |
|
140 |
|
141 /* We have nothing to do, get out of the way. */ |
|
142 - if (num_ranges == 0) { |
|
143 + if (num_ranges == 0 || (AP_DEFAULT_MAX_RANGES >= 0 && num_ranges > AP_DEFAULT_MAX_RANGES)) { |
|
144 r->status = original_status; |
|
145 ap_remove_output_filter(f); |
|
146 return ap_pass_brigade(f->next, bb); |
|
147 } |
|
148 |
|
149 + /* this brigade holds what we will be sending */ |
|
150 + bsend = apr_brigade_create(r->pool, c->bucket_alloc); |
|
151 + |
|
152 + if (num_ranges < 0) |
|
153 + return send_416(f, bsend); |
|
154 + |
|
155 if (num_ranges > 1) { |
|
156 /* Is ap_make_content_type required here? */ |
|
157 const char *orig_ct = ap_make_content_type(r, r->content_type); |
|
158 boundary = apr_psprintf(r->pool, "%" APR_UINT64_T_HEX_FMT "%lx", |
|
159 - (apr_uint64_t)r->request_time, (long) getpid()); |
|
160 + (apr_uint64_t)r->request_time, c->id); |
|
161 |
|
162 ap_set_content_type(r, apr_pstrcat(r->pool, "multipart", |
|
163 use_range_x(r) ? "/x-" : "/", |
|
164 @@ -325,8 +285,6 @@ |
|
165 ap_xlate_proto_to_ascii(bound_head, strlen(bound_head)); |
|
166 } |
|
167 |
|
168 - /* this brigade holds what we will be sending */ |
|
169 - bsend = apr_brigade_create(r->pool, c->bucket_alloc); |
|
170 tmpbb = apr_brigade_create(r->pool, c->bucket_alloc); |
|
171 |
|
172 idx = (indexes_t *)indexes->elts; |
|
173 @@ -384,15 +342,8 @@ |
|
174 } |
|
175 |
|
176 if (found == 0) { |
|
177 - ap_remove_output_filter(f); |
|
178 - r->status = HTTP_OK; |
|
179 /* bsend is assumed to be empty if we get here. */ |
|
180 - e = ap_bucket_error_create(HTTP_RANGE_NOT_SATISFIABLE, NULL, |
|
181 - r->pool, c->bucket_alloc); |
|
182 - APR_BRIGADE_INSERT_TAIL(bsend, e); |
|
183 - e = apr_bucket_eos_create(c->bucket_alloc); |
|
184 - APR_BRIGADE_INSERT_TAIL(bsend, e); |
|
185 - return ap_pass_brigade(f->next, bsend); |
|
186 + return send_416(f, bsend); |
|
187 } |
|
188 |
|
189 if (num_ranges > 1) { |
|
190 @@ -424,7 +375,7 @@ |
|
191 const char *match; |
|
192 const char *ct; |
|
193 char *cur; |
|
194 - int num_ranges = 0; |
|
195 + int num_ranges = 0, unsatisfiable = 0; |
|
196 apr_off_t sum_lengths = 0; |
|
197 indexes_t *idx; |
|
198 int ranges = 1; |
|
199 @@ -497,14 +448,25 @@ |
|
200 char *errp; |
|
201 apr_off_t number, start, end; |
|
202 |
|
203 - if (!(dash = strchr(cur, '-'))) { |
|
204 + if (!*cur) |
|
205 break; |
|
206 + |
|
207 + /* |
|
208 + * Per RFC 2616 14.35.1: If there is at least one syntactically invalid |
|
209 + * byte-range-spec, we must ignore the whole header. |
|
210 + */ |
|
211 + |
|
212 + if (!(dash = strchr(cur, '-'))) { |
|
213 + return 0; |
|
214 } |
|
215 |
|
216 - if (dash == range) { |
|
217 + if (dash == cur) { |
|
218 /* In the form "-5" */ |
|
219 if (apr_strtoff(&number, dash+1, &errp, 10) || *errp) { |
|
220 - break; |
|
221 + return 0; |
|
222 + } |
|
223 + if (number < 1) { |
|
224 + return 0; |
|
225 } |
|
226 start = clength - number; |
|
227 end = clength - 1; |
|
228 @@ -512,14 +474,17 @@ |
|
229 else { |
|
230 *dash++ = '\0'; |
|
231 if (apr_strtoff(&number, cur, &errp, 10) || *errp) { |
|
232 - break; |
|
233 + return 0; |
|
234 } |
|
235 start = number; |
|
236 if (*dash) { |
|
237 if (apr_strtoff(&number, dash, &errp, 10) || *errp) { |
|
238 - break; |
|
239 + return 0; |
|
240 } |
|
241 end = number; |
|
242 + if (start > end) { |
|
243 + return 0; |
|
244 + } |
|
245 } |
|
246 else { /* "5-" */ |
|
247 end = clength - 1; |
|
248 @@ -529,15 +494,14 @@ |
|
249 if (start < 0) { |
|
250 start = 0; |
|
251 } |
|
252 + if (start >= clength) { |
|
253 + unsatisfiable = 1; |
|
254 + continue; |
|
255 + } |
|
256 if (end >= clength) { |
|
257 end = clength - 1; |
|
258 } |
|
259 |
|
260 - if (start > end) { |
|
261 - /* ignore? count? */ |
|
262 - break; |
|
263 - } |
|
264 - |
|
265 idx = (indexes_t *)apr_array_push(*indexes); |
|
266 idx->start = start; |
|
267 idx->end = end; |
|
268 @@ -546,6 +510,10 @@ |
|
269 num_ranges++; |
|
270 } |
|
271 |
|
272 + if (num_ranges == 0 && unsatisfiable) { |
|
273 + /* If all ranges are unsatisfiable, we should return 416 */ |
|
274 + return -1; |
|
275 + } |
|
276 if (sum_lengths >= clength) { |
|
277 ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, |
|
278 "Sum of ranges not smaller than file, ignoring."); |
|