| OLD | NEW |
| 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2014, 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 library pub_server.shelf_pubserver; | 5 library pub_server.shelf_pubserver; |
| 6 | 6 |
| 7 import 'dart:async'; | 7 import 'dart:async'; |
| 8 import 'dart:convert'; | 8 import 'dart:convert'; |
| 9 | 9 |
| 10 import 'package:logging/logging.dart'; | 10 import 'package:logging/logging.dart'; |
| (...skipping 290 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 301 }); | 301 }); |
| 302 } | 302 } |
| 303 | 303 |
| 304 Future<shelf.Response> _uploadSimple( | 304 Future<shelf.Response> _uploadSimple( |
| 305 Uri uri, String contentType, Stream<List<int>> stream) { | 305 Uri uri, String contentType, Stream<List<int>> stream) { |
| 306 _logger.info('Perform simple upload.'); | 306 _logger.info('Perform simple upload.'); |
| 307 if (contentType.startsWith('multipart/form-data')) { | 307 if (contentType.startsWith('multipart/form-data')) { |
| 308 var match = _boundaryRegExp.matchAsPrefix(contentType); | 308 var match = _boundaryRegExp.matchAsPrefix(contentType); |
| 309 if (match != null) { | 309 if (match != null) { |
| 310 var boundary = match.group(1); | 310 var boundary = match.group(1); |
| 311 return stream | 311 |
| 312 .transform(new MimeMultipartTransformer(boundary)) | 312 // We have to listen to all multiparts: Just doing `parts.first` will |
| 313 .first.then((MimeMultipart part) { | 313 // result in the cancelation of the subscription which causes |
| 314 // eventually a destruction of the socket, this is an odd side-effect. |
| 315 // What we would like to have is something like this: |
| 316 // parts.expect(1).then((part) { upload(part); }) |
| 317 bool firstPartArrived = false; |
| 318 var completer = new Completer(); |
| 319 var subscription; |
| 320 |
| 321 var parts = stream.transform(new MimeMultipartTransformer(boundary)); |
| 322 subscription = parts.listen((MimeMultipart part) { |
| 323 // If we get more than one part, we'll ignore the rest of the input. |
| 324 if (firstPartArrived) { |
| 325 subscription.cancel(); |
| 326 return; |
| 327 } |
| 328 firstPartArrived = true; |
| 329 |
| 314 // TODO: Ensure that `part.headers['content-disposition']` is | 330 // TODO: Ensure that `part.headers['content-disposition']` is |
| 315 // `form-data; name="file"; filename="package.tar.gz` | 331 // `form-data; name="file"; filename="package.tar.gz` |
| 316 return repository.upload(part).then((_) { | 332 repository.upload(part).then((_) { |
| 333 _logger.info('Redirecting to found url.'); |
| 317 return new shelf.Response.found(_finishUploadSimpleUrl(uri)); | 334 return new shelf.Response.found(_finishUploadSimpleUrl(uri)); |
| 318 }).catchError((error, stack) { | 335 }).catchError((error, stack) { |
| 336 _logger.warning('Error occured: $error\n$stack.'); |
| 319 // TODO: Do error checking and return error codes? | 337 // TODO: Do error checking and return error codes? |
| 320 return new shelf.Response.found( | 338 return new shelf.Response.found( |
| 321 _finishUploadSimpleUrl(uri, error: error)); | 339 _finishUploadSimpleUrl(uri, error: error)); |
| 322 }); | 340 }).then(completer.complete); |
| 323 }); | 341 }); |
| 342 |
| 343 return completer.future; |
| 324 } | 344 } |
| 325 } | 345 } |
| 326 return | 346 return |
| 327 _badRequest('Upload must contain a multipart/form-data content type.'); | 347 _badRequest('Upload must contain a multipart/form-data content type.'); |
| 328 } | 348 } |
| 329 | 349 |
| 330 Future<shelf.Response> _finishUploadSimple(Uri uri) { | 350 Future<shelf.Response> _finishUploadSimple(Uri uri) { |
| 331 var error = uri.queryParameters['error']; | 351 var error = uri.queryParameters['error']; |
| 332 _logger.info('Finish simple upload (error: $error).'); | 352 _logger.info('Finish simple upload (error: $error).'); |
| 333 if (error != null) { | 353 if (error != null) { |
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 390 | 410 |
| 391 Uri _uploadSimpleUrl(Uri url) { | 411 Uri _uploadSimpleUrl(Uri url) { |
| 392 return url.resolve('/api/packages/versions/newUpload'); | 412 return url.resolve('/api/packages/versions/newUpload'); |
| 393 } | 413 } |
| 394 | 414 |
| 395 Uri _finishUploadSimpleUrl(Uri url, {String error}) { | 415 Uri _finishUploadSimpleUrl(Uri url, {String error}) { |
| 396 var postfix = error == null ? '' : '?error=${Uri.encodeComponent(error)}'; | 416 var postfix = error == null ? '' : '?error=${Uri.encodeComponent(error)}'; |
| 397 return url.resolve('/api/packages/versions/newUploadFinish$postfix'); | 417 return url.resolve('/api/packages/versions/newUploadFinish$postfix'); |
| 398 } | 418 } |
| 399 } | 419 } |
| OLD | NEW |