📄 httpurlconnection.java
字号:
/*
* @(#)HttpURLConnection.java 0.3-3 18/06/1999
*
* This file is part of the HTTPClient package
* Copyright (C) 1996-2001 Ronald Tschal鋜
*
* 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:
*
* ronald@innovation.ch
*
* The HTTPClient's home page is located at:
*
* http://www.innovation.ch/java/HTTPClient/
*
*/
package HTTPClient;
import java.io.IOException;
import java.io.InterruptedIOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.BufferedInputStream;
import java.io.ByteArrayOutputStream;
import java.net.URL;
import java.net.ProtocolException;
import java.util.Date;
import java.util.Hashtable;
import java.util.Enumeration;
/**
* This class is a wrapper around HTTPConnection providing the interface
* defined by java.net.URLConnection and java.net.HttpURLConnection.
*
* <P>This class is a hacked version of the HttpURLConnection class for use
* with HotJava 1.1.x. It extends sun.net.www.protocol.http.HttpURLConnection
* instead of java.net.HttpURLConnection, because the HotJava uses the
* setInstanceFollowRedirect() method which is defined in the
* sun.*.HttpURLConnection class, but only if this is an instance of the
* sun.*.HttpURLConnection class (or a subclass).
*
* <P>One difference between Sun's HttpClient and this one is that this
* one will provide you with a real output stream if possible. This leads
* to two changes: you should set the request property "Content-Length",
* if possible, before invoking getOutputStream(); and in many cases
* getOutputStream() implies connect(). This should be transparent, though,
* apart from the fact that you can't change any headers or other settings
* anymore once you've gotten the output stream.
* So, for large data do:
* <PRE>
* HttpURLConnection con = (HttpURLConnection) url.openConnection();
*
* con.setDoOutput(true);
* con.setRequestProperty("Content-Length", ...);
* OutputStream out = con.getOutputStream();
*
* out.write(...);
* out.close();
*
* if (con.getResponseCode() != 200)
* ...
* </PRE>
*
* <P>The HTTPClient will send the request data using the chunked transfer
* encoding when no Content-Length is specified and the server is HTTP/1.1
* compatible. Because cgi-scripts can't usually handle this, you may
* experience problems trying to POST data. For this reason, whenever
* the Content-Type is application/x-www-form-urlencoded getOutputStream()
* will buffer the data before sending it so as prevent chunking. If you
* are sending requests with a different Content-Type and are experiencing
* problems then you may want to try setting the system property
* <var>HTTPClient.dontChunkRequests</var> to <var>true</var> (this needs
* to be done either on the command line or somewhere in the code before
* the first URLConnection.openConnection() is invoked).
*
* <P>A second potential incompatibility is that the HTTPClient aggresively
* resuses connections, and can do so more often that Sun's client. This
* can cause problems if you send multiple requests, and the first one has
* a long response. In this case (assuming the server allows the connection
* to be used for multiple requests) the responses to second, third, etc
* request won't be received until the first response has been completely
* read. With Sun's client on the other hand you may not experience this,
* as it may not be able to keep the connection open and there may create
* multiple connections for the requests. This allows the responses to the
* second, third, etc requests to be read before the first response has
* completed. <strong>Note:</strong> whether this will happen depends on
* details of the resource being requested and the server. In many cases
* the HTTPClient and Sun's client will exhibit the same behaviour. Also,
* applications which depend on being able to read the second response
* before the first one has completed must be considered broken, because
* A) this behaviour cannot be relied upon even in Sun's current client,
* and B) Sun's implementation will exhibit the same problem if they ever
* switch to HTTP/1.1.
*
* @version 0.3-3 18/06/1999
* @author Ronald Tschal鋜
* @since V0.3
*/
public class HttpURLConnection
extends sun.net.www.protocol.http.HttpURLConnection
implements GlobalConstants
{
/** a list of HTTPConnections */
private static Hashtable connections = new Hashtable();
/** the current connection */
private HTTPConnection con;
/** the cached url.toString() */
private String urlString;
/** the resource */
private String resource;
/** the current method */
private String method;
/** has the current method been set via setRequestMethod()? */
private boolean method_set;
/** the default request headers */
private static NVPair[] default_headers = new NVPair[0];
/** the request headers */
private NVPair[] headers;
/** the response */
private HTTPResponse resp;
/** is the redirection module activated for this instance? */
private boolean do_redir;
/** the RedirectionModule class */
private static Class redir_mod;
/** the output stream used for POST and PUT */
private OutputStream output_stream;
/** HotJava hacks */
private static boolean in_hotjava = false;
static
{
try
{
String browser = System.getProperty("browser");
if (browser != null && browser.equals("HotJava"))
in_hotjava = true;
}
catch (SecurityException se)
{ }
// The default allowUserAction in java.net.URLConnection is
// false.
try
{
if (Boolean.getBoolean("HTTPClient.HttpURLConnection.AllowUI") ||
in_hotjava)
setDefaultAllowUserInteraction(true);
}
catch (SecurityException se)
{ }
// get the RedirectionModule class
try
{ redir_mod = Class.forName("HTTPClient.RedirectionModule"); }
catch (ClassNotFoundException cnfe)
{ throw new NoClassDefFoundError(cnfe.getMessage()); }
// Set the User-Agent if the http.agent property is set
try
{
String agent = System.getProperty("http.agent");
if (agent != null)
setDefaultRequestProperty("User-Agent", agent);
}
catch (SecurityException se)
{ }
}
// Constructors
private static String non_proxy_hosts = "";
private static String proxy_host = "";
private static int proxy_port = -1;
/**
* Construct a connection to the specified url. A cache of
* HTTPConnections is used to maximize the reuse of these across
* multiple HttpURLConnections.
*
* <BR>The default method is "GET".
*
* @param url the url of the request
* @exception ProtocolNotSuppException if the protocol is not supported
*/
public HttpURLConnection(URL url)
throws ProtocolNotSuppException, IOException
{
super(url, null);
// first read proxy properties and set
try
{
String hosts = System.getProperty("http.nonProxyHosts", "");
if (!hosts.equalsIgnoreCase(non_proxy_hosts))
{
connections.clear();
non_proxy_hosts = hosts;
String[] list = Util.splitProperty(hosts);
for (int idx=0; idx<list.length; idx++)
HTTPConnection.dontProxyFor(list[idx]);
}
}
catch (ParseException pe)
{ throw new IOException(pe.toString()); }
catch (SecurityException se)
{ }
try
{
String host = System.getProperty("http.proxyHost", "");
int port = Integer.getInteger("http.proxyPort", -1).intValue();
if (!host.equalsIgnoreCase(proxy_host) || port != proxy_port)
{
connections.clear();
proxy_host = host;
proxy_port = port;
HTTPConnection.setProxyServer(host, port);
}
}
catch (SecurityException se)
{ }
// now setup stuff
con = getConnection(url);
method = "GET";
method_set = false;
resource = url.getFile();
headers = default_headers;
do_redir = getFollowRedirects();
output_stream = null;
urlString = url.toString();
}
/**
* Returns an HTTPConnection. A cache of connections is kept and first
* consulted; only when the cache lookup fails is a new one created
* and added to the cache.
*
* @param url the url
* @return an HTTPConnection
* @exception ProtocolNotSuppException if the protocol is not supported
*/
private HTTPConnection getConnection(URL url)
throws ProtocolNotSuppException
{
// try the cache, using the host name
String php = url.getProtocol() + ":" + url.getHost() + ":" +
((url.getPort() != -1) ? url.getPort() :
URI.defaultPort(url.getProtocol()));
php = php.toLowerCase();
HTTPConnection con = (HTTPConnection) connections.get(php);
if (con != null) return con;
// Not in cache, so create new one and cache it
con = new HTTPConnection(url);
connections.put(php, con);
return con;
}
// Methods
/**
* Sets the request method (e.g. "PUT" or "HEAD"). Can only be set
* before connect() is called.
*
* @param method the http method.
* @exception ProtocolException if already connected.
*/
public void setRequestMethod(String method) throws ProtocolException
{
if (connected)
throw new ProtocolException("Already connected!");
Log.write(Log.URLC, "URLC: (" + urlString + ") Setting request method: " +
method);
this.method = method.trim().toUpperCase();
method_set = true;
}
/**
* Return the request method used.
*
* @return the http method.
*/
public String getRequestMethod()
{
return method;
}
/**
* Get the response code. Calls connect() if not connected.
*
* @return the http response code returned.
*/
public int getResponseCode() throws IOException
{
if (!connected) connect();
try
{
if (in_hotjava && resp.getStatusCode() >= 300)
{
try
{ resp.getData(); } // force response stream to be read
catch (InterruptedIOException iioe)
{ disconnect(); }
}
return resp.getStatusCode();
}
catch (ModuleException me)
{ throw new IOException(me.toString()); }
}
/**
* Get the response message describing the response code. Calls connect()
* if not connected.
*
* @return the http response message returned with the response code.
*/
public String getResponseMessage() throws IOException
{
if (!connected) connect();
try
{ return resp.getReasonLine(); }
catch (ModuleException me)
{ throw new IOException(me.toString()); }
}
/**
* Get the value part of a header. Calls connect() if not connected.
*
* @param name the of the header.
* @return the value of the header, or null if no such header was returned.
*/
public String getHeaderField(String name)
{
try
{
if (!connected) connect();
return resp.getHeader(name);
}
catch (Exception e)
{ return null; }
}
/**
* Get the value part of a header and converts it to an int. If the
* header does not exist or if its value could not be converted to an
* int then the default is returned. Calls connect() if not connected.
*
* @param name the of the header.
* @param def the default value to return in case of an error.
* @return the value of the header, or null if no such header was returned.
*/
public int getHeaderFieldInt(String name, int def)
{
try
{
if (!connected) connect();
return resp.getHeaderAsInt(name);
}
catch (Exception e)
{ return def; }
}
/**
* Get the value part of a header, interprets it as a date and converts
* it to a long representing the number of milliseconds since 1970. If
* the header does not exist or if its value could not be converted to a
* date then the default is returned. Calls connect() if not connected.
*
* @param name the of the header.
* @param def the default value to return in case of an error.
* @return the value of the header, or def in case of an error.
*/
public long getHeaderFieldDate(String name, long def)
{
try
{
if (!connected) connect();
return resp.getHeaderAsDate(name).getTime();
}
catch (Exception e)
{ return def; }
}
private String[] hdr_keys, hdr_values;
/**
* Gets header name of the n-th header. Calls connect() if not connected.
* The name of the 0-th header is <var>null</var>, even though it the
* 0-th header has a value.
*
* @param n which header to return.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -