Advertisement
Guest User

Untitled

a guest
Mar 24th, 2017
78
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 19.94 KB | None | 0 0
  1. /*
  2. * Licensed to the Apache Software Foundation (ASF) under one
  3. * or more contributor license agreements. See the NOTICE file
  4. * distributed with this work for additional information
  5. * regarding copyright ownership. The ASF licenses this file
  6. * to you under the Apache License, Version 2.0 (the
  7. * "License"); you may not use this file except in compliance
  8. * with the License. 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,
  13. * software distributed under the License is distributed on an
  14. * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  15. * KIND, either express or implied. See the License for the
  16. * specific language governing permissions and limitations
  17. * under the License.
  18. */
  19. package org.apache.sling.engine.impl;
  20.  
  21. import static org.apache.sling.api.SlingConstants.ERROR_SERVLET_NAME;
  22.  
  23. import java.io.IOException;
  24. import java.io.OutputStream;
  25. import java.io.OutputStreamWriter;
  26. import java.io.PrintWriter;
  27. import java.io.Writer;
  28. import java.security.AccessControlException;
  29. import javax.servlet.FilterChain;
  30. import javax.servlet.Servlet;
  31. import javax.servlet.ServletException;
  32. import javax.servlet.ServletRequest;
  33. import javax.servlet.ServletResponse;
  34. import javax.servlet.UnavailableException;
  35. import javax.servlet.http.HttpServletRequest;
  36. import javax.servlet.http.HttpServletResponse;
  37. import javax.servlet.http.HttpServletResponseWrapper;
  38. import javax.jcr.Session;
  39. import org.apache.sling.api.SlingException;
  40. import org.apache.sling.api.SlingHttpServletRequest;
  41. import org.apache.sling.api.SlingHttpServletResponse;
  42. import org.apache.sling.api.SlingServletException;
  43. import org.apache.sling.api.request.RequestPathInfo;
  44. import org.apache.sling.api.resource.Resource;
  45. import org.apache.sling.api.resource.ResourceNotFoundException;
  46. import org.apache.sling.api.resource.ResourceResolver;
  47. import org.apache.sling.api.servlets.ServletResolver;
  48. import org.apache.sling.api.wrappers.SlingHttpServletResponseWrapper;
  49. import org.apache.sling.commons.metrics.Histogram;
  50. import org.apache.sling.commons.metrics.MetricsService;
  51. import org.apache.sling.engine.SlingRequestProcessor;
  52. import org.apache.sling.engine.impl.filter.AbstractSlingFilterChain;
  53. import org.apache.sling.engine.impl.filter.FilterHandle;
  54. import org.apache.sling.engine.impl.filter.RequestSlingFilterChain;
  55. import org.apache.sling.engine.impl.filter.ServletFilterManager;
  56. import org.apache.sling.engine.impl.filter.ServletFilterManager.FilterChainType;
  57. import org.apache.sling.engine.impl.filter.SlingComponentFilterChain;
  58. import org.apache.sling.engine.impl.parameters.ParameterSupport;
  59. import org.apache.sling.engine.impl.request.ContentData;
  60. import org.apache.sling.engine.impl.request.RequestData;
  61. import org.apache.sling.engine.impl.request.RequestHistoryConsolePlugin;
  62. import org.apache.sling.engine.servlets.ErrorHandler;
  63. import org.slf4j.Logger;
  64. import org.slf4j.LoggerFactory;
  65.  
  66.  
  67. public class SlingRequestProcessorImpl implements SlingRequestProcessor {
  68.  
  69. /** default log */
  70. private final Logger log = LoggerFactory.getLogger(SlingRequestProcessorImpl.class);
  71.  
  72. // used fields ....
  73.  
  74. private MetricsService metricsService;
  75. private Histogram histogram;
  76.  
  77.  
  78. SlingRequestProcessorImpl (MetricsService metricsService) {
  79. this.metricsService = metricsService;
  80. histogram = metricsService.histogram("engine.main.histogram-Filter-in-Chain");
  81. }
  82.  
  83. private final DefaultErrorHandler errorHandler = new DefaultErrorHandler();
  84.  
  85. private ServletResolver servletResolver;
  86.  
  87. private ServletFilterManager filterManager;
  88.  
  89. private RequestProcessorMBeanImpl mbean;
  90.  
  91. // ---------- helper setters
  92.  
  93. void setServerInfo(final String serverInfo) {
  94. errorHandler.setServerInfo(serverInfo);
  95. }
  96.  
  97. void setErrorHandler(final ErrorHandler eh) {
  98. errorHandler.setDelegate(eh);
  99. }
  100.  
  101. void unsetErrorHandler(final ErrorHandler eh) {
  102. if (errorHandler.getDelegate() == eh) {
  103. errorHandler.setDelegate(null);
  104. }
  105. }
  106.  
  107. void setServletResolver(final ServletResolver servletResolver) {
  108. this.servletResolver = servletResolver;
  109. }
  110.  
  111. void unsetServletResolver(final ServletResolver servletResolver) {
  112. if (this.servletResolver == servletResolver) {
  113. this.servletResolver = null;
  114. }
  115. }
  116.  
  117. void setFilterManager(final ServletFilterManager filterManager) {
  118. this.filterManager = filterManager;
  119. }
  120.  
  121. void setMBean(final RequestProcessorMBeanImpl mbean) {
  122. this.mbean = mbean;
  123. }
  124.  
  125. /**
  126. * Wrap an HttpServletRequest to generate metrics
  127. * mesuring the request per second of each HTTP
  128. * request to a session and the authentication Type*/
  129.  
  130. private void getSessionUser(SlingHttpServletRequest request){
  131.  
  132. Resource resource = request.getResource();
  133. if(resource != null){
  134. String sessionUser = resource.adaptTo(Session.class).getUserID();
  135. if(sessionUser == null){
  136. metricsService.counter("engine.main.count-Authenticated-Request").increment();
  137. } else {
  138. metricsService.counter("engine.main.count-Anonymous-Request").increment();
  139. }
  140. }
  141. }
  142.  
  143. /**
  144. * This method is directly called by the Sling main servlet.
  145. */
  146. public void doProcessRequest(final HttpServletRequest servletRequest,
  147. final HttpServletResponse originalServlet,
  148. final ResourceResolver resourceResolver) throws IOException {
  149. final HttpServletResponse servletResponse = new MetricsResponseWrapper(originalServlet);
  150.  
  151. // setting the Sling request and response
  152. final RequestData requestData = new RequestData(this, servletRequest,
  153. servletResponse);
  154. final SlingHttpServletRequest request = requestData.getSlingRequest();
  155. final SlingHttpServletResponse response = requestData.getSlingResponse();
  156. getSessionUser(request);
  157.  
  158. RequestHistoryConsolePlugin.recordRequest(request);
  159.  
  160. try {
  161. final ServletResolver sr = this.servletResolver;
  162.  
  163. // check that we have all required services
  164. if (resourceResolver == null) {
  165. throw new UnavailableException("ResourceResolver");
  166. } else if (sr == null) {
  167. throw new UnavailableException("ServletResolver");
  168. }
  169.  
  170. // initialize the request data - resolve resource and servlet
  171. Resource resource = requestData.initResource(resourceResolver);
  172. requestData.initServlet(resource, sr);
  173.  
  174. FilterHandle[] filters = filterManager.getFilters(FilterChainType.REQUEST);
  175. if (filters != null) {
  176. histogram.update(filters.length);
  177. FilterChain processor = new RequestSlingFilterChain(this,
  178. filters);
  179.  
  180. request.getRequestProgressTracker().log(
  181. "Applying " + FilterChainType.REQUEST + "filters");
  182.  
  183. processor.doFilter(request, response);
  184.  
  185. } else {
  186.  
  187. // no filters, directly call resource level filters and servlet
  188. processComponent(request, response, FilterChainType.COMPONENT);
  189.  
  190. }
  191.  
  192. } catch ( final SlingHttpServletResponseImpl.WriterAlreadyClosedException wace ) {
  193. log.error("Writer has already been closed.", wace);
  194. } catch (ResourceNotFoundException rnfe) {
  195. // send this exception as a 404 status
  196. log.info("service: Resource {} not found", rnfe.getResource());
  197.  
  198. handleError(HttpServletResponse.SC_NOT_FOUND, rnfe.getMessage(),
  199. request, response);
  200.  
  201. } catch (final SlingException se) {
  202.  
  203. // if we have request data and a non-null F servlet name
  204. // we assume, that this is the name of the causing servlet
  205. if (requestData.getActiveServletName() != null) {
  206. request.setAttribute(ERROR_SERVLET_NAME,
  207. requestData.getActiveServletName());
  208. }
  209.  
  210. // send this exception as is (albeit unwrapping and wrapped
  211. // exception.
  212. Throwable t = se;
  213. while ( t instanceof SlingException && t.getCause() != null ) {
  214. t = t.getCause();
  215. }
  216. log.error("service: Uncaught SlingException", t);
  217. handleError(t, request, response);
  218.  
  219. } catch (AccessControlException ace) {
  220. // SLING-319 if anything goes wrong, send 403/FORBIDDEN
  221. log.info(
  222. "service: Authenticated user {} does not have enough rights to executed requested action",
  223. request.getRemoteUser());
  224. handleError(HttpServletResponse.SC_FORBIDDEN, null, request,
  225. response);
  226.  
  227. } catch (UnavailableException ue) {
  228.  
  229. // exception is thrown before the SlingHttpServletRequest/Response
  230. // is properly set up due to missing dependencies. In this case
  231. // we must not use the Sling error handling infrastructure but
  232. // just return a 503 status response handled by the servlet
  233. // container environment
  234.  
  235. final int status = HttpServletResponse.SC_SERVICE_UNAVAILABLE;
  236. final String errorMessage = ue.getMessage()
  237. + " service missing, cannot service requests";
  238. log.error("{} , sending status {}", errorMessage, status);
  239. servletResponse.sendError(status, errorMessage);
  240.  
  241. } catch (IOException ioe) {
  242. // forward IOException up the call chain to properly handle it
  243. throw ioe;
  244.  
  245. } catch (Throwable t) {
  246.  
  247. // if we have request data and a non-null active servlet name
  248. // we assume, that this is the name of the causing servlet
  249. if (requestData.getActiveServletName() != null) {
  250. request.setAttribute(ERROR_SERVLET_NAME,
  251. requestData.getActiveServletName());
  252. }
  253. log.error("service: Uncaught Throwable", t);
  254. handleError(t, request, response);
  255.  
  256. } finally {
  257. if (mbean != null) {
  258. mbean.addRequestData(requestData);
  259. }
  260. }
  261. }
  262.  
  263. // ---------- SlingRequestProcessor interface
  264.  
  265. /**
  266. * @see org.apache.sling.engine.SlingRequestProcessor#processRequest(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, org.apache.sling.api.resource.ResourceResolver)
  267. */
  268. public void processRequest(final HttpServletRequest servletRequest,
  269. final HttpServletResponse servletResponse,
  270. final ResourceResolver resourceResolver) throws IOException {
  271. // set the marker for the parameter support
  272. final Object oldValue = servletRequest.getAttribute(ParameterSupport.MARKER_IS_SERVICE_PROCESSING);
  273. servletRequest.setAttribute(ParameterSupport.MARKER_IS_SERVICE_PROCESSING, Boolean.TRUE);
  274. try {
  275. this.doProcessRequest(servletRequest, servletResponse, resourceResolver);
  276. } finally {
  277. // restore the old value
  278. if ( oldValue != null ) {
  279. servletRequest.setAttribute(ParameterSupport.MARKER_IS_SERVICE_PROCESSING, oldValue);
  280. } else {
  281. servletRequest.removeAttribute(ParameterSupport.MARKER_IS_SERVICE_PROCESSING);
  282. }
  283. }
  284. }
  285.  
  286. /**
  287. * Renders the component defined by the RequestData's current ComponentData
  288. * instance after calling all filters of the given
  289. * {@link org.apache.sling.engine.impl.filter.ServletFilterManager.FilterChainType
  290. * filterChainType}.
  291. *
  292. * @param request
  293. * @param response
  294. * @param filterChainType
  295. * @throws IOException
  296. * @throws ServletException
  297. */
  298.  
  299. public void processComponent(SlingHttpServletRequest request,
  300. SlingHttpServletResponse response,
  301. final FilterChainType filterChainType) throws IOException,
  302. ServletException {
  303.  
  304. FilterHandle filters[] = filterManager.getFilters(filterChainType);
  305. if (filters != null) {
  306.  
  307. FilterChain processor = new SlingComponentFilterChain(filters);
  308. request.getRequestProgressTracker().log(
  309. "Applying " + filterChainType + "filters");
  310. processor.doFilter(request, response);
  311.  
  312. } else {
  313.  
  314. log.debug("service: No Resource level filters, calling servlet");
  315. RequestData.service(request, response);
  316.  
  317. }
  318. }
  319.  
  320. // ---------- Generic Content Request processor ----------------------------
  321.  
  322. /**
  323. * Dispatches the request on behalf of the
  324. * {@link org.apache.sling.engine.impl.request.SlingRequestDispatcher}.
  325. */
  326. public void dispatchRequest(ServletRequest request,
  327. ServletResponse response, Resource resource,
  328. RequestPathInfo resolvedURL, boolean include) throws IOException,
  329. ServletException {
  330.  
  331. // we need a SlingHttpServletRequest/SlingHttpServletResponse tupel
  332. // to continue
  333. SlingHttpServletRequest cRequest = RequestData.toSlingHttpServletRequest(request);
  334. SlingHttpServletResponse cResponse = RequestData.toSlingHttpServletResponse(response);
  335.  
  336. // get the request data (and btw check the correct type)
  337. final RequestData requestData = RequestData.getRequestData(cRequest);
  338. final ContentData oldContentData = requestData.getContentData();
  339. final ContentData contentData = requestData.setContent(resource, resolvedURL);
  340.  
  341. try {
  342. // resolve the servlet
  343. Servlet servlet = servletResolver.resolveServlet(cRequest);
  344. contentData.setServlet(servlet);
  345.  
  346. FilterChainType type = include
  347. ? FilterChainType.INCLUDE
  348. : FilterChainType.FORWARD;
  349.  
  350. processComponent(cRequest, cResponse, type);
  351. } finally {
  352. requestData.resetContent(oldContentData);
  353. }
  354. }
  355.  
  356. // ---------- Error Handling with Filters
  357.  
  358. void handleError(final int status, final String message,
  359. final SlingHttpServletRequest request,
  360. SlingHttpServletResponse response) throws IOException {
  361.  
  362. // wrap the response ensuring getWriter will fall back to wrapping
  363. // the response output stream if reset does not reset this
  364. response = new ErrorResponseWrapper(response);
  365.  
  366. FilterHandle[] filters = filterManager.getFilters(FilterChainType.ERROR);
  367. if (filters != null && filters.length > 0) {
  368. FilterChain processor = new AbstractSlingFilterChain(filters) {
  369.  
  370. @Override
  371. protected void render(SlingHttpServletRequest request,
  372. SlingHttpServletResponse response) throws IOException {
  373. errorHandler.handleError(status, message, request, response);
  374. }
  375. };
  376. request.getRequestProgressTracker().log(
  377. "Applying " + FilterChainType.ERROR + " filters");
  378.  
  379. try {
  380. processor.doFilter(request, response);
  381. } catch (ServletException se) {
  382. throw new SlingServletException(se);
  383. }
  384. } else {
  385. errorHandler.handleError(status, message, request, response);
  386. }
  387. }
  388.  
  389. // just rethrow the exception as explained in the class comment
  390. private void handleError(final Throwable throwable,
  391. final SlingHttpServletRequest request,
  392. SlingHttpServletResponse response) throws IOException {
  393.  
  394. // wrap the response ensuring getWriter will fall back to wrapping
  395. // the response output stream if reset does not reset this
  396. response = new ErrorResponseWrapper(response);
  397.  
  398. FilterHandle[] filters = filterManager.getFilters(FilterChainType.ERROR);
  399. if (filters != null && filters.length > 0) {
  400. FilterChain processor = new AbstractSlingFilterChain(filters) {
  401.  
  402. @Override
  403. protected void render(SlingHttpServletRequest request,
  404. SlingHttpServletResponse response) throws IOException {
  405. errorHandler.handleError(throwable, request, response);
  406. }
  407. };
  408. request.getRequestProgressTracker().log(
  409. "Applying " + FilterChainType.ERROR + " filters");
  410.  
  411. try {
  412. processor.doFilter(request, response);
  413. } catch (ServletException se) {
  414. throw new SlingServletException(se);
  415. }
  416. } else {
  417. errorHandler.handleError(throwable, request, response);
  418. }
  419. }
  420.  
  421.  
  422. /**Wrap an HttpSerletResponse to generate metrics counting and mesuring the request per second of each HTTP
  423. * response status code*/
  424. private class MetricsResponseWrapper extends HttpServletResponseWrapper{
  425.  
  426. MetricsResponseWrapper(HttpServletResponse servletResponse) {
  427. super(servletResponse);
  428. }
  429. private void computeMetrics(int statusCode) {
  430. if(metricsService == null) {
  431. log.warn("Missing MetricsService, cannot compute metrics for status {}", statusCode);
  432. return;
  433. }
  434. metricsService.counter("engine.main.count." + statusCode).increment();
  435. metricsService.meter("engine.main.mark"+statusCode).mark();
  436. }
  437.  
  438. @Override
  439. public void sendError(int statusCode) throws IOException {
  440. computeMetrics(statusCode);
  441. super.sendError(statusCode);
  442. }
  443.  
  444. @Override
  445. public void sendError(int sc, String msg) throws IOException {
  446. computeMetrics(sc);
  447. super.sendError(sc, msg);
  448. }
  449.  
  450. @Override
  451. public void setStatus(int sc) {
  452.  
  453. computeMetrics(sc);
  454. super.setStatus(sc);
  455. }
  456.  
  457. @Override
  458. public void setStatus(int sc, String sm) {
  459. computeMetrics(sc);
  460. super.setStatus(sc, sm);
  461. }
  462. }
  463.  
  464. private static class ErrorResponseWrapper extends
  465. SlingHttpServletResponseWrapper {
  466.  
  467. private PrintWriter writer;
  468.  
  469. public ErrorResponseWrapper(SlingHttpServletResponse wrappedResponse) {
  470. super(wrappedResponse);
  471. }
  472.  
  473. @Override
  474. public PrintWriter getWriter() throws IOException {
  475. if (writer == null) {
  476. try {
  477. writer = super.getWriter();
  478. } catch (IllegalStateException ise) {
  479. // resetting the response did not reset the output channel
  480. // status and we have to create a writer based on the output
  481. // stream using the character encoding already set on the
  482. // response, defaulting to ISO-8859-1
  483. OutputStream out = getOutputStream();
  484. String encoding = getCharacterEncoding();
  485. if (encoding == null) {
  486. encoding = "ISO-8859-1";
  487. setCharacterEncoding(encoding);
  488. }
  489. Writer w = new OutputStreamWriter(out, encoding);
  490. writer = new PrintWriter(w);
  491. }
  492. }
  493. return writer;
  494. }
  495.  
  496. /**
  497. * Flush the writer if the {@link #getWriter()} method was called
  498. * to potentially wrap an OuputStream still existing in the response.
  499. */
  500. @Override
  501. public void flushBuffer() throws IOException {
  502. if (writer != null) {
  503. writer.flush();
  504. }
  505. super.flushBuffer();
  506. }
  507. }
  508. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement