OLD | NEW |
| (Empty) |
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 | |
3 // BSD-style license that can be found in the LICENSE file. | |
4 | |
5 library pub.barback.base_server; | |
6 | |
7 import 'dart:async'; | |
8 import 'dart:convert'; | |
9 import 'dart:io'; | |
10 | |
11 import 'package:barback/barback.dart'; | |
12 import 'package:shelf/shelf.dart' as shelf; | |
13 import 'package:shelf/shelf_io.dart' as shelf_io; | |
14 | |
15 import '../log.dart' as log; | |
16 import '../utils.dart'; | |
17 import 'asset_environment.dart'; | |
18 | |
19 /// Base class for a pub-controlled server. | |
20 abstract class BaseServer<T> { | |
21 /// The [BuildEnvironment] being served. | |
22 final AssetEnvironment environment; | |
23 | |
24 /// The underlying HTTP server. | |
25 final HttpServer _server; | |
26 | |
27 /// The server's port. | |
28 int get port => _server.port; | |
29 | |
30 /// The servers's address. | |
31 InternetAddress get address => _server.address; | |
32 | |
33 /// The server's base URL. | |
34 Uri get url => baseUrlForAddress(_server.address, port); | |
35 | |
36 /// The results of requests handled by the server. | |
37 /// | |
38 /// These can be used to provide visual feedback for the server's processing. | |
39 /// This stream is also used to emit any programmatic errors that occur in the | |
40 /// server. | |
41 Stream<T> get results => _resultsController.stream; | |
42 final _resultsController = new StreamController<T>.broadcast(); | |
43 | |
44 BaseServer(this.environment, this._server) { | |
45 shelf_io.serveRequests(_server, const shelf.Pipeline() | |
46 .addMiddleware(shelf.createMiddleware(errorHandler: _handleError)) | |
47 .addHandler(handleRequest)); | |
48 } | |
49 | |
50 /// Closes this server. | |
51 Future close() { | |
52 return Future.wait([_server.close(), _resultsController.close()]); | |
53 } | |
54 | |
55 /// Handles an HTTP request. | |
56 handleRequest(shelf.Request request); | |
57 | |
58 /// Returns a 405 response to [request]. | |
59 shelf.Response methodNotAllowed(shelf.Request request) { | |
60 logRequest(request, "405 Method Not Allowed"); | |
61 return new shelf.Response(405, | |
62 body: "The ${request.method} method is not allowed for ${request.url}.", | |
63 headers: {'Allow': 'GET, HEAD'}); | |
64 } | |
65 | |
66 /// Returns a 404 response to [request]. | |
67 /// | |
68 /// If [asset] is given, it is the ID of the asset that couldn't be found. | |
69 shelf.Response notFound(shelf.Request request, {String error, | |
70 AssetId asset}) { | |
71 logRequest(request, "Not Found"); | |
72 | |
73 // TODO(rnystrom): Apply some styling to make it visually clear that this | |
74 // error is coming from pub serve itself. | |
75 var body = new StringBuffer(); | |
76 body.writeln(""" | |
77 <!DOCTYPE html> | |
78 <head> | |
79 <title>404 Not Found</title> | |
80 </head> | |
81 <body> | |
82 <h1>404 Not Found</h1>"""); | |
83 | |
84 if (asset != null) { | |
85 body.writeln("<p>Could not find asset " | |
86 "<code>${HTML_ESCAPE.convert(asset.path)}</code> in package " | |
87 "<code>${HTML_ESCAPE.convert(asset.package)}</code>.</p>"); | |
88 } | |
89 | |
90 if (error != null) { | |
91 body.writeln("<p>Error: ${HTML_ESCAPE.convert(error)}</p>"); | |
92 } | |
93 | |
94 body.writeln(""" | |
95 </body>"""); | |
96 | |
97 // Force a UTF-8 encoding so that error messages in non-English locales are | |
98 // sent correctly. | |
99 return new shelf.Response.notFound(body.toString(), | |
100 headers: {'Content-Type': 'text/html; charset=utf-8'}); | |
101 } | |
102 | |
103 /// Log [message] at [log.Level.FINE] with metadata about [request]. | |
104 void logRequest(shelf.Request request, String message) => | |
105 log.fine("$this ${request.method} ${request.url}\n$message"); | |
106 | |
107 /// Adds [result] to the server's [results] stream. | |
108 void addResult(T result) { | |
109 _resultsController.add(result); | |
110 } | |
111 | |
112 /// Adds [error] as an error to the server's [results] stream. | |
113 void addError(error, [stackTrace]) { | |
114 _resultsController.addError(error, stackTrace); | |
115 } | |
116 | |
117 /// Handles an error thrown by [handleRequest]. | |
118 _handleError(error, StackTrace stackTrace) { | |
119 _resultsController.addError(error, stackTrace); | |
120 close(); | |
121 return new shelf.Response.internalServerError(); | |
122 } | |
123 } | |
OLD | NEW |