Merge remote-tracking branch 'origin/master' into jetty-9.1

Conflicts:
	jetty-io/src/main/java/org/eclipse/jetty/io/AbstractConnection.java
	jetty-server/src/test/java/org/eclipse/jetty/server/HttpServerTestBase.java
	jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/proxy/ProxyHTTPSPDYConnection.java
This commit is contained in:
Greg Wilkins 2013-09-02 17:00:07 +10:00
commit 2e444d2f17
11 changed files with 119 additions and 21 deletions

View File

@ -531,15 +531,22 @@ public abstract class AbstractConnection implements Connection
}
@Override
public void failed(Throwable x)
public void failed(final Throwable x)
{
_executor.execute(new Runnable()
{
@Override
public void run()
{
while(true)
{
State state=_state.get();
if (next(state,state.onFailed()))
break;
}
onFillInterestedFailed(x);
onFillInterestedFailed(x);
}
});
}
@Override

View File

@ -291,12 +291,12 @@ public class SslConnection extends AbstractConnection
}
@Override
public void failed(Throwable x)
public void failed(final Throwable x)
{
// This means that a write of data has failed. Writes are done
// only if there is an active writeflusher or a read needed to write
// data. In either case the appropriate callback is passed on.
boolean failFiller = false;
boolean fail_filler = false;
synchronized (DecryptedEndPoint.this)
{
if (DEBUG)
@ -309,12 +309,23 @@ public class SslConnection extends AbstractConnection
if (_fillRequiresFlushToProgress)
{
_fillRequiresFlushToProgress = false;
failFiller = true;
fail_filler = true;
}
}
if (failFiller)
getFillInterest().onFail(x);
getWriteFlusher().onFail(x);
final boolean filler_failed=fail_filler;
getExecutor().execute(new Runnable()
{
@Override
public void run()
{
if (filler_failed)
getFillInterest().onFail(x);
getWriteFlusher().onFail(x);
}
});
}
};

View File

@ -761,8 +761,8 @@ public class HttpChannel<T> implements HttpParser.RequestHandler<T>, Runnable
if (x instanceof EofException)
{
LOG.debug(x);
_response.getHttpOutput().closed();
_callback.failed(x);
_response.getHttpOutput().closed();
}
else
{
@ -772,16 +772,16 @@ public class HttpChannel<T> implements HttpParser.RequestHandler<T>, Runnable
@Override
public void succeeded()
{
_response.getHttpOutput().closed();
_callback.failed(x);
_response.getHttpOutput().closed();
}
@Override
public void failed(Throwable th)
{
LOG.ignore(th);
_response.getHttpOutput().closed();
_callback.failed(x);
_response.getHttpOutput().closed();
}
});
}

View File

@ -143,6 +143,26 @@ public class ServerConnector extends AbstractNetworkConnector
this(server,null,null,null,0,0,AbstractConnectionFactory.getFactories(sslContextFactory,new HttpConnectionFactory()));
}
/* ------------------------------------------------------------ */
/** HTTP Server Connection.
* <p>Construct a ServerConnector with a private instance of {@link HttpConnectionFactory} as the primary protocol</p>.
* @param server The {@link Server} this connector will accept connection for.
* @param sslContextFactory If non null, then a {@link SslConnectionFactory} is instantiated and prepended to the
* list of HTTP Connection Factory.
* @param acceptors
* the number of acceptor threads to use, or 0 for a default value. Acceptors accept new TCP/IP connections.
* @param selectors
* the number of selector threads, or 0 for a default value. Selectors notice and schedule established connection that can make IO progress.
*/
public ServerConnector(
@Name("server") Server server,
@Name("acceptors") int acceptors,
@Name("selectors") int selectors,
@Name("sslContextFactory") SslContextFactory sslContextFactory)
{
this(server,null,null,null,acceptors,selectors,AbstractConnectionFactory.getFactories(sslContextFactory,new HttpConnectionFactory()));
}
/* ------------------------------------------------------------ */
/** Generic SSL Server Connection.
* @param server The {@link Server} this connector will accept connection for.

View File

@ -22,6 +22,7 @@ import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.greaterThanOrEqualTo;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.not;
import static org.hamcrest.Matchers.startsWith;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertThat;
@ -35,9 +36,12 @@ import java.io.InputStreamReader;
import java.io.LineNumberReader;
import java.io.OutputStream;
import java.net.Socket;
import java.net.URI;
import java.net.URL;
import java.util.Arrays;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Exchanger;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import javax.servlet.ServletException;
@ -660,6 +664,57 @@ public abstract class HttpServerTestBase extends HttpServerTestFixture
}
}
@Test
public void testCloseWhileWriteBlocked() throws Exception
{
configureServer(new DataHandler());
try (Socket client = newSocket(_serverURI.getHost(), _serverURI.getPort()))
{
OutputStream os = client.getOutputStream();
InputStream is = client.getInputStream();
os.write((
"GET /data?encoding=iso-8859-1&writes=100&block=100000 HTTP/1.1\r\n" +
"host: " + _serverURI.getHost() + ":" + _serverURI.getPort() + "\r\n" +
"connection: close\r\n" +
"content-type: unknown\r\n" +
"\r\n"
).getBytes());
os.flush();
// Read the first part of the response
byte[] buf = new byte[1024 * 8];
is.read(buf);
// sleep to ensure server is blocking
Thread.sleep(500);
// Close the client
client.close();
}
Thread.sleep(200);
// check server is still handling requests quickly
try (Socket client = newSocket(_serverURI.getHost(), _serverURI.getPort()))
{
client.setSoTimeout(500);
OutputStream os = client.getOutputStream();
InputStream is = client.getInputStream();
os.write(("GET /data?writes=1&block=1024 HTTP/1.1\r\n" +
"host: " + _serverURI.getHost() + ":" + _serverURI.getPort() + "\r\n" +
"connection: close\r\n" +
"content-type: unknown\r\n" +
"\r\n"
).getBytes());
os.flush();
String response = IO.toString(is);
assertThat(response,startsWith("HTTP/1.1 200 OK"));
}
}
@Test
public void testBigBlocks() throws Exception
{
@ -1432,7 +1487,7 @@ public abstract class HttpServerTestBase extends HttpServerTestFixture
os.flush();
String response = readResponse(client);
assertThat(response, JUnitMatchers.containsString("RESUMEDHTTP/1.1 200 OK"));
assertThat(response, containsString("RESUMEDHTTP/1.1 200 OK"));
assertThat((System.currentTimeMillis() - start), greaterThanOrEqualTo(1999L));
// TODO This test should also check that that the CPU did not spin during the suspend.

View File

@ -151,6 +151,7 @@ public class HttpServerTestFixture
protected static class HelloWorldHandler extends AbstractHandler
{
@Override
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
{
baseRequest.setHandled(true);
@ -195,20 +196,24 @@ public class HttpServerTestFixture
else if ("true".equals(chars))
{
response.setCharacterEncoding(encoding);
Writer out=response.getWriter();
PrintWriter out=response.getWriter();
char[] c=chunk.toCharArray();
for (int i=0;i<writes;i++)
{
out.write(c);
if (out.checkError())
break;
}
}
else
{
response.setCharacterEncoding(encoding);
Writer out=response.getWriter();
PrintWriter out=response.getWriter();
for (int i=0;i<writes;i++)
{
out.write(chunk);
if (out.checkError())
break;
}
}

View File

@ -28,6 +28,6 @@ public class SelectChannelServerTest extends HttpServerTestBase
@Before
public void init() throws Exception
{
startServer(new ServerConnector(_server));
startServer(new ServerConnector(_server,1,1));
}
}

View File

@ -36,7 +36,7 @@ public class SelectChannelTimeoutTest extends ConnectorTimeoutTest
@Before
public void init() throws Exception
{
ServerConnector connector = new ServerConnector(_server);
ServerConnector connector = new ServerConnector(_server,1,1);
connector.setIdleTimeout(MAX_IDLE_TIME); // 250 msec max idle
startServer(connector);
}

View File

@ -106,7 +106,7 @@ public class SelectChannelServerSslTest extends HttpServerTestBase
sslContextFactory.setKeyManagerPassword("keypwd");
sslContextFactory.setTrustStorePath(keystorePath);
sslContextFactory.setTrustStorePassword("storepwd");
ServerConnector connector = new ServerConnector(_server, sslContextFactory);
ServerConnector connector = new ServerConnector(_server, 1, 1, sslContextFactory);
startServer(connector);

View File

@ -50,7 +50,7 @@ public class SslSelectChannelTimeoutTest extends ConnectorTimeoutTest
sslContextFactory.setKeyManagerPassword("keypwd");
sslContextFactory.setTrustStorePath(keystorePath);
sslContextFactory.setTrustStorePassword("storepwd");
ServerConnector connector = new ServerConnector(_server, sslContextFactory);
ServerConnector connector = new ServerConnector(_server, 1, 1, sslContextFactory);
connector.setIdleTimeout(MAX_IDLE_TIME); //250 msec max idle
startServer(connector);

View File

@ -68,7 +68,7 @@ public class ProxyHTTPSPDYConnection extends HttpConnection implements HttpParse
public ProxyHTTPSPDYConnection(Connector connector, HttpConfiguration config, EndPoint endPoint, short version, ProxyEngineSelector proxyEngineSelector)
{
super(config,connector,endPoint);
super(config, connector, endPoint);
this.version = version;
this.proxyEngineSelector = proxyEngineSelector;
this.session = new HTTPSession(version, connector);
@ -95,7 +95,7 @@ public class ProxyHTTPSPDYConnection extends HttpConnection implements HttpParse
@Override
public boolean parsedHeader(HttpField field)
{
if (field.getHeader()==HttpHeader.HOST)
if (field.getHeader() == HttpHeader.HOST)
headers.put(HTTPSPDYHeader.HOST.name(version), field.getValue());
else
headers.put(field.getName(), field.getValue());
@ -243,7 +243,7 @@ public class ProxyHTTPSPDYConnection extends HttpConnection implements HttpParse
{
Fields headers = new Fields(replyInfo.getHeaders(), false);
addPersistenceHeader(headers);
addPersistenceHeader(headers);
headers.remove(HTTPSPDYHeader.SCHEME.name(version));