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