in lib/src/http_impl.dart [1300:1379]
Future close() {
// If we are already closed, return that future.
if (_closeFuture != null) return _closeFuture;
// If we earlier saw an error, return immediate. The notification to
// _Http*Connection is already done.
if (_socketError) return Future.value(outbound);
if (outbound._isConnectionClosed) return Future.value(outbound);
if (!headersWritten && !ignoreBody) {
if (outbound.headers.contentLength == -1) {
// If no body was written, ignoreBody is false (it's not a HEAD
// request) and the content-length is unspecified, set contentLength to
// 0.
outbound.headers.chunkedTransferEncoding = false;
outbound.headers.contentLength = 0;
} else if (outbound.headers.contentLength > 0) {
var error = HttpException(
"No content even though contentLength was specified to be "
"greater than 0: ${outbound.headers.contentLength}.",
uri: outbound._uri);
_doneCompleter.completeError(error);
return _closeFuture = Future.error(error);
}
}
// If contentLength was specified, validate it.
if (contentLength != null) {
if (_bytesWritten < contentLength) {
var error = HttpException(
"Content size below specified contentLength. "
" $_bytesWritten bytes written but expected "
"$contentLength.",
uri: outbound._uri);
_doneCompleter.completeError(error);
return _closeFuture = Future.error(error);
}
}
Future finalize() {
// In case of chunked encoding (and gzip), handle remaining gzip data and
// append the 'footer' for chunked encoding.
if (chunked) {
if (_gzip) {
_gzipAdd = socket.add;
if (_gzipBufferLength > 0) {
_gzipSink
.add(Uint8List.view(_gzipBuffer.buffer, 0, _gzipBufferLength));
}
_gzipBuffer = null;
_gzipSink.close();
_gzipAdd = null;
}
_addChunk(_chunkHeader(0), socket.add);
}
// Add any remaining data in the buffer.
if (_length > 0) {
socket.add(Uint8List.view(_buffer.buffer, 0, _length));
}
// Clear references, for better GC.
_buffer = null;
// And finally flush it. As we support keep-alive, never close it from
// here. Once the socket is flushed, we'll be able to reuse it (signaled
// by the 'done' future).
return socket.flush().then((_) {
_doneCompleter.complete(socket);
return outbound;
}, onError: (error, StackTrace stackTrace) {
_doneCompleter.completeError(error, stackTrace);
if (_ignoreError(error)) {
return outbound;
} else {
throw error;
}
});
}
var future = writeHeaders();
if (future != null) {
return _closeFuture = future.whenComplete(finalize);
}
return _closeFuture = finalize();
}