All Downloads are FREE. Search and download functionalities are using the official Maven repository.

HTTPClient.RetryModule Maven / Gradle / Ivy

Go to download

Modified version of HTTPClient used by The Grinder. The original can be found at http://www.innovation.ch/java/HTTPClient/.

The newest version!
/*
 * @(#)RetryModule.java					0.3-3 06/05/2001
 *
 *  This file is part of the HTTPClient package
 *  Copyright (C) 1996-2001 Ronald Tschalär
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License as published by the Free Software Foundation; either
 *  version 2 of the License, or (at your option) any later version.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free
 *  Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA 02111-1307, USA
 *
 *  For questions, suggestions, bug-reports, enhancement-requests etc.
 *  I may be contacted at:
 *
 *  [email protected]
 *
 *  The HTTPClient's home page is located at:
 *
 *  http://www.innovation.ch/java/HTTPClient/ 
 *
 */

package HTTPClient;

import java.io.IOException;


/**
 * This module handles request retries when a connection closes prematurely.
 * It is triggered by the RetryException thrown by the StreamDemultiplexor.
 *
 * 

This module is somewhat unique in that it doesn't strictly limit itself * to the HTTPClientModule interface and its return values. That is, it * sends request directly using the HTTPConnection.sendRequest() method. This * is necessary because this module will not only resend its request but it * also resend all other requests in the chain. Also, it rethrows the * RetryException in Phase1 to restart the processing of the modules. * * @version 0.3-3 06/05/2001 * @author Ronald Tschalär * @since V0.3 */ class RetryModule implements HTTPClientModule, GlobalConstants { // Constructors /** */ RetryModule() { } // Methods /** * Invoked by the HTTPClient. */ public int requestHandler(Request req, Response[] resp) { return REQ_CONTINUE; } /** * Invoked by the HTTPClient. */ public void responsePhase1Handler(Response resp, RoRequest roreq) throws IOException, ModuleException { try { resp.getStatusCode(); } catch (RetryException re) { Log.write(Log.MODS, "RtryM: Caught RetryException"); boolean got_lock = false; try { synchronized (re.first) { got_lock = true; // initialize idempotent sequence checking IdempotentSequence seq = new IdempotentSequence(); for (RetryException e=re.first; e!=null; e=e.next) seq.add(e.request); for (RetryException e=re.first; e!=null; e=e.next) { Log.write(Log.MODS, "RtryM: handling exception ", e); Request req = e.request; HTTPConnection con = req.getConnection(); /* Don't retry if either the sequence is not idempotent * (Sec 8.1.4 and 9.1.2), or we've already retried enough * times, or the headers have been read and parsed * already */ if (!seq.isIdempotent(req) || (con.ServProtVersKnown && con.ServerProtocolVersion >= HTTP_1_1 && req.num_retries > 0) || ((!con.ServProtVersKnown || con.ServerProtocolVersion <= HTTP_1_0) && req.num_retries > 4) || e.response.got_headers) { e.first = null; continue; } /** * if an output stream was used (i.e. we don't have the * data to resend) then delegate the responsibility for * resending to the application. */ if (req.getStream() != null) { if (HTTPConnection.deferStreamed) { req.getStream().reset(); e.response.setRetryRequest(true); } e.first = null; continue; } /* If we have an entity then setup either the entity-delay * or the Expect header */ if (req.getData() != null && e.conn_reset) { if (con.ServProtVersKnown && con.ServerProtocolVersion >= HTTP_1_1) addToken(req, "Expect", "100-continue"); else req.delay_entity = 5000L << req.num_retries; } /* If the next request in line has an entity and we're * talking to an HTTP/1.0 server then close the socket * after this request. This is so that the available() * call (to watch for an error response from the server) * will work correctly. */ if (e.next != null && e.next.request.getData() != null && (!con.ServProtVersKnown || con.ServerProtocolVersion < HTTP_1_1) && e.conn_reset) { addToken(req, "Connection", "close"); } /* If this an HTTP/1.1 server then don't pipeline retries. * The problem is that if the server for some reason * decides not to use persistent connections and it does * not do a correct shutdown of the connection, then the * response will be ReSeT. If we did pipeline then we * would keep falling into this trap indefinitely. * * Note that for HTTP/1.0 servers, if they don't support * keep-alives then the normal code will already handle * this accordingly and won't pipe over the same * connection. */ if (con.ServProtVersKnown && con.ServerProtocolVersion >= HTTP_1_1 && e.conn_reset) { req.dont_pipeline = true; } // The above is too risky - for moment let's be safe // and never pipeline retried request at all. req.dont_pipeline = true; // now resend the request Log.write(Log.MODS, "RtryM: Retrying request '" + req.getMethod() + " " + req.getRequestURI() + "'"); if (e.conn_reset) req.num_retries++; e.response.http_resp.set(req, con.sendRequest(req, e.response.timeout)); e.exception = null; e.first = null; } } } catch (NullPointerException npe) { if (got_lock) throw npe; } catch (ParseException pe) { throw new IOException(pe.getMessage()); } if (re.exception != null) throw re.exception; re.restart = true; throw re; } } /** * Invoked by the HTTPClient. */ public int responsePhase2Handler(Response resp, Request req) { // reset any stuff we might have set previously req.delay_entity = 0; req.dont_pipeline = false; req.num_retries = 0; return RSP_CONTINUE; } /** * Invoked by the HTTPClient. */ public void responsePhase3Handler(Response resp, RoRequest req) { } /** * Invoked by the HTTPClient. */ public void trailerHandler(Response resp, RoRequest req) { } /** * Add a token to the given header. If the header does not exist then * create it with the given token. * * @param req the request who's headers are to be modified * @param hdr the name of the header to add the token to (or to create) * @param tok the token to add * @exception ParseException if parsing the header fails */ private void addToken(Request req, String hdr, String tok) throws ParseException { int idx; NVPair[] hdrs = req.getHeaders(); for (idx=0; idx





© 2015 - 2024 Weber Informatics LLC | Privacy Policy