HTTPClient.HTTPConnection Maven / Gradle / Ivy
Show all versions of grinder-httpclient Show documentation
/* * @(#)HTTPConnection.java 0.3-3E 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/ * * This file contains modifications for use with "The Grinder" * (http://grinder.sourceforge.net) under the terms of the LGPL. They * are marked below with the comment "GRINDER MODIFICATION". * */ package HTTPClient; import java.io.OutputStream; import java.io.DataOutputStream; import java.io.FilterOutputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InterruptedIOException; import java.net.URL; import java.net.Socket; import java.net.InetAddress; import java.net.SocketException; import java.net.ConnectException; import java.net.UnknownHostException; import java.net.NoRouteToHostException; import java.util.Vector; import java.util.concurrent.atomic.AtomicLong; import java.applet.Applet; import javax.net.ssl.SSLSocket; import javax.net.ssl.SSLException; import javax.net.ssl.SSLSocketFactory; import javax.security.cert.X509Certificate; /** * This class implements http protocol requests; it contains most of HTTP/1.1 * and ought to be unconditionally compliant. * Redirections are automatically handled, and authorizations requests are * recognized and dealt with via an authorization handler. * Only full HTTP/1.0 and HTTP/1.1 requests are generated. HTTP/1.1, HTTP/1.0 * and HTTP/0.9 responses are recognized. * *
should be * invoked. * *Using the HTTPClient should be quite simple. First add the import * statement '
import HTTPClient.*;
' to your file(s). Request * can then be sent using one of the methods Head(), * Get(), Post(), etc in HTTPConnection. * These methods all return an instance of HTTPResponse which * has methods for accessing the response headers (getHeader(), * getHeaderAsInt(), etc), various response info * (getStatusCode(), getReasonLine(), etc) and the * reponse data (getData(), getText(), and * getInputStream()). Following are some examples. * *If this is in an applet you can retrieve files from your server * as follows: * *
* try * { * HTTPConnection con = new HTTPConnection(this); * HTTPResponse rsp = con.Get("/my_file"); * if (rsp.getStatusCode() >= 300) * { * System.err.println("Received Error: "+rsp.getReasonLine()); * System.err.println(rsp.getText()); * } * else * data = rsp.getData(); * * rsp = con.Get("/another_file"); * if (rsp.getStatusCode() >= 300) * { * System.err.println("Received Error: "+rsp.getReasonLine()); * System.err.println(rsp.getText()); * } * else * other_data = rsp.getData(); * } * catch (IOException ioe) * { * System.err.println(ioe.toString()); * } * catch (ModuleException me) * { * System.err.println("Error handling request: " + me.getMessage()); * } ** * This will get the files "/my_file" and "/another_file" and put their * contents into byte[]'s accessible viagetData()
. Note that * you need to only create a new HTTPConnection when sending a * request to a new server (different host or port); although you may create * a new HTTPConnection for every request to the same server this * not recommended, as various information about the server * is cached after the first request (to optimize subsequent requests) and * persistent connections are used whenever possible. * *To POST form data you would use something like this (assuming you * have two fields called name and e-mail, whose * contents are stored in the variables name and email): * *
* try * { * NVPair form_data[] = new NVPair[2]; * form_data[0] = new NVPair("name", name); * form_data[1] = new NVPair("e-mail", email); * * HTTPConnection con = new HTTPConnection(this); * HTTPResponse rsp = con.Post("/cgi-bin/my_script", form_data); * if (rsp.getStatusCode() >= 300) * { * System.err.println("Received Error: "+rsp.getReasonLine()); * System.err.println(rsp.getText()); * } * else * stream = rsp.getInputStream(); * } * catch (IOException ioe) * { * System.err.println(ioe.toString()); * } * catch (ModuleException me) * { * System.err.println("Error handling request: " + me.getMessage()); * } ** * Here the response data is read at leasure via an InputStream * instead of all at once into a byte[]. * *As another example, if you have a URL you're trying to send a request * to you would do something like the following: * *
* try * { * URL url = new URL("http://www.mydomain.us/test/my_file"); * HTTPConnection con = new HTTPConnection(url); * HTTPResponse rsp = con.Put(url.getFile(), "Hello World"); * if (rsp.getStatusCode() >= 300) * { * System.err.println("Received Error: "+rsp.getReasonLine()); * System.err.println(rsp.getText()); * } * else * text = rsp.getText(); * } * catch (IOException ioe) * { * System.err.println(ioe.toString()); * } * catch (ModuleException me) * { * System.err.println("Error handling request: " + me.getMessage()); * } ** *There are a whole number of methods for each request type; however the * general forms are ([...] means that the enclosed is optional): *
*
* * @version 0.3-3E 06/05/2001 * @author Ronald Tschalär */ public class HTTPConnection implements GlobalConstants, HTTPClientModuleConstants { /** The current version of this package. */ public final static String version = "RPT-HTTPClient/0.3-3E"; /** The default context */ private final static Object dflt_context = new Object(); /** The current context */ private Object Context = null; /** The protocol used on this connection */ private int Protocol; /** The server's protocol version; M.m stored as (M<<16 | m) */ int ServerProtocolVersion; /** Have we gotten the server's protocol version yet? */ boolean ServProtVersKnown; /** The protocol version we send in a request; this is always HTTP/1.1 unless we're talking to a broken server in which case it's HTTP/1.0 */ private String RequestProtocolVersion; /** The remote host this connection is associated with */ private String Host; /** The remote port this connection is attached to */ private int Port; /** The local address this connection is associated with */ private InetAddress LocalAddr; /** The local port this connection is attached to */ private int LocalPort; /** The current proxy host to use (if any) */ private String Proxy_Host = null; /** The current proxy port */ private int Proxy_Port; /** The default proxy host to use (if any) */ private static String Default_Proxy_Host = null; /** The default proxy port */ private static int Default_Proxy_Port; /** The list of hosts for which no proxy is to be used */ private static CIHashtable non_proxy_host_list = new CIHashtable(); private static Vector non_proxy_dom_list = new Vector(); private static Vector non_proxy_addr_list = new Vector(); private static Vector non_proxy_mask_list = new Vector(); /** The socks server to use */ private SocksClient Socks_client = null; /** The default socks server to use */ private static SocksClient Default_Socks_client = null; /** the current stream demultiplexor */ private StreamDemultiplexor input_demux = null; /** a list of active stream demultiplexors */ LinkedList DemuxList = new LinkedList(); /** a list of active requests */ private LinkedList RequestList = new LinkedList(); /** does the server support keep-alive's? */ private boolean doesKeepAlive = false; /** have we been able to determine the above yet? */ private boolean keepAliveUnknown = true; /** the maximum number of requests over a HTTP/1.0 keep-alive connection */ private int keepAliveReqMax = -1; /** the number of requests over a HTTP/1.0 keep-alive connection left */ private int keepAliveReqLeft; /** hack to force buffering of data instead of using chunked T-E */ private static boolean no_chunked = false; /** hack to force HTTP/1.0 requests */ private static boolean force_1_0 = false; /** hack to be able to disable pipelining */ private static boolean neverPipeline = false; /** hack to be able to disable keep-alives */ private static boolean noKeepAlives = false; /** hack to work around M$ bug */ private static boolean haveMSLargeWritesBug = false; /** hack to only enable defered handling of streamed requests when * configured to do so. */ static boolean deferStreamed = false; /** ++GRINDER MODIFICATION **/ /** hack to disable trailers */ private static boolean noTrailers = false; /** hack to capture DNS lookup time */ private AtomicLong DNS_time = new AtomicLong(); /** hack to capture Initial Connection time */ private AtomicLong con_time = new AtomicLong(); public interface TimeAuthority { long getTimeInMilliseconds(); } private static TimeAuthority standardTimeAuthority = new TimeAuthority() { public long getTimeInMilliseconds() { return System.currentTimeMillis(); } }; private TimeAuthority timeAuthority = standardTimeAuthority; public void setTimeAuthority(TimeAuthority timeAuthority) { this.timeAuthority = timeAuthority; } public TimeAuthority getTimeAuthority() { return timeAuthority; } /** --GRINDER MODIFICATION **/ /** the default timeout to use for new connections */ private static int DefaultTimeout = 0; /** the timeout to use for reading responses */ private int Timeout; /** The list of default http headers */ private NVPair[] DefaultHeaders = new NVPair[0]; /** The default list of modules (as a Vector of Class objects) */ private static Vector DefaultModuleList; /** The list of modules (as a Vector of Class objects) */ private Vector ModuleList; /** controls whether modules are allowed to interact with user */ private static boolean defaultAllowUI = true; /** controls whether modules are allowed to interact with user */ private boolean allowUI; /** JSSE's default socket factory */ private static SSLSocketFactory defaultSSLFactory = (SSLSocketFactory) SSLSocketFactory.getDefault(); /** JSSE's socket factory */ private SSLSocketFactory sslFactory; static { /* * Let's try and see if we can figure out whether any proxies are * being used. */ try // JDK 1.1 naming { String host = System.getProperty("http.proxyHost"); if (host == null) throw new Exception(); // try JDK 1.0.x naming int port = Integer.getInteger("http.proxyPort", -1).intValue(); Log.write(Log.CONN, "Conn: using proxy " + host + ":" + port); setProxyServer(host, port); } catch (Exception e) { try // JDK 1.0.x naming { if (Boolean.getBoolean("proxySet")) { String host = System.getProperty("proxyHost"); int port = Integer.getInteger("proxyPort", -1).intValue(); Log.write(Log.CONN, "Conn: using proxy " + host + ":" + port); setProxyServer(host, port); } } catch (Exception ee) { Default_Proxy_Host = null; } } /* * now check for the non-proxy list */ try { String hosts = System.getProperty("HTTPClient.nonProxyHosts"); if (hosts == null) hosts = System.getProperty("http.nonProxyHosts"); String[] list = Util.splitProperty(hosts); dontProxyFor(list); } catch (Exception e) { } /* * we can't turn the JDK SOCKS handling off, so we don't use the * properties 'socksProxyHost' and 'socksProxyPort'. Instead we * define 'HTTPClient.socksHost', 'HTTPClient.socksPort' and * 'HTTPClient.socksVersion'. */ try { String host = System.getProperty("HTTPClient.socksHost"); if (host != null && host.length() > 0) { int port = Integer.getInteger("HTTPClient.socksPort", -1).intValue(); int version = Integer.getInteger("HTTPClient.socksVersion", -1).intValue(); Log.write(Log.CONN, "Conn: using SOCKS " + host + ":" + port); if (version == -1) setSocksServer(host, port); else setSocksServer(host, port, version); } } catch (Exception e) { Default_Socks_client = null; } // Set up module list String modules = "HTTPClient.RetryModule|" + "HTTPClient.CookieModule|" + "HTTPClient.RedirectionModule|" + "HTTPClient.AuthorizationModule|" + "HTTPClient.DefaultModule|" + "HTTPClient.TransferEncodingModule|" + "HTTPClient.ContentMD5Module|" + "HTTPClient.ContentEncodingModule"; boolean in_applet = false; try { modules = System.getProperty("HTTPClient.Modules", modules); } catch (SecurityException se) { in_applet = true; } DefaultModuleList = new Vector(); String[] list = Util.splitProperty(modules); for (int idx=0; idx- Head ( file [, form-data [, headers ] ] ) *
- Head ( file [, query [, headers ] ] ) *
- Get ( file [, form-data [, headers ] ] ) *
- Get ( file [, query [, headers ] ] ) *
- Post ( file [, form-data [, headers ] ] ) *
- Post ( file [, data [, headers ] ] ) *
- Post ( file [, stream [, headers ] ] ) *
- Put ( file , data [, headers ] ) *
- Put ( file , stream [, headers ] ) *
- Delete ( file [, headers ] ) *
- Options ( file [, headers [, data] ] ) *
- Options ( file [, headers [, stream] ] ) *
- Trace ( file [, headers ] ) *
= 0 && System.getProperty("java.version").startsWith("1.1")) haveMSLargeWritesBug = true; if (haveMSLargeWritesBug) Log.write(Log.CONN, "Conn: splitting large writes into 20K chunks (M$ bug)"); } catch (Exception e) { } /** ++GRINDER MODIFICATION **/ /* * Hack: disable trailers */ try { noTrailers = Boolean.getBoolean("HTTPClient.disableTrailers"); if (noTrailers) Log.write(Log.CONN, "Conn: disabling trailers"); } catch (Exception e) { } /** --GRINDER MODIFICATION **/ /* * Deferring the handling of responses to requests which used an output * stream is new in V0.3-3. Because it can cause memory leaks for apps * which aren't expecting this, we only enable this feature if * explicitly requested to do so. */ try { deferStreamed = Boolean.getBoolean("HTTPClient.deferStreamed"); if (deferStreamed) Log.write(Log.CONN, "Conn: enabling defered handling of " + "responses to streamed requests"); } catch (Exception e) { } } /** ++GRINDER MODIFICATION **/ private static final String[] sslCipherSuites; private static final String[] sslProtocols; static { final String cipherSuiteProperty = System.getProperty("https.cipherSuites"); if (cipherSuiteProperty != null) { sslCipherSuites = cipherSuiteProperty.split(","); } else { sslCipherSuites = defaultSSLFactory.getSupportedCipherSuites(); } final String protocolProperty = System.getProperty("https.protocols"); if (protocolProperty != null) { sslProtocols = protocolProperty.split(","); } else { try { final SSLSocket socket = (SSLSocket)defaultSSLFactory.createSocket(); sslProtocols = socket.getSupportedProtocols(); socket.close(); } catch (IOException e) { throw new ExceptionInInitializerError(e); } } } /** * The list of cipher suites that will used for SSL sockets. * * By default, this is the list of all cipher suites supported by the * JVM. It can be overridden with the system property {@code * https.cipherSuites}.
* * @return The list of cipher suites. */ public static String[] getSSLCipherSuites() { return sslCipherSuites; } /** * The list of protocols that will used for SSL sockets. * *By default, this is the list of all protocols supported by the * JVM. It can be overridden with the system property {@code * https.protocols}.
* * @return The list of protocols. */ public static String[] getSSLProtocols() { return sslProtocols; } /** --GRINDER MODIFICATION **/ // Constructors /** * Constructs a connection to the host from where the applet was loaded. * Note that current security policies only let applets connect home. * * @param applet the current applet */ public HTTPConnection(Applet applet) throws ProtocolNotSuppException { this(applet.getCodeBase().getProtocol(), applet.getCodeBase().getHost(), applet.getCodeBase().getPort()); } /** * Constructs a connection to the specified host on port 80 * * @param host the host */ public HTTPConnection(String host) { Setup(HTTP, host, 80, null, -1); } /** * Constructs a connection to the specified host on the specified port * * @param host the host * @param port the port */ public HTTPConnection(String host, int port) { Setup(HTTP, host, port, null, -1); } /** * Constructs a connection to the specified host on the specified port, * using the specified protocol (currently only "http" is supported). * * @param prot the protocol * @param host the host * @param port the port, or -1 for the default port * @exception ProtocolNotSuppException if the protocol is not HTTP */ public HTTPConnection(String prot, String host, int port) throws ProtocolNotSuppException { this(prot, host, port, null, -1); } /** * Constructs a connection to the specified host on the specified port, * using the specified protocol (currently only "http" is supported), * local address, and local port. * * @param prot the protocol * @param host the host * @param port the port, or -1 for the default port * @param localAddr the local address to bind to * @param lcoalPort the local port to bind to * @exception ProtocolNotSuppException if the protocol is not HTTP */ public HTTPConnection(String prot, String host, int port, InetAddress localAddr, int localPort) throws ProtocolNotSuppException { prot = prot.trim().toLowerCase(); if (!prot.equals("http") && !prot.equals("https")) throw new ProtocolNotSuppException("Unsupported protocol '" + prot + "'"); if (prot.equals("http")) Setup(HTTP, host, port, localAddr, localPort); else if (prot.equals("https")) Setup(HTTPS, host, port, localAddr, localPort); else if (prot.equals("shttp")) Setup(SHTTP, host, port, localAddr, localPort); else if (prot.equals("http-ng")) Setup(HTTP_NG, host, port, localAddr, localPort); } /** * Constructs a connection to the host (port) as given in the url. * * @param url the url * @exception ProtocolNotSuppException if the protocol is not HTTP */ public HTTPConnection(URL url) throws ProtocolNotSuppException { this(url.getProtocol(), url.getHost(), url.getPort()); } /** * Constructs a connection to the host (port) as given in the uri. * * @param uri the uri * @exception ProtocolNotSuppException if the protocol is not HTTP */ public HTTPConnection(URI uri) throws ProtocolNotSuppException { this(uri.getScheme(), uri.getHost(), uri.getPort()); } /** * Sets the class variables. Must not be public. * * @param prot the protocol * @param host the host * @param port the port * @param localAddr the local address to bind to; if null, it's ignored * @param localPort the local port to bind to */ private void Setup(int prot, String host, int port, InetAddress localAddr, int localPort) { Protocol = prot; Host = host.trim().toLowerCase(); Port = port; LocalAddr = localAddr; LocalPort = localPort; if (Port == -1) Port = URI.defaultPort(getProtocol()); if (Default_Proxy_Host != null && !matchNonProxy(Host)) setCurrentProxy(Default_Proxy_Host, Default_Proxy_Port); else setCurrentProxy(null, 0); Socks_client = Default_Socks_client; Timeout = DefaultTimeout; ModuleList = (Vector) DefaultModuleList.clone(); allowUI = defaultAllowUI; if (noKeepAlives) setDefaultHeaders(new NVPair[] { new NVPair("Connection", "close") }); sslFactory = defaultSSLFactory; } /** * Determines if the given host matches any entry in the non-proxy list. * * @param host the host to match - must be trim()'d and lowercase * @return true if a match is found, false otherwise * @see #dontProxyFor(java.lang.String) */ private boolean matchNonProxy(String host) { // Check host name list if (non_proxy_host_list.get(host) != null) return true; // Check domain name list for (int idx=0; idx0) File += "?" + query; return setupRequest("HEAD", File, headers, null, null); } /** * Sends the HEAD request. This request is just like the corresponding * GET except that it only returns the headers and no data. * * @see #Get(java.lang.String, java.lang.String) * @param file the absolute path of the file * @param query the query string; it will be urlencoded * @return an HTTPResponse structure containing the response * @exception java.io.IOException when an exception is returned from * the socket. * @exception ModuleException if an exception is encountered in any module. */ public HTTPResponse Head(String file, String query) throws IOException, ModuleException { return Head(file, query, null); } /** * Sends the HEAD request. This request is just like the corresponding * GET except that it only returns the headers and no data. * * @see #Get(java.lang.String, java.lang.String, HTTPClient.NVPair[]) * @param file the absolute path of the file * @param query the query string; it will be urlencoded * @param headers additional headers * @return an HTTPResponse structure containing the response * @exception java.io.IOException when an exception is returned from * the socket. * @exception ModuleException if an exception is encountered in any module. */ public HTTPResponse Head(String file, String query, NVPair[] headers) throws IOException, ModuleException { String File = stripRef(file); if (query != null && query.length() > 0) File += "?" + Codecs.URLEncode(query); return setupRequest("HEAD", File, headers, null, null); } /** * GETs the file. * * @param file the absolute path of the file * @return an HTTPResponse structure containing the response * @exception java.io.IOException when an exception is returned from * the socket. * @exception ModuleException if an exception is encountered in any module. */ public HTTPResponse Get(String file) throws IOException, ModuleException { return Get(file, (String) null, null); } /** * GETs the file with a query consisting of the specified form-data. * The data is urlencoded, turned into a string of the form * "name1=value1&name2=value2" and then sent as a query string. * * @param file the absolute path of the file * @param form_data an array of Name/Value pairs * @return an HTTPResponse structure containing the response * @exception java.io.IOException when an exception is returned from * the socket. * @exception ModuleException if an exception is encountered in any module. */ public HTTPResponse Get(String file, NVPair form_data[]) throws IOException, ModuleException { return Get(file, form_data, null); } /** * GETs the file with a query consisting of the specified form-data. * The data is urlencoded, turned into a string of the form * "name1=value1&name2=value2" and then sent as a query string. * * @param file the absolute path of the file * @param form_data an array of Name/Value pairs * @param headers additional headers * @return an HTTPResponse structure containing the response * @exception java.io.IOException when an exception is returned from * the socket. * @exception ModuleException if an exception is encountered in any module. */ public HTTPResponse Get(String file, NVPair[] form_data, NVPair[] headers) throws IOException, ModuleException { String File = stripRef(file), query = Codecs.nv2query(form_data); if (query != null && query.length() > 0) File += "?" + query; return setupRequest("GET", File, headers, null, null); } /** * GETs the file using the specified query string. The query string * is first urlencoded. * * @param file the absolute path of the file * @param query the query * @return an HTTPResponse structure containing the response * @exception java.io.IOException when an exception is returned from * the socket. * @exception ModuleException if an exception is encountered in any module. */ public HTTPResponse Get(String file, String query) throws IOException, ModuleException { return Get(file, query, null); } /** * GETs the file using the specified query string. The query string * is first urlencoded. * * @param file the absolute path of the file * @param query the query string * @param headers additional headers * @return an HTTPResponse structure containing the response * @exception java.io.IOException when an exception is returned from * the socket. * @exception ModuleException if an exception is encountered in any module. */ public HTTPResponse Get(String file, String query, NVPair[] headers) throws IOException, ModuleException { String File = stripRef(file); if (query != null && query.length() > 0) File += "?" + Codecs.URLEncode(query); return setupRequest("GET", File, headers, null, null); } /** * POSTs to the specified file. No data is sent. * * @param file the absolute path of the file * @return an HTTPResponse structure containing the response * @exception java.io.IOException when an exception is returned from * the socket. * @exception ModuleException if an exception is encountered in any module. */ public HTTPResponse Post(String file) throws IOException, ModuleException { return Post(file, (byte []) null, null); } /** * POSTs form-data to the specified file. The data is first urlencoded * and then turned into a string of the form "name1=value1&name2=value2". * A Content-type header with the value * application/x-www-form-urlencoded is added. * * @param file the absolute path of the file * @param form_data an array of Name/Value pairs * @return an HTTPResponse structure containing the response * @exception java.io.IOException when an exception is returned from * the socket. * @exception ModuleException if an exception is encountered in any module. */ public HTTPResponse Post(String file, NVPair form_data[]) throws IOException, ModuleException { NVPair[] headers = /** ++GRINDER MODIFICATION **/ // { new NVPair("Content-type", "application/x-www-form-urlencoded") }; { new NVPair("Content-Type", "application/x-www-form-urlencoded") }; /** --GRINDER MODIFICATION **/ return Post(file, Codecs.nv2query(form_data), headers); } /** * POST's form-data to the specified file using the specified headers. * The data is first urlencoded and then turned into a string of the * form "name1=value1&name2=value2". If no Content-type header * is given then one is added with a value of * application/x-www-form-urlencoded. * * @param file the absolute path of the file * @param form_data an array of Name/Value pairs * @param headers additional headers * @return a HTTPResponse structure containing the response * @exception java.io.IOException when an exception is returned from * the socket. * @exception ModuleException if an exception is encountered in any module. */ public HTTPResponse Post(String file, NVPair form_data[], NVPair headers[]) throws IOException, ModuleException { int idx; for (idx=0; idx 0) tmp = data.getBytes(); return Post(file, tmp, headers); } /** * POSTs the raw data to the specified file. * The request is sent using the content-type "application/octet-stream" * * @param file the absolute path of the file * @param data the data * @return an HTTPResponse structure containing the response * @exception java.io.IOException when an exception is returned from * the socket. * @exception ModuleException if an exception is encountered in any module. */ public HTTPResponse Post(String file, byte data[]) throws IOException, ModuleException { return Post(file, data, null); } /** * POSTs the raw data to the specified file using the specified headers. * * @param file the absolute path of the file * @param data the data * @param headers additional headers * @return an HTTPResponse structure containing the response * @exception java.io.IOException when an exception is returned from * the socket. * @exception ModuleException if an exception is encountered in any module. */ public HTTPResponse Post(String file, byte data[], NVPair[] headers) throws IOException, ModuleException { if (data == null) data = new byte[0]; // POST must always have a CL return setupRequest("POST", stripRef(file), headers, data, null); } /** * POSTs the data written to the output stream to the specified file. * The request is sent using the content-type "application/octet-stream" * * @param file the absolute path of the file * @param stream the output stream on which the data is written * @return an HTTPResponse structure containing the response * @exception java.io.IOException when an exception is returned from * the socket. * @exception ModuleException if an exception is encountered in any module. */ public HTTPResponse Post(String file, HttpOutputStream stream) throws IOException, ModuleException { return Post(file, stream, null); } /** * POSTs the data written to the output stream to the specified file * using the specified headers. * * @param file the absolute path of the file * @param stream the output stream on which the data is written * @param headers additional headers * @return an HTTPResponse structure containing the response * @exception java.io.IOException when an exception is returned from * the socket. * @exception ModuleException if an exception is encountered in any module. */ public HTTPResponse Post(String file, HttpOutputStream stream, NVPair[] headers) throws IOException, ModuleException { return setupRequest("POST", stripRef(file), headers, null, stream); } /** * PUTs the data into the specified file. The data is converted to an * array of bytes using the default character converter. * The request ist sent using the content-type "application/octet-stream". * * @param file the absolute path of the file * @param data the data * @return an HTTPResponse structure containing the response * @exception java.io.IOException when an exception is returned from * the socket. * @exception ModuleException if an exception is encountered in any module. * @see java.lang.String#getBytes() */ public HTTPResponse Put(String file, String data) throws IOException, ModuleException { return Put(file, data, null); } /** * PUTs the data into the specified file using the additional headers * for the request. * * @param file the absolute path of the file * @param data the data * @param headers additional headers * @return an HTTPResponse structure containing the response * @exception java.io.IOException when an exception is returned from * the socket. * @exception ModuleException if an exception is encountered in any module. * @see java.lang.String#getBytes() */ public HTTPResponse Put(String file, String data, NVPair[] headers) throws IOException, ModuleException { byte tmp[] = null; if (data != null && data.length() > 0) tmp = data.getBytes(); return Put(file, tmp, headers); } /** * PUTs the raw data into the specified file. * The request is sent using the content-type "application/octet-stream". * * @param file the absolute path of the file * @param data the data * @return an HTTPResponse structure containing the response * @exception java.io.IOException when an exception is returned from * the socket. * @exception ModuleException if an exception is encountered in any module. */ public HTTPResponse Put(String file, byte data[]) throws IOException, ModuleException { return Put(file, data, null); } /** * PUTs the raw data into the specified file using the additional * headers. * * @param file the absolute path of the file * @param data the data * @param headers any additional headers * @return an HTTPResponse structure containing the response * @exception java.io.IOException when an exception is returned from * the socket. * @exception ModuleException if an exception is encountered in any module. */ public HTTPResponse Put(String file, byte data[], NVPair[] headers) throws IOException, ModuleException { if (data == null) data = new byte[0]; // PUT must always have a CL return setupRequest("PUT", stripRef(file), headers, data, null); } /** * PUTs the data written to the output stream into the specified file. * The request is sent using the content-type "application/octet-stream". * * @param file the absolute path of the file * @param stream the output stream on which the data is written * @return an HTTPResponse structure containing the response * @exception java.io.IOException when an exception is returned from * the socket. * @exception ModuleException if an exception is encountered in any module. */ public HTTPResponse Put(String file, HttpOutputStream stream) throws IOException, ModuleException { return Put(file, stream, null); } /** * PUTs the data written to the output stream into the specified file * using the additional headers. * * @param file the absolute path of the file * @param stream the output stream on which the data is written * @param headers any additional headers * @return an HTTPResponse structure containing the response * @exception java.io.IOException when an exception is returned from * the socket. * @exception ModuleException if an exception is encountered in any module. */ public HTTPResponse Put(String file, HttpOutputStream stream, NVPair[] headers) throws IOException, ModuleException { return setupRequest("PUT", stripRef(file), headers, null, stream); } /** * Request OPTIONS from the server. If file is "*" then * the request applies to the server as a whole; otherwise it applies * only to that resource. * * @param file the absolute path of the resource, or "*" * @return an HTTPResponse structure containing the response * @exception java.io.IOException when an exception is returned from * the socket. * @exception ModuleException if an exception is encountered in any module. */ public HTTPResponse Options(String file) throws IOException, ModuleException { return Options(file, null, (byte[]) null); } /** * Request OPTIONS from the server. If file is "*" then * the request applies to the server as a whole; otherwise it applies * only to that resource. * * @param file the absolute path of the resource, or "*" * @param headers the headers containing optional info. * @return an HTTPResponse structure containing the response * @exception java.io.IOException when an exception is returned from * the socket. * @exception ModuleException if an exception is encountered in any module. */ public HTTPResponse Options(String file, NVPair[] headers) throws IOException, ModuleException { return Options(file, headers, (byte[]) null); } /** * Request OPTIONS from the server. If file is "*" then * the request applies to the server as a whole; otherwise it applies * only to that resource. * * @param file the absolute path of the resource, or "*" * @param headers the headers containing optional info. * @param data any data to be sent in the optional body * @return an HTTPResponse structure containing the response * @exception java.io.IOException when an exception is returned from * the socket. * @exception ModuleException if an exception is encountered in any module. */ public HTTPResponse Options(String file, NVPair[] headers, byte[] data) throws IOException, ModuleException { return setupRequest("OPTIONS", stripRef(file), headers, data, null); } /** * Request OPTIONS from the server. If file is "*" then * the request applies to the server as a whole; otherwise it applies * only to that resource. * * @param file the absolute path of the resource, or "*" * @param headers the headers containing optional info. * @param stream an output stream for sending the optional body * @return an HTTPResponse structure containing the response * @exception java.io.IOException when an exception is returned from * the socket. * @exception ModuleException if an exception is encountered in any module. */ public HTTPResponse Options(String file, NVPair[] headers, HttpOutputStream stream) throws IOException, ModuleException { return setupRequest("OPTIONS", stripRef(file), headers, null, stream); } /** * Requests that file be DELETEd from the server. * * @param file the absolute path of the resource * @return an HTTPResponse structure containing the response * @exception java.io.IOException when an exception is returned from * the socket. * @exception ModuleException if an exception is encountered in any module. */ public HTTPResponse Delete(String file) throws IOException, ModuleException { return Delete(file, null); } /** * Requests that file be DELETEd from the server. * * @param file the absolute path of the resource * @param headers additional headers * @return an HTTPResponse structure containing the response * @exception java.io.IOException when an exception is returned from * the socket. * @exception ModuleException if an exception is encountered in any module. */ public HTTPResponse Delete(String file, NVPair[] headers) throws IOException, ModuleException { return setupRequest("DELETE", stripRef(file), headers, null, null); } /** * Requests a TRACE. Headers of particular interest here are "Via" * and "Max-Forwards". * * @param file the absolute path of the resource * @param headers additional headers * @return an HTTPResponse structure containing the response * @exception java.io.IOException when an exception is returned from * the socket. * @exception ModuleException if an exception is encountered in any module. */ public HTTPResponse Trace(String file, NVPair[] headers) throws IOException, ModuleException { return setupRequest("TRACE", stripRef(file), headers, null, null); } /** * Requests a TRACE. * * @param file the absolute path of the resource * @return an HTTPResponse structure containing the response * @exception java.io.IOException when an exception is returned from * the socket. * @exception ModuleException if an exception is encountered in any module. */ public HTTPResponse Trace(String file) throws IOException, ModuleException { return Trace(file, null); } /** * This is here to allow an arbitrary, non-standard request to be sent. * I'm assuming you know what you are doing... * * @param method the extension method * @param file the absolute path of the resource, or null * @param data optional data, or null * @param headers optional headers, or null * @return an HTTPResponse structure containing the response * @exception java.io.IOException when an exception is returned from * the socket. * @exception ModuleException if an exception is encountered in any module. */ public HTTPResponse ExtensionMethod(String method, String file, byte[] data, NVPair[] headers) throws IOException, ModuleException { return setupRequest(method.trim(), stripRef(file), headers, data, null); } /** * This is here to allow an arbitrary, non-standard request to be sent. * I'm assuming you know what you are doing... * * @param method the extension method * @param file the absolute path of the resource, or null * @param stream optional output stream, or null * @param headers optional headers, or null * @return an HTTPResponse structure containing the response * @exception java.io.IOException when an exception is returned from * the socket. * @exception ModuleException if an exception is encountered in any module. */ public HTTPResponse ExtensionMethod(String method, String file, HttpOutputStream os, NVPair[] headers) throws IOException, ModuleException { return setupRequest(method.trim(), stripRef(file), headers, null, os); } /** * Aborts all the requests currently in progress on this connection and * closes all associated sockets. You usually do not need to * invoke this - it only meant for when you need to abruptly stop things, * such as for example the stop button in a browser. * * Note: there is a small window where a request method such as *
Get()
may have been invoked but the request has not * been built and added to the list. Any request in this window will * not be aborted. * * @since V0.2-3 */ public void stop() { for (Request req = (Request) RequestList.enumerate(); req != null; req = (Request) RequestList.next()) req.aborted = true; for (StreamDemultiplexor demux = (StreamDemultiplexor) DemuxList.enumerate(); demux != null; demux = (StreamDemultiplexor) DemuxList.next()) demux.abort(); } /** * Set the SSL socket factory for this connection. If not set, uses the * default factory. * * @param sslFactory the SSL socket factory */ public static void setDefaultSSLSocketFactory(SSLSocketFactory sslFactory) { defaultSSLFactory = sslFactory; } /** * Set the current SSL socket factory for this connection. * * @return the current SSL socket factory */ public static SSLSocketFactory getDefaultSSLSocketFactory() { return defaultSSLFactory; } /** * Set the SSL socket factory for this connection. If not set, uses the * default factory. * * @param sslFactory the SSL socket factory */ public void setSSLSocketFactory(SSLSocketFactory sslFactory) { this.sslFactory = sslFactory; } /** * Set the current SSL socket factory for this connection. * * @return the current SSL socket factory */ public SSLSocketFactory getSSLSocketFactory() { return sslFactory; } /** * Sets the default http headers to be sent with each request. The * actual headers sent are determined as follows: for each header * specified in multiple places a value given as part of the request * takes priority over any default values set by this method, which * in turn takes priority over any built-in default values. A different * way of looking at it is that we start off with a list of all headers * specified with the request, then add any default headers set by this * method which aren't already in our list, and finally add any built-in * headers which aren't yet in the list. There is one exception to this * rule: the "Content-length" header is always ignored; and when posting * form-data any default "Content-type" is ignored in favor of the built-in * "application/x-www-form-urlencoded" (however it will be overriden by any * content-type header specified as part of the request). * *Typical headers you might want to set here are "Accept" and its * "Accept-*" relatives, "Connection", "From", "User-Agent", etc. * * @param headers an array of header-name/value pairs (do not give the * separating ':'). */ public void setDefaultHeaders(NVPair[] headers) { int length = (headers == null ? 0 : headers.length); NVPair[] def_hdrs = new NVPair[length]; // weed out undesired headers int sidx, didx; for (sidx=0, didx=0; sidx
The default is false. * * @deprecated This is not really needed anymore; in V0.2 request were * synchronous and therefore to do pipelining you needed * to disable the processing of responses. * @see #removeModule(java.lang.Class) * * @param raw if true removes all modules (except for the retry module) */ public void setRawMode(boolean raw) { // Don't remove the retry module String[] modules = { "HTTPClient.CookieModule", "HTTPClient.RedirectionModule", "HTTPClient.AuthorizationModule", "HTTPClient.DefaultModule", "HTTPClient.TransferEncodingModule", "HTTPClient.ContentMD5Module", "HTTPClient.ContentEncodingModule"}; for (int idx=0; idx resp.getInputStream().close() When creating new sockets the timeout will limit the time spent * doing the host name translation and establishing the connection with * the server. * *
The timeout also influences the reading of the response headers. * However, it does not specify a how long, for example, getStatusCode() * may take, as might be assumed. Instead it specifies how long a read * on the socket may take. If the response dribbles in slowly with * packets arriving quicker than the timeout then the method will * complete normally. I.e. the exception is only thrown if nothing * arrives on the socket for the specified time. Furthermore, the * timeout only influences the reading of the headers, not the reading * of the body. * *
Read Timeouts are associated with responses, so that you may change * this value before each request and it won't affect the reading of * responses to previous requests. * * @param time the time in milliseconds. A time of 0 means wait * indefinitely. * @see #stop() */ public void setTimeout(int time) { Timeout = time; } /** * Gets the timeout used for reading response data. * * @return the current timeout value * @see #setTimeout(int) */ public int getTimeout() { return Timeout; } /** * Controls whether modules are allowed to prompt the user or pop up * dialogs if neccessary. * * @param allow if true allows modules to interact with user. */ public void setAllowUserInteraction(boolean allow) { allowUI = allow; } /** * returns whether modules are allowed to prompt or popup dialogs * if neccessary. * * @return true if modules are allowed to interact with user. */ public boolean getAllowUserInteraction() { return allowUI; } /** * Sets the default allow-user-action. * * @param allow if true allows modules to interact with user. */ public static void setDefaultAllowUserInteraction(boolean allow) { defaultAllowUI = allow; } /** * Gets the default allow-user-action. * * @return true if modules are allowed to interact with user. */ public static boolean getDefaultAllowUserInteraction() { return defaultAllowUI; } /** * Returns the default list of modules. * * @return an array of classes */ public static Class[] getDefaultModules() { return getModules(DefaultModuleList); } /** * Adds a module to the default list. It must implement the * HTTPClientModule interface. If the module is already in * the list then this method does nothing. This method only affects * instances of HTTPConnection created after this method has been * invoked; it does not affect existing instances. * *
Example: *
* HTTPConnection.addDefaultModule(Class.forName("HTTPClient.CookieModule"), 1); ** adds the cookie module as the second module in the list. * *The default list is created at class initialization time from the * property HTTPClient.Modules. This must contain a "|" * separated list of classes in the order they're to be invoked. If this * property is not set it defaults to: * * "HTTPClient.RetryModule | HTTPClient.CookieModule | * HTTPClient.RedirectionModule | HTTPClient.AuthorizationModule | * HTTPClient.DefaultModule | HTTPClient.TransferEncodingModule | * HTTPClient.ContentMD5Module | HTTPClient.ContentEncodingModule" * * @see HTTPClientModule * @param module the module's Class object * @param pos the position of this module in the list; if pos * >= 0 then this is the absolute position in the list (0 is * the first position); if pos < 0 then this is * the position relative to the end of the list (-1 means * the last element, -2 the second to last element, etc). * @return true if module was successfully added; false if the * module is already in the list. * @exception ArrayIndexOutOfBoundsException if pos > * list-size or if pos < -(list-size). * @exception ClassCastException if module does not * implement the HTTPClientModule interface. * @exception RuntimeException if module cannot be * instantiated. */ public static boolean addDefaultModule(Class module, int pos) { return addModule(DefaultModuleList, module, pos); } /** * Removes a module from the default list. If the module is not in the * list it does nothing. This method only affects instances of * HTTPConnection created after this method has been invoked; it does not * affect existing instances. * * @param module the module's Class object * @return true if module was successfully removed; false otherwise */ public static boolean removeDefaultModule(Class module) { return removeModule(DefaultModuleList, module); } /** * Returns the list of modules used currently. * * @return an array of classes */ public Class[] getModules() { return getModules(ModuleList); } /** * Adds a module to the current list. It must implement the * HTTPClientModule interface. If the module is already in * the list then this method does nothing. * * @see HTTPClientModule * @param module the module's Class object * @param pos the position of this module in the list; if pos * >= 0 then this is the absolute position in the list (0 is * the first position); if pos < 0 then this is * the position relative to the end of the list (-1 means * the last element, -2 the second to last element, etc). * @return true if module was successfully added; false if the * module is already in the list. * @exception ArrayIndexOutOfBoundsException if pos > * list-size or if pos < -(list-size). * @exception ClassCastException if module does not * implement the HTTPClientModule interface. * @exception RuntimeException if module cannot be * instantiated. */ public boolean addModule(Class module, int pos) { return addModule(ModuleList, module, pos); } /** * Removes a module from the current list. If the module is not in the * list it does nothing. * * @param module the module's Class object * @return true if module was successfully removed; false otherwise */ public boolean removeModule(Class module) { return removeModule(ModuleList, module); } private static final Class[] getModules(Vector list) { synchronized(list) { Class[] modules = new Class[list.size()]; list.copyInto(modules); return modules; } } private static final boolean addModule(Vector list, Class module, int pos) { if (module == null) return false; // check if module implements HTTPClientModule try { HTTPClientModule tmp = (HTTPClientModule) module.newInstance(); } catch (RuntimeException re) { throw re; } catch (Exception e) { throw new RuntimeException(e.toString()); } synchronized (list) { // check if module already in list if (list.contains(module)) return false; // add module to list if (pos < 0) list.insertElementAt(module, DefaultModuleList.size()+pos+1); else list.insertElementAt(module, pos); } Log.write(Log.CONN, "Conn: Added module " + module.getName() + " to " + ((list == DefaultModuleList) ? "default " : "") + "list"); return true; } private static final boolean removeModule(Vector list, Class module) { if (module == null) return false; boolean removed = list.removeElement(module); if (removed) Log.write(Log.CONN, "Conn: Removed module " + module.getName() + " from " + ((list == DefaultModuleList) ? "default " : "") + "list"); return removed; } /** * Sets the current context. The context is used by modules such as * the AuthorizationModule and the CookieModule which keep lists of * info that is normally shared between all instances of HTTPConnection. * This is usually the desired behaviour. However, in some cases one * would like to simulate multiple independent clients within the * same application and hence the sharing of such info should be * restricted. This is where the context comes in. Modules will only * share their info between requests using the same context (i.e. they * keep multiple lists, one for each context). * *
The context may be any object. Contexts are considered equal * if
equals()
returns true. Examples of useful context * objects are threads (e.g. if you are running multiple clients, one * per thread) and sockets (e.g. if you are implementing a gateway). * *When a new HTTPConnection is created it is initialized with a * default context which is the same for all instances. This method * must be invoked immediately after a new HTTPConnection is created * and before any request method is invoked. Furthermore, this method * may only be called once (i.e. the context is "sticky"). * * @param context the new context; must be non-null * @exception IllegalArgumentException if context is null * @exception IllegalStateException if the context has already been set */ public void setContext(Object context) { if (context == null) throw new IllegalArgumentException("Context must be non-null"); if (Context != null) throw new IllegalStateException("Context already set"); Context = context; } /** * Returns the current context. * * @see #setContext(java.lang.Object) * @return the current context, or the default context if *
setContext()
hasn't been invoked */ public Object getContext() { if (Context != null) return Context; else return dflt_context; } /** * Returns the default context. * * @see #setContext(java.lang.Object) * @return the default context */ public static Object getDefaultContext() { return dflt_context; } /** * Adds an authorization entry for the "digest" authorization scheme to * the list. If an entry already exists for the "digest" scheme and the * specified realm then it is overwritten. * *This is a convenience method and just invokes the corresponding * method in AuthorizationInfo. * * @param realm the realm * @param user the username * @param passw the password * @see AuthorizationInfo#addDigestAuthorization(java.lang.String, int, java.lang.String, java.lang.String, java.lang.String) */ public void addDigestAuthorization(String realm, String user, String passwd) { AuthorizationInfo.addDigestAuthorization(Host, Port, realm, user, passwd, getContext()); } /** * Adds an authorization entry for the "basic" authorization scheme to * the list. If an entry already exists for the "basic" scheme and the * specified realm then it is overwritten. * *
This is a convenience method and just invokes the corresponding * method in AuthorizationInfo. * * @param realm the realm * @param user the username * @param passw the password * @see AuthorizationInfo#addBasicAuthorization(java.lang.String, int, java.lang.String, java.lang.String, java.lang.String) */ public void addBasicAuthorization(String realm, String user, String passwd) { AuthorizationInfo.addBasicAuthorization(Host, Port, realm, user, passwd, getContext()); } /** * Sets the default proxy server to use. The proxy will only be used * for new HTTPConnections created after this call and will * not affect currrent instances of HTTPConnection. A null * or empty string host parameter disables the proxy. * *
In an application or using the Appletviewer an alternative to * this method is to set the following properties (either in the * properties file or on the command line): * http.proxyHost and http.proxyPort. Whether * http.proxyHost is set or not determines whether a proxy * server is used. * *
If the proxy server requires authorization and you wish to set * this authorization information in the code, then you may use any * of the AuthorizationInfo.addXXXAuthorization() methods to * do so. Specify the same host and port as in * this method. If you have not given any authorization info and the * proxy server requires authorization then you will be prompted for * the necessary info via a popup the first time you do a request. * * @see #setCurrentProxy(java.lang.String, int) * @param host the host on which the proxy server resides. * @param port the port the proxy server is listening on. */ public static void setProxyServer(String host, int port) { if (host == null || host.trim().length() == 0) Default_Proxy_Host = null; else { Default_Proxy_Host = host.trim().toLowerCase(); Default_Proxy_Port = port; } } /** * Sets the proxy used by this instance. This can be used to override * the proxy setting inherited from the default proxy setting. A null * or empty string host parameter disables the proxy. * *
Note that if you set a proxy for the connection using this * method, and a request made over this connection is redirected * to a different server, then the connection used for new server * will not pick this proxy setting, but instead will use * the default proxy settings. * * @see #setProxyServer(java.lang.String, int) * @param host the host the proxy runs on * @param port the port the proxy is listening on */ public synchronized void setCurrentProxy(String host, int port) { if (host == null || host.trim().length() == 0) Proxy_Host = null; else { Proxy_Host = host.trim().toLowerCase(); if (port <= 0) Proxy_Port = 80; else Proxy_Port = port; } // the proxy might be talking a different version, so renegotiate switch(Protocol) { case HTTP: case HTTPS: if (force_1_0) { ServerProtocolVersion = HTTP_1_0; ServProtVersKnown = true; RequestProtocolVersion = "HTTP/1.0"; } else { ServerProtocolVersion = HTTP_1_1; ServProtVersKnown = false; RequestProtocolVersion = "HTTP/1.1"; } break; case HTTP_NG: ServerProtocolVersion = -1; /* Unknown */ ServProtVersKnown = false; RequestProtocolVersion = ""; break; case SHTTP: ServerProtocolVersion = -1; /* Unknown */ ServProtVersKnown = false; RequestProtocolVersion = "Secure-HTTP/1.3"; break; default: throw new Error("HTTPClient Internal Error: invalid protocol " + Protocol); } keepAliveUnknown = true; doesKeepAlive = false; input_demux = null; early_stall = null; late_stall = null; prev_resp = null; } /** * Add host to the list of hosts which should be accessed * directly, not via any proxy set by
setProxyServer()
. * *The host may be any of: *
-
*
- a complete host name (e.g. "www.disney.com") *
- a domain name; domain names must begin with a dot (e.g. * ".disney.com") *
- an IP-address (e.g. "12.34.56.78") *
- an IP-subnet, specified as an IP-address and a netmask separated * by a "/" (e.g. "34.56.78/255.255.255.192"); a 0 bit in the netmask * means that that bit won't be used in the comparison (i.e. the * addresses are AND'ed with the netmask before comparison). *
The two properties HTTPClient.nonProxyHosts and
* http.nonProxyHosts are used when this class is loaded to
* initialize the list of non-proxy hosts. The second property is only
* read if the first one is not set; the second property is also used
* the JDK's URLConnection. These properties must contain a "|"
* separated list of entries which conform to the above rules for the
* host parameter (e.g. "11.22.33.44|.disney.com").
*
* @param host a host name, domain name, IP-address or IP-subnet.
* @exception ParseException if the length of the netmask does not match
* the length of the IP-address
*/
public static void dontProxyFor(String host) throws ParseException
{
host = host.trim().toLowerCase();
// check for domain name
if (host.charAt(0) == '.')
{
if (!non_proxy_dom_list.contains(host))
non_proxy_dom_list.addElement(host);
return;
}
// check for host name
for (int idx=0; idx The code will try to determine the SOCKS version to use at
* connection time. This might fail for a number of reasons, however,
* in which case you must specify the version explicitly.
*
* @see #setSocksServer(java.lang.String, int, int)
* @param host the host on which the proxy server resides.
* @param port the port the proxy server is listening on.
*/
public static void setSocksServer(String host, int port)
{
if (port <= 0)
port = 1080;
if (host == null || host.length() == 0)
Default_Socks_client = null;
else
Default_Socks_client = new SocksClient(host, port);
}
/**
* Sets the SOCKS server to use. The server will only be used
* for new HTTPConnections created after this call and will not affect
* currrent instances of HTTPConnection. A null or empty string host
* parameter disables SOCKS.
*
* In an application or using the Appletviewer an alternative to
* this method is to set the following properties (either in the
* properties file or on the command line):
* HTTPClient.socksHost, HTTPClient.socksPort
* and HTTPClient.socksVersion. Whether
* HTTPClient.socksHost is set or not determines whether a
* SOCKS server is used; if HTTPClient.socksPort is not set
* it defaults to 1080; if HTTPClient.socksVersion is not
* set an attempt will be made to automatically determine the version
* used by the server.
*
* Note: If you have also set a proxy server then a connection
* will be made to the SOCKS server, which in turn then makes a
* connection to the proxy server (possibly via other SOCKS servers),
* which in turn makes the final connection.
*
* If the proxy server is running SOCKS version 5 and requires
* username/password authorization, and you wish to set
* this authorization information in the code, then you may use the
* AuthorizationInfo.addAuthorization() method to do so.
* Specify the same host and port as in this
* method, give the scheme "SOCKS5" and the realm
* "USER/PASS", set the cookie to null and the
* params to an array containing a single NVPair
* in turn containing the username and password. Example:
* dontProxyFor()
uses, i.e. this is used to undo a
* dontProxyFor()
setting. The syntax for host is
* specified in dontProxyFor()
.
*
* @param host a host name, domain name, IP-address or IP-subnet.
* @return true if the remove was sucessful, false otherwise
* @exception ParseException if the length of the netmask does not match
* the length of the IP-address
* @see #dontProxyFor(java.lang.String)
*/
public static boolean doProxyFor(String host) throws ParseException
{
host = host.trim().toLowerCase();
// check for domain name
if (host.charAt(0) == '.')
return non_proxy_dom_list.removeElement(host);
// check for host name
for (int idx=0; idx
* NVPair[] up = { new NVPair(username, password) };
* AuthorizationInfo.addAuthorization(host, port, "SOCKS5", "USER/PASS",
* null, up);
*
* If you have not given any authorization info and the proxy server
* requires authorization then you will be prompted for the necessary
* info via a popup the first time you do a request.
*
* @param host the host on which the proxy server resides.
* @param port the port the proxy server is listening on.
* @param version the SOCKS version the server is running. Currently
* this must be '4' or '5'.
* @exception SocksException If version is not '4' or '5'.
*/
public static void setSocksServer(String host, int port, int version)
throws SocksException
{
if (port <= 0)
port = 1080;
if (host == null || host.length() == 0)
Default_Socks_client = null;
else
Default_Socks_client = new SocksClient(host, port, version);
}
/**
* Removes the #... part. Returns the stripped name, or "" if either
* the file is null or is the empty string (after stripping).
*
* @param file the name to strip
* @return the stripped name
*/
private final String stripRef(String file)
{
if (file == null) return "";
int hash = file.indexOf('#');
if (hash != -1)
file = file.substring(0,hash);
return file.trim();
}
// private helper methods
/**
* Sets up the request, creating the list of headers to send and
* creating instances of the modules. This may be invoked by subclasses
* which add further methods (such as those from DAV and IPP).
*
* @param method GET, POST, etc.
* @param resource the resource
* @param headers an array of headers to be used
* @param entity the entity (or null)
* @param stream the output stream (or null) - only one of stream and
* entity may be non-null
* @return the response.
* @exception java.io.IOException when an exception is returned from
* the socket.
* @exception ModuleException if an exception is encountered in any module.
*/
protected final HTTPResponse setupRequest(String method, String resource,
NVPair[] headers, byte[] entity,
HttpOutputStream stream)
throws IOException, ModuleException
{
Request req = new Request(this, method, resource,
mergedHeaders(headers), entity, stream,
allowUI);
RequestList.addToEnd(req);
try
{
HTTPResponse resp = new HTTPResponse(gen_mod_insts(), Timeout, req);
handleRequest(req, resp, null, true);
return resp;
}
finally
{ RequestList.remove(req); }
}
/**
* This merges built-in default headers, user-specified default headers,
* and method-specified headers. Method-specified take precedence over
* user defaults, which take precedence over built-in defaults.
*
* The following headers are removed if found: "Content-length".
*
* @param spec the headers specified in the call to the method
* @return an array consisting of merged headers.
*/
private NVPair[] mergedHeaders(NVPair[] spec)
{
int spec_len = (spec != null ? spec.length : 0),
defs_len;
NVPair[] merged;
synchronized (DefaultHeaders)
{
defs_len = (DefaultHeaders != null ? DefaultHeaders.length : 0);
merged = new NVPair[spec_len + defs_len];
// copy default headers
System.arraycopy(DefaultHeaders, 0, merged, 0, defs_len);
}
// merge in selected headers
int sidx, didx = defs_len;
for (sidx=0; sidxint
value
*/
public final void setLocalAddress(InetAddress localAddress, int localPort) {
LocalAddr = localAddress;
LocalPort = localPort;
}
final InetAddress getLocalAddress() {
return LocalAddr;
}
/** --GRINDER MODIFICATION **/
/**
* sends the request over the line.
*
* @param req the request
* @param con_timeout the timeout to use when establishing a socket
* connection; an InterruptedIOException is thrown
* if the procedure times out.
* @param http_resp the HTTPResponse to add the new response to
* @exception IOException if thrown by the socket
* @exception InterruptedIOException if the connection is not established
* within the specified timeout
* @exception ModuleException if any module throws it during the SSL-
* tunneling handshake
*/
Response sendRequest(Request req, int con_timeout)
throws IOException, ModuleException
{
ByteArrayOutputStream hdr_buf = new ByteArrayOutputStream(600);
Response resp = null;
boolean keep_alive;
// The very first request is special in that we need its response
// before any further requests may be made. This is to set things
// like the server version.
if (early_stall != null)
{
try
{
Log.write(Log.CONN, "Conn: Early-stalling Request: " +
req.getMethod() + " " +
req.getRequestURI());
synchronized (early_stall)
{
// wait till the response is received
try
{ early_stall.getVersion(); }
catch (IOException ioe)
{ }
early_stall = null;
}
}
catch (NullPointerException npe)
{ }
}
String[] con_hdrs = assembleHeaders(req, hdr_buf);
// determine if the connection should be kept alive after this
// request
try
{
if (ServerProtocolVersion >= HTTP_1_1 &&
!Util.hasToken(con_hdrs[0], "close")
||
ServerProtocolVersion == HTTP_1_0 &&
Util.hasToken(con_hdrs[0], "keep-alive")
)
keep_alive = true;
else
keep_alive = false;
}
catch (ParseException pe)
{ throw new IOException(pe.toString()); }
synchronized (this)
{
// Sometimes we must stall the pipeline until the previous request
// has been answered. However, if we are going to open up a new
// connection anyway we don't really need to stall.
if (late_stall != null)
{
if (input_demux != null || keepAliveUnknown)
{
Log.write(Log.CONN, "Conn: Stalling Request: " +
req.getMethod() + " " + req.getRequestURI());
try // wait till the response is received
{
late_stall.getVersion();
if (keepAliveUnknown)
determineKeepAlive(late_stall);
}
catch (IOException ioe)
{ }
}
late_stall = null;
}
/* POSTs must not be pipelined because of problems if the connection
* is aborted. Since it is generally impossible to know what urls
* POST will influence it is impossible to determine if a sequence
* of requests containing a POST is idempotent.
* Also, for retried requests we don't want to pipeline either.
*/
if ((req.getMethod().equals("POST") || req.dont_pipeline) &&
prev_resp != null && input_demux != null)
{
Log.write(Log.CONN, "Conn: Stalling Request: " +
req.getMethod() + " " + req.getRequestURI());
try // wait till the response is received
{ prev_resp.getVersion(); }
catch (IOException ioe)
{ }
}
// If the previous request used an output stream, then wait till
// all the data has been written
if (!output_finished)
{
try
{ wait(); }
catch (InterruptedException ie)
{ throw new IOException(ie.toString()); }
}
if (req.aborted) throw new IOException("Request aborted by user");
int try_count = 3;
/* what a hack! This is to handle the case where the server closes
* the connection but we don't realize it until we try to send
* something. The problem is that we only get IOException, but
* we need a finer specification (i.e. whether it's an EPIPE or
* something else); I don't trust relying on the message part
* of IOException (which on SunOS/Solaris gives 'Broken pipe',
* but what on Windoze/Mac?).
*/
while (try_count-- > 0)
{
try
{
// get a client socket
Socket sock;
if (input_demux == null ||
(sock = input_demux.getSocket()) == null)
{
sock = getSocket(con_timeout);
if (Protocol == HTTPS)
{
if (Proxy_Host != null)
{
Socket[] sarr = { sock };
resp = enableSSLTunneling(sarr, req, con_timeout);
if (resp != null)
{
resp.final_resp = true;
return resp;
}
sock = sarr[0];
}
sock.setSoTimeout(con_timeout);
sock = sslFactory.createSocket(sock, Host, Port, true);
/** GRINDER MODIFICATION++ **/
final SSLSocket sslSocket = (SSLSocket)sock;
sslSocket.setEnabledCipherSuites(getSSLCipherSuites());
sslSocket.setEnabledProtocols(getSSLProtocols());
if (getCheckCertificates()) {
/** --GRINDER MODIFICATION **/
checkCert(((SSLSocket) sock).getSession().
getPeerCertificateChain()[0], Host);
/** GRINDER MODIFICATION++ **/
}
/** --GRINDER MODIFICATION **/
}
/** GRINDER MODIFICATION++ **/
else {
sock.setSoTimeout(con_timeout);
}
/** --GRINDER MODIFICATION **/
input_demux = new StreamDemultiplexor(Protocol, sock, this);
DemuxList.addToEnd(input_demux);
keepAliveReqLeft = keepAliveReqMax;
}
if (req.aborted)
throw new IOException("Request aborted by user");
Log.write(Log.CONN, "Conn: Sending Request: ", hdr_buf);
// Send headers
OutputStream sock_out = sock.getOutputStream();
if (haveMSLargeWritesBug)
sock_out = new MSLargeWritesBugStream(sock_out);
hdr_buf.writeTo(sock_out);
// Wait for "100 Continue" status if necessary
try
{
if (ServProtVersKnown &&
ServerProtocolVersion >= HTTP_1_1 &&
Util.hasToken(con_hdrs[1], "100-continue"))
{
resp = new Response(req, (Proxy_Host != null && Protocol != HTTPS), input_demux);
resp.timeout = 60;
if (resp.getContinue() != 100)
break;
}
}
catch (ParseException pe)
{ throw new IOException(pe.toString()); }
catch (InterruptedIOException iioe)
{ }
finally
{ if (resp != null) resp.timeout = 0; }
// POST/PUT data
if (req.getData() != null && req.getData().length > 0)
{
if (req.delay_entity > 0)
{
// wait for something on the network; check available()
// roughly every 100 ms
long num_units = req.delay_entity / 100;
long one_unit = req.delay_entity / num_units;
for (int idx=0; idx
*
*
* Furthermore, it escapes various characters in request-URI.
*
* @param req the Request
* @param hdr_buf the buffer onto which to write the headers
* @return an array of headers; the first element contains the
* the value of the Connection or Proxy-Connectin header,
* the second element the value of the Expect header.
* @exception IOException if writing on hdr_buf generates an
* an IOException, or if an error occurs during
* parsing of a header
*/
private String[] assembleHeaders(Request req,
ByteArrayOutputStream hdr_buf)
throws IOException
{
DataOutputStream dataout = new DataOutputStream(hdr_buf);
String[] con_hdrs = { "", "" };
NVPair[] hdrs = req.getHeaders();
// remember various headers
int ho_idx = -1,
ct_idx = -1,
ua_idx = -1,
co_idx = -1,
pc_idx = -1,
ka_idx = -1,
ex_idx = -1,
te_idx = -1,
tc_idx = -1,
ug_idx = -1;
for (int idx=0; idx