Return-Path: Delivered-To: apmail-jakarta-commons-dev-archive@apache.org Received: (qmail 85930 invoked from network); 8 Jul 2002 14:51:41 -0000 Received: from unknown (HELO nagoya.betaversion.org) (192.18.49.131) by daedalus.apache.org with SMTP; 8 Jul 2002 14:51:41 -0000 Received: (qmail 15497 invoked by uid 97); 8 Jul 2002 14:51:06 -0000 Delivered-To: qmlist-jakarta-archive-commons-dev@jakarta.apache.org Received: (qmail 15185 invoked by uid 97); 8 Jul 2002 14:51:04 -0000 Mailing-List: contact commons-dev-help@jakarta.apache.org; run by ezmlm Precedence: bulk List-Unsubscribe: List-Subscribe: List-Help: List-Post: List-Id: "Jakarta Commons Developers List" Reply-To: "Jakarta Commons Developers List" Delivered-To: mailing list commons-dev@jakarta.apache.org Received: (qmail 15036 invoked by uid 98); 8 Jul 2002 14:51:03 -0000 X-Antivirus: nagoya (v4198 created Apr 24 2002) Subject: [HttpClient] [Patch] Proxies From: Evert Hoff To: Jakarta Commons Developers List In-Reply-To: <3D273DA5.382CB9B2@sympatico.ca> References: <3D273DA5.382CB9B2@sympatico.ca> Content-Type: multipart/mixed; boundary="=-YkpFepswu6eCKJ/YNi3v" X-Mailer: Ximian Evolution 1.0.7 Date: 08 Jul 2002 16:11:35 +0200 Message-Id: <1026137496.6228.60.camel@localhost.localdomain> Mime-Version: 1.0 X-Spam-Rating: daedalus.apache.org 1.6.2 0/1000/N X-Spam-Rating: daedalus.apache.org 1.6.2 0/1000/N --=-YkpFepswu6eCKJ/YNi3v Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: quoted-printable Hi, Attached is a patch that includes changes by myself, Ortwin Gl=FCck and Sachin Hamirwasia. I would appreciate it if someone could look at it and commit it to CVS if it is OK. It enables access through authenitcated and unauthenticated proxy servers for both HTTP and HTTPS. Ortwin - I haven't had time to look at the latest SSL code that you sent me today. I used the SSL code that I got from Sachin and added my changes to that. I have been running this code for a few days now with various sites and seems to work fine. Regards, Evert --=-YkpFepswu6eCKJ/YNi3v Content-Disposition: attachment; filename=diffs-evert.txt Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; name=diffs-evert.txt; charset=ISO-8859-1 ? diffs-evert.txt=0D Index: java/org/apache/commons/httpclient/Authenticator.java=0D =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=0D RCS file: /home/cvspublic/jakarta-commons/httpclient/src/java/org/apache/co= mmons/httpclient/Authenticator.java,v=0D retrieving revision 1.11=0D diff -c -r1.11 Authenticator.java=0D *** java/org/apache/commons/httpclient/Authenticator.java 5 Jan 2002 11:15:= 59 -0000 1.11=0D --- java/org/apache/commons/httpclient/Authenticator.java 8 Jul 2002 14:34:= 01 -0000=0D ***************=0D *** 70,97 ****=0D *

Utility methods for HTTP authorization and authentication.

=0D *

=0D * This class provides utility methods for generating=0D ! * responses to HTTP authentication challenges.=0D *

=0D * @author Remy Maucherat=0D * @author Rodney Waldhoff=0D * @version $Revision: 1.11 $ $Date: 2002/01/05 11:15:59 $=0D */=0D class Authenticator {=0D =20=0D /**=0D * Add requisite authentication credentials to the given=0D * {@link HttpMethod}, if possible.=0D *=0D * @param method a {@link HttpMethod} which requires authentication=0D * @param state a {@link HttpState} object providing {@link Credentia= ls}=0D *=0D * @throws HttpException when a parsing or other error occurs=0D * @throws UnsupportedOperationException when the given challenge typ= e is not supported=0D */=0D static boolean authenticate(HttpMethod method, HttpState state) throw= s HttpException {=0D log.debug("Authenticator.authenticate(HttpMethod, HttpState)");=0D ! Header challengeHeader =3D method.getResponseHeader("WWW-Authenti= cate");=0D if(null =3D=3D challengeHeader) { return false; }=0D String challenge =3D challengeHeader.getValue();=0D if(null =3D=3D challenge) { return false; }=0D =20=0D --- 70,151 ----=0D *

Utility methods for HTTP authorization and authentication.

=0D *

=0D * This class provides utility methods for generating=0D ! * responses to HTTP www and proxy authentication challenges.=0D *

=0D * @author Remy Maucherat=0D * @author Rodney Waldhoff=0D * @version $Revision: 1.11 $ $Date: 2002/01/05 11:15:59 $=0D */=0D class Authenticator {=0D + /**=0D + * The www authenticate challange header=0D + */=0D + public static final String WWW_AUTH =3D "WWW-Authenticate";=0D +=20=0D + /**=0D + * The www authenticate response header=0D + */=0D + public static final String WWW_AUTH_RESP =3D "Authorization";=0D +=20=0D + /**=0D + * The proxy authenticate challange header=0D + */=0D + public static final String PROXY_AUTH =3D "Proxy-Authenticate";=0D +=20=0D + /**=0D + * The proxy authenticate response header=0D + */=0D + public static final String PROXY_AUTH_RESP =3D "Proxy-Authorization";=0D =20=0D /**=0D * Add requisite authentication credentials to the given=0D * {@link HttpMethod}, if possible.=0D *=0D + * @see HttpState#setCredentials(String, Credentials) HttpState.setCr= edentials=0D + *=0D * @param method a {@link HttpMethod} which requires authentication=0D * @param state a {@link HttpState} object providing {@link Credentia= ls}=0D *=0D * @throws HttpException when a parsing or other error occurs=0D * @throws UnsupportedOperationException when the given challenge typ= e is not supported=0D + * @return true if only if a response header was added=0D */=0D static boolean authenticate(HttpMethod method, HttpState state) throw= s HttpException {=0D log.debug("Authenticator.authenticate(HttpMethod, HttpState)");=0D !=20=0D ! Header challengeHeader =3D method.getResponseHeader(WWW_AUTH);=0D if(null =3D=3D challengeHeader) { return false; }=0D +=20=0D + return authenticate(method, state, challengeHeader, WWW_AUTH_RESP= );=0D + }=0D +=20=0D + /**=0D + * Add requisite proxy authentication credentials to the given=0D + * {@link HttpMethod}, if possible.=0D + *=0D + * @see HttpState#setProxyCredentials(String, Credentials) HttpState.= setProxyCredentials=0D + *=0D + * @param method a {@link HttpMethod} which requires authentication=0D + * @param state a {@link HttpState} object providing {@link Credentia= ls}=0D + *=0D + * @throws HttpException when a parsing or other error occurs=0D + * @throws UnsupportedOperationException when the given challenge typ= e is not supported=0D + * @return true if only if a response header was added=0D + */=0D + static boolean authenticateProxy(HttpMethod method, HttpState state) = throws HttpException {=0D + log.debug("Authenticator.authenticateProxy(HttpMethod, HttpState)= ");=0D +=20=0D + Header challengeHeader =3D method.getResponseHeader(PROXY_AUTH);=0D + if (null =3D=3D challengeHeader) { return false; }=0D + return authenticate(method, state, challengeHeader, PROXY_AUTH_RE= SP);=0D + }=0D +=20=0D +=20=0D + private static boolean authenticate(HttpMethod method, HttpState stat= e,=0D + Header challengeHeader,=0D + String respHeader)=0D + throws HttpException {=0D +=20=0D String challenge =3D challengeHeader.getValue();=0D if(null =3D=3D challenge) { return false; }=0D =20=0D ***************=0D *** 119,125 ****=0D }=0D String realm =3D realmstr.substring("realm=3D\"".length(),rea= lmstr.length()-1);=0D log.debug("Parsed realm \"" + realm + "\" from challenge \"" = + challenge + "\".");=0D ! Header header =3D Authenticator.basic(realm,state);=0D if(null !=3D header) {=0D method.addRequestHeader(header);=0D return true;=0D --- 173,179 ----=0D }=0D String realm =3D realmstr.substring("realm=3D\"".length(),rea= lmstr.length()-1);=0D log.debug("Parsed realm \"" + realm + "\" from challenge \"" = + challenge + "\".");=0D ! Header header =3D Authenticator.basic(realm, state, respHeader= );=0D if(null !=3D header) {=0D method.addRequestHeader(header);=0D return true;=0D ***************=0D *** 137,155 ****=0D * Create a Basic Authorization header for the given=0D * realm and state to the given method.=0D *=0D - * @param method the {@link HttpMethod} to authenticate to=0D * @param realm the basic realm to authenticate to=0D * @param state a {@link HttpState} object providing {@link Credentia= ls}=0D *=0D ! * @return a basic Authorization value=0D *=0D * @throws HttpException when no matching credentials are available=0D */=0D ! static Header basic(String realm, HttpState state) throws HttpExcepti= on {=0D log.debug("Authenticator.basic(String,HttpState)");=0D UsernamePasswordCredentials cred =3D null;=0D try {=0D ! cred =3D (UsernamePasswordCredentials)(state.getCredentials(r= ealm));=0D } catch(ClassCastException e) {=0D throw new HttpException("UsernamePasswordCredentials required= for Basic authentication.");=0D }=0D --- 191,213 ----=0D * Create a Basic Authorization header for the given=0D * realm and state to the given method.=0D *=0D * @param realm the basic realm to authenticate to=0D * @param state a {@link HttpState} object providing {@link Credentia= ls}=0D + * @param respHeader the header's name to store the authentication re= sponse=0D + * in. PROXY_AUTH_RESP will force the proxy credentials to be used.=0D *=0D ! * @return a basic Authorization header=0D *=0D * @throws HttpException when no matching credentials are available=0D */=0D ! static Header basic(String realm, HttpState state, String respHeader)= throws HttpException {=0D log.debug("Authenticator.basic(String,HttpState)");=0D + boolean proxy =3D PROXY_AUTH_RESP.equals(respHeader);=0D UsernamePasswordCredentials cred =3D null;=0D try {=0D ! cred =3D (UsernamePasswordCredentials) ( proxy ?=0D ! state.getProxyCredentials(realm) :=0D ! state.getCredentials(realm));=0D } catch(ClassCastException e) {=0D throw new HttpException("UsernamePasswordCredentials required= for Basic authentication.");=0D }=0D ***************=0D *** 158,164 ****=0D log.info("No credentials found for realm \"" + realm + "\= ", attempting to use default credentials.");=0D }=0D try {=0D ! cred =3D (UsernamePasswordCredentials)(state.getCredentia= ls(null));=0D } catch(ClassCastException e) {=0D throw new HttpException("UsernamePasswordCredentials requ= ired for Basic authentication.");=0D }=0D --- 216,224 ----=0D log.info("No credentials found for realm \"" + realm + "\= ", attempting to use default credentials.");=0D }=0D try {=0D ! cred =3D (UsernamePasswordCredentials)( proxy ?=0D ! state.getProxyCredentials(null) :=0D ! state.getCredentials(null));=0D } catch(ClassCastException e) {=0D throw new HttpException("UsernamePasswordCredentials requ= ired for Basic authentication.");=0D }=0D ***************=0D *** 166,172 ****=0D if(null =3D=3D cred) {=0D throw new HttpException("No credentials available for the Bas= ic authentication realm \"" + realm + "\"/");=0D } else {=0D ! return new Header("Authorization",Authenticator.basic(cred));=0D }=0D }=0D =20=0D --- 226,232 ----=0D if(null =3D=3D cred) {=0D throw new HttpException("No credentials available for the Bas= ic authentication realm \"" + realm + "\"/");=0D } else {=0D ! return new Header(respHeader, Authenticator.basic(cred));=0D }=0D }=0D =20=0D Index: java/org/apache/commons/httpclient/HttpConnection.java=0D =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=0D RCS file: /home/cvspublic/jakarta-commons/httpclient/src/java/org/apache/co= mmons/httpclient/HttpConnection.java,v=0D retrieving revision 1.9=0D diff -c -r1.9 HttpConnection.java=0D *** java/org/apache/commons/httpclient/HttpConnection.java 12 Apr 2002 21:0= 9:20 -0000 1.9=0D --- java/org/apache/commons/httpclient/HttpConnection.java 8 Jul 2002 14:34= :05 -0000=0D ***************=0D *** 66,76 ****=0D --- 66,79 ----=0D import java.net.SocketException;=0D import java.io.InputStream;=0D import java.io.OutputStream;=0D + import java.io.UnsupportedEncodingException;=20=0D import java.io.IOException;=0D + import javax.net.SocketFactory;=0D import javax.net.ssl.SSLSocket;=0D import javax.net.ssl.SSLSocketFactory;=0D import org.apache.commons.httpclient.log.*;=0D import java.lang.reflect.Method;=0D + import java.util.HashSet;=0D =20=0D /**=0D *

=0D ***************=0D *** 115,121 ****=0D }=0D =20=0D /**=0D ! * Fully-specified constructor.=0D * @param proxyHost the host I should proxy via=0D * @param proxyPort the port I should proxy via=0D * @param host the host I should connect to. Parameter value must be = non-null.=0D --- 118,124 ----=0D }=0D =20=0D /**=0D ! * Constructor.=0D * @param proxyHost the host I should proxy via=0D * @param proxyPort the port I should proxy via=0D * @param host the host I should connect to. Parameter value must be = non-null.=0D ***************=0D *** 123,128 ****=0D --- 126,146 ----=0D * @param secure when true, connect via HTTPS (SSL)=0D */=0D public HttpConnection(String proxyHost, int proxyPort, String host, i= nt port, boolean secure) {=0D + this(proxyHost, proxyPort, host, port, secure, null, null);=0D + }=0D + =20=0D + /**=0D + * Fully-specified constructor.=0D + * @param proxyHost the host I should proxy via=0D + * @param proxyPort the port I should proxy via=0D + * @param host the host I should connect to. Parameter value must be = non-null.=0D + * @param port the port I should connect to=0D + * @param secure when true, connect via HTTPS (SSL)=0D + * @param state the HttpSharedState for establishing connections thro= ugh authenticated proxies.=0D + * @param factory the factory to be used for creating SSL sockets. Or= , null for the default.=0D + */=0D + public HttpConnection(String proxyHost, int proxyPort, String host, i= nt port, boolean secure,=0D + HttpSharedState state, SSLSocketFactory factory= ) {=0D log.debug("HttpConnection.HttpConnection");=0D if (host =3D=3D null) {=0D throw new NullPointerException("host parameter is null");=0D ***************=0D *** 132,137 ****=0D --- 150,157 ----=0D _host =3D host;=0D _port =3D port;=0D _ssl =3D secure;=0D + _state =3D state;=0D + _sslSocketFactory =3D factory;=0D }=0D =20=0D // ------------------------------------------ Attribute Setters and G= etters=0D ***************=0D *** 278,289 ****=0D assertNotOpen(); // ??? is this worth doing?=0D try {=0D if (null =3D=3D _socket) {=0D - String host =3D (null =3D=3D _proxyHost) ? _host : _proxy= Host;=0D - int port =3D (null =3D=3D _proxyHost) ? _port : _proxyPor= t;=0D if (_ssl) {=0D ! _socket =3D SSLSocketFactory.getDefault().createSocke= t(host,port);=0D } else {=0D _socket =3D new Socket(host,port);=0D }=0D }=0D _socket.setSoTimeout(_so_timeout);=0D --- 298,323 ----=0D assertNotOpen(); // ??? is this worth doing?=0D try {=0D if (null =3D=3D _socket) {=0D if (_ssl) {=0D ! if (_sslSocketFactory =3D=3D null)=0D ! _sslSocketFactory =3D (SSLSocketFactory)SSLSocket= Factory.getDefault();=0D ! if ((_proxyHost !=3D null) && (_proxyPort > 0)) {=0D ! // ssl using proxy - create a tunnellec connection=20=0D ! doTunnelHandshake(false, null);=0D ! Socket tunnel =3D _socket;=0D ! _socket =3D _sslSocketFactory.createSocket(tunnel, _hos= t, _port, true);=0D ! } else {=0D ! // using with no proxy=20=0D ! _socket =3D _sslSocketFactory.createSocket(_host, _port= );=0D ! }=0D } else {=0D + // non ssl connection=20=0D + String host =3D (null =3D=3D _proxyHost) ? _host : _prox= yHost;=0D + int port =3D (null =3D=3D _proxyHost) ? _port : _proxyPo= rt;=0D _socket =3D new Socket(host,port);=0D + // Not creating a tunnel socket, but authenticating.=0D + //if ((_proxyHost !=3D null) && (_proxyPort > 0))=0D + // doTunnelHandshake(false, null);=0D }=0D }=0D _socket.setSoTimeout(_so_timeout);=0D ***************=0D *** 293,303 ****=0D --- 327,441 ----=0D } catch (IOException e) {=0D // Connection wasn't opened properly=0D // so close everything out=0D + //log.debug("IOException in opening connection: " + e, e);=0D closeSocketAndStreams();=0D throw e;=0D + } finally {=0D + _attemptedRealms.clear();=0D }=0D }=0D =20=0D + private void doTunnelHandshake(boolean authenticate, String realm) throw= s IOException=0D + {=0D + log.debug("doTunnelHandshake(authenticate=3D'" + authenticate + "= ', realm=3D'" + realm + "')");=0D + _attemptedRealms.add(realm);=0D + String authorizationHeader =3D null;=0D + if (authenticate && _state !=3D null) {=0D + Credentials credentials =3D _state.getProxyCredentials(realm)= ;=0D + if ((credentials !=3D null) &&=20=0D + (credentials instanceof UsernamePasswordCredentials)) {=0D + try {=0D + authorizationHeader =3D Authenticator.basic((Username= PasswordCredentials)credentials);=0D + } catch (HttpException ex) {=0D + log.debug("doTunnelHandshake(): Exception reading cre= dentials: " + ex);=0D + }=0D + }=0D + else if (realm !=3D null) {=0D + // Try it once with the default credentials that are stor= ed=20=0D + // with a null realm.=0D + doTunnelHandshake(true, null);=0D + return;=0D + }=0D + }=0D + _socket =3D new Socket(_proxyHost, _proxyPort);=0D + _output =3D _socket.getOutputStream();=0D + String msg =3D "CONNECT " + _host + ":" + _port + " HTTP/1.0\r\n" +=20=0D + "User-Agent: " + sun.net.www.protocol.http.HttpURLConnection.user= Agent + "\r\n" +=20=0D + //"Host: " + _host + ":" + _port + "\r\n" +=20=0D + "Host: " + _host + "\r\n" +=20=0D + "Content-Length: 0\r\n" +=20=0D + "Proxy-Connection: Keep-Alive\r\n" +=20=0D + "Pragma: no-cache\r\n";=0D + if (authorizationHeader !=3D null)=0D + msg +=3D "Proxy-Authorization: " + authorizationHeader + "\r\= n";=0D + msg +=3D "\r\n";=0D + =09=0D + wireLog.info(">>\r\n" + msg);=0D + =20=0D + byte b[];=0D + try {=0D + b =3D msg.getBytes("ASCII7");=0D + } catch (UnsupportedEncodingException ignored) {=0D + b =3D msg.getBytes();=0D + }=0D + _output.write(b);=0D + _output.flush();=0D + =09=0D + _input =3D _socket.getInputStream();=0D + boolean error =3D false;=0D + =20=0D + _open =3D true;=0D + StringBuffer replyBuffer =3D new StringBuffer();=0D + String proxyAuthenticate =3D null;=0D + String firstLine =3D null;=0D + while (true) {=0D + String line =3D readLine();=0D + if (line =3D=3D null || line.length() < 1)=0D + break;=0D + if (firstLine =3D=3D null)=0D + firstLine =3D line;=0D + replyBuffer.append(line + "\r\n");=0D + int colonPosition =3D line.indexOf(":");=0D + if (colonPosition > -1) {=0D + String key =3D line.substring(0, colonPosition);=0D + String value =3D line.substring(colonPosition);=0D + if (key.trim().equalsIgnoreCase("Proxy-Authenticate"))=0D + proxyAuthenticate =3D value;=0D + }=0D + }=0D + String replyStr =3D replyBuffer.toString();=0D + wireLog.info("<<\r\n" + replyStr);=0D + _open =3D false;=0D + =20=0D + String newRealm =3D null;=0D + if (proxyAuthenticate !=3D null) {=0D + int start =3D proxyAuthenticate.indexOf("\"") + 1;=0D + int end =3D proxyAuthenticate.lastIndexOf("\"");=0D + if (start > -1 && end > -1 && start !=3D end)=0D + newRealm =3D proxyAuthenticate.substring(start, end);=0D + }=0D + =20=0D + if (newRealm !=3D null && !_attemptedRealms.contains(newRealm)) {=0D + //closeSocketAndStreams();=0D + doTunnelHandshake(true, newRealm);=0D + return;=0D + }=0D + =20=0D + log.debug("doTunnelHandshake(): Reply: " + replyStr);=0D + =09=0D + /* We asked for HTTP/1.0, so we should get that back */=0D + if (!replyStr.startsWith("HTTP/1.0 200")) {=0D + msg =3D "Unable to tunnel through "=0D + + _proxyHost + ":" + _proxyPort=0D + + ". Proxy returns \"" + firstLine + "\"";=0D + log.debug("doTunnelHandshake(): " + msg);=0D + throw new IOException(msg);=0D + }=0D + =09=0D + /* tunneling Handshake was successful! */=0D + =20=0D + }=0D +=20=0D /**=0D * Return a {@link RequestOutputStream}=0D * suitable for writing (possibly chunked)=0D ***************=0D *** 347,357 ****=0D }=0D =20=0D /**=0D ! * Write the specified bytes to my output stream.=0D * @throws IllegalStateException if I am not connected=0D * @throws IOException if an I/O problem occurs=0D */=0D ! public void write(byte[] data) throws IOException, IllegalStateExcept= ion, HttpRecoverableException {=0D if(log.isDebugEnabled()){=0D log.debug("HttpConnection.write(byte[])");=0D }=0D --- 485,501 ----=0D }=0D =20=0D /**=0D ! * Write the specified bytes to my output stream. The first byte writ= ten is=0D ! * data[off]. len bytes of data will=0D ! * be written.=0D ! *=0D ! * @param data The data that will be written=0D ! * @param off Offset=0D ! * @param len Length=0D * @throws IllegalStateException if I am not connected=0D * @throws IOException if an I/O problem occurs=0D */=0D ! public void write(byte[] data, int off, int len) throws IOException, = IllegalStateException, HttpRecoverableException {=0D if(log.isDebugEnabled()){=0D log.debug("HttpConnection.write(byte[])");=0D }=0D ***************=0D *** 360,366 ****=0D wireLog.info(">> \"" + new String(data) + "\"");=0D }=0D try {=0D ! _output.write(data);=0D } catch(SocketException e){=0D if(log.isDebugEnabled()) {=0D log.debug("HttpConnection: Socket exception while writing= data",e);=0D --- 504,510 ----=0D wireLog.info(">> \"" + new String(data) + "\"");=0D }=0D try {=0D ! _output.write(data, off, len);=0D } catch(SocketException e){=0D if(log.isDebugEnabled()) {=0D log.debug("HttpConnection: Socket exception while writing= data",e);=0D ***************=0D *** 374,379 ****=0D --- 518,532 ----=0D }=0D }=0D =20=0D + /**=0D + * Write the specified bytes to my output stream.=0D + * @param data The data that will be written=0D + * @throws IllegalStateException if I am not connected=0D + * @throws IOException if an I/O problem occurs=0D + */=0D + public void write(byte[] data) throws IOException, IllegalStateExcept= ion, HttpRecoverableException {=0D + write(data, 0, data.length);=0D + }=0D =20=0D /**=0D * Write the specified bytes, followed by=0D ***************=0D *** 593,597 ****=0D private static final byte[] CRLF =3D "\r\n".getBytes();=0D /** SO_TIMEOUT value */=0D private int _so_timeout =3D 0;=0D !=20=0D }=0D --- 746,755 ----=0D private static final byte[] CRLF =3D "\r\n".getBytes();=0D /** SO_TIMEOUT value */=0D private int _so_timeout =3D 0;=0D ! /** The factory to be used for creating SSL sockets. **/=0D ! private SSLSocketFactory _sslSocketFactory =3D null;=0D ! /** The state to be used for establishing connections through authent= icated proxies. **/=0D ! private HttpSharedState _state =3D null;=0D ! /** All the realms for which authentication has already been attempte= d once. **/=0D ! private HashSet _attemptedRealms =3D new HashSet();=0D }=0D Index: java/org/apache/commons/httpclient/HttpConnectionManager.java=0D =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=0D RCS file: /home/cvspublic/jakarta-commons/httpclient/src/java/org/apache/co= mmons/httpclient/HttpConnectionManager.java,v=0D retrieving revision 1.5=0D diff -c -r1.5 HttpConnectionManager.java=0D *** java/org/apache/commons/httpclient/HttpConnectionManager.java 15 Apr 20= 02 18:35:29 -0000 1.5=0D --- java/org/apache/commons/httpclient/HttpConnectionManager.java 8 Jul 200= 2 14:34:07 -0000=0D ***************=0D *** 67,72 ****=0D --- 67,73 ----=0D import java.util.HashMap;=0D import java.util.List;=0D import java.util.LinkedList;=0D + import javax.net.ssl.SSLSocketFactory;=0D =20=0D import org.apache.commons.httpclient.log.*;=0D =20=0D ***************=0D *** 87,92 ****=0D --- 88,95 ----=0D private int maxConnections =3D 2; // Per RFC 2616 sec 8.1.4=0D private String proxyHost =3D null;=0D private int proxyPort =3D -1;=0D + private HttpSharedState state =3D null;=0D + private SSLSocketFactory factory =3D null;=0D =20=0D /**=0D * No-args constructor=0D ***************=0D *** 96,101 ****=0D --- 99,113 ----=0D }=0D =20=0D /**=0D + * This constructor is necessary for making connections through authe= nticated proxies.=0D + * @param state for making connections through authenticated proxies,= or null.=0D + */=0D + public HttpConnectionManager(HttpSharedState state)=0D + {=0D + this.state =3D state;=0D + }=0D + =20=0D + /**=0D * Set the proxy host to use for all connections.=0D *=20=0D * @param proxyHost - the proxy host name=0D ***************=0D *** 157,162 ****=0D --- 169,183 ----=0D }=0D =20=0D /**=0D + * Allows you to specify a new factory to be used as the default=20=0D + * for creating SSL sockets. Setting the factory to null will=0D + * reset it to using SSLSocketFactory.getDefault().=0D + */=0D + public void setSSLSocketFactory(SSLSocketFactory factory) {=0D + this.factory =3D factory;=0D + }=0D + =20=0D + /**=0D * Get an HttpConnection for a given URL. The URL must be fully=0D * specified (i.e. contain a protocol and a host (and optional port n= umber).=0D * If the maximum number of connections for the host has been reached= , this=0D ***************=0D *** 249,255 ****=0D if(log.isDebugEnabled()){=0D log.debug("HttpConnectionManager.getConnection: = creating connection for " + host + ":" + port + " via " + proxyHost + ":" += proxyPort);=0D }=0D ! conn =3D new HttpConnection(proxyHost, proxyPort, hos= t, port, isSecure);=0D numConnections =3D new Integer(numConnections.intValu= e()+1);=0D mapNumConnections.put(key, numConnections);=0D }else{=0D --- 270,276 ----=0D if(log.isDebugEnabled()){=0D log.debug("HttpConnectionManager.getConnection: = creating connection for " + host + ":" + port + " via " + proxyHost + ":" += proxyPort);=0D }=0D ! conn =3D new HttpConnection(proxyHost, proxyPort, hos= t, port, isSecure, state, factory);=0D numConnections =3D new Integer(numConnections.intValu= e()+1);=0D mapNumConnections.put(key, numConnections);=0D }else{=0D Index: java/org/apache/commons/httpclient/HttpMethod.java=0D =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=0D RCS file: /home/cvspublic/jakarta-commons/httpclient/src/java/org/apache/co= mmons/httpclient/HttpMethod.java,v=0D retrieving revision 1.12=0D diff -c -r1.12 HttpMethod.java=0D *** java/org/apache/commons/httpclient/HttpMethod.java 22 Feb 2002 19:15:54= -0000 1.12=0D --- java/org/apache/commons/httpclient/HttpMethod.java 8 Jul 2002 14:34:08 = -0000=0D ***************=0D *** 262,267 ****=0D --- 262,290 ----=0D public InputStream getResponseBodyAsStream() throws IOException;=0D =20=0D /**=0D + * Returns the time in milliseconds when a connection was=0D + * available and open.=0D + * If an error occurred before this event, then it will return -1= .=0D + */=0D + public long getWhenConnectedMillis();=0D + =20=0D + /**=0D + * Returns the time in milliseconds when the headers of the request=0D + * were sent, not the body of the request. It might first wait for=20=0D + * a 100 response before sending the body of the request.=0D + * If an error occurred before this event, then it will return -1= .=0D + */=0D + public long getWhenRequestedMillis();=0D + =20=0D + /**=0D + * Returns the time in milliseconds when the first response was recei= ved=0D + * from the server, regardless of whether it was a success, failure=20=0D + * or continue response.=0D + * If an error occurred before this event, then it will return -1= .=0D + */=0D + public long getWhenRespondedMillis();=0D + =20=0D + /**=0D * Return true if I have been {@link #execute executed}=0D * but not recycled.=0D */=0D Index: java/org/apache/commons/httpclient/HttpMethodBase.java=0D =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=0D RCS file: /home/cvspublic/jakarta-commons/httpclient/src/java/org/apache/co= mmons/httpclient/HttpMethodBase.java,v=0D retrieving revision 1.28=0D diff -c -r1.28 HttpMethodBase.java=0D *** java/org/apache/commons/httpclient/HttpMethodBase.java 16 Apr 2002 14:3= 0:42 -0000 1.28=0D --- java/org/apache/commons/httpclient/HttpMethodBase.java 8 Jul 2002 14:34= :15 -0000=0D ***************=0D *** 267,273 ****=0D * Remove the request header associated with the given name.=0D * Note that header-name matching is case insensitive.=0D * @param headerName the header name=0D - * @return the header=0D */=0D public void removeRequestHeader(String headerName) {=0D requestHeaders.remove(headerName.toLowerCase());=0D --- 267,272 ----=0D ***************=0D *** 405,410 ****=0D --- 404,438 ----=0D }=0D =20=0D /**=0D + * Returns the time in milliseconds when a connection was=0D + * available and open.=0D + * If an error occurred before this event, then it will return -1= .=0D + */=0D + public long getWhenConnectedMillis() {=0D + return whenConnected;=0D + }=0D + =20=0D + /**=0D + * Returns the time in milliseconds when the headers of the request=0D + * were sent, not the body of the request. It might first wait for=20=0D + * a 100 response before sending the body of the request.=0D + * If an error occurred before this event, then it will return -1= .=0D + */=0D + public long getWhenRequestedMillis() {=0D + return whenRequested;=0D + }=0D + =20=0D + /**=0D + * Returns the time in milliseconds when the first response was recei= ved=0D + * from the server, regardless of whether it was a success, failure=20=0D + * or continue response.=0D + * If an error occurred before this event, then it will return -1= .=0D + */=0D + public long getWhenRespondedMillis() {=0D + return whenResponded;=0D + }=0D + =20=0D + /**=0D * Return true if I have been {@link #execute executed}=0D * but not recycled.=0D */=0D ***************=0D *** 450,455 ****=0D --- 478,484 ----=0D =20=0D Set visited =3D new HashSet();=0D Set realms =3D new HashSet();=0D + Set proxyRealms =3D new HashSet();=0D int retryCount =3D 0;=0D for(;;) {=0D visited.add(connection.getHost() + ":" + connection.getPort()= + "|" + HttpMethodBase.generateRequestLine(connection, getName(),getPath()= ,getQueryString(),(http11 ? "HTTP/1.1" : "HTTP/1.0")));=0D ***************=0D *** 466,476 ****=0D --- 495,514 ----=0D connection.open();=0D }=0D =20=0D + if (whenConnected =3D=3D -1)=0D + whenConnected =3D System.currentTimeMillis();=0D + =20=0D writeRequest(state,connection);=0D used =3D true;=0D =20=0D + if (whenRequested =3D=3D -1)=0D + whenRequested =3D System.currentTimeMillis();=0D +=20=0D // need to close output?, but when?=0D readResponse(state,connection);=0D + =20=0D + if (whenResponded =3D=3D -1)=0D + whenResponded =3D System.currentTimeMillis();=0D }catch(HttpRecoverableException e){=0D if(retryCount >=3D maxRetries){=0D throw new HttpException(e.toString());=0D ***************=0D *** 505,526 ****=0D }=0D }=0D =20=0D ! if (HttpStatus.SC_UNAUTHORIZED =3D=3D statusCode) {=0D ! Header wwwauth =3D getResponseHeader("WWW-Authenticate");=0D if (null !=3D wwwauth) {=0D String pathAndCreds =3D getPath() + ":" + wwwauth.get= Value();=0D ! if (realms.contains(pathAndCreds)) {=0D if (log.isInfoEnabled()) {=0D log.info("Already tried to authenticate to \"= " + wwwauth.getValue() + "\" but still receiving " + HttpStatus.SC_UNAUTHOR= IZED + ".");=0D }=0D break;=0D } else {=0D ! realms.add(pathAndCreds);=0D }=0D =20=0D boolean authenticated =3D false;=0D try {=0D ! authenticated =3D Authenticator.authenticate(this= ,state);=0D } catch(HttpException e) {=0D // ignored=0D }=0D --- 543,587 ----=0D }=0D }=0D =20=0D ! if ((HttpStatus.SC_UNAUTHORIZED =3D=3D statusCode)=0D ! || (HttpStatus.SC_PROXY_AUTHENTICATION_REQUIRED =3D=3D st= atusCode)) {=0D !=20=0D ! Header wwwauth =3D null;=0D ! Set realmsUsed =3D null;=0D ! switch (statusCode) {=0D ! case HttpStatus.SC_UNAUTHORIZED:=0D ! wwwauth =3D getResponseHeader(Authenticator.WWW_A= UTH);=0D ! realmsUsed =3D realms;=0D ! break;=0D !=20=0D ! case HttpStatus.SC_PROXY_AUTHENTICATION_REQUIRED:=0D ! wwwauth =3D getResponseHeader(Authenticator.PROXY= _AUTH);=0D ! realmsUsed =3D proxyRealms;=0D ! break;=0D ! }=0D if (null !=3D wwwauth) {=0D String pathAndCreds =3D getPath() + ":" + wwwauth.get= Value();=0D ! if (realmsUsed.contains(pathAndCreds)) {=0D if (log.isInfoEnabled()) {=0D log.info("Already tried to authenticate to \"= " + wwwauth.getValue() + "\" but still receiving " + HttpStatus.SC_UNAUTHOR= IZED + ".");=0D }=0D break;=0D } else {=0D ! realmsUsed.add(pathAndCreds);=0D }=0D =20=0D boolean authenticated =3D false;=0D try {=0D ! switch (statusCode) {=0D ! case HttpStatus.SC_UNAUTHORIZED:=0D ! authenticated =3D Authenticator.authentic= ate(this,state);=0D ! break;=0D !=20=0D ! case HttpStatus.SC_PROXY_AUTHENTICATION_REQUI= RED:=0D ! authenticated =3D Authenticator.authentic= ateProxy(this,state);=0D ! break;=0D ! }=0D !=20=0D } catch(HttpException e) {=0D // ignored=0D }=0D ***************=0D *** 539,657 ****=0D continue;=0D }=0D }=0D - } else if (HttpStatus.SC_MOVED_TEMPORARILY =3D=3D statusCode = ||=0D - HttpStatus.SC_MOVED_PERMANENTLY =3D=3D statusCode ||=0D - HttpStatus.SC_TEMPORARY_REDIRECT =3D=3D statusCode) {=0D - if (getFollowRedirects()) {=0D - //=0D - // Note that we cannot current support=0D - // redirects that change the HttpConnection=0D - // parameters (host, port, protocol)=0D - // because we don't yet have a good way to=0D - // get the new connection.=0D - //=0D - // For the time being, we just return=0D - // the 302 response, and allow the user=0D - // agent to resubmit if desired.=0D - //=0D - Header location =3D getResponseHeader("location");=0D - if (location !=3D null) {=0D - URL url =3D null;=0D - try {=0D - if (location.getValue().startsWith("/")) {=0D - if (log.isDebugEnabled()) {=0D - log.debug("Following relative Locatio= n header \"" + location + "\".");=0D - }=0D - String protocol =3D connection.isSecure()= ? "https" : "http";=0D - int port =3D connection.getPort();=0D - if (-1 =3D=3D port) {=0D - port =3D connection.isSecure() ? 443 = : 80;=0D - }=0D - url =3D new URL(protocol,connection.getHo= st(),port,location.getValue()); =20=0D - } else if(!isStrictMode() && location.getValu= e().indexOf("://") < 0) {=0D - /*=0D - * Location doesn't start with / but it d= oesn't contain a protocol.=0D - * Per RFC 2616, that's an error. In non= -strict mode we'll try=0D - * to build a URL relative to the current= path.=0D - */=0D - String protocol =3D connection.isSecure()= ? "https" : "http";=0D - int port =3D connection.getPort();=0D - if(-1 =3D=3D port) {=0D - port =3D connection.isSecure() ? 443 = : 80;=0D - }=0D - URL currentUrl =3D new URL(protocol,conne= ction.getHost(),port,getPath());=0D - url =3D new URL(currentUrl, location.getV= alue());=0D - } else {=0D - url =3D new URL(location.getValue());=0D - } =20=0D - } catch(MalformedURLException e) {=0D - log.error("Exception while parsing location h= eader \"" + location + "\"",e);=0D - throw new HttpException(e.toString());=0D - }=0D - if ("http".equalsIgnoreCase(url.getProtocol())) {=0D - if (connection.isSecure()) {=0D - log.info("Server is attempting to redirec= t an HTTPS request to an HTTP one.");=0D - throw new HttpException("Server is attemp= ting to redirect an HTTPS request to an HTTP one.");=0D - }=0D - } else if ("https".equalsIgnoreCase(url.getProtoc= ol())) {=0D - if (!connection.isSecure()) {=0D - log.info("Server is attempting to convert= an HTTP request to an HTTP one, which is currently not supported. Returnin= g " + statusCode + ".");=0D - break;=0D - }=0D - }=0D - if (!connection.getHost().equalsIgnoreCase(url.ge= tHost())) {=0D - log.info("Server is attempting to redirect a = different host, which is currently not supported. Returning " + statusCode = + ".");=0D - break;=0D - }=0D - if (url.getPort() =3D=3D -1) {=0D - if (connection.isSecure()) {=0D - if (connection.getPort() !=3D 443) {=0D - log.info("Server is attempting to red= irect a different port, which is currently not supported. Returning " + sta= tusCode + ".");=0D - break;=0D - }=0D - } else {=0D - if (connection.getPort() !=3D 80) {=0D - log.info("Server is attempting to red= irect a different port, which is currently not supported. Returning " + sta= tusCode + ".");=0D - break;=0D - }=0D - }=0D - } else if (connection.getPort() !=3D url.getPort(= )) {=0D - log.info("Server is attempting to redirect a = different port, which is currently not supported. Returning " + statusCode = + ".");=0D - break;=0D - }=0D - String absolutePath =3D URIUtil.getPath(url.toStr= ing());=0D - String qs =3D URIUtil.getQueryString(url.toString= ());=0D -=20=0D - // if we haven't already, let's try it again with= the new path=0D - if (visited.contains(connection.getHost() + ":" += connection.getPort() + "|" + HttpMethodBase.generateRequestLine(connection= , getName(),absolutePath,qs,(http11 ? "HTTP/1.1" : "HTTP/1.0")))) {=0D - throw new HttpException("Redirect going into = a loop, visited \"" + absolutePath + "\" already.");=0D - } else {=0D - if (log.isDebugEnabled()) {=0D - log.debug("Changing path from \"" + getPa= th() + "\" to \"" + absolutePath + "\" in response to " + statusCode + " re= sponse.");=0D - log.debug("Changing query string from \""= + getQueryString() + "\" to \"" + qs + "\" in response to " + statusCode += " response.");=0D - }=0D - setPath(URIUtil.decode(absolutePath));=0D - setQueryString(qs);=0D - continue;=0D - }=0D - } else {=0D - // got a redirect response, but no location heade= r=0D - if (log.isInfoEnabled()) {=0D - log.info("HttpMethodBase.execute(): Received = " + statusCode + " response, but no \"Location\" header. Returning " + stat= usCode + ".");=0D - }=0D - break;=0D - }=0D - } else {=0D - // got a redirect response,=0D - // but followRedirects is false=0D - log.info("HttpMethodBase.execute(): Received " + stat= usCode + " response, but followRedirects is false. Returning " + statusCode= + ".");=0D - break;=0D - }=0D - } else {=0D - // neither an UNAUTHORIZED nor a redirect response=0D - // so exit=0D - break;=0D }=0D }=0D =20=0D return statusCode;=0D --- 600,610 ----=0D continue;=0D }=0D }=0D }=0D + // Moved the handling of redirects to HttpMultiClient. Replac= ed all the=20=0D + // code to build a URL relative to the original URL with:=0D + // URL newUrl =3D new URL( URL context, String newUrlStr ) --= Evert=0D + break;=0D }=0D =20=0D return statusCode;=0D ***************=0D *** 767,772 ****=0D --- 720,726 ----=0D addHostRequestHeader(state,conn);=0D addCookieRequestHeader(state,conn);=0D addAuthorizationRequestHeader(state,conn);=0D + addProxyAuthorizationRequestHeader(state, conn);=0D addContentLengthRequestHeader(state,conn);=0D }=0D =20=0D ***************=0D *** 810,817 ****=0D */=0D protected void addAuthorizationRequestHeader(HttpState state, HttpCon= nection conn) throws IOException, HttpException {=0D // add authorization header, if needed=0D ! if (!requestHeaders.containsKey("authorization")) {=0D ! Header wwwAuthenticateHeader =3D (Header)(responseHeaders.get= ("www-authenticate"));=0D if (null !=3D wwwAuthenticateHeader) {=0D try {=0D Authenticator.authenticate(this,state);=0D --- 764,771 ----=0D */=0D protected void addAuthorizationRequestHeader(HttpState state, HttpCon= nection conn) throws IOException, HttpException {=0D // add authorization header, if needed=0D ! if (!requestHeaders.containsKey(Authenticator.WWW_AUTH_RESP.toLow= erCase())) {=0D ! Header wwwAuthenticateHeader =3D (Header)(responseHeaders.get= (Authenticator.WWW_AUTH.toLowerCase()));=0D if (null !=3D wwwAuthenticateHeader) {=0D try {=0D Authenticator.authenticate(this,state);=0D ***************=0D *** 823,828 ****=0D --- 777,801 ----=0D }=0D =20=0D /**=0D + * Adds a Proxy-Authorization request if needed,=0D + * as long as no Proxy-Authorization request header=0D + * already exists.=0D + */=0D + protected void addProxyAuthorizationRequestHeader(HttpState state, Ht= tpConnection conn) throws IOException, HttpException {=0D + // add authorization header, if needed=0D + if (!requestHeaders.containsKey(Authenticator.PROXY_AUTH_RESP.toL= owerCase())) {=0D + Header wwwAuthenticateHeader =3D (Header)(responseHeaders.get= (Authenticator.PROXY_AUTH.toLowerCase()));=0D + if (null !=3D wwwAuthenticateHeader) {=0D + try {=0D + Authenticator.authenticateProxy(this,state);=0D + } catch(HttpException e) {=0D + // ignored=0D + }=0D + }=0D + }=0D + }=0D +=20=0D + /**=0D * Adds a Content-Length or=0D * Transer-Encoding: Chunked request header,=0D * as long as no Content-Length request header=0D ***************=0D *** 1239,1244 ****=0D --- 1212,1220 ----=0D http11 =3D true;=0D bodySent =3D false;=0D responseBody =3D null;=0D + whenConnected =3D -1;=0D + whenRequested =3D -1;=0D + whenResponded =3D -1;=0D }=0D =20=0D // ---------------------------------------------- Protected Utility M= ethods=0D ***************=0D *** 1299,1312 ****=0D return (name + " " + buf.toString() + " " + protocol + "\r\n"= );=0D } else {=0D if (connection.isSecure()) {=0D ! return (name +=0D ! " https://" +=0D ! connection.getHost() +=0D ! ((443 =3D=3D connection.getPort() || -1 =3D=3D con= nection.getPort()) ? "" : (":" + connection.getPort()) ) +=0D ! buf.toString() +=0D ! " " +=0D ! protocol +=0D ! "\r\n");=0D } else {=0D return (name +=0D " http://" +=0D --- 1275,1289 ----=0D return (name + " " + buf.toString() + " " + protocol + "\r\n"= );=0D } else {=0D if (connection.isSecure()) {=0D ! // return (name +=0D ! // " https://" +=0D ! // connection.getHost() +=0D ! // ((443 =3D=3D connection.getPort() || -1 =3D=3D c= onnection.getPort()) ? "" : (":" + connection.getPort()) ) +=0D ! // buf.toString() +=0D ! // " " +=0D ! // protocol +=0D ! // "\r\n");=0D ! return (name + " " + buf.toString() + " " + protocol + "\= r\n");=20=0D } else {=0D return (name +=0D " http://" +=0D ***************=0D *** 1367,1372 ****=0D --- 1344,1355 ----=0D private int maxRetries =3D 3;=0D /** True if we're in strict mode. */=0D private boolean strictMode =3D true;=0D + /** The moment when an open connection is available. **/=0D + private long whenConnected =3D -1;=0D + /** The moment when the request headers have been sent, not the reque= st body. **/=0D + private long whenRequested =3D -1;=0D + /** The moment of the first response received back from the server. *= */=0D + private long whenResponded =3D -1;=0D =20=0D // -------------------------------------------------------------- Con= stants=0D =20=0D Index: java/org/apache/commons/httpclient/HttpMultiClient.java=0D =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=0D RCS file: /home/cvspublic/jakarta-commons/httpclient/src/java/org/apache/co= mmons/httpclient/HttpMultiClient.java,v=0D retrieving revision 1.5=0D diff -c -r1.5 HttpMultiClient.java=0D *** java/org/apache/commons/httpclient/HttpMultiClient.java 5 Jul 2002 07:1= 3:46 -0000 1.5=0D --- java/org/apache/commons/httpclient/HttpMultiClient.java 8 Jul 2002 14:3= 4:16 -0000=0D ***************=0D *** 63,70 ****=0D --- 63,75 ----=0D package org.apache.commons.httpclient;=0D =20=0D import java.io.IOException;=0D + import java.net.MalformedURLException;=0D + import java.net.URL;=0D + import javax.net.ssl.SSLSocketFactory;=0D =20=0D import org.apache.commons.httpclient.log.*;=0D + import org.apache.commons.httpclient.methods.GetMethod;=0D + import org.apache.commons.httpclient.methods.PostMethod;=0D =20=0D /**=0D *=0D ***************=0D *** 85,91 ****=0D =20=0D // ----------------------------------------------------- Instance Var= iables=0D private HttpSharedState state =3D null;=0D ! private HttpConnectionManager mgr =3D new HttpConnectionManager();=0D private boolean strictMode =3D true;=0D private int timeoutConnection =3D 0;=0D private int timeoutRequest =3D 0;=0D --- 90,96 ----=0D =20=0D // ----------------------------------------------------- Instance Var= iables=0D private HttpSharedState state =3D null;=0D ! private HttpConnectionManager mgr =3D null;=0D private boolean strictMode =3D true;=0D private int timeoutConnection =3D 0;=0D private int timeoutRequest =3D 0;=0D ***************=0D *** 100,105 ****=0D --- 105,111 ----=0D */=0D public HttpMultiClient()=0D {=0D + mgr =3D new HttpConnectionManager(getState());=0D }=0D =20=0D /**=0D ***************=0D *** 266,271 ****=0D --- 272,297 ----=0D }=0D =20=0D /**=0D + * Set the maximum number of connections allowed for a given host:por= t.=0D + * Per RFC 2616 section 8.1.4, this value defaults to 2.=0D + *=0D + * @param maxConnections - number of connections allowed for each hos= t:port=0D + */=0D + public void setMaxConnectionsPerHost(int maxConnections)=0D + {=0D + mgr.setMaxConnectionsPerHost(maxConnections);=0D + }=0D +=20=0D + /**=0D + * Allows you to specify a new factory to be used as the default=20=0D + * for creating SSL sockets. Setting the factory to null will=0D + * reset it to using SSLSocketFactory.getDefault().=0D + */=0D + public void setSSLSocketFactory(SSLSocketFactory factory) {=0D + mgr.setSSLSocketFactory(factory);=0D + }=0D + =20=0D + /**=0D *=0D * Execute the given {@link HttpUrlMethod} using my current=0D * {@link HttpConnection connection} and {@link HttpState}. =20=0D ***************=0D *** 279,290 ****=0D --- 305,325 ----=0D */=0D public int executeMethod(HttpUrlMethod method) throws IOException, Ht= tpException=0D {=0D + return executeMethod(method, 0);=0D + }=0D =20=0D + protected int executeMethod(HttpUrlMethod method, int numberOfRedirec= ts)=20=0D + throws IOException, HttpException=0D + {=0D if (null =3D=3D method)=0D {=0D throw new NullPointerException("method parameter");=0D }=0D =20=0D + if(numberOfRedirects > 10)=0D + {=0D + throw new HttpException("Redirected more than 10 times.");=0D + }=0D HttpConnection connection =3D mgr.getConnection(method.getUrl(), = timeoutConnection);=0D connection.setSoTimeout(timeoutRequest);=0D =20=0D ***************=0D *** 309,316 ****=0D mgr.releaseConnection(connection);=0D }=0D =20=0D ! if (status =3D=3D 301 || status =3D=3D 302 ||=20=0D ! status =3D=3D 303 || status =3D=3D 307)=0D {=0D Header header =3D method.getResponseHeader("Location");=0D String url =3D header.getValue();=0D --- 344,356 ----=0D mgr.releaseConnection(connection);=0D }=0D =20=0D ! // Excluding post methods from redirects. Paragraph 10.3=20=0D ! // of HTTP/1.1 RFC2616 says that any method other than GET or HEA= D=0D ! // requires user intervention before redirecting. --Evert=0D ! if (method.getFollowRedirects() &&=0D ! (method instanceof GetMethod || method instanceof PostMethod)= &&=0D ! (status =3D=3D 301 || status =3D=3D 302 ||=20=0D ! status =3D=3D 303 || status =3D=3D 307))=0D {=0D Header header =3D method.getResponseHeader("Location");=0D String url =3D header.getValue();=0D ***************=0D *** 319,331 ****=0D log.error("HttpMultiClient.executeMethod: Received redir= ect without Location header.");=0D throw new HttpException("Received redirect without Locati= on header.");=0D }=0D !=20=0D method.recycle();=0D ! method.setUrl(url);=0D ! return executeMethod(method);=0D }=0D =20=0D return status;=0D }=0D -=20=0D }=0D --- 359,392 ----=0D log.error("HttpMultiClient.executeMethod: Received redir= ect without Location header.");=0D throw new HttpException("Received redirect without Locati= on header.");=0D }=0D ! =20=0D ! log.debug("HttpMultiClient.executeMethod: Following redirect = to: " + url);=0D ! =20=0D ! String oldUrlStr =3D method.getUrl();=0D ! //String oldRequestBody =3D null;=0D ! //if (method instanceof PostMethod)=20=0D ! //{=0D ! // oldRequestBody =3D ((PostMethod)method).getRequestBody(= );=0D ! //}=0D ! URL oldUrl =3D null;=0D ! try=20=0D ! {=0D ! oldUrl =3D new URL(oldUrlStr);=0D ! } catch (MalformedURLException e)=20=0D ! {=0D ! // This means the original url was also malformed. But, i= f that=0D ! // was the case we should never have gotten this far.=0D ! log.debug("HttpMultiClient.executemethod: The original ur= l was malformed: " + e);=0D ! throw e;=0D ! }=0D ! URL newUrl =3D new java.net.URL(oldUrl, url);=0D method.recycle();=0D ! method.setUrl(newUrl.toString());=0D ! //if (method instanceof PostMethod)=0D ! // ((PostMethod)method).setRequestBody(oldRequestBody);=0D ! return executeMethod(method, numberOfRedirects++);=0D }=0D =20=0D return status;=0D }=0D }=0D Index: java/org/apache/commons/httpclient/HttpState.java=0D =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=0D RCS file: /home/cvspublic/jakarta-commons/httpclient/src/java/org/apache/co= mmons/httpclient/HttpState.java,v=0D retrieving revision 1.5=0D diff -c -r1.5 HttpState.java=0D *** java/org/apache/commons/httpclient/HttpState.java 5 Jan 2002 11:16:00 -= 0000 1.5=0D --- java/org/apache/commons/httpclient/HttpState.java 8 Jul 2002 14:34:18 -= 0000=0D ***************=0D *** 92,97 ****=0D --- 92,102 ----=0D private HashMap credMap =3D new HashMap();=0D =20=0D /**=0D + * My proxy {@link Credentials Credentials}, by realm.=0D + */=0D + private HashMap proxyCred =3D new HashMap();=0D +=20=0D + /**=0D * My {@link Cookie Cookie}s.=0D */=0D private ArrayList cookies =3D new ArrayList();=0D ***************=0D *** 226,229 ****=0D --- 231,270 ----=0D return (Credentials)(credMap.get(realm));=0D }=0D =20=0D + /**=0D + *

=0D + * Set the {@link Credentials} for the proxy with the given=0D + * authentication realm.=0D + *

=0D + *

=0D + * When realm is null, I'll use the given=0D + * credentials when no other {@link Credentials} have=0D + * been supplied for the given challenging realm.=0D + * (I.e., use a null realm to set the "default"=0D + * credentials.) Realms rarely make much sense with proxies, so=0D + * null is normally a good choice here.=0D + *

=0D + * @param realm the authentication realm=0D + * @param credentials the authentication credentials for the given re= alm=0D + */=0D + public void setProxyCredentials(String realm, Credentials credentials= ) {=0D + proxyCred.put(realm, credentials);=0D + }=0D +=20=0D + /**=0D + *

=0D + * Get the {@link Credentials} for the proxy with the given authentic= ation=0D + * realm.=0D + *

=0D + *

=0D + * When realm is null, I'll return the=0D + * "default" credentials.=0D + * (See {@link #setCredentials setCredentials}.)=0D + *

=0D + * @param realm the authentication realm=0D + * @return=0D + */=0D + public Credentials getProxyCredentials(String realm) {=0D + return (Credentials) (proxyCred.get(realm));=0D + }=0D }=0D Index: java/org/apache/commons/httpclient/methods/GetMethod.java=0D =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=0D RCS file: /home/cvspublic/jakarta-commons/httpclient/src/java/org/apache/co= mmons/httpclient/methods/GetMethod.java,v=0D retrieving revision 1.10=0D diff -c -r1.10 GetMethod.java=0D *** java/org/apache/commons/httpclient/methods/GetMethod.java 29 Apr 2002 1= 6:04:05 -0000 1.10=0D --- java/org/apache/commons/httpclient/methods/GetMethod.java 8 Jul 2002 14= :34:19 -0000=0D ***************=0D *** 190,198 ****=0D =20=0D =20=0D /**=0D ! * Use disk setter.=0D *=0D ! * @param useDisk New value of useDisk=0D */=0D public void setUseDisk(boolean useDisk) {=0D checkNotUsed();=0D --- 190,199 ----=0D =20=0D =20=0D /**=0D ! * Buffer the response in a file or not. The default is false.=0D *=0D ! * @param useDisk If true the entire response will be buffered in a=0D ! * temporary file.=0D */=0D public void setUseDisk(boolean useDisk) {=0D checkNotUsed();=0D ***************=0D *** 201,209 ****=0D =20=0D =20=0D /**=0D ! * Use disk getter.=0D *=0D ! * @param boolean useDisk value=0D */=0D public boolean getUseDisk() {=0D return useDisk;=0D --- 202,211 ----=0D =20=0D =20=0D /**=0D ! * Tells if the response will be buffered in a file.=0D *=0D ! * @param boolean If true the entire response will be buffered in a=0D ! * temporary file.=0D */=0D public boolean getUseDisk() {=0D return useDisk;=0D Index: java/org/apache/commons/httpclient/methods/PostMethod.java=0D =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=0D RCS file: /home/cvspublic/jakarta-commons/httpclient/src/java/org/apache/co= mmons/httpclient/methods/PostMethod.java,v=0D retrieving revision 1.9=0D diff -c -r1.9 PostMethod.java=0D *** java/org/apache/commons/httpclient/methods/PostMethod.java 24 Apr 2002 = 14:44:50 -0000 1.9=0D --- java/org/apache/commons/httpclient/methods/PostMethod.java 8 Jul 2002 1= 4:34:22 -0000=0D ***************=0D *** 82,88 ****=0D --- 82,99 ----=0D * @author Doug Sale=0D */=0D public class PostMethod extends GetMethod {=0D + /**=0D + * The content length will be calculated automatically. This implies = buffering=0D + * of the content.=0D + */=0D + public static final int CONTENT_LENGTH_AUTO =3D -2;=0D =20=0D + /**=0D + * The request will use chunked transfer encoding. Content length is = not=0D + * calculated and the content is not buffered.
=0D + * Note: Chunked requests are not supported at the moment.=0D + */=0D + public static final int CONTENT_LENGTH_CHUNKED =3D -1;=0D =20=0D // ----------------------------------------------------------- Constr= uctors=0D =20=0D ***************=0D *** 137,142 ****=0D --- 148,155 ----=0D public void recycle() {=0D super.recycle();=0D requestBody =3D null;=0D + requestContentLength =3D CONTENT_LENGTH_AUTO;=0D + buffer =3D null;=0D parameters.clear();=0D }=0D =20=0D ***************=0D *** 157,162 ****=0D --- 170,191 ----=0D }=0D =20=0D /**=0D + * Sets length information about the request body.=0D + *=0D + * @param length size in bytes or any of CONTENT_LENGTH_AUTO,=0D + * CONTENT_LENGTH_CHUNKED. If number of bytes is specified the conten= t will=0D + * not be buffered internally and the Content-Length header of the re= quest=0D + * will be used. In this case the user is responsible to supply the c= orrect=0D + * content length.=0D + */=0D + public void setRequestContentLength(int length) {=0D + if ((length =3D=3D CONTENT_LENGTH_CHUNKED) && !isHttp11()) {=0D + throw new RuntimeException("Chunked transfer encoding not all= owed for HTTP/1.0");=0D + }=0D + requestContentLength =3D length;=0D + }=0D +=20=0D + /**=0D * Overrides method of {@link HttpMethodBase}=0D * to throw {@link IllegalStateException} if=0D * my request body has already been=0D ***************=0D *** 238,248 ****=0D --- 267,286 ----=0D =20=0D /**=0D * @throws IllegalStateException if request params have been added=0D + * @deprecated This method converts characters to bytes in a platform= dependent=0D + * encoding. Use setRequestBody(InputStream) instead.=0D */=0D public void setRequestBody(String body) {=0D if(!parameters.isEmpty()) {=0D throw new IllegalStateException("Request parameters have alre= ady been added.");=0D }=0D + requestBody =3D new ByteArrayInputStream(body.getBytes());=0D + }=0D +=20=0D + public void setRequestBody(InputStream body) {=0D + if(!parameters.isEmpty()) {=0D + throw new IllegalStateException("Request parameters have alre= ady been added.");=0D + }=0D requestBody =3D body;=0D }=0D =20=0D ***************=0D *** 259,274 ****=0D }=0D =20=0D /**=0D ! * Override method of {@link HttpMethodBase}=0D ! * to write request parameters as the=0D ! * request body.=0D */=0D protected boolean writeRequestBody(HttpState state, HttpConnection co= nn) throws IOException, HttpException {=0D log.debug("PostMethod.writeRequestBody(HttpState,HttpConnection)"= );=0D if(null =3D=3D requestBody) {=0D requestBody =3D generateRequestBody(parameters);=0D }=0D ! conn.print(requestBody);=0D return true;=0D }=0D =20=0D --- 297,333 ----=0D }=0D =20=0D /**=0D ! * Override method of {@link HttpMethodBase} to write request paramet= ers as=0D ! * the request body.=0D ! * The input stream will be truncated after the specified content len= gth.=0D ! * @throws IOException if the stream ends before the specified conten= t length.=0D */=0D protected boolean writeRequestBody(HttpState state, HttpConnection co= nn) throws IOException, HttpException {=0D log.debug("PostMethod.writeRequestBody(HttpState,HttpConnection)"= );=0D if(null =3D=3D requestBody) {=0D requestBody =3D generateRequestBody(parameters);=0D }=0D !=20=0D ! byte[] data =3D new byte[10000];=0D ! int l =3D requestBody.read(data);=0D ! int total =3D 0;=0D ! while (l > 0) {=0D ! if ((requestContentLength > 0) && (total + l > requestContent= Length)) {=0D ! l =3D requestContentLength - total;=0D ! conn.write(data, 0, l);=0D ! break;=0D ! }=0D ! conn.write(data, 0, l);=0D ! total +=3D l;=0D ! l =3D requestBody.read(data);=0D ! }=0D ! if ((requestContentLength > 0) && (total < requestContentLength))= {=0D ! throw new IOException("unexpected end of input stream");=0D ! }=0D ! if (buffer !=3D null) {=0D ! //restore buffered content for repeated requests=0D ! requestBody =3D new ByteArrayInputStream(buffer.toByteArray()= );=0D ! }=0D return true;=0D }=0D =20=0D ***************=0D *** 283,293 ****=0D protected int getRequestContentLength() {=0D if(null =3D=3D requestBody) {=0D requestBody =3D generateRequestBody(parameters);=0D }=0D - return requestBody.getBytes().length;=0D }=0D =20=0D ! protected String generateRequestBody(Map params) {=0D if (!params.isEmpty()) {=0D StringBuffer sb =3D new StringBuffer();=0D Iterator it =3D parameters.keySet().iterator();=0D --- 342,385 ----=0D protected int getRequestContentLength() {=0D if(null =3D=3D requestBody) {=0D requestBody =3D generateRequestBody(parameters);=0D + bufferContent();=0D + }=0D +=20=0D + if (requestContentLength !=3D CONTENT_LENGTH_AUTO) {=0D + return requestContentLength;=0D + }=0D +=20=0D + bufferContent();=0D +=20=0D + return requestContentLength;=0D + }=0D +=20=0D + /**=0D + * Buffers the request body and calculates the content length.=0D + * If the method was called earlier it returns immediately.=0D + */=0D + private void bufferContent() {=0D + if (buffer !=3D null) return;=0D + try {=0D + buffer =3D new ByteArrayOutputStream();=0D + byte[] data =3D new byte[10000];=0D + int l =3D requestBody.read(data);=0D + int total =3D 0;=0D + while (l > 0) {=0D + buffer.write(data, 0, l);=0D + total +=3D l;=0D + l =3D requestBody.read(data);=0D + }=0D + requestBody =3D new ByteArrayInputStream(buffer.toByteArray()= );=0D + requestContentLength =3D total;=0D + } catch(IOException e) {=0D + requestBody =3D null;=0D + requestContentLength =3D 0;=0D }=0D }=0D =20=0D ! //shouldn't this be private ?=0D ! protected InputStream generateRequestBody(Map params) {=0D if (!params.isEmpty()) {=0D StringBuffer sb =3D new StringBuffer();=0D Iterator it =3D parameters.keySet().iterator();=0D ***************=0D *** 315,328 ****=0D }=0D }=0D }=0D ! return sb.toString();=0D } else {=0D ! return "";=0D }=0D }=0D =20=0D ! private String requestBody =3D null;=0D private HashMap parameters =3D new HashMap();=0D =20=0D // -------------------------------------------------------------- Con= stants=0D =20=0D --- 407,422 ----=0D }=0D }=0D }=0D ! return new ByteArrayInputStream(sb.toString().getBytes());=0D } else {=0D ! return new ByteArrayInputStream(new byte[0]);=0D }=0D }=0D =20=0D ! private InputStream requestBody =3D null;=0D private HashMap parameters =3D new HashMap();=0D + private int requestContentLength =3D CONTENT_LENGTH_AUTO;=0D + private ByteArrayOutputStream buffer =3D null;=0D =20=0D // -------------------------------------------------------------- Con= stants=0D =20=0D Index: test/org/apache/commons/httpclient/TestWebappMethods.java=0D =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=0D RCS file: /home/cvspublic/jakarta-commons/httpclient/src/test/org/apache/co= mmons/httpclient/TestWebappMethods.java,v=0D retrieving revision 1.4=0D diff -c -r1.4 TestWebappMethods.java=0D *** test/org/apache/commons/httpclient/TestWebappMethods.java 24 Apr 2002 1= 4:44:50 -0000 1.4=0D --- test/org/apache/commons/httpclient/TestWebappMethods.java 8 Jul 2002 14= :34:25 -0000=0D ***************=0D *** 62,67 ****=0D --- 62,69 ----=0D =20=0D package org.apache.commons.httpclient;=0D =20=0D + import java.io.ByteArrayInputStream;=0D +=20=0D import junit.framework.*;=0D import org.apache.commons.httpclient.methods.*;=0D =20=0D ***************=0D *** 322,327 ****=0D --- 324,388 ----=0D assertTrue(method.getResponseBodyAsString().indexOf("quote=3D= It+was+the+best+of+times%2C+it+was+the+worst+of+times.") >=3D 0);=0D assertEquals(200,method.getStatusCode());=0D }=0D +=20=0D +=20=0D + public void testPostBodyCustomLength() throws Exception {=0D + HttpClient client =3D new HttpClient();=0D + client.startSession(host, port);=0D + PostMethod method =3D new PostMethod("/" + context + "/body");=0D + method.setUseDisk(false);=0D + String body =3D "quote=3DIt+was+the+best+of+times%2C+it+was+the+w= orst+of+times.";=0D + method.setRequestBody(new ByteArrayInputStream(body.getBytes()));=0D + method.setRequestContentLength(body.length());=0D + try {=0D + client.executeMethod(method);=0D + } catch (Throwable t) {=0D + t.printStackTrace();=0D + fail("Unable to execute method : " + t.toString());=0D + }=0D + assertTrue(method.getResponseBodyAsString().indexOf("quote=3D= It+was+the+best+of+times%2C+it+was+the+worst+of+times.") >=3D 0);=0D + assertEquals(200,method.getStatusCode());=0D + }=0D +=20=0D +=20=0D + public void testPostBodyAutoLength() throws Exception {=0D + HttpClient client =3D new HttpClient();=0D + client.startSession(host, port);=0D + PostMethod method =3D new PostMethod("/" + context + "/body");=0D + method.setUseDisk(false);=0D + String body =3D "quote=3DIt+was+the+best+of+times%2C+it+was+the+w= orst+of+times.";=0D + method.setRequestBody(new ByteArrayInputStream(body.getBytes()));=0D + method.setRequestContentLength(PostMethod.CONTENT_LENGTH_AUTO);=0D + try {=0D + client.executeMethod(method);=0D + } catch (Throwable t) {=0D + t.printStackTrace();=0D + fail("Unable to execute method : " + t.toString());=0D + }=0D + assertTrue(method.getResponseBodyAsString().indexOf("quote=3D= It+was+the+best+of+times%2C+it+was+the+worst+of+times.") >=3D 0);=0D + assertEquals(200,method.getStatusCode());=0D + }=0D +=20=0D + /*=0D + //enable this when chunked requests are properly implemented=0D + public void testPostBodyChunked() throws Exception {=0D + HttpClient client =3D new HttpClient();=0D + client.startSession(host, port);=0D + PostMethod method =3D new PostMethod("/" + context + "/body");=0D + method.setUseDisk(false);=0D + String body =3D "quote=3DIt+was+the+best+of+times%2C+it+was+the+w= orst+of+times.";=0D + method.setRequestBody(new ByteArrayInputStream(body.getBytes()));=0D + method.setRequestContentLength(PostMethod.CONTENT_LENGTH_CHUNKED)= ;=0D + try {=0D + client.executeMethod(method);=0D + } catch (Throwable t) {=0D + t.printStackTrace();=0D + fail("Unable to execute method : " + t.toString());=0D + }=0D + assertTrue(method.getResponseBodyAsString().indexOf("quote=3D= It+was+the+best+of+times%2C+it+was+the+worst+of+times.") >=3D 0);=0D + assertEquals(200,method.getStatusCode());=0D + }=0D + */=0D =20=0D public void testPutBody() throws Exception {=0D HttpClient client =3D new HttpClient();=0D Index: test/org/apache/commons/httpclient/TestWebappRedirect.java=0D =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=0D RCS file: /home/cvspublic/jakarta-commons/httpclient/src/test/org/apache/co= mmons/httpclient/TestWebappRedirect.java,v=0D retrieving revision 1.4=0D diff -c -r1.4 TestWebappRedirect.java=0D *** test/org/apache/commons/httpclient/TestWebappRedirect.java 4 Feb 2002 1= 5:26:43 -0000 1.4=0D --- test/org/apache/commons/httpclient/TestWebappRedirect.java 8 Jul 2002 1= 4:34:26 -0000=0D ***************=0D *** 206,216 ****=0D t.printStackTrace();=0D fail("Unable to execute method : " + t.toString());=0D }=0D ! assertEquals(200,method.getStatusCode());=0D ! assertTrue(method.getResponseBodyAsString().indexOf("Param= Servlet: POST") >=3D 0);=0D ! assertTrue(method.getResponseBodyAsString().indexOf("

QueryStri= ng=3D\"foo=3Dbar&bar=3Dfoo\"

") >=3D 0);=0D ! assertTrue(method.getResponseBodyAsString().indexOf("name=3D\"par= a\";value=3D\"meter\"") >=3D 0);=0D ! assertTrue(method.getResponseBodyAsString().indexOf("name=3D\"par= am\";value=3D\"eter\"") >=3D 0);=0D }=0D =20=0D public void testPutRedirect() throws Exception {=0D --- 206,212 ----=0D t.printStackTrace();=0D fail("Unable to execute method : " + t.toString());=0D }=0D ! assertEquals(HttpStatus.SC_MOVED_TEMPORARILY,method.getStatusCode= ());=0D }=0D =20=0D public void testPutRedirect() throws Exception {=0D ***************=0D *** 226,233 ****=0D t.printStackTrace();=0D fail("Unable to execute method : " + t.toString());=0D }=0D ! assertTrue(method.getResponseBodyAsString(),method.getResponseBod= yAsString().indexOf("This is data to be sent in the body of an HTTP PUT= .") >=3D 0);=0D ! assertEquals(200,method.getStatusCode());=0D }=0D }=0D =20=0D --- 222,228 ----=0D t.printStackTrace();=0D fail("Unable to execute method : " + t.toString());=0D }=0D ! assertEquals(HttpStatus.SC_MOVED_TEMPORARILY,method.getStatusCode= ());=0D }=0D }=0D =20=0D --=-YkpFepswu6eCKJ/YNi3v Content-Type: text/plain; charset=us-ascii -- To unsubscribe, e-mail: For additional commands, e-mail: --=-YkpFepswu6eCKJ/YNi3v--