1 /*
2  * Copyright 2008-2019 by Emeric Vernat
3  *
4  *     This file is part of Java Melody.
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */

18 package net.bull.javamelody.internal.web; // NOPMD
19
20 import java.io.BufferedInputStream;
21 import java.io.BufferedWriter;
22 import java.io.File;
23 import java.io.IOException;
24 import java.io.InputStream;
25 import java.io.OutputStream;
26 import java.io.Serializable;
27 import java.net.URLDecoder;
28 import java.util.Collections;
29 import java.util.List;
30
31 import javax.servlet.ServletContext;
32 import javax.servlet.ServletException;
33 import javax.servlet.http.HttpServletRequest;
34 import javax.servlet.http.HttpServletResponse;
35 import javax.servlet.http.HttpSession;
36
37 import net.bull.javamelody.Parameter;
38 import net.bull.javamelody.SessionListener;
39 import net.bull.javamelody.internal.common.HttpParameter;
40 import net.bull.javamelody.internal.common.HttpPart;
41 import net.bull.javamelody.internal.common.I18N;
42 import net.bull.javamelody.internal.common.InputOutput;
43 import net.bull.javamelody.internal.common.LOG;
44 import net.bull.javamelody.internal.common.Parameters;
45 import net.bull.javamelody.internal.model.Action;
46 import net.bull.javamelody.internal.model.Collector;
47 import net.bull.javamelody.internal.model.CollectorServer;
48 import net.bull.javamelody.internal.model.HsErrPid;
49 import net.bull.javamelody.internal.model.JRobin;
50 import net.bull.javamelody.internal.model.JavaInformations;
51 import net.bull.javamelody.internal.model.MBeans;
52 import net.bull.javamelody.internal.model.MavenArtifact;
53 import net.bull.javamelody.internal.model.Range;
54 import net.bull.javamelody.internal.model.TransportFormat;
55
56 /**
57  * Contrôleur au sens MVC de l'ihm de monitoring.
58  * @author Emeric Vernat
59  */

60 public class MonitoringController {
61     static {
62         boolean webXmlExists = false;
63         boolean pomXmlExists = false;
64         try {
65             final InputStream webXmlAsStream = getWebXmlAsStream();
66             if (webXmlAsStream != null) {
67                 webXmlAsStream.close();
68                 webXmlExists = true;
69             }
70             final InputStream pomXmlAsStream = MavenArtifact.getWebappPomXmlAsStream();
71             if (pomXmlAsStream != null) {
72                 pomXmlAsStream.close();
73                 pomXmlExists = true;
74             }
75         } catch (final IOException e) {
76             LOG.warn(e.toString(), e);
77         }
78         JavaInformations.setWebXmlExistsAndPomXmlExists(webXmlExists, pomXmlExists);
79     }
80
81     private static final boolean GZIP_COMPRESSION_DISABLED = Parameter.GZIP_COMPRESSION_DISABLED
82             .getValueAsBoolean();
83     private static final boolean CSRF_PROTECTION_ENABLED = Parameter.CSRF_PROTECTION_ENABLED
84             .getValueAsBoolean();
85
86     private final HttpCookieManager httpCookieManager = new HttpCookieManager();
87     private final Collector collector;
88     private final CollectorServer collectorServer;
89     private String messageForReport;
90     private String anchorNameForRedirect;
91
92     public MonitoringController(Collector collector, CollectorServer collectorServer) {
93         super();
94         assert collector != null;
95         this.collector = collector;
96         this.collectorServer = collectorServer;
97     }
98
99     public String executeActionIfNeeded(HttpServletRequest httpRequest) throws IOException {
100         assert httpRequest != null;
101         final String actionParameter = HttpParameter.ACTION.getParameterFrom(httpRequest);
102         if (actionParameter != null) {
103             if (CSRF_PROTECTION_ENABLED) {
104                 checkCsrfToken(httpRequest);
105             }
106             try {
107                 // langue préférée du navigateur, getLocale ne peut être null
108                 I18N.bindLocale(httpRequest.getLocale());
109                 // par sécurité
110                 final Action action = Action.valueOfIgnoreCase(actionParameter);
111                 if (action != Action.CLEAR_COUNTER && action != Action.MAIL_TEST) {
112                     Action.checkSystemActionsEnabled();
113                 }
114                 final HttpSession currentSession = httpRequest.getSession(false);
115                 final String counterName = HttpParameter.COUNTER.getParameterFrom(httpRequest);
116                 final String sessionId = HttpParameter.SESSION_ID.getParameterFrom(httpRequest);
117                 final String threadId = HttpParameter.THREAD_ID.getParameterFrom(httpRequest);
118                 final String jobId = HttpParameter.JOB_ID.getParameterFrom(httpRequest);
119                 final String cacheId = HttpParameter.CACHE_ID.getParameterFrom(httpRequest);
120                 final String cacheKey = HttpParameter.CACHE_KEY.getParameterFrom(httpRequest);
121                 messageForReport = action.execute(collector, collectorServer, currentSession,
122                         counterName, sessionId, threadId, jobId, cacheId, cacheKey);
123                 if (collector.getCounterByName(counterName) != null) {
124                     // on ne veut pas d'injection de faux counterName dans l'ancre
125                     anchorNameForRedirect = action.getContextName(counterName);
126                 } else {
127                     anchorNameForRedirect = action.getContextName(null);
128                 }
129                 return messageForReport;
130             } finally {
131                 I18N.unbindLocale();
132             }
133         }
134         return null;
135     }
136
137     public static void checkCsrfToken(HttpServletRequest httpRequest) {
138         final String token = HttpParameter.TOKEN.getParameterFrom(httpRequest);
139         if (token == null) {
140             throw new IllegalArgumentException("csrf token missing");
141         }
142         final HttpSession session = httpRequest.getSession(false);
143         if (session == null
144                 || !token.equals(session.getAttribute(SessionListener.CSRF_TOKEN_SESSION_NAME))) {
145             throw new IllegalArgumentException("invalid token parameter");
146         }
147     }
148
149     public void doActionIfNeededAndReport(HttpServletRequest httpRequest,
150             HttpServletResponse httpResponse, ServletContext servletContext)
151             throws IOException, ServletException {
152         executeActionIfNeeded(httpRequest);
153
154         // javaInformations doit être réinstanciée et doit être après executeActionIfNeeded
155         // pour avoir des informations à jour
156         final JavaInformations javaInformations;
157         if (isJavaInformationsNeeded(httpRequest)) {
158             javaInformations = new JavaInformations(servletContext, true);
159         } else {
160             javaInformations = null;
161         }
162
163         doReport(httpRequest, httpResponse, Collections.singletonList(javaInformations));
164     }
165
166     public void doReport(HttpServletRequest httpRequest, HttpServletResponse httpResponse,
167             List<JavaInformations> javaInformationsList) throws IOException, ServletException {
168         assert httpRequest != null;
169         assert httpResponse != null;
170         assert javaInformationsList != null;
171
172         final String resource = HttpParameter.RESOURCE.getParameterFrom(httpRequest);
173         if (resource != null) {
174             doResource(httpResponse, resource);
175             return;
176         }
177
178         // dans tous les cas sauf resource,
179         // il n'y a pas de cache navigateur (sur la page html, les courbes ou le flux sérialisé)
180         noCache(httpResponse);
181
182         try {
183             // langue préférée du navigateur, getLocale ne peut être null
184             I18N.bindLocale(httpRequest.getLocale());
185             // session http s'il y en a une
186             SessionListener.bindSession(httpRequest.getSession(false));
187
188             final String part = HttpParameter.PART.getParameterFrom(httpRequest);
189             final String graph = HttpParameter.GRAPH.getParameterFrom(httpRequest);
190             if (part == null && graph != null) {
191                 final Range range = httpCookieManager.getRange(httpRequest, httpResponse);
192                 doGraph(httpRequest, httpResponse, range, graph);
193             } else if (HttpPart.WEB_XML.isPart(httpRequest)) {
194                 doWebXml(httpResponse);
195             } else if (HttpPart.POM_XML.isPart(httpRequest)) {
196                 doPomXml(httpResponse);
197             } else if (HttpPart.JNLP.isPart(httpRequest)) {
198                 final Range range = httpCookieManager.getRange(httpRequest, httpResponse);
199                 doJnlp(httpRequest, httpResponse, range);
200             } else if (HttpPart.CRASHES.isPart(httpRequest)
201                     && HttpParameter.PATH.getParameterFrom(httpRequest) != null) {
202                 final String path = HttpParameter.PATH.getParameterFrom(httpRequest);
203                 doHsErrPid(httpResponse, javaInformationsList, path);
204             } else if (HttpParameter.REPORT.getParameterFrom(httpRequest) != null) {
205                 final String reportName = URLDecoder
206                         .decode(HttpParameter.REPORT.getParameterFrom(httpRequest), "UTF-8");
207                 doCustomReport(httpRequest, httpResponse, reportName);
208             } else {
209                 doReportCore(httpRequest, httpResponse, javaInformationsList);
210             }
211         } finally {
212             I18N.unbindLocale();
213             SessionListener.unbindSession();
214         }
215     }
216
217     private void doReportCore(HttpServletRequest httpRequest, HttpServletResponse httpResponse,
218             List<JavaInformations> javaInformationsList) throws IOException {
219         final String format = HttpParameter.FORMAT.getParameterFrom(httpRequest);
220         if (HttpPart.LAST_VALUE.isPart(httpRequest)
221                 && !TransportFormat.isATransportFormat(format)) {
222             doLastValue(httpResponse, HttpParameter.GRAPH.getParameterFrom(httpRequest));
223         } else if (HttpParameter.JMX_VALUE.getParameterFrom(httpRequest) != null
224                 && !TransportFormat.isATransportFormat(format)) {
225             // par sécurité
226             Action.checkSystemActionsEnabled();
227             doJmxValue(httpResponse, HttpParameter.JMX_VALUE.getParameterFrom(httpRequest));
228         } else if (format == null || "html".equalsIgnoreCase(format)
229                 || HtmlController.HTML_BODY_FORMAT.equalsIgnoreCase(format)) {
230             doCompressedHtml(httpRequest, httpResponse, javaInformationsList);
231         } else if ("pdf".equalsIgnoreCase(format)) {
232             final PdfController pdfController = new PdfController(collector, collectorServer);
233             pdfController.doPdf(httpRequest, httpResponse, javaInformationsList);
234         } else if ("prometheus".equalsIgnoreCase(format)) {
235             final boolean includeLastValue = Boolean
236                     .parseBoolean(httpRequest.getParameter("includeLastValue"));
237             doPrometheus(httpResponse, javaInformationsList, includeLastValue);
238         } else {
239             doCompressedSerializable(httpRequest, httpResponse, javaInformationsList);
240         }
241     }
242
243     public void doPrometheus(HttpServletResponse httpResponse,
244             List<JavaInformations> javaInformationsList, final boolean includeLastValue)
245             throws IOException {
246         httpResponse.setContentType("text/plain; version=0.0.4;charset=UTF-8");
247         final PrometheusController prometheusController = new PrometheusController(
248                 javaInformationsList, collector, httpResponse.getWriter());
249         prometheusController.report(includeLastValue);
250     }
251
252     public static void noCache(HttpServletResponse httpResponse) {
253         httpResponse.addHeader("Cache-Control""no-cache");
254         httpResponse.addHeader("Pragma""no-cache");
255         httpResponse.addHeader("Expires""-1");
256     }
257
258     public void addPdfContentTypeAndDisposition(HttpServletRequest httpRequest,
259             HttpServletResponse httpResponse) {
260         // méthode utilisée dans le monitoring Jenkins
261         new PdfController(collector, collectorServer).addPdfContentTypeAndDisposition(httpRequest,
262                 httpResponse);
263     }
264
265     private void doCompressedHtml(HttpServletRequest httpRequest, HttpServletResponse httpResponse,
266             List<JavaInformations> javaInformationsList) throws IOException {
267         if (CSRF_PROTECTION_ENABLED && SessionListener.getCurrentSession() == null) {
268             SessionListener.bindSession(httpRequest.getSession());
269         }
270         final HtmlController htmlController = new HtmlController(collector, collectorServer,
271                 messageForReport, anchorNameForRedirect);
272         if (isCompressionSupported(httpRequest, httpResponse)) {
273             // comme la page html peut être volumineuse avec toutes les requêtes sql et http
274             // on compresse le flux de réponse en gzip à partir de 4 Ko
275             // (à moins que la compression http ne soit pas supportée
276             // comme par ex s'il y a un proxy squid qui ne supporte que http 1.0)
277             final CompressionServletResponseWrapper wrappedResponse = new CompressionServletResponseWrapper(
278                     httpResponse, 4096);
279             try {
280                 htmlController.doHtml(httpRequest, wrappedResponse, javaInformationsList);
281             } finally {
282                 wrappedResponse.finishResponse();
283             }
284         } else {
285             htmlController.doHtml(httpRequest, httpResponse, javaInformationsList);
286         }
287     }
288
289     public void writeHtmlToLastShutdownFile() {
290         new HtmlController(collector, collectorServer, messageForReport, anchorNameForRedirect)
291                 .writeHtmlToLastShutdownFile();
292     }
293
294     static BufferedWriter getWriter(HttpServletResponse httpResponse) throws IOException {
295         return HtmlController.getWriter(httpResponse);
296     }
297
298     private void doCompressedSerializable(HttpServletRequest httpRequest,
299             HttpServletResponse httpResponse, List<JavaInformations> javaInformationsList)
300             throws IOException {
301         final String part = HttpParameter.PART.getParameterFrom(httpRequest);
302         if (HtmlController.isLocalCollectNeeded(part)
303                 && HttpParameter.PERIOD.getParameterFrom(httpRequest) != null) {
304             // pour l'ihm swing, on fait une collecte, pour que les courbes
305             // et les compteurs par jour soit à jour avec les dernières requêtes
306             collector.collectLocalContextWithoutErrors();
307         }
308         Serializable serializable;
309         try {
310             final SerializableController serializableController = new SerializableController(
311                     collector);
312             serializable = serializableController.createSerializable(httpRequest,
313                     javaInformationsList, messageForReport);
314         } catch (final Throwable t) { // NOPMD
315             serializable = t;
316         }
317         doCompressedSerializable(httpRequest, httpResponse, serializable);
318     }
319
320     public void doCompressedSerializable(HttpServletRequest httpRequest,
321             HttpServletResponse httpResponse, Serializable serializable) throws IOException {
322         // note: normalement la compression est supportée ici car s'il s'agit du serveur de collecte,
323         // LabradorRetriever appelle connection.setRequestProperty("Accept-Encoding""gzip");
324         final SerializableController serializableController = new SerializableController(collector);
325         if (isCompressionSupported(httpRequest, httpResponse)) {
326             // comme les données peuvent être volumineuses avec toutes les requêtes sql et http
327             // et les threads on compresse le flux de réponse en gzip à partir de 50 Ko
328             // (à moins que la compression http ne soit pas supportée
329             // comme par ex s'il y a un proxy squid qui ne supporte que http 1.0)
330             final CompressionServletResponseWrapper wrappedResponse = new CompressionServletResponseWrapper(
331                     httpResponse, 50 * 1024);
332             try {
333                 serializableController.doSerializable(httpRequest, wrappedResponse, serializable);
334             } finally {
335                 wrappedResponse.finishResponse();
336             }
337         } else {
338             serializableController.doSerializable(httpRequest, httpResponse, serializable);
339         }
340     }
341
342     public static void doResource(HttpServletResponse httpResponse, String resource)
343             throws IOException {
344         // on enlève tout ".." dans le paramètre par sécurité
345         final String localResource = Parameters.getResourcePath(resource.replace(".."""));
346         final InputStream resourceAsStream = MonitoringController.class
347                 .getResourceAsStream(localResource);
348         if (resourceAsStream == null) {
349             httpResponse.sendError(HttpServletResponse.SC_NOT_FOUND, "Resource not found");
350             return;
351         }
352         try {
353             addHeadersForResource(httpResponse, localResource);
354
355             final OutputStream out = httpResponse.getOutputStream();
356             InputOutput.pump(resourceAsStream, out);
357         } finally {
358             resourceAsStream.close();
359         }
360     }
361
362     public static void addHeadersForResource(HttpServletResponse httpResponse, String resource) {
363         httpResponse.addHeader("Cache-Control""max-age=3600"); // cache navigateur 1h
364         // un contentType est nécessaire sinon la css n'est pas prise en compte
365         // sous firefox sur un serveur distant
366         if (resource.endsWith(".css")) {
367             httpResponse.setContentType("text/css");
368         } else {
369             final String mimeType = Parameters.getServletContext().getMimeType(resource);
370             // mimeType peut être null, cf issue 69
371             if (mimeType != null) {
372                 httpResponse.setContentType(mimeType);
373             }
374         }
375     }
376
377     private void doGraph(HttpServletRequest httpRequest, HttpServletResponse httpResponse,
378             Range range, String graphName) throws IOException {
379         final JRobin jrobin = collector.getJRobin(graphName);
380         if (jrobin != null) {
381             final String format = HttpParameter.FORMAT.getParameterFrom(httpRequest);
382             if ("xml".equals(format)) {
383                 // any charset is ok
384                 httpResponse.setContentType("text/xml; charset=UTF-8");
385                 if (isCompressionSupported(httpRequest, httpResponse)) {
386                     final CompressionServletResponseWrapper wrappedResponse = new CompressionServletResponseWrapper(
387                             httpResponse, 4096);
388                     try {
389                         jrobin.dumpXml(wrappedResponse.getOutputStream(), range);
390                     } finally {
391                         wrappedResponse.finishResponse();
392                     }
393                 } else {
394                     jrobin.dumpXml(httpResponse.getOutputStream(), range);
395                 }
396             } else if ("txt".equals(format)) {
397                 // any charset is ok
398                 httpResponse.setContentType("text/plain; charset=UTF-8");
399                 final String txt = jrobin.dumpTxt(range);
400                 httpResponse.setContentLength(txt.length());
401                 httpResponse.getWriter().write(txt);
402             } else {
403                 final int width = Math.min(
404                         Integer.parseInt(HttpParameter.WIDTH.getParameterFrom(httpRequest)), 1600);
405                 final int height = Math.min(
406                         Integer.parseInt(HttpParameter.HEIGHT.getParameterFrom(httpRequest)), 1600);
407                 final String max = HttpParameter.MAX.getParameterFrom(httpRequest);
408                 final boolean maxHidden = max != null && !Boolean.parseBoolean(max);
409                 final byte[] img = jrobin.graph(range, width, height, maxHidden);
410                 // png comme indiqué dans la classe jrobin
411                 httpResponse.setContentType("image/png");
412                 httpResponse.setContentLength(img.length);
413                 final String fileName = graphName + ".png";
414                 // encoding des CRLF pour http://en.wikipedia.org/wiki/HTTP_response_splitting
415                 httpResponse.addHeader("Content-Disposition",
416                         "inline;filename=" + fileName.replace('\n', '_').replace('\r', '_'));
417                 httpResponse.getOutputStream().write(img);
418                 httpResponse.flushBuffer();
419             }
420         }
421     }
422
423     // part=lastValue&graph=x,y,z sera utilisé par munin notamment
424     private void doLastValue(HttpServletResponse httpResponse, String graphName)
425             throws IOException {
426         httpResponse.setContentType("text/plain");
427         boolean first = true;
428         for (final String graph : graphName.split(",")) {
429             final JRobin jrobin = collector.getJRobin(graph);
430             final double lastValue;
431             if (jrobin == null) {
432                 lastValue = -1;
433             } else {
434                 lastValue = jrobin.getLastValue();
435             }
436             if (first) {
437                 first = false;
438             } else {
439                 httpResponse.getWriter().write(",");
440             }
441             httpResponse.getWriter().write(String.valueOf(lastValue));
442         }
443         httpResponse.flushBuffer();
444     }
445
446     // jmxValue=x|y|z pourra aussi être utilisé par munin notamment
447     private void doJmxValue(HttpServletResponse httpResponse, String jmxValueParameter)
448             throws IOException {
449         httpResponse.setContentType("text/plain");
450         httpResponse.getWriter().write(MBeans.getConvertedAttributes(jmxValueParameter));
451         httpResponse.flushBuffer();
452     }
453
454     private void doWebXml(HttpServletResponse httpResponse) throws IOException {
455         // par sécurité
456         Action.checkSystemActionsEnabled();
457         final OutputStream out = httpResponse.getOutputStream();
458         httpResponse.setContentType("application/xml");
459         httpResponse.addHeader("Content-Disposition""inline;filename=web.xml");
460         final InputStream in = getWebXmlAsStream();
461         if (in != null) {
462             try {
463                 InputOutput.pump(in, out);
464             } finally {
465                 in.close();
466             }
467         }
468     }
469
470     private void doPomXml(HttpServletResponse httpResponse) throws IOException {
471         // par sécurité
472         Action.checkSystemActionsEnabled();
473         final OutputStream out = httpResponse.getOutputStream();
474         httpResponse.setContentType("application/xml");
475         httpResponse.addHeader("Content-Disposition""inline;filename=pom.xml");
476         final InputStream in = MavenArtifact.getWebappPomXmlAsStream();
477         if (in != null) {
478             try {
479                 InputOutput.pump(in, out);
480             } finally {
481                 in.close();
482             }
483         }
484     }
485
486     private static InputStream getWebXmlAsStream() {
487         final InputStream webXml = Parameters.getServletContext()
488                 .getResourceAsStream("/WEB-INF/web.xml");
489         if (webXml == null) {
490             return null;
491         }
492         return new BufferedInputStream(webXml);
493     }
494
495     private void doJnlp(HttpServletRequest httpRequest, HttpServletResponse httpResponse,
496             Range range) throws IOException {
497         httpResponse.setContentType("application/x-java-jnlp-file");
498         final String codebase = httpRequest.getRequestURL().toString();
499         final String cookies = httpCookieManager.getCookiesAsString(httpRequest);
500
501         new JnlpPage(collector, collectorServer, codebase, cookies, range, httpResponse.getWriter())
502                 .toJnlp();
503     }
504
505     private void doHsErrPid(HttpServletResponse httpResponse,
506             List<JavaInformations> javaInformationsList, String path) throws IOException {
507         for (final JavaInformations javaInformations : javaInformationsList) {
508             for (final HsErrPid hsErrPid : javaInformations.getHsErrPidList()) {
509                 if (hsErrPid.getFile().replace('\\', '/').equals(path) && new File(path).exists()) {
510                     final File file = new File(path);
511                     final OutputStream out = httpResponse.getOutputStream();
512                     httpResponse.setContentType("text/plain");
513                     // attachment et non inline pour proposer le téléchargement et non l'affichage direct dans le navigateur
514                     httpResponse.addHeader("Content-Disposition",
515                             "attachment;filename=" + file.getName());
516                     InputOutput.pumpFromFile(file, out);
517                     return;
518                 }
519             }
520         }
521         // si le fichier demandé n'est pas dans la liste des fichiers hs_err_pid*.log,
522         // alors il n'existe plus ou alors le fichier demandé est une invention malveillante
523         httpResponse.sendError(HttpServletResponse.SC_NOT_FOUND);
524     }
525
526     private static void doCustomReport(HttpServletRequest httpRequest,
527             HttpServletResponse httpResponse, String reportName)
528             throws ServletException, IOException {
529         final String customReportPath = Parameters.getParameterValueByName(reportName);
530         if (!customReportPath.isEmpty() && customReportPath.charAt(0) == '/'
531                 && Parameters.getServletContext().getRequestDispatcher(customReportPath) != null) {
532             Parameters.getServletContext().getRequestDispatcher(customReportPath)
533                     .forward(httpRequest, httpResponse);
534         } else {
535             httpResponse.sendRedirect(customReportPath);
536         }
537     }
538
539     static boolean isCompressionSupported(HttpServletRequest httpRequest,
540             HttpServletResponse httpResponse) {
541         // GZIP_COMPRESSION_DISABLED checks if it is the Jenkins plugin
542         // (another filter may already compress the stream, in which case we must not compress a second time,
543         // in particular for org.kohsuke.stapler.compression.CompressionFilter
544         // from https://github.com/stapler/stapler in Jenkins v1.470+ (issue JENKINS-14050)
545         // et on teste CompressionServletResponseWrapper car il peut déjà être mis dans le serveur de collecte
546         // par CollectorController.doCompressedPart
547         if (GZIP_COMPRESSION_DISABLED
548                 || httpResponse instanceof CompressionServletResponseWrapper) {
549             return false;
550         }
551         // est-ce que le navigateur déclare accepter la compression gzip ?
552         boolean supportCompression = false;
553         final List<String> acceptEncodings = Collections
554                 .list(httpRequest.getHeaders("Accept-Encoding"));
555         for (final String name : acceptEncodings) {
556             if (name.contains("gzip")) {
557                 supportCompression = true;
558                 break;
559             }
560         }
561         return supportCompression;
562     }
563
564     public static boolean isJavaInformationsNeeded(HttpServletRequest httpRequest) {
565         if (HttpParameter.RESOURCE.getParameterFrom(httpRequest) == null
566                 && HttpParameter.GRAPH.getParameterFrom(httpRequest) == null) {
567             final String part = HttpParameter.PART.getParameterFrom(httpRequest);
568             return part == null || HttpPart.CURRENT_REQUESTS.getName().equals(part)
569                     || HttpPart.DEFAULT_WITH_CURRENT_REQUESTS.getName().equals(part)
570                     || HttpPart.JVM.getName().equals(part)
571                     || HttpPart.THREADS.getName().equals(part)
572                     || HttpPart.THREADS_DUMP.getName().equals(part)
573                     || HttpPart.CRASHES.getName().equals(part);
574         }
575         return false;
576     }
577 }
578