@Override public void invoke(Request request, Response response) throws IOException, ServletException { /* * mod_header converts the '\n' into ' ' so we have to rebuild the client * certificate */ String strcert0 = mygetHeader(request, "ssl_client_cert"); if (strcert0 != null && strcert0.length() > 28) { String strcert1 = strcert0.replace(' ', '\n'); String strcert2 = strcert1.substring(28, strcert1.length() - 26); String strcert3 = "-----BEGIN CERTIFICATE-----\n"; String strcert4 = strcert3.concat(strcert2); String strcerts = strcert4.concat("\n-----END CERTIFICATE-----\n"); // ByteArrayInputStream bais = new // ByteArrayInputStream(strcerts.getBytes("UTF-8")); ByteArrayInputStream bais = new ByteArrayInputStream(strcerts.getBytes(Charset.defaultCharset())); X509Certificate jsseCerts[] = null; String providerName = (String) request.getConnector().getProperty("clientCertProvider"); try { CertificateFactory cf; if (providerName == null) { cf = CertificateFactory.getInstance("X.509"); } else { cf = CertificateFactory.getInstance("X.509", providerName); } X509Certificate cert = (X509Certificate) cf.generateCertificate(bais); jsseCerts = new X509Certificate[1]; jsseCerts[0] = cert; } catch (java.security.cert.CertificateException e) { log.warn(sm.getString("sslValve.certError", strcerts), e); } catch (NoSuchProviderException e) { log.error(sm.getString("sslValve.invalidProvider", providerName), e); } request.setAttribute(Globals.CERTIFICATES_ATTR, jsseCerts); } strcert0 = mygetHeader(request, "ssl_cipher"); if (strcert0 != null) { request.setAttribute(Globals.CIPHER_SUITE_ATTR, strcert0); } strcert0 = mygetHeader(request, "ssl_session_id"); if (strcert0 != null) { request.setAttribute(Globals.SSL_SESSION_ID_ATTR, strcert0); request.setAttribute(Globals.SSL_SESSION_ID_TOMCAT_ATTR, strcert0); } strcert0 = mygetHeader(request, "ssl_cipher_usekeysize"); if (strcert0 != null) { request.setAttribute(Globals.KEY_SIZE_ATTR, Integer.valueOf(strcert0)); } getNext().invoke(request, response); }
/** * Mark Request that processed at primary node with attribute primaryIndicatorName * * @param request * @throws IOException */ protected void createPrimaryIndicator(Request request) throws IOException { String id = request.getRequestedSessionId(); if ((id != null) && (id.length() > 0)) { Manager manager = request.getContext().getManager(); Session session = manager.findSession(id); if (session instanceof ClusterSession) { ClusterSession cses = (ClusterSession) session; if (log.isDebugEnabled()) log.debug( sm.getString( "ReplicationValve.session.indicator", request.getContext().getName(), id, primaryIndicatorName, Boolean.valueOf(cses.isPrimarySession()))); request.setAttribute( primaryIndicatorName, cses.isPrimarySession() ? Boolean.TRUE : Boolean.FALSE); } else { if (log.isDebugEnabled()) { if (session != null) { log.debug( sm.getString("ReplicationValve.session.found", request.getContext().getName(), id)); } else { log.debug( sm.getString( "ReplicationValve.session.invalid", request.getContext().getName(), id)); } } } } }
/** * Handle the HTTP status code (and corresponding message) generated while processing the * specified Request to produce the specified Response. Any exceptions that occur during * generation of the error report are logged and swallowed. * * @param request The request being processed * @param response The response being generated */ private void status(Request request, Response response) { int statusCode = response.getStatus(); // Handle a custom error page for this status code Context context = request.getContext(); if (context == null) return; /* Only look for error pages when isError() is set. * isError() is set when response.sendError() is invoked. This * allows custom error pages without relying on default from * web.xml. */ if (!response.isError()) return; ErrorPage errorPage = context.findErrorPage(statusCode); if (errorPage == null) { // Look for a default error page errorPage = context.findErrorPage(0); } if (errorPage != null && response.setErrorReported()) { response.setAppCommitted(false); request.setAttribute(RequestDispatcher.ERROR_STATUS_CODE, Integer.valueOf(statusCode)); String message = response.getMessage(); if (message == null) message = ""; request.setAttribute(RequestDispatcher.ERROR_MESSAGE, message); request.setAttribute(Globals.DISPATCHER_REQUEST_PATH_ATTR, errorPage.getLocation()); request.setAttribute(Globals.DISPATCHER_TYPE_ATTR, DispatcherType.ERROR); Wrapper wrapper = request.getWrapper(); if (wrapper != null) request.setAttribute(RequestDispatcher.ERROR_SERVLET_NAME, wrapper.getName()); request.setAttribute(RequestDispatcher.ERROR_REQUEST_URI, request.getRequestURI()); if (custom(request, response, errorPage)) { try { response.finishResponse(); } catch (ClientAbortException e) { // Ignore } catch (IOException e) { container.getLogger().warn("Exception Processing " + errorPage, e); } } } }
/** * Handle the specified Throwable 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 throwable The exception that occurred (which possibly wraps a root cause exception */ protected void throwable(Request request, Response response, Throwable throwable) { Context context = request.getContext(); if (context == null) return; Throwable realError = throwable; if (realError instanceof ServletException) { realError = ((ServletException) realError).getRootCause(); if (realError == null) { realError = throwable; } } // If this is an aborted request from a client just log it and return if (realError instanceof ClientAbortException) { if (log.isDebugEnabled()) { log.debug(sm.getString("standardHost.clientAbort", realError.getCause().getMessage())); } return; } ErrorPage errorPage = findErrorPage(context, throwable); if ((errorPage == null) && (realError != throwable)) { errorPage = findErrorPage(context, realError); } if (errorPage != null) { if (response.setErrorReported()) { response.setAppCommitted(false); request.setAttribute(Globals.DISPATCHER_REQUEST_PATH_ATTR, errorPage.getLocation()); request.setAttribute(Globals.DISPATCHER_TYPE_ATTR, DispatcherType.ERROR); request.setAttribute( RequestDispatcher.ERROR_STATUS_CODE, new Integer(HttpServletResponse.SC_INTERNAL_SERVER_ERROR)); request.setAttribute(RequestDispatcher.ERROR_MESSAGE, throwable.getMessage()); request.setAttribute(RequestDispatcher.ERROR_EXCEPTION, realError); Wrapper wrapper = request.getWrapper(); if (wrapper != null) request.setAttribute(RequestDispatcher.ERROR_SERVLET_NAME, wrapper.getName()); request.setAttribute(RequestDispatcher.ERROR_REQUEST_URI, request.getRequestURI()); request.setAttribute(RequestDispatcher.ERROR_EXCEPTION_TYPE, realError.getClass()); if (custom(request, response, errorPage)) { try { response.finishResponse(); } catch (IOException e) { container.getLogger().warn("Exception Processing " + errorPage, e); } } } } else { // A custom error-page has not been defined for the exception // that was thrown during request processing. Check if an // error-page for error code 500 was specified and if so, // send that page back as the response. response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); // The response is an error response.setError(); status(request, response); } }
/** * 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()); } }