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  import jakarta.servlet.http.HttpSession;
18  
19  import java.io.InputStream;
20  
21  import org.apache.catalina.Context;
22  import org.apache.jasper.EmbeddedServletOptions;
23  import org.apache.jasper.Options;
24  import org.slf4j.Logger;
25  import org.slf4j.LoggerFactory;
26  import org.springframework.beans.factory.annotation.Value;
27  import org.springframework.stereotype.Controller;
28  import org.springframework.web.bind.ServletRequestUtils;
29  import org.springframework.web.bind.annotation.RequestMapping;
30  import org.springframework.web.servlet.ModelAndView;
31  
32  import psiprobe.Utils;
33  import psiprobe.controllers.AbstractContextHandlerController;
34  import psiprobe.model.jsp.Item;
35  import psiprobe.model.jsp.Summary;
36  
37  /**
38   * The Class ViewSourceController.
39   */
40  @Controller
41  public class ViewSourceController extends AbstractContextHandlerController {
42  
43    /** The Constant logger. */
44    private static final Logger logger = LoggerFactory.getLogger(ViewSourceController.class);
45  
46    @RequestMapping(path = "/app/viewsource.htm")
47    @Override
48    public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response)
49        throws Exception {
50      return super.handleRequest(request, response);
51    }
52  
53    @Override
54    protected ModelAndView handleContext(String contextName, Context context,
55        HttpServletRequest request, HttpServletResponse response) throws Exception {
56  
57      String jspName = ServletRequestUtils.getStringParameter(request, "source");
58      boolean highlight = ServletRequestUtils.getBooleanParameter(request, "highlight", true);
59      HttpSession session = request.getSession(false);
60      Summary summary = session == null ? null
61          : (Summary) session.getAttribute(DisplayJspController.SUMMARY_ATTRIBUTE);
62  
63      if (jspName != null && summary != null && contextName.equals(summary.getName())) {
64  
65        Item item = summary.getItems().get(jspName);
66  
67        if (item != null) {
68          // replace "\" with "/"
69          jspName = jspName.replace('\\', '/');
70  
71          // remove cheeky "../" from the path to avoid exploits
72          while (jspName.contains("../")) {
73            jspName = jspName.replace("../", "");
74          }
75  
76          if (containerWrapper.getTomcatContainer().resourceExists(jspName, context)) {
77            ServletContext sctx = context.getServletContext();
78            ServletConfig scfg = (ServletConfig) context.findChild("jsp");
79            Options opt = new EmbeddedServletOptions(scfg, sctx);
80            String descriptorPageEncoding =
81                opt.getJspConfig().findJspProperty(jspName).getPageEncoding();
82  
83            if (descriptorPageEncoding != null && !descriptorPageEncoding.isEmpty()) {
84              item.setEncoding(descriptorPageEncoding);
85            } else {
86  
87              /*
88               * we have to read the JSP twice, once to figure out the content encoding the second
89               * time to read the actual content using the correct encoding
90               */
91              try (InputStream encodedStream =
92                  containerWrapper.getTomcatContainer().getResourceStream(jspName, context)) {
93                item.setEncoding(Utils.getJspEncoding(encodedStream));
94              }
95            }
96            try (InputStream jspStream =
97                containerWrapper.getTomcatContainer().getResourceStream(jspName, context)) {
98              if (highlight) {
99                request.setAttribute("highlightedContent",
100                   Utils.highlightStream(jspName, jspStream, "xhtml", item.getEncoding()));
101             } else {
102               request.setAttribute("content", Utils.readStream(jspStream, item.getEncoding()));
103             }
104           }
105 
106         } else {
107           logger.error("{} does not exist", jspName);
108         }
109 
110         request.setAttribute("item", item);
111 
112       } else {
113         logger.error("jsp name passed is not in the summary, ignored");
114       }
115     } else {
116       if (jspName == null) {
117         logger.error("Passed empty 'source' parameter");
118       }
119       if (summary == null) {
120         logger.error("Session has expired or there is no summary");
121       }
122     }
123     return new ModelAndView(getViewName());
124   }
125 
126   @Value("view_jsp_source")
127   @Override
128   public void setViewName(String viewName) {
129     super.setViewName(viewName);
130   }
131 
132 }