View Javadoc
1   /*
2    * Licensed under the GPL License. You may not use this file except in compliance with the License.
3    * You may obtain a copy of the License at
4    *
5    *   https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
6    *
7    * THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
8    * WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
9    * PURPOSE.
10   */
11  package psiprobe.controllers.jsp;
12  
13  import jakarta.servlet.ServletConfig;
14  import jakarta.servlet.ServletContext;
15  import jakarta.servlet.http.HttpServletRequest;
16  import jakarta.servlet.http.HttpServletResponse;
17  
18  import java.io.InputStream;
19  
20  import org.apache.catalina.Context;
21  import org.apache.jasper.EmbeddedServletOptions;
22  import org.apache.jasper.Options;
23  import org.slf4j.Logger;
24  import org.slf4j.LoggerFactory;
25  import org.springframework.beans.factory.annotation.Value;
26  import org.springframework.stereotype.Controller;
27  import org.springframework.web.bind.ServletRequestUtils;
28  import org.springframework.web.bind.annotation.RequestMapping;
29  import org.springframework.web.servlet.ModelAndView;
30  
31  import psiprobe.Utils;
32  import psiprobe.controllers.AbstractContextHandlerController;
33  import psiprobe.model.jsp.Item;
34  import psiprobe.model.jsp.Summary;
35  
36  /**
37   * The Class ViewSourceController.
38   */
39  @Controller
40  public class ViewSourceController extends AbstractContextHandlerController {
41  
42    /** The Constant logger. */
43    private static final Logger logger = LoggerFactory.getLogger(ViewSourceController.class);
44  
45    @RequestMapping(path = "/app/viewsource.htm")
46    @Override
47    public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response)
48        throws Exception {
49      return super.handleRequest(request, response);
50    }
51  
52    @Override
53    protected ModelAndView handleContext(String contextName, Context context,
54        HttpServletRequest request, HttpServletResponse response) throws Exception {
55  
56      String jspName = ServletRequestUtils.getStringParameter(request, "source");
57      boolean highlight = ServletRequestUtils.getBooleanParameter(request, "highlight", true);
58      Summary summary = (Summary) (request.getSession(false) != null
59          ? request.getSession(false).getAttribute(DisplayJspController.SUMMARY_ATTRIBUTE)
60          : null);
61  
62      if (jspName != null && summary != null && contextName.equals(summary.getName())) {
63  
64        Item item = summary.getItems().get(jspName);
65  
66        if (item != null) {
67          // replace "\" with "/"
68          jspName = jspName.replace('\\', '/');
69  
70          // remove cheeky "../" from the path to avoid exploits
71          while (jspName.contains("../")) {
72            jspName = jspName.replace("../", "");
73          }
74  
75          if (getContainerWrapper().getTomcatContainer().resourceExists(jspName, context)) {
76            ServletContext sctx = context.getServletContext();
77            ServletConfig scfg = (ServletConfig) context.findChild("jsp");
78            Options opt = new EmbeddedServletOptions(scfg, sctx);
79            String descriptorPageEncoding =
80                opt.getJspConfig().findJspProperty(jspName).getPageEncoding();
81  
82            if (descriptorPageEncoding != null && descriptorPageEncoding.length() > 0) {
83              item.setEncoding(descriptorPageEncoding);
84            } else {
85  
86              /*
87               * we have to read the JSP twice, once to figure out the content encoding the second
88               * time to read the actual content using the correct encoding
89               */
90              try (InputStream encodedStream =
91                  getContainerWrapper().getTomcatContainer().getResourceStream(jspName, context)) {
92                item.setEncoding(Utils.getJspEncoding(encodedStream));
93              }
94            }
95            try (InputStream jspStream =
96                getContainerWrapper().getTomcatContainer().getResourceStream(jspName, context)) {
97              if (highlight) {
98                request.setAttribute("highlightedContent",
99                    Utils.highlightStream(jspName, jspStream, "xhtml", item.getEncoding()));
100             } else {
101               request.setAttribute("content", Utils.readStream(jspStream, item.getEncoding()));
102             }
103           }
104 
105         } else {
106           logger.error("{} does not exist", jspName);
107         }
108 
109         request.setAttribute("item", item);
110 
111       } else {
112         logger.error("jsp name passed is not in the summary, ignored");
113       }
114     } else {
115       if (jspName == null) {
116         logger.error("Passed empty 'source' parameter");
117       }
118       if (summary == null) {
119         logger.error("Session has expired or there is no summary");
120       }
121     }
122     return new ModelAndView(getViewName());
123   }
124 
125   @Value("view_jsp_source")
126   @Override
127   public void setViewName(String viewName) {
128     super.setViewName(viewName);
129   }
130 
131 }