package org.webpieces.frontend2.impl;
import java.nio.ByteBuffer;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.atomic.AtomicReference;
import org.webpieces.frontend2.api.FrontendSocket;
import org.webpieces.frontend2.api.FrontendStream;
import org.webpieces.frontend2.impl.translation.Http2Translations;
import org.webpieces.httpparser.api.HttpParser;
import org.webpieces.httpparser.api.dto.HttpPayload;
import org.webpieces.httpparser.api.dto.HttpResponse;
import org.webpieces.nio.api.channels.Channel;
import com.webpieces.hpack.api.dto.Http2Headers;
import com.webpieces.hpack.api.dto.Http2Push;
import com.webpieces.http2engine.api.StreamWriter;
import com.webpieces.http2parser.api.dto.lib.PartialStream;
public class Http1_1StreamImpl implements FrontendStream {
private FrontendSocketImpl socket;
private HttpParser http11Parser;
private AtomicReference<PartialStream> endingFrame = new AtomicReference<>();
public Http1_1StreamImpl(FrontendSocketImpl socket, HttpParser http11Parser) {
this.socket = socket;
this.http11Parser = http11Parser;
}
@Override
public CompletableFuture<StreamWriter> sendResponse(Http2Headers headers) {
maybeRemove(headers);
HttpResponse response = Http2Translations.translateResponse(headers);
return write(response).thenApply(c -> new StreamImpl());
}
private class StreamImpl implements StreamWriter {
@Override
public CompletableFuture<StreamWriter> send(PartialStream data) {
maybeRemove(data);
List<HttpPayload> responses = Http2Translations.translate(data);
CompletableFuture<Channel> future = CompletableFuture.completedFuture(null);
for(HttpPayload p : responses) {
future = future.thenCompose( (s) -> write(p));
}
return future.thenApply((s) -> this);
}
}
private void maybeRemove(PartialStream data) {
if(endingFrame.get() != null)
throw new IllegalStateException("You had already sent a frame with endOfStream "
+ "set and can't send more. ending frame was="+endingFrame+" but you just sent="+data);
Http1_1StreamImpl current = socket.getCurrentStream();
if(current != this)
throw new IllegalStateException("Due to http1.1 spec, YOU MUST return "
+ "responses in order and this is not the current response that needs responding to");
if(!data.isEndOfStream())
return;
endingFrame.set(data);
socket.removeStream(this);
}
private CompletableFuture<Channel> write(HttpPayload payload) {
ByteBuffer buf = http11Parser.marshalToByteBuffer(payload);
return socket.getChannel().write(buf);
}
@Override
public CompletableFuture<StreamWriter> sendPush(Http2Push push) {
throw new UnsupportedOperationException("not supported for http1.1 requests");
}
@Override
public void cancelStream() {
throw new UnsupportedOperationException("not supported for http1.1 requests. you can use getSocket().close() instead if you like");
}
@Override
public FrontendSocket getSocket() {
return socket;
}
}