From 268ca92ce2e8135c02edb9170e7bc9e9946fe89e Mon Sep 17 00:00:00 2001 From: Jan Bartel Date: Thu, 10 Apr 2014 09:34:39 +1000 Subject: [PATCH 01/14] 432473 web.xml declaration order of filters not preserved on calls to init() --- .../webapp/StandardDescriptorProcessor.java | 36 ++++++++++++------- 1 file changed, 24 insertions(+), 12 deletions(-) diff --git a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/StandardDescriptorProcessor.java b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/StandardDescriptorProcessor.java index 43c33480374..06cd46f9ad5 100644 --- a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/StandardDescriptorProcessor.java +++ b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/StandardDescriptorProcessor.java @@ -70,9 +70,11 @@ public class StandardDescriptorProcessor extends IterativeDescriptorProcessor public static final String STANDARD_PROCESSOR = "org.eclipse.jetty.standardDescriptorProcessor"; - final Map _filterHolders = new HashMap<>(); + final Map _filterHolderMap = new HashMap<>(); + final List _filterHolders = new ArrayList<>(); final List _filterMappings = new ArrayList<>(); - final Map _servletHolders = new HashMap<>(); + final Map _servletHolderMap = new HashMap<>(); + final List _servletHolders = new ArrayList<>(); final List _servletMappings = new ArrayList<>(); public StandardDescriptorProcessor () @@ -113,11 +115,17 @@ public class StandardDescriptorProcessor extends IterativeDescriptorProcessor public void start(WebAppContext context, Descriptor descriptor) { for (FilterHolder h : context.getServletHandler().getFilters()) - _filterHolders.put(h.getName(),h); + { + _filterHolderMap.put(h.getName(),h); + _filterHolders.add(h); + } if (context.getServletHandler().getFilterMappings()!=null) _filterMappings.addAll(Arrays.asList(context.getServletHandler().getFilterMappings())); for (ServletHolder h : context.getServletHandler().getServlets()) - _servletHolders.put(h.getName(),h); + { + _servletHolderMap.put(h.getName(),h); + _servletHolders.add(h); + } if (context.getServletHandler().getServletMappings()!=null) _servletMappings.addAll(Arrays.asList(context.getServletHandler().getServletMappings())); } @@ -128,14 +136,16 @@ public class StandardDescriptorProcessor extends IterativeDescriptorProcessor */ public void end(WebAppContext context, Descriptor descriptor) { - context.getServletHandler().setFilters(_filterHolders.values().toArray(new FilterHolder[_filterHolders.size()])); - context.getServletHandler().setServlets(_servletHolders.values().toArray(new ServletHolder[_servletHolders.size()])); + context.getServletHandler().setFilters(_filterHolders.toArray(new FilterHolder[_filterHolderMap.size()])); + context.getServletHandler().setServlets(_servletHolders.toArray(new ServletHolder[_servletHolderMap.size()])); context.getServletHandler().setFilterMappings(_filterMappings.toArray(new FilterMapping[_filterMappings.size()])); context.getServletHandler().setServletMappings(_servletMappings.toArray(new ServletMapping[_servletMappings.size()])); + _filterHolderMap.clear(); _filterHolders.clear(); _filterMappings.clear(); + _servletHolderMap.clear(); _servletHolders.clear(); _servletMappings.clear(); } @@ -217,14 +227,15 @@ public class StandardDescriptorProcessor extends IterativeDescriptorProcessor // initialize holder String name = node.getString("servlet-name", false, true); - ServletHolder holder = _servletHolders.get(name); + ServletHolder holder = _servletHolderMap.get(name); //If servlet of that name does not already exist, create it. if (holder == null) { holder = context.getServletHandler().newServletHolder(Source.DESCRIPTOR); holder.setName(name); - _servletHolders.put(name,holder); + _servletHolderMap.put(name,holder); + _servletHolders.add(holder); } // init params @@ -1401,11 +1412,11 @@ public class StandardDescriptorProcessor extends IterativeDescriptorProcessor if (paths.size() > 0) { ServletHandler handler = context.getServletHandler(); - ServletHolder jsp_pg_servlet = _servletHolders.get(JspPropertyGroupServlet.NAME); + ServletHolder jsp_pg_servlet = _servletHolderMap.get(JspPropertyGroupServlet.NAME); if (jsp_pg_servlet==null) { jsp_pg_servlet=new ServletHolder(JspPropertyGroupServlet.NAME,new JspPropertyGroupServlet(context,handler)); - _servletHolders.put(JspPropertyGroupServlet.NAME,jsp_pg_servlet); + _servletHolderMap.put(JspPropertyGroupServlet.NAME,jsp_pg_servlet); } ServletMapping mapping = new ServletMapping(); @@ -1721,12 +1732,13 @@ public class StandardDescriptorProcessor extends IterativeDescriptorProcessor protected void visitFilter(WebAppContext context, Descriptor descriptor, XmlParser.Node node) { String name = node.getString("filter-name", false, true); - FilterHolder holder = _filterHolders.get(name); + FilterHolder holder = _filterHolderMap.get(name); if (holder == null) { holder = context.getServletHandler().newFilterHolder(Source.DESCRIPTOR); holder.setName(name); - _filterHolders.put(name,holder); + _filterHolderMap.put(name,holder); + _filterHolders.add(holder); } String filter_class = node.getString("filter-class", false, true); From 9f3e9861198a610480c4a1e559932231982e04b7 Mon Sep 17 00:00:00 2001 From: Greg Wilkins Date: Thu, 10 Apr 2014 16:20:10 +1000 Subject: [PATCH 02/14] 431519 Fixed NetworkTrafficListener --- .../NetworkTrafficSelectChannelEndPoint.java | 59 +++++++++++-------- .../server/NetworkTrafficServerConnector.java | 1 - .../server/NetworkTrafficListenerTest.java | 21 +++++-- 3 files changed, 51 insertions(+), 30 deletions(-) diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/NetworkTrafficSelectChannelEndPoint.java b/jetty-io/src/main/java/org/eclipse/jetty/io/NetworkTrafficSelectChannelEndPoint.java index d45902e36dd..a4b6f7d2a16 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/NetworkTrafficSelectChannelEndPoint.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/NetworkTrafficSelectChannelEndPoint.java @@ -19,11 +19,13 @@ package org.eclipse.jetty.io; import java.io.IOException; +import java.net.Socket; import java.nio.ByteBuffer; import java.nio.channels.SelectionKey; import java.nio.channels.SocketChannel; import java.util.List; +import org.eclipse.jetty.util.BufferUtil; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; import org.eclipse.jetty.util.thread.Scheduler; @@ -57,9 +59,11 @@ public class NetworkTrafficSelectChannelEndPoint extends SelectChannelEndPoint if (b.hasRemaining()) { int position = b.position(); + ByteBuffer view=b.slice(); flushed&=super.flush(b); int l=b.position()-position; - notifyOutgoing(b, position, l); + view.limit(view.position()+l); + notifyOutgoing(view); if (!flushed) break; } @@ -67,9 +71,12 @@ public class NetworkTrafficSelectChannelEndPoint extends SelectChannelEndPoint return flushed; } + - public void notifyOpened() + @Override + public void onOpen() { + super.onOpen(); if (listeners != null && !listeners.isEmpty()) { for (NetworkTrafficListener listener : listeners) @@ -86,6 +93,27 @@ public class NetworkTrafficSelectChannelEndPoint extends SelectChannelEndPoint } } + @Override + public void onClose() + { + super.onClose(); + if (listeners != null && !listeners.isEmpty()) + { + for (NetworkTrafficListener listener : listeners) + { + try + { + listener.closed(getSocket()); + } + catch (Exception x) + { + LOG.warn(x); + } + } + } + } + + public void notifyIncoming(ByteBuffer buffer, int read) { if (listeners != null && !listeners.isEmpty() && read > 0) @@ -105,18 +133,16 @@ public class NetworkTrafficSelectChannelEndPoint extends SelectChannelEndPoint } } - public void notifyOutgoing(ByteBuffer buffer, int position, int written) + public void notifyOutgoing(ByteBuffer view) { - if (listeners != null && !listeners.isEmpty() && written > 0) + if (listeners != null && !listeners.isEmpty() && view.hasRemaining()) { + Socket socket=getSocket(); for (NetworkTrafficListener listener : listeners) { try { - ByteBuffer view = buffer.slice(); - view.position(position); - view.limit(position + written); - listener.outgoing(getSocket(), view); + listener.outgoing(socket, view); } catch (Exception x) { @@ -126,21 +152,4 @@ public class NetworkTrafficSelectChannelEndPoint extends SelectChannelEndPoint } } - public void notifyClosed() - { - if (listeners != null && !listeners.isEmpty()) - { - for (NetworkTrafficListener listener : listeners) - { - try - { - listener.closed(getSocket()); - } - catch (Exception x) - { - LOG.warn(x); - } - } - } - } } diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/NetworkTrafficServerConnector.java b/jetty-server/src/main/java/org/eclipse/jetty/server/NetworkTrafficServerConnector.java index 24ac7e47446..34de615be58 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/NetworkTrafficServerConnector.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/NetworkTrafficServerConnector.java @@ -87,7 +87,6 @@ public class NetworkTrafficServerConnector extends ServerConnector protected SelectChannelEndPoint newEndPoint(SocketChannel channel, SelectorManager.ManagedSelector selectSet, SelectionKey key) throws IOException { NetworkTrafficSelectChannelEndPoint endPoint = new NetworkTrafficSelectChannelEndPoint(channel, selectSet, key, getScheduler(), getIdleTimeout(), listeners); - endPoint.notifyOpened(); return endPoint; } } diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/NetworkTrafficListenerTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/NetworkTrafficListenerTest.java index bf84223df11..ca9d7999cb9 100644 --- a/jetty-server/src/test/java/org/eclipse/jetty/server/NetworkTrafficListenerTest.java +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/NetworkTrafficListenerTest.java @@ -44,7 +44,6 @@ import org.junit.After; import org.junit.Ignore; import org.junit.Test; -@Ignore public class NetworkTrafficListenerTest { private static final byte END_OF_CONTENT = '~'; @@ -114,6 +113,7 @@ public class NetworkTrafficListenerTest { initConnector(new AbstractHandler() { + @Override public void handle(String uri, Request request, HttpServletRequest servletRequest, HttpServletResponse servletResponse) throws IOException, ServletException { request.setHandled(true); @@ -176,6 +176,7 @@ public class NetworkTrafficListenerTest final String responseContent = "response_content"; initConnector(new AbstractHandler() { + @Override public void handle(String uri, Request request, HttpServletRequest servletRequest, HttpServletResponse servletResponse) throws IOException, ServletException { request.setHandled(true); @@ -191,12 +192,14 @@ public class NetworkTrafficListenerTest final CountDownLatch outgoingLatch = new CountDownLatch(2); connector.addNetworkTrafficListener(new NetworkTrafficListener.Adapter() { + @Override public void incoming(Socket socket, ByteBuffer bytes) { incomingData.set(BufferUtil.toString(bytes,StandardCharsets.UTF_8)); incomingLatch.countDown(); } + @Override public void outgoing(Socket socket, ByteBuffer bytes) { outgoingData.set(outgoingData.get() + BufferUtil.toString(bytes,StandardCharsets.UTF_8)); @@ -241,6 +244,7 @@ public class NetworkTrafficListenerTest final String responseChunk2 = "response_content".substring(responseContent.length() / 2, responseContent.length()); initConnector(new AbstractHandler() { + @Override public void handle(String uri, Request request, HttpServletRequest servletRequest, HttpServletResponse servletResponse) throws IOException, ServletException { request.setHandled(true); @@ -255,19 +259,22 @@ public class NetworkTrafficListenerTest final AtomicReference incomingData = new AtomicReference<>(); final CountDownLatch incomingLatch = new CountDownLatch(1); final AtomicReference outgoingData = new AtomicReference<>(""); - final CountDownLatch outgoingLatch = new CountDownLatch(4); + final CountDownLatch outgoingLatch = new CountDownLatch(1); connector.addNetworkTrafficListener(new NetworkTrafficListener.Adapter() { + @Override public void incoming(Socket socket, ByteBuffer bytes) { incomingData.set(BufferUtil.toString(bytes,StandardCharsets.UTF_8)); incomingLatch.countDown(); } + @Override public void outgoing(Socket socket, ByteBuffer bytes) { - outgoingData.set(outgoingData.get() + BufferUtil.toString(bytes,StandardCharsets.UTF_8)); - outgoingLatch.countDown(); + outgoingData.set(outgoingData.get() + BufferUtil.toString(bytes,StandardCharsets.UTF_8)); + if (outgoingData.get().endsWith("\r\n0\r\n\r\n")) + outgoingLatch.countDown(); } }); int port = connector.getLocalPort(); @@ -311,6 +318,7 @@ public class NetworkTrafficListenerTest final String location = "/redirect"; initConnector(new AbstractHandler() { + @Override public void handle(String uri, Request request, HttpServletRequest servletRequest, HttpServletResponse servletResponse) throws IOException, ServletException { request.setHandled(true); @@ -324,12 +332,14 @@ public class NetworkTrafficListenerTest final CountDownLatch outgoingLatch = new CountDownLatch(1); connector.addNetworkTrafficListener(new NetworkTrafficListener.Adapter() { + @Override public void incoming(Socket socket, ByteBuffer bytes) { incomingData.set(BufferUtil.toString(bytes,StandardCharsets.UTF_8)); incomingLatch.countDown(); } + @Override public void outgoing(Socket socket, ByteBuffer bytes) { outgoingData.set(outgoingData.get() + BufferUtil.toString(bytes,StandardCharsets.UTF_8)); @@ -375,6 +385,7 @@ public class NetworkTrafficListenerTest { initConnector(new AbstractHandler() { + @Override public void handle(String uri, Request request, HttpServletRequest servletRequest, HttpServletResponse servletResponse) throws IOException, ServletException { // Read and discard the request body to make the test more @@ -397,11 +408,13 @@ public class NetworkTrafficListenerTest final CountDownLatch outgoingLatch = new CountDownLatch(1); connector.addNetworkTrafficListener(new NetworkTrafficListener.Adapter() { + @Override public void incoming(Socket socket, ByteBuffer bytes) { incomingData.set(incomingData.get() + BufferUtil.toString(bytes,StandardCharsets.UTF_8)); } + @Override public void outgoing(Socket socket, ByteBuffer bytes) { outgoingData.set(outgoingData.get() + BufferUtil.toString(bytes,StandardCharsets.UTF_8)); From 0e458c80f4763ac1b56c30cd7276a613c39f7343 Mon Sep 17 00:00:00 2001 From: Greg Wilkins Date: Thu, 10 Apr 2014 16:37:25 +1000 Subject: [PATCH 03/14] reverted version to SNAPSHOT --- aggregates/jetty-all/pom.xml | 2 +- examples/async-rest/async-rest-jar/pom.xml | 2 +- examples/async-rest/async-rest-webapp/pom.xml | 2 +- examples/async-rest/pom.xml | 2 +- examples/embedded/pom.xml | 2 +- examples/pom.xml | 2 +- jetty-annotations/pom.xml | 2 +- jetty-ant/pom.xml | 2 +- jetty-client/pom.xml | 2 +- jetty-continuation/pom.xml | 2 +- jetty-deploy/pom.xml | 2 +- jetty-distribution/pom.xml | 2 +- jetty-fcgi/fcgi-client/pom.xml | 2 +- jetty-fcgi/fcgi-server/pom.xml | 2 +- jetty-fcgi/pom.xml | 2 +- jetty-http-spi/pom.xml | 2 +- jetty-http/pom.xml | 2 +- jetty-io/pom.xml | 2 +- jetty-jaas/pom.xml | 2 +- jetty-jaspi/pom.xml | 2 +- jetty-jmx/pom.xml | 2 +- jetty-jndi/pom.xml | 2 +- jetty-jsp/pom.xml | 2 +- jetty-jspc-maven-plugin/pom.xml | 2 +- jetty-maven-plugin/pom.xml | 2 +- jetty-monitor/pom.xml | 2 +- jetty-nosql/pom.xml | 2 +- jetty-osgi/jetty-osgi-boot-jsp/pom.xml | 2 +- jetty-osgi/jetty-osgi-boot-warurl/pom.xml | 2 +- jetty-osgi/jetty-osgi-boot/pom.xml | 2 +- jetty-osgi/jetty-osgi-httpservice/pom.xml | 2 +- jetty-osgi/jetty-osgi-npn/pom.xml | 2 +- jetty-osgi/pom.xml | 2 +- jetty-osgi/test-jetty-osgi-context/pom.xml | 2 +- jetty-osgi/test-jetty-osgi-webapp/pom.xml | 2 +- jetty-osgi/test-jetty-osgi/pom.xml | 2 +- jetty-plus/pom.xml | 2 +- jetty-proxy/pom.xml | 2 +- jetty-rewrite/pom.xml | 2 +- jetty-runner/pom.xml | 2 +- jetty-security/pom.xml | 2 +- jetty-server/pom.xml | 2 +- jetty-servlet/pom.xml | 2 +- jetty-servlets/pom.xml | 2 +- jetty-spdy/pom.xml | 2 +- jetty-spdy/spdy-client/pom.xml | 2 +- jetty-spdy/spdy-core/pom.xml | 2 +- jetty-spdy/spdy-example-webapp/pom.xml | 2 +- jetty-spdy/spdy-http-client-transport/pom.xml | 2 +- jetty-spdy/spdy-http-common/pom.xml | 2 +- jetty-spdy/spdy-http-server/pom.xml | 2 +- jetty-spdy/spdy-npn-tests/pom.xml | 2 +- jetty-spdy/spdy-server/pom.xml | 2 +- jetty-spring/pom.xml | 2 +- jetty-start/pom.xml | 2 +- jetty-util-ajax/pom.xml | 2 +- jetty-util/pom.xml | 2 +- jetty-webapp/pom.xml | 2 +- jetty-websocket/javax-websocket-client-impl/pom.xml | 2 +- jetty-websocket/javax-websocket-server-impl/pom.xml | 2 +- jetty-websocket/pom.xml | 2 +- jetty-websocket/websocket-api/pom.xml | 2 +- jetty-websocket/websocket-client/pom.xml | 2 +- jetty-websocket/websocket-common/pom.xml | 2 +- jetty-websocket/websocket-server/pom.xml | 2 +- jetty-websocket/websocket-servlet/pom.xml | 2 +- jetty-xml/pom.xml | 2 +- pom.xml | 2 +- tests/pom.xml | 2 +- tests/test-continuation/pom.xml | 2 +- tests/test-integration/pom.xml | 2 +- tests/test-loginservice/pom.xml | 2 +- tests/test-sessions/pom.xml | 2 +- tests/test-sessions/test-hash-sessions/pom.xml | 2 +- tests/test-sessions/test-jdbc-sessions/pom.xml | 2 +- tests/test-sessions/test-sessions-common/pom.xml | 2 +- tests/test-webapps/pom.xml | 2 +- tests/test-webapps/test-jaas-webapp/pom.xml | 2 +- tests/test-webapps/test-jetty-webapp/pom.xml | 2 +- tests/test-webapps/test-jndi-webapp/pom.xml | 2 +- tests/test-webapps/test-mock-resources/pom.xml | 2 +- tests/test-webapps/test-proxy-webapp/pom.xml | 2 +- tests/test-webapps/test-servlet-spec/pom.xml | 2 +- .../test-servlet-spec/test-container-initializer/pom.xml | 2 +- tests/test-webapps/test-servlet-spec/test-spec-webapp/pom.xml | 2 +- tests/test-webapps/test-servlet-spec/test-web-fragment/pom.xml | 2 +- tests/test-webapps/test-webapp-rfc2616/pom.xml | 2 +- 87 files changed, 87 insertions(+), 87 deletions(-) diff --git a/aggregates/jetty-all/pom.xml b/aggregates/jetty-all/pom.xml index 8c7a2aa41a3..37932e60717 100644 --- a/aggregates/jetty-all/pom.xml +++ b/aggregates/jetty-all/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty jetty-project - 9.1.4.v20140401 + 9.1.5-SNAPSHOT ../../pom.xml 4.0.0 diff --git a/examples/async-rest/async-rest-jar/pom.xml b/examples/async-rest/async-rest-jar/pom.xml index b97841232a8..a8ff5148ac0 100644 --- a/examples/async-rest/async-rest-jar/pom.xml +++ b/examples/async-rest/async-rest-jar/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty example-async-rest - 9.1.4.v20140401 + 9.1.5-SNAPSHOT 4.0.0 org.eclipse.jetty.example-async-rest diff --git a/examples/async-rest/async-rest-webapp/pom.xml b/examples/async-rest/async-rest-webapp/pom.xml index a065511f0d0..582d5a01e1a 100644 --- a/examples/async-rest/async-rest-webapp/pom.xml +++ b/examples/async-rest/async-rest-webapp/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty example-async-rest - 9.1.4.v20140401 + 9.1.5-SNAPSHOT 4.0.0 org.eclipse.jetty.example-async-rest diff --git a/examples/async-rest/pom.xml b/examples/async-rest/pom.xml index ccbb885c3e0..b2b6ca3efdf 100644 --- a/examples/async-rest/pom.xml +++ b/examples/async-rest/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty.examples examples-parent - 9.1.4.v20140401 + 9.1.5-SNAPSHOT ../pom.xml 4.0.0 diff --git a/examples/embedded/pom.xml b/examples/embedded/pom.xml index ac5a9689701..8c0abaef80a 100644 --- a/examples/embedded/pom.xml +++ b/examples/embedded/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty.examples examples-parent - 9.1.4.v20140401 + 9.1.5-SNAPSHOT ../pom.xml 4.0.0 diff --git a/examples/pom.xml b/examples/pom.xml index 482ec13c636..2fadf1a7ed8 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -21,7 +21,7 @@ org.eclipse.jetty jetty-project - 9.1.4.v20140401 + 9.1.5-SNAPSHOT ../pom.xml org.eclipse.jetty.examples diff --git a/jetty-annotations/pom.xml b/jetty-annotations/pom.xml index e39037ae2f3..80ba3aa246a 100644 --- a/jetty-annotations/pom.xml +++ b/jetty-annotations/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty jetty-project - 9.1.4.v20140401 + 9.1.5-SNAPSHOT 4.0.0 jetty-annotations diff --git a/jetty-ant/pom.xml b/jetty-ant/pom.xml index 654f058db92..cc2012dece3 100644 --- a/jetty-ant/pom.xml +++ b/jetty-ant/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty jetty-project - 9.1.4.v20140401 + 9.1.5-SNAPSHOT 4.0.0 jetty-ant diff --git a/jetty-client/pom.xml b/jetty-client/pom.xml index 4fb970776bf..9eee4c93187 100644 --- a/jetty-client/pom.xml +++ b/jetty-client/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty jetty-project - 9.1.4.v20140401 + 9.1.5-SNAPSHOT 4.0.0 diff --git a/jetty-continuation/pom.xml b/jetty-continuation/pom.xml index bf498e39262..e7219dc2571 100644 --- a/jetty-continuation/pom.xml +++ b/jetty-continuation/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty jetty-project - 9.1.4.v20140401 + 9.1.5-SNAPSHOT 4.0.0 jetty-continuation diff --git a/jetty-deploy/pom.xml b/jetty-deploy/pom.xml index 6cc202cc41b..979acb0c2d3 100644 --- a/jetty-deploy/pom.xml +++ b/jetty-deploy/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty jetty-project - 9.1.4.v20140401 + 9.1.5-SNAPSHOT 4.0.0 jetty-deploy diff --git a/jetty-distribution/pom.xml b/jetty-distribution/pom.xml index 9cb320f17ad..5e43fa7e827 100644 --- a/jetty-distribution/pom.xml +++ b/jetty-distribution/pom.xml @@ -3,7 +3,7 @@ org.eclipse.jetty jetty-project - 9.1.4.v20140401 + 9.1.5-SNAPSHOT jetty-distribution Jetty :: Distribution Assemblies diff --git a/jetty-fcgi/fcgi-client/pom.xml b/jetty-fcgi/fcgi-client/pom.xml index bbb97a331ef..aeb2d6d667f 100644 --- a/jetty-fcgi/fcgi-client/pom.xml +++ b/jetty-fcgi/fcgi-client/pom.xml @@ -3,7 +3,7 @@ org.eclipse.jetty.fcgi fcgi-parent - 9.1.4.v20140401 + 9.1.5-SNAPSHOT 4.0.0 diff --git a/jetty-fcgi/fcgi-server/pom.xml b/jetty-fcgi/fcgi-server/pom.xml index c1acdc714ce..9335f2973ed 100644 --- a/jetty-fcgi/fcgi-server/pom.xml +++ b/jetty-fcgi/fcgi-server/pom.xml @@ -3,7 +3,7 @@ org.eclipse.jetty.fcgi fcgi-parent - 9.1.4.v20140401 + 9.1.5-SNAPSHOT 4.0.0 diff --git a/jetty-fcgi/pom.xml b/jetty-fcgi/pom.xml index 8e7f7083d01..1812d5744d1 100644 --- a/jetty-fcgi/pom.xml +++ b/jetty-fcgi/pom.xml @@ -3,7 +3,7 @@ org.eclipse.jetty jetty-project - 9.1.4.v20140401 + 9.1.5-SNAPSHOT 4.0.0 diff --git a/jetty-http-spi/pom.xml b/jetty-http-spi/pom.xml index 3c6b41d0f70..3697bbd5437 100644 --- a/jetty-http-spi/pom.xml +++ b/jetty-http-spi/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty jetty-project - 9.1.4.v20140401 + 9.1.5-SNAPSHOT 4.0.0 jetty-http-spi diff --git a/jetty-http/pom.xml b/jetty-http/pom.xml index 4dd5e4e6f0d..0681b33d667 100644 --- a/jetty-http/pom.xml +++ b/jetty-http/pom.xml @@ -3,7 +3,7 @@ jetty-project org.eclipse.jetty - 9.1.4.v20140401 + 9.1.5-SNAPSHOT 4.0.0 jetty-http diff --git a/jetty-io/pom.xml b/jetty-io/pom.xml index d2a9ac4a3fe..d146f2e4e25 100644 --- a/jetty-io/pom.xml +++ b/jetty-io/pom.xml @@ -2,7 +2,7 @@ jetty-project org.eclipse.jetty - 9.1.4.v20140401 + 9.1.5-SNAPSHOT 4.0.0 jetty-io diff --git a/jetty-jaas/pom.xml b/jetty-jaas/pom.xml index 51ba98d73bd..f8f57e6fab0 100644 --- a/jetty-jaas/pom.xml +++ b/jetty-jaas/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty jetty-project - 9.1.4.v20140401 + 9.1.5-SNAPSHOT 4.0.0 jetty-jaas diff --git a/jetty-jaspi/pom.xml b/jetty-jaspi/pom.xml index 80a962c1719..e45825c55ef 100644 --- a/jetty-jaspi/pom.xml +++ b/jetty-jaspi/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty jetty-project - 9.1.4.v20140401 + 9.1.5-SNAPSHOT 4.0.0 jetty-jaspi diff --git a/jetty-jmx/pom.xml b/jetty-jmx/pom.xml index 0c8b97add14..803d0841dbd 100644 --- a/jetty-jmx/pom.xml +++ b/jetty-jmx/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty jetty-project - 9.1.4.v20140401 + 9.1.5-SNAPSHOT 4.0.0 jetty-jmx diff --git a/jetty-jndi/pom.xml b/jetty-jndi/pom.xml index 3cd9ef9ddfe..66ffd586656 100644 --- a/jetty-jndi/pom.xml +++ b/jetty-jndi/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty jetty-project - 9.1.4.v20140401 + 9.1.5-SNAPSHOT 4.0.0 jetty-jndi diff --git a/jetty-jsp/pom.xml b/jetty-jsp/pom.xml index ef9e7ac9abc..21c1dca5332 100644 --- a/jetty-jsp/pom.xml +++ b/jetty-jsp/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty jetty-project - 9.1.4.v20140401 + 9.1.5-SNAPSHOT 4.0.0 jetty-jsp diff --git a/jetty-jspc-maven-plugin/pom.xml b/jetty-jspc-maven-plugin/pom.xml index dc640fbb05b..ad5472a38c5 100644 --- a/jetty-jspc-maven-plugin/pom.xml +++ b/jetty-jspc-maven-plugin/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty jetty-project - 9.1.4.v20140401 + 9.1.5-SNAPSHOT 4.0.0 jetty-jspc-maven-plugin diff --git a/jetty-maven-plugin/pom.xml b/jetty-maven-plugin/pom.xml index 482fd3cb2e0..b92a91f3333 100644 --- a/jetty-maven-plugin/pom.xml +++ b/jetty-maven-plugin/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty jetty-project - 9.1.4.v20140401 + 9.1.5-SNAPSHOT 4.0.0 jetty-maven-plugin diff --git a/jetty-monitor/pom.xml b/jetty-monitor/pom.xml index df7bfdb6de1..a6fdceb387c 100644 --- a/jetty-monitor/pom.xml +++ b/jetty-monitor/pom.xml @@ -19,7 +19,7 @@ org.eclipse.jetty jetty-project - 9.1.4.v20140401 + 9.1.5-SNAPSHOT 4.0.0 jetty-monitor diff --git a/jetty-nosql/pom.xml b/jetty-nosql/pom.xml index d54b042ed33..d65a221f8a9 100644 --- a/jetty-nosql/pom.xml +++ b/jetty-nosql/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty jetty-project - 9.1.4.v20140401 + 9.1.5-SNAPSHOT 4.0.0 jetty-nosql diff --git a/jetty-osgi/jetty-osgi-boot-jsp/pom.xml b/jetty-osgi/jetty-osgi-boot-jsp/pom.xml index 2fb0d9c02fb..0efecc3f0d8 100644 --- a/jetty-osgi/jetty-osgi-boot-jsp/pom.xml +++ b/jetty-osgi/jetty-osgi-boot-jsp/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty.osgi jetty-osgi-project - 9.1.4.v20140401 + 9.1.5-SNAPSHOT 4.0.0 jetty-osgi-boot-jsp diff --git a/jetty-osgi/jetty-osgi-boot-warurl/pom.xml b/jetty-osgi/jetty-osgi-boot-warurl/pom.xml index f3bead0c678..1bc71770dc6 100644 --- a/jetty-osgi/jetty-osgi-boot-warurl/pom.xml +++ b/jetty-osgi/jetty-osgi-boot-warurl/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty.osgi jetty-osgi-project - 9.1.4.v20140401 + 9.1.5-SNAPSHOT ../pom.xml 4.0.0 diff --git a/jetty-osgi/jetty-osgi-boot/pom.xml b/jetty-osgi/jetty-osgi-boot/pom.xml index 33de0b17388..a52ebfabcd2 100644 --- a/jetty-osgi/jetty-osgi-boot/pom.xml +++ b/jetty-osgi/jetty-osgi-boot/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty.osgi jetty-osgi-project - 9.1.4.v20140401 + 9.1.5-SNAPSHOT 4.0.0 jetty-osgi-boot diff --git a/jetty-osgi/jetty-osgi-httpservice/pom.xml b/jetty-osgi/jetty-osgi-httpservice/pom.xml index 31dbed2d82f..c061b281aa0 100644 --- a/jetty-osgi/jetty-osgi-httpservice/pom.xml +++ b/jetty-osgi/jetty-osgi-httpservice/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty.osgi jetty-osgi-project - 9.1.4.v20140401 + 9.1.5-SNAPSHOT 4.0.0 jetty-httpservice diff --git a/jetty-osgi/jetty-osgi-npn/pom.xml b/jetty-osgi/jetty-osgi-npn/pom.xml index 3279ab2a3db..63a46e64477 100644 --- a/jetty-osgi/jetty-osgi-npn/pom.xml +++ b/jetty-osgi/jetty-osgi-npn/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty.osgi jetty-osgi-project - 9.1.4.v20140401 + 9.1.5-SNAPSHOT 4.0.0 jetty-osgi-npn diff --git a/jetty-osgi/pom.xml b/jetty-osgi/pom.xml index e842571e07b..a89a1c6cbf2 100644 --- a/jetty-osgi/pom.xml +++ b/jetty-osgi/pom.xml @@ -3,7 +3,7 @@ org.eclipse.jetty jetty-project - 9.1.4.v20140401 + 9.1.5-SNAPSHOT org.eclipse.jetty.osgi jetty-osgi-project diff --git a/jetty-osgi/test-jetty-osgi-context/pom.xml b/jetty-osgi/test-jetty-osgi-context/pom.xml index 0b6e1aca9ec..46ad381c050 100644 --- a/jetty-osgi/test-jetty-osgi-context/pom.xml +++ b/jetty-osgi/test-jetty-osgi-context/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty.osgi jetty-osgi-project - 9.1.4.v20140401 + 9.1.5-SNAPSHOT 4.0.0 test-jetty-osgi-context diff --git a/jetty-osgi/test-jetty-osgi-webapp/pom.xml b/jetty-osgi/test-jetty-osgi-webapp/pom.xml index 64f833981e0..23a67d6023a 100644 --- a/jetty-osgi/test-jetty-osgi-webapp/pom.xml +++ b/jetty-osgi/test-jetty-osgi-webapp/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty.osgi jetty-osgi-project - 9.1.4.v20140401 + 9.1.5-SNAPSHOT ../pom.xml 4.0.0 diff --git a/jetty-osgi/test-jetty-osgi/pom.xml b/jetty-osgi/test-jetty-osgi/pom.xml index 8be34f94635..d417372a0b6 100644 --- a/jetty-osgi/test-jetty-osgi/pom.xml +++ b/jetty-osgi/test-jetty-osgi/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty.osgi jetty-osgi-project - 9.1.4.v20140401 + 9.1.5-SNAPSHOT ../pom.xml 4.0.0 diff --git a/jetty-plus/pom.xml b/jetty-plus/pom.xml index fe432a6c9ba..377ea4f63ca 100644 --- a/jetty-plus/pom.xml +++ b/jetty-plus/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty jetty-project - 9.1.4.v20140401 + 9.1.5-SNAPSHOT 4.0.0 jetty-plus diff --git a/jetty-proxy/pom.xml b/jetty-proxy/pom.xml index 7053d77ac2a..8ae47bee2d0 100644 --- a/jetty-proxy/pom.xml +++ b/jetty-proxy/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty jetty-project - 9.1.4.v20140401 + 9.1.5-SNAPSHOT 4.0.0 jetty-proxy diff --git a/jetty-rewrite/pom.xml b/jetty-rewrite/pom.xml index ffc0e14c4ac..ef6374468e6 100644 --- a/jetty-rewrite/pom.xml +++ b/jetty-rewrite/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty jetty-project - 9.1.4.v20140401 + 9.1.5-SNAPSHOT 4.0.0 jetty-rewrite diff --git a/jetty-runner/pom.xml b/jetty-runner/pom.xml index 31d84d29f23..4c98ff3c765 100644 --- a/jetty-runner/pom.xml +++ b/jetty-runner/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty jetty-project - 9.1.4.v20140401 + 9.1.5-SNAPSHOT 4.0.0 jetty-runner diff --git a/jetty-security/pom.xml b/jetty-security/pom.xml index d0c9b037df1..6dbc0e115d0 100644 --- a/jetty-security/pom.xml +++ b/jetty-security/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty jetty-project - 9.1.4.v20140401 + 9.1.5-SNAPSHOT 4.0.0 jetty-security diff --git a/jetty-server/pom.xml b/jetty-server/pom.xml index 1b4d677b63f..d7d2a18d0ab 100644 --- a/jetty-server/pom.xml +++ b/jetty-server/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty jetty-project - 9.1.4.v20140401 + 9.1.5-SNAPSHOT 4.0.0 jetty-server diff --git a/jetty-servlet/pom.xml b/jetty-servlet/pom.xml index 21ade3ec675..46325d69396 100644 --- a/jetty-servlet/pom.xml +++ b/jetty-servlet/pom.xml @@ -3,7 +3,7 @@ jetty-project org.eclipse.jetty - 9.1.4.v20140401 + 9.1.5-SNAPSHOT 4.0.0 jetty-servlet diff --git a/jetty-servlets/pom.xml b/jetty-servlets/pom.xml index a2a965bf166..3c8210c8164 100644 --- a/jetty-servlets/pom.xml +++ b/jetty-servlets/pom.xml @@ -3,7 +3,7 @@ jetty-project org.eclipse.jetty - 9.1.4.v20140401 + 9.1.5-SNAPSHOT 4.0.0 jetty-servlets diff --git a/jetty-spdy/pom.xml b/jetty-spdy/pom.xml index eb775604160..502723318e8 100644 --- a/jetty-spdy/pom.xml +++ b/jetty-spdy/pom.xml @@ -3,7 +3,7 @@ org.eclipse.jetty jetty-project - 9.1.4.v20140401 + 9.1.5-SNAPSHOT 4.0.0 diff --git a/jetty-spdy/spdy-client/pom.xml b/jetty-spdy/spdy-client/pom.xml index 37443fac14a..f3e2ed1f8b1 100644 --- a/jetty-spdy/spdy-client/pom.xml +++ b/jetty-spdy/spdy-client/pom.xml @@ -3,7 +3,7 @@ org.eclipse.jetty.spdy spdy-parent - 9.1.4.v20140401 + 9.1.5-SNAPSHOT 4.0.0 diff --git a/jetty-spdy/spdy-core/pom.xml b/jetty-spdy/spdy-core/pom.xml index faf11085231..db39f06635e 100644 --- a/jetty-spdy/spdy-core/pom.xml +++ b/jetty-spdy/spdy-core/pom.xml @@ -3,7 +3,7 @@ org.eclipse.jetty.spdy spdy-parent - 9.1.4.v20140401 + 9.1.5-SNAPSHOT 4.0.0 diff --git a/jetty-spdy/spdy-example-webapp/pom.xml b/jetty-spdy/spdy-example-webapp/pom.xml index 8e2e212dcff..5cd47a69be1 100644 --- a/jetty-spdy/spdy-example-webapp/pom.xml +++ b/jetty-spdy/spdy-example-webapp/pom.xml @@ -3,7 +3,7 @@ org.eclipse.jetty.spdy spdy-parent - 9.1.4.v20140401 + 9.1.5-SNAPSHOT 4.0.0 spdy-example-webapp diff --git a/jetty-spdy/spdy-http-client-transport/pom.xml b/jetty-spdy/spdy-http-client-transport/pom.xml index da2e64d43da..e428e247672 100644 --- a/jetty-spdy/spdy-http-client-transport/pom.xml +++ b/jetty-spdy/spdy-http-client-transport/pom.xml @@ -3,7 +3,7 @@ org.eclipse.jetty.spdy spdy-parent - 9.1.4.v20140401 + 9.1.5-SNAPSHOT 4.0.0 diff --git a/jetty-spdy/spdy-http-common/pom.xml b/jetty-spdy/spdy-http-common/pom.xml index 3002e01109c..01849252e51 100644 --- a/jetty-spdy/spdy-http-common/pom.xml +++ b/jetty-spdy/spdy-http-common/pom.xml @@ -3,7 +3,7 @@ org.eclipse.jetty.spdy spdy-parent - 9.1.4.v20140401 + 9.1.5-SNAPSHOT 4.0.0 diff --git a/jetty-spdy/spdy-http-server/pom.xml b/jetty-spdy/spdy-http-server/pom.xml index 7e683ea60e3..af685e87b1a 100644 --- a/jetty-spdy/spdy-http-server/pom.xml +++ b/jetty-spdy/spdy-http-server/pom.xml @@ -3,7 +3,7 @@ org.eclipse.jetty.spdy spdy-parent - 9.1.4.v20140401 + 9.1.5-SNAPSHOT 4.0.0 spdy-http-server diff --git a/jetty-spdy/spdy-npn-tests/pom.xml b/jetty-spdy/spdy-npn-tests/pom.xml index 1596d61d0c9..8fc12c266dd 100644 --- a/jetty-spdy/spdy-npn-tests/pom.xml +++ b/jetty-spdy/spdy-npn-tests/pom.xml @@ -3,7 +3,7 @@ org.eclipse.jetty.spdy spdy-parent - 9.1.4.v20140401 + 9.1.5-SNAPSHOT 4.0.0 diff --git a/jetty-spdy/spdy-server/pom.xml b/jetty-spdy/spdy-server/pom.xml index f418cad43f7..8266726ea00 100644 --- a/jetty-spdy/spdy-server/pom.xml +++ b/jetty-spdy/spdy-server/pom.xml @@ -3,7 +3,7 @@ org.eclipse.jetty.spdy spdy-parent - 9.1.4.v20140401 + 9.1.5-SNAPSHOT 4.0.0 diff --git a/jetty-spring/pom.xml b/jetty-spring/pom.xml index 780ce223274..01e14485a8e 100644 --- a/jetty-spring/pom.xml +++ b/jetty-spring/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty jetty-project - 9.1.4.v20140401 + 9.1.5-SNAPSHOT 4.0.0 jetty-spring diff --git a/jetty-start/pom.xml b/jetty-start/pom.xml index 4a3b0c02d2a..d0d01b03f59 100644 --- a/jetty-start/pom.xml +++ b/jetty-start/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty jetty-project - 9.1.4.v20140401 + 9.1.5-SNAPSHOT 4.0.0 jetty-start diff --git a/jetty-util-ajax/pom.xml b/jetty-util-ajax/pom.xml index 5093697e91a..7fdea25c042 100644 --- a/jetty-util-ajax/pom.xml +++ b/jetty-util-ajax/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty jetty-project - 9.1.4.v20140401 + 9.1.5-SNAPSHOT 4.0.0 jetty-util-ajax diff --git a/jetty-util/pom.xml b/jetty-util/pom.xml index 10ce6c0b7b0..0b0f987cd55 100644 --- a/jetty-util/pom.xml +++ b/jetty-util/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty jetty-project - 9.1.4.v20140401 + 9.1.5-SNAPSHOT 4.0.0 jetty-util diff --git a/jetty-webapp/pom.xml b/jetty-webapp/pom.xml index f1a0ab2e1aa..b6812cf66f0 100644 --- a/jetty-webapp/pom.xml +++ b/jetty-webapp/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty jetty-project - 9.1.4.v20140401 + 9.1.5-SNAPSHOT 4.0.0 jetty-webapp diff --git a/jetty-websocket/javax-websocket-client-impl/pom.xml b/jetty-websocket/javax-websocket-client-impl/pom.xml index 04f082302bd..75986c27296 100644 --- a/jetty-websocket/javax-websocket-client-impl/pom.xml +++ b/jetty-websocket/javax-websocket-client-impl/pom.xml @@ -3,7 +3,7 @@ org.eclipse.jetty.websocket websocket-parent - 9.1.4.v20140401 + 9.1.5-SNAPSHOT 4.0.0 diff --git a/jetty-websocket/javax-websocket-server-impl/pom.xml b/jetty-websocket/javax-websocket-server-impl/pom.xml index ccd010c3267..0b62c8f9c7d 100644 --- a/jetty-websocket/javax-websocket-server-impl/pom.xml +++ b/jetty-websocket/javax-websocket-server-impl/pom.xml @@ -3,7 +3,7 @@ org.eclipse.jetty.websocket websocket-parent - 9.1.4.v20140401 + 9.1.5-SNAPSHOT 4.0.0 diff --git a/jetty-websocket/pom.xml b/jetty-websocket/pom.xml index 5c76e8de25c..a955fe051db 100644 --- a/jetty-websocket/pom.xml +++ b/jetty-websocket/pom.xml @@ -3,7 +3,7 @@ jetty-project org.eclipse.jetty - 9.1.4.v20140401 + 9.1.5-SNAPSHOT 4.0.0 diff --git a/jetty-websocket/websocket-api/pom.xml b/jetty-websocket/websocket-api/pom.xml index 0c058d76057..ba16ff00b6e 100644 --- a/jetty-websocket/websocket-api/pom.xml +++ b/jetty-websocket/websocket-api/pom.xml @@ -3,7 +3,7 @@ org.eclipse.jetty.websocket websocket-parent - 9.1.4.v20140401 + 9.1.5-SNAPSHOT 4.0.0 diff --git a/jetty-websocket/websocket-client/pom.xml b/jetty-websocket/websocket-client/pom.xml index 82c4af183f9..fce652edd90 100644 --- a/jetty-websocket/websocket-client/pom.xml +++ b/jetty-websocket/websocket-client/pom.xml @@ -3,7 +3,7 @@ org.eclipse.jetty.websocket websocket-parent - 9.1.4.v20140401 + 9.1.5-SNAPSHOT 4.0.0 diff --git a/jetty-websocket/websocket-common/pom.xml b/jetty-websocket/websocket-common/pom.xml index 366b98988b7..ada7d5c5774 100644 --- a/jetty-websocket/websocket-common/pom.xml +++ b/jetty-websocket/websocket-common/pom.xml @@ -3,7 +3,7 @@ org.eclipse.jetty.websocket websocket-parent - 9.1.4.v20140401 + 9.1.5-SNAPSHOT 4.0.0 diff --git a/jetty-websocket/websocket-server/pom.xml b/jetty-websocket/websocket-server/pom.xml index fdcda00d1a1..5288e54ec2c 100644 --- a/jetty-websocket/websocket-server/pom.xml +++ b/jetty-websocket/websocket-server/pom.xml @@ -3,7 +3,7 @@ org.eclipse.jetty.websocket websocket-parent - 9.1.4.v20140401 + 9.1.5-SNAPSHOT 4.0.0 diff --git a/jetty-websocket/websocket-servlet/pom.xml b/jetty-websocket/websocket-servlet/pom.xml index 7534085e4e1..b90d2f64b91 100644 --- a/jetty-websocket/websocket-servlet/pom.xml +++ b/jetty-websocket/websocket-servlet/pom.xml @@ -3,7 +3,7 @@ org.eclipse.jetty.websocket websocket-parent - 9.1.4.v20140401 + 9.1.5-SNAPSHOT 4.0.0 diff --git a/jetty-xml/pom.xml b/jetty-xml/pom.xml index 025e149c463..96e50cfedb3 100644 --- a/jetty-xml/pom.xml +++ b/jetty-xml/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty jetty-project - 9.1.4.v20140401 + 9.1.5-SNAPSHOT 4.0.0 jetty-xml diff --git a/pom.xml b/pom.xml index 9d85b03d4a9..b8ef433c27b 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ 22 jetty-project - 9.1.4.v20140401 + 9.1.5-SNAPSHOT Jetty :: Project http://www.eclipse.org/jetty pom diff --git a/tests/pom.xml b/tests/pom.xml index 985f3ae53d8..ef365917df3 100644 --- a/tests/pom.xml +++ b/tests/pom.xml @@ -21,7 +21,7 @@ org.eclipse.jetty jetty-project - 9.1.4.v20140401 + 9.1.5-SNAPSHOT ../pom.xml org.eclipse.jetty.tests diff --git a/tests/test-continuation/pom.xml b/tests/test-continuation/pom.xml index 25a2a97ac1e..ec02de3ec4b 100644 --- a/tests/test-continuation/pom.xml +++ b/tests/test-continuation/pom.xml @@ -20,7 +20,7 @@ org.eclipse.jetty.tests tests-parent - 9.1.4.v20140401 + 9.1.5-SNAPSHOT ../pom.xml 4.0.0 diff --git a/tests/test-integration/pom.xml b/tests/test-integration/pom.xml index 1e63fbc7e31..3d0baac7a3f 100644 --- a/tests/test-integration/pom.xml +++ b/tests/test-integration/pom.xml @@ -20,7 +20,7 @@ org.eclipse.jetty.tests tests-parent - 9.1.4.v20140401 + 9.1.5-SNAPSHOT 4.0.0 test-integration diff --git a/tests/test-loginservice/pom.xml b/tests/test-loginservice/pom.xml index 1e001d2d404..fd99f8c3ab9 100644 --- a/tests/test-loginservice/pom.xml +++ b/tests/test-loginservice/pom.xml @@ -21,7 +21,7 @@ org.eclipse.jetty.tests tests-parent - 9.1.4.v20140401 + 9.1.5-SNAPSHOT test-loginservice Jetty Tests :: Login Service diff --git a/tests/test-sessions/pom.xml b/tests/test-sessions/pom.xml index 3edb243c8ad..7843d64fca4 100644 --- a/tests/test-sessions/pom.xml +++ b/tests/test-sessions/pom.xml @@ -21,7 +21,7 @@ org.eclipse.jetty.tests tests-parent - 9.1.4.v20140401 + 9.1.5-SNAPSHOT test-sessions-parent Jetty Tests :: Sessions :: Parent diff --git a/tests/test-sessions/test-hash-sessions/pom.xml b/tests/test-sessions/test-hash-sessions/pom.xml index 4caf8c42d62..feae3f9946c 100644 --- a/tests/test-sessions/test-hash-sessions/pom.xml +++ b/tests/test-sessions/test-hash-sessions/pom.xml @@ -21,7 +21,7 @@ org.eclipse.jetty.tests test-sessions-parent - 9.1.4.v20140401 + 9.1.5-SNAPSHOT test-hash-sessions Jetty Tests :: Sessions :: Hash diff --git a/tests/test-sessions/test-jdbc-sessions/pom.xml b/tests/test-sessions/test-jdbc-sessions/pom.xml index 72b5fd4d3bd..3b5e12ed71e 100644 --- a/tests/test-sessions/test-jdbc-sessions/pom.xml +++ b/tests/test-sessions/test-jdbc-sessions/pom.xml @@ -21,7 +21,7 @@ org.eclipse.jetty.tests test-sessions-parent - 9.1.4.v20140401 + 9.1.5-SNAPSHOT test-jdbc-sessions Jetty Tests :: Sessions :: JDBC diff --git a/tests/test-sessions/test-sessions-common/pom.xml b/tests/test-sessions/test-sessions-common/pom.xml index c353eb40a57..369041aa1d1 100644 --- a/tests/test-sessions/test-sessions-common/pom.xml +++ b/tests/test-sessions/test-sessions-common/pom.xml @@ -21,7 +21,7 @@ org.eclipse.jetty.tests test-sessions-parent - 9.1.4.v20140401 + 9.1.5-SNAPSHOT test-sessions-common Jetty Tests :: Sessions :: Common diff --git a/tests/test-webapps/pom.xml b/tests/test-webapps/pom.xml index 960fae72f43..5d872c3bcea 100644 --- a/tests/test-webapps/pom.xml +++ b/tests/test-webapps/pom.xml @@ -21,7 +21,7 @@ org.eclipse.jetty.tests tests-parent - 9.1.4.v20140401 + 9.1.5-SNAPSHOT ../pom.xml test-webapps-parent diff --git a/tests/test-webapps/test-jaas-webapp/pom.xml b/tests/test-webapps/test-jaas-webapp/pom.xml index 950e50d7201..f44221b9d23 100644 --- a/tests/test-webapps/test-jaas-webapp/pom.xml +++ b/tests/test-webapps/test-jaas-webapp/pom.xml @@ -4,7 +4,7 @@ org.eclipse.jetty.tests test-webapps-parent - 9.1.4.v20140401 + 9.1.5-SNAPSHOT test-jaas-webapp Jetty Tests :: WebApp :: JAAS diff --git a/tests/test-webapps/test-jetty-webapp/pom.xml b/tests/test-webapps/test-jetty-webapp/pom.xml index 080b3dbec96..588f0c0da6c 100644 --- a/tests/test-webapps/test-jetty-webapp/pom.xml +++ b/tests/test-webapps/test-jetty-webapp/pom.xml @@ -20,7 +20,7 @@ org.eclipse.jetty.tests test-webapps-parent - 9.1.4.v20140401 + 9.1.5-SNAPSHOT ../pom.xml 4.0.0 diff --git a/tests/test-webapps/test-jndi-webapp/pom.xml b/tests/test-webapps/test-jndi-webapp/pom.xml index 4ffc29eaae3..31074cf5157 100644 --- a/tests/test-webapps/test-jndi-webapp/pom.xml +++ b/tests/test-webapps/test-jndi-webapp/pom.xml @@ -4,7 +4,7 @@ org.eclipse.jetty.tests test-webapps-parent - 9.1.4.v20140401 + 9.1.5-SNAPSHOT test-jndi-webapp Jetty Tests :: WebApp :: JNDI diff --git a/tests/test-webapps/test-mock-resources/pom.xml b/tests/test-webapps/test-mock-resources/pom.xml index 0164cc14311..1b078df44e2 100644 --- a/tests/test-webapps/test-mock-resources/pom.xml +++ b/tests/test-webapps/test-mock-resources/pom.xml @@ -3,7 +3,7 @@ org.eclipse.jetty.tests test-webapps-parent - 9.1.4.v20140401 + 9.1.5-SNAPSHOT Jetty Tests :: WebApp :: Mock Resources test-mock-resources diff --git a/tests/test-webapps/test-proxy-webapp/pom.xml b/tests/test-webapps/test-proxy-webapp/pom.xml index 5667d6d5f28..4a3ccac9ea3 100644 --- a/tests/test-webapps/test-proxy-webapp/pom.xml +++ b/tests/test-webapps/test-proxy-webapp/pom.xml @@ -20,7 +20,7 @@ org.eclipse.jetty.tests test-webapps-parent - 9.1.4.v20140401 + 9.1.5-SNAPSHOT ../pom.xml 4.0.0 diff --git a/tests/test-webapps/test-servlet-spec/pom.xml b/tests/test-webapps/test-servlet-spec/pom.xml index d236e1d37d2..9dccef11738 100644 --- a/tests/test-webapps/test-servlet-spec/pom.xml +++ b/tests/test-webapps/test-servlet-spec/pom.xml @@ -4,7 +4,7 @@ org.eclipse.jetty.tests test-webapps-parent - 9.1.4.v20140401 + 9.1.5-SNAPSHOT test-servlet-spec-parent Jetty Tests :: Spec Test WebApp :: Parent diff --git a/tests/test-webapps/test-servlet-spec/test-container-initializer/pom.xml b/tests/test-webapps/test-servlet-spec/test-container-initializer/pom.xml index 970e62cba1f..358b9e4cccf 100644 --- a/tests/test-webapps/test-servlet-spec/test-container-initializer/pom.xml +++ b/tests/test-webapps/test-servlet-spec/test-container-initializer/pom.xml @@ -3,7 +3,7 @@ org.eclipse.jetty.tests test-servlet-spec-parent - 9.1.4.v20140401 + 9.1.5-SNAPSHOT test-container-initializer jar diff --git a/tests/test-webapps/test-servlet-spec/test-spec-webapp/pom.xml b/tests/test-webapps/test-servlet-spec/test-spec-webapp/pom.xml index 210f1e2e8fd..e21f34c6411 100644 --- a/tests/test-webapps/test-servlet-spec/test-spec-webapp/pom.xml +++ b/tests/test-webapps/test-servlet-spec/test-spec-webapp/pom.xml @@ -4,7 +4,7 @@ org.eclipse.jetty.tests test-servlet-spec-parent - 9.1.4.v20140401 + 9.1.5-SNAPSHOT Jetty Tests :: Webapps :: Spec Webapp test-spec-webapp diff --git a/tests/test-webapps/test-servlet-spec/test-web-fragment/pom.xml b/tests/test-webapps/test-servlet-spec/test-web-fragment/pom.xml index 7a4420cb312..eb874e800a4 100644 --- a/tests/test-webapps/test-servlet-spec/test-web-fragment/pom.xml +++ b/tests/test-webapps/test-servlet-spec/test-web-fragment/pom.xml @@ -3,7 +3,7 @@ org.eclipse.jetty.tests test-servlet-spec-parent - 9.1.4.v20140401 + 9.1.5-SNAPSHOT Jetty Tests :: WebApp :: Servlet Spec :: Fragment Jar org.eclipse.jetty.tests diff --git a/tests/test-webapps/test-webapp-rfc2616/pom.xml b/tests/test-webapps/test-webapp-rfc2616/pom.xml index 0a26e93d43e..8930d64d8c8 100644 --- a/tests/test-webapps/test-webapp-rfc2616/pom.xml +++ b/tests/test-webapps/test-webapp-rfc2616/pom.xml @@ -21,7 +21,7 @@ org.eclipse.jetty.tests test-webapps-parent - 9.1.4.v20140401 + 9.1.5-SNAPSHOT test-webapp-rfc2616 Jetty Tests :: WebApp :: RFC2616 From e3662a9b236a322abfc3743657d2f0e426a7b0f1 Mon Sep 17 00:00:00 2001 From: Simone Bordet Date: Mon, 7 Apr 2014 17:31:25 +0200 Subject: [PATCH 04/14] 432145 - Pending request is not failed when HttpClient is stopped. Fixed by fixing the code in close() to also abort pending exchanges. Reviewed for HTTP, FastCGI and SPDY transports. --- .../client/MultiplexHttpDestination.java | 9 +++++ .../client/http/HttpConnectionOverHTTP.java | 25 ++++++++---- .../client/http/HttpReceiverOverHTTP.java | 3 +- .../eclipse/jetty/client/HttpClientTest.java | 36 ++++++++++++++++++ .../fcgi/client/http/HttpChannelOverFCGI.java | 4 +- .../client/http/HttpConnectionOverFCGI.java | 37 ++++++++++++------ .../jetty/fcgi/server/HttpClientTest.java | 38 +++++++++++++++++++ .../spdy/client/http/HttpChannelOverSPDY.java | 12 +++++- .../client/http/HttpConnectionOverSPDY.java | 28 +++++++++++++- .../client/http/HttpDestinationOverSPDY.java | 8 ---- .../spdy/client/http/HttpClientTest.java | 38 +++++++++++++++++++ 11 files changed, 206 insertions(+), 32 deletions(-) diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/MultiplexHttpDestination.java b/jetty-client/src/main/java/org/eclipse/jetty/client/MultiplexHttpDestination.java index 7404ce3ed1b..563c92dc904 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/MultiplexHttpDestination.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/MultiplexHttpDestination.java @@ -129,6 +129,15 @@ public abstract class MultiplexHttpDestination extends Htt return true; } + @Override + public void close() + { + super.close(); + C connection = this.connection; + if (connection != null) + connection.close(); + } + @Override public void close(Connection connection) { diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/http/HttpConnectionOverHTTP.java b/jetty-client/src/main/java/org/eclipse/jetty/client/http/HttpConnectionOverHTTP.java index 219a56ee047..0b1b1b0fcf2 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/http/HttpConnectionOverHTTP.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/http/HttpConnectionOverHTTP.java @@ -18,6 +18,7 @@ package org.eclipse.jetty.client.http; +import java.nio.channels.AsynchronousCloseException; import java.util.concurrent.TimeoutException; import java.util.concurrent.atomic.AtomicBoolean; @@ -85,13 +86,8 @@ public class HttpConnectionOverHTTP extends AbstractConnection implements Connec protected boolean onReadTimeout() { LOG.debug("{} idle timeout", this); - - HttpExchange exchange = channel.getHttpExchange(); - if (exchange != null) - return exchange.getRequest().abort(new TimeoutException()); - - getHttpDestination().close(this); - return true; + close(new TimeoutException()); + return false; } @Override @@ -119,14 +115,23 @@ public class HttpConnectionOverHTTP extends AbstractConnection implements Connec @Override public void close() + { + close(new AsynchronousCloseException()); + } + + protected void close(Throwable failure) { if (softClose()) { + // First close then abort, to be sure that the connection cannot be reused + // from an onFailure() handler or by blocking code waiting for completion. getHttpDestination().close(this); getEndPoint().shutdownOutput(); LOG.debug("{} oshut", this); getEndPoint().close(); LOG.debug("{} closed", this); + + abort(failure); } } @@ -135,6 +140,12 @@ public class HttpConnectionOverHTTP extends AbstractConnection implements Connec return closed.compareAndSet(false, true); } + private boolean abort(Throwable failure) + { + HttpExchange exchange = channel.getHttpExchange(); + return exchange != null && exchange.getRequest().abort(failure); + } + @Override public String toString() { diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/http/HttpReceiverOverHTTP.java b/jetty-client/src/main/java/org/eclipse/jetty/client/http/HttpReceiverOverHTTP.java index f8894f8ab85..76efb9e3bdc 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/http/HttpReceiverOverHTTP.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/http/HttpReceiverOverHTTP.java @@ -127,8 +127,7 @@ public class HttpReceiverOverHTTP extends HttpReceiver implements HttpParser.Res // Shutting down the parser may invoke messageComplete() or earlyEOF() parser.atEOF(); parser.parseNext(BufferUtil.EMPTY_BUFFER); - if (!responseFailure(new EOFException())) - getHttpConnection().close(); + getHttpConnection().close(new EOFException()); } @Override diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientTest.java index 1b7e3ee42ca..5d19a1eccf2 100644 --- a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientTest.java +++ b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientTest.java @@ -1161,4 +1161,40 @@ public class HttpClientTest extends AbstractHttpClientServerTest Assert.assertEquals(200, response.getStatus()); Assert.assertTrue(response.getHeaders().contains(HttpHeader.CONNECTION, HttpHeaderValue.KEEP_ALIVE.asString())); } + + @Test + public void testLongPollIsAbortedWhenClientIsStopped() throws Exception + { + final CountDownLatch latch = new CountDownLatch(1); + start(new AbstractHandler() + { + @Override + public void handle(String target, org.eclipse.jetty.server.Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException + { + baseRequest.setHandled(true); + request.startAsync(); + latch.countDown(); + } + }); + + final CountDownLatch completeLatch = new CountDownLatch(1); + client.newRequest("localhost", connector.getLocalPort()) + .scheme(scheme) + .send(new Response.CompleteListener() + { + @Override + public void onComplete(Result result) + { + if (result.isFailed()) + completeLatch.countDown(); + } + }); + + Assert.assertTrue(latch.await(5, TimeUnit.SECONDS)); + + // Stop the client, the complete listener must be invoked. + client.stop(); + + Assert.assertTrue(completeLatch.await(5, TimeUnit.SECONDS)); + } } diff --git a/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/client/http/HttpChannelOverFCGI.java b/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/client/http/HttpChannelOverFCGI.java index ac5687ef41a..a6f7de6ec3b 100644 --- a/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/client/http/HttpChannelOverFCGI.java +++ b/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/client/http/HttpChannelOverFCGI.java @@ -132,7 +132,7 @@ public class HttpChannelOverFCGI extends HttpChannel if (close) connection.close(); else - connection.release(); + connection.release(this); } protected void flush(Generator.Result... results) @@ -155,7 +155,7 @@ public class HttpChannelOverFCGI extends HttpChannel protected void onIdleExpired(TimeoutException timeout) { LOG.debug("Idle timeout for request {}", request); - abort(timeout); + connection.abort(timeout); } @Override diff --git a/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/client/http/HttpConnectionOverFCGI.java b/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/client/http/HttpConnectionOverFCGI.java index 599455f9709..262a7c498c9 100644 --- a/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/client/http/HttpConnectionOverFCGI.java +++ b/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/client/http/HttpConnectionOverFCGI.java @@ -20,6 +20,7 @@ package org.eclipse.jetty.fcgi.client.http; import java.io.EOFException; import java.nio.ByteBuffer; +import java.nio.channels.AsynchronousCloseException; import java.util.LinkedList; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; @@ -139,25 +140,19 @@ public class HttpConnectionOverFCGI extends AbstractConnection implements Connec private void shutdown() { - // First close then abort, to be sure that the - // connection cannot be reused from an onFailure() - // handler or by blocking code waiting for completion. - close(); - for (HttpChannelOverFCGI channel : channels.values()) - channel.abort(new EOFException()); + close(new EOFException()); } @Override protected boolean onReadTimeout() { - for (HttpChannelOverFCGI channel : channels.values()) - channel.abort(new TimeoutException()); - close(); + close(new TimeoutException()); return false; } - public void release() + protected void release(HttpChannelOverFCGI channel) { + channels.remove(channel.getRequest()); if (destination instanceof PoolingHttpDestination) { @SuppressWarnings("unchecked") @@ -169,17 +164,37 @@ public class HttpConnectionOverFCGI extends AbstractConnection implements Connec @Override public void close() + { + close(new AsynchronousCloseException()); + } + + private void close(Throwable failure) { if (closed.compareAndSet(false, true)) { + // First close then abort, to be sure that the connection cannot be reused + // from an onFailure() handler or by blocking code waiting for completion. getHttpDestination().close(this); getEndPoint().shutdownOutput(); LOG.debug("{} oshut", this); getEndPoint().close(); LOG.debug("{} closed", this); + + abort(failure); } } + protected void abort(Throwable failure) + { + for (HttpChannelOverFCGI channel : channels.values()) + { + HttpExchange exchange = channel.getHttpExchange(); + if (exchange != null) + exchange.getRequest().abort(failure); + } + channels.clear(); + } + private int acquireRequest() { synchronized (requests) @@ -304,7 +319,7 @@ public class HttpConnectionOverFCGI extends AbstractConnection implements Connec @Override public void onEnd(int request) { - HttpChannelOverFCGI channel = channels.remove(request); + HttpChannelOverFCGI channel = channels.get(request); if (channel != null) { channel.responseSuccess(); diff --git a/jetty-fcgi/fcgi-server/src/test/java/org/eclipse/jetty/fcgi/server/HttpClientTest.java b/jetty-fcgi/fcgi-server/src/test/java/org/eclipse/jetty/fcgi/server/HttpClientTest.java index 3db51fd48c9..103a326eabb 100644 --- a/jetty-fcgi/fcgi-server/src/test/java/org/eclipse/jetty/fcgi/server/HttpClientTest.java +++ b/jetty-fcgi/fcgi-server/src/test/java/org/eclipse/jetty/fcgi/server/HttpClientTest.java @@ -24,6 +24,7 @@ import java.net.URI; import java.net.URLEncoder; import java.nio.ByteBuffer; import java.util.Arrays; +import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; @@ -37,6 +38,7 @@ import javax.servlet.http.HttpServletResponse; import org.eclipse.jetty.client.api.ContentResponse; import org.eclipse.jetty.client.api.Request; import org.eclipse.jetty.client.api.Response; +import org.eclipse.jetty.client.api.Result; import org.eclipse.jetty.client.util.BytesContentProvider; import org.eclipse.jetty.http.HttpMethod; import org.eclipse.jetty.server.handler.AbstractHandler; @@ -513,4 +515,40 @@ public class HttpClientTest extends AbstractHttpClientServerTest Assert.assertEquals(200, response.getStatus()); Assert.assertEquals(length, response.getContent().length); } + + @Test + public void testLongPollIsAbortedWhenClientIsStopped() throws Exception + { + final CountDownLatch latch = new CountDownLatch(1); + start(new AbstractHandler() + { + @Override + public void handle(String target, org.eclipse.jetty.server.Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException + { + baseRequest.setHandled(true); + request.startAsync(); + latch.countDown(); + } + }); + + final CountDownLatch completeLatch = new CountDownLatch(1); + client.newRequest("localhost", connector.getLocalPort()) + .scheme(scheme) + .send(new Response.CompleteListener() + { + @Override + public void onComplete(Result result) + { + if (result.isFailed()) + completeLatch.countDown(); + } + }); + + Assert.assertTrue(latch.await(5, TimeUnit.SECONDS)); + + // Stop the client, the complete listener must be invoked. + client.stop(); + + Assert.assertTrue(completeLatch.await(5, TimeUnit.SECONDS)); + } } diff --git a/jetty-spdy/spdy-http-client-transport/src/main/java/org/eclipse/jetty/spdy/client/http/HttpChannelOverSPDY.java b/jetty-spdy/spdy-http-client-transport/src/main/java/org/eclipse/jetty/spdy/client/http/HttpChannelOverSPDY.java index bd19978803f..00f87cd498b 100644 --- a/jetty-spdy/spdy-http-client-transport/src/main/java/org/eclipse/jetty/spdy/client/http/HttpChannelOverSPDY.java +++ b/jetty-spdy/spdy-http-client-transport/src/main/java/org/eclipse/jetty/spdy/client/http/HttpChannelOverSPDY.java @@ -21,17 +21,20 @@ package org.eclipse.jetty.spdy.client.http; import org.eclipse.jetty.client.HttpChannel; import org.eclipse.jetty.client.HttpDestination; import org.eclipse.jetty.client.HttpExchange; +import org.eclipse.jetty.client.api.Result; import org.eclipse.jetty.spdy.api.Session; public class HttpChannelOverSPDY extends HttpChannel { + private final HttpConnectionOverSPDY connection; private final Session session; private final HttpSenderOverSPDY sender; private final HttpReceiverOverSPDY receiver; - public HttpChannelOverSPDY(HttpDestination destination, Session session) + public HttpChannelOverSPDY(HttpDestination destination, HttpConnectionOverSPDY connection, Session session) { super(destination); + this.connection = connection; this.session = session; this.sender = new HttpSenderOverSPDY(this); this.receiver = new HttpReceiverOverSPDY(this); @@ -72,4 +75,11 @@ public class HttpChannelOverSPDY extends HttpChannel sender.abort(cause); return receiver.abort(cause); } + + @Override + public void exchangeTerminated(Result result) + { + super.exchangeTerminated(result); + connection.release(this); + } } diff --git a/jetty-spdy/spdy-http-client-transport/src/main/java/org/eclipse/jetty/spdy/client/http/HttpConnectionOverSPDY.java b/jetty-spdy/spdy-http-client-transport/src/main/java/org/eclipse/jetty/spdy/client/http/HttpConnectionOverSPDY.java index ef96e4158eb..57ba0652e28 100644 --- a/jetty-spdy/spdy-http-client-transport/src/main/java/org/eclipse/jetty/spdy/client/http/HttpConnectionOverSPDY.java +++ b/jetty-spdy/spdy-http-client-transport/src/main/java/org/eclipse/jetty/spdy/client/http/HttpConnectionOverSPDY.java @@ -18,6 +18,9 @@ package org.eclipse.jetty.spdy.client.http; +import java.nio.channels.AsynchronousCloseException; +import java.util.Set; + import org.eclipse.jetty.client.HttpChannel; import org.eclipse.jetty.client.HttpConnection; import org.eclipse.jetty.client.HttpDestination; @@ -25,9 +28,11 @@ import org.eclipse.jetty.client.HttpExchange; import org.eclipse.jetty.spdy.api.GoAwayInfo; import org.eclipse.jetty.spdy.api.Session; import org.eclipse.jetty.util.Callback; +import org.eclipse.jetty.util.ConcurrentHashSet; public class HttpConnectionOverSPDY extends HttpConnection { + private final Set channels = new ConcurrentHashSet<>(); private final Session session; public HttpConnectionOverSPDY(HttpDestination destination, Session session) @@ -41,14 +46,35 @@ public class HttpConnectionOverSPDY extends HttpConnection { normalizeRequest(exchange.getRequest()); // One connection maps to N channels, so for each exchange we create a new channel - HttpChannel channel = new HttpChannelOverSPDY(getHttpDestination(), session); + HttpChannel channel = new HttpChannelOverSPDY(getHttpDestination(), this, session); + channels.add(channel); channel.associate(exchange); channel.send(); } + protected void release(HttpChannel channel) + { + channels.remove(channel); + } + @Override public void close() { + // First close then abort, to be sure that the connection cannot be reused + // from an onFailure() handler or by blocking code waiting for completion. + getHttpDestination().close(this); session.goAway(new GoAwayInfo(), new Callback.Adapter()); + abort(new AsynchronousCloseException()); + } + + private void abort(Throwable failure) + { + for (HttpChannel channel : channels) + { + HttpExchange exchange = channel.getHttpExchange(); + if (exchange != null) + exchange.getRequest().abort(failure); + } + channels.clear(); } } diff --git a/jetty-spdy/spdy-http-client-transport/src/main/java/org/eclipse/jetty/spdy/client/http/HttpDestinationOverSPDY.java b/jetty-spdy/spdy-http-client-transport/src/main/java/org/eclipse/jetty/spdy/client/http/HttpDestinationOverSPDY.java index dff5a0785b3..bdc4c05b5f1 100644 --- a/jetty-spdy/spdy-http-client-transport/src/main/java/org/eclipse/jetty/spdy/client/http/HttpDestinationOverSPDY.java +++ b/jetty-spdy/spdy-http-client-transport/src/main/java/org/eclipse/jetty/spdy/client/http/HttpDestinationOverSPDY.java @@ -35,12 +35,4 @@ public class HttpDestinationOverSPDY extends MultiplexHttpDestination Date: Tue, 8 Apr 2014 13:57:27 +0200 Subject: [PATCH 05/14] 432270 - Slow requests with response content delimited by EOF fail. Fixed by using a flag to determine the need to close the connection, and by closing the connection only at exchange termination. --- .../client/http/HttpChannelOverHTTP.java | 5 ++- .../client/http/HttpReceiverOverHTTP.java | 24 +++++++++-- .../eclipse/jetty/client/HttpClientTest.java | 41 +++++++++++++++++++ 3 files changed, 64 insertions(+), 6 deletions(-) diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/http/HttpChannelOverHTTP.java b/jetty-client/src/main/java/org/eclipse/jetty/client/http/HttpChannelOverHTTP.java index 76d99d74bda..cd5bcf274f6 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/http/HttpChannelOverHTTP.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/http/HttpChannelOverHTTP.java @@ -77,9 +77,10 @@ public class HttpChannelOverHTTP extends HttpChannel public void exchangeTerminated(Result result) { super.exchangeTerminated(result); - boolean close = result.isFailed(); HttpFields responseHeaders = result.getResponse().getHeaders(); - close |= responseHeaders.contains(HttpHeader.CONNECTION, HttpHeaderValue.CLOSE.asString()); + boolean close = result.isFailed() || + responseHeaders.contains(HttpHeader.CONNECTION, HttpHeaderValue.CLOSE.asString()) || + receiver.isShutdown(); if (close) connection.close(); else diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/http/HttpReceiverOverHTTP.java b/jetty-client/src/main/java/org/eclipse/jetty/client/http/HttpReceiverOverHTTP.java index 76efb9e3bdc..505d264747f 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/http/HttpReceiverOverHTTP.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/http/HttpReceiverOverHTTP.java @@ -38,6 +38,7 @@ import org.eclipse.jetty.util.BufferUtil; public class HttpReceiverOverHTTP extends HttpReceiver implements HttpParser.ResponseHandler { private final HttpParser parser = new HttpParser(this); + private boolean shutdown; public HttpReceiverOverHTTP(HttpChannelOverHTTP channel) { @@ -124,10 +125,23 @@ public class HttpReceiverOverHTTP extends HttpReceiver implements HttpParser.Res private void shutdown() { - // Shutting down the parser may invoke messageComplete() or earlyEOF() + // Mark this receiver as shutdown, so that we can + // close the connection when the exchange terminates. + // We cannot close the connection from here because + // the request may still be in process. + shutdown = true; + + // Shutting down the parser may invoke messageComplete() or earlyEOF(). + // In case of content delimited by EOF, without a Connection: close + // header, the connection will be closed at exchange termination + // thanks to the flag we have set above. parser.atEOF(); parser.parseNext(BufferUtil.EMPTY_BUFFER); - getHttpConnection().close(new EOFException()); + } + + protected boolean isShutdown() + { + return shutdown; } @Override @@ -230,8 +244,10 @@ public class HttpReceiverOverHTTP extends HttpReceiver implements HttpParser.Res private void failAndClose(Throwable failure) { - if (responseFailure(failure)) - getHttpChannel().getHttpConnection().close(); + // Close the connection anyway, even if responseFailure() returns false. + // This may happen for idle closes (there is no exchange to fail). + responseFailure(failure); + getHttpConnection().close(failure); } @Override diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientTest.java index 5d19a1eccf2..c6789e20cdb 100644 --- a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientTest.java +++ b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientTest.java @@ -59,6 +59,7 @@ import org.eclipse.jetty.client.http.HttpConnectionOverHTTP; import org.eclipse.jetty.client.http.HttpDestinationOverHTTP; import org.eclipse.jetty.client.util.BufferingResponseListener; import org.eclipse.jetty.client.util.BytesContentProvider; +import org.eclipse.jetty.client.util.DeferredContentProvider; import org.eclipse.jetty.client.util.FutureResponseListener; import org.eclipse.jetty.http.HttpField; import org.eclipse.jetty.http.HttpHeader; @@ -72,6 +73,7 @@ import org.eclipse.jetty.util.FuturePromise; import org.eclipse.jetty.util.IO; import org.eclipse.jetty.util.ssl.SslContextFactory; import org.junit.Assert; +import org.junit.Assume; import org.junit.Rule; import org.junit.Test; @@ -1197,4 +1199,43 @@ public class HttpClientTest extends AbstractHttpClientServerTest Assert.assertTrue(completeLatch.await(5, TimeUnit.SECONDS)); } + + @Test + public void testContentDelimitedByEOFWithSlowRequest() throws Exception + { + // This test is crafted in a way that the response completes before the request is fully written. + // With SSL, the response coming down will close the SSLEngine so it would not be possible to + // write the last chunk of the request content, and the request will be failed, failing also the + // test, which is not what we want. + // This is a limit of Java's SSL implementation that does not allow half closes. + Assume.assumeTrue(sslContextFactory == null); + + final byte[] data = new byte[8 * 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 + { + baseRequest.setHandled(true); + response.setHeader("Connection", "close"); + response.getOutputStream().write(data); + } + }); + + DeferredContentProvider content = new DeferredContentProvider(ByteBuffer.wrap(new byte[]{0})); + Request request = client.newRequest("localhost", connector.getLocalPort()) + .scheme(scheme) + .content(content); + FutureResponseListener listener = new FutureResponseListener(request); + request.send(listener); + // Wait some time to simulate a slow request. + Thread.sleep(1000); + content.close(); + + ContentResponse response = listener.get(5, TimeUnit.SECONDS); + + Assert.assertEquals(200, response.getStatus()); + Assert.assertArrayEquals(data, response.getContent()); + } } From 74d66a87f6511dea92296299e0a18716f1edaadc Mon Sep 17 00:00:00 2001 From: Simone Bordet Date: Tue, 8 Apr 2014 13:57:55 +0200 Subject: [PATCH 06/14] Made the test more reliable. --- .../jetty/client/HttpClientExplicitConnectionTest.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientExplicitConnectionTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientExplicitConnectionTest.java index 2071aa0bcc2..9762b2eb450 100644 --- a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientExplicitConnectionTest.java +++ b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientExplicitConnectionTest.java @@ -82,9 +82,12 @@ public class HttpClientExplicitConnectionTest extends AbstractHttpClientServerTe Assert.assertEquals(200, response.getStatus()); + // Wait some time to have the client is an idle state. + TimeUnit.SECONDS.sleep(1); + connector.stop(); - // Give the connection some time to process the remote close + // Give the connection some time to process the remote close. TimeUnit.SECONDS.sleep(1); HttpConnectionOverHTTP httpConnection = (HttpConnectionOverHTTP)connection; From 8e24cdf913935fbd11082dfcafa16025b5147634 Mon Sep 17 00:00:00 2001 From: Simone Bordet Date: Tue, 8 Apr 2014 13:58:21 +0200 Subject: [PATCH 07/14] Fixed timeout value left over during debugging. --- .../java/org/eclipse/jetty/spdy/client/http/HttpClientTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jetty-spdy/spdy-http-client-transport/src/test/java/org/eclipse/jetty/spdy/client/http/HttpClientTest.java b/jetty-spdy/spdy-http-client-transport/src/test/java/org/eclipse/jetty/spdy/client/http/HttpClientTest.java index 4fa701746df..871e9d7d5ca 100644 --- a/jetty-spdy/spdy-http-client-transport/src/test/java/org/eclipse/jetty/spdy/client/http/HttpClientTest.java +++ b/jetty-spdy/spdy-http-client-transport/src/test/java/org/eclipse/jetty/spdy/client/http/HttpClientTest.java @@ -243,7 +243,7 @@ public class HttpClientTest extends AbstractHttpClientServerTest ContentResponse response = client.POST(scheme + "://localhost:" + connector.getLocalPort() + "/?b=1") .param(paramName, paramValue) .content(new BytesContentProvider(content)) - .timeout(555, TimeUnit.SECONDS) + .timeout(5, TimeUnit.SECONDS) .send(); Assert.assertNotNull(response); From dfa2d05bcc8ac11fa2f0de03a65cef4483a09a49 Mon Sep 17 00:00:00 2001 From: Simone Bordet Date: Tue, 8 Apr 2014 17:36:23 +0200 Subject: [PATCH 08/14] 432270 - Slow requests with response content delimited by EOF fail. Better handling of the idle case, and closing the connection only if the response can be failed. --- .../client/http/HttpReceiverOverHTTP.java | 12 ++++--- .../eclipse/jetty/client/HttpClientTest.java | 32 +++++++++++++++++-- 2 files changed, 36 insertions(+), 8 deletions(-) diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/http/HttpReceiverOverHTTP.java b/jetty-client/src/main/java/org/eclipse/jetty/client/http/HttpReceiverOverHTTP.java index 505d264747f..1b688e16e50 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/http/HttpReceiverOverHTTP.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/http/HttpReceiverOverHTTP.java @@ -213,7 +213,11 @@ public class HttpReceiverOverHTTP extends HttpReceiver implements HttpParser.Res @Override public void earlyEOF() { - failAndClose(new EOFException()); + HttpExchange exchange = getHttpExchange(); + if (exchange == null) + getHttpConnection().close(); + else + failAndClose(new EOFException()); } @Override @@ -244,10 +248,8 @@ public class HttpReceiverOverHTTP extends HttpReceiver implements HttpParser.Res private void failAndClose(Throwable failure) { - // Close the connection anyway, even if responseFailure() returns false. - // This may happen for idle closes (there is no exchange to fail). - responseFailure(failure); - getHttpConnection().close(failure); + if (responseFailure(failure)) + getHttpConnection().close(failure); } @Override diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientTest.java index c6789e20cdb..bedd3482776 100644 --- a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientTest.java +++ b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientTest.java @@ -1201,7 +1201,30 @@ public class HttpClientTest extends AbstractHttpClientServerTest } @Test - public void testContentDelimitedByEOFWithSlowRequest() throws Exception + public void testSmallContentDelimitedByEOFWithSlowRequestHTTP10() throws Exception + { + testContentDelimitedByEOFWithSlowRequest(HttpVersion.HTTP_1_0, 1024); + } + + @Test + public void testBigContentDelimitedByEOFWithSlowRequestHTTP10() throws Exception + { + testContentDelimitedByEOFWithSlowRequest(HttpVersion.HTTP_1_0, 128 * 1024); + } + + @Test + public void testSmallContentDelimitedByEOFWithSlowRequestHTTP11() throws Exception + { + testContentDelimitedByEOFWithSlowRequest(HttpVersion.HTTP_1_1, 1024); + } + + @Test + public void testBigContentDelimitedByEOFWithSlowRequestHTTP11() throws Exception + { + testContentDelimitedByEOFWithSlowRequest(HttpVersion.HTTP_1_1, 128 * 1024); + } + + private void testContentDelimitedByEOFWithSlowRequest(final HttpVersion version, int length) throws Exception { // This test is crafted in a way that the response completes before the request is fully written. // With SSL, the response coming down will close the SSLEngine so it would not be possible to @@ -1210,7 +1233,7 @@ public class HttpClientTest extends AbstractHttpClientServerTest // This is a limit of Java's SSL implementation that does not allow half closes. Assume.assumeTrue(sslContextFactory == null); - final byte[] data = new byte[8 * 1024]; + final byte[] data = new byte[length]; new Random().nextBytes(data); start(new AbstractHandler() { @@ -1218,7 +1241,9 @@ public class HttpClientTest extends AbstractHttpClientServerTest public void handle(String target, org.eclipse.jetty.server.Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { baseRequest.setHandled(true); - response.setHeader("Connection", "close"); + // Send Connection: close to avoid that the server chunks the content with HTTP 1.1. + if (version.compareTo(HttpVersion.HTTP_1_0) > 0) + response.setHeader("Connection", "close"); response.getOutputStream().write(data); } }); @@ -1226,6 +1251,7 @@ public class HttpClientTest extends AbstractHttpClientServerTest DeferredContentProvider content = new DeferredContentProvider(ByteBuffer.wrap(new byte[]{0})); Request request = client.newRequest("localhost", connector.getLocalPort()) .scheme(scheme) + .version(version) .content(content); FutureResponseListener listener = new FutureResponseListener(request); request.send(listener); From aebab6919cece28bc32fd3daa2cc8a135cd84aee Mon Sep 17 00:00:00 2001 From: Simone Bordet Date: Wed, 9 Apr 2014 00:08:30 +0200 Subject: [PATCH 09/14] Improved IllegalStateException reporting. --- .../org/eclipse/jetty/client/HttpSender.java | 21 ++++++++++++------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpSender.java b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpSender.java index 8358243501e..0e39d1e05ce 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpSender.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpSender.java @@ -152,7 +152,7 @@ public abstract class HttpSender implements AsyncContentProvider.Listener } default: { - throw new IllegalStateException(current.toString()); + throw illegalSenderState(current); } } } @@ -178,7 +178,7 @@ public abstract class HttpSender implements AsyncContentProvider.Listener if (expects100Continue(request)) newSenderState = content.hasContent() ? SenderState.EXPECTING_WITH_CONTENT : SenderState.EXPECTING; if (!updateSenderState(SenderState.IDLE, newSenderState)) - throw new IllegalStateException(); + throw illegalSenderState(SenderState.IDLE); // Setting the listener may trigger calls to onContent() by other // threads so we must set it only after the sender state has been updated @@ -462,7 +462,7 @@ public abstract class HttpSender implements AsyncContentProvider.Listener { // There is content to send. if (!updateSenderState(current, SenderState.SENDING)) - throw new IllegalStateException(); + throw illegalSenderState(current); LOG.debug("Proceeding while waiting"); sendContent(exchange, content, contentCallback); // TODO old style usage! return; @@ -471,14 +471,14 @@ public abstract class HttpSender implements AsyncContentProvider.Listener { // No content to send yet - it's deferred. if (!updateSenderState(current, SenderState.IDLE)) - throw new IllegalStateException(); + throw illegalSenderState(current); LOG.debug("Proceeding deferred"); return; } } default: { - throw new IllegalStateException(current.toString()); + throw illegalSenderState(current); } } } @@ -532,6 +532,11 @@ public abstract class HttpSender implements AsyncContentProvider.Listener } } + private RuntimeException illegalSenderState(SenderState current) + { + return new IllegalStateException("Expected " + current + " found " + senderState.get() + " instead"); + } + /** * The request states {@link HttpSender} goes through when sending a request. */ @@ -723,7 +728,7 @@ public abstract class HttpSender implements AsyncContentProvider.Listener } default: { - throw new IllegalStateException(); + throw illegalSenderState(current); } } } @@ -792,11 +797,11 @@ public abstract class HttpSender implements AsyncContentProvider.Listener return Action.SCHEDULED; } } - throw new IllegalStateException(); + throw illegalSenderState(current); } default: { - throw new IllegalStateException(); + throw illegalSenderState(current); } } } From 5a0811b328031c4da35c060bbcf33c5bdf3f04c5 Mon Sep 17 00:00:00 2001 From: Greg Wilkins Date: Fri, 11 Apr 2014 10:48:24 +1000 Subject: [PATCH 10/14] 432468 Improve command CGI path handling --- .../java/org/eclipse/jetty/servlets/CGI.java | 198 +++++++++++------- 1 file changed, 119 insertions(+), 79 deletions(-) diff --git a/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/CGI.java b/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/CGI.java index dc2a9c65599..ba56bc7d90c 100644 --- a/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/CGI.java +++ b/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/CGI.java @@ -47,32 +47,33 @@ import org.eclipse.jetty.util.log.Logger; //----------------------------------------------------------------------------- /** * CGI Servlet. - *

- * The cgi bin directory can be set with the "cgibinResourceBase" init parameter or it will default to the resource base of the context. If the - * "cgibinResourceBaseIsRelative" init parameter is set the resource base is relative to the webapp. For example "WEB-INF/cgi" would work. - *
- * Not that this only works for extracted war files as "jar cf" will not reserve the execute permissions on the cgi files. - *

- * The "commandPrefix" init parameter may be used to set a prefix to all commands passed to exec. This can be used on systems that need assistance to execute a - * particular file type. For example on windows this can be set to "perl" so that perl scripts are executed. - *

- * The "Path" init param is passed to the exec environment as PATH. Note: Must be run unpacked somewhere in the filesystem. - *

- * Any initParameter that starts with ENV_ is used to set an environment variable with the name stripped of the leading ENV_ and using the init parameter value. + *

+ * + * The following init parameters are used to configure this servlet: + *

+ *
cgibinResourceBase
Path to the cgi bin directory if set or it will default to the resource base of the context.
+ *
resourceBase
An alias for cgibinResourceBase.
+ *
cgibinResourceBaseIsRelative
If true then cgibinResourceBase is relative to the webapp (eg "WEB-INF/cgi")
+ *
commandPrefix
may be used to set a prefix to all commands passed to exec. This can be used on systems that need assistance to execute a + * particular file type. For example on windows this can be set to "perl" so that perl scripts are executed.
+ *
Path
passed to the exec environment as PATH.
+ *
ENV_*
used to set an arbitrary environment variable with the name stripped of the leading ENV_ and using the init parameter value
+ *
useFullPath
If true, the full URI path within the context is used for the exec command, otherwise a search is done for a partial URL that matches an exec Command
+ *
+ * */ public class CGI extends HttpServlet { - /** - * - */ - private static final long serialVersionUID = -6182088932884791073L; + private static final long serialVersionUID = -6182088932884791074L; private static final Logger LOG = Log.getLogger(CGI.class); private boolean _ok; private File _docRoot; + private boolean _cgiBinProvided; private String _path; private String _cmdPrefix; + private boolean _useFullPath; private EnvList _env; private boolean _ignoreExitState; private boolean _relative; @@ -83,16 +84,22 @@ public class CGI extends HttpServlet { _env = new EnvList(); _cmdPrefix = getInitParameter("commandPrefix"); + _useFullPath = Boolean.parseBoolean(getInitParameter("useFullPath")); _relative = Boolean.parseBoolean(getInitParameter("cgibinResourceBaseIsRelative")); String tmp = getInitParameter("cgibinResourceBase"); - if (tmp == null) + if (tmp != null) + _cgiBinProvided = true; + else { tmp = getInitParameter("resourceBase"); - if (tmp == null) + if (tmp != null) + _cgiBinProvided = true; + else tmp = getServletContext().getRealPath("/"); } - else if (_relative) + + if (_relative && _cgiBinProvided) { tmp = getServletContext().getRealPath(tmp); } @@ -137,10 +144,10 @@ public class CGI extends HttpServlet _env.set("PATH",_path); _ignoreExitState = "true".equalsIgnoreCase(getInitParameter("ignoreExitState")); - Enumeration e = getInitParameterNames(); + Enumeration e = getInitParameterNames(); while (e.hasMoreElements()) { - String n = (String)e.nextElement(); + String n = e.nextElement(); if (n != null && n.startsWith("ENV_")) _env.set(n.substring(4),getInitParameter(n)); } @@ -166,7 +173,6 @@ public class CGI extends HttpServlet return; } - String pathInContext = (_relative?"":StringUtil.nonNull(req.getServletPath())) + StringUtil.nonNull(req.getPathInfo()); if (LOG.isDebugEnabled()) { LOG.debug("CGI: ContextPath : " + req.getContextPath()); @@ -180,63 +186,69 @@ public class CGI extends HttpServlet // pathInContext may actually comprises scriptName/pathInfo...We will // walk backwards up it until we find the script - the rest must // be the pathInfo; + String pathInContext = (_relative ? "" : StringUtil.nonNull(req.getServletPath())) + StringUtil.nonNull(req.getPathInfo()); + File execCmd = new File(_docRoot, pathInContext); + String pathInfo = pathInContext; - String both = pathInContext; - String first = both; - String last = ""; - - File exe = new File(_docRoot,first); - - while ((first.endsWith("/") || !exe.exists()) && first.length() >= 0) + if(!_useFullPath) { - int index = first.lastIndexOf('/'); + String path = pathInContext; + String info = ""; - first = first.substring(0,index); - last = both.substring(index,both.length()); - exe = new File(_docRoot,first); - } - - if (first.length() == 0 || !exe.exists() || exe.isDirectory() || !exe.getCanonicalPath().equals(exe.getAbsolutePath())) - { - res.sendError(404); - } - else - { - if (LOG.isDebugEnabled()) + // Search docroot for a matching execCmd + while (path.endsWith("/") && path.length() >= 0) { - LOG.debug("CGI: script is " + exe); - LOG.debug("CGI: pathInfo is " + last); + if(!execCmd.exists()) + break; + + int index = path.lastIndexOf('/'); + + path = path.substring(0,index); + info = pathInContext.substring(index,pathInContext.length()); + execCmd = new File(_docRoot,path); } - exec(exe,last,req,res); + + if (path.length() == 0 || !execCmd.exists() || execCmd.isDirectory() || !execCmd.getCanonicalPath().equals(execCmd.getAbsolutePath())) + { + res.sendError(404); + } + + pathInfo = info; } + exec(execCmd,pathInfo,req,res); } - /* ------------------------------------------------------------ */ + /** executes the CGI process /* - * @param root @param path @param req @param res @exception IOException + * @param command the command to execute, this command is prefixed by + * the context parameter "commandPrefix". + * @param pathInfo The PATH_INFO to process, + * see http://docs.oracle.com/javaee/6/api/javax/servlet/http/HttpServletRequest.html#getPathInfo%28%29. Cannot be null + * @param req + * @param res + * @exception IOException */ private void exec(File command, String pathInfo, HttpServletRequest req, HttpServletResponse res) throws IOException { - String path = command.getAbsolutePath(); - File dir = command.getParentFile(); - String scriptName = req.getRequestURI().substring(0,req.getRequestURI().length() - pathInfo.length()); - String scriptPath = getServletContext().getRealPath(scriptName); - String pathTranslated = req.getPathTranslated(); + assert req != null; + assert res != null; + assert pathInfo != null; + assert command != null; - int len = req.getContentLength(); - if (len < 0) - len = 0; - if ((pathTranslated == null) || (pathTranslated.length() == 0)) - pathTranslated = path; + if (LOG.isDebugEnabled()) + { + LOG.debug("CGI: script is " + command); + LOG.debug("CGI: pathInfo is " + pathInfo); + } String bodyFormEncoded = null; if ((HttpMethod.POST.equals(req.getMethod()) || HttpMethod.PUT.equals(req.getMethod())) && "application/x-www-form-urlencoded".equals(req.getContentType())) { MultiMap parameterMap = new MultiMap(); - Enumeration names = req.getParameterNames(); + Enumeration names = req.getParameterNames(); while (names.hasMoreElements()) { - String parameterName = (String)names.nextElement(); + String parameterName = names.nextElement(); parameterMap.addValues(parameterName, req.getParameterValues(parameterName)); } bodyFormEncoded = UrlEncoded.encode(parameterMap, Charset.forName(req.getCharacterEncoding()), true); @@ -247,24 +259,33 @@ public class CGI extends HttpServlet // look at : // http://Web.Golux.Com/coar/cgi/draft-coar-cgi-v11-03-clean.html#6.1.1 env.set("AUTH_TYPE", req.getAuthType()); + + int contentLen = req.getContentLength(); + if (contentLen < 0) + contentLen = 0; if (bodyFormEncoded != null) { env.set("CONTENT_LENGTH", Integer.toString(bodyFormEncoded.length())); } else { - env.set("CONTENT_LENGTH", Integer.toString(len)); + env.set("CONTENT_LENGTH", Integer.toString(contentLen)); } env.set("CONTENT_TYPE", req.getContentType()); env.set("GATEWAY_INTERFACE", "CGI/1.1"); - if ((pathInfo != null) && (pathInfo.length() > 0)) + if (pathInfo.length() > 0) { env.set("PATH_INFO", pathInfo); } + + String pathTranslated = req.getPathTranslated(); + if ((pathTranslated == null) || (pathTranslated.length() == 0)) + pathTranslated = pathInfo; env.set("PATH_TRANSLATED", pathTranslated); env.set("QUERY_STRING", req.getQueryString()); env.set("REMOTE_ADDR", req.getRemoteAddr()); env.set("REMOTE_HOST", req.getRemoteHost()); + // The identity information reported about the connection by a // RFC 1413 [11] request to the remote agent, if // available. Servers MAY choose not to support this feature, or @@ -272,17 +293,33 @@ public class CGI extends HttpServlet // "REMOTE_IDENT" => "NYI" env.set("REMOTE_USER", req.getRemoteUser()); env.set("REQUEST_METHOD", req.getMethod()); - env.set("SCRIPT_NAME", scriptName); + + String scriptPath; + String scriptName; + // use docRoot for scriptPath, too + if(_cgiBinProvided) + { + scriptPath = command.getAbsolutePath(); + scriptName = scriptPath.substring(_docRoot.getAbsolutePath().length()); + } + else + { + String requestURI = req.getRequestURI(); + scriptName = requestURI.substring(0,requestURI.length() - pathInfo.length()); + scriptPath = getServletContext().getRealPath(scriptName); + } env.set("SCRIPT_FILENAME", scriptPath); + env.set("SCRIPT_NAME", scriptName); + env.set("SERVER_NAME", req.getServerName()); env.set("SERVER_PORT", Integer.toString(req.getServerPort())); env.set("SERVER_PROTOCOL", req.getProtocol()); env.set("SERVER_SOFTWARE", getServletContext().getServerInfo()); - Enumeration enm = req.getHeaderNames(); + Enumeration enm = req.getHeaderNames(); while (enm.hasMoreElements()) { - String name = (String)enm.nextElement(); + String name = enm.nextElement(); String value = req.getHeader(name); env.set("HTTP_" + name.toUpperCase(Locale.ENGLISH).replace('-','_'),value); } @@ -293,29 +330,30 @@ public class CGI extends HttpServlet // "SERVER_URL" => "NYI - http://us0245", // "TZ" => System.getProperty("user.timezone"), - // are we meant to decode args here ? or does the script get them - // via PATH_INFO ? if we are, they should be decoded and passed + // are we meant to decode args here? or does the script get them + // via PATH_INFO? if we are, they should be decoded and passed // into exec here... - String execCmd = path; - if ((execCmd.charAt(0) != '"') && (execCmd.indexOf(" ") >= 0)) + String absolutePath = command.getAbsolutePath(); + String execCmd = absolutePath; + + // escape the execCommand + if (execCmd.length() > 0 && execCmd.charAt(0) != '"' && execCmd.indexOf(" ") >= 0) execCmd = "\"" + execCmd + "\""; + if (_cmdPrefix != null) execCmd = _cmdPrefix + " " + execCmd; + assert execCmd != null; LOG.debug("Environment: " + env.getExportString()); LOG.debug("Command: " + execCmd); - final Process p; - if (dir == null) - p = Runtime.getRuntime().exec(execCmd, env.getEnvArray()); - else - p = Runtime.getRuntime().exec(execCmd, env.getEnvArray(), dir); + final Process p = Runtime.getRuntime().exec(execCmd, env.getEnvArray(), _docRoot); // hook processes input to browser's output (async) if (bodyFormEncoded != null) writeProcessInput(p, bodyFormEncoded); - else if (len > 0) - writeProcessInput(p, req.getInputStream(), len); + else if (contentLen > 0) + writeProcessInput(p, req.getInputStream(), contentLen); // hook processes output to browser's input (sync) // if browser closes stream, we should detect it and kill process... @@ -336,9 +374,9 @@ public class CGI extends HttpServlet { LOG.warn(e); } - } + } }); - + // read any headers off the top of our input stream // NOTE: Multiline header items not supported! String line = null; @@ -383,7 +421,7 @@ public class CGI extends HttpServlet int exitValue = p.exitValue(); if (0 != exitValue) { - LOG.warn("Non-zero exit status (" + exitValue + ") from CGI program: " + path); + LOG.warn("Non-zero exit status (" + exitValue + ") from CGI program: " + absolutePath); if (!res.isCommitted()) res.sendError(500,"Failed to exec CGI"); } @@ -393,7 +431,7 @@ public class CGI extends HttpServlet { // browser has probably closed its input stream - we // terminate and clean up... - LOG.debug("CGI: Client closed connection!"); + LOG.debug("CGI: Client closed connection!", e); } catch (InterruptedException ie) { @@ -422,6 +460,7 @@ public class CGI extends HttpServlet { new Thread(new Runnable() { + @Override public void run() { try @@ -445,6 +484,7 @@ public class CGI extends HttpServlet new Thread(new Runnable() { + @Override public void run() { try From deb7102e0edc5904dac5577a1904a7af1c4aa940 Mon Sep 17 00:00:00 2001 From: Greg Wilkins Date: Fri, 11 Apr 2014 10:57:39 +1000 Subject: [PATCH 11/14] 404511 removed deprecated StringMap --- .../org/eclipse/jetty/util/StringMap.java | 196 ---------------- .../org/eclipse/jetty/util/StringMapTest.java | 209 ------------------ 2 files changed, 405 deletions(-) delete mode 100644 jetty-util/src/main/java/org/eclipse/jetty/util/StringMap.java delete mode 100644 jetty-util/src/test/java/org/eclipse/jetty/util/StringMapTest.java diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/StringMap.java b/jetty-util/src/main/java/org/eclipse/jetty/util/StringMap.java deleted file mode 100644 index 63f5cd7d9ca..00000000000 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/StringMap.java +++ /dev/null @@ -1,196 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.util; - -import java.nio.ByteBuffer; -import java.util.AbstractMap; -import java.util.Collections; -import java.util.Comparator; -import java.util.Map; -import java.util.Set; -import java.util.TreeMap; - -/* ------------------------------------------------------------ */ -/** Map implementation Optimized for Strings keys.. - * This String Map has been optimized for mapping small sets of - * Strings where the most frequently accessed Strings have been put to - * the map first. - * - * It also has the benefit that it can look up entries by substring or - * sections of char and byte arrays. This can prevent many String - * objects from being created just to look up in the map. - * - * This map is NOT synchronized. - * @deprecated Use {@link Trie} - */ -public class StringMap extends AbstractMap -{ - private final TreeMap _map; - - - public static final boolean CASE_INSENSTIVE=true; - - /* ------------------------------------------------------------ */ - - private final boolean _caseInsensitive; - - - /* ------------------------------------------------------------ */ - /** Constructor. - */ - public StringMap() - { - this(false); - } - - /* ------------------------------------------------------------ */ - /** Constructor. - * @param ignoreCase - */ - public StringMap(final boolean ignoreCase) - { - _caseInsensitive=ignoreCase; - _map = new TreeMap(new Comparator() - { - @Override - public int compare(Object o1, Object o2) - { - String s1=(o1 instanceof String)?(String)o1:null; - ByteBuffer b1=(o1 instanceof ByteBuffer)?(ByteBuffer)o1:null; - if (s1==null && b1==null) - s1=o1.toString(); - String s2=(String)o2; - - int n1 = s1==null?b1.remaining():s1.length(); - int n2 = s2.length(); - int min = Math.min(n1, n2); - for (int i = 0; i < min; i++) { - char c1 = s1==null?(char)b1.get(b1.position()+i):s1.charAt(i); - char c2 = s2.charAt(i); - if (c1 != c2) { - if (ignoreCase) - { - c1 = Character.toUpperCase(c1); - c2 = Character.toUpperCase(c2); - if (c1 != c2) { - c1 = Character.toLowerCase(c1); - c2 = Character.toLowerCase(c2); - if (c1 != c2) { - // No overflow because of numeric promotion - return c1 - c2; - } - } - } - else - return c1 - c2; - } - } - return n1 - n2; - } - }); - } - - /* ------------------------------------------------------------ */ - public boolean isIgnoreCase() - { - return _caseInsensitive; - } - - /* ------------------------------------------------------------ */ - @Override - public O put(String key, O value) - { - return _map.put(key,value); - } - - /* ------------------------------------------------------------ */ - @Override - public O get(Object key) - { - return _map.get(key); - } - - /* ------------------------------------------------------------ */ - public O get(String key) - { - return _map.get(key); - } - - /* ------------------------------------------------------------ */ - public O get(String key,int offset,int length) - { - return _map.get(key.substring(offset,offset+length)); - } - - /* ------------------------------------------------------------ */ - public O get(ByteBuffer buffer) - { - return _map.get(buffer); - } - - /* ------------------------------------------------------------ */ - @Override - public O remove(Object key) - { - return _map.remove(key); - } - - /* ------------------------------------------------------------ */ - public O remove(String key) - { - return _map.remove(key); - } - - /* ------------------------------------------------------------ */ - @Override - public Set> entrySet() - { - Object o=_map.entrySet(); - return Collections.unmodifiableSet((Set>)o); - } - - /* ------------------------------------------------------------ */ - @Override - public int size() - { - return _map.size(); - } - - /* ------------------------------------------------------------ */ - @Override - public boolean isEmpty() - { - return _map.isEmpty(); - } - - /* ------------------------------------------------------------ */ - @Override - public boolean containsKey(Object key) - { - return _map.containsKey(key); - } - - /* ------------------------------------------------------------ */ - @Override - public void clear() - { - _map.clear(); - } - -} diff --git a/jetty-util/src/test/java/org/eclipse/jetty/util/StringMapTest.java b/jetty-util/src/test/java/org/eclipse/jetty/util/StringMapTest.java deleted file mode 100644 index c20e9f16269..00000000000 --- a/jetty-util/src/test/java/org/eclipse/jetty/util/StringMapTest.java +++ /dev/null @@ -1,209 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.util; - -import java.util.Set; - -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; - -public class StringMapTest -{ - StringMap m0; - StringMap m1; - StringMap m5; - StringMap m5i; - - /* - * @see TestCase#setUp() - */ - - @Before - public void setUp() throws Exception - { - m0=new StringMap<>(); - m1=new StringMap<>(false); - m1.put("abc", "0"); - - m5=new StringMap<>(false); - m5.put("a", "0"); - m5.put("ab", "1"); - m5.put("abc", "2"); - m5.put("abb", "3"); - m5.put("bbb", "4"); - - m5i=new StringMap<>(true); - m5i.put("ab", "1"); - m5i.put("abc", "2"); - m5i.put("abb", "3"); - } - - @Test - public void testSize() - { - Assert.assertEquals(0, m0.size()); - Assert.assertEquals(1, m1.size()); - Assert.assertEquals(5, m5.size()); - Assert.assertEquals(3, m5i.size()); - - m1.remove("abc"); - m5.remove("abc"); - m5.put("bbb","x"); - m5i.put("ABC", "x"); - Assert.assertEquals(0, m0.size()); - Assert.assertEquals(0, m1.size()); - Assert.assertEquals(4, m5.size()); - Assert.assertEquals(3, m5i.size()); - } - - @Test - public void testIsEmpty() - { - Assert.assertTrue(m0.isEmpty()); - Assert.assertFalse(m1.isEmpty()); - Assert.assertFalse(m5.isEmpty()); - Assert.assertFalse(m5i.isEmpty()); - } - - @Test - public void testClear() - { - m0.clear(); - m1.clear(); - m5.clear(); - m5i.clear(); - Assert.assertTrue(m0.isEmpty()); - Assert.assertTrue(m1.isEmpty()); - Assert.assertTrue(m5.isEmpty()); - Assert.assertTrue(m5i.isEmpty()); - Assert.assertEquals(null, m1.get("abc")); - Assert.assertEquals(null, m5.get("abc")); - Assert.assertEquals(null, m5i.get("abc")); - } - - - /* - * Test for Object put(Object, Object) - */ - @Test - public void testPutGet() - { - Assert.assertEquals("2", m5.get("abc")); - Assert.assertEquals(null, m5.get("aBc")); - Assert.assertEquals("2", m5i.get("abc")); - Assert.assertEquals("2", m5i.get("aBc")); - - m5.put("aBc", "x"); - m5i.put("AbC", "x"); - - StringBuilder buffer=new StringBuilder(); - buffer.append("aBc"); - Assert.assertEquals("2", m5.get("abc")); - Assert.assertEquals("x", m5.get(buffer)); - Assert.assertEquals("x", m5i.get((Object)"abc")); - Assert.assertEquals("x", m5i.get("aBc")); - - - } - - /* - * Test for Object remove(Object) - */ - @Test - public void testRemove() - { - m0.remove("abc"); - m1.remove("abc"); - m5.remove("aBc"); - m5.remove("bbb"); - m5i.remove("aBc"); - - Assert.assertEquals(0, m0.size()); - Assert.assertEquals(0, m1.size()); - Assert.assertEquals(4, m5.size()); - Assert.assertEquals(2, m5i.size()); - - Assert.assertEquals("2", m5.get("abc")); - Assert.assertEquals(null, m5.get("bbb")); - Assert.assertEquals(null, m5i.get("AbC")); - } - - /* - * Test for Set entrySet() - */ - @Test - public void testEntrySet() - { - Set es0=m0.entrySet(); - Set es1=m1.entrySet(); - Set es5=m5.entrySet(); - Assert.assertEquals(0, es0.size()); - Assert.assertEquals(1, es1.size()); - Assert.assertEquals(5, es5.size()); - } - - /* - * Test for boolean containsKey(Object) - */ - @Test - public void testContainsKey() - { - Assert.assertTrue(m5.containsKey("abc")); - Assert.assertTrue(!m5.containsKey("aBc")); - Assert.assertTrue(m5.containsKey("bbb")); - Assert.assertTrue(!m5.containsKey("xyz")); - - Assert.assertTrue(m5i.containsKey("abc")); - Assert.assertTrue(m5i.containsKey("aBc")); - Assert.assertTrue(m5i.containsKey("ABC")); - } - - @Test - public void testToString() - { - Assert.assertEquals("{}", m0.toString()); - Assert.assertEquals("{abc=0}", m1.toString()); - Assert.assertTrue(m5.toString().indexOf("abc=2") > 0); - } - - @Test - public void testIgnoreCase() - { - StringMap map = new StringMap<>(true); - map.put("POST","1"); - map.put("HEAD","2"); - map.put("PUT","3"); - map.put("OPTIONS","4"); - map.put("DELETE","5"); - map.put("TRACE","6"); - map.put("CONNECT","7"); - map.put("Upgrade","8"); - - Assert.assertEquals("1", map.get("POST")); - Assert.assertEquals("1", map.get("pOST")); - Assert.assertEquals("1", map.get("Post")); - - Assert.assertEquals("8", map.get("UPGRADE")); - Assert.assertEquals("8", map.get("Upgrade")); - Assert.assertEquals("8", map.get("upgrade")); - - } - -} From f2f5353a29846d560f018c5491ee2240407a9f13 Mon Sep 17 00:00:00 2001 From: Jan Bartel Date: Fri, 11 Apr 2014 17:23:42 +1000 Subject: [PATCH 12/14] 432483 jetty-annotations bundle does not start if there are no bundles that provide a service javax.servlet.ServletContainerInitializer --- jetty-osgi/jetty-osgi-boot/pom.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/jetty-osgi/jetty-osgi-boot/pom.xml b/jetty-osgi/jetty-osgi-boot/pom.xml index 5a02af5fdbf..bd5486a5936 100644 --- a/jetty-osgi/jetty-osgi-boot/pom.xml +++ b/jetty-osgi/jetty-osgi-boot/pom.xml @@ -102,6 +102,7 @@ org.eclipse.jetty.osgi.boot;singleton:=true org.eclipse.jetty.osgi.boot.JettyBootstrapActivator + osgi.serviceloader; osgi.serviceloader=javax.servlet.ServletContainerInitializer org.eclipse.jetty.*;version="[9.1,10.0)" javax.mail;version="1.4.0";resolution:=optional, javax.mail.event;version="1.4.0";resolution:=optional, From eb45d45dbf607172bdb70c9d1f6fb8a8798eb6a5 Mon Sep 17 00:00:00 2001 From: Jan Bartel Date: Fri, 11 Apr 2014 17:23:42 +1000 Subject: [PATCH 13/14] 432483 jetty-annotations bundle does not start if there are no bundles that provide a service javax.servlet.ServletContainerInitializer (cherry picked from commit f2f5353a29846d560f018c5491ee2240407a9f13) --- jetty-osgi/jetty-osgi-boot/pom.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/jetty-osgi/jetty-osgi-boot/pom.xml b/jetty-osgi/jetty-osgi-boot/pom.xml index a52ebfabcd2..0c1dbf56790 100644 --- a/jetty-osgi/jetty-osgi-boot/pom.xml +++ b/jetty-osgi/jetty-osgi-boot/pom.xml @@ -102,6 +102,7 @@ org.eclipse.jetty.osgi.boot;singleton:=true org.eclipse.jetty.osgi.boot.JettyBootstrapActivator + osgi.serviceloader; osgi.serviceloader=javax.servlet.ServletContainerInitializer org.eclipse.jetty.*;version="[9.1,10.0)" javax.mail;version="1.4.0";resolution:=optional, javax.mail.event;version="1.4.0";resolution:=optional, From 5eeda38f0af1ba5606465a1899c21c91a20eacc1 Mon Sep 17 00:00:00 2001 From: Simone Bordet Date: Fri, 11 Apr 2014 15:57:26 +0200 Subject: [PATCH 14/14] 432270 - Slow requests with response content delimited by EOF fail. Fixed also in the FastCGI module. --- .../eclipse/jetty/client/HttpDestination.java | 4 + .../jetty/client/PoolingHttpDestination.java | 5 +- .../fcgi/client/http/HttpChannelOverFCGI.java | 50 ++++++------ .../http/HttpClientTransportOverFCGI.java | 2 +- .../client/http/HttpConnectionOverFCGI.java | 69 +++++++++++++---- .../jetty/fcgi/generator/ServerGenerator.java | 41 ++++++---- .../jetty/fcgi/parser/ClientParser.java | 8 ++ .../fcgi/parser/EndRequestContentParser.java | 8 +- .../org/eclipse/jetty/fcgi/parser/Parser.java | 8 ++ .../jetty/fcgi/parser/ClientParserTest.java | 6 +- .../fcgi/server/HttpTransportOverFCGI.java | 31 +++++--- .../fcgi/server/ServerFCGIConnection.java | 12 +++ .../jetty/fcgi/server/HttpClientTest.java | 76 +++++++++++++++++++ 13 files changed, 249 insertions(+), 71 deletions(-) diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpDestination.java b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpDestination.java index 5a40a2c4061..cc83372c437 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpDestination.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpDestination.java @@ -215,6 +215,10 @@ public abstract class HttpDestination implements Destination, Closeable, Dumpabl LOG.debug("Closed {}", this); } + public void release(Connection connection) + { + } + public void close(Connection connection) { } diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/PoolingHttpDestination.java b/jetty-client/src/main/java/org/eclipse/jetty/client/PoolingHttpDestination.java index 6bba6a58205..73c13ad45da 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/PoolingHttpDestination.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/PoolingHttpDestination.java @@ -140,8 +140,11 @@ public abstract class PoolingHttpDestination extends HttpD protected abstract void send(C connection, HttpExchange exchange); - public void release(C connection) + @Override + public void release(Connection c) { + @SuppressWarnings("unchecked") + C connection = (C)c; LOG.debug("{} released", connection); HttpClient client = getHttpClient(); if (client.isRunning()) diff --git a/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/client/http/HttpChannelOverFCGI.java b/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/client/http/HttpChannelOverFCGI.java index a6f7de6ec3b..1c33cf0518d 100644 --- a/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/client/http/HttpChannelOverFCGI.java +++ b/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/client/http/HttpChannelOverFCGI.java @@ -28,8 +28,6 @@ import org.eclipse.jetty.fcgi.generator.Flusher; import org.eclipse.jetty.fcgi.generator.Generator; import org.eclipse.jetty.http.HttpField; import org.eclipse.jetty.http.HttpFields; -import org.eclipse.jetty.http.HttpHeader; -import org.eclipse.jetty.http.HttpHeaderValue; import org.eclipse.jetty.http.HttpVersion; import org.eclipse.jetty.io.IdleTimeout; @@ -83,42 +81,43 @@ public class HttpChannelOverFCGI extends HttpChannel return receiver.abort(cause); } - protected void responseBegin(int code, String reason) + protected boolean responseBegin(int code, String reason) { HttpExchange exchange = getHttpExchange(); - if (exchange != null) - { - exchange.getResponse().version(version).status(code).reason(reason); - receiver.responseBegin(exchange); - } + if (exchange == null) + return false; + exchange.getResponse().version(version).status(code).reason(reason); + return receiver.responseBegin(exchange); } - protected void responseHeader(HttpField field) + protected boolean responseHeader(HttpField field) { HttpExchange exchange = getHttpExchange(); - if (exchange != null) - receiver.responseHeader(exchange, field); + return exchange != null && receiver.responseHeader(exchange, field); } - protected void responseHeaders() + protected boolean responseHeaders() { HttpExchange exchange = getHttpExchange(); - if (exchange != null) - receiver.responseHeaders(exchange); + return exchange != null && receiver.responseHeaders(exchange); } - protected void content(ByteBuffer buffer) + protected boolean content(ByteBuffer buffer) { HttpExchange exchange = getHttpExchange(); - if (exchange != null) - receiver.responseContent(exchange, buffer); + return exchange != null && receiver.responseContent(exchange, buffer); } - protected void responseSuccess() + protected boolean responseSuccess() { HttpExchange exchange = getHttpExchange(); - if (exchange != null) - receiver.responseSuccess(exchange); + return exchange != null && receiver.responseSuccess(exchange); + } + + protected boolean responseFailure(Throwable failure) + { + HttpExchange exchange = getHttpExchange(); + return exchange != null && receiver.responseFailure(failure); } @Override @@ -126,12 +125,10 @@ public class HttpChannelOverFCGI extends HttpChannel { super.exchangeTerminated(result); idle.onClose(); - boolean close = result.isFailed(); HttpFields responseHeaders = result.getResponse().getHeaders(); - close |= responseHeaders.contains(HttpHeader.CONNECTION, HttpHeaderValue.CLOSE.asString()); - if (close) - connection.close(); - else + if (result.isFailed()) + connection.close(result.getFailure()); + else if (!connection.closeByHTTP(responseHeaders)) connection.release(this); } @@ -154,7 +151,8 @@ public class HttpChannelOverFCGI extends HttpChannel @Override protected void onIdleExpired(TimeoutException timeout) { - LOG.debug("Idle timeout for request {}", request); + if (LOG.isDebugEnabled()) + LOG.debug("Idle timeout for request {}", request); connection.abort(timeout); } diff --git a/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/client/http/HttpClientTransportOverFCGI.java b/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/client/http/HttpClientTransportOverFCGI.java index eed8c892a60..00c6778d5e3 100644 --- a/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/client/http/HttpClientTransportOverFCGI.java +++ b/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/client/http/HttpClientTransportOverFCGI.java @@ -69,7 +69,7 @@ public class HttpClientTransportOverFCGI extends AbstractHttpClientTransport public org.eclipse.jetty.io.Connection newConnection(EndPoint endPoint, Map context) throws IOException { HttpDestination destination = (HttpDestination)context.get(HTTP_DESTINATION_CONTEXT_KEY); - HttpConnectionOverFCGI connection = new HttpConnectionOverFCGI(endPoint, destination); + HttpConnectionOverFCGI connection = new HttpConnectionOverFCGI(endPoint, destination, isMultiplexed()); LOG.debug("Created {}", connection); @SuppressWarnings("unchecked") Promise promise = (Promise)context.get(HTTP_CONNECTION_PROMISE_CONTEXT_KEY); diff --git a/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/client/http/HttpConnectionOverFCGI.java b/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/client/http/HttpConnectionOverFCGI.java index 262a7c498c9..f14143bfb0c 100644 --- a/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/client/http/HttpConnectionOverFCGI.java +++ b/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/client/http/HttpConnectionOverFCGI.java @@ -31,7 +31,6 @@ import org.eclipse.jetty.client.HttpClient; import org.eclipse.jetty.client.HttpConnection; import org.eclipse.jetty.client.HttpDestination; import org.eclipse.jetty.client.HttpExchange; -import org.eclipse.jetty.client.PoolingHttpDestination; import org.eclipse.jetty.client.api.Connection; import org.eclipse.jetty.client.api.Request; import org.eclipse.jetty.client.api.Response; @@ -39,6 +38,9 @@ import org.eclipse.jetty.fcgi.FCGI; import org.eclipse.jetty.fcgi.generator.Flusher; import org.eclipse.jetty.fcgi.parser.ClientParser; import org.eclipse.jetty.http.HttpField; +import org.eclipse.jetty.http.HttpFields; +import org.eclipse.jetty.http.HttpHeader; +import org.eclipse.jetty.http.HttpHeaderValue; import org.eclipse.jetty.io.AbstractConnection; import org.eclipse.jetty.io.ByteBufferPool; import org.eclipse.jetty.io.EndPoint; @@ -55,14 +57,16 @@ public class HttpConnectionOverFCGI extends AbstractConnection implements Connec private final AtomicBoolean closed = new AtomicBoolean(); private final Flusher flusher; private final HttpDestination destination; + private final boolean multiplexed; private final Delegate delegate; private final ClientParser parser; - public HttpConnectionOverFCGI(EndPoint endPoint, HttpDestination destination) + public HttpConnectionOverFCGI(EndPoint endPoint, HttpDestination destination, boolean multiplexed) { super(endPoint, destination.getHttpClient().getExecutor(), destination.getHttpClient().isDispatchIO()); - this.flusher = new Flusher(endPoint); this.destination = destination; + this.multiplexed = multiplexed; + this.flusher = new Flusher(endPoint); this.delegate = new Delegate(destination); this.parser = new ClientParser(new ResponseListener()); requests.addLast(0); @@ -103,7 +107,7 @@ public class HttpConnectionOverFCGI extends AbstractConnection implements Connec while (true) { int read = endPoint.fill(buffer); - if (LOG.isDebugEnabled()) // Avoid boxing of variable 'read' + if (LOG.isDebugEnabled()) // Avoid boxing of variable 'read'. LOG.debug("Read {} bytes from {}", read, endPoint); if (read > 0) { @@ -124,7 +128,7 @@ public class HttpConnectionOverFCGI extends AbstractConnection implements Connec catch (Exception x) { LOG.debug(x); - // TODO: fail and close ? + close(x); } finally { @@ -140,7 +144,12 @@ public class HttpConnectionOverFCGI extends AbstractConnection implements Connec private void shutdown() { - close(new EOFException()); + // Close explicitly only if we are idle, since the request may still + // be in progress, otherwise close only if we can fail the responses. + if (channels.isEmpty()) + close(); + else + failAndClose(new EOFException()); } @Override @@ -153,13 +162,7 @@ public class HttpConnectionOverFCGI extends AbstractConnection implements Connec protected void release(HttpChannelOverFCGI channel) { channels.remove(channel.getRequest()); - if (destination instanceof PoolingHttpDestination) - { - @SuppressWarnings("unchecked") - PoolingHttpDestination fcgiDestination = - (PoolingHttpDestination)destination; - fcgiDestination.release(this); - } + destination.release(this); } @Override @@ -168,7 +171,7 @@ public class HttpConnectionOverFCGI extends AbstractConnection implements Connec close(new AsynchronousCloseException()); } - private void close(Throwable failure) + protected void close(Throwable failure) { if (closed.compareAndSet(false, true)) { @@ -184,6 +187,16 @@ public class HttpConnectionOverFCGI extends AbstractConnection implements Connec } } + protected boolean closeByHTTP(HttpFields fields) + { + if (multiplexed) + return false; + if (!fields.contains(HttpHeader.CONNECTION, HttpHeaderValue.CLOSE.asString())) + return false; + close(); + return true; + } + protected void abort(Throwable failure) { for (HttpChannelOverFCGI channel : channels.values()) @@ -195,6 +208,15 @@ public class HttpConnectionOverFCGI extends AbstractConnection implements Connec channels.clear(); } + private void failAndClose(Throwable failure) + { + boolean result = false; + for (HttpChannelOverFCGI channel : channels.values()) + result |= channel.responseFailure(failure); + if (result) + close(failure); + } + private int acquireRequest() { synchronized (requests) @@ -322,8 +344,23 @@ public class HttpConnectionOverFCGI extends AbstractConnection implements Connec HttpChannelOverFCGI channel = channels.get(request); if (channel != null) { - channel.responseSuccess(); - releaseRequest(request); + if (channel.responseSuccess()) + releaseRequest(request); + } + else + { + noChannel(request); + } + } + + @Override + public void onFailure(int request, Throwable failure) + { + HttpChannelOverFCGI channel = channels.get(request); + if (channel != null) + { + if (channel.responseFailure(failure)) + releaseRequest(request); } else { diff --git a/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/generator/ServerGenerator.java b/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/generator/ServerGenerator.java index 39619268a7b..e113dd29b78 100644 --- a/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/generator/ServerGenerator.java +++ b/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/generator/ServerGenerator.java @@ -88,21 +88,36 @@ public class ServerGenerator extends Generator return generateContent(request, buffer, true, false, callback, FCGI.FrameType.STDOUT); } - public Result generateResponseContent(int request, ByteBuffer content, boolean lastContent, Callback callback) + public Result generateResponseContent(int request, ByteBuffer content, boolean lastContent, boolean aborted, Callback callback) { - Result result = generateContent(request, content, false, lastContent, callback, FCGI.FrameType.STDOUT); - if (lastContent) + if (aborted) { - // Generate the FCGI_END_REQUEST - request &= 0xFF_FF; - ByteBuffer endRequestBuffer = byteBufferPool.acquire(8, false); - BufferUtil.clearToFill(endRequestBuffer); - endRequestBuffer.putInt(0x01_03_00_00 + request); - endRequestBuffer.putInt(0x00_08_00_00); - endRequestBuffer.putLong(0x00L); - endRequestBuffer.flip(); - result = result.append(endRequestBuffer, true); + Result result = new Result(byteBufferPool, callback); + if (lastContent) + result.append(generateEndRequest(request, true), true); + else + result.append(BufferUtil.EMPTY_BUFFER, false); + return result; } - return result; + else + { + Result result = generateContent(request, content, false, lastContent, callback, FCGI.FrameType.STDOUT); + if (lastContent) + result.append(generateEndRequest(request, false), true); + return result; + } + } + + private ByteBuffer generateEndRequest(int request, boolean aborted) + { + request &= 0xFF_FF; + ByteBuffer endRequestBuffer = byteBufferPool.acquire(8, false); + BufferUtil.clearToFill(endRequestBuffer); + endRequestBuffer.putInt(0x01_03_00_00 + request); + endRequestBuffer.putInt(0x00_08_00_00); + endRequestBuffer.putInt(aborted ? 1 : 0); + endRequestBuffer.putInt(0); + endRequestBuffer.flip(); + return endRequestBuffer; } } diff --git a/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/parser/ClientParser.java b/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/parser/ClientParser.java index 4ba70b44e22..d7a7dc6604d 100644 --- a/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/parser/ClientParser.java +++ b/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/parser/ClientParser.java @@ -98,5 +98,13 @@ public class ClientParser extends Parser for (StreamContentParser streamParser : streamParsers) streamParser.end(request); } + + @Override + public void onFailure(int request, Throwable failure) + { + listener.onFailure(request, failure); + for (StreamContentParser streamParser : streamParsers) + streamParser.end(request); + } } } diff --git a/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/parser/EndRequestContentParser.java b/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/parser/EndRequestContentParser.java index 419536af77d..1f77eaf0ea6 100644 --- a/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/parser/EndRequestContentParser.java +++ b/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/parser/EndRequestContentParser.java @@ -107,8 +107,12 @@ public class EndRequestContentParser extends ContentParser private void onEnd() { - // TODO: if protocol != 0, invoke an error callback - listener.onEnd(getRequest()); + if (application != 0) + listener.onFailure(getRequest(), new Exception("FastCGI application returned code " + application)); + else if (protocol != 0) + listener.onFailure(getRequest(), new Exception("FastCGI server returned code " + protocol)); + else + listener.onEnd(getRequest()); } private void reset() diff --git a/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/parser/Parser.java b/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/parser/Parser.java index 577219c301c..5739ef32012 100644 --- a/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/parser/Parser.java +++ b/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/parser/Parser.java @@ -100,6 +100,8 @@ public abstract class Parser public void onEnd(int request); + public void onFailure(int request, Throwable failure); + public static class Adapter implements Listener { @Override @@ -121,6 +123,12 @@ public abstract class Parser public void onEnd(int request) { } + + @Override + public void onFailure(int request, Throwable failure) + { + + } } } diff --git a/jetty-fcgi/fcgi-client/src/test/java/org/eclipse/jetty/fcgi/parser/ClientParserTest.java b/jetty-fcgi/fcgi-client/src/test/java/org/eclipse/jetty/fcgi/parser/ClientParserTest.java index 5f80ed2827c..826ed84b43e 100644 --- a/jetty-fcgi/fcgi-client/src/test/java/org/eclipse/jetty/fcgi/parser/ClientParserTest.java +++ b/jetty-fcgi/fcgi-client/src/test/java/org/eclipse/jetty/fcgi/parser/ClientParserTest.java @@ -111,7 +111,7 @@ public class ClientParserTest ByteBufferPool byteBufferPool = new MappedByteBufferPool(); ServerGenerator generator = new ServerGenerator(byteBufferPool); Generator.Result result1 = generator.generateResponseHeaders(id, 200, "OK", fields, null); - Generator.Result result2 = generator.generateResponseContent(id, null, true, null); + Generator.Result result2 = generator.generateResponseContent(id, null, true, false, null); final AtomicInteger verifier = new AtomicInteger(); ClientParser parser = new ClientParser(new ClientParser.Listener.Adapter() @@ -162,7 +162,7 @@ public class ClientParserTest ByteBufferPool byteBufferPool = new MappedByteBufferPool(); ServerGenerator generator = new ServerGenerator(byteBufferPool); Generator.Result result1 = generator.generateResponseHeaders(id, code, "OK", fields, null); - Generator.Result result2 = generator.generateResponseContent(id, content, true, null); + Generator.Result result2 = generator.generateResponseContent(id, content, true, false, null); final AtomicInteger verifier = new AtomicInteger(); ClientParser parser = new ClientParser(new ClientParser.Listener.Adapter() @@ -214,7 +214,7 @@ public class ClientParserTest ByteBufferPool byteBufferPool = new MappedByteBufferPool(); ServerGenerator generator = new ServerGenerator(byteBufferPool); Generator.Result result1 = generator.generateResponseHeaders(id, code, "OK", fields, null); - Generator.Result result2 = generator.generateResponseContent(id, content, true, null); + Generator.Result result2 = generator.generateResponseContent(id, content, true, false, null); final AtomicInteger totalLength = new AtomicInteger(); final AtomicBoolean verifier = new AtomicBoolean(); diff --git a/jetty-fcgi/fcgi-server/src/main/java/org/eclipse/jetty/fcgi/server/HttpTransportOverFCGI.java b/jetty-fcgi/fcgi-server/src/main/java/org/eclipse/jetty/fcgi/server/HttpTransportOverFCGI.java index fd62656164e..91459ed7798 100644 --- a/jetty-fcgi/fcgi-server/src/main/java/org/eclipse/jetty/fcgi/server/HttpTransportOverFCGI.java +++ b/jetty-fcgi/fcgi-server/src/main/java/org/eclipse/jetty/fcgi/server/HttpTransportOverFCGI.java @@ -24,6 +24,8 @@ import org.eclipse.jetty.fcgi.generator.Flusher; import org.eclipse.jetty.fcgi.generator.Generator; import org.eclipse.jetty.fcgi.generator.ServerGenerator; import org.eclipse.jetty.http.HttpGenerator; +import org.eclipse.jetty.http.HttpHeader; +import org.eclipse.jetty.http.HttpHeaderValue; import org.eclipse.jetty.io.ByteBufferPool; import org.eclipse.jetty.server.HttpTransport; import org.eclipse.jetty.util.BufferUtil; @@ -35,6 +37,8 @@ public class HttpTransportOverFCGI implements HttpTransport private final Flusher flusher; private final int request; private volatile boolean head; + private volatile boolean shutdown; + private volatile boolean aborted; public HttpTransportOverFCGI(ByteBufferPool byteBufferPool, Flusher flusher, int request) { @@ -47,13 +51,15 @@ public class HttpTransportOverFCGI implements HttpTransport public void send(HttpGenerator.ResponseInfo info, ByteBuffer content, boolean lastContent, Callback callback) { boolean head = this.head = info.isHead(); + boolean shutdown = this.shutdown = info.getHttpFields().contains(HttpHeader.CONNECTION, HttpHeaderValue.CLOSE.asString()); + if (head) { if (lastContent) { Generator.Result headersResult = generator.generateResponseHeaders(request, info.getStatus(), info.getReason(), info.getHttpFields(), new Callback.Adapter()); - Generator.Result contentResult = generator.generateResponseContent(request, BufferUtil.EMPTY_BUFFER, lastContent, callback); + Generator.Result contentResult = generator.generateResponseContent(request, BufferUtil.EMPTY_BUFFER, lastContent, aborted, callback); flusher.flush(headersResult, contentResult); } else @@ -67,9 +73,12 @@ public class HttpTransportOverFCGI implements HttpTransport { Generator.Result headersResult = generator.generateResponseHeaders(request, info.getStatus(), info.getReason(), info.getHttpFields(), new Callback.Adapter()); - Generator.Result contentResult = generator.generateResponseContent(request, content, lastContent, callback); + Generator.Result contentResult = generator.generateResponseContent(request, content, lastContent, aborted, callback); flusher.flush(headersResult, contentResult); } + + if (lastContent && shutdown) + flusher.shutdown(); } @Override @@ -79,7 +88,7 @@ public class HttpTransportOverFCGI implements HttpTransport { if (lastContent) { - Generator.Result result = generator.generateResponseContent(request, BufferUtil.EMPTY_BUFFER, lastContent, callback); + Generator.Result result = generator.generateResponseContent(request, BufferUtil.EMPTY_BUFFER, lastContent, aborted, callback); flusher.flush(result); } else @@ -90,18 +99,22 @@ public class HttpTransportOverFCGI implements HttpTransport } else { - Generator.Result result = generator.generateResponseContent(request, content, lastContent, callback); + Generator.Result result = generator.generateResponseContent(request, content, lastContent, aborted, callback); flusher.flush(result); } + + if (lastContent && shutdown) + flusher.shutdown(); + } + + @Override + public void abort() + { + aborted = true; } @Override public void completed() { } - - @Override - public void abort() - { - } } diff --git a/jetty-fcgi/fcgi-server/src/main/java/org/eclipse/jetty/fcgi/server/ServerFCGIConnection.java b/jetty-fcgi/fcgi-server/src/main/java/org/eclipse/jetty/fcgi/server/ServerFCGIConnection.java index c69253e4ded..2e8187966e0 100644 --- a/jetty-fcgi/fcgi-server/src/main/java/org/eclipse/jetty/fcgi/server/ServerFCGIConnection.java +++ b/jetty-fcgi/fcgi-server/src/main/java/org/eclipse/jetty/fcgi/server/ServerFCGIConnection.java @@ -175,5 +175,17 @@ public class ServerFCGIConnection extends AbstractConnection channel.dispatch(); } } + + @Override + public void onFailure(int request, Throwable failure) + { + HttpChannelOverFCGI channel = channels.remove(request); + if (LOG.isDebugEnabled()) + LOG.debug("Request {} failure on {}: {}", request, channel, failure); + if (channel != null) + { + channel.badMessage(400, failure.toString()); + } + } } } diff --git a/jetty-fcgi/fcgi-server/src/test/java/org/eclipse/jetty/fcgi/server/HttpClientTest.java b/jetty-fcgi/fcgi-server/src/test/java/org/eclipse/jetty/fcgi/server/HttpClientTest.java index 103a326eabb..2146f6305be 100644 --- a/jetty-fcgi/fcgi-server/src/test/java/org/eclipse/jetty/fcgi/server/HttpClientTest.java +++ b/jetty-fcgi/fcgi-server/src/test/java/org/eclipse/jetty/fcgi/server/HttpClientTest.java @@ -24,6 +24,7 @@ import java.net.URI; import java.net.URLEncoder; import java.nio.ByteBuffer; import java.util.Arrays; +import java.util.Random; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; @@ -40,6 +41,8 @@ import org.eclipse.jetty.client.api.Request; import org.eclipse.jetty.client.api.Response; import org.eclipse.jetty.client.api.Result; import org.eclipse.jetty.client.util.BytesContentProvider; +import org.eclipse.jetty.client.util.DeferredContentProvider; +import org.eclipse.jetty.client.util.FutureResponseListener; import org.eclipse.jetty.http.HttpMethod; import org.eclipse.jetty.server.handler.AbstractHandler; import org.eclipse.jetty.toolchain.test.IO; @@ -551,4 +554,77 @@ public class HttpClientTest extends AbstractHttpClientServerTest Assert.assertTrue(completeLatch.await(5, TimeUnit.SECONDS)); } + + @Test + public void testEarlyEOF() throws Exception + { + start(new AbstractHandler() + { + @Override + public void handle(String target, org.eclipse.jetty.server.Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException + { + baseRequest.setHandled(true); + // Promise some content, then flush the headers, then fail to send the content. + response.setContentLength(16); + response.flushBuffer(); + throw new NullPointerException(); + } + }); + + try + { + client.newRequest("localhost", connector.getLocalPort()) + .scheme(scheme) + .timeout(5, TimeUnit.SECONDS) + .send(); + Assert.fail(); + } + catch (ExecutionException x) + { + // Expected. + } + } + + @Test + public void testSmallContentDelimitedByEOFWithSlowRequest() throws Exception + { + testContentDelimitedByEOFWithSlowRequest(1024); + } + + @Test + public void testBigContentDelimitedByEOFWithSlowRequest() throws Exception + { + testContentDelimitedByEOFWithSlowRequest(128 * 1024); + } + + private void testContentDelimitedByEOFWithSlowRequest(int length) throws Exception + { + final byte[] data = new byte[length]; + 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 + { + baseRequest.setHandled(true); + response.setHeader("Connection", "close"); + response.getOutputStream().write(data); + } + }); + + DeferredContentProvider content = new DeferredContentProvider(ByteBuffer.wrap(new byte[]{0})); + Request request = client.newRequest("localhost", connector.getLocalPort()) + .scheme(scheme) + .content(content); + FutureResponseListener listener = new FutureResponseListener(request); + request.send(listener); + // Wait some time to simulate a slow request. + Thread.sleep(1000); + content.close(); + + ContentResponse response = listener.get(5, TimeUnit.SECONDS); + + Assert.assertEquals(200, response.getStatus()); + Assert.assertArrayEquals(data, response.getContent()); + } }