public StreamSinkConduit wrap(final ConduitFactory<StreamSinkConduit> factory, final HttpServerExchange exchange) {
if(exchange.getRequestMethod().equals(Methods.HEAD)) {
return new HeadStreamSinkConduit(factory.create(), terminateResponseListener(exchange));
}
final StreamSinkConduit channel = factory.create();
final HeaderMap responseHeaders = exchange.getResponseHeaders();
// test to see if we're still persistent
String connection = responseHeaders.getFirst(Headers.CONNECTION);
boolean stillPersistent = requestLooksPersistent && exchange.isPersistent() && (connection == null || !HttpString.tryFromString(connection).equals(Headers.CLOSE));
HttpString transferEncoding = Headers.IDENTITY;
final String transferEncodingHeader = responseHeaders.getLast(Headers.TRANSFER_ENCODING);
final String contentLengthHeader = responseHeaders.getFirst(Headers.CONTENT_LENGTH);
if (transferEncodingHeader != null) {
if (exchange.isHttp11()) {
transferEncoding = new HttpString(transferEncodingHeader);
} else {
// RFC 2616 3.6 last paragraph
responseHeaders.remove(Headers.TRANSFER_ENCODING);
}
} else if (exchange.isHttp11() && contentLengthHeader == null) {
//if we have a HTTP 1.1 request with no transfer encoding and no content length
//then we default to chunked, to enable persistent connections to work
responseHeaders.put(Headers.TRANSFER_ENCODING, Headers.CHUNKED.toString());
transferEncoding = Headers.CHUNKED;
}
StreamSinkConduit wrappedConduit;
final int code = exchange.getResponseCode();
if (exchange.getRequestMethod().equals(Methods.HEAD) || (100 <= code && code <= 199) || code == 204 || code == 304) {
final ConduitListener<StreamSinkConduit> finishListener = stillPersistent ? terminateResponseListener(exchange) : null;
if (code == 101 && contentLengthHeader != null) {
// add least for websocket upgrades we can have a content length
final long contentLength;
try {
contentLength = Long.parseLong(contentLengthHeader);
// fixed-length response
wrappedConduit = new FixedLengthStreamSinkConduit(channel, contentLength, true, !stillPersistent, finishListener);
} catch (NumberFormatException e) {
// assume that the response is unbounded, but forbid persistence (this will cause subsequent requests to fail when they write their replies)
stillPersistent = false;
wrappedConduit = new FinishableStreamSinkConduit(channel, terminateResponseListener(exchange));
}
} else {
wrappedConduit = new FixedLengthStreamSinkConduit(channel, 0L, true, !stillPersistent, finishListener);
}
} else if (!transferEncoding.equals(Headers.IDENTITY)) {
final ConduitListener<StreamSinkConduit> finishListener = stillPersistent ? terminateResponseListener(exchange) : null;
wrappedConduit = new ChunkedStreamSinkConduit(channel, true, !stillPersistent, finishListener, exchange);
} else if (contentLengthHeader != null) {
final long contentLength;
try {
contentLength = Long.parseLong(contentLengthHeader);
final ConduitListener<StreamSinkConduit> finishListener = stillPersistent ? terminateResponseListener(exchange) : null;
// fixed-length response
wrappedConduit = new FixedLengthStreamSinkConduit(channel, contentLength, true, !stillPersistent, finishListener);
} catch (NumberFormatException e) {
// assume that the response is unbounded, but forbid persistence (this will cause subsequent requests to fail when they write their replies)
stillPersistent = false;
wrappedConduit = new FinishableStreamSinkConduit(channel, terminateResponseListener(exchange));
}
} else {
log.trace("Cancelling persistence because response is identity with no content length");
// make it not persistent - very unfortunate for the next request handler really...
stillPersistent = false;
wrappedConduit = new FinishableStreamSinkConduit(channel, terminateResponseListener(exchange));
}
if (code != 101) {
// only set connection header if it was not an upgrade
if (exchange.isHttp11()) {
if (stillPersistent) {
// not strictly required but user agents seem to like it
responseHeaders.put(Headers.CONNECTION, Headers.KEEP_ALIVE.toString());
} else {
responseHeaders.put(Headers.CONNECTION, Headers.CLOSE.toString());
}
} else if (exchange.isHttp10()) {
if (stillPersistent) {
responseHeaders.put(Headers.CONNECTION, Headers.KEEP_ALIVE.toString());
} else {
responseHeaders.remove(Headers.CONNECTION);
}
}
}
return wrappedConduit;
}