Wed, 31 Dec 2014 07:22:50 +0100
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.conn; |
michael@0 | 29 | |
michael@0 | 30 | import java.io.IOException; |
michael@0 | 31 | import java.net.Socket; |
michael@0 | 32 | import java.util.HashMap; |
michael@0 | 33 | import java.util.Map; |
michael@0 | 34 | |
michael@0 | 35 | import ch.boye.httpclientandroidlib.annotation.NotThreadSafe; |
michael@0 | 36 | |
michael@0 | 37 | import ch.boye.httpclientandroidlib.androidextra.HttpClientAndroidLog; |
michael@0 | 38 | /* LogFactory removed by HttpClient for Android script. */ |
michael@0 | 39 | import ch.boye.httpclientandroidlib.Header; |
michael@0 | 40 | import ch.boye.httpclientandroidlib.HttpException; |
michael@0 | 41 | import ch.boye.httpclientandroidlib.HttpHost; |
michael@0 | 42 | import ch.boye.httpclientandroidlib.HttpRequest; |
michael@0 | 43 | import ch.boye.httpclientandroidlib.HttpResponse; |
michael@0 | 44 | import ch.boye.httpclientandroidlib.HttpResponseFactory; |
michael@0 | 45 | import ch.boye.httpclientandroidlib.params.HttpParams; |
michael@0 | 46 | import ch.boye.httpclientandroidlib.params.HttpProtocolParams; |
michael@0 | 47 | import ch.boye.httpclientandroidlib.protocol.HttpContext; |
michael@0 | 48 | import ch.boye.httpclientandroidlib.impl.SocketHttpClientConnection; |
michael@0 | 49 | import ch.boye.httpclientandroidlib.io.HttpMessageParser; |
michael@0 | 50 | import ch.boye.httpclientandroidlib.io.SessionInputBuffer; |
michael@0 | 51 | import ch.boye.httpclientandroidlib.io.SessionOutputBuffer; |
michael@0 | 52 | |
michael@0 | 53 | import ch.boye.httpclientandroidlib.conn.OperatedClientConnection; |
michael@0 | 54 | |
michael@0 | 55 | /** |
michael@0 | 56 | * Default implementation of an operated client connection. |
michael@0 | 57 | * <p> |
michael@0 | 58 | * The following parameters can be used to customize the behavior of this |
michael@0 | 59 | * class: |
michael@0 | 60 | * <ul> |
michael@0 | 61 | * <li>{@link ch.boye.httpclientandroidlib.params.CoreProtocolPNames#STRICT_TRANSFER_ENCODING}</li> |
michael@0 | 62 | * <li>{@link ch.boye.httpclientandroidlib.params.CoreProtocolPNames#HTTP_ELEMENT_CHARSET}</li> |
michael@0 | 63 | * <li>{@link ch.boye.httpclientandroidlib.params.CoreConnectionPNames#SOCKET_BUFFER_SIZE}</li> |
michael@0 | 64 | * <li>{@link ch.boye.httpclientandroidlib.params.CoreConnectionPNames#MAX_LINE_LENGTH}</li> |
michael@0 | 65 | * <li>{@link ch.boye.httpclientandroidlib.params.CoreConnectionPNames#MAX_HEADER_COUNT}</li> |
michael@0 | 66 | * </ul> |
michael@0 | 67 | * |
michael@0 | 68 | * @since 4.0 |
michael@0 | 69 | */ |
michael@0 | 70 | @NotThreadSafe // connSecure, targetHost |
michael@0 | 71 | public class DefaultClientConnection extends SocketHttpClientConnection |
michael@0 | 72 | implements OperatedClientConnection, HttpContext { |
michael@0 | 73 | |
michael@0 | 74 | public HttpClientAndroidLog log = new HttpClientAndroidLog(getClass()); |
michael@0 | 75 | public HttpClientAndroidLog headerLog = new HttpClientAndroidLog("ch.boye.httpclientandroidlib.headers"); |
michael@0 | 76 | public HttpClientAndroidLog wireLog = new HttpClientAndroidLog("ch.boye.httpclientandroidlib.wire"); |
michael@0 | 77 | |
michael@0 | 78 | /** The unconnected socket */ |
michael@0 | 79 | private volatile Socket socket; |
michael@0 | 80 | |
michael@0 | 81 | /** The target host of this connection. */ |
michael@0 | 82 | private HttpHost targetHost; |
michael@0 | 83 | |
michael@0 | 84 | /** Whether this connection is secure. */ |
michael@0 | 85 | private boolean connSecure; |
michael@0 | 86 | |
michael@0 | 87 | /** True if this connection was shutdown. */ |
michael@0 | 88 | private volatile boolean shutdown; |
michael@0 | 89 | |
michael@0 | 90 | /** connection specific attributes */ |
michael@0 | 91 | private final Map<String, Object> attributes; |
michael@0 | 92 | |
michael@0 | 93 | public DefaultClientConnection() { |
michael@0 | 94 | super(); |
michael@0 | 95 | this.attributes = new HashMap<String, Object>(); |
michael@0 | 96 | } |
michael@0 | 97 | |
michael@0 | 98 | public final HttpHost getTargetHost() { |
michael@0 | 99 | return this.targetHost; |
michael@0 | 100 | } |
michael@0 | 101 | |
michael@0 | 102 | public final boolean isSecure() { |
michael@0 | 103 | return this.connSecure; |
michael@0 | 104 | } |
michael@0 | 105 | |
michael@0 | 106 | @Override |
michael@0 | 107 | public final Socket getSocket() { |
michael@0 | 108 | return this.socket; |
michael@0 | 109 | } |
michael@0 | 110 | |
michael@0 | 111 | public void opening(Socket sock, HttpHost target) throws IOException { |
michael@0 | 112 | assertNotOpen(); |
michael@0 | 113 | this.socket = sock; |
michael@0 | 114 | this.targetHost = target; |
michael@0 | 115 | |
michael@0 | 116 | // Check for shutdown after assigning socket, so that |
michael@0 | 117 | if (this.shutdown) { |
michael@0 | 118 | sock.close(); // allow this to throw... |
michael@0 | 119 | // ...but if it doesn't, explicitly throw one ourselves. |
michael@0 | 120 | throw new IOException("Connection already shutdown"); |
michael@0 | 121 | } |
michael@0 | 122 | } |
michael@0 | 123 | |
michael@0 | 124 | public void openCompleted(boolean secure, HttpParams params) throws IOException { |
michael@0 | 125 | assertNotOpen(); |
michael@0 | 126 | if (params == null) { |
michael@0 | 127 | throw new IllegalArgumentException |
michael@0 | 128 | ("Parameters must not be null."); |
michael@0 | 129 | } |
michael@0 | 130 | this.connSecure = secure; |
michael@0 | 131 | bind(this.socket, params); |
michael@0 | 132 | } |
michael@0 | 133 | |
michael@0 | 134 | /** |
michael@0 | 135 | * Force-closes this connection. |
michael@0 | 136 | * If the connection is still in the process of being open (the method |
michael@0 | 137 | * {@link #opening opening} was already called but |
michael@0 | 138 | * {@link #openCompleted openCompleted} was not), the associated |
michael@0 | 139 | * socket that is being connected to a remote address will be closed. |
michael@0 | 140 | * That will interrupt a thread that is blocked on connecting |
michael@0 | 141 | * the socket. |
michael@0 | 142 | * If the connection is not yet open, this will prevent the connection |
michael@0 | 143 | * from being opened. |
michael@0 | 144 | * |
michael@0 | 145 | * @throws IOException in case of a problem |
michael@0 | 146 | */ |
michael@0 | 147 | @Override |
michael@0 | 148 | public void shutdown() throws IOException { |
michael@0 | 149 | shutdown = true; |
michael@0 | 150 | try { |
michael@0 | 151 | super.shutdown(); |
michael@0 | 152 | log.debug("Connection shut down"); |
michael@0 | 153 | Socket sock = this.socket; // copy volatile attribute |
michael@0 | 154 | if (sock != null) |
michael@0 | 155 | sock.close(); |
michael@0 | 156 | } catch (IOException ex) { |
michael@0 | 157 | log.debug("I/O error shutting down connection", ex); |
michael@0 | 158 | } |
michael@0 | 159 | } |
michael@0 | 160 | |
michael@0 | 161 | @Override |
michael@0 | 162 | public void close() throws IOException { |
michael@0 | 163 | try { |
michael@0 | 164 | super.close(); |
michael@0 | 165 | log.debug("Connection closed"); |
michael@0 | 166 | } catch (IOException ex) { |
michael@0 | 167 | log.debug("I/O error closing connection", ex); |
michael@0 | 168 | } |
michael@0 | 169 | } |
michael@0 | 170 | |
michael@0 | 171 | @Override |
michael@0 | 172 | protected SessionInputBuffer createSessionInputBuffer( |
michael@0 | 173 | final Socket socket, |
michael@0 | 174 | int buffersize, |
michael@0 | 175 | final HttpParams params) throws IOException { |
michael@0 | 176 | if (buffersize == -1) { |
michael@0 | 177 | buffersize = 8192; |
michael@0 | 178 | } |
michael@0 | 179 | SessionInputBuffer inbuffer = super.createSessionInputBuffer( |
michael@0 | 180 | socket, |
michael@0 | 181 | buffersize, |
michael@0 | 182 | params); |
michael@0 | 183 | if (wireLog.isDebugEnabled()) { |
michael@0 | 184 | inbuffer = new LoggingSessionInputBuffer( |
michael@0 | 185 | inbuffer, |
michael@0 | 186 | new Wire(wireLog), |
michael@0 | 187 | HttpProtocolParams.getHttpElementCharset(params)); |
michael@0 | 188 | } |
michael@0 | 189 | return inbuffer; |
michael@0 | 190 | } |
michael@0 | 191 | |
michael@0 | 192 | @Override |
michael@0 | 193 | protected SessionOutputBuffer createSessionOutputBuffer( |
michael@0 | 194 | final Socket socket, |
michael@0 | 195 | int buffersize, |
michael@0 | 196 | final HttpParams params) throws IOException { |
michael@0 | 197 | if (buffersize == -1) { |
michael@0 | 198 | buffersize = 8192; |
michael@0 | 199 | } |
michael@0 | 200 | SessionOutputBuffer outbuffer = super.createSessionOutputBuffer( |
michael@0 | 201 | socket, |
michael@0 | 202 | buffersize, |
michael@0 | 203 | params); |
michael@0 | 204 | if (wireLog.isDebugEnabled()) { |
michael@0 | 205 | outbuffer = new LoggingSessionOutputBuffer( |
michael@0 | 206 | outbuffer, |
michael@0 | 207 | new Wire(wireLog), |
michael@0 | 208 | HttpProtocolParams.getHttpElementCharset(params)); |
michael@0 | 209 | } |
michael@0 | 210 | return outbuffer; |
michael@0 | 211 | } |
michael@0 | 212 | |
michael@0 | 213 | @Override |
michael@0 | 214 | protected HttpMessageParser createResponseParser( |
michael@0 | 215 | final SessionInputBuffer buffer, |
michael@0 | 216 | final HttpResponseFactory responseFactory, |
michael@0 | 217 | final HttpParams params) { |
michael@0 | 218 | // override in derived class to specify a line parser |
michael@0 | 219 | return new DefaultResponseParser |
michael@0 | 220 | (buffer, null, responseFactory, params); |
michael@0 | 221 | } |
michael@0 | 222 | |
michael@0 | 223 | public void update(Socket sock, HttpHost target, |
michael@0 | 224 | boolean secure, HttpParams params) |
michael@0 | 225 | throws IOException { |
michael@0 | 226 | |
michael@0 | 227 | assertOpen(); |
michael@0 | 228 | if (target == null) { |
michael@0 | 229 | throw new IllegalArgumentException |
michael@0 | 230 | ("Target host must not be null."); |
michael@0 | 231 | } |
michael@0 | 232 | if (params == null) { |
michael@0 | 233 | throw new IllegalArgumentException |
michael@0 | 234 | ("Parameters must not be null."); |
michael@0 | 235 | } |
michael@0 | 236 | |
michael@0 | 237 | if (sock != null) { |
michael@0 | 238 | this.socket = sock; |
michael@0 | 239 | bind(sock, params); |
michael@0 | 240 | } |
michael@0 | 241 | targetHost = target; |
michael@0 | 242 | connSecure = secure; |
michael@0 | 243 | } |
michael@0 | 244 | |
michael@0 | 245 | @Override |
michael@0 | 246 | public HttpResponse receiveResponseHeader() throws HttpException, IOException { |
michael@0 | 247 | HttpResponse response = super.receiveResponseHeader(); |
michael@0 | 248 | if (log.isDebugEnabled()) { |
michael@0 | 249 | log.debug("Receiving response: " + response.getStatusLine()); |
michael@0 | 250 | } |
michael@0 | 251 | if (headerLog.isDebugEnabled()) { |
michael@0 | 252 | headerLog.debug("<< " + response.getStatusLine().toString()); |
michael@0 | 253 | Header[] headers = response.getAllHeaders(); |
michael@0 | 254 | for (Header header : headers) { |
michael@0 | 255 | headerLog.debug("<< " + header.toString()); |
michael@0 | 256 | } |
michael@0 | 257 | } |
michael@0 | 258 | return response; |
michael@0 | 259 | } |
michael@0 | 260 | |
michael@0 | 261 | @Override |
michael@0 | 262 | public void sendRequestHeader(HttpRequest request) throws HttpException, IOException { |
michael@0 | 263 | if (log.isDebugEnabled()) { |
michael@0 | 264 | log.debug("Sending request: " + request.getRequestLine()); |
michael@0 | 265 | } |
michael@0 | 266 | super.sendRequestHeader(request); |
michael@0 | 267 | if (headerLog.isDebugEnabled()) { |
michael@0 | 268 | headerLog.debug(">> " + request.getRequestLine().toString()); |
michael@0 | 269 | Header[] headers = request.getAllHeaders(); |
michael@0 | 270 | for (Header header : headers) { |
michael@0 | 271 | headerLog.debug(">> " + header.toString()); |
michael@0 | 272 | } |
michael@0 | 273 | } |
michael@0 | 274 | } |
michael@0 | 275 | |
michael@0 | 276 | public Object getAttribute(final String id) { |
michael@0 | 277 | return this.attributes.get(id); |
michael@0 | 278 | } |
michael@0 | 279 | |
michael@0 | 280 | public Object removeAttribute(final String id) { |
michael@0 | 281 | return this.attributes.remove(id); |
michael@0 | 282 | } |
michael@0 | 283 | |
michael@0 | 284 | public void setAttribute(final String id, final Object obj) { |
michael@0 | 285 | this.attributes.put(id, obj); |
michael@0 | 286 | } |
michael@0 | 287 | |
michael@0 | 288 | } |