use of org.webpieces.util.futures.XFuture in project webpieces by deanhiller.
the class Layer2Http11Handler method processWithBackpressure.
public XFuture<Void> processWithBackpressure(FrontendSocketImpl socket, int newDataSize, int numBytesRead) {
Memento state = socket.getHttp11ParseState();
List<HttpPayload> parsed = state.getParsedMessages();
WebSession session = (WebSession) socket.getSession().get(WEB_SESSION_KEY);
if (session == null) {
session = new WebSession();
socket.getSession().put(WEB_SESSION_KEY, session);
}
// ALL of the below MUST happen AFTER the previous processing happened
// which may not have finished so chain the below with the previous future
XFuture<Void> future = session.getProcessFuture();
for (HttpPayload payload : parsed) {
// VERY IMPORTANT: Writing the code like this would slam through calling process N times
// BUT it doesn't give the clients a chance to seet a flag between packets
// Mainly done for exceptions and streaming so you can log exc, set a boolean so you
// don't get 100 exceptions while something is happening like socket disconnect
// In these 2 lines of code, processCorrectly is CALLED N times RIGHT NOW
// The code below this only calls them right now IF AND ONLY IF the client returns
// a completed future each time!!!
// XFuture<Void> fut = processCorrectly(socket, payload);
// future = future.thenCompose(s -> fut);
future = future.thenCompose(s -> processCorrectly(socket, payload));
}
// replace with new future so it blocks any future pieces if these are not processed
session.setProcessFuture(future);
return future;
}
use of org.webpieces.util.futures.XFuture in project webpieces by deanhiller.
the class Http11StreamImpl method process.
@Override
public XFuture<StreamWriter> process(Http2Response headers) {
closeCheck(headers);
HttpResponse response = Http2ToHttp11.translateResponse(headers);
if (http2Request.getKnownMethod() == Http2Method.CONNECT) {
// bytes so we don't care about parsing anymore(ie. SSL or http)..
return write(response).thenApply(c -> new Http11ChunkedWriter(http1Req, http2Request));
} else if (headers.isEndOfStream()) {
validateHeader(response);
remove(headers);
return write(response).thenApply(w -> {
permitQueue.releasePermit();
return new NoWritesWriter();
});
} else if (contentLengthGreaterThanZero(headers)) {
return write(response).thenApply(w -> new ContentLengthResponseWriter(headers));
}
return write(response).thenApply(c -> new Http11ChunkedWriter(http1Req, http2Request));
}
use of org.webpieces.util.futures.XFuture in project webpieces by deanhiller.
the class ProxyHttpStream method incomingRequest.
@Override
public StreamRef incomingRequest(Http2Request request, ResponseStream stream) {
String expect = request.getSingleHeaderValue("Expect");
XFuture<StreamWriter> future = XFuture.completedFuture(null);
if (expect != null && "100-continue".equals(expect.toLowerCase())) {
Http2Response continueResponse = new Http2Response();
continueResponse.setEndOfStream(false);
continueResponse.addHeader(new Http2Header(Http2HeaderName.STATUS, "100"));
future = stream.process(continueResponse);
}
// This is only for streaming to backpressure clients IF we responded OR cancelled so we don't
// waste CPU on a client stream coming in
XFuture<ProxyWriter> futureWriter = new XFuture<>();
ProxyResponseStream proxy = new ProxyResponseStream(request, stream, futureWriter);
StreamRef streamRef = openStream.incomingRequest(request, proxy);
XFuture<StreamWriter> writer = future.thenCompose(w -> {
return createProxy(streamRef.getWriter(), futureWriter);
});
return new ProxyStreamRef(writer, streamRef);
}
use of org.webpieces.util.futures.XFuture in project webpieces by deanhiller.
the class StreamProxy method openStream.
@Override
public RouterStreamRef openStream(MethodMeta meta, ProxyStreamHandle handle) {
RequestContext requestCtx = meta.getCtx();
LoadedController loadedController = meta.getLoadedController();
Object instance = loadedController.getControllerInstance();
Method controllerMethod = loadedController.getControllerMethod();
Parameter[] parameters = loadedController.getParameters();
if (parameters.length != 1)
throw new IllegalArgumentException("Your method='" + controllerMethod + "' MUST one parameter and does not. It needs to take a RouterStreamHandler");
else if (!ResponseStreamHandle.class.equals(parameters[0].getType()))
throw new IllegalArgumentException("The single parameter must be RouterStreamHandle and was not for this method='" + controllerMethod + "'");
else if (!StreamRef.class.equals(controllerMethod.getReturnType()))
throw new IllegalArgumentException("The return value must be a subclass of StreamRef and was not for this method='" + controllerMethod + "'");
StreamRef streamRef = invokeStream(meta, controllerMethod, instance, requestCtx, handle);
XFuture<StreamWriter> writer = streamRef.getWriter();
XFuture<StreamWriter> newFuture = futureUtil.catchBlockWrap(() -> writer, (t) -> convert(loadedController, t));
Function<CancelReason, XFuture<Void>> cancelFunc = (reason) -> streamRef.cancel(reason);
return new RouterStreamRef("streamProxy", newFuture, cancelFunc);
}
use of org.webpieces.util.futures.XFuture in project webpieces by deanhiller.
the class XFileReader method runFileRead.
public XFuture<Void> runFileRead(RequestInfo info, RenderStaticResponse renderStatic, ProxyStreamHandle handle) throws IOException {
VirtualFile fullFilePath = renderStatic.getFilePath();
if (!fullFilePath.exists()) {
throw new NotFoundException("File not found=" + fullFilePath);
} else if (fullFilePath.isDirectory()) {
throw new NotFoundException("File not found (it was a directory that can't be rendered)=" + fullFilePath);
}
String fileName = getNameToUse(fullFilePath);
String extension = null;
int lastDot = fileName.lastIndexOf(".");
if (lastDot > 0) {
extension = fileName.substring(lastDot + 1);
}
ResponseCreator.ResponseEncodingTuple tuple = responseCreator.createResponse(info.getRequest(), StatusCode.HTTP_200_OK, extension, "application/octet-stream", false);
Http2Response response = tuple.response;
// On startup, we protect developers from breaking clients. In http, all files that change
// must also change the hash automatically and the %%{ }%% tag generates those hashes so the
// files loaded are always the latest
Long timeSeconds = config.getStaticFileCacheTimeSeconds();
if (timeSeconds != null)
response.addHeader(new Http2Header(Http2HeaderName.CACHE_CONTROL, "max-age=" + timeSeconds));
ChunkReader reader = createFileReader(response, renderStatic, fileName, fullFilePath, info, extension, tuple, handle);
if (log.isDebugEnabled())
log.debug("sending chunked file via async read=" + reader);
ProxyStreamHandle stream = info.getResponseSender();
return futureUtil.finallyBlock(() -> stream.process(response).thenCompose(s -> readLoop(s, info.getPool(), reader, 0)), () -> handleClose(info, reader));
}
Aggregations