@Override public Connection newConnection(Connector connector, EndPoint endPoint) { ServerSessionListener listener = newSessionListener(connector, endPoint); Generator generator = new Generator(connector.getByteBufferPool(), getMaxHeaderTableSize()); HTTP2ServerSession session = new HTTP2ServerSession( connector.getScheduler(), endPoint, generator, listener, new HTTP2FlowControl(getInitialStreamWindow())); session.setMaxLocalStreams(getMaxConcurrentStreams()); session.setMaxRemoteStreams(getMaxConcurrentStreams()); long idleTimeout = endPoint.getIdleTimeout(); if (idleTimeout > 0) idleTimeout /= 2; session.setStreamIdleTimeout(idleTimeout); Parser parser = newServerParser(connector.getByteBufferPool(), session); HTTP2Connection connection = new HTTP2ServerConnection( connector.getByteBufferPool(), connector.getExecutor(), endPoint, parser, session, getInputBufferSize(), listener); return configure(connection, connector, endPoint); }
/** * This method is invoked when the idle timeout triggers. We check the close state to act * appropriately: * * <p>* NOT_CLOSED: it's a real idle timeout, we just initiate a close, see {@link #close(int, * String, Callback)}. * * <p>* LOCALLY_CLOSED: we have sent a GO_AWAY and only shutdown the output, but the other peer * did not close the connection so we never received the TCP FIN, and therefore we terminate. * * <p>* REMOTELY_CLOSED: the other peer sent us a GO_AWAY, we should have queued a disconnect, but * for some reason it was not processed (for example, queue was stuck because of TCP congestion), * therefore we terminate. See {@link #onGoAway(GoAwayFrame)}. * * @return true if the session should be closed, false otherwise * @see #onGoAway(GoAwayFrame) * @see #close(int, String, Callback) * @see #onShutdown() */ @Override public boolean onIdleTimeout() { switch (closed.get()) { case NOT_CLOSED: { long elapsed = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - idleTime); if (elapsed < endPoint.getIdleTimeout()) return false; return notifyIdleTimeout(this); } case LOCALLY_CLOSED: case REMOTELY_CLOSED: { abort(new TimeoutException("Idle timeout " + endPoint.getIdleTimeout() + " ms")); return false; } default: { return false; } } }
@Override protected void send(HttpExchange exchange) { Request request = exchange.getRequest(); normalizeRequest(request); // Save the old idle timeout to restore it EndPoint endPoint = getEndPoint(); idleTimeout = endPoint.getIdleTimeout(); endPoint.setIdleTimeout(request.getIdleTimeout()); // One channel per connection, just delegate the send if (channel.associate(exchange)) channel.send(); else channel.release(); }
public HTTP2Session( Scheduler scheduler, EndPoint endPoint, Generator generator, Session.Listener listener, FlowControlStrategy flowControl, int initialStreamId) { this.scheduler = scheduler; this.endPoint = endPoint; this.generator = generator; this.listener = listener; this.flowControl = flowControl; this.flusher = new HTTP2Flusher(this); this.maxLocalStreams = -1; this.maxRemoteStreams = -1; this.streamIds.set(initialStreamId); this.streamIdleTimeout = endPoint.getIdleTimeout(); this.sendWindow.set(FlowControlStrategy.DEFAULT_WINDOW_SIZE); this.recvWindow.set(FlowControlStrategy.DEFAULT_WINDOW_SIZE); this.pushEnabled = true; // SPEC: by default, push is enabled. this.idleTime = System.nanoTime(); }