harmony-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From telli...@apache.org
Subject svn commit: r405120 - /incubator/harmony/enhanced/classlib/trunk/modules/luni/src/main/java/org/apache/harmony/luni/internal/net/www/protocol/http/HttpURLConnection.java
Date Mon, 08 May 2006 18:20:43 GMT
Author: tellison
Date: Mon May  8 11:20:42 2006
New Revision: 405120

URL: http://svn.apache.org/viewcvs?rev=405120&view=rev
Log:
Reformatting

Modified:
    incubator/harmony/enhanced/classlib/trunk/modules/luni/src/main/java/org/apache/harmony/luni/internal/net/www/protocol/http/HttpURLConnection.java

Modified: incubator/harmony/enhanced/classlib/trunk/modules/luni/src/main/java/org/apache/harmony/luni/internal/net/www/protocol/http/HttpURLConnection.java
URL: http://svn.apache.org/viewcvs/incubator/harmony/enhanced/classlib/trunk/modules/luni/src/main/java/org/apache/harmony/luni/internal/net/www/protocol/http/HttpURLConnection.java?rev=405120&r1=405119&r2=405120&view=diff
==============================================================================
--- incubator/harmony/enhanced/classlib/trunk/modules/luni/src/main/java/org/apache/harmony/luni/internal/net/www/protocol/http/HttpURLConnection.java (original)
+++ incubator/harmony/enhanced/classlib/trunk/modules/luni/src/main/java/org/apache/harmony/luni/internal/net/www/protocol/http/HttpURLConnection.java Mon May  8 11:20:42 2006
@@ -15,8 +15,9 @@
 
 package org.apache.harmony.luni.internal.net.www.protocol.http;
 
-
+import java.io.BufferedInputStream;
 import java.io.ByteArrayOutputStream;
+import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
@@ -37,8 +38,10 @@
 import java.net.URLStreamHandler;
 import java.net.UnknownServiceException;
 import java.security.AccessController;
+import java.security.Permission;
 import java.text.SimpleDateFormat;
 import java.util.ArrayList;
+import java.util.Date;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Locale;
@@ -46,1083 +49,1238 @@
 import java.util.TimeZone;
 
 import org.apache.harmony.luni.net.NetUtil;
+import org.apache.harmony.luni.util.Base64;
 import org.apache.harmony.luni.util.Msg;
 import org.apache.harmony.luni.util.PriviAction;
 
 /**
- * This subclass extends <code>HttpURLConnection</code> which in turns extends <code>URLConnection</code>
- * This is the actual class that "does the work", such as connecting, sending request and getting the content from
- * the remote server.
- *
- */
-
-public class HttpURLConnection extends java.net.HttpURLConnection {
-	int httpVersion = 1;	// Assume HTTP/1.1
-	private final int defaultPort;
-	InputStream is;
-	private InputStream uis;
-	OutputStream socketOut;
-	private HttpOutputStream os;
-	private boolean sentRequest = false;
-	boolean sendChunked = false;
-	private String proxyName;
-	private int hostPort = -1;
-	private int readTimeout = -1;
-	
-	// proxy which is used to make the connection.
-	private Proxy proxy = null;
-	
-	// the proxy list which is used to make the connection.
-	private List proxyList = null;
-	
-	// the current proxy which is used to make the connection.
-	private Proxy currentProxy;
-	
-	// the destination uri
-	private URI uri = null;
-	
-	// default request header
-	private static Header defaultReqHeader = new Header();
-
-	// request header that will be sent to the server
-	private Header reqHeader;
-
-	// response header received from the server
-	private Header resHeader;
-
-	private class LimitedInputStream extends InputStream {
-		int bytesRemaining;
-	public LimitedInputStream(int length) {
-		bytesRemaining = length;
-	}
-	public void close() throws IOException {
-		bytesRemaining = 0;
-		closeSocket();
-	}
-	public int available() throws IOException {
-		int result = is.available();
-		if (result > bytesRemaining) return bytesRemaining;
-		return result;
-	}
-	public int read() throws IOException {
-		if (bytesRemaining <= 0) return -1;
-		int result = is.read();
-		bytesRemaining--;
-		return result;
-	}
-	public int read(byte[] buf, int offset, int length) throws IOException {
-		if (buf == null) throw new NullPointerException();
-		// avoid int overflow
-		if (offset < 0 || length < 0 || offset > buf.length || buf.length - offset < length)
-			throw new ArrayIndexOutOfBoundsException();
-		if (bytesRemaining <= 0) return -1;
-		if (length > bytesRemaining) length = bytesRemaining;
-		int result = is.read(buf, offset, length);
-		if (result > 0) bytesRemaining -= result;
-		return result;
-	}
-	public long skip(int amount) throws IOException {
-		if (bytesRemaining <= 0) return -1;
-		if (amount > bytesRemaining) amount = bytesRemaining;
-		long result = is.skip(amount);
-		if (result > 0) bytesRemaining -= result;
-		return result;
-	}
-	}
-
-	private class ChunkedInputStream extends InputStream {
-		int bytesRemaining = -1;
-		boolean atEnd = false;
-	public ChunkedInputStream() throws IOException {
-		readChunkSize();
-	}
-	public void close() throws IOException {
-		atEnd = true;
-		closeSocket();
-	}
-	public int available() throws IOException {
-		int result = is.available();
-		if (result > bytesRemaining) return bytesRemaining;
-		return result;
-	}
-	private void readChunkSize() throws IOException {
-		if (atEnd) return;
-		if (bytesRemaining == 0) readln(); // read CR/LF
-		String size = readln();
-		int index = size.indexOf(";");
-		if (index >= 0) size = size.substring(0, index);
-		bytesRemaining = Integer.parseInt(size.trim(), 16);
-		if (bytesRemaining == 0) {
-			atEnd = true;
-			readHeaders();
-		}
-	}
-	public int read() throws IOException {
-		if (bytesRemaining <= 0) readChunkSize();
-		if (atEnd) return -1;
-		bytesRemaining--;
-		return is.read();
-	}
-	public int read(byte[] buf, int offset, int length) throws IOException {
-		if (buf == null) throw new NullPointerException();
-		// avoid int overflow
-		if (offset < 0 || length < 0 || offset > buf.length || buf.length - offset < length)
-			throw new ArrayIndexOutOfBoundsException();
-		if (bytesRemaining <= 0) readChunkSize();
-		if (atEnd) return -1;
-		if (length > bytesRemaining) length = bytesRemaining;
-		int result = is.read(buf, offset, length);
-		if (result > 0) bytesRemaining -= result;
-		return result;
-	}
-	public long skip(int amount) throws IOException {
-		if (atEnd) return -1;
-		if (bytesRemaining <= 0) readChunkSize();
-		if (amount > bytesRemaining) amount = bytesRemaining;
-		long result = is.skip(amount);
-		if (result > 0) bytesRemaining -= result;
-		return result;
-	}
-	}
-
-	private class HttpOutputStream extends OutputStream {
-		static final int MAX = 1024;
-		ByteArrayOutputStream cache = new ByteArrayOutputStream(MAX+7);
-		boolean writeToSocket, closed = false;
-		int limit;
-	public HttpOutputStream() {
-		limit = -1;
-	}
-	public HttpOutputStream(int limit) {
-		writeToSocket = true;
-		this.limit = limit;
-	}
-	private void output(String output) throws IOException {
-		socketOut.write(output.getBytes("ISO8859_1"));
-	}
-	private void sendCache(boolean close) throws IOException {
-		int size = cache.size();
-		if (size > 0 || close) {
-			if (limit < 0) {
-				if (size > 0) {
-					output(Integer.toHexString(size) + "\r\n");
-					cache.write('\r'); cache.write('\n');
-				}
-				if (close) {
-					cache.write('0');
-					cache.write('\r'); cache.write('\n');
-					cache.write('\r'); cache.write('\n');
-				}
-			}
-			socketOut.write(cache.toByteArray());
-			cache.reset();
-		}
-	}
-	public synchronized void flush() throws IOException {
-		if (closed) throw new IOException(org.apache.harmony.luni.util.Msg.getString("K0059"));
-		if (writeToSocket) {
-			sendCache(false);
-			socketOut.flush();
-		}
-	}
-	public synchronized void close() throws IOException {
-		if (closed) return;
-		closed = true;
-		if (writeToSocket) {
-			if (limit > 0) throw new IOException(org.apache.harmony.luni.util.Msg.getString("K00a4"));
-			sendCache(closed);
-		}
-	}
-	public synchronized void write(int data) throws IOException {
-		if (closed) throw new IOException(org.apache.harmony.luni.util.Msg.getString("K0059"));
-		if (limit >= 0) {
-			if (limit == 0) throw new IOException(org.apache.harmony.luni.util.Msg.getString("K00b2"));
-			limit--;
-		}
-		cache.write(data);
-		if (writeToSocket && cache.size() >= MAX)
-			sendCache(false);
-	}
-	public synchronized void write(byte[] buffer, int offset, int count) throws IOException {
-		if (closed) throw new IOException(org.apache.harmony.luni.util.Msg.getString("K0059"));
-		if (buffer==null) throw new NullPointerException();
-		// avoid int overflow
-		if (offset < 0 || count < 0 || offset > buffer.length || buffer.length - offset < count)
-			throw new ArrayIndexOutOfBoundsException(org.apache.harmony.luni.util.Msg.getString("K002f"));
-
-		if (limit >= 0) {
-			if (count > limit) throw new IOException(org.apache.harmony.luni.util.Msg.getString("K00b2"));
-			limit -= count;
-		}
-		if (!writeToSocket || cache.size() + count < MAX) {
-			cache.write(buffer, offset, count);
-		} else {
-			if (limit < 0)
-				output(Integer.toHexString(count + cache.size()) + "\r\n");
-			socketOut.write(cache.toByteArray());
-			cache.reset();
-			socketOut.write(buffer, offset, count);
-			if (limit < 0) output("\r\n");
-		}
-	}
-	synchronized int size() {
-		return cache.size();
-	}
-	synchronized byte[] toByteArray() {
-		return cache.toByteArray();
-	}
-	boolean isCached() {
-		return !writeToSocket;
-	}
-	boolean isChunked() {
-		return writeToSocket && limit == -1;
-	}
-	}
-
-/**
- * Creates an instance of the <code>HttpURLConnection</code>
- * using default port 80.
- * @param url URL	The URL this connection is connecting
- */
-protected HttpURLConnection(URL url) {
-	this(url, 80);
-}
-
-/**
- * Creates an instance of the <code>HttpURLConnection</code>
- * @param url URL	The URL this connection is connecting
- * @param port int	The default connection port
- */
-protected HttpURLConnection(URL url, int port) {
-	super(url);
-	defaultPort = port;
-
-	reqHeader = (Header)defaultReqHeader.clone();
-	try {
-		uri = url.toURI();
-	} catch (URISyntaxException e) {
-		// do nothing.
-	}
-}
-
-	/**
-	 * Creates an instance of the <code>HttpURLConnection</code>
-	 * 
-	 * @param url
-	 *            URL The URL this connection is connecting
-	 * @param port
-	 *            int The default connection port
-	 * @param proxy
-	 *            Proxy The proxy which is used to make the connection
-	 */
-	protected HttpURLConnection(URL url, int port, Proxy proxy) {
-		this(url, port);
-		this.proxy = proxy;
-	}
-
-/**
- * Establishes the connection to the remote HTTP server
- *
- * Any methods that requires a valid connection to the resource will call this method implicitly.
- * After the connection is established, <code>connected</code> is set to true.
- *
- *
- * @see 		#connected
- * @see 		java.io.IOException
- * @see 		URLStreamHandler
- */
-public void connect() throws java.io.IOException {
-	if (connected) return;
-	Socket socket;
-	
-	InetAddress host = getHostAddress();
-	int port = getHostPort();
-	if(null == currentProxy || Proxy.Type.HTTP == currentProxy.type()){
-		socket = new Socket(host, port);
-	}else{
-		socket = new Socket(currentProxy);
-		SocketAddress sa = new InetSocketAddress(host, port);
-		socket.connect(sa);
-	}
-	
-	if (readTimeout >= 0) socket.setSoTimeout(readTimeout);
-	connected = true;
-	socketOut = socket.getOutputStream();
-	is = new java.io.BufferedInputStream(socket.getInputStream());
-}
-
-/**
- * Sets the read timeout for the http connection.
- *
- *
- * @param	value	the read timeout value. Must be >= 0
- *
- * @see	java.net.Socket#setSoTimeout
- */
-public void setReadTimeout(int value) {
-	if (value < 0)
-		throw new IllegalArgumentException(org.apache.harmony.luni.util.Msg.getString("K0036"));
-	readTimeout = value;
-}
-
-/**
- * Closes the connection with the HTTP server
- *
- *
- * @see			URLConnection#connect()
- */
-public void disconnect() {
-	try {closeSocket();} catch (IOException e) {}
-}
-
-void closeSocket() throws IOException {
-	if (is != null)
-		is.close();
-}
-
-void endRequest() throws IOException {
-	if (os != null)
-		os.close();
-	sentRequest = false;
-}
-
-/**
- * Answers the default value for the field specified by <code>field</code>,
- * 			null if there's no such a field.
- *
- *
- */
-public static String getDefaultRequestProperty(String field) {
-	return defaultReqHeader.get(field);
-}
-/**
- * Answers an input stream from the server in the case of error such as the requested
- * file (txt, htm, html) is not found on the remote server.
- * <p>
- * If the content type is not what stated above, <code>FileNotFoundException</code>
- * is thrown.
- *
- * @return java.io.InputStream		the error input stream returned by the server.
- */
-public InputStream getErrorStream() {
-	if (connected && method != "HEAD" && responseCode >= HTTP_BAD_REQUEST)
-		return uis;
-	return null;
-}
-/**
- * Answers the value of the field at position <code>pos<code>.
- * Answers <code>null</code> if there is fewer than <code>pos</code> fields
- * in the response header.
- *
- *
- * @return java.lang.String		The value of the field
- * @param pos int				the position of the field from the top
- *
- * @see 		#getHeaderField(String)
- * @see 		#getHeaderFieldKey
- */
-public String getHeaderField(int pos) {
-	try {
-		getInputStream();
-		return resHeader.get(pos);
-	} catch (IOException e) {
-		return null;
-	}
-	}
-/**
- * Answers the value of the field corresponding to the <code>key</code>
- * Answers <code>null</code> if there is no such field.
- *
- * If there are multiple fields with that key, the last field value is returned.
- *
- *
- * @return java.lang.String			The value of the header field
- * @param key java.lang.String		the name of the header field
- *
- * @see 		#getHeaderField(int)
- * @see 		#getHeaderFieldKey
- */
-public String getHeaderField(String key) {
-	try {
-		getInputStream();
-		return resHeader.get(key);
-	} catch (IOException e) {
-		return null;
-	}
-}
-/**
- * This method answers the header field at position <code>pos</code> from the response header,
- * null if there is fewer fields than <code>pos</code>.
- *
- *
- * @return java.lang.String
- * @param pos int
- *
- * @see #getHeaderField(String)
- * @see #getHeaderField(int)
- */
-public String getHeaderFieldKey(int pos) {
-	try {
-		getInputStream();
-		return resHeader.getKey(pos);
-	} catch (IOException e) {
-		return null;
-	}
-}
-
-/**
- * Provides an unmodifiable map of the connection header values.  The map keys are the String
- * header field names.  Each map value is a list of the header field values associated with
- * that key name.
- *
- * @return the mapping of header field names to values
- *
- * @since 1.4
- */
-public Map getHeaderFields() {
-	return resHeader.getFieldMap();
-}
-
-/**
- * Provides an unmodifiable map of the request properties.  The map keys are Strings, the map
- * values are each a List of Strings, with each request property name mapped to its corresponding property values.
- *
- * @return the mapping of request property names to values
- *
- * @since 1.4
- */
-public Map getRequestProperties() {
-	return reqHeader.getFieldMap();
-}
-
-/**
- * Creates an input stream for reading from this URL Connection.
- *
- *
- * @return 		InputStream		The input stream to read from
- * @exception 	UnknownServiceException 	Exception thrown when reading to URL isn't supported
- *
- * @see 		#getContent()
- * @see 		#getOutputStream()
- * @see 		java.io.InputStream
- * @see 		java.io.IOException
- */
-public InputStream getInputStream() throws IOException {
-	if (!doInput)
-		throw new ProtocolException(org.apache.harmony.luni.util.Msg.getString("K008d"));
-
-	doRequest();
-
-	// if the requested file does not exist, throw an exception
-	//formerly the Error page from the server was returned
-	//if the requested file was text/html
-	//this has changed to return FileNotFoundException for all file types
-	if (responseCode >= HTTP_BAD_REQUEST)
-		throw new java.io.FileNotFoundException(url.toString());
-
-	return uis;
-}
-
-private InputStream getContentStream() throws IOException {
-	if (uis != null) return uis;
-
-	String encoding = resHeader.get("Transfer-Encoding");
-	if (encoding != null && encoding.toLowerCase().equals("chunked"))
-		return uis = new ChunkedInputStream();
-
-	String sLength = resHeader.get("Content-Length");
-	if (sLength != null) {
-		try {
-			int length = Integer.parseInt(sLength);
-			return uis = new LimitedInputStream(length);
-		} catch (NumberFormatException e) {}
-	}
-	return uis = is;
-}
-/**
- * Creates an output stream for writing to this URL Connection.
- * <code>UnknownServiceException</code> will be thrown if this url denies write access
- *
- *
- * @return 		OutputStream	The output stream to write to
- * @exception 	UnknownServiceException 	thrown when writing to URL is not supported
- *
- * @see 		#getContent()
- * @see 		#getInputStream()
- * @see 		java.io.IOException
- *
- */
-public OutputStream getOutputStream() throws IOException {
-	if (!doOutput)
-		throw new ProtocolException(org.apache.harmony.luni.util.Msg.getString("K008e"));
-
-	// you can't write after you read
-	if (sentRequest)
-		throw new ProtocolException(org.apache.harmony.luni.util.Msg.getString("K0090"));
-
-	if (os != null) return os;
-
-	// they are requesting a stream to write to. This implies a POST method
-	if (method == "GET")
-		setRequestMethod("POST");
-	// If the request method is neither PUT or POST, then you're not writing
-	if (method != "PUT" && method != "POST")
-		throw new ProtocolException(org.apache.harmony.luni.util.Msg.getString("K008f", method));
-
-	int limit = -1;
-	String contentLength = reqHeader.get("Content-Length");
-	if (contentLength != null) limit = Integer.parseInt(contentLength);
-
-	String encoding = reqHeader.get("Transfer-Encoding");
-	if (httpVersion > 0 && encoding != null) {
-		encoding = encoding.toLowerCase();
-		if ("chunked".equals(encoding)) {
-			sendChunked = true;
-			limit = -1;
-		}
-	}
-	if ((httpVersion > 0 && sendChunked) || limit >= 0) {
-		os = new HttpOutputStream(limit);
-		doRequest();
-		return os;
-	}
-	return os = new HttpOutputStream();
-
-}
-/**
- * Answers the permission required to make the connection
- *
- *
- * @return 		java.security.Permission	the connection required to make the connection.
- * @exception 	java.io.IOException
- *						thrown if an IO exception occurs while computing the permission.
- */
-public java.security.Permission getPermission() throws java.io.IOException {
-	return new SocketPermission(getHostName() + ":" + getHostPort(), "connect, resolve");
-}
-/**
- * Answers the value corresponds to the field in the request Header,
- * 			null if no such field exists
- *
- *
- * @return java.lang.String		The field to look up
- *
- * @see 		#getDefaultRequestProperty
- * @see 		#setDefaultRequestProperty
- * @see 		#setRequestProperty
- */
-public String getRequestProperty(String field) {
-	if (connected) throw new IllegalAccessError(org.apache.harmony.luni.util.Msg.getString("K0091"));
-	return reqHeader.get(field);
-}
-/**
- * Answers a line read from the input stream. Does not include the \n
- *
- *
- * @return java.lang.String
- */
-String readln() throws IOException {
-	boolean lastCr = false;
-	StringBuffer result = new StringBuffer(80);
-	int c = is.read();
-	if (c < 0) return null;
-	while (c != '\n') {
-		if (lastCr) {
-			result.append('\r');
-			lastCr = false;
-		}
-		if (c == '\r') lastCr = true;
-		else result.append((char)c);
-		c = is.read();
-		if (c < 0) break;
-	}
-	return result.toString();
-}
-
-private String requestString() {
-	if (usingProxy() || proxyName != null) {
-		return url.toString();
-	}
-	String file = url.getFile();
-	if (file == null || file.length() == 0)
-		file = "/";
-	return file;
-}
-/**
- * Sends the request header to the remote HTTP server
- * Not all of them are guaranteed to have any effect on the content the
- * server will return, depending on if the server supports that field.
- *
- *
- * Examples :	Accept: text/*, text/html, text/html;level=1,
- * 				Accept-Charset: iso-8859-5, unicode-1-1;q=0.8
- */
-private boolean sendRequest() throws java.io.IOException {
-	byte[] request = createRequest();
-
-	// make sure we have a connection
-	if (!connected) connect();
-	// send out the HTTP request
-	socketOut.write(request);
-	sentRequest = true;
-	// send any output to the socket (i.e. POST data)
-	if (os != null && os.isCached()) {
-		socketOut.write(os.toByteArray());
-	}
-	if (os == null || os.isCached()) {
-		readServerResponse();
-		return true;
-	}
-	return false;
-}
-
-void readServerResponse() throws IOException {
-	socketOut.flush();
-	do {
-		responseCode = -1;
-		responseMessage = null;
-		resHeader = new Header();
-		String line = readln();
-		// Add the response, it may contain ':' which we ignore
-		if (line != null) {
-			resHeader.setStatusLine(line.trim());
-			readHeaders();
-		}
-	} while (getResponseCode() == 100);
-
-	if (method == "HEAD" || (responseCode >= 100 && responseCode < 200) ||
-		responseCode == HTTP_NO_CONTENT || responseCode == HTTP_NOT_MODIFIED)
-	{
-		closeSocket();
-		uis = new LimitedInputStream(0);
-	}
-}
-
-/**
- * Answers the reponse code returned by the remote HTTP server
- *
- *
- * @return int	the response code, -1 if no valid response code
- * @exception java.io.IOException 	thrown when there is a IO error during the retrieval.
- *
- * @see #getResponseMessage()
- */
-public int getResponseCode() throws IOException {
-	// Response Code Sample : "HTTP/1.0 200 OK"
-
-	// Call connect() first since getHeaderField() doesn't return exceptions
-	doRequest();
-	if (responseCode != -1) return responseCode;
-	String response = resHeader.getStatusLine();
-	if (response == null || !response.startsWith("HTTP/"))
-		return -1;
-	response.trim();
-	int mark = response.indexOf(" ") + 1;
-	if (mark == 0) return -1;
-	if (response.charAt(mark - 2) != '1')
-		httpVersion = 0;
-	int last = mark + 3;
-	if (last > response.length()) last = response.length();
-	responseCode = Integer.parseInt(response.substring(mark, last));
-	if (last + 1 <= response.length())
-		responseMessage = response.substring(last + 1);
-	return responseCode;
-}
-
-void readHeaders() throws IOException {
-	// parse the result headers until the first blank line
-	String line;
-	while (((line = readln())!=null) && (line.length() > 1)) {
-		// Header parsing
-		int idx;
-		if ((idx = line.indexOf(":")) < 0)
-			resHeader.add("", line.trim());
-		else
-			resHeader.add(line.substring(0, idx), line.substring(idx + 1).trim());
-	}
-}
-
-private byte[] createRequest() throws IOException {
-	StringBuffer output = new StringBuffer(256);
-	output.append(method);
-	output.append(' ');
-	output.append(requestString());
-	output.append(' ');
-	output.append("HTTP/1.");
-	if (httpVersion == 0) output.append("0\r\n");
-	else output.append("1\r\n");
-	if (reqHeader.get("User-Agent") == null) {
-		output.append("User-Agent: ");
-		String agent = getSystemProperty("http.agent");
-		if (agent == null) {
-			output.append("Java");
-			output.append(getSystemProperty("java.version"));
-		} else {
-			output.append(agent);
-		}
-		output.append("\r\n");
-	}
-	if (reqHeader.get("Host") == null) {
-		output.append("Host: ");
-		output.append(url.getHost());
-		int port = url.getPort();
-		if (port > 0 && port != defaultPort) {
-			output.append(':');
-			output.append(Integer.toString(port));
-		}
-		output.append("\r\n");
-	}
-	if (httpVersion > 0 && reqHeader.get("Connection") == null)
-		output.append("Connection: close\r\n");
-
-	// if we are doing output make sure the approprate headers are sent
-	if (os != null) {
-		if (reqHeader.get("Content-Type") == null)
-			output.append("Content-Type: application/x-www-form-urlencoded\r\n");
-		if (os.isCached()) {
-			if (reqHeader.get("Content-Length") == null) {
-				output.append("Content-Length: ");
-				output.append(Integer.toString(os.size()));
-				output.append("\r\n");
-			}
-		} else if (os.isChunked())
-			output.append("Transfer-Encoding: chunked\r\n");
-	}
-
-	// then the user-specified request headers, if any
-	for (int i = 0; i < reqHeader.length(); i++) {
-		String key = reqHeader.getKey(i);
-		if (key != null) {
-			String lKey = key.toLowerCase();
-			if ((os != null && !os.isChunked()) || (!lKey.equals("transfer-encoding") &&
-				!lKey.equals("content-length")))
-			{
-				output.append(key);
-				output.append(": ");
-				/* duplicates are allowed under certain conditions
-				 * see http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.2
-				 */
-				output.append(reqHeader.get(i));
-				output.append("\r\n");
-			}
-		}
-	}
-	// end the headers
-	output.append("\r\n");
-	return output.toString().getBytes("ISO8859_1");
-}
-
-/**
- * Sets the default request header fields to be sent to the remote server. This does
- * not affect the current URL Connection, only newly created ones.
- *
- * @param field		java.lang.String	The name of the field to be changed
- * @param value 	java.lang.String	The new value of the field
- */
-public static void setDefaultRequestProperty(String field, String value) {
-	defaultReqHeader.add(field, value);
-}
-/**
- * A slightly different implementation from this parent's <code>setIfModifiedSince()</code>
- * Since this HTTP impl supports IfModifiedSince as one of the header field, the request header
- * is updated with the new value.
- *
- *
- * @param newValue the number of millisecond since epoch
- *
- * @exception 	IllegalAccessError 	thrown when this method attempts to change the flag
- *						after connected
- */
-public void setIfModifiedSince(long newValue) throws IllegalAccessError {
-	super.setIfModifiedSince(newValue);
-	// convert from millisecond since epoch to date string
-	SimpleDateFormat sdf = new SimpleDateFormat("E, dd MMM yyyy HH:mm:ss 'GMT'", Locale.US);
-	sdf.setTimeZone(TimeZone.getTimeZone("GMT"));
-	String date = sdf.format(new java.util.Date(newValue));
-	reqHeader.add("If-Modified-Since", date);
-}
-/**
- * Sets the value of the request header field <code> field </code> to <code>newValue</code>
- * Only the current URL Connection is affected. It can only be called before the connection is made
- * This method must be overridden by protocols  which support the value of the fields.
- *
- *
- * @param field java.lang.String		the name of field to be set
- * @param newValue java.lang.String		the new value for this field
- *
- * @see 		#getDefaultRequestProperty
- * @see 		#setDefaultRequestProperty
- * @see 		#getRequestProperty
- */
-public void setRequestProperty(String field, String newValue) {
-	if (connected) {
-		throw new IllegalAccessError(org.apache.harmony.luni.util.Msg.getString("K0092"));
-	}
-	if(field == null) {
-		throw new NullPointerException();
-	}
-	reqHeader.set(field, newValue);
-}
-
-/**
- * Adds the given request property.  Will not overwrite any existing properties associated
- * with the given field name.
- *
- * @param field the request property field name
- * @param value the property value
- *
- * @since 1.4
- */
-public void addRequestProperty(String field, String value) {
-	if (connected) {
-			throw new IllegalAccessError(org.apache.harmony.luni.util.Msg.getString("K0092"));
-	}
-	if(field == null) {
-		throw new NullPointerException();
-	}
-	reqHeader.add(field, value);
-}
-
-/**
- * Get the connection port. This is either the URL's port or the
- * proxy port if a proxy port has been set.
- */
-private int getHostPort() {
-	if(usingProxy()){
-		if(null == currentProxy){
-			// get from system property
-			String portString = getSystemPropertyOrAlternative("http.proxyPort", "proxyPort");
-			if (portString != null) {
-				hostPort = Integer.parseInt(portString);
-			}
-		}else{
-			// get from proxy
-			InetSocketAddress addr = (InetSocketAddress) currentProxy.address();
-			hostPort = addr.getPort();
-		}
-	}else{
-		hostPort = url.getPort();
-	}
-	if (hostPort < 0){ 
-		hostPort = defaultPort;
-	}
-	return hostPort;
-}
-
-/**
- * Get the InetAddress of the connection machine. This is either
- * the address given in the URL or the address of the proxy
+ * This subclass extends <code>HttpURLConnection</code> which in turns extends
+ * <code>URLConnection</code> This is the actual class that "does the work",
+ * such as connecting, sending request and getting the content from the remote
  * server.
+ * 
  */
-private InetAddress getHostAddress() throws IOException {
-	return InetAddress.getByName(getHostName());
-}
+public class HttpURLConnection extends java.net.HttpURLConnection {
+    int httpVersion = 1; // Assume HTTP/1.1
 
-/**
- * Get the hostname of the connection machine. This is either
- * the name given in the URL or the name of the proxy
- * server.
- */
-private String getHostName() {
-	if (proxyName != null) {
-		return proxyName;
-	}
-	if (usingProxy()) {
-		if(null == currentProxy){
-			proxyName = getSystemPropertyOrAlternative("http.proxyHost", "proxyHost");
-		}else{
-			InetSocketAddress addr = (InetSocketAddress)currentProxy.address();
-			proxyName = addr.getHostName();
-		}
-		return proxyName;
-	}
-	return url.getHost();
-}
-
-private String getSystemPropertyOrAlternative(final String key, final String alternativeKey) {
-	String value = getSystemProperty(key);
-	if (value == null) { // For backward compatibility.
-	    value = getSystemProperty(alternativeKey);
-	}
-	return value;
-}
-
-private String getSystemProperty(final String property) {
-	return (String)AccessController.doPrivileged(new PriviAction(property));
-}
+    private final int defaultPort;
 
-/**
- * Answer whether the connection should use a proxy server.
- *
- * Need to check both proxy* and http.proxy* because of change between JDK 1.0 and JDK 1.1
- */
-public boolean usingProxy() {
-	if(Proxy.NO_PROXY == currentProxy){
-		return false;
-	}
-	// using proxy if http proxy is set by caller.
-	if(null != currentProxy && Proxy.Type.HTTP == currentProxy.type()){
-		return true;
-	}
-	// First check whether the user explicitly set whether to use a proxy.
-    String proxySet = getSystemProperty("http.proxySet");
-	if (proxySet != null) return proxySet.toLowerCase().equals("true");
-
-	proxySet = getSystemProperty("proxySet");
-	if (proxySet != null) return proxySet.toLowerCase().equals("true");
-
-	// The user didn't explicitly set whether to use a proxy. Answer true if the user specified a proxyHost.
-	if (getSystemProperty("http.proxyHost") != null) return true;
-	return getSystemProperty("proxyHost") != null;
-}
+    InputStream is;
 
+    private InputStream uis;
 
-/**
- * Handles an HTTP request along with its redirects and authentication
- *
- *
- */
-void doRequest() throws java.io.IOException {
-	// do nothing if we've already sent the request
-	if (sentRequest) {
-		// If necessary, finish the request by
-		// closing the uncached output stream.
-		if (resHeader == null && os != null) {
-			os.close();
-			readServerResponse();
-			getContentStream();
-		}
-		return;
-	}
-	// Use system-wide ProxySelect to select proxy list,
-	// then try to connect via elements in the proxy list.
-	if(null != proxy){
-		proxyList = new ArrayList(1);
-		proxyList.add(proxy);
-	}else{
-		proxyList = NetUtil.getProxyList(uri);
-	}
-	if(null == proxyList){
-		currentProxy = null;
-		doRequestInternal();
-	}else{
-		// try the proxy list until one of them establish
-		// the connection successfully.
-		ProxySelector selector = ProxySelector.getDefault();
-		Iterator iter = proxyList.iterator();
-		boolean doRequestOK = false;
-		while(iter.hasNext() && !doRequestOK){
-			currentProxy = (Proxy)iter.next();
-			try{
-				doRequestInternal();
-				doRequestOK = true;
-			}catch(IOException ioe){
-				// if connect failed, callback method "connectFailed" 
-				// should be invoked.
-				if(null != selector && Proxy.NO_PROXY != currentProxy){
-					selector.connectFailed(uri, currentProxy.address(), ioe);
-				}
-			}
-		}
-		if(!doRequestOK){
-			throw new IOException(Msg.getString("K0097"));
-		}
-	}
-}
-
-void doRequestInternal() throws java.io.IOException {
-	int redirect = 0;
-	while(true) {
-		// send the request and process the results
-		if (!sendRequest()) return;
-
-		// authorization failed ?
-		if (responseCode == HTTP_UNAUTHORIZED) {		// keep asking for username/password until authorized
-			String challenge = resHeader.get("WWW-Authenticate");
-			if (challenge == null) break;
-			int idx = challenge.indexOf(" ");
-			String scheme = challenge.substring(0, idx);
-			int realm = challenge.indexOf("realm=\"") + 7;
-			String prompt = null;
-			if (realm != -1) {
-				int end = challenge.indexOf('"', realm);
-				if (end != -1) prompt = challenge.substring(realm, end);
-			}
-
-			// the following will use the user-defined authenticator to get the password
-			PasswordAuthentication pa =
-					Authenticator.requestPasswordAuthentication(getHostAddress(),
-											getHostPort(),
-											url.getProtocol(),
-											prompt,
-											scheme);
-			if (pa == null) break;
-			// drop everything and reconnect, might not be required for HTTP/1.1
-			endRequest();
-			closeSocket();
-			connected = false;
-			// base64 encode the username and password
-			byte[] bytes = (pa.getUserName() + ":" + new String(pa.getPassword())).getBytes("ISO8859_1");
-			String encoded = org.apache.harmony.luni.util.Base64.encode(bytes, "ISO8859_1");
-			setRequestProperty("Authorization", scheme + " " + encoded);
-			continue;
-		}
-
-		// See if there is a server redirect to the URL, but only handle 1 level of
-		// URL redirection from the server to avoid being caught in an infinite loop
-		if (getInstanceFollowRedirects()) {
-			if ((responseCode == HTTP_MULT_CHOICE || responseCode == HTTP_MOVED_PERM ||
-				responseCode == HTTP_MOVED_TEMP || responseCode == HTTP_SEE_OTHER ||
-				responseCode == HTTP_USE_PROXY) && os == null) {
-
-				if (++redirect > 4)
-					throw new ProtocolException(org.apache.harmony.luni.util.Msg.getString("K0093"));
-				String location = getHeaderField("Location");
-			 	if (location != null) {
-					// start over
-					if (responseCode == HTTP_USE_PROXY) {
-						int start = 0;
-						if(location.startsWith(url.getProtocol() + ':'))
-							start = url.getProtocol().length() + 1;
-						if(location.startsWith("//", start))
-							start += 2;
-						setProxy(location.substring(start));
-					}
-					else {
-						url = new URL(url, location);
-						//update the port
-						hostPort = -1;
-					}
-					endRequest();
-					closeSocket();
-					connected = false;
-					continue;
-				}
-			}
-		}
-
-		break;
-	}
-
-	// Cache the content stream and read the first chunked header
-	getContentStream();
-}
-
-private void setProxy(String proxy) {
-	int index = proxy.indexOf(':');
-	if (index == -1) {
-		proxyName = proxy;
-		hostPort = defaultPort;
-	} else {
-		proxyName = proxy.substring(0, index);
-		String port = proxy.substring(index + 1);
-		try {
-			hostPort = Integer.parseInt(port);
-		} catch (NumberFormatException e) {
-			throw new IllegalArgumentException(org.apache.harmony.luni.util.Msg.getString("K00af", port));
-		}
-		if (hostPort < 0 || hostPort > 65535)
-			throw new IllegalArgumentException(org.apache.harmony.luni.util.Msg.getString("K00b0"));
-	}
-}
+    OutputStream socketOut;
+
+    private HttpOutputStream os;
+
+    private boolean sentRequest = false;
+
+    boolean sendChunked = false;
+
+    private String proxyName;
+
+    private int hostPort = -1;
+
+    private int readTimeout = -1;
+
+    // proxy which is used to make the connection.
+    private Proxy proxy = null;
+
+    // the proxy list which is used to make the connection.
+    private List proxyList = null;
+
+    // the current proxy which is used to make the connection.
+    private Proxy currentProxy;
+
+    // the destination uri
+    private URI uri = null;
+
+    // default request header
+    private static Header defaultReqHeader = new Header();
+
+    // request header that will be sent to the server
+    private Header reqHeader;
+
+    // response header received from the server
+    private Header resHeader;
+
+    private class LimitedInputStream extends InputStream {
+        int bytesRemaining;
+
+        public LimitedInputStream(int length) {
+            bytesRemaining = length;
+        }
+
+        public void close() throws IOException {
+            bytesRemaining = 0;
+            closeSocket();
+        }
+
+        public int available() throws IOException {
+            int result = is.available();
+            if (result > bytesRemaining)
+                return bytesRemaining;
+            return result;
+        }
+
+        public int read() throws IOException {
+            if (bytesRemaining <= 0)
+                return -1;
+            int result = is.read();
+            bytesRemaining--;
+            return result;
+        }
+
+        public int read(byte[] buf, int offset, int length) throws IOException {
+            if (buf == null)
+                throw new NullPointerException();
+            // avoid int overflow
+            if (offset < 0 || length < 0 || offset > buf.length
+                    || buf.length - offset < length)
+                throw new ArrayIndexOutOfBoundsException();
+            if (bytesRemaining <= 0)
+                return -1;
+            if (length > bytesRemaining)
+                length = bytesRemaining;
+            int result = is.read(buf, offset, length);
+            if (result > 0)
+                bytesRemaining -= result;
+            return result;
+        }
+
+        public long skip(int amount) throws IOException {
+            if (bytesRemaining <= 0)
+                return -1;
+            if (amount > bytesRemaining)
+                amount = bytesRemaining;
+            long result = is.skip(amount);
+            if (result > 0)
+                bytesRemaining -= result;
+            return result;
+        }
+    }
+
+    private class ChunkedInputStream extends InputStream {
+        int bytesRemaining = -1;
+
+        boolean atEnd = false;
+
+        public ChunkedInputStream() throws IOException {
+            readChunkSize();
+        }
+
+        public void close() throws IOException {
+            atEnd = true;
+            closeSocket();
+        }
+
+        public int available() throws IOException {
+            int result = is.available();
+            if (result > bytesRemaining)
+                return bytesRemaining;
+            return result;
+        }
+
+        private void readChunkSize() throws IOException {
+            if (atEnd)
+                return;
+            if (bytesRemaining == 0)
+                readln(); // read CR/LF
+            String size = readln();
+            int index = size.indexOf(";");
+            if (index >= 0)
+                size = size.substring(0, index);
+            bytesRemaining = Integer.parseInt(size.trim(), 16);
+            if (bytesRemaining == 0) {
+                atEnd = true;
+                readHeaders();
+            }
+        }
+
+        public int read() throws IOException {
+            if (bytesRemaining <= 0)
+                readChunkSize();
+            if (atEnd)
+                return -1;
+            bytesRemaining--;
+            return is.read();
+        }
+
+        public int read(byte[] buf, int offset, int length) throws IOException {
+            if (buf == null)
+                throw new NullPointerException();
+            // avoid int overflow
+            if (offset < 0 || length < 0 || offset > buf.length
+                    || buf.length - offset < length)
+                throw new ArrayIndexOutOfBoundsException();
+            if (bytesRemaining <= 0)
+                readChunkSize();
+            if (atEnd)
+                return -1;
+            if (length > bytesRemaining)
+                length = bytesRemaining;
+            int result = is.read(buf, offset, length);
+            if (result > 0)
+                bytesRemaining -= result;
+            return result;
+        }
+
+        public long skip(int amount) throws IOException {
+            if (atEnd)
+                return -1;
+            if (bytesRemaining <= 0)
+                readChunkSize();
+            if (amount > bytesRemaining)
+                amount = bytesRemaining;
+            long result = is.skip(amount);
+            if (result > 0)
+                bytesRemaining -= result;
+            return result;
+        }
+    }
+
+    private class HttpOutputStream extends OutputStream {
+        static final int MAX = 1024;
+
+        ByteArrayOutputStream cache = new ByteArrayOutputStream(MAX + 7);
+
+        boolean writeToSocket, closed = false;
+
+        int limit;
+
+        public HttpOutputStream() {
+            limit = -1;
+        }
+
+        public HttpOutputStream(int limit) {
+            writeToSocket = true;
+            this.limit = limit;
+        }
+
+        private void output(String output) throws IOException {
+            socketOut.write(output.getBytes("ISO8859_1"));
+        }
+
+        private void sendCache(boolean close) throws IOException {
+            int size = cache.size();
+            if (size > 0 || close) {
+                if (limit < 0) {
+                    if (size > 0) {
+                        output(Integer.toHexString(size) + "\r\n");
+                        cache.write('\r');
+                        cache.write('\n');
+                    }
+                    if (close) {
+                        cache.write('0');
+                        cache.write('\r');
+                        cache.write('\n');
+                        cache.write('\r');
+                        cache.write('\n');
+                    }
+                }
+                socketOut.write(cache.toByteArray());
+                cache.reset();
+            }
+        }
+
+        public synchronized void flush() throws IOException {
+            if (closed)
+                throw new IOException(Msg.getString("K0059"));
+            if (writeToSocket) {
+                sendCache(false);
+                socketOut.flush();
+            }
+        }
+
+        public synchronized void close() throws IOException {
+            if (closed)
+                return;
+            closed = true;
+            if (writeToSocket) {
+                if (limit > 0)
+                    throw new IOException(Msg.getString("K00a4"));
+                sendCache(closed);
+            }
+        }
+
+        public synchronized void write(int data) throws IOException {
+            if (closed)
+                throw new IOException(Msg.getString("K0059"));
+            if (limit >= 0) {
+                if (limit == 0)
+                    throw new IOException(Msg.getString("K00b2"));
+                limit--;
+            }
+            cache.write(data);
+            if (writeToSocket && cache.size() >= MAX)
+                sendCache(false);
+        }
+
+        public synchronized void write(byte[] buffer, int offset, int count)
+                throws IOException {
+            if (closed)
+                throw new IOException(Msg.getString("K0059"));
+            if (buffer == null)
+                throw new NullPointerException();
+            // avoid int overflow
+            if (offset < 0 || count < 0 || offset > buffer.length
+                    || buffer.length - offset < count)
+                throw new ArrayIndexOutOfBoundsException(Msg.getString("K002f"));
+
+            if (limit >= 0) {
+                if (count > limit)
+                    throw new IOException(Msg.getString("K00b2"));
+                limit -= count;
+            }
+            if (!writeToSocket || cache.size() + count < MAX) {
+                cache.write(buffer, offset, count);
+            } else {
+                if (limit < 0)
+                    output(Integer.toHexString(count + cache.size()) + "\r\n");
+                socketOut.write(cache.toByteArray());
+                cache.reset();
+                socketOut.write(buffer, offset, count);
+                if (limit < 0)
+                    output("\r\n");
+            }
+        }
+
+        synchronized int size() {
+            return cache.size();
+        }
+
+        synchronized byte[] toByteArray() {
+            return cache.toByteArray();
+        }
+
+        boolean isCached() {
+            return !writeToSocket;
+        }
+
+        boolean isChunked() {
+            return writeToSocket && limit == -1;
+        }
+    }
+
+    /**
+     * Creates an instance of the <code>HttpURLConnection</code> using default
+     * port 80.
+     * 
+     * @param url
+     *            URL The URL this connection is connecting
+     */
+    protected HttpURLConnection(URL url) {
+        this(url, 80);
+    }
+
+    /**
+     * Creates an instance of the <code>HttpURLConnection</code>
+     * 
+     * @param url
+     *            URL The URL this connection is connecting
+     * @param port
+     *            int The default connection port
+     */
+    protected HttpURLConnection(URL url, int port) {
+        super(url);
+        defaultPort = port;
+
+        reqHeader = (Header) defaultReqHeader.clone();
+        try {
+            uri = url.toURI();
+        } catch (URISyntaxException e) {
+            // do nothing.
+        }
+    }
+
+    /**
+     * Creates an instance of the <code>HttpURLConnection</code>
+     * 
+     * @param url
+     *            URL The URL this connection is connecting
+     * @param port
+     *            int The default connection port
+     * @param proxy
+     *            Proxy The proxy which is used to make the connection
+     */
+    protected HttpURLConnection(URL url, int port, Proxy proxy) {
+        this(url, port);
+        this.proxy = proxy;
+    }
+
+    /**
+     * Establishes the connection to the remote HTTP server
+     * 
+     * Any methods that requires a valid connection to the resource will call
+     * this method implicitly. After the connection is established,
+     * <code>connected</code> is set to true.
+     * 
+     * 
+     * @see #connected
+     * @see java.io.IOException
+     * @see URLStreamHandler
+     */
+    public void connect() throws IOException {
+        if (connected)
+            return;
+        Socket socket;
+
+        InetAddress host = getHostAddress();
+        int port = getHostPort();
+        if (null == currentProxy || Proxy.Type.HTTP == currentProxy.type()) {
+            socket = new Socket(host, port);
+        } else {
+            socket = new Socket(currentProxy);
+            SocketAddress sa = new InetSocketAddress(host, port);
+            socket.connect(sa);
+        }
+
+        if (readTimeout >= 0)
+            socket.setSoTimeout(readTimeout);
+        connected = true;
+        socketOut = socket.getOutputStream();
+        is = new BufferedInputStream(socket.getInputStream());
+    }
+
+    /**
+     * Sets the read timeout for the http connection.
+     * 
+     * 
+     * @param value
+     *            the read timeout value. Must be >= 0
+     * 
+     * @see java.net.Socket#setSoTimeout
+     */
+    public void setReadTimeout(int value) {
+        if (value < 0)
+            throw new IllegalArgumentException(Msg.getString("K0036"));
+        readTimeout = value;
+    }
+
+    /**
+     * Closes the connection with the HTTP server
+     * 
+     * 
+     * @see URLConnection#connect()
+     */
+    public void disconnect() {
+        try {
+            closeSocket();
+        } catch (IOException e) {
+        }
+    }
+
+    void closeSocket() throws IOException {
+        if (is != null)
+            is.close();
+    }
+
+    void endRequest() throws IOException {
+        if (os != null)
+            os.close();
+        sentRequest = false;
+    }
+
+    /**
+     * Answers the default value for the field specified by <code>field</code>,
+     * null if there's no such a field.
+     */
+    public static String getDefaultRequestProperty(String field) {
+        return defaultReqHeader.get(field);
+    }
+
+    /**
+     * Answers an input stream from the server in the case of error such as the
+     * requested file (txt, htm, html) is not found on the remote server.
+     * <p>
+     * If the content type is not what stated above,
+     * <code>FileNotFoundException</code> is thrown.
+     * 
+     * @return java.io.InputStream the error input stream returned by the
+     *         server.
+     */
+    public InputStream getErrorStream() {
+        if (connected && method != "HEAD" && responseCode >= HTTP_BAD_REQUEST)
+            return uis;
+        return null;
+    }
+
+    /**
+     * Answers the value of the field at position <code>pos<code>.
+     * Answers <code>null</code> if there is fewer than <code>pos</code> fields
+     * in the response header.
+     *
+     * @return java.lang.String		The value of the field
+     * @param pos int				the position of the field from the top
+     *
+     * @see 		#getHeaderField(String)
+     * @see 		#getHeaderFieldKey
+     */
+    public String getHeaderField(int pos) {
+        try {
+            getInputStream();
+            return resHeader.get(pos);
+        } catch (IOException e) {
+            return null;
+        }
+    }
+
+    /**
+     * Answers the value of the field corresponding to the <code>key</code>
+     * Answers <code>null</code> if there is no such field.
+     * 
+     * If there are multiple fields with that key, the last field value is
+     * returned.
+     * 
+     * @return java.lang.String The value of the header field
+     * @param key
+     *            java.lang.String the name of the header field
+     * 
+     * @see #getHeaderField(int)
+     * @see #getHeaderFieldKey
+     */
+    public String getHeaderField(String key) {
+        try {
+            getInputStream();
+            return resHeader.get(key);
+        } catch (IOException e) {
+            return null;
+        }
+    }
+
+    /**
+     * This method answers the header field at position <code>pos</code> from
+     * the response header, null if there is fewer fields than <code>pos</code>.
+     * 
+     * 
+     * @return java.lang.String
+     * @param pos
+     *            int
+     * 
+     * @see #getHeaderField(String)
+     * @see #getHeaderField(int)
+     */
+    public String getHeaderFieldKey(int pos) {
+        try {
+            getInputStream();
+            return resHeader.getKey(pos);
+        } catch (IOException e) {
+            return null;
+        }
+    }
+
+    /**
+     * Provides an unmodifiable map of the connection header values. The map
+     * keys are the String header field names. Each map value is a list of the
+     * header field values associated with that key name.
+     * 
+     * @return the mapping of header field names to values
+     * 
+     * @since 1.4
+     */
+    public Map getHeaderFields() {
+        return resHeader.getFieldMap();
+    }
+
+    /**
+     * Provides an unmodifiable map of the request properties. The map keys are
+     * Strings, the map values are each a List of Strings, with each request
+     * property name mapped to its corresponding property values.
+     * 
+     * @return the mapping of request property names to values
+     * 
+     * @since 1.4
+     */
+    public Map getRequestProperties() {
+        return reqHeader.getFieldMap();
+    }
+
+    /**
+     * Creates an input stream for reading from this URL Connection.
+     * 
+     * 
+     * @return InputStream The input stream to read from
+     * @exception UnknownServiceException
+     *                Exception thrown when reading to URL isn't supported
+     * 
+     * @see #getContent()
+     * @see #getOutputStream()
+     * @see java.io.InputStream
+     * @see java.io.IOException
+     */
+    public InputStream getInputStream() throws IOException {
+        if (!doInput)
+            throw new ProtocolException(Msg.getString("K008d"));
+
+        doRequest();
+
+        // if the requested file does not exist, throw an exception
+        // formerly the Error page from the server was returned
+        // if the requested file was text/html
+        // this has changed to return FileNotFoundException for all file types
+        if (responseCode >= HTTP_BAD_REQUEST)
+            throw new FileNotFoundException(url.toString());
+
+        return uis;
+    }
+
+    private InputStream getContentStream() throws IOException {
+        if (uis != null)
+            return uis;
+
+        String encoding = resHeader.get("Transfer-Encoding");
+        if (encoding != null && encoding.toLowerCase().equals("chunked"))
+            return uis = new ChunkedInputStream();
+
+        String sLength = resHeader.get("Content-Length");
+        if (sLength != null) {
+            try {
+                int length = Integer.parseInt(sLength);
+                return uis = new LimitedInputStream(length);
+            } catch (NumberFormatException e) {
+            }
+        }
+        return uis = is;
+    }
+
+    /**
+     * Creates an output stream for writing to this URL Connection.
+     * <code>UnknownServiceException</code> will be thrown if this url denies
+     * write access
+     * 
+     * 
+     * @return OutputStream The output stream to write to
+     * @exception UnknownServiceException
+     *                thrown when writing to URL is not supported
+     * 
+     * @see #getContent()
+     * @see #getInputStream()
+     * @see java.io.IOException
+     * 
+     */
+    public OutputStream getOutputStream() throws IOException {
+        if (!doOutput)
+            throw new ProtocolException(Msg.getString("K008e"));
+
+        // you can't write after you read
+        if (sentRequest)
+            throw new ProtocolException(Msg.getString("K0090"));
+
+        if (os != null)
+            return os;
+
+        // they are requesting a stream to write to. This implies a POST method
+        if (method == "GET")
+            setRequestMethod("POST");
+        // If the request method is neither PUT or POST, then you're not writing
+        if (method != "PUT" && method != "POST")
+            throw new ProtocolException(Msg.getString("K008f", method));
+
+        int limit = -1;
+        String contentLength = reqHeader.get("Content-Length");
+        if (contentLength != null)
+            limit = Integer.parseInt(contentLength);
+
+        String encoding = reqHeader.get("Transfer-Encoding");
+        if (httpVersion > 0 && encoding != null) {
+            encoding = encoding.toLowerCase();
+            if ("chunked".equals(encoding)) {
+                sendChunked = true;
+                limit = -1;
+            }
+        }
+        if ((httpVersion > 0 && sendChunked) || limit >= 0) {
+            os = new HttpOutputStream(limit);
+            doRequest();
+            return os;
+        }
+        return os = new HttpOutputStream();
+
+    }
+
+    /**
+     * Answers the permission required to make the connection
+     * 
+     * @return java.security.Permission the connection required to make the
+     *         connection.
+     * @exception java.io.IOException
+     *                thrown if an IO exception occurs while computing the
+     *                permission.
+     */
+    public Permission getPermission() throws IOException {
+        return new SocketPermission(getHostName() + ":" + getHostPort(),
+                "connect, resolve");
+    }
+
+    /**
+     * Answers the value corresponds to the field in the request Header, null if
+     * no such field exists
+     * 
+     * @return java.lang.String The field to look up
+     * 
+     * @see #getDefaultRequestProperty
+     * @see #setDefaultRequestProperty
+     * @see #setRequestProperty
+     */
+    public String getRequestProperty(String field) {
+        if (connected)
+            throw new IllegalAccessError(Msg.getString("K0091"));
+        return reqHeader.get(field);
+    }
+
+    /**
+     * Answers a line read from the input stream. Does not include the \n
+     * 
+     * @return java.lang.String
+     */
+    String readln() throws IOException {
+        boolean lastCr = false;
+        StringBuffer result = new StringBuffer(80);
+        int c = is.read();
+        if (c < 0)
+            return null;
+        while (c != '\n') {
+            if (lastCr) {
+                result.append('\r');
+                lastCr = false;
+            }
+            if (c == '\r')
+                lastCr = true;
+            else
+                result.append((char) c);
+            c = is.read();
+            if (c < 0)
+                break;
+        }
+        return result.toString();
+    }
+
+    private String requestString() {
+        if (usingProxy() || proxyName != null) {
+            return url.toString();
+        }
+        String file = url.getFile();
+        if (file == null || file.length() == 0)
+            file = "/";
+        return file;
+    }
+
+    /**
+     * Sends the request header to the remote HTTP server Not all of them are
+     * guaranteed to have any effect on the content the server will return,
+     * depending on if the server supports that field.
+     * 
+     * Examples : Accept: text/*, text/html, text/html;level=1, Accept-Charset:
+     * iso-8859-5, unicode-1-1;q=0.8
+     */
+    private boolean sendRequest() throws IOException {
+        byte[] request = createRequest();
+
+        // make sure we have a connection
+        if (!connected)
+            connect();
+        // send out the HTTP request
+        socketOut.write(request);
+        sentRequest = true;
+        // send any output to the socket (i.e. POST data)
+        if (os != null && os.isCached()) {
+            socketOut.write(os.toByteArray());
+        }
+        if (os == null || os.isCached()) {
+            readServerResponse();
+            return true;
+        }
+        return false;
+    }
+
+    void readServerResponse() throws IOException {
+        socketOut.flush();
+        do {
+            responseCode = -1;
+            responseMessage = null;
+            resHeader = new Header();
+            String line = readln();
+            // Add the response, it may contain ':' which we ignore
+            if (line != null) {
+                resHeader.setStatusLine(line.trim());
+                readHeaders();
+            }
+        } while (getResponseCode() == 100);
+
+        if (method == "HEAD" || (responseCode >= 100 && responseCode < 200)
+                || responseCode == HTTP_NO_CONTENT
+                || responseCode == HTTP_NOT_MODIFIED) {
+            closeSocket();
+            uis = new LimitedInputStream(0);
+        }
+    }
+
+    /**
+     * Answers the reponse code returned by the remote HTTP server
+     * 
+     * 
+     * @return int the response code, -1 if no valid response code
+     * @exception java.io.IOException
+     *                thrown when there is a IO error during the retrieval.
+     * 
+     * @see #getResponseMessage()
+     */
+    public int getResponseCode() throws IOException {
+        // Response Code Sample : "HTTP/1.0 200 OK"
+
+        // Call connect() first since getHeaderField() doesn't return exceptions
+        doRequest();
+        if (responseCode != -1)
+            return responseCode;
+        String response = resHeader.getStatusLine();
+        if (response == null || !response.startsWith("HTTP/"))
+            return -1;
+        response.trim();
+        int mark = response.indexOf(" ") + 1;
+        if (mark == 0)
+            return -1;
+        if (response.charAt(mark - 2) != '1')
+            httpVersion = 0;
+        int last = mark + 3;
+        if (last > response.length())
+            last = response.length();
+        responseCode = Integer.parseInt(response.substring(mark, last));
+        if (last + 1 <= response.length())
+            responseMessage = response.substring(last + 1);
+        return responseCode;
+    }
+
+    void readHeaders() throws IOException {
+        // parse the result headers until the first blank line
+        String line;
+        while (((line = readln()) != null) && (line.length() > 1)) {
+            // Header parsing
+            int idx;
+            if ((idx = line.indexOf(":")) < 0)
+                resHeader.add("", line.trim());
+            else
+                resHeader.add(line.substring(0, idx), line.substring(idx + 1)
+                        .trim());
+        }
+    }
+
+    private byte[] createRequest() throws IOException {
+        StringBuffer output = new StringBuffer(256);
+        output.append(method);
+        output.append(' ');
+        output.append(requestString());
+        output.append(' ');
+        output.append("HTTP/1.");
+        if (httpVersion == 0)
+            output.append("0\r\n");
+        else
+            output.append("1\r\n");
+        if (reqHeader.get("User-Agent") == null) {
+            output.append("User-Agent: ");
+            String agent = getSystemProperty("http.agent");
+            if (agent == null) {
+                output.append("Java");
+                output.append(getSystemProperty("java.version"));
+            } else {
+                output.append(agent);
+            }
+            output.append("\r\n");
+        }
+        if (reqHeader.get("Host") == null) {
+            output.append("Host: ");
+            output.append(url.getHost());
+            int port = url.getPort();
+            if (port > 0 && port != defaultPort) {
+                output.append(':');
+                output.append(Integer.toString(port));
+            }
+            output.append("\r\n");
+        }
+        if (httpVersion > 0 && reqHeader.get("Connection") == null)
+            output.append("Connection: close\r\n");
+
+        // if we are doing output make sure the approprate headers are sent
+        if (os != null) {
+            if (reqHeader.get("Content-Type") == null)
+                output
+                        .append("Content-Type: application/x-www-form-urlencoded\r\n");
+            if (os.isCached()) {
+                if (reqHeader.get("Content-Length") == null) {
+                    output.append("Content-Length: ");
+                    output.append(Integer.toString(os.size()));
+                    output.append("\r\n");
+                }
+            } else if (os.isChunked())
+                output.append("Transfer-Encoding: chunked\r\n");
+        }
+
+        // then the user-specified request headers, if any
+        for (int i = 0; i < reqHeader.length(); i++) {
+            String key = reqHeader.getKey(i);
+            if (key != null) {
+                String lKey = key.toLowerCase();
+                if ((os != null && !os.isChunked())
+                        || (!lKey.equals("transfer-encoding") && !lKey
+                                .equals("content-length"))) {
+                    output.append(key);
+                    output.append(": ");
+                    /*
+                     * duplicates are allowed under certain conditions see
+                     * http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.2
+                     */
+                    output.append(reqHeader.get(i));
+                    output.append("\r\n");
+                }
+            }
+        }
+        // end the headers
+        output.append("\r\n");
+        return output.toString().getBytes("ISO8859_1");
+    }
+
+    /**
+     * Sets the default request header fields to be sent to the remote server.
+     * This does not affect the current URL Connection, only newly created ones.
+     * 
+     * @param field
+     *            java.lang.String The name of the field to be changed
+     * @param value
+     *            java.lang.String The new value of the field
+     */
+    public static void setDefaultRequestProperty(String field, String value) {
+        defaultReqHeader.add(field, value);
+    }
+
+    /**
+     * A slightly different implementation from this parent's
+     * <code>setIfModifiedSince()</code> Since this HTTP impl supports
+     * IfModifiedSince as one of the header field, the request header is updated
+     * with the new value.
+     * 
+     * 
+     * @param newValue
+     *            the number of millisecond since epoch
+     * 
+     * @exception IllegalAccessError
+     *                thrown when this method attempts to change the flag after
+     *                connected
+     */
+    public void setIfModifiedSince(long newValue) throws IllegalAccessError {
+        super.setIfModifiedSince(newValue);
+        // convert from millisecond since epoch to date string
+        SimpleDateFormat sdf = new SimpleDateFormat(
+                "E, dd MMM yyyy HH:mm:ss 'GMT'", Locale.US);
+        sdf.setTimeZone(TimeZone.getTimeZone("GMT"));
+        String date = sdf.format(new Date(newValue));
+        reqHeader.add("If-Modified-Since", date);
+    }
+
+    /**
+     * Sets the value of the request header field <code> field </code> to
+     * <code>newValue</code> Only the current URL Connection is affected. It
+     * can only be called before the connection is made This method must be
+     * overridden by protocols which support the value of the fields.
+     * 
+     * 
+     * @param field
+     *            java.lang.String the name of field to be set
+     * @param newValue
+     *            java.lang.String the new value for this field
+     * 
+     * @see #getDefaultRequestProperty
+     * @see #setDefaultRequestProperty
+     * @see #getRequestProperty
+     */
+    public void setRequestProperty(String field, String newValue) {
+        if (connected) {
+            throw new IllegalAccessError(Msg.getString("K0092"));
+        }
+        if (field == null) {
+            throw new NullPointerException();
+        }
+        reqHeader.set(field, newValue);
+    }
+
+    /**
+     * Adds the given request property. Will not overwrite any existing
+     * properties associated with the given field name.
+     * 
+     * @param field
+     *            the request property field name
+     * @param value
+     *            the property value
+     * 
+     * @since 1.4
+     */
+    public void addRequestProperty(String field, String value) {
+        if (connected) {
+            throw new IllegalAccessError(Msg.getString("K0092"));
+        }
+        if (field == null) {
+            throw new NullPointerException();
+        }
+        reqHeader.add(field, value);
+    }
+
+    /**
+     * Get the connection port. This is either the URL's port or the proxy port
+     * if a proxy port has been set.
+     */
+    private int getHostPort() {
+        if (usingProxy()) {
+            if (null == currentProxy) {
+                // get from system property
+                String portString = getSystemPropertyOrAlternative(
+                        "http.proxyPort", "proxyPort");
+                if (portString != null) {
+                    hostPort = Integer.parseInt(portString);
+                }
+            } else {
+                // get from proxy
+                InetSocketAddress addr = (InetSocketAddress) currentProxy
+                        .address();
+                hostPort = addr.getPort();
+            }
+        } else {
+            hostPort = url.getPort();
+        }
+        if (hostPort < 0) {
+            hostPort = defaultPort;
+        }
+        return hostPort;
+    }
+
+    /**
+     * Get the InetAddress of the connection machine. This is either the address
+     * given in the URL or the address of the proxy server.
+     */
+    private InetAddress getHostAddress() throws IOException {
+        return InetAddress.getByName(getHostName());
+    }
+
+    /**
+     * Get the hostname of the connection machine. This is either the name given
+     * in the URL or the name of the proxy server.
+     */
+    private String getHostName() {
+        if (proxyName != null) {
+            return proxyName;
+        }
+        if (usingProxy()) {
+            if (null == currentProxy) {
+                proxyName = getSystemPropertyOrAlternative("http.proxyHost",
+                        "proxyHost");
+            } else {
+                InetSocketAddress addr = (InetSocketAddress) currentProxy
+                        .address();
+                proxyName = addr.getHostName();
+            }
+            return proxyName;
+        }
+        return url.getHost();
+    }
+
+    private String getSystemPropertyOrAlternative(final String key,
+            final String alternativeKey) {
+        String value = getSystemProperty(key);
+        if (value == null) { // For backward compatibility.
+            value = getSystemProperty(alternativeKey);
+        }
+        return value;
+    }
+
+    private String getSystemProperty(final String property) {
+        return (String) AccessController
+                .doPrivileged(new PriviAction(property));
+    }
+
+    /**
+     * Answer whether the connection should use a proxy server.
+     * 
+     * Need to check both proxy* and http.proxy* because of change between JDK
+     * 1.0 and JDK 1.1
+     */
+    public boolean usingProxy() {
+        if (Proxy.NO_PROXY == currentProxy) {
+            return false;
+        }
+        // using proxy if http proxy is set by caller.
+        if (null != currentProxy && Proxy.Type.HTTP == currentProxy.type()) {
+            return true;
+        }
+        // First check whether the user explicitly set whether to use a proxy.
+        String proxySet = getSystemProperty("http.proxySet");
+        if (proxySet != null)
+            return proxySet.toLowerCase().equals("true");
+
+        proxySet = getSystemProperty("proxySet");
+        if (proxySet != null)
+            return proxySet.toLowerCase().equals("true");
+
+        // The user didn't explicitly set whether to use a proxy. Answer true if
+        // the user specified a proxyHost.
+        if (getSystemProperty("http.proxyHost") != null)
+            return true;
+        return getSystemProperty("proxyHost") != null;
+    }
+
+    /**
+     * Handles an HTTP request along with its redirects and authentication
+     */
+    void doRequest() throws IOException {
+        // do nothing if we've already sent the request
+        if (sentRequest) {
+            // If necessary, finish the request by
+            // closing the uncached output stream.
+            if (resHeader == null && os != null) {
+                os.close();
+                readServerResponse();
+                getContentStream();
+            }
+            return;
+        }
+        // Use system-wide ProxySelect to select proxy list,
+        // then try to connect via elements in the proxy list.
+        if (null != proxy) {
+            proxyList = new ArrayList(1);
+            proxyList.add(proxy);
+        } else {
+            proxyList = NetUtil.getProxyList(uri);
+        }
+        if (null == proxyList) {
+            currentProxy = null;
+            doRequestInternal();
+        } else {
+            // try the proxy list until one of them establish
+            // the connection successfully.
+            ProxySelector selector = ProxySelector.getDefault();
+            Iterator iter = proxyList.iterator();
+            boolean doRequestOK = false;
+            while (iter.hasNext() && !doRequestOK) {
+                currentProxy = (Proxy) iter.next();
+                try {
+                    doRequestInternal();
+                    doRequestOK = true;
+                } catch (IOException ioe) {
+                    // if connect failed, callback method "connectFailed"
+                    // should be invoked.
+                    if (null != selector && Proxy.NO_PROXY != currentProxy) {
+                        selector
+                                .connectFailed(uri, currentProxy.address(), ioe);
+                    }
+                }
+            }
+            if (!doRequestOK) {
+                throw new IOException(Msg.getString("K0097"));
+            }
+        }
+    }
+
+    void doRequestInternal() throws IOException {
+        int redirect = 0;
+        while (true) {
+            // send the request and process the results
+            if (!sendRequest())
+                return;
+
+            // authorization failed ?
+            if (responseCode == HTTP_UNAUTHORIZED) { // keep asking for
+                // username/password
+                // until authorized
+                String challenge = resHeader.get("WWW-Authenticate");
+                if (challenge == null)
+                    break;
+                int idx = challenge.indexOf(" ");
+                String scheme = challenge.substring(0, idx);
+                int realm = challenge.indexOf("realm=\"") + 7;
+                String prompt = null;
+                if (realm != -1) {
+                    int end = challenge.indexOf('"', realm);
+                    if (end != -1)
+                        prompt = challenge.substring(realm, end);
+                }
+
+                // the following will use the user-defined authenticator to get
+                // the password
+                PasswordAuthentication pa = Authenticator
+                        .requestPasswordAuthentication(getHostAddress(),
+                                getHostPort(), url.getProtocol(), prompt,
+                                scheme);
+                if (pa == null)
+                    break;
+                // drop everything and reconnect, might not be required for
+                // HTTP/1.1
+                endRequest();
+                closeSocket();
+                connected = false;
+                // base64 encode the username and password
+                byte[] bytes = (pa.getUserName() + ":" + new String(pa
+                        .getPassword())).getBytes("ISO8859_1");
+                String encoded = Base64.encode(bytes, "ISO8859_1");
+                setRequestProperty("Authorization", scheme + " " + encoded);
+                continue;
+            }
+
+            // See if there is a server redirect to the URL, but only handle 1
+            // level of
+            // URL redirection from the server to avoid being caught in an
+            // infinite loop
+            if (getInstanceFollowRedirects()) {
+                if ((responseCode == HTTP_MULT_CHOICE
+                        || responseCode == HTTP_MOVED_PERM
+                        || responseCode == HTTP_MOVED_TEMP
+                        || responseCode == HTTP_SEE_OTHER || responseCode == HTTP_USE_PROXY)
+                        && os == null) {
+
+                    if (++redirect > 4)
+                        throw new ProtocolException(
+                                org.apache.harmony.luni.util.Msg
+                                        .getString("K0093"));
+                    String location = getHeaderField("Location");
+                    if (location != null) {
+                        // start over
+                        if (responseCode == HTTP_USE_PROXY) {
+                            int start = 0;
+                            if (location.startsWith(url.getProtocol() + ':'))
+                                start = url.getProtocol().length() + 1;
+                            if (location.startsWith("//", start))
+                                start += 2;
+                            setProxy(location.substring(start));
+                        } else {
+                            url = new URL(url, location);
+                            // update the port
+                            hostPort = -1;
+                        }
+                        endRequest();
+                        closeSocket();
+                        connected = false;
+                        continue;
+                    }
+                }
+            }
+
+            break;
+        }
+
+        // Cache the content stream and read the first chunked header
+        getContentStream();
+    }
+
+    private void setProxy(String proxy) {
+        int index = proxy.indexOf(':');
+        if (index == -1) {
+            proxyName = proxy;
+            hostPort = defaultPort;
+        } else {
+            proxyName = proxy.substring(0, index);
+            String port = proxy.substring(index + 1);
+            try {
+                hostPort = Integer.parseInt(port);
+            } catch (NumberFormatException e) {
+                throw new IllegalArgumentException(Msg.getString("K00af", port));
+            }
+            if (hostPort < 0 || hostPort > 65535)
+                throw new IllegalArgumentException(Msg.getString("K00b0"));
+        }
+    }
 }



Mime
View raw message