/* * Copyright (c) 2012 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.eclipse.jetty.spdy.http; import java.util.concurrent.Executor; import java.util.concurrent.ScheduledExecutorService; import org.eclipse.jetty.io.AsyncEndPoint; import org.eclipse.jetty.server.Connector; import org.eclipse.jetty.spdy.ByteBufferPool; import org.eclipse.jetty.spdy.EmptyAsyncEndPoint; import org.eclipse.jetty.spdy.SPDYAsyncConnection; import org.eclipse.jetty.spdy.ServerSPDYAsyncConnectionFactory; import org.eclipse.jetty.spdy.api.DataInfo; import org.eclipse.jetty.spdy.api.Headers; import org.eclipse.jetty.spdy.api.HeadersInfo; import org.eclipse.jetty.spdy.api.ReplyInfo; import org.eclipse.jetty.spdy.api.Stream; import org.eclipse.jetty.spdy.api.StreamFrameListener; import org.eclipse.jetty.spdy.api.SynInfo; import org.eclipse.jetty.spdy.api.server.ServerSessionFrameListener; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class ServerHTTPSPDYAsyncConnectionFactory extends ServerSPDYAsyncConnectionFactory { private static final String CONNECTION_ATTRIBUTE = "org.eclipse.jetty.spdy.http.connection"; private static final Logger logger = LoggerFactory.getLogger(ServerHTTPSPDYAsyncConnectionFactory.class); private final Connector connector; public ServerHTTPSPDYAsyncConnectionFactory(short version, ByteBufferPool bufferPool, Executor threadPool, ScheduledExecutorService scheduler, Connector connector) { super(version, bufferPool, threadPool, scheduler); this.connector = connector; } @Override protected ServerSessionFrameListener newServerSessionFrameListener(AsyncEndPoint endPoint, Object attachment) { return new HTTPServerFrameListener(endPoint); } private class HTTPServerFrameListener extends ServerSessionFrameListener.Adapter implements StreamFrameListener { private final AsyncEndPoint endPoint; public HTTPServerFrameListener(AsyncEndPoint endPoint) { this.endPoint = endPoint; } @Override public StreamFrameListener onSyn(final Stream stream, SynInfo synInfo) { // Every time we have a SYN, it maps to a HTTP request. // We can have multiple concurrent SYNs on the same connection, // and this is very different from HTTP, where only one request/response // cycle is processed at a time, so we need to fake an http connection // for each SYN in order to run concurrently. logger.debug("Received {} on {}", synInfo, stream); HTTPSPDYAsyncEndPoint asyncEndPoint = new HTTPSPDYAsyncEndPoint(stream); ServerHTTPSPDYAsyncConnection connection = new ServerHTTPSPDYAsyncConnection(connector, asyncEndPoint, connector.getServer(), (SPDYAsyncConnection)endPoint.getConnection(), stream); asyncEndPoint.setConnection(connection); stream.setAttribute(CONNECTION_ATTRIBUTE, connection); Headers headers = synInfo.getHeaders(); connection.beginRequest(headers); if (headers.isEmpty()) { // If the SYN has no headers, they may come later in a HEADERS frame return this; } else { if (synInfo.isClose()) { connection.endRequest(); return null; } else { return this; } } } @Override public void onReply(Stream stream, ReplyInfo replyInfo) { // Do nothing, servers cannot get replies } @Override public void onHeaders(Stream stream, HeadersInfo headersInfo) { logger.debug("Received {} on {}", headersInfo, stream); ServerHTTPSPDYAsyncConnection connection = (ServerHTTPSPDYAsyncConnection)stream.getAttribute(CONNECTION_ATTRIBUTE); connection.headers(headersInfo.getHeaders()); if (headersInfo.isClose()) connection.endRequest(); } @Override public void onData(Stream stream, DataInfo dataInfo) { logger.debug("Received {} on {}", dataInfo, stream); ServerHTTPSPDYAsyncConnection connection = (ServerHTTPSPDYAsyncConnection)stream.getAttribute(CONNECTION_ATTRIBUTE); connection.content(dataInfo, dataInfo.isClose()); if (dataInfo.isClose()) connection.endRequest(); } } private class HTTPSPDYAsyncEndPoint extends EmptyAsyncEndPoint { private final Stream stream; public HTTPSPDYAsyncEndPoint(Stream stream) { this.stream = stream; } @Override public void asyncDispatch() { ServerHTTPSPDYAsyncConnection connection = (ServerHTTPSPDYAsyncConnection)stream.getAttribute(CONNECTION_ATTRIBUTE); connection.async(); } } }