📄 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 + -