@Override public void sendError(int sc) throws IOException { if (isCommitted()) throw new IllegalStateException(sm.getString("coyoteResponse.sendError.ise")); response.setAppCommitted(true); response.sendError(sc); }
/** * Invoke the next Valve in the sequence. When the invoke returns, check the response state, and * output an error report is necessary. * * @param request The servlet request to be processed * @param response The servlet response to be created * @exception IOException if an input/output error occurs * @exception ServletException if a servlet error occurs */ @Override public void invoke(Request request, Response response) throws IOException, ServletException { // Perform the request getNext().invoke(request, response); if (response.isCommitted()) { return; } Throwable throwable = (Throwable) request.getAttribute(RequestDispatcher.ERROR_EXCEPTION); if (request.isAsyncStarted() && response.getStatus() < 400 && throwable == null) { return; } if (throwable != null) { // The response is an error response.setError(); // Reset the response (if possible) try { response.reset(); } catch (IllegalStateException e) { // Ignore } response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); } response.setSuspended(false); try { report(request, response, throwable); } catch (Throwable tt) { ExceptionUtils.handleThrowable(tt); } if (request.isAsyncStarted()) { request.getAsyncContext().complete(); } }
/** * Reject the request that was denied by this valve. * * @param request The servlet request to be processed * @param response The servlet response to be processed * @exception IOException if an input/output error occurs * @exception ServletException if a servlet error occurs */ protected void denyRequest(Request request, Response response) throws IOException, ServletException { response.sendError(denyStatus); }
/** * Send an error response with the specified status and a default message. * * @param status HTTP status code to send * @exception IllegalStateException if this response has already been committed * @exception IOException if an input/output error occurs */ @Override public void sendError(int status) throws IOException { sendError(status, null); }
/** * Select the appropriate child Context to process this request, based on the specified request * URI. If no matching Context can be found, return an appropriate HTTP error. * * @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 final void invoke(Request request, Response response) throws IOException, ServletException { /* * xujb: * 和Engine一样,调用下层的context,让它来做一些处理 * 自身也处理了一些的逻辑 * * */ // Select the Context to be used for this Request Context context = request.getContext(); if (context == null) { response.sendError( HttpServletResponse.SC_INTERNAL_SERVER_ERROR, sm.getString("standardHost.noContext")); return; } // Bind the context CL to the current thread if (context.getLoader() != null) { // Not started - it should check for availability first // This should eventually move to Engine, it's generic. if (Globals.IS_SECURITY_ENABLED) { PrivilegedAction<Void> pa = new PrivilegedSetTccl(context.getLoader().getClassLoader()); AccessController.doPrivileged(pa); } else { Thread.currentThread().setContextClassLoader(context.getLoader().getClassLoader()); } } if (request.isAsyncSupported()) { request.setAsyncSupported(context.getPipeline().isAsyncSupported()); } boolean asyncAtStart = request.isAsync(); boolean asyncDispatching = request.isAsyncDispatching(); if (asyncAtStart || context.fireRequestInitEvent(request)) { // Ask this Context to process this request. Requests that are in // async mode and are not being dispatched to this resource must be // in error and have been routed here to check for application // defined error pages. try { if (!asyncAtStart || asyncDispatching) { context.getPipeline().getFirst().invoke(request, response); } else { // Make sure this request/response is here because an error // report is required. if (!response.isErrorReportRequired()) { throw new IllegalStateException(sm.getString("standardHost.asyncStateError")); } } } catch (Throwable t) { ExceptionUtils.handleThrowable(t); // If a new error occurred while trying to report a previous // error simply log the new error and allow the original error // to be reported. if (response.isErrorReportRequired()) { container.getLogger().error("Exception Processing " + request.getRequestURI(), t); } else { request.setAttribute(RequestDispatcher.ERROR_EXCEPTION, t); throwable(request, response, t); } } // Now that the request/response pair is back under container // control lift the suspension so that the error handling can // complete and/or the container can flush any remaining data response.setSuspended(false); Throwable t = (Throwable) request.getAttribute(RequestDispatcher.ERROR_EXCEPTION); // Protect against NPEs if the context was destroyed during a // long running request. if (!context.getState().isAvailable()) { return; } // Look for (and render if found) an application level error page if (response.isErrorReportRequired()) { if (t != null) { throwable(request, response, t); } else { status(request, response); } } if (!request.isAsync() && (!asyncAtStart || !response.isErrorReportRequired())) { context.fireRequestDestroyEvent(request); } } // Access a session (if present) to update last accessed time, based on a // strict interpretation of the specification if (ACCESS_SESSION) { request.getSession(false); } // Restore the context classloader if (Globals.IS_SECURITY_ENABLED) { PrivilegedAction<Void> pa = new PrivilegedSetTccl(StandardHostValve.class.getClassLoader()); AccessController.doPrivileged(pa); } else { Thread.currentThread().setContextClassLoader(StandardHostValve.class.getClassLoader()); } }
/** * Enforce any user data constraint required by the security constraint guarding this request URI. * Return <code>true</code> if this constraint was not violated and processing should continue, or * <code>false</code> if we have created a response already. * * @param request Request we are processing * @param response Response we are creating * @param constraints Security constraint being checked * @exception IOException if an input/output error occurs */ @Override public boolean hasUserDataPermission( Request request, Response response, SecurityConstraint[] constraints) throws IOException { // Is there a relevant user data constraint? if (constraints == null || constraints.length == 0) { if (log.isDebugEnabled()) log.debug(" No applicable security constraint defined"); return (true); } for (int i = 0; i < constraints.length; i++) { SecurityConstraint constraint = constraints[i]; String userConstraint = constraint.getUserConstraint(); if (userConstraint == null) { if (log.isDebugEnabled()) log.debug(" No applicable user data constraint defined"); return (true); } if (userConstraint.equals(Constants.NONE_TRANSPORT)) { if (log.isDebugEnabled()) log.debug(" User data constraint has no restrictions"); return (true); } } // Validate the request against the user data constraint if (request.getRequest().isSecure()) { if (log.isDebugEnabled()) log.debug(" User data constraint already satisfied"); return (true); } // Initialize variables we need to determine the appropriate action int redirectPort = request.getConnector().getRedirectPort(); // Is redirecting disabled? if (redirectPort <= 0) { if (log.isDebugEnabled()) log.debug(" SSL redirect is disabled"); response.sendError(HttpServletResponse.SC_FORBIDDEN, request.getRequestURI()); return (false); } // Redirect to the corresponding SSL port StringBuilder file = new StringBuilder(); String protocol = "https"; String host = request.getServerName(); // Protocol file.append(protocol).append("://").append(host); // Host with port if (redirectPort != 443) { file.append(":").append(redirectPort); } // URI file.append(request.getRequestURI()); String requestedSessionId = request.getRequestedSessionId(); if ((requestedSessionId != null) && request.isRequestedSessionIdFromURL()) { file.append(";"); file.append(SessionConfig.getSessionUriParamName(request.getContext())); file.append("="); file.append(requestedSessionId); } String queryString = request.getQueryString(); if (queryString != null) { file.append('?'); file.append(queryString); } if (log.isDebugEnabled()) log.debug(" Redirecting to " + file.toString()); response.sendRedirect(file.toString()); return (false); }
/** * Perform access control based on the specified authorization constraint. Return <code>true * </code> if this constraint is satisfied and processing should continue, or <code>false</code> * otherwise. * * @param request Request we are processing * @param response Response we are creating * @param constraints Security constraint we are enforcing * @param context The Context to which client of this class is attached. * @exception IOException if an input/output error occurs */ @Override public boolean hasResourcePermission( Request request, Response response, SecurityConstraint[] constraints, Context context) throws IOException { if (constraints == null || constraints.length == 0) return (true); // Specifically allow access to the form login and form error pages // and the "j_security_check" action LoginConfig config = context.getLoginConfig(); if ((config != null) && (Constants.FORM_METHOD.equals(config.getAuthMethod()))) { String requestURI = request.getRequestPathMB().toString(); String loginPage = config.getLoginPage(); if (loginPage.equals(requestURI)) { if (log.isDebugEnabled()) log.debug(" Allow access to login page " + loginPage); return (true); } String errorPage = config.getErrorPage(); if (errorPage.equals(requestURI)) { if (log.isDebugEnabled()) log.debug(" Allow access to error page " + errorPage); return (true); } if (requestURI.endsWith(Constants.FORM_ACTION)) { if (log.isDebugEnabled()) log.debug(" Allow access to username/password submission"); return (true); } } // Which user principal have we already authenticated? Principal principal = request.getPrincipal(); boolean status = false; boolean denyfromall = false; for (int i = 0; i < constraints.length; i++) { SecurityConstraint constraint = constraints[i]; String roles[]; if (constraint.getAllRoles()) { // * means all roles defined in web.xml roles = request.getContext().findSecurityRoles(); } else { roles = constraint.findAuthRoles(); } if (roles == null) roles = new String[0]; if (log.isDebugEnabled()) log.debug(" Checking roles " + principal); if (roles.length == 0 && !constraint.getAllRoles()) { if (constraint.getAuthConstraint()) { if (log.isDebugEnabled()) log.debug("No roles"); status = false; // No listed roles means no access at all denyfromall = true; break; } if (log.isDebugEnabled()) log.debug("Passing all access"); status = true; } else if (principal == null) { if (log.isDebugEnabled()) log.debug(" No user authenticated, cannot grant access"); } else { for (int j = 0; j < roles.length; j++) { if (hasRole(null, principal, roles[j])) { status = true; if (log.isDebugEnabled()) log.debug("Role found: " + roles[j]); } else if (log.isDebugEnabled()) log.debug("No role found: " + roles[j]); } } } if (!denyfromall && allRolesMode != AllRolesMode.STRICT_MODE && !status && principal != null) { if (log.isDebugEnabled()) { log.debug("Checking for all roles mode: " + allRolesMode); } // Check for an all roles(role-name="*") for (int i = 0; i < constraints.length; i++) { SecurityConstraint constraint = constraints[i]; String roles[]; // If the all roles mode exists, sets if (constraint.getAllRoles()) { if (allRolesMode == AllRolesMode.AUTH_ONLY_MODE) { if (log.isDebugEnabled()) { log.debug("Granting access for role-name=*, auth-only"); } status = true; break; } // For AllRolesMode.STRICT_AUTH_ONLY_MODE there must be zero roles roles = request.getContext().findSecurityRoles(); if (roles.length == 0 && allRolesMode == AllRolesMode.STRICT_AUTH_ONLY_MODE) { if (log.isDebugEnabled()) { log.debug("Granting access for role-name=*, strict auth-only"); } status = true; break; } } } } // Return a "Forbidden" message denying access to this resource if (!status) { response.sendError(HttpServletResponse.SC_FORBIDDEN, sm.getString("realmBase.forbidden")); } return status; }