1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28 package org.apache.http.protocol;
29
30 import java.io.IOException;
31
32 import org.apache.http.HttpClientConnection;
33 import org.apache.http.HttpEntityEnclosingRequest;
34 import org.apache.http.HttpException;
35 import org.apache.http.HttpRequest;
36 import org.apache.http.HttpResponse;
37 import org.apache.http.HttpStatus;
38 import org.apache.http.HttpVersion;
39 import org.apache.http.ProtocolException;
40 import org.apache.http.ProtocolVersion;
41 import org.apache.http.annotation.Contract;
42 import org.apache.http.annotation.ThreadingBehavior;
43 import org.apache.http.util.Args;
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58 @Contract(threading = ThreadingBehavior.IMMUTABLE)
59 public class HttpRequestExecutor {
60
61 public static final int DEFAULT_WAIT_FOR_CONTINUE = 3000;
62
63 private final int waitForContinue;
64
65
66
67
68
69
70 public HttpRequestExecutor(final int waitForContinue) {
71 super();
72 this.waitForContinue = Args.positive(waitForContinue, "Wait for continue time");
73 }
74
75 public HttpRequestExecutor() {
76 this(DEFAULT_WAIT_FOR_CONTINUE);
77 }
78
79
80
81
82
83
84
85
86
87
88
89
90 protected boolean canResponseHaveBody(final HttpRequest request,
91 final HttpResponse response) {
92
93 if ("HEAD".equalsIgnoreCase(request.getRequestLine().getMethod())) {
94 return false;
95 }
96 final int status = response.getStatusLine().getStatusCode();
97 return status >= HttpStatus.SC_OK
98 && status != HttpStatus.SC_NO_CONTENT
99 && status != HttpStatus.SC_NOT_MODIFIED
100 && status != HttpStatus.SC_RESET_CONTENT;
101 }
102
103
104
105
106
107
108
109
110
111
112
113
114
115 public HttpResponse execute(
116 final HttpRequest request,
117 final HttpClientConnection conn,
118 final HttpContext context) throws IOException, HttpException {
119 Args.notNull(request, "HTTP request");
120 Args.notNull(conn, "Client connection");
121 Args.notNull(context, "HTTP context");
122 try {
123 HttpResponse response = doSendRequest(request, conn, context);
124 if (response == null) {
125 response = doReceiveResponse(request, conn, context);
126 }
127 return response;
128 } catch (final IOException ex) {
129 closeConnection(conn);
130 throw ex;
131 } catch (final HttpException ex) {
132 closeConnection(conn);
133 throw ex;
134 } catch (final RuntimeException ex) {
135 closeConnection(conn);
136 throw ex;
137 }
138 }
139
140 private static void closeConnection(final HttpClientConnection conn) {
141 try {
142 conn.close();
143 } catch (final IOException ignore) {
144 }
145 }
146
147
148
149
150
151
152
153
154
155
156
157
158
159 public void preProcess(
160 final HttpRequest request,
161 final HttpProcessor processor,
162 final HttpContext context) throws HttpException, IOException {
163 Args.notNull(request, "HTTP request");
164 Args.notNull(processor, "HTTP processor");
165 Args.notNull(context, "HTTP context");
166 context.setAttribute(HttpCoreContext.HTTP_REQUEST, request);
167 processor.process(request, context);
168 }
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192 protected HttpResponse doSendRequest(
193 final HttpRequest request,
194 final HttpClientConnection conn,
195 final HttpContext context) throws IOException, HttpException {
196 Args.notNull(request, "HTTP request");
197 Args.notNull(conn, "Client connection");
198 Args.notNull(context, "HTTP context");
199
200 HttpResponse response = null;
201
202 context.setAttribute(HttpCoreContext.HTTP_CONNECTION, conn);
203 context.setAttribute(HttpCoreContext.HTTP_REQ_SENT, Boolean.FALSE);
204
205 conn.sendRequestHeader(request);
206 if (request instanceof HttpEntityEnclosingRequest) {
207
208
209
210 boolean sendentity = true;
211 final ProtocolVersion ver =
212 request.getRequestLine().getProtocolVersion();
213 if (((HttpEntityEnclosingRequest) request).expectContinue() &&
214 !ver.lessEquals(HttpVersion.HTTP_1_0)) {
215
216 conn.flush();
217
218
219 if (conn.isResponseAvailable(this.waitForContinue)) {
220 response = conn.receiveResponseHeader();
221 if (canResponseHaveBody(request, response)) {
222 conn.receiveResponseEntity(response);
223 }
224 final int status = response.getStatusLine().getStatusCode();
225 if (status < 200) {
226 if (status != HttpStatus.SC_CONTINUE) {
227 throw new ProtocolException(
228 "Unexpected response: " + response.getStatusLine());
229 }
230
231 response = null;
232 } else {
233 sendentity = false;
234 }
235 }
236 }
237 if (sendentity) {
238 conn.sendRequestEntity((HttpEntityEnclosingRequest) request);
239 }
240 }
241 conn.flush();
242 context.setAttribute(HttpCoreContext.HTTP_REQ_SENT, Boolean.TRUE);
243 return response;
244 }
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261 protected HttpResponse doReceiveResponse(
262 final HttpRequest request,
263 final HttpClientConnection conn,
264 final HttpContext context) throws HttpException, IOException {
265 Args.notNull(request, "HTTP request");
266 Args.notNull(conn, "Client connection");
267 Args.notNull(context, "HTTP context");
268 HttpResponse response = null;
269 int statusCode = 0;
270
271 while (response == null || statusCode < HttpStatus.SC_OK) {
272
273 response = conn.receiveResponseHeader();
274 statusCode = response.getStatusLine().getStatusCode();
275 if (statusCode < HttpStatus.SC_CONTINUE) {
276 throw new ProtocolException("Invalid response: " + response.getStatusLine());
277 }
278 if (canResponseHaveBody(request, response)) {
279 conn.receiveResponseEntity(response);
280 }
281
282 }
283
284 return response;
285 }
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305 public void postProcess(
306 final HttpResponse response,
307 final HttpProcessor processor,
308 final HttpContext context) throws HttpException, IOException {
309 Args.notNull(response, "HTTP response");
310 Args.notNull(processor, "HTTP processor");
311 Args.notNull(context, "HTTP context");
312 context.setAttribute(HttpCoreContext.HTTP_RESPONSE, response);
313 processor.process(response, context);
314 }
315
316 }