summaryrefslogtreecommitdiffstats
path: root/libjava/gnu/java/net/protocol/http/Request.java
diff options
context:
space:
mode:
Diffstat (limited to 'libjava/gnu/java/net/protocol/http/Request.java')
-rw-r--r--libjava/gnu/java/net/protocol/http/Request.java914
1 files changed, 0 insertions, 914 deletions
diff --git a/libjava/gnu/java/net/protocol/http/Request.java b/libjava/gnu/java/net/protocol/http/Request.java
deleted file mode 100644
index 15a459e3eac..00000000000
--- a/libjava/gnu/java/net/protocol/http/Request.java
+++ /dev/null
@@ -1,914 +0,0 @@
-/* Request.java --
- Copyright (C) 2004 Free Software Foundation, Inc.
-
-This file is part of GNU Classpath.
-
-GNU Classpath is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2, or (at your option)
-any later version.
-
-GNU Classpath 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
-General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with GNU Classpath; see the file COPYING. If not, write to the
-Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
-02110-1301 USA.
-
-Linking this library statically or dynamically with other modules is
-making a combined work based on this library. Thus, the terms and
-conditions of the GNU General Public License cover the whole
-combination.
-
-As a special exception, the copyright holders of this library give you
-permission to link this library with independent modules to produce an
-executable, regardless of the license terms of these independent
-modules, and to copy and distribute the resulting executable under
-terms of your choice, provided that you also meet, for each linked
-independent module, the terms and conditions of the license of that
-module. An independent module is a module which is not derived from
-or based on this library. If you modify this library, you may extend
-this exception to your version of the library, but you are not
-obligated to do so. If you do not wish to do so, delete this
-exception statement from your version. */
-
-
-package gnu.java.net.protocol.http;
-
-import gnu.java.net.BASE64;
-import gnu.java.net.LineInputStream;
-import gnu.java.net.protocol.http.event.RequestEvent;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.net.ProtocolException;
-import java.security.MessageDigest;
-import java.security.NoSuchAlgorithmException;
-import java.text.DateFormat;
-import java.text.ParseException;
-import java.util.Calendar;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.Map;
-import java.util.Properties;
-import java.util.zip.GZIPInputStream;
-import java.util.zip.InflaterInputStream;
-
-/**
- * A single HTTP request.
- *
- * @author Chris Burdess (dog@gnu.org)
- */
-public class Request
-{
-
- /**
- * The connection context in which this request is invoked.
- */
- protected final HTTPConnection connection;
-
- /**
- * The HTTP method to invoke.
- */
- protected final String method;
-
- /**
- * The path identifying the resource.
- * This string must conform to the abs_path definition given in RFC2396,
- * with an optional "?query" part, and must be URI-escaped by the caller.
- */
- protected final String path;
-
- /**
- * The headers in this request.
- */
- protected final Headers requestHeaders;
-
- /**
- * The request body provider.
- */
- protected RequestBodyWriter requestBodyWriter;
-
- /**
- * Request body negotiation threshold for 100-continue expectations.
- */
- protected int requestBodyNegotiationThreshold;
-
- /**
- * The response body reader.
- */
- protected ResponseBodyReader responseBodyReader;
-
- /**
- * Map of response header handlers.
- */
- protected Map responseHeaderHandlers;
-
- /**
- * The authenticator.
- */
- protected Authenticator authenticator;
-
- /**
- * Whether this request has been dispatched yet.
- */
- private boolean dispatched;
-
- /**
- * Constructor for a new request.
- * @param connection the connection context
- * @param method the HTTP method
- * @param path the resource path including query part
- */
- protected Request(HTTPConnection connection, String method,
- String path)
- {
- this.connection = connection;
- this.method = method;
- this.path = path;
- requestHeaders = new Headers();
- responseHeaderHandlers = new HashMap();
- requestBodyNegotiationThreshold = 4096;
- }
-
- /**
- * Returns the connection associated with this request.
- * @see #connection
- */
- public HTTPConnection getConnection()
- {
- return connection;
- }
-
- /**
- * Returns the HTTP method to invoke.
- * @see #method
- */
- public String getMethod()
- {
- return method;
- }
-
- /**
- * Returns the resource path.
- * @see #path
- */
- public String getPath()
- {
- return path;
- }
-
- /**
- * Returns the full request-URI represented by this request, as specified
- * by HTTP/1.1.
- */
- public String getRequestURI()
- {
- return connection.getURI() + path;
- }
-
- /**
- * Returns the headers in this request.
- */
- public Headers getHeaders()
- {
- return requestHeaders;
- }
-
- /**
- * Returns the value of the specified header in this request.
- * @param name the header name
- */
- public String getHeader(String name)
- {
- return requestHeaders.getValue(name);
- }
-
- /**
- * Returns the value of the specified header in this request as an integer.
- * @param name the header name
- */
- public int getIntHeader(String name)
- {
- return requestHeaders.getIntValue(name);
- }
-
- /**
- * Returns the value of the specified header in this request as a date.
- * @param name the header name
- */
- public Date getDateHeader(String name)
- {
- return requestHeaders.getDateValue(name);
- }
-
- /**
- * Sets the specified header in this request.
- * @param name the header name
- * @param value the header value
- */
- public void setHeader(String name, String value)
- {
- requestHeaders.put(name, value);
- }
-
- /**
- * Convenience method to set the entire request body.
- * @param requestBody the request body content
- */
- public void setRequestBody(byte[] requestBody)
- {
- setRequestBodyWriter(new ByteArrayRequestBodyWriter(requestBody));
- }
-
- /**
- * Sets the request body provider.
- * @param requestBodyWriter the handler used to obtain the request body
- */
- public void setRequestBodyWriter(RequestBodyWriter requestBodyWriter)
- {
- this.requestBodyWriter = requestBodyWriter;
- }
-
- /**
- * Sets the response body reader.
- * @param responseBodyReader the handler to receive notifications of
- * response body content
- */
- public void setResponseBodyReader(ResponseBodyReader responseBodyReader)
- {
- this.responseBodyReader = responseBodyReader;
- }
-
- /**
- * Sets a callback handler to be invoked for the specified header name.
- * @param name the header name
- * @param handler the handler to receive the value for the header
- */
- public void setResponseHeaderHandler(String name,
- ResponseHeaderHandler handler)
- {
- responseHeaderHandlers.put(name, handler);
- }
-
- /**
- * Sets an authenticator that can be used to handle authentication
- * automatically.
- * @param authenticator the authenticator
- */
- public void setAuthenticator(Authenticator authenticator)
- {
- this.authenticator = authenticator;
- }
-
- /**
- * Sets the request body negotiation threshold.
- * If this is set, it determines the maximum size that the request body
- * may be before body negotiation occurs(via the
- * <code>100-continue</code> expectation). This ensures that a large
- * request body is not sent when the server wouldn't have accepted it
- * anyway.
- * @param threshold the body negotiation threshold, or &lt;=0 to disable
- * request body negotation entirely
- */
- public void setRequestBodyNegotiationThreshold(int threshold)
- {
- requestBodyNegotiationThreshold = threshold;
- }
-
- /**
- * Dispatches this request.
- * A request can only be dispatched once; calling this method a second
- * time results in a protocol exception.
- * @exception IOException if an I/O error occurred
- * @return an HTTP response object representing the result of the operation
- */
- public Response dispatch()
- throws IOException
- {
- if (dispatched)
- {
- throw new ProtocolException("request already dispatched");
- }
- final String CRLF = "\r\n";
- final String HEADER_SEP = ": ";
- final String US_ASCII = "US-ASCII";
- final String version = connection.getVersion();
- Response response;
- int contentLength = -1;
- boolean retry = false;
- int attempts = 0;
- boolean expectingContinue = false;
- if (requestBodyWriter != null)
- {
- contentLength = requestBodyWriter.getContentLength();
- if (contentLength > requestBodyNegotiationThreshold)
- {
- expectingContinue = true;
- setHeader("Expect", "100-continue");
- }
- else
- {
- setHeader("Content-Length", Integer.toString(contentLength));
- }
- }
-
- try
- {
- // Loop while authentication fails or continue
- do
- {
- retry = false;
- // Send request
- connection.fireRequestEvent(RequestEvent.REQUEST_SENDING, this);
-
- // Get socket output and input streams
- OutputStream out = connection.getOutputStream();
- LineInputStream in =
- new LineInputStream(connection.getInputStream());
- // Request line
- String requestUri = path;
- if (connection.isUsingProxy() &&
- !"*".equals(requestUri) &&
- !"CONNECT".equals(method))
- {
- requestUri = getRequestURI();
- }
- String line = method + ' ' + requestUri + ' ' + version + CRLF;
- out.write(line.getBytes(US_ASCII));
- // Request headers
- for (Iterator i = requestHeaders.keySet().iterator();
- i.hasNext(); )
- {
- String name =(String) i.next();
- String value =(String) requestHeaders.get(name);
- line = name + HEADER_SEP + value + CRLF;
- out.write(line.getBytes(US_ASCII));
- }
- out.write(CRLF.getBytes(US_ASCII));
- // Request body
- if (requestBodyWriter != null && !expectingContinue)
- {
- byte[] buffer = new byte[4096];
- int len;
- int count = 0;
-
- requestBodyWriter.reset();
- do
- {
- len = requestBodyWriter.write(buffer);
- if (len > 0)
- {
- out.write(buffer, 0, len);
- }
- count += len;
- }
- while (len > -1 && count < contentLength);
- out.write(CRLF.getBytes(US_ASCII));
- }
- out.flush();
- // Sent event
- connection.fireRequestEvent(RequestEvent.REQUEST_SENT, this);
- // Get response
- response = readResponse(in);
- int sc = response.getCode();
- if (sc == 401 && authenticator != null)
- {
- if (authenticate(response, attempts++))
- {
- retry = true;
- }
- }
- else if (sc == 100 && expectingContinue)
- {
- requestHeaders.remove("Expect");
- setHeader("Content-Length", Integer.toString(contentLength));
- expectingContinue = false;
- retry = true;
- }
- }
- while (retry);
- }
- catch (IOException e)
- {
- connection.close();
- throw e;
- }
- return response;
- }
-
- Response readResponse(LineInputStream in)
- throws IOException
- {
- String line;
- int len;
-
- // Read response status line
- line = in.readLine();
- if (line == null)
- {
- throw new ProtocolException("Peer closed connection");
- }
- if (!line.startsWith("HTTP/"))
- {
- throw new ProtocolException(line);
- }
- len = line.length();
- int start = 5, end = 6;
- while (line.charAt(end) != '.')
- {
- end++;
- }
- int majorVersion = Integer.parseInt(line.substring(start, end));
- start = end + 1;
- end = start + 1;
- while (line.charAt(end) != ' ')
- {
- end++;
- }
- int minorVersion = Integer.parseInt(line.substring(start, end));
- start = end + 1;
- end = start + 3;
- int code = Integer.parseInt(line.substring(start, end));
- String message = line.substring(end + 1, len - 1);
- // Read response headers
- Headers responseHeaders = new Headers();
- responseHeaders.parse(in);
- notifyHeaderHandlers(responseHeaders);
- // Construct response
- int codeClass = code / 100;
- Response ret = new Response(majorVersion, minorVersion, code,
- codeClass, message, responseHeaders);
- switch (code)
- {
- case 204:
- case 205:
- break;
- default:
- // Does response body reader want body?
- boolean notify = (responseBodyReader != null);
- if (notify)
- {
- if (!responseBodyReader.accept(this, ret))
- {
- notify = false;
- }
- }
- readResponseBody(ret, in, notify);
- }
- return ret;
- }
-
- void notifyHeaderHandlers(Headers headers)
- {
- for (Iterator i = headers.entrySet().iterator(); i.hasNext(); )
- {
- Map.Entry entry = (Map.Entry) i.next();
- String name =(String) entry.getKey();
- // Handle Set-Cookie
- if ("Set-Cookie".equalsIgnoreCase(name))
- {
- String value = (String) entry.getValue();
- handleSetCookie(value);
- }
- ResponseHeaderHandler handler =
- (ResponseHeaderHandler) responseHeaderHandlers.get(name);
- if (handler != null)
- {
- String value = (String) entry.getValue();
- handler.setValue(value);
- }
- }
- }
-
- void readResponseBody(Response response, InputStream in,
- boolean notify)
- throws IOException
- {
- byte[] buffer = new byte[4096];
- int contentLength = -1;
- Headers trailer = null;
-
- String transferCoding = response.getHeader("Transfer-Encoding");
- if ("chunked".equalsIgnoreCase(transferCoding))
- {
- trailer = new Headers();
- in = new ChunkedInputStream(in, trailer);
- }
- else
- {
- contentLength = response.getIntHeader("Content-Length");
- }
- String contentCoding = response.getHeader("Content-Encoding");
- if (contentCoding != null && !"identity".equals(contentCoding))
- {
- if ("gzip".equals(contentCoding))
- {
- in = new GZIPInputStream(in);
- }
- else if ("deflate".equals(contentCoding))
- {
- in = new InflaterInputStream(in);
- }
- else
- {
- throw new ProtocolException("Unsupported Content-Encoding: " +
- contentCoding);
- }
- }
-
- // Persistent connections are the default in HTTP/1.1
- boolean doClose = "close".equalsIgnoreCase(getHeader("Connection")) ||
- "close".equalsIgnoreCase(response.getHeader("Connection")) ||
- (connection.majorVersion == 1 && connection.minorVersion == 0) ||
- (response.majorVersion == 1 && response.minorVersion == 0);
-
- int count = contentLength;
- int len = (count > -1) ? count : buffer.length;
- len = (len > buffer.length) ? buffer.length : len;
- while (len > -1)
- {
- len = in.read(buffer, 0, len);
- if (len < 0)
- {
- // EOF
- connection.closeConnection();
- break;
- }
- if (notify)
- {
- responseBodyReader.read(buffer, 0, len);
- }
- if (count > -1)
- {
- count -= len;
- if (count < 1)
- {
- if (doClose)
- {
- connection.closeConnection();
- }
- break;
- }
- }
- }
- if (notify)
- {
- responseBodyReader.close();
- }
- if (trailer != null)
- {
- response.getHeaders().putAll(trailer);
- notifyHeaderHandlers(trailer);
- }
- }
-
- boolean authenticate(Response response, int attempts)
- throws IOException
- {
- String challenge = response.getHeader("WWW-Authenticate");
- if (challenge == null)
- {
- challenge = response.getHeader("Proxy-Authenticate");
- }
- int si = challenge.indexOf(' ');
- String scheme = (si == -1) ? challenge : challenge.substring(0, si);
- if ("Basic".equalsIgnoreCase(scheme))
- {
- Properties params = parseAuthParams(challenge.substring(si + 1));
- String realm = params.getProperty("realm");
- Credentials creds = authenticator.getCredentials(realm, attempts);
- String userPass = creds.getUsername() + ':' + creds.getPassword();
- byte[] b_userPass = userPass.getBytes("US-ASCII");
- byte[] b_encoded = BASE64.encode(b_userPass);
- String authorization =
- scheme + " " + new String(b_encoded, "US-ASCII");
- setHeader("Authorization", authorization);
- return true;
- }
- else if ("Digest".equalsIgnoreCase(scheme))
- {
- Properties params = parseAuthParams(challenge.substring(si + 1));
- String realm = params.getProperty("realm");
- String nonce = params.getProperty("nonce");
- String qop = params.getProperty("qop");
- String algorithm = params.getProperty("algorithm");
- String digestUri = getRequestURI();
- Credentials creds = authenticator.getCredentials(realm, attempts);
- String username = creds.getUsername();
- String password = creds.getPassword();
- connection.incrementNonce(nonce);
- try
- {
- MessageDigest md5 = MessageDigest.getInstance("MD5");
- final byte[] COLON = { 0x3a };
-
- // Calculate H(A1)
- md5.reset();
- md5.update(username.getBytes("US-ASCII"));
- md5.update(COLON);
- md5.update(realm.getBytes("US-ASCII"));
- md5.update(COLON);
- md5.update(password.getBytes("US-ASCII"));
- byte[] ha1 = md5.digest();
- if ("md5-sess".equals(algorithm))
- {
- byte[] cnonce = generateNonce();
- md5.reset();
- md5.update(ha1);
- md5.update(COLON);
- md5.update(nonce.getBytes("US-ASCII"));
- md5.update(COLON);
- md5.update(cnonce);
- ha1 = md5.digest();
- }
- String ha1Hex = toHexString(ha1);
-
- // Calculate H(A2)
- md5.reset();
- md5.update(method.getBytes("US-ASCII"));
- md5.update(COLON);
- md5.update(digestUri.getBytes("US-ASCII"));
- if ("auth-int".equals(qop))
- {
- byte[] hEntity = null; // TODO hash of entity body
- md5.update(COLON);
- md5.update(hEntity);
- }
- byte[] ha2 = md5.digest();
- String ha2Hex = toHexString(ha2);
-
- // Calculate response
- md5.reset();
- md5.update(ha1Hex.getBytes("US-ASCII"));
- md5.update(COLON);
- md5.update(nonce.getBytes("US-ASCII"));
- if ("auth".equals(qop) || "auth-int".equals(qop))
- {
- String nc = getNonceCount(nonce);
- byte[] cnonce = generateNonce();
- md5.update(COLON);
- md5.update(nc.getBytes("US-ASCII"));
- md5.update(COLON);
- md5.update(cnonce);
- md5.update(COLON);
- md5.update(qop.getBytes("US-ASCII"));
- }
- md5.update(COLON);
- md5.update(ha2Hex.getBytes("US-ASCII"));
- String digestResponse = toHexString(md5.digest());
-
- String authorization = scheme +
- " username=\"" + username + "\"" +
- " realm=\"" + realm + "\"" +
- " nonce=\"" + nonce + "\"" +
- " uri=\"" + digestUri + "\"" +
- " response=\"" + digestResponse + "\"";
- setHeader("Authorization", authorization);
- return true;
- }
- catch (NoSuchAlgorithmException e)
- {
- return false;
- }
- }
- // Scheme not recognised
- return false;
- }
-
- Properties parseAuthParams(String text)
- {
- int len = text.length();
- String key = null;
- StringBuffer buf = new StringBuffer();
- Properties ret = new Properties();
- boolean inQuote = false;
- for (int i = 0; i < len; i++)
- {
- char c = text.charAt(i);
- if (c == '"')
- {
- inQuote = !inQuote;
- }
- else if (c == '=' && key == null)
- {
- key = buf.toString().trim();
- buf.setLength(0);
- }
- else if (c == ' ' && !inQuote)
- {
- String value = unquote(buf.toString().trim());
- ret.put(key, value);
- key = null;
- buf.setLength(0);
- }
- else if (c != ',' || (i <(len - 1) && text.charAt(i + 1) != ' '))
- {
- buf.append(c);
- }
- }
- if (key != null)
- {
- String value = unquote(buf.toString().trim());
- ret.put(key, value);
- }
- return ret;
- }
-
- String unquote(String text)
- {
- int len = text.length();
- if (len > 0 && text.charAt(0) == '"' && text.charAt(len - 1) == '"')
- {
- return text.substring(1, len - 1);
- }
- return text;
- }
-
- /**
- * Returns the number of times the specified nonce value has been seen.
- * This always returns an 8-byte 0-padded hexadecimal string.
- */
- String getNonceCount(String nonce)
- {
- int nc = connection.getNonceCount(nonce);
- String hex = Integer.toHexString(nc);
- StringBuffer buf = new StringBuffer();
- for (int i = 8 - hex.length(); i > 0; i--)
- {
- buf.append('0');
- }
- buf.append(hex);
- return buf.toString();
- }
-
- /**
- * Client nonce value.
- */
- byte[] nonce;
-
- /**
- * Generates a new client nonce value.
- */
- byte[] generateNonce()
- throws IOException, NoSuchAlgorithmException
- {
- if (nonce == null)
- {
- long time = System.currentTimeMillis();
- MessageDigest md5 = MessageDigest.getInstance("MD5");
- md5.update(Long.toString(time).getBytes("US-ASCII"));
- nonce = md5.digest();
- }
- return nonce;
- }
-
- String toHexString(byte[] bytes)
- {
- char[] ret = new char[bytes.length * 2];
- for (int i = 0, j = 0; i < bytes.length; i++)
- {
- int c =(int) bytes[i];
- if (c < 0)
- {
- c += 0x100;
- }
- ret[j++] = Character.forDigit(c / 0x10, 0x10);
- ret[j++] = Character.forDigit(c % 0x10, 0x10);
- }
- return new String(ret);
- }
-
- /**
- * Parse the specified cookie list and notify the cookie manager.
- */
- void handleSetCookie(String text)
- {
- CookieManager cookieManager = connection.getCookieManager();
- if (cookieManager == null)
- {
- return;
- }
- String name = null;
- String value = null;
- String comment = null;
- String domain = connection.getHostName();
- String path = this.path;
- int lsi = path.lastIndexOf('/');
- if (lsi != -1)
- {
- path = path.substring(0, lsi);
- }
- boolean secure = false;
- Date expires = null;
-
- int len = text.length();
- String attr = null;
- StringBuffer buf = new StringBuffer();
- boolean inQuote = false;
- for (int i = 0; i <= len; i++)
- {
- char c =(i == len) ? '\u0000' : text.charAt(i);
- if (c == '"')
- {
- inQuote = !inQuote;
- }
- else if (!inQuote)
- {
- if (c == '=' && attr == null)
- {
- attr = buf.toString().trim();
- buf.setLength(0);
- }
- else if (c == ';' || i == len || c == ',')
- {
- String val = unquote(buf.toString().trim());
- if (name == null)
- {
- name = attr;
- value = val;
- }
- else if ("Comment".equalsIgnoreCase(attr))
- {
- comment = val;
- }
- else if ("Domain".equalsIgnoreCase(attr))
- {
- domain = val;
- }
- else if ("Path".equalsIgnoreCase(attr))
- {
- path = val;
- }
- else if ("Secure".equalsIgnoreCase(val))
- {
- secure = true;
- }
- else if ("Max-Age".equalsIgnoreCase(attr))
- {
- int delta = Integer.parseInt(val);
- Calendar cal = Calendar.getInstance();
- cal.setTimeInMillis(System.currentTimeMillis());
- cal.add(Calendar.SECOND, delta);
- expires = cal.getTime();
- }
- else if ("Expires".equalsIgnoreCase(attr))
- {
- DateFormat dateFormat = new HTTPDateFormat();
- try
- {
- expires = dateFormat.parse(val);
- }
- catch (ParseException e)
- {
- // if this isn't a valid date, it may be that
- // the value was returned unquoted; in that case, we
- // want to continue buffering the value
- buf.append(c);
- continue;
- }
- }
- attr = null;
- buf.setLength(0);
- // case EOL
- if (i == len || c == ',')
- {
- Cookie cookie = new Cookie(name, value, comment, domain,
- path, secure, expires);
- cookieManager.setCookie(cookie);
- }
- if (c == ',')
- {
- // Reset cookie fields
- name = null;
- value = null;
- comment = null;
- domain = connection.getHostName();
- path = this.path;
- if (lsi != -1)
- {
- path = path.substring(0, lsi);
- }
- secure = false;
- expires = null;
- }
- }
- else
- {
- buf.append(c);
- }
- }
- else
- {
- buf.append(c);
- }
- }
- }
-
-}
-
OpenPOWER on IntegriCloud