1
2
3
4
5
6
7 package nl.mineleni.cbsviewer.servlet;
8
9 import static javax.servlet.http.HttpServletResponse.SC_FORBIDDEN;
10 import static javax.servlet.http.HttpServletResponse.SC_OK;
11
12 import java.io.IOException;
13 import java.io.PrintWriter;
14 import java.io.UnsupportedEncodingException;
15 import java.net.URLDecoder;
16 import java.net.URLEncoder;
17 import java.util.HashSet;
18 import java.util.Set;
19
20 import javax.servlet.ServletConfig;
21 import javax.servlet.ServletException;
22 import javax.servlet.http.HttpServletRequest;
23 import javax.servlet.http.HttpServletResponse;
24
25 import nl.mineleni.cbsviewer.servlet.wms.FeatureInfoResponseConverter;
26 import nl.mineleni.cbsviewer.servlet.wms.FeatureInfoResponseConverter.CONVERTER_TYPE;
27 import nl.mineleni.cbsviewer.util.AvailableLayersBean;
28 import nl.mineleni.cbsviewer.util.EncodingUtil;
29
30 import org.apache.http.HttpHost;
31 import org.apache.http.HttpResponse;
32 import org.apache.http.client.config.CookieSpecs;
33 import org.apache.http.client.config.RequestConfig;
34 import org.apache.http.client.methods.HttpGet;
35 import org.apache.http.impl.client.CloseableHttpClient;
36 import org.apache.http.impl.client.HttpClients;
37 import org.apache.http.util.EntityUtils;
38 import org.slf4j.Logger;
39 import org.slf4j.LoggerFactory;
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
66
67
68
69
70 public class ReverseProxyServlet extends AbstractBaseServlet {
71
72 public static final String ALLOWED_HOSTS = "allowed_hosts";
73
74
75 public static final String FORCE_XML_MIME = "force_xml_mime";
76
77
78 public static final String ERR_MSG_MISSING_CONFIG = "De \'allowed_hosts\' parameter ontbreekt in servletconfig.";
79
80
81 private static final String ERR_MSG_FORBIDDEN = " is niet in de lijst met toegestane servers opgenomen.";
82
83
84 private static final Logger LOGGER = LoggerFactory
85 .getLogger(ReverseProxyServlet.class);
86
87
88 private static final long serialVersionUID = 1512103319305509379L;
89
90
91
92
93 private static CONVERTER_TYPE type = CONVERTER_TYPE.GMLTYPE;
94
95
96
97
98
99
100 private final Set<String> allowedHosts = new HashSet<>();
101
102
103 private final transient AvailableLayersBean layers = new AvailableLayersBean();
104
105
106 private transient CloseableHttpClient client;
107
108
109
110
111
112
113
114
115 private transient boolean forceXmlResponse;
116
117
118 private transient RequestConfig requestConfig;
119
120
121
122
123
124
125
126
127
128 private boolean checkUrlAllowed(final String serverUrl) {
129 String sUrl = serverUrl.toLowerCase().substring(
130 serverUrl.indexOf("//") + 2);
131 if (serverUrl.contains("/")) {
132 sUrl = sUrl.substring(0, sUrl.indexOf('/'));
133 }
134 if (LOGGER.isDebugEnabled()) {
135 LOGGER.debug("test server = " + sUrl);
136 }
137 return this.allowedHosts.contains(sUrl);
138 }
139
140
141
142
143
144
145 @Override
146 public void destroy() {
147 try {
148 this.client.close();
149 } catch (final IOException e) {
150 LOGGER.error("Fout tijdens servlet destroy.", e);
151 }
152 super.destroy();
153 }
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168 @Override
169 protected void doGet(final HttpServletRequest request,
170 final HttpServletResponse response) throws ServletException {
171 try {
172 String serverUrl = request.getQueryString();
173 serverUrl = URLDecoder.decode(serverUrl, "UTF-8");
174 if (serverUrl.startsWith("http://")
175 || serverUrl.startsWith("https://")) {
176
177 if (!this.checkUrlAllowed(serverUrl)) {
178 LOGGER.warn(serverUrl + ERR_MSG_FORBIDDEN);
179 response.sendError(SC_FORBIDDEN, serverUrl
180 + ERR_MSG_FORBIDDEN);
181 response.flushBuffer();
182 } else {
183
184 if (serverUrl.contains("GetFeatureInfo")) {
185 serverUrl = serverUrl.replace("text%2Fhtml",
186 URLEncoder.encode(type.toString(), "UTF-8"));
187 serverUrl = serverUrl.replace("text/html",
188 URLEncoder.encode(type.toString(), "UTF-8"));
189 if (LOGGER.isDebugEnabled()) {
190 LOGGER.debug("proxy GetFeatureInfo GET param: "
191 + serverUrl);
192 }
193 }
194 if (LOGGER.isDebugEnabled()) {
195 LOGGER.debug("Execute proxy GET param:" + serverUrl);
196 }
197 final HttpGet httpget = new HttpGet(serverUrl);
198 httpget.setConfig(this.requestConfig);
199 final HttpResponse get = this.client.execute(httpget);
200 if (get.getStatusLine().getStatusCode() == SC_OK) {
201 String responseBody;
202 if (serverUrl.contains("GetFeatureInfo")) {
203 String lName = "";
204 String styles = "";
205
206 final String[] params = serverUrl.split("&");
207 for (final String s : params) {
208 if (s.contains("QUERY_LAYERS=")) {
209 lName = EncodingUtil.decodeURIComponent(s
210 .substring(
211 "QUERY_LAYERS=".length(),
212 s.length()));
213 if (LOGGER.isDebugEnabled()) {
214 LOGGER.debug("Query layers = " + lName);
215 }
216 }
217 if (s.contains("STYLES=")) {
218 styles = EncodingUtil.decodeURIComponent(s
219 .substring("STYLES=".length(),
220 s.length()));
221 if (LOGGER.isDebugEnabled()) {
222 LOGGER.debug("Layer styles = " + styles);
223 }
224 }
225 }
226 final String wmsUrl = serverUrl.substring(0,
227 serverUrl.indexOf('?'));
228 if (LOGGER.isDebugEnabled()) {
229 LOGGER.debug("WMS url = " + wmsUrl);
230 }
231 responseBody = FeatureInfoResponseConverter
232 .convertToHTMLTable(get.getEntity()
233 .getContent(), type, this.layers
234 .getLayerByLayers(lName, wmsUrl,
235 styles));
236 response.setContentType("text/html; charset=UTF-8");
237 } else {
238
239
240 if (this.forceXmlResponse) {
241 response.setContentType("text/xml");
242 }
243 responseBody = EntityUtils
244 .toString(get.getEntity()).trim();
245 }
246 response.setCharacterEncoding("UTF-8");
247
248
249
250
251 final PrintWriter out = response.getWriter();
252 out.print(responseBody);
253 response.flushBuffer();
254 } else {
255 LOGGER.warn("Onverwachte fout(server url=" + serverUrl
256 + "): " + get.getStatusLine().toString());
257 response.sendError(get.getStatusLine().getStatusCode(),
258 get.getStatusLine().toString());
259 }
260 httpget.reset();
261 }
262 } else {
263 throw new ServletException("Only HTTP(S) protocol is supported");
264 }
265 } catch (final UnsupportedEncodingException e) {
266 LOGGER.error("Proxy fout.", e);
267 throw new ServletException(e);
268 } catch (final IOException e) {
269 LOGGER.error("Proxy IO fout.", e);
270 throw new ServletException(e);
271 }
272 }
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354 @Override
355 public void init(final ServletConfig config) throws ServletException {
356 super.init(config);
357 final String forceXML = config.getInitParameter(FORCE_XML_MIME);
358 this.forceXmlResponse = (null != forceXML ? Boolean
359 .parseBoolean(forceXML) : false);
360
361 String csvHostnames = config.getInitParameter(ALLOWED_HOSTS);
362 if (csvHostnames == null) {
363 LOGGER.error(ERR_MSG_MISSING_CONFIG);
364 throw new ServletException(ERR_MSG_MISSING_CONFIG);
365 }
366
367 csvHostnames = csvHostnames.replaceAll("\\s", "").toLowerCase();
368 final String[] names = csvHostnames.split(";");
369 for (final String name : names) {
370 this.allowedHosts.add(name);
371 if (LOGGER.isDebugEnabled()) {
372 LOGGER.debug("toevoegen aan allowed host namen: " + name);
373 }
374 }
375
376
377 this.client = HttpClients.createSystem();
378 this.requestConfig = RequestConfig.custom()
379 .setCookieSpec(CookieSpecs.IGNORE_COOKIES).build();
380 if ((null != this.getProxyHost()) && (this.getProxyPort() > 0)) {
381 final HttpHost proxy = new HttpHost(this.getProxyHost(),
382 this.getProxyPort(), "http");
383 this.requestConfig = RequestConfig.copy(this.requestConfig)
384 .setProxy(proxy).build();
385 }
386
387
388 final String mType = config.getInitParameter("featureInfoType");
389 if (LOGGER.isDebugEnabled()) {
390 LOGGER.debug("voorgrond kaartlagen mimetype: " + mType);
391 }
392 if ((mType != null) && (mType.length() > 0)) {
393 type = CONVERTER_TYPE.valueOf(mType);
394 }
395
396 }
397 }