OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file |
| 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. |
| 4 |
| 5 import 'dart:async'; |
| 6 import 'dart:io'; |
| 7 |
| 8 import 'package:path/path.dart' as p; |
| 9 import 'package:pub/src/utils.dart'; |
| 10 import 'package:scheduled_test/scheduled_test.dart' hide fail; |
| 11 import 'package:shelf/shelf.dart' as shelf; |
| 12 import 'package:shelf/shelf_io.dart' as shelf_io; |
| 13 |
| 14 import 'descriptor.dart' as d; |
| 15 |
| 16 /// The global [DescriptorServer] that's used by default. |
| 17 /// |
| 18 /// `null` if there's no global server in use. This can be set to replace the |
| 19 /// existing global server. |
| 20 DescriptorServer get globalServer => _globalServer; |
| 21 set globalServer(DescriptorServer value) { |
| 22 if (_globalServer == null) { |
| 23 currentSchedule.onComplete.schedule(() { |
| 24 _globalServer = null; |
| 25 }, 'clearing the global server'); |
| 26 } else { |
| 27 _globalServer.close(); |
| 28 } |
| 29 |
| 30 _globalServer = value; |
| 31 } |
| 32 DescriptorServer _globalServer; |
| 33 |
| 34 /// Creates a global [DescriptorServer] to serve [contents] as static files. |
| 35 /// |
| 36 /// This server will exist only for the duration of the pub run. It's accessible |
| 37 /// via [server]. Subsequent calls to [serve] replace the previous server. |
| 38 void serve([List<d.Descriptor> contents]) { |
| 39 globalServer = new DescriptorServer(contents); |
| 40 } |
| 41 |
| 42 /// Like [serve], but reports an error if a request ever comes in to the server. |
| 43 void serveErrors() { |
| 44 globalServer = new DescriptorServer.errors(); |
| 45 } |
| 46 |
| 47 class DescriptorServer { |
| 48 /// The server, or `null` before it's available. |
| 49 HttpServer _server; |
| 50 |
| 51 /// A future that will complete to the port used for the server. |
| 52 Future<int> get port => _portCompleter.future; |
| 53 final _portCompleter = new Completer<int>(); |
| 54 |
| 55 /// Gets the list of paths that have been requested from the server. |
| 56 Future<List<String>> get requestedPaths => |
| 57 schedule(() => _requestedPaths.toList(), |
| 58 "get previous network requests"); |
| 59 |
| 60 /// The list of paths that have been requested from this server. |
| 61 final _requestedPaths = <String>[]; |
| 62 |
| 63 /// Creates an HTTP server to serve [contents] as static files. |
| 64 /// |
| 65 /// This server exists only for the duration of the pub run. Subsequent calls |
| 66 /// to [serve] replace the previous server. |
| 67 DescriptorServer([List<d.Descriptor> contents]) { |
| 68 var baseDir = d.dir("serve-dir", contents); |
| 69 |
| 70 schedule(() async { |
| 71 _server = await shelf_io.serve((request) async { |
| 72 var path = p.posix.fromUri(request.url.path); |
| 73 _requestedPaths.add(path); |
| 74 |
| 75 try { |
| 76 var stream = await validateStream(baseDir.load(path)); |
| 77 return new shelf.Response.ok(stream); |
| 78 } catch (_) { |
| 79 return new shelf.Response.notFound('File "$path" not found.'); |
| 80 } |
| 81 }, 'localhost', 0); |
| 82 |
| 83 _portCompleter.complete(_server.port); |
| 84 _closeOnComplete(); |
| 85 }, 'starting a server serving:\n${baseDir.describe()}'); |
| 86 } |
| 87 |
| 88 /// Creates a server that reports an error if a request is ever received. |
| 89 DescriptorServer.errors() { |
| 90 schedule(() async { |
| 91 _server = await shelf_io.serve((request) { |
| 92 fail("The HTTP server received an unexpected request:\n" |
| 93 "${request.method} ${request.requestedUri}"); |
| 94 return new shelf.Response.forbidden(null); |
| 95 }, 'localhost', 0); |
| 96 |
| 97 _portCompleter.complete(_server.port); |
| 98 _closeOnComplete(); |
| 99 }); |
| 100 } |
| 101 |
| 102 /// Schedules [requestedPaths] to be emptied. |
| 103 void clearRequestedPaths() { |
| 104 schedule(() { |
| 105 _requestedPaths.clear(); |
| 106 }, "clearing requested paths"); |
| 107 } |
| 108 |
| 109 /// Schedules the closing of this server. |
| 110 void close() { |
| 111 schedule(() async { |
| 112 if (_server == null) return; |
| 113 await _server.close(); |
| 114 }, "closing DescriptorServer"); |
| 115 } |
| 116 |
| 117 /// Schedules this server to close once the schedule is done. |
| 118 void _closeOnComplete() { |
| 119 currentSchedule.onComplete.schedule(() async { |
| 120 if (_server == null) return; |
| 121 await _server.close(); |
| 122 }, "closing DescriptorServer"); |
| 123 } |
| 124 } |
OLD | NEW |