package org.webpieces.frontend2.impl;
import java.util.concurrent.ConcurrentLinkedQueue;
import org.webpieces.frontend2.api.FrontendSocket;
import org.webpieces.frontend2.api.HttpRequestListener;
import org.webpieces.httpparser.api.Memento;
import org.webpieces.nio.api.channels.TCPChannel;
import org.webpieces.util.logging.Logger;
import org.webpieces.util.logging.LoggerFactory;
import com.webpieces.http2engine.api.ConnectionReset;
import com.webpieces.http2engine.api.StreamWriter;
import com.webpieces.http2engine.api.server.Http2ServerEngine;
import com.webpieces.http2parser.api.dto.RstStreamFrame;
import com.webpieces.http2parser.api.dto.lib.Http2ErrorCode;
public class FrontendSocketImpl implements FrontendSocket {
private static final Logger log = LoggerFactory.getLogger(FrontendSocketImpl.class);
private TCPChannel channel;
private ProtocolType protocol;
private Memento http1_1ParseState;
private Http2ServerEngine http2Engine;
private StreamWriter writer;
private ConcurrentLinkedQueue<Http1_1StreamImpl> http11Queue = new ConcurrentLinkedQueue<>();
private boolean isClosed;
public FrontendSocketImpl(TCPChannel channel, ProtocolType protocol) {
this.channel = channel;
this.protocol = protocol;
}
public ProtocolType getProtocol() {
return protocol;
}
@Override
public void close(String reason) {
//need to do goAway here
internalClose();
}
public void internalClose() {
channel.close();
}
public void setHttp1_1ParseState(Memento parseState) {
this.http1_1ParseState = parseState;
}
public Memento getHttp1_1ParseState() {
return http1_1ParseState;
}
public void setProtocol(ProtocolType protocol) {
this.protocol = protocol;
}
public void setHttp2Engine(Http2ServerEngine engine) {
this.http2Engine = engine;
}
public Http2ServerEngine getHttp2Engine() {
return http2Engine;
}
public TCPChannel getChannel() {
return channel;
}
public void addWriter(StreamWriter writer) {
this.writer = writer;
}
public StreamWriter getWriter() {
return writer;
}
public void setAddStream(Http1_1StreamImpl stream) {
http11Queue.add(stream);
}
public void removeStream(Http1_1StreamImpl http1_1StreamImpl) {
if(isClosed)
throw new IllegalStateException("The socket is closed(the far end most likely closed it)");
Http1_1StreamImpl str = http11Queue.poll();
if(str != http1_1StreamImpl)
throw new IllegalArgumentException("bug, these streams should always match");
}
public Http1_1StreamImpl getCurrentStream() {
if(isClosed)
throw new IllegalStateException("The socket is closed(the far end most likely closed it)");
return http11Queue.peek();
}
public void farEndClosed(HttpRequestListener httpListener) {
isClosed = true;
ConnectionReset f = new ConnectionReset("The far end closed the socket", true);
f.setKnownErrorCode(Http2ErrorCode.CONNECT_ERROR);
if(protocol == ProtocolType.HTTP1_1) {
cancelAllStreams(httpListener, f);
}
}
private void cancelAllStreams(HttpRequestListener httpListener, ConnectionReset f) {
while(true) {
Http1_1StreamImpl poll = http11Queue.poll();
if(poll == null)
break;
fireCancel(httpListener, f, poll);
}
}
private void fireCancel(HttpRequestListener httpListener, ConnectionReset f, Http1_1StreamImpl poll) {
try {
httpListener.cancelRequest(poll, f);
} catch(Throwable e) {
log.warn("exception from stream trying to cancel. swallowing and continuing", e);
}
}
}