Index: sdk/lib/io/http_impl.dart |
diff --git a/sdk/lib/io/http_impl.dart b/sdk/lib/io/http_impl.dart |
index f61c555d5a440bc0899bc21cd510a8ec4d2f2d32..caee2c250b1e48d2505dc1ffe3404f39f7839679 100644 |
--- a/sdk/lib/io/http_impl.dart |
+++ b/sdk/lib/io/http_impl.dart |
@@ -41,10 +41,14 @@ class _HttpIncoming extends Stream<List<int>> { |
void onDone(), |
bool cancelOnError}) { |
hasSubscriber = true; |
- return _stream.listen(onData, |
- onError: onError, |
- onDone: onDone, |
- cancelOnError: cancelOnError); |
+ return _stream |
+ .handleError((error) { |
+ throw new HttpException(error.message, uri: uri); |
+ }) |
+ .listen(onData, |
+ onError: onError, |
+ onDone: onDone, |
+ cancelOnError: cancelOnError); |
} |
// Is completed once all data have been received. |
@@ -160,7 +164,10 @@ class _HttpClientResponse |
_HttpClientResponse(_HttpIncoming _incoming, |
_HttpClientRequest this._httpRequest, |
_HttpClient this._httpClient) |
- : super(_incoming); |
+ : super(_incoming) { |
+ // Set uri for potential exceptions. |
+ _incoming.uri = _httpRequest.uri; |
+ } |
int get statusCode => _incoming.statusCode; |
String get reasonPhrase => _incoming.reasonPhrase; |
@@ -395,10 +402,13 @@ abstract class _HttpOutboundMessage<T> implements IOSink { |
IOSink _dataSink; |
final _HttpOutgoing _outgoing; |
+ final Uri _uri; |
final _HttpHeaders headers; |
- _HttpOutboundMessage(String protocolVersion, _HttpOutgoing outgoing) |
+ _HttpOutboundMessage(Uri this._uri, |
+ String protocolVersion, |
+ _HttpOutgoing outgoing) |
: _outgoing = outgoing, |
_headersSink = new IOSink(outgoing, encoding: Encoding.ASCII), |
headers = new _HttpHeaders(protocolVersion) { |
@@ -511,7 +521,7 @@ abstract class _HttpOutboundMessage<T> implements IOSink { |
stream = stream.transform(new _ChunkedTransformer()); |
} else if (contentLength >= 0) { |
stream = stream.transform( |
- new _ContentLengthValidator(contentLength)); |
+ new _ContentLengthValidator(contentLength, _uri)); |
} |
return _headersSink.addStream(stream); |
}); |
@@ -531,7 +541,8 @@ abstract class _HttpOutboundMessage<T> implements IOSink { |
_headersSink.close().catchError((_) {}); |
return new Future.error(new HttpException( |
"No content while contentLength was specified to be greater " |
- " than 0: ${headers.contentLength}.")); |
+ " than 0: ${headers.contentLength}.", |
+ uri: _uri)); |
} |
} |
return _writeHeaders().then((_) => _headersSink.close()); |
@@ -676,10 +687,11 @@ class _HttpResponse extends _HttpOutboundMessage<HttpResponse> |
List<Cookie> _cookies; |
_HttpRequest _httpRequest; |
- _HttpResponse(String protocolVersion, |
+ _HttpResponse(Uri uri, |
+ String protocolVersion, |
_HttpOutgoing _outgoing, |
String serverHeader) |
- : super(protocolVersion, _outgoing) { |
+ : super(uri, protocolVersion, _outgoing) { |
if (serverHeader != null) headers.set('Server', serverHeader); |
} |
@@ -844,12 +856,13 @@ class _HttpClientRequest extends _HttpOutboundMessage<HttpClientResponse> |
List<RedirectInfo> _responseRedirects = []; |
_HttpClientRequest(_HttpOutgoing outgoing, |
- Uri this.uri, |
+ Uri uri, |
String this.method, |
_Proxy this._proxy, |
_HttpClient this._httpClient, |
_HttpClientConnection this._httpClientConnection) |
- : super("1.1", outgoing) { |
+ : super(uri, "1.1", outgoing), |
+ uri = uri { |
// GET and HEAD have 'content-length: 0' by default. |
if (method == "GET" || method == "HEAD") { |
contentLength = 0; |
@@ -1049,9 +1062,10 @@ class _ChunkedTransformer extends StreamEventTransformer<List<int>, List<int>> { |
class _ContentLengthValidator |
extends StreamEventTransformer<List<int>, List<int>> { |
final int expectedContentLength; |
+ final Uri uri; |
int _bytesWritten = 0; |
- _ContentLengthValidator(int this.expectedContentLength); |
+ _ContentLengthValidator(int this.expectedContentLength, Uri this.uri); |
void handleData(List<int> data, EventSink<List<int>> sink) { |
_bytesWritten += data.length; |
@@ -1060,7 +1074,8 @@ class _ContentLengthValidator |
"Content size exceeds specified contentLength. " |
"$_bytesWritten bytes written while expected " |
"$expectedContentLength. " |
- "[${new String.fromCharCodes(data)}]")); |
+ "[${new String.fromCharCodes(data)}]", |
+ uri: uri)); |
sink.close(); |
} else { |
sink.add(data); |
@@ -1072,7 +1087,8 @@ class _ContentLengthValidator |
sink.addError(new HttpException( |
"Content size below specified contentLength. " |
" $_bytesWritten bytes written while expected " |
- "$expectedContentLength.")); |
+ "$expectedContentLength.", |
+ uri: uri)); |
} |
sink.close(); |
} |
@@ -1112,6 +1128,7 @@ class _HttpClientConnection { |
bool _dispose = false; |
Timer _idleTimer; |
bool closed = false; |
+ Uri _currentUri; |
Completer<_HttpIncoming> _nextResponseCompleter; |
Future _streamFuture; |
@@ -1132,21 +1149,23 @@ class _HttpClientConnection { |
_subscription.pause(); |
// We assume the response is not here, until we have send the request. |
if (_nextResponseCompleter == null) { |
- throw new HttpException("Unexpected response."); |
+ throw new HttpException("Unexpected response.", uri: _currentUri); |
} |
_nextResponseCompleter.complete(incoming); |
_nextResponseCompleter = null; |
}, |
onError: (error) { |
if (_nextResponseCompleter != null) { |
- _nextResponseCompleter.completeError(error); |
+ _nextResponseCompleter.completeError( |
+ new HttpException(error.message, uri: _currentUri)); |
_nextResponseCompleter = null; |
} |
}, |
onDone: () { |
if (_nextResponseCompleter != null) { |
_nextResponseCompleter.completeError(new HttpException( |
- "Connection closed before response was received")); |
+ "Connection closed before response was received", |
+ uri: _currentUri)); |
_nextResponseCompleter = null; |
} |
close(); |
@@ -1155,8 +1174,10 @@ class _HttpClientConnection { |
_HttpClientRequest send(Uri uri, int port, String method, _Proxy proxy) { |
if (closed) { |
- throw new HttpException("Socket closed before request was sent"); |
+ throw new HttpException( |
+ "Socket closed before request was sent", uri: uri); |
} |
+ _currentUri = uri; |
// Start with pausing the parser. |
_subscription.pause(); |
_ProxyCredentials proxyCreds; // Credentials used to authorize proxy. |
@@ -1211,6 +1232,7 @@ class _HttpClientConnection { |
// Listen for response. |
_nextResponseCompleter.future |
.then((incoming) { |
+ _currentUri = null; |
incoming.dataDone.then((_) { |
if (!_dispose && |
incoming.headers.persistentConnection && |
@@ -1255,7 +1277,7 @@ class _HttpClientConnection { |
// element. |
.catchError((error) { |
throw new HttpException( |
- "Connection closed before data was received"); |
+ "Connection closed before data was received", uri); |
}, test: (error) => error is StateError) |
.catchError((error) { |
// We are done with the socket. |
@@ -1783,7 +1805,8 @@ class _HttpConnection extends LinkedListEntry<_HttpConnection> { |
_subscription.pause(); |
_state = _ACTIVE; |
var outgoing = new _HttpOutgoing(_socket); |
- var response = new _HttpResponse(incoming.headers.protocolVersion, |
+ var response = new _HttpResponse(incoming.uri, |
+ incoming.headers.protocolVersion, |
outgoing, |
_httpServer.serverHeader); |
var request = new _HttpRequest(response, incoming, _httpServer, this); |