You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cordova.apache.org by fi...@apache.org on 2013/06/13 20:22:05 UTC
[42/78] [partial] start of lazy loading: axe all vendored-in libs
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/67fa7ebb/lib/cordova-android/framework/src/com/squareup/okhttp/internal/http/AbstractHttpInputStream.java
----------------------------------------------------------------------
diff --git a/lib/cordova-android/framework/src/com/squareup/okhttp/internal/http/AbstractHttpInputStream.java b/lib/cordova-android/framework/src/com/squareup/okhttp/internal/http/AbstractHttpInputStream.java
deleted file mode 100644
index 187f3b6..0000000
--- a/lib/cordova-android/framework/src/com/squareup/okhttp/internal/http/AbstractHttpInputStream.java
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.squareup.okhttp.internal.http;
-
-import com.squareup.okhttp.internal.Util;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.net.CacheRequest;
-
-/**
- * An input stream for the body of an HTTP response.
- *
- * <p>Since a single socket's input stream may be used to read multiple HTTP
- * responses from the same server, subclasses shouldn't close the socket stream.
- *
- * <p>A side effect of reading an HTTP response is that the response cache
- * is populated. If the stream is closed early, that cache entry will be
- * invalidated.
- */
-abstract class AbstractHttpInputStream extends InputStream {
- protected final InputStream in;
- protected final HttpEngine httpEngine;
- private final CacheRequest cacheRequest;
- private final OutputStream cacheBody;
- protected boolean closed;
-
- AbstractHttpInputStream(InputStream in, HttpEngine httpEngine, CacheRequest cacheRequest)
- throws IOException {
- this.in = in;
- this.httpEngine = httpEngine;
-
- OutputStream cacheBody = cacheRequest != null ? cacheRequest.getBody() : null;
-
- // some apps return a null body; for compatibility we treat that like a null cache request
- if (cacheBody == null) {
- cacheRequest = null;
- }
-
- this.cacheBody = cacheBody;
- this.cacheRequest = cacheRequest;
- }
-
- /**
- * read() is implemented using read(byte[], int, int) so subclasses only
- * need to override the latter.
- */
- @Override public final int read() throws IOException {
- return Util.readSingleByte(this);
- }
-
- protected final void checkNotClosed() throws IOException {
- if (closed) {
- throw new IOException("stream closed");
- }
- }
-
- protected final void cacheWrite(byte[] buffer, int offset, int count) throws IOException {
- if (cacheBody != null) {
- cacheBody.write(buffer, offset, count);
- }
- }
-
- /**
- * Closes the cache entry and makes the socket available for reuse. This
- * should be invoked when the end of the body has been reached.
- */
- protected final void endOfInput(boolean streamCancelled) throws IOException {
- if (cacheRequest != null) {
- cacheBody.close();
- }
- httpEngine.release(streamCancelled);
- }
-
- /**
- * Calls abort on the cache entry and disconnects the socket. This
- * should be invoked when the connection is closed unexpectedly to
- * invalidate the cache entry and to prevent the HTTP connection from
- * being reused. HTTP messages are sent in serial so whenever a message
- * cannot be read to completion, subsequent messages cannot be read
- * either and the connection must be discarded.
- *
- * <p>An earlier implementation skipped the remaining bytes, but this
- * requires that the entire transfer be completed. If the intention was
- * to cancel the transfer, closing the connection is the only solution.
- */
- protected final void unexpectedEndOfInput() {
- if (cacheRequest != null) {
- cacheRequest.abort();
- }
- httpEngine.release(true);
- }
-}
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/67fa7ebb/lib/cordova-android/framework/src/com/squareup/okhttp/internal/http/AbstractHttpOutputStream.java
----------------------------------------------------------------------
diff --git a/lib/cordova-android/framework/src/com/squareup/okhttp/internal/http/AbstractHttpOutputStream.java b/lib/cordova-android/framework/src/com/squareup/okhttp/internal/http/AbstractHttpOutputStream.java
deleted file mode 100644
index 90675b0..0000000
--- a/lib/cordova-android/framework/src/com/squareup/okhttp/internal/http/AbstractHttpOutputStream.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.squareup.okhttp.internal.http;
-
-import java.io.IOException;
-import java.io.OutputStream;
-
-/**
- * An output stream for the body of an HTTP request.
- *
- * <p>Since a single socket's output stream may be used to write multiple HTTP
- * requests to the same server, subclasses should not close the socket stream.
- */
-abstract class AbstractHttpOutputStream extends OutputStream {
- protected boolean closed;
-
- @Override public final void write(int data) throws IOException {
- write(new byte[] { (byte) data });
- }
-
- protected final void checkNotClosed() throws IOException {
- if (closed) {
- throw new IOException("stream closed");
- }
- }
-}
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/67fa7ebb/lib/cordova-android/framework/src/com/squareup/okhttp/internal/http/HeaderParser.java
----------------------------------------------------------------------
diff --git a/lib/cordova-android/framework/src/com/squareup/okhttp/internal/http/HeaderParser.java b/lib/cordova-android/framework/src/com/squareup/okhttp/internal/http/HeaderParser.java
deleted file mode 100644
index 12e6409..0000000
--- a/lib/cordova-android/framework/src/com/squareup/okhttp/internal/http/HeaderParser.java
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.squareup.okhttp.internal.http;
-
-final class HeaderParser {
-
- public interface CacheControlHandler {
- void handle(String directive, String parameter);
- }
-
- /** Parse a comma-separated list of cache control header values. */
- public static void parseCacheControl(String value, CacheControlHandler handler) {
- int pos = 0;
- while (pos < value.length()) {
- int tokenStart = pos;
- pos = skipUntil(value, pos, "=,");
- String directive = value.substring(tokenStart, pos).trim();
-
- if (pos == value.length() || value.charAt(pos) == ',') {
- pos++; // consume ',' (if necessary)
- handler.handle(directive, null);
- continue;
- }
-
- pos++; // consume '='
- pos = skipWhitespace(value, pos);
-
- String parameter;
-
- // quoted string
- if (pos < value.length() && value.charAt(pos) == '\"') {
- pos++; // consume '"' open quote
- int parameterStart = pos;
- pos = skipUntil(value, pos, "\"");
- parameter = value.substring(parameterStart, pos);
- pos++; // consume '"' close quote (if necessary)
-
- // unquoted string
- } else {
- int parameterStart = pos;
- pos = skipUntil(value, pos, ",");
- parameter = value.substring(parameterStart, pos).trim();
- }
-
- handler.handle(directive, parameter);
- }
- }
-
- /**
- * Returns the next index in {@code input} at or after {@code pos} that
- * contains a character from {@code characters}. Returns the input length if
- * none of the requested characters can be found.
- */
- public static int skipUntil(String input, int pos, String characters) {
- for (; pos < input.length(); pos++) {
- if (characters.indexOf(input.charAt(pos)) != -1) {
- break;
- }
- }
- return pos;
- }
-
- /**
- * Returns the next non-whitespace character in {@code input} that is white
- * space. Result is undefined if input contains newline characters.
- */
- public static int skipWhitespace(String input, int pos) {
- for (; pos < input.length(); pos++) {
- char c = input.charAt(pos);
- if (c != ' ' && c != '\t') {
- break;
- }
- }
- return pos;
- }
-
- /**
- * Returns {@code value} as a positive integer, or 0 if it is negative, or
- * -1 if it cannot be parsed.
- */
- public static int parseSeconds(String value) {
- try {
- long seconds = Long.parseLong(value);
- if (seconds > Integer.MAX_VALUE) {
- return Integer.MAX_VALUE;
- } else if (seconds < 0) {
- return 0;
- } else {
- return (int) seconds;
- }
- } catch (NumberFormatException e) {
- return -1;
- }
- }
-
- private HeaderParser() {
- }
-}
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/67fa7ebb/lib/cordova-android/framework/src/com/squareup/okhttp/internal/http/HttpAuthenticator.java
----------------------------------------------------------------------
diff --git a/lib/cordova-android/framework/src/com/squareup/okhttp/internal/http/HttpAuthenticator.java b/lib/cordova-android/framework/src/com/squareup/okhttp/internal/http/HttpAuthenticator.java
deleted file mode 100644
index 4ccd12a..0000000
--- a/lib/cordova-android/framework/src/com/squareup/okhttp/internal/http/HttpAuthenticator.java
+++ /dev/null
@@ -1,175 +0,0 @@
-/*
- * Copyright (C) 2012 Square, Inc.
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.squareup.okhttp.internal.http;
-
-import com.squareup.okhttp.internal.Base64;
-import java.io.IOException;
-import java.net.Authenticator;
-import java.net.InetAddress;
-import java.net.InetSocketAddress;
-import java.net.PasswordAuthentication;
-import java.net.Proxy;
-import java.net.URL;
-import java.util.ArrayList;
-import java.util.List;
-
-import static java.net.HttpURLConnection.HTTP_PROXY_AUTH;
-import static java.net.HttpURLConnection.HTTP_UNAUTHORIZED;
-
-/** Handles HTTP authentication headers from origin and proxy servers. */
-public final class HttpAuthenticator {
- private HttpAuthenticator() {
- }
-
- /**
- * React to a failed authorization response by looking up new credentials.
- *
- * @return true if credentials have been added to successorRequestHeaders
- * and another request should be attempted.
- */
- public static boolean processAuthHeader(int responseCode, RawHeaders responseHeaders,
- RawHeaders successorRequestHeaders, Proxy proxy, URL url) throws IOException {
- if (responseCode != HTTP_PROXY_AUTH && responseCode != HTTP_UNAUTHORIZED) {
- throw new IllegalArgumentException();
- }
-
- // Keep asking for username/password until authorized.
- String challengeHeader =
- responseCode == HTTP_PROXY_AUTH ? "Proxy-Authenticate" : "WWW-Authenticate";
- String credentials = getCredentials(responseHeaders, challengeHeader, proxy, url);
- if (credentials == null) {
- return false; // Could not find credentials so end the request cycle.
- }
-
- // Add authorization credentials, bypassing the already-connected check.
- String fieldName = responseCode == HTTP_PROXY_AUTH ? "Proxy-Authorization" : "Authorization";
- successorRequestHeaders.set(fieldName, credentials);
- return true;
- }
-
- /**
- * Returns the authorization credentials that may satisfy the challenge.
- * Returns null if a challenge header was not provided or if credentials
- * were not available.
- */
- private static String getCredentials(RawHeaders responseHeaders, String challengeHeader,
- Proxy proxy, URL url) throws IOException {
- List<Challenge> challenges = parseChallenges(responseHeaders, challengeHeader);
- if (challenges.isEmpty()) {
- return null;
- }
-
- for (Challenge challenge : challenges) {
- // Use the global authenticator to get the password.
- PasswordAuthentication auth;
- if (responseHeaders.getResponseCode() == HTTP_PROXY_AUTH) {
- InetSocketAddress proxyAddress = (InetSocketAddress) proxy.address();
- auth = Authenticator.requestPasswordAuthentication(proxyAddress.getHostName(),
- getConnectToInetAddress(proxy, url), proxyAddress.getPort(), url.getProtocol(),
- challenge.realm, challenge.scheme, url, Authenticator.RequestorType.PROXY);
- } else {
- auth = Authenticator.requestPasswordAuthentication(url.getHost(),
- getConnectToInetAddress(proxy, url), url.getPort(), url.getProtocol(), challenge.realm,
- challenge.scheme, url, Authenticator.RequestorType.SERVER);
- }
- if (auth == null) {
- continue;
- }
-
- // Use base64 to encode the username and password.
- String usernameAndPassword = auth.getUserName() + ":" + new String(auth.getPassword());
- byte[] bytes = usernameAndPassword.getBytes("ISO-8859-1");
- String encoded = Base64.encode(bytes);
- return challenge.scheme + " " + encoded;
- }
-
- return null;
- }
-
- private static InetAddress getConnectToInetAddress(Proxy proxy, URL url) throws IOException {
- return (proxy != null && proxy.type() != Proxy.Type.DIRECT)
- ? ((InetSocketAddress) proxy.address()).getAddress() : InetAddress.getByName(url.getHost());
- }
-
- /**
- * Parse RFC 2617 challenges. This API is only interested in the scheme
- * name and realm.
- */
- private static List<Challenge> parseChallenges(RawHeaders responseHeaders,
- String challengeHeader) {
- // auth-scheme = token
- // auth-param = token "=" ( token | quoted-string )
- // challenge = auth-scheme 1*SP 1#auth-param
- // realm = "realm" "=" realm-value
- // realm-value = quoted-string
- List<Challenge> result = new ArrayList<Challenge>();
- for (int h = 0; h < responseHeaders.length(); h++) {
- if (!challengeHeader.equalsIgnoreCase(responseHeaders.getFieldName(h))) {
- continue;
- }
- String value = responseHeaders.getValue(h);
- int pos = 0;
- while (pos < value.length()) {
- int tokenStart = pos;
- pos = HeaderParser.skipUntil(value, pos, " ");
-
- String scheme = value.substring(tokenStart, pos).trim();
- pos = HeaderParser.skipWhitespace(value, pos);
-
- // TODO: This currently only handles schemes with a 'realm' parameter;
- // It needs to be fixed to handle any scheme and any parameters
- // http://code.google.com/p/android/issues/detail?id=11140
-
- if (!value.regionMatches(pos, "realm=\"", 0, "realm=\"".length())) {
- break; // Unexpected challenge parameter; give up!
- }
-
- pos += "realm=\"".length();
- int realmStart = pos;
- pos = HeaderParser.skipUntil(value, pos, "\"");
- String realm = value.substring(realmStart, pos);
- pos++; // Consume '"' close quote.
- pos = HeaderParser.skipUntil(value, pos, ",");
- pos++; // Consume ',' comma.
- pos = HeaderParser.skipWhitespace(value, pos);
- result.add(new Challenge(scheme, realm));
- }
- }
- return result;
- }
-
- /** An RFC 2617 challenge. */
- private static final class Challenge {
- final String scheme;
- final String realm;
-
- Challenge(String scheme, String realm) {
- this.scheme = scheme;
- this.realm = realm;
- }
-
- @Override public boolean equals(Object o) {
- return o instanceof Challenge
- && ((Challenge) o).scheme.equals(scheme)
- && ((Challenge) o).realm.equals(realm);
- }
-
- @Override public int hashCode() {
- return scheme.hashCode() + 31 * realm.hashCode();
- }
- }
-}
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/67fa7ebb/lib/cordova-android/framework/src/com/squareup/okhttp/internal/http/HttpDate.java
----------------------------------------------------------------------
diff --git a/lib/cordova-android/framework/src/com/squareup/okhttp/internal/http/HttpDate.java b/lib/cordova-android/framework/src/com/squareup/okhttp/internal/http/HttpDate.java
deleted file mode 100644
index acb5fda..0000000
--- a/lib/cordova-android/framework/src/com/squareup/okhttp/internal/http/HttpDate.java
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.squareup.okhttp.internal.http;
-
-import java.text.DateFormat;
-import java.text.ParseException;
-import java.text.SimpleDateFormat;
-import java.util.Date;
-import java.util.Locale;
-import java.util.TimeZone;
-
-/**
- * Best-effort parser for HTTP dates.
- */
-final class HttpDate {
-
- /**
- * Most websites serve cookies in the blessed format. Eagerly create the parser to ensure such
- * cookies are on the fast path.
- */
- private static final ThreadLocal<DateFormat> STANDARD_DATE_FORMAT =
- new ThreadLocal<DateFormat>() {
- @Override protected DateFormat initialValue() {
- DateFormat rfc1123 = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz", Locale.US);
- rfc1123.setTimeZone(TimeZone.getTimeZone("UTC"));
- return rfc1123;
- }
- };
-
- /** If we fail to parse a date in a non-standard format, try each of these formats in sequence. */
- private static final String[] BROWSER_COMPATIBLE_DATE_FORMATS = new String[] {
- /* This list comes from {@code org.apache.http.impl.cookie.BrowserCompatSpec}. */
- "EEEE, dd-MMM-yy HH:mm:ss zzz", // RFC 1036
- "EEE MMM d HH:mm:ss yyyy", // ANSI C asctime()
- "EEE, dd-MMM-yyyy HH:mm:ss z", "EEE, dd-MMM-yyyy HH-mm-ss z", "EEE, dd MMM yy HH:mm:ss z",
- "EEE dd-MMM-yyyy HH:mm:ss z", "EEE dd MMM yyyy HH:mm:ss z", "EEE dd-MMM-yyyy HH-mm-ss z",
- "EEE dd-MMM-yy HH:mm:ss z", "EEE dd MMM yy HH:mm:ss z", "EEE,dd-MMM-yy HH:mm:ss z",
- "EEE,dd-MMM-yyyy HH:mm:ss z", "EEE, dd-MM-yyyy HH:mm:ss z",
-
- /* RI bug 6641315 claims a cookie of this format was once served by www.yahoo.com */
- "EEE MMM d yyyy HH:mm:ss z", };
-
- /**
- * Returns the date for {@code value}. Returns null if the value couldn't be
- * parsed.
- */
- public static Date parse(String value) {
- try {
- return STANDARD_DATE_FORMAT.get().parse(value);
- } catch (ParseException ignore) {
- }
- for (String formatString : BROWSER_COMPATIBLE_DATE_FORMATS) {
- try {
- return new SimpleDateFormat(formatString, Locale.US).parse(value);
- } catch (ParseException ignore) {
- }
- }
- return null;
- }
-
- /** Returns the string for {@code value}. */
- public static String format(Date value) {
- return STANDARD_DATE_FORMAT.get().format(value);
- }
-
- private HttpDate() {
- }
-}
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/67fa7ebb/lib/cordova-android/framework/src/com/squareup/okhttp/internal/http/HttpEngine.java
----------------------------------------------------------------------
diff --git a/lib/cordova-android/framework/src/com/squareup/okhttp/internal/http/HttpEngine.java b/lib/cordova-android/framework/src/com/squareup/okhttp/internal/http/HttpEngine.java
deleted file mode 100644
index 7a06dca..0000000
--- a/lib/cordova-android/framework/src/com/squareup/okhttp/internal/http/HttpEngine.java
+++ /dev/null
@@ -1,664 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.squareup.okhttp.internal.http;
-
-import com.squareup.okhttp.Address;
-import com.squareup.okhttp.Connection;
-import com.squareup.okhttp.ResponseSource;
-import com.squareup.okhttp.TunnelRequest;
-import com.squareup.okhttp.internal.Dns;
-import com.squareup.okhttp.internal.Platform;
-import com.squareup.okhttp.internal.Util;
-import java.io.ByteArrayInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.net.CacheRequest;
-import java.net.CacheResponse;
-import java.net.CookieHandler;
-import java.net.Proxy;
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.net.URL;
-import java.net.UnknownHostException;
-import java.util.Collections;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.zip.GZIPInputStream;
-import javax.net.ssl.HostnameVerifier;
-import javax.net.ssl.SSLSocketFactory;
-
-import static com.squareup.okhttp.internal.Util.EMPTY_BYTE_ARRAY;
-import static com.squareup.okhttp.internal.Util.getDefaultPort;
-import static com.squareup.okhttp.internal.Util.getEffectivePort;
-
-/**
- * Handles a single HTTP request/response pair. Each HTTP engine follows this
- * lifecycle:
- * <ol>
- * <li>It is created.
- * <li>The HTTP request message is sent with sendRequest(). Once the request
- * is sent it is an error to modify the request headers. After
- * sendRequest() has been called the request body can be written to if
- * it exists.
- * <li>The HTTP response message is read with readResponse(). After the
- * response has been read the response headers and body can be read.
- * All responses have a response body input stream, though in some
- * instances this stream is empty.
- * </ol>
- *
- * <p>The request and response may be served by the HTTP response cache, by the
- * network, or by both in the event of a conditional GET.
- *
- * <p>This class may hold a socket connection that needs to be released or
- * recycled. By default, this socket connection is held when the last byte of
- * the response is consumed. To release the connection when it is no longer
- * required, use {@link #automaticallyReleaseConnectionToPool()}.
- */
-public class HttpEngine {
- private static final CacheResponse GATEWAY_TIMEOUT_RESPONSE = new CacheResponse() {
- @Override public Map<String, List<String>> getHeaders() throws IOException {
- Map<String, List<String>> result = new HashMap<String, List<String>>();
- result.put(null, Collections.singletonList("HTTP/1.1 504 Gateway Timeout"));
- return result;
- }
- @Override public InputStream getBody() throws IOException {
- return new ByteArrayInputStream(EMPTY_BYTE_ARRAY);
- }
- };
- public static final int HTTP_CONTINUE = 100;
-
- protected final HttpURLConnectionImpl policy;
-
- protected final String method;
-
- private ResponseSource responseSource;
-
- protected Connection connection;
- protected RouteSelector routeSelector;
- private OutputStream requestBodyOut;
-
- private Transport transport;
-
- private InputStream responseTransferIn;
- private InputStream responseBodyIn;
-
- private CacheResponse cacheResponse;
- private CacheRequest cacheRequest;
-
- /** The time when the request headers were written, or -1 if they haven't been written yet. */
- long sentRequestMillis = -1;
-
- /**
- * True if this client added an "Accept-Encoding: gzip" header field and is
- * therefore responsible for also decompressing the transfer stream.
- */
- private boolean transparentGzip;
-
- final URI uri;
-
- final RequestHeaders requestHeaders;
-
- /** Null until a response is received from the network or the cache. */
- ResponseHeaders responseHeaders;
-
- // The cache response currently being validated on a conditional get. Null
- // if the cached response doesn't exist or doesn't need validation. If the
- // conditional get succeeds, these will be used for the response headers and
- // body. If it fails, these be closed and set to null.
- private ResponseHeaders cachedResponseHeaders;
- private InputStream cachedResponseBody;
-
- /**
- * True if the socket connection should be released to the connection pool
- * when the response has been fully read.
- */
- private boolean automaticallyReleaseConnectionToPool;
-
- /** True if the socket connection is no longer needed by this engine. */
- private boolean connectionReleased;
-
- /**
- * @param requestHeaders the client's supplied request headers. This class
- * creates a private copy that it can mutate.
- * @param connection the connection used for an intermediate response
- * immediately prior to this request/response pair, such as a same-host
- * redirect. This engine assumes ownership of the connection and must
- * release it when it is unneeded.
- */
- public HttpEngine(HttpURLConnectionImpl policy, String method, RawHeaders requestHeaders,
- Connection connection, RetryableOutputStream requestBodyOut) throws IOException {
- this.policy = policy;
- this.method = method;
- this.connection = connection;
- this.requestBodyOut = requestBodyOut;
-
- try {
- uri = Platform.get().toUriLenient(policy.getURL());
- } catch (URISyntaxException e) {
- throw new IOException(e.getMessage());
- }
-
- this.requestHeaders = new RequestHeaders(uri, new RawHeaders(requestHeaders));
- }
-
- public URI getUri() {
- return uri;
- }
-
- /**
- * Figures out what the response source will be, and opens a socket to that
- * source if necessary. Prepares the request headers and gets ready to start
- * writing the request body if it exists.
- */
- public final void sendRequest() throws IOException {
- if (responseSource != null) {
- return;
- }
-
- prepareRawRequestHeaders();
- initResponseSource();
- if (policy.responseCache != null) {
- policy.responseCache.trackResponse(responseSource);
- }
-
- // The raw response source may require the network, but the request
- // headers may forbid network use. In that case, dispose of the network
- // response and use a GATEWAY_TIMEOUT response instead, as specified
- // by http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9.4.
- if (requestHeaders.isOnlyIfCached() && responseSource.requiresConnection()) {
- if (responseSource == ResponseSource.CONDITIONAL_CACHE) {
- Util.closeQuietly(cachedResponseBody);
- }
- this.responseSource = ResponseSource.CACHE;
- this.cacheResponse = GATEWAY_TIMEOUT_RESPONSE;
- RawHeaders rawResponseHeaders = RawHeaders.fromMultimap(cacheResponse.getHeaders(), true);
- setResponse(new ResponseHeaders(uri, rawResponseHeaders), cacheResponse.getBody());
- }
-
- if (responseSource.requiresConnection()) {
- sendSocketRequest();
- } else if (connection != null) {
- policy.connectionPool.recycle(connection);
- policy.getFailedRoutes().remove(connection.getRoute());
- connection = null;
- }
- }
-
- /**
- * Initialize the source for this response. It may be corrected later if the
- * request headers forbids network use.
- */
- private void initResponseSource() throws IOException {
- responseSource = ResponseSource.NETWORK;
- if (!policy.getUseCaches() || policy.responseCache == null) {
- return;
- }
-
- CacheResponse candidate =
- policy.responseCache.get(uri, method, requestHeaders.getHeaders().toMultimap(false));
- if (candidate == null) {
- return;
- }
-
- Map<String, List<String>> responseHeadersMap = candidate.getHeaders();
- cachedResponseBody = candidate.getBody();
- if (!acceptCacheResponseType(candidate)
- || responseHeadersMap == null
- || cachedResponseBody == null) {
- Util.closeQuietly(cachedResponseBody);
- return;
- }
-
- RawHeaders rawResponseHeaders = RawHeaders.fromMultimap(responseHeadersMap, true);
- cachedResponseHeaders = new ResponseHeaders(uri, rawResponseHeaders);
- long now = System.currentTimeMillis();
- this.responseSource = cachedResponseHeaders.chooseResponseSource(now, requestHeaders);
- if (responseSource == ResponseSource.CACHE) {
- this.cacheResponse = candidate;
- setResponse(cachedResponseHeaders, cachedResponseBody);
- } else if (responseSource == ResponseSource.CONDITIONAL_CACHE) {
- this.cacheResponse = candidate;
- } else if (responseSource == ResponseSource.NETWORK) {
- Util.closeQuietly(cachedResponseBody);
- } else {
- throw new AssertionError();
- }
- }
-
- private void sendSocketRequest() throws IOException {
- if (connection == null) {
- connect();
- }
-
- if (transport != null) {
- throw new IllegalStateException();
- }
-
- transport = (Transport) connection.newTransport(this);
-
- if (hasRequestBody() && requestBodyOut == null) {
- // Create a request body if we don't have one already. We'll already
- // have one if we're retrying a failed POST.
- requestBodyOut = transport.createRequestBody();
- }
- }
-
- /** Connect to the origin server either directly or via a proxy. */
- protected final void connect() throws IOException {
- if (connection != null) {
- return;
- }
- if (routeSelector == null) {
- String uriHost = uri.getHost();
- if (uriHost == null) {
- throw new UnknownHostException(uri.toString());
- }
- SSLSocketFactory sslSocketFactory = null;
- HostnameVerifier hostnameVerifier = null;
- if (uri.getScheme().equalsIgnoreCase("https")) {
- sslSocketFactory = policy.sslSocketFactory;
- hostnameVerifier = policy.hostnameVerifier;
- }
- Address address = new Address(uriHost, getEffectivePort(uri), sslSocketFactory,
- hostnameVerifier, policy.requestedProxy);
- routeSelector = new RouteSelector(address, uri, policy.proxySelector, policy.connectionPool,
- Dns.DEFAULT, policy.getFailedRoutes());
- }
- connection = routeSelector.next();
- if (!connection.isConnected()) {
- connection.connect(policy.getConnectTimeout(), policy.getReadTimeout(), getTunnelConfig());
- policy.connectionPool.maybeShare(connection);
- policy.getFailedRoutes().remove(connection.getRoute());
- }
- connected(connection);
- if (connection.getRoute().getProxy() != policy.requestedProxy) {
- // Update the request line if the proxy changed; it may need a host name.
- requestHeaders.getHeaders().setRequestLine(getRequestLine());
- }
- }
-
- /**
- * Called after a socket connection has been created or retrieved from the
- * pool. Subclasses use this hook to get a reference to the TLS data.
- */
- protected void connected(Connection connection) {
- }
-
- /**
- * Called immediately before the transport transmits HTTP request headers.
- * This is used to observe the sent time should the request be cached.
- */
- public void writingRequestHeaders() {
- if (sentRequestMillis != -1) {
- throw new IllegalStateException();
- }
- sentRequestMillis = System.currentTimeMillis();
- }
-
- /**
- * @param body the response body, or null if it doesn't exist or isn't
- * available.
- */
- private void setResponse(ResponseHeaders headers, InputStream body) throws IOException {
- if (this.responseBodyIn != null) {
- throw new IllegalStateException();
- }
- this.responseHeaders = headers;
- if (body != null) {
- initContentStream(body);
- }
- }
-
- boolean hasRequestBody() {
- return method.equals("POST") || method.equals("PUT");
- }
-
- /** Returns the request body or null if this request doesn't have a body. */
- public final OutputStream getRequestBody() {
- if (responseSource == null) {
- throw new IllegalStateException();
- }
- return requestBodyOut;
- }
-
- public final boolean hasResponse() {
- return responseHeaders != null;
- }
-
- public final RequestHeaders getRequestHeaders() {
- return requestHeaders;
- }
-
- public final ResponseHeaders getResponseHeaders() {
- if (responseHeaders == null) {
- throw new IllegalStateException();
- }
- return responseHeaders;
- }
-
- public final int getResponseCode() {
- if (responseHeaders == null) {
- throw new IllegalStateException();
- }
- return responseHeaders.getHeaders().getResponseCode();
- }
-
- public final InputStream getResponseBody() {
- if (responseHeaders == null) {
- throw new IllegalStateException();
- }
- return responseBodyIn;
- }
-
- public final CacheResponse getCacheResponse() {
- return cacheResponse;
- }
-
- public final Connection getConnection() {
- return connection;
- }
-
- /**
- * Returns true if {@code cacheResponse} is of the right type. This
- * condition is necessary but not sufficient for the cached response to
- * be used.
- */
- protected boolean acceptCacheResponseType(CacheResponse cacheResponse) {
- return true;
- }
-
- private void maybeCache() throws IOException {
- // Are we caching at all?
- if (!policy.getUseCaches() || policy.responseCache == null) {
- return;
- }
-
- // Should we cache this response for this request?
- if (!responseHeaders.isCacheable(requestHeaders)) {
- return;
- }
-
- // Offer this request to the cache.
- cacheRequest = policy.responseCache.put(uri, policy.getHttpConnectionToCache());
- }
-
- /**
- * Cause the socket connection to be released to the connection pool when
- * it is no longer needed. If it is already unneeded, it will be pooled
- * immediately. Otherwise the connection is held so that redirects can be
- * handled by the same connection.
- */
- public final void automaticallyReleaseConnectionToPool() {
- automaticallyReleaseConnectionToPool = true;
- if (connection != null && connectionReleased) {
- policy.connectionPool.recycle(connection);
- connection = null;
- }
- }
-
- /**
- * Releases this engine so that its resources may be either reused or
- * closed. Also call {@link #automaticallyReleaseConnectionToPool} unless
- * the connection will be used to follow a redirect.
- */
- public final void release(boolean streamCancelled) {
- // If the response body comes from the cache, close it.
- if (responseBodyIn == cachedResponseBody) {
- Util.closeQuietly(responseBodyIn);
- }
-
- if (!connectionReleased && connection != null) {
- connectionReleased = true;
-
- if (transport == null || !transport.makeReusable(streamCancelled, requestBodyOut,
- responseTransferIn)) {
- Util.closeQuietly(connection);
- connection = null;
- } else if (automaticallyReleaseConnectionToPool) {
- policy.connectionPool.recycle(connection);
- connection = null;
- }
- }
- }
-
- private void initContentStream(InputStream transferStream) throws IOException {
- responseTransferIn = transferStream;
- if (transparentGzip && responseHeaders.isContentEncodingGzip()) {
- // If the response was transparently gzipped, remove the gzip header field
- // so clients don't double decompress. http://b/3009828
- //
- // Also remove the Content-Length in this case because it contains the
- // length 528 of the gzipped response. This isn't terribly useful and is
- // dangerous because 529 clients can query the content length, but not
- // the content encoding.
- responseHeaders.stripContentEncoding();
- responseHeaders.stripContentLength();
- responseBodyIn = new GZIPInputStream(transferStream);
- } else {
- responseBodyIn = transferStream;
- }
- }
-
- /**
- * Returns true if the response must have a (possibly 0-length) body.
- * See RFC 2616 section 4.3.
- */
- public final boolean hasResponseBody() {
- int responseCode = responseHeaders.getHeaders().getResponseCode();
-
- // HEAD requests never yield a body regardless of the response headers.
- if (method.equals("HEAD")) {
- return false;
- }
-
- if ((responseCode < HTTP_CONTINUE || responseCode >= 200)
- && responseCode != HttpURLConnectionImpl.HTTP_NO_CONTENT
- && responseCode != HttpURLConnectionImpl.HTTP_NOT_MODIFIED) {
- return true;
- }
-
- // If the Content-Length or Transfer-Encoding headers disagree with the
- // response code, the response is malformed. For best compatibility, we
- // honor the headers.
- if (responseHeaders.getContentLength() != -1 || responseHeaders.isChunked()) {
- return true;
- }
-
- return false;
- }
-
- /**
- * Populates requestHeaders with defaults and cookies.
- *
- * <p>This client doesn't specify a default {@code Accept} header because it
- * doesn't know what content types the application is interested in.
- */
- private void prepareRawRequestHeaders() throws IOException {
- requestHeaders.getHeaders().setRequestLine(getRequestLine());
-
- if (requestHeaders.getUserAgent() == null) {
- requestHeaders.setUserAgent(getDefaultUserAgent());
- }
-
- if (requestHeaders.getHost() == null) {
- requestHeaders.setHost(getOriginAddress(policy.getURL()));
- }
-
- if ((connection == null || connection.getHttpMinorVersion() != 0)
- && requestHeaders.getConnection() == null) {
- requestHeaders.setConnection("Keep-Alive");
- }
-
- if (requestHeaders.getAcceptEncoding() == null) {
- transparentGzip = true;
- requestHeaders.setAcceptEncoding("gzip");
- }
-
- if (hasRequestBody() && requestHeaders.getContentType() == null) {
- requestHeaders.setContentType("application/x-www-form-urlencoded");
- }
-
- long ifModifiedSince = policy.getIfModifiedSince();
- if (ifModifiedSince != 0) {
- requestHeaders.setIfModifiedSince(new Date(ifModifiedSince));
- }
-
- CookieHandler cookieHandler = policy.cookieHandler;
- if (cookieHandler != null) {
- requestHeaders.addCookies(
- cookieHandler.get(uri, requestHeaders.getHeaders().toMultimap(false)));
- }
- }
-
- /**
- * Returns the request status line, like "GET / HTTP/1.1". This is exposed
- * to the application by {@link HttpURLConnectionImpl#getHeaderFields}, so
- * it needs to be set even if the transport is SPDY.
- */
- String getRequestLine() {
- String protocol =
- (connection == null || connection.getHttpMinorVersion() != 0) ? "HTTP/1.1" : "HTTP/1.0";
- return method + " " + requestString() + " " + protocol;
- }
-
- private String requestString() {
- URL url = policy.getURL();
- if (includeAuthorityInRequestLine()) {
- return url.toString();
- } else {
- return requestPath(url);
- }
- }
-
- /**
- * Returns the path to request, like the '/' in 'GET / HTTP/1.1'. Never
- * empty, even if the request URL is. Includes the query component if it
- * exists.
- */
- public static String requestPath(URL url) {
- String fileOnly = url.getFile();
- if (fileOnly == null) {
- return "/";
- } else if (!fileOnly.startsWith("/")) {
- return "/" + fileOnly;
- } else {
- return fileOnly;
- }
- }
-
- /**
- * Returns true if the request line should contain the full URL with host
- * and port (like "GET http://android.com/foo HTTP/1.1") or only the path
- * (like "GET /foo HTTP/1.1").
- *
- * <p>This is non-final because for HTTPS it's never necessary to supply the
- * full URL, even if a proxy is in use.
- */
- protected boolean includeAuthorityInRequestLine() {
- return connection == null
- ? policy.usingProxy() // A proxy was requested.
- : connection.getRoute().getProxy().type() == Proxy.Type.HTTP; // A proxy was selected.
- }
-
- public static String getDefaultUserAgent() {
- String agent = System.getProperty("http.agent");
- return agent != null ? agent : ("Java" + System.getProperty("java.version"));
- }
-
- public static String getOriginAddress(URL url) {
- int port = url.getPort();
- String result = url.getHost();
- if (port > 0 && port != getDefaultPort(url.getProtocol())) {
- result = result + ":" + port;
- }
- return result;
- }
-
- /**
- * Flushes the remaining request header and body, parses the HTTP response
- * headers and starts reading the HTTP response body if it exists.
- */
- public final void readResponse() throws IOException {
- if (hasResponse()) {
- responseHeaders.setResponseSource(responseSource);
- return;
- }
-
- if (responseSource == null) {
- throw new IllegalStateException("readResponse() without sendRequest()");
- }
-
- if (!responseSource.requiresConnection()) {
- return;
- }
-
- if (sentRequestMillis == -1) {
- if (requestBodyOut instanceof RetryableOutputStream) {
- int contentLength = ((RetryableOutputStream) requestBodyOut).contentLength();
- requestHeaders.setContentLength(contentLength);
- }
- transport.writeRequestHeaders();
- }
-
- if (requestBodyOut != null) {
- requestBodyOut.close();
- if (requestBodyOut instanceof RetryableOutputStream) {
- transport.writeRequestBody((RetryableOutputStream) requestBodyOut);
- }
- }
-
- transport.flushRequest();
-
- responseHeaders = transport.readResponseHeaders();
- responseHeaders.setLocalTimestamps(sentRequestMillis, System.currentTimeMillis());
- responseHeaders.setResponseSource(responseSource);
-
- if (responseSource == ResponseSource.CONDITIONAL_CACHE) {
- if (cachedResponseHeaders.validate(responseHeaders)) {
- release(false);
- ResponseHeaders combinedHeaders = cachedResponseHeaders.combine(responseHeaders);
- setResponse(combinedHeaders, cachedResponseBody);
- policy.responseCache.trackConditionalCacheHit();
- policy.responseCache.update(cacheResponse, policy.getHttpConnectionToCache());
- return;
- } else {
- Util.closeQuietly(cachedResponseBody);
- }
- }
-
- if (hasResponseBody()) {
- maybeCache(); // reentrant. this calls into user code which may call back into this!
- }
-
- initContentStream(transport.getTransferStream(cacheRequest));
- }
-
- protected TunnelRequest getTunnelConfig() {
- return null;
- }
-
- public void receiveHeaders(RawHeaders headers) throws IOException {
- CookieHandler cookieHandler = policy.cookieHandler;
- if (cookieHandler != null) {
- cookieHandler.put(uri, headers.toMultimap(true));
- }
- }
-}
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/67fa7ebb/lib/cordova-android/framework/src/com/squareup/okhttp/internal/http/HttpResponseCache.java
----------------------------------------------------------------------
diff --git a/lib/cordova-android/framework/src/com/squareup/okhttp/internal/http/HttpResponseCache.java b/lib/cordova-android/framework/src/com/squareup/okhttp/internal/http/HttpResponseCache.java
deleted file mode 100644
index 8735166..0000000
--- a/lib/cordova-android/framework/src/com/squareup/okhttp/internal/http/HttpResponseCache.java
+++ /dev/null
@@ -1,608 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.squareup.okhttp.internal.http;
-
-import com.squareup.okhttp.OkResponseCache;
-import com.squareup.okhttp.ResponseSource;
-import com.squareup.okhttp.internal.Base64;
-import com.squareup.okhttp.internal.DiskLruCache;
-import com.squareup.okhttp.internal.StrictLineReader;
-import com.squareup.okhttp.internal.Util;
-import java.io.BufferedWriter;
-import java.io.ByteArrayInputStream;
-import java.io.File;
-import java.io.FilterInputStream;
-import java.io.FilterOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.io.OutputStreamWriter;
-import java.io.UnsupportedEncodingException;
-import java.io.Writer;
-import java.net.CacheRequest;
-import java.net.CacheResponse;
-import java.net.HttpURLConnection;
-import java.net.ResponseCache;
-import java.net.SecureCacheResponse;
-import java.net.URI;
-import java.net.URLConnection;
-import java.security.MessageDigest;
-import java.security.NoSuchAlgorithmException;
-import java.security.Principal;
-import java.security.cert.Certificate;
-import java.security.cert.CertificateEncodingException;
-import java.security.cert.CertificateException;
-import java.security.cert.CertificateFactory;
-import java.security.cert.X509Certificate;
-import java.util.Arrays;
-import java.util.List;
-import java.util.Map;
-import javax.net.ssl.HttpsURLConnection;
-import javax.net.ssl.SSLPeerUnverifiedException;
-
-import static com.squareup.okhttp.internal.Util.US_ASCII;
-import static com.squareup.okhttp.internal.Util.UTF_8;
-
-/**
- * Cache responses in a directory on the file system. Most clients should use
- * {@code android.net.HttpResponseCache}, the stable, documented front end for
- * this.
- */
-public final class HttpResponseCache extends ResponseCache implements OkResponseCache {
- private static final char[] DIGITS =
- { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
-
- // TODO: add APIs to iterate the cache?
- private static final int VERSION = 201105;
- private static final int ENTRY_METADATA = 0;
- private static final int ENTRY_BODY = 1;
- private static final int ENTRY_COUNT = 2;
-
- private final DiskLruCache cache;
-
- /* read and write statistics, all guarded by 'this' */
- private int writeSuccessCount;
- private int writeAbortCount;
- private int networkCount;
- private int hitCount;
- private int requestCount;
-
- public HttpResponseCache(File directory, long maxSize) throws IOException {
- cache = DiskLruCache.open(directory, VERSION, ENTRY_COUNT, maxSize);
- }
-
- private String uriToKey(URI uri) {
- try {
- MessageDigest messageDigest = MessageDigest.getInstance("MD5");
- byte[] md5bytes = messageDigest.digest(uri.toString().getBytes("UTF-8"));
- return bytesToHexString(md5bytes);
- } catch (NoSuchAlgorithmException e) {
- throw new AssertionError(e);
- } catch (UnsupportedEncodingException e) {
- throw new AssertionError(e);
- }
- }
-
- private static String bytesToHexString(byte[] bytes) {
- char[] digits = DIGITS;
- char[] buf = new char[bytes.length * 2];
- int c = 0;
- for (byte b : bytes) {
- buf[c++] = digits[(b >> 4) & 0xf];
- buf[c++] = digits[b & 0xf];
- }
- return new String(buf);
- }
-
- @Override public CacheResponse get(URI uri, String requestMethod,
- Map<String, List<String>> requestHeaders) {
- String key = uriToKey(uri);
- DiskLruCache.Snapshot snapshot;
- Entry entry;
- try {
- snapshot = cache.get(key);
- if (snapshot == null) {
- return null;
- }
- entry = new Entry(snapshot.getInputStream(ENTRY_METADATA));
- } catch (IOException e) {
- // Give up because the cache cannot be read.
- return null;
- }
-
- if (!entry.matches(uri, requestMethod, requestHeaders)) {
- snapshot.close();
- return null;
- }
-
- return entry.isHttps() ? new EntrySecureCacheResponse(entry, snapshot)
- : new EntryCacheResponse(entry, snapshot);
- }
-
- @Override public CacheRequest put(URI uri, URLConnection urlConnection) throws IOException {
- if (!(urlConnection instanceof HttpURLConnection)) {
- return null;
- }
-
- HttpURLConnection httpConnection = (HttpURLConnection) urlConnection;
- String requestMethod = httpConnection.getRequestMethod();
- String key = uriToKey(uri);
-
- if (requestMethod.equals("POST") || requestMethod.equals("PUT") || requestMethod.equals(
- "DELETE")) {
- try {
- cache.remove(key);
- } catch (IOException ignored) {
- // The cache cannot be written.
- }
- return null;
- } else if (!requestMethod.equals("GET")) {
- // Don't cache non-GET responses. We're technically allowed to cache
- // HEAD requests and some POST requests, but the complexity of doing
- // so is high and the benefit is low.
- return null;
- }
-
- HttpEngine httpEngine = getHttpEngine(httpConnection);
- if (httpEngine == null) {
- // Don't cache unless the HTTP implementation is ours.
- return null;
- }
-
- ResponseHeaders response = httpEngine.getResponseHeaders();
- if (response.hasVaryAll()) {
- return null;
- }
-
- RawHeaders varyHeaders =
- httpEngine.getRequestHeaders().getHeaders().getAll(response.getVaryFields());
- Entry entry = new Entry(uri, varyHeaders, httpConnection);
- DiskLruCache.Editor editor = null;
- try {
- editor = cache.edit(key);
- if (editor == null) {
- return null;
- }
- entry.writeTo(editor);
- return new CacheRequestImpl(editor);
- } catch (IOException e) {
- abortQuietly(editor);
- return null;
- }
- }
-
- /**
- * Handles a conditional request hit by updating the stored cache response
- * with the headers from {@code httpConnection}. The cached response body is
- * not updated. If the stored response has changed since {@code
- * conditionalCacheHit} was returned, this does nothing.
- */
- @Override public void update(CacheResponse conditionalCacheHit, HttpURLConnection httpConnection)
- throws IOException {
- HttpEngine httpEngine = getHttpEngine(httpConnection);
- URI uri = httpEngine.getUri();
- ResponseHeaders response = httpEngine.getResponseHeaders();
- RawHeaders varyHeaders =
- httpEngine.getRequestHeaders().getHeaders().getAll(response.getVaryFields());
- Entry entry = new Entry(uri, varyHeaders, httpConnection);
- DiskLruCache.Snapshot snapshot = (conditionalCacheHit instanceof EntryCacheResponse)
- ? ((EntryCacheResponse) conditionalCacheHit).snapshot
- : ((EntrySecureCacheResponse) conditionalCacheHit).snapshot;
- DiskLruCache.Editor editor = null;
- try {
- editor = snapshot.edit(); // returns null if snapshot is not current
- if (editor != null) {
- entry.writeTo(editor);
- editor.commit();
- }
- } catch (IOException e) {
- abortQuietly(editor);
- }
- }
-
- private void abortQuietly(DiskLruCache.Editor editor) {
- // Give up because the cache cannot be written.
- try {
- if (editor != null) {
- editor.abort();
- }
- } catch (IOException ignored) {
- }
- }
-
- private HttpEngine getHttpEngine(URLConnection httpConnection) {
- if (httpConnection instanceof HttpURLConnectionImpl) {
- return ((HttpURLConnectionImpl) httpConnection).getHttpEngine();
- } else if (httpConnection instanceof HttpsURLConnectionImpl) {
- return ((HttpsURLConnectionImpl) httpConnection).getHttpEngine();
- } else {
- return null;
- }
- }
-
- public DiskLruCache getCache() {
- return cache;
- }
-
- public synchronized int getWriteAbortCount() {
- return writeAbortCount;
- }
-
- public synchronized int getWriteSuccessCount() {
- return writeSuccessCount;
- }
-
- public synchronized void trackResponse(ResponseSource source) {
- requestCount++;
-
- switch (source) {
- case CACHE:
- hitCount++;
- break;
- case CONDITIONAL_CACHE:
- case NETWORK:
- networkCount++;
- break;
- }
- }
-
- public synchronized void trackConditionalCacheHit() {
- hitCount++;
- }
-
- public synchronized int getNetworkCount() {
- return networkCount;
- }
-
- public synchronized int getHitCount() {
- return hitCount;
- }
-
- public synchronized int getRequestCount() {
- return requestCount;
- }
-
- private final class CacheRequestImpl extends CacheRequest {
- private final DiskLruCache.Editor editor;
- private OutputStream cacheOut;
- private boolean done;
- private OutputStream body;
-
- public CacheRequestImpl(final DiskLruCache.Editor editor) throws IOException {
- this.editor = editor;
- this.cacheOut = editor.newOutputStream(ENTRY_BODY);
- this.body = new FilterOutputStream(cacheOut) {
- @Override public void close() throws IOException {
- synchronized (HttpResponseCache.this) {
- if (done) {
- return;
- }
- done = true;
- writeSuccessCount++;
- }
- super.close();
- editor.commit();
- }
-
- @Override
- public void write(byte[] buffer, int offset, int length) throws IOException {
- // Since we don't override "write(int oneByte)", we can write directly to "out"
- // and avoid the inefficient implementation from the FilterOutputStream.
- out.write(buffer, offset, length);
- }
- };
- }
-
- @Override public void abort() {
- synchronized (HttpResponseCache.this) {
- if (done) {
- return;
- }
- done = true;
- writeAbortCount++;
- }
- Util.closeQuietly(cacheOut);
- try {
- editor.abort();
- } catch (IOException ignored) {
- }
- }
-
- @Override public OutputStream getBody() throws IOException {
- return body;
- }
- }
-
- private static final class Entry {
- private final String uri;
- private final RawHeaders varyHeaders;
- private final String requestMethod;
- private final RawHeaders responseHeaders;
- private final String cipherSuite;
- private final Certificate[] peerCertificates;
- private final Certificate[] localCertificates;
-
- /**
- * Reads an entry from an input stream. A typical entry looks like this:
- * <pre>{@code
- * http://google.com/foo
- * GET
- * 2
- * Accept-Language: fr-CA
- * Accept-Charset: UTF-8
- * HTTP/1.1 200 OK
- * 3
- * Content-Type: image/png
- * Content-Length: 100
- * Cache-Control: max-age=600
- * }</pre>
- *
- * <p>A typical HTTPS file looks like this:
- * <pre>{@code
- * https://google.com/foo
- * GET
- * 2
- * Accept-Language: fr-CA
- * Accept-Charset: UTF-8
- * HTTP/1.1 200 OK
- * 3
- * Content-Type: image/png
- * Content-Length: 100
- * Cache-Control: max-age=600
- *
- * AES_256_WITH_MD5
- * 2
- * base64-encoded peerCertificate[0]
- * base64-encoded peerCertificate[1]
- * -1
- * }</pre>
- * The file is newline separated. The first two lines are the URL and
- * the request method. Next is the number of HTTP Vary request header
- * lines, followed by those lines.
- *
- * <p>Next is the response status line, followed by the number of HTTP
- * response header lines, followed by those lines.
- *
- * <p>HTTPS responses also contain SSL session information. This begins
- * with a blank line, and then a line containing the cipher suite. Next
- * is the length of the peer certificate chain. These certificates are
- * base64-encoded and appear each on their own line. The next line
- * contains the length of the local certificate chain. These
- * certificates are also base64-encoded and appear each on their own
- * line. A length of -1 is used to encode a null array.
- */
- public Entry(InputStream in) throws IOException {
- try {
- StrictLineReader reader = new StrictLineReader(in, US_ASCII);
- uri = reader.readLine();
- requestMethod = reader.readLine();
- varyHeaders = new RawHeaders();
- int varyRequestHeaderLineCount = reader.readInt();
- for (int i = 0; i < varyRequestHeaderLineCount; i++) {
- varyHeaders.addLine(reader.readLine());
- }
-
- responseHeaders = new RawHeaders();
- responseHeaders.setStatusLine(reader.readLine());
- int responseHeaderLineCount = reader.readInt();
- for (int i = 0; i < responseHeaderLineCount; i++) {
- responseHeaders.addLine(reader.readLine());
- }
-
- if (isHttps()) {
- String blank = reader.readLine();
- if (!blank.isEmpty()) {
- throw new IOException("expected \"\" but was \"" + blank + "\"");
- }
- cipherSuite = reader.readLine();
- peerCertificates = readCertArray(reader);
- localCertificates = readCertArray(reader);
- } else {
- cipherSuite = null;
- peerCertificates = null;
- localCertificates = null;
- }
- } finally {
- in.close();
- }
- }
-
- public Entry(URI uri, RawHeaders varyHeaders, HttpURLConnection httpConnection)
- throws IOException {
- this.uri = uri.toString();
- this.varyHeaders = varyHeaders;
- this.requestMethod = httpConnection.getRequestMethod();
- this.responseHeaders = RawHeaders.fromMultimap(httpConnection.getHeaderFields(), true);
-
- if (isHttps()) {
- HttpsURLConnection httpsConnection = (HttpsURLConnection) httpConnection;
- cipherSuite = httpsConnection.getCipherSuite();
- Certificate[] peerCertificatesNonFinal = null;
- try {
- peerCertificatesNonFinal = httpsConnection.getServerCertificates();
- } catch (SSLPeerUnverifiedException ignored) {
- }
- peerCertificates = peerCertificatesNonFinal;
- localCertificates = httpsConnection.getLocalCertificates();
- } else {
- cipherSuite = null;
- peerCertificates = null;
- localCertificates = null;
- }
- }
-
- public void writeTo(DiskLruCache.Editor editor) throws IOException {
- OutputStream out = editor.newOutputStream(ENTRY_METADATA);
- Writer writer = new BufferedWriter(new OutputStreamWriter(out, UTF_8));
-
- writer.write(uri + '\n');
- writer.write(requestMethod + '\n');
- writer.write(Integer.toString(varyHeaders.length()) + '\n');
- for (int i = 0; i < varyHeaders.length(); i++) {
- writer.write(varyHeaders.getFieldName(i) + ": " + varyHeaders.getValue(i) + '\n');
- }
-
- writer.write(responseHeaders.getStatusLine() + '\n');
- writer.write(Integer.toString(responseHeaders.length()) + '\n');
- for (int i = 0; i < responseHeaders.length(); i++) {
- writer.write(responseHeaders.getFieldName(i) + ": " + responseHeaders.getValue(i) + '\n');
- }
-
- if (isHttps()) {
- writer.write('\n');
- writer.write(cipherSuite + '\n');
- writeCertArray(writer, peerCertificates);
- writeCertArray(writer, localCertificates);
- }
- writer.close();
- }
-
- private boolean isHttps() {
- return uri.startsWith("https://");
- }
-
- private Certificate[] readCertArray(StrictLineReader reader) throws IOException {
- int length = reader.readInt();
- if (length == -1) {
- return null;
- }
- try {
- CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
- Certificate[] result = new Certificate[length];
- for (int i = 0; i < result.length; i++) {
- String line = reader.readLine();
- byte[] bytes = Base64.decode(line.getBytes("US-ASCII"));
- result[i] = certificateFactory.generateCertificate(new ByteArrayInputStream(bytes));
- }
- return result;
- } catch (CertificateException e) {
- throw new IOException(e);
- }
- }
-
- private void writeCertArray(Writer writer, Certificate[] certificates) throws IOException {
- if (certificates == null) {
- writer.write("-1\n");
- return;
- }
- try {
- writer.write(Integer.toString(certificates.length) + '\n');
- for (Certificate certificate : certificates) {
- byte[] bytes = certificate.getEncoded();
- String line = Base64.encode(bytes);
- writer.write(line + '\n');
- }
- } catch (CertificateEncodingException e) {
- throw new IOException(e);
- }
- }
-
- public boolean matches(URI uri, String requestMethod,
- Map<String, List<String>> requestHeaders) {
- return this.uri.equals(uri.toString())
- && this.requestMethod.equals(requestMethod)
- && new ResponseHeaders(uri, responseHeaders).varyMatches(varyHeaders.toMultimap(false),
- requestHeaders);
- }
- }
-
- /**
- * Returns an input stream that reads the body of a snapshot, closing the
- * snapshot when the stream is closed.
- */
- private static InputStream newBodyInputStream(final DiskLruCache.Snapshot snapshot) {
- return new FilterInputStream(snapshot.getInputStream(ENTRY_BODY)) {
- @Override public void close() throws IOException {
- snapshot.close();
- super.close();
- }
- };
- }
-
- static class EntryCacheResponse extends CacheResponse {
- private final Entry entry;
- private final DiskLruCache.Snapshot snapshot;
- private final InputStream in;
-
- public EntryCacheResponse(Entry entry, DiskLruCache.Snapshot snapshot) {
- this.entry = entry;
- this.snapshot = snapshot;
- this.in = newBodyInputStream(snapshot);
- }
-
- @Override public Map<String, List<String>> getHeaders() {
- return entry.responseHeaders.toMultimap(true);
- }
-
- @Override public InputStream getBody() {
- return in;
- }
- }
-
- static class EntrySecureCacheResponse extends SecureCacheResponse {
- private final Entry entry;
- private final DiskLruCache.Snapshot snapshot;
- private final InputStream in;
-
- public EntrySecureCacheResponse(Entry entry, DiskLruCache.Snapshot snapshot) {
- this.entry = entry;
- this.snapshot = snapshot;
- this.in = newBodyInputStream(snapshot);
- }
-
- @Override public Map<String, List<String>> getHeaders() {
- return entry.responseHeaders.toMultimap(true);
- }
-
- @Override public InputStream getBody() {
- return in;
- }
-
- @Override public String getCipherSuite() {
- return entry.cipherSuite;
- }
-
- @Override public List<Certificate> getServerCertificateChain()
- throws SSLPeerUnverifiedException {
- if (entry.peerCertificates == null || entry.peerCertificates.length == 0) {
- throw new SSLPeerUnverifiedException(null);
- }
- return Arrays.asList(entry.peerCertificates.clone());
- }
-
- @Override public Principal getPeerPrincipal() throws SSLPeerUnverifiedException {
- if (entry.peerCertificates == null || entry.peerCertificates.length == 0) {
- throw new SSLPeerUnverifiedException(null);
- }
- return ((X509Certificate) entry.peerCertificates[0]).getSubjectX500Principal();
- }
-
- @Override public List<Certificate> getLocalCertificateChain() {
- if (entry.localCertificates == null || entry.localCertificates.length == 0) {
- return null;
- }
- return Arrays.asList(entry.localCertificates.clone());
- }
-
- @Override public Principal getLocalPrincipal() {
- if (entry.localCertificates == null || entry.localCertificates.length == 0) {
- return null;
- }
- return ((X509Certificate) entry.localCertificates[0]).getSubjectX500Principal();
- }
- }
-}
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/67fa7ebb/lib/cordova-android/framework/src/com/squareup/okhttp/internal/http/HttpTransport.java
----------------------------------------------------------------------
diff --git a/lib/cordova-android/framework/src/com/squareup/okhttp/internal/http/HttpTransport.java b/lib/cordova-android/framework/src/com/squareup/okhttp/internal/http/HttpTransport.java
deleted file mode 100644
index f6d77b2..0000000
--- a/lib/cordova-android/framework/src/com/squareup/okhttp/internal/http/HttpTransport.java
+++ /dev/null
@@ -1,485 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.squareup.okhttp.internal.http;
-
-import com.squareup.okhttp.Connection;
-import com.squareup.okhttp.internal.AbstractOutputStream;
-import com.squareup.okhttp.internal.Util;
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.net.CacheRequest;
-import java.net.ProtocolException;
-import java.net.Socket;
-
-import static com.squareup.okhttp.internal.Util.checkOffsetAndCount;
-
-public final class HttpTransport implements Transport {
- /**
- * The timeout to use while discarding a stream of input data. Since this is
- * used for connection reuse, this timeout should be significantly less than
- * the time it takes to establish a new connection.
- */
- private static final int DISCARD_STREAM_TIMEOUT_MILLIS = 100;
-
- public static final int DEFAULT_CHUNK_LENGTH = 1024;
-
- private final HttpEngine httpEngine;
- private final InputStream socketIn;
- private final OutputStream socketOut;
-
- /**
- * This stream buffers the request headers and the request body when their
- * combined size is less than MAX_REQUEST_BUFFER_LENGTH. By combining them
- * we can save socket writes, which in turn saves a packet transmission.
- * This is socketOut if the request size is large or unknown.
- */
- private OutputStream requestOut;
-
- public HttpTransport(HttpEngine httpEngine, OutputStream outputStream, InputStream inputStream) {
- this.httpEngine = httpEngine;
- this.socketOut = outputStream;
- this.requestOut = outputStream;
- this.socketIn = inputStream;
- }
-
- @Override public OutputStream createRequestBody() throws IOException {
- boolean chunked = httpEngine.requestHeaders.isChunked();
- if (!chunked
- && httpEngine.policy.getChunkLength() > 0
- && httpEngine.connection.getHttpMinorVersion() != 0) {
- httpEngine.requestHeaders.setChunked();
- chunked = true;
- }
-
- // Stream a request body of unknown length.
- if (chunked) {
- int chunkLength = httpEngine.policy.getChunkLength();
- if (chunkLength == -1) {
- chunkLength = DEFAULT_CHUNK_LENGTH;
- }
- writeRequestHeaders();
- return new ChunkedOutputStream(requestOut, chunkLength);
- }
-
- // Stream a request body of a known length.
- int fixedContentLength = httpEngine.policy.getFixedContentLength();
- if (fixedContentLength != -1) {
- httpEngine.requestHeaders.setContentLength(fixedContentLength);
- writeRequestHeaders();
- return new FixedLengthOutputStream(requestOut, fixedContentLength);
- }
-
- // Buffer a request body of a known length.
- int contentLength = httpEngine.requestHeaders.getContentLength();
- if (contentLength != -1) {
- writeRequestHeaders();
- return new RetryableOutputStream(contentLength);
- }
-
- // Buffer a request body of an unknown length. Don't write request
- // headers until the entire body is ready; otherwise we can't set the
- // Content-Length header correctly.
- return new RetryableOutputStream();
- }
-
- @Override public void flushRequest() throws IOException {
- requestOut.flush();
- requestOut = socketOut;
- }
-
- @Override public void writeRequestBody(RetryableOutputStream requestBody) throws IOException {
- requestBody.writeToSocket(requestOut);
- }
-
- /**
- * Prepares the HTTP headers and sends them to the server.
- *
- * <p>For streaming requests with a body, headers must be prepared
- * <strong>before</strong> the output stream has been written to. Otherwise
- * the body would need to be buffered!
- *
- * <p>For non-streaming requests with a body, headers must be prepared
- * <strong>after</strong> the output stream has been written to and closed.
- * This ensures that the {@code Content-Length} header field receives the
- * proper value.
- */
- public void writeRequestHeaders() throws IOException {
- httpEngine.writingRequestHeaders();
- RawHeaders headersToSend = httpEngine.requestHeaders.getHeaders();
- byte[] bytes = headersToSend.toBytes();
- requestOut.write(bytes);
- }
-
- @Override public ResponseHeaders readResponseHeaders() throws IOException {
- RawHeaders headers = RawHeaders.fromBytes(socketIn);
- httpEngine.connection.setHttpMinorVersion(headers.getHttpMinorVersion());
- httpEngine.receiveHeaders(headers);
- return new ResponseHeaders(httpEngine.uri, headers);
- }
-
- public boolean makeReusable(boolean streamCancelled, OutputStream requestBodyOut,
- InputStream responseBodyIn) {
- if (streamCancelled) {
- return false;
- }
-
- // We cannot reuse sockets that have incomplete output.
- if (requestBodyOut != null && !((AbstractOutputStream) requestBodyOut).isClosed()) {
- return false;
- }
-
- // If the request specified that the connection shouldn't be reused, don't reuse it.
- if (httpEngine.requestHeaders.hasConnectionClose()) {
- return false;
- }
-
- // If the response specified that the connection shouldn't be reused, don't reuse it.
- if (httpEngine.responseHeaders != null && httpEngine.responseHeaders.hasConnectionClose()) {
- return false;
- }
-
- if (responseBodyIn instanceof UnknownLengthHttpInputStream) {
- return false;
- }
-
- if (responseBodyIn != null) {
- return discardStream(httpEngine, responseBodyIn);
- }
-
- return true;
- }
-
- /**
- * Discards the response body so that the connection can be reused. This
- * needs to be done judiciously, since it delays the current request in
- * order to speed up a potential future request that may never occur.
- */
- private static boolean discardStream(HttpEngine httpEngine, InputStream responseBodyIn) {
- Connection connection = httpEngine.connection;
- if (connection == null) return false;
- Socket socket = connection.getSocket();
- if (socket == null) return false;
- try {
- int socketTimeout = socket.getSoTimeout();
- socket.setSoTimeout(DISCARD_STREAM_TIMEOUT_MILLIS);
- try {
- Util.skipAll(responseBodyIn);
- return true;
- } finally {
- socket.setSoTimeout(socketTimeout);
- }
- } catch (IOException e) {
- return false;
- }
- }
-
- @Override public InputStream getTransferStream(CacheRequest cacheRequest) throws IOException {
- if (!httpEngine.hasResponseBody()) {
- return new FixedLengthInputStream(socketIn, cacheRequest, httpEngine, 0);
- }
-
- if (httpEngine.responseHeaders.isChunked()) {
- return new ChunkedInputStream(socketIn, cacheRequest, this);
- }
-
- if (httpEngine.responseHeaders.getContentLength() != -1) {
- return new FixedLengthInputStream(socketIn, cacheRequest, httpEngine,
- httpEngine.responseHeaders.getContentLength());
- }
-
- // Wrap the input stream from the connection (rather than just returning
- // "socketIn" directly here), so that we can control its use after the
- // reference escapes.
- return new UnknownLengthHttpInputStream(socketIn, cacheRequest, httpEngine);
- }
-
- /** An HTTP body with a fixed length known in advance. */
- private static final class FixedLengthOutputStream extends AbstractOutputStream {
- private final OutputStream socketOut;
- private int bytesRemaining;
-
- private FixedLengthOutputStream(OutputStream socketOut, int bytesRemaining) {
- this.socketOut = socketOut;
- this.bytesRemaining = bytesRemaining;
- }
-
- @Override public void write(byte[] buffer, int offset, int count) throws IOException {
- checkNotClosed();
- checkOffsetAndCount(buffer.length, offset, count);
- if (count > bytesRemaining) {
- throw new ProtocolException("expected " + bytesRemaining + " bytes but received " + count);
- }
- socketOut.write(buffer, offset, count);
- bytesRemaining -= count;
- }
-
- @Override public void flush() throws IOException {
- if (closed) {
- return; // don't throw; this stream might have been closed on the caller's behalf
- }
- socketOut.flush();
- }
-
- @Override public void close() throws IOException {
- if (closed) {
- return;
- }
- closed = true;
- if (bytesRemaining > 0) {
- throw new ProtocolException("unexpected end of stream");
- }
- }
- }
-
- /**
- * An HTTP body with alternating chunk sizes and chunk bodies. Chunks are
- * buffered until {@code maxChunkLength} bytes are ready, at which point the
- * chunk is written and the buffer is cleared.
- */
- private static final class ChunkedOutputStream extends AbstractOutputStream {
- private static final byte[] CRLF = { '\r', '\n' };
- private static final byte[] HEX_DIGITS = {
- '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
- };
- private static final byte[] FINAL_CHUNK = new byte[] { '0', '\r', '\n', '\r', '\n' };
-
- /** Scratch space for up to 8 hex digits, and then a constant CRLF. */
- private final byte[] hex = { 0, 0, 0, 0, 0, 0, 0, 0, '\r', '\n' };
-
- private final OutputStream socketOut;
- private final int maxChunkLength;
- private final ByteArrayOutputStream bufferedChunk;
-
- private ChunkedOutputStream(OutputStream socketOut, int maxChunkLength) {
- this.socketOut = socketOut;
- this.maxChunkLength = Math.max(1, dataLength(maxChunkLength));
- this.bufferedChunk = new ByteArrayOutputStream(maxChunkLength);
- }
-
- /**
- * Returns the amount of data that can be transmitted in a chunk whose total
- * length (data+headers) is {@code dataPlusHeaderLength}. This is presumably
- * useful to match sizes with wire-protocol packets.
- */
- private int dataLength(int dataPlusHeaderLength) {
- int headerLength = 4; // "\r\n" after the size plus another "\r\n" after the data
- for (int i = dataPlusHeaderLength - headerLength; i > 0; i >>= 4) {
- headerLength++;
- }
- return dataPlusHeaderLength - headerLength;
- }
-
- @Override public synchronized void write(byte[] buffer, int offset, int count)
- throws IOException {
- checkNotClosed();
- checkOffsetAndCount(buffer.length, offset, count);
-
- while (count > 0) {
- int numBytesWritten;
-
- if (bufferedChunk.size() > 0 || count < maxChunkLength) {
- // fill the buffered chunk and then maybe write that to the stream
- numBytesWritten = Math.min(count, maxChunkLength - bufferedChunk.size());
- // TODO: skip unnecessary copies from buffer->bufferedChunk?
- bufferedChunk.write(buffer, offset, numBytesWritten);
- if (bufferedChunk.size() == maxChunkLength) {
- writeBufferedChunkToSocket();
- }
- } else {
- // write a single chunk of size maxChunkLength to the stream
- numBytesWritten = maxChunkLength;
- writeHex(numBytesWritten);
- socketOut.write(buffer, offset, numBytesWritten);
- socketOut.write(CRLF);
- }
-
- offset += numBytesWritten;
- count -= numBytesWritten;
- }
- }
-
- /**
- * Equivalent to, but cheaper than writing Integer.toHexString().getBytes()
- * followed by CRLF.
- */
- private void writeHex(int i) throws IOException {
- int cursor = 8;
- do {
- hex[--cursor] = HEX_DIGITS[i & 0xf];
- } while ((i >>>= 4) != 0);
- socketOut.write(hex, cursor, hex.length - cursor);
- }
-
- @Override public synchronized void flush() throws IOException {
- if (closed) {
- return; // don't throw; this stream might have been closed on the caller's behalf
- }
- writeBufferedChunkToSocket();
- socketOut.flush();
- }
-
- @Override public synchronized void close() throws IOException {
- if (closed) {
- return;
- }
- closed = true;
- writeBufferedChunkToSocket();
- socketOut.write(FINAL_CHUNK);
- }
-
- private void writeBufferedChunkToSocket() throws IOException {
- int size = bufferedChunk.size();
- if (size <= 0) {
- return;
- }
-
- writeHex(size);
- bufferedChunk.writeTo(socketOut);
- bufferedChunk.reset();
- socketOut.write(CRLF);
- }
- }
-
- /** An HTTP body with a fixed length specified in advance. */
- private static class FixedLengthInputStream extends AbstractHttpInputStream {
- private int bytesRemaining;
-
- public FixedLengthInputStream(InputStream is, CacheRequest cacheRequest, HttpEngine httpEngine,
- int length) throws IOException {
- super(is, httpEngine, cacheRequest);
- bytesRemaining = length;
- if (bytesRemaining == 0) {
- endOfInput(false);
- }
- }
-
- @Override public int read(byte[] buffer, int offset, int count) throws IOException {
- checkOffsetAndCount(buffer.length, offset, count);
- checkNotClosed();
- if (bytesRemaining == 0) {
- return -1;
- }
- int read = in.read(buffer, offset, Math.min(count, bytesRemaining));
- if (read == -1) {
- unexpectedEndOfInput(); // the server didn't supply the promised content length
- throw new ProtocolException("unexpected end of stream");
- }
- bytesRemaining -= read;
- cacheWrite(buffer, offset, read);
- if (bytesRemaining == 0) {
- endOfInput(false);
- }
- return read;
- }
-
- @Override public int available() throws IOException {
- checkNotClosed();
- return bytesRemaining == 0 ? 0 : Math.min(in.available(), bytesRemaining);
- }
-
- @Override public void close() throws IOException {
- if (closed) {
- return;
- }
- if (bytesRemaining != 0 && !discardStream(httpEngine, this)) {
- unexpectedEndOfInput();
- }
- closed = true;
- }
- }
-
- /** An HTTP body with alternating chunk sizes and chunk bodies. */
- private static class ChunkedInputStream extends AbstractHttpInputStream {
- private static final int NO_CHUNK_YET = -1;
- private final HttpTransport transport;
- private int bytesRemainingInChunk = NO_CHUNK_YET;
- private boolean hasMoreChunks = true;
-
- ChunkedInputStream(InputStream is, CacheRequest cacheRequest, HttpTransport transport)
- throws IOException {
- super(is, transport.httpEngine, cacheRequest);
- this.transport = transport;
- }
-
- @Override public int read(byte[] buffer, int offset, int count) throws IOException {
- checkOffsetAndCount(buffer.length, offset, count);
- checkNotClosed();
-
- if (!hasMoreChunks) {
- return -1;
- }
- if (bytesRemainingInChunk == 0 || bytesRemainingInChunk == NO_CHUNK_YET) {
- readChunkSize();
- if (!hasMoreChunks) {
- return -1;
- }
- }
- int read = in.read(buffer, offset, Math.min(count, bytesRemainingInChunk));
- if (read == -1) {
- unexpectedEndOfInput(); // the server didn't supply the promised chunk length
- throw new IOException("unexpected end of stream");
- }
- bytesRemainingInChunk -= read;
- cacheWrite(buffer, offset, read);
- return read;
- }
-
- private void readChunkSize() throws IOException {
- // read the suffix of the previous chunk
- if (bytesRemainingInChunk != NO_CHUNK_YET) {
- Util.readAsciiLine(in);
- }
- String chunkSizeString = Util.readAsciiLine(in);
- int index = chunkSizeString.indexOf(";");
- if (index != -1) {
- chunkSizeString = chunkSizeString.substring(0, index);
- }
- try {
- bytesRemainingInChunk = Integer.parseInt(chunkSizeString.trim(), 16);
- } catch (NumberFormatException e) {
- throw new ProtocolException("Expected a hex chunk size but was " + chunkSizeString);
- }
- if (bytesRemainingInChunk == 0) {
- hasMoreChunks = false;
- RawHeaders rawResponseHeaders = httpEngine.responseHeaders.getHeaders();
- RawHeaders.readHeaders(transport.socketIn, rawResponseHeaders);
- httpEngine.receiveHeaders(rawResponseHeaders);
- endOfInput(false);
- }
- }
-
- @Override public int available() throws IOException {
- checkNotClosed();
- if (!hasMoreChunks || bytesRemainingInChunk == NO_CHUNK_YET) {
- return 0;
- }
- return Math.min(in.available(), bytesRemainingInChunk);
- }
-
- @Override public void close() throws IOException {
- if (closed) {
- return;
- }
- if (hasMoreChunks && !discardStream(httpEngine, this)) {
- unexpectedEndOfInput();
- }
- closed = true;
- }
- }
-}