package io.vertx.core.http.impl;
import io.netty.handler.codec.http.DefaultHttpHeaders;
import io.vertx.core.Handler;
import io.vertx.core.MultiMap;
import io.vertx.core.buffer.Buffer;
import io.vertx.core.http.*;
import io.vertx.core.logging.Logger;
import io.vertx.core.logging.LoggerFactory;
import io.vertx.core.net.NetSocket;
import java.util.ArrayList;
import java.util.List;
public class HttpClientResponseImpl implements HttpClientResponse {
private static final Logger log = LoggerFactory.getLogger(HttpClientResponseImpl.class);
private final HttpVersion version;
private final int statusCode;
private final String statusMessage;
private final HttpClientRequestBase request;
private final HttpConnection conn;
private final HttpClientStream stream;
private Handler<Buffer> dataHandler;
private Handler<HttpFrame> customFrameHandler;
private Handler<Void> endHandler;
private Handler<Throwable> exceptionHandler;
private Handler<StreamPriority> priorityHandler;
private NetSocket netSocket;
private MultiMap ;
private MultiMap trailers;
private List<String> cookies;
HttpClientResponseImpl(HttpClientRequestBase request, HttpVersion version, HttpClientStream stream, int statusCode, String statusMessage, MultiMap headers) {
this.version = version;
this.statusCode = statusCode;
this.statusMessage = statusMessage;
this.request = request;
this.stream = stream;
this.conn = stream.connection();
this.headers = headers;
}
@Override
public HttpClientRequestBase request() {
return request;
}
@Override
public HttpVersion version() {
return version;
}
@Override
public int statusCode() {
return statusCode;
}
@Override
public String statusMessage() {
return statusMessage;
}
@Override
public MultiMap () {
return headers;
}
@Override
public String (String headerName) {
return headers.get(headerName);
}
@Override
public String (CharSequence headerName) {
return headers.get(headerName);
}
@Override
public MultiMap trailers() {
synchronized (conn) {
if (trailers == null) {
trailers = new HeadersAdaptor(new DefaultHttpHeaders());
}
return trailers;
}
}
@Override
public String getTrailer(String trailerName) {
return trailers != null ? trailers.get(trailerName) : null;
}
@Override
public List<String> cookies() {
synchronized (conn) {
if (cookies == null) {
cookies = new ArrayList<>();
cookies.addAll(headers().getAll(HttpHeaders.SET_COOKIE));
if (trailers != null) {
cookies.addAll(trailers.getAll(HttpHeaders.SET_COOKIE));
}
}
return cookies;
}
}
private void checkEnded() {
if (trailers != null) {
throw new IllegalStateException();
}
}
@Override
public HttpClientResponse handler(Handler<Buffer> handler) {
synchronized (conn) {
if (handler != null) {
checkEnded();
}
dataHandler = handler;
return this;
}
}
@Override
public HttpClientResponse endHandler(Handler<Void> handler) {
synchronized (conn) {
if (handler != null) {
checkEnded();
}
endHandler = handler;
return this;
}
}
@Override
public HttpClientResponse exceptionHandler(Handler<Throwable> handler) {
synchronized (conn) {
if (handler != null) {
checkEnded();
}
exceptionHandler = handler;
return this;
}
}
@Override
public HttpClientResponse pause() {
stream.doPause();
return this;
}
@Override
public HttpClientResponse resume() {
return fetch(Long.MAX_VALUE);
}
@Override
public HttpClientResponse fetch(long amount) {
stream.doFetch(amount);
return this;
}
@Override
public HttpClientResponse bodyHandler(final Handler<Buffer> handler) {
if (handler != null) {
BodyHandler bodyHandler = new BodyHandler();
handler(bodyHandler);
endHandler(v -> bodyHandler.notifyHandler(handler));
} else {
handler(null);
endHandler(null);
}
return this;
}
@Override
public HttpClientResponse customFrameHandler(Handler<HttpFrame> handler) {
synchronized (conn) {
if (endHandler != null) {
checkEnded();
}
customFrameHandler = handler;
return this;
}
}
void handleUnknownFrame(HttpFrame frame) {
synchronized (conn) {
if (customFrameHandler != null) {
try {
customFrameHandler.handle(frame);
} catch (Throwable t) {
handleException(t);
}
}
}
}
void handleChunk(Buffer data) {
request.dataReceived();
Handler<Buffer> handler;
synchronized (conn) {
handler = dataHandler;
}
if (handler != null) {
try {
handler.handle(data);
} catch (Throwable t) {
handleException(t);
}
}
}
void handleEnd(MultiMap trailers) {
Handler<Void> handler;
synchronized (conn) {
this.trailers = trailers;
handler = endHandler;
endHandler = null;
}
if (handler != null) {
try {
handler.handle(null);
} catch (Throwable t) {
handleException(t);
}
}
}
void handleException(Throwable e) {
Handler<Throwable> handler;
synchronized (conn) {
handler = exceptionHandler;
if (handler == null) {
handler = log::error;
}
}
handler.handle(e);
}
@Override
public NetSocket netSocket() {
synchronized (conn) {
if (netSocket == null) {
netSocket = stream.createNetSocket();
}
return netSocket;
}
}
private static final class BodyHandler implements Handler<Buffer> {
private Buffer body;
@Override
public void handle(Buffer event) {
body().appendBuffer(event);
}
private Buffer body() {
if (body == null) {
body = Buffer.buffer();
}
return body;
}
void notifyHandler(Handler<Buffer> bodyHandler) {
bodyHandler.handle(body());
body = null;
}
}
@Override
public HttpClientResponse streamPriorityHandler(Handler<StreamPriority> handler) {
synchronized (conn) {
if (handler != null) {
checkEnded();
}
priorityHandler = handler;
}
return this;
}
void handlePriorityChange(StreamPriority streamPriority) {
Handler<StreamPriority> handler;
synchronized (conn) {
if ((handler = priorityHandler) == null) {
return;
}
}
handler.handle(streamPriority);
}
}