Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(68)

Side by Side Diff: pkg/http_server/lib/src/virtual_directory.dart

Issue 721213002: Fix a number of issues with the Range header handling for serving files (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Addressed review comments Created 6 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « pkg/http_server/CHANGELOG.md ('k') | pkg/http_server/pubspec.yaml » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 part of http_server; 5 part of http_server;
6 6
7 7
8 // Used for signal a directory redirecting, where a tailing slash is missing. 8 // Used for signal a directory redirecting, where a tailing slash is missing.
9 class _DirectoryRedirect { 9 class _DirectoryRedirect {
10 const _DirectoryRedirect(); 10 const _DirectoryRedirect();
(...skipping 191 matching lines...) Expand 10 before | Expand all | Expand 10 after
202 if (request.headers.ifModifiedSince != null && 202 if (request.headers.ifModifiedSince != null &&
203 !lastModified.isAfter(request.headers.ifModifiedSince)) { 203 !lastModified.isAfter(request.headers.ifModifiedSince)) {
204 response.statusCode = HttpStatus.NOT_MODIFIED; 204 response.statusCode = HttpStatus.NOT_MODIFIED;
205 response.close(); 205 response.close();
206 return null; 206 return null;
207 } 207 }
208 208
209 response.headers.set(HttpHeaders.LAST_MODIFIED, lastModified); 209 response.headers.set(HttpHeaders.LAST_MODIFIED, lastModified);
210 response.headers.set(HttpHeaders.ACCEPT_RANGES, "bytes"); 210 response.headers.set(HttpHeaders.ACCEPT_RANGES, "bytes");
211 211
212 if (request.method == 'HEAD') {
213 response.close();
214 return null;
215 }
216
217 return file.length().then((length) { 212 return file.length().then((length) {
218 String range = request.headers.value("range"); 213 String range = request.headers.value(HttpHeaders.RANGE);
219 if (range != null) { 214 if (range != null) {
220 // We only support one range, where the standard support several. 215 // We only support one range, where the standard support several.
221 Match matches = new RegExp(r"^bytes=(\d*)\-(\d*)$").firstMatch(range); 216 Match matches = new RegExp(r"^bytes=(\d*)\-(\d*)$").firstMatch(range);
222 // If the range header have the right format, handle it. 217 // If the range header have the right format, handle it.
223 if (matches != null) { 218 if (matches != null &&
219 (matches[1].isNotEmpty || matches[2].isNotEmpty)) {
224 // Serve sub-range. 220 // Serve sub-range.
225 int start; 221 int start; // First byte position - inclusive.
226 int end; 222 int end; // Last byte position - inclusive.
227 if (matches[1].isEmpty) { 223 if (matches[1].isEmpty) {
228 start = matches[2].isEmpty ? 224 start = length - int.parse(matches[2]);
229 length : 225 if (start < 0) start = 0;
230 length - int.parse(matches[2]); 226 end = length - 1;
231 end = length;
232 } else { 227 } else {
233 start = int.parse(matches[1]); 228 start = int.parse(matches[1]);
234 end = matches[2].isEmpty ? length : int.parse(matches[2]) + 1; 229 end = matches[2].isEmpty ? length - 1: int.parse(matches[2]);
235 } 230 }
231 // If the range is syntactically invalid the Range header
232 // MUST be ignored (RFC 2616 section 14.35.1).
233 if (start <= end) {
234 if (end >= length) {
235 end = length - 1;
236 }
236 237
237 // Override Content-Length with the actual bytes sent. 238 if (start >= length) {
238 response.headers.set(HttpHeaders.CONTENT_LENGTH, end - start); 239 response
240 ..statusCode = HttpStatus.REQUESTED_RANGE_NOT_SATISFIABLE
241 ..close();
242 return;
243 }
239 244
240 // Set 'Partial Content' status code. 245 // Override Content-Length with the actual bytes sent.
241 response.statusCode = HttpStatus.PARTIAL_CONTENT; 246 response.headers.set(HttpHeaders.CONTENT_LENGTH, end - start + 1);
242 response.headers.set(HttpHeaders.CONTENT_RANGE,
243 "bytes $start-${end - 1}/$length");
244 247
245 // Pipe the 'range' of the file. 248 // Set 'Partial Content' status code.
246 file.openRead(start, end) 249 response
247 .pipe(new _VirtualDirectoryFileStream(response, file.path)) 250 ..statusCode = HttpStatus.PARTIAL_CONTENT
248 .catchError((_) { 251 ..headers.set(HttpHeaders.CONTENT_RANGE,
249 // TODO(kevmoo): log errors 252 'bytes $start-$end/$length');
250 }); 253
251 return; 254 // Pipe the 'range' of the file.
255 if (request.method == 'HEAD') {
256 response.close();
257 } else {
258 file.openRead(start, end + 1)
259 .pipe(new _VirtualDirectoryFileStream(response, file.path))
260 .catchError((_) {
261 // TODO(kevmoo): log errors
262 });
263 }
264 return;
265 }
252 } 266 }
253 } 267 }
254 268
255 file.openRead() 269 response.headers.set(HttpHeaders.CONTENT_LENGTH, length);
256 .pipe(new _VirtualDirectoryFileStream(response, file.path)) 270 if (request.method == 'HEAD') {
257 .catchError((_) { 271 response.close();
258 // TODO(kevmoo): log errors 272 } else {
259 }); 273 file.openRead()
274 .pipe(new _VirtualDirectoryFileStream(response, file.path))
275 .catchError((_) {
276 // TODO(kevmoo): log errors
277 });
278 }
260 }); 279 });
261 }).catchError((_) { 280 }).catchError((_) {
262 response.statusCode = HttpStatus.NOT_FOUND; 281 response.statusCode = HttpStatus.NOT_FOUND;
263 response.close(); 282 response.close();
264 }); 283 });
265 } 284 }
266 285
267 void _serveDirectory(Directory dir, HttpRequest request) { 286 void _serveDirectory(Directory dir, HttpRequest request) {
268 if (_dirCallback != null) { 287 if (_dirCallback != null) {
269 _dirCallback(dir, request); 288 _dirCallback(dir, request);
(...skipping 174 matching lines...) Expand 10 before | Expand all | Expand 10 after
444 463
445 Future close() => new Future.value(); 464 Future close() => new Future.value();
446 465
447 void setMimeType(List<int> bytes) { 466 void setMimeType(List<int> bytes) {
448 var mimeType = lookupMimeType(path, headerBytes: bytes); 467 var mimeType = lookupMimeType(path, headerBytes: bytes);
449 if (mimeType != null) { 468 if (mimeType != null) {
450 response.headers.contentType = ContentType.parse(mimeType); 469 response.headers.contentType = ContentType.parse(mimeType);
451 } 470 }
452 } 471 }
453 } 472 }
OLDNEW
« no previous file with comments | « pkg/http_server/CHANGELOG.md ('k') | pkg/http_server/pubspec.yaml » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698