From 7fe7c68e3b8ebee3a344b2d3fd6ebc2be7cf0f35 Mon Sep 17 00:00:00 2001 From: Simone Bordet Date: Fri, 25 Oct 2013 10:53:37 +0200 Subject: [PATCH] Fixed values for REQUEST_URI, DOCUMENT_URI and SERVER_NAME FastCGI fields. Added Drupal and WordPress working examples. --- .../java/org/eclipse/jetty/fcgi/FCGI.java | 1 + .../http/HttpClientTransportOverFCGI.java | 2 - .../fcgi/client/http/HttpSenderOverFCGI.java | 6 +- .../fcgi/client/http/HttpClientTest.java | 32 ++++++ fcgi-proxy/pom.xml | 6 ++ .../jetty/fcgi/proxy/FastCGIProxyServlet.java | 41 ++++++- ...ver.java => DrupalFastCGIProxyServer.java} | 28 +++-- .../proxy/WordPressFastCGIProxyServer.java | 102 ++++++++++++++++++ .../test/resources/jetty-logging.properties | 3 + 9 files changed, 204 insertions(+), 17 deletions(-) rename fcgi-proxy/src/test/java/org/eclipse/jetty/fcgi/proxy/{FastCGIProxyServer.java => DrupalFastCGIProxyServer.java} (57%) create mode 100644 fcgi-proxy/src/test/java/org/eclipse/jetty/fcgi/proxy/WordPressFastCGIProxyServer.java create mode 100644 fcgi-proxy/src/test/resources/jetty-logging.properties diff --git a/fcgi-core/src/main/java/org/eclipse/jetty/fcgi/FCGI.java b/fcgi-core/src/main/java/org/eclipse/jetty/fcgi/FCGI.java index 36ec33b5962..14da7aab8f9 100644 --- a/fcgi-core/src/main/java/org/eclipse/jetty/fcgi/FCGI.java +++ b/fcgi-core/src/main/java/org/eclipse/jetty/fcgi/FCGI.java @@ -112,6 +112,7 @@ public class FCGI public static final String CONTENT_LENGTH = "CONTENT_LENGTH"; public static final String CONTENT_TYPE = "CONTENT_TYPE"; public static final String DOCUMENT_ROOT = "DOCUMENT_ROOT"; + public static final String DOCUMENT_URI = "DOCUMENT_URI"; public static final String GATEWAY_INTERFACE = "GATEWAY_INTERFACE"; public static final String PATH_INFO = "PATH_INFO"; public static final String QUERY_STRING = "QUERY_STRING"; diff --git a/fcgi-http-client-transport/src/main/java/org/eclipse/jetty/fcgi/client/http/HttpClientTransportOverFCGI.java b/fcgi-http-client-transport/src/main/java/org/eclipse/jetty/fcgi/client/http/HttpClientTransportOverFCGI.java index f3983e5a03f..87a719a9c87 100644 --- a/fcgi-http-client-transport/src/main/java/org/eclipse/jetty/fcgi/client/http/HttpClientTransportOverFCGI.java +++ b/fcgi-http-client-transport/src/main/java/org/eclipse/jetty/fcgi/client/http/HttpClientTransportOverFCGI.java @@ -67,8 +67,6 @@ public class HttpClientTransportOverFCGI extends AbstractHttpClientTransport protected void customize(Request request, HttpFields fastCGIHeaders) { - String scriptName = fastCGIHeaders.get(FCGI.Headers.SCRIPT_NAME); - fastCGIHeaders.put(FCGI.Headers.SCRIPT_FILENAME, scriptRoot + scriptName); fastCGIHeaders.put(FCGI.Headers.DOCUMENT_ROOT, scriptRoot); } } diff --git a/fcgi-http-client-transport/src/main/java/org/eclipse/jetty/fcgi/client/http/HttpSenderOverFCGI.java b/fcgi-http-client-transport/src/main/java/org/eclipse/jetty/fcgi/client/http/HttpSenderOverFCGI.java index 9d16d5c3eca..6af5be81229 100644 --- a/fcgi-http-client-transport/src/main/java/org/eclipse/jetty/fcgi/client/http/HttpSenderOverFCGI.java +++ b/fcgi-http-client-transport/src/main/java/org/eclipse/jetty/fcgi/client/http/HttpSenderOverFCGI.java @@ -46,12 +46,10 @@ public class HttpSenderOverFCGI extends HttpSender // FastCGI headers based on the URI URI uri = request.getURI(); String path = uri.getRawPath(); - fcgiHeaders.put(FCGI.Headers.REQUEST_URI, path); + fcgiHeaders.put(FCGI.Headers.DOCUMENT_URI, path); String query = uri.getRawQuery(); fcgiHeaders.put(FCGI.Headers.QUERY_STRING, query == null ? "" : query); - int lastSegment = path.lastIndexOf('/'); - String scriptName = lastSegment < 0 ? path : path.substring(lastSegment); - fcgiHeaders.put(FCGI.Headers.SCRIPT_NAME, scriptName); + fcgiHeaders.put(FCGI.Headers.REQUEST_URI, query == null ? path : path + "?" + query); // FastCGI headers based on HTTP headers HttpField httpField = headers.remove(HttpHeader.AUTHORIZATION); diff --git a/fcgi-http-client-transport/src/test/java/org/eclipse/jetty/fcgi/client/http/HttpClientTest.java b/fcgi-http-client-transport/src/test/java/org/eclipse/jetty/fcgi/client/http/HttpClientTest.java index 7ba69ff172c..518e12cf830 100644 --- a/fcgi-http-client-transport/src/test/java/org/eclipse/jetty/fcgi/client/http/HttpClientTest.java +++ b/fcgi-http-client-transport/src/test/java/org/eclipse/jetty/fcgi/client/http/HttpClientTest.java @@ -183,6 +183,38 @@ public class HttpClientTest extends AbstractHttpClientServerTest Assert.assertEquals(paramValue, new String(response.getContent(), "UTF-8")); } + @Test + public void testPOSTWithQueryString() throws Exception + { + final String paramName = "a"; + final String paramValue = "\u20AC"; + 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); + String value = request.getParameter(paramName); + if (paramValue.equals(value)) + { + response.setCharacterEncoding("UTF-8"); + response.setContentType("text/plain"); + response.getOutputStream().print(value); + } + } + }); + + String uri = scheme + "://localhost:" + connector.getLocalPort() + + "/?" + paramName + "=" + URLEncoder.encode(paramValue, "UTF-8"); + ContentResponse response = client.POST(uri) + .timeout(5, TimeUnit.SECONDS) + .send(); + + Assert.assertNotNull(response); + Assert.assertEquals(200, response.getStatus()); + Assert.assertEquals(paramValue, new String(response.getContent(), "UTF-8")); + } + @Test public void testPUTWithParameters() throws Exception { diff --git a/fcgi-proxy/pom.xml b/fcgi-proxy/pom.xml index 81f1cbd8c87..0aee57ec7f3 100644 --- a/fcgi-proxy/pom.xml +++ b/fcgi-proxy/pom.xml @@ -42,6 +42,12 @@ ${jetty-version} test + + org.eclipse.jetty + jetty-rewrite + ${jetty-version} + test + diff --git a/fcgi-proxy/src/main/java/org/eclipse/jetty/fcgi/proxy/FastCGIProxyServlet.java b/fcgi-proxy/src/main/java/org/eclipse/jetty/fcgi/proxy/FastCGIProxyServlet.java index 1a7bccbc167..e19431e0daa 100644 --- a/fcgi-proxy/src/main/java/org/eclipse/jetty/fcgi/proxy/FastCGIProxyServlet.java +++ b/fcgi-proxy/src/main/java/org/eclipse/jetty/fcgi/proxy/FastCGIProxyServlet.java @@ -18,7 +18,10 @@ package org.eclipse.jetty.fcgi.proxy; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import javax.servlet.ServletConfig; +import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import org.eclipse.jetty.client.HttpClient; @@ -31,11 +34,26 @@ import org.eclipse.jetty.proxy.ProxyServlet; public class FastCGIProxyServlet extends ProxyServlet.Transparent { public static final String SCRIPT_ROOT_INIT_PARAM = "scriptRoot"; + public static final String SCRIPT_PATTERN_INIT_PARAM = "scriptPattern"; private static final String REMOTE_ADDR_ATTRIBUTE = FastCGIProxyServlet.class.getName() + ".remoteAddr"; private static final String REMOTE_PORT_ATTRIBUTE = FastCGIProxyServlet.class.getName() + ".remotePort"; + private static final String SERVER_NAME_ATTRIBUTE = FastCGIProxyServlet.class.getName() + ".serverName"; private static final String SERVER_ADDR_ATTRIBUTE = FastCGIProxyServlet.class.getName() + ".serverAddr"; private static final String SERVER_PORT_ATTRIBUTE = FastCGIProxyServlet.class.getName() + ".serverPort"; + private Pattern scriptPattern; + + @Override + public void init() throws ServletException + { + super.init(); + + String value = getInitParameter(SCRIPT_PATTERN_INIT_PARAM); + if (value == null) + value = "(.+\\.php)"; + scriptPattern = Pattern.compile(value); + } + @Override protected HttpClient newHttpClient() { @@ -51,12 +69,28 @@ public class FastCGIProxyServlet extends ProxyServlet.Transparent { proxyRequest.attribute(REMOTE_ADDR_ATTRIBUTE, request.getRemoteAddr()); proxyRequest.attribute(REMOTE_PORT_ATTRIBUTE, String.valueOf(request.getRemotePort())); + proxyRequest.attribute(SERVER_NAME_ATTRIBUTE, request.getServerName()); proxyRequest.attribute(SERVER_ADDR_ATTRIBUTE, request.getLocalAddr()); proxyRequest.attribute(SERVER_PORT_ATTRIBUTE, String.valueOf(request.getLocalPort())); super.customizeProxyRequest(proxyRequest, request); } - private static class ProxyHttpClientTransportOverFCGI extends HttpClientTransportOverFCGI + protected void customizeFastCGIHeaders(Request proxyRequest, HttpFields fastCGIHeaders) + { + fastCGIHeaders.put(FCGI.Headers.REMOTE_ADDR, (String)proxyRequest.getAttributes().get(REMOTE_ADDR_ATTRIBUTE)); + fastCGIHeaders.put(FCGI.Headers.REMOTE_PORT, (String)proxyRequest.getAttributes().get(REMOTE_PORT_ATTRIBUTE)); + fastCGIHeaders.put(FCGI.Headers.SERVER_NAME, (String)proxyRequest.getAttributes().get(SERVER_NAME_ATTRIBUTE)); + fastCGIHeaders.put(FCGI.Headers.SERVER_ADDR, (String)proxyRequest.getAttributes().get(SERVER_ADDR_ATTRIBUTE)); + fastCGIHeaders.put(FCGI.Headers.SERVER_PORT, (String)proxyRequest.getAttributes().get(SERVER_PORT_ATTRIBUTE)); + String root = fastCGIHeaders.get(FCGI.Headers.DOCUMENT_ROOT); + String path = proxyRequest.getURI().getRawPath(); + Matcher matcher = scriptPattern.matcher(path); + String scriptName = matcher.matches() ? matcher.group(1) : path; + fastCGIHeaders.put(FCGI.Headers.SCRIPT_NAME, scriptName); + fastCGIHeaders.put(FCGI.Headers.SCRIPT_FILENAME, root + scriptName); + } + + private class ProxyHttpClientTransportOverFCGI extends HttpClientTransportOverFCGI { public ProxyHttpClientTransportOverFCGI(String scriptRoot) { @@ -67,10 +101,7 @@ public class FastCGIProxyServlet extends ProxyServlet.Transparent protected void customize(Request request, HttpFields fastCGIHeaders) { super.customize(request, fastCGIHeaders); - fastCGIHeaders.put(FCGI.Headers.REMOTE_ADDR, (String)request.getAttributes().get(REMOTE_ADDR_ATTRIBUTE)); - fastCGIHeaders.put(FCGI.Headers.REMOTE_PORT, (String)request.getAttributes().get(REMOTE_PORT_ATTRIBUTE)); - fastCGIHeaders.put(FCGI.Headers.SERVER_ADDR, (String)request.getAttributes().get(SERVER_ADDR_ATTRIBUTE)); - fastCGIHeaders.put(FCGI.Headers.SERVER_PORT, (String)request.getAttributes().get(SERVER_PORT_ATTRIBUTE)); + customizeFastCGIHeaders(request, fastCGIHeaders); } } } diff --git a/fcgi-proxy/src/test/java/org/eclipse/jetty/fcgi/proxy/FastCGIProxyServer.java b/fcgi-proxy/src/test/java/org/eclipse/jetty/fcgi/proxy/DrupalFastCGIProxyServer.java similarity index 57% rename from fcgi-proxy/src/test/java/org/eclipse/jetty/fcgi/proxy/FastCGIProxyServer.java rename to fcgi-proxy/src/test/java/org/eclipse/jetty/fcgi/proxy/DrupalFastCGIProxyServer.java index 75d3e6c8f3e..458a9921264 100644 --- a/fcgi-proxy/src/test/java/org/eclipse/jetty/fcgi/proxy/FastCGIProxyServer.java +++ b/fcgi-proxy/src/test/java/org/eclipse/jetty/fcgi/proxy/DrupalFastCGIProxyServer.java @@ -20,10 +20,11 @@ package org.eclipse.jetty.fcgi.proxy; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.ServerConnector; +import org.eclipse.jetty.servlet.DefaultServlet; import org.eclipse.jetty.servlet.ServletContextHandler; import org.eclipse.jetty.servlet.ServletHolder; -public class FastCGIProxyServer +public class DrupalFastCGIProxyServer { public static void main(String[] args) throws Exception { @@ -32,12 +33,27 @@ public class FastCGIProxyServer connector.setPort(8080); server.addConnector(connector); + // Drupal seems to only work on the root context, + // at least out of the box without additional plugins + + String root = "/home/simon/programs/drupal-7.23"; + ServletContextHandler context = new ServletContextHandler(server, "/"); - ServletHolder servletHolder = new ServletHolder(FastCGIProxyServlet.class); - servletHolder.setInitParameter(FastCGIProxyServlet.SCRIPT_ROOT_INIT_PARAM, "/var/www/php-fcgi"); - servletHolder.setInitParameter("proxyTo", "http://localhost:9000/"); - servletHolder.setInitParameter("prefix", "/"); - context.addServlet(servletHolder, "/*"); + context.setResourceBase(root); + context.setWelcomeFiles(new String[]{"index.php"}); + + // Serve static resources + ServletHolder defaultServlet = new ServletHolder(DefaultServlet.class); + defaultServlet.setName("default"); + context.addServlet(defaultServlet, "/"); + + // FastCGI + ServletHolder fcgiServlet = new ServletHolder(FastCGIProxyServlet.class); + fcgiServlet.setInitParameter(FastCGIProxyServlet.SCRIPT_ROOT_INIT_PARAM, root); + fcgiServlet.setInitParameter("proxyTo", "http://localhost:9000"); + fcgiServlet.setInitParameter("prefix", "/"); + fcgiServlet.setInitParameter(FastCGIProxyServlet.SCRIPT_PATTERN_INIT_PARAM, "(.+\\.php)"); + context.addServlet(fcgiServlet, "*.php"); server.start(); } diff --git a/fcgi-proxy/src/test/java/org/eclipse/jetty/fcgi/proxy/WordPressFastCGIProxyServer.java b/fcgi-proxy/src/test/java/org/eclipse/jetty/fcgi/proxy/WordPressFastCGIProxyServer.java new file mode 100644 index 00000000000..353724144c0 --- /dev/null +++ b/fcgi-proxy/src/test/java/org/eclipse/jetty/fcgi/proxy/WordPressFastCGIProxyServer.java @@ -0,0 +1,102 @@ +// +// ======================================================================== +// Copyright (c) 1995-2013 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.fcgi.proxy; + +import java.io.IOException; +import java.util.EnumSet; +import java.util.Locale; +import javax.servlet.DispatcherType; +import javax.servlet.Filter; +import javax.servlet.FilterChain; +import javax.servlet.FilterConfig; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletRequest; + +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.server.ServerConnector; +import org.eclipse.jetty.servlet.DefaultServlet; +import org.eclipse.jetty.servlet.ServletContextHandler; +import org.eclipse.jetty.servlet.ServletHolder; + +public class WordPressFastCGIProxyServer +{ + public static void main(String[] args) throws Exception + { + Server server = new Server(); + ServerConnector connector = new ServerConnector(server); + connector.setPort(8080); + server.addConnector(connector); + + String root = "/home/simon/programs/wordpress-3.6.1"; + + ServletContextHandler context = new ServletContextHandler(server, "/"); + context.setResourceBase(root); + context.setWelcomeFiles(new String[]{"index.php"}); + + // Serve static resources + ServletHolder defaultServlet = new ServletHolder(DefaultServlet.class); + defaultServlet.setName("default"); + context.addServlet(defaultServlet, "/"); + + context.addFilter(WordPressFilter.class, "/index.php/*", EnumSet.of(DispatcherType.REQUEST)); + + // FastCGI + ServletHolder fcgiServlet = new ServletHolder(FastCGIProxyServlet.class); + fcgiServlet.setInitParameter(FastCGIProxyServlet.SCRIPT_ROOT_INIT_PARAM, root); + fcgiServlet.setInitParameter("proxyTo", "http://localhost:9000"); + fcgiServlet.setInitParameter("prefix", "/"); + fcgiServlet.setInitParameter(FastCGIProxyServlet.SCRIPT_PATTERN_INIT_PARAM, "/index\\.php(.+\\.php)"); + context.addServlet(fcgiServlet, "*.php"); + + server.start(); + } + + /** + * This filter is needed to get rid of the annoying "/index.php" prefix + * in WordPress URLs that prevents serving correctly static resources. + */ + public static class WordPressFilter implements Filter + { + @Override + public void init(FilterConfig filterConfig) throws ServletException + { + } + + @Override + public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException + { + String path = ((HttpServletRequest)request).getRequestURI().toLowerCase(Locale.ENGLISH); + if (!path.endsWith(".php") && path.startsWith("/index.php/")) + { + request.getRequestDispatcher(path.substring("/index.php".length())).forward(request, response); + } + else + { + chain.doFilter(request, response); + } + } + + @Override + public void destroy() + { + } + } +} diff --git a/fcgi-proxy/src/test/resources/jetty-logging.properties b/fcgi-proxy/src/test/resources/jetty-logging.properties new file mode 100644 index 00000000000..11c27cfd24f --- /dev/null +++ b/fcgi-proxy/src/test/resources/jetty-logging.properties @@ -0,0 +1,3 @@ +org.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.StdErrLog +org.eclipse.jetty.client.LEVEL=DEBUG +org.eclipse.jetty.fcgi.LEVEL=DEBUG