/** * Used <code>retryCount</code> and <code>requestSentRetryEnabled</code> to determine if the given * method should be retried. * * @see HttpMethodRetryHandler#retryMethod(HttpMethod, IOException, int) */ public boolean retryMethod( final HttpMethod method, final IOException exception, int executionCount) { if (method == null) { throw new IllegalArgumentException("HTTP method may not be null"); } if (exception == null) { throw new IllegalArgumentException("Exception parameter may not be null"); } // HttpMethod interface is the WORST thing ever done to HttpClient if (method instanceof HttpMethodBase) { if (((HttpMethodBase) method).isAborted()) { return false; } } if (executionCount > this.retryCount) { // Do not retry if over max retry count return false; } if (exception instanceof NoHttpResponseException) { // Retry if the server dropped connection on us return true; } if (exception instanceof InterruptedIOException) { // Timeout return false; } if (exception instanceof UnknownHostException) { // Unknown host return false; } if (exception instanceof NoRouteToHostException) { // Host unreachable return false; } if (SSL_HANDSHAKE_EXCEPTION != null && SSL_HANDSHAKE_EXCEPTION.isInstance(exception)) { // SSL handshake exception return false; } if (!method.isRequestSent() || this.requestSentRetryEnabled) { // Retry if the request has not been sent fully or // if it's OK to retry methods that have been sent return true; } // otherwise do not retry return false; }
/** * Executes a method with the current hostConfiguration. * * @throws IOException if an I/O (transport) error occurs. Some transport exceptions can be * recovered from. * @throws HttpException if a protocol exception occurs. Usually protocol exceptions cannot be * recovered from. */ private void executeWithRetry(final HttpMethod method) throws IOException, HttpException { /** How many times did this transparently handle a recoverable exception? */ int execCount = 0; // loop until the method is successfully processed, the retryHandler // returns false or a non-recoverable exception is thrown try { while (true) { execCount++; try { if (LOG.isTraceEnabled()) { LOG.trace("Attempt number " + execCount + " to process request"); } if (this.conn.getParams().isStaleCheckingEnabled()) { this.conn.closeIfStale(); } if (!this.conn.isOpen()) { // this connection must be opened before it can be used // This has nothing to do with opening a secure tunnel this.conn.open(); if (this.conn.isProxied() && this.conn.isSecure() && !(method instanceof ConnectMethod)) { // we need to create a secure tunnel before we can execute the real method if (!executeConnect()) { // abort, the connect method failed return; } } } applyConnectionParams(method); method.execute(state, this.conn); break; } catch (HttpException e) { // filter out protocol exceptions which cannot be recovered from throw e; } catch (IOException e) { LOG.debug("Closing the connection."); this.conn.close(); // test if this method should be retried // ======================================== // this code is provided for backward compatibility with 2.0 // will be removed in the next major release if (method instanceof HttpMethodBase) { MethodRetryHandler handler = ((HttpMethodBase) method).getMethodRetryHandler(); if (handler != null) { if (!handler.retryMethod( method, this.conn, new HttpRecoverableException(e.getMessage()), execCount, method.isRequestSent())) { LOG.debug( "Method retry handler returned false. " + "Automatic recovery will not be attempted"); throw e; } } } // ======================================== HttpMethodRetryHandler handler = (HttpMethodRetryHandler) method.getParams().getParameter(HttpMethodParams.RETRY_HANDLER); if (handler == null) { handler = new DefaultHttpMethodRetryHandler(); } if (!handler.retryMethod(method, e, execCount)) { LOG.debug( "Method retry handler returned false. " + "Automatic recovery will not be attempted"); throw e; } if (LOG.isInfoEnabled()) { LOG.info( "I/O exception (" + e.getClass().getName() + ") caught when processing request: " + e.getMessage()); } if (LOG.isDebugEnabled()) { LOG.debug(e.getMessage(), e); } LOG.info("Retrying request"); } } } catch (IOException e) { if (this.conn.isOpen()) { LOG.debug("Closing the connection."); this.conn.close(); } releaseConnection = true; throw e; } catch (RuntimeException e) { if (this.conn.isOpen()) { LOG.debug("Closing the connection."); this.conn.close(); } releaseConnection = true; throw e; } }