private void handleThrowableOnSend(Throwable t) throws WsIOException { ExceptionUtils.handleThrowable(t); wsSession.getLocal().onError(wsSession, t); CloseReason cr = new CloseReason(CloseCodes.CLOSED_ABNORMALLY, sm.getString("wsFrame.ioeTriggeredClose")); throw new WsIOException(cr); }
/** Release the Filter instance associated with this FilterConfig, if there is one. */ void release() { unregisterJMX(); if (this.filter != null) { if (Globals.IS_SECURITY_ENABLED) { try { SecurityUtil.doAsPrivilege("destroy", filter); } catch (java.lang.Exception ex) { context.getLogger().error("ApplicationFilterConfig.doAsPrivilege", ex); } SecurityUtil.remove(filter); } else { filter.destroy(); } if (!context.getIgnoreAnnotations()) { try { ((StandardContext) context).getInstanceManager().destroyInstance(this.filter); } catch (Exception e) { Throwable t = ExceptionUtils.unwrapInvocationTargetException(e); ExceptionUtils.handleThrowable(t); context.getLogger().error("ApplicationFilterConfig.preDestroy", t); } } } this.filter = null; }
/** * Handle an HTTP status code or Java exception by forwarding control to the location included in * the specified errorPage object. It is assumed that the caller has already recorded any request * attributes that are to be forwarded to this page. Return <code>true</code> if we successfully * utilized the specified error page location, or <code>false</code> if the default error report * should be rendered. * * @param request The request being processed * @param response The response being generated * @param errorPage The errorPage directive we are obeying */ private boolean custom(Request request, Response response, ErrorPage errorPage) { if (container.getLogger().isDebugEnabled()) container.getLogger().debug("Processing " + errorPage); try { // Forward control to the specified location ServletContext servletContext = request.getContext().getServletContext(); RequestDispatcher rd = servletContext.getRequestDispatcher(errorPage.getLocation()); if (response.isCommitted()) { // Response is committed - including the error page is the // best we can do rd.include(request.getRequest(), response.getResponse()); } else { // Reset the response (keeping the real error code and message) response.resetBuffer(true); response.setContentLength(-1); rd.forward(request.getRequest(), response.getResponse()); // If we forward, the response is suspended again response.setSuspended(false); } // Indicate that we have successfully processed this custom page return (true); } catch (Throwable t) { ExceptionUtils.handleThrowable(t); // Report our failure to process this custom page container.getLogger().error("Exception Processing " + errorPage, t); return (false); } }
/** * Wrap the incoming value into quotes and escape any inner quotes with double quotes. * * @param value - The value to wrap quotes around * @return '-' if empty of null. Otherwise, toString() will be called on the object and the value * will be wrapped in quotes and any quotes will be escaped with 2 sets of quotes. */ private String wrap(Object value) { String svalue; // Does the value contain a " ? If so must encode it if (value == null || "-".equals(value)) return "-"; try { svalue = value.toString(); if ("".equals(svalue)) return "-"; } catch (Throwable e) { ExceptionUtils.handleThrowable(e); /* Log error */ return "-"; } /* Wrap all quotes in double quotes. */ StringBuilder buffer = new StringBuilder(svalue.length() + 2); buffer.append('\''); int i = 0; while (i < svalue.length()) { int j = svalue.indexOf('\'', i); if (j == -1) { buffer.append(svalue.substring(i)); i = svalue.length(); } else { buffer.append(svalue.substring(i, j + 1)); buffer.append('"'); i = j + 2; } } buffer.append('\''); return buffer.toString(); }
/** * The background thread that adds sockets to the Poller, checks the poller for triggered events * and hands the associated socket off to an appropriate processor as events occur. */ @Override public void run() { // Loop until destroy() is called while (true) { boolean hasEvents = false; try { if (!close) { hasEvents = events(); if (wakeupCounter.getAndSet(-1) > 0) { // if we are here, means we have other stuff to do // do a non blocking select keyCount = selector.selectNow(); } else { keyCount = selector.select(selectorTimeout); } wakeupCounter.set(0); } if (close) { events(); timeout(0, false); try { selector.close(); } catch (IOException ioe) { log.error(sm.getString("endpoint.nio.selectorCloseFail"), ioe); } break; } } catch (Throwable x) { ExceptionUtils.handleThrowable(x); log.error("", x); continue; } // either we timed out or we woke up, process events first if (keyCount == 0) hasEvents = (hasEvents | events()); Iterator<SelectionKey> iterator = keyCount > 0 ? selector.selectedKeys().iterator() : null; // Walk through the collection of ready keys and dispatch // any active event. while (iterator != null && iterator.hasNext()) { SelectionKey sk = iterator.next(); NioSocketWrapper attachment = (NioSocketWrapper) sk.attachment(); // Attachment may be null if another thread has called // cancelledKey() if (attachment == null) { iterator.remove(); } else { iterator.remove(); processKey(sk, attachment); } } // while // process timeouts timeout(keyCount, hasEvents); } // while stopLatch.countDown(); }
protected final void handlePojoMethodException(Throwable t) { t = ExceptionUtils.unwrapInvocationTargetException(t); ExceptionUtils.handleThrowable(t); if (t instanceof RuntimeException) { throw (RuntimeException) t; } else { throw new RuntimeException(t); } }
/** * Set the Valve instance that has been distinguished as the basic Valve for this Pipeline (if * any). Prior to setting the basic Valve, the Valve's <code>setContainer()</code> will be called, * if it implements <code>Contained</code>, with the owning Container as an argument. The method * may throw an <code>IllegalArgumentException</code> if this Valve chooses not to be associated * with this Container, or <code>IllegalStateException</code> if it is already associated with a * different Container. * * @param valve Valve to be distinguished as the basic Valve */ @Override public void setBasic(Valve valve) { // Change components if necessary Valve oldBasic = this.basic; if (oldBasic == valve) return; // Stop the old component if necessary if (oldBasic != null) { if (getState().isAvailable() && (oldBasic instanceof Lifecycle)) { try { ((Lifecycle) oldBasic).stop(); } catch (LifecycleException e) { log.error("StandardPipeline.setBasic: stop", e); } } if (oldBasic instanceof Contained) { try { ((Contained) oldBasic).setContainer(null); } catch (Throwable t) { ExceptionUtils.handleThrowable(t); } } } // Start the new component if necessary if (valve == null) return; if (valve instanceof Contained) { ((Contained) valve).setContainer(this.container); } if (getState().isAvailable() && valve instanceof Lifecycle) { try { ((Lifecycle) valve).start(); } catch (LifecycleException e) { log.error("StandardPipeline.setBasic: start", e); return; } } // Update the pipeline Valve current = first; while (current != null) { if (current.getNext() == oldBasic) { current.setNext(valve); break; } current = current.getNext(); } this.basic = valve; }
/** * Process the specified connection. * * @param socket The socket channel * @return <code>true</code> if the socket was correctly configured and processing may continue, * <code>false</code> if the socket needs to be close immediately */ protected boolean setSocketOptions(SocketChannel socket) { // Process the connection try { // disable blocking, APR style, we are gonna be polling it socket.configureBlocking(false); Socket sock = socket.socket(); socketProperties.setProperties(sock); NioChannel channel = nioChannels.pop(); if (channel == null) { SocketBufferHandler bufhandler = new SocketBufferHandler( socketProperties.getAppReadBufSize(), socketProperties.getAppWriteBufSize(), socketProperties.getDirectBuffer()); if (isSSLEnabled()) { channel = new SecureNioChannel(socket, bufhandler, selectorPool, this); } else { channel = new NioChannel(socket, bufhandler); } } else { channel.setIOChannel(socket); channel.reset(); } getPoller0().register(channel); } catch (Throwable t) { ExceptionUtils.handleThrowable(t); try { log.error("", t); } catch (Throwable tt) { ExceptionUtils.handleThrowable(tt); } // Tell to close the socket return false; } return true; }
@Override public void log(org.apache.coyote.Request req, org.apache.coyote.Response res, long time) { Request request = (Request) req.getNote(ADAPTER_NOTES); Response response = (Response) res.getNote(ADAPTER_NOTES); if (request == null) { // Create objects request = connector.createRequest(); request.setCoyoteRequest(req); response = connector.createResponse(); response.setCoyoteResponse(res); // Link objects request.setResponse(response); response.setRequest(request); // Set as notes req.setNote(ADAPTER_NOTES, request); res.setNote(ADAPTER_NOTES, response); // Set query string encoding req.getParameters().setQueryStringEncoding(connector.getURIEncoding()); } try { // Log at the lowest level available. logAccess() will be // automatically called on parent containers. boolean logged = false; if (request.mappingData != null) { if (request.mappingData.context != null) { logged = true; ((Context) request.mappingData.context).logAccess(request, response, time, true); } else if (request.mappingData.host != null) { logged = true; ((Host) request.mappingData.host).logAccess(request, response, time, true); } } if (!logged) { connector.getService().getContainer().logAccess(request, response, time, true); } } catch (Throwable t) { ExceptionUtils.handleThrowable(t); log.warn(sm.getString("coyoteAdapter.accesslogFail"), t); } finally { request.recycle(); response.recycle(); } }
private void fireEndpointOnClose(CloseReason closeReason) { // Fire the onClose event Thread t = Thread.currentThread(); ClassLoader cl = t.getContextClassLoader(); t.setContextClassLoader(applicationClassLoader); try { localEndpoint.onClose(this, closeReason); } catch (Throwable throwable) { ExceptionUtils.handleThrowable(throwable); localEndpoint.onError(this, throwable); } finally { t.setContextClassLoader(cl); } }
public NioSocketWrapper cancelledKey(SelectionKey key) { NioSocketWrapper ka = null; try { if (key == null) return null; // nothing to do ka = (NioSocketWrapper) key.attach(null); if (ka != null) { // If attachment is non-null then there may be a current // connection with an associated processor. getHandler().release(ka); } if (key.isValid()) key.cancel(); if (key.channel().isOpen()) { try { key.channel().close(); } catch (Exception e) { if (log.isDebugEnabled()) { log.debug(sm.getString("endpoint.debug.channelCloseFail"), e); } } } try { if (ka != null) { ka.getSocket().close(true); } } catch (Exception e) { if (log.isDebugEnabled()) { log.debug(sm.getString("endpoint.debug.socketCloseFail"), e); } } try { if (ka != null && ka.getSendfileData() != null && ka.getSendfileData().fchannel != null && ka.getSendfileData().fchannel.isOpen()) { ka.getSendfileData().fchannel.close(); } } catch (Exception ignore) { } if (ka != null) { countDownConnection(); } } catch (Throwable e) { ExceptionUtils.handleThrowable(e); if (log.isDebugEnabled()) log.error("", e); } return ka; }
/** * Use reflection to invoke the requested method. Cache the method object to speed up the process * * @param methodName The method to invoke. * @param clazz The class where the method is. * @param params The arguments passed to the called method. */ private Object doPrivileged(final String methodName, final Class<?>[] clazz, Object[] params) { try { Method method = context.getClass().getMethod(methodName, clazz); return executeMethod(method, context, params); } catch (Exception ex) { try { handleException(ex); } catch (Throwable t) { ExceptionUtils.handleThrowable(t); throw new RuntimeException(t.getMessage()); } return null; } finally { params = null; } }
/** @deprecated */ @Override @Deprecated public Servlet getServlet(String name) throws ServletException { if (SecurityUtil.isPackageProtectionEnabled()) { try { return (Servlet) invokeMethod(context, "getServlet", new Object[] {name}); } catch (Throwable t) { ExceptionUtils.handleThrowable(t); if (t instanceof ServletException) { throw (ServletException) t; } return null; } } else { return context.getServlet(name); } }
@Override @SuppressWarnings("unchecked") // doPrivileged() returns the correct type public <T extends EventListener> T createListener(Class<T> c) throws ServletException { if (SecurityUtil.isPackageProtectionEnabled()) { try { return (T) invokeMethod(context, "createListener", new Object[] {c}); } catch (Throwable t) { ExceptionUtils.handleThrowable(t); if (t instanceof ServletException) { throw (ServletException) t; } return null; } } else { return context.createListener(c); } }
/** * Attempt to load a class using the given Container's class loader. If the class cannot be * loaded, a debug level log message will be written to the Container's log and null will be * returned. */ public static Class<?> loadClass(Context context, String className) { ClassLoader cl = context.getLoader().getClassLoader(); Log log = context.getLogger(); Class<?> clazz = null; try { clazz = cl.loadClass(className); } catch (ClassNotFoundException e) { log.debug(sm.getString("introspection.classLoadFailed", className), e); } catch (NoClassDefFoundError e) { log.debug(sm.getString("introspection.classLoadFailed", className), e); } catch (ClassFormatError e) { log.debug(sm.getString("introspection.classLoadFailed", className), e); } catch (Throwable t) { ExceptionUtils.handleThrowable(t); log.debug(sm.getString("introspection.classLoadFailed", className), t); } return clazz; }
@Override public void run() { try { if (getServer() != null) { Catalina.this.stop(); } } catch (Throwable ex) { ExceptionUtils.handleThrowable(ex); log.error(sm.getString("catalina.shutdownHookFail"), ex); } finally { // If JULI is used, shut JULI down *after* the server shuts down // so log messages aren't lost LogManager logManager = LogManager.getLogManager(); if (logManager instanceof ClassLoaderLogManager) { ((ClassLoaderLogManager) logManager).shutdown(); } } }
/** * Set the filter definition we are configured for. This has the side effect of instantiating an * instance of the corresponding filter class. * * @param filterDef The new filter definition * @exception ClassCastException if the specified class does not implement the <code> * javax.servlet.Filter</code> interface * @exception ClassNotFoundException if the filter class cannot be found * @exception IllegalAccessException if the filter class cannot be publicly instantiated * @exception InstantiationException if an exception occurs while instantiating the filter object * @exception ServletException if thrown by the filter's init() method * @throws NamingException * @throws InvocationTargetException */ void setFilterDef(FilterDef filterDef) throws ClassCastException, ClassNotFoundException, IllegalAccessException, InstantiationException, ServletException, InvocationTargetException, NamingException { this.filterDef = filterDef; if (filterDef == null) { // Release any previously allocated filter instance if (this.filter != null) { if (Globals.IS_SECURITY_ENABLED) { try { SecurityUtil.doAsPrivilege("destroy", filter); } catch (java.lang.Exception ex) { context.getLogger().error("ApplicationFilterConfig.doAsPrivilege", ex); } SecurityUtil.remove(filter); } else { filter.destroy(); } if (!context.getIgnoreAnnotations()) { try { ((StandardContext) context).getInstanceManager().destroyInstance(this.filter); } catch (Exception e) { Throwable t = ExceptionUtils.unwrapInvocationTargetException(e); ExceptionUtils.handleThrowable(t); context.getLogger().error("ApplicationFilterConfig.preDestroy", t); } } } this.filter = null; } else { // Allocate a new filter instance if necessary if (filterDef.getFilter() == null) { getFilter(); } } }
protected void processKey(SelectionKey sk, NioSocketWrapper attachment) { try { if (close) { cancelledKey(sk); } else if (sk.isValid() && attachment != null) { if (sk.isReadable() || sk.isWritable()) { if (attachment.getSendfileData() != null) { processSendfile(sk, attachment, false); } else { unreg(sk, attachment, sk.readyOps()); boolean closeSocket = false; // Read goes before write if (sk.isReadable()) { if (!processSocket(attachment, SocketEvent.OPEN_READ, true)) { closeSocket = true; } } if (!closeSocket && sk.isWritable()) { if (!processSocket(attachment, SocketEvent.OPEN_WRITE, true)) { closeSocket = true; } } if (closeSocket) { cancelledKey(sk); } } } } else { // invalid key cancelledKey(sk); } } catch (CancelledKeyException ckx) { cancelledKey(sk); } catch (Throwable t) { ExceptionUtils.handleThrowable(t); log.error("", t); } }
/** Stop an existing server instance. */ public void stop() { try { // Remove the ShutdownHook first so that server.stop() // doesn't get invoked twice if (useShutdownHook) { Runtime.getRuntime().removeShutdownHook(shutdownHook); // If JULI is being used, re-enable JULI's shutdown to ensure // log messages are not lost LogManager logManager = LogManager.getLogManager(); if (logManager instanceof ClassLoaderLogManager) { ((ClassLoaderLogManager) logManager).setUseShutdownHook(true); } } } catch (Throwable t) { ExceptionUtils.handleThrowable(t); // This will fail on JDK 1.2. Ignoring, as Tomcat can run // fine without the shutdown hook. } // Shut down the server try { Server s = getServer(); LifecycleState state = s.getState(); if (LifecycleState.STOPPING_PREP.compareTo(state) <= 0 && LifecycleState.DESTROYED.compareTo(state) >= 0) { // Nothing to do. stop() was already called } else { s.stop(); s.destroy(); } } catch (LifecycleException e) { log.error("Catalina.stop", e); } }
/** * 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()); } }
@Override public boolean asyncDispatch( org.apache.coyote.Request req, org.apache.coyote.Response res, SocketStatus status) throws Exception { Request request = (Request) req.getNote(ADAPTER_NOTES); Response response = (Response) res.getNote(ADAPTER_NOTES); if (request == null) { throw new IllegalStateException("Dispatch may only happen on an existing request."); } boolean comet = false; boolean success = true; AsyncContextImpl asyncConImpl = (AsyncContextImpl) request.getAsyncContext(); req.getRequestProcessor().setWorkerThreadName(Thread.currentThread().getName()); try { if (!request.isAsync() && !comet) { // Error or timeout - need to tell listeners the request is over // Have to test this first since state may change while in this // method and this is only required if entering this method in // this state Context ctxt = (Context) request.getMappingData().context; if (ctxt != null) { ctxt.fireRequestDestroyEvent(request); } // Lift any suspension (e.g. if sendError() was used by an async // request) to allow the response to be written to the client response.setSuspended(false); } if (status == SocketStatus.TIMEOUT) { if (!asyncConImpl.timeout()) { asyncConImpl.setErrorState(null, false); } } // Has an error occurred during async processing that needs to be // processed by the application's error page mechanism (or Tomcat's // if the application doesn't define one)? if (!request.isAsyncDispatching() && request.isAsync() && response.isErrorReportRequired()) { connector.getService().getContainer().getPipeline().getFirst().invoke(request, response); } if (request.isAsyncDispatching()) { connector.getService().getContainer().getPipeline().getFirst().invoke(request, response); Throwable t = (Throwable) request.getAttribute(RequestDispatcher.ERROR_EXCEPTION); if (t != null) { asyncConImpl.setErrorState(t, true); } } if (request.isComet()) { if (!response.isClosed() && !response.isError()) { if (request.getAvailable() || (request.getContentLength() > 0 && (!request.isParametersParsed()))) { // Invoke a read event right away if there are available bytes if (event(req, res, SocketStatus.OPEN_READ)) { comet = true; res.action(ActionCode.COMET_BEGIN, null); } } else { comet = true; res.action(ActionCode.COMET_BEGIN, null); } } else { // Clear the filter chain, as otherwise it will not be reset elsewhere // since this is a Comet request request.setFilterChain(null); } } if (!request.isAsync() && !comet) { request.finishRequest(); response.finishResponse(); req.action(ActionCode.POST_REQUEST, null); ((Context) request.getMappingData().context) .logAccess(request, response, System.currentTimeMillis() - req.getStartTime(), false); } // Check to see if the processor is in an error state. If it is, // bail out now. AtomicBoolean error = new AtomicBoolean(false); res.action(ActionCode.IS_ERROR, error); if (error.get()) { success = false; } } catch (IOException e) { success = false; // Ignore } catch (Throwable t) { ExceptionUtils.handleThrowable(t); success = false; log.error(sm.getString("coyoteAdapter.service"), t); } finally { req.getRequestProcessor().setWorkerThreadName(null); // Recycle the wrapper request and response if (!success || (!comet && !request.isAsync())) { request.recycle(); response.recycle(); } else { // Clear converters so that the minimum amount of memory // is used by this processor request.clearEncoders(); response.clearEncoders(); } } return success; }
/** * Event method. * * @return false to indicate an error, expected or not */ @Override public boolean event( org.apache.coyote.Request req, org.apache.coyote.Response res, SocketStatus status) { Request request = (Request) req.getNote(ADAPTER_NOTES); Response response = (Response) res.getNote(ADAPTER_NOTES); if (request.getWrapper() == null) { return false; } boolean error = false; boolean read = false; try { if (status == SocketStatus.OPEN_READ) { if (response.isClosed()) { // The event has been closed asynchronously, so call end instead of // read to cleanup the pipeline request.getEvent().setEventType(CometEvent.EventType.END); request.getEvent().setEventSubType(null); } else { try { // Fill the read buffer of the servlet layer if (request.read()) { read = true; } } catch (IOException e) { error = true; } if (read) { request.getEvent().setEventType(CometEvent.EventType.READ); request.getEvent().setEventSubType(null); } else if (error) { request.getEvent().setEventType(CometEvent.EventType.ERROR); request.getEvent().setEventSubType(CometEvent.EventSubType.CLIENT_DISCONNECT); } else { request.getEvent().setEventType(CometEvent.EventType.END); request.getEvent().setEventSubType(null); } } } else if (status == SocketStatus.DISCONNECT) { request.getEvent().setEventType(CometEvent.EventType.ERROR); request.getEvent().setEventSubType(CometEvent.EventSubType.CLIENT_DISCONNECT); error = true; } else if (status == SocketStatus.ERROR) { request.getEvent().setEventType(CometEvent.EventType.ERROR); request.getEvent().setEventSubType(CometEvent.EventSubType.IOEXCEPTION); error = true; } else if (status == SocketStatus.STOP) { request.getEvent().setEventType(CometEvent.EventType.END); request.getEvent().setEventSubType(CometEvent.EventSubType.SERVER_SHUTDOWN); } else if (status == SocketStatus.TIMEOUT) { if (response.isClosed()) { // The event has been closed asynchronously, so call end instead of // read to cleanup the pipeline request.getEvent().setEventType(CometEvent.EventType.END); request.getEvent().setEventSubType(null); } else { request.getEvent().setEventType(CometEvent.EventType.ERROR); request.getEvent().setEventSubType(CometEvent.EventSubType.TIMEOUT); } } req.getRequestProcessor().setWorkerThreadName(Thread.currentThread().getName()); // Calling the container connector .getService() .getContainer() .getPipeline() .getFirst() .event(request, response, request.getEvent()); if (!error && !response.isClosed() && (request.getAttribute(RequestDispatcher.ERROR_EXCEPTION) != null)) { // An unexpected exception occurred while processing the event, so // error should be called request.getEvent().setEventType(CometEvent.EventType.ERROR); request.getEvent().setEventSubType(null); error = true; connector .getService() .getContainer() .getPipeline() .getFirst() .event(request, response, request.getEvent()); } if (response.isClosed() || !request.isComet()) { if (status == SocketStatus.OPEN_READ && request.getEvent().getEventType() != EventType.END) { // CometEvent.close was called during an event other than END request.getEvent().setEventType(CometEvent.EventType.END); request.getEvent().setEventSubType(null); error = true; connector .getService() .getContainer() .getPipeline() .getFirst() .event(request, response, request.getEvent()); } res.action(ActionCode.COMET_END, null); } else if (!error && read && request.getAvailable()) { // If this was a read and not all bytes have been read, or if no data // was read from the connector, then it is an error request.getEvent().setEventType(CometEvent.EventType.ERROR); request.getEvent().setEventSubType(CometEvent.EventSubType.IOEXCEPTION); error = true; connector .getService() .getContainer() .getPipeline() .getFirst() .event(request, response, request.getEvent()); } return (!error); } catch (Throwable t) { ExceptionUtils.handleThrowable(t); if (!(t instanceof IOException)) { log.error(sm.getString("coyoteAdapter.service"), t); } error = true; return false; } finally { req.getRequestProcessor().setWorkerThreadName(null); // Recycle the wrapper request and response if (error || response.isClosed() || !request.isComet()) { ((Context) request.getMappingData().context) .logAccess(request, response, System.currentTimeMillis() - req.getStartTime(), false); request.recycle(); request.setFilterChain(null); response.recycle(); } } }
/** * Perform work as a particular </code>Subject</code>. Here the work will be granted to a <code> * null</code> subject. * * @param methodName the method to apply the security restriction * @param targetObject the <code>Servlet</code> on which the method will be called. * @param targetArguments <code>Object</code> array contains the runtime parameters instance. * @param principal the <code>Principal</code> to which the security privilege applies */ private static void execute( final Method method, final Object targetObject, final Object[] targetArguments, Principal principal) throws java.lang.Exception { try { Subject subject = null; PrivilegedExceptionAction<Void> pea = new PrivilegedExceptionAction<Void>() { @Override public Void run() throws Exception { method.invoke(targetObject, targetArguments); return null; } }; // The first argument is always the request object if (targetArguments != null && targetArguments[0] instanceof HttpServletRequest) { HttpServletRequest request = (HttpServletRequest) targetArguments[0]; boolean hasSubject = false; HttpSession session = request.getSession(false); if (session != null) { subject = (Subject) session.getAttribute(Globals.SUBJECT_ATTR); hasSubject = (subject != null); } if (subject == null) { subject = new Subject(); if (principal != null) { subject.getPrincipals().add(principal); } } if (session != null && !hasSubject) { session.setAttribute(Globals.SUBJECT_ATTR, subject); } } Subject.doAsPrivileged(subject, pea, null); } catch (PrivilegedActionException pe) { Throwable e; if (pe.getException() instanceof InvocationTargetException) { e = pe.getException().getCause(); ExceptionUtils.handleThrowable(e); } else { e = pe; } if (log.isDebugEnabled()) { log.debug(sm.getString("SecurityUtil.doAsPrivilege"), e); } if (e instanceof UnavailableException) throw (UnavailableException) e; else if (e instanceof ServletException) throw (ServletException) e; else if (e instanceof IOException) throw (IOException) e; else if (e instanceof RuntimeException) throw (RuntimeException) e; else throw new ServletException(e.getMessage(), e); } }
/** * Process pipelined HTTP requests using the specified input and output streams. * * @throws IOException error during an I/O operation */ @Override public SocketState process(SocketWrapper<NioChannel> socket) throws IOException { RequestInfo rp = request.getRequestProcessor(); rp.setStage(org.apache.coyote.Constants.STAGE_PARSE); // Setting up the socket this.socketWrapper = socket; long soTimeout = endpoint.getSoTimeout(); boolean cping = false; // Error flag error = false; while (!error && !endpoint.isPaused()) { // Parsing the request header try { // Get first message of the request int bytesRead = readMessage(requestHeaderMessage, false); if (bytesRead == 0) { break; } // Set back timeout if keep alive timeout is enabled if (keepAliveTimeout > 0) { socket.setTimeout(soTimeout); } // Check message type, process right away and break if // not regular request processing int type = requestHeaderMessage.getByte(); if (type == Constants.JK_AJP13_CPING_REQUEST) { if (endpoint.isPaused()) { recycle(true); break; } cping = true; try { output(pongMessageArray, 0, pongMessageArray.length); } catch (IOException e) { error = true; } recycle(false); continue; } else if (type != Constants.JK_AJP13_FORWARD_REQUEST) { // Unexpected packet type. Unread body packets should have // been swallowed in finish(). if (log.isDebugEnabled()) { log.debug("Unexpected message: " + type); } error = true; recycle(true); break; } request.setStartTime(System.currentTimeMillis()); } catch (IOException e) { error = true; break; } catch (Throwable t) { ExceptionUtils.handleThrowable(t); log.debug(sm.getString("ajpprocessor.header.error"), t); // 400 - Bad Request response.setStatus(400); adapter.log(request, response, 0); error = true; } if (!error) { // Setting up filters, and parse some request headers rp.setStage(org.apache.coyote.Constants.STAGE_PREPARE); try { prepareRequest(); } catch (Throwable t) { ExceptionUtils.handleThrowable(t); log.debug(sm.getString("ajpprocessor.request.prepare"), t); // 400 - Internal Server Error response.setStatus(400); adapter.log(request, response, 0); error = true; } } if (!error && !cping && endpoint.isPaused()) { // 503 - Service unavailable response.setStatus(503); adapter.log(request, response, 0); error = true; } cping = false; // Process the request in the adapter if (!error) { try { rp.setStage(org.apache.coyote.Constants.STAGE_SERVICE); adapter.service(request, response); } catch (InterruptedIOException e) { error = true; } catch (Throwable t) { ExceptionUtils.handleThrowable(t); log.error(sm.getString("ajpprocessor.request.process"), t); // 500 - Internal Server Error response.setStatus(500); adapter.log(request, response, 0); error = true; } } if (isAsync() && !error) { break; } // Finish the response if not done yet if (!finished) { try { finish(); } catch (Throwable t) { ExceptionUtils.handleThrowable(t); error = true; } } // If there was an error, make sure the request is counted as // and error, and update the statistics counter if (error) { response.setStatus(500); } request.updateCounters(); rp.setStage(org.apache.coyote.Constants.STAGE_KEEPALIVE); // Set keep alive timeout if enabled if (keepAliveTimeout > 0) { socket.setTimeout(keepAliveTimeout); } recycle(false); } rp.setStage(org.apache.coyote.Constants.STAGE_ENDED); if (!error && !endpoint.isPaused()) { if (isAsync()) { return SocketState.LONG; } else { return SocketState.OPEN; } } else { return SocketState.CLOSED; } }
@Override protected void doRun() { NioChannel socket = socketWrapper.getSocket(); SelectionKey key = socket.getIOChannel().keyFor(socket.getPoller().getSelector()); try { int handshake = -1; try { if (key != null) { // For STOP there is no point trying to handshake as the // Poller has been stopped. if (socket.isHandshakeComplete() || event == SocketEvent.STOP) { handshake = 0; } else { handshake = socket.handshake(key.isReadable(), key.isWritable()); // The handshake process reads/writes from/to the // socket. status may therefore be OPEN_WRITE once // the handshake completes. However, the handshake // happens when the socket is opened so the status // must always be OPEN_READ after it completes. It // is OK to always set this as it is only used if // the handshake completes. event = SocketEvent.OPEN_READ; } } } catch (IOException x) { handshake = -1; if (log.isDebugEnabled()) log.debug("Error during SSL handshake", x); } catch (CancelledKeyException ckx) { handshake = -1; } if (handshake == 0) { SocketState state = SocketState.OPEN; // Process the request from this socket if (event == null) { state = getHandler().process(socketWrapper, SocketEvent.OPEN_READ); } else { state = getHandler().process(socketWrapper, event); } if (state == SocketState.CLOSED) { close(socket, key); } } else if (handshake == -1) { close(socket, key); } else if (handshake == SelectionKey.OP_READ) { socketWrapper.registerReadInterest(); } else if (handshake == SelectionKey.OP_WRITE) { socketWrapper.registerWriteInterest(); } } catch (CancelledKeyException cx) { socket.getPoller().cancelledKey(key); } catch (VirtualMachineError vme) { ExceptionUtils.handleThrowable(vme); } catch (Throwable t) { log.error("", t); socket.getPoller().cancelledKey(key); } finally { socketWrapper = null; event = null; // return to cache if (running && !paused) { processorCache.push(this); } } }
@Override public void run() { int errorDelay = 0; // Loop until we receive a shutdown command while (running) { // Loop if endpoint is paused while (paused && running) { state = AcceptorState.PAUSED; try { Thread.sleep(50); } catch (InterruptedException e) { // Ignore } } if (!running) { break; } state = AcceptorState.RUNNING; try { // if we have reached max connections, wait countUpOrAwaitConnection(); SocketChannel socket = null; try { // Accept the next incoming connection from the server // socket socket = serverSock.accept(); } catch (IOException ioe) { // we didn't get a socket countDownConnection(); // Introduce delay if necessary errorDelay = handleExceptionWithDelay(errorDelay); // re-throw throw ioe; } // Successful accept, reset the error delay errorDelay = 0; // setSocketOptions() will add channel to the poller // if successful if (running && !paused) { if (!setSocketOptions(socket)) { countDownConnection(); closeSocket(socket); } } else { countDownConnection(); closeSocket(socket); } } catch (SocketTimeoutException sx) { // Ignore: Normal condition } catch (IOException x) { if (running) { log.error(sm.getString("endpoint.accept.fail"), x); } } catch (Throwable t) { ExceptionUtils.handleThrowable(t); log.error(sm.getString("endpoint.accept.fail"), t); } } state = AcceptorState.ENDED; }
@SuppressWarnings("deprecation") // Old HTTP upgrade method has been deprecated public SocketState process(SocketWrapper<S> wrapper, SocketStatus status) { if (wrapper == null) { // Nothing to do. Socket has been closed. return SocketState.CLOSED; } S socket = wrapper.getSocket(); if (socket == null) { // Nothing to do. Socket has been closed. return SocketState.CLOSED; } Processor<S> processor = connections.get(socket); if (status == SocketStatus.DISCONNECT && processor == null) { // Nothing to do. Endpoint requested a close and there is no // longer a processor associated with this socket. return SocketState.CLOSED; } wrapper.setAsync(false); ContainerThreadMarker.markAsContainerThread(); try { if (processor == null) { processor = recycledProcessors.poll(); } if (processor == null) { processor = createProcessor(); } initSsl(wrapper, processor); SocketState state = SocketState.CLOSED; do { if (status == SocketStatus.CLOSE_NOW) { processor.errorDispatch(); state = SocketState.CLOSED; } else if (status == SocketStatus.DISCONNECT && !processor.isComet()) { // Do nothing here, just wait for it to get recycled // Don't do this for Comet we need to generate an end // event (see BZ 54022) } else if (processor.isAsync()) { state = processor.asyncDispatch(status); } else if (state == SocketState.ASYNC_END) { state = processor.asyncDispatch(status); // release() won't get called so in case this request // takes a long time to process remove the socket from // the waiting requests now else the async timeout will // fire getProtocol().endpoint.removeWaitingRequest(wrapper); if (state == SocketState.OPEN) { // There may be pipe-lined data to read. If the data // isn't processed now, execution will exit this // loop and call release() which will recycle the // processor (and input buffer) deleting any // pipe-lined data. To avoid this, process it now. state = processor.process(wrapper); } } else if (processor.isComet()) { state = processor.event(status); } else if (processor.getUpgradeInbound() != null) { state = processor.upgradeDispatch(); } else if (processor.isUpgrade()) { state = processor.upgradeDispatch(status); } else { state = processor.process(wrapper); } if (state != SocketState.CLOSED && processor.isAsync()) { state = processor.asyncPostProcess(); } if (state == SocketState.UPGRADING) { // Get the HTTP upgrade handler HttpUpgradeHandler httpUpgradeHandler = processor.getHttpUpgradeHandler(); // Release the Http11 processor to be re-used release(wrapper, processor, false, false); // Create the upgrade processor processor = createUpgradeProcessor(wrapper, httpUpgradeHandler); // Mark the connection as upgraded wrapper.setUpgraded(true); // Associate with the processor with the connection connections.put(socket, processor); // Initialise the upgrade handler (which may trigger // some IO using the new protocol which is why the lines // above are necessary) // This cast should be safe. If it fails the error // handling for the surrounding try/catch will deal with // it. httpUpgradeHandler.init((WebConnection) processor); } else if (state == SocketState.UPGRADING_TOMCAT) { // Get the UpgradeInbound handler org.apache.coyote.http11.upgrade.UpgradeInbound inbound = processor.getUpgradeInbound(); // Release the Http11 processor to be re-used release(wrapper, processor, false, false); // Create the light-weight upgrade processor processor = createUpgradeProcessor(wrapper, inbound); inbound.onUpgradeComplete(); } if (getLog().isDebugEnabled()) { getLog() .debug( "Socket: [" + wrapper + "], Status in: [" + status + "], State out: [" + state + "]"); } } while (state == SocketState.ASYNC_END || state == SocketState.UPGRADING || state == SocketState.UPGRADING_TOMCAT); if (state == SocketState.LONG) { // In the middle of processing a request/response. Keep the // socket associated with the processor. Exact requirements // depend on type of long poll connections.put(socket, processor); longPoll(wrapper, processor); } else if (state == SocketState.OPEN) { // In keep-alive but between requests. OK to recycle // processor. Continue to poll for the next request. connections.remove(socket); release(wrapper, processor, false, true); } else if (state == SocketState.SENDFILE) { // Sendfile in progress. If it fails, the socket will be // closed. If it works, the socket will be re-added to the // poller connections.remove(socket); release(wrapper, processor, false, false); } else if (state == SocketState.UPGRADED) { // Need to keep the connection associated with the processor connections.put(socket, processor); // Don't add sockets back to the poller if this was a // non-blocking write otherwise the poller may trigger // multiple read events which may lead to thread starvation // in the connector. The write() method will add this socket // to the poller if necessary. if (status != SocketStatus.OPEN_WRITE) { longPoll(wrapper, processor); } } else { // Connection closed. OK to recycle the processor. Upgrade // processors are not recycled. connections.remove(socket); if (processor.isUpgrade()) { processor.getHttpUpgradeHandler().destroy(); } else if (processor instanceof org.apache.coyote.http11.upgrade.UpgradeProcessor) { // NO-OP } else { release(wrapper, processor, true, false); } } return state; } catch (java.net.SocketException e) { // SocketExceptions are normal getLog().debug(sm.getString("abstractConnectionHandler.socketexception.debug"), e); } catch (java.io.IOException e) { // IOExceptions are normal getLog().debug(sm.getString("abstractConnectionHandler.ioexception.debug"), e); } // Future developers: if you discover any other // rare-but-nonfatal exceptions, catch them here, and log as // above. catch (Throwable e) { ExceptionUtils.handleThrowable(e); // any other exception or error is odd. Here we log it // with "ERROR" level, so it will show up even on // less-than-verbose logs. getLog().error(sm.getString("abstractConnectionHandler.error"), e); } // Make sure socket/processor is removed from the list of current // connections connections.remove(socket); // Don't try to add upgrade processors back into the pool if (!(processor instanceof org.apache.coyote.http11.upgrade.UpgradeProcessor) && !processor.isUpgrade()) { release(wrapper, processor, true, false); } return SocketState.CLOSED; }