/** * Report and attempt to recover from {@code e}. Returns true if the HTTP engine was replaced and * the request should be retried. Otherwise the failure is permanent. */ private boolean handleFailure(IOException e) throws IOException { RouteSelector routeSelector = httpEngine.routeSelector; if (routeSelector != null && httpEngine.connection != null) { routeSelector.connectFailed(httpEngine.connection, e); } OutputStream requestBody = httpEngine.getRequestBody(); boolean canRetryRequestBody = requestBody == null || requestBody instanceof RetryableOutputStream || (faultRecoveringRequestBody != null && faultRecoveringRequestBody.isRecoverable()); if (routeSelector == null && httpEngine.connection == null // No connection. || routeSelector != null && !routeSelector.hasNext() // No more routes to attempt. || !isRecoverable(e) || !canRetryRequestBody) { httpEngineFailure = e; return false; } httpEngine.release(true); RetryableOutputStream retryableOutputStream = requestBody instanceof RetryableOutputStream ? (RetryableOutputStream) requestBody : null; httpEngine = newHttpEngine(method, rawRequestHeaders, null, retryableOutputStream); httpEngine.routeSelector = routeSelector; // Keep the same routeSelector. if (faultRecoveringRequestBody != null && faultRecoveringRequestBody.isRecoverable()) { httpEngine.sendRequest(); faultRecoveringRequestBody.replaceStream(httpEngine.getRequestBody()); } return true; }
/** * Sends a request and optionally reads a response. Returns true if the request was successfully * executed, and false if the request can be retried. Throws an exception if the request failed * permanently. */ private boolean execute(boolean readResponse) throws IOException { try { httpEngine.sendRequest(); if (readResponse) { httpEngine.readResponse(); } return true; } catch (IOException e) { if (handleFailure(e)) { return false; } else { throw e; } } }