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