Index: lib/src/barback/barback_server.dart |
diff --git a/lib/src/barback/barback_server.dart b/lib/src/barback/barback_server.dart |
index b6f5d5766d02c8a355edef9c30d4b8f529bde9c7..ba055aafcdbb46728f93826e35b70bba0e6f314c 100644 |
--- a/lib/src/barback/barback_server.dart |
+++ b/lib/src/barback/barback_server.dart |
@@ -6,6 +6,7 @@ import 'dart:async'; |
import 'dart:io'; |
import 'package:barback/barback.dart'; |
+import "package:crypto/crypto.dart"; |
import 'package:mime/mime.dart'; |
import 'package:path/path.dart' as path; |
import 'package:shelf/shelf.dart' as shelf; |
@@ -89,7 +90,7 @@ class BarbackServer extends BaseServer<BarbackServerResult> { |
} |
/// Handles an HTTP request. |
- handleRequest(shelf.Request request) { |
+ Future<shelf.Response> handleRequest(shelf.Request request) async { |
if (request.method != "GET" && request.method != "HEAD") { |
return methodNotAllowed(request); |
} |
@@ -154,14 +155,38 @@ class BarbackServer extends BaseServer<BarbackServerResult> { |
} |
/// Returns the body of [asset] as a response to [request]. |
- Future<shelf.Response> _serveAsset(shelf.Request request, Asset asset) { |
- return validateStream(asset.read()).then((stream) { |
- addResult(new BarbackServerResult._success(request.url, asset.id)); |
- var headers = {}; |
- var mimeType = lookupMimeType(asset.id.path); |
- if (mimeType != null) headers['Content-Type'] = mimeType; |
- return new shelf.Response.ok(stream, headers: headers); |
- }).catchError((error, trace) { |
+ Future<shelf.Response> _serveAsset(shelf.Request request, Asset asset) async { |
+ try { |
+ var pair = tee(await validateStream(asset.read())); |
+ var responseStream = pair.first; |
+ var hashStream = pair.last; |
+ |
+ // Allow the asset to be cached based on its content hash. |
+ var sha = new SHA1(); |
+ await hashStream.forEach((chunk) { |
+ sha.add(chunk); |
+ }); |
+ |
+ var assetSha = CryptoUtils.bytesToHex(sha.close()); |
nweiz
2016/03/12 01:30:51
CryptoUtils is going to get removed once I get aro
Bob Nystrom
2016/03/14 19:15:10
I didn't see anything related to hex in there, so
nweiz
2016/03/14 19:29:13
https://www.dartdocs.org/documentation/convert/1.0
|
+ var previousSha = request.headers["if-none-match"]; |
+ |
+ var headers = { |
+ "Cache-Control": "max-age=3600", |
nweiz
2016/03/12 01:30:51
It's not clear to me why this is being set. Consid
Bob Nystrom
2016/03/14 19:15:10
I'm an HTTP noob, but from what I read, you have t
|
+ "ETag": assetSha |
+ }; |
+ |
+ if (assetSha == previousSha) { |
+ // We're requesting an unchanged asset so don't push it down the wire |
+ // again. |
+ addResult(new BarbackServerResult._cached(request.url, asset.id)); |
+ return new shelf.Response.notModified(headers: headers); |
+ } else { |
+ addResult(new BarbackServerResult._success(request.url, asset.id)); |
+ var mimeType = lookupMimeType(asset.id.path); |
+ if (mimeType != null) headers['Content-Type'] = mimeType; |
+ return new shelf.Response.ok(responseStream, headers: headers); |
+ } |
+ } catch (error, trace) { |
addResult(new BarbackServerResult._failure(request.url, asset.id, error)); |
// If we couldn't read the asset, handle the error gracefully. |
@@ -176,7 +201,7 @@ class BarbackServer extends BaseServer<BarbackServerResult> { |
// Otherwise, it's some internal error. |
return new shelf.Response.internalServerError(body: error.toString()); |
- }); |
+ } |
} |
} |
@@ -199,11 +224,20 @@ class BarbackServerResult { |
/// Whether the request was served successfully. |
bool get isSuccess => error == null; |
+ /// Whether the request was for a previously cached asset. |
+ final bool isCached; |
+ |
/// Whether the request was served unsuccessfully. |
bool get isFailure => !isSuccess; |
BarbackServerResult._success(this.url, this.id) |
- : error = null; |
+ : error = null, |
+ isCached = false; |
+ |
+ BarbackServerResult._cached(this.url, this.id) |
+ : error = null, |
+ isCached = true; |
- BarbackServerResult._failure(this.url, this.id, this.error); |
+ BarbackServerResult._failure(this.url, this.id, this.error) |
+ : isCached = false; |
} |