View Javadoc
1   /*
2    * ====================================================================
3    * Licensed to the Apache Software Foundation (ASF) under one
4    * or more contributor license agreements.  See the NOTICE file
5    * distributed with this work for additional information
6    * regarding copyright ownership.  The ASF licenses this file
7    * to you under the Apache License, Version 2.0 (the
8    * "License"); you may not use this file except in compliance
9    * with the License.  You may obtain a copy of the License at
10   *
11   *   http://www.apache.org/licenses/LICENSE-2.0
12   *
13   * Unless required by applicable law or agreed to in writing,
14   * software distributed under the License is distributed on an
15   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16   * KIND, either express or implied.  See the License for the
17   * specific language governing permissions and limitations
18   * under the License.
19   * ====================================================================
20   *
21   * This software consists of voluntary contributions made by many
22   * individuals on behalf of the Apache Software Foundation.  For more
23   * information on the Apache Software Foundation, please see
24   * <http://www.apache.org/>.
25   *
26   */
27  
28  package org.apache.http.impl.execchain;
29  
30  import java.io.IOException;
31  import java.io.InputStream;
32  import java.io.OutputStream;
33  import java.net.SocketException;
34  
35  import org.apache.http.HttpEntity;
36  import org.apache.http.HttpResponse;
37  import org.apache.http.conn.EofSensorInputStream;
38  import org.apache.http.conn.EofSensorWatcher;
39  import org.apache.http.entity.HttpEntityWrapper;
40  
41  /**
42   * A wrapper class for {@link HttpEntity} enclosed in a response message.
43   *
44   * @since 4.3
45   */
46  class ResponseEntityProxy extends HttpEntityWrapper implements EofSensorWatcher {
47  
48      private final ConnectionHolder connHolder;
49  
50      public static void enchance(final HttpResponse response, final ConnectionHolder connHolder) {
51          final HttpEntity entity = response.getEntity();
52          if (entity != null && entity.isStreaming() && connHolder != null) {
53              response.setEntity(new ResponseEntityProxy(entity, connHolder));
54          }
55      }
56  
57      ResponseEntityProxy(final HttpEntity entity, final ConnectionHolder connHolder) {
58          super(entity);
59          this.connHolder = connHolder;
60      }
61  
62      private void cleanup() throws IOException {
63          if (this.connHolder != null) {
64              this.connHolder.close();
65          }
66      }
67  
68      private void abortConnection() throws IOException {
69          if (this.connHolder != null) {
70              this.connHolder.abortConnection();
71          }
72      }
73  
74      public void releaseConnection() throws IOException {
75          if (this.connHolder != null) {
76              this.connHolder.releaseConnection();
77          }
78      }
79  
80      @Override
81      public boolean isRepeatable() {
82          return false;
83      }
84  
85      @Override
86      public InputStream getContent() throws IOException {
87          return new EofSensorInputStream(this.wrappedEntity.getContent(), this);
88      }
89  
90      @Deprecated
91      @Override
92      public void consumeContent() throws IOException {
93          releaseConnection();
94      }
95  
96      @Override
97      public void writeTo(final OutputStream outstream) throws IOException {
98          try {
99              if (outstream != null) {
100                 this.wrappedEntity.writeTo(outstream);
101             }
102             releaseConnection();
103         } catch (final IOException ex) {
104             abortConnection();
105             throw ex;
106         } catch (final RuntimeException ex) {
107             abortConnection();
108             throw ex;
109         } finally {
110             cleanup();
111         }
112     }
113 
114     @Override
115     public boolean eofDetected(final InputStream wrapped) throws IOException {
116         try {
117             // there may be some cleanup required, such as
118             // reading trailers after the response body:
119             if (wrapped != null) {
120                 wrapped.close();
121             }
122             releaseConnection();
123         } catch (final IOException ex) {
124             abortConnection();
125             throw ex;
126         } catch (final RuntimeException ex) {
127             abortConnection();
128             throw ex;
129         } finally {
130             cleanup();
131         }
132         return false;
133     }
134 
135     @Override
136     public boolean streamClosed(final InputStream wrapped) throws IOException {
137         try {
138             final boolean open = connHolder != null && !connHolder.isReleased();
139             // this assumes that closing the stream will
140             // consume the remainder of the response body:
141             try {
142                 if (wrapped != null) {
143                     wrapped.close();
144                 }
145                 releaseConnection();
146             } catch (final SocketException ex) {
147                 if (open) {
148                     throw ex;
149                 }
150             }
151         } catch (final IOException ex) {
152             abortConnection();
153             throw ex;
154         } catch (final RuntimeException ex) {
155             abortConnection();
156             throw ex;
157         } finally {
158             cleanup();
159         }
160         return false;
161     }
162 
163     @Override
164     public boolean streamAbort(final InputStream wrapped) throws IOException {
165         cleanup();
166         return false;
167     }
168 
169     @Override
170     public String toString() {
171         final StringBuilder sb = new StringBuilder("ResponseEntityProxy{");
172         sb.append(wrappedEntity);
173         sb.append('}');
174         return sb.toString();
175     }
176 
177 }