com.webpieces.http2engine.impl.svr.Level5ServerStateMachine Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of http2-engine Show documentation
Show all versions of http2-engine Show documentation
A re-usable asynchronous HTTP/2 parser
package com.webpieces.http2engine.impl.svr;
import static com.webpieces.http2engine.impl.shared.data.Http2Event.RECV_DATA;
import static com.webpieces.http2engine.impl.shared.data.Http2Event.RECV_DATA_EOS;
import static com.webpieces.http2engine.impl.shared.data.Http2Event.RECV_HEADERS;
import static com.webpieces.http2engine.impl.shared.data.Http2Event.RECV_HEADERS_EOS;
import static com.webpieces.http2engine.impl.shared.data.Http2Event.RECV_RST;
import static com.webpieces.http2engine.impl.shared.data.Http2Event.SENT_DATA;
import static com.webpieces.http2engine.impl.shared.data.Http2Event.SENT_DATA_EOS;
import static com.webpieces.http2engine.impl.shared.data.Http2Event.SENT_HEADERS;
import static com.webpieces.http2engine.impl.shared.data.Http2Event.SENT_HEADERS_EOS;
import static com.webpieces.http2engine.impl.shared.data.Http2Event.SENT_PUSH;
import static com.webpieces.http2engine.impl.shared.data.Http2Event.SENT_RST;
import org.webpieces.util.futures.XFuture;
import org.webpieces.javasm.api.Memento;
import org.webpieces.javasm.api.State;
import org.webpieces.util.locking.PermitQueue;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.webpieces.http2.api.dto.error.CancelReasonCode;
import com.webpieces.http2.api.dto.error.StreamException;
import com.webpieces.http2.api.dto.highlevel.Http2Push;
import com.webpieces.http2.api.dto.highlevel.Http2Request;
import com.webpieces.http2.api.dto.highlevel.Http2Response;
import com.webpieces.http2.api.dto.highlevel.Http2Trailers;
import com.webpieces.http2.api.dto.lowlevel.DataFrame;
import com.webpieces.http2engine.impl.shared.Level5CStateMachine;
import com.webpieces.http2engine.impl.shared.Level6RemoteFlowControl;
import com.webpieces.http2engine.impl.shared.StreamState;
import com.webpieces.http2engine.impl.shared.data.HeaderSettings;
import com.webpieces.http2engine.impl.shared.data.Stream;
public class Level5ServerStateMachine extends Level5CStateMachine {
private static final Logger log = LoggerFactory.getLogger(Level5ServerStateMachine.class);
private Level6SvrLocalFlowControl local;
private HeaderSettings localSettings;
private HeaderSettings remoteSettings;
public Level5ServerStateMachine(
String id,
StreamState streamState,
Level6RemoteFlowControl remoteFlowControl,
Level6SvrLocalFlowControl localFlowControl,
HeaderSettings localSettings,
HeaderSettings remoteSettings,
PermitQueue maxConcurrentQueue
) {
super(id, streamState, remoteFlowControl, localFlowControl, maxConcurrentQueue);
local = localFlowControl;
this.localSettings = localSettings;
this.remoteSettings = remoteSettings;
State reservedLocal = stateMachine.createState("Reserved(local)");
NoTransitionImpl failIfNoTransition = new NoTransitionImpl(true);
NoTransitionImpl streamErrorNoTransition = new NoTransitionImpl(false);
idleState.setNoTransitionListener(failIfNoTransition);
openState.setNoTransitionListener(failIfNoTransition);
closed.setNoTransitionListener(streamErrorNoTransition);
reservedLocal.setNoTransitionListener(failIfNoTransition);
halfClosedRemote.setNoTransitionListener(streamErrorNoTransition);
stateMachine.createTransition(idleState, openState, RECV_HEADERS);
stateMachine.createTransition(idleState, halfClosedRemote, RECV_HEADERS_EOS); //jump to half closed as is send H AND send ES
stateMachine.createTransition(idleState, reservedLocal, SENT_PUSH);
stateMachine.createTransition(openState, openState, RECV_DATA, SENT_DATA, SENT_HEADERS);
stateMachine.createTransition(openState, halfClosedRemote, RECV_DATA_EOS, RECV_HEADERS_EOS);
stateMachine.createTransition(openState, halfClosedLocal, SENT_DATA_EOS, SENT_HEADERS_EOS);
stateMachine.createTransition(openState, closed, SENT_RST, RECV_RST);
stateMachine.createTransition(reservedLocal, halfClosedRemote, SENT_HEADERS);
stateMachine.createTransition(reservedLocal, closed, SENT_HEADERS_EOS, SENT_RST, RECV_RST);
stateMachine.createTransition(halfClosedRemote, halfClosedRemote, SENT_HEADERS, SENT_DATA);
stateMachine.createTransition(halfClosedLocal, halfClosedLocal, RECV_DATA); //only trailing headers allowed (ie. must have EOS)
}
public XFuture fireToClient(ServerStream stream, Http2Request payload) {
return fireRecvToSM(stream, payload)
.thenCompose(v-> {
return local.fireHeadersToClient(stream, payload);
});
}
public XFuture sendRequestToApp(Http2Request request) {
if(!streamState.isLargeEnough(request))
throw new StreamException(CancelReasonCode.CLOSED_STREAM, logId, request.getStreamId(), "Stream id too low and stream not exist(ie. stream was closed) request="+request);
ServerStream stream = createStream(request.getStreamId());
return fireToClient(stream, request).thenApply(s -> null);
}
private ServerStream createStream(int streamId) {
Memento initialState = createStateMachine("stream" + streamId);
long localWindowSize = localSettings.getInitialWindowSize();
long remoteWindowSize = remoteSettings.getInitialWindowSize();
ServerStream stream = new ServerStream(logId, streamId, initialState, localWindowSize, remoteWindowSize);
streamState.create(stream);
return stream;
}
private ServerPushStream createPushStream(PushStreamHandleImpl handle, int streamId) {
Memento initialState = createStateMachine("stream" + streamId);
long localWindowSize = localSettings.getInitialWindowSize();
long remoteWindowSize = remoteSettings.getInitialWindowSize();
ServerPushStream stream = new ServerPushStream(logId, handle, streamId, initialState, localWindowSize, remoteWindowSize);
streamState.create(stream);
return stream;
}
@Override
public XFuture sendDataToApp(DataFrame frame) {
return sendDataToAppImpl(frame, false);
}
@Override
protected XFuture sendTrailersToApp(Http2Trailers frame) {
return sendTrailersToAppImpl(frame, false);
}
public XFuture sendPush(PushStreamHandleImpl handle, Http2Push push) {
int newStreamId = push.getPromisedStreamId();
ServerPushStream stream = createPushStream(handle, newStreamId);
return fireToSocket(stream, push)
.thenApply(s -> stream);
}
public XFuture sendResponseHeaders(Stream stream, Http2Response response) {
return fireToSocket(stream, response);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy