use of com.koushikdutta.async.http.filter.ChunkedOutputFilter in project AndroidAsync by koush.
the class AsyncHttpServerResponseImpl method end.
@Override
public void end() {
if (ended)
return;
ended = true;
if (headWritten && mSink == null) {
// end will be called again after finished.
return;
}
if (!headWritten) {
// end was called, and no head or body was yet written,
// so strip the transfer encoding as that is superfluous.
mRawHeaders.remove("Transfer-Encoding");
}
if (mSink instanceof ChunkedOutputFilter) {
((ChunkedOutputFilter) mSink).setMaxBuffer(Integer.MAX_VALUE);
mSink.write(new ByteBufferList());
onEnd();
} else if (!headWritten) {
if (!mRequest.getMethod().equalsIgnoreCase(AsyncHttpHead.METHOD))
send("text/html", "");
else {
writeHead();
onEnd();
}
} else {
onEnd();
}
}
use of com.koushikdutta.async.http.filter.ChunkedOutputFilter in project AndroidAsync by koush.
the class AsyncHttpServerResponseImpl method initFirstWrite.
void initFirstWrite() {
if (headWritten)
return;
headWritten = true;
final boolean isChunked;
String currentEncoding = mRawHeaders.get("Transfer-Encoding");
if ("".equals(currentEncoding))
mRawHeaders.removeAll("Transfer-Encoding");
boolean canUseChunked = ("Chunked".equalsIgnoreCase(currentEncoding) || currentEncoding == null) && !"close".equalsIgnoreCase(mRawHeaders.get("Connection"));
if (mContentLength < 0) {
String contentLength = mRawHeaders.get("Content-Length");
if (!TextUtils.isEmpty(contentLength))
mContentLength = Long.valueOf(contentLength);
}
if (mContentLength < 0 && canUseChunked) {
mRawHeaders.set("Transfer-Encoding", "Chunked");
isChunked = true;
} else {
isChunked = false;
}
String statusLine = String.format(Locale.ENGLISH, "%s %s %s", httpVersion, code, AsyncHttpServer.getResponseCodeDescription(code));
String rh = mRawHeaders.toPrefixString(statusLine);
Util.writeAll(mSocket, rh.getBytes(), ex -> {
if (ex != null) {
report(ex);
return;
}
if (isChunked) {
ChunkedOutputFilter chunked = new ChunkedOutputFilter(mSocket);
chunked.setMaxBuffer(0);
mSink = chunked;
} else {
mSink = mSocket;
}
mSink.setClosedCallback(closedCallback);
closedCallback = null;
mSink.setWriteableCallback(writable);
writable = null;
if (ended) {
// the response ended while headers were written
end();
return;
}
getServer().post(() -> {
WritableCallback wb = getWriteableCallback();
if (wb != null)
wb.onWriteable();
});
});
}
use of com.koushikdutta.async.http.filter.ChunkedOutputFilter in project AndroidAsync by koush.
the class HttpTransportMiddleware method exchangeHeaders.
@Override
public boolean exchangeHeaders(final OnExchangeHeaderData data) {
Protocol p = Protocol.get(data.protocol);
if (p != null && p != Protocol.HTTP_1_0 && p != Protocol.HTTP_1_1)
return super.exchangeHeaders(data);
AsyncHttpRequest request = data.request;
AsyncHttpRequestBody requestBody = data.request.getBody();
if (requestBody != null) {
if (requestBody.length() >= 0) {
request.getHeaders().set("Content-Length", String.valueOf(requestBody.length()));
data.response.sink(data.socket);
} else if ("close".equals(request.getHeaders().get("Connection"))) {
data.response.sink(data.socket);
} else {
request.getHeaders().set("Transfer-Encoding", "Chunked");
data.response.sink(new ChunkedOutputFilter(data.socket));
}
}
String rl = request.getRequestLine().toString();
String rs = request.getHeaders().toPrefixString(rl);
byte[] rsBytes = rs.getBytes();
// try to get the request body in the same packet as the request headers... if it will fit
// in the max MTU (1540 or whatever).
final boolean waitForBody = requestBody != null && requestBody.length() >= 0 && requestBody.length() + rsBytes.length < 1024;
final BufferedDataSink bsink;
final DataSink headerSink;
if (waitForBody) {
// force buffering of headers
bsink = new BufferedDataSink(data.response.sink());
bsink.forceBuffering(true);
data.response.sink(bsink);
headerSink = bsink;
} else {
bsink = null;
headerSink = data.socket;
}
request.logv("\n" + rs);
final CompletedCallback sentCallback = data.sendHeadersCallback;
Util.writeAll(headerSink, rsBytes, new CompletedCallback() {
@Override
public void onCompleted(Exception ex) {
Util.end(sentCallback, ex);
// flush headers and any request body that was written by the callback
if (bsink != null) {
bsink.forceBuffering(false);
bsink.setMaxBuffer(0);
}
}
});
LineEmitter.StringCallback headerCallback = new LineEmitter.StringCallback() {
Headers mRawHeaders = new Headers();
String statusLine;
@Override
public void onStringAvailable(String s) {
try {
s = s.trim();
if (statusLine == null) {
statusLine = s;
} else if (!TextUtils.isEmpty(s)) {
mRawHeaders.addLine(s);
} else {
String[] parts = statusLine.split(" ", 3);
if (parts.length < 2)
throw new Exception(new IOException("Not HTTP"));
data.response.headers(mRawHeaders);
String protocol = parts[0];
data.response.protocol(protocol);
data.response.code(Integer.parseInt(parts[1]));
data.response.message(parts.length == 3 ? parts[2] : "");
data.receiveHeadersCallback.onCompleted(null);
// socket may get detached after headers (websocket)
AsyncSocket socket = data.response.socket();
if (socket == null)
return;
DataEmitter emitter;
// return content length, etc, which will confuse the body decoder
if (!data.request.hasBody()) {
emitter = HttpUtil.EndEmitter.create(socket.getServer(), null);
} else if (responseIsEmpty(data.response.code())) {
emitter = HttpUtil.EndEmitter.create(socket.getServer(), null);
} else {
emitter = HttpUtil.getBodyDecoder(socket, Protocol.get(protocol), mRawHeaders, false);
}
data.response.emitter(emitter);
}
} catch (Exception ex) {
data.receiveHeadersCallback.onCompleted(ex);
}
}
};
LineEmitter liner = new LineEmitter();
data.socket.setDataCallback(liner);
liner.setLineCallback(headerCallback);
return true;
}
Aggregations