Merged branch 'jetty-9.3.x' into 'master'.

This commit is contained in:
Simone Bordet 2015-10-22 20:52:22 +02:00
commit c39bfa2e4a
8 changed files with 113 additions and 39 deletions

View File

@ -18,7 +18,6 @@
package org.eclipse.jetty.client; package org.eclipse.jetty.client;
import java.io.IOException;
import java.net.CookieManager; import java.net.CookieManager;
import java.net.CookiePolicy; import java.net.CookiePolicy;
import java.net.CookieStore; import java.net.CookieStore;
@ -1054,13 +1053,6 @@ public class HttpClient extends ContainerLifeCycle
return port == 80; return port == 80;
} }
@Override
public void dump(Appendable out, String indent) throws IOException
{
dumpThis(out);
dump(out, indent, getBeans(), destinations.values());
}
private class ContentDecoderFactorySet implements Set<ContentDecoder.Factory> private class ContentDecoderFactorySet implements Set<ContentDecoder.Factory>
{ {
private final Set<ContentDecoder.Factory> set = new HashSet<>(); private final Set<ContentDecoder.Factory> set = new HashSet<>();

View File

@ -23,6 +23,23 @@ import java.nio.ByteBuffer;
import org.eclipse.jetty.fcgi.FCGI; import org.eclipse.jetty.fcgi.FCGI;
import org.eclipse.jetty.http.HttpField; import org.eclipse.jetty.http.HttpField;
/**
* <p>The FastCGI protocol exchanges <em>frames</em>.</p>
* <pre>
* struct frame {
* ubyte version;
* ubyte type;
* ushort requestId;
* ushort contentLength;
* ubyte paddingLength;
* ubyte reserved;
* ubyte[] content;
* ubyte[] padding;
* }
* </pre>
* <p>Depending on the {@code type}, the content may have a different format,
* so there are specialized content parsers.</p>
*/
public abstract class Parser public abstract class Parser
{ {
protected final HeaderParser headerParser = new HeaderParser(); protected final HeaderParser headerParser = new HeaderParser();

View File

@ -18,11 +18,13 @@
package org.eclipse.jetty.fcgi.parser; package org.eclipse.jetty.fcgi.parser;
import java.io.EOFException;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.util.Map; import java.util.Map;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import org.eclipse.jetty.fcgi.FCGI; import org.eclipse.jetty.fcgi.FCGI;
import org.eclipse.jetty.http.BadMessageException;
import org.eclipse.jetty.http.HttpField; import org.eclipse.jetty.http.HttpField;
import org.eclipse.jetty.http.HttpFields; import org.eclipse.jetty.http.HttpFields;
import org.eclipse.jetty.http.HttpHeader; import org.eclipse.jetty.http.HttpHeader;
@ -32,6 +34,14 @@ import org.eclipse.jetty.http.HttpVersion;
import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger; import org.eclipse.jetty.util.log.Logger;
/**
* <p>The parser for STDOUT type frames.</p>
* <p>STDOUT frames contain both the HTTP headers (but not the response line)
* and the HTTP content (either Content-Length delimited or chunked).</p>
* <p>For this reason, a special HTTP parser is used to parse the frames body.
* This special HTTP parser is configured to skip the response line, and to
* parse HTTP headers and HTTP content.</p>
*/
public class ResponseContentParser extends StreamContentParser public class ResponseContentParser extends StreamContentParser
{ {
private static final Logger LOG = Log.getLogger(ResponseContentParser.class); private static final Logger LOG = Log.getLogger(ResponseContentParser.class);
@ -245,12 +255,12 @@ public class ResponseContentParser extends StreamContentParser
{ {
if (!seenResponseCode) if (!seenResponseCode)
{ {
// No Status header but we have other headers, assume 200 OK // No Status header but we have other headers, assume 200 OK.
notifyBegin(200, "OK"); notifyBegin(200, "OK");
notifyHeaders(fields); notifyHeaders(fields);
} }
notifyHeaders(); notifyHeaders();
// Return from parsing so that we can parse the content // Return from HTTP parsing so that we can parse the content.
return true; return true;
} }
@ -277,21 +287,34 @@ public class ResponseContentParser extends StreamContentParser
@Override @Override
public boolean messageComplete() public boolean messageComplete()
{ {
// Return from parsing so that we can parse the next headers or the raw content. // No need to notify the end of the response to the
// No need to notify the listener because it will be done by FCGI_END_REQUEST. // listener because it will be done by FCGI_END_REQUEST.
return true; return false;
} }
@Override @Override
public void earlyEOF() public void earlyEOF()
{ {
// TODO fail(new EOFException());
} }
@Override @Override
public void badMessage(int status, String reason) public void badMessage(int status, String reason)
{ {
// TODO fail(new BadMessageException(status, reason));
}
protected void fail(Throwable failure)
{
try
{
listener.onFailure(request, failure);
}
catch (Throwable x)
{
if (LOG.isDebugEnabled())
LOG.debug("Exception while invoking listener " + listener, x);
}
} }
} }

View File

@ -24,6 +24,10 @@ import org.eclipse.jetty.fcgi.FCGI;
import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger; import org.eclipse.jetty.util.log.Logger;
/**
* <p>A stream content parser parses frames of type STDIN, STDOUT and STDERR.</p>
* <p>STDOUT frames are handled specially by {@link ResponseContentParser}.
*/
public class StreamContentParser extends ContentParser public class StreamContentParser extends ContentParser
{ {
private static final Logger LOG = Log.getLogger(StreamContentParser.class); private static final Logger LOG = Log.getLogger(StreamContentParser.class);

View File

@ -95,6 +95,35 @@ public class HttpClientTest extends AbstractHttpClientServerTest
} }
} }
@Test
public void testGETResponseWithBigContent() throws Exception
{
final byte[] data = new byte[16 * 1024 * 1024];
new Random().nextBytes(data);
start(new AbstractHandler()
{
@Override
public void handle(String target, org.eclipse.jetty.server.Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
{
// Setting the Content-Length triggers the HTTP
// content mode for response content parsing,
// otherwise the RAW content mode is used.
response.setContentLength(data.length);
response.getOutputStream().write(data);
baseRequest.setHandled(true);
}
});
Request request = client.newRequest(scheme + "://localhost:" + connector.getLocalPort());
FutureResponseListener listener = new FutureResponseListener(request, data.length);
request.send(listener);
ContentResponse response = listener.get(15, TimeUnit.SECONDS);
Assert.assertNotNull(response);
Assert.assertEquals(200, response.getStatus());
byte[] content = response.getContent();
Assert.assertArrayEquals(data, content);
}
@Test @Test
public void testGETWithParametersResponseWithContent() throws Exception public void testGETWithParametersResponseWithContent() throws Exception
{ {

View File

@ -19,11 +19,9 @@
package org.eclipse.jetty.fcgi.server.proxy; package org.eclipse.jetty.fcgi.server.proxy;
import java.io.IOException; import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.Arrays;
import java.util.Collection;
import java.util.Random; import java.util.Random;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import javax.servlet.ServletException; import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
@ -32,7 +30,6 @@ import javax.servlet.http.HttpServletResponse;
import org.eclipse.jetty.client.HttpClient; import org.eclipse.jetty.client.HttpClient;
import org.eclipse.jetty.client.api.ContentResponse; import org.eclipse.jetty.client.api.ContentResponse;
import org.eclipse.jetty.client.api.Request; import org.eclipse.jetty.client.api.Request;
import org.eclipse.jetty.client.api.Response;
import org.eclipse.jetty.client.util.FutureResponseListener; import org.eclipse.jetty.client.util.FutureResponseListener;
import org.eclipse.jetty.fcgi.server.ServerFCGIConnectionFactory; import org.eclipse.jetty.fcgi.server.ServerFCGIConnectionFactory;
import org.eclipse.jetty.server.HttpConfiguration; import org.eclipse.jetty.server.HttpConfiguration;
@ -40,7 +37,7 @@ import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.ServerConnector; import org.eclipse.jetty.server.ServerConnector;
import org.eclipse.jetty.servlet.ServletContextHandler; import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder; import org.eclipse.jetty.servlet.ServletHolder;
import org.eclipse.jetty.util.Callback; import org.eclipse.jetty.util.thread.QueuedThreadPool;
import org.junit.After; import org.junit.After;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Test; import org.junit.Test;
@ -51,9 +48,9 @@ import org.junit.runners.Parameterized;
public class FastCGIProxyServletTest public class FastCGIProxyServletTest
{ {
@Parameterized.Parameters @Parameterized.Parameters
public static Collection<Object[]> parameters() public static Object[] parameters()
{ {
return Arrays.asList(new Object[]{true}, new Object[]{false}); return new Object[]{true, false};
} }
private final boolean sendStatus200; private final boolean sendStatus200;
@ -69,7 +66,9 @@ public class FastCGIProxyServletTest
public void prepare(HttpServlet servlet) throws Exception public void prepare(HttpServlet servlet) throws Exception
{ {
server = new Server(); QueuedThreadPool serverThreads = new QueuedThreadPool();
serverThreads.setName("server");
server = new Server(serverThreads);
httpConnector = new ServerConnector(server); httpConnector = new ServerConnector(server);
server.addConnector(httpConnector); server.addConnector(httpConnector);
@ -89,14 +88,18 @@ public class FastCGIProxyServletTest
} }
}; };
ServletHolder fcgiServletHolder = new ServletHolder(fcgiServlet); ServletHolder fcgiServletHolder = new ServletHolder(fcgiServlet);
context.addServlet(fcgiServletHolder, "*.php"); fcgiServletHolder.setName("fcgi");
fcgiServletHolder.setInitParameter(FastCGIProxyServlet.SCRIPT_ROOT_INIT_PARAM, "/scriptRoot"); fcgiServletHolder.setInitParameter(FastCGIProxyServlet.SCRIPT_ROOT_INIT_PARAM, "/scriptRoot");
fcgiServletHolder.setInitParameter("proxyTo", "http://localhost"); fcgiServletHolder.setInitParameter("proxyTo", "http://localhost");
fcgiServletHolder.setInitParameter(FastCGIProxyServlet.SCRIPT_PATTERN_INIT_PARAM, "(.+?\\.php)"); fcgiServletHolder.setInitParameter(FastCGIProxyServlet.SCRIPT_PATTERN_INIT_PARAM, "(.+?\\.php)");
context.addServlet(fcgiServletHolder, "*.php");
context.addServlet(new ServletHolder(servlet), servletPath + "/*"); context.addServlet(new ServletHolder(servlet), servletPath + "/*");
QueuedThreadPool clientThreads = new QueuedThreadPool();
clientThreads.setName("client");
client = new HttpClient(); client = new HttpClient();
client.setExecutor(clientThreads);
server.addBean(client); server.addBean(client);
server.start(); server.start();
@ -144,10 +147,7 @@ public class FastCGIProxyServletTest
}); });
Request request = client.newRequest("localhost", httpConnector.getLocalPort()) Request request = client.newRequest("localhost", httpConnector.getLocalPort())
.onResponseContentAsync(new Response.AsyncContentListener() .onResponseContentAsync((response, content, callback) ->
{
@Override
public void onContent(Response response, ByteBuffer content, Callback callback)
{ {
try try
{ {
@ -159,7 +159,6 @@ public class FastCGIProxyServletTest
{ {
callback.failed(x); callback.failed(x);
} }
}
}) })
.path(path); .path(path);
FutureResponseListener listener = new FutureResponseListener(request, length); FutureResponseListener listener = new FutureResponseListener(request, length);

View File

@ -20,7 +20,17 @@
<Set name="rewritePathInfo"><Property name="jetty.rewrite.rewritePathInfo" deprecated="rewrite.rewritePathInfo" default="false"/></Set> <Set name="rewritePathInfo"><Property name="jetty.rewrite.rewritePathInfo" deprecated="rewrite.rewritePathInfo" default="false"/></Set>
<Set name="originalPathAttribute"><Property name="jetty.rewrite.originalPathAttribute" deprecated="rewrite.originalPathAttribute" default="requestedPath"/></Set> <Set name="originalPathAttribute"><Property name="jetty.rewrite.originalPathAttribute" deprecated="rewrite.originalPathAttribute" default="requestedPath"/></Set>
</New> </New>
<!-- Set DispatcherTypes -->
<Set name="dispatcherTypes">
<Array type="javax.servlet.DispatcherType">
<Item><Call class="javax.servlet.DispatcherType" name="valueOf"><Arg>REQUEST</Arg></Call></Item>
<Item><Call class="javax.servlet.DispatcherType" name="valueOf"><Arg>ASYNC</Arg></Call></Item>
</Array>
</Set> </Set>
</Set>
<!-- example rule --> <!-- example rule -->
<!-- <!--

View File

@ -173,7 +173,7 @@ import org.eclipse.jetty.server.handler.HandlerWrapper;
public class RewriteHandler extends HandlerWrapper public class RewriteHandler extends HandlerWrapper
{ {
private RuleContainer _rules; private RuleContainer _rules;
private EnumSet<DispatcherType> _dispatchTypes = EnumSet.of(DispatcherType.REQUEST); private EnumSet<DispatcherType> _dispatchTypes = EnumSet.of(DispatcherType.REQUEST, DispatcherType.ASYNC);
/* ------------------------------------------------------------ */ /* ------------------------------------------------------------ */
public RewriteHandler() public RewriteHandler()