mobile/android/thirdparty/ch/boye/httpclientandroidlib/impl/DefaultConnectionReuseStrategy.java

Wed, 31 Dec 2014 07:22:50 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 07:22:50 +0100
branch
TOR_BUG_3246
changeset 4
fc2d59ddac77
permissions
-rw-r--r--

Correct previous dual key logic pending first delivery installment.

michael@0 1 /*
michael@0 2 * ====================================================================
michael@0 3 * Licensed to the Apache Software Foundation (ASF) under one
michael@0 4 * or more contributor license agreements. See the NOTICE file
michael@0 5 * distributed with this work for additional information
michael@0 6 * regarding copyright ownership. The ASF licenses this file
michael@0 7 * to you under the Apache License, Version 2.0 (the
michael@0 8 * "License"); you may not use this file except in compliance
michael@0 9 * with the License. You may obtain a copy of the License at
michael@0 10 *
michael@0 11 * http://www.apache.org/licenses/LICENSE-2.0
michael@0 12 *
michael@0 13 * Unless required by applicable law or agreed to in writing,
michael@0 14 * software distributed under the License is distributed on an
michael@0 15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
michael@0 16 * KIND, either express or implied. See the License for the
michael@0 17 * specific language governing permissions and limitations
michael@0 18 * under the License.
michael@0 19 * ====================================================================
michael@0 20 *
michael@0 21 * This software consists of voluntary contributions made by many
michael@0 22 * individuals on behalf of the Apache Software Foundation. For more
michael@0 23 * information on the Apache Software Foundation, please see
michael@0 24 * <http://www.apache.org/>.
michael@0 25 *
michael@0 26 */
michael@0 27
michael@0 28 package ch.boye.httpclientandroidlib.impl;
michael@0 29
michael@0 30 import ch.boye.httpclientandroidlib.ConnectionReuseStrategy;
michael@0 31 import ch.boye.httpclientandroidlib.HttpConnection;
michael@0 32 import ch.boye.httpclientandroidlib.HeaderIterator;
michael@0 33 import ch.boye.httpclientandroidlib.HttpEntity;
michael@0 34 import ch.boye.httpclientandroidlib.HttpResponse;
michael@0 35 import ch.boye.httpclientandroidlib.HttpVersion;
michael@0 36 import ch.boye.httpclientandroidlib.ParseException;
michael@0 37 import ch.boye.httpclientandroidlib.ProtocolVersion;
michael@0 38 import ch.boye.httpclientandroidlib.protocol.HTTP;
michael@0 39 import ch.boye.httpclientandroidlib.protocol.HttpContext;
michael@0 40 import ch.boye.httpclientandroidlib.protocol.ExecutionContext;
michael@0 41 import ch.boye.httpclientandroidlib.TokenIterator;
michael@0 42 import ch.boye.httpclientandroidlib.message.BasicTokenIterator;
michael@0 43
michael@0 44 /**
michael@0 45 * Default implementation of a strategy deciding about connection re-use.
michael@0 46 * The default implementation first checks some basics, for example
michael@0 47 * whether the connection is still open or whether the end of the
michael@0 48 * request entity can be determined without closing the connection.
michael@0 49 * If these checks pass, the tokens in the <code>Connection</code> header will
michael@0 50 * be examined. In the absence of a <code>Connection</code> header, the
michael@0 51 * non-standard but commonly used <code>Proxy-Connection</code> header takes
michael@0 52 * it's role. A token <code>close</code> indicates that the connection cannot
michael@0 53 * be reused. If there is no such token, a token <code>keep-alive</code>
michael@0 54 * indicates that the connection should be re-used. If neither token is found,
michael@0 55 * or if there are no <code>Connection</code> headers, the default policy for
michael@0 56 * the HTTP version is applied. Since <code>HTTP/1.1</code>, connections are
michael@0 57 * re-used by default. Up until <code>HTTP/1.0</code>, connections are not
michael@0 58 * re-used by default.
michael@0 59 *
michael@0 60 * @since 4.0
michael@0 61 */
michael@0 62 public class DefaultConnectionReuseStrategy implements ConnectionReuseStrategy {
michael@0 63
michael@0 64 public DefaultConnectionReuseStrategy() {
michael@0 65 super();
michael@0 66 }
michael@0 67
michael@0 68 // see interface ConnectionReuseStrategy
michael@0 69 public boolean keepAlive(final HttpResponse response,
michael@0 70 final HttpContext context) {
michael@0 71 if (response == null) {
michael@0 72 throw new IllegalArgumentException
michael@0 73 ("HTTP response may not be null.");
michael@0 74 }
michael@0 75 if (context == null) {
michael@0 76 throw new IllegalArgumentException
michael@0 77 ("HTTP context may not be null.");
michael@0 78 }
michael@0 79
michael@0 80 HttpConnection conn = (HttpConnection)
michael@0 81 context.getAttribute(ExecutionContext.HTTP_CONNECTION);
michael@0 82
michael@0 83 if (conn != null && !conn.isOpen())
michael@0 84 return false;
michael@0 85 // do NOT check for stale connection, that is an expensive operation
michael@0 86
michael@0 87 // Check for a self-terminating entity. If the end of the entity will
michael@0 88 // be indicated by closing the connection, there is no keep-alive.
michael@0 89 HttpEntity entity = response.getEntity();
michael@0 90 ProtocolVersion ver = response.getStatusLine().getProtocolVersion();
michael@0 91 if (entity != null) {
michael@0 92 if (entity.getContentLength() < 0) {
michael@0 93 if (!entity.isChunked() ||
michael@0 94 ver.lessEquals(HttpVersion.HTTP_1_0)) {
michael@0 95 // if the content length is not known and is not chunk
michael@0 96 // encoded, the connection cannot be reused
michael@0 97 return false;
michael@0 98 }
michael@0 99 }
michael@0 100 }
michael@0 101
michael@0 102 // Check for the "Connection" header. If that is absent, check for
michael@0 103 // the "Proxy-Connection" header. The latter is an unspecified and
michael@0 104 // broken but unfortunately common extension of HTTP.
michael@0 105 HeaderIterator hit = response.headerIterator(HTTP.CONN_DIRECTIVE);
michael@0 106 if (!hit.hasNext())
michael@0 107 hit = response.headerIterator("Proxy-Connection");
michael@0 108
michael@0 109 // Experimental usage of the "Connection" header in HTTP/1.0 is
michael@0 110 // documented in RFC 2068, section 19.7.1. A token "keep-alive" is
michael@0 111 // used to indicate that the connection should be persistent.
michael@0 112 // Note that the final specification of HTTP/1.1 in RFC 2616 does not
michael@0 113 // include this information. Neither is the "Connection" header
michael@0 114 // mentioned in RFC 1945, which informally describes HTTP/1.0.
michael@0 115 //
michael@0 116 // RFC 2616 specifies "close" as the only connection token with a
michael@0 117 // specific meaning: it disables persistent connections.
michael@0 118 //
michael@0 119 // The "Proxy-Connection" header is not formally specified anywhere,
michael@0 120 // but is commonly used to carry one token, "close" or "keep-alive".
michael@0 121 // The "Connection" header, on the other hand, is defined as a
michael@0 122 // sequence of tokens, where each token is a header name, and the
michael@0 123 // token "close" has the above-mentioned additional meaning.
michael@0 124 //
michael@0 125 // To get through this mess, we treat the "Proxy-Connection" header
michael@0 126 // in exactly the same way as the "Connection" header, but only if
michael@0 127 // the latter is missing. We scan the sequence of tokens for both
michael@0 128 // "close" and "keep-alive". As "close" is specified by RFC 2068,
michael@0 129 // it takes precedence and indicates a non-persistent connection.
michael@0 130 // If there is no "close" but a "keep-alive", we take the hint.
michael@0 131
michael@0 132 if (hit.hasNext()) {
michael@0 133 try {
michael@0 134 TokenIterator ti = createTokenIterator(hit);
michael@0 135 boolean keepalive = false;
michael@0 136 while (ti.hasNext()) {
michael@0 137 final String token = ti.nextToken();
michael@0 138 if (HTTP.CONN_CLOSE.equalsIgnoreCase(token)) {
michael@0 139 return false;
michael@0 140 } else if (HTTP.CONN_KEEP_ALIVE.equalsIgnoreCase(token)) {
michael@0 141 // continue the loop, there may be a "close" afterwards
michael@0 142 keepalive = true;
michael@0 143 }
michael@0 144 }
michael@0 145 if (keepalive)
michael@0 146 return true;
michael@0 147 // neither "close" nor "keep-alive", use default policy
michael@0 148
michael@0 149 } catch (ParseException px) {
michael@0 150 // invalid connection header means no persistent connection
michael@0 151 // we don't have logging in HttpCore, so the exception is lost
michael@0 152 return false;
michael@0 153 }
michael@0 154 }
michael@0 155
michael@0 156 // default since HTTP/1.1 is persistent, before it was non-persistent
michael@0 157 return !ver.lessEquals(HttpVersion.HTTP_1_0);
michael@0 158 }
michael@0 159
michael@0 160
michael@0 161 /**
michael@0 162 * Creates a token iterator from a header iterator.
michael@0 163 * This method can be overridden to replace the implementation of
michael@0 164 * the token iterator.
michael@0 165 *
michael@0 166 * @param hit the header iterator
michael@0 167 *
michael@0 168 * @return the token iterator
michael@0 169 */
michael@0 170 protected TokenIterator createTokenIterator(HeaderIterator hit) {
michael@0 171 return new BasicTokenIterator(hit);
michael@0 172 }
michael@0 173 }

mercurial