| /* |
| * Copyright (c) 1997-2018 Oracle and/or its affiliates. All rights reserved. |
| * Copyright 2004 The Apache Software Foundation |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package org.apache.catalina.core; |
| |
| import java.io.IOException; |
| import java.text.MessageFormat; |
| import java.util.ResourceBundle; |
| import java.util.logging.Level; |
| import java.util.logging.Logger; |
| import javax.management.MalformedObjectNameException; |
| import javax.management.ObjectName; |
| import jakarta.servlet.RequestDispatcher; |
| import jakarta.servlet.Servlet; |
| import jakarta.servlet.ServletException; |
| import jakarta.servlet.ServletRequest; |
| import jakarta.servlet.ServletResponse; |
| import jakarta.servlet.UnavailableException; |
| import jakarta.servlet.http.HttpServletResponse; |
| |
| import org.apache.catalina.Context; |
| import org.apache.catalina.Globals; |
| import org.apache.catalina.HttpRequest; |
| import org.apache.catalina.LogFacade; |
| import org.apache.catalina.Request; |
| import org.apache.catalina.Response; |
| import org.apache.catalina.connector.ClientAbortException; |
| import org.apache.catalina.connector.RequestFacade; |
| import org.apache.catalina.valves.ValveBase; |
| import org.glassfish.grizzly.http.util.DataChunk; |
| |
| /** |
| * Valve that implements the default basic behavior for the |
| * <code>StandardWrapper</code> container implementation. |
| * |
| * @author Craig R. McClanahan |
| * @version $Revision: 1.10 $ $Date: 2007/05/05 05:31:54 $ |
| */ |
| |
| final class StandardWrapperValve extends ValveBase { |
| |
| private static final Logger log = LogFacade.getLogger(); |
| private static final ResourceBundle rb = log.getResourceBundle(); |
| |
| // --------------------------------------------------------- Public Methods |
| |
| |
| /** |
| * Invoke the servlet we are managing, respecting the rules regarding |
| * servlet lifecycle and SingleThreadModel support. |
| * |
| * @param request Request to be processed |
| * @param response Response to be produced |
| * |
| * @exception IOException if an input/output error occurred |
| * @exception ServletException if a servlet error occurred |
| */ |
| @Override |
| public int invoke(Request request, Response response) |
| throws IOException, ServletException { |
| |
| boolean unavailable = false; |
| Throwable throwable = null; |
| Servlet servlet = null; |
| |
| StandardWrapper wrapper = (StandardWrapper) getContainer(); |
| Context context = (Context) wrapper.getParent(); |
| |
| HttpRequest hrequest = (HttpRequest) request; |
| |
| /* |
| * Create a request facade such that if the request was received |
| * at the root context, and the root context is mapped to a |
| * default-web-module, the default-web-module mapping is masked from |
| * the application code to which the request facade is being passed. |
| * For example, the request.facade's getContextPath() method will |
| * return "/", rather than the context root of the default-web-module, |
| * in this case. |
| */ |
| RequestFacade hreq = (RequestFacade) request.getRequest(true); |
| HttpServletResponse hres = |
| (HttpServletResponse) response.getResponse(); |
| |
| // Check for the application being marked unavailable |
| if (!context.getAvailable()) { |
| // BEGIN S1AS 4878272 |
| hres.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE); |
| response.setDetailMessage(rb.getString(LogFacade.APP_UNAVAILABLE)); |
| // END S1AS 4878272 |
| unavailable = true; |
| } |
| |
| // Check for the servlet being marked unavailable |
| if (!unavailable && wrapper.isUnavailable()) { |
| String msg = MessageFormat.format(rb.getString(LogFacade.SERVLET_UNAVAILABLE), wrapper.getName()); |
| log(msg); |
| if (hres == null) { |
| ; // NOTE - Not much we can do generically |
| } else { |
| long available = wrapper.getAvailable(); |
| if ((available > 0L) && (available < Long.MAX_VALUE)) { |
| hres.setDateHeader("Retry-After", available); |
| // BEGIN S1AS 4878272 |
| hres.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE); |
| |
| response.setDetailMessage(msg); |
| // END S1AS 4878272 |
| } else if (available == Long.MAX_VALUE) { |
| // BEGIN S1AS 4878272 |
| hres.sendError(HttpServletResponse.SC_NOT_FOUND); |
| msg = MessageFormat.format(rb.getString(LogFacade.SERVLET_NOT_FOUND), wrapper.getName()); |
| response.setDetailMessage(msg); |
| // END S1AS 4878272 |
| } |
| } |
| unavailable = true; |
| } |
| |
| // Allocate a servlet instance to process this request |
| try { |
| if (!unavailable) { |
| servlet = wrapper.allocate(); |
| } |
| } catch (UnavailableException e) { |
| if (e.isPermanent()) { |
| // BEGIN S1AS 4878272 |
| hres.sendError(HttpServletResponse.SC_NOT_FOUND); |
| |
| String msg = MessageFormat.format(rb.getString(LogFacade.SERVLET_NOT_FOUND), wrapper.getName()); |
| response.setDetailMessage(msg); |
| |
| // END S1AS 4878272 |
| } else { |
| hres.setDateHeader("Retry-After", e.getUnavailableSeconds()); |
| // BEGIN S1AS 4878272 |
| hres.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE); |
| String msg = MessageFormat.format(rb.getString(LogFacade.SERVLET_UNAVAILABLE), wrapper.getName()); |
| response.setDetailMessage(msg); |
| // END S1AS 4878272 |
| } |
| } catch (ServletException e) { |
| |
| String msg = MessageFormat.format(rb.getString(LogFacade.SERVLET_ALLOCATE_EXCEPTION), wrapper.getName()); |
| log(msg, StandardWrapper.getRootCause(e)); |
| |
| throwable = e; |
| exception(request, response, e); |
| servlet = null; |
| } catch (Throwable e) { |
| |
| String msg = MessageFormat.format(rb.getString(LogFacade.SERVLET_ALLOCATE_EXCEPTION), wrapper.getName()); |
| log(msg, e); |
| |
| throwable = e; |
| exception(request, response, e); |
| servlet = null; |
| } |
| |
| // Acknowlege the request |
| try { |
| response.sendAcknowledgement(); |
| } catch (IOException e) { |
| String msg = MessageFormat.format(rb.getString(LogFacade.SEND_ACKNOWLEDGEMENT_EXCEPTION), wrapper.getName()); |
| log(msg, e); |
| throwable = e; |
| exception(request, response, e); |
| } catch (Throwable e) { |
| String msg = MessageFormat.format(rb.getString(LogFacade.SEND_ACKNOWLEDGEMENT_EXCEPTION), wrapper.getName()); |
| log(msg, e); |
| throwable = e; |
| exception(request, response, e); |
| servlet = null; |
| } |
| DataChunk requestPathMB = hrequest.getRequestPathMB(); |
| hreq.setAttribute(Globals.DISPATCHER_REQUEST_PATH_ATTR, |
| requestPathMB); |
| |
| // Create the filter chain for this request |
| ApplicationFilterFactory factory = |
| ApplicationFilterFactory.getInstance(); |
| ApplicationFilterChain filterChain = |
| factory.createFilterChain((ServletRequest) request, |
| wrapper, servlet); |
| |
| // Call the filter chain for this request |
| // NOTE: This also calls the servlet's service() method |
| try { |
| String jspFile = wrapper.getJspFile(); |
| if (jspFile != null) { |
| hreq.setAttribute(Globals.JSP_FILE_ATTR, jspFile); |
| } |
| /* IASRI 4665318 |
| if ((servlet != null) && (filterChain != null)) { |
| filterChain.doFilter(hreq, hres); |
| } |
| */ |
| // START IASRI 4665318 |
| if (servlet != null) { |
| if (filterChain != null) { |
| filterChain.setWrapper(wrapper); |
| filterChain.doFilter(hreq, hres); |
| } else { |
| wrapper.service(hreq, hres, servlet); |
| } |
| } |
| // END IASRI 4665318 |
| } catch (ClientAbortException e) { |
| throwable = e; |
| exception(request, response, e); |
| } catch (IOException e) { |
| String msg = MessageFormat.format(rb.getString(LogFacade.SERVLET_SERVICE_EXCEPTION), wrapper.getName()); |
| log(msg, e); |
| throwable = e; |
| exception(request, response, e); |
| } catch (UnavailableException e) { |
| String msg = MessageFormat.format(rb.getString(LogFacade.SERVLET_SERVICE_EXCEPTION), wrapper.getName()); |
| log(msg, e); |
| // throwable = e; |
| // exception(request, response, e); |
| wrapper.unavailable(e); |
| long available = wrapper.getAvailable(); |
| if ((available > 0L) && (available < Long.MAX_VALUE)) { |
| hres.setDateHeader("Retry-After", available); |
| // BEGIN S1AS 4878272 |
| hres.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE); |
| String msgServletUnavailable = MessageFormat.format(rb.getString(LogFacade.SERVLET_UNAVAILABLE), wrapper.getName()); |
| response.setDetailMessage(msgServletUnavailable); |
| // END S1AS 4878272 |
| } else if (available == Long.MAX_VALUE) { |
| // BEGIN S1AS 4878272 |
| hres.sendError(HttpServletResponse.SC_NOT_FOUND); |
| String msgServletNotFound = MessageFormat.format(rb.getString(LogFacade.SERVLET_NOT_FOUND), wrapper.getName()); |
| response.setDetailMessage(msgServletNotFound); |
| // END S1AS 4878272 |
| } |
| // Do not save exception in 'throwable', because we |
| // do not want to do exception(request, response, e) processing |
| } catch (ServletException e) { |
| Throwable rootCause = StandardWrapper.getRootCause(e); |
| if (!(rootCause instanceof ClientAbortException)) { |
| String msg = MessageFormat.format(rb.getString(LogFacade.SERVLET_SERVICE_EXCEPTION), wrapper.getName()); |
| log(msg, rootCause); |
| } |
| throwable = e; |
| exception(request, response, e); |
| } catch (Throwable e) { |
| String msg = MessageFormat.format(rb.getString(LogFacade.SERVLET_SERVICE_EXCEPTION), wrapper.getName()); |
| log(msg, e); |
| throwable = e; |
| exception(request, response, e); |
| } |
| |
| // Release the filter chain (if any) for this request |
| try { |
| if (filterChain != null) |
| filterChain.release(); |
| } catch (Throwable e) { |
| String msg = MessageFormat.format(rb.getString(LogFacade.RELEASE_FILTERS_EXCEPTION), wrapper.getName()); |
| log(msg, e); |
| if (throwable == null) { |
| throwable = e; |
| exception(request, response, e); |
| } |
| } |
| |
| // Deallocate the allocated servlet instance |
| try { |
| if (servlet != null) { |
| wrapper.deallocate(servlet); |
| } |
| } catch (Throwable e) { |
| String msg = MessageFormat.format(rb.getString(LogFacade.DEALLOCATE_EXCEPTION), wrapper.getName()); |
| log(msg, e); |
| if (throwable == null) { |
| throwable = e; |
| exception(request, response, e); |
| } |
| } |
| |
| // If this servlet has been marked permanently unavailable, |
| // unload it and release this instance |
| try { |
| if ((servlet != null) && |
| (wrapper.getAvailable() == Long.MAX_VALUE)) { |
| wrapper.unload(); |
| } |
| } catch (Throwable e) { |
| String msg = MessageFormat.format(rb.getString(LogFacade.SERVLET_UNLOAD_EXCEPTION), wrapper.getName()); |
| log(msg, e); |
| if (throwable == null) { |
| exception(request, response, e); |
| } |
| } |
| |
| return END_PIPELINE; |
| } |
| |
| |
| /** |
| * Tomcat style invocation. |
| */ |
| @Override |
| public void invoke(org.apache.catalina.connector.Request request, |
| org.apache.catalina.connector.Response response) |
| throws IOException, ServletException { |
| invoke((Request) request, (Response) response); |
| } |
| |
| |
| // -------------------------------------------------------- Private Methods |
| |
| |
| /** |
| * Log a message on the Logger associated with our Container (if any) |
| * |
| * @param message Message to be logged |
| */ |
| private void log(String message) { |
| org.apache.catalina.Logger logger = null; |
| String containerName = null; |
| if (container != null) { |
| logger = container.getLogger(); |
| containerName = container.getName(); |
| } |
| if (logger != null) { |
| logger.log("StandardWrapperValve[" + containerName + "]: " + |
| message); |
| } else { |
| if (log.isLoggable(Level.INFO)) { |
| log.log(Level.INFO, LogFacade.STANDARD_WRAPPER_VALVE, new Object[] {containerName, message}); |
| } |
| } |
| } |
| |
| |
| /** |
| * Log a message on the Logger associated with our Container (if any) |
| * |
| * @param message Message to be logged |
| * @param t Associated exception |
| */ |
| private void log(String message, Throwable t) { |
| org.apache.catalina.Logger logger = null; |
| String containerName = null; |
| if (container != null) { |
| logger = container.getLogger(); |
| containerName = container.getName(); |
| } |
| if (logger != null) { |
| logger.log("StandardWrapperValve[" + containerName + "]: " + |
| message, t, org.apache.catalina.Logger.WARNING); |
| } else { |
| String msg = MessageFormat.format(rb.getString(LogFacade.STANDARD_WRAPPER_VALVE), |
| new Object[] {containerName, message}); |
| log.log(Level.WARNING, msg, t); |
| } |
| } |
| |
| |
| /** |
| * Handle the specified ServletException encountered while processing |
| * the specified Request to produce the specified Response. Any |
| * exceptions that occur during generation of the exception report are |
| * logged and swallowed. |
| * |
| * @param request The request being processed |
| * @param response The response being generated |
| * @param exception The exception that occurred (which possibly wraps |
| * a root cause exception |
| */ |
| private void exception(Request request, Response response, |
| Throwable exception) { |
| ServletRequest sreq = request.getRequest(); |
| sreq.setAttribute(RequestDispatcher.ERROR_EXCEPTION, exception); |
| |
| ServletResponse sresponse = response.getResponse(); |
| |
| /* GlassFish 6386229 |
| if (sresponse instanceof HttpServletResponse) |
| ((HttpServletResponse) sresponse).setStatus |
| (HttpServletResponse.SC_INTERNAL_SERVER_ERROR); |
| */ |
| // START GlassFish 6386229 |
| ((HttpServletResponse) sresponse).setStatus |
| (HttpServletResponse.SC_INTERNAL_SERVER_ERROR); |
| // END GlassFish 6386229 |
| } |
| |
| // Don't register in JMX |
| |
| public ObjectName createObjectName(String domain, ObjectName parent) |
| throws MalformedObjectNameException { |
| return null; |
| } |
| } |