1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.eclipse.jetty.fcgi.server.proxy;
20
21 import java.net.URI;
22 import java.util.List;
23 import java.util.regex.Matcher;
24 import java.util.regex.Pattern;
25 import javax.servlet.RequestDispatcher;
26 import javax.servlet.ServletConfig;
27 import javax.servlet.ServletException;
28 import javax.servlet.http.HttpServletRequest;
29 import javax.servlet.http.HttpServletResponse;
30
31 import org.eclipse.jetty.client.HttpClient;
32 import org.eclipse.jetty.client.api.Request;
33 import org.eclipse.jetty.fcgi.FCGI;
34 import org.eclipse.jetty.fcgi.client.http.HttpClientTransportOverFCGI;
35 import org.eclipse.jetty.http.HttpFields;
36 import org.eclipse.jetty.http.HttpHeader;
37 import org.eclipse.jetty.http.HttpScheme;
38 import org.eclipse.jetty.proxy.AsyncProxyServlet;
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65 public class FastCGIProxyServlet extends AsyncProxyServlet.Transparent
66 {
67 public static final String SCRIPT_ROOT_INIT_PARAM = "scriptRoot";
68 public static final String SCRIPT_PATTERN_INIT_PARAM = "scriptPattern";
69 public static final String FASTCGI_HTTPS_INIT_PARAM = "fastCGI.HTTPS";
70
71 private static final String REMOTE_ADDR_ATTRIBUTE = FastCGIProxyServlet.class.getName() + ".remoteAddr";
72 private static final String REMOTE_PORT_ATTRIBUTE = FastCGIProxyServlet.class.getName() + ".remotePort";
73 private static final String SERVER_NAME_ATTRIBUTE = FastCGIProxyServlet.class.getName() + ".serverName";
74 private static final String SERVER_ADDR_ATTRIBUTE = FastCGIProxyServlet.class.getName() + ".serverAddr";
75 private static final String SERVER_PORT_ATTRIBUTE = FastCGIProxyServlet.class.getName() + ".serverPort";
76 private static final String SCHEME_ATTRIBUTE = FastCGIProxyServlet.class.getName() + ".scheme";
77 private static final String REQUEST_URI_ATTRIBUTE = FastCGIProxyServlet.class.getName() + ".requestURI";
78
79 private Pattern scriptPattern;
80 private boolean fcgiHTTPS;
81
82 @Override
83 public void init() throws ServletException
84 {
85 super.init();
86
87 String value = getInitParameter(SCRIPT_PATTERN_INIT_PARAM);
88 if (value == null)
89 value = "(.+?\\.php)";
90 scriptPattern = Pattern.compile(value);
91
92 fcgiHTTPS = Boolean.parseBoolean(getInitParameter(FASTCGI_HTTPS_INIT_PARAM));
93 }
94
95 @Override
96 protected HttpClient newHttpClient()
97 {
98 ServletConfig config = getServletConfig();
99 String scriptRoot = config.getInitParameter(SCRIPT_ROOT_INIT_PARAM);
100 if (scriptRoot == null)
101 throw new IllegalArgumentException("Mandatory parameter '" + SCRIPT_ROOT_INIT_PARAM + "' not configured");
102 return new HttpClient(new ProxyHttpClientTransportOverFCGI(scriptRoot), null);
103 }
104
105 @Override
106 protected void sendProxyRequest(HttpServletRequest request, HttpServletResponse proxyResponse, Request proxyRequest)
107 {
108 proxyRequest.attribute(REMOTE_ADDR_ATTRIBUTE, request.getRemoteAddr());
109 proxyRequest.attribute(REMOTE_PORT_ATTRIBUTE, String.valueOf(request.getRemotePort()));
110 proxyRequest.attribute(SERVER_NAME_ATTRIBUTE, request.getServerName());
111 proxyRequest.attribute(SERVER_ADDR_ATTRIBUTE, request.getLocalAddr());
112 proxyRequest.attribute(SERVER_PORT_ATTRIBUTE, String.valueOf(request.getLocalPort()));
113
114 proxyRequest.attribute(SCHEME_ATTRIBUTE, request.getScheme());
115
116
117 String originalPath = (String)request.getAttribute(RequestDispatcher.FORWARD_REQUEST_URI);
118 String originalQuery = (String)request.getAttribute(RequestDispatcher.FORWARD_QUERY_STRING);
119 if (originalPath == null)
120 {
121 originalPath = (String)request.getAttribute(RequestDispatcher.INCLUDE_REQUEST_URI);
122 originalQuery = (String)request.getAttribute(RequestDispatcher.INCLUDE_QUERY_STRING);
123 }
124 if (originalPath != null)
125 {
126 String originalURI = originalPath;
127 if (originalQuery != null)
128 originalURI += "?" + originalQuery;
129 proxyRequest.attribute(REQUEST_URI_ATTRIBUTE, originalURI);
130 }
131
132
133 if (!proxyRequest.getHeaders().containsKey(HttpHeader.HOST.asString()))
134 {
135 String host = request.getServerName();
136 int port = request.getServerPort();
137 if (!getHttpClient().isDefaultPort(request.getScheme(), port))
138 host += ":" + port;
139 proxyRequest.header(HttpHeader.HOST, host);
140 proxyRequest.header(HttpHeader.X_FORWARDED_HOST, host);
141 }
142
143
144 List<String> cookies = proxyRequest.getHeaders().getValuesList(HttpHeader.COOKIE.asString());
145 if (cookies.size() > 1)
146 {
147 StringBuilder builder = new StringBuilder();
148 for (int i = 0; i < cookies.size(); ++i)
149 {
150 if (i > 0)
151 builder.append("; ");
152 String cookie = cookies.get(i);
153 builder.append(cookie);
154 }
155 proxyRequest.header(HttpHeader.COOKIE, null);
156 proxyRequest.header(HttpHeader.COOKIE, builder.toString());
157 }
158
159 super.sendProxyRequest(request, proxyResponse, proxyRequest);
160 }
161
162 protected void customizeFastCGIHeaders(Request proxyRequest, HttpFields fastCGIHeaders)
163 {
164 fastCGIHeaders.put(FCGI.Headers.REMOTE_ADDR, (String)proxyRequest.getAttributes().get(REMOTE_ADDR_ATTRIBUTE));
165 fastCGIHeaders.put(FCGI.Headers.REMOTE_PORT, (String)proxyRequest.getAttributes().get(REMOTE_PORT_ATTRIBUTE));
166 fastCGIHeaders.put(FCGI.Headers.SERVER_NAME, (String)proxyRequest.getAttributes().get(SERVER_NAME_ATTRIBUTE));
167 fastCGIHeaders.put(FCGI.Headers.SERVER_ADDR, (String)proxyRequest.getAttributes().get(SERVER_ADDR_ATTRIBUTE));
168 fastCGIHeaders.put(FCGI.Headers.SERVER_PORT, (String)proxyRequest.getAttributes().get(SERVER_PORT_ATTRIBUTE));
169
170 if (fcgiHTTPS || HttpScheme.HTTPS.is((String)proxyRequest.getAttributes().get(SCHEME_ATTRIBUTE)))
171 fastCGIHeaders.put(FCGI.Headers.HTTPS, "on");
172
173 URI proxyRequestURI = proxyRequest.getURI();
174 String rawPath = proxyRequestURI.getRawPath();
175 String rawQuery = proxyRequestURI.getRawQuery();
176
177 String requestURI = (String)proxyRequest.getAttributes().get(REQUEST_URI_ATTRIBUTE);
178 if (requestURI == null)
179 {
180 requestURI = rawPath;
181 if (rawQuery != null)
182 requestURI += "?" + rawQuery;
183 }
184 fastCGIHeaders.put(FCGI.Headers.REQUEST_URI, requestURI);
185
186 String scriptName = rawPath;
187 Matcher matcher = scriptPattern.matcher(rawPath);
188 if (matcher.matches())
189 {
190
191 scriptName = matcher.group(1);
192
193
194 if (matcher.groupCount() > 1)
195 fastCGIHeaders.put(FCGI.Headers.PATH_INFO, matcher.group(2));
196 }
197 fastCGIHeaders.put(FCGI.Headers.SCRIPT_NAME, scriptName);
198
199 String root = fastCGIHeaders.get(FCGI.Headers.DOCUMENT_ROOT);
200 fastCGIHeaders.put(FCGI.Headers.SCRIPT_FILENAME, root + scriptName);
201 }
202
203 private class ProxyHttpClientTransportOverFCGI extends HttpClientTransportOverFCGI
204 {
205 public ProxyHttpClientTransportOverFCGI(String scriptRoot)
206 {
207 super(scriptRoot);
208 }
209
210 @Override
211 protected void customize(Request request, HttpFields fastCGIHeaders)
212 {
213 super.customize(request, fastCGIHeaders);
214 customizeFastCGIHeaders(request, fastCGIHeaders);
215 }
216 }
217 }