package org.webpieces.httpfrontend.api;
import java.net.InetSocketAddress;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import org.webpieces.data.api.BufferCreationPool;
import org.webpieces.data.api.DataWrapper;
import org.webpieces.data.api.DataWrapperGenerator;
import org.webpieces.data.api.DataWrapperGeneratorFactory;
import org.webpieces.frontend.api.FrontendConfig;
import org.webpieces.frontend.api.HttpFrontendFactory;
import org.webpieces.frontend.api.HttpFrontendManager;
import org.webpieces.frontend.api.HttpServer;
import org.webpieces.httpcommon.Requests;
import org.webpieces.httpcommon.Responses;
import org.webpieces.httpcommon.api.HttpSocket;
import org.webpieces.httpcommon.api.Protocol;
import org.webpieces.httpcommon.api.RequestId;
import org.webpieces.httpcommon.api.RequestListener;
import org.webpieces.httpcommon.api.ResponseSender;
import org.webpieces.httpcommon.api.exceptions.HttpException;
import org.webpieces.httpparser.api.dto.HttpRequest;
import org.webpieces.httpparser.api.dto.HttpResponse;
import org.webpieces.httpparser.api.dto.KnownHttpMethod;
import org.webpieces.httpparser.api.dto.KnownStatusCode;
import org.webpieces.util.threading.NamedThreadFactory;
import com.webpieces.http2parser.api.dto.lib.Http2Header;
class ServerFactory {
static final String MAIN_RESPONSE = "Here's the file";
static final String PUSHED_RESPONSE = "Here's the css";
static int createTestServer(boolean alwaysHttp2, Long maxConcurrentStreams) {
BufferCreationPool pool = new BufferCreationPool();
ScheduledExecutorService timer = new ScheduledThreadPoolExecutor(1, new NamedThreadFactory("webpieces-timer"));
HttpFrontendManager frontEndMgr = HttpFrontendFactory.createFrontEnd("frontEnd", 10, timer, pool);
FrontendConfig config = new FrontendConfig("id2", new InetSocketAddress(0));
// Set this to true to test with h2spec
config.alwaysHttp2 = alwaysHttp2;
config.maxConcurrentStreams = Optional.of(maxConcurrentStreams);
HttpServer server = frontEndMgr.createHttpServer(config, new OurListener());
server.start();
return server.getUnderlyingChannel().getLocalAddress().getPort();
}
private static class OurListener implements RequestListener {
private DataWrapperGenerator dataGen = DataWrapperGeneratorFactory.createDataWrapperGenerator();
private HttpResponse responseA = Responses.createResponse(KnownStatusCode.HTTP_200_OK, dataGen.wrapString(MAIN_RESPONSE));
private HttpResponse responseANoBody = Responses.createResponse(KnownStatusCode.HTTP_200_OK, dataGen.emptyWrapper());
private HttpResponse pushedResponse = Responses.createResponse(KnownStatusCode.HTTP_200_OK, dataGen.wrapString(PUSHED_RESPONSE));
private HttpRequest pushedRequest = Requests.createRequest(KnownHttpMethod.GET, "/file.css");
private Map<RequestId, HttpRequest> idMap = new HashMap<>();
private void sendResponse(RequestId requestId, ResponseSender sender) {
HttpRequest req = idMap.get(requestId);
if(req.getRequestLine().getMethod().getMethodAsString().equals("HEAD")) {
sender.sendResponse(responseANoBody, req, requestId, true);
} else {
sender.sendResponse(responseA, req, requestId, true);
}
if(sender.getProtocol() == Protocol.HTTP2) {
sender.sendResponse(pushedResponse, pushedRequest, requestId, true);
}
}
@Override
public void incomingRequest(HttpRequest req, RequestId requestId, boolean isComplete, ResponseSender sender) {
idMap.put(requestId, req);
if(isComplete) {
sendResponse(requestId, sender);
}
}
@Override
public CompletableFuture<Void> incomingData(DataWrapper data, RequestId id, boolean isComplete, ResponseSender sender) {
if(isComplete) {
sendResponse(id, sender);
}
return CompletableFuture.completedFuture(null);
}
@Override
public void incomingTrailer(List<Http2Header> headers, RequestId id, boolean isComplete, ResponseSender sender) {
if(isComplete) {
sendResponse(id, sender);
}
}
@Override
public void incomingError(HttpException exc, HttpSocket channel) {
}
@Override
public void clientOpenChannel(HttpSocket HttpSocket) {
}
@Override
public void channelClosed(HttpSocket httpSocket, boolean browserClosed) {
}
@Override
public void applyWriteBackPressure(ResponseSender sender) {
}
@Override
public void releaseBackPressure(ResponseSender sender) {
}
}
}