Codebase list httpcomponents-asyncclient / 3784d98
Imported Upstream version 4.1 Emmanuel Bourg 8 years ago
137 changed file(s) with 22332 addition(s) and 0 deletion(s). Raw diff Collapse all Expand all
0 .classpath
1 .project
2 .settings
3 .clover
4 .externalToolBuilders
5 target
6 maven-eclipse.xml
7 .idea
8 *.iml
0 Building HttpComponents AsyncClient
1 ============================
2
3 (1) Requisites
4 --------------
5 JDK 1.6+ is required in order to compile and run HttpAsyncClient.
6
7 HttpAsyncClient utilizes Maven as a distribution management and packaging tool.
8 Version 3.0.3 or later is required.
9
10 Maven installation and configuration instructions can be found here:
11
12 http://maven.apache.org/run-maven/index.html
13
14 (2) Executing test cases
15
16 Execute the following command in order to compile and test the components
17
18 mvn test
19
20 (3) Building packages
21
22 Execute the following command in order to build the JAR packages
23
24 mvn package
25
26 The resultant packages can be found in the target folders of their respective modules
27
28 httpasyncclient/target/httpasyncclient-<VERSION>.jar
29 httpasyncclient-cache/target/httpasyncclient-cache-<VERSION>.jar
30 httpasyncclient-osgi/target/org.apache.httpcomponents.httpasyncclient_<VERSION>.jar
31
32 where <VERSION> is the release version
33
34 (4) Validating packages
35
36 Check for binary compatibility with the previous version with:
37
38 mvn clirr:check
39
40 Check for proper license headers with:
41
42 mvn apache-rat:check
43
44 (5) Building documentation
45
46 Execute the following commands in order to generate Javadoc:
47
48 mvn install
49 mvn javadoc:aggregate
50
0 Apache License
1 Version 2.0, January 2004
2 http://www.apache.org/licenses/
3
4 TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
5
6 1. Definitions.
7
8 "License" shall mean the terms and conditions for use, reproduction,
9 and distribution as defined by Sections 1 through 9 of this document.
10
11 "Licensor" shall mean the copyright owner or entity authorized by
12 the copyright owner that is granting the License.
13
14 "Legal Entity" shall mean the union of the acting entity and all
15 other entities that control, are controlled by, or are under common
16 control with that entity. For the purposes of this definition,
17 "control" means (i) the power, direct or indirect, to cause the
18 direction or management of such entity, whether by contract or
19 otherwise, or (ii) ownership of fifty percent (50%) or more of the
20 outstanding shares, or (iii) beneficial ownership of such entity.
21
22 "You" (or "Your") shall mean an individual or Legal Entity
23 exercising permissions granted by this License.
24
25 "Source" form shall mean the preferred form for making modifications,
26 including but not limited to software source code, documentation
27 source, and configuration files.
28
29 "Object" form shall mean any form resulting from mechanical
30 transformation or translation of a Source form, including but
31 not limited to compiled object code, generated documentation,
32 and conversions to other media types.
33
34 "Work" shall mean the work of authorship, whether in Source or
35 Object form, made available under the License, as indicated by a
36 copyright notice that is included in or attached to the work
37 (an example is provided in the Appendix below).
38
39 "Derivative Works" shall mean any work, whether in Source or Object
40 form, that is based on (or derived from) the Work and for which the
41 editorial revisions, annotations, elaborations, or other modifications
42 represent, as a whole, an original work of authorship. For the purposes
43 of this License, Derivative Works shall not include works that remain
44 separable from, or merely link (or bind by name) to the interfaces of,
45 the Work and Derivative Works thereof.
46
47 "Contribution" shall mean any work of authorship, including
48 the original version of the Work and any modifications or additions
49 to that Work or Derivative Works thereof, that is intentionally
50 submitted to Licensor for inclusion in the Work by the copyright owner
51 or by an individual or Legal Entity authorized to submit on behalf of
52 the copyright owner. For the purposes of this definition, "submitted"
53 means any form of electronic, verbal, or written communication sent
54 to the Licensor or its representatives, including but not limited to
55 communication on electronic mailing lists, source code control systems,
56 and issue tracking systems that are managed by, or on behalf of, the
57 Licensor for the purpose of discussing and improving the Work, but
58 excluding communication that is conspicuously marked or otherwise
59 designated in writing by the copyright owner as "Not a Contribution."
60
61 "Contributor" shall mean Licensor and any individual or Legal Entity
62 on behalf of whom a Contribution has been received by Licensor and
63 subsequently incorporated within the Work.
64
65 2. Grant of Copyright License. Subject to the terms and conditions of
66 this License, each Contributor hereby grants to You a perpetual,
67 worldwide, non-exclusive, no-charge, royalty-free, irrevocable
68 copyright license to reproduce, prepare Derivative Works of,
69 publicly display, publicly perform, sublicense, and distribute the
70 Work and such Derivative Works in Source or Object form.
71
72 3. Grant of Patent License. Subject to the terms and conditions of
73 this License, each Contributor hereby grants to You a perpetual,
74 worldwide, non-exclusive, no-charge, royalty-free, irrevocable
75 (except as stated in this section) patent license to make, have made,
76 use, offer to sell, sell, import, and otherwise transfer the Work,
77 where such license applies only to those patent claims licensable
78 by such Contributor that are necessarily infringed by their
79 Contribution(s) alone or by combination of their Contribution(s)
80 with the Work to which such Contribution(s) was submitted. If You
81 institute patent litigation against any entity (including a
82 cross-claim or counterclaim in a lawsuit) alleging that the Work
83 or a Contribution incorporated within the Work constitutes direct
84 or contributory patent infringement, then any patent licenses
85 granted to You under this License for that Work shall terminate
86 as of the date such litigation is filed.
87
88 4. Redistribution. You may reproduce and distribute copies of the
89 Work or Derivative Works thereof in any medium, with or without
90 modifications, and in Source or Object form, provided that You
91 meet the following conditions:
92
93 (a) You must give any other recipients of the Work or
94 Derivative Works a copy of this License; and
95
96 (b) You must cause any modified files to carry prominent notices
97 stating that You changed the files; and
98
99 (c) You must retain, in the Source form of any Derivative Works
100 that You distribute, all copyright, patent, trademark, and
101 attribution notices from the Source form of the Work,
102 excluding those notices that do not pertain to any part of
103 the Derivative Works; and
104
105 (d) If the Work includes a "NOTICE" text file as part of its
106 distribution, then any Derivative Works that You distribute must
107 include a readable copy of the attribution notices contained
108 within such NOTICE file, excluding those notices that do not
109 pertain to any part of the Derivative Works, in at least one
110 of the following places: within a NOTICE text file distributed
111 as part of the Derivative Works; within the Source form or
112 documentation, if provided along with the Derivative Works; or,
113 within a display generated by the Derivative Works, if and
114 wherever such third-party notices normally appear. The contents
115 of the NOTICE file are for informational purposes only and
116 do not modify the License. You may add Your own attribution
117 notices within Derivative Works that You distribute, alongside
118 or as an addendum to the NOTICE text from the Work, provided
119 that such additional attribution notices cannot be construed
120 as modifying the License.
121
122 You may add Your own copyright statement to Your modifications and
123 may provide additional or different license terms and conditions
124 for use, reproduction, or distribution of Your modifications, or
125 for any such Derivative Works as a whole, provided Your use,
126 reproduction, and distribution of the Work otherwise complies with
127 the conditions stated in this License.
128
129 5. Submission of Contributions. Unless You explicitly state otherwise,
130 any Contribution intentionally submitted for inclusion in the Work
131 by You to the Licensor shall be under the terms and conditions of
132 this License, without any additional terms or conditions.
133 Notwithstanding the above, nothing herein shall supersede or modify
134 the terms of any separate license agreement you may have executed
135 with Licensor regarding such Contributions.
136
137 6. Trademarks. This License does not grant permission to use the trade
138 names, trademarks, service marks, or product names of the Licensor,
139 except as required for reasonable and customary use in describing the
140 origin of the Work and reproducing the content of the NOTICE file.
141
142 7. Disclaimer of Warranty. Unless required by applicable law or
143 agreed to in writing, Licensor provides the Work (and each
144 Contributor provides its Contributions) on an "AS IS" BASIS,
145 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
146 implied, including, without limitation, any warranties or conditions
147 of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
148 PARTICULAR PURPOSE. You are solely responsible for determining the
149 appropriateness of using or redistributing the Work and assume any
150 risks associated with Your exercise of permissions under this License.
151
152 8. Limitation of Liability. In no event and under no legal theory,
153 whether in tort (including negligence), contract, or otherwise,
154 unless required by applicable law (such as deliberate and grossly
155 negligent acts) or agreed to in writing, shall any Contributor be
156 liable to You for damages, including any direct, indirect, special,
157 incidental, or consequential damages of any character arising as a
158 result of this License or out of the use or inability to use the
159 Work (including but not limited to damages for loss of goodwill,
160 work stoppage, computer failure or malfunction, or any and all
161 other commercial damages or losses), even if such Contributor
162 has been advised of the possibility of such damages.
163
164 9. Accepting Warranty or Additional Liability. While redistributing
165 the Work or Derivative Works thereof, You may choose to offer,
166 and charge a fee for, acceptance of support, warranty, indemnity,
167 or other liability obligations and/or rights consistent with this
168 License. However, in accepting such obligations, You may act only
169 on Your own behalf and on Your sole responsibility, not on behalf
170 of any other Contributor, and only if You agree to indemnify,
171 defend, and hold each Contributor harmless for any liability
172 incurred by, or claims asserted against, such Contributor by reason
173 of your accepting any such warranty or additional liability.
174
175 END OF TERMS AND CONDITIONS
176
177 This project contains annotations derived from JCIP-ANNOTATIONS
178 Copyright (c) 2005 Brian Goetz and Tim Peierls.
179 See http://www.jcip.net and the Creative Commons Attribution License
180 (http://creativecommons.org/licenses/by/2.5)
181
0 Apache HttpComponents AsyncClient
1 Copyright 2010-2015 The Apache Software Foundation
2
3 This product includes software developed at
4 The Apache Software Foundation (http://www.apache.org/).
0 Apache HttpComponents AsyncClient
1 ============================
2
3 Welcome to the HttpAsyncClient component of the Apache HttpComponents project.
4
5 Building Instructions
6 ---------------------
7
8 For building from source instructions please refer to BUILDING.txt.
9
10 Dependencies
11 ------------
12
13 HttpAsyncClient main module requires Java 5.0 compatible runtime and
14 depends on the following external libraries:
15
16 * Apache HttpComponents HttpCore
17 * Apache HttpComponents HttpCore NIO
18 * Apache HttpComponents HttpClient
19 * Apache Commons Logging
20 * Apache Commons Codec
21
22 (for detailed information on external dependencies please see pom.xml)
23
24 Licensing
25 ---------
26
27 Apache HttpComponents AsyncClient is licensed under the Apache License 2.0.
28 See the files called LICENSE.txt and NOTICE.txt for more information.
29
30 Cryptographic Software Notice
31 -----------------------------
32
33 This distribution may include software that has been designed for use
34 with cryptographic software. The country in which you currently reside
35 may have restrictions on the import, possession, use, and/or re-export
36 to another country, of encryption software. BEFORE using any encryption
37 software, please check your country's laws, regulations and policies
38 concerning the import, possession, or use, and re-export of encryption
39 software, to see if this is permitted. See <http://www.wassenaar.org/>
40 for more information.
41
42 The U.S. Government Department of Commerce, Bureau of Industry and
43 Security (BIS), has classified this software as Export Commodity
44 Control Number (ECCN) 5D002.C.1, which includes information security
45 software using or performing cryptographic functions with asymmetric
46 algorithms. The form and manner of this Apache Software Foundation
47 distribution makes it eligible for export under the License Exception
48 ENC Technology Software Unrestricted (TSU) exception (see the BIS
49 Export Administration Regulations, Section 740.13) for both object
50 code and source code.
51
52 The following provides more details on the included software that
53 may be subject to export controls on cryptographic software:
54
55 Apache HttpComponents AsyncClient interfaces with the
56 Java Secure Socket Extension (JSSE) API to provide
57
58 - HTTPS support
59
60 Apache HttpComponents AsyncClient does not include any
61 implementation of JSSE.
62
63 Contact
64 -------
65
66 o For general information visit the main project site at
67 http://hc.apache.org/
68
69 o For current status information visit the status page at
70 http://hc.apache.org/status.html
0 Release 4.1
1 -------------------
2
3 This is the first stable (GA) release of HttpAsyncClient 4.1. Notable features and enhancements
4 included in 4.1 series are:
5
6 * Support for pipelined request execution
7
8 * Support for the latest HTTP state management specification (RFC 6265). Please note that the old
9 cookie policy is still used by default for compatibility reasons. RFC 6265 compliant cookie
10 policies need to be explicitly configured by the user. Please also note that as of next feature
11 release support for Netscape draft, RFC 2109 and RFC 2965 cookie policies will be deprecated
12 and disabled by default. It is recommended to use RFC 6265 compliant policies for new applications
13 unless compatibility with RFC 2109 and RFC 2965 is required and to migrate existing applications
14 to the default cookie policy.
15
16 * Enhanced, redesigned and rewritten default SSL hostname verifier with improved RFC 2818
17 compliance
18
19 * Default SSL hostname verifier and default cookie policy now validate certificate identity
20 and cookie domain of origin against the public suffix list maintained by Mozilla.org
21 <https://publicsuffix.org/list>
22
23 * Authentication cache thread-safety: authentication cache used by HttpClient is now thread-safe
24 and can be shared by multiple threads in order to re-use authentication state for subsequent
25 requests
26
27
28 Changelog:
29 -------------------
30
31 * [HTTPASYNC-90] Fixed SNI support.
32 Contributed by David <dblack at atlassian.com>
33
34 * [HTTPASYNC-88] persistent connections can time out while kept alive in the pool
35 causing unexpected SocketTimeoutException
36 Contributed by Oleg Kalnichevski <olegk at apache.org>
37
38 * [HTTPASYNC-86]: fixed a race condition upon connection lease from the connection pool:
39 in very rare circumstances the main execution thread can get jammed for so long
40 that the I/O dispatch thread succeeds in completing the request and releasing the connection
41 while the main still is performing connection validation.
42 Contributed by Oleg Kalnichevski <olegk at apache.org>
43
44 * Update Apache Commons Logging version from 1.1.3 to 1.2.
45 Contributed by Gary Gregory <ggregory at apache.org>
46
47
48 Release 4.1 BETA1
49 -------------------
50
51 This is the first BETA release of HttpAsyncClient 4.1. Notable features and enhancements included
52 in 4.1 series are:
53
54 * Support for pipelined request execution
55
56 * Enhanced redesigned and rewritten default SSL hostname verifier with improved RFC 2818
57 compliance
58
59 * Default SSL hostname verifier and default cookie policy now validate certificate identity
60 and cookie domain of origin against the public suffix list maintained by Mozilla.org
61 <https://publicsuffix.org/list>
62
63 * Authentication cache thread-safety: authentication caches used by HttpAsyncClient is now
64 thread-safe and can be shared by multiple contexts in order to re-use authentication state for
65 subsequent requests
66
67
68 Release 4.0.2
69 -------------------
70
71 HttpAsyncClient 4.0.2 (GA) is a bug fix release that addresses several issues reported since
72 release 4.0.1. This release also upgrades HttpClient dependency to the latest stable version.
73
74 All users of HttpAsyncClient 4.0 are strongly advised to upgrade.
75
76 Changelog
77 -------------------
78
79 * [HTTPASYNC-79] Rearranged sequence of operations upon connection lease to eliminate possibility
80 of a connection leak due to race condition on keep-alive boundary
81 Contributed by Oleg Kalnichevski <olegk at apache.org>
82
83 * Replaced dynamic proxies with custom proxy classes to reduce thread contention.
84 Contributed by Oleg Kalnichevski <olegk at apache.org>
85
86 * [HTTPASYNC-73] Original request headers are not copied upon redirect
87 Contributed by Oleg Kalnichevski <olegk at apache.org>
88
89
90
91 Release 4.0.1
92 -------------------
93
94 This maintenance release fixes a number of bugs including incorrect OSGi bundle metadata
95 found since release 4.0. This release also upgrades HttpCore and HttpClient dependencies to
96 the latest stable versions.
97
98 All users of HttpAsyncClient 4.0 are advised to upgrade.
99
100 Changelog
101 -------------------
102
103 * [HTTPASYNC-69] Premature cancellation of the response consumer to immediately shut down
104 and release the underlying connection.
105 Contributed by Oleg Kalnichevski <olegk at apache.org>
106
107 * [HTTPASYNC-68] Connection closed by the opposite endpoint immediately upon its lease from
108 the pool is never released back and reclaimed by the pool (collection leak).
109 Contributed by Dmitry Potapov <potapov.d at gmail.com>
110
111 * Persistent connections always get discarded in case of a response future cancellation
112 even if they can be kept alive.
113 Contributed by Oleg Kalnichevski <olegk at apache.org>
114
115 * [HTTPASYNC-64] Race conditions in async caching module.
116 Contributed by Oleg Kalnichevski <olegk at apache.org>
117
118 * [HTTPASYNC-65] Relaxed OSGi dependency import version ranges
119 Contributed by Christian Schneider <chris at die-schneider.net>
120
121 * [HTTPCLIENT-1446] NTLM proxy + BASIC target auth fails with 'Unexpected state:
122 MSG_TYPE3_GENERATED'.
123 Contributed by Oleg Kalnichevski <olegk at apache.org>
124
125 * [HTTPASYNC-63] ConnectionShutdownException thrown in case of out-of-sequence response.
126 Contributed by Oleg Kalnichevski <olegk at apache.org>
127
128 * [HTTPCLIENT-1442] Authentication header set by the user gets removed in case
129 of proxy authentication.
130 Contributed by Oleg Kalnichevski <olegk at apache.org>
131
132 * [HTTPASYNC-60] Fixed incorrect OSGi Symbolic-BundleName.
133 Contributed by M. van Cuijk <mark at phedny.net>
134
135
136
137 Release 4.0
138 -------------------
139
140 This is the first stable (GA) release of Apache HttpAsyncClient 4.0. HttpAsyncClient is a library
141 for asynchronous client-side HTTP communication built on top of HttpCore NIO transport.
142 It is a complementary library to Apache HttpClient intended and optimized for special cases
143 whereby ability to scale to many thousands of concurrent connections is more important than
144 performance in terms of raw data throughput.
145
146 HttpAsyncClient 4.0 is designed to have similar APIs as Apache HttpClient 4.3 and a comparable
147 feature set. In addition HttpAsyncClient provides full support for zero-copy file upload and
148 download operations. It presently does not support transparent content decompression and automatic
149 I/O error recovery. These features may be added in future releases.
150
151
152 Changelog:
153 -------------------
154
155 * [HTTPASYNC-56] Fixed thread deadlock in DefaultClientExchangeHandlerImpl.
156 Contributed by Oleg Kalnichevski <olegk at apache.org>
157
158 * [HTTPASYNC-57] HTTPS request execution via a HTTP proxy can cause an infinite loop.
159 Contributed by Oleg Kalnichevski <olegk at apache.org>
160
161 * [HTTPASYNC-52] Proxy configuration set at the request level does not apply.
162 Contributed by Oleg Kalnichevski <olegk at apache.org>
163
164 * [HTTPASYNC-51] Request producers do not get correctly reset if the server responds early
165 (out of sequence), which can cause entity enclosing requests to be malformed in case of
166 re-execution.
167 Contributed by Oleg Kalnichevski <olegk at apache.org>
168
169 * [HTTPASYNC-45] CachingHttpAsyncClient to override Future returned by the backend.
170 Contributed by James Leigh <james at 3roundstones dot com>
171
172
173 Release 4.0 Beta 4
174 -------------------
175
176 The 4.0 BETA4 release delivers significant performance improvements in request execution,
177 especially for short HTTP messages, and also re-aligns programming interfaces used by the library
178 with HttpCore 4.3 and HttpClient 4.3 APIs. Configuration and preference APIs of HttpAsyncClient
179 are now consistent with those used by HttpClient 4.3.
180
181 Users of previous releases of HttpAsyncClient are advised to upgrade.
182
183 Changelog:
184
185 * [HTTPCLIENT-1353] 303 Redirects Should be Cacheable
186 Contributed by James Leigh <james at 3roundstones dot com>
187
188 * Redesign of configuration and preference APIs.
189 Contributed by Oleg Kalnichevski <olegk at apache.org>
190
191 * Redesign of connection management APIs.
192 Contributed by Oleg Kalnichevski <olegk at apache.org>
193
194 * [HTTPASYNC-34] HttpAsyncClient fails to re-start request execution if the opposite end
195 prematurely terminates persistent connection.
196 Contributed by Oleg Kalnichevski <olegk at apache.org>
197
198 * [HTTPASYNC-28] PoolEntry's expiry information is never updated.
199 Contributed by Daniel Kulp <dkulp at apache.org>
200
201
202
203 Release 4.0 Beta 3
204 -------------------
205
206 The 4.0 BETA3 is a maintenance release that picks up the latest bug fixes in the core components.
207
208 Changelog:
209
210 * Upgraded HttpCore to version 4.2.2
211
212 * [HTTPASYNC-26] OSGi bundle import fix.
213 Contributed by Daniel Kulp <dkulp at apache.org>
214
215 * [HTTPASYNC-25] AsyncSchemeRegistry instance set in the execution context takes precedence over
216 the default one.
217 Contributed by Daniel Kulp <dkulp at apache.org>
218
219 * Ported fix for HTTPCLIENT-1224
220 Contributed by Oleg Kalnichevski <olegk at apache.org>
221
222
223 Release 4.0 Beta 2
224 -------------------
225
226 The 4.0 BETA2 release fixes a number of non-critical issues found since release 4.0-beta1 and
227 introduces basic support for HTTP/1.1 response caching. Please note that caching for streaming
228 HTTP exchanges is currently not supported.
229
230 Users of previous releases of HttpAsyncClient are advised to upgrade.
231
232 Changelog:
233
234 * [HTTPASYNC-20] HTTP exchange can now be aborted with HttpUriRequest#abort().
235 Contributed by Oleg Kalnichevski <olegk at apache.org>
236
237 * [HTTPASYNC-17] Caching HttpAsyncClient facade.
238 Contributed by Clinton Nielsen <clinton.h.nielsen at gmail.com>
239
240 * [HTTPASYNC-19] Fixed incorrect execution of message exchanges that span across multiple hosts
241 (for instance, in case of a request redirect).
242 Contributed by Oleg Kalnichevski <olegk at apache.org>
243
244 * [HTTPASYNC-18] Fixed thread deadlock that could occur in the DefaultAsyncRequestDirector
245 in case of a runtime exception.
246 Contributed by Oleg Kalnichevski <olegk at apache.org>
247
248 * [HTTPASYNC-15]: HttpAsyncClient hangs if connection leased from the pool gets immediately closed
249 by the opposite endpoint.
250 Contributed by Oleg Kalnichevski <olegk at apache.org>
251
252
253 Release 4.0 Beta 1
254 -------------------
255
256 The 4.0 BETA1 release completes the application programming interface and the feature set
257 of HttpAsyncClient and upgrades to the latest versions of core and client components
258 (HttpCore 4.2-beta1 and HttpClient 4.2-beta1). As of this release HttpAsyncClient is expected
259 to be API stable.
260
261 Users of previous releases of HttpAsyncClient are advised to upgrade.
262
263 Changelog:
264
265 * [HTTPASYNC-11]: HttpAsyncClient fails to re-authenticate if connection is non-persistent.
266 Contributed by Oleg Kalnichevski <olegk at apache.org>
267
268 * [HTTPASYNC-5]: Allow customized LineParser for asynchronous connections.
269 Contributed by Oleg Kalnichevski <olegk at apache.org>
270
271
272
273 Release 4.0 Alpha 3
274 -------------------
275
276 The 4.0 ALPHA3 release largely completes the application programming interface and feature set
277 of HttpAsyncClient. While the API may still change in the course of the ALPHA development phase,
278 this is expected to be the last round of major API changes and the API is expected to be reasonably
279 stable as of this release.
280
281 We are kindly asking actual and prospective users of HttpAsyncClient to review its API, evaluate
282 its functionality and give us feedback while the 4.0 API is still not final. If no major flaws
283 are discovered the 4.0 API is expected to be frozen with the next BETA release.
284
285 Changelog:
286
287 * [HTTPASYNC-6]: Fixed NPE in the DefaultAsyncRequestDirector#responseCompleted method.
288 Contributed by Oleg Kalnichevski <olegk at apache.org>
289
290
291 Release 4.0 Alpha 2
292 -------------------
293
294 The second ALPHA release of HttpAsyncClient 4.0 comes with a number of important improvements and
295 enhancements. As of this version HttpAsyncClient fully supports HTTP state management (cookies)
296 and HTTP authentication (basic, digest, NTLM, spnego/kerberos). Connection management classes have
297 been thoroughly reworked and improved. This version also improves support for zero copy file
298 upload / download operations.
299
300 The HttpAsyncClient 4.0 API is still considered experimental and is expected to change
301 in the course of the ALPHA development phase.
302
303 Please note that currently HttpAsyncClient DOES NOT support
304
305 * Stateful HTTP connections
306
307
308 Changelog:
309
310 * [HTTPASYNC-3]: Fixed incorrect handling of expired I/O sessions by SessionPool.
311 Contributed by Oleg Kalnichevski <olegk at apache.org>
312
313
314 Release 4.0 Alpha 1
315 -------------------
316
317 HttpAsyncClient is a library for asynchronous client-side HTTP communication built on HttpCore NIO
318 and HttpClient components.
319
320 HttpAsyncClient is NOT meant to replace or supersede Apache HttpClient. It is a complementary
321 library to Apache HttpClient intended for special cases where ability to handle a great number of
322 concurrent connections is more important than performance in terms of a raw data throughput or
323 for those users who prefer event-driven APIs.
324
325 The HttpAsyncClient 4.0 API is still very experimental and is expected to change in the course
326 of the ALPHA development phase.
327
328 Please note that currently HttpAsyncClient DOES NOT support
329
330 * HTTP state management (cookies)
331 * HTTP authentication
332 * Stateful HTTP connections
0 <?xml version="1.0"?>
1 <?xml-stylesheet type="text/xsl"?>
2 <rdf:RDF xml:lang="en"
3 xmlns="http://usefulinc.com/ns/doap#"
4 xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
5 xmlns:asfext="http://projects.apache.org/ns/asfext#"
6 xmlns:foaf="http://xmlns.com/foaf/0.1/">
7 <!--
8 ====================================================================
9 Licensed to the Apache Software Foundation (ASF) under one
10 or more contributor license agreements. See the NOTICE file
11 distributed with this work for additional information
12 regarding copyright ownership. The ASF licenses this file
13 to you under the Apache License, Version 2.0 (the
14 "License"); you may not use this file except in compliance
15 with the License. You may obtain a copy of the License at
16
17 http://www.apache.org/licenses/LICENSE-2.0
18
19 Unless required by applicable law or agreed to in writing,
20 software distributed under the License is distributed on an
21 "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
22 KIND, either express or implied. See the License for the
23 specific language governing permissions and limitations
24 under the License.
25 ====================================================================
26
27 This software consists of voluntary contributions made by many
28 individuals on behalf of the Apache Software Foundation. For more
29 information on the Apache Software Foundation, please see
30 <http://www.apache.org />.
31 -->
32
33 <Project rdf:about="http://hc.apache.org/httpcomponents-asyncclient/">
34 <created>2007-11-15</created>
35 <license rdf:resource="http://usefulinc.com/doap/licenses/asl20" />
36 <name>Apache HttpComponents AsyncClient</name>
37 <homepage rdf:resource="http://hc.apache.org/httpcomponents-asyncclient/" />
38 <asfext:pmc rdf:resource="http://httpcomponents.apache.org" />
39 <shortdesc>
40 Java library implementing an asynchronous HTTP client based on HttpCore NIO and HttpClient
41 components.
42 </shortdesc>
43 <description>
44 HttpAsyncClient is a library for asynchronous client-side HTTP communication built on HttpCore NIO
45 and HttpClient components. It is a complementary library to Apache HttpClient for special cases
46 where ability to handle a great number of concurrent connections is more important than
47 performance in terms of a raw data throughput.
48 </description>
49 <bug-database rdf:resource="http://issues.apache.org/jira/browse/HTTPASYNC" />
50 <mailing-list rdf:resource="http://httpcomponents.apache.org/mail-lists.html" />
51 <download-page rdf:resource="http://httpcomponents.apache.org/downloads.cgi" />
52 <programming-language>Java</programming-language>
53 <category rdf:resource="http://projects.apache.org/category/http" />
54 <category rdf:resource="http://projects.apache.org/category/library" />
55 <category rdf:resource="http://projects.apache.org/category/network-client" />
56
57 <!-- multiple releases can be listed, each in it's own section -->
58 <release>
59 <Version>
60 <name>httpcomponents-asyncclient-4.0-alpha1</name>
61 <created>2011-01-18</created>
62 <revision>4.0-alpha1</revision>
63 </Version>
64 <Version>
65 <name>httpcomponents-asyncclient-4.0-alpha2</name>
66 <created>2011-05-24</created>
67 <revision>4.0-alpha2</revision>
68 </Version>
69 <Version>
70 <name>httpcomponents-asyncclient-4.0-alpha3</name>
71 <created>2011-09-29</created>
72 <revision>4.0-alpha3</revision>
73 </Version>
74 </release>
75
76 <repository>
77 <SVNRepository>
78 <location rdf:resource="http://svn.apache.org/repos/asf/httpcomponents/httpasyncclient/trunk"/>
79 <browse rdf:resource="http://svn.apache.org/viewvc/httpcomponents/httpasyncclient/trunk"/>
80 </SVNRepository>
81 </repository>
82
83 <asfext:implements><asfext:Standard>
84 <asfext:title>Hypertext Transfer Protocol -- HTTP/1.1</asfext:title>
85 <asfext:body>IETF</asfext:body>
86 <asfext:id>RFC 2616</asfext:id>
87 <asfext:url rdf:resource="http://tools.ietf.org/html/rfc2616"/>
88 </asfext:Standard></asfext:implements>
89 <asfext:implements><asfext:Standard>
90 <asfext:title>Hypertext Transfer Protocol -- HTTP/1.0</asfext:title>
91 <asfext:body>IETF</asfext:body>
92 <asfext:id>RFC 1945</asfext:id>
93 <asfext:url rdf:resource="http://tools.ietf.org/html/rfc1945"/>
94 </asfext:Standard></asfext:implements>
95 <asfext:implements><asfext:Standard>
96 <asfext:title>Upgrading to TLS Within HTTP/1.1</asfext:title>
97 <asfext:body>IETF</asfext:body>
98 <asfext:id>RFC 2817</asfext:id>
99 <asfext:url rdf:resource="http://tools.ietf.org/html/rfc2817"/>
100 </asfext:Standard></asfext:implements>
101 <asfext:implements><asfext:Standard>
102 <asfext:title>HTTP Over TLS</asfext:title>
103 <asfext:body>IETF</asfext:body>
104 <asfext:id>RFC 2818</asfext:id>
105 <asfext:url rdf:resource="http://tools.ietf.org/html/rfc2818"/>
106 </asfext:Standard></asfext:implements>
107 <asfext:implements><asfext:Standard>
108 <asfext:title>HTTP Authentication: Basic and Digest Access Authentication</asfext:title>
109 <asfext:body>IETF</asfext:body>
110 <asfext:id>RFC 2617</asfext:id>
111 <asfext:url rdf:resource="http://tools.ietf.org/html/rfc2617"/>
112 </asfext:Standard></asfext:implements>
113 <asfext:implements><asfext:Standard>
114 <asfext:title>HTTP State Management Mechanism (Cookies)</asfext:title>
115 <asfext:body>IETF</asfext:body>
116 <asfext:id>RFC 2109</asfext:id>
117 <asfext:url rdf:resource="http://tools.ietf.org/html/rfc2109"/>
118 </asfext:Standard></asfext:implements>
119 <asfext:implements><asfext:Standard>
120 <asfext:title>HTTP State Management Mechanism (Cookie2)</asfext:title>
121 <asfext:body>IETF</asfext:body>
122 <asfext:id>RFC 2965</asfext:id>
123 <asfext:url rdf:resource="http://tools.ietf.org/html/rfc2965"/>
124 </asfext:Standard></asfext:implements>
125
126 </Project>
127 </rdf:RDF>
0 <?xml version="1.0" encoding="UTF-8"?>
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 --><project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
26 <modelVersion>4.0.0</modelVersion>
27 <parent>
28 <groupId>org.apache.httpcomponents</groupId>
29 <artifactId>httpcomponents-asyncclient</artifactId>
30 <version>4.1</version>
31 </parent>
32 <artifactId>httpasyncclient</artifactId>
33 <name>Apache HttpAsyncClient</name>
34 <description>
35 Apache HttpComponents AsyncClient
36 </description>
37 <url>http://hc.apache.org/httpcomponents-asyncclient</url>
38 <packaging>jar</packaging>
39
40 <dependencies>
41 <dependency>
42 <groupId>org.apache.httpcomponents</groupId>
43 <artifactId>httpcore</artifactId>
44 <scope>compile</scope>
45 </dependency>
46 <dependency>
47 <groupId>org.apache.httpcomponents</groupId>
48 <artifactId>httpcore-nio</artifactId>
49 <scope>compile</scope>
50 </dependency>
51 <dependency>
52 <groupId>org.apache.httpcomponents</groupId>
53 <artifactId>httpclient</artifactId>
54 <scope>compile</scope>
55 </dependency>
56 <dependency>
57 <groupId>commons-logging</groupId>
58 <artifactId>commons-logging</artifactId>
59 <scope>compile</scope>
60 </dependency>
61 <dependency>
62 <groupId>junit</groupId>
63 <artifactId>junit</artifactId>
64 <scope>test</scope>
65 </dependency>
66 <dependency>
67 <groupId>commons-io</groupId>
68 <artifactId>commons-io</artifactId>
69 <scope>test</scope>
70 </dependency>
71 <dependency>
72 <groupId>org.mockito</groupId>
73 <artifactId>mockito-core</artifactId>
74 <scope>test</scope>
75 </dependency>
76 </dependencies>
77
78 <build>
79 <resources>
80 <resource>
81 <directory>src/main/resources</directory>
82 <filtering>true</filtering>
83 <includes>
84 <include>**/*.properties</include>
85 </includes>
86 </resource>
87 </resources>
88 <plugins>
89 <plugin>
90 <groupId>org.codehaus.mojo</groupId>
91 <artifactId>build-helper-maven-plugin</artifactId>
92 <version>1.8</version>
93 <executions>
94 <execution>
95 <id>add-source</id>
96 <phase>generate-sources</phase>
97 <goals>
98 <goal>add-source</goal>
99 </goals>
100 <configuration>
101 <sources>
102 <source>src/main/java-deprecated</source>
103 </sources>
104 </configuration>
105 </execution>
106 </executions>
107 </plugin>
108 </plugins>
109 </build>
110
111 <reporting>
112 <plugins>
113
114 <plugin>
115 <artifactId>maven-javadoc-plugin</artifactId>
116 <version>${hc.javadoc.version}</version>
117 <configuration>
118 <source>${maven.compiler.source}</source>
119 <links>
120 <link>http://download.oracle.com/javase/1.5.0/docs/api/</link>
121 <link>http://hc.apache.org/httpcomponents-core-ga/httpcore/apidocs/</link>
122 <link>http://hc.apache.org/httpcomponents-client-ga/httpclient/apidocs/</link>
123 </links>
124 </configuration>
125 <reportSets>
126 <reportSet>
127 <reports>
128 <report>javadoc</report>
129 </reports>
130 </reportSet>
131 </reportSets>
132 </plugin>
133
134 <plugin>
135 <artifactId>maven-project-info-reports-plugin</artifactId>
136 <version>${hc.project-info.version}</version>
137 <inherited>false</inherited>
138 <reportSets>
139 <reportSet>
140 <reports>
141 <report>dependencies</report>
142 <report>dependency-info</report>
143 <report>summary</report>
144 </reports>
145 </reportSet>
146 </reportSets>
147 </plugin>
148
149 <plugin>
150 <artifactId>maven-jxr-plugin</artifactId>
151 <version>${hc.jxr.version}</version>
152 </plugin>
153
154 <plugin>
155 <artifactId>maven-surefire-report-plugin</artifactId>
156 <version>${hc.surefire-report.version}</version>
157 </plugin>
158
159 </plugins>
160 </reporting>
161
162 </project>
0 /*
1 * ====================================================================
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 * ====================================================================
19 *
20 * This software consists of voluntary contributions made by many
21 * individuals on behalf of the Apache Software Foundation. For more
22 * information on the Apache Software Foundation, please see
23 * <http://www.apache.org/>.
24 *
25 */
26 package org.apache.http.examples.nio.client;
27
28 import org.apache.http.HttpResponse;
29 import org.apache.http.auth.AuthScope;
30 import org.apache.http.auth.UsernamePasswordCredentials;
31 import org.apache.http.client.CredentialsProvider;
32 import org.apache.http.client.methods.HttpGet;
33 import org.apache.http.impl.client.BasicCredentialsProvider;
34 import org.apache.http.impl.nio.client.CloseableHttpAsyncClient;
35 import org.apache.http.impl.nio.client.HttpAsyncClients;
36
37 import java.util.concurrent.Future;
38
39 /**
40 * A simple example that uses HttpClient to execute an HTTP request against
41 * a target site that requires user authentication.
42 */
43 public class AsyncClientAuthentication {
44
45 public static void main(String[] args) throws Exception {
46 CredentialsProvider credsProvider = new BasicCredentialsProvider();
47 credsProvider.setCredentials(
48 new AuthScope("localhost", 443),
49 new UsernamePasswordCredentials("username", "password"));
50 CloseableHttpAsyncClient httpclient = HttpAsyncClients.custom()
51 .setDefaultCredentialsProvider(credsProvider)
52 .build();
53 try {
54 HttpGet httpget = new HttpGet("http://localhost/");
55
56 System.out.println("Executing request " + httpget.getRequestLine());
57 Future<HttpResponse> future = httpclient.execute(httpget, null);
58 HttpResponse response = future.get();
59 System.out.println("Response: " + response.getStatusLine());
60 System.out.println("Shutting down");
61 } finally {
62 httpclient.close();
63 }
64 }
65 }
0 /*
1 * ====================================================================
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 * ====================================================================
19 *
20 * This software consists of voluntary contributions made by many
21 * individuals on behalf of the Apache Software Foundation. For more
22 * information on the Apache Software Foundation, please see
23 * <http://www.apache.org/>.
24 *
25 */
26
27 package org.apache.http.examples.nio.client;
28
29 import java.net.InetAddress;
30 import java.net.UnknownHostException;
31 import java.nio.charset.CodingErrorAction;
32 import java.util.Arrays;
33 import java.util.concurrent.Future;
34
35 import javax.net.ssl.HostnameVerifier;
36 import javax.net.ssl.SSLContext;
37
38 import org.apache.http.Consts;
39 import org.apache.http.Header;
40 import org.apache.http.HttpHost;
41 import org.apache.http.HttpRequest;
42 import org.apache.http.HttpResponse;
43 import org.apache.http.ParseException;
44 import org.apache.http.client.CookieStore;
45 import org.apache.http.client.CredentialsProvider;
46 import org.apache.http.client.config.AuthSchemes;
47 import org.apache.http.client.config.CookieSpecs;
48 import org.apache.http.client.config.RequestConfig;
49 import org.apache.http.client.methods.HttpGet;
50 import org.apache.http.client.protocol.HttpClientContext;
51 import org.apache.http.config.ConnectionConfig;
52 import org.apache.http.config.MessageConstraints;
53 import org.apache.http.config.Registry;
54 import org.apache.http.config.RegistryBuilder;
55 import org.apache.http.conn.DnsResolver;
56 import org.apache.http.conn.routing.HttpRoute;
57 import org.apache.http.conn.ssl.DefaultHostnameVerifier;
58 import org.apache.http.conn.ssl.SSLContexts;
59 import org.apache.http.impl.DefaultHttpResponseFactory;
60 import org.apache.http.impl.client.BasicCookieStore;
61 import org.apache.http.impl.client.BasicCredentialsProvider;
62 import org.apache.http.impl.conn.SystemDefaultDnsResolver;
63 import org.apache.http.impl.nio.client.CloseableHttpAsyncClient;
64 import org.apache.http.impl.nio.client.HttpAsyncClients;
65 import org.apache.http.impl.nio.codecs.DefaultHttpRequestWriterFactory;
66 import org.apache.http.impl.nio.codecs.DefaultHttpResponseParser;
67 import org.apache.http.impl.nio.codecs.DefaultHttpResponseParserFactory;
68 import org.apache.http.impl.nio.conn.ManagedNHttpClientConnectionFactory;
69 import org.apache.http.impl.nio.conn.PoolingNHttpClientConnectionManager;
70 import org.apache.http.impl.nio.reactor.DefaultConnectingIOReactor;
71 import org.apache.http.impl.nio.reactor.IOReactorConfig;
72 import org.apache.http.message.BasicHeader;
73 import org.apache.http.message.BasicLineParser;
74 import org.apache.http.message.LineParser;
75 import org.apache.http.nio.NHttpMessageParser;
76 import org.apache.http.nio.NHttpMessageParserFactory;
77 import org.apache.http.nio.NHttpMessageWriterFactory;
78 import org.apache.http.nio.conn.ManagedNHttpClientConnection;
79 import org.apache.http.nio.conn.NHttpConnectionFactory;
80 import org.apache.http.nio.conn.NoopIOSessionStrategy;
81 import org.apache.http.nio.conn.SchemeIOSessionStrategy;
82 import org.apache.http.nio.conn.ssl.SSLIOSessionStrategy;
83 import org.apache.http.nio.reactor.ConnectingIOReactor;
84 import org.apache.http.nio.reactor.SessionInputBuffer;
85 import org.apache.http.nio.util.HeapByteBufferAllocator;
86 import org.apache.http.util.CharArrayBuffer;
87
88 /**
89 * This example demonstrates how to customize and configure the most common aspects
90 * of HTTP request execution and connection management.
91 */
92 public class AsyncClientConfiguration {
93
94 public final static void main(String[] args) throws Exception {
95
96 // Use custom message parser / writer to customize the way HTTP
97 // messages are parsed from and written out to the data stream.
98 NHttpMessageParserFactory<HttpResponse> responseParserFactory = new DefaultHttpResponseParserFactory() {
99
100 @Override
101 public NHttpMessageParser<HttpResponse> create(
102 final SessionInputBuffer buffer,
103 final MessageConstraints constraints) {
104 LineParser lineParser = new BasicLineParser() {
105
106 @Override
107 public Header parseHeader(final CharArrayBuffer buffer) {
108 try {
109 return super.parseHeader(buffer);
110 } catch (ParseException ex) {
111 return new BasicHeader(buffer.toString(), null);
112 }
113 }
114
115 };
116 return new DefaultHttpResponseParser(
117 buffer, lineParser, DefaultHttpResponseFactory.INSTANCE, constraints);
118 }
119
120 };
121 NHttpMessageWriterFactory<HttpRequest> requestWriterFactory = new DefaultHttpRequestWriterFactory();
122
123 // Use a custom connection factory to customize the process of
124 // initialization of outgoing HTTP connections. Beside standard connection
125 // configuration parameters HTTP connection factory can define message
126 // parser / writer routines to be employed by individual connections.
127 NHttpConnectionFactory<ManagedNHttpClientConnection> connFactory = new ManagedNHttpClientConnectionFactory(
128 requestWriterFactory, responseParserFactory, HeapByteBufferAllocator.INSTANCE);
129
130 // Client HTTP connection objects when fully initialized can be bound to
131 // an arbitrary network socket. The process of network socket initialization,
132 // its connection to a remote address and binding to a local one is controlled
133 // by a connection socket factory.
134
135 // SSL context for secure connections can be created either based on
136 // system or application specific properties.
137 SSLContext sslcontext = SSLContexts.createSystemDefault();
138 // Use custom hostname verifier to customize SSL hostname verification.
139 HostnameVerifier hostnameVerifier = new DefaultHostnameVerifier();
140
141 // Create a registry of custom connection session strategies for supported
142 // protocol schemes.
143 Registry<SchemeIOSessionStrategy> sessionStrategyRegistry = RegistryBuilder.<SchemeIOSessionStrategy>create()
144 .register("http", NoopIOSessionStrategy.INSTANCE)
145 .register("https", new SSLIOSessionStrategy(sslcontext, hostnameVerifier))
146 .build();
147
148 // Use custom DNS resolver to override the system DNS resolution.
149 DnsResolver dnsResolver = new SystemDefaultDnsResolver() {
150
151 @Override
152 public InetAddress[] resolve(final String host) throws UnknownHostException {
153 if (host.equalsIgnoreCase("myhost")) {
154 return new InetAddress[] { InetAddress.getByAddress(new byte[] {127, 0, 0, 1}) };
155 } else {
156 return super.resolve(host);
157 }
158 }
159
160 };
161
162 // Create I/O reactor configuration
163 IOReactorConfig ioReactorConfig = IOReactorConfig.custom()
164 .setIoThreadCount(Runtime.getRuntime().availableProcessors())
165 .setConnectTimeout(30000)
166 .setSoTimeout(30000)
167 .build();
168
169 // Create a custom I/O reactort
170 ConnectingIOReactor ioReactor = new DefaultConnectingIOReactor(ioReactorConfig);
171
172 // Create a connection manager with custom configuration.
173 PoolingNHttpClientConnectionManager connManager = new PoolingNHttpClientConnectionManager(
174 ioReactor, connFactory, sessionStrategyRegistry, dnsResolver);
175
176 // Create message constraints
177 MessageConstraints messageConstraints = MessageConstraints.custom()
178 .setMaxHeaderCount(200)
179 .setMaxLineLength(2000)
180 .build();
181 // Create connection configuration
182 ConnectionConfig connectionConfig = ConnectionConfig.custom()
183 .setMalformedInputAction(CodingErrorAction.IGNORE)
184 .setUnmappableInputAction(CodingErrorAction.IGNORE)
185 .setCharset(Consts.UTF_8)
186 .setMessageConstraints(messageConstraints)
187 .build();
188 // Configure the connection manager to use connection configuration either
189 // by default or for a specific host.
190 connManager.setDefaultConnectionConfig(connectionConfig);
191 connManager.setConnectionConfig(new HttpHost("somehost", 80), ConnectionConfig.DEFAULT);
192
193 // Configure total max or per route limits for persistent connections
194 // that can be kept in the pool or leased by the connection manager.
195 connManager.setMaxTotal(100);
196 connManager.setDefaultMaxPerRoute(10);
197 connManager.setMaxPerRoute(new HttpRoute(new HttpHost("somehost", 80)), 20);
198
199 // Use custom cookie store if necessary.
200 CookieStore cookieStore = new BasicCookieStore();
201 // Use custom credentials provider if necessary.
202 CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
203 // Create global request configuration
204 RequestConfig defaultRequestConfig = RequestConfig.custom()
205 .setCookieSpec(CookieSpecs.DEFAULT)
206 .setExpectContinueEnabled(true)
207 .setTargetPreferredAuthSchemes(Arrays.asList(AuthSchemes.NTLM, AuthSchemes.DIGEST))
208 .setProxyPreferredAuthSchemes(Arrays.asList(AuthSchemes.BASIC))
209 .build();
210
211 // Create an HttpClient with the given custom dependencies and configuration.
212 CloseableHttpAsyncClient httpclient = HttpAsyncClients.custom()
213 .setConnectionManager(connManager)
214 .setDefaultCookieStore(cookieStore)
215 .setDefaultCredentialsProvider(credentialsProvider)
216 .setProxy(new HttpHost("myproxy", 8080))
217 .setDefaultRequestConfig(defaultRequestConfig)
218 .build();
219
220 try {
221 HttpGet httpget = new HttpGet("http://localhost/");
222 // Request configuration can be overridden at the request level.
223 // They will take precedence over the one set at the client level.
224 RequestConfig requestConfig = RequestConfig.copy(defaultRequestConfig)
225 .setSocketTimeout(5000)
226 .setConnectTimeout(5000)
227 .setConnectionRequestTimeout(5000)
228 .setProxy(new HttpHost("myotherproxy", 8080))
229 .build();
230 httpget.setConfig(requestConfig);
231
232 // Execution context can be customized locally.
233 HttpClientContext localContext = HttpClientContext.create();
234 // Contextual attributes set the local context level will take
235 // precedence over those set at the client level.
236 localContext.setCookieStore(cookieStore);
237 localContext.setCredentialsProvider(credentialsProvider);
238
239 System.out.println("Executing request " + httpget.getRequestLine());
240
241 httpclient.start();
242
243 // Pass local context as a parameter
244 Future<HttpResponse> future = httpclient.execute(httpget, localContext, null);
245
246 // Please note that it may be unsafe to access HttpContext instance
247 // while the request is still being executed
248
249 HttpResponse response = future.get();
250 System.out.println("Response: " + response.getStatusLine());
251
252 // Once the request has been executed the local context can
253 // be used to examine updated state and various objects affected
254 // by the request execution.
255
256 // Last executed request
257 localContext.getRequest();
258 // Execution route
259 localContext.getHttpRoute();
260 // Target auth state
261 localContext.getTargetAuthState();
262 // Proxy auth state
263 localContext.getTargetAuthState();
264 // Cookie origin
265 localContext.getCookieOrigin();
266 // Cookie spec used
267 localContext.getCookieSpec();
268 // User security token
269 localContext.getUserToken();
270 } finally {
271 httpclient.close();
272 }
273 }
274
275 }
276
0 /*
1 * ====================================================================
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 * ====================================================================
19 *
20 * This software consists of voluntary contributions made by many
21 * individuals on behalf of the Apache Software Foundation. For more
22 * information on the Apache Software Foundation, please see
23 * <http://www.apache.org/>.
24 *
25 */
26
27 package org.apache.http.examples.nio.client;
28
29 import org.apache.http.HttpResponse;
30 import org.apache.http.client.CookieStore;
31 import org.apache.http.client.methods.HttpGet;
32 import org.apache.http.client.protocol.HttpClientContext;
33 import org.apache.http.cookie.Cookie;
34 import org.apache.http.impl.client.BasicCookieStore;
35 import org.apache.http.impl.nio.client.CloseableHttpAsyncClient;
36 import org.apache.http.impl.nio.client.HttpAsyncClients;
37
38 import java.util.List;
39 import java.util.concurrent.Future;
40
41 /**
42 * This example demonstrates the use of a local HTTP context populated with
43 * custom attributes.
44 */
45 public class AsyncClientCustomContext {
46
47 public final static void main(String[] args) throws Exception {
48 CloseableHttpAsyncClient httpclient = HttpAsyncClients.createDefault();
49 try {
50 // Create a local instance of cookie store
51 CookieStore cookieStore = new BasicCookieStore();
52
53 // Create local HTTP context
54 HttpClientContext localContext = HttpClientContext.create();
55 // Bind custom cookie store to the local context
56 localContext.setCookieStore(cookieStore);
57
58 HttpGet httpget = new HttpGet("http://localhost/");
59 System.out.println("Executing request " + httpget.getRequestLine());
60
61 httpclient.start();
62
63 // Pass local context as a parameter
64 Future<HttpResponse> future = httpclient.execute(httpget, localContext, null);
65
66 // Please note that it may be unsafe to access HttpContext instance
67 // while the request is still being executed
68
69 HttpResponse response = future.get();
70 System.out.println("Response: " + response.getStatusLine());
71 List<Cookie> cookies = cookieStore.getCookies();
72 for (int i = 0; i < cookies.size(); i++) {
73 System.out.println("Local cookie: " + cookies.get(i));
74 }
75 System.out.println("Shutting down");
76 } finally {
77 httpclient.close();
78 }
79 }
80
81 }
82
0 /*
1 * ====================================================================
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 * ====================================================================
19 *
20 * This software consists of voluntary contributions made by many
21 * individuals on behalf of the Apache Software Foundation. For more
22 * information on the Apache Software Foundation, please see
23 * <http://www.apache.org/>.
24 *
25 */
26 package org.apache.http.examples.nio.client;
27
28 import java.io.File;
29 import java.io.FileInputStream;
30 import java.security.KeyStore;
31 import java.util.concurrent.Future;
32
33 import javax.net.ssl.SSLContext;
34
35 import org.apache.http.HttpResponse;
36 import org.apache.http.client.methods.HttpGet;
37 import org.apache.http.conn.ssl.TrustSelfSignedStrategy;
38 import org.apache.http.impl.nio.client.CloseableHttpAsyncClient;
39 import org.apache.http.impl.nio.client.HttpAsyncClients;
40 import org.apache.http.nio.conn.ssl.SSLIOSessionStrategy;
41 import org.apache.http.ssl.SSLContexts;
42
43 /**
44 * This example demonstrates how to create secure connections with a custom SSL
45 * context.
46 */
47 public class AsyncClientCustomSSL {
48
49 public final static void main(String[] args) throws Exception {
50 KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
51 FileInputStream instream = new FileInputStream(new File("my.keystore"));
52 try {
53 trustStore.load(instream, "nopassword".toCharArray());
54 } finally {
55 instream.close();
56 }
57 // Trust own CA and all self-signed certs
58 SSLContext sslcontext = SSLContexts.custom()
59 .loadTrustMaterial(trustStore, new TrustSelfSignedStrategy())
60 .build();
61 // Allow TLSv1 protocol only
62 SSLIOSessionStrategy sslSessionStrategy = new SSLIOSessionStrategy(
63 sslcontext,
64 new String[] { "TLSv1" },
65 null,
66 SSLIOSessionStrategy.getDefaultHostnameVerifier());
67 CloseableHttpAsyncClient httpclient = HttpAsyncClients.custom()
68 .setSSLStrategy(sslSessionStrategy)
69 .build();
70 try {
71 httpclient.start();
72 HttpGet request = new HttpGet("https://issues.apache.org/");
73 Future<HttpResponse> future = httpclient.execute(request, null);
74 HttpResponse response = future.get();
75 System.out.println("Response: " + response.getStatusLine());
76 System.out.println("Shutting down");
77 } finally {
78 httpclient.close();
79 }
80 System.out.println("Done");
81 }
82
83 }
0 /*
1 * ====================================================================
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 * ====================================================================
19 *
20 * This software consists of voluntary contributions made by many
21 * individuals on behalf of the Apache Software Foundation. For more
22 * information on the Apache Software Foundation, please see
23 * <http://www.apache.org/>.
24 *
25 */
26 package org.apache.http.examples.nio.client;
27
28 import org.apache.http.HttpResponse;
29 import org.apache.http.client.methods.HttpGet;
30 import org.apache.http.concurrent.FutureCallback;
31 import org.apache.http.impl.nio.client.CloseableHttpAsyncClient;
32 import org.apache.http.impl.nio.client.HttpAsyncClients;
33 import org.apache.http.impl.nio.conn.PoolingNHttpClientConnectionManager;
34 import org.apache.http.impl.nio.reactor.DefaultConnectingIOReactor;
35 import org.apache.http.nio.conn.NHttpClientConnectionManager;
36 import org.apache.http.nio.reactor.ConnectingIOReactor;
37
38 import java.util.concurrent.CountDownLatch;
39 import java.util.concurrent.TimeUnit;
40
41 /**
42 * Example demonstrating how to evict expired and idle connections
43 * from the connection pool.
44 */
45 public class AsyncClientEvictExpiredConnections {
46
47 public static void main(String[] args) throws Exception {
48 ConnectingIOReactor ioReactor = new DefaultConnectingIOReactor();
49 PoolingNHttpClientConnectionManager cm = new PoolingNHttpClientConnectionManager(ioReactor);
50 cm.setMaxTotal(100);
51 CloseableHttpAsyncClient httpclient = HttpAsyncClients.custom()
52 .setConnectionManager(cm)
53 .build();
54 try {
55 httpclient.start();
56
57 // create an array of URIs to perform GETs on
58 String[] urisToGet = {
59 "http://hc.apache.org/",
60 "http://hc.apache.org/httpcomponents-core-ga/",
61 "http://hc.apache.org/httpcomponents-client-ga/",
62 };
63
64 IdleConnectionEvictor connEvictor = new IdleConnectionEvictor(cm);
65 connEvictor.start();
66
67 final CountDownLatch latch = new CountDownLatch(urisToGet.length);
68 for (final String uri: urisToGet) {
69 final HttpGet httpget = new HttpGet(uri);
70 httpclient.execute(httpget, new FutureCallback<HttpResponse>() {
71
72 @Override
73 public void completed(final HttpResponse response) {
74 latch.countDown();
75 System.out.println(httpget.getRequestLine() + "->" + response.getStatusLine());
76 }
77
78 @Override
79 public void failed(final Exception ex) {
80 latch.countDown();
81 System.out.println(httpget.getRequestLine() + "->" + ex);
82 }
83
84 @Override
85 public void cancelled() {
86 latch.countDown();
87 System.out.println(httpget.getRequestLine() + " cancelled");
88 }
89
90 });
91 }
92 latch.await();
93
94 // Sleep 10 sec and let the connection evictor do its job
95 Thread.sleep(20000);
96
97 // Shut down the evictor thread
98 connEvictor.shutdown();
99 connEvictor.join();
100
101 } finally {
102 httpclient.close();
103 }
104 }
105
106 public static class IdleConnectionEvictor extends Thread {
107
108 private final NHttpClientConnectionManager connMgr;
109
110 private volatile boolean shutdown;
111
112 public IdleConnectionEvictor(NHttpClientConnectionManager connMgr) {
113 super();
114 this.connMgr = connMgr;
115 }
116
117 @Override
118 public void run() {
119 try {
120 while (!shutdown) {
121 synchronized (this) {
122 wait(5000);
123 // Close expired connections
124 connMgr.closeExpiredConnections();
125 // Optionally, close connections
126 // that have been idle longer than 5 sec
127 connMgr.closeIdleConnections(5, TimeUnit.SECONDS);
128 }
129 }
130 } catch (InterruptedException ex) {
131 // terminate
132 }
133 }
134
135 public void shutdown() {
136 shutdown = true;
137 synchronized (this) {
138 notifyAll();
139 }
140 }
141
142 }
143
144 }
0 /*
1 * ====================================================================
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 * ====================================================================
19 *
20 * This software consists of voluntary contributions made by many
21 * individuals on behalf of the Apache Software Foundation. For more
22 * information on the Apache Software Foundation, please see
23 * <http://www.apache.org/>.
24 *
25 */
26
27 package org.apache.http.examples.nio.client;
28
29 import java.util.concurrent.Future;
30
31 import org.apache.http.HttpHost;
32 import org.apache.http.HttpResponse;
33 import org.apache.http.client.config.RequestConfig;
34 import org.apache.http.client.methods.HttpGet;
35 import org.apache.http.impl.nio.client.CloseableHttpAsyncClient;
36 import org.apache.http.impl.nio.client.HttpAsyncClients;
37
38 /**
39 * This example demonstrates a basic asynchronous HTTP request / response exchange
40 * via an HTTP proxy.
41 */
42 public class AsyncClientExecuteProxy {
43
44 public static void main(String[] args)throws Exception {
45 CloseableHttpAsyncClient httpclient = HttpAsyncClients.createDefault();
46 try {
47 httpclient.start();
48 HttpHost proxy = new HttpHost("someproxy", 8080);
49 RequestConfig config = RequestConfig.custom()
50 .setProxy(proxy)
51 .build();
52 HttpGet request = new HttpGet("https://issues.apache.org/");
53 request.setConfig(config);
54 Future<HttpResponse> future = httpclient.execute(request, null);
55 HttpResponse response = future.get();
56 System.out.println("Response: " + response.getStatusLine());
57 System.out.println("Shutting down");
58 } finally {
59 httpclient.close();
60 }
61 }
62
63 }
0 /*
1 * ====================================================================
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 * ====================================================================
19 *
20 * This software consists of voluntary contributions made by many
21 * individuals on behalf of the Apache Software Foundation. For more
22 * information on the Apache Software Foundation, please see
23 * <http://www.apache.org/>.
24 *
25 */
26 package org.apache.http.examples.nio.client;
27
28 import java.util.concurrent.Future;
29
30 import org.apache.http.HttpResponse;
31 import org.apache.http.client.methods.HttpGet;
32 import org.apache.http.impl.nio.client.CloseableHttpAsyncClient;
33 import org.apache.http.impl.nio.client.HttpAsyncClients;
34
35 /**
36 * This example demonstrates a basic asynchronous HTTP request / response exchange.
37 * Response content is buffered in memory for simplicity.
38 */
39 public class AsyncClientHttpExchange {
40
41 public static void main(final String[] args) throws Exception {
42 CloseableHttpAsyncClient httpclient = HttpAsyncClients.createDefault();
43 try {
44 httpclient.start();
45 HttpGet request = new HttpGet("http://www.apache.org/");
46 Future<HttpResponse> future = httpclient.execute(request, null);
47 HttpResponse response = future.get();
48 System.out.println("Response: " + response.getStatusLine());
49 System.out.println("Shutting down");
50 } finally {
51 httpclient.close();
52 }
53 System.out.println("Done");
54 }
55
56 }
0 /*
1 * ====================================================================
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 * ====================================================================
19 *
20 * This software consists of voluntary contributions made by many
21 * individuals on behalf of the Apache Software Foundation. For more
22 * information on the Apache Software Foundation, please see
23 * <http://www.apache.org/>.
24 *
25 */
26 package org.apache.http.examples.nio.client;
27
28 import java.util.concurrent.CountDownLatch;
29
30 import org.apache.http.HttpResponse;
31 import org.apache.http.client.config.RequestConfig;
32 import org.apache.http.client.methods.HttpGet;
33 import org.apache.http.concurrent.FutureCallback;
34 import org.apache.http.impl.nio.client.CloseableHttpAsyncClient;
35 import org.apache.http.impl.nio.client.HttpAsyncClients;
36
37 /**
38 * This example demonstrates a fully asynchronous execution of multiple HTTP exchanges
39 * where the result of an individual operation is reported using a callback interface.
40 */
41 public class AsyncClientHttpExchangeFutureCallback {
42
43 public static void main(final String[] args) throws Exception {
44 RequestConfig requestConfig = RequestConfig.custom()
45 .setSocketTimeout(3000)
46 .setConnectTimeout(3000).build();
47 CloseableHttpAsyncClient httpclient = HttpAsyncClients.custom()
48 .setDefaultRequestConfig(requestConfig)
49 .build();
50 try {
51 httpclient.start();
52 final HttpGet[] requests = new HttpGet[] {
53 new HttpGet("http://www.apache.org/"),
54 new HttpGet("https://www.verisign.com/"),
55 new HttpGet("http://www.google.com/")
56 };
57 final CountDownLatch latch = new CountDownLatch(requests.length);
58 for (final HttpGet request: requests) {
59 httpclient.execute(request, new FutureCallback<HttpResponse>() {
60
61 @Override
62 public void completed(final HttpResponse response) {
63 latch.countDown();
64 System.out.println(request.getRequestLine() + "->" + response.getStatusLine());
65 }
66
67 @Override
68 public void failed(final Exception ex) {
69 latch.countDown();
70 System.out.println(request.getRequestLine() + "->" + ex);
71 }
72
73 @Override
74 public void cancelled() {
75 latch.countDown();
76 System.out.println(request.getRequestLine() + " cancelled");
77 }
78
79 });
80 }
81 latch.await();
82 System.out.println("Shutting down");
83 } finally {
84 httpclient.close();
85 }
86 System.out.println("Done");
87 }
88
89 }
0 /*
1 * ====================================================================
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 * ====================================================================
19 *
20 * This software consists of voluntary contributions made by many
21 * individuals on behalf of the Apache Software Foundation. For more
22 * information on the Apache Software Foundation, please see
23 * <http://www.apache.org/>.
24 *
25 */
26 package org.apache.http.examples.nio.client;
27
28 import java.io.IOException;
29 import java.nio.CharBuffer;
30 import java.util.concurrent.Future;
31
32 import org.apache.http.HttpResponse;
33 import org.apache.http.impl.nio.client.CloseableHttpAsyncClient;
34 import org.apache.http.impl.nio.client.HttpAsyncClients;
35 import org.apache.http.nio.IOControl;
36 import org.apache.http.nio.client.methods.AsyncCharConsumer;
37 import org.apache.http.nio.client.methods.HttpAsyncMethods;
38 import org.apache.http.protocol.HttpContext;
39
40 /**
41 * This example demonstrates an asynchronous HTTP request / response exchange with
42 * a full content streaming.
43 */
44 public class AsyncClientHttpExchangeStreaming {
45
46 public static void main(final String[] args) throws Exception {
47 CloseableHttpAsyncClient httpclient = HttpAsyncClients.createDefault();
48 try {
49 httpclient.start();
50 Future<Boolean> future = httpclient.execute(
51 HttpAsyncMethods.createGet("http://localhost:8080/"),
52 new MyResponseConsumer(), null);
53 Boolean result = future.get();
54 if (result != null && result.booleanValue()) {
55 System.out.println("Request successfully executed");
56 } else {
57 System.out.println("Request failed");
58 }
59 System.out.println("Shutting down");
60 } finally {
61 httpclient.close();
62 }
63 System.out.println("Done");
64 }
65
66 static class MyResponseConsumer extends AsyncCharConsumer<Boolean> {
67
68 @Override
69 protected void onResponseReceived(final HttpResponse response) {
70 }
71
72 @Override
73 protected void onCharReceived(final CharBuffer buf, final IOControl ioctrl) throws IOException {
74 while (buf.hasRemaining()) {
75 System.out.print(buf.get());
76 }
77 }
78
79 @Override
80 protected void releaseResources() {
81 }
82
83 @Override
84 protected Boolean buildResult(final HttpContext context) {
85 return Boolean.TRUE;
86 }
87
88 }
89
90 }
0 /*
1 * ====================================================================
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 * ====================================================================
19 *
20 * This software consists of voluntary contributions made by many
21 * individuals on behalf of the Apache Software Foundation. For more
22 * information on the Apache Software Foundation, please see
23 * <http://www.apache.org/>.
24 *
25 */
26 package org.apache.http.examples.nio.client;
27
28 import java.util.Arrays;
29 import java.util.List;
30 import java.util.concurrent.Future;
31
32 import org.apache.http.HttpHost;
33 import org.apache.http.HttpRequest;
34 import org.apache.http.HttpResponse;
35 import org.apache.http.client.methods.HttpGet;
36 import org.apache.http.impl.nio.client.CloseableHttpPipeliningClient;
37 import org.apache.http.impl.nio.client.HttpAsyncClients;
38
39 /**
40 * This example demonstrates a pipelinfed execution of multiple HTTP request / response exchanges
41 * Response content is buffered in memory for simplicity.
42 */
43 public class AsyncClientPipelined {
44
45 public static void main(final String[] args) throws Exception {
46 CloseableHttpPipeliningClient httpclient = HttpAsyncClients.createPipelining();
47 try {
48 httpclient.start();
49
50 HttpHost targetHost = new HttpHost("localhost", 8080);
51 HttpGet[] resquests = {
52 new HttpGet("/docs/index.html"),
53 new HttpGet("/docs/introduction.html"),
54 new HttpGet("/docs/setup.html"),
55 new HttpGet("/docs/config/index.html")
56 };
57
58 Future<List<HttpResponse>> future = httpclient.execute(targetHost,
59 Arrays.<HttpRequest>asList(resquests), null);
60 List<HttpResponse> responses = future.get();
61 System.out.println(responses);
62
63 System.out.println("Shutting down");
64 } finally {
65 httpclient.close();
66 }
67 System.out.println("Done");
68 }
69
70 }
0 /*
1 * ====================================================================
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 * ====================================================================
19 *
20 * This software consists of voluntary contributions made by many
21 * individuals on behalf of the Apache Software Foundation. For more
22 * information on the Apache Software Foundation, please see
23 * <http://www.apache.org/>.
24 *
25 */
26 package org.apache.http.examples.nio.client;
27
28 import java.io.IOException;
29 import java.nio.CharBuffer;
30 import java.util.ArrayList;
31 import java.util.List;
32 import java.util.concurrent.Future;
33
34 import org.apache.http.HttpHost;
35 import org.apache.http.HttpRequest;
36 import org.apache.http.HttpResponse;
37 import org.apache.http.client.methods.HttpGet;
38 import org.apache.http.impl.nio.client.CloseableHttpPipeliningClient;
39 import org.apache.http.impl.nio.client.HttpAsyncClients;
40 import org.apache.http.nio.IOControl;
41 import org.apache.http.nio.client.methods.AsyncCharConsumer;
42 import org.apache.http.nio.protocol.BasicAsyncRequestProducer;
43 import org.apache.http.protocol.HttpContext;
44
45 /**
46 * This example demonstrates a pipelinfed execution of multiple HTTP request / response exchanges
47 * with a full content streaming.
48 */
49 public class AsyncClientPipelinedStreaming {
50
51 public static void main(final String[] args) throws Exception {
52 CloseableHttpPipeliningClient httpclient = HttpAsyncClients.createPipelining();
53 try {
54 httpclient.start();
55
56 HttpHost targetHost = new HttpHost("localhost", 8080);
57 HttpGet[] resquests = {
58 new HttpGet("/docs/index.html"),
59 new HttpGet("/docs/introduction.html"),
60 new HttpGet("/docs/setup.html"),
61 new HttpGet("/docs/config/index.html")
62 };
63
64 List<MyRequestProducer> requestProducers = new ArrayList<MyRequestProducer>();
65 List<MyResponseConsumer> responseConsumers = new ArrayList<MyResponseConsumer>();
66 for (HttpGet request: resquests) {
67 requestProducers.add(new MyRequestProducer(targetHost, request));
68 responseConsumers.add(new MyResponseConsumer(request));
69 }
70
71 Future<List<Boolean>> future = httpclient.execute(
72 targetHost, requestProducers, responseConsumers, null);
73 future.get();
74 System.out.println("Shutting down");
75 } finally {
76 httpclient.close();
77 }
78 System.out.println("Done");
79 }
80
81 static class MyRequestProducer extends BasicAsyncRequestProducer {
82
83 private final HttpRequest request;
84
85 MyRequestProducer(final HttpHost target, final HttpRequest request) {
86 super(target, request);
87 this.request = request;
88 }
89
90 @Override
91 public void requestCompleted(final HttpContext context) {
92 super.requestCompleted(context);
93 System.out.println();
94 System.out.println("Request sent: " + this.request.getRequestLine());
95 System.out.println("=================================================");
96 }
97 }
98
99 static class MyResponseConsumer extends AsyncCharConsumer<Boolean> {
100
101 private final HttpRequest request;
102
103 MyResponseConsumer(final HttpRequest request) {
104 this.request = request;
105 }
106
107 @Override
108 protected void onResponseReceived(final HttpResponse response) {
109 System.out.println();
110 System.out.println("Response received: " + response.getStatusLine() + " -> " + this.request.getRequestLine());
111 System.out.println("=================================================");
112 }
113
114 @Override
115 protected void onCharReceived(final CharBuffer buf, final IOControl ioctrl) throws IOException {
116 while (buf.hasRemaining()) {
117 System.out.print(buf.get());
118 }
119 }
120
121 @Override
122 protected void releaseResources() {
123 }
124
125 @Override
126 protected Boolean buildResult(final HttpContext context) {
127 System.out.println();
128 System.out.println("=================================================");
129 System.out.println();
130 return Boolean.TRUE;
131 }
132
133 }
134
135 }
0 /*
1 * ====================================================================
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 * ====================================================================
19 *
20 * This software consists of voluntary contributions made by many
21 * individuals on behalf of the Apache Software Foundation. For more
22 * information on the Apache Software Foundation, please see
23 * <http://www.apache.org/>.
24 *
25 */
26
27 package org.apache.http.examples.nio.client;
28
29 import org.apache.http.HttpHost;
30 import org.apache.http.HttpResponse;
31 import org.apache.http.auth.AuthScope;
32 import org.apache.http.auth.UsernamePasswordCredentials;
33 import org.apache.http.client.CredentialsProvider;
34 import org.apache.http.client.config.RequestConfig;
35 import org.apache.http.client.methods.HttpGet;
36 import org.apache.http.impl.client.BasicCredentialsProvider;
37 import org.apache.http.impl.nio.client.CloseableHttpAsyncClient;
38 import org.apache.http.impl.nio.client.HttpAsyncClients;
39
40 import java.util.concurrent.Future;
41
42 /**
43 * This example demonstrates a basic asynchronous HTTP request / response exchange
44 * over a secure connection tunneled through an authenticating proxy.
45 */
46 public class AsyncClientProxyAuthentication {
47
48 public static void main(String[] args)throws Exception {
49 CredentialsProvider credsProvider = new BasicCredentialsProvider();
50 credsProvider.setCredentials(
51 new AuthScope("someproxy", 8080),
52 new UsernamePasswordCredentials("username", "password"));
53 CloseableHttpAsyncClient httpclient = HttpAsyncClients.custom()
54 .setDefaultCredentialsProvider(credsProvider)
55 .build();
56 try {
57 httpclient.start();
58 HttpHost proxy = new HttpHost("someproxy", 8080);
59 RequestConfig config = RequestConfig.custom()
60 .setProxy(proxy)
61 .build();
62 HttpGet httpget = new HttpGet("https://issues.apache.org/");
63 httpget.setConfig(config);
64 Future<HttpResponse> future = httpclient.execute(httpget, null);
65 HttpResponse response = future.get();
66 System.out.println("Response: " + response.getStatusLine());
67 System.out.println("Shutting down");
68 } finally {
69 httpclient.close();
70 }
71 }
72
73 }
0 /*
1 * ====================================================================
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 * ====================================================================
19 *
20 * This software consists of voluntary contributions made by many
21 * individuals on behalf of the Apache Software Foundation. For more
22 * information on the Apache Software Foundation, please see
23 * <http://www.apache.org/>.
24 *
25 */
26 package org.apache.http.examples.nio.client;
27
28 import org.apache.http.HttpResponse;
29 import org.apache.http.client.methods.HttpGet;
30 import org.apache.http.concurrent.FutureCallback;
31 import org.apache.http.impl.nio.client.CloseableHttpAsyncClient;
32 import org.apache.http.impl.nio.client.HttpAsyncClients;
33 import org.apache.http.nio.IOControl;
34 import org.apache.http.nio.client.methods.AsyncCharConsumer;
35 import org.apache.http.nio.client.methods.HttpAsyncMethods;
36 import org.apache.http.nio.protocol.HttpAsyncRequestProducer;
37 import org.apache.http.protocol.HttpContext;
38
39 import java.io.IOException;
40 import java.nio.CharBuffer;
41 import java.util.concurrent.CountDownLatch;
42 import java.util.concurrent.Future;
43
44 public class QuickStart {
45
46 public static void main(String[] args) throws Exception {
47 CloseableHttpAsyncClient httpclient = HttpAsyncClients.createDefault();
48 try {
49 // Start the client
50 httpclient.start();
51
52 // Execute request
53 final HttpGet request1 = new HttpGet("http://www.apache.org/");
54 Future<HttpResponse> future = httpclient.execute(request1, null);
55 // and wait until response is received
56 HttpResponse response1 = future.get();
57 System.out.println(request1.getRequestLine() + "->" + response1.getStatusLine());
58
59 // One most likely would want to use a callback for operation result
60 final CountDownLatch latch1 = new CountDownLatch(1);
61 final HttpGet request2 = new HttpGet("http://www.apache.org/");
62 httpclient.execute(request2, new FutureCallback<HttpResponse>() {
63
64 @Override
65 public void completed(final HttpResponse response2) {
66 latch1.countDown();
67 System.out.println(request2.getRequestLine() + "->" + response2.getStatusLine());
68 }
69
70 @Override
71 public void failed(final Exception ex) {
72 latch1.countDown();
73 System.out.println(request2.getRequestLine() + "->" + ex);
74 }
75
76 @Override
77 public void cancelled() {
78 latch1.countDown();
79 System.out.println(request2.getRequestLine() + " cancelled");
80 }
81
82 });
83 latch1.await();
84
85 // In real world one most likely would want also want to stream
86 // request and response body content
87 final CountDownLatch latch2 = new CountDownLatch(1);
88 final HttpGet request3 = new HttpGet("http://www.apache.org/");
89 HttpAsyncRequestProducer producer3 = HttpAsyncMethods.create(request3);
90 AsyncCharConsumer<HttpResponse> consumer3 = new AsyncCharConsumer<HttpResponse>() {
91
92 HttpResponse response;
93
94 @Override
95 protected void onResponseReceived(final HttpResponse response) {
96 this.response = response;
97 }
98
99 @Override
100 protected void onCharReceived(final CharBuffer buf, final IOControl ioctrl) throws IOException {
101 // Do something useful
102 }
103
104 @Override
105 protected void releaseResources() {
106 }
107
108 @Override
109 protected HttpResponse buildResult(final HttpContext context) {
110 return this.response;
111 }
112
113 };
114 httpclient.execute(producer3, consumer3, new FutureCallback<HttpResponse>() {
115
116 @Override
117 public void completed(final HttpResponse response3) {
118 latch2.countDown();
119 System.out.println(request2.getRequestLine() + "->" + response3.getStatusLine());
120 }
121
122 @Override
123 public void failed(final Exception ex) {
124 latch2.countDown();
125 System.out.println(request2.getRequestLine() + "->" + ex);
126 }
127
128 @Override
129 public void cancelled() {
130 latch2.countDown();
131 System.out.println(request2.getRequestLine() + " cancelled");
132 }
133
134 });
135 latch2.await();
136
137 } finally {
138 httpclient.close();
139 }
140 }
141
142 }
0 /*
1 * ====================================================================
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 * ====================================================================
19 *
20 * This software consists of voluntary contributions made by many
21 * individuals on behalf of the Apache Software Foundation. For more
22 * information on the Apache Software Foundation, please see
23 * <http://www.apache.org/>.
24 *
25 */
26 package org.apache.http.examples.nio.client;
27
28 import java.io.File;
29 import java.util.concurrent.Future;
30
31 import org.apache.http.HttpResponse;
32 import org.apache.http.HttpStatus;
33 import org.apache.http.client.ClientProtocolException;
34 import org.apache.http.entity.ContentType;
35 import org.apache.http.impl.nio.client.CloseableHttpAsyncClient;
36 import org.apache.http.impl.nio.client.HttpAsyncClients;
37 import org.apache.http.nio.client.methods.ZeroCopyConsumer;
38 import org.apache.http.nio.client.methods.ZeroCopyPost;
39
40 /**
41 * This example demonstrates how HttpAsyncClient can be used to upload or download files
42 * without creating an intermediate content buffer in memory (zero copy file transfer).
43 */
44 public class ZeroCopyHttpExchange {
45
46 public static void main(final String[] args) throws Exception {
47 CloseableHttpAsyncClient httpclient = HttpAsyncClients.createDefault();
48 try {
49 httpclient.start();
50 File upload = new File(args[0]);
51 File download = new File(args[1]);
52 ZeroCopyPost httpost = new ZeroCopyPost("http://localhost:8080/", upload,
53 ContentType.create("text/plain"));
54 ZeroCopyConsumer<File> consumer = new ZeroCopyConsumer<File>(download) {
55
56 @Override
57 protected File process(
58 final HttpResponse response,
59 final File file,
60 final ContentType contentType) throws Exception {
61 if (response.getStatusLine().getStatusCode() != HttpStatus.SC_OK) {
62 throw new ClientProtocolException("Upload failed: " + response.getStatusLine());
63 }
64 return file;
65 }
66
67 };
68 Future<File> future = httpclient.execute(httpost, consumer, null);
69 File result = future.get();
70 System.out.println("Response file length: " + result.length());
71 System.out.println("Shutting down");
72 } finally {
73 httpclient.close();
74 }
75 System.out.println("Done");
76 }
77
78 }
0 /*
1 * ====================================================================
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 * ====================================================================
19 *
20 * This software consists of voluntary contributions made by many
21 * individuals on behalf of the Apache Software Foundation. For more
22 * information on the Apache Software Foundation, please see
23 * <http://www.apache.org/>.
24 *
25 */
26 package org.apache.http.impl.nio.client;
27
28 import java.io.IOException;
29 import java.util.concurrent.TimeUnit;
30 import java.util.concurrent.atomic.AtomicBoolean;
31 import java.util.concurrent.atomic.AtomicLong;
32 import java.util.concurrent.atomic.AtomicReference;
33
34 import org.apache.commons.logging.Log;
35 import org.apache.http.ConnectionClosedException;
36 import org.apache.http.ConnectionReuseStrategy;
37 import org.apache.http.HttpHost;
38 import org.apache.http.HttpResponse;
39 import org.apache.http.client.config.RequestConfig;
40 import org.apache.http.client.methods.HttpRequestWrapper;
41 import org.apache.http.client.protocol.HttpClientContext;
42 import org.apache.http.concurrent.BasicFuture;
43 import org.apache.http.concurrent.FutureCallback;
44 import org.apache.http.conn.ConnectionKeepAliveStrategy;
45 import org.apache.http.conn.routing.HttpRoute;
46 import org.apache.http.conn.routing.RouteTracker;
47 import org.apache.http.nio.NHttpClientConnection;
48 import org.apache.http.nio.conn.NHttpClientConnectionManager;
49 import org.apache.http.nio.protocol.HttpAsyncClientExchangeHandler;
50 import org.apache.http.nio.protocol.HttpAsyncRequestExecutor;
51 import org.apache.http.util.Asserts;
52
53 /**
54 * Abstract {@link org.apache.http.nio.protocol.HttpAsyncClientExchangeHandler} class
55 * that implements connection management aspects shared by all HTTP exchange handlers.
56 * <p>
57 * Instances of this class are expected to be accessed by one thread at a time only.
58 * The {@link #cancel()} method can be called concurrently by multiple threads.
59 */
60 abstract class AbstractClientExchangeHandler<T> implements HttpAsyncClientExchangeHandler {
61
62 private static final AtomicLong COUNTER = new AtomicLong(1);
63
64 protected final Log log;
65
66 private final long id;
67 private final HttpClientContext localContext;
68 private final BasicFuture<T> resultFuture;
69 private final NHttpClientConnectionManager connmgr;
70 private final ConnectionReuseStrategy connReuseStrategy;
71 private final ConnectionKeepAliveStrategy keepaliveStrategy;
72 private final AtomicReference<NHttpClientConnection> managedConnRef;
73 private final AtomicReference<HttpRoute> routeRef;
74 private final AtomicReference<RouteTracker> routeTrackerRef;
75 private final AtomicBoolean routeEstablished;
76 private final AtomicReference<Long> validDurationRef;
77 private final AtomicReference<HttpRequestWrapper> requestRef;
78 private final AtomicReference<HttpResponse> responseRef;
79 private final AtomicBoolean completed;
80 private final AtomicBoolean closed;
81
82 AbstractClientExchangeHandler(
83 final Log log,
84 final HttpClientContext localContext,
85 final BasicFuture<T> resultFuture,
86 final NHttpClientConnectionManager connmgr,
87 final ConnectionReuseStrategy connReuseStrategy,
88 final ConnectionKeepAliveStrategy keepaliveStrategy) {
89 super();
90 this.log = log;
91 this.id = COUNTER.getAndIncrement();
92 this.localContext = localContext;
93 this.resultFuture = resultFuture;
94 this.connmgr = connmgr;
95 this.connReuseStrategy = connReuseStrategy;
96 this.keepaliveStrategy = keepaliveStrategy;
97 this.managedConnRef = new AtomicReference<NHttpClientConnection>(null);
98 this.routeRef = new AtomicReference<HttpRoute>(null);
99 this.routeTrackerRef = new AtomicReference<RouteTracker>(null);
100 this.routeEstablished = new AtomicBoolean(false);
101 this.validDurationRef = new AtomicReference<Long>(null);
102 this.requestRef = new AtomicReference<HttpRequestWrapper>(null);
103 this.responseRef = new AtomicReference<HttpResponse>(null);
104 this.completed = new AtomicBoolean(false);
105 this.closed = new AtomicBoolean(false);
106 }
107
108 final long getId() {
109 return this.id;
110 }
111
112 final boolean isCompleted() {
113 return this.completed.get();
114 }
115
116 final void markCompleted() {
117 this.completed.set(true);
118 }
119
120 final void markConnectionNonReusable() {
121 this.validDurationRef.set(null);
122 }
123
124 final boolean isRouteEstablished() {
125 return this.routeEstablished.get();
126 }
127
128 final HttpRoute getRoute() {
129 return this.routeRef.get();
130 }
131
132 final void setRoute(final HttpRoute route) {
133 this.routeRef.set(route);
134 }
135
136 final HttpRequestWrapper getCurrentRequest() {
137 return this.requestRef.get();
138 }
139
140 final void setCurrentRequest(final HttpRequestWrapper request) {
141 this.requestRef.set(request);
142 }
143
144 final HttpResponse getCurrentResponse() {
145 return this.responseRef.get();
146 }
147
148 final void setCurrentResponse(final HttpResponse response) {
149 this.responseRef.set(response);
150 }
151
152 final HttpRoute getActualRoute() {
153 final RouteTracker routeTracker = this.routeTrackerRef.get();
154 return routeTracker != null ? routeTracker.toRoute() : null;
155 }
156
157 final void verifytRoute() {
158 if (!this.routeEstablished.get() && this.routeTrackerRef.get() == null) {
159 final NHttpClientConnection managedConn = this.managedConnRef.get();
160 Asserts.check(managedConn != null, "Inconsistent state: managed connection is null");
161 final boolean routeComplete = this.connmgr.isRouteComplete(managedConn);
162 this.routeEstablished.set(routeComplete);
163 if (!routeComplete) {
164 this.log.debug("Start connection routing");
165 final HttpRoute route = this.routeRef.get();
166 this.routeTrackerRef.set(new RouteTracker(route));
167 } else {
168 this.log.debug("Connection route already established");
169 }
170 }
171 }
172
173 final void onRouteToTarget() throws IOException {
174 final NHttpClientConnection managedConn = this.managedConnRef.get();
175 Asserts.check(managedConn != null, "Inconsistent state: managed connection is null");
176 final HttpRoute route = this.routeRef.get();
177 Asserts.check(route != null, "Inconsistent state: HTTP route is null");
178 final RouteTracker routeTracker = this.routeTrackerRef.get();
179 Asserts.check(routeTracker != null, "Inconsistent state: HTTP route tracker");
180 this.connmgr.startRoute(managedConn, route, this.localContext);
181 routeTracker.connectTarget(route.isSecure());
182 }
183
184 final void onRouteToProxy() throws IOException {
185 final NHttpClientConnection managedConn = this.managedConnRef.get();
186 Asserts.check(managedConn != null, "Inconsistent state: managed connection is null");
187 final HttpRoute route = this.routeRef.get();
188 Asserts.check(route != null, "Inconsistent state: HTTP route is null");
189 final RouteTracker routeTracker = this.routeTrackerRef.get();
190 Asserts.check(routeTracker != null, "Inconsistent state: HTTP route tracker");
191 this.connmgr.startRoute(managedConn, route, this.localContext);
192 final HttpHost proxy = route.getProxyHost();
193 routeTracker.connectProxy(proxy, false);
194 }
195
196 final void onRouteUpgrade() throws IOException {
197 final NHttpClientConnection managedConn = this.managedConnRef.get();
198 Asserts.check(managedConn != null, "Inconsistent state: managed connection is null");
199 final HttpRoute route = this.routeRef.get();
200 Asserts.check(route != null, "Inconsistent state: HTTP route is null");
201 final RouteTracker routeTracker = this.routeTrackerRef.get();
202 Asserts.check(routeTracker != null, "Inconsistent state: HTTP route tracker");
203 this.connmgr.upgrade(managedConn, route, this.localContext);
204 routeTracker.layerProtocol(route.isSecure());
205 }
206
207 final void onRouteTunnelToTarget() {
208 final RouteTracker routeTracker = this.routeTrackerRef.get();
209 Asserts.check(routeTracker != null, "Inconsistent state: HTTP route tracker");
210 routeTracker.tunnelTarget(false);
211 }
212
213 final void onRouteComplete() {
214 final NHttpClientConnection managedConn = this.managedConnRef.get();
215 Asserts.check(managedConn != null, "Inconsistent state: managed connection is null");
216 final HttpRoute route = this.routeRef.get();
217 Asserts.check(route != null, "Inconsistent state: HTTP route is null");
218 this.connmgr.routeComplete(managedConn, route, this.localContext);
219 this.routeEstablished.set(true);
220 this.routeTrackerRef.set(null);
221 }
222
223 final NHttpClientConnection getConnection() {
224 return this.managedConnRef.get();
225 }
226
227 final void releaseConnection() {
228 final NHttpClientConnection localConn = this.managedConnRef.getAndSet(null);
229 if (localConn != null) {
230 if (this.log.isDebugEnabled()) {
231 this.log.debug("[exchange: " + this.id + "] releasing connection");
232 }
233 localConn.getContext().removeAttribute(HttpAsyncRequestExecutor.HTTP_HANDLER);
234 final Long validDuration = this.validDurationRef.get();
235 if (validDuration != null) {
236 final Object userToken = this.localContext.getUserToken();
237 this.connmgr.releaseConnection(localConn, userToken, validDuration, TimeUnit.MILLISECONDS);
238 } else {
239 try {
240 localConn.close();
241 if (this.log.isDebugEnabled()) {
242 this.log.debug("[exchange: " + this.id + "] connection discarded");
243 }
244 } catch (final IOException ex) {
245 if (this.log.isDebugEnabled()) {
246 this.log.debug(ex.getMessage(), ex);
247 }
248 } finally {
249 this.connmgr.releaseConnection(localConn, null, 0, TimeUnit.MILLISECONDS);
250 }
251 }
252 }
253 }
254
255 final void discardConnection() {
256 final NHttpClientConnection localConn = this.managedConnRef.getAndSet(null);
257 if (localConn != null) {
258 try {
259 localConn.shutdown();
260 if (this.log.isDebugEnabled()) {
261 this.log.debug("[exchange: " + this.id + "] connection aborted");
262 }
263 } catch (final IOException ex) {
264 if (this.log.isDebugEnabled()) {
265 this.log.debug(ex.getMessage(), ex);
266 }
267 } finally {
268 this.connmgr.releaseConnection(localConn, null, 0, TimeUnit.MILLISECONDS);
269 }
270 }
271 }
272
273 final boolean manageConnectionPersistence() {
274 final HttpResponse response = this.responseRef.get();
275 Asserts.check(response != null, "Inconsistent state: HTTP response");
276 final NHttpClientConnection managedConn = this.managedConnRef.get();
277 Asserts.check(managedConn != null, "Inconsistent state: managed connection is null");
278 final boolean keepAlive = managedConn.isOpen() &&
279 this.connReuseStrategy.keepAlive(response, this.localContext);
280 if (keepAlive) {
281 final long validDuration = this.keepaliveStrategy.getKeepAliveDuration(
282 response, this.localContext);
283 if (this.log.isDebugEnabled()) {
284 final String s;
285 if (validDuration > 0) {
286 s = "for " + validDuration + " " + TimeUnit.MILLISECONDS;
287 } else {
288 s = "indefinitely";
289 }
290 this.log.debug("[exchange: " + this.id + "] Connection can be kept alive " + s);
291 }
292 this.validDurationRef.set(validDuration);
293 } else {
294 if (this.log.isDebugEnabled()) {
295 this.log.debug("[exchange: " + this.id + "] Connection cannot be kept alive");
296 }
297 this.validDurationRef.set(null);
298 }
299 return keepAlive;
300 }
301
302 private void connectionAllocated(final NHttpClientConnection managedConn) {
303 try {
304 if (this.log.isDebugEnabled()) {
305 this.log.debug("[exchange: " + this.id + "] Connection allocated: " + managedConn);
306 }
307 this.managedConnRef.set(managedConn);
308
309 if (this.closed.get()) {
310 discardConnection();
311 return;
312 }
313
314 managedConn.getContext().setAttribute(HttpAsyncRequestExecutor.HTTP_HANDLER, this);
315 managedConn.requestOutput();
316 if (managedConn.isStale()) {
317 failed(new ConnectionClosedException("Connection closed"));
318 }
319 } catch (final RuntimeException runex) {
320 failed(runex);
321 throw runex;
322 }
323 }
324
325 private void connectionRequestFailed(final Exception ex) {
326 if (this.log.isDebugEnabled()) {
327 this.log.debug("[exchange: " + this.id + "] connection request failed");
328 }
329 failed(ex);
330 }
331
332 private void connectionRequestCancelled() {
333 if (this.log.isDebugEnabled()) {
334 this.log.debug("[exchange: " + this.id + "] Connection request cancelled");
335 }
336 try {
337 this.resultFuture.cancel();
338 } finally {
339 close();
340 }
341 }
342
343 final void requestConnection() {
344 final HttpRoute route = this.routeRef.get();
345 if (this.log.isDebugEnabled()) {
346 this.log.debug("[exchange: " + this.id + "] Request connection for " + route);
347 }
348
349 discardConnection();
350
351 this.validDurationRef.set(null);
352 this.routeTrackerRef.set(null);
353 this.routeEstablished.set(false);
354
355 final Object userToken = this.localContext.getUserToken();
356 final RequestConfig config = this.localContext.getRequestConfig();
357 this.connmgr.requestConnection(
358 route,
359 userToken,
360 config.getConnectTimeout(),
361 config.getConnectionRequestTimeout(),
362 TimeUnit.MILLISECONDS,
363 new FutureCallback<NHttpClientConnection>() {
364
365 @Override
366 public void completed(final NHttpClientConnection managedConn) {
367 connectionAllocated(managedConn);
368 }
369
370 @Override
371 public void failed(final Exception ex) {
372 connectionRequestFailed(ex);
373 }
374
375 @Override
376 public void cancelled() {
377 connectionRequestCancelled();
378 }
379
380 });
381 }
382
383 abstract void releaseResources();
384
385 abstract void executionFailed(final Exception ex);
386
387 abstract boolean executionCancelled();
388
389 @Override
390 public final void close() {
391 if (this.closed.compareAndSet(false, true)) {
392 discardConnection();
393 releaseResources();
394 }
395 }
396
397 @Override
398 public final boolean isDone() {
399 return this.completed.get();
400 }
401
402 @Override
403 public final void failed(final Exception ex) {
404 if (this.closed.compareAndSet(false, true)) {
405 try {
406 try {
407 executionFailed(ex);
408 } finally {
409 discardConnection();
410 releaseResources();
411 }
412 } finally {
413 this.resultFuture.failed(ex);
414 }
415 }
416 }
417
418 @Override
419 public final boolean cancel() {
420 if (this.log.isDebugEnabled()) {
421 this.log.debug("[exchange: " + this.id + "] Cancelled");
422 }
423 if (this.closed.compareAndSet(false, true)) {
424 try {
425 try {
426 return executionCancelled();
427 } finally {
428 discardConnection();
429 releaseResources();
430 }
431 } finally {
432 this.resultFuture.cancel();
433 }
434 }
435 return false;
436 }
437
438 }
0 /*
1 * ====================================================================
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 * ====================================================================
19 *
20 * This software consists of voluntary contributions made by many
21 * individuals on behalf of the Apache Software Foundation. For more
22 * information on the Apache Software Foundation, please see
23 * <http://www.apache.org/>.
24 *
25 */
26 package org.apache.http.impl.nio.client;
27
28 import java.io.Closeable;
29 import java.net.URI;
30 import java.util.concurrent.Future;
31
32 import org.apache.http.HttpHost;
33 import org.apache.http.HttpRequest;
34 import org.apache.http.HttpResponse;
35 import org.apache.http.annotation.ThreadSafe;
36 import org.apache.http.client.ClientProtocolException;
37 import org.apache.http.client.methods.HttpUriRequest;
38 import org.apache.http.client.protocol.HttpClientContext;
39 import org.apache.http.client.utils.URIUtils;
40 import org.apache.http.concurrent.BasicFuture;
41 import org.apache.http.concurrent.FutureCallback;
42 import org.apache.http.nio.client.HttpAsyncClient;
43 import org.apache.http.nio.client.methods.HttpAsyncMethods;
44 import org.apache.http.nio.protocol.HttpAsyncRequestProducer;
45 import org.apache.http.nio.protocol.HttpAsyncResponseConsumer;
46 import org.apache.http.protocol.HttpContext;
47 import org.apache.http.util.Args;
48
49 /**
50 * Base implementation of {@link HttpAsyncClient} that also implements {@link Closeable}.
51 *
52 * @since 4.0
53 */
54 @ThreadSafe
55 public abstract class CloseableHttpAsyncClient implements HttpAsyncClient, Closeable {
56
57 public abstract boolean isRunning();
58
59 public abstract void start();
60
61 @Override
62 public <T> Future<T> execute(
63 final HttpAsyncRequestProducer requestProducer,
64 final HttpAsyncResponseConsumer<T> responseConsumer,
65 final FutureCallback<T> callback) {
66 return execute(requestProducer, responseConsumer, HttpClientContext.create(), callback);
67 }
68
69 @Override
70 public Future<HttpResponse> execute(
71 final HttpHost target, final HttpRequest request, final HttpContext context,
72 final FutureCallback<HttpResponse> callback) {
73 return execute(
74 HttpAsyncMethods.create(target, request),
75 HttpAsyncMethods.createConsumer(),
76 context, callback);
77 }
78
79 @Override
80 public Future<HttpResponse> execute(
81 final HttpHost target, final HttpRequest request,
82 final FutureCallback<HttpResponse> callback) {
83 return execute(target, request, HttpClientContext.create(), callback);
84 }
85
86 @Override
87 public Future<HttpResponse> execute(
88 final HttpUriRequest request,
89 final FutureCallback<HttpResponse> callback) {
90 return execute(request, HttpClientContext.create(), callback);
91 }
92
93 @Override
94 public Future<HttpResponse> execute(
95 final HttpUriRequest request,
96 final HttpContext context,
97 final FutureCallback<HttpResponse> callback) {
98 final HttpHost target;
99 try {
100 target = determineTarget(request);
101 } catch (final ClientProtocolException ex) {
102 final BasicFuture<HttpResponse> future = new BasicFuture<HttpResponse>(callback);
103 future.failed(ex);
104 return future;
105 }
106 return execute(target, request, context, callback);
107 }
108
109 private HttpHost determineTarget(final HttpUriRequest request) throws ClientProtocolException {
110 Args.notNull(request, "HTTP request");
111 // A null target may be acceptable if there is a default target.
112 // Otherwise, the null target is detected in the director.
113 HttpHost target = null;
114
115 final URI requestURI = request.getURI();
116 if (requestURI.isAbsolute()) {
117 target = URIUtils.extractHost(requestURI);
118 if (target == null) {
119 throw new ClientProtocolException(
120 "URI does not specify a valid host name: " + requestURI);
121 }
122 }
123 return target;
124 }
125
126 }
0 /*
1 * ====================================================================
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 * ====================================================================
19 *
20 * This software consists of voluntary contributions made by many
21 * individuals on behalf of the Apache Software Foundation. For more
22 * information on the Apache Software Foundation, please see
23 * <http://www.apache.org/>.
24 *
25 */
26 package org.apache.http.impl.nio.client;
27
28 import java.io.IOException;
29 import java.util.concurrent.ThreadFactory;
30 import java.util.concurrent.atomic.AtomicReference;
31
32 import org.apache.commons.logging.Log;
33 import org.apache.commons.logging.LogFactory;
34 import org.apache.http.nio.NHttpClientEventHandler;
35 import org.apache.http.nio.conn.NHttpClientConnectionManager;
36 import org.apache.http.nio.reactor.IOEventDispatch;
37 import org.apache.http.util.Asserts;
38
39 abstract class CloseableHttpAsyncClientBase extends CloseableHttpPipeliningClient {
40
41 private final Log log = LogFactory.getLog(getClass());
42
43 static enum Status {INACTIVE, ACTIVE, STOPPED}
44
45 private final NHttpClientConnectionManager connmgr;
46 private final Thread reactorThread;
47
48 private final AtomicReference<Status> status;
49
50 public CloseableHttpAsyncClientBase(
51 final NHttpClientConnectionManager connmgr,
52 final ThreadFactory threadFactory,
53 final NHttpClientEventHandler handler) {
54 super();
55 this.connmgr = connmgr;
56 if (threadFactory != null && handler != null) {
57 this.reactorThread = threadFactory.newThread(new Runnable() {
58
59 @Override
60 public void run() {
61 try {
62 final IOEventDispatch ioEventDispatch = new InternalIODispatch(handler);
63 connmgr.execute(ioEventDispatch);
64 } catch (final Exception ex) {
65 log.error("I/O reactor terminated abnormally", ex);
66 } finally {
67 status.set(Status.STOPPED);
68 }
69 }
70
71 });
72 } else {
73 this.reactorThread = null;
74 }
75 this.status = new AtomicReference<Status>(Status.INACTIVE);
76 }
77
78 @Override
79 public void start() {
80 if (this.status.compareAndSet(Status.INACTIVE, Status.ACTIVE)) {
81 if (this.reactorThread != null) {
82 this.reactorThread.start();
83 }
84 }
85 }
86
87 protected void ensureRunning() {
88 final Status currentStatus = this.status.get();
89 Asserts.check(currentStatus == Status.ACTIVE, "Request cannot be executed; " +
90 "I/O reactor status: %s", currentStatus);
91 }
92
93 @Override
94 public void close() {
95 if (this.status.compareAndSet(Status.ACTIVE, Status.STOPPED)) {
96 if (this.reactorThread != null) {
97 try {
98 this.connmgr.shutdown();
99 } catch (IOException ex) {
100 this.log.error("I/O error shutting down connection manager", ex);
101 }
102 try {
103 this.reactorThread.join();
104 } catch (final InterruptedException ex) {
105 Thread.currentThread().interrupt();
106 }
107 }
108 }
109 }
110
111 @Override
112 public boolean isRunning() {
113 return this.status.get() == Status.ACTIVE;
114 }
115
116 }
0 /*
1 * ====================================================================
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 * ====================================================================
19 *
20 * This software consists of voluntary contributions made by many
21 * individuals on behalf of the Apache Software Foundation. For more
22 * information on the Apache Software Foundation, please see
23 * <http://www.apache.org/>.
24 *
25 */
26 package org.apache.http.impl.nio.client;
27
28 import java.util.ArrayList;
29 import java.util.List;
30 import java.util.concurrent.Future;
31
32 import org.apache.http.HttpHost;
33 import org.apache.http.HttpRequest;
34 import org.apache.http.HttpResponse;
35 import org.apache.http.annotation.ThreadSafe;
36 import org.apache.http.client.protocol.HttpClientContext;
37 import org.apache.http.concurrent.FutureCallback;
38 import org.apache.http.nio.client.HttpPipeliningClient;
39 import org.apache.http.nio.client.methods.HttpAsyncMethods;
40 import org.apache.http.nio.protocol.HttpAsyncRequestProducer;
41 import org.apache.http.nio.protocol.HttpAsyncResponseConsumer;
42 import org.apache.http.protocol.HttpContext;
43 import org.apache.http.util.Args;
44
45 /**
46 * Base implementation of {@link org.apache.http.nio.client.HttpPipeliningClient} that also
47 * implements {@link java.io.Closeable}.
48 *
49 * @since 4.1
50 */
51 @ThreadSafe
52 public abstract class CloseableHttpPipeliningClient
53 extends CloseableHttpAsyncClient implements HttpPipeliningClient {
54
55 @Override
56 public <T> Future<List<T>> execute(
57 final HttpHost target,
58 final List<? extends HttpAsyncRequestProducer> requestProducers,
59 final List<? extends HttpAsyncResponseConsumer<T>> responseConsumers,
60 final FutureCallback<List<T>> callback) {
61 return execute(target, requestProducers, responseConsumers, HttpClientContext.create(), callback);
62 }
63
64 @Override
65 public Future<List<HttpResponse>> execute(
66 final HttpHost target,
67 final List<HttpRequest> requests,
68 final FutureCallback<List<HttpResponse>> callback) {
69 return execute(target, requests, HttpClientContext.create(), callback);
70 }
71
72 @Override
73 public Future<List<HttpResponse>> execute(
74 final HttpHost target,
75 final List<HttpRequest> requests,
76 final HttpContext context,
77 final FutureCallback<List<HttpResponse>> callback) {
78 Args.notEmpty(requests, "HTTP request list");
79 final List<HttpAsyncRequestProducer> requestProducers = new ArrayList<HttpAsyncRequestProducer>(
80 requests.size());
81 final List<HttpAsyncResponseConsumer<HttpResponse>> responseConsumers = new ArrayList<HttpAsyncResponseConsumer<HttpResponse>>(
82 requests.size());
83 for (int i = 0; i < requests.size(); i++) {
84 final HttpRequest request = requests.get(i);
85 requestProducers.add(HttpAsyncMethods.create(target, request));
86 responseConsumers.add(HttpAsyncMethods.createConsumer());
87 }
88 return execute(target, requestProducers, responseConsumers, context, callback);
89 }
90
91 }
0 /*
1 * ====================================================================
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 * ====================================================================
19 *
20 * This software consists of voluntary contributions made by many
21 * individuals on behalf of the Apache Software Foundation. For more
22 * information on the Apache Software Foundation, please see
23 * <http://www.apache.org/>.
24 *
25 */
26 package org.apache.http.impl.nio.client;
27
28 import org.apache.http.HttpConnection;
29 import org.apache.http.annotation.Immutable;
30 import org.apache.http.auth.AuthScheme;
31 import org.apache.http.auth.AuthState;
32 import org.apache.http.auth.Credentials;
33 import org.apache.http.client.UserTokenHandler;
34 import org.apache.http.client.protocol.HttpClientContext;
35 import org.apache.http.nio.conn.ManagedNHttpClientConnection;
36 import org.apache.http.protocol.HttpContext;
37
38 import javax.net.ssl.SSLSession;
39 import java.security.Principal;
40
41 /**
42 * Default implementation of {@link org.apache.http.client.UserTokenHandler}
43 * for asynchrounous HTTP client communication. This class will use
44 * an instance of {@link java.security.Principal} as a state object for
45 * non-blocking HTTP connections, if it can be obtained from the given
46 * execution context. This helps ensure persistent connections created with
47 * a particular user identity within a particular security context can be
48 * reused by the same user only.
49 * <p>
50 * This implementation will use the user principle of connection based
51 * authentication schemes such as NTLM or that of the SSL session with
52 * the client authentication turned on. If both are unavailable,
53 * {@code null} token will be returned.
54 *
55 * @since 4.0
56 */
57 @Immutable
58 public class DefaultAsyncUserTokenHandler implements UserTokenHandler {
59
60 public static final DefaultAsyncUserTokenHandler INSTANCE = new DefaultAsyncUserTokenHandler();
61
62 @Override
63 public Object getUserToken(final HttpContext context) {
64
65 final HttpClientContext clientContext = HttpClientContext.adapt(context);
66
67 Principal userPrincipal = null;
68
69 final AuthState targetAuthState = clientContext.getTargetAuthState();
70 if (targetAuthState != null) {
71 userPrincipal = getAuthPrincipal(targetAuthState);
72 if (userPrincipal == null) {
73 final AuthState proxyAuthState = clientContext.getProxyAuthState();
74 userPrincipal = getAuthPrincipal(proxyAuthState);
75 }
76 }
77
78 if (userPrincipal == null) {
79 final HttpConnection conn = clientContext.getConnection();
80 if (conn.isOpen() && conn instanceof ManagedNHttpClientConnection) {
81 final SSLSession sslsession = ((ManagedNHttpClientConnection) conn).getSSLSession();
82 if (sslsession != null) {
83 userPrincipal = sslsession.getLocalPrincipal();
84 }
85 }
86 }
87
88 return userPrincipal;
89 }
90
91 private static Principal getAuthPrincipal(final AuthState authState) {
92 final AuthScheme scheme = authState.getAuthScheme();
93 if (scheme != null && scheme.isComplete() && scheme.isConnectionBased()) {
94 final Credentials creds = authState.getCredentials();
95 if (creds != null) {
96 return creds.getUserPrincipal();
97 }
98 }
99 return null;
100 }
101
102 }
0 /*
1 * ====================================================================
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 * ====================================================================
19 *
20 * This software consists of voluntary contributions made by many
21 * individuals on behalf of the Apache Software Foundation. For more
22 * information on the Apache Software Foundation, please see
23 * <http://www.apache.org/>.
24 *
25 */
26 package org.apache.http.impl.nio.client;
27
28 import java.io.IOException;
29
30 import org.apache.commons.logging.Log;
31 import org.apache.http.ConnectionReuseStrategy;
32 import org.apache.http.HttpException;
33 import org.apache.http.HttpHost;
34 import org.apache.http.HttpRequest;
35 import org.apache.http.HttpResponse;
36 import org.apache.http.client.methods.HttpExecutionAware;
37 import org.apache.http.client.protocol.HttpClientContext;
38 import org.apache.http.concurrent.BasicFuture;
39 import org.apache.http.conn.ConnectionKeepAliveStrategy;
40 import org.apache.http.nio.ContentDecoder;
41 import org.apache.http.nio.ContentEncoder;
42 import org.apache.http.nio.IOControl;
43 import org.apache.http.nio.NHttpClientConnection;
44 import org.apache.http.nio.conn.NHttpClientConnectionManager;
45 import org.apache.http.nio.protocol.HttpAsyncRequestProducer;
46 import org.apache.http.nio.protocol.HttpAsyncResponseConsumer;
47
48 /**
49 * Default implementation of {@link org.apache.http.nio.protocol.HttpAsyncClientExchangeHandler}.
50 * <p>
51 * Instances of this class are expected to be accessed by one thread at a time only.
52 * The {@link #cancel()} method can be called concurrently by multiple threads.
53 */
54 class DefaultClientExchangeHandlerImpl<T> extends AbstractClientExchangeHandler {
55
56 private final HttpAsyncRequestProducer requestProducer;
57 private final HttpAsyncResponseConsumer<T> responseConsumer;
58 private final BasicFuture<T> resultFuture;
59 private final InternalClientExec exec;
60 private final InternalState state;
61
62 public DefaultClientExchangeHandlerImpl(
63 final Log log,
64 final HttpAsyncRequestProducer requestProducer,
65 final HttpAsyncResponseConsumer<T> responseConsumer,
66 final HttpClientContext localContext,
67 final BasicFuture<T> resultFuture,
68 final NHttpClientConnectionManager connmgr,
69 final ConnectionReuseStrategy connReuseStrategy,
70 final ConnectionKeepAliveStrategy keepaliveStrategy,
71 final InternalClientExec exec) {
72 super(log, localContext, resultFuture, connmgr, connReuseStrategy, keepaliveStrategy);
73 this.requestProducer = requestProducer;
74 this.responseConsumer = responseConsumer;
75 this.resultFuture = resultFuture;
76 this.exec = exec;
77 this.state = new InternalState(getId(), requestProducer, responseConsumer, localContext);
78 }
79
80 @Override
81 void releaseResources() {
82 try {
83 this.requestProducer.close();
84 } catch (final IOException ex) {
85 this.log.debug("I/O error closing request producer", ex);
86 }
87 try {
88 this.responseConsumer.close();
89 } catch (final IOException ex) {
90 this.log.debug("I/O error closing response consumer", ex);
91 }
92 }
93
94 @Override
95 void executionFailed(final Exception ex) {
96 this.requestProducer.failed(ex);
97 this.responseConsumer.failed(ex);
98 }
99
100 @Override
101 boolean executionCancelled() {
102 final boolean cancelled = this.responseConsumer.cancel();
103
104 final T result = this.responseConsumer.getResult();
105 final Exception ex = this.responseConsumer.getException();
106 if (ex != null) {
107 this.resultFuture.failed(ex);
108 } else if (result != null) {
109 this.resultFuture.completed(result);
110 } else {
111 this.resultFuture.cancel();
112 }
113 return cancelled;
114 }
115
116 public void start() throws HttpException, IOException {
117 final HttpHost target = this.requestProducer.getTarget();
118 final HttpRequest original = this.requestProducer.generateRequest();
119
120 if (original instanceof HttpExecutionAware) {
121 ((HttpExecutionAware) original).setCancellable(this);
122 }
123 this.exec.prepare(target, original, this.state, this);
124 requestConnection();
125 }
126
127 @Override
128 public HttpRequest generateRequest() throws IOException, HttpException {
129 return this.exec.generateRequest(this.state, this);
130 }
131
132 @Override
133 public void produceContent(
134 final ContentEncoder encoder, final IOControl ioctrl) throws IOException {
135 this.exec.produceContent(this.state, encoder, ioctrl);
136 }
137
138 @Override
139 public void requestCompleted() {
140 this.exec.requestCompleted(this.state, this);
141 }
142
143 @Override
144 public void responseReceived(
145 final HttpResponse response) throws IOException, HttpException {
146 this.exec.responseReceived(response, this.state, this);
147 }
148
149 @Override
150 public void consumeContent(
151 final ContentDecoder decoder, final IOControl ioctrl) throws IOException {
152 this.exec.consumeContent(this.state, decoder, ioctrl);
153 if (!decoder.isCompleted() && this.responseConsumer.isDone()) {
154 markConnectionNonReusable();
155 try {
156 markCompleted();
157 releaseConnection();
158 this.resultFuture.cancel();
159 } finally {
160 close();
161 }
162 }
163 }
164
165 @Override
166 public void responseCompleted() throws IOException, HttpException {
167 this.exec.responseCompleted(this.state, this);
168
169 if (this.state.getFinalResponse() != null || this.resultFuture.isDone()) {
170 try {
171 markCompleted();
172 releaseConnection();
173 final T result = this.responseConsumer.getResult();
174 final Exception ex = this.responseConsumer.getException();
175 if (ex == null) {
176 this.resultFuture.completed(result);
177 } else {
178 this.resultFuture.failed(ex);
179 }
180 } finally {
181 close();
182 }
183 } else {
184 NHttpClientConnection localConn = getConnection();
185 if (localConn != null && !localConn.isOpen()) {
186 releaseConnection();
187 localConn = null;
188 }
189 if (localConn != null) {
190 localConn.requestOutput();
191 } else {
192 requestConnection();
193 }
194 }
195 }
196
197 @Override
198 public void inputTerminated() {
199 if (!isCompleted()) {
200 requestConnection();
201 } else {
202 close();
203 }
204 }
205
206 public void abortConnection() {
207 discardConnection();
208 }
209
210 }
0 /*
1 * ====================================================================
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 * ====================================================================
19 *
20 * This software consists of voluntary contributions made by many
21 * individuals on behalf of the Apache Software Foundation. For more
22 * information on the Apache Software Foundation, please see
23 * <http://www.apache.org/>.
24 *
25 */
26
27 package org.apache.http.impl.nio.client;
28
29 import java.net.ProxySelector;
30 import java.util.Collection;
31 import java.util.LinkedList;
32 import java.util.concurrent.Executors;
33 import java.util.concurrent.ThreadFactory;
34
35 import javax.net.ssl.HostnameVerifier;
36 import javax.net.ssl.SSLContext;
37
38 import org.apache.http.ConnectionReuseStrategy;
39 import org.apache.http.Header;
40 import org.apache.http.HttpHost;
41 import org.apache.http.HttpRequestInterceptor;
42 import org.apache.http.HttpResponseInterceptor;
43 import org.apache.http.annotation.NotThreadSafe;
44 import org.apache.http.auth.AuthSchemeProvider;
45 import org.apache.http.client.AuthenticationStrategy;
46 import org.apache.http.client.CookieStore;
47 import org.apache.http.client.CredentialsProvider;
48 import org.apache.http.client.RedirectStrategy;
49 import org.apache.http.client.UserTokenHandler;
50 import org.apache.http.client.config.AuthSchemes;
51 import org.apache.http.client.config.CookieSpecs;
52 import org.apache.http.client.config.RequestConfig;
53 import org.apache.http.client.protocol.RequestAddCookies;
54 import org.apache.http.client.protocol.RequestAuthCache;
55 import org.apache.http.client.protocol.RequestClientConnControl;
56 import org.apache.http.client.protocol.RequestDefaultHeaders;
57 import org.apache.http.client.protocol.RequestExpectContinue;
58 import org.apache.http.client.protocol.ResponseProcessCookies;
59 import org.apache.http.config.ConnectionConfig;
60 import org.apache.http.config.Lookup;
61 import org.apache.http.config.RegistryBuilder;
62 import org.apache.http.conn.ConnectionKeepAliveStrategy;
63 import org.apache.http.conn.SchemePortResolver;
64 import org.apache.http.conn.routing.HttpRoutePlanner;
65 import org.apache.http.conn.ssl.DefaultHostnameVerifier;
66 import org.apache.http.conn.ssl.X509HostnameVerifier;
67 import org.apache.http.conn.util.PublicSuffixMatcher;
68 import org.apache.http.conn.util.PublicSuffixMatcherLoader;
69 import org.apache.http.cookie.CookieSpecProvider;
70 import org.apache.http.impl.DefaultConnectionReuseStrategy;
71 import org.apache.http.impl.NoConnectionReuseStrategy;
72 import org.apache.http.impl.auth.BasicSchemeFactory;
73 import org.apache.http.impl.auth.DigestSchemeFactory;
74 import org.apache.http.impl.auth.KerberosSchemeFactory;
75 import org.apache.http.impl.auth.NTLMSchemeFactory;
76 import org.apache.http.impl.auth.SPNegoSchemeFactory;
77 import org.apache.http.impl.client.BasicCookieStore;
78 import org.apache.http.impl.client.BasicCredentialsProvider;
79 import org.apache.http.impl.client.DefaultConnectionKeepAliveStrategy;
80 import org.apache.http.impl.client.DefaultRedirectStrategy;
81 import org.apache.http.impl.client.NoopUserTokenHandler;
82 import org.apache.http.impl.client.ProxyAuthenticationStrategy;
83 import org.apache.http.impl.client.TargetAuthenticationStrategy;
84 import org.apache.http.impl.conn.DefaultProxyRoutePlanner;
85 import org.apache.http.impl.conn.DefaultRoutePlanner;
86 import org.apache.http.impl.conn.DefaultSchemePortResolver;
87 import org.apache.http.impl.conn.SystemDefaultRoutePlanner;
88 import org.apache.http.impl.cookie.DefaultCookieSpecProvider;
89 import org.apache.http.impl.cookie.IgnoreSpecProvider;
90 import org.apache.http.impl.cookie.NetscapeDraftSpecProvider;
91 import org.apache.http.impl.cookie.RFC6265CookieSpecProvider;
92 import org.apache.http.impl.nio.conn.PoolingNHttpClientConnectionManager;
93 import org.apache.http.impl.nio.reactor.IOReactorConfig;
94 import org.apache.http.nio.NHttpClientEventHandler;
95 import org.apache.http.nio.conn.NHttpClientConnectionManager;
96 import org.apache.http.nio.conn.NoopIOSessionStrategy;
97 import org.apache.http.nio.conn.SchemeIOSessionStrategy;
98 import org.apache.http.nio.conn.ssl.SSLIOSessionStrategy;
99 import org.apache.http.nio.protocol.HttpAsyncRequestExecutor;
100 import org.apache.http.nio.reactor.ConnectingIOReactor;
101 import org.apache.http.protocol.HttpProcessor;
102 import org.apache.http.protocol.HttpProcessorBuilder;
103 import org.apache.http.protocol.RequestContent;
104 import org.apache.http.protocol.RequestTargetHost;
105 import org.apache.http.protocol.RequestUserAgent;
106 import org.apache.http.ssl.SSLContexts;
107 import org.apache.http.util.TextUtils;
108 import org.apache.http.util.VersionInfo;
109
110 /**
111 * Builder for {@link CloseableHttpAsyncClient} instances.
112 * <p>
113 * When a particular component is not explicitly this class will
114 * use its default implementation. System properties will be taken
115 * into account when configuring the default implementations when
116 * {@link #useSystemProperties()} method is called prior to calling
117 * {@link #build()}.
118 * <ul>
119 * <li>ssl.TrustManagerFactory.algorithm</li>
120 * <li>javax.net.ssl.trustStoreType</li>
121 * <li>javax.net.ssl.trustStore</li>
122 * <li>javax.net.ssl.trustStoreProvider</li>
123 * <li>javax.net.ssl.trustStorePassword</li>
124 * <li>ssl.KeyManagerFactory.algorithm</li>
125 * <li>javax.net.ssl.keyStoreType</li>
126 * <li>javax.net.ssl.keyStore</li>
127 * <li>javax.net.ssl.keyStoreProvider</li>
128 * <li>javax.net.ssl.keyStorePassword</li>
129 * <li>https.protocols</li>
130 * <li>https.cipherSuites</li>
131 * <li>http.proxyHost</li>
132 * <li>http.proxyPort</li>
133 * <li>http.keepAlive</li>
134 * <li>http.maxConnections</li>
135 * <li>http.agent</li>
136 * </ul>
137 * <p>
138 * Please note that some settings used by this class can be mutually
139 * exclusive and may not apply when building {@link CloseableHttpAsyncClient}
140 * instances.
141 *
142 * @since 4.0
143 */
144 @NotThreadSafe
145 public class HttpAsyncClientBuilder {
146
147 private NHttpClientConnectionManager connManager;
148 private boolean connManagerShared;
149 private SchemePortResolver schemePortResolver;
150 private SchemeIOSessionStrategy sslStrategy;
151 private HostnameVerifier hostnameVerifier;
152 private SSLContext sslcontext;
153 private ConnectionReuseStrategy reuseStrategy;
154 private ConnectionKeepAliveStrategy keepAliveStrategy;
155 private AuthenticationStrategy targetAuthStrategy;
156 private AuthenticationStrategy proxyAuthStrategy;
157 private UserTokenHandler userTokenHandler;
158 private HttpProcessor httpprocessor;
159
160 private LinkedList<HttpRequestInterceptor> requestFirst;
161 private LinkedList<HttpRequestInterceptor> requestLast;
162 private LinkedList<HttpResponseInterceptor> responseFirst;
163 private LinkedList<HttpResponseInterceptor> responseLast;
164
165 private HttpRoutePlanner routePlanner;
166 private RedirectStrategy redirectStrategy;
167 private Lookup<AuthSchemeProvider> authSchemeRegistry;
168 private Lookup<CookieSpecProvider> cookieSpecRegistry;
169 private CookieStore cookieStore;
170 private CredentialsProvider credentialsProvider;
171 private String userAgent;
172 private HttpHost proxy;
173 private Collection<? extends Header> defaultHeaders;
174 private IOReactorConfig defaultIOReactorConfig;
175 private ConnectionConfig defaultConnectionConfig;
176 private RequestConfig defaultRequestConfig;
177
178 private ThreadFactory threadFactory;
179 private NHttpClientEventHandler eventHandler;
180
181 private PublicSuffixMatcher publicSuffixMatcher;
182
183 private boolean systemProperties;
184 private boolean cookieManagementDisabled;
185 private boolean authCachingDisabled;
186 private boolean connectionStateDisabled;
187
188 private int maxConnTotal = 0;
189 private int maxConnPerRoute = 0;
190
191 public static HttpAsyncClientBuilder create() {
192 return new HttpAsyncClientBuilder();
193 }
194
195 protected HttpAsyncClientBuilder() {
196 super();
197 }
198
199 /**
200 * Assigns file containing public suffix matcher. Instances of this class can be created
201 * with {@link org.apache.http.conn.util.PublicSuffixMatcherLoader}.
202 *
203 * @see org.apache.http.conn.util.PublicSuffixMatcher
204 * @see org.apache.http.conn.util.PublicSuffixMatcherLoader
205 *
206 * @since 4.1
207 */
208 public final HttpAsyncClientBuilder setPublicSuffixMatcher(final PublicSuffixMatcher publicSuffixMatcher) {
209 this.publicSuffixMatcher = publicSuffixMatcher;
210 return this;
211 }
212
213 /**
214 * Assigns {@link NHttpClientConnectionManager} instance.
215 */
216 public final HttpAsyncClientBuilder setConnectionManager(
217 final NHttpClientConnectionManager connManager) {
218 this.connManager = connManager;
219 return this;
220 }
221
222 /**
223 * Defines the connection manager is to be shared by multiple
224 * client instances.
225 * <p>
226 * If the connection manager is shared its life-cycle is expected
227 * to be managed by the caller and it will not be shut down
228 * if the client is closed.
229 *
230 * @param shared defines whether or not the connection manager can be shared
231 * by multiple clients.
232 *
233 * @since 4.1
234 */
235 public final HttpAsyncClientBuilder setConnectionManagerShared(
236 final boolean shared) {
237 this.connManagerShared = shared;
238 return this;
239 }
240
241 /**
242 * Assigns {@link SchemePortResolver} instance.
243 */
244 public final HttpAsyncClientBuilder setSchemePortResolver(
245 final SchemePortResolver schemePortResolver) {
246 this.schemePortResolver = schemePortResolver;
247 return this;
248 }
249
250 /**
251 * Assigns maximum total connection value.
252 * <p>
253 * Please note this value can be overridden by the {@link #setConnectionManager(
254 * org.apache.http.nio.conn.NHttpClientConnectionManager)} method.
255 */
256 public final HttpAsyncClientBuilder setMaxConnTotal(final int maxConnTotal) {
257 this.maxConnTotal = maxConnTotal;
258 return this;
259 }
260
261 /**
262 * Assigns maximum connection per route value.
263 * <p>
264 * Please note this value can be overridden by the {@link #setConnectionManager(
265 * org.apache.http.nio.conn.NHttpClientConnectionManager)} method.
266 */
267 public final HttpAsyncClientBuilder setMaxConnPerRoute(final int maxConnPerRoute) {
268 this.maxConnPerRoute = maxConnPerRoute;
269 return this;
270 }
271
272 /**
273 * Assigns {@link ConnectionReuseStrategy} instance.
274 */
275 public final HttpAsyncClientBuilder setConnectionReuseStrategy(
276 final ConnectionReuseStrategy reuseStrategy) {
277 this.reuseStrategy = reuseStrategy;
278 return this;
279 }
280
281 /**
282 * Assigns {@link ConnectionKeepAliveStrategy} instance.
283 */
284 public final HttpAsyncClientBuilder setKeepAliveStrategy(
285 final ConnectionKeepAliveStrategy keepAliveStrategy) {
286 this.keepAliveStrategy = keepAliveStrategy;
287 return this;
288 }
289
290 /**
291 * Assigns {@link UserTokenHandler} instance.
292 * <p>
293 * Please note this value can be overridden by the {@link #disableConnectionState()}
294 * method.
295 */
296 public final HttpAsyncClientBuilder setUserTokenHandler(final UserTokenHandler userTokenHandler) {
297 this.userTokenHandler = userTokenHandler;
298 return this;
299 }
300
301 /**
302 * Assigns {@link AuthenticationStrategy} instance for proxy
303 * authentication.
304 */
305 public final HttpAsyncClientBuilder setTargetAuthenticationStrategy(
306 final AuthenticationStrategy targetAuthStrategy) {
307 this.targetAuthStrategy = targetAuthStrategy;
308 return this;
309 }
310
311 /**
312 * Assigns {@link AuthenticationStrategy} instance for target
313 * host authentication.
314 */
315 public final HttpAsyncClientBuilder setProxyAuthenticationStrategy(
316 final AuthenticationStrategy proxyAuthStrategy) {
317 this.proxyAuthStrategy = proxyAuthStrategy;
318 return this;
319 }
320
321 /**
322 * Assigns {@link HttpProcessor} instance.
323 */
324 public final HttpAsyncClientBuilder setHttpProcessor(final HttpProcessor httpprocessor) {
325 this.httpprocessor = httpprocessor;
326 return this;
327 }
328
329 /**
330 * Adds this protocol interceptor to the head of the protocol processing list.
331 * <p>
332 * Please note this value can be overridden by the {@link #setHttpProcessor(
333 * org.apache.http.protocol.HttpProcessor)} method.
334 */
335 public final HttpAsyncClientBuilder addInterceptorFirst(final HttpResponseInterceptor itcp) {
336 if (itcp == null) {
337 return this;
338 }
339 if (responseFirst == null) {
340 responseFirst = new LinkedList<HttpResponseInterceptor>();
341 }
342 responseFirst.addFirst(itcp);
343 return this;
344 }
345
346 /**
347 * Adds this protocol interceptor to the tail of the protocol processing list.
348 * <p>
349 * Please note this value can be overridden by the {@link #setHttpProcessor(
350 * org.apache.http.protocol.HttpProcessor)} method.
351 */
352 public final HttpAsyncClientBuilder addInterceptorLast(final HttpResponseInterceptor itcp) {
353 if (itcp == null) {
354 return this;
355 }
356 if (responseLast == null) {
357 responseLast = new LinkedList<HttpResponseInterceptor>();
358 }
359 responseLast.addLast(itcp);
360 return this;
361 }
362
363 /**
364 * Adds this protocol interceptor to the head of the protocol processing list.
365 * <p>
366 * Please note this value can be overridden by the {@link #setHttpProcessor(
367 * org.apache.http.protocol.HttpProcessor)} method.
368 */
369 public final HttpAsyncClientBuilder addInterceptorFirst(final HttpRequestInterceptor itcp) {
370 if (itcp == null) {
371 return this;
372 }
373 if (requestFirst == null) {
374 requestFirst = new LinkedList<HttpRequestInterceptor>();
375 }
376 requestFirst.addFirst(itcp);
377 return this;
378 }
379
380 /**
381 * Adds this protocol interceptor to the tail of the protocol processing list.
382 * <p>
383 * Please note this value can be overridden by the {@link #setHttpProcessor(
384 * org.apache.http.protocol.HttpProcessor)} method.
385 */
386 public final HttpAsyncClientBuilder addInterceptorLast(final HttpRequestInterceptor itcp) {
387 if (itcp == null) {
388 return this;
389 }
390 if (requestLast == null) {
391 requestLast = new LinkedList<HttpRequestInterceptor>();
392 }
393 requestLast.addLast(itcp);
394 return this;
395 }
396
397 /**
398 * Assigns {@link HttpRoutePlanner} instance.
399 */
400 public final HttpAsyncClientBuilder setRoutePlanner(final HttpRoutePlanner routePlanner) {
401 this.routePlanner = routePlanner;
402 return this;
403 }
404
405 /**
406 * Assigns {@link RedirectStrategy} instance.
407 */
408 public final HttpAsyncClientBuilder setRedirectStrategy(final RedirectStrategy redirectStrategy) {
409 this.redirectStrategy = redirectStrategy;
410 return this;
411 }
412
413 /**
414 * Assigns default {@link CookieStore} instance which will be used for
415 * request execution if not explicitly set in the client execution context.
416 */
417 public final HttpAsyncClientBuilder setDefaultCookieStore(final CookieStore cookieStore) {
418 this.cookieStore = cookieStore;
419 return this;
420 }
421
422 /**
423 * Assigns default {@link CredentialsProvider} instance which will be used
424 * for request execution if not explicitly set in the client execution
425 * context.
426 */
427 public final HttpAsyncClientBuilder setDefaultCredentialsProvider(
428 final CredentialsProvider credentialsProvider) {
429 this.credentialsProvider = credentialsProvider;
430 return this;
431 }
432
433
434 /**
435 * Assigns default {@link org.apache.http.auth.AuthScheme} registry which will
436 * be used for request execution if not explicitly set in the client execution
437 * context.
438 */
439 public final HttpAsyncClientBuilder setDefaultAuthSchemeRegistry(
440 final Lookup<AuthSchemeProvider> authSchemeRegistry) {
441 this.authSchemeRegistry = authSchemeRegistry;
442 return this;
443 }
444
445 /**
446 * Assigns default {@link org.apache.http.cookie.CookieSpec} registry which will
447 * be used for request execution if not explicitly set in the client execution
448 * context.
449 */
450 public final HttpAsyncClientBuilder setDefaultCookieSpecRegistry(
451 final Lookup<CookieSpecProvider> cookieSpecRegistry) {
452 this.cookieSpecRegistry = cookieSpecRegistry;
453 return this;
454 }
455
456 /**
457 * Assigns {@code User-Agent} value.
458 * <p>
459 * Please note this value can be overridden by the {@link #setHttpProcessor(
460 * org.apache.http.protocol.HttpProcessor)} method.
461 */
462 public final HttpAsyncClientBuilder setUserAgent(final String userAgent) {
463 this.userAgent = userAgent;
464 return this;
465 }
466
467 /**
468 * Assigns default proxy value.
469 * <p>
470 * Please note this value can be overridden by the {@link #setRoutePlanner(
471 * org.apache.http.conn.routing.HttpRoutePlanner)} method.
472 */
473 public final HttpAsyncClientBuilder setProxy(final HttpHost proxy) {
474 this.proxy = proxy;
475 return this;
476 }
477
478 /**
479 * Assigns {@link SchemeIOSessionStrategy} instance.
480 * <p>
481 * Please note this value can be overridden by the {@link #setConnectionManager(
482 * org.apache.http.nio.conn.NHttpClientConnectionManager)} method.
483 */
484 public final HttpAsyncClientBuilder setSSLStrategy(final SchemeIOSessionStrategy strategy) {
485 this.sslStrategy = strategy;
486 return this;
487 }
488
489 /**
490 * Assigns {@link SSLContext} instance.
491 * <p>
492 * Please note this value can be overridden by the {@link #setConnectionManager(
493 * org.apache.http.nio.conn.NHttpClientConnectionManager)} and the {@link #setSSLStrategy(
494 * org.apache.http.nio.conn.SchemeIOSessionStrategy)} methods.
495 */
496 public final HttpAsyncClientBuilder setSSLContext(final SSLContext sslcontext) {
497 this.sslcontext = sslcontext;
498 return this;
499 }
500
501 /**
502 * Assigns {@link X509HostnameVerifier} instance.
503 * <p>
504 * Please note this value can be overridden by the {@link #setConnectionManager(
505 * org.apache.http.nio.conn.NHttpClientConnectionManager)} and the {@link #setSSLStrategy(
506 * org.apache.http.nio.conn.SchemeIOSessionStrategy)} methods.
507 *
508 * @deprecated (4.1) use {@link #setSSLHostnameVerifier(javax.net.ssl.HostnameVerifier)}
509 */
510 @Deprecated
511 public final HttpAsyncClientBuilder setHostnameVerifier(final X509HostnameVerifier hostnameVerifier) {
512 this.hostnameVerifier = hostnameVerifier;
513 return this;
514 }
515
516 /**
517 * Assigns {@link javax.net.ssl.HostnameVerifier} instance.
518 * <p>
519 * Please note this value can be overridden by the {@link #setConnectionManager(
520 * org.apache.http.nio.conn.NHttpClientConnectionManager)} and the {@link #setSSLStrategy(
521 * org.apache.http.nio.conn.SchemeIOSessionStrategy)} methods.
522 *
523 * @since 4.1
524 */
525 public final HttpAsyncClientBuilder setSSLHostnameVerifier(final HostnameVerifier hostnameVerifier) {
526 this.hostnameVerifier = hostnameVerifier;
527 return this;
528 }
529
530 /**
531 * Assigns default request header values.
532 * <p>
533 * Please note this value can be overridden by the {@link #setHttpProcessor(
534 * org.apache.http.protocol.HttpProcessor)} method.
535 */
536 public final HttpAsyncClientBuilder setDefaultHeaders(final Collection<? extends Header> defaultHeaders) {
537 this.defaultHeaders = defaultHeaders;
538 return this;
539 }
540
541 /**
542 * Assigns default {@link IOReactorConfig}.
543 * <p>
544 * Please note this value can be overridden by the {@link #setConnectionManager(
545 * org.apache.http.nio.conn.NHttpClientConnectionManager)} method.
546 */
547 public final HttpAsyncClientBuilder setDefaultIOReactorConfig(final IOReactorConfig config) {
548 this.defaultIOReactorConfig = config;
549 return this;
550 }
551
552 /**
553 * Assigns default {@link ConnectionConfig}.
554 * <p>
555 * Please note this value can be overridden by the {@link #setConnectionManager(
556 * org.apache.http.nio.conn.NHttpClientConnectionManager)} method.
557 */
558 public final HttpAsyncClientBuilder setDefaultConnectionConfig(final ConnectionConfig config) {
559 this.defaultConnectionConfig = config;
560 return this;
561 }
562
563 /**
564 * Assigns default {@link RequestConfig} instance which will be used
565 * for request execution if not explicitly set in the client execution
566 * context.
567 */
568 public final HttpAsyncClientBuilder setDefaultRequestConfig(final RequestConfig config) {
569 this.defaultRequestConfig = config;
570 return this;
571 }
572
573 /**
574 * Assigns {@link ThreadFactory} instance.
575 */
576 public final HttpAsyncClientBuilder setThreadFactory(final ThreadFactory threadFactory) {
577 this.threadFactory = threadFactory;
578 return this;
579 }
580
581 /**
582 * Assigns {@link NHttpClientEventHandler} instance.
583 *
584 * @since 4.1
585 */
586 public final HttpAsyncClientBuilder setEventHandler(final NHttpClientEventHandler eventHandler) {
587 this.eventHandler = eventHandler;
588 return this;
589 }
590
591 /**
592 * Disables connection state tracking.
593 */
594 public final HttpAsyncClientBuilder disableConnectionState() {
595 connectionStateDisabled = true;
596 return this;
597 }
598
599 /**
600 * Disables state (cookie) management.
601 * <p>
602 * Please note this value can be overridden by the {@link #setHttpProcessor(
603 * org.apache.http.protocol.HttpProcessor)} method.
604 */
605 public final HttpAsyncClientBuilder disableCookieManagement() {
606 cookieManagementDisabled = true;
607 return this;
608 }
609
610 /**
611 * Disables authentication scheme caching.
612 * <p>
613 * Please note this value can be overridden by the {@link #setHttpProcessor(
614 * org.apache.http.protocol.HttpProcessor)} method.
615 */
616 public final HttpAsyncClientBuilder disableAuthCaching() {
617 authCachingDisabled = true;
618 return this;
619 }
620
621 /**
622 * Use system properties when creating and configuring default
623 * implementations.
624 */
625 public final HttpAsyncClientBuilder useSystemProperties() {
626 systemProperties = true;
627 return this;
628 }
629
630 private static String[] split(final String s) {
631 if (TextUtils.isBlank(s)) {
632 return null;
633 }
634 return s.split(" *, *");
635 }
636
637 public CloseableHttpAsyncClient build() {
638
639 PublicSuffixMatcher publicSuffixMatcher = this.publicSuffixMatcher;
640 if (publicSuffixMatcher == null) {
641 publicSuffixMatcher = PublicSuffixMatcherLoader.getDefault();
642 }
643
644 NHttpClientConnectionManager connManager = this.connManager;
645 if (connManager == null) {
646 SchemeIOSessionStrategy sslStrategy = this.sslStrategy;
647 if (sslStrategy == null) {
648 SSLContext sslcontext = this.sslcontext;
649 if (sslcontext == null) {
650 if (systemProperties) {
651 sslcontext = SSLContexts.createDefault();
652 } else {
653 sslcontext = SSLContexts.createSystemDefault();
654 }
655 }
656 final String[] supportedProtocols = systemProperties ? split(
657 System.getProperty("https.protocols")) : null;
658 final String[] supportedCipherSuites = systemProperties ? split(
659 System.getProperty("https.cipherSuites")) : null;
660 HostnameVerifier hostnameVerifier = this.hostnameVerifier;
661 if (hostnameVerifier == null) {
662 hostnameVerifier = new DefaultHostnameVerifier(publicSuffixMatcher);
663 }
664 sslStrategy = new SSLIOSessionStrategy(
665 sslcontext, supportedProtocols, supportedCipherSuites, hostnameVerifier);
666 }
667 final ConnectingIOReactor ioreactor = IOReactorUtils.create(
668 defaultIOReactorConfig != null ? defaultIOReactorConfig : IOReactorConfig.DEFAULT);
669 final PoolingNHttpClientConnectionManager poolingmgr = new PoolingNHttpClientConnectionManager(
670 ioreactor,
671 RegistryBuilder.<SchemeIOSessionStrategy>create()
672 .register("http", NoopIOSessionStrategy.INSTANCE)
673 .register("https", sslStrategy)
674 .build());
675 if (defaultConnectionConfig != null) {
676 poolingmgr.setDefaultConnectionConfig(defaultConnectionConfig);
677 }
678 if (systemProperties) {
679 String s = System.getProperty("http.keepAlive", "true");
680 if ("true".equalsIgnoreCase(s)) {
681 s = System.getProperty("http.maxConnections", "5");
682 final int max = Integer.parseInt(s);
683 poolingmgr.setDefaultMaxPerRoute(max);
684 poolingmgr.setMaxTotal(2 * max);
685 }
686 } else {
687 if (maxConnTotal > 0) {
688 poolingmgr.setMaxTotal(maxConnTotal);
689 }
690 if (maxConnPerRoute > 0) {
691 poolingmgr.setDefaultMaxPerRoute(maxConnPerRoute);
692 }
693 }
694 connManager = poolingmgr;
695 }
696 ConnectionReuseStrategy reuseStrategy = this.reuseStrategy;
697 if (reuseStrategy == null) {
698 if (systemProperties) {
699 final String s = System.getProperty("http.keepAlive", "true");
700 if ("true".equalsIgnoreCase(s)) {
701 reuseStrategy = DefaultConnectionReuseStrategy.INSTANCE;
702 } else {
703 reuseStrategy = NoConnectionReuseStrategy.INSTANCE;
704 }
705 } else {
706 reuseStrategy = DefaultConnectionReuseStrategy.INSTANCE;
707 }
708 }
709 ConnectionKeepAliveStrategy keepAliveStrategy = this.keepAliveStrategy;
710 if (keepAliveStrategy == null) {
711 keepAliveStrategy = DefaultConnectionKeepAliveStrategy.INSTANCE;
712 }
713 AuthenticationStrategy targetAuthStrategy = this.targetAuthStrategy;
714 if (targetAuthStrategy == null) {
715 targetAuthStrategy = TargetAuthenticationStrategy.INSTANCE;
716 }
717 AuthenticationStrategy proxyAuthStrategy = this.proxyAuthStrategy;
718 if (proxyAuthStrategy == null) {
719 proxyAuthStrategy = ProxyAuthenticationStrategy.INSTANCE;
720 }
721 UserTokenHandler userTokenHandler = this.userTokenHandler;
722 if (userTokenHandler == null) {
723 if (!connectionStateDisabled) {
724 userTokenHandler = DefaultAsyncUserTokenHandler.INSTANCE;
725 } else {
726 userTokenHandler = NoopUserTokenHandler.INSTANCE;
727 }
728 }
729 SchemePortResolver schemePortResolver = this.schemePortResolver;
730 if (schemePortResolver == null) {
731 schemePortResolver = DefaultSchemePortResolver.INSTANCE;
732 }
733
734 HttpProcessor httpprocessor = this.httpprocessor;
735 if (httpprocessor == null) {
736
737 String userAgent = this.userAgent;
738 if (userAgent == null) {
739 if (systemProperties) {
740 userAgent = System.getProperty("http.agent");
741 }
742 if (userAgent == null) {
743 userAgent = VersionInfo.getUserAgent(
744 "Apache-HttpAsyncClient",
745 "org.apache.http.nio.client", getClass());
746 }
747 }
748
749 final HttpProcessorBuilder b = HttpProcessorBuilder.create();
750 if (requestFirst != null) {
751 for (final HttpRequestInterceptor i: requestFirst) {
752 b.addFirst(i);
753 }
754 }
755 if (responseFirst != null) {
756 for (final HttpResponseInterceptor i: responseFirst) {
757 b.addFirst(i);
758 }
759 }
760 b.addAll(
761 new RequestDefaultHeaders(defaultHeaders),
762 new RequestContent(),
763 new RequestTargetHost(),
764 new RequestClientConnControl(),
765 new RequestUserAgent(userAgent),
766 new RequestExpectContinue());
767 if (!cookieManagementDisabled) {
768 b.add(new RequestAddCookies());
769 }
770 if (!authCachingDisabled) {
771 b.add(new RequestAuthCache());
772 }
773 if (!cookieManagementDisabled) {
774 b.add(new ResponseProcessCookies());
775 }
776 if (requestLast != null) {
777 for (final HttpRequestInterceptor i: requestLast) {
778 b.addLast(i);
779 }
780 }
781 if (responseLast != null) {
782 for (final HttpResponseInterceptor i: responseLast) {
783 b.addLast(i);
784 }
785 }
786 httpprocessor = b.build();
787 }
788 // Add redirect executor, if not disabled
789 HttpRoutePlanner routePlanner = this.routePlanner;
790 if (routePlanner == null) {
791 if (proxy != null) {
792 routePlanner = new DefaultProxyRoutePlanner(proxy, schemePortResolver);
793 } else if (systemProperties) {
794 routePlanner = new SystemDefaultRoutePlanner(
795 schemePortResolver, ProxySelector.getDefault());
796 } else {
797 routePlanner = new DefaultRoutePlanner(schemePortResolver);
798 }
799 }
800 Lookup<AuthSchemeProvider> authSchemeRegistry = this.authSchemeRegistry;
801 if (authSchemeRegistry == null) {
802 authSchemeRegistry = RegistryBuilder.<AuthSchemeProvider>create()
803 .register(AuthSchemes.BASIC, new BasicSchemeFactory())
804 .register(AuthSchemes.DIGEST, new DigestSchemeFactory())
805 .register(AuthSchemes.NTLM, new NTLMSchemeFactory())
806 .register(AuthSchemes.SPNEGO, new SPNegoSchemeFactory())
807 .register(AuthSchemes.KERBEROS, new KerberosSchemeFactory())
808 .build();
809 }
810 Lookup<CookieSpecProvider> cookieSpecRegistry = this.cookieSpecRegistry;
811 if (cookieSpecRegistry == null) {
812 final CookieSpecProvider defaultProvider = new DefaultCookieSpecProvider(publicSuffixMatcher);
813 final CookieSpecProvider laxStandardProvider = new RFC6265CookieSpecProvider(
814 RFC6265CookieSpecProvider.CompatibilityLevel.RELAXED, publicSuffixMatcher);
815 final CookieSpecProvider strictStandardProvider = new RFC6265CookieSpecProvider(
816 RFC6265CookieSpecProvider.CompatibilityLevel.STRICT, publicSuffixMatcher);
817 cookieSpecRegistry = RegistryBuilder.<CookieSpecProvider>create()
818 .register(CookieSpecs.DEFAULT, defaultProvider)
819 .register("best-match", defaultProvider)
820 .register("compatibility", defaultProvider)
821 .register(CookieSpecs.STANDARD, laxStandardProvider)
822 .register(CookieSpecs.STANDARD_STRICT, strictStandardProvider)
823 .register(CookieSpecs.NETSCAPE, new NetscapeDraftSpecProvider())
824 .register(CookieSpecs.IGNORE_COOKIES, new IgnoreSpecProvider())
825 .build();
826 }
827
828 CookieStore defaultCookieStore = this.cookieStore;
829 if (defaultCookieStore == null) {
830 defaultCookieStore = new BasicCookieStore();
831 }
832
833 CredentialsProvider defaultCredentialsProvider = this.credentialsProvider;
834 if (defaultCredentialsProvider == null) {
835 defaultCredentialsProvider = new BasicCredentialsProvider();
836 }
837
838 RedirectStrategy redirectStrategy = this.redirectStrategy;
839 if (redirectStrategy == null) {
840 redirectStrategy = DefaultRedirectStrategy.INSTANCE;
841 }
842
843 RequestConfig defaultRequestConfig = this.defaultRequestConfig;
844 if (defaultRequestConfig == null) {
845 defaultRequestConfig = RequestConfig.DEFAULT;
846 }
847
848 final MainClientExec exec = new MainClientExec(
849 httpprocessor,
850 routePlanner,
851 redirectStrategy,
852 targetAuthStrategy,
853 proxyAuthStrategy,
854 userTokenHandler);
855
856 ThreadFactory threadFactory = null;
857 NHttpClientEventHandler eventHandler = null;
858 if (!this.connManagerShared) {
859 threadFactory = this.threadFactory;
860 if (threadFactory == null) {
861 threadFactory = Executors.defaultThreadFactory();
862 }
863 eventHandler = this.eventHandler;
864 if (eventHandler == null) {
865 eventHandler = new HttpAsyncRequestExecutor();
866 }
867 }
868 return new InternalHttpAsyncClient(
869 connManager,
870 reuseStrategy,
871 keepAliveStrategy,
872 threadFactory,
873 eventHandler,
874 exec,
875 cookieSpecRegistry,
876 authSchemeRegistry,
877 defaultCookieStore,
878 defaultCredentialsProvider,
879 defaultRequestConfig);
880 }
881
882 }
0 /*
1 * ====================================================================
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 * ====================================================================
19 *
20 * This software consists of voluntary contributions made by many
21 * individuals on behalf of the Apache Software Foundation. For more
22 * information on the Apache Software Foundation, please see
23 * <http://www.apache.org/>.
24 *
25 */
26
27 package org.apache.http.impl.nio.client;
28
29 import org.apache.http.annotation.Immutable;
30 import org.apache.http.impl.nio.conn.PoolingNHttpClientConnectionManager;
31 import org.apache.http.nio.conn.NHttpClientConnectionManager;
32 import org.apache.http.nio.reactor.ConnectingIOReactor;
33 import org.apache.http.util.Args;
34
35 /**
36 * Factory methods for {@link org.apache.http.impl.nio.client.CloseableHttpAsyncClient} and
37 * {@link org.apache.http.impl.nio.client.CloseableHttpPipeliningClient} instances.
38 *
39 * @since 4.0
40 */
41 @Immutable
42 public class HttpAsyncClients {
43
44 private HttpAsyncClients() {
45 super();
46 }
47
48 /**
49 * Creates builder object for construction of custom
50 * {@link CloseableHttpAsyncClient} instances.
51 */
52 public static HttpAsyncClientBuilder custom() {
53 return HttpAsyncClientBuilder.create();
54 }
55
56 /**
57 * Creates {@link CloseableHttpAsyncClient} instance with default
58 * configuration.
59 */
60 public static CloseableHttpAsyncClient createDefault() {
61 return HttpAsyncClientBuilder.create().build();
62 }
63
64 /**
65 * Creates {@link CloseableHttpAsyncClient} instance with default
66 * configuration based on ssytem properties.
67 */
68 public static CloseableHttpAsyncClient createSystem() {
69 return HttpAsyncClientBuilder.create()
70 .useSystemProperties()
71 .build();
72 }
73
74 /**
75 * Creates {@link CloseableHttpAsyncClient} instance that supports esential HTTP protocol
76 * aspects only. This client does not support HTTP state management, authentication
77 * and automatic redirects.
78 */
79 public static CloseableHttpAsyncClient createMinimal() {
80 return MinimalHttpAsyncClientBuilder.create()
81 .disableCookieManagement()
82 .build();
83 }
84
85 /**
86 * Creates {@link CloseableHttpAsyncClient} instance that supports esential HTTP protocol
87 * aspects only. This client does not support HTTP state management, authentication
88 * and automatic redirects.
89 */
90 public static CloseableHttpAsyncClient createMinimal(final ConnectingIOReactor ioreactor) {
91 Args.notNull(ioreactor, "I/O reactor");
92 return createMinimal(new PoolingNHttpClientConnectionManager(ioreactor), false);
93 }
94
95 /**
96 * Creates {@link CloseableHttpAsyncClient} instance that supports esential HTTP protocol
97 * aspects only. This client does not support HTTP state management, authentication
98 * and automatic redirects.
99 */
100 public static CloseableHttpAsyncClient createMinimal(final NHttpClientConnectionManager connManager) {
101 return createMinimal(connManager, false);
102 }
103
104 /**
105 * Creates {@link CloseableHttpAsyncClient} instance that supports esential HTTP protocol
106 * aspects only. This client does not support HTTP state management, authentication
107 * and automatic redirects.
108 * <p>
109 * Please note that clients with a shared connection manager make no attempts to control
110 * its life cycle and dealocation of resources. It is a responibility of the caller to
111 * ensure that the shared connection manager is properly started and shut down when no
112 * longer needed.
113 *
114 * @since 4.1
115 */
116 public static CloseableHttpAsyncClient createMinimal(
117 final NHttpClientConnectionManager connManager, final boolean shared) {
118 Args.notNull(connManager, "Connection manager");
119 return MinimalHttpAsyncClientBuilder.create()
120 .setConnectionManager(connManager)
121 .setConnectionManagerShared(shared)
122 .disableCookieManagement()
123 .build();
124 }
125
126 /**
127 * Creates {@link CloseableHttpPipeliningClient} instance that supports pipelined request
128 * execution. This client does not support authentication and automatic redirects.
129 *
130 * @since 4.1
131 */
132 public static CloseableHttpPipeliningClient createPipelining() {
133 return MinimalHttpAsyncClientBuilder.create().build();
134 }
135
136 /**
137 * Creates {@link CloseableHttpPipeliningClient} instance that supports pipelined request
138 * execution. This client does not support authentication and automatic redirects.
139 *
140 * @since 4.1
141 */
142 public static CloseableHttpPipeliningClient createPipelining(final ConnectingIOReactor ioreactor) {
143 return createPipelining(new PoolingNHttpClientConnectionManager(ioreactor), false);
144 }
145
146 /**
147 * Creates {@link CloseableHttpPipeliningClient} instance that supports pipelined request
148 * execution. This client does not support authentication and automatic redirects.
149 *
150 * @since 4.1
151 */
152 public static CloseableHttpPipeliningClient createPipelining(final NHttpClientConnectionManager connManager) {
153 return createPipelining(connManager, false);
154 }
155
156 /**
157 * Creates {@link CloseableHttpPipeliningClient} instance that supports pipelined request
158 * execution. This client does not support authentication and automatic redirects.
159 * <p>
160 * Please note that clients with a shared connection manager make no attempts to control
161 * its life cycle and dealocation of resources. It is a responibility of the caller to
162 * ensure that the shared connection manager is properly started and shut down when no
163 * longer needed.
164 *
165 * @since 4.1
166 */
167 public static CloseableHttpPipeliningClient createPipelining(
168 final NHttpClientConnectionManager connManager, final boolean shared) {
169 Args.notNull(connManager, "Connection manager");
170 return MinimalHttpAsyncClientBuilder.create()
171 .setConnectionManager(connManager)
172 .setConnectionManagerShared(shared)
173 .build();
174 }
175
176 }
0 /*
1 * ====================================================================
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 * ====================================================================
19 *
20 * This software consists of voluntary contributions made by many
21 * individuals on behalf of the Apache Software Foundation. For more
22 * information on the Apache Software Foundation, please see
23 * <http://www.apache.org/>.
24 *
25 */
26 package org.apache.http.impl.nio.client;
27
28 import org.apache.http.impl.nio.reactor.DefaultConnectingIOReactor;
29 import org.apache.http.impl.nio.reactor.IOReactorConfig;
30 import org.apache.http.nio.reactor.ConnectingIOReactor;
31 import org.apache.http.nio.reactor.IOReactorException;
32
33 final class IOReactorUtils {
34
35 private IOReactorUtils() {
36 }
37
38 public static ConnectingIOReactor create(final IOReactorConfig config) {
39 try {
40 return new DefaultConnectingIOReactor(config);
41 } catch (final IOReactorException ex) {
42 throw new IllegalStateException(ex);
43 }
44 }
45
46 }
0 /*
1 * ====================================================================
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 * ====================================================================
19 *
20 * This software consists of voluntary contributions made by many
21 * individuals on behalf of the Apache Software Foundation. For more
22 * information on the Apache Software Foundation, please see
23 * <http://www.apache.org/>.
24 *
25 */
26 package org.apache.http.impl.nio.client;
27
28 import java.io.IOException;
29
30 import org.apache.http.HttpException;
31 import org.apache.http.HttpHost;
32 import org.apache.http.HttpRequest;
33 import org.apache.http.HttpResponse;
34 import org.apache.http.nio.ContentDecoder;
35 import org.apache.http.nio.ContentEncoder;
36 import org.apache.http.nio.IOControl;
37
38 interface InternalClientExec {
39
40 void prepare(
41 HttpHost target,
42 HttpRequest original,
43 InternalState state,
44 AbstractClientExchangeHandler<?> handler) throws IOException, HttpException;
45
46 HttpRequest generateRequest(
47 InternalState state,
48 AbstractClientExchangeHandler<?> handler) throws IOException, HttpException;
49
50 void produceContent(
51 InternalState state,
52 ContentEncoder encoder,
53 IOControl ioctrl) throws IOException;
54
55 void requestCompleted(
56 InternalState state,
57 AbstractClientExchangeHandler<?> handler);
58
59 void responseReceived(
60 HttpResponse response,
61 InternalState state,
62 AbstractClientExchangeHandler<?> handler) throws IOException, HttpException;
63
64 void consumeContent(
65 InternalState state,
66 ContentDecoder decoder,
67 IOControl ioctrl) throws IOException;
68
69 void responseCompleted(
70 InternalState state,
71 AbstractClientExchangeHandler<?> handler) throws IOException, HttpException;
72
73 }
0 /*
1 * ====================================================================
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 * ====================================================================
19 *
20 * This software consists of voluntary contributions made by many
21 * individuals on behalf of the Apache Software Foundation. For more
22 * information on the Apache Software Foundation, please see
23 * <http://www.apache.org/>.
24 *
25 */
26 package org.apache.http.impl.nio.client;
27
28 import java.util.List;
29 import java.util.concurrent.Future;
30 import java.util.concurrent.ThreadFactory;
31
32 import org.apache.commons.logging.Log;
33 import org.apache.commons.logging.LogFactory;
34 import org.apache.http.ConnectionReuseStrategy;
35 import org.apache.http.HttpHost;
36 import org.apache.http.auth.AuthSchemeProvider;
37 import org.apache.http.auth.AuthState;
38 import org.apache.http.client.CookieStore;
39 import org.apache.http.client.CredentialsProvider;
40 import org.apache.http.client.config.RequestConfig;
41 import org.apache.http.client.protocol.HttpClientContext;
42 import org.apache.http.concurrent.BasicFuture;
43 import org.apache.http.concurrent.FutureCallback;
44 import org.apache.http.config.Lookup;
45 import org.apache.http.conn.ConnectionKeepAliveStrategy;
46 import org.apache.http.cookie.CookieSpecProvider;
47 import org.apache.http.nio.NHttpClientEventHandler;
48 import org.apache.http.nio.conn.NHttpClientConnectionManager;
49 import org.apache.http.nio.protocol.HttpAsyncRequestProducer;
50 import org.apache.http.nio.protocol.HttpAsyncResponseConsumer;
51 import org.apache.http.protocol.BasicHttpContext;
52 import org.apache.http.protocol.HttpContext;
53
54 class InternalHttpAsyncClient extends CloseableHttpAsyncClientBase {
55
56 private final Log log = LogFactory.getLog(getClass());
57
58 private final NHttpClientConnectionManager connmgr;
59 private final ConnectionReuseStrategy connReuseStrategy;
60 private final ConnectionKeepAliveStrategy keepaliveStrategy;
61 private final InternalClientExec exec;
62 private final Lookup<CookieSpecProvider> cookieSpecRegistry;
63 private final Lookup<AuthSchemeProvider> authSchemeRegistry;
64 private final CookieStore cookieStore;
65 private final CredentialsProvider credentialsProvider;
66 private final RequestConfig defaultConfig;
67
68 public InternalHttpAsyncClient(
69 final NHttpClientConnectionManager connmgr,
70 final ConnectionReuseStrategy connReuseStrategy,
71 final ConnectionKeepAliveStrategy keepaliveStrategy,
72 final ThreadFactory threadFactory,
73 final NHttpClientEventHandler handler,
74 final InternalClientExec exec,
75 final Lookup<CookieSpecProvider> cookieSpecRegistry,
76 final Lookup<AuthSchemeProvider> authSchemeRegistry,
77 final CookieStore cookieStore,
78 final CredentialsProvider credentialsProvider,
79 final RequestConfig defaultConfig) {
80 super(connmgr, threadFactory, handler);
81 this.connmgr = connmgr;
82 this.connReuseStrategy = connReuseStrategy;
83 this.keepaliveStrategy = keepaliveStrategy;
84 this.exec = exec;
85 this.cookieSpecRegistry = cookieSpecRegistry;
86 this.authSchemeRegistry = authSchemeRegistry;
87 this.cookieStore = cookieStore;
88 this.credentialsProvider = credentialsProvider;
89 this.defaultConfig = defaultConfig;
90 }
91
92 private void setupContext(final HttpClientContext context) {
93 if (context.getAttribute(HttpClientContext.TARGET_AUTH_STATE) == null) {
94 context.setAttribute(HttpClientContext.TARGET_AUTH_STATE, new AuthState());
95 }
96 if (context.getAttribute(HttpClientContext.PROXY_AUTH_STATE) == null) {
97 context.setAttribute(HttpClientContext.PROXY_AUTH_STATE, new AuthState());
98 }
99 if (context.getAttribute(HttpClientContext.AUTHSCHEME_REGISTRY) == null) {
100 context.setAttribute(HttpClientContext.AUTHSCHEME_REGISTRY, this.authSchemeRegistry);
101 }
102 if (context.getAttribute(HttpClientContext.COOKIESPEC_REGISTRY) == null) {
103 context.setAttribute(HttpClientContext.COOKIESPEC_REGISTRY, this.cookieSpecRegistry);
104 }
105 if (context.getAttribute(HttpClientContext.COOKIE_STORE) == null) {
106 context.setAttribute(HttpClientContext.COOKIE_STORE, this.cookieStore);
107 }
108 if (context.getAttribute(HttpClientContext.CREDS_PROVIDER) == null) {
109 context.setAttribute(HttpClientContext.CREDS_PROVIDER, this.credentialsProvider);
110 }
111 if (context.getAttribute(HttpClientContext.REQUEST_CONFIG) == null) {
112 context.setAttribute(HttpClientContext.REQUEST_CONFIG, this.defaultConfig);
113 }
114 }
115
116 @Override
117 public <T> Future<T> execute(
118 final HttpAsyncRequestProducer requestProducer,
119 final HttpAsyncResponseConsumer<T> responseConsumer,
120 final HttpContext context,
121 final FutureCallback<T> callback) {
122 ensureRunning();
123 final BasicFuture<T> future = new BasicFuture<T>(callback);
124 final HttpClientContext localcontext = HttpClientContext.adapt(
125 context != null ? context : new BasicHttpContext());
126 setupContext(localcontext);
127
128 @SuppressWarnings("resource")
129 final DefaultClientExchangeHandlerImpl<T> handler = new DefaultClientExchangeHandlerImpl<T>(
130 this.log,
131 requestProducer,
132 responseConsumer,
133 localcontext,
134 future,
135 this.connmgr,
136 this.connReuseStrategy,
137 this.keepaliveStrategy,
138 this.exec);
139 try {
140 handler.start();
141 } catch (final Exception ex) {
142 handler.failed(ex);
143 }
144 return future;
145 }
146
147 @Override
148 public <T> Future<List<T>> execute(
149 final HttpHost target,
150 final List<? extends HttpAsyncRequestProducer> requestProducers,
151 final List<? extends HttpAsyncResponseConsumer<T>> responseConsumers,
152 final HttpContext context,
153 final FutureCallback<List<T>> callback) {
154 throw new UnsupportedOperationException("Pipelining not supported");
155 }
156
157 }
0 /*
1 * ====================================================================
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 * ====================================================================
19 *
20 * This software consists of voluntary contributions made by many
21 * individuals on behalf of the Apache Software Foundation. For more
22 * information on the Apache Software Foundation, please see
23 * <http://www.apache.org/>.
24 *
25 */
26
27 package org.apache.http.impl.nio.client;
28
29 import java.io.IOException;
30
31 import org.apache.commons.logging.Log;
32 import org.apache.commons.logging.LogFactory;
33 import org.apache.http.impl.nio.DefaultNHttpClientConnection;
34 import org.apache.http.impl.nio.reactor.AbstractIODispatch;
35 import org.apache.http.nio.NHttpClientEventHandler;
36 import org.apache.http.nio.reactor.IOSession;
37
38 class InternalIODispatch extends AbstractIODispatch<DefaultNHttpClientConnection> {
39
40 private final Log log = LogFactory.getLog(InternalIODispatch.class);
41
42 private final NHttpClientEventHandler handler;
43
44 public InternalIODispatch(final NHttpClientEventHandler handler) {
45 super();
46 if (this.log.isDebugEnabled()) {
47 this.handler = new InternalRequestExecutor(this.log, handler);
48 } else {
49 this.handler = handler;
50 }
51 }
52
53 @Override
54 protected DefaultNHttpClientConnection createConnection(final IOSession session) {
55 throw new IllegalStateException("Connection must be created by connection manager");
56 }
57
58 @Override
59 protected void onConnected(final DefaultNHttpClientConnection conn) {
60 final Object attachment = conn.getContext().getAttribute(IOSession.ATTACHMENT_KEY);
61 try {
62 this.handler.connected(conn, attachment);
63 } catch (final Exception ex) {
64 this.handler.exception(conn, ex);
65 }
66 }
67
68 @Override
69 protected void onClosed(final DefaultNHttpClientConnection conn) {
70 this.handler.closed(conn);
71 }
72
73 @Override
74 protected void onException(final DefaultNHttpClientConnection conn, final IOException ex) {
75 this.handler.exception(conn, ex);
76 }
77
78 @Override
79 protected void onInputReady(final DefaultNHttpClientConnection conn) {
80 conn.consumeInput(this.handler);
81 }
82
83 @Override
84 protected void onOutputReady(final DefaultNHttpClientConnection conn) {
85 conn.produceOutput(this.handler);
86 }
87
88 @Override
89 protected void onTimeout(final DefaultNHttpClientConnection conn) {
90 try {
91 this.handler.timeout(conn);
92 } catch (final Exception ex) {
93 this.handler.exception(conn, ex);
94 }
95 }
96
97 }
0 /*
1 * ====================================================================
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 * ====================================================================
19 *
20 * This software consists of voluntary contributions made by many
21 * individuals on behalf of the Apache Software Foundation. For more
22 * information on the Apache Software Foundation, please see
23 * <http://www.apache.org/>.
24 *
25 */
26 package org.apache.http.impl.nio.client;
27
28 import java.io.IOException;
29
30 import org.apache.commons.logging.Log;
31 import org.apache.http.nio.reactor.IOReactorExceptionHandler;
32
33 class InternalIOReactorExceptionHandler implements IOReactorExceptionHandler {
34
35 private final Log log;
36
37 InternalIOReactorExceptionHandler(final Log log) {
38 super();
39 this.log = log;
40 }
41
42 @Override
43 public boolean handle(final IOException ex) {
44 this.log.error("Fatal I/O error", ex);
45 return false;
46 }
47
48 @Override
49 public boolean handle(final RuntimeException ex) {
50 this.log.error("Fatal runtime error", ex);
51 return false;
52 }
53
54 }
0 /*
1 * ====================================================================
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 * ====================================================================
19 *
20 * This software consists of voluntary contributions made by many
21 * individuals on behalf of the Apache Software Foundation. For more
22 * information on the Apache Software Foundation, please see
23 * <http://www.apache.org/>.
24 *
25 */
26
27 package org.apache.http.impl.nio.client;
28
29 import java.io.IOException;
30
31 import org.apache.commons.logging.Log;
32 import org.apache.http.HttpException;
33 import org.apache.http.nio.ContentDecoder;
34 import org.apache.http.nio.ContentEncoder;
35 import org.apache.http.nio.NHttpClientConnection;
36 import org.apache.http.nio.NHttpClientEventHandler;
37
38 class InternalRequestExecutor implements NHttpClientEventHandler {
39
40 private final Log log;
41 private final NHttpClientEventHandler handler;
42
43 public InternalRequestExecutor(final Log log, final NHttpClientEventHandler handler) {
44 this.log = log;
45 this.handler = handler;
46 }
47
48 @Override
49 public void connected(
50 final NHttpClientConnection conn,
51 final Object attachment) throws IOException, HttpException {
52 if (this.log.isDebugEnabled()) {
53 this.log.debug(conn + ": Connected");
54 }
55 this.handler.connected(conn, attachment);
56 }
57
58 @Override
59 public void closed(final NHttpClientConnection conn) {
60 if (this.log.isDebugEnabled()) {
61 this.log.debug(conn + ": Disconnected");
62 }
63 this.handler.closed(conn);
64 }
65
66 @Override
67 public void requestReady(
68 final NHttpClientConnection conn) throws IOException, HttpException {
69 if (this.log.isDebugEnabled()) {
70 this.log.debug(conn + " Request ready");
71 }
72 this.handler.requestReady(conn);
73 }
74
75 @Override
76 public void inputReady(
77 final NHttpClientConnection conn,
78 final ContentDecoder decoder) throws IOException, HttpException {
79 if (this.log.isDebugEnabled()) {
80 this.log.debug(conn + " Input ready");
81 }
82 this.handler.inputReady(conn, decoder);
83 if (this.log.isDebugEnabled()) {
84 this.log.debug(conn + " " + decoder);
85 }
86 }
87
88 @Override
89 public void outputReady(
90 final NHttpClientConnection conn,
91 final ContentEncoder encoder) throws IOException, HttpException {
92 if (this.log.isDebugEnabled()) {
93 this.log.debug(conn + " Output ready");
94 }
95 this.handler.outputReady(conn, encoder);
96 if (this.log.isDebugEnabled()) {
97 this.log.debug(conn + " " + encoder);
98 }
99 }
100
101 @Override
102 public void responseReceived(
103 final NHttpClientConnection conn) throws HttpException, IOException {
104 if (this.log.isDebugEnabled()) {
105 this.log.debug(conn + " Response received");
106 }
107 this.handler.responseReceived(conn);
108 }
109
110 @Override
111 public void timeout(final NHttpClientConnection conn) throws HttpException, IOException {
112 if (this.log.isDebugEnabled()) {
113 this.log.debug(conn + " Timeout");
114 }
115 this.handler.timeout(conn);
116 }
117
118 @Override
119 public void exception(final NHttpClientConnection conn, final Exception ex) {
120 if (this.log.isDebugEnabled()) {
121 this.log.debug(conn + " Exception", ex);
122 }
123 this.handler.exception(conn, ex);
124 }
125
126 @Override
127 public void endOfInput(final NHttpClientConnection conn) throws IOException {
128 if (this.log.isDebugEnabled()) {
129 this.log.debug(conn + " End of input");
130 }
131 this.handler.endOfInput(conn);
132 }
133
134 }
0 /*
1 * ====================================================================
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 * ====================================================================
19 *
20 * This software consists of voluntary contributions made by many
21 * individuals on behalf of the Apache Software Foundation. For more
22 * information on the Apache Software Foundation, please see
23 * <http://www.apache.org/>.
24 *
25 */
26 package org.apache.http.impl.nio.client;
27
28 import java.nio.ByteBuffer;
29
30 import org.apache.http.HttpResponse;
31 import org.apache.http.client.methods.HttpRequestWrapper;
32 import org.apache.http.client.methods.HttpUriRequest;
33 import org.apache.http.client.protocol.HttpClientContext;
34 import org.apache.http.nio.protocol.HttpAsyncRequestProducer;
35 import org.apache.http.nio.protocol.HttpAsyncResponseConsumer;
36
37 class InternalState {
38
39 private final long id;
40 private final HttpAsyncRequestProducer requestProducer;
41 private final HttpAsyncResponseConsumer<?> responseConsumer;
42 private final HttpClientContext localContext;
43
44 private HttpRequestWrapper mainRequest;
45 private HttpResponse finalResponse;
46 private ByteBuffer tmpbuf;
47 private boolean requestContentProduced;
48 private int execCount;
49
50 private int redirectCount;
51 private HttpUriRequest redirect;
52
53 public InternalState(
54 final long id,
55 final HttpAsyncRequestProducer requestProducer,
56 final HttpAsyncResponseConsumer<?> responseConsumer,
57 final HttpClientContext localContext) {
58 super();
59 this.id = id;
60 this.requestProducer = requestProducer;
61 this.responseConsumer = responseConsumer;
62 this.localContext = localContext;
63 }
64
65 public long getId() {
66 return id;
67 }
68
69 public HttpAsyncRequestProducer getRequestProducer() {
70 return requestProducer;
71 }
72
73 public HttpAsyncResponseConsumer<?> getResponseConsumer() {
74 return responseConsumer;
75 }
76
77 public HttpClientContext getLocalContext() {
78 return localContext;
79 }
80
81 public HttpRequestWrapper getMainRequest() {
82 return mainRequest;
83 }
84
85 public void setMainRequest(final HttpRequestWrapper mainRequest) {
86 this.mainRequest = mainRequest;
87 }
88
89 public HttpResponse getFinalResponse() {
90 return finalResponse;
91 }
92
93 public void setFinalResponse(final HttpResponse finalResponse) {
94 this.finalResponse = finalResponse;
95 }
96
97 public ByteBuffer getTmpbuf() {
98 if (tmpbuf == null) {
99 tmpbuf = ByteBuffer.allocate(4 * 1024);
100 }
101 return tmpbuf;
102 }
103
104 public boolean isRequestContentProduced() {
105 return requestContentProduced;
106 }
107
108 public void setRequestContentProduced() {
109 this.requestContentProduced = true;
110 }
111
112 public int getExecCount() {
113 return execCount;
114 }
115
116 public void incrementExecCount() {
117 this.execCount++;
118 }
119
120 public int getRedirectCount() {
121 return redirectCount;
122 }
123
124 public void incrementRedirectCount() {
125 this.redirectCount++;
126 }
127
128 public HttpUriRequest getRedirect() {
129 return redirect;
130 }
131
132 public void setRedirect(final HttpUriRequest redirect) {
133 this.redirect = redirect;
134 }
135
136 @Override
137 public String toString() {
138 return Long.toString(id);
139 }
140
141 }
0 /*
1 * ====================================================================
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 * ====================================================================
19 *
20 * This software consists of voluntary contributions made by many
21 * individuals on behalf of the Apache Software Foundation. For more
22 * information on the Apache Software Foundation, please see
23 * <http://www.apache.org/>.
24 *
25 */
26 package org.apache.http.impl.nio.client;
27
28 import java.io.IOException;
29 import java.net.URI;
30 import java.net.URISyntaxException;
31 import java.nio.ByteBuffer;
32 import java.util.List;
33
34 import org.apache.commons.logging.Log;
35 import org.apache.commons.logging.LogFactory;
36 import org.apache.http.HttpException;
37 import org.apache.http.HttpHost;
38 import org.apache.http.HttpRequest;
39 import org.apache.http.HttpResponse;
40 import org.apache.http.HttpStatus;
41 import org.apache.http.HttpVersion;
42 import org.apache.http.ProtocolException;
43 import org.apache.http.auth.AUTH;
44 import org.apache.http.auth.AuthProtocolState;
45 import org.apache.http.auth.AuthScheme;
46 import org.apache.http.auth.AuthScope;
47 import org.apache.http.auth.AuthState;
48 import org.apache.http.auth.UsernamePasswordCredentials;
49 import org.apache.http.client.AuthenticationStrategy;
50 import org.apache.http.client.CredentialsProvider;
51 import org.apache.http.client.NonRepeatableRequestException;
52 import org.apache.http.client.RedirectException;
53 import org.apache.http.client.RedirectStrategy;
54 import org.apache.http.client.UserTokenHandler;
55 import org.apache.http.client.config.RequestConfig;
56 import org.apache.http.client.methods.Configurable;
57 import org.apache.http.client.methods.HttpRequestWrapper;
58 import org.apache.http.client.methods.HttpUriRequest;
59 import org.apache.http.client.protocol.HttpClientContext;
60 import org.apache.http.client.protocol.RequestClientConnControl;
61 import org.apache.http.client.utils.URIUtils;
62 import org.apache.http.conn.routing.BasicRouteDirector;
63 import org.apache.http.conn.routing.HttpRoute;
64 import org.apache.http.conn.routing.HttpRouteDirector;
65 import org.apache.http.conn.routing.HttpRoutePlanner;
66 import org.apache.http.impl.auth.HttpAuthenticator;
67 import org.apache.http.message.BasicHttpRequest;
68 import org.apache.http.nio.ContentDecoder;
69 import org.apache.http.nio.ContentEncoder;
70 import org.apache.http.nio.IOControl;
71 import org.apache.http.nio.NHttpClientConnection;
72 import org.apache.http.nio.protocol.HttpAsyncRequestProducer;
73 import org.apache.http.nio.protocol.HttpAsyncResponseConsumer;
74 import org.apache.http.protocol.HttpCoreContext;
75 import org.apache.http.protocol.HttpProcessor;
76 import org.apache.http.protocol.ImmutableHttpProcessor;
77 import org.apache.http.protocol.RequestTargetHost;
78
79 class MainClientExec implements InternalClientExec {
80
81 private final Log log = LogFactory.getLog(getClass());
82
83 private final HttpProcessor httpProcessor;
84 private final HttpProcessor proxyHttpProcessor;
85 private final HttpRoutePlanner routePlanner;
86 private final AuthenticationStrategy targetAuthStrategy;
87 private final AuthenticationStrategy proxyAuthStrategy;
88 private final UserTokenHandler userTokenHandler;
89 private final RedirectStrategy redirectStrategy;
90 private final HttpRouteDirector routeDirector;
91 private final HttpAuthenticator authenticator;
92
93 public MainClientExec(
94 final HttpProcessor httpProcessor,
95 final HttpRoutePlanner routePlanner,
96 final RedirectStrategy redirectStrategy,
97 final AuthenticationStrategy targetAuthStrategy,
98 final AuthenticationStrategy proxyAuthStrategy,
99 final UserTokenHandler userTokenHandler) {
100 super();
101 this.httpProcessor = httpProcessor;
102 this.proxyHttpProcessor = new ImmutableHttpProcessor(
103 new RequestTargetHost(), new RequestClientConnControl());
104 this.routePlanner = routePlanner;
105 this.redirectStrategy = redirectStrategy;
106 this.targetAuthStrategy = targetAuthStrategy;
107 this.proxyAuthStrategy = proxyAuthStrategy;
108 this.userTokenHandler = userTokenHandler;
109 this.routeDirector = new BasicRouteDirector();
110 this.authenticator = new HttpAuthenticator(log);
111 }
112
113 @Override
114 public void prepare(
115 final HttpHost target,
116 final HttpRequest original,
117 final InternalState state,
118 final AbstractClientExchangeHandler<?> handler) throws HttpException, IOException {
119 if (this.log.isDebugEnabled()) {
120 this.log.debug("[exchange: " + state.getId() + "] start execution");
121 }
122
123 final HttpClientContext localContext = state.getLocalContext();
124
125 if (original instanceof Configurable) {
126 final RequestConfig config = ((Configurable) original).getConfig();
127 if (config != null) {
128 localContext.setRequestConfig(config);
129 }
130 }
131
132 final List<URI> redirectLocations = localContext.getRedirectLocations();
133 if (redirectLocations != null) {
134 redirectLocations.clear();
135 }
136
137 final HttpRequestWrapper request = HttpRequestWrapper.wrap(original);
138 final HttpRoute route = this.routePlanner.determineRoute(target, request, localContext);
139
140 handler.setRoute(route);
141
142 state.setMainRequest(request);
143 handler.setCurrentRequest(request);
144
145 prepareRequest(state, handler);
146 }
147
148 @Override
149 public HttpRequest generateRequest(
150 final InternalState state,
151 final AbstractClientExchangeHandler<?> handler) throws IOException, HttpException {
152
153 final HttpRoute route = handler.getRoute();
154
155 handler.verifytRoute();
156
157 if (!handler.isRouteEstablished()) {
158 int step;
159 loop:
160 do {
161 final HttpRoute fact = handler.getActualRoute();
162 step = this.routeDirector.nextStep(route, fact);
163 switch (step) {
164 case HttpRouteDirector.CONNECT_TARGET:
165 handler.onRouteToTarget();
166 break;
167 case HttpRouteDirector.CONNECT_PROXY:
168 handler.onRouteToProxy();
169 break;
170 case HttpRouteDirector.TUNNEL_TARGET:
171 if (this.log.isDebugEnabled()) {
172 this.log.debug("[exchange: " + state.getId() + "] Tunnel required");
173 }
174 final HttpRequest connect = createConnectRequest(route, state);
175 handler.setCurrentRequest(HttpRequestWrapper.wrap(connect));
176 break loop;
177 case HttpRouteDirector.TUNNEL_PROXY:
178 throw new HttpException("Proxy chains are not supported");
179 case HttpRouteDirector.LAYER_PROTOCOL:
180 handler.onRouteUpgrade();
181 break;
182 case HttpRouteDirector.UNREACHABLE:
183 throw new HttpException("Unable to establish route: " +
184 "planned = " + route + "; current = " + fact);
185 case HttpRouteDirector.COMPLETE:
186 handler.onRouteComplete();
187 this.log.debug("Connection route established");
188 break;
189 default:
190 throw new IllegalStateException("Unknown step indicator "
191 + step + " from RouteDirector.");
192 }
193 } while (step > HttpRouteDirector.COMPLETE);
194 }
195
196 final HttpClientContext localContext = state.getLocalContext();
197 HttpRequestWrapper currentRequest = handler.getCurrentRequest();
198 if (currentRequest == null) {
199 currentRequest = state.getMainRequest();
200 handler.setCurrentRequest(currentRequest);
201 }
202
203 if (handler.isRouteEstablished()) {
204 state.incrementExecCount();
205 if (state.getExecCount() > 1) {
206 final HttpAsyncRequestProducer requestProducer = state.getRequestProducer();
207 if (!requestProducer.isRepeatable() && state.isRequestContentProduced()) {
208 throw new NonRepeatableRequestException("Cannot retry request " +
209 "with a non-repeatable request entity.");
210 }
211 requestProducer.resetRequest();
212 }
213 if (this.log.isDebugEnabled()) {
214 this.log.debug("[exchange: " + state.getId() + "] Attempt " + state.getExecCount() +
215 " to execute request");
216 }
217
218 if (!currentRequest.containsHeader(AUTH.WWW_AUTH_RESP)) {
219 final AuthState targetAuthState = localContext.getTargetAuthState();
220 if (this.log.isDebugEnabled()) {
221 this.log.debug("Target auth state: " + targetAuthState.getState());
222 }
223 this.authenticator.generateAuthResponse(currentRequest, targetAuthState, localContext);
224 }
225 if (!currentRequest.containsHeader(AUTH.PROXY_AUTH_RESP) && !route.isTunnelled()) {
226 final AuthState proxyAuthState = localContext.getProxyAuthState();
227 if (this.log.isDebugEnabled()) {
228 this.log.debug("Proxy auth state: " + proxyAuthState.getState());
229 }
230 this.authenticator.generateAuthResponse(currentRequest, proxyAuthState, localContext);
231 }
232 } else {
233 if (!currentRequest.containsHeader(AUTH.PROXY_AUTH_RESP)) {
234 final AuthState proxyAuthState = localContext.getProxyAuthState();
235 if (this.log.isDebugEnabled()) {
236 this.log.debug("Proxy auth state: " + proxyAuthState.getState());
237 }
238 this.authenticator.generateAuthResponse(currentRequest, proxyAuthState, localContext);
239 }
240 }
241
242 final NHttpClientConnection managedConn = handler.getConnection();
243 localContext.setAttribute(HttpCoreContext.HTTP_CONNECTION, managedConn);
244 final RequestConfig config = localContext.getRequestConfig();
245 if (config.getSocketTimeout() > 0) {
246 managedConn.setSocketTimeout(config.getSocketTimeout());
247 }
248 return currentRequest;
249 }
250
251 @Override
252 public void produceContent(
253 final InternalState state,
254 final ContentEncoder encoder,
255 final IOControl ioctrl) throws IOException {
256 if (this.log.isDebugEnabled()) {
257 this.log.debug("[exchange: " + state.getId() + "] produce content");
258 }
259 final HttpAsyncRequestProducer requestProducer = state.getRequestProducer();
260 state.setRequestContentProduced();
261 requestProducer.produceContent(encoder, ioctrl);
262 if (encoder.isCompleted()) {
263 requestProducer.resetRequest();
264 }
265 }
266
267 @Override
268 public void requestCompleted(
269 final InternalState state,
270 final AbstractClientExchangeHandler<?> handler) {
271 if (this.log.isDebugEnabled()) {
272 this.log.debug("[exchange: " + state.getId() + "] Request completed");
273 }
274 final HttpClientContext localContext = state.getLocalContext();
275 final HttpAsyncRequestProducer requestProducer = state.getRequestProducer();
276 requestProducer.requestCompleted(localContext);
277 }
278
279 @Override
280 public void responseReceived(
281 final HttpResponse response,
282 final InternalState state,
283 final AbstractClientExchangeHandler<?> handler) throws IOException, HttpException {
284 if (this.log.isDebugEnabled()) {
285 this.log.debug("[exchange: " + state.getId() + "] Response received " + response.getStatusLine());
286 }
287 final HttpClientContext context = state.getLocalContext();
288 context.setAttribute(HttpClientContext.HTTP_RESPONSE, response);
289 this.httpProcessor.process(response, context);
290
291 handler.setCurrentResponse(response);
292
293 if (!handler.isRouteEstablished()) {
294 final int status = response.getStatusLine().getStatusCode();
295 if (status < 200) {
296 throw new HttpException("Unexpected response to CONNECT request: " +
297 response.getStatusLine());
298 }
299 if (status == HttpStatus.SC_OK) {
300 handler.onRouteTunnelToTarget();
301 handler.setCurrentRequest(null);
302 } else {
303 if (!handleConnectResponse(state, handler)) {
304 state.setFinalResponse(response);
305 }
306 }
307 } else {
308 if (!handleResponse(state, handler)) {
309 state.setFinalResponse(response);
310 }
311 }
312 if (state.getFinalResponse() != null) {
313 final HttpAsyncResponseConsumer<?> responseConsumer = state.getResponseConsumer();
314 responseConsumer.responseReceived(response);
315 }
316 }
317
318 @Override
319 public void consumeContent(
320 final InternalState state,
321 final ContentDecoder decoder,
322 final IOControl ioctrl) throws IOException {
323 if (this.log.isDebugEnabled()) {
324 this.log.debug("[exchange: " + state.getId() + "] Consume content");
325 }
326 if (state.getFinalResponse() != null) {
327 final HttpAsyncResponseConsumer<?> responseConsumer = state.getResponseConsumer();
328 responseConsumer.consumeContent(decoder, ioctrl);
329 } else {
330 final ByteBuffer tmpbuf = state.getTmpbuf();
331 tmpbuf.clear();
332 decoder.read(tmpbuf);
333 }
334 }
335
336 @Override
337 public void responseCompleted(
338 final InternalState state,
339 final AbstractClientExchangeHandler<?> handler) throws IOException, HttpException {
340 final HttpClientContext localContext = state.getLocalContext();
341 final HttpResponse currentResponse = handler.getCurrentResponse();
342
343 if (!handler.isRouteEstablished()) {
344 final int status = currentResponse.getStatusLine().getStatusCode();
345 if (status == HttpStatus.SC_OK) {
346 handler.setCurrentResponse(null);
347 return;
348 }
349 }
350
351 final boolean keepAlive = handler.manageConnectionPersistence();
352 if (!keepAlive) {
353 handler.releaseConnection();
354 final AuthState proxyAuthState = localContext.getProxyAuthState();
355 if (proxyAuthState.getState() == AuthProtocolState.SUCCESS
356 && proxyAuthState.getAuthScheme() != null
357 && proxyAuthState.getAuthScheme().isConnectionBased()) {
358 if (this.log.isDebugEnabled()) {
359 this.log.debug("[exchange: " + state.getId() + "] Resetting proxy auth state");
360 }
361 proxyAuthState.reset();
362 }
363 final AuthState targetAuthState = localContext.getTargetAuthState();
364 if (targetAuthState.getState() == AuthProtocolState.SUCCESS
365 && targetAuthState.getAuthScheme() != null
366 && targetAuthState.getAuthScheme().isConnectionBased()) {
367 if (this.log.isDebugEnabled()) {
368 this.log.debug("[exchange: " + state.getId() + "] Resetting target auth state");
369 }
370 targetAuthState.reset();
371 }
372 }
373
374 Object userToken = localContext.getUserToken();
375 if (userToken == null) {
376 userToken = this.userTokenHandler.getUserToken(localContext);
377 localContext.setAttribute(HttpClientContext.USER_TOKEN, userToken);
378 }
379
380 if (state.getFinalResponse() != null) {
381 final HttpAsyncResponseConsumer<?> responseConsumer = state.getResponseConsumer();
382 responseConsumer.responseCompleted(localContext);
383 if (this.log.isDebugEnabled()) {
384 this.log.debug("[exchange: " + state.getId() + "] Response processed");
385 }
386 handler.releaseConnection();
387 } else {
388 if (state.getRedirect() != null) {
389 final HttpUriRequest redirect = state.getRedirect();
390 final URI uri = redirect.getURI();
391 if (this.log.isDebugEnabled()) {
392 this.log.debug("[exchange: " + state.getId() + "] Redirecting to '" + uri + "'");
393 }
394 state.setRedirect(null);
395
396 final HttpHost newTarget = URIUtils.extractHost(uri);
397 if (newTarget == null) {
398 throw new ProtocolException("Redirect URI does not specify a valid host name: " + uri);
399 }
400
401 // Reset auth states if redirecting to another host
402 final HttpRoute route = handler.getRoute();
403 if (!route.getTargetHost().equals(newTarget)) {
404 final AuthState targetAuthState = localContext.getTargetAuthState();
405 if (this.log.isDebugEnabled()) {
406 this.log.debug("[exchange: " + state.getId() + "] Resetting target auth state");
407 }
408 targetAuthState.reset();
409 final AuthState proxyAuthState = localContext.getProxyAuthState();
410 final AuthScheme authScheme = proxyAuthState.getAuthScheme();
411 if (authScheme != null && authScheme.isConnectionBased()) {
412 if (this.log.isDebugEnabled()) {
413 this.log.debug("[exchange: " + state.getId() + "] Resetting proxy auth state");
414 }
415 proxyAuthState.reset();
416 }
417 }
418
419 if (!redirect.headerIterator().hasNext()) {
420 final HttpRequest original = state.getMainRequest().getOriginal();
421 redirect.setHeaders(original.getAllHeaders());
422 }
423
424 final HttpRequestWrapper newRequest = HttpRequestWrapper.wrap(redirect);
425 final HttpRoute newRoute = this.routePlanner.determineRoute(
426 newTarget, newRequest, localContext);
427 if (!route.equals(newRoute)) {
428 handler.releaseConnection();
429 }
430 handler.setRoute(newRoute);
431 handler.setCurrentRequest(newRequest);
432 state.setMainRequest(newRequest);
433 prepareRequest(state, handler);
434 }
435 }
436 handler.setCurrentResponse(null);
437 }
438
439 private void rewriteRequestURI(
440 final HttpRequestWrapper request,
441 final HttpRoute route) throws ProtocolException {
442 try {
443 URI uri = request.getURI();
444 if (uri != null) {
445 if (route.getProxyHost() != null && !route.isTunnelled()) {
446 // Make sure the request URI is absolute
447 if (!uri.isAbsolute()) {
448 final HttpHost target = route.getTargetHost();
449 uri = URIUtils.rewriteURI(uri, target, true);
450 } else {
451 uri = URIUtils.rewriteURI(uri);
452 }
453 } else {
454 // Make sure the request URI is relative
455 if (uri.isAbsolute()) {
456 uri = URIUtils.rewriteURI(uri, null, true);
457 } else {
458 uri = URIUtils.rewriteURI(uri);
459 }
460 }
461 request.setURI(uri);
462 }
463 } catch (final URISyntaxException ex) {
464 throw new ProtocolException("Invalid URI: " +
465 request.getRequestLine().getUri(), ex);
466 }
467 }
468
469 private void prepareRequest(
470 final InternalState state,
471 final AbstractClientExchangeHandler<?> handler) throws IOException, HttpException {
472 final HttpClientContext localContext = state.getLocalContext();
473 final HttpRequestWrapper currentRequest = handler.getCurrentRequest();
474 final HttpRoute route = handler.getRoute();
475
476 final HttpRequest original = currentRequest.getOriginal();
477 URI uri = null;
478 if (original instanceof HttpUriRequest) {
479 uri = ((HttpUriRequest) original).getURI();
480 } else {
481 final String uriString = original.getRequestLine().getUri();
482 try {
483 uri = URI.create(uriString);
484 } catch (final IllegalArgumentException ex) {
485 if (this.log.isDebugEnabled()) {
486 this.log.debug("Unable to parse '" + uriString + "' as a valid URI; " +
487 "request URI and Host header may be inconsistent", ex);
488 }
489 }
490
491 }
492 currentRequest.setURI(uri);
493
494 // Re-write request URI if needed
495 rewriteRequestURI(currentRequest, route);
496
497 HttpHost target = null;
498 if (uri != null && uri.isAbsolute() && uri.getHost() != null) {
499 target = new HttpHost(uri.getHost(), uri.getPort(), uri.getScheme());
500 }
501 if (target == null) {
502 target = route.getTargetHost();
503 }
504
505 // Get user info from the URI
506 if (uri != null) {
507 final String userinfo = uri.getUserInfo();
508 if (userinfo != null) {
509 final CredentialsProvider credsProvider = localContext.getCredentialsProvider();
510 credsProvider.setCredentials(
511 new AuthScope(target),
512 new UsernamePasswordCredentials(userinfo));
513 }
514 }
515
516 localContext.setAttribute(HttpClientContext.HTTP_REQUEST, currentRequest);
517 localContext.setAttribute(HttpClientContext.HTTP_TARGET_HOST, target);
518 localContext.setAttribute(HttpClientContext.HTTP_ROUTE, route);
519 this.httpProcessor.process(currentRequest, localContext);
520 }
521
522 private HttpRequest createConnectRequest(
523 final HttpRoute route, final InternalState state) throws IOException, HttpException {
524 // see RFC 2817, section 5.2 and
525 // INTERNET-DRAFT: Tunneling TCP based protocols through
526 // Web proxy servers
527 final HttpHost target = route.getTargetHost();
528 final String host = target.getHostName();
529 final int port = target.getPort();
530 final StringBuilder buffer = new StringBuilder(host.length() + 6);
531 buffer.append(host);
532 buffer.append(':');
533 buffer.append(Integer.toString(port));
534 final HttpRequest request = new BasicHttpRequest("CONNECT", buffer.toString(), HttpVersion.HTTP_1_1);
535 final HttpClientContext localContext = state.getLocalContext();
536 this.proxyHttpProcessor.process(request, localContext);
537 return request;
538 }
539
540 private boolean handleConnectResponse(
541 final InternalState state,
542 final AbstractClientExchangeHandler<?> handler) throws HttpException {
543 final HttpClientContext localContext = state.getLocalContext();
544 final RequestConfig config = localContext.getRequestConfig();
545 if (config.isAuthenticationEnabled()) {
546 final CredentialsProvider credsProvider = localContext.getCredentialsProvider();
547 if (credsProvider != null) {
548 final HttpRoute route = handler.getRoute();
549 final HttpHost proxy = route.getProxyHost();
550 final HttpResponse currentResponse = handler.getCurrentResponse();
551 final AuthState proxyAuthState = localContext.getProxyAuthState();
552 if (this.authenticator.isAuthenticationRequested(proxy, currentResponse,
553 this.proxyAuthStrategy, proxyAuthState, localContext)) {
554 return this.authenticator.handleAuthChallenge(proxy, currentResponse,
555 this.proxyAuthStrategy, proxyAuthState, localContext);
556 }
557 }
558 }
559 return false;
560 }
561
562 private boolean handleResponse(
563 final InternalState state,
564 final AbstractClientExchangeHandler<?> handler) throws HttpException {
565 final HttpClientContext localContext = state.getLocalContext();
566 final RequestConfig config = localContext.getRequestConfig();
567 if (config.isAuthenticationEnabled()) {
568 if (needAuthentication(state, handler)) {
569 // discard previous auth headers
570 final HttpRequestWrapper currentRequest = handler.getCurrentRequest();
571 final HttpRequest original = currentRequest.getOriginal();
572 if (!original.containsHeader(AUTH.WWW_AUTH_RESP)) {
573 currentRequest.removeHeaders(AUTH.WWW_AUTH_RESP);
574 }
575 if (!original.containsHeader(AUTH.PROXY_AUTH_RESP)) {
576 currentRequest.removeHeaders(AUTH.PROXY_AUTH_RESP);
577 }
578 return true;
579 }
580 }
581 if (config.isRedirectsEnabled()) {
582 final HttpRequest currentRequest = handler.getCurrentRequest();
583 final HttpResponse currentResponse = handler.getCurrentResponse();
584 if (this.redirectStrategy.isRedirected(currentRequest, currentResponse, localContext)) {
585 final int maxRedirects = config.getMaxRedirects() >= 0 ? config.getMaxRedirects() : 100;
586 if (state.getRedirectCount() >= maxRedirects) {
587 throw new RedirectException("Maximum redirects (" + maxRedirects + ") exceeded");
588 }
589 state.incrementRedirectCount();
590 final HttpUriRequest redirect = this.redirectStrategy.getRedirect(currentRequest, currentResponse,
591 localContext);
592 state.setRedirect(redirect);
593 return true;
594 }
595 }
596 return false;
597 }
598
599 private boolean needAuthentication(
600 final InternalState state,
601 final AbstractClientExchangeHandler<?> handler) throws HttpException {
602 final HttpClientContext localContext = state.getLocalContext();
603 final CredentialsProvider credsProvider = localContext.getCredentialsProvider();
604 if (credsProvider != null) {
605 final HttpRoute route = handler.getRoute();
606 final HttpResponse currentResponse = handler.getCurrentResponse();
607 HttpHost target = localContext.getTargetHost();
608 if (target == null) {
609 target = route.getTargetHost();
610 }
611 if (target.getPort() < 0) {
612 target = new HttpHost(
613 target.getHostName(),
614 route.getTargetHost().getPort(),
615 target.getSchemeName());
616 }
617 final AuthState targetAuthState = localContext.getTargetAuthState();
618 final AuthState proxyAuthState = localContext.getProxyAuthState();
619
620 final boolean targetAuthRequested = this.authenticator.isAuthenticationRequested(
621 target, currentResponse, this.targetAuthStrategy, targetAuthState, localContext);
622
623 HttpHost proxy = route.getProxyHost();
624 // if proxy is not set use target host instead
625 if (proxy == null) {
626 proxy = route.getTargetHost();
627 }
628 final boolean proxyAuthRequested = this.authenticator.isAuthenticationRequested(
629 proxy, currentResponse, this.proxyAuthStrategy, proxyAuthState, localContext);
630
631 if (targetAuthRequested) {
632 return this.authenticator.handleAuthChallenge(target, currentResponse,
633 this.targetAuthStrategy, targetAuthState, localContext);
634 }
635 if (proxyAuthRequested) {
636 return this.authenticator.handleAuthChallenge(proxy, currentResponse,
637 this.proxyAuthStrategy, proxyAuthState, localContext);
638 }
639 }
640 return false;
641 }
642
643 }
0 /*
1 * ====================================================================
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 * ====================================================================
19 *
20 * This software consists of voluntary contributions made by many
21 * individuals on behalf of the Apache Software Foundation. For more
22 * information on the Apache Software Foundation, please see
23 * <http://www.apache.org/>.
24 *
25 */
26 package org.apache.http.impl.nio.client;
27
28 import java.io.IOException;
29
30 import org.apache.commons.logging.Log;
31 import org.apache.http.ConnectionReuseStrategy;
32 import org.apache.http.HttpException;
33 import org.apache.http.HttpHost;
34 import org.apache.http.HttpRequest;
35 import org.apache.http.HttpResponse;
36 import org.apache.http.client.config.RequestConfig;
37 import org.apache.http.client.methods.Configurable;
38 import org.apache.http.client.methods.HttpExecutionAware;
39 import org.apache.http.client.methods.HttpRequestWrapper;
40 import org.apache.http.client.protocol.HttpClientContext;
41 import org.apache.http.concurrent.BasicFuture;
42 import org.apache.http.conn.ConnectionKeepAliveStrategy;
43 import org.apache.http.conn.routing.HttpRoute;
44 import org.apache.http.nio.ContentDecoder;
45 import org.apache.http.nio.ContentEncoder;
46 import org.apache.http.nio.IOControl;
47 import org.apache.http.nio.NHttpClientConnection;
48 import org.apache.http.nio.conn.NHttpClientConnectionManager;
49 import org.apache.http.nio.protocol.HttpAsyncRequestProducer;
50 import org.apache.http.nio.protocol.HttpAsyncResponseConsumer;
51 import org.apache.http.protocol.HttpCoreContext;
52 import org.apache.http.protocol.HttpProcessor;
53
54 /**
55 * Default implementation of {@link org.apache.http.nio.protocol.HttpAsyncClientExchangeHandler}.
56 * <p>
57 * Instances of this class are expected to be accessed by one thread at a time only.
58 * The {@link #cancel()} method can be called concurrently by multiple threads.
59 */
60 class MinimalClientExchangeHandlerImpl<T> extends AbstractClientExchangeHandler {
61
62 private final HttpAsyncRequestProducer requestProducer;
63 private final HttpAsyncResponseConsumer<T> responseConsumer;
64 private final HttpClientContext localContext;
65 private final BasicFuture<T> resultFuture;
66 private final HttpProcessor httpProcessor;
67
68 public MinimalClientExchangeHandlerImpl(
69 final Log log,
70 final HttpAsyncRequestProducer requestProducer,
71 final HttpAsyncResponseConsumer<T> responseConsumer,
72 final HttpClientContext localContext,
73 final BasicFuture<T> resultFuture,
74 final NHttpClientConnectionManager connmgr,
75 final HttpProcessor httpProcessor,
76 final ConnectionReuseStrategy connReuseStrategy,
77 final ConnectionKeepAliveStrategy keepaliveStrategy) {
78 super(log, localContext, resultFuture, connmgr, connReuseStrategy, keepaliveStrategy);
79 this.requestProducer = requestProducer;
80 this.responseConsumer = responseConsumer;
81 this.localContext = localContext;
82 this.resultFuture = resultFuture;
83 this.httpProcessor = httpProcessor;
84 }
85
86 @Override
87 void releaseResources() {
88 try {
89 this.requestProducer.close();
90 } catch (final IOException ex) {
91 this.log.debug("I/O error closing request producer", ex);
92 }
93 try {
94 this.responseConsumer.close();
95 } catch (final IOException ex) {
96 this.log.debug("I/O error closing response consumer", ex);
97 }
98 }
99
100 @Override
101 void executionFailed(final Exception ex) {
102 this.requestProducer.failed(ex);
103 this.responseConsumer.failed(ex);
104 }
105
106 @Override
107 boolean executionCancelled() {
108 final boolean cancelled = this.responseConsumer.cancel();
109
110 final T result = this.responseConsumer.getResult();
111 final Exception ex = this.responseConsumer.getException();
112 if (ex != null) {
113 this.resultFuture.failed(ex);
114 } else if (result != null) {
115 this.resultFuture.completed(result);
116 } else {
117 this.resultFuture.cancel();
118 }
119 return cancelled;
120 }
121
122 public void start() throws HttpException, IOException {
123 final HttpHost target = this.requestProducer.getTarget();
124 final HttpRequest original = this.requestProducer.generateRequest();
125
126 if (original instanceof HttpExecutionAware) {
127 ((HttpExecutionAware) original).setCancellable(this);
128 }
129 if (this.log.isDebugEnabled()) {
130 this.log.debug("[exchange: " + getId() + "] start execution");
131 }
132
133 if (original instanceof Configurable) {
134 final RequestConfig config = ((Configurable) original).getConfig();
135 if (config != null) {
136 this.localContext.setRequestConfig(config);
137 }
138 }
139
140 final HttpRequestWrapper request = HttpRequestWrapper.wrap(original);
141 final HttpRoute route = new HttpRoute(target);
142 setCurrentRequest(request);
143 setRoute(route);
144
145 this.localContext.setAttribute(HttpClientContext.HTTP_REQUEST, request);
146 this.localContext.setAttribute(HttpClientContext.HTTP_TARGET_HOST, target);
147 this.localContext.setAttribute(HttpClientContext.HTTP_ROUTE, route);
148
149 this.httpProcessor.process(request, this.localContext);
150
151 requestConnection();
152 }
153
154 @Override
155 public HttpRequest generateRequest() throws IOException, HttpException {
156 verifytRoute();
157 if (!isRouteEstablished()) {
158 onRouteToTarget();
159 onRouteComplete();
160 }
161
162 final NHttpClientConnection localConn = getConnection();
163 this.localContext.setAttribute(HttpCoreContext.HTTP_CONNECTION, localConn);
164 final RequestConfig config = this.localContext.getRequestConfig();
165 if (config.getSocketTimeout() > 0) {
166 localConn.setSocketTimeout(config.getSocketTimeout());
167 }
168 return getCurrentRequest();
169 }
170
171 @Override
172 public void produceContent(
173 final ContentEncoder encoder, final IOControl ioctrl) throws IOException {
174 if (this.log.isDebugEnabled()) {
175 this.log.debug("[exchange: " + getId() + "] produce content");
176 }
177 this.requestProducer.produceContent(encoder, ioctrl);
178 if (encoder.isCompleted()) {
179 this.requestProducer.resetRequest();
180 }
181 }
182
183 @Override
184 public void requestCompleted() {
185 if (this.log.isDebugEnabled()) {
186 this.log.debug("[exchange: " + getId() + "] Request completed");
187 }
188 this.requestProducer.requestCompleted(this.localContext);
189 }
190
191 @Override
192 public void responseReceived(
193 final HttpResponse response) throws IOException, HttpException {
194 if (this.log.isDebugEnabled()) {
195 this.log.debug("[exchange: " + getId() + "] Response received " + response.getStatusLine());
196 }
197 this.localContext.setAttribute(HttpClientContext.HTTP_RESPONSE, response);
198 this.httpProcessor.process(response, this.localContext);
199
200 setCurrentResponse(response);
201
202 this.responseConsumer.responseReceived(response);
203 }
204
205 @Override
206 public void consumeContent(
207 final ContentDecoder decoder, final IOControl ioctrl) throws IOException {
208 if (this.log.isDebugEnabled()) {
209 this.log.debug("[exchange: " + getId() + "] Consume content");
210 }
211 this.responseConsumer.consumeContent(decoder, ioctrl);
212 if (!decoder.isCompleted() && this.responseConsumer.isDone()) {
213 markConnectionNonReusable();
214 try {
215 markCompleted();
216 releaseConnection();
217 this.resultFuture.cancel();
218 } finally {
219 close();
220 }
221 }
222 }
223
224 @Override
225 public void responseCompleted() throws IOException, HttpException {
226 manageConnectionPersistence();
227 this.responseConsumer.responseCompleted(this.localContext);
228 if (this.log.isDebugEnabled()) {
229 this.log.debug("[exchange: " + getId() + "] Response processed");
230 }
231 try {
232 markCompleted();
233 releaseConnection();
234 final T result = this.responseConsumer.getResult();
235 final Exception ex = this.responseConsumer.getException();
236 if (ex == null) {
237 this.resultFuture.completed(result);
238 } else {
239 this.resultFuture.failed(ex);
240 }
241 } finally {
242 close();
243 }
244 }
245
246 @Override
247 public void inputTerminated() {
248 close();
249 }
250
251 public void abortConnection() {
252 discardConnection();
253 }
254
255 }
0 /*
1 * ====================================================================
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 * ====================================================================
19 *
20 * This software consists of voluntary contributions made by many
21 * individuals on behalf of the Apache Software Foundation. For more
22 * information on the Apache Software Foundation, please see
23 * <http://www.apache.org/>.
24 *
25 */
26 package org.apache.http.impl.nio.client;
27
28 import java.util.List;
29 import java.util.concurrent.Executors;
30 import java.util.concurrent.Future;
31 import java.util.concurrent.ThreadFactory;
32
33 import org.apache.commons.logging.Log;
34 import org.apache.commons.logging.LogFactory;
35 import org.apache.http.ConnectionReuseStrategy;
36 import org.apache.http.HttpHost;
37 import org.apache.http.client.protocol.HttpClientContext;
38 import org.apache.http.concurrent.BasicFuture;
39 import org.apache.http.concurrent.FutureCallback;
40 import org.apache.http.conn.ConnectionKeepAliveStrategy;
41 import org.apache.http.impl.DefaultConnectionReuseStrategy;
42 import org.apache.http.impl.client.DefaultConnectionKeepAliveStrategy;
43 import org.apache.http.nio.NHttpClientEventHandler;
44 import org.apache.http.nio.conn.NHttpClientConnectionManager;
45 import org.apache.http.nio.protocol.HttpAsyncRequestExecutor;
46 import org.apache.http.nio.protocol.HttpAsyncRequestProducer;
47 import org.apache.http.nio.protocol.HttpAsyncResponseConsumer;
48 import org.apache.http.protocol.BasicHttpContext;
49 import org.apache.http.protocol.HttpContext;
50 import org.apache.http.protocol.HttpProcessor;
51
52 class MinimalHttpAsyncClient extends CloseableHttpAsyncClientBase {
53
54 private final Log log = LogFactory.getLog(getClass());
55
56 private final NHttpClientConnectionManager connmgr;
57 private final HttpProcessor httpProcessor;
58 private final ConnectionReuseStrategy connReuseStrategy;
59 private final ConnectionKeepAliveStrategy keepaliveStrategy;
60
61 public MinimalHttpAsyncClient(
62 final NHttpClientConnectionManager connmgr,
63 final ThreadFactory threadFactory,
64 final NHttpClientEventHandler eventHandler,
65 final HttpProcessor httpProcessor,
66 final ConnectionReuseStrategy connReuseStrategy,
67 final ConnectionKeepAliveStrategy keepaliveStrategy) {
68 super(connmgr, threadFactory, eventHandler);
69 this.connmgr = connmgr;
70 this.httpProcessor = httpProcessor;
71 this.connReuseStrategy = connReuseStrategy;
72 this.keepaliveStrategy = keepaliveStrategy;
73 }
74
75 public MinimalHttpAsyncClient(
76 final NHttpClientConnectionManager connmgr,
77 final HttpProcessor httpProcessor) {
78 this(connmgr,
79 Executors.defaultThreadFactory(),
80 new HttpAsyncRequestExecutor(),
81 httpProcessor,
82 DefaultConnectionReuseStrategy.INSTANCE,
83 DefaultConnectionKeepAliveStrategy.INSTANCE);
84 }
85
86 @Override
87 public <T> Future<T> execute(
88 final HttpAsyncRequestProducer requestProducer,
89 final HttpAsyncResponseConsumer<T> responseConsumer,
90 final HttpContext context,
91 final FutureCallback<T> callback) {
92 ensureRunning();
93 final BasicFuture<T> future = new BasicFuture<T>(callback);
94 final HttpClientContext localcontext = HttpClientContext.adapt(
95 context != null ? context : new BasicHttpContext());
96
97 @SuppressWarnings("resource")
98 final MinimalClientExchangeHandlerImpl<T> handler = new MinimalClientExchangeHandlerImpl<T>(
99 this.log,
100 requestProducer,
101 responseConsumer,
102 localcontext,
103 future,
104 this.connmgr,
105 this.httpProcessor,
106 this.connReuseStrategy,
107 this.keepaliveStrategy);
108 try {
109 handler.start();
110 } catch (final Exception ex) {
111 handler.failed(ex);
112 }
113 return future;
114 }
115
116 @Override
117 public <T> Future<List<T>> execute(
118 final HttpHost target,
119 final List<? extends HttpAsyncRequestProducer> requestProducers,
120 final List<? extends HttpAsyncResponseConsumer<T>> responseConsumers,
121 final HttpContext context,
122 final FutureCallback<List<T>> callback) {
123 ensureRunning();
124 final BasicFuture<List<T>> future = new BasicFuture<List<T>>(callback);
125 final HttpClientContext localcontext = HttpClientContext.adapt(
126 context != null ? context : new BasicHttpContext());
127 @SuppressWarnings("resource")
128 final PipeliningClientExchangeHandlerImpl<T> handler = new PipeliningClientExchangeHandlerImpl<T>(
129 this.log,
130 target,
131 requestProducers,
132 responseConsumers,
133 localcontext,
134 future,
135 this.connmgr,
136 this.httpProcessor,
137 this.connReuseStrategy,
138 this.keepaliveStrategy);
139 try {
140 handler.start();
141 } catch (final Exception ex) {
142 handler.failed(ex);
143 }
144 return future;
145 }
146
147 }
0 /*
1 * ====================================================================
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 * ====================================================================
19 *
20 * This software consists of voluntary contributions made by many
21 * individuals on behalf of the Apache Software Foundation. For more
22 * information on the Apache Software Foundation, please see
23 * <http://www.apache.org/>.
24 *
25 */
26
27 package org.apache.http.impl.nio.client;
28
29 import java.util.concurrent.Executors;
30 import java.util.concurrent.ThreadFactory;
31
32 import org.apache.http.ConnectionReuseStrategy;
33 import org.apache.http.annotation.NotThreadSafe;
34 import org.apache.http.client.protocol.RequestAddCookies;
35 import org.apache.http.client.protocol.RequestClientConnControl;
36 import org.apache.http.client.protocol.ResponseProcessCookies;
37 import org.apache.http.conn.ConnectionKeepAliveStrategy;
38 import org.apache.http.impl.DefaultConnectionReuseStrategy;
39 import org.apache.http.impl.client.DefaultConnectionKeepAliveStrategy;
40 import org.apache.http.impl.nio.conn.PoolingNHttpClientConnectionManager;
41 import org.apache.http.impl.nio.reactor.IOReactorConfig;
42 import org.apache.http.nio.NHttpClientEventHandler;
43 import org.apache.http.nio.conn.NHttpClientConnectionManager;
44 import org.apache.http.nio.protocol.HttpAsyncRequestExecutor;
45 import org.apache.http.protocol.HttpProcessor;
46 import org.apache.http.protocol.HttpProcessorBuilder;
47 import org.apache.http.protocol.RequestContent;
48 import org.apache.http.protocol.RequestTargetHost;
49 import org.apache.http.protocol.RequestUserAgent;
50 import org.apache.http.util.VersionInfo;
51
52 /**
53 * Builder for {@link org.apache.http.impl.nio.client.MinimalHttpAsyncClient} instances.
54 *
55 * @since 4.1
56 */
57 @NotThreadSafe
58 class MinimalHttpAsyncClientBuilder {
59
60 private NHttpClientConnectionManager connManager;
61 private boolean connManagerShared;
62 private ConnectionReuseStrategy reuseStrategy;
63 private ConnectionKeepAliveStrategy keepAliveStrategy;
64 private String userAgent;
65 private ThreadFactory threadFactory;
66 private boolean cookieManagementDisabled;
67
68 public static MinimalHttpAsyncClientBuilder create() {
69 return new MinimalHttpAsyncClientBuilder();
70 }
71
72 protected MinimalHttpAsyncClientBuilder() {
73 super();
74 }
75
76 public final MinimalHttpAsyncClientBuilder setConnectionManager(
77 final NHttpClientConnectionManager connManager) {
78 this.connManager = connManager;
79 return this;
80 }
81
82 public final MinimalHttpAsyncClientBuilder setConnectionManagerShared(
83 final boolean shared) {
84 this.connManagerShared = shared;
85 return this;
86 }
87
88 public final MinimalHttpAsyncClientBuilder setConnectionReuseStrategy(
89 final ConnectionReuseStrategy reuseStrategy) {
90 this.reuseStrategy = reuseStrategy;
91 return this;
92 }
93
94 public final MinimalHttpAsyncClientBuilder setKeepAliveStrategy(
95 final ConnectionKeepAliveStrategy keepAliveStrategy) {
96 this.keepAliveStrategy = keepAliveStrategy;
97 return this;
98 }
99
100 public final MinimalHttpAsyncClientBuilder setUserAgent(final String userAgent) {
101 this.userAgent = userAgent;
102 return this;
103 }
104
105 public final MinimalHttpAsyncClientBuilder setThreadFactory(final ThreadFactory threadFactory) {
106 this.threadFactory = threadFactory;
107 return this;
108 }
109
110 public final MinimalHttpAsyncClientBuilder disableCookieManagement() {
111 cookieManagementDisabled = true;
112 return this;
113 }
114
115 public MinimalHttpAsyncClient build() {
116
117 NHttpClientConnectionManager connManager = this.connManager;
118 if (connManager == null) {
119 connManager = new PoolingNHttpClientConnectionManager(
120 IOReactorUtils.create(IOReactorConfig.DEFAULT));
121 }
122 ConnectionReuseStrategy reuseStrategy = this.reuseStrategy;
123 if (reuseStrategy == null) {
124 reuseStrategy = DefaultConnectionReuseStrategy.INSTANCE;
125 }
126 ConnectionKeepAliveStrategy keepAliveStrategy = this.keepAliveStrategy;
127 if (keepAliveStrategy == null) {
128 keepAliveStrategy = DefaultConnectionKeepAliveStrategy.INSTANCE;
129 }
130 String userAgent = this.userAgent;
131 if (userAgent == null) {
132 userAgent = VersionInfo.getUserAgent(
133 "Apache-HttpAsyncClient", "org.apache.http.nio.client", getClass());
134 }
135 final HttpProcessorBuilder b = HttpProcessorBuilder.create();
136 b.addAll(
137 new RequestContent(),
138 new RequestTargetHost(),
139 new RequestClientConnControl(),
140 new RequestUserAgent(userAgent));
141 if (!cookieManagementDisabled) {
142 b.add(new RequestAddCookies());
143 b.add(new ResponseProcessCookies());
144 }
145 final HttpProcessor httpprocessor = b.build();
146
147 ThreadFactory threadFactory = null;
148 NHttpClientEventHandler eventHandler = null;
149 if (!this.connManagerShared) {
150 threadFactory = this.threadFactory;
151 if (threadFactory == null) {
152 threadFactory = Executors.defaultThreadFactory();
153 }
154 eventHandler = new HttpAsyncRequestExecutor();
155 }
156 return new MinimalHttpAsyncClient(
157 connManager,
158 threadFactory,
159 eventHandler,
160 httpprocessor,
161 reuseStrategy,
162 keepAliveStrategy);
163 }
164
165 }
0 /*
1 * ====================================================================
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 * ====================================================================
19 *
20 * This software consists of voluntary contributions made by many
21 * individuals on behalf of the Apache Software Foundation. For more
22 * information on the Apache Software Foundation, please see
23 * <http://www.apache.org/>.
24 *
25 */
26 package org.apache.http.impl.nio.client;
27
28 import java.io.IOException;
29 import java.util.ArrayList;
30 import java.util.List;
31 import java.util.Queue;
32 import java.util.concurrent.ConcurrentLinkedQueue;
33 import java.util.concurrent.atomic.AtomicReference;
34
35 import org.apache.commons.logging.Log;
36 import org.apache.http.ConnectionClosedException;
37 import org.apache.http.ConnectionReuseStrategy;
38 import org.apache.http.HttpException;
39 import org.apache.http.HttpHost;
40 import org.apache.http.HttpRequest;
41 import org.apache.http.HttpResponse;
42 import org.apache.http.client.config.RequestConfig;
43 import org.apache.http.client.methods.HttpRequestWrapper;
44 import org.apache.http.client.protocol.HttpClientContext;
45 import org.apache.http.concurrent.BasicFuture;
46 import org.apache.http.conn.ConnectionKeepAliveStrategy;
47 import org.apache.http.conn.routing.HttpRoute;
48 import org.apache.http.nio.ContentDecoder;
49 import org.apache.http.nio.ContentEncoder;
50 import org.apache.http.nio.IOControl;
51 import org.apache.http.nio.NHttpClientConnection;
52 import org.apache.http.nio.conn.NHttpClientConnectionManager;
53 import org.apache.http.nio.protocol.HttpAsyncRequestProducer;
54 import org.apache.http.nio.protocol.HttpAsyncResponseConsumer;
55 import org.apache.http.nio.protocol.Pipelined;
56 import org.apache.http.protocol.HttpCoreContext;
57 import org.apache.http.protocol.HttpProcessor;
58 import org.apache.http.util.Args;
59 import org.apache.http.util.Asserts;
60
61 /**
62 * {@link org.apache.http.nio.protocol.HttpAsyncClientExchangeHandler} implementation
63 * that supports HTTP message pipelining.
64 * <p>
65 * Instances of this class are expected to be accessed by one thread at a time only.
66 * The {@link #cancel()} method can be called concurrently by multiple threads.
67 */
68 @Pipelined
69 class PipeliningClientExchangeHandlerImpl<T> extends AbstractClientExchangeHandler {
70
71 private final HttpHost target;
72 private final Queue<HttpAsyncRequestProducer> requestProducerQueue;
73 private final Queue<HttpAsyncResponseConsumer<T>> responseConsumerQueue;
74 private final Queue<HttpRequest> requestQueue;
75 private final Queue<T> resultQueue;
76 private final HttpClientContext localContext;
77 private final BasicFuture<List<T>> resultFuture;
78 private final HttpProcessor httpProcessor;
79 private final AtomicReference<HttpAsyncRequestProducer> requestProducerRef;
80 private final AtomicReference<HttpAsyncResponseConsumer<T>> responseConsumerRef;
81
82 public PipeliningClientExchangeHandlerImpl(
83 final Log log,
84 final HttpHost target,
85 final List<? extends HttpAsyncRequestProducer> requestProducers,
86 final List<? extends HttpAsyncResponseConsumer<T>> responseConsumers,
87 final HttpClientContext localContext,
88 final BasicFuture<List<T>> resultFuture,
89 final NHttpClientConnectionManager connmgr,
90 final HttpProcessor httpProcessor,
91 final ConnectionReuseStrategy connReuseStrategy,
92 final ConnectionKeepAliveStrategy keepaliveStrategy) {
93 super(log, localContext, resultFuture, connmgr, connReuseStrategy, keepaliveStrategy);
94 Args.notNull(target, "HTTP target");
95 Args.notEmpty(requestProducers, "Request producer list");
96 Args.notEmpty(responseConsumers, "Response consumer list");
97 Args.check(requestProducers.size() == responseConsumers.size(),
98 "Number of request producers does not match that of response consumers");
99 this.target = target;
100 this.requestProducerQueue = new ConcurrentLinkedQueue<HttpAsyncRequestProducer>(requestProducers);
101 this.responseConsumerQueue = new ConcurrentLinkedQueue<HttpAsyncResponseConsumer<T>>(responseConsumers);
102 this.requestQueue = new ConcurrentLinkedQueue<HttpRequest>();
103 this.resultQueue = new ConcurrentLinkedQueue<T>();
104 this.localContext = localContext;
105 this.resultFuture = resultFuture;
106 this.httpProcessor = httpProcessor;
107 this.requestProducerRef = new AtomicReference<HttpAsyncRequestProducer>(null);
108 this.responseConsumerRef = new AtomicReference<HttpAsyncResponseConsumer<T>>(null);
109 }
110
111 private void closeProducer(final HttpAsyncRequestProducer requestProducer) {
112 if (requestProducer != null) {
113 try {
114 requestProducer.close();
115 } catch (IOException ex) {
116 this.log.debug("I/O error closing request producer", ex);
117 }
118 }
119 }
120
121 private void closeConsumer(final HttpAsyncResponseConsumer<?> responseConsumer) {
122 if (responseConsumer != null) {
123 try {
124 responseConsumer.close();
125 } catch (IOException ex) {
126 this.log.debug("I/O error closing response consumer", ex);
127 }
128 }
129 }
130
131 @Override
132 void releaseResources() {
133 closeProducer(this.requestProducerRef.getAndSet(null));
134 closeConsumer(this.responseConsumerRef.getAndSet(null));
135 while (!this.requestProducerQueue.isEmpty()) {
136 closeProducer(this.requestProducerQueue.remove());
137 }
138 while (!this.responseConsumerQueue.isEmpty()) {
139 closeConsumer(this.responseConsumerQueue.remove());
140 }
141 this.requestQueue.clear();
142 this.resultQueue.clear();
143 }
144
145 @Override
146 void executionFailed(final Exception ex) {
147 final HttpAsyncRequestProducer requestProducer = this.requestProducerRef.get();
148 if (requestProducer != null) {
149 requestProducer.failed(ex);
150 }
151 final HttpAsyncResponseConsumer<T> responseConsumer = this.responseConsumerRef.get();
152 if (responseConsumer != null) {
153 responseConsumer.failed(ex);
154 }
155 for (final HttpAsyncResponseConsumer<T> cancellable: this.responseConsumerQueue) {
156 cancellable.cancel();
157 }
158 }
159
160 @Override
161 boolean executionCancelled() {
162 final HttpAsyncResponseConsumer<T> responseConsumer = this.responseConsumerRef.get();
163 final boolean cancelled = responseConsumer != null && responseConsumer.cancel();
164 this.resultFuture.cancel();
165 return cancelled;
166 }
167
168 public void start() throws HttpException, IOException {
169 if (this.log.isDebugEnabled()) {
170 this.log.debug("[exchange: " + getId() + "] start execution");
171 }
172
173 final HttpRoute route = new HttpRoute(this.target);
174 setRoute(route);
175
176 this.localContext.setAttribute(HttpClientContext.HTTP_TARGET_HOST, this.target);
177 this.localContext.setAttribute(HttpClientContext.HTTP_ROUTE, route);
178
179 requestConnection();
180 }
181
182 @Override
183 public HttpRequest generateRequest() throws IOException, HttpException {
184 verifytRoute();
185 if (!isRouteEstablished()) {
186 onRouteToTarget();
187 onRouteComplete();
188 }
189 final NHttpClientConnection localConn = getConnection();
190 this.localContext.setAttribute(HttpCoreContext.HTTP_CONNECTION, localConn);
191
192 Asserts.check(this.requestProducerRef.get() == null, "Inconsistent state: currentRequest producer is not null");
193 final HttpAsyncRequestProducer requestProducer = this.requestProducerQueue.poll();
194 if (requestProducer == null) {
195 return null;
196 }
197 this.requestProducerRef.set(requestProducer);
198
199 final HttpRequest original = requestProducer.generateRequest();
200 final HttpRequestWrapper currentRequest = HttpRequestWrapper.wrap(original);
201 final RequestConfig config = this.localContext.getRequestConfig();
202 if (config.getSocketTimeout() > 0) {
203 localConn.setSocketTimeout(config.getSocketTimeout());
204 }
205
206 this.httpProcessor.process(currentRequest, this.localContext);
207
208 this.requestQueue.add(currentRequest);
209 setCurrentRequest(currentRequest);
210
211 return currentRequest;
212 }
213
214 @Override
215 public void produceContent(
216 final ContentEncoder encoder, final IOControl ioctrl) throws IOException {
217 if (this.log.isDebugEnabled()) {
218 this.log.debug("[exchange: " + getId() + "] produce content");
219 }
220 final HttpAsyncRequestProducer requestProducer = this.requestProducerRef.get();
221 Asserts.check(requestProducer != null, "Inconsistent state: request producer is null");
222 requestProducer.produceContent(encoder, ioctrl);
223 if (encoder.isCompleted()) {
224 requestProducer.resetRequest();
225 }
226 }
227
228 @Override
229 public void requestCompleted() {
230 if (this.log.isDebugEnabled()) {
231 this.log.debug("[exchange: " + getId() + "] Request completed");
232 }
233 final HttpAsyncRequestProducer requestProducer = this.requestProducerRef.getAndSet(null);
234 Asserts.check(requestProducer != null, "Inconsistent state: request producer is null");
235 requestProducer.requestCompleted(this.localContext);
236 try {
237 requestProducer.close();
238 } catch (IOException ioex) {
239 this.log.debug(ioex.getMessage(), ioex);
240 }
241 }
242
243 @Override
244 public void responseReceived(
245 final HttpResponse response) throws IOException, HttpException {
246 if (this.log.isDebugEnabled()) {
247 this.log.debug("[exchange: " + getId() + "] Response received " + response.getStatusLine());
248 }
249
250 Asserts.check(this.responseConsumerRef.get() == null, "Inconsistent state: response consumer is not null");
251
252 final HttpAsyncResponseConsumer<T> responseConsumer = this.responseConsumerQueue.poll();
253 Asserts.check(responseConsumer != null, "Inconsistent state: response consumer queue is empty");
254 this.responseConsumerRef.set(responseConsumer);
255
256 final HttpRequest request = this.requestQueue.poll();
257 Asserts.check(request != null, "Inconsistent state: request queue is empty");
258
259 this.localContext.setAttribute(HttpCoreContext.HTTP_REQUEST, request);
260 this.localContext.setAttribute(HttpCoreContext.HTTP_RESPONSE, response);
261 this.httpProcessor.process(response, this.localContext);
262
263 responseConsumer.responseReceived(response);
264
265 setCurrentResponse(response);
266 }
267
268 @Override
269 public void consumeContent(
270 final ContentDecoder decoder, final IOControl ioctrl) throws IOException {
271 if (this.log.isDebugEnabled()) {
272 this.log.debug("[exchange: " + getId() + "] Consume content");
273 }
274 final HttpAsyncResponseConsumer<T> responseConsumer = this.responseConsumerRef.get();
275 Asserts.check(responseConsumer != null, "Inconsistent state: response consumer is null");
276 responseConsumer.consumeContent(decoder, ioctrl);
277 }
278
279 @Override
280 public void responseCompleted() throws IOException, HttpException {
281 if (this.log.isDebugEnabled()) {
282 this.log.debug("[exchange: " + getId() + "] Response processed");
283 }
284
285 final boolean keepAlive = manageConnectionPersistence();
286
287 final HttpAsyncResponseConsumer<T> responseConsumer = this.responseConsumerRef.getAndSet(null);
288 Asserts.check(responseConsumer != null, "Inconsistent state: response consumer is null");
289 try {
290 responseConsumer.responseCompleted(this.localContext);
291 final T result = responseConsumer.getResult();
292 final Exception ex = responseConsumer.getException();
293 try {
294 responseConsumer.close();
295 } catch (IOException ioex) {
296 this.log.debug(ioex.getMessage(), ioex);
297 }
298 if (result != null) {
299 this.resultQueue.add(result);
300 } else {
301 failed(ex);
302 }
303 if (!this.resultFuture.isDone() && this.responseConsumerQueue.isEmpty()) {
304 this.resultFuture.completed(new ArrayList<T>(this.resultQueue));
305 this.resultQueue.clear();
306 }
307
308 if (this.resultFuture.isDone()) {
309 close();
310 } else {
311 if (!keepAlive) {
312 failed(new ConnectionClosedException("Connection closed"));
313 } else {
314 final NHttpClientConnection localConn = getConnection();
315 if (localConn != null) {
316 localConn.requestOutput();
317 } else {
318 requestConnection();
319 }
320 }
321 }
322 } catch (final RuntimeException ex) {
323 failed(ex);
324 throw ex;
325 }
326 }
327
328 @Override
329 public void inputTerminated() {
330 failed(new ConnectionClosedException("Connection closed"));
331 }
332
333 public void abortConnection() {
334 discardConnection();
335 }
336
337 }
0 /*
1 * ====================================================================
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 * ====================================================================
19 *
20 * This software consists of voluntary contributions made by many
21 * individuals on behalf of the Apache Software Foundation. For more
22 * information on the Apache Software Foundation, please see
23 * <http://www.apache.org/>.
24 *
25 */
26
27 /**
28 * Default asynchronous HTTP client implementation.
29 * <p>
30 * The usual execution flow can be demonstrated by the code snippet below:
31 * <pre>
32 * CloseableHttpAsyncClient httpclient = HttpAsyncClients.createDefault();
33 * try {
34 * httpclient.start();
35 * HttpGet request = new HttpGet("http://www.apache.org/");
36 * Future<HttpResponse> future = httpclient.execute(request, null);
37 * HttpResponse response = future.get();
38 * System.out.println(response.getStatusLine());
39 * // Do something useful with the response body
40 * } finally {
41 * httpclient.close();
42 * }
43 * </pre>
44 */
45 package org.apache.http.impl.nio.client;
0 /*
1 * ====================================================================
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 * ====================================================================
19 *
20 * This software consists of voluntary contributions made by many
21 * individuals on behalf of the Apache Software Foundation. For more
22 * information on the Apache Software Foundation, please see
23 * <http://www.apache.org/>.
24 *
25 */
26 package org.apache.http.impl.nio.conn;
27
28 import java.util.concurrent.TimeUnit;
29
30 import org.apache.commons.logging.Log;
31 import org.apache.commons.logging.LogFactory;
32 import org.apache.http.annotation.ThreadSafe;
33 import org.apache.http.conn.routing.HttpRoute;
34 import org.apache.http.nio.NHttpClientConnection;
35 import org.apache.http.nio.conn.ManagedNHttpClientConnection;
36 import org.apache.http.nio.pool.AbstractNIOConnPool;
37 import org.apache.http.nio.pool.NIOConnFactory;
38 import org.apache.http.nio.pool.SocketAddressResolver;
39 import org.apache.http.nio.reactor.ConnectingIOReactor;
40
41 @ThreadSafe
42 class CPool extends AbstractNIOConnPool<HttpRoute, ManagedNHttpClientConnection, CPoolEntry> {
43
44 private final Log log = LogFactory.getLog(CPool.class);
45
46 private final long timeToLive;
47 private final TimeUnit tunit;
48
49 public CPool(
50 final ConnectingIOReactor ioreactor,
51 final NIOConnFactory<HttpRoute, ManagedNHttpClientConnection> connFactory,
52 final SocketAddressResolver<HttpRoute> addressResolver,
53 final int defaultMaxPerRoute, final int maxTotal,
54 final long timeToLive, final TimeUnit tunit) {
55 super(ioreactor, connFactory, addressResolver, defaultMaxPerRoute, maxTotal);
56 this.timeToLive = timeToLive;
57 this.tunit = tunit;
58 }
59
60 @Override
61 protected CPoolEntry createEntry(final HttpRoute route, final ManagedNHttpClientConnection conn) {
62 final CPoolEntry entry = new CPoolEntry(this.log, conn.getId(), route, conn, this.timeToLive, this.tunit);
63 entry.setSocketTimeout(conn.getSocketTimeout());
64 return entry;
65 }
66
67 @Override
68 protected void onLease(final CPoolEntry entry) {
69 final NHttpClientConnection conn = entry.getConnection();
70 conn.setSocketTimeout(entry.getSocketTimeout());
71 }
72
73 @Override
74 protected void onRelease(final CPoolEntry entry) {
75 final NHttpClientConnection conn = entry.getConnection();
76 entry.setSocketTimeout(conn.getSocketTimeout());
77 conn.setSocketTimeout(0);
78 }
79
80 }
0 /*
1 * ====================================================================
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 * ====================================================================
19 *
20 * This software consists of voluntary contributions made by many
21 * individuals on behalf of the Apache Software Foundation. For more
22 * information on the Apache Software Foundation, please see
23 * <http://www.apache.org/>.
24 *
25 */
26 package org.apache.http.impl.nio.conn;
27
28 import java.io.IOException;
29 import java.util.Date;
30 import java.util.concurrent.TimeUnit;
31
32 import org.apache.commons.logging.Log;
33 import org.apache.http.annotation.ThreadSafe;
34 import org.apache.http.conn.routing.HttpRoute;
35 import org.apache.http.nio.conn.ManagedNHttpClientConnection;
36 import org.apache.http.pool.PoolEntry;
37
38 @ThreadSafe
39 class CPoolEntry extends PoolEntry<HttpRoute, ManagedNHttpClientConnection> {
40
41 private final Log log;
42 private volatile int socketTimeout;
43 private volatile boolean routeComplete;
44
45 public CPoolEntry(
46 final Log log,
47 final String id,
48 final HttpRoute route,
49 final ManagedNHttpClientConnection conn,
50 final long timeToLive, final TimeUnit tunit) {
51 super(id, route, conn, timeToLive, tunit);
52 this.log = log;
53 }
54
55 public boolean isRouteComplete() {
56 return this.routeComplete;
57 }
58
59 public void markRouteComplete() {
60 this.routeComplete = true;
61 }
62
63 public int getSocketTimeout() {
64 return this.socketTimeout;
65 }
66
67 public void setSocketTimeout(final int socketTimeout) {
68 this.socketTimeout = socketTimeout;
69 }
70
71 public void closeConnection() throws IOException {
72 final ManagedNHttpClientConnection conn = getConnection();
73 conn.close();
74 }
75
76 public void shutdownConnection() throws IOException {
77 final ManagedNHttpClientConnection conn = getConnection();
78 conn.shutdown();
79 }
80
81 @Override
82 public boolean isExpired(final long now) {
83 final boolean expired = super.isExpired(now);
84 if (expired && this.log.isDebugEnabled()) {
85 this.log.debug("Connection " + this + " expired @ " + new Date(getExpiry()));
86 }
87 return expired;
88 }
89
90 @Override
91 public boolean isClosed() {
92 final ManagedNHttpClientConnection conn = getConnection();
93 return !conn.isOpen();
94 }
95
96 @Override
97 public void close() {
98 try {
99 closeConnection();
100 } catch (final IOException ex) {
101 this.log.debug("I/O error closing connection", ex);
102 }
103 }
104
105 }
0 /*
1 * ====================================================================
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 * ====================================================================
19 *
20 * This software consists of voluntary contributions made by many
21 * individuals on behalf of the Apache Software Foundation. For more
22 * information on the Apache Software Foundation, please see
23 * <http://www.apache.org/>.
24 *
25 */
26 package org.apache.http.impl.nio.conn;
27
28 import java.io.IOException;
29 import java.net.InetAddress;
30
31 import javax.net.ssl.SSLSession;
32
33 import org.apache.http.HttpConnectionMetrics;
34 import org.apache.http.HttpException;
35 import org.apache.http.HttpRequest;
36 import org.apache.http.HttpResponse;
37 import org.apache.http.annotation.NotThreadSafe;
38 import org.apache.http.impl.conn.ConnectionShutdownException;
39 import org.apache.http.nio.NHttpClientConnection;
40 import org.apache.http.nio.conn.ManagedNHttpClientConnection;
41 import org.apache.http.nio.reactor.IOSession;
42 import org.apache.http.protocol.HttpContext;
43
44 @NotThreadSafe
45 class CPoolProxy implements ManagedNHttpClientConnection {
46
47 private volatile CPoolEntry poolEntry;
48
49 CPoolProxy(final CPoolEntry entry) {
50 super();
51 this.poolEntry = entry;
52 }
53
54 CPoolEntry getPoolEntry() {
55 return this.poolEntry;
56 }
57
58 CPoolEntry detach() {
59 final CPoolEntry local = this.poolEntry;
60 this.poolEntry = null;
61 return local;
62 }
63
64 ManagedNHttpClientConnection getConnection() {
65 final CPoolEntry local = this.poolEntry;
66 if (local == null) {
67 return null;
68 }
69 return local.getConnection();
70 }
71
72 ManagedNHttpClientConnection getValidConnection() {
73 final ManagedNHttpClientConnection conn = getConnection();
74 if (conn == null) {
75 throw new ConnectionShutdownException();
76 }
77 return conn;
78 }
79
80 @Override
81 public void close() throws IOException {
82 final CPoolEntry local = this.poolEntry;
83 if (local != null) {
84 local.closeConnection();
85 }
86 }
87
88 @Override
89 public void shutdown() throws IOException {
90 final CPoolEntry local = this.poolEntry;
91 if (local != null) {
92 local.shutdownConnection();
93 }
94 }
95
96 @Override
97 public HttpConnectionMetrics getMetrics() {
98 return getValidConnection().getMetrics();
99 }
100
101 @Override
102 public void requestInput() {
103 final NHttpClientConnection conn = getConnection();
104 if (conn != null) {
105 conn.requestInput();
106 }
107 }
108
109 @Override
110 public void suspendInput() {
111 final NHttpClientConnection conn = getConnection();
112 if (conn != null) {
113 conn.suspendInput();
114 }
115 }
116
117 @Override
118 public void requestOutput() {
119 final NHttpClientConnection conn = getConnection();
120 if (conn != null) {
121 conn.requestOutput();
122 }
123 }
124
125 @Override
126 public void suspendOutput() {
127 final NHttpClientConnection conn = getConnection();
128 if (conn != null) {
129 conn.suspendOutput();
130 }
131 }
132
133 @Override
134 public InetAddress getLocalAddress() {
135 return getValidConnection().getLocalAddress();
136 }
137
138 @Override
139 public int getLocalPort() {
140 return getValidConnection().getLocalPort();
141 }
142
143 @Override
144 public InetAddress getRemoteAddress() {
145 return getValidConnection().getRemoteAddress();
146 }
147
148 @Override
149 public int getRemotePort() {
150 return getValidConnection().getRemotePort();
151 }
152
153 @Override
154 public boolean isOpen() {
155 final CPoolEntry local = this.poolEntry;
156 if (local != null) {
157 return !local.isClosed();
158 } else {
159 return false;
160 }
161 }
162
163 @Override
164 public boolean isStale() {
165 final NHttpClientConnection conn = getConnection();
166 if (conn != null) {
167 return !conn.isOpen();
168 } else {
169 return false;
170 }
171 }
172
173 @Override
174 public void setSocketTimeout(final int i) {
175 getValidConnection().setSocketTimeout(i);
176 }
177
178 @Override
179 public int getSocketTimeout() {
180 return getValidConnection().getSocketTimeout();
181 }
182
183 @Override
184 public void submitRequest(final HttpRequest request) throws IOException, HttpException {
185 getValidConnection().submitRequest(request);
186 }
187
188 @Override
189 public boolean isRequestSubmitted() {
190 return getValidConnection().isRequestSubmitted();
191 }
192
193 @Override
194 public void resetOutput() {
195 getValidConnection().resetOutput();
196 }
197
198 @Override
199 public void resetInput() {
200 getValidConnection().resetInput();
201 }
202
203 @Override
204 public int getStatus() {
205 return getValidConnection().getStatus();
206 }
207
208 @Override
209 public HttpRequest getHttpRequest() {
210 return getValidConnection().getHttpRequest();
211 }
212
213 @Override
214 public HttpResponse getHttpResponse() {
215 return getValidConnection().getHttpResponse();
216 }
217
218 @Override
219 public HttpContext getContext() {
220 return getValidConnection().getContext();
221 }
222
223 public static NHttpClientConnection newProxy(final CPoolEntry poolEntry) {
224 return new CPoolProxy(poolEntry);
225 }
226
227 private static CPoolProxy getProxy(final NHttpClientConnection conn) {
228 if (!CPoolProxy.class.isInstance(conn)) {
229 throw new IllegalStateException("Unexpected connection proxy class: " + conn.getClass());
230 }
231 return CPoolProxy.class.cast(conn);
232 }
233
234 public static CPoolEntry getPoolEntry(final NHttpClientConnection proxy) {
235 final CPoolEntry entry = getProxy(proxy).getPoolEntry();
236 if (entry == null) {
237 throw new ConnectionShutdownException();
238 }
239 return entry;
240 }
241
242 public static CPoolEntry detach(final NHttpClientConnection proxy) {
243 return getProxy(proxy).detach();
244 }
245
246 @Override
247 public String getId() {
248 return getValidConnection().getId();
249 }
250
251 @Override
252 public void bind(final IOSession iosession) {
253 getValidConnection().bind(iosession);
254 }
255
256 @Override
257 public IOSession getIOSession() {
258 return getValidConnection().getIOSession();
259 }
260
261 @Override
262 public SSLSession getSSLSession() {
263 return getValidConnection().getSSLSession();
264 }
265
266 @Override
267 public String toString() {
268 final StringBuilder sb = new StringBuilder("CPoolProxy{");
269 final ManagedNHttpClientConnection conn = getConnection();
270 if (conn != null) {
271 sb.append(conn);
272 } else {
273 sb.append("detached");
274 }
275 sb.append('}');
276 return sb.toString();
277 }
278
279 }
0 /*
1 * ====================================================================
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 * ====================================================================
19 *
20 * This software consists of voluntary contributions made by many
21 * individuals on behalf of the Apache Software Foundation. For more
22 * information on the Apache Software Foundation, please see
23 * <http://www.apache.org/>.
24 *
25 */
26
27 package org.apache.http.impl.nio.conn;
28
29 import java.io.IOException;
30 import java.net.SocketAddress;
31 import java.nio.ByteBuffer;
32 import java.nio.channels.ByteChannel;
33 import java.nio.channels.SelectionKey;
34
35 import org.apache.commons.logging.Log;
36 import org.apache.http.nio.reactor.IOSession;
37 import org.apache.http.nio.reactor.SessionBufferStatus;
38
39 class LoggingIOSession implements IOSession {
40
41 private final IOSession session;
42 private final ByteChannel channel;
43 private final String id;
44 private final Log log;
45 private final Wire wirelog;
46
47 public LoggingIOSession(final IOSession session, final String id, final Log log, final Log wirelog) {
48 super();
49 this.session = session;
50 this.channel = new LoggingByteChannel();
51 this.id = id;
52 this.log = log;
53 this.wirelog = new Wire(wirelog, this.id);
54 }
55
56 @Override
57 public ByteChannel channel() {
58 return this.channel;
59 }
60
61 @Override
62 public SocketAddress getLocalAddress() {
63 return this.session.getLocalAddress();
64 }
65
66 @Override
67 public SocketAddress getRemoteAddress() {
68 return this.session.getRemoteAddress();
69 }
70
71 @Override
72 public int getEventMask() {
73 return this.session.getEventMask();
74 }
75
76 private static String formatOps(final int ops) {
77 final StringBuilder buffer = new StringBuilder(6);
78 buffer.append('[');
79 if ((ops & SelectionKey.OP_READ) > 0) {
80 buffer.append('r');
81 }
82 if ((ops & SelectionKey.OP_WRITE) > 0) {
83 buffer.append('w');
84 }
85 if ((ops & SelectionKey.OP_ACCEPT) > 0) {
86 buffer.append('a');
87 }
88 if ((ops & SelectionKey.OP_CONNECT) > 0) {
89 buffer.append('c');
90 }
91 buffer.append(']');
92 return buffer.toString();
93 }
94
95 @Override
96 public void setEventMask(final int ops) {
97 this.session.setEventMask(ops);
98 if (this.log.isDebugEnabled()) {
99 this.log.debug(this.id + " " + this.session + ": Event mask set " + formatOps(ops));
100 }
101 }
102
103 @Override
104 public void setEvent(final int op) {
105 this.session.setEvent(op);
106 if (this.log.isDebugEnabled()) {
107 this.log.debug(this.id + " " + this.session + ": Event set " + formatOps(op));
108 }
109 }
110
111 @Override
112 public void clearEvent(final int op) {
113 this.session.clearEvent(op);
114 if (this.log.isDebugEnabled()) {
115 this.log.debug(this.id + " " + this.session + ": Event cleared " + formatOps(op));
116 }
117 }
118
119 @Override
120 public void close() {
121 if (this.log.isDebugEnabled()) {
122 this.log.debug(this.id + " " + this.session + ": Close");
123 }
124 this.session.close();
125 }
126
127 @Override
128 public int getStatus() {
129 return this.session.getStatus();
130 }
131
132 @Override
133 public boolean isClosed() {
134 return this.session.isClosed();
135 }
136
137 @Override
138 public void shutdown() {
139 if (this.log.isDebugEnabled()) {
140 this.log.debug(this.id + " " + this.session + ": Shutdown");
141 }
142 this.session.shutdown();
143 }
144
145 @Override
146 public int getSocketTimeout() {
147 return this.session.getSocketTimeout();
148 }
149
150 @Override
151 public void setSocketTimeout(final int timeout) {
152 if (this.log.isDebugEnabled()) {
153 this.log.debug(this.id + " " + this.session + ": Set timeout " + timeout);
154 }
155 this.session.setSocketTimeout(timeout);
156 }
157
158 @Override
159 public void setBufferStatus(final SessionBufferStatus status) {
160 this.session.setBufferStatus(status);
161 }
162
163 @Override
164 public boolean hasBufferedInput() {
165 return this.session.hasBufferedInput();
166 }
167
168 @Override
169 public boolean hasBufferedOutput() {
170 return this.session.hasBufferedOutput();
171 }
172
173 @Override
174 public Object getAttribute(final String name) {
175 return this.session.getAttribute(name);
176 }
177
178 @Override
179 public void setAttribute(final String name, final Object obj) {
180 if (this.log.isDebugEnabled()) {
181 this.log.debug(this.id + " " + this.session + ": Set attribute " + name);
182 }
183 this.session.setAttribute(name, obj);
184 }
185
186 @Override
187 public Object removeAttribute(final String name) {
188 if (this.log.isDebugEnabled()) {
189 this.log.debug(this.id + " " + this.session + ": Remove attribute " + name);
190 }
191 return this.session.removeAttribute(name);
192 }
193
194 @Override
195 public String toString() {
196 return this.id + " " + this.session.toString();
197 }
198
199 class LoggingByteChannel implements ByteChannel {
200
201 @Override
202 public int read(final ByteBuffer dst) throws IOException {
203 final int bytesRead = session.channel().read(dst);
204 if (log.isDebugEnabled()) {
205 log.debug(id + " " + session + ": " + bytesRead + " bytes read");
206 }
207 if (bytesRead > 0 && wirelog.isEnabled()) {
208 final ByteBuffer b = dst.duplicate();
209 final int p = b.position();
210 b.limit(p);
211 b.position(p - bytesRead);
212 wirelog.input(b);
213 }
214 return bytesRead;
215 }
216
217 @Override
218 public int write(final ByteBuffer src) throws IOException {
219 final int byteWritten = session.channel().write(src);
220 if (log.isDebugEnabled()) {
221 log.debug(id + " " + session + ": " + byteWritten + " bytes written");
222 }
223 if (byteWritten > 0 && wirelog.isEnabled()) {
224 final ByteBuffer b = src.duplicate();
225 final int p = b.position();
226 b.limit(p);
227 b.position(p - byteWritten);
228 wirelog.output(b);
229 }
230 return byteWritten;
231 }
232
233 @Override
234 public void close() throws IOException {
235 if (log.isDebugEnabled()) {
236 log.debug(id + " " + session + ": Channel close");
237 }
238 session.channel().close();
239 }
240
241 @Override
242 public boolean isOpen() {
243 return session.channel().isOpen();
244 }
245
246 }
247
248 }
0 /*
1 * ====================================================================
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 * ====================================================================
19 *
20 * This software consists of voluntary contributions made by many
21 * individuals on behalf of the Apache Software Foundation. For more
22 * information on the Apache Software Foundation, please see
23 * <http://www.apache.org/>.
24 *
25 */
26 package org.apache.http.impl.nio.conn;
27
28 import java.nio.charset.Charset;
29 import java.nio.charset.CharsetDecoder;
30 import java.nio.charset.CharsetEncoder;
31 import java.nio.charset.CodingErrorAction;
32 import java.util.concurrent.atomic.AtomicLong;
33
34 import org.apache.commons.logging.Log;
35 import org.apache.commons.logging.LogFactory;
36 import org.apache.http.HttpRequest;
37 import org.apache.http.HttpResponse;
38 import org.apache.http.config.ConnectionConfig;
39 import org.apache.http.impl.nio.codecs.DefaultHttpRequestWriterFactory;
40 import org.apache.http.impl.nio.codecs.DefaultHttpResponseParserFactory;
41 import org.apache.http.nio.NHttpMessageParserFactory;
42 import org.apache.http.nio.NHttpMessageWriterFactory;
43 import org.apache.http.nio.conn.ManagedNHttpClientConnection;
44 import org.apache.http.nio.conn.NHttpConnectionFactory;
45 import org.apache.http.nio.reactor.IOEventDispatch;
46 import org.apache.http.nio.reactor.IOSession;
47 import org.apache.http.nio.util.ByteBufferAllocator;
48 import org.apache.http.nio.util.HeapByteBufferAllocator;
49
50 /**
51 * Default factory for {@link ManagedNHttpClientConnection} instances.
52 *
53 * @since 4.0
54 */
55 public class ManagedNHttpClientConnectionFactory implements NHttpConnectionFactory<ManagedNHttpClientConnection> {
56
57 private final Log headerlog = LogFactory.getLog("org.apache.http.headers");
58 private final Log wirelog = LogFactory.getLog("org.apache.http.wire");
59 private final Log log = LogFactory.getLog(ManagedNHttpClientConnectionImpl.class);
60
61 private static final AtomicLong COUNTER = new AtomicLong();
62
63 public static final ManagedNHttpClientConnectionFactory INSTANCE = new ManagedNHttpClientConnectionFactory();
64
65 private final ByteBufferAllocator allocator;
66 private final NHttpMessageWriterFactory<HttpRequest> requestWriterFactory;
67 private final NHttpMessageParserFactory<HttpResponse> responseParserFactory;
68
69 public ManagedNHttpClientConnectionFactory(
70 final NHttpMessageWriterFactory<HttpRequest> requestWriterFactory,
71 final NHttpMessageParserFactory<HttpResponse> responseParserFactory,
72 final ByteBufferAllocator allocator) {
73 super();
74 this.requestWriterFactory = requestWriterFactory != null ? requestWriterFactory :
75 DefaultHttpRequestWriterFactory.INSTANCE;
76 this.responseParserFactory = responseParserFactory != null ? responseParserFactory :
77 DefaultHttpResponseParserFactory.INSTANCE;
78 this.allocator = allocator != null ? allocator : HeapByteBufferAllocator.INSTANCE;
79 }
80
81 public ManagedNHttpClientConnectionFactory() {
82 this(null, null, null);
83 }
84
85 @Override
86 public ManagedNHttpClientConnection create(
87 final IOSession iosession, final ConnectionConfig config) {
88 final String id = "http-outgoing-" + Long.toString(COUNTER.getAndIncrement());
89 CharsetDecoder chardecoder = null;
90 CharsetEncoder charencoder = null;
91 final Charset charset = config.getCharset();
92 final CodingErrorAction malformedInputAction = config.getMalformedInputAction() != null ?
93 config.getMalformedInputAction() : CodingErrorAction.REPORT;
94 final CodingErrorAction unmappableInputAction = config.getUnmappableInputAction() != null ?
95 config.getUnmappableInputAction() : CodingErrorAction.REPORT;
96 if (charset != null) {
97 chardecoder = charset.newDecoder();
98 chardecoder.onMalformedInput(malformedInputAction);
99 chardecoder.onUnmappableCharacter(unmappableInputAction);
100 charencoder = charset.newEncoder();
101 charencoder.onMalformedInput(malformedInputAction);
102 charencoder.onUnmappableCharacter(unmappableInputAction);
103 }
104 final ManagedNHttpClientConnection conn = new ManagedNHttpClientConnectionImpl(
105 id,
106 this.log,
107 this.headerlog,
108 this.wirelog,
109 iosession,
110 config.getBufferSize(),
111 config.getFragmentSizeHint(),
112 this.allocator,
113 chardecoder,
114 charencoder,
115 config.getMessageConstraints(),
116 null,
117 null,
118 this.requestWriterFactory,
119 this.responseParserFactory);
120 iosession.setAttribute(IOEventDispatch.CONNECTION_KEY, conn);
121 return conn;
122 }
123
124 }
0 /*
1 * ====================================================================
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 * ====================================================================
19 *
20 * This software consists of voluntary contributions made by many
21 * individuals on behalf of the Apache Software Foundation. For more
22 * information on the Apache Software Foundation, please see
23 * <http://www.apache.org/>.
24 *
25 */
26 package org.apache.http.impl.nio.conn;
27
28 import java.nio.charset.CharsetDecoder;
29 import java.nio.charset.CharsetEncoder;
30
31 import javax.net.ssl.SSLSession;
32
33 import org.apache.commons.logging.Log;
34 import org.apache.http.Header;
35 import org.apache.http.HttpRequest;
36 import org.apache.http.HttpResponse;
37 import org.apache.http.config.MessageConstraints;
38 import org.apache.http.entity.ContentLengthStrategy;
39 import org.apache.http.impl.nio.DefaultNHttpClientConnection;
40 import org.apache.http.nio.NHttpMessageParserFactory;
41 import org.apache.http.nio.NHttpMessageWriterFactory;
42 import org.apache.http.nio.conn.ManagedNHttpClientConnection;
43 import org.apache.http.nio.reactor.IOSession;
44 import org.apache.http.nio.reactor.ssl.SSLIOSession;
45 import org.apache.http.nio.util.ByteBufferAllocator;
46 import org.apache.http.util.Args;
47 import org.apache.http.util.Asserts;
48
49 class ManagedNHttpClientConnectionImpl
50 extends DefaultNHttpClientConnection implements ManagedNHttpClientConnection {
51
52 private final Log headerlog;
53 private final Log wirelog;
54 private final Log log;
55
56 private final String id;
57 private IOSession original;
58
59 public ManagedNHttpClientConnectionImpl(
60 final String id,
61 final Log log,
62 final Log headerlog,
63 final Log wirelog,
64 final IOSession iosession,
65 final int buffersize,
66 final int fragmentSizeHint,
67 final ByteBufferAllocator allocator,
68 final CharsetDecoder chardecoder,
69 final CharsetEncoder charencoder,
70 final MessageConstraints constraints,
71 final ContentLengthStrategy incomingContentStrategy,
72 final ContentLengthStrategy outgoingContentStrategy,
73 final NHttpMessageWriterFactory<HttpRequest> requestWriterFactory,
74 final NHttpMessageParserFactory<HttpResponse> responseParserFactory) {
75 super(iosession, buffersize, fragmentSizeHint, allocator, chardecoder, charencoder, constraints,
76 incomingContentStrategy, outgoingContentStrategy,
77 requestWriterFactory, responseParserFactory);
78 this.id = id;
79 this.log = log;
80 this.headerlog = headerlog;
81 this.wirelog = wirelog;
82 this.original = iosession;
83 if (this.log.isDebugEnabled() || this.wirelog.isDebugEnabled()) {
84 super.bind(new LoggingIOSession(iosession, this.id, this.log, this.wirelog));
85 }
86 }
87
88 @Override
89 public void bind(final IOSession iosession) {
90 Args.notNull(iosession, "I/O session");
91 Asserts.check(!iosession.isClosed(), "I/O session is closed");
92 this.status = ACTIVE;
93 this.original = iosession;
94 if (this.log.isDebugEnabled() || this.wirelog.isDebugEnabled()) {
95 this.log.debug(this.id + " Upgrade session " + iosession);
96 super.bind(new LoggingIOSession(iosession, this.id, this.log, this.wirelog));
97 } else {
98 super.bind(iosession);
99 }
100 }
101
102 @Override
103 public IOSession getIOSession() {
104 return this.original;
105 }
106
107 @Override
108 public SSLSession getSSLSession() {
109 if (this.original instanceof SSLIOSession) {
110 return ((SSLIOSession) this.original).getSSLSession();
111 } else {
112 return null;
113 }
114 }
115
116 @Override
117 public String getId() {
118 return this.id;
119 }
120
121 @Override
122 protected void onResponseReceived(final HttpResponse response) {
123 if (response != null && this.headerlog.isDebugEnabled()) {
124 this.headerlog.debug(this.id + " << " + response.getStatusLine().toString());
125 final Header[] headers = response.getAllHeaders();
126 for (final Header header : headers) {
127 this.headerlog.debug(this.id + " << " + header.toString());
128 }
129 }
130 }
131
132 @Override
133 protected void onRequestSubmitted(final HttpRequest request) {
134 if (request != null && this.headerlog.isDebugEnabled()) {
135 this.headerlog.debug(this.id + " >> " + request.getRequestLine().toString());
136 final Header[] headers = request.getAllHeaders();
137 for (final Header header : headers) {
138 this.headerlog.debug(this.id + " >> " + header.toString());
139 }
140 }
141 }
142
143 @Override
144 public String toString() {
145 final StringBuilder buf = new StringBuilder();
146 buf.append(this.id);
147 buf.append(" [");
148 switch (this.status) {
149 case ACTIVE:
150 buf.append("ACTIVE");
151 if (this.inbuf.hasData()) {
152 buf.append("(").append(this.inbuf.length()).append(")");
153 }
154 break;
155 case CLOSING:
156 buf.append("CLOSING");
157 break;
158 case CLOSED:
159 buf.append("CLOSED");
160 break;
161 }
162 buf.append("]");
163 return buf.toString();
164 }
165
166 }
0 /*
1 * ====================================================================
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 * ====================================================================
19 *
20 * This software consists of voluntary contributions made by many
21 * individuals on behalf of the Apache Software Foundation. For more
22 * information on the Apache Software Foundation, please see
23 * <http://www.apache.org/>.
24 *
25 */
26 package org.apache.http.impl.nio.conn;
27
28 import java.io.IOException;
29 import java.net.InetAddress;
30 import java.net.InetSocketAddress;
31 import java.net.SocketAddress;
32 import java.util.Map;
33 import java.util.Set;
34 import java.util.concurrent.ConcurrentHashMap;
35 import java.util.concurrent.Future;
36 import java.util.concurrent.TimeUnit;
37
38 import org.apache.commons.logging.Log;
39 import org.apache.commons.logging.LogFactory;
40 import org.apache.http.HttpHost;
41 import org.apache.http.annotation.ThreadSafe;
42 import org.apache.http.concurrent.BasicFuture;
43 import org.apache.http.concurrent.FutureCallback;
44 import org.apache.http.config.ConnectionConfig;
45 import org.apache.http.config.Lookup;
46 import org.apache.http.config.Registry;
47 import org.apache.http.config.RegistryBuilder;
48 import org.apache.http.conn.DnsResolver;
49 import org.apache.http.conn.SchemePortResolver;
50 import org.apache.http.conn.UnsupportedSchemeException;
51 import org.apache.http.conn.routing.HttpRoute;
52 import org.apache.http.impl.conn.DefaultSchemePortResolver;
53 import org.apache.http.impl.conn.SystemDefaultDnsResolver;
54 import org.apache.http.nio.NHttpClientConnection;
55 import org.apache.http.nio.conn.ManagedNHttpClientConnection;
56 import org.apache.http.nio.conn.NHttpClientConnectionManager;
57 import org.apache.http.nio.conn.NHttpConnectionFactory;
58 import org.apache.http.nio.conn.NoopIOSessionStrategy;
59 import org.apache.http.nio.conn.SchemeIOSessionStrategy;
60 import org.apache.http.nio.conn.ssl.SSLIOSessionStrategy;
61 import org.apache.http.nio.pool.NIOConnFactory;
62 import org.apache.http.nio.pool.SocketAddressResolver;
63 import org.apache.http.nio.reactor.ConnectingIOReactor;
64 import org.apache.http.nio.reactor.IOEventDispatch;
65 import org.apache.http.nio.reactor.IOSession;
66 import org.apache.http.pool.ConnPoolControl;
67 import org.apache.http.pool.PoolStats;
68 import org.apache.http.protocol.HttpContext;
69 import org.apache.http.util.Args;
70 import org.apache.http.util.Asserts;
71
72 /**
73 * {@code PoolingNHttpClientConnectionManager} maintains a pool of
74 * {@link NHttpClientConnection}s and is able to service connection requests
75 * from multiple execution threads. Connections are pooled on a per route
76 * basis. A request for a route which already the manager has persistent
77 * connections for available in the pool will be services by leasing
78 * a connection from the pool rather than creating a brand new connection.
79 * <p>
80 * {@code PoolingNHttpClientConnectionManager} maintains a maximum limit
81 * of connection on a per route basis and in total. Per default this
82 * implementation will create no more than than 2 concurrent connections
83 * per given route and no more 20 connections in total. For many real-world
84 * applications these limits may prove too constraining, especially if they
85 * use HTTP as a transport protocol for their services. Connection limits,
86 * however, can be adjusted using {@link ConnPoolControl} methods.
87 *
88 * @since 4.0
89 */
90 @ThreadSafe
91 public class PoolingNHttpClientConnectionManager
92 implements NHttpClientConnectionManager, ConnPoolControl<HttpRoute> {
93
94 private final Log log = LogFactory.getLog(getClass());
95
96 static final String IOSESSION_FACTORY_REGISTRY = "http.iosession-factory-registry";
97
98 private final ConnectingIOReactor ioreactor;
99 private final ConfigData configData;
100 private final CPool pool;
101 private final Registry<SchemeIOSessionStrategy> iosessionFactoryRegistry;
102
103 private static Registry<SchemeIOSessionStrategy> getDefaultRegistry() {
104 return RegistryBuilder.<SchemeIOSessionStrategy>create()
105 .register("http", NoopIOSessionStrategy.INSTANCE)
106 .register("https", SSLIOSessionStrategy.getDefaultStrategy())
107 .build();
108 }
109
110 public PoolingNHttpClientConnectionManager(final ConnectingIOReactor ioreactor) {
111 this(ioreactor, getDefaultRegistry());
112 }
113
114 public PoolingNHttpClientConnectionManager(
115 final ConnectingIOReactor ioreactor,
116 final Registry<SchemeIOSessionStrategy> iosessionFactoryRegistry) {
117 this(ioreactor, null, iosessionFactoryRegistry, null);
118 }
119
120 public PoolingNHttpClientConnectionManager(
121 final ConnectingIOReactor ioreactor,
122 final NHttpConnectionFactory<ManagedNHttpClientConnection> connFactory,
123 final DnsResolver dnsResolver) {
124 this(ioreactor, connFactory, getDefaultRegistry(), dnsResolver);
125 }
126
127 public PoolingNHttpClientConnectionManager(
128 final ConnectingIOReactor ioreactor,
129 final NHttpConnectionFactory<ManagedNHttpClientConnection> connFactory) {
130 this(ioreactor, connFactory, getDefaultRegistry(), null);
131 }
132
133 public PoolingNHttpClientConnectionManager(
134 final ConnectingIOReactor ioreactor,
135 final NHttpConnectionFactory<ManagedNHttpClientConnection> connFactory,
136 final Registry<SchemeIOSessionStrategy> iosessionFactoryRegistry) {
137 this(ioreactor, connFactory, iosessionFactoryRegistry, null);
138 }
139
140 public PoolingNHttpClientConnectionManager(
141 final ConnectingIOReactor ioreactor,
142 final NHttpConnectionFactory<ManagedNHttpClientConnection> connFactory,
143 final Registry<SchemeIOSessionStrategy> iosessionFactoryRegistry,
144 final DnsResolver dnsResolver) {
145 this(ioreactor, connFactory, iosessionFactoryRegistry, null, dnsResolver,
146 -1, TimeUnit.MILLISECONDS);
147 }
148
149 public PoolingNHttpClientConnectionManager(
150 final ConnectingIOReactor ioreactor,
151 final NHttpConnectionFactory<ManagedNHttpClientConnection> connFactory,
152 final Registry<SchemeIOSessionStrategy> iosessionFactoryRegistry,
153 final SchemePortResolver schemePortResolver,
154 final DnsResolver dnsResolver,
155 final long timeToLive, final TimeUnit tunit) {
156 super();
157 Args.notNull(ioreactor, "I/O reactor");
158 Args.notNull(iosessionFactoryRegistry, "I/O session factory registry");
159 this.ioreactor = ioreactor;
160 this.configData = new ConfigData();
161 this.pool = new CPool(ioreactor,
162 new InternalConnectionFactory(this.configData, connFactory),
163 new InternalAddressResolver(schemePortResolver, dnsResolver),
164 2, 20, timeToLive, tunit != null ? tunit : TimeUnit.MILLISECONDS);
165 this.iosessionFactoryRegistry = iosessionFactoryRegistry;
166 }
167
168 PoolingNHttpClientConnectionManager(
169 final ConnectingIOReactor ioreactor,
170 final CPool pool,
171 final Registry<SchemeIOSessionStrategy> iosessionFactoryRegistry) {
172 super();
173 this.ioreactor = ioreactor;
174 this.configData = new ConfigData();
175 this.pool = pool;
176 this.iosessionFactoryRegistry = iosessionFactoryRegistry;
177 }
178
179 @Override
180 protected void finalize() throws Throwable {
181 try {
182 shutdown();
183 } finally {
184 super.finalize();
185 }
186 }
187
188 @Override
189 public void execute(final IOEventDispatch eventDispatch) throws IOException {
190 this.ioreactor.execute(eventDispatch);
191 }
192
193 public void shutdown(final long waitMs) throws IOException {
194 this.log.debug("Connection manager is shutting down");
195 this.pool.shutdown(waitMs);
196 this.log.debug("Connection manager shut down");
197 }
198
199 @Override
200 public void shutdown() throws IOException {
201 this.log.debug("Connection manager is shutting down");
202 this.pool.shutdown(2000);
203 this.log.debug("Connection manager shut down");
204 }
205
206 private String format(final HttpRoute route, final Object state) {
207 final StringBuilder buf = new StringBuilder();
208 buf.append("[route: ").append(route).append("]");
209 if (state != null) {
210 buf.append("[state: ").append(state).append("]");
211 }
212 return buf.toString();
213 }
214
215 private String formatStats(final HttpRoute route) {
216 final StringBuilder buf = new StringBuilder();
217 final PoolStats totals = this.pool.getTotalStats();
218 final PoolStats stats = this.pool.getStats(route);
219 buf.append("[total kept alive: ").append(totals.getAvailable()).append("; ");
220 buf.append("route allocated: ").append(stats.getLeased() + stats.getAvailable());
221 buf.append(" of ").append(stats.getMax()).append("; ");
222 buf.append("total allocated: ").append(totals.getLeased() + totals.getAvailable());
223 buf.append(" of ").append(totals.getMax()).append("]");
224 return buf.toString();
225 }
226
227 private String format(final CPoolEntry entry) {
228 final StringBuilder buf = new StringBuilder();
229 buf.append("[id: ").append(entry.getId()).append("]");
230 buf.append("[route: ").append(entry.getRoute()).append("]");
231 final Object state = entry.getState();
232 if (state != null) {
233 buf.append("[state: ").append(state).append("]");
234 }
235 return buf.toString();
236 }
237
238 @Override
239 public Future<NHttpClientConnection> requestConnection(
240 final HttpRoute route,
241 final Object state,
242 final long connectTimeout,
243 final long leaseTimeout,
244 final TimeUnit tunit,
245 final FutureCallback<NHttpClientConnection> callback) {
246 Args.notNull(route, "HTTP route");
247 if (this.log.isDebugEnabled()) {
248 this.log.debug("Connection request: " + format(route, state) + formatStats(route));
249 }
250 final BasicFuture<NHttpClientConnection> future = new BasicFuture<NHttpClientConnection>(callback);
251 final HttpHost host;
252 if (route.getProxyHost() != null) {
253 host = route.getProxyHost();
254 } else {
255 host = route.getTargetHost();
256 }
257 final SchemeIOSessionStrategy sf = this.iosessionFactoryRegistry.lookup(
258 host.getSchemeName());
259 if (sf == null) {
260 future.failed(new UnsupportedSchemeException(host.getSchemeName() +
261 " protocol is not supported"));
262 return future;
263 }
264 this.pool.lease(route, state,
265 connectTimeout, leaseTimeout, tunit != null ? tunit : TimeUnit.MILLISECONDS,
266 new InternalPoolEntryCallback(future));
267 return future;
268 }
269
270 @Override
271 public void releaseConnection(
272 final NHttpClientConnection managedConn,
273 final Object state,
274 final long keepalive,
275 final TimeUnit tunit) {
276 Args.notNull(managedConn, "Managed connection");
277 synchronized (managedConn) {
278 final CPoolEntry entry = CPoolProxy.detach(managedConn);
279 if (entry == null) {
280 return;
281 }
282 if (this.log.isDebugEnabled()) {
283 this.log.debug("Releasing connection: " + format(entry) + formatStats(entry.getRoute()));
284 }
285 final NHttpClientConnection conn = entry.getConnection();
286 try {
287 if (conn.isOpen()) {
288 entry.setState(state);
289 entry.updateExpiry(keepalive, tunit != null ? tunit : TimeUnit.MILLISECONDS);
290 if (this.log.isDebugEnabled()) {
291 final String s;
292 if (keepalive > 0) {
293 s = "for " + (double) keepalive / 1000 + " seconds";
294 } else {
295 s = "indefinitely";
296 }
297 this.log.debug("Connection " + format(entry) + " can be kept alive " + s);
298 }
299 }
300 } finally {
301 this.pool.release(entry, conn.isOpen() && entry.isRouteComplete());
302 if (this.log.isDebugEnabled()) {
303 this.log.debug("Connection released: " + format(entry) + formatStats(entry.getRoute()));
304 }
305 }
306 }
307 }
308
309 private Lookup<SchemeIOSessionStrategy> getIOSessionFactoryRegistry(final HttpContext context) {
310 @SuppressWarnings("unchecked")
311 Lookup<SchemeIOSessionStrategy> reg = (Lookup<SchemeIOSessionStrategy>) context.getAttribute(
312 IOSESSION_FACTORY_REGISTRY);
313 if (reg == null) {
314 reg = this.iosessionFactoryRegistry;
315 }
316 return reg;
317 }
318
319 @Override
320 public void startRoute(
321 final NHttpClientConnection managedConn,
322 final HttpRoute route,
323 final HttpContext context) throws IOException {
324 Args.notNull(managedConn, "Managed connection");
325 Args.notNull(route, "HTTP route");
326 final HttpHost host;
327 if (route.getProxyHost() != null) {
328 host = route.getProxyHost();
329 } else {
330 host = route.getTargetHost();
331 }
332 final Lookup<SchemeIOSessionStrategy> reg = getIOSessionFactoryRegistry(context);
333 final SchemeIOSessionStrategy sf = reg.lookup(host.getSchemeName());
334 if (sf == null) {
335 throw new UnsupportedSchemeException(host.getSchemeName() +
336 " protocol is not supported");
337 }
338 if (sf.isLayeringRequired()) {
339 synchronized (managedConn) {
340 final CPoolEntry entry = CPoolProxy.getPoolEntry(managedConn);
341 final ManagedNHttpClientConnection conn = entry.getConnection();
342 final IOSession ioSession = conn.getIOSession();
343 final IOSession currentSession = sf.upgrade(host, ioSession);
344 conn.bind(currentSession);
345 }
346 }
347 }
348
349 @Override
350 public void upgrade(
351 final NHttpClientConnection managedConn,
352 final HttpRoute route,
353 final HttpContext context) throws IOException {
354 Args.notNull(managedConn, "Managed connection");
355 Args.notNull(route, "HTTP route");
356 final HttpHost host = route.getTargetHost();
357 final Lookup<SchemeIOSessionStrategy> reg = getIOSessionFactoryRegistry(context);
358 final SchemeIOSessionStrategy sf = reg.lookup(host.getSchemeName());
359 if (sf == null) {
360 throw new UnsupportedSchemeException(host.getSchemeName() +
361 " protocol is not supported");
362 }
363 if (!sf.isLayeringRequired()) {
364 throw new UnsupportedSchemeException(host.getSchemeName() +
365 " protocol does not support connection upgrade");
366 }
367 synchronized (managedConn) {
368 final CPoolEntry entry = CPoolProxy.getPoolEntry(managedConn);
369 final ManagedNHttpClientConnection conn = entry.getConnection();
370 final IOSession currentSession = sf.upgrade(host, conn.getIOSession());
371 conn.bind(currentSession);
372 }
373 }
374
375 @Override
376 public void routeComplete(
377 final NHttpClientConnection managedConn,
378 final HttpRoute route,
379 final HttpContext context) {
380 Args.notNull(managedConn, "Managed connection");
381 Args.notNull(route, "HTTP route");
382 synchronized (managedConn) {
383 final CPoolEntry entry = CPoolProxy.getPoolEntry(managedConn);
384 entry.markRouteComplete();
385 }
386 }
387
388 @Override
389 public boolean isRouteComplete(
390 final NHttpClientConnection managedConn) {
391 Args.notNull(managedConn, "Managed connection");
392 synchronized (managedConn) {
393 final CPoolEntry entry = CPoolProxy.getPoolEntry(managedConn);
394 return entry.isRouteComplete();
395 }
396 }
397
398 @Override
399 public void closeIdleConnections(final long idleTimeout, final TimeUnit tunit) {
400 if (this.log.isDebugEnabled()) {
401 this.log.debug("Closing connections idle longer than " + idleTimeout + " " + tunit);
402 }
403 this.pool.closeIdle(idleTimeout, tunit);
404 }
405
406 @Override
407 public void closeExpiredConnections() {
408 log.debug("Closing expired connections");
409 this.pool.closeExpired();
410 }
411
412 @Override
413 public int getMaxTotal() {
414 return this.pool.getMaxTotal();
415 }
416
417 @Override
418 public void setMaxTotal(final int max) {
419 this.pool.setMaxTotal(max);
420 }
421
422 @Override
423 public int getDefaultMaxPerRoute() {
424 return this.pool.getDefaultMaxPerRoute();
425 }
426
427 @Override
428 public void setDefaultMaxPerRoute(final int max) {
429 this.pool.setDefaultMaxPerRoute(max);
430 }
431
432 @Override
433 public int getMaxPerRoute(final HttpRoute route) {
434 return this.pool.getMaxPerRoute(route);
435 }
436
437 @Override
438 public void setMaxPerRoute(final HttpRoute route, final int max) {
439 this.pool.setMaxPerRoute(route, max);
440 }
441
442 @Override
443 public PoolStats getTotalStats() {
444 return this.pool.getTotalStats();
445 }
446
447 @Override
448 public PoolStats getStats(final HttpRoute route) {
449 return this.pool.getStats(route);
450 }
451
452 /**
453 * @since 4.1
454 */
455 public Set<HttpRoute> getRoutes() {
456 return this.pool.getRoutes();
457 }
458
459 public ConnectionConfig getDefaultConnectionConfig() {
460 return this.configData.getDefaultConnectionConfig();
461 }
462
463 public void setDefaultConnectionConfig(final ConnectionConfig defaultConnectionConfig) {
464 this.configData.setDefaultConnectionConfig(defaultConnectionConfig);
465 }
466
467 public ConnectionConfig getConnectionConfig(final HttpHost host) {
468 return this.configData.getConnectionConfig(host);
469 }
470
471 public void setConnectionConfig(final HttpHost host, final ConnectionConfig connectionConfig) {
472 this.configData.setConnectionConfig(host, connectionConfig);
473 }
474
475 class InternalPoolEntryCallback implements FutureCallback<CPoolEntry> {
476
477 private final BasicFuture<NHttpClientConnection> future;
478
479 public InternalPoolEntryCallback(
480 final BasicFuture<NHttpClientConnection> future) {
481 super();
482 this.future = future;
483 }
484
485 @Override
486 public void completed(final CPoolEntry entry) {
487 Asserts.check(entry.getConnection() != null, "Pool entry with no connection");
488 if (log.isDebugEnabled()) {
489 log.debug("Connection leased: " + format(entry) + formatStats(entry.getRoute()));
490 }
491 final NHttpClientConnection managedConn = CPoolProxy.newProxy(entry);
492 if (!this.future.completed(managedConn)) {
493 pool.release(entry, true);
494 }
495 }
496
497 @Override
498 public void failed(final Exception ex) {
499 if (log.isDebugEnabled()) {
500 log.debug("Connection request failed", ex);
501 }
502 this.future.failed(ex);
503 }
504
505 @Override
506 public void cancelled() {
507 log.debug("Connection request cancelled");
508 this.future.cancel(true);
509 }
510
511 }
512
513 static class ConfigData {
514
515 private final Map<HttpHost, ConnectionConfig> connectionConfigMap;
516 private volatile ConnectionConfig defaultConnectionConfig;
517
518 ConfigData() {
519 super();
520 this.connectionConfigMap = new ConcurrentHashMap<HttpHost, ConnectionConfig>();
521 }
522
523 public ConnectionConfig getDefaultConnectionConfig() {
524 return this.defaultConnectionConfig;
525 }
526
527 public void setDefaultConnectionConfig(final ConnectionConfig defaultConnectionConfig) {
528 this.defaultConnectionConfig = defaultConnectionConfig;
529 }
530
531 public ConnectionConfig getConnectionConfig(final HttpHost host) {
532 return this.connectionConfigMap.get(host);
533 }
534
535 public void setConnectionConfig(final HttpHost host, final ConnectionConfig connectionConfig) {
536 this.connectionConfigMap.put(host, connectionConfig);
537 }
538
539 }
540
541 static class InternalConnectionFactory implements NIOConnFactory<HttpRoute, ManagedNHttpClientConnection> {
542
543 private final ConfigData configData;
544 private final NHttpConnectionFactory<ManagedNHttpClientConnection> connFactory;
545
546 InternalConnectionFactory(
547 final ConfigData configData,
548 final NHttpConnectionFactory<ManagedNHttpClientConnection> connFactory) {
549 super();
550 this.configData = configData != null ? configData : new ConfigData();
551 this.connFactory = connFactory != null ? connFactory :
552 ManagedNHttpClientConnectionFactory.INSTANCE;
553 }
554
555 @Override
556 public ManagedNHttpClientConnection create(
557 final HttpRoute route, final IOSession iosession) throws IOException {
558 ConnectionConfig config = null;
559 if (route.getProxyHost() != null) {
560 config = this.configData.getConnectionConfig(route.getProxyHost());
561 }
562 if (config == null) {
563 config = this.configData.getConnectionConfig(route.getTargetHost());
564 }
565 if (config == null) {
566 config = this.configData.getDefaultConnectionConfig();
567 }
568 if (config == null) {
569 config = ConnectionConfig.DEFAULT;
570 }
571 final ManagedNHttpClientConnection conn = this.connFactory.create(iosession, config);
572 iosession.setAttribute(IOEventDispatch.CONNECTION_KEY, conn);
573 return conn;
574 }
575
576 }
577
578 static class InternalAddressResolver implements SocketAddressResolver<HttpRoute> {
579
580 private final SchemePortResolver schemePortResolver;
581 private final DnsResolver dnsResolver;
582
583 public InternalAddressResolver(
584 final SchemePortResolver schemePortResolver,
585 final DnsResolver dnsResolver) {
586 super();
587 this.schemePortResolver = schemePortResolver != null ? schemePortResolver :
588 DefaultSchemePortResolver.INSTANCE;
589 this.dnsResolver = dnsResolver != null ? dnsResolver :
590 SystemDefaultDnsResolver.INSTANCE;
591 }
592
593 @Override
594 public SocketAddress resolveLocalAddress(final HttpRoute route) throws IOException {
595 return route.getLocalAddress() != null ? new InetSocketAddress(route.getLocalAddress(), 0) : null;
596 }
597
598 @Override
599 public SocketAddress resolveRemoteAddress(final HttpRoute route) throws IOException {
600 final HttpHost host;
601 if (route.getProxyHost() != null) {
602 host = route.getProxyHost();
603 } else {
604 host = route.getTargetHost();
605 }
606 final int port = this.schemePortResolver.resolve(host);
607 final InetAddress[] addresses = this.dnsResolver.resolve(host.getHostName());
608 return new InetSocketAddress(addresses[0], port);
609 }
610
611 }
612 }
0 /*
1 * ====================================================================
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 * ====================================================================
19 *
20 * This software consists of voluntary contributions made by many
21 * individuals on behalf of the Apache Software Foundation. For more
22 * information on the Apache Software Foundation, please see
23 * <http://www.apache.org/>.
24 *
25 */
26 package org.apache.http.impl.nio.conn;
27
28 import java.nio.ByteBuffer;
29
30 import org.apache.commons.logging.Log;
31
32 class Wire {
33
34 private final Log log;
35 private final String id;
36
37 public Wire(final Log log, final String id) {
38 super();
39 this.log = log;
40 this.id = id;
41 }
42
43 private void wire(final String header, final byte[] b, final int pos, final int off) {
44 final StringBuilder buffer = new StringBuilder();
45 for (int i = 0; i < off; i++) {
46 final int ch = b[pos + i];
47 if (ch == 13) {
48 buffer.append("[\\r]");
49 } else if (ch == 10) {
50 buffer.append("[\\n]\"");
51 buffer.insert(0, "\"");
52 buffer.insert(0, header);
53 this.log.debug(this.id + " " + buffer.toString());
54 buffer.setLength(0);
55 } else if ((ch < 32) || (ch > 127)) {
56 buffer.append("[0x");
57 buffer.append(Integer.toHexString(ch));
58 buffer.append("]");
59 } else {
60 buffer.append((char) ch);
61 }
62 }
63 if (buffer.length() > 0) {
64 buffer.append('\"');
65 buffer.insert(0, '\"');
66 buffer.insert(0, header);
67 this.log.debug(this.id + " " + buffer.toString());
68 }
69 }
70
71
72 public boolean isEnabled() {
73 return this.log.isDebugEnabled();
74 }
75
76 public void output(final byte[] b, final int pos, final int off) {
77 wire(">> ", b, pos, off);
78 }
79
80 public void input(final byte[] b, final int pos, final int off) {
81 wire("<< ", b, pos, off);
82 }
83
84 public void output(final byte[] b) {
85 output(b, 0, b.length);
86 }
87
88 public void input(final byte[] b) {
89 input(b, 0, b.length);
90 }
91
92 public void output(final int b) {
93 output(new byte[] {(byte) b});
94 }
95
96 public void input(final int b) {
97 input(new byte[] {(byte) b});
98 }
99
100 public void output(final ByteBuffer b) {
101 if (b.hasArray()) {
102 output(b.array(), b.arrayOffset() + b.position(), b.remaining());
103 } else {
104 final byte[] tmp = new byte[b.remaining()];
105 b.get(tmp);
106 output(tmp);
107 }
108 }
109
110 public void input(final ByteBuffer b) {
111 if (b.hasArray()) {
112 input(b.array(), b.arrayOffset() + b.position(), b.remaining());
113 } else {
114 final byte[] tmp = new byte[b.remaining()];
115 b.get(tmp);
116 input(tmp);
117 }
118 }
119
120 }
0 /*
1 * ====================================================================
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 * ====================================================================
19 *
20 * This software consists of voluntary contributions made by many
21 * individuals on behalf of the Apache Software Foundation. For more
22 * information on the Apache Software Foundation, please see
23 * <http://www.apache.org/>.
24 *
25 */
26
27 /**
28 * Default implementations of asynchronous client connection
29 * management functions.
30 */
31 package org.apache.http.impl.nio.conn;
0 /*
1 * ====================================================================
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 * ====================================================================
19 *
20 * This software consists of voluntary contributions made by many
21 * individuals on behalf of the Apache Software Foundation. For more
22 * information on the Apache Software Foundation, please see
23 * <http://www.apache.org/>.
24 *
25 */
26 package org.apache.http.nio.client;
27
28 import java.util.concurrent.Future;
29
30 import org.apache.http.HttpHost;
31 import org.apache.http.HttpRequest;
32 import org.apache.http.HttpResponse;
33 import org.apache.http.client.methods.HttpUriRequest;
34 import org.apache.http.concurrent.FutureCallback;
35 import org.apache.http.nio.protocol.HttpAsyncRequestProducer;
36 import org.apache.http.nio.protocol.HttpAsyncResponseConsumer;
37 import org.apache.http.protocol.HttpContext;
38
39 /**
40 * This interface represents only the most basic contract for HTTP request
41 * execution. It imposes no restrictions or particular details on the request
42 * execution process and leaves the specifics of state management,
43 * authentication and redirect handling up to individual implementations.
44 *
45 * @since 4.0
46 */
47 public interface HttpAsyncClient {
48
49 /**
50 * Initiates asynchronous HTTP request execution using the given context.
51 * <p>
52 * The request producer passed to this method will be used to generate
53 * a request message and stream out its content without buffering it
54 * in memory. The response consumer passed to this method will be used
55 * to process a response message without buffering its content in memory.
56 * <p>
57 * Please note it may be unsafe to interact with the context instance
58 * while the request is still being executed.
59 *
60 * @param <T> the result type of request execution.
61 * @param requestProducer request producer callback.
62 * @param responseConsumer response consumer callaback.
63 * @param context HTTP context
64 * @param callback future callback.
65 * @return future representing pending completion of the operation.
66 */
67 <T> Future<T> execute(
68 HttpAsyncRequestProducer requestProducer,
69 HttpAsyncResponseConsumer<T> responseConsumer,
70 HttpContext context,
71 FutureCallback<T> callback);
72
73 /**
74 * Initiates asynchronous HTTP request execution using the default
75 * context.
76 * <p>
77 * The request producer passed to this method will be used to generate
78 * a request message and stream out its content without buffering it
79 * in memory. The response consumer passed to this method will be used
80 * to process a response message without buffering its content in memory.
81 *
82 * @param <T> the result type of request execution.
83 * @param requestProducer request producer callback.
84 * @param responseConsumer response consumer callaback.
85 * @param callback future callback.
86 * @return future representing pending completion of the operation.
87 */
88 <T> Future<T> execute(
89 HttpAsyncRequestProducer requestProducer,
90 HttpAsyncResponseConsumer<T> responseConsumer,
91 FutureCallback<T> callback);
92
93 /**
94 * Initiates asynchronous HTTP request execution against the given target
95 * using the given context.
96 * <p>
97 * Please note it may be unsafe to interact with the context instance
98 * while the request is still being executed.
99 *
100 * @param target the target host for the request.
101 * Implementations may accept {@code null}
102 * if they can still determine a route, for example
103 * to a default target or by inspecting the request.
104 * @param request the request to execute
105 * @param context the context to use for the execution, or
106 * {@code null} to use the default context
107 * @param callback future callback.
108 * @return future representing pending completion of the operation.
109 */
110 Future<HttpResponse> execute(
111 HttpHost target, HttpRequest request, HttpContext context,
112 FutureCallback<HttpResponse> callback);
113
114 /**
115 * Initiates asynchronous HTTP request execution against the given target.
116 *
117 * @param target the target host for the request.
118 * Implementations may accept {@code null}
119 * if they can still determine a route, for example
120 * to a default target or by inspecting the request.
121 * @param request the request to execute
122 * @param callback future callback.
123 * @return future representing pending completion of the operation.
124 */
125 Future<HttpResponse> execute(
126 HttpHost target, HttpRequest request,
127 FutureCallback<HttpResponse> callback);
128
129 /**
130 * Initiates asynchronous HTTP request execution using the given
131 * context.
132 * <p>
133 * Please note it may be unsafe to interact with the context instance
134 * while the request is still being executed.
135 *
136 * @param request the request to execute
137 * @param context HTTP context
138 * @param callback future callback.
139 * @return future representing pending completion of the operation.
140 */
141 Future<HttpResponse> execute(
142 HttpUriRequest request, HttpContext context,
143 FutureCallback<HttpResponse> callback);
144
145 /**
146 * Initiates asynchronous HTTP request execution.
147 *
148 * @param request the request to execute
149 * @param callback future callback.
150 * @return future representing pending completion of the operation.
151 */
152 Future<HttpResponse> execute(
153 HttpUriRequest request,
154 FutureCallback<HttpResponse> callback);
155
156 }
0 /*
1 * ====================================================================
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 * ====================================================================
19 *
20 * This software consists of voluntary contributions made by many
21 * individuals on behalf of the Apache Software Foundation. For more
22 * information on the Apache Software Foundation, please see
23 * <http://www.apache.org/>.
24 *
25 */
26 package org.apache.http.nio.client;
27
28 import java.util.List;
29 import java.util.concurrent.Future;
30
31 import org.apache.http.HttpHost;
32 import org.apache.http.HttpRequest;
33 import org.apache.http.HttpResponse;
34 import org.apache.http.concurrent.FutureCallback;
35 import org.apache.http.nio.protocol.HttpAsyncRequestProducer;
36 import org.apache.http.nio.protocol.HttpAsyncResponseConsumer;
37 import org.apache.http.protocol.HttpContext;
38
39 /**
40 * This interface represents only the most basic contract for HTTP request
41 * execution. It imposes no restrictions or particular details on the request
42 * execution process and leaves the specifics of state management,
43 * authentication and redirect handling up to individual implementations.
44 *
45 * @since 4.1
46 */
47 public interface HttpPipeliningClient extends HttpAsyncClient {
48
49 /**
50 * Initiates pipelined execution of a sequence of requests.
51 * <p>
52 * The request producers passed to this method will be used to generate
53 * a request message and stream out its content without buffering it
54 * in memory. The response consumers passed to this method will be used
55 * to process a response message without buffering its content in memory.
56 * <p>
57 * Please note it may be unsafe to interact with the context instance
58 * while the request is still being executed.
59 *
60 * @param <T> the result type of request execution.
61 * @param target the target host for the request.
62 * @param requestProducers list of request producers.
63 * @param responseConsumers list of response consumers.
64 * @param context HTTP context
65 * @param callback future callback.
66 * @return future representing pending completion of the operation.
67 */
68 <T> Future<List<T>> execute(
69 HttpHost target,
70 List<? extends HttpAsyncRequestProducer> requestProducers,
71 List<? extends HttpAsyncResponseConsumer<T>> responseConsumers,
72 HttpContext context,
73 FutureCallback<List<T>> callback);
74
75 /**
76 * Initiates pipelined execution of a sequence of requests.
77 * <p>
78 * The request producers passed to this method will be used to generate
79 * a request message and stream out its content without buffering it
80 * in memory. The response consumers passed to this method will be used
81 * to process a response message without buffering its content in memory.
82 *
83 * @param <T> the result type of request execution.
84 * @param target the target host for the request.
85 * @param requestProducers list of request producers.
86 * @param responseConsumers list of response consumers.
87 * @param callback future callback.
88 * @return future representing pending completion of the operation.
89 */
90 <T> Future<List<T>> execute(
91 HttpHost target,
92 List<? extends HttpAsyncRequestProducer> requestProducers,
93 List<? extends HttpAsyncResponseConsumer<T>> responseConsumers,
94 FutureCallback<List<T>> callback);
95
96 /**
97 * Initiates pipelined execution of a sequence of requests against
98 * the given target using the given context.
99 * <p>
100 * Please note it may be unsafe to interact with the context instance
101 * while the request is still being executed.
102 *
103 * @param target the target host for the requests.
104 * Implementations may accept {@code null}
105 * if they can still determine a route, for example
106 * to a default target or by inspecting the request.
107 * @param requests the requests to execute
108 * @param context the context to use for the execution, or
109 * {@code null} to use the default context
110 * @param callback future callback.
111 * @return future representing pending completion of the operation.
112 */
113 Future<List<HttpResponse>> execute(
114 HttpHost target,
115 List<HttpRequest> requests,
116 HttpContext context,
117 FutureCallback<List<HttpResponse>> callback);
118
119 /**
120 * Initiates pipelined execution of a sequence of requests against
121 * the given target.
122 *
123 * @param target the target host for the requests.
124 * Implementations may accept {@code null}
125 * if they can still determine a route, for example
126 * to a default target or by inspecting the request.
127 * @param requests the requests to execute
128 * @param callback future callback.
129 * @return future representing pending completion of the operation.
130 */
131 Future<List<HttpResponse>> execute(
132 HttpHost target,
133 List<HttpRequest> requests,
134 FutureCallback<List<HttpResponse>> callback);
135
136 }
0 /*
1 * ====================================================================
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 * ====================================================================
19 *
20 * This software consists of voluntary contributions made by many
21 * individuals on behalf of the Apache Software Foundation. For more
22 * information on the Apache Software Foundation, please see
23 * <http://www.apache.org/>.
24 *
25 */
26 package org.apache.http.nio.client.methods;
27
28 import java.io.IOException;
29 import java.nio.ByteBuffer;
30
31 import org.apache.http.HttpEntity;
32 import org.apache.http.entity.ContentType;
33 import org.apache.http.nio.ContentDecoder;
34 import org.apache.http.nio.IOControl;
35 import org.apache.http.nio.protocol.AbstractAsyncResponseConsumer;
36 import org.apache.http.util.Asserts;
37
38 /**
39 * {@link org.apache.http.nio.protocol.HttpAsyncResponseConsumer} implementation that
40 * provides convenience methods for processing of binary content entities enclosed
41 * in an HTTP response.
42 *
43 * @since 4.0
44 */
45 public abstract class AsyncByteConsumer<T> extends AbstractAsyncResponseConsumer<T> {
46
47 private final ByteBuffer bbuf;
48
49 public AsyncByteConsumer(final int bufSize) {
50 super();
51 this.bbuf = ByteBuffer.allocate(bufSize);
52 }
53
54 public AsyncByteConsumer() {
55 this(8 * 1024);
56 }
57
58 /**
59 * Invoked to process a {@link ByteBuffer chunk} of content.
60 * The {@link IOControl} interface can be used to suspend input events
61 * if the consumer is temporarily unable to consume more content.
62 *
63 * @param buf chunk of content.
64 * @param ioctrl I/O control of the underlying connection.
65 * @throws IOException in case of an I/O error
66 */
67 protected abstract void onByteReceived(
68 ByteBuffer buf, IOControl ioctrl) throws IOException;
69
70 @Override
71 protected final void onEntityEnclosed(
72 final HttpEntity entity, final ContentType contentType) throws IOException {
73 }
74
75 @Override
76 protected final void onContentReceived(
77 final ContentDecoder decoder, final IOControl ioctrl) throws IOException {
78 Asserts.notNull(this.bbuf, "Byte buffer");
79 final int bytesRead = decoder.read(this.bbuf);
80 if (bytesRead <= 0) {
81 return;
82 }
83 this.bbuf.flip();
84 onByteReceived(this.bbuf, ioctrl);
85 this.bbuf.clear();
86 }
87
88 @Override
89 protected void releaseResources() {
90 }
91
92 }
0 /*
1 * ====================================================================
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 * ====================================================================
19 *
20 * This software consists of voluntary contributions made by many
21 * individuals on behalf of the Apache Software Foundation. For more
22 * information on the Apache Software Foundation, please see
23 * <http://www.apache.org/>.
24 *
25 */
26 package org.apache.http.nio.client.methods;
27
28 import java.io.IOException;
29 import java.nio.ByteBuffer;
30 import java.nio.CharBuffer;
31 import java.nio.charset.Charset;
32 import java.nio.charset.CharsetDecoder;
33 import java.nio.charset.CoderResult;
34
35 import org.apache.http.HttpEntity;
36 import org.apache.http.entity.ContentType;
37 import org.apache.http.nio.ContentDecoder;
38 import org.apache.http.nio.IOControl;
39 import org.apache.http.nio.protocol.AbstractAsyncResponseConsumer;
40 import org.apache.http.protocol.HTTP;
41 import org.apache.http.util.Asserts;
42
43 /**
44 * {@link org.apache.http.nio.protocol.HttpAsyncResponseConsumer} implementation that
45 * provides convenience methods for processing of textual content entities enclosed
46 * in an HTTP response.
47 *
48 * @since 4.0
49 */
50 public abstract class AsyncCharConsumer<T> extends AbstractAsyncResponseConsumer<T> {
51
52 private final ByteBuffer bbuf;
53 private final CharBuffer cbuf;
54
55 private CharsetDecoder chardecoder;
56
57 public AsyncCharConsumer(final int bufSize) {
58 super();
59 this.bbuf = ByteBuffer.allocate(bufSize);
60 this.cbuf = CharBuffer.allocate(bufSize);
61 }
62
63 public AsyncCharConsumer() {
64 this(8 * 1024);
65 }
66
67 /**
68 * Invoked to process a {@link CharBuffer chunk} of content.
69 * The {@link IOControl} interface can be used to suspend input events
70 * if the consumer is temporarily unable to consume more content.
71 *
72 * @param buf chunk of content.
73 * @param ioctrl I/O control of the underlying connection.
74 * @throws IOException in case of an I/O error
75 */
76 protected abstract void onCharReceived(
77 CharBuffer buf, IOControl ioctrl) throws IOException;
78
79 /**
80 * Invoked to create a @{link CharsetDecoder} for contentType.
81 * This allows to use different default charsets for different content
82 * types and set appropriate coding error actions.
83 *
84 * @param contentType response Content-Type or null if not specified.
85 * @return content decoder.
86 *
87 * @since 4.1
88 */
89 protected CharsetDecoder createDecoder(final ContentType contentType) {
90 Charset charset = contentType != null ? contentType.getCharset() : null;
91 if (charset == null) {
92 charset = HTTP.DEF_CONTENT_CHARSET;
93 }
94 return charset.newDecoder();
95 }
96
97 @Override
98 protected final void onEntityEnclosed(
99 final HttpEntity entity, final ContentType contentType) throws IOException {
100 this.chardecoder = createDecoder(contentType != null ? contentType : ContentType.DEFAULT_TEXT);
101 }
102
103 @Override
104 protected final void onContentReceived(
105 final ContentDecoder decoder, final IOControl ioctrl) throws IOException {
106 Asserts.notNull(this.bbuf, "Byte buffer");
107
108 final int bytesRead = decoder.read(this.bbuf);
109 if (bytesRead <= 0) {
110 return;
111 }
112 this.bbuf.flip();
113 final boolean completed = decoder.isCompleted();
114 CoderResult result = this.chardecoder.decode(this.bbuf, this.cbuf, completed);
115 handleDecodingResult(result, ioctrl);
116 this.bbuf.compact();
117 if (completed) {
118 result = this.chardecoder.flush(this.cbuf);
119 handleDecodingResult(result, ioctrl);
120 }
121 }
122
123 private void handleDecodingResult(
124 final CoderResult result, final IOControl ioctrl) throws IOException {
125 if (result.isError()) {
126 result.throwException();
127 }
128 this.cbuf.flip();
129 if (this.cbuf.hasRemaining()) {
130 onCharReceived(this.cbuf, ioctrl);
131 }
132 this.cbuf.clear();
133 }
134
135 @Override
136 protected void releaseResources() {
137 }
138
139 }
0 /*
1 * ====================================================================
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 * ====================================================================
19 *
20 * This software consists of voluntary contributions made by many
21 * individuals on behalf of the Apache Software Foundation. For more
22 * information on the Apache Software Foundation, please see
23 * <http://www.apache.org/>.
24 *
25 */
26 package org.apache.http.nio.client.methods;
27
28 import java.io.File;
29 import java.io.FileNotFoundException;
30 import java.io.IOException;
31 import java.io.RandomAccessFile;
32 import java.net.URI;
33 import java.nio.channels.FileChannel;
34
35 import org.apache.http.HttpEntity;
36 import org.apache.http.HttpEntityEnclosingRequest;
37 import org.apache.http.HttpException;
38 import org.apache.http.HttpHost;
39 import org.apache.http.HttpRequest;
40 import org.apache.http.client.utils.URIUtils;
41 import org.apache.http.entity.BasicHttpEntity;
42 import org.apache.http.entity.ContentType;
43 import org.apache.http.nio.ContentEncoder;
44 import org.apache.http.nio.ContentEncoderChannel;
45 import org.apache.http.nio.FileContentEncoder;
46 import org.apache.http.nio.IOControl;
47 import org.apache.http.nio.protocol.HttpAsyncRequestProducer;
48 import org.apache.http.protocol.HttpContext;
49 import org.apache.http.util.Args;
50
51 abstract class BaseZeroCopyRequestProducer implements HttpAsyncRequestProducer {
52
53 private final URI requestURI;
54 private final File file;
55 private final RandomAccessFile accessfile;
56 private final ContentType contentType;
57
58 private FileChannel fileChannel;
59 private long idx = -1;
60
61 protected BaseZeroCopyRequestProducer(
62 final URI requestURI,
63 final File file, final ContentType contentType) throws FileNotFoundException {
64 super();
65 Args.notNull(requestURI, "Request URI");
66 Args.notNull(file, "Source file");
67 this.requestURI = requestURI;
68 this.file = file;
69 this.accessfile = new RandomAccessFile(file, "r");
70 this.contentType = contentType;
71 }
72
73 private void closeChannel() throws IOException {
74 if (this.fileChannel != null) {
75 this.fileChannel.close();
76 this.fileChannel = null;
77 }
78 }
79
80 protected abstract HttpEntityEnclosingRequest createRequest(final URI requestURI, final HttpEntity entity);
81
82 @Override
83 public HttpRequest generateRequest() throws IOException, HttpException {
84 final BasicHttpEntity entity = new BasicHttpEntity();
85 entity.setChunked(false);
86 entity.setContentLength(this.file.length());
87 if (this.contentType != null) {
88 entity.setContentType(this.contentType.toString());
89 }
90 return createRequest(this.requestURI, entity);
91 }
92
93 @Override
94 public synchronized HttpHost getTarget() {
95 return URIUtils.extractHost(this.requestURI);
96 }
97
98 @Override
99 public synchronized void produceContent(
100 final ContentEncoder encoder, final IOControl ioctrl) throws IOException {
101 if (this.fileChannel == null) {
102 this.fileChannel = this.accessfile.getChannel();
103 this.idx = 0;
104 }
105 final long transferred;
106 if (encoder instanceof FileContentEncoder) {
107 transferred = ((FileContentEncoder)encoder).transfer(
108 this.fileChannel, this.idx, Integer.MAX_VALUE);
109 } else {
110 transferred = this.fileChannel.transferTo(
111 this.idx, Integer.MAX_VALUE, new ContentEncoderChannel(encoder));
112 }
113 if (transferred > 0) {
114 this.idx += transferred;
115 }
116
117 if (this.idx >= this.fileChannel.size()) {
118 encoder.complete();
119 closeChannel();
120 }
121 }
122
123 @Override
124 public void requestCompleted(final HttpContext context) {
125 }
126
127 @Override
128 public void failed(final Exception ex) {
129 }
130
131 @Override
132 public boolean isRepeatable() {
133 return true;
134 }
135
136 @Override
137 public synchronized void resetRequest() throws IOException {
138 closeChannel();
139 }
140
141 @Override
142 public synchronized void close() throws IOException {
143 try {
144 this.accessfile.close();
145 } catch (final IOException ignore) {
146 }
147 }
148
149 }
0 /*
1 * ====================================================================
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 * ====================================================================
19 *
20 * This software consists of voluntary contributions made by many
21 * individuals on behalf of the Apache Software Foundation. For more
22 * information on the Apache Software Foundation, please see
23 * <http://www.apache.org/>.
24 *
25 */
26 package org.apache.http.nio.client.methods;
27
28 import java.io.File;
29 import java.io.FileNotFoundException;
30 import java.io.UnsupportedEncodingException;
31 import java.net.URI;
32
33 import org.apache.http.HttpEntityEnclosingRequest;
34 import org.apache.http.HttpHost;
35 import org.apache.http.HttpRequest;
36 import org.apache.http.HttpResponse;
37 import org.apache.http.client.methods.HttpDelete;
38 import org.apache.http.client.methods.HttpGet;
39 import org.apache.http.client.methods.HttpOptions;
40 import org.apache.http.client.methods.HttpPost;
41 import org.apache.http.client.methods.HttpPut;
42 import org.apache.http.client.methods.HttpTrace;
43 import org.apache.http.client.methods.HttpUriRequest;
44 import org.apache.http.client.utils.URIUtils;
45 import org.apache.http.entity.ContentType;
46 import org.apache.http.nio.entity.HttpAsyncContentProducer;
47 import org.apache.http.nio.entity.NByteArrayEntity;
48 import org.apache.http.nio.entity.NStringEntity;
49 import org.apache.http.nio.protocol.BasicAsyncRequestProducer;
50 import org.apache.http.nio.protocol.BasicAsyncResponseConsumer;
51 import org.apache.http.nio.protocol.HttpAsyncRequestProducer;
52 import org.apache.http.nio.protocol.HttpAsyncResponseConsumer;
53 import org.apache.http.util.Args;
54
55 /**
56 * Factory methods for asynchronous request producers and response consumers.
57 *
58 * @since 4.0
59 */
60 public final class HttpAsyncMethods {
61
62 /**
63 * Creates asynchronous request generator for the given request message.
64 *
65 * @param target request target.
66 * @param request request message.
67 * @return asynchronous request generator
68 */
69 public static HttpAsyncRequestProducer create(final HttpHost target, final HttpRequest request) {
70 Args.notNull(target, "HTTP host");
71 Args.notNull(request, "HTTP request");
72 return new RequestProducerImpl(target, request);
73 }
74
75 /**
76 * Creates asynchronous request generator for the given request message.
77 *
78 * @param request request message.
79 * @return asynchronous request generator
80 */
81 public static HttpAsyncRequestProducer create(final HttpUriRequest request) {
82 Args.notNull(request, "HTTP request");
83 final HttpHost target = URIUtils.extractHost(request.getURI());
84 return new RequestProducerImpl(target, request);
85 }
86
87 /**
88 * Creates asynchronous {@code GET} request generator.
89 *
90 * @param requestURI request URI.
91 * @return asynchronous request generator
92 */
93 public static HttpAsyncRequestProducer createGet(final URI requestURI) {
94 return create(new HttpGet(requestURI));
95 }
96
97 /**
98 * Creates asynchronous {@code GET} request generator.
99 *
100 * @param requestURI request URI.
101 * @return asynchronous request generator
102 */
103 public static HttpAsyncRequestProducer createGet(final String requestURI) {
104 return create(new HttpGet(URI.create(requestURI)));
105 }
106
107 /**
108 * Creates asynchronous {@code HEAD} request generator.
109 *
110 * @param requestURI request URI.
111 * @return asynchronous request generator
112 */
113 public static HttpAsyncRequestProducer createHead(final URI requestURI) {
114 return create(new HttpGet(requestURI));
115 }
116
117 /**
118 * Creates asynchronous {@code HEAD} request generator.
119 *
120 * @param requestURI request URI.
121 * @return asynchronous request generator
122 */
123 public static HttpAsyncRequestProducer createHead(final String requestURI) {
124 return create(new HttpGet(URI.create(requestURI)));
125 }
126
127 /**
128 * Creates asynchronous {@code DELETE} request generator.
129 *
130 * @param requestURI request URI.
131 * @return asynchronous request generator
132 */
133 public static HttpAsyncRequestProducer createDelete(final URI requestURI) {
134 return create(new HttpDelete(requestURI));
135 }
136
137 /**
138 * Creates asynchronous {@code DELETE} request generator.
139 *
140 * @param requestURI request URI.
141 * @return asynchronous request generator
142 */
143 public static HttpAsyncRequestProducer createDelete(final String requestURI) {
144 return create(new HttpDelete(URI.create(requestURI)));
145 }
146
147 /**
148 * Creates asynchronous {@code OPTIONS} request generator.
149 *
150 * @param requestURI request URI.
151 * @return asynchronous request generator
152 */
153 public static HttpAsyncRequestProducer createOptions(final URI requestURI) {
154 return create(new HttpOptions(requestURI));
155 }
156
157 /**
158 * Creates asynchronous {@code OPTIONS} request generator.
159 *
160 * @param requestURI request URI.
161 * @return asynchronous request generator
162 */
163 public static HttpAsyncRequestProducer createOptions(final String requestURI) {
164 return create(new HttpOptions(URI.create(requestURI)));
165 }
166
167 /**
168 * Creates asynchronous {@code TRACE} request generator.
169 *
170 * @param requestURI request URI.
171 * @return asynchronous request generator
172 */
173 public static HttpAsyncRequestProducer createTrace(final URI requestURI) {
174 return create(new HttpTrace(requestURI));
175 }
176
177 /**
178 * Creates asynchronous {@code TRACE} request generator.
179 *
180 * @param requestURI request URI.
181 * @return asynchronous request generator
182 */
183 public static HttpAsyncRequestProducer createTrace(final String requestURI) {
184 return create(new HttpTrace(URI.create(requestURI)));
185 }
186
187 /**
188 * Creates asynchronous {@code POST} request generator.
189 *
190 * @param requestURI request URI.
191 * @param content request content.
192 * @param contentType request contentType.
193 * @return asynchronous request generator
194 */
195 public static HttpAsyncRequestProducer createPost(
196 final URI requestURI,
197 final String content,
198 final ContentType contentType) throws UnsupportedEncodingException {
199 final HttpPost httppost = new HttpPost(requestURI);
200 final NStringEntity entity = new NStringEntity(content, contentType);
201 httppost.setEntity(entity);
202 final HttpHost target = URIUtils.extractHost(requestURI);
203 return new RequestProducerImpl(target, httppost, entity);
204 }
205
206 /**
207 * Creates asynchronous {@code POST} request generator.
208 *
209 * @param requestURI request URI.
210 * @param content request content.
211 * @param contentType request contentType.
212 * @return asynchronous request generator
213 */
214 public static HttpAsyncRequestProducer createPost(
215 final String requestURI,
216 final String content,
217 final ContentType contentType) throws UnsupportedEncodingException {
218 return createPost(URI.create(requestURI), content, contentType);
219 }
220
221 /**
222 * Creates asynchronous {@code POST} request generator.
223 *
224 * @param requestURI request URI.
225 * @param content request content.
226 * @param contentType request contentType.
227 * @return asynchronous request generator
228 */
229 public static HttpAsyncRequestProducer createPost(
230 final URI requestURI,
231 final byte[] content,
232 final ContentType contentType) {
233 final HttpPost httppost = new HttpPost(requestURI);
234 final NByteArrayEntity entity = new NByteArrayEntity(content, contentType);
235 final HttpHost target = URIUtils.extractHost(requestURI);
236 return new RequestProducerImpl(target, httppost, entity);
237 }
238
239 /**
240 * Creates asynchronous {@code POST} request generator.
241 *
242 * @param requestURI request URI.
243 * @param content request content.
244 * @param contentType request contentType.
245 * @return asynchronous request generator
246 */
247 public static HttpAsyncRequestProducer createPost(
248 final String requestURI,
249 final byte[] content,
250 final ContentType contentType) {
251 return createPost(URI.create(requestURI), content, contentType);
252 }
253
254 /**
255 * Creates asynchronous {@code PUT} request generator.
256 *
257 * @param requestURI request URI.
258 * @param content request content.
259 * @param contentType request contentType.
260 * @return asynchronous request generator
261 */
262 public static HttpAsyncRequestProducer createPut(
263 final URI requestURI,
264 final String content,
265 final ContentType contentType) throws UnsupportedEncodingException {
266 final HttpPut httpput = new HttpPut(requestURI);
267 final NStringEntity entity = new NStringEntity(content, contentType);
268 httpput.setEntity(entity);
269 final HttpHost target = URIUtils.extractHost(requestURI);
270 return new RequestProducerImpl(target, httpput, entity);
271 }
272
273 /**
274 * Creates asynchronous {@code PUT} request generator.
275 *
276 * @param requestURI request URI.
277 * @param content request content.
278 * @param contentType request contentType.
279 * @return asynchronous request generator
280 */
281 public static HttpAsyncRequestProducer createPut(
282 final String requestURI,
283 final String content,
284 final ContentType contentType) throws UnsupportedEncodingException {
285 return createPut(URI.create(requestURI), content, contentType);
286 }
287
288 /**
289 * Creates asynchronous {@code PUT} request generator.
290 *
291 * @param requestURI request URI.
292 * @param content request content.
293 * @param contentType request contentType.
294 * @return asynchronous request generator
295 */
296 public static HttpAsyncRequestProducer createPut(
297 final URI requestURI,
298 final byte[] content,
299 final ContentType contentType) {
300 final HttpPut httpput = new HttpPut(requestURI);
301 final NByteArrayEntity entity = new NByteArrayEntity(content, contentType);
302 final HttpHost target = URIUtils.extractHost(requestURI);
303 return new RequestProducerImpl(target, httpput, entity);
304 }
305
306 /**
307 * Creates asynchronous {@code PUT} request generator.
308 *
309 * @param requestURI request URI.
310 * @param content request content.
311 * @param contentType request contentType.
312 * @return asynchronous request generator
313 */
314 public static HttpAsyncRequestProducer createPut(
315 final String requestURI,
316 final byte[] content,
317 final ContentType contentType) {
318 return createPut(URI.create(requestURI), content, contentType);
319 }
320
321 /**
322 * Creates asynchronous zero-copy {@code POST} request generator.
323 *
324 * @param requestURI request URI.
325 * @param content request content.
326 * @param contentType request contentType.
327 * @return asynchronous request generator
328 */
329 public static HttpAsyncRequestProducer createZeroCopyPost(
330 final URI requestURI,
331 final File content,
332 final ContentType contentType) throws FileNotFoundException {
333 return new ZeroCopyPost(requestURI, content, contentType);
334 }
335
336 /**
337 * Creates asynchronous zero-copy {@code POST} request generator.
338 *
339 * @param requestURI request URI.
340 * @param content request content.
341 * @param contentType request contentType.
342 * @return asynchronous request generator
343 */
344 public static HttpAsyncRequestProducer createZeroCopyPost(
345 final String requestURI,
346 final File content,
347 final ContentType contentType) throws FileNotFoundException {
348 return new ZeroCopyPost(URI.create(requestURI), content, contentType);
349 }
350
351 /**
352 * Creates asynchronous zero-copy {@code PUT} request generator.
353 *
354 * @param requestURI request URI.
355 * @param content request content.
356 * @param contentType request contentType.
357 * @return asynchronous request generator
358 */
359 public static HttpAsyncRequestProducer createZeroCopyPut(
360 final URI requestURI,
361 final File content,
362 final ContentType contentType) throws FileNotFoundException {
363 return new ZeroCopyPut(requestURI, content, contentType);
364 }
365
366 /**
367 * Creates asynchronous zero-copy {@code PUT} request generator.
368 *
369 * @param requestURI request URI.
370 * @param content request content.
371 * @param contentType request contentType.
372 * @return asynchronous request generator
373 */
374 public static HttpAsyncRequestProducer createZeroCopyPut(
375 final String requestURI,
376 final File content,
377 final ContentType contentType) throws FileNotFoundException {
378 return new ZeroCopyPut(URI.create(requestURI), content, contentType);
379 }
380
381 /**
382 * Creates basic response consumer that will buffer response content in memory.
383 * @return asynchronous response consumer.
384 */
385 public static HttpAsyncResponseConsumer<HttpResponse> createConsumer() {
386 return new BasicAsyncResponseConsumer();
387 }
388
389 /**
390 * Creates zero-copy response consumer that will stream response content
391 * directly to the given file.
392 * @return asynchronous response consumer.
393 */
394 public static HttpAsyncResponseConsumer<HttpResponse> createZeroCopyConsumer(
395 final File file) throws FileNotFoundException {
396 return new ZeroCopyConsumer<HttpResponse>(file) {
397
398 @Override
399 protected HttpResponse process(
400 final HttpResponse response,
401 final File file,
402 final ContentType contentType) {
403 return response;
404 }
405
406 };
407 }
408
409 static class RequestProducerImpl extends BasicAsyncRequestProducer {
410
411 protected RequestProducerImpl(
412 final HttpHost target,
413 final HttpEntityEnclosingRequest request,
414 final HttpAsyncContentProducer producer) {
415 super(target, request, producer);
416 }
417
418 public RequestProducerImpl(final HttpHost target, final HttpRequest request) {
419 super(target, request);
420 }
421
422 }
423
424 }
0 /*
1 * ====================================================================
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 * ====================================================================
19 *
20 * This software consists of voluntary contributions made by many
21 * individuals on behalf of the Apache Software Foundation. For more
22 * information on the Apache Software Foundation, please see
23 * <http://www.apache.org/>.
24 *
25 */
26 package org.apache.http.nio.client.methods;
27
28 import java.io.File;
29 import java.io.FileNotFoundException;
30 import java.io.IOException;
31 import java.io.RandomAccessFile;
32 import java.nio.channels.FileChannel;
33
34 import org.apache.http.Header;
35 import org.apache.http.HttpEntity;
36 import org.apache.http.HttpResponse;
37 import org.apache.http.entity.ContentType;
38 import org.apache.http.entity.FileEntity;
39 import org.apache.http.nio.ContentDecoder;
40 import org.apache.http.nio.ContentDecoderChannel;
41 import org.apache.http.nio.FileContentDecoder;
42 import org.apache.http.nio.IOControl;
43 import org.apache.http.nio.protocol.AbstractAsyncResponseConsumer;
44 import org.apache.http.protocol.HttpContext;
45 import org.apache.http.util.Asserts;
46
47 /**
48 * {@link org.apache.http.nio.protocol.HttpAsyncResponseConsumer} implementation that
49 * streams content entity enclosed in an HTTP response directly into a file
50 * without an intermediate in-memory buffer.
51 * <p>
52 * This consumer can be useful for file downloads.
53 *
54 * @since 4.0
55 */
56 public abstract class ZeroCopyConsumer<T> extends AbstractAsyncResponseConsumer<T> {
57
58 private final File file;
59 private final RandomAccessFile accessfile;
60
61 private HttpResponse response;
62 private ContentType contentType;
63 private Header contentEncoding;
64 private FileChannel fileChannel;
65 private long idx = -1;
66
67 public ZeroCopyConsumer(final File file) throws FileNotFoundException {
68 super();
69 if (file == null) {
70 throw new IllegalArgumentException("File may nor be null");
71 }
72 this.file = file;
73 this.accessfile = new RandomAccessFile(this.file, "rw");
74 }
75
76 @Override
77 protected void onResponseReceived(final HttpResponse response) {
78 this.response = response;
79 }
80
81 @Override
82 protected void onEntityEnclosed(
83 final HttpEntity entity, final ContentType contentType) throws IOException {
84 this.contentType = contentType;
85 this.contentEncoding = entity.getContentEncoding();
86 this.fileChannel = this.accessfile.getChannel();
87 this.idx = 0;
88 }
89
90 @Override
91 protected void onContentReceived(
92 final ContentDecoder decoder, final IOControl ioctrl) throws IOException {
93 Asserts.notNull(this.fileChannel, "File channel");
94 final long transferred;
95 if (decoder instanceof FileContentDecoder) {
96 transferred = ((FileContentDecoder)decoder).transfer(
97 this.fileChannel, this.idx, Integer.MAX_VALUE);
98 } else {
99 transferred = this.fileChannel.transferFrom(
100 new ContentDecoderChannel(decoder), this.idx, Integer.MAX_VALUE);
101 }
102 if (transferred > 0) {
103 this.idx += transferred;
104 }
105 if (decoder.isCompleted()) {
106 this.fileChannel.close();
107 }
108 }
109
110 /**
111 * Invoked to process received file.
112 *
113 * @param response original response head.
114 * @param file file containing response content.
115 * @param contentType the cotnent type.
116 * @return result of the response processing
117 */
118 protected abstract T process(
119 HttpResponse response, File file, ContentType contentType) throws Exception;
120
121 @Override
122 protected T buildResult(final HttpContext context) throws Exception {
123 final FileEntity entity = new FileEntity(this.file, this.contentType);
124 entity.setContentEncoding(this.contentEncoding);
125 this.response.setEntity(entity);
126 return process(this.response, this.file, this.contentType);
127 }
128
129 @Override
130 protected void releaseResources() {
131 try {
132 this.accessfile.close();
133 } catch (final IOException ignore) {
134 }
135 }
136
137 }
0 /*
1 * ====================================================================
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 * ====================================================================
19 *
20 * This software consists of voluntary contributions made by many
21 * individuals on behalf of the Apache Software Foundation. For more
22 * information on the Apache Software Foundation, please see
23 * <http://www.apache.org/>.
24 *
25 */
26 package org.apache.http.nio.client.methods;
27
28 import java.io.File;
29 import java.io.FileNotFoundException;
30 import java.net.URI;
31
32 import org.apache.http.HttpEntity;
33 import org.apache.http.HttpEntityEnclosingRequest;
34 import org.apache.http.client.methods.HttpPost;
35 import org.apache.http.entity.ContentType;
36
37 /**
38 * {@link org.apache.http.nio.protocol.HttpAsyncRequestProducer} implementation
39 * that generates an HTTP {@code POST} request enclosing content of a file.
40 * The request content will be streamed out directly from the underlying file
41 * without an intermediate in-memory buffer.
42 *
43 * @since 4.0
44 */
45 public class ZeroCopyPost extends BaseZeroCopyRequestProducer {
46
47 public ZeroCopyPost(
48 final URI requestURI,
49 final File content,
50 final ContentType contentType) throws FileNotFoundException {
51 super(requestURI, content, contentType);
52 }
53
54 public ZeroCopyPost(
55 final String requestURI,
56 final File content,
57 final ContentType contentType) throws FileNotFoundException {
58 super(URI.create(requestURI), content, contentType);
59 }
60
61 @Override
62 protected HttpEntityEnclosingRequest createRequest(final URI requestURI, final HttpEntity entity) {
63 final HttpPost httppost = new HttpPost(requestURI);
64 httppost.setEntity(entity);
65 return httppost;
66 }
67
68 }
0 /*
1 * ====================================================================
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 * ====================================================================
19 *
20 * This software consists of voluntary contributions made by many
21 * individuals on behalf of the Apache Software Foundation. For more
22 * information on the Apache Software Foundation, please see
23 * <http://www.apache.org/>.
24 *
25 */
26 package org.apache.http.nio.client.methods;
27
28 import java.io.File;
29 import java.io.FileNotFoundException;
30 import java.net.URI;
31
32 import org.apache.http.HttpEntity;
33 import org.apache.http.HttpEntityEnclosingRequest;
34 import org.apache.http.client.methods.HttpPut;
35 import org.apache.http.entity.ContentType;
36
37 /**
38 * {@link org.apache.http.nio.protocol.HttpAsyncRequestProducer} implementation
39 * that generates an HTTP {@code PUT} request enclosing content of a file.
40 * The request content will be streamed out directly from the underlying file
41 * without an intermediate in-memory buffer.
42 *
43 * @since 4.0
44 */
45 public class ZeroCopyPut extends BaseZeroCopyRequestProducer {
46
47 public ZeroCopyPut(
48 final URI requestURI,
49 final File content,
50 final ContentType contentType) throws FileNotFoundException {
51 super(requestURI, content, contentType);
52 }
53
54 public ZeroCopyPut(
55 final String requestURI,
56 final File content,
57 final ContentType contentType) throws FileNotFoundException {
58 super(URI.create(requestURI), content, contentType);
59 }
60
61 @Override
62 protected HttpEntityEnclosingRequest createRequest(final URI requestURI, final HttpEntity entity) {
63 final HttpPut httpput = new HttpPut(requestURI);
64 httpput.setEntity(entity);
65 return httpput;
66 }
67
68 }
0 /*
1 * ====================================================================
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 * ====================================================================
19 *
20 * This software consists of voluntary contributions made by many
21 * individuals on behalf of the Apache Software Foundation. For more
22 * information on the Apache Software Foundation, please see
23 * <http://www.apache.org/>.
24 *
25 */
26
27 /**
28 * Asynchronous HTTP method implementations.
29 */
30 package org.apache.http.nio.client.methods;
0 /*
1 * ====================================================================
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 * ====================================================================
19 *
20 * This software consists of voluntary contributions made by many
21 * individuals on behalf of the Apache Software Foundation. For more
22 * information on the Apache Software Foundation, please see
23 * <http://www.apache.org/>.
24 *
25 */
26
27 /**
28 * Asynchronous HTTP client communication APIs.
29 */
30 package org.apache.http.nio.client;
0 /*
1 * ====================================================================
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 * ====================================================================
19 *
20 * This software consists of voluntary contributions made by many
21 * individuals on behalf of the Apache Software Foundation. For more
22 * information on the Apache Software Foundation, please see
23 * <http://www.apache.org/>.
24 *
25 */
26 package org.apache.http.nio.client.util;
27
28 import java.io.IOException;
29
30 import org.apache.http.impl.nio.client.CloseableHttpAsyncClient;
31
32 /**
33 * Static helpers for dealing with {@link org.apache.http.nio.client.HttpAsyncClient}.
34 */
35 public class HttpAsyncClientUtils {
36
37 private HttpAsyncClientUtils() {
38 }
39
40 /**
41 * Unconditionally close a httpAsyncClient. Shuts down the underlying
42 * connection manager and releases the resources.
43 * <p>
44 * Example Code:
45 *
46 * <pre>
47 * HttpAsyncClient httpAsyncClient = null;
48 * try {
49 * httpAsyncClient = ...;
50 * } catch (Exception e) {
51 * // error handling
52 * } finally {
53 * HttpAsyncClientUtils.closeQuietly(httpAsyncClient);
54 * }
55 * </pre>
56 *
57 * @param httpAsyncClient
58 * the HttpAsyncClient to close, may be null or already closed.
59 */
60 public static void closeQuietly(final CloseableHttpAsyncClient httpAsyncClient) {
61 if (httpAsyncClient != null) {
62 try {
63 httpAsyncClient.close();
64 } catch (final IOException ignore) {
65 }
66 }
67 }
68
69 }
0 /*
1 * ====================================================================
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 * ====================================================================
19 *
20 * This software consists of voluntary contributions made by many
21 * individuals on behalf of the Apache Software Foundation. For more
22 * information on the Apache Software Foundation, please see
23 * <http://www.apache.org/>.
24 *
25 */
26
27 /**
28 * Asynchronous client utility classes.
29 */
30 package org.apache.http.nio.client.util;
0 /*
1 * ====================================================================
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 * ====================================================================
19 *
20 * This software consists of voluntary contributions made by many
21 * individuals on behalf of the Apache Software Foundation. For more
22 * information on the Apache Software Foundation, please see
23 * <http://www.apache.org/>.
24 *
25 */
26 package org.apache.http.nio.conn;
27
28 import javax.net.ssl.SSLSession;
29
30 import org.apache.http.HttpInetConnection;
31 import org.apache.http.nio.NHttpClientConnection;
32 import org.apache.http.nio.reactor.IOSession;
33
34 /**
35 * Represents a managed connection whose state and life cycle is managed by
36 * a connection manager. This interface extends {@link NHttpClientConnection}
37 * with methods to bind the connection to an arbitrary {@link IOSession} and
38 * to obtain SSL session details.
39 *
40 * @since 4.0
41 */
42 public interface ManagedNHttpClientConnection extends NHttpClientConnection, HttpInetConnection {
43
44 /**
45 * Returns connection ID which is expected to be unique
46 * for the life span of the connection manager.
47 */
48 String getId();
49
50 /**
51 * Binds connection to the given I/O session.
52 */
53 void bind(IOSession iosession);
54
55 /**
56 * Returns the underlying I/O session.
57 */
58 IOSession getIOSession();
59
60 /**
61 * Obtains the SSL session of the underlying connection, if any.
62 *
63 * @return the underlying SSL session if available,
64 * {@code null} otherwise
65 */
66 SSLSession getSSLSession();
67
68 }
0 /*
1 * ====================================================================
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 * ====================================================================
19 *
20 * This software consists of voluntary contributions made by many
21 * individuals on behalf of the Apache Software Foundation. For more
22 * information on the Apache Software Foundation, please see
23 * <http://www.apache.org/>.
24 *
25 */
26 package org.apache.http.nio.conn;
27
28 import java.io.IOException;
29 import java.util.concurrent.Future;
30 import java.util.concurrent.TimeUnit;
31
32 import org.apache.http.concurrent.FutureCallback;
33 import org.apache.http.conn.routing.HttpRoute;
34 import org.apache.http.nio.NHttpClientConnection;
35 import org.apache.http.nio.reactor.IOEventDispatch;
36 import org.apache.http.protocol.HttpContext;
37
38 /**
39 * Represents a manager of persistent client connections.
40 * <p>
41 * The purpose of an HTTP connection manager is to serve as a factory for new
42 * HTTP connections, manage persistent connections and synchronize access to
43 * persistent connections making sure that only one thread of execution can
44 * have access to a connection at a time.
45 * <p>
46 * Implementations of this interface must be thread-safe. Access to shared
47 * data must be synchronized as methods of this interface may be executed
48 * from multiple threads.
49 *
50 * @since 4.0
51 */
52 public interface NHttpClientConnectionManager {
53
54 /**
55 * Returns a {@link Future} for a {@link NHttpClientConnection}.
56 * <p>
57 * Please note that the consumer of that connection is responsible
58 * for fully establishing the route the to the connection target
59 * by calling {@link #startRoute(org.apache.http.nio.NHttpClientConnection,
60 * org.apache.http.conn.routing.HttpRoute,
61 * org.apache.http.protocol.HttpContext) startRoute} in order to start
62 * the process of connection initialization, optionally calling
63 * {@link #upgrade(org.apache.http.nio.NHttpClientConnection,
64 * org.apache.http.conn.routing.HttpRoute,
65 * org.apache.http.protocol.HttpContext) upgrade} method to upgrade
66 * the connection after having executed {@code CONNECT} method to
67 * all intermediate proxy hops and and finally calling
68 * {@link #routeComplete(org.apache.http.nio.NHttpClientConnection,
69 * org.apache.http.conn.routing.HttpRoute,
70 * org.apache.http.protocol.HttpContext) routeComplete} to mark the route
71 * as fully completed.
72 *
73 * @param route HTTP route of the requested connection.
74 * @param state expected state of the connection or {@code null}
75 * if the connection is not expected to carry any state.
76 * @param connectTimeout connect timeout.
77 * @param connectionRequestTimeout connection request timeout.
78 * @param timeUnit time unit of the previous two timeout values.
79 * @param callback future callback.
80 */
81 Future<NHttpClientConnection> requestConnection(
82 HttpRoute route,
83 Object state,
84 long connectTimeout,
85 long connectionRequestTimeout,
86 TimeUnit timeUnit,
87 FutureCallback<NHttpClientConnection> callback);
88
89 /**
90 * Releases the connection back to the manager making it potentially
91 * re-usable by other consumers. Optionally, the maximum period
92 * of how long the manager should keep the connection alive can be
93 * defined using {@code validDuration} and {@code timeUnit}
94 * parameters.
95 *
96 * @param conn the managed connection to release.
97 * @param validDuration the duration of time this connection is valid for reuse.
98 * @param timeUnit the time unit.
99 *
100 * @see #closeExpiredConnections()
101 */
102 void releaseConnection(
103 NHttpClientConnection conn, Object newState, long validDuration, TimeUnit timeUnit);
104
105 /**
106 * Starts the process of connection initialization. Connection route may consist of several
107 * intermediate hops and may require a protocol upgrade. Once the route is fully established
108 * the {@link #routeComplete(org.apache.http.nio.NHttpClientConnection,
109 * org.apache.http.conn.routing.HttpRoute,
110 * org.apache.http.protocol.HttpContext) routeComplete} method must be called.
111 *
112 * @param conn the managed connection to initialize.
113 * @param route the connection route.
114 * @param context the context
115 */
116 void startRoute(
117 NHttpClientConnection conn,
118 HttpRoute route,
119 HttpContext context) throws IOException;
120
121 /**
122 * Upgrades the underlying connection I/O session to TLS/SSL (or another layering
123 * protocol) after having executed {@code CONNECT} method to all
124 * intermediate proxy hops.
125 *
126 * @param conn the managed connection to upgrade.
127 * @param route the connection route.
128 * @param context the context
129 */
130 void upgrade(
131 NHttpClientConnection conn,
132 HttpRoute route,
133 HttpContext context) throws IOException;
134
135 /**
136 * Marks the connection as fully established with all its intermediate
137 * hops completed.
138 *
139 * @param conn the managed connection to mark as route complete.
140 * @param route the connection route.
141 * @param context the context
142 */
143 void routeComplete(
144 NHttpClientConnection conn,
145 HttpRoute route,
146 HttpContext context);
147
148 /**
149 * Determines if the given connection has been fully established and
150 * marked as route complete.
151 *
152 * @param conn the managed connection.
153 */
154 boolean isRouteComplete(NHttpClientConnection conn);
155
156 /**
157 * Closes idle connections in the pool.
158 * <p>
159 * Open connections in the pool that have not been used for the
160 * timespan given by the argument will be closed.
161 * Currently allocated connections are not subject to this method.
162 * Times will be checked with milliseconds precision
163 *
164 * All expired connections will also be closed.
165 *
166 * @param idletime the idle time of connections to be closed
167 * @param tunit the unit for the {@code idletime}
168 *
169 * @see #closeExpiredConnections()
170 */
171 void closeIdleConnections(long idletime, TimeUnit tunit);
172
173 /**
174 * Closes all expired connections in the pool.
175 * <p>
176 * Open connections in the pool that have not been used for
177 * the timespan defined when the connection was released will be closed.
178 * Currently allocated connections are not subject to this method.
179 * Times will be checked with milliseconds precision.
180 */
181 void closeExpiredConnections();
182
183 /**
184 * Starts the underlying I/O reactor and initiates the dispatch of
185 * I/O event notifications to the given {@link IOEventDispatch}.
186 */
187 void execute(IOEventDispatch eventDispatch) throws IOException;
188
189 /**
190 * Shuts down this connection manager and releases allocated resources.
191 * This includes closing all connections, whether they are currently
192 * used or not.
193 */
194 void shutdown() throws IOException;
195
196 }
0 /*
1 * ====================================================================
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 * ====================================================================
19 *
20 * This software consists of voluntary contributions made by many
21 * individuals on behalf of the Apache Software Foundation. For more
22 * information on the Apache Software Foundation, please see
23 * <http://www.apache.org/>.
24 *
25 */
26 package org.apache.http.nio.conn;
27
28 import org.apache.http.config.ConnectionConfig;
29 import org.apache.http.nio.NHttpConnection;
30 import org.apache.http.nio.reactor.IOSession;
31
32 /**
33 * Generic {@link NHttpConnection} factory.
34 *
35 * @since 4.0
36 */
37 public interface NHttpConnectionFactory<T extends NHttpConnection> {
38
39 T create(IOSession iosession, ConnectionConfig config);
40
41 }
0 /*
1 * ====================================================================
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 * ====================================================================
19 *
20 * This software consists of voluntary contributions made by many
21 * individuals on behalf of the Apache Software Foundation. For more
22 * information on the Apache Software Foundation, please see
23 * <http://www.apache.org/>.
24 *
25 */
26 package org.apache.http.nio.conn;
27
28 import org.apache.http.HttpHost;
29 import org.apache.http.nio.reactor.IOSession;
30
31 /**
32 * Noop implementation for protocol schemes that have no transport level
33 * security.
34 *
35 * @since 4.0
36 */
37 public class NoopIOSessionStrategy implements SchemeIOSessionStrategy {
38
39 public static final NoopIOSessionStrategy INSTANCE = new NoopIOSessionStrategy();
40
41 @Override
42 public IOSession upgrade(final HttpHost host, final IOSession iosession) {
43 return iosession;
44 }
45
46 @Override
47 public boolean isLayeringRequired() {
48 return false;
49 }
50
51 }
0 /*
1 * ====================================================================
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 * ====================================================================
19 *
20 * This software consists of voluntary contributions made by many
21 * individuals on behalf of the Apache Software Foundation. For more
22 * information on the Apache Software Foundation, please see
23 * <http://www.apache.org/>.
24 *
25 */
26 package org.apache.http.nio.conn;
27
28 import org.apache.http.HttpHost;
29 import org.apache.http.nio.reactor.IOSession;
30
31 import java.io.IOException;
32
33 /**
34 * I/O session layering strategy for complex protocol schemes, which employ
35 * a transport level security protocol to secure HTTP communication
36 * (in other words those schemes 'layer' HTTP on top of a transport level
37 * protocol such as TLS/SSL).
38 *
39 * @since 4.0
40 */
41 public interface SchemeIOSessionStrategy {
42
43 /**
44 * Determines whether or not protocol layering is required. If this method
45 * returns {@code false} the {@link #upgrade(org.apache.http.HttpHost,
46 * org.apache.http.nio.reactor.IOSession) upgrade} method is expected
47 * to have no effect and should not be called.
48 */
49 boolean isLayeringRequired();
50
51 /**
52 * Decorates the original {@link IOSession} with a transport level security
53 * protocol implementation.
54 * @param host the target host.
55 * @param iosession the I/O session.
56 * @return upgraded I/O session.
57 */
58 IOSession upgrade(HttpHost host, IOSession iosession) throws IOException;
59
60 }
0 /*
1 * ====================================================================
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 * ====================================================================
19 *
20 * This software consists of voluntary contributions made by many
21 * individuals on behalf of the Apache Software Foundation. For more
22 * information on the Apache Software Foundation, please see
23 * <http://www.apache.org/>.
24 *
25 */
26
27 /**
28 * Asynchronous client connection management APIs.
29 */
30 package org.apache.http.nio.conn;
0 /*
1 * ====================================================================
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 * ====================================================================
19 *
20 * This software consists of voluntary contributions made by many
21 * individuals on behalf of the Apache Software Foundation. For more
22 * information on the Apache Software Foundation, please see
23 * <http://www.apache.org/>.
24 *
25 */
26
27 package org.apache.http.nio.conn.ssl;
28
29 import java.io.IOException;
30 import java.security.cert.Certificate;
31 import java.security.cert.X509Certificate;
32
33 import javax.net.ssl.HostnameVerifier;
34 import javax.net.ssl.SSLContext;
35 import javax.net.ssl.SSLEngine;
36 import javax.net.ssl.SSLException;
37 import javax.net.ssl.SSLPeerUnverifiedException;
38 import javax.net.ssl.SSLSession;
39 import javax.security.auth.x500.X500Principal;
40
41 import org.apache.http.HttpHost;
42 import org.apache.http.conn.ssl.AllowAllHostnameVerifier;
43 import org.apache.http.conn.ssl.BrowserCompatHostnameVerifier;
44 import org.apache.http.conn.ssl.DefaultHostnameVerifier;
45 import org.apache.http.conn.ssl.StrictHostnameVerifier;
46 import org.apache.http.conn.ssl.X509HostnameVerifier;
47 import org.apache.http.conn.util.PublicSuffixMatcherLoader;
48 import org.apache.http.nio.conn.SchemeIOSessionStrategy;
49 import org.apache.http.nio.reactor.IOSession;
50 import org.apache.http.nio.reactor.ssl.SSLIOSession;
51 import org.apache.http.nio.reactor.ssl.SSLMode;
52 import org.apache.http.nio.reactor.ssl.SSLSetupHandler;
53 import org.apache.http.ssl.SSLContexts;
54 import org.apache.http.util.Args;
55 import org.apache.http.util.Asserts;
56 import org.apache.http.util.TextUtils;
57
58 /**
59 * TLS/SSL transport level security strategy.
60 *
61 * @since 4.0
62 */
63 public class SSLIOSessionStrategy implements SchemeIOSessionStrategy {
64
65 @Deprecated
66 public static final X509HostnameVerifier ALLOW_ALL_HOSTNAME_VERIFIER =
67 new AllowAllHostnameVerifier();
68
69 @Deprecated
70 public static final X509HostnameVerifier BROWSER_COMPATIBLE_HOSTNAME_VERIFIER =
71 new BrowserCompatHostnameVerifier();
72
73 @Deprecated
74 public static final X509HostnameVerifier STRICT_HOSTNAME_VERIFIER =
75 new StrictHostnameVerifier();
76
77 private static String[] split(final String s) {
78 if (TextUtils.isBlank(s)) {
79 return null;
80 }
81 return s.split(" *, *");
82 }
83
84 /**
85 * @since 4.1
86 */
87 public static HostnameVerifier getDefaultHostnameVerifier() {
88 return new DefaultHostnameVerifier(PublicSuffixMatcherLoader.getDefault());
89 }
90
91 public static SSLIOSessionStrategy getDefaultStrategy() {
92 return new SSLIOSessionStrategy(
93 SSLContexts.createDefault(),
94 getDefaultHostnameVerifier());
95 }
96
97 public static SSLIOSessionStrategy getSystemDefaultStrategy() {
98 return new SSLIOSessionStrategy(
99 SSLContexts.createSystemDefault(),
100 split(System.getProperty("https.protocols")),
101 split(System.getProperty("https.cipherSuites")),
102 getDefaultHostnameVerifier());
103 }
104
105 private final SSLContext sslContext;
106 private final String[] supportedProtocols;
107 private final String[] supportedCipherSuites;
108 private final HostnameVerifier hostnameVerifier;
109
110 /**
111 * @deprecated (4.1) use {@link SSLIOSessionStrategy#SSLIOSessionStrategy(
112 * javax.net.ssl.SSLContext, String[], String[], javax.net.ssl.HostnameVerifier)}
113 */
114 @Deprecated
115 public SSLIOSessionStrategy(
116 final SSLContext sslContext,
117 final String[] supportedProtocols,
118 final String[] supportedCipherSuites,
119 final X509HostnameVerifier hostnameVerifier) {
120 this(sslContext, supportedProtocols, supportedCipherSuites, (HostnameVerifier) hostnameVerifier);
121 }
122
123 /**
124 * @deprecated (4.1)
125 */
126 @Deprecated
127 public SSLIOSessionStrategy(
128 final SSLContext sslcontext,
129 final X509HostnameVerifier hostnameVerifier) {
130 this(sslcontext, null, null, (HostnameVerifier) hostnameVerifier);
131 }
132
133 /**
134 * @since 4.1
135 */
136 public SSLIOSessionStrategy(
137 final SSLContext sslContext,
138 final String[] supportedProtocols,
139 final String[] supportedCipherSuites,
140 final HostnameVerifier hostnameVerifier) {
141 super();
142 this.sslContext = Args.notNull(sslContext, "SSL context");
143 this.supportedProtocols = supportedProtocols;
144 this.supportedCipherSuites = supportedCipherSuites;
145 this.hostnameVerifier = hostnameVerifier != null ? hostnameVerifier : getDefaultHostnameVerifier();
146 }
147
148 /**
149 * @since 4.1
150 */
151 public SSLIOSessionStrategy(
152 final SSLContext sslcontext,
153 final HostnameVerifier hostnameVerifier) {
154 this(sslcontext, null, null, hostnameVerifier);
155 }
156
157 public SSLIOSessionStrategy(final SSLContext sslcontext) {
158 this(sslcontext, null, null, getDefaultHostnameVerifier());
159 }
160
161 @Override
162 public SSLIOSession upgrade(final HttpHost host, final IOSession iosession) throws IOException {
163 Asserts.check(!(iosession instanceof SSLIOSession), "I/O session is already upgraded to TLS/SSL");
164 final SSLIOSession ssliosession = new SSLIOSession(
165 iosession,
166 SSLMode.CLIENT,
167 host,
168 this.sslContext,
169 new SSLSetupHandler() {
170
171 @Override
172 public void initalize(
173 final SSLEngine sslengine) throws SSLException {
174 if (supportedProtocols != null) {
175 sslengine.setEnabledProtocols(supportedProtocols);
176 }
177 if (supportedCipherSuites != null) {
178 sslengine.setEnabledCipherSuites(supportedCipherSuites);
179 }
180 initializeEngine(sslengine);
181 }
182
183 @Override
184 public void verify(
185 final IOSession iosession,
186 final SSLSession sslsession) throws SSLException {
187 verifySession(host, iosession, sslsession);
188 }
189
190 });
191 iosession.setAttribute(SSLIOSession.SESSION_KEY, ssliosession);
192 ssliosession.initialize();
193 return ssliosession;
194 }
195
196 protected void initializeEngine(final SSLEngine engine) {
197 }
198
199 protected void verifySession(
200 final HttpHost host,
201 final IOSession iosession,
202 final SSLSession sslsession) throws SSLException {
203 if (!this.hostnameVerifier.verify(host.getHostName(), sslsession)) {
204 final Certificate[] certs = sslsession.getPeerCertificates();
205 final X509Certificate x509 = (X509Certificate) certs[0];
206 final X500Principal x500Principal = x509.getSubjectX500Principal();
207 throw new SSLPeerUnverifiedException("Host name '" + host.getHostName() + "' does not match " +
208 "the certificate subject provided by the peer (" + x500Principal.toString() + ")");
209 }
210 }
211
212 @Override
213 public boolean isLayeringRequired() {
214 return true;
215 }
216
217 }
0 /*
1 * ====================================================================
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 * ====================================================================
19 *
20 * This software consists of voluntary contributions made by many
21 * individuals on behalf of the Apache Software Foundation. For more
22 * information on the Apache Software Foundation, please see
23 * <http://www.apache.org/>.
24 *
25 */
26
27 /**
28 * Asynchronous client TLS/SSL support.
29 */
30 package org.apache.http.nio.conn.ssl;
0 /*
1 * ====================================================================
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 * ====================================================================
19 *
20 * This software consists of voluntary contributions made by many
21 * individuals on behalf of the Apache Software Foundation. For more
22 * information on the Apache Software Foundation, please see
23 * <http://www.apache.org/>.
24 *
25 */
26 package org.apache.http.impl.nio.client;
27
28 import java.io.IOException;
29 import java.net.URI;
30 import java.util.Queue;
31 import java.util.concurrent.ConcurrentLinkedQueue;
32 import java.util.concurrent.Future;
33
34 import org.apache.commons.logging.Log;
35 import org.apache.commons.logging.LogFactory;
36 import org.apache.http.ConnectionReuseStrategy;
37 import org.apache.http.HttpHost;
38 import org.apache.http.HttpRequest;
39 import org.apache.http.HttpRequestInterceptor;
40 import org.apache.http.HttpResponse;
41 import org.apache.http.HttpResponseInterceptor;
42 import org.apache.http.auth.AuthSchemeRegistry;
43 import org.apache.http.client.AuthenticationStrategy;
44 import org.apache.http.client.ClientProtocolException;
45 import org.apache.http.client.CookieStore;
46 import org.apache.http.client.CredentialsProvider;
47 import org.apache.http.client.RedirectStrategy;
48 import org.apache.http.client.UserTokenHandler;
49 import org.apache.http.client.methods.HttpUriRequest;
50 import org.apache.http.client.params.AuthPolicy;
51 import org.apache.http.client.params.CookiePolicy;
52 import org.apache.http.client.protocol.ClientContext;
53 import org.apache.http.client.utils.URIUtils;
54 import org.apache.http.concurrent.BasicFuture;
55 import org.apache.http.concurrent.FutureCallback;
56 import org.apache.http.conn.ConnectionKeepAliveStrategy;
57 import org.apache.http.conn.routing.HttpRoutePlanner;
58 import org.apache.http.cookie.CookieSpecRegistry;
59 import org.apache.http.impl.DefaultConnectionReuseStrategy;
60 import org.apache.http.impl.auth.BasicSchemeFactory;
61 import org.apache.http.impl.auth.DigestSchemeFactory;
62 import org.apache.http.impl.auth.KerberosSchemeFactory;
63 import org.apache.http.impl.auth.NTLMSchemeFactory;
64 import org.apache.http.impl.auth.SPNegoSchemeFactory;
65 import org.apache.http.impl.client.BasicCookieStore;
66 import org.apache.http.impl.client.BasicCredentialsProvider;
67 import org.apache.http.impl.client.DefaultConnectionKeepAliveStrategy;
68 import org.apache.http.impl.client.DefaultRedirectStrategy;
69 import org.apache.http.impl.client.DefaultUserTokenHandler;
70 import org.apache.http.impl.client.ProxyAuthenticationStrategy;
71 import org.apache.http.impl.client.TargetAuthenticationStrategy;
72 import org.apache.http.impl.cookie.BestMatchSpecFactory;
73 import org.apache.http.impl.cookie.BrowserCompatSpecFactory;
74 import org.apache.http.impl.cookie.IgnoreSpecFactory;
75 import org.apache.http.impl.cookie.NetscapeDraftSpecFactory;
76 import org.apache.http.impl.cookie.RFC2109SpecFactory;
77 import org.apache.http.impl.cookie.RFC2965SpecFactory;
78 import org.apache.http.impl.nio.DefaultHttpClientIODispatch;
79 import org.apache.http.impl.nio.conn.DefaultHttpAsyncRoutePlanner;
80 import org.apache.http.impl.nio.conn.PoolingClientAsyncConnectionManager;
81 import org.apache.http.impl.nio.reactor.DefaultConnectingIOReactor;
82 import org.apache.http.impl.nio.reactor.IOReactorConfig;
83 import org.apache.http.nio.client.HttpAsyncClient;
84 import org.apache.http.nio.client.methods.HttpAsyncMethods;
85 import org.apache.http.nio.conn.ClientAsyncConnectionManager;
86 import org.apache.http.nio.protocol.HttpAsyncRequestExecutionHandler;
87 import org.apache.http.nio.protocol.HttpAsyncRequestExecutor;
88 import org.apache.http.nio.protocol.HttpAsyncRequestProducer;
89 import org.apache.http.nio.protocol.HttpAsyncResponseConsumer;
90 import org.apache.http.nio.reactor.IOEventDispatch;
91 import org.apache.http.nio.reactor.IOReactorException;
92 import org.apache.http.nio.reactor.IOReactorStatus;
93 import org.apache.http.params.HttpParams;
94 import org.apache.http.protocol.BasicHttpContext;
95 import org.apache.http.protocol.BasicHttpProcessor;
96 import org.apache.http.protocol.DefaultedHttpContext;
97 import org.apache.http.protocol.HttpContext;
98 import org.apache.http.protocol.HttpProcessor;
99 import org.apache.http.protocol.ImmutableHttpProcessor;
100
101 @Deprecated
102 public abstract class AbstractHttpAsyncClient implements HttpAsyncClient {
103
104 private final Log log = LogFactory.getLog(getClass());
105 private final ClientAsyncConnectionManager connmgr;
106 private final Queue<HttpAsyncRequestExecutionHandler<?>> queue;
107
108 private Thread reactorThread;
109 private BasicHttpProcessor mutableProcessor;
110 private ImmutableHttpProcessor protocolProcessor;
111 private ConnectionReuseStrategy reuseStrategy;
112 private ConnectionKeepAliveStrategy keepAliveStrategy;
113 private RedirectStrategy redirectStrategy;
114 private CookieSpecRegistry supportedCookieSpecs;
115 private CookieStore cookieStore;
116 private AuthSchemeRegistry supportedAuthSchemes;
117 private AuthenticationStrategy targetAuthStrategy;
118 private AuthenticationStrategy proxyAuthStrategy;
119 private CredentialsProvider credsProvider;
120 private HttpRoutePlanner routePlanner;
121 private UserTokenHandler userTokenHandler;
122 private HttpParams params;
123
124 private volatile boolean terminated;
125
126 protected AbstractHttpAsyncClient(final ClientAsyncConnectionManager connmgr) {
127 super();
128 this.connmgr = connmgr;
129 this.queue = new ConcurrentLinkedQueue<HttpAsyncRequestExecutionHandler<?>>();
130 }
131
132 protected AbstractHttpAsyncClient(final IOReactorConfig config) throws IOReactorException {
133 super();
134 final DefaultConnectingIOReactor defaultioreactor = new DefaultConnectingIOReactor(config);
135 defaultioreactor.setExceptionHandler(new InternalIOReactorExceptionHandler(this.log));
136 this.connmgr = new PoolingClientAsyncConnectionManager(defaultioreactor);
137 this.queue = new ConcurrentLinkedQueue<HttpAsyncRequestExecutionHandler<?>>();
138 }
139
140 protected abstract HttpParams createHttpParams();
141
142 protected abstract BasicHttpProcessor createHttpProcessor();
143
144 protected HttpContext createHttpContext() {
145 final HttpContext context = new BasicHttpContext();
146 context.setAttribute(
147 ClientContext.SCHEME_REGISTRY,
148 getConnectionManager().getSchemeRegistry());
149 context.setAttribute(
150 ClientContext.AUTHSCHEME_REGISTRY,
151 getAuthSchemes());
152 context.setAttribute(
153 ClientContext.COOKIESPEC_REGISTRY,
154 getCookieSpecs());
155 context.setAttribute(
156 ClientContext.COOKIE_STORE,
157 getCookieStore());
158 context.setAttribute(
159 ClientContext.CREDS_PROVIDER,
160 getCredentialsProvider());
161 return context;
162 }
163
164 protected ConnectionReuseStrategy createConnectionReuseStrategy() {
165 return new DefaultConnectionReuseStrategy();
166 }
167
168 protected ConnectionKeepAliveStrategy createConnectionKeepAliveStrategy() {
169 return new DefaultConnectionKeepAliveStrategy();
170 }
171
172 protected AuthSchemeRegistry createAuthSchemeRegistry() {
173 final AuthSchemeRegistry registry = new AuthSchemeRegistry();
174 registry.register(
175 AuthPolicy.BASIC,
176 new BasicSchemeFactory());
177 registry.register(
178 AuthPolicy.DIGEST,
179 new DigestSchemeFactory());
180 registry.register(
181 AuthPolicy.NTLM,
182 new NTLMSchemeFactory());
183 registry.register(
184 AuthPolicy.SPNEGO,
185 new SPNegoSchemeFactory());
186 registry.register(
187 AuthPolicy.KERBEROS,
188 new KerberosSchemeFactory());
189 return registry;
190 }
191
192 protected CookieSpecRegistry createCookieSpecRegistry() {
193 final CookieSpecRegistry registry = new CookieSpecRegistry();
194 registry.register(
195 CookiePolicy.BEST_MATCH,
196 new BestMatchSpecFactory());
197 registry.register(
198 CookiePolicy.BROWSER_COMPATIBILITY,
199 new BrowserCompatSpecFactory());
200 registry.register(
201 CookiePolicy.NETSCAPE,
202 new NetscapeDraftSpecFactory());
203 registry.register(
204 CookiePolicy.RFC_2109,
205 new RFC2109SpecFactory());
206 registry.register(
207 CookiePolicy.RFC_2965,
208 new RFC2965SpecFactory());
209 registry.register(
210 CookiePolicy.IGNORE_COOKIES,
211 new IgnoreSpecFactory());
212 return registry;
213 }
214
215 protected AuthenticationStrategy createTargetAuthenticationStrategy() {
216 return new TargetAuthenticationStrategy();
217 }
218
219 protected AuthenticationStrategy createProxyAuthenticationStrategy() {
220 return new ProxyAuthenticationStrategy();
221 }
222
223 protected CookieStore createCookieStore() {
224 return new BasicCookieStore();
225 }
226
227 protected CredentialsProvider createCredentialsProvider() {
228 return new BasicCredentialsProvider();
229 }
230
231 protected HttpRoutePlanner createHttpRoutePlanner() {
232 return new DefaultHttpAsyncRoutePlanner(getConnectionManager().getSchemeRegistry());
233 }
234
235 protected UserTokenHandler createUserTokenHandler() {
236 return new DefaultUserTokenHandler();
237 }
238
239 public synchronized final HttpParams getParams() {
240 if (this.params == null) {
241 this.params = createHttpParams();
242 }
243 return this.params;
244 }
245
246 public synchronized void setParams(final HttpParams params) {
247 this.params = params;
248 }
249
250 public synchronized ClientAsyncConnectionManager getConnectionManager() {
251 return this.connmgr;
252 }
253
254 public synchronized final ConnectionReuseStrategy getConnectionReuseStrategy() {
255 if (this.reuseStrategy == null) {
256 this.reuseStrategy = createConnectionReuseStrategy();
257 }
258 return this.reuseStrategy;
259 }
260
261 public synchronized void setReuseStrategy(final ConnectionReuseStrategy reuseStrategy) {
262 this.reuseStrategy = reuseStrategy;
263 }
264
265 public synchronized final ConnectionKeepAliveStrategy getConnectionKeepAliveStrategy() {
266 if (this.keepAliveStrategy == null) {
267 this.keepAliveStrategy = createConnectionKeepAliveStrategy();
268 }
269 return this.keepAliveStrategy;
270 }
271
272 public synchronized void setKeepAliveStrategy(final ConnectionKeepAliveStrategy keepAliveStrategy) {
273 this.keepAliveStrategy = keepAliveStrategy;
274 }
275
276 public synchronized final RedirectStrategy getRedirectStrategy() {
277 if (this.redirectStrategy == null) {
278 this.redirectStrategy = new DefaultRedirectStrategy();
279 }
280 return this.redirectStrategy;
281 }
282
283 public synchronized void setRedirectStrategy(final RedirectStrategy redirectStrategy) {
284 this.redirectStrategy = redirectStrategy;
285 }
286
287 public synchronized final AuthSchemeRegistry getAuthSchemes() {
288 if (this.supportedAuthSchemes == null) {
289 this.supportedAuthSchemes = createAuthSchemeRegistry();
290 }
291 return this.supportedAuthSchemes;
292 }
293
294 public synchronized void setAuthSchemes(final AuthSchemeRegistry authSchemeRegistry) {
295 this.supportedAuthSchemes = authSchemeRegistry;
296 }
297
298 public synchronized final CookieSpecRegistry getCookieSpecs() {
299 if (this.supportedCookieSpecs == null) {
300 this.supportedCookieSpecs = createCookieSpecRegistry();
301 }
302 return this.supportedCookieSpecs;
303 }
304
305 public synchronized void setCookieSpecs(final CookieSpecRegistry cookieSpecRegistry) {
306 this.supportedCookieSpecs = cookieSpecRegistry;
307 }
308
309 public synchronized final AuthenticationStrategy getTargetAuthenticationStrategy() {
310 if (this.targetAuthStrategy == null) {
311 this.targetAuthStrategy = createTargetAuthenticationStrategy();
312 }
313 return this.targetAuthStrategy;
314 }
315
316 public synchronized void setTargetAuthenticationStrategy(
317 final AuthenticationStrategy targetAuthStrategy) {
318 this.targetAuthStrategy = targetAuthStrategy;
319 }
320
321 public synchronized final AuthenticationStrategy getProxyAuthenticationStrategy() {
322 if (this.proxyAuthStrategy == null) {
323 this.proxyAuthStrategy = createProxyAuthenticationStrategy();
324 }
325 return this.proxyAuthStrategy;
326 }
327
328 public synchronized void setProxyAuthenticationStrategy(
329 final AuthenticationStrategy proxyAuthStrategy) {
330 this.proxyAuthStrategy = proxyAuthStrategy;
331 }
332
333 public synchronized final CookieStore getCookieStore() {
334 if (this.cookieStore == null) {
335 this.cookieStore = createCookieStore();
336 }
337 return this.cookieStore;
338 }
339
340 public synchronized void setCookieStore(final CookieStore cookieStore) {
341 this.cookieStore = cookieStore;
342 }
343
344 public synchronized final CredentialsProvider getCredentialsProvider() {
345 if (this.credsProvider == null) {
346 this.credsProvider = createCredentialsProvider();
347 }
348 return this.credsProvider;
349 }
350
351 public synchronized void setCredentialsProvider(final CredentialsProvider credsProvider) {
352 this.credsProvider = credsProvider;
353 }
354
355 public synchronized final HttpRoutePlanner getRoutePlanner() {
356 if (this.routePlanner == null) {
357 this.routePlanner = createHttpRoutePlanner();
358 }
359 return this.routePlanner;
360 }
361
362 public synchronized void setRoutePlanner(final HttpRoutePlanner routePlanner) {
363 this.routePlanner = routePlanner;
364 }
365
366 public synchronized final UserTokenHandler getUserTokenHandler() {
367 if (this.userTokenHandler == null) {
368 this.userTokenHandler = createUserTokenHandler();
369 }
370 return this.userTokenHandler;
371 }
372
373
374 public synchronized void setUserTokenHandler(final UserTokenHandler userTokenHandler) {
375 this.userTokenHandler = userTokenHandler;
376 }
377
378 protected synchronized final BasicHttpProcessor getHttpProcessor() {
379 if (this.mutableProcessor == null) {
380 this.mutableProcessor = createHttpProcessor();
381 }
382 return this.mutableProcessor;
383 }
384
385 private synchronized final HttpProcessor getProtocolProcessor() {
386 if (this.protocolProcessor == null) {
387 // Get mutable HTTP processor
388 final BasicHttpProcessor proc = getHttpProcessor();
389 // and upgrade an immutable copy of it
390 final int reqc = proc.getRequestInterceptorCount();
391 final HttpRequestInterceptor[] reqinterceptors = new HttpRequestInterceptor[reqc];
392 for (int i = 0; i < reqc; i++) {
393 reqinterceptors[i] = proc.getRequestInterceptor(i);
394 }
395 final int resc = proc.getResponseInterceptorCount();
396 final HttpResponseInterceptor[] resinterceptors = new HttpResponseInterceptor[resc];
397 for (int i = 0; i < resc; i++) {
398 resinterceptors[i] = proc.getResponseInterceptor(i);
399 }
400 this.protocolProcessor = new ImmutableHttpProcessor(reqinterceptors, resinterceptors);
401 }
402 return this.protocolProcessor;
403 }
404
405 public synchronized int getResponseInterceptorCount() {
406 return getHttpProcessor().getResponseInterceptorCount();
407 }
408
409 public synchronized HttpResponseInterceptor getResponseInterceptor(final int index) {
410 return getHttpProcessor().getResponseInterceptor(index);
411 }
412
413 public synchronized HttpRequestInterceptor getRequestInterceptor(final int index) {
414 return getHttpProcessor().getRequestInterceptor(index);
415 }
416
417 public synchronized int getRequestInterceptorCount() {
418 return getHttpProcessor().getRequestInterceptorCount();
419 }
420
421 public synchronized void addResponseInterceptor(final HttpResponseInterceptor itcp) {
422 getHttpProcessor().addInterceptor(itcp);
423 this.protocolProcessor = null;
424 }
425
426 public synchronized void addResponseInterceptor(final HttpResponseInterceptor itcp, final int index) {
427 getHttpProcessor().addInterceptor(itcp, index);
428 this.protocolProcessor = null;
429 }
430
431 public synchronized void clearResponseInterceptors() {
432 getHttpProcessor().clearResponseInterceptors();
433 this.protocolProcessor = null;
434 }
435
436 public synchronized void removeResponseInterceptorByClass(final Class<? extends HttpResponseInterceptor> clazz) {
437 getHttpProcessor().removeResponseInterceptorByClass(clazz);
438 this.protocolProcessor = null;
439 }
440
441 public synchronized void addRequestInterceptor(final HttpRequestInterceptor itcp) {
442 getHttpProcessor().addInterceptor(itcp);
443 this.protocolProcessor = null;
444 }
445
446 public synchronized void addRequestInterceptor(final HttpRequestInterceptor itcp, final int index) {
447 getHttpProcessor().addInterceptor(itcp, index);
448 this.protocolProcessor = null;
449 }
450
451 public synchronized void clearRequestInterceptors() {
452 getHttpProcessor().clearRequestInterceptors();
453 this.protocolProcessor = null;
454 }
455
456 public synchronized void removeRequestInterceptorByClass(final Class<? extends HttpRequestInterceptor> clazz) {
457 getHttpProcessor().removeRequestInterceptorByClass(clazz);
458 this.protocolProcessor = null;
459 }
460
461 private void doExecute() {
462 final InternalRequestExecutor handler = new InternalRequestExecutor(this.log, new HttpAsyncRequestExecutor());
463 try {
464 final IOEventDispatch ioEventDispatch = new DefaultHttpClientIODispatch(handler, getParams());
465 this.connmgr.execute(ioEventDispatch);
466 } catch (final Exception ex) {
467 this.log.error("I/O reactor terminated abnormally", ex);
468 } finally {
469 this.terminated = true;
470 while (!this.queue.isEmpty()) {
471 final HttpAsyncRequestExecutionHandler<?> exchangeHandler = this.queue.remove();
472 exchangeHandler.cancel();
473 }
474 }
475 }
476
477 public IOReactorStatus getStatus() {
478 return this.connmgr.getStatus();
479 }
480
481 public synchronized void start() {
482 this.reactorThread = new Thread() {
483
484 @Override
485 public void run() {
486 doExecute();
487 }
488
489 };
490 this.reactorThread.start();
491 }
492
493 public void shutdown() throws InterruptedException {
494 try {
495 this.connmgr.shutdown(5000);
496 } catch (final IOException ex) {
497 this.log.error("I/O error shutting down", ex);
498 }
499 if (this.reactorThread != null) {
500 this.reactorThread.join();
501 }
502 }
503
504 @Override
505 public <T> Future<T> execute(
506 final HttpAsyncRequestProducer requestProducer,
507 final HttpAsyncResponseConsumer<T> responseConsumer,
508 final HttpContext context,
509 final FutureCallback<T> callback) {
510 if (this.terminated) {
511 throw new IllegalStateException("Client has been shut down");
512 }
513 final BasicFuture<T> future = new BasicFuture<T>(callback);
514 final ResultCallback<T> resultCallback = new DefaultResultCallback<T>(future, this.queue);
515 DefaultAsyncRequestDirector<T> httpexchange;
516 synchronized (this) {
517 final HttpContext defaultContext = createHttpContext();
518 HttpContext execContext;
519 if (context == null) {
520 execContext = defaultContext;
521 } else {
522 execContext = new DefaultedHttpContext(context, defaultContext);
523 }
524 httpexchange = new DefaultAsyncRequestDirector<T>(
525 this.log,
526 requestProducer,
527 responseConsumer,
528 execContext,
529 resultCallback,
530 this.connmgr,
531 getProtocolProcessor(),
532 getRoutePlanner(),
533 getConnectionReuseStrategy(),
534 getConnectionKeepAliveStrategy(),
535 getRedirectStrategy(),
536 getTargetAuthenticationStrategy(),
537 getProxyAuthenticationStrategy(),
538 getUserTokenHandler(),
539 getParams());
540 }
541 this.queue.add(httpexchange);
542 httpexchange.start();
543 return future;
544 }
545
546 @Override
547 public <T> Future<T> execute(
548 final HttpAsyncRequestProducer requestProducer,
549 final HttpAsyncResponseConsumer<T> responseConsumer,
550 final FutureCallback<T> callback) {
551 return execute(requestProducer, responseConsumer, new BasicHttpContext(), callback);
552 }
553
554 @Override
555 public Future<HttpResponse> execute(
556 final HttpHost target, final HttpRequest request, final HttpContext context,
557 final FutureCallback<HttpResponse> callback) {
558 return execute(
559 HttpAsyncMethods.create(target, request),
560 HttpAsyncMethods.createConsumer(),
561 context, callback);
562 }
563
564 @Override
565 public Future<HttpResponse> execute(
566 final HttpHost target, final HttpRequest request,
567 final FutureCallback<HttpResponse> callback) {
568 return execute(target, request, new BasicHttpContext(), callback);
569 }
570
571 @Override
572 public Future<HttpResponse> execute(
573 final HttpUriRequest request,
574 final FutureCallback<HttpResponse> callback) {
575 return execute(request, new BasicHttpContext(), callback);
576 }
577
578 @Override
579 public Future<HttpResponse> execute(
580 final HttpUriRequest request,
581 final HttpContext context,
582 final FutureCallback<HttpResponse> callback) {
583 HttpHost target;
584 try {
585 target = determineTarget(request);
586 } catch (final ClientProtocolException ex) {
587 final BasicFuture<HttpResponse> future = new BasicFuture<HttpResponse>(callback);
588 future.failed(ex);
589 return future;
590 }
591 return execute(target, request, context, callback);
592 }
593
594 private HttpHost determineTarget(final HttpUriRequest request) throws ClientProtocolException {
595 // A null target may be acceptable if there is a default target.
596 // Otherwise, the null target is detected in the director.
597 HttpHost target = null;
598
599 final URI requestURI = request.getURI();
600 if (requestURI.isAbsolute()) {
601 target = URIUtils.extractHost(requestURI);
602 if (target == null) {
603 throw new ClientProtocolException(
604 "URI does not specify a valid host name: " + requestURI);
605 }
606 }
607 return target;
608 }
609
610 }
0 /*
1 * ====================================================================
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 * ====================================================================
19 *
20 * This software consists of voluntary contributions made by many
21 * individuals on behalf of the Apache Software Foundation. For more
22 * information on the Apache Software Foundation, please see
23 * <http://www.apache.org/>.
24 *
25 */
26 package org.apache.http.impl.nio.client;
27
28 import java.io.IOException;
29 import java.net.URI;
30 import java.net.URISyntaxException;
31 import java.nio.ByteBuffer;
32 import java.util.concurrent.TimeUnit;
33 import java.util.concurrent.atomic.AtomicLong;
34
35 import org.apache.commons.logging.Log;
36 import org.apache.http.ConnectionClosedException;
37 import org.apache.http.ConnectionReuseStrategy;
38 import org.apache.http.HttpEntityEnclosingRequest;
39 import org.apache.http.HttpException;
40 import org.apache.http.HttpHost;
41 import org.apache.http.HttpRequest;
42 import org.apache.http.HttpResponse;
43 import org.apache.http.HttpStatus;
44 import org.apache.http.ProtocolException;
45 import org.apache.http.ProtocolVersion;
46 import org.apache.http.auth.AuthProtocolState;
47 import org.apache.http.auth.AuthScheme;
48 import org.apache.http.auth.AuthState;
49 import org.apache.http.auth.UsernamePasswordCredentials;
50 import org.apache.http.client.AuthenticationStrategy;
51 import org.apache.http.client.CredentialsProvider;
52 import org.apache.http.client.NonRepeatableRequestException;
53 import org.apache.http.client.RedirectException;
54 import org.apache.http.client.RedirectStrategy;
55 import org.apache.http.client.UserTokenHandler;
56 import org.apache.http.client.config.RequestConfig;
57 import org.apache.http.client.methods.AbortableHttpRequest;
58 import org.apache.http.client.methods.HttpUriRequest;
59 import org.apache.http.client.params.ClientPNames;
60 import org.apache.http.client.params.HttpClientParams;
61 import org.apache.http.client.protocol.ClientContext;
62 import org.apache.http.client.utils.URIUtils;
63 import org.apache.http.concurrent.FutureCallback;
64 import org.apache.http.conn.ConnectionKeepAliveStrategy;
65 import org.apache.http.conn.ConnectionReleaseTrigger;
66 import org.apache.http.conn.routing.BasicRouteDirector;
67 import org.apache.http.conn.routing.HttpRoute;
68 import org.apache.http.conn.routing.HttpRouteDirector;
69 import org.apache.http.conn.routing.HttpRoutePlanner;
70 import org.apache.http.impl.auth.BasicScheme;
71 import org.apache.http.impl.client.ClientParamsStack;
72 import org.apache.http.impl.client.EntityEnclosingRequestWrapper;
73 import org.apache.http.impl.client.HttpAuthenticator;
74 import org.apache.http.impl.client.RequestWrapper;
75 import org.apache.http.impl.client.RoutedRequest;
76 import org.apache.http.message.BasicHttpRequest;
77 import org.apache.http.nio.ContentDecoder;
78 import org.apache.http.nio.ContentEncoder;
79 import org.apache.http.nio.IOControl;
80 import org.apache.http.nio.conn.ClientAsyncConnectionManager;
81 import org.apache.http.nio.conn.ManagedClientAsyncConnection;
82 import org.apache.http.nio.conn.scheme.AsyncScheme;
83 import org.apache.http.nio.conn.scheme.AsyncSchemeRegistry;
84 import org.apache.http.nio.protocol.HttpAsyncRequestExecutionHandler;
85 import org.apache.http.nio.protocol.HttpAsyncRequestExecutor;
86 import org.apache.http.nio.protocol.HttpAsyncRequestProducer;
87 import org.apache.http.nio.protocol.HttpAsyncResponseConsumer;
88 import org.apache.http.params.HttpConnectionParams;
89 import org.apache.http.params.HttpParams;
90 import org.apache.http.params.HttpProtocolParams;
91 import org.apache.http.protocol.ExecutionContext;
92 import org.apache.http.protocol.HttpContext;
93 import org.apache.http.protocol.HttpProcessor;
94
95 @Deprecated
96 class DefaultAsyncRequestDirector<T> implements HttpAsyncRequestExecutionHandler<T> {
97
98 private static final AtomicLong COUNTER = new AtomicLong(1);
99
100 private final Log log;
101
102 private final HttpAsyncRequestProducer requestProducer;
103 private final HttpAsyncResponseConsumer<T> responseConsumer;
104 private final HttpContext localContext;
105 private final ResultCallback<T> resultCallback;
106 private final ClientAsyncConnectionManager connmgr;
107 private final HttpProcessor httppocessor;
108 private final HttpRoutePlanner routePlanner;
109 private final HttpRouteDirector routeDirector;
110 private final ConnectionReuseStrategy reuseStrategy;
111 private final ConnectionKeepAliveStrategy keepaliveStrategy;
112 private final RedirectStrategy redirectStrategy;
113 private final AuthenticationStrategy targetAuthStrategy;
114 private final AuthenticationStrategy proxyAuthStrategy;
115 private final UserTokenHandler userTokenHandler;
116 private final AuthState targetAuthState;
117 private final AuthState proxyAuthState;
118 private final HttpAuthenticator authenticator;
119 private final HttpParams clientParams;
120 private final long id;
121
122 private volatile boolean closed;
123 private volatile InternalFutureCallback connRequestCallback;
124 private volatile ManagedClientAsyncConnection managedConn;
125
126 private RoutedRequest mainRequest;
127 private RoutedRequest followup;
128 private HttpResponse finalResponse;
129
130 private ClientParamsStack params;
131 private RequestWrapper currentRequest;
132 private HttpResponse currentResponse;
133 private boolean routeEstablished;
134 private int redirectCount;
135 private ByteBuffer tmpbuf;
136 private boolean requestContentProduced;
137 private boolean requestSent;
138 private int execCount;
139
140 public DefaultAsyncRequestDirector(
141 final Log log,
142 final HttpAsyncRequestProducer requestProducer,
143 final HttpAsyncResponseConsumer<T> responseConsumer,
144 final HttpContext localContext,
145 final ResultCallback<T> callback,
146 final ClientAsyncConnectionManager connmgr,
147 final HttpProcessor httppocessor,
148 final HttpRoutePlanner routePlanner,
149 final ConnectionReuseStrategy reuseStrategy,
150 final ConnectionKeepAliveStrategy keepaliveStrategy,
151 final RedirectStrategy redirectStrategy,
152 final AuthenticationStrategy targetAuthStrategy,
153 final AuthenticationStrategy proxyAuthStrategy,
154 final UserTokenHandler userTokenHandler,
155 final HttpParams clientParams) {
156 super();
157 this.log = log;
158 this.requestProducer = requestProducer;
159 this.responseConsumer = responseConsumer;
160 this.localContext = localContext;
161 this.resultCallback = callback;
162 this.connmgr = connmgr;
163 this.httppocessor = httppocessor;
164 this.routePlanner = routePlanner;
165 this.reuseStrategy = reuseStrategy;
166 this.keepaliveStrategy = keepaliveStrategy;
167 this.redirectStrategy = redirectStrategy;
168 this.routeDirector = new BasicRouteDirector();
169 this.targetAuthStrategy = targetAuthStrategy;
170 this.proxyAuthStrategy = proxyAuthStrategy;
171 this.userTokenHandler = userTokenHandler;
172 this.targetAuthState = new AuthState();
173 this.proxyAuthState = new AuthState();
174 this.authenticator = new HttpAuthenticator(log);
175 this.clientParams = clientParams;
176 this.id = COUNTER.getAndIncrement();
177 }
178
179 @Override
180 public void close() {
181 if (this.closed) {
182 return;
183 }
184 this.closed = true;
185 final ManagedClientAsyncConnection localConn = this.managedConn;
186 if (localConn != null) {
187 if (this.log.isDebugEnabled()) {
188 this.log.debug("[exchange: " + this.id + "] aborting connection " + localConn);
189 }
190 try {
191 localConn.abortConnection();
192 } catch (final IOException ioex) {
193 this.log.debug("I/O error releasing connection", ioex);
194 }
195 }
196 try {
197 this.requestProducer.close();
198 } catch (final IOException ex) {
199 this.log.debug("I/O error closing request producer", ex);
200 }
201 try {
202 this.responseConsumer.close();
203 } catch (final IOException ex) {
204 this.log.debug("I/O error closing response consumer", ex);
205 }
206 }
207
208 public synchronized void start() {
209 try {
210 if (this.log.isDebugEnabled()) {
211 this.log.debug("[exchange: " + this.id + "] start execution");
212 }
213 this.localContext.setAttribute(ClientContext.TARGET_AUTH_STATE, this.targetAuthState);
214 this.localContext.setAttribute(ClientContext.PROXY_AUTH_STATE, this.proxyAuthState);
215
216 final HttpHost target = this.requestProducer.getTarget();
217 final HttpRequest request = this.requestProducer.generateRequest();
218 if (request instanceof AbortableHttpRequest) {
219 ((AbortableHttpRequest) request).setReleaseTrigger(new ConnectionReleaseTrigger() {
220
221 @Override
222 public void releaseConnection() throws IOException {
223 }
224
225 @Override
226 public void abortConnection() throws IOException {
227 cancel();
228 }
229
230 });
231 }
232 this.params = new ClientParamsStack(null, this.clientParams, request.getParams(), null);
233 final RequestWrapper wrapper = wrapRequest(request);
234 wrapper.setParams(this.params);
235 final HttpRoute route = determineRoute(target, wrapper, this.localContext);
236 this.mainRequest = new RoutedRequest(wrapper, route);
237 final RequestConfig config = ParamConfig.getRequestConfig(params);
238 this.localContext.setAttribute(ClientContext.REQUEST_CONFIG, config);
239 this.requestContentProduced = false;
240 requestConnection();
241 } catch (final Exception ex) {
242 failed(ex);
243 }
244 }
245
246 @Override
247 public HttpHost getTarget() {
248 return this.requestProducer.getTarget();
249 }
250
251 @Override
252 public synchronized HttpRequest generateRequest() throws IOException, HttpException {
253 final HttpRoute route = this.mainRequest.getRoute();
254 if (!this.routeEstablished) {
255 int step;
256 do {
257 final HttpRoute fact = this.managedConn.getRoute();
258 step = this.routeDirector.nextStep(route, fact);
259 switch (step) {
260 case HttpRouteDirector.CONNECT_TARGET:
261 case HttpRouteDirector.CONNECT_PROXY:
262 break;
263 case HttpRouteDirector.TUNNEL_TARGET:
264 if (this.log.isDebugEnabled()) {
265 this.log.debug("[exchange: " + this.id + "] Tunnel required");
266 }
267 final HttpRequest connect = createConnectRequest(route);
268 this.currentRequest = wrapRequest(connect);
269 this.currentRequest.setParams(this.params);
270 break;
271 case HttpRouteDirector.TUNNEL_PROXY:
272 throw new HttpException("Proxy chains are not supported");
273 case HttpRouteDirector.LAYER_PROTOCOL:
274 managedConn.layerProtocol(this.localContext, this.params);
275 break;
276 case HttpRouteDirector.UNREACHABLE:
277 throw new HttpException("Unable to establish route: " +
278 "planned = " + route + "; current = " + fact);
279 case HttpRouteDirector.COMPLETE:
280 this.routeEstablished = true;
281 break;
282 default:
283 throw new IllegalStateException("Unknown step indicator "
284 + step + " from RouteDirector.");
285 }
286 } while (step > HttpRouteDirector.COMPLETE && this.currentRequest == null);
287 }
288
289 HttpHost target = (HttpHost) this.params.getParameter(ClientPNames.VIRTUAL_HOST);
290 if (target == null) {
291 target = route.getTargetHost();
292 }
293 final HttpHost proxy = route.getProxyHost();
294 this.localContext.setAttribute(ExecutionContext.HTTP_TARGET_HOST, target);
295 this.localContext.setAttribute(ExecutionContext.HTTP_PROXY_HOST, proxy);
296 this.localContext.setAttribute(ExecutionContext.HTTP_CONNECTION, this.managedConn);
297 this.localContext.setAttribute(ClientContext.ROUTE, route);
298
299 if (this.currentRequest == null) {
300 this.currentRequest = this.mainRequest.getRequest();
301
302 final String userinfo = this.currentRequest.getURI().getUserInfo();
303 if (userinfo != null) {
304 this.targetAuthState.update(
305 new BasicScheme(), new UsernamePasswordCredentials(userinfo));
306 }
307
308 // Re-write request URI if needed
309 rewriteRequestURI(this.currentRequest, route);
310 }
311 // Reset headers on the request wrapper
312 this.currentRequest.resetHeaders();
313
314 this.currentRequest.incrementExecCount();
315 if (this.currentRequest.getExecCount() > 1
316 && !this.requestProducer.isRepeatable()
317 && this.requestContentProduced) {
318 throw new NonRepeatableRequestException("Cannot retry request " +
319 "with a non-repeatable request entity.");
320 }
321 this.execCount++;
322 if (this.log.isDebugEnabled()) {
323 this.log.debug("[exchange: " + this.id + "] Attempt " + this.execCount + " to execute request");
324 }
325 return this.currentRequest;
326 }
327
328 @Override
329 public synchronized void produceContent(
330 final ContentEncoder encoder, final IOControl ioctrl) throws IOException {
331 if (this.log.isDebugEnabled()) {
332 this.log.debug("[exchange: " + this.id + "] produce content");
333 }
334 this.requestContentProduced = true;
335 this.requestProducer.produceContent(encoder, ioctrl);
336 if (encoder.isCompleted()) {
337 this.requestProducer.resetRequest();
338 }
339 }
340
341 @Override
342 public void requestCompleted(final HttpContext context) {
343 if (this.log.isDebugEnabled()) {
344 this.log.debug("[exchange: " + this.id + "] Request completed");
345 }
346 this.requestSent = true;
347 this.requestProducer.requestCompleted(context);
348 }
349
350 @Override
351 public boolean isRepeatable() {
352 return this.requestProducer.isRepeatable();
353 }
354
355 @Override
356 public void resetRequest() throws IOException {
357 this.requestSent = false;
358 this.requestProducer.resetRequest();
359 }
360
361 @Override
362 public synchronized void responseReceived(
363 final HttpResponse response) throws IOException, HttpException {
364 if (this.log.isDebugEnabled()) {
365 this.log.debug("[exchange: " + this.id + "] Response received " + response.getStatusLine());
366 }
367 this.currentResponse = response;
368 this.currentResponse.setParams(this.params);
369
370 final int status = this.currentResponse.getStatusLine().getStatusCode();
371
372 if (!this.routeEstablished) {
373 final String method = this.currentRequest.getMethod();
374 if (method.equalsIgnoreCase("CONNECT") && status == HttpStatus.SC_OK) {
375 this.managedConn.tunnelTarget(this.params);
376 } else {
377 this.followup = handleConnectResponse();
378 if (this.followup == null) {
379 this.finalResponse = response;
380 }
381 }
382 } else {
383 this.followup = handleResponse();
384 if (this.followup == null) {
385 this.finalResponse = response;
386 }
387
388 Object userToken = this.localContext.getAttribute(ClientContext.USER_TOKEN);
389 if (managedConn != null) {
390 if (userToken == null) {
391 userToken = userTokenHandler.getUserToken(this.localContext);
392 this.localContext.setAttribute(ClientContext.USER_TOKEN, userToken);
393 }
394 if (userToken != null) {
395 managedConn.setState(userToken);
396 }
397 }
398 }
399 if (this.finalResponse != null) {
400 this.responseConsumer.responseReceived(response);
401 }
402 }
403
404 @Override
405 public synchronized void consumeContent(
406 final ContentDecoder decoder, final IOControl ioctrl) throws IOException {
407 if (this.log.isDebugEnabled()) {
408 this.log.debug("[exchange: " + this.id + "] Consume content");
409 }
410 if (this.finalResponse != null) {
411 this.responseConsumer.consumeContent(decoder, ioctrl);
412 } else {
413 if (this.tmpbuf == null) {
414 this.tmpbuf = ByteBuffer.allocate(2048);
415 }
416 this.tmpbuf.clear();
417 decoder.read(this.tmpbuf);
418 }
419 }
420
421 private void releaseConnection() {
422 if (this.managedConn != null) {
423 if (this.log.isDebugEnabled()) {
424 this.log.debug("[exchange: " + this.id + "] releasing connection " + this.managedConn);
425 }
426 try {
427 this.managedConn.getContext().removeAttribute(HttpAsyncRequestExecutor.HTTP_HANDLER);
428 this.managedConn.releaseConnection();
429 } catch (final IOException ioex) {
430 this.log.debug("I/O error releasing connection", ioex);
431 }
432 this.managedConn = null;
433 }
434 }
435
436 @Override
437 public synchronized void failed(final Exception ex) {
438 try {
439 if (!this.requestSent) {
440 this.requestProducer.failed(ex);
441 }
442 this.responseConsumer.failed(ex);
443 } finally {
444 try {
445 this.resultCallback.failed(ex, this);
446 } finally {
447 close();
448 }
449 }
450 }
451
452 @Override
453 public synchronized void responseCompleted(final HttpContext context) {
454 if (this.log.isDebugEnabled()) {
455 this.log.debug("[exchange: " + this.id + "] Response fully read");
456 }
457 try {
458 if (this.resultCallback.isDone()) {
459 return;
460 }
461 if (this.managedConn.isOpen()) {
462 final long duration = this.keepaliveStrategy.getKeepAliveDuration(
463 this.currentResponse, this.localContext);
464 if (this.log.isDebugEnabled()) {
465 final String s;
466 if (duration > 0) {
467 s = "for " + duration + " " + TimeUnit.MILLISECONDS;
468 } else {
469 s = "indefinitely";
470 }
471 this.log.debug("[exchange: " + this.id + "] Connection can be kept alive " + s);
472 }
473 this.managedConn.setIdleDuration(duration, TimeUnit.MILLISECONDS);
474 } else {
475 if (this.log.isDebugEnabled()) {
476 this.log.debug("[exchange: " + this.id + "] Connection cannot be kept alive");
477 }
478 this.managedConn.unmarkReusable();
479 if (this.proxyAuthState.getState() == AuthProtocolState.SUCCESS
480 && this.proxyAuthState.getAuthScheme() != null
481 && this.proxyAuthState.getAuthScheme().isConnectionBased()) {
482 if (this.log.isDebugEnabled()) {
483 this.log.debug("[exchange: " + this.id + "] Resetting proxy auth state");
484 }
485 this.proxyAuthState.reset();
486 }
487 if (this.targetAuthState.getState() == AuthProtocolState.SUCCESS
488 && this.targetAuthState.getAuthScheme() != null
489 && this.targetAuthState.getAuthScheme().isConnectionBased()) {
490 if (this.log.isDebugEnabled()) {
491 this.log.debug("[exchange: " + this.id + "] Resetting target auth state");
492 }
493 this.targetAuthState.reset();
494 }
495 }
496
497 if (this.finalResponse != null) {
498 this.responseConsumer.responseCompleted(this.localContext);
499 if (this.log.isDebugEnabled()) {
500 this.log.debug("[exchange: " + this.id + "] Response processed");
501 }
502 releaseConnection();
503 final T result = this.responseConsumer.getResult();
504 final Exception ex = this.responseConsumer.getException();
505 if (ex == null) {
506 this.resultCallback.completed(result, this);
507 } else {
508 this.resultCallback.failed(ex, this);
509 }
510 } else {
511 if (this.followup != null) {
512 final HttpRoute actualRoute = this.mainRequest.getRoute();
513 final HttpRoute newRoute = this.followup.getRoute();
514 if (!actualRoute.equals(newRoute)) {
515 releaseConnection();
516 }
517 this.mainRequest = this.followup;
518 }
519 if (this.managedConn != null && !this.managedConn.isOpen()) {
520 releaseConnection();
521 }
522 if (this.managedConn != null) {
523 this.managedConn.requestOutput();
524 } else {
525 requestConnection();
526 }
527 }
528 this.followup = null;
529 this.currentRequest = null;
530 this.currentResponse = null;
531 } catch (final RuntimeException runex) {
532 failed(runex);
533 throw runex;
534 }
535 }
536
537 @Override
538 public synchronized boolean cancel() {
539 if (this.log.isDebugEnabled()) {
540 this.log.debug("[exchange: " + this.id + "] Cancelled");
541 }
542 try {
543 final boolean cancelled = this.responseConsumer.cancel();
544
545 final T result = this.responseConsumer.getResult();
546 final Exception ex = this.responseConsumer.getException();
547 if (ex != null) {
548 this.resultCallback.failed(ex, this);
549 } else if (result != null) {
550 this.resultCallback.completed(result, this);
551 } else {
552 this.resultCallback.cancelled(this);
553 }
554 return cancelled;
555 } catch (final RuntimeException runex) {
556 this.resultCallback.failed(runex, this);
557 throw runex;
558 } finally {
559 close();
560 }
561 }
562
563 @Override
564 public boolean isDone() {
565 return this.resultCallback.isDone();
566 }
567
568 @Override
569 public T getResult() {
570 return this.responseConsumer.getResult();
571 }
572
573 @Override
574 public Exception getException() {
575 return this.responseConsumer.getException();
576 }
577
578 private synchronized void connectionRequestCompleted(final ManagedClientAsyncConnection conn) {
579 if (this.log.isDebugEnabled()) {
580 this.log.debug("[exchange: " + this.id + "] Connection allocated: " + conn);
581 }
582 this.connRequestCallback = null;
583 try {
584 this.managedConn = conn;
585 if (this.closed) {
586 conn.releaseConnection();
587 return;
588 }
589 final HttpRoute route = this.mainRequest.getRoute();
590 if (!conn.isOpen()) {
591 conn.open(route, this.localContext, this.params);
592 }
593 conn.getContext().setAttribute(HttpAsyncRequestExecutor.HTTP_HANDLER, this);
594 conn.requestOutput();
595 this.routeEstablished = route.equals(conn.getRoute());
596 if (!conn.isOpen()) {
597 throw new ConnectionClosedException("Connection closed");
598 }
599 } catch (final IOException ex) {
600 failed(ex);
601 } catch (final RuntimeException runex) {
602 failed(runex);
603 throw runex;
604 }
605 }
606
607 private synchronized void connectionRequestFailed(final Exception ex) {
608 if (this.log.isDebugEnabled()) {
609 this.log.debug("[exchange: " + this.id + "] connection request failed");
610 }
611 this.connRequestCallback = null;
612 try {
613 this.resultCallback.failed(ex, this);
614 } finally {
615 close();
616 }
617 }
618
619 private synchronized void connectionRequestCancelled() {
620 if (this.log.isDebugEnabled()) {
621 this.log.debug("[exchange: " + this.id + "] Connection request cancelled");
622 }
623 this.connRequestCallback = null;
624 try {
625 this.resultCallback.cancelled(this);
626 } finally {
627 close();
628 }
629 }
630
631 class InternalFutureCallback implements FutureCallback<ManagedClientAsyncConnection> {
632
633 @Override
634 public void completed(final ManagedClientAsyncConnection session) {
635 connectionRequestCompleted(session);
636 }
637
638 @Override
639 public void failed(final Exception ex) {
640 connectionRequestFailed(ex);
641 }
642
643 @Override
644 public void cancelled() {
645 connectionRequestCancelled();
646 }
647
648 }
649
650 private void requestConnection() {
651 final HttpRoute route = this.mainRequest.getRoute();
652 if (this.log.isDebugEnabled()) {
653 this.log.debug("[exchange: " + this.id + "] Request connection for " + route);
654 }
655 final long connectTimeout = HttpConnectionParams.getConnectionTimeout(this.params);
656 final Object userToken = this.localContext.getAttribute(ClientContext.USER_TOKEN);
657 this.connRequestCallback = new InternalFutureCallback();
658 this.connmgr.leaseConnection(
659 route, userToken,
660 connectTimeout, TimeUnit.MILLISECONDS,
661 this.connRequestCallback);
662 }
663
664 public synchronized void endOfStream() {
665 if (this.managedConn != null) {
666 if (this.log.isDebugEnabled()) {
667 this.log.debug("[exchange: " + this.id + "] Unexpected end of data stream");
668 }
669 releaseConnection();
670 if (this.connRequestCallback == null) {
671 requestConnection();
672 }
673 }
674 }
675
676 protected HttpRoute determineRoute(
677 final HttpHost target,
678 final HttpRequest request,
679 final HttpContext context) throws HttpException {
680 final HttpHost t = target != null ? target :
681 (HttpHost) request.getParams().getParameter(ClientPNames.DEFAULT_HOST);
682 if (t == null) {
683 throw new IllegalStateException("Target host could not be resolved");
684 }
685 return this.routePlanner.determineRoute(t, request, context);
686 }
687
688 private RequestWrapper wrapRequest(final HttpRequest request) throws ProtocolException {
689 if (request instanceof HttpEntityEnclosingRequest) {
690 return new EntityEnclosingRequestWrapper((HttpEntityEnclosingRequest) request);
691 } else {
692 return new RequestWrapper(request);
693 }
694 }
695
696 protected void rewriteRequestURI(
697 final RequestWrapper request, final HttpRoute route) throws ProtocolException {
698 try {
699 URI uri = request.getURI();
700 if (route.getProxyHost() != null && !route.isTunnelled()) {
701 // Make sure the request URI is absolute
702 if (!uri.isAbsolute()) {
703 final HttpHost target = route.getTargetHost();
704 uri = URIUtils.rewriteURI(uri, target);
705 request.setURI(uri);
706 }
707 } else {
708 // Make sure the request URI is relative
709 if (uri.isAbsolute()) {
710 uri = URIUtils.rewriteURI(uri, null);
711 request.setURI(uri);
712 }
713 }
714 } catch (final URISyntaxException ex) {
715 throw new ProtocolException("Invalid URI: " + request.getRequestLine().getUri(), ex);
716 }
717 }
718
719 private AsyncSchemeRegistry getSchemeRegistry(final HttpContext context) {
720 AsyncSchemeRegistry reg = (AsyncSchemeRegistry) context.getAttribute(
721 ClientContext.SCHEME_REGISTRY);
722 if (reg == null) {
723 reg = this.connmgr.getSchemeRegistry();
724 }
725 return reg;
726 }
727
728 private HttpRequest createConnectRequest(final HttpRoute route) {
729 // see RFC 2817, section 5.2 and
730 // INTERNET-DRAFT: Tunneling TCP based protocols through
731 // Web proxy servers
732 final HttpHost target = route.getTargetHost();
733 final String host = target.getHostName();
734 int port = target.getPort();
735 if (port < 0) {
736 final AsyncSchemeRegistry registry = getSchemeRegistry(this.localContext);
737 final AsyncScheme scheme = registry.getScheme(target.getSchemeName());
738 port = scheme.getDefaultPort();
739 }
740 final StringBuilder buffer = new StringBuilder(host.length() + 6);
741 buffer.append(host);
742 buffer.append(':');
743 buffer.append(Integer.toString(port));
744 final ProtocolVersion ver = HttpProtocolParams.getVersion(this.params);
745 final HttpRequest req = new BasicHttpRequest("CONNECT", buffer.toString(), ver);
746 return req;
747 }
748
749 private RoutedRequest handleResponse() throws HttpException {
750 RoutedRequest followup = null;
751 if (HttpClientParams.isAuthenticating(this.params)) {
752 final CredentialsProvider credsProvider = (CredentialsProvider) this.localContext.getAttribute(
753 ClientContext.CREDS_PROVIDER);
754 if (credsProvider != null) {
755 followup = handleTargetChallenge(credsProvider);
756 if (followup != null) {
757 return followup;
758 }
759 followup = handleProxyChallenge(credsProvider);
760 if (followup != null) {
761 return followup;
762 }
763 }
764 }
765 if (HttpClientParams.isRedirecting(this.params)) {
766 followup = handleRedirect();
767 if (followup != null) {
768 return followup;
769 }
770 }
771 return null;
772 }
773
774 private RoutedRequest handleConnectResponse() throws HttpException {
775 RoutedRequest followup = null;
776 if (HttpClientParams.isAuthenticating(this.params)) {
777 final CredentialsProvider credsProvider = (CredentialsProvider) this.localContext.getAttribute(
778 ClientContext.CREDS_PROVIDER);
779 if (credsProvider != null) {
780 followup = handleProxyChallenge(credsProvider);
781 if (followup != null) {
782 return followup;
783 }
784 }
785 }
786 return null;
787 }
788
789 private RoutedRequest handleRedirect() throws HttpException {
790 if (this.redirectStrategy.isRedirected(
791 this.currentRequest, this.currentResponse, this.localContext)) {
792
793 final HttpRoute route = this.mainRequest.getRoute();
794 final RequestWrapper request = this.mainRequest.getRequest();
795
796 final int maxRedirects = this.params.getIntParameter(ClientPNames.MAX_REDIRECTS, 100);
797 if (this.redirectCount >= maxRedirects) {
798 throw new RedirectException("Maximum redirects ("
799 + maxRedirects + ") exceeded");
800 }
801 this.redirectCount++;
802
803 final HttpUriRequest redirect = this.redirectStrategy.getRedirect(
804 this.currentRequest, this.currentResponse, this.localContext);
805 final HttpRequest orig = request.getOriginal();
806 redirect.setHeaders(orig.getAllHeaders());
807
808 final URI uri = redirect.getURI();
809 if (uri.getHost() == null) {
810 throw new ProtocolException("Redirect URI does not specify a valid host name: " + uri);
811 }
812 final HttpHost newTarget = new HttpHost(uri.getHost(), uri.getPort(), uri.getScheme());
813
814 // Reset auth states if redirecting to another host
815 if (!route.getTargetHost().equals(newTarget)) {
816 if (this.log.isDebugEnabled()) {
817 this.log.debug("[exchange: " + this.id + "] Resetting target auth state");
818 }
819 this.targetAuthState.reset();
820 final AuthScheme authScheme = this.proxyAuthState.getAuthScheme();
821 if (authScheme != null && authScheme.isConnectionBased()) {
822 if (this.log.isDebugEnabled()) {
823 this.log.debug("[exchange: " + this.id + "] Resetting proxy auth state");
824 }
825 this.proxyAuthState.reset();
826 }
827 }
828
829 final RequestWrapper newRequest = wrapRequest(redirect);
830 newRequest.setParams(this.params);
831
832 final HttpRoute newRoute = determineRoute(newTarget, newRequest, this.localContext);
833
834 if (this.log.isDebugEnabled()) {
835 this.log.debug("[exchange: " + this.id + "] Redirecting to '" + uri + "' via " + newRoute);
836 }
837 return new RoutedRequest(newRequest, newRoute);
838 }
839 return null;
840 }
841
842 private RoutedRequest handleTargetChallenge(
843 final CredentialsProvider credsProvider) throws HttpException {
844 final HttpRoute route = this.mainRequest.getRoute();
845 HttpHost target = (HttpHost) this.localContext.getAttribute(
846 ExecutionContext.HTTP_TARGET_HOST);
847 if (target == null) {
848 target = route.getTargetHost();
849 }
850 if (this.authenticator.isAuthenticationRequested(target, this.currentResponse,
851 this.targetAuthStrategy, this.targetAuthState, this.localContext)) {
852 if (this.authenticator.authenticate(target, this.currentResponse,
853 this.targetAuthStrategy, this.targetAuthState, this.localContext)) {
854 // Re-try the same request via the same route
855 return this.mainRequest;
856 } else {
857 return null;
858 }
859 }
860 return null;
861 }
862
863 private RoutedRequest handleProxyChallenge(
864 final CredentialsProvider credsProvider) throws HttpException {
865 final HttpRoute route = this.mainRequest.getRoute();
866 final HttpHost proxy = route.getProxyHost();
867 if (this.authenticator.isAuthenticationRequested(proxy, this.currentResponse,
868 this.proxyAuthStrategy, this.proxyAuthState, this.localContext)) {
869 if (this.authenticator.authenticate(proxy, this.currentResponse,
870 this.proxyAuthStrategy, this.proxyAuthState, this.localContext)) {
871 // Re-try the same request via the same route
872 return this.mainRequest;
873 } else {
874 return null;
875 }
876 }
877 return null;
878 }
879
880 @Override
881 public HttpContext getContext() {
882 return this.localContext;
883 }
884
885 @Override
886 public HttpProcessor getHttpProcessor() {
887 return this.httppocessor;
888 }
889
890 @Override
891 public ConnectionReuseStrategy getConnectionReuseStrategy() {
892 return this.reuseStrategy;
893 }
894
895 }
0 /*
1 * ====================================================================
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 * ====================================================================
19 *
20 * This software consists of voluntary contributions made by many
21 * individuals on behalf of the Apache Software Foundation. For more
22 * information on the Apache Software Foundation, please see
23 * <http://www.apache.org/>.
24 *
25 */
26 package org.apache.http.impl.nio.client;
27
28 import org.apache.http.HttpVersion;
29 import org.apache.http.client.protocol.RequestAddCookies;
30 import org.apache.http.client.protocol.RequestAuthCache;
31 import org.apache.http.client.protocol.RequestClientConnControl;
32 import org.apache.http.client.protocol.RequestDefaultHeaders;
33 import org.apache.http.client.protocol.RequestProxyAuthentication;
34 import org.apache.http.client.protocol.RequestTargetAuthentication;
35 import org.apache.http.client.protocol.ResponseProcessCookies;
36 import org.apache.http.impl.nio.reactor.IOReactorConfig;
37 import org.apache.http.nio.conn.ClientAsyncConnectionManager;
38 import org.apache.http.nio.reactor.IOReactorException;
39 import org.apache.http.params.HttpConnectionParams;
40 import org.apache.http.params.HttpParams;
41 import org.apache.http.params.HttpProtocolParams;
42 import org.apache.http.params.SyncBasicHttpParams;
43 import org.apache.http.protocol.BasicHttpProcessor;
44 import org.apache.http.protocol.HTTP;
45 import org.apache.http.protocol.RequestContent;
46 import org.apache.http.protocol.RequestExpectContinue;
47 import org.apache.http.protocol.RequestTargetHost;
48 import org.apache.http.protocol.RequestUserAgent;
49 import org.apache.http.util.VersionInfo;
50
51 @Deprecated
52 public class DefaultHttpAsyncClient extends AbstractHttpAsyncClient {
53
54 public DefaultHttpAsyncClient(final ClientAsyncConnectionManager connmgr) {
55 super(connmgr);
56 }
57
58 public DefaultHttpAsyncClient(final IOReactorConfig config) throws IOReactorException {
59 super(config);
60 }
61
62 public DefaultHttpAsyncClient() throws IOReactorException {
63 super(new IOReactorConfig());
64 }
65
66 @Override
67 protected HttpParams createHttpParams() {
68 final HttpParams params = new SyncBasicHttpParams();
69 setDefaultHttpParams(params);
70 return params;
71 }
72
73 public static void setDefaultHttpParams(final HttpParams params) {
74 HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
75 HttpProtocolParams.setContentCharset(params, HTTP.DEF_CONTENT_CHARSET.name());
76 HttpConnectionParams.setTcpNoDelay(params, true);
77 HttpConnectionParams.setSocketBufferSize(params, 8192);
78 HttpProtocolParams.setUserAgent(params, VersionInfo.getUserAgent(
79 "Apache-HttpAsyncClient",
80 "org.apache.http.nio.client", DefaultHttpAsyncClient.class));
81 }
82
83 @Override
84 protected BasicHttpProcessor createHttpProcessor() {
85 final BasicHttpProcessor httpproc = new BasicHttpProcessor();
86 httpproc.addInterceptor(new RequestDefaultHeaders());
87 // Required protocol interceptors
88 httpproc.addInterceptor(new RequestContent());
89 httpproc.addInterceptor(new RequestTargetHost());
90 // Recommended protocol interceptors
91 httpproc.addInterceptor(new RequestClientConnControl());
92 httpproc.addInterceptor(new RequestUserAgent());
93 httpproc.addInterceptor(new RequestExpectContinue());
94 // HTTP state management interceptors
95 httpproc.addInterceptor(new RequestAddCookies());
96 httpproc.addInterceptor(new ResponseProcessCookies());
97 // HTTP authentication interceptors
98 httpproc.addInterceptor(new RequestAuthCache());
99 httpproc.addInterceptor(new RequestTargetAuthentication());
100 httpproc.addInterceptor(new RequestProxyAuthentication());
101 return httpproc;
102 }
103
104 }
0 /*
1 * ====================================================================
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 * ====================================================================
19 *
20 * This software consists of voluntary contributions made by many
21 * individuals on behalf of the Apache Software Foundation. For more
22 * information on the Apache Software Foundation, please see
23 * <http://www.apache.org/>.
24 *
25 */
26 package org.apache.http.impl.nio.client;
27
28 import java.util.Queue;
29
30 import org.apache.http.concurrent.BasicFuture;
31 import org.apache.http.nio.protocol.HttpAsyncRequestExecutionHandler;
32
33 @Deprecated
34 class DefaultResultCallback<T> implements ResultCallback<T> {
35
36 private final BasicFuture<T> future;
37 private final Queue<HttpAsyncRequestExecutionHandler<?>> queue;
38
39 DefaultResultCallback(
40 final BasicFuture<T> future, final Queue<HttpAsyncRequestExecutionHandler<?>> queue) {
41 super();
42 this.future = future;
43 this.queue = queue;
44 }
45
46 @Override
47 public void completed(final T result, final HttpAsyncRequestExecutionHandler<T> handler) {
48 this.future.completed(result);
49 this.queue.remove(handler);
50 }
51
52 @Override
53 public void failed(final Exception ex, final HttpAsyncRequestExecutionHandler<T> handler) {
54 this.future.failed(ex);
55 this.queue.remove(handler);
56 }
57
58 @Override
59 public void cancelled(final HttpAsyncRequestExecutionHandler<T> handler) {
60 this.future.cancel(true);
61 this.queue.remove(handler);
62 }
63
64 @Override
65 public boolean isDone() {
66 return this.future.isDone();
67 }
68
69 }
0 /*
1 * ====================================================================
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 * ====================================================================
19 *
20 * This software consists of voluntary contributions made by many
21 * individuals on behalf of the Apache Software Foundation. For more
22 * information on the Apache Software Foundation, please see
23 * <http://www.apache.org/>.
24 *
25 */
26 package org.apache.http.impl.nio.client;
27
28 import java.util.Collection;
29
30 import org.apache.http.auth.params.AuthPNames;
31 import org.apache.http.client.config.RequestConfig;
32 import org.apache.http.client.params.ClientPNames;
33 import org.apache.http.client.params.HttpClientParams;
34 import org.apache.http.conn.params.ConnRouteParams;
35 import org.apache.http.params.HttpConnectionParams;
36 import org.apache.http.params.HttpParams;
37 import org.apache.http.params.HttpProtocolParams;
38
39 @Deprecated
40 final class ParamConfig {
41
42 private ParamConfig() {
43 }
44
45 @SuppressWarnings("unchecked")
46 public static RequestConfig getRequestConfig(final HttpParams params) {
47 return RequestConfig.custom()
48 .setAuthenticationEnabled(HttpClientParams.isAuthenticating(params))
49 .setCircularRedirectsAllowed(params.getBooleanParameter(ClientPNames.ALLOW_CIRCULAR_REDIRECTS, false))
50 .setConnectionRequestTimeout((int) HttpClientParams.getConnectionManagerTimeout(params))
51 .setConnectTimeout(HttpConnectionParams.getConnectionTimeout(params))
52 .setCookieSpec(HttpClientParams.getCookiePolicy(params))
53 .setProxy(ConnRouteParams.getDefaultProxy(params))
54 .setExpectContinueEnabled(HttpProtocolParams.useExpectContinue(params))
55 .setLocalAddress(ConnRouteParams.getLocalAddress(params))
56 .setMaxRedirects(params.getIntParameter(ClientPNames.MAX_REDIRECTS, 50))
57 .setProxyPreferredAuthSchemes((Collection<String>) params.getParameter(
58 AuthPNames.PROXY_AUTH_PREF))
59 .setTargetPreferredAuthSchemes((Collection<String>) params.getParameter(
60 AuthPNames.TARGET_AUTH_PREF))
61 .setRedirectsEnabled(HttpClientParams.isRedirecting(params))
62 .setRelativeRedirectsAllowed(!params.getBooleanParameter(ClientPNames.REJECT_RELATIVE_REDIRECT, false))
63 .setSocketTimeout(HttpConnectionParams.getSoTimeout(params))
64 .setStaleConnectionCheckEnabled(HttpConnectionParams.isStaleCheckingEnabled(params))
65 .build();
66 }
67
68 }
0 /*
1 * ====================================================================
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 * ====================================================================
19 *
20 * This software consists of voluntary contributions made by many
21 * individuals on behalf of the Apache Software Foundation. For more
22 * information on the Apache Software Foundation, please see
23 * <http://www.apache.org/>.
24 *
25 */
26 package org.apache.http.impl.nio.client;
27
28 import org.apache.http.nio.protocol.HttpAsyncRequestExecutionHandler;
29
30 @Deprecated
31 interface ResultCallback<T> {
32
33 void completed(T result, HttpAsyncRequestExecutionHandler<T> handler);
34
35 void failed(Exception ex, HttpAsyncRequestExecutionHandler<T> handler);
36
37 void cancelled(HttpAsyncRequestExecutionHandler<T> handler);
38
39 boolean isDone();
40
41 }
0 /*
1 * ====================================================================
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 * ====================================================================
19 *
20 * This software consists of voluntary contributions made by many
21 * individuals on behalf of the Apache Software Foundation. For more
22 * information on the Apache Software Foundation, please see
23 * <http://www.apache.org/>.
24 *
25 */
26 package org.apache.http.impl.nio.conn;
27
28 import org.apache.http.annotation.ThreadSafe;
29 import org.apache.http.nio.conn.scheme.AsyncScheme;
30 import org.apache.http.nio.conn.scheme.AsyncSchemeRegistry;
31 import org.apache.http.nio.conn.ssl.SSLLayeringStrategy;
32
33 @Deprecated
34 @ThreadSafe
35 public final class AsyncSchemeRegistryFactory {
36
37 public static AsyncSchemeRegistry createDefault() {
38 final AsyncSchemeRegistry registry = new AsyncSchemeRegistry();
39 registry.register(
40 new AsyncScheme("http", 80, null));
41 registry.register(
42 new AsyncScheme("https", 443, SSLLayeringStrategy.getDefaultStrategy()));
43 return registry;
44 }
45
46 }
47
0 /*
1 * ====================================================================
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 * ====================================================================
19 *
20 * This software consists of voluntary contributions made by many
21 * individuals on behalf of the Apache Software Foundation. For more
22 * information on the Apache Software Foundation, please see
23 * <http://www.apache.org/>.
24 *
25 */
26 package org.apache.http.impl.nio.conn;
27
28 import org.apache.commons.logging.Log;
29 import org.apache.commons.logging.LogFactory;
30 import org.apache.http.Header;
31 import org.apache.http.HttpRequest;
32 import org.apache.http.HttpResponse;
33 import org.apache.http.HttpResponseFactory;
34 import org.apache.http.impl.nio.DefaultNHttpClientConnection;
35 import org.apache.http.nio.conn.ClientAsyncConnection;
36 import org.apache.http.nio.reactor.IOSession;
37 import org.apache.http.nio.util.ByteBufferAllocator;
38 import org.apache.http.params.HttpParams;
39
40 @Deprecated
41 public class DefaultClientAsyncConnection
42 extends DefaultNHttpClientConnection implements ClientAsyncConnection {
43
44 private final Log headerlog = LogFactory.getLog("org.apache.http.headers");
45 private final Log wirelog = LogFactory.getLog("org.apache.http.wire");
46 private final Log log;
47
48 private final String id;
49 private IOSession original;
50
51 public DefaultClientAsyncConnection(
52 final String id,
53 final IOSession iosession,
54 final HttpResponseFactory responseFactory,
55 final ByteBufferAllocator allocator,
56 final HttpParams params) {
57 super(iosession, responseFactory, allocator, params);
58 this.id = id;
59 this.original = iosession;
60 this.log = LogFactory.getLog(iosession.getClass());
61 if (this.log.isDebugEnabled() || this.wirelog.isDebugEnabled()) {
62 bind(new LoggingIOSession(iosession, this.id, this.log, this.wirelog));
63 }
64 }
65
66 @Override
67 public void upgrade(final IOSession iosession) {
68 this.original = iosession;
69 if (this.log.isDebugEnabled() || this.wirelog.isDebugEnabled()) {
70 this.log.debug(this.id + " Upgrade session " + iosession);
71 bind(new LoggingIOSession(iosession, this.id, this.headerlog, this.wirelog));
72 } else {
73 bind(iosession);
74 }
75 }
76
77 @Override
78 public IOSession getIOSession() {
79 return this.original;
80 }
81
82 public String getId() {
83 return this.id;
84 }
85
86 @Override
87 protected void onResponseReceived(final HttpResponse response) {
88 if (response != null && this.headerlog.isDebugEnabled()) {
89 this.headerlog.debug(this.id + " << " + response.getStatusLine().toString());
90 final Header[] headers = response.getAllHeaders();
91 for (final Header header : headers) {
92 this.headerlog.debug(this.id + " << " + header.toString());
93 }
94 }
95 }
96
97 @Override
98 protected void onRequestSubmitted(final HttpRequest request) {
99 if (request != null && this.headerlog.isDebugEnabled()) {
100 this.headerlog.debug(this.id + " >> " + request.getRequestLine().toString());
101 final Header[] headers = request.getAllHeaders();
102 for (final Header header : headers) {
103 this.headerlog.debug(this.id + " >> " + header.toString());
104 }
105 }
106 }
107
108 @Override
109 public String toString() {
110 final StringBuilder buf = new StringBuilder();
111 buf.append(this.id);
112 buf.append(" [");
113 switch (this.status) {
114 case ACTIVE:
115 buf.append("ACTIVE");
116 if (this.inbuf.hasData()) {
117 buf.append("(").append(this.inbuf.length()).append(")");
118 }
119 break;
120 case CLOSING:
121 buf.append("CLOSING");
122 break;
123 case CLOSED:
124 buf.append("CLOSED");
125 break;
126 }
127 buf.append("]");
128 return buf.toString();
129 }
130
131 }
0 /*
1 * ====================================================================
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 * ====================================================================
19 *
20 * This software consists of voluntary contributions made by many
21 * individuals on behalf of the Apache Software Foundation. For more
22 * information on the Apache Software Foundation, please see
23 * <http://www.apache.org/>.
24 *
25 */
26 package org.apache.http.impl.nio.conn;
27
28 import java.nio.charset.Charset;
29 import java.nio.charset.CharsetDecoder;
30 import java.nio.charset.CharsetEncoder;
31 import java.nio.charset.CodingErrorAction;
32 import java.util.concurrent.atomic.AtomicLong;
33
34 import org.apache.commons.logging.Log;
35 import org.apache.commons.logging.LogFactory;
36 import org.apache.http.HttpResponse;
37 import org.apache.http.HttpResponseFactory;
38 import org.apache.http.config.ConnectionConfig;
39 import org.apache.http.impl.DefaultHttpResponseFactory;
40 import org.apache.http.impl.nio.codecs.DefaultHttpResponseParserFactory;
41 import org.apache.http.message.BasicLineParser;
42 import org.apache.http.nio.NHttpMessageParserFactory;
43 import org.apache.http.nio.conn.ClientAsyncConnection;
44 import org.apache.http.nio.conn.ClientAsyncConnectionFactory;
45 import org.apache.http.nio.conn.ManagedNHttpClientConnection;
46 import org.apache.http.nio.conn.NHttpConnectionFactory;
47 import org.apache.http.nio.reactor.IOEventDispatch;
48 import org.apache.http.nio.reactor.IOSession;
49 import org.apache.http.nio.util.ByteBufferAllocator;
50 import org.apache.http.nio.util.HeapByteBufferAllocator;
51 import org.apache.http.params.HttpParams;
52
53 @Deprecated
54 public class DefaultClientAsyncConnectionFactory
55 implements ClientAsyncConnectionFactory, NHttpConnectionFactory<ManagedNHttpClientConnection> {
56
57 private final Log headerlog = LogFactory.getLog("org.apache.http.headers");
58 private final Log wirelog = LogFactory.getLog("org.apache.http.wire");
59 private final Log log = LogFactory.getLog(ManagedNHttpClientConnectionImpl.class);
60
61 public static final DefaultClientAsyncConnectionFactory INSTANCE = new DefaultClientAsyncConnectionFactory(null, null);
62
63 private static AtomicLong COUNTER = new AtomicLong();
64
65 private final HttpResponseFactory responseFactory;
66 private final NHttpMessageParserFactory<HttpResponse> responseParserFactory;
67 private final ByteBufferAllocator allocator;
68
69 public DefaultClientAsyncConnectionFactory(
70 final NHttpMessageParserFactory<HttpResponse> responseParserFactory,
71 final ByteBufferAllocator allocator) {
72 super();
73 this.responseFactory = createHttpResponseFactory();
74 this.responseParserFactory = responseParserFactory != null ? responseParserFactory :
75 DefaultHttpResponseParserFactory.INSTANCE;
76 this.allocator = allocator != null ? allocator : HeapByteBufferAllocator.INSTANCE;
77 }
78
79 public DefaultClientAsyncConnectionFactory() {
80 super();
81 this.responseFactory = createHttpResponseFactory();
82 this.responseParserFactory = new DefaultHttpResponseParserFactory(
83 BasicLineParser.INSTANCE, this.responseFactory);
84 this.allocator = createByteBufferAllocator();
85 }
86
87 @Override
88 @Deprecated
89 public ClientAsyncConnection create(
90 final String id,
91 final IOSession iosession,
92 final HttpParams params) {
93 return new DefaultClientAsyncConnection(
94 id, iosession, this.responseFactory, this.allocator, params);
95 }
96
97 @Deprecated
98 protected ByteBufferAllocator createByteBufferAllocator() {
99 return HeapByteBufferAllocator.INSTANCE;
100 }
101
102 @Deprecated
103 protected HttpResponseFactory createHttpResponseFactory() {
104 return DefaultHttpResponseFactory.INSTANCE;
105 }
106
107 @Override
108 public ManagedNHttpClientConnection create(
109 final IOSession iosession, final ConnectionConfig config) {
110 final String id = "http-outgoing-" + Long.toString(COUNTER.getAndIncrement());
111 CharsetDecoder chardecoder = null;
112 CharsetEncoder charencoder = null;
113 final Charset charset = config.getCharset();
114 final CodingErrorAction malformedInputAction = config.getMalformedInputAction() != null ?
115 config.getMalformedInputAction() : CodingErrorAction.REPORT;
116 final CodingErrorAction unmappableInputAction = config.getUnmappableInputAction() != null ?
117 config.getUnmappableInputAction() : CodingErrorAction.REPORT;
118 if (charset != null) {
119 chardecoder = charset.newDecoder();
120 chardecoder.onMalformedInput(malformedInputAction);
121 chardecoder.onUnmappableCharacter(unmappableInputAction);
122 charencoder = charset.newEncoder();
123 charencoder.onMalformedInput(malformedInputAction);
124 charencoder.onUnmappableCharacter(unmappableInputAction);
125 }
126 final ManagedNHttpClientConnection conn = new ManagedNHttpClientConnectionImpl(
127 id,
128 this.log,
129 this.headerlog,
130 this.wirelog,
131 iosession,
132 config.getBufferSize(),
133 config.getFragmentSizeHint(),
134 this.allocator,
135 chardecoder, charencoder, config.getMessageConstraints(),
136 null, null, null,
137 this.responseParserFactory);
138 iosession.setAttribute(IOEventDispatch.CONNECTION_KEY, conn);
139 return conn;
140 }
141
142 }
0 /*
1 * ====================================================================
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 * ====================================================================
19 *
20 * This software consists of voluntary contributions made by many
21 * individuals on behalf of the Apache Software Foundation. For more
22 * information on the Apache Software Foundation, please see
23 * <http://www.apache.org/>.
24 *
25 */
26
27 package org.apache.http.impl.nio.conn;
28
29 import java.net.InetAddress;
30
31 import org.apache.http.HttpException;
32 import org.apache.http.HttpHost;
33 import org.apache.http.HttpRequest;
34 import org.apache.http.client.protocol.ClientContext;
35 import org.apache.http.conn.params.ConnRouteParams;
36 import org.apache.http.conn.routing.HttpRoute;
37 import org.apache.http.conn.routing.HttpRoutePlanner;
38 import org.apache.http.nio.conn.scheme.AsyncScheme;
39 import org.apache.http.nio.conn.scheme.AsyncSchemeRegistry;
40 import org.apache.http.nio.conn.scheme.LayeringStrategy;
41 import org.apache.http.protocol.HttpContext;
42
43 @Deprecated
44 public class DefaultHttpAsyncRoutePlanner implements HttpRoutePlanner {
45
46 private final AsyncSchemeRegistry schemeRegistry;
47
48 public DefaultHttpAsyncRoutePlanner(final AsyncSchemeRegistry schemeRegistry) {
49 super();
50 this.schemeRegistry = schemeRegistry;
51 }
52
53 private AsyncSchemeRegistry getSchemeRegistry(final HttpContext context) {
54 AsyncSchemeRegistry reg = (AsyncSchemeRegistry) context.getAttribute(
55 ClientContext.SCHEME_REGISTRY);
56 if (reg == null) {
57 reg = this.schemeRegistry;
58 }
59 return reg;
60 }
61
62 @Override
63 public HttpRoute determineRoute(
64 final HttpHost target,
65 final HttpRequest request,
66 final HttpContext context) throws HttpException {
67 if (request == null) {
68 throw new IllegalStateException("Request may not be null");
69 }
70 HttpRoute route = ConnRouteParams.getForcedRoute(request.getParams());
71 if (route != null) {
72 return route;
73 }
74 if (target == null) {
75 throw new IllegalStateException("Target host may be null");
76 }
77 final InetAddress local = ConnRouteParams.getLocalAddress(request.getParams());
78 final HttpHost proxy = ConnRouteParams.getDefaultProxy(request.getParams());
79 AsyncScheme scheme;
80 try {
81 final AsyncSchemeRegistry registry = getSchemeRegistry(context);
82 scheme = registry.getScheme(target);
83 } catch (final IllegalStateException ex) {
84 throw new HttpException(ex.getMessage());
85 }
86 final LayeringStrategy layeringStrategy = scheme.getLayeringStrategy();
87 final boolean secure = layeringStrategy != null && layeringStrategy.isSecure();
88 if (proxy == null) {
89 route = new HttpRoute(target, local, secure);
90 } else {
91 route = new HttpRoute(target, local, proxy, secure);
92 }
93 return route;
94 }
95
96 }
0 /*
1 * ====================================================================
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 * ====================================================================
19 *
20 * This software consists of voluntary contributions made by many
21 * individuals on behalf of the Apache Software Foundation. For more
22 * information on the Apache Software Foundation, please see
23 * <http://www.apache.org/>.
24 *
25 */
26 package org.apache.http.impl.nio.conn;
27
28 import java.net.InetSocketAddress;
29 import java.net.SocketAddress;
30 import java.util.concurrent.TimeUnit;
31 import java.util.concurrent.atomic.AtomicLong;
32
33 import org.apache.commons.logging.Log;
34 import org.apache.http.HttpHost;
35 import org.apache.http.conn.routing.HttpRoute;
36 import org.apache.http.nio.conn.scheme.AsyncScheme;
37 import org.apache.http.nio.conn.scheme.AsyncSchemeRegistry;
38 import org.apache.http.nio.pool.AbstractNIOConnPool;
39 import org.apache.http.nio.reactor.ConnectingIOReactor;
40 import org.apache.http.nio.reactor.IOSession;
41
42 @Deprecated
43 class HttpNIOConnPool extends AbstractNIOConnPool<HttpRoute, IOSession, HttpPoolEntry> {
44
45 private static final AtomicLong COUNTER = new AtomicLong(1);
46
47 private final Log log;
48 private final AsyncSchemeRegistry schemeRegistry;
49 private final long connTimeToLive;
50 private final TimeUnit tunit;
51
52 HttpNIOConnPool(
53 final Log log,
54 final ConnectingIOReactor ioreactor,
55 final AsyncSchemeRegistry schemeRegistry,
56 final long connTimeToLive, final TimeUnit tunit) {
57 super(ioreactor, new HttpNIOConnPoolFactory(), 2, 20);
58 this.log = log;
59 this.schemeRegistry = schemeRegistry;
60 this.connTimeToLive = connTimeToLive;
61 this.tunit = tunit;
62 }
63
64 @Override
65 protected SocketAddress resolveLocalAddress(final HttpRoute route) {
66 return new InetSocketAddress(route.getLocalAddress(), 0);
67 }
68
69 @Override
70 protected SocketAddress resolveRemoteAddress(final HttpRoute route) {
71 HttpHost firsthop = route.getProxyHost();
72 if (firsthop == null) {
73 firsthop = route.getTargetHost();
74 }
75 final String hostname = firsthop.getHostName();
76 int port = firsthop.getPort();
77 if (port < 0) {
78 final AsyncScheme scheme = this.schemeRegistry.getScheme(firsthop);
79 port = scheme.resolvePort(port);
80 }
81 return new InetSocketAddress(hostname, port);
82 }
83
84 @Override
85 protected HttpPoolEntry createEntry(final HttpRoute route, final IOSession session) {
86 final String id = Long.toString(COUNTER.getAndIncrement());
87 return new HttpPoolEntry(this.log, id, route, session, this.connTimeToLive, this.tunit);
88 }
89
90 }
0 /*
1 * ====================================================================
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 * ====================================================================
19 *
20 * This software consists of voluntary contributions made by many
21 * individuals on behalf of the Apache Software Foundation. For more
22 * information on the Apache Software Foundation, please see
23 * <http://www.apache.org/>.
24 *
25 */
26 package org.apache.http.impl.nio.conn;
27
28 import java.io.IOException;
29
30 import org.apache.http.conn.routing.HttpRoute;
31 import org.apache.http.nio.pool.NIOConnFactory;
32 import org.apache.http.nio.reactor.IOSession;
33
34 @Deprecated
35 class HttpNIOConnPoolFactory implements NIOConnFactory<HttpRoute, IOSession> {
36
37 @Override
38 public IOSession create(final HttpRoute route, final IOSession session) throws IOException {
39 return session;
40 }
41
42 }
0 /*
1 * ====================================================================
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 * ====================================================================
19 *
20 * This software consists of voluntary contributions made by many
21 * individuals on behalf of the Apache Software Foundation. For more
22 * information on the Apache Software Foundation, please see
23 * <http://www.apache.org/>.
24 *
25 */
26 package org.apache.http.impl.nio.conn;
27
28 import java.io.IOException;
29 import java.util.Date;
30 import java.util.concurrent.TimeUnit;
31
32 import org.apache.commons.logging.Log;
33 import org.apache.http.conn.routing.HttpRoute;
34 import org.apache.http.conn.routing.RouteTracker;
35 import org.apache.http.nio.conn.ClientAsyncConnection;
36 import org.apache.http.nio.reactor.IOEventDispatch;
37 import org.apache.http.nio.reactor.IOSession;
38 import org.apache.http.pool.PoolEntry;
39
40 @Deprecated
41 class HttpPoolEntry extends PoolEntry<HttpRoute, IOSession> {
42
43 private final Log log;
44 private final RouteTracker tracker;
45
46 HttpPoolEntry(final Log log, final String id, final HttpRoute route, final IOSession session,
47 final long timeToLive, final TimeUnit tunit) {
48 super(id, route, session, timeToLive, tunit);
49 this.log = log;
50 this.tracker = new RouteTracker(route);
51 }
52
53 @Override
54 public boolean isExpired(final long now) {
55 final boolean expired = super.isExpired(now);
56 if (expired && this.log.isDebugEnabled()) {
57 this.log.debug("Connection " + this + " expired @ " + new Date(getExpiry()));
58 }
59 return expired;
60 }
61
62 public ClientAsyncConnection getOperatedClientConnection() {
63 final IOSession session = getConnection();
64 return (ClientAsyncConnection) session.getAttribute(IOEventDispatch.CONNECTION_KEY);
65 }
66
67 @Override
68 public void close() {
69 try {
70 getOperatedClientConnection().shutdown();
71 } catch (final IOException ex) {
72 if (this.log.isDebugEnabled()) {
73 this.log.debug("I/O error shutting down connection", ex);
74 }
75 }
76 }
77
78 @Override
79 public boolean isClosed() {
80 final IOSession session = getConnection();
81 return session.isClosed();
82 }
83
84 HttpRoute getPlannedRoute() {
85 return super.getRoute();
86 }
87
88 RouteTracker getTracker() {
89 return this.tracker;
90 }
91
92 HttpRoute getEffectiveRoute() {
93 return this.tracker.toRoute();
94 }
95
96 }
0 /*
1 * ====================================================================
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 * ====================================================================
19 *
20 * This software consists of voluntary contributions made by many
21 * individuals on behalf of the Apache Software Foundation. For more
22 * information on the Apache Software Foundation, please see
23 * <http://www.apache.org/>.
24 *
25 */
26 package org.apache.http.impl.nio.conn;
27
28 import java.io.IOException;
29 import java.net.InetAddress;
30 import java.util.concurrent.TimeUnit;
31
32 import javax.net.ssl.SSLSession;
33
34 import org.apache.http.HttpConnectionMetrics;
35 import org.apache.http.HttpException;
36 import org.apache.http.HttpHost;
37 import org.apache.http.HttpRequest;
38 import org.apache.http.HttpResponse;
39 import org.apache.http.client.protocol.ClientContext;
40 import org.apache.http.conn.routing.HttpRoute;
41 import org.apache.http.conn.routing.RouteTracker;
42 import org.apache.http.impl.conn.ConnectionShutdownException;
43 import org.apache.http.nio.conn.ClientAsyncConnection;
44 import org.apache.http.nio.conn.ClientAsyncConnectionFactory;
45 import org.apache.http.nio.conn.ClientAsyncConnectionManager;
46 import org.apache.http.nio.conn.ManagedClientAsyncConnection;
47 import org.apache.http.nio.conn.scheme.AsyncScheme;
48 import org.apache.http.nio.conn.scheme.AsyncSchemeRegistry;
49 import org.apache.http.nio.conn.scheme.LayeringStrategy;
50 import org.apache.http.nio.reactor.IOEventDispatch;
51 import org.apache.http.nio.reactor.IOSession;
52 import org.apache.http.nio.reactor.ssl.SSLIOSession;
53 import org.apache.http.params.HttpParams;
54 import org.apache.http.protocol.HttpContext;
55
56 @Deprecated
57 class ManagedClientAsyncConnectionImpl implements ManagedClientAsyncConnection {
58
59 private final ClientAsyncConnectionManager manager;
60 private final ClientAsyncConnectionFactory connFactory;
61 private volatile HttpPoolEntry poolEntry;
62 private volatile boolean reusable;
63 private volatile long duration;
64
65 ManagedClientAsyncConnectionImpl(
66 final ClientAsyncConnectionManager manager,
67 final ClientAsyncConnectionFactory connFactory,
68 final HttpPoolEntry poolEntry) {
69 super();
70 this.manager = manager;
71 this.connFactory = connFactory;
72 this.poolEntry = poolEntry;
73 this.reusable = true;
74 this.duration = Long.MAX_VALUE;
75 }
76
77 HttpPoolEntry getPoolEntry() {
78 return this.poolEntry;
79 }
80
81 HttpPoolEntry detach() {
82 final HttpPoolEntry local = this.poolEntry;
83 this.poolEntry = null;
84 return local;
85 }
86
87 public ClientAsyncConnectionManager getManager() {
88 return this.manager;
89 }
90
91 private ClientAsyncConnection getConnection() {
92 final HttpPoolEntry local = this.poolEntry;
93 if (local == null) {
94 return null;
95 }
96 final IOSession session = local.getConnection();
97 return (ClientAsyncConnection) session.getAttribute(IOEventDispatch.CONNECTION_KEY);
98 }
99
100 private ClientAsyncConnection ensureConnection() {
101 final HttpPoolEntry local = this.poolEntry;
102 if (local == null) {
103 throw new ConnectionShutdownException();
104 }
105 final IOSession session = local.getConnection();
106 return (ClientAsyncConnection) session.getAttribute(IOEventDispatch.CONNECTION_KEY);
107 }
108
109 private HttpPoolEntry ensurePoolEntry() {
110 final HttpPoolEntry local = this.poolEntry;
111 if (local == null) {
112 throw new ConnectionShutdownException();
113 }
114 return local;
115 }
116
117 @Override
118 public void close() throws IOException {
119 final ClientAsyncConnection conn = getConnection();
120 if (conn != null) {
121 conn.close();
122 }
123 }
124
125 @Override
126 public void shutdown() throws IOException {
127 final ClientAsyncConnection conn = getConnection();
128 if (conn != null) {
129 conn.shutdown();
130 }
131 }
132
133 @Override
134 public boolean isOpen() {
135 final ClientAsyncConnection conn = getConnection();
136 if (conn != null) {
137 return conn.isOpen();
138 } else {
139 return false;
140 }
141 }
142
143 @Override
144 public boolean isStale() {
145 return isOpen();
146 }
147
148 @Override
149 public void setSocketTimeout(final int timeout) {
150 final ClientAsyncConnection conn = ensureConnection();
151 conn.setSocketTimeout(timeout);
152 }
153
154 @Override
155 public int getSocketTimeout() {
156 final ClientAsyncConnection conn = ensureConnection();
157 return conn.getSocketTimeout();
158 }
159
160 @Override
161 public HttpConnectionMetrics getMetrics() {
162 final ClientAsyncConnection conn = ensureConnection();
163 return conn.getMetrics();
164 }
165
166 @Override
167 public InetAddress getLocalAddress() {
168 final ClientAsyncConnection conn = ensureConnection();
169 return conn.getLocalAddress();
170 }
171
172 @Override
173 public int getLocalPort() {
174 final ClientAsyncConnection conn = ensureConnection();
175 return conn.getLocalPort();
176 }
177
178 @Override
179 public InetAddress getRemoteAddress() {
180 final ClientAsyncConnection conn = ensureConnection();
181 return conn.getRemoteAddress();
182 }
183
184 @Override
185 public int getRemotePort() {
186 final ClientAsyncConnection conn = ensureConnection();
187 return conn.getRemotePort();
188 }
189
190 @Override
191 public int getStatus() {
192 final ClientAsyncConnection conn = ensureConnection();
193 return conn.getStatus();
194 }
195
196 @Override
197 public HttpRequest getHttpRequest() {
198 final ClientAsyncConnection conn = ensureConnection();
199 return conn.getHttpRequest();
200 }
201
202 @Override
203 public HttpResponse getHttpResponse() {
204 final ClientAsyncConnection conn = ensureConnection();
205 return conn.getHttpResponse();
206 }
207
208 @Override
209 public HttpContext getContext() {
210 final ClientAsyncConnection conn = ensureConnection();
211 return conn.getContext();
212 }
213
214 @Override
215 public void requestInput() {
216 final ClientAsyncConnection conn = ensureConnection();
217 conn.requestInput();
218 }
219
220 @Override
221 public void suspendInput() {
222 final ClientAsyncConnection conn = ensureConnection();
223 conn.suspendInput();
224 }
225
226 @Override
227 public void requestOutput() {
228 final ClientAsyncConnection conn = ensureConnection();
229 conn.requestOutput();
230 }
231
232 @Override
233 public void suspendOutput() {
234 final ClientAsyncConnection conn = ensureConnection();
235 conn.suspendOutput();
236 }
237
238 @Override
239 public void submitRequest(final HttpRequest request) throws IOException, HttpException {
240 final ClientAsyncConnection conn = ensureConnection();
241 conn.submitRequest(request);
242 }
243
244 @Override
245 public boolean isRequestSubmitted() {
246 final ClientAsyncConnection conn = ensureConnection();
247 return conn.isRequestSubmitted();
248 }
249
250 @Override
251 public void resetOutput() {
252 final ClientAsyncConnection conn = ensureConnection();
253 conn.resetOutput();
254 }
255
256 @Override
257 public void resetInput() {
258 final ClientAsyncConnection conn = ensureConnection();
259 conn.resetInput();
260 }
261
262 @Override
263 public boolean isSecure() {
264 final ClientAsyncConnection conn = ensureConnection();
265 return conn.getIOSession() instanceof SSLIOSession;
266 }
267
268 @Override
269 public HttpRoute getRoute() {
270 final HttpPoolEntry entry = ensurePoolEntry();
271 return entry.getEffectiveRoute();
272 }
273
274 @Override
275 public SSLSession getSSLSession() {
276 final ClientAsyncConnection conn = ensureConnection();
277 final IOSession iosession = conn.getIOSession();
278 if (iosession instanceof SSLIOSession) {
279 return ((SSLIOSession) iosession).getSSLSession();
280 } else {
281 return null;
282 }
283 }
284
285 @Override
286 public Object getState() {
287 final HttpPoolEntry entry = ensurePoolEntry();
288 return entry.getState();
289 }
290
291 @Override
292 public void setState(final Object state) {
293 final HttpPoolEntry entry = ensurePoolEntry();
294 entry.setState(state);
295 }
296
297 @Override
298 public void markReusable() {
299 this.reusable = true;
300 }
301
302 @Override
303 public void unmarkReusable() {
304 this.reusable = false;
305 }
306
307 @Override
308 public boolean isMarkedReusable() {
309 return this.reusable;
310 }
311
312 @Override
313 public void setIdleDuration(final long duration, final TimeUnit unit) {
314 if(duration > 0) {
315 this.duration = unit.toMillis(duration);
316 } else {
317 this.duration = -1;
318 }
319 }
320
321 private AsyncSchemeRegistry getSchemeRegistry(final HttpContext context) {
322 AsyncSchemeRegistry reg = (AsyncSchemeRegistry) context.getAttribute(
323 ClientContext.SCHEME_REGISTRY);
324 if (reg == null) {
325 reg = this.manager.getSchemeRegistry();
326 }
327 return reg;
328 }
329
330 @Override
331 public synchronized void open(
332 final HttpRoute route,
333 final HttpContext context,
334 final HttpParams params) throws IOException {
335 final HttpPoolEntry entry = ensurePoolEntry();
336 final RouteTracker tracker = entry.getTracker();
337 if (tracker.isConnected()) {
338 throw new IllegalStateException("Connection already open");
339 }
340
341 final HttpHost target = route.getTargetHost();
342 final HttpHost proxy = route.getProxyHost();
343 IOSession iosession = entry.getConnection();
344
345 if (proxy == null) {
346 final AsyncScheme scheme = getSchemeRegistry(context).getScheme(target);
347 final LayeringStrategy layeringStrategy = scheme.getLayeringStrategy();
348 if (layeringStrategy != null) {
349 iosession = layeringStrategy.layer(iosession);
350 }
351 }
352
353 final ClientAsyncConnection conn = this.connFactory.create(
354 "http-outgoing-" + entry.getId(),
355 iosession,
356 params);
357 iosession.setAttribute(IOEventDispatch.CONNECTION_KEY, conn);
358
359 if (proxy == null) {
360 tracker.connectTarget(conn.getIOSession() instanceof SSLIOSession);
361 } else {
362 tracker.connectProxy(proxy, false);
363 }
364 }
365
366 @Override
367 public synchronized void tunnelProxy(
368 final HttpHost next, final HttpParams params) throws IOException {
369 final HttpPoolEntry entry = ensurePoolEntry();
370 final RouteTracker tracker = entry.getTracker();
371 if (!tracker.isConnected()) {
372 throw new IllegalStateException("Connection not open");
373 }
374 tracker.tunnelProxy(next, false);
375 }
376
377 @Override
378 public synchronized void tunnelTarget(
379 final HttpParams params) throws IOException {
380 final HttpPoolEntry entry = ensurePoolEntry();
381 final RouteTracker tracker = entry.getTracker();
382 if (!tracker.isConnected()) {
383 throw new IllegalStateException("Connection not open");
384 }
385 if (tracker.isTunnelled()) {
386 throw new IllegalStateException("Connection is already tunnelled");
387 }
388 tracker.tunnelTarget(false);
389 }
390
391 @Override
392 public synchronized void layerProtocol(
393 final HttpContext context, final HttpParams params) throws IOException {
394 final HttpPoolEntry entry = ensurePoolEntry();
395 final RouteTracker tracker = entry.getTracker();
396 if (!tracker.isConnected()) {
397 throw new IllegalStateException("Connection not open");
398 }
399 if (!tracker.isTunnelled()) {
400 throw new IllegalStateException("Protocol layering without a tunnel not supported");
401 }
402 if (tracker.isLayered()) {
403 throw new IllegalStateException("Multiple protocol layering not supported");
404 }
405 final HttpHost target = tracker.getTargetHost();
406 final AsyncScheme scheme = getSchemeRegistry(context).getScheme(target);
407 final LayeringStrategy layeringStrategy = scheme.getLayeringStrategy();
408 if (layeringStrategy == null) {
409 throw new IllegalStateException(scheme.getName() +
410 " scheme does not provider support for protocol layering");
411 }
412 final IOSession iosession = entry.getConnection();
413 final ClientAsyncConnection conn = (ClientAsyncConnection) iosession.getAttribute(
414 IOEventDispatch.CONNECTION_KEY);
415 conn.upgrade((SSLIOSession) layeringStrategy.layer(iosession));
416 tracker.layerProtocol(layeringStrategy.isSecure());
417 }
418
419 @Override
420 public synchronized void releaseConnection() {
421 if (this.poolEntry == null) {
422 return;
423 }
424 this.manager.releaseConnection(this, this.duration, TimeUnit.MILLISECONDS);
425 this.poolEntry = null;
426 }
427
428 @Override
429 public synchronized void abortConnection() {
430 if (this.poolEntry == null) {
431 return;
432 }
433 this.reusable = false;
434 final IOSession iosession = this.poolEntry.getConnection();
435 final ClientAsyncConnection conn = (ClientAsyncConnection) iosession.getAttribute(
436 IOEventDispatch.CONNECTION_KEY);
437 try {
438 conn.shutdown();
439 } catch (final IOException ignore) {
440 }
441 this.manager.releaseConnection(this, this.duration, TimeUnit.MILLISECONDS);
442 this.poolEntry = null;
443 }
444
445 @Override
446 public synchronized String toString() {
447 if (this.poolEntry != null) {
448 return this.poolEntry.toString();
449 } else {
450 return "released";
451 }
452 }
453
454 }
0 /*
1 * ====================================================================
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 * ====================================================================
19 *
20 * This software consists of voluntary contributions made by many
21 * individuals on behalf of the Apache Software Foundation. For more
22 * information on the Apache Software Foundation, please see
23 * <http://www.apache.org/>.
24 *
25 */
26 package org.apache.http.impl.nio.conn;
27
28 import java.io.IOException;
29 import java.util.concurrent.Future;
30 import java.util.concurrent.TimeUnit;
31
32 import org.apache.commons.logging.Log;
33 import org.apache.commons.logging.LogFactory;
34 import org.apache.http.concurrent.BasicFuture;
35 import org.apache.http.concurrent.FutureCallback;
36 import org.apache.http.conn.routing.HttpRoute;
37 import org.apache.http.nio.conn.ClientAsyncConnectionFactory;
38 import org.apache.http.nio.conn.ClientAsyncConnectionManager;
39 import org.apache.http.nio.conn.ManagedClientAsyncConnection;
40 import org.apache.http.nio.conn.scheme.AsyncSchemeRegistry;
41 import org.apache.http.nio.reactor.ConnectingIOReactor;
42 import org.apache.http.nio.reactor.IOEventDispatch;
43 import org.apache.http.nio.reactor.IOReactorException;
44 import org.apache.http.nio.reactor.IOReactorStatus;
45 import org.apache.http.pool.ConnPoolControl;
46 import org.apache.http.pool.PoolStats;
47 import org.apache.http.util.Args;
48
49 @Deprecated
50 public class PoolingClientAsyncConnectionManager
51 implements ClientAsyncConnectionManager, ConnPoolControl<HttpRoute> {
52
53 private final Log log = LogFactory.getLog(getClass());
54
55 private final ConnectingIOReactor ioreactor;
56 private final HttpNIOConnPool pool;
57 private final AsyncSchemeRegistry schemeRegistry;
58 private final ClientAsyncConnectionFactory connFactory;
59
60 public PoolingClientAsyncConnectionManager(
61 final ConnectingIOReactor ioreactor,
62 final AsyncSchemeRegistry schemeRegistry,
63 final long timeToLive, final TimeUnit tunit) {
64 super();
65 Args.notNull(ioreactor, "I/O reactor");
66 Args.notNull(schemeRegistry, "Scheme registory");
67 Args.notNull(tunit, "Time unit");
68 this.ioreactor = ioreactor;
69 this.pool = new HttpNIOConnPool(this.log, ioreactor, schemeRegistry, timeToLive, tunit);
70 this.schemeRegistry = schemeRegistry;
71 this.connFactory = createClientAsyncConnectionFactory();
72 }
73
74 public PoolingClientAsyncConnectionManager(
75 final ConnectingIOReactor ioreactor,
76 final AsyncSchemeRegistry schemeRegistry) throws IOReactorException {
77 this(ioreactor, schemeRegistry, -1, TimeUnit.MILLISECONDS);
78 }
79
80 public PoolingClientAsyncConnectionManager(
81 final ConnectingIOReactor ioreactor) throws IOReactorException {
82 this(ioreactor, AsyncSchemeRegistryFactory.createDefault());
83 }
84
85 @Override
86 protected void finalize() throws Throwable {
87 try {
88 shutdown();
89 } finally {
90 super.finalize();
91 }
92 }
93
94 protected ClientAsyncConnectionFactory createClientAsyncConnectionFactory() {
95 return new DefaultClientAsyncConnectionFactory();
96 }
97
98 @Override
99 public AsyncSchemeRegistry getSchemeRegistry() {
100 return this.schemeRegistry;
101 }
102
103 @Override
104 public void execute(final IOEventDispatch eventDispatch) throws IOException {
105 this.ioreactor.execute(eventDispatch);
106 }
107
108 @Override
109 public IOReactorStatus getStatus() {
110 return this.ioreactor.getStatus();
111 }
112
113 @Override
114 public void shutdown(final long waitMs) throws IOException {
115 this.log.debug("Connection manager is shutting down");
116 this.pool.shutdown(waitMs);
117 this.log.debug("Connection manager shut down");
118 }
119
120 @Override
121 public void shutdown() throws IOException {
122 this.log.debug("Connection manager is shutting down");
123 this.pool.shutdown(2000);
124 this.log.debug("Connection manager shut down");
125 }
126
127 private String format(final HttpRoute route, final Object state) {
128 final StringBuilder buf = new StringBuilder();
129 buf.append("[route: ").append(route).append("]");
130 if (state != null) {
131 buf.append("[state: ").append(state).append("]");
132 }
133 return buf.toString();
134 }
135
136 private String formatStats(final HttpRoute route) {
137 final StringBuilder buf = new StringBuilder();
138 final PoolStats totals = this.pool.getTotalStats();
139 final PoolStats stats = this.pool.getStats(route);
140 buf.append("[total kept alive: ").append(totals.getAvailable()).append("; ");
141 buf.append("route allocated: ").append(stats.getLeased() + stats.getAvailable());
142 buf.append(" of ").append(stats.getMax()).append("; ");
143 buf.append("total allocated: ").append(totals.getLeased() + totals.getAvailable());
144 buf.append(" of ").append(totals.getMax()).append("]");
145 return buf.toString();
146 }
147
148 private String format(final HttpPoolEntry entry) {
149 final StringBuilder buf = new StringBuilder();
150 buf.append("[id: ").append(entry.getId()).append("]");
151 buf.append("[route: ").append(entry.getRoute()).append("]");
152 final Object state = entry.getState();
153 if (state != null) {
154 buf.append("[state: ").append(state).append("]");
155 }
156 return buf.toString();
157 }
158
159 @Override
160 public Future<ManagedClientAsyncConnection> leaseConnection(
161 final HttpRoute route,
162 final Object state,
163 final long connectTimeout,
164 final TimeUnit tunit,
165 final FutureCallback<ManagedClientAsyncConnection> callback) {
166 Args.notNull(route, "HTTP route");
167 Args.notNull(tunit, "Time unit");
168 if (this.log.isDebugEnabled()) {
169 this.log.debug("Connection request: " + format(route, state) + formatStats(route));
170 }
171 final BasicFuture<ManagedClientAsyncConnection> future = new BasicFuture<ManagedClientAsyncConnection>(
172 callback);
173 this.pool.lease(route, state, connectTimeout, tunit, new InternalPoolEntryCallback(future));
174 return future;
175 }
176
177 @Override
178 public void releaseConnection(
179 final ManagedClientAsyncConnection conn,
180 final long keepalive,
181 final TimeUnit tunit) {
182 Args.notNull(conn, "HTTP connection");
183 if (!(conn instanceof ManagedClientAsyncConnectionImpl)) {
184 throw new IllegalArgumentException("Connection class mismatch, " +
185 "connection not obtained from this manager");
186 }
187 Args.notNull(tunit, "Time unit");
188 final ManagedClientAsyncConnectionImpl managedConn = (ManagedClientAsyncConnectionImpl) conn;
189 final ClientAsyncConnectionManager manager = managedConn.getManager();
190 if (manager != null && manager != this) {
191 throw new IllegalArgumentException("Connection not obtained from this manager");
192 }
193 if (this.pool.isShutdown()) {
194 return;
195 }
196
197 synchronized (managedConn) {
198 final HttpPoolEntry entry = managedConn.getPoolEntry();
199 if (entry == null) {
200 return;
201 }
202 try {
203 if (managedConn.isOpen() && !managedConn.isMarkedReusable()) {
204 try {
205 managedConn.shutdown();
206 } catch (final IOException iox) {
207 if (this.log.isDebugEnabled()) {
208 this.log.debug("I/O exception shutting down released connection", iox);
209 }
210 }
211 }
212 if (managedConn.isOpen()) {
213 entry.updateExpiry(keepalive, tunit != null ? tunit : TimeUnit.MILLISECONDS);
214 if (this.log.isDebugEnabled()) {
215 String s;
216 if (keepalive > 0) {
217 s = "for " + keepalive + " " + tunit;
218 } else {
219 s = "indefinitely";
220 }
221 this.log.debug("Connection " + format(entry) + " can be kept alive " + s);
222 }
223 // Do not time out pooled connection
224 managedConn.setSocketTimeout(0);
225 }
226 } finally {
227 this.pool.release(managedConn.detach(), managedConn.isMarkedReusable());
228 }
229 if (this.log.isDebugEnabled()) {
230 this.log.debug("Connection released: " + format(entry) + formatStats(entry.getRoute()));
231 }
232 }
233 }
234
235 @Override
236 public PoolStats getTotalStats() {
237 return this.pool.getTotalStats();
238 }
239
240 @Override
241 public PoolStats getStats(final HttpRoute route) {
242 return this.pool.getStats(route);
243 }
244
245 @Override
246 public void setMaxTotal(final int max) {
247 this.pool.setMaxTotal(max);
248 }
249
250 @Override
251 public void setDefaultMaxPerRoute(final int max) {
252 this.pool.setDefaultMaxPerRoute(max);
253 }
254
255 @Override
256 public void setMaxPerRoute(final HttpRoute route, final int max) {
257 this.pool.setMaxPerRoute(route, max);
258 }
259
260 @Override
261 public int getMaxTotal() {
262 return this.pool.getMaxTotal();
263 }
264
265 @Override
266 public int getDefaultMaxPerRoute() {
267 return this.pool.getDefaultMaxPerRoute();
268 }
269
270 @Override
271 public int getMaxPerRoute(final HttpRoute route) {
272 return this.pool.getMaxPerRoute(route);
273 }
274
275 public void closeIdleConnections(final long idleTimeout, final TimeUnit tunit) {
276 if (log.isDebugEnabled()) {
277 log.debug("Closing connections idle longer than " + idleTimeout + " " + tunit);
278 }
279 this.pool.closeIdle(idleTimeout, tunit);
280 }
281
282 public void closeExpiredConnections() {
283 log.debug("Closing expired connections");
284 this.pool.closeExpired();
285 }
286
287 class InternalPoolEntryCallback implements FutureCallback<HttpPoolEntry> {
288
289 private final BasicFuture<ManagedClientAsyncConnection> future;
290
291 public InternalPoolEntryCallback(
292 final BasicFuture<ManagedClientAsyncConnection> future) {
293 super();
294 this.future = future;
295 }
296
297 @Override
298 public void completed(final HttpPoolEntry entry) {
299 if (log.isDebugEnabled()) {
300 log.debug("Connection leased: " + format(entry) + formatStats(entry.getRoute()));
301 }
302 final ManagedClientAsyncConnection conn = new ManagedClientAsyncConnectionImpl(
303 PoolingClientAsyncConnectionManager.this,
304 PoolingClientAsyncConnectionManager.this.connFactory,
305 entry);
306 if (!this.future.completed(conn)) {
307 pool.release(entry, true);
308 }
309 }
310
311 @Override
312 public void failed(final Exception ex) {
313 if (log.isDebugEnabled()) {
314 log.debug("Connection request failed", ex);
315 }
316 this.future.failed(ex);
317 }
318
319 @Override
320 public void cancelled() {
321 log.debug("Connection request cancelled");
322 this.future.cancel(true);
323 }
324
325 }
326
327 }
0 /*
1 * ====================================================================
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 * ====================================================================
19 *
20 * This software consists of voluntary contributions made by many
21 * individuals on behalf of the Apache Software Foundation. For more
22 * information on the Apache Software Foundation, please see
23 * <http://www.apache.org/>.
24 *
25 */
26 package org.apache.http.nio.conn;
27
28 import org.apache.http.HttpInetConnection;
29 import org.apache.http.nio.NHttpClientConnection;
30 import org.apache.http.nio.reactor.IOSession;
31
32 @Deprecated
33 public interface ClientAsyncConnection extends NHttpClientConnection, HttpInetConnection {
34
35 void upgrade(IOSession iosession);
36
37 IOSession getIOSession();
38
39 }
0 /*
1 * ====================================================================
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 * ====================================================================
19 *
20 * This software consists of voluntary contributions made by many
21 * individuals on behalf of the Apache Software Foundation. For more
22 * information on the Apache Software Foundation, please see
23 * <http://www.apache.org/>.
24 *
25 */
26 package org.apache.http.nio.conn;
27
28 import org.apache.http.nio.reactor.IOSession;
29 import org.apache.http.params.HttpParams;
30
31 @Deprecated
32 public interface ClientAsyncConnectionFactory {
33
34 ClientAsyncConnection create(String id, IOSession iosession, HttpParams params);
35
36 }
0 /*
1 * ====================================================================
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 * ====================================================================
19 *
20 * This software consists of voluntary contributions made by many
21 * individuals on behalf of the Apache Software Foundation. For more
22 * information on the Apache Software Foundation, please see
23 * <http://www.apache.org/>.
24 *
25 */
26 package org.apache.http.nio.conn;
27
28 import java.util.concurrent.Future;
29 import java.util.concurrent.TimeUnit;
30
31 import org.apache.http.concurrent.FutureCallback;
32 import org.apache.http.conn.routing.HttpRoute;
33 import org.apache.http.nio.conn.scheme.AsyncSchemeRegistry;
34 import org.apache.http.nio.reactor.IOReactor;
35
36 @Deprecated
37 public interface ClientAsyncConnectionManager extends IOReactor {
38
39 AsyncSchemeRegistry getSchemeRegistry();
40
41 Future<ManagedClientAsyncConnection> leaseConnection(
42 HttpRoute route, Object state,
43 long connectTimeout, TimeUnit timeUnit,
44 FutureCallback<ManagedClientAsyncConnection> callback);
45
46 void releaseConnection(ManagedClientAsyncConnection session,
47 long validDuration, TimeUnit timeUnit);
48
49 }
0 /*
1 * ====================================================================
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 * ====================================================================
19 *
20 * This software consists of voluntary contributions made by many
21 * individuals on behalf of the Apache Software Foundation. For more
22 * information on the Apache Software Foundation, please see
23 * <http://www.apache.org/>.
24 *
25 */
26 package org.apache.http.nio.conn;
27
28 import java.io.IOException;
29 import java.util.concurrent.TimeUnit;
30
31 import org.apache.http.HttpHost;
32 import org.apache.http.conn.ConnectionReleaseTrigger;
33 import org.apache.http.conn.HttpRoutedConnection;
34 import org.apache.http.conn.routing.HttpRoute;
35 import org.apache.http.nio.NHttpClientConnection;
36 import org.apache.http.params.HttpParams;
37 import org.apache.http.protocol.HttpContext;
38
39 @Deprecated
40 public interface ManagedClientAsyncConnection
41 extends HttpRoutedConnection, NHttpClientConnection, ConnectionReleaseTrigger {
42
43 Object getState();
44
45 void setState(Object state);
46
47 void markReusable();
48
49 void unmarkReusable();
50
51 boolean isMarkedReusable();
52
53 void open(HttpRoute route, HttpContext context, HttpParams params) throws IOException;
54
55 void tunnelTarget(HttpParams params) throws IOException;
56
57 void tunnelProxy(HttpHost next, HttpParams params) throws IOException;
58
59 void layerProtocol(HttpContext context, HttpParams params) throws IOException;
60
61 void setIdleDuration(long duration, TimeUnit tunit);
62
63 }
0 /*
1 * ====================================================================
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 * ====================================================================
19 *
20 * This software consists of voluntary contributions made by many
21 * individuals on behalf of the Apache Software Foundation. For more
22 * information on the Apache Software Foundation, please see
23 * <http://www.apache.org/>.
24 *
25 */
26 package org.apache.http.nio.conn.scheme;
27
28 import java.util.Locale;
29
30 import org.apache.http.util.Args;
31 import org.apache.http.util.LangUtils;
32
33 @Deprecated
34 public final class AsyncScheme {
35
36 /** The name of this scheme, in lowercase. (e.g. http, https) */
37 private final String name;
38
39 /** The layering strategy for this scheme, if applicable */
40 private final LayeringStrategy strategy;
41
42 /** The default port for this scheme */
43 private final int defaultPort;
44
45 /** A string representation, for {@link #toString toString}. */
46 private String stringRep;
47 /*
48 * This is used to cache the result of the toString() method
49 * Since the method always generates the same value, there's no
50 * need to synchronize, and it does not affect immutability.
51 */
52
53 public AsyncScheme(final String name, final int port, final LayeringStrategy strategy) {
54 Args.notNull(name, "Scheme name");
55 if ((port <= 0) || (port > 0xffff)) {
56 throw new IllegalArgumentException("Port is invalid: " + port);
57 }
58 this.name = name.toLowerCase(Locale.ROOT);
59 this.strategy = strategy;
60 this.defaultPort = port;
61 }
62
63 public final int getDefaultPort() {
64 return defaultPort;
65 }
66
67 public final LayeringStrategy getLayeringStrategy() {
68 return this.strategy;
69 }
70
71 public final String getName() {
72 return name;
73 }
74
75 public final int resolvePort(final int port) {
76 return port <= 0 ? defaultPort : port;
77 }
78
79 @Override
80 public final String toString() {
81 if (stringRep == null) {
82 final StringBuilder buffer = new StringBuilder();
83 buffer.append(this.name);
84 buffer.append(':');
85 buffer.append(Integer.toString(this.defaultPort));
86 stringRep = buffer.toString();
87 }
88 return stringRep;
89 }
90
91 @Override
92 public final boolean equals(final Object obj) {
93 if (this == obj) {
94 return true;
95 }
96 if (obj instanceof AsyncScheme) {
97 final AsyncScheme that = (AsyncScheme) obj;
98 return this.name.equals(that.name)
99 && this.defaultPort == that.defaultPort
100 && this.strategy.equals(that.strategy);
101 } else {
102 return false;
103 }
104 }
105
106 @Override
107 public int hashCode() {
108 int hash = LangUtils.HASH_SEED;
109 hash = LangUtils.hashCode(hash, this.defaultPort);
110 hash = LangUtils.hashCode(hash, this.name);
111 hash = LangUtils.hashCode(hash, this.strategy);
112 return hash;
113 }
114
115 }
0 /*
1 * ====================================================================
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 * ====================================================================
19 *
20 * This software consists of voluntary contributions made by many
21 * individuals on behalf of the Apache Software Foundation. For more
22 * information on the Apache Software Foundation, please see
23 * <http://www.apache.org/>.
24 *
25 */
26 package org.apache.http.nio.conn.scheme;
27
28 import java.util.ArrayList;
29 import java.util.List;
30 import java.util.Map;
31 import java.util.concurrent.ConcurrentHashMap;
32
33 import org.apache.http.HttpHost;
34
35 /**
36 * A set of supported protocol {@link AsyncScheme}s.
37 * Schemes are identified by lowercase names.
38 *
39 */
40 @Deprecated
41 public final class AsyncSchemeRegistry {
42
43 /** The available schemes in this registry. */
44 private final Map<String, AsyncScheme> registeredSchemes;
45
46 /**
47 * Creates a new, empty scheme registry.
48 */
49 public AsyncSchemeRegistry() {
50 super();
51 registeredSchemes = new ConcurrentHashMap<String, AsyncScheme>();
52 }
53
54 /**
55 * Obtains a scheme by name.
56 *
57 * @param name the name of the scheme to look up (in lowercase)
58 *
59 * @return the scheme, never {@code null}
60 *
61 * @throws IllegalStateException
62 * if the scheme with the given name is not registered
63 */
64 public final AsyncScheme getScheme(final String name) {
65 final AsyncScheme found = get(name);
66 if (found == null) {
67 throw new IllegalStateException
68 ("Scheme '"+name+"' not registered.");
69 }
70 return found;
71 }
72
73 /**
74 * Obtains the scheme for a host.
75 * Convenience method for {@code getScheme(host.getSchemeName())}
76 *
77 * @param host the host for which to obtain the scheme
78 *
79 * @return the scheme for the given host, never {@code null}
80 *
81 * @throws IllegalStateException
82 * if a scheme with the respective name is not registered
83 */
84 public final AsyncScheme getScheme(final HttpHost host) {
85 if (host == null) {
86 throw new IllegalArgumentException("Host must not be null.");
87 }
88 return getScheme(host.getSchemeName());
89 }
90
91 /**
92 * Obtains a scheme by name, if registered.
93 *
94 * @param name the name of the scheme to look up (in lowercase)
95 *
96 * @return the scheme, or
97 * {@code null} if there is none by this name
98 */
99 public final AsyncScheme get(final String name) {
100 if (name == null) {
101 throw new IllegalArgumentException("Name must not be null.");
102 }
103
104 // leave it to the caller to use the correct name - all lowercase
105 //name = name.toLowerCase(Locale.ENGLISH);
106 final AsyncScheme found = registeredSchemes.get(name);
107 return found;
108 }
109
110 /**
111 * Registers a scheme.
112 * The scheme can later be retrieved by its name
113 * using {@link #getScheme(String) getScheme} or {@link #get get}.
114 *
115 * @param sch the scheme to register
116 *
117 * @return the scheme previously registered with that name, or
118 * {@code null} if none was registered
119 */
120 public final AsyncScheme register(final AsyncScheme sch) {
121 if (sch == null) {
122 throw new IllegalArgumentException("Scheme must not be null.");
123 }
124
125 final AsyncScheme old = registeredSchemes.put(sch.getName(), sch);
126 return old;
127 }
128
129 /**
130 * Unregisters a scheme.
131 *
132 * @param name the name of the scheme to unregister (in lowercase)
133 *
134 * @return the unregistered scheme, or
135 * {@code null} if there was none
136 */
137 public final AsyncScheme unregister(final String name) {
138 if (name == null) {
139 throw new IllegalArgumentException("Name must not be null.");
140 }
141
142 // leave it to the caller to use the correct name - all lowercase
143 //name = name.toLowerCase(Locale.ENGLISH);
144 final AsyncScheme gone = registeredSchemes.remove(name);
145 return gone;
146 }
147
148 /**
149 * Obtains the names of the registered schemes.
150 *
151 * @return List containing registered scheme names.
152 */
153 public final List<String> getSchemeNames() {
154 return new ArrayList<String>(registeredSchemes.keySet());
155 }
156
157 /**
158 * Populates the internal collection of registered {@link AsyncScheme protocol schemes}
159 * with the content of the map passed as a parameter.
160 *
161 * @param map protocol schemes
162 */
163 public void setItems(final Map<String, AsyncScheme> map) {
164 if (map == null) {
165 return;
166 }
167 registeredSchemes.clear();
168 registeredSchemes.putAll(map);
169 }
170
171 }
172
0 /*
1 * ====================================================================
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 * ====================================================================
19 *
20 * This software consists of voluntary contributions made by many
21 * individuals on behalf of the Apache Software Foundation. For more
22 * information on the Apache Software Foundation, please see
23 * <http://www.apache.org/>.
24 *
25 */
26 package org.apache.http.nio.conn.scheme;
27
28 import org.apache.http.nio.reactor.IOSession;
29
30 @Deprecated
31 public interface LayeringStrategy {
32
33 boolean isSecure();
34
35 IOSession layer(IOSession iosession);
36
37 }
0 /*
1 * ====================================================================
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 * ====================================================================
19 *
20 * This software consists of voluntary contributions made by many
21 * individuals on behalf of the Apache Software Foundation. For more
22 * information on the Apache Software Foundation, please see
23 * <http://www.apache.org/>.
24 *
25 */
26
27 /**
28 * Deprecated
29 */
30 package org.apache.http.nio.conn.scheme;
0 /*
1 * ====================================================================
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 * ====================================================================
19 *
20 * This software consists of voluntary contributions made by many
21 * individuals on behalf of the Apache Software Foundation. For more
22 * information on the Apache Software Foundation, please see
23 * <http://www.apache.org/>.
24 *
25 */
26
27 package org.apache.http.nio.conn.ssl;
28
29 import java.net.InetSocketAddress;
30 import java.security.KeyManagementException;
31 import java.security.KeyStore;
32 import java.security.KeyStoreException;
33 import java.security.NoSuchAlgorithmException;
34 import java.security.SecureRandom;
35 import java.security.UnrecoverableKeyException;
36 import java.security.cert.Certificate;
37 import java.security.cert.X509Certificate;
38
39 import javax.net.ssl.KeyManager;
40 import javax.net.ssl.KeyManagerFactory;
41 import javax.net.ssl.SSLContext;
42 import javax.net.ssl.SSLEngine;
43 import javax.net.ssl.SSLException;
44 import javax.net.ssl.SSLSession;
45 import javax.net.ssl.TrustManager;
46 import javax.net.ssl.TrustManagerFactory;
47 import javax.net.ssl.X509TrustManager;
48
49 import org.apache.http.conn.ssl.BrowserCompatHostnameVerifier;
50 import org.apache.http.conn.ssl.SSLContexts;
51 import org.apache.http.conn.ssl.TrustStrategy;
52 import org.apache.http.conn.ssl.X509HostnameVerifier;
53 import org.apache.http.nio.conn.scheme.LayeringStrategy;
54 import org.apache.http.nio.reactor.IOSession;
55 import org.apache.http.nio.reactor.ssl.SSLIOSession;
56 import org.apache.http.nio.reactor.ssl.SSLMode;
57 import org.apache.http.nio.reactor.ssl.SSLSetupHandler;
58
59 @Deprecated
60 public class SSLLayeringStrategy implements LayeringStrategy {
61
62 public static final String TLS = "TLS";
63 public static final String SSL = "SSL";
64 public static final String SSLV2 = "SSLv2";
65
66 public static SSLLayeringStrategy getDefaultStrategy() {
67 return new SSLLayeringStrategy(SSLContexts.createDefault());
68 }
69
70 public static SSLLayeringStrategy getSystemDefaultStrategy() {
71 return new SSLLayeringStrategy(SSLContexts.createSystemDefault());
72 }
73
74 private final SSLContext sslContext;
75 private final X509HostnameVerifier hostnameVerifier;
76
77 private static SSLContext createSSLContext(
78 final String algorithm,
79 final KeyStore keystore,
80 final String keystorePassword,
81 final KeyStore truststore,
82 final SecureRandom random,
83 final TrustStrategy trustStrategy)
84 throws NoSuchAlgorithmException, KeyStoreException, UnrecoverableKeyException, KeyManagementException {
85 final String algo = algorithm != null ? algorithm : TLS;
86 final KeyManagerFactory kmfactory = KeyManagerFactory.getInstance(
87 KeyManagerFactory.getDefaultAlgorithm());
88 kmfactory.init(keystore, keystorePassword != null ? keystorePassword.toCharArray(): null);
89 final KeyManager[] keymanagers = kmfactory.getKeyManagers();
90 final TrustManagerFactory tmfactory = TrustManagerFactory.getInstance(
91 TrustManagerFactory.getDefaultAlgorithm());
92 tmfactory.init(truststore);
93 final TrustManager[] trustmanagers = tmfactory.getTrustManagers();
94 if (trustmanagers != null && trustStrategy != null) {
95 for (int i = 0; i < trustmanagers.length; i++) {
96 final TrustManager tm = trustmanagers[i];
97 if (tm instanceof X509TrustManager) {
98 trustmanagers[i] = new TrustManagerDecorator(
99 (X509TrustManager) tm, trustStrategy);
100 }
101 }
102 }
103 final SSLContext sslcontext = SSLContext.getInstance(algo);
104 sslcontext.init(keymanagers, trustmanagers, random);
105 return sslcontext;
106 }
107
108 public SSLLayeringStrategy(
109 final String algorithm,
110 final KeyStore keystore,
111 final String keystorePassword,
112 final KeyStore truststore,
113 final SecureRandom random,
114 final X509HostnameVerifier hostnameVerifier)
115 throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException {
116 this(createSSLContext(
117 algorithm, keystore, keystorePassword, truststore, random, null),
118 hostnameVerifier);
119 }
120
121 public SSLLayeringStrategy(
122 final String algorithm,
123 final KeyStore keystore,
124 final String keystorePassword,
125 final KeyStore truststore,
126 final SecureRandom random,
127 final TrustStrategy trustStrategy,
128 final X509HostnameVerifier hostnameVerifier)
129 throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException {
130 this(createSSLContext(
131 algorithm, keystore, keystorePassword, truststore, random, trustStrategy),
132 hostnameVerifier);
133 }
134
135 public SSLLayeringStrategy(
136 final KeyStore keystore,
137 final String keystorePassword,
138 final KeyStore truststore)
139 throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException {
140 this(TLS, keystore, keystorePassword, truststore, null, null, new BrowserCompatHostnameVerifier());
141 }
142
143 public SSLLayeringStrategy(
144 final KeyStore keystore,
145 final String keystorePassword)
146 throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException{
147 this(TLS, keystore, keystorePassword, null, null, null, new BrowserCompatHostnameVerifier());
148 }
149
150 public SSLLayeringStrategy(
151 final KeyStore truststore)
152 throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException {
153 this(TLS, null, null, truststore, null, null, new BrowserCompatHostnameVerifier());
154 }
155
156 public SSLLayeringStrategy(
157 final TrustStrategy trustStrategy,
158 final X509HostnameVerifier hostnameVerifier)
159 throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException {
160 this(TLS, null, null, null, null, trustStrategy, hostnameVerifier);
161 }
162
163 public SSLLayeringStrategy(
164 final TrustStrategy trustStrategy)
165 throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException {
166 this(TLS, null, null, null, null, trustStrategy, new BrowserCompatHostnameVerifier());
167 }
168
169 public SSLLayeringStrategy(
170 final SSLContext sslContext, final X509HostnameVerifier hostnameVerifier) {
171 super();
172 this.sslContext = sslContext;
173 this.hostnameVerifier = hostnameVerifier;
174 }
175
176 public SSLLayeringStrategy(final SSLContext sslContext) {
177 this(sslContext, new BrowserCompatHostnameVerifier());
178 }
179
180 @Override
181 public boolean isSecure() {
182 return true;
183 }
184
185 @Override
186 public SSLIOSession layer(final IOSession iosession) {
187 final SSLIOSession ssliosession = new SSLIOSession(
188 iosession,
189 SSLMode.CLIENT,
190 this.sslContext,
191 new SSLSetupHandler() {
192
193 @Override
194 public void initalize(
195 final SSLEngine sslengine) throws SSLException {
196 initializeEngine(sslengine);
197 }
198
199 @Override
200 public void verify(
201 final IOSession iosession,
202 final SSLSession sslsession) throws SSLException {
203 verifySession(iosession, sslsession);
204 }
205
206 });
207 iosession.setAttribute(SSLIOSession.SESSION_KEY, ssliosession);
208 return ssliosession;
209 }
210
211 protected void initializeEngine(final SSLEngine engine) {
212 }
213
214 protected void verifySession(
215 final IOSession iosession,
216 final SSLSession sslsession) throws SSLException {
217 final InetSocketAddress address = (InetSocketAddress) iosession.getRemoteAddress();
218
219 final Certificate[] certs = sslsession.getPeerCertificates();
220 final X509Certificate x509 = (X509Certificate) certs[0];
221 this.hostnameVerifier.verify(address.getHostName(), x509);
222 }
223
224 }
0 /*
1 * ====================================================================
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 * ====================================================================
19 *
20 * This software consists of voluntary contributions made by many
21 * individuals on behalf of the Apache Software Foundation. For more
22 * information on the Apache Software Foundation, please see
23 * <http://www.apache.org/>.
24 *
25 */
26 package org.apache.http.nio.conn.ssl;
27
28 import java.security.cert.CertificateException;
29 import java.security.cert.X509Certificate;
30
31 import javax.net.ssl.X509TrustManager;
32
33 import org.apache.http.conn.ssl.TrustStrategy;
34
35 @Deprecated
36 class TrustManagerDecorator implements X509TrustManager {
37
38 private final X509TrustManager trustManager;
39 private final TrustStrategy trustStrategy;
40
41 TrustManagerDecorator(final X509TrustManager trustManager, final TrustStrategy trustStrategy) {
42 super();
43 this.trustManager = trustManager;
44 this.trustStrategy = trustStrategy;
45 }
46
47 @Override
48 public void checkClientTrusted(
49 final X509Certificate[] chain, final String authType) throws CertificateException {
50 this.trustManager.checkClientTrusted(chain, authType);
51 }
52
53 @Override
54 public void checkServerTrusted(
55 final X509Certificate[] chain, final String authType) throws CertificateException {
56 if (!this.trustStrategy.isTrusted(chain, authType)) {
57 this.trustManager.checkServerTrusted(chain, authType);
58 }
59 }
60
61 @Override
62 public X509Certificate[] getAcceptedIssuers() {
63 return this.trustManager.getAcceptedIssuers();
64 }
65
66 }
0 #
1 # Licensed to the Apache Software Foundation (ASF) under one
2 # or more contributor license agreements. See the NOTICE file
3 # distributed with this work for additional information
4 # regarding copyright ownership. The ASF licenses this file
5 # to you under the Apache License, Version 2.0 (the
6 # "License"); you may not use this file except in compliance
7 # with the License. You may obtain a copy of the License at
8 #
9 # http://www.apache.org/licenses/LICENSE-2.0
10 #
11 # Unless required by applicable law or agreed to in writing,
12 # software distributed under the License is distributed on an
13 # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14 # KIND, either express or implied. See the License for the
15 # specific language governing permissions and limitations
16 # under the License.
17 #
18 info.module = HttpAsyncClient
19 info.release = ${pom.version}
20 info.timestamp = ${mvn.timestamp}
21 # timestamp requires Maven 2.1
0 /*
1 * ====================================================================
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 * ====================================================================
19 *
20 * This software consists of voluntary contributions made by many
21 * individuals on behalf of the Apache Software Foundation. For more
22 * information on the Apache Software Foundation, please see
23 * <http://www.apache.org/>.
24 *
25 */
26 package org.apache.http.impl.nio.conn;
27
28 import org.apache.http.conn.routing.HttpRoute;
29 import org.apache.http.nio.NHttpClientConnection;
30 import org.apache.http.nio.conn.ManagedNHttpClientConnection;
31 import org.apache.http.pool.PoolEntry;
32
33 public class CPoolUtils {
34
35 public static PoolEntry<HttpRoute, ManagedNHttpClientConnection> getPoolEntry(final NHttpClientConnection managedConn) {
36 return CPoolProxy.getPoolEntry(managedConn);
37 }
38
39 }
0 /*
1 * ====================================================================
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 * ====================================================================
19 *
20 * This software consists of voluntary contributions made by many
21 * individuals on behalf of the Apache Software Foundation. For more
22 * information on the Apache Software Foundation, please see
23 * <http://www.apache.org/>.
24 *
25 */
26 package org.apache.http.impl.nio.conn;
27
28 import java.net.InetAddress;
29 import java.net.InetSocketAddress;
30 import java.util.Calendar;
31 import java.util.concurrent.ExecutionException;
32 import java.util.concurrent.Future;
33 import java.util.concurrent.TimeUnit;
34
35 import org.apache.commons.logging.Log;
36 import org.apache.http.HttpHost;
37 import org.apache.http.concurrent.FutureCallback;
38 import org.apache.http.config.ConnectionConfig;
39 import org.apache.http.config.Registry;
40 import org.apache.http.config.RegistryBuilder;
41 import org.apache.http.conn.DnsResolver;
42 import org.apache.http.conn.SchemePortResolver;
43 import org.apache.http.conn.UnsupportedSchemeException;
44 import org.apache.http.conn.routing.HttpRoute;
45 import org.apache.http.impl.nio.conn.PoolingNHttpClientConnectionManager.ConfigData;
46 import org.apache.http.impl.nio.conn.PoolingNHttpClientConnectionManager.InternalAddressResolver;
47 import org.apache.http.impl.nio.conn.PoolingNHttpClientConnectionManager.InternalConnectionFactory;
48 import org.apache.http.nio.NHttpClientConnection;
49 import org.apache.http.nio.conn.ManagedNHttpClientConnection;
50 import org.apache.http.nio.conn.NHttpConnectionFactory;
51 import org.apache.http.nio.conn.SchemeIOSessionStrategy;
52 import org.apache.http.nio.reactor.ConnectingIOReactor;
53 import org.apache.http.nio.reactor.IOSession;
54 import org.apache.http.nio.reactor.SessionRequest;
55 import org.apache.http.protocol.BasicHttpContext;
56 import org.apache.http.protocol.HttpContext;
57 import org.junit.Assert;
58 import org.junit.Before;
59 import org.junit.Test;
60 import org.mockito.ArgumentCaptor;
61 import org.mockito.Captor;
62 import org.mockito.Mock;
63 import org.mockito.Mockito;
64 import org.mockito.MockitoAnnotations;
65
66 public class TestPoolingHttpClientAsyncConnectionManager {
67
68 @Mock
69 private ConnectingIOReactor ioreactor;
70 @Mock
71 private CPool pool;
72 @Mock
73 private SchemeIOSessionStrategy noopStrategy;
74 @Mock
75 private SchemeIOSessionStrategy sslStrategy;
76 @Mock
77 private SchemePortResolver schemePortResolver;
78 @Mock
79 private DnsResolver dnsResolver;
80 @Mock
81 private FutureCallback<NHttpClientConnection> connCallback;
82 @Captor
83 private ArgumentCaptor<FutureCallback<CPoolEntry>> poolEntryCallbackCaptor;
84 @Mock
85 private ManagedNHttpClientConnection conn;
86 @Mock
87 private NHttpConnectionFactory<ManagedNHttpClientConnection> connFactory;
88 @Mock
89 private SessionRequest sessionRequest;
90 @Mock
91 private IOSession iosession;
92
93 private Registry<SchemeIOSessionStrategy> layeringStrategyRegistry;
94 private PoolingNHttpClientConnectionManager connman;
95
96 @Before
97 public void setUp() throws Exception {
98 MockitoAnnotations.initMocks(this);
99 Mockito.when(sslStrategy.isLayeringRequired()).thenReturn(Boolean.TRUE);
100
101 layeringStrategyRegistry = RegistryBuilder.<SchemeIOSessionStrategy>create()
102 .register("http", noopStrategy)
103 .register("https", sslStrategy)
104 .build();
105 connman = new PoolingNHttpClientConnectionManager(
106 ioreactor, pool, layeringStrategyRegistry);
107 }
108
109 @Test
110 public void testShutdown() throws Exception {
111 connman.shutdown();
112
113 Mockito.verify(pool).shutdown(2000);
114 }
115
116 @Test
117 public void testShutdownMs() throws Exception {
118 connman.shutdown(500);
119
120 Mockito.verify(pool).shutdown(500);
121 }
122
123 @Test
124 public void testRequestReleaseConnection() throws Exception {
125 final HttpHost target = new HttpHost("localhost");
126 final HttpRoute route = new HttpRoute(target);
127 final Future<NHttpClientConnection> future = connman.requestConnection(
128 route, "some state", 1000L, 2000L, TimeUnit.MILLISECONDS, connCallback);
129 Assert.assertNotNull(future);
130
131 Mockito.verify(pool).lease(
132 Mockito.same(route),
133 Mockito.eq("some state"),
134 Mockito.eq(1000L),
135 Mockito.eq(2000L),
136 Mockito.eq(TimeUnit.MILLISECONDS),
137 poolEntryCallbackCaptor.capture());
138 final FutureCallback<CPoolEntry> callaback = poolEntryCallbackCaptor.getValue();
139 final Log log = Mockito.mock(Log.class);
140 final CPoolEntry poolentry = new CPoolEntry(log, "some-id", route, conn, -1, TimeUnit.MILLISECONDS);
141 poolentry.markRouteComplete();
142 callaback.completed(poolentry);
143
144 Assert.assertTrue(future.isDone());
145 final NHttpClientConnection managedConn = future.get();
146 Mockito.verify(connCallback).completed(Mockito.<NHttpClientConnection>any());
147
148 Mockito.when(conn.isOpen()).thenReturn(Boolean.TRUE);
149 connman.releaseConnection(managedConn, "new state", 5, TimeUnit.SECONDS);
150
151 Mockito.verify(pool).release(poolentry, true);
152 Assert.assertEquals("new state", poolentry.getState());
153 final Calendar cal = Calendar.getInstance();
154 cal.setTimeInMillis(poolentry.getUpdated());
155 cal.add(Calendar.SECOND, 5);
156 Assert.assertEquals(cal.getTimeInMillis(), poolentry.getExpiry());
157 }
158
159 @Test
160 public void testReleaseConnectionIncompleteRoute() throws Exception {
161 final HttpHost target = new HttpHost("localhost");
162 final HttpRoute route = new HttpRoute(target);
163 final Future<NHttpClientConnection> future = connman.requestConnection(
164 route, "some state", 1000L, 2000L, TimeUnit.MILLISECONDS, connCallback);
165 Assert.assertNotNull(future);
166
167 Mockito.verify(pool).lease(
168 Mockito.same(route),
169 Mockito.eq("some state"),
170 Mockito.eq(1000L),
171 Mockito.eq(2000L),
172 Mockito.eq(TimeUnit.MILLISECONDS),
173 poolEntryCallbackCaptor.capture());
174 final FutureCallback<CPoolEntry> callaback = poolEntryCallbackCaptor.getValue();
175 final Log log = Mockito.mock(Log.class);
176 final CPoolEntry poolentry = new CPoolEntry(log, "some-id", route, conn, -1, TimeUnit.MILLISECONDS);
177 callaback.completed(poolentry);
178
179 Assert.assertTrue(future.isDone());
180 final NHttpClientConnection managedConn = future.get();
181 Mockito.verify(connCallback).completed(Mockito.<NHttpClientConnection>any());
182
183 Mockito.when(conn.isOpen()).thenReturn(Boolean.TRUE);
184 connman.releaseConnection(managedConn, "new state", 5, TimeUnit.SECONDS);
185
186 Mockito.verify(pool).release(poolentry, false);
187 }
188
189 @Test
190 public void testRequestConnectionFutureCancelled() throws Exception {
191 final HttpHost target = new HttpHost("localhost");
192 final HttpRoute route = new HttpRoute(target);
193 final Future<NHttpClientConnection> future = connman.requestConnection(
194 route, "some state", 1000L, 2000L, TimeUnit.MILLISECONDS, null);
195 Assert.assertNotNull(future);
196 future.cancel(true);
197
198 Mockito.verify(pool).lease(
199 Mockito.same(route),
200 Mockito.eq("some state"),
201 Mockito.eq(1000L),
202 Mockito.eq(2000L),
203 Mockito.eq(TimeUnit.MILLISECONDS),
204 poolEntryCallbackCaptor.capture());
205 final FutureCallback<CPoolEntry> callaback = poolEntryCallbackCaptor.getValue();
206 final Log log = Mockito.mock(Log.class);
207 final CPoolEntry poolentry = new CPoolEntry(log, "some-id", route, conn, -1, TimeUnit.MILLISECONDS);
208 poolentry.markRouteComplete();
209 callaback.completed(poolentry);
210
211 Mockito.verify(pool).release(poolentry, true);
212 }
213
214 @Test(expected=ExecutionException.class)
215 public void testRequestConnectionFailed() throws Exception {
216 final HttpHost target = new HttpHost("localhost");
217 final HttpRoute route = new HttpRoute(target);
218 final Future<NHttpClientConnection> future = connman.requestConnection(
219 route, "some state", 1000L, 2000L, TimeUnit.MILLISECONDS, null);
220 Assert.assertNotNull(future);
221
222 Mockito.verify(pool).lease(
223 Mockito.same(route),
224 Mockito.eq("some state"),
225 Mockito.eq(1000L),
226 Mockito.eq(2000L),
227 Mockito.eq(TimeUnit.MILLISECONDS),
228 poolEntryCallbackCaptor.capture());
229 final FutureCallback<CPoolEntry> callaback = poolEntryCallbackCaptor.getValue();
230 callaback.failed(new Exception());
231
232 Assert.assertTrue(future.isDone());
233 future.get();
234 }
235
236 @Test
237 public void testRequestConnectionCancelled() throws Exception {
238 final HttpHost target = new HttpHost("localhost");
239 final HttpRoute route = new HttpRoute(target);
240 final Future<NHttpClientConnection> future = connman.requestConnection(
241 route, "some state", 1000L, 2000L, TimeUnit.MILLISECONDS, null);
242 Assert.assertNotNull(future);
243
244 Mockito.verify(pool).lease(
245 Mockito.same(route),
246 Mockito.eq("some state"),
247 Mockito.eq(1000L),
248 Mockito.eq(2000L),
249 Mockito.eq(TimeUnit.MILLISECONDS),
250 poolEntryCallbackCaptor.capture());
251 final FutureCallback<CPoolEntry> callaback = poolEntryCallbackCaptor.getValue();
252 callaback.cancelled();
253
254 Assert.assertTrue(future.isDone());
255 Assert.assertTrue(future.isCancelled());
256 Assert.assertNull(future.get());
257 }
258
259 @Test
260 public void testConnectionInitialize() throws Exception {
261 final HttpHost target = new HttpHost("somehost", -1, "http");
262 final HttpRoute route = new HttpRoute(target);
263 final HttpContext context = new BasicHttpContext();
264
265 final Log log = Mockito.mock(Log.class);
266 final CPoolEntry poolentry = new CPoolEntry(log, "some-id", route, conn, -1, TimeUnit.MILLISECONDS);
267 final NHttpClientConnection managedConn = CPoolProxy.newProxy(poolentry);
268
269 Mockito.when(conn.getIOSession()).thenReturn(iosession);
270 Mockito.when(sslStrategy.upgrade(target, iosession)).thenReturn(iosession);
271
272 connman.startRoute(managedConn, route, context);
273
274 Mockito.verify(noopStrategy, Mockito.never()).upgrade(target, iosession);
275 Mockito.verify(conn, Mockito.never()).bind(iosession);
276
277 Assert.assertFalse(connman.isRouteComplete(managedConn));
278 }
279
280 @Test
281 public void testConnectionInitializeHttps() throws Exception {
282 final HttpHost target = new HttpHost("somehost", 443, "https");
283 final HttpRoute route = new HttpRoute(target, null, true);
284 final HttpContext context = new BasicHttpContext();
285
286 final Log log = Mockito.mock(Log.class);
287 final CPoolEntry poolentry = new CPoolEntry(log, "some-id", route, conn, -1, TimeUnit.MILLISECONDS);
288 poolentry.markRouteComplete();
289 final NHttpClientConnection managedConn = CPoolProxy.newProxy(poolentry);
290
291 Mockito.when(conn.getIOSession()).thenReturn(iosession);
292 Mockito.when(sslStrategy.upgrade(target, iosession)).thenReturn(iosession);
293
294 connman.startRoute(managedConn, route, context);
295
296 Mockito.verify(sslStrategy).upgrade(target, iosession);
297 Mockito.verify(conn).bind(iosession);
298 }
299
300 @Test
301 public void testConnectionInitializeContextSpecific() throws Exception {
302 final HttpHost target = new HttpHost("somehost", 80, "http11");
303 final HttpRoute route = new HttpRoute(target);
304 final HttpContext context = new BasicHttpContext();
305
306 final Registry<SchemeIOSessionStrategy> reg = RegistryBuilder.<SchemeIOSessionStrategy>create()
307 .register("http11", noopStrategy)
308 .build();
309 context.setAttribute(PoolingNHttpClientConnectionManager.IOSESSION_FACTORY_REGISTRY, reg);
310
311 final Log log = Mockito.mock(Log.class);
312 final CPoolEntry poolentry = new CPoolEntry(log, "some-id", route, conn, -1, TimeUnit.MILLISECONDS);
313 final NHttpClientConnection managedConn = CPoolProxy.newProxy(poolentry);
314
315 Mockito.when(conn.getIOSession()).thenReturn(iosession);
316 Mockito.when(sslStrategy.upgrade(target, iosession)).thenReturn(iosession);
317
318 connman.startRoute(managedConn, route, context);
319
320 Mockito.verify(noopStrategy, Mockito.never()).upgrade(target, iosession);
321 Mockito.verify(conn, Mockito.never()).bind(iosession);
322
323 Assert.assertFalse(connman.isRouteComplete(managedConn));
324 }
325
326 @Test(expected=UnsupportedSchemeException.class)
327 public void testConnectionInitializeUnknownScheme() throws Exception {
328 final HttpHost target = new HttpHost("somehost", -1, "whatever");
329 final HttpRoute route = new HttpRoute(target, null, true);
330 final HttpContext context = new BasicHttpContext();
331
332 final Log log = Mockito.mock(Log.class);
333 final CPoolEntry poolentry = new CPoolEntry(log, "some-id", route, conn, -1, TimeUnit.MILLISECONDS);
334 poolentry.markRouteComplete();
335 final NHttpClientConnection managedConn = CPoolProxy.newProxy(poolentry);
336
337 Mockito.when(conn.getIOSession()).thenReturn(iosession);
338 Mockito.when(sslStrategy.upgrade(target, iosession)).thenReturn(iosession);
339
340 connman.startRoute(managedConn, route, context);
341 }
342
343 @Test
344 public void testConnectionUpgrade() throws Exception {
345 final HttpHost target = new HttpHost("somehost", 443, "https");
346 final HttpRoute route = new HttpRoute(target);
347 final HttpContext context = new BasicHttpContext();
348
349 final Log log = Mockito.mock(Log.class);
350 final CPoolEntry poolentry = new CPoolEntry(log, "some-id", route, conn, -1, TimeUnit.MILLISECONDS);
351 poolentry.markRouteComplete();
352 final NHttpClientConnection managedConn = CPoolProxy.newProxy(poolentry);
353
354 Mockito.when(conn.getIOSession()).thenReturn(iosession);
355 Mockito.when(sslStrategy.upgrade(target, iosession)).thenReturn(iosession);
356
357 connman.upgrade(managedConn, route, context);
358
359 Mockito.verify(sslStrategy).upgrade(target, iosession);
360 Mockito.verify(conn).bind(iosession);
361 }
362
363 @Test(expected=UnsupportedSchemeException.class)
364 public void testConnectionUpgradeUnknownScheme() throws Exception {
365 final HttpHost target = new HttpHost("somehost", -1, "whatever");
366 final HttpRoute route = new HttpRoute(target);
367 final HttpContext context = new BasicHttpContext();
368
369 final Log log = Mockito.mock(Log.class);
370 final CPoolEntry poolentry = new CPoolEntry(log, "some-id", route, conn, -1, TimeUnit.MILLISECONDS);
371 poolentry.markRouteComplete();
372 final NHttpClientConnection managedConn = CPoolProxy.newProxy(poolentry);
373
374 Mockito.when(conn.getIOSession()).thenReturn(iosession);
375 Mockito.when(sslStrategy.upgrade(target, iosession)).thenReturn(iosession);
376
377 connman.upgrade(managedConn, route, context);
378 }
379
380 @Test(expected=UnsupportedSchemeException.class)
381 public void testConnectionUpgradeIllegalScheme() throws Exception {
382 final HttpHost target = new HttpHost("somehost", 80, "http");
383 final HttpRoute route = new HttpRoute(target);
384 final HttpContext context = new BasicHttpContext();
385
386 final Log log = Mockito.mock(Log.class);
387 final CPoolEntry poolentry = new CPoolEntry(log, "some-id", route, conn, -1, TimeUnit.MILLISECONDS);
388 poolentry.markRouteComplete();
389 final NHttpClientConnection managedConn = CPoolProxy.newProxy(poolentry);
390
391 Mockito.when(conn.getIOSession()).thenReturn(iosession);
392 Mockito.when(sslStrategy.upgrade(target, iosession)).thenReturn(iosession);
393
394 connman.upgrade(managedConn, route, context);
395 }
396
397 @Test
398 public void testConnectionRouteComplete() throws Exception {
399 final HttpHost target = new HttpHost("somehost", 80, "http");
400 final HttpRoute route = new HttpRoute(target);
401 final HttpContext context = new BasicHttpContext();
402
403 final Log log = Mockito.mock(Log.class);
404 final CPoolEntry poolentry = new CPoolEntry(log, "some-id", route, conn, -1, TimeUnit.MILLISECONDS);
405 poolentry.markRouteComplete();
406 final NHttpClientConnection managedConn = CPoolProxy.newProxy(poolentry);
407
408 Mockito.when(conn.getIOSession()).thenReturn(iosession);
409 Mockito.when(sslStrategy.upgrade(target, iosession)).thenReturn(iosession);
410
411 connman.startRoute(managedConn, route, context);
412 connman.routeComplete(managedConn, route, context);
413
414 Assert.assertTrue(connman.isRouteComplete(managedConn));
415 }
416
417 @Test
418 public void testDelegationToCPool() throws Exception {
419 connman.closeExpiredConnections();
420 Mockito.verify(pool).closeExpired();
421
422 connman.closeIdleConnections(3, TimeUnit.SECONDS);
423 Mockito.verify(pool).closeIdle(3, TimeUnit.SECONDS);
424
425 connman.getMaxTotal();
426 Mockito.verify(pool).getMaxTotal();
427
428 connman.getDefaultMaxPerRoute();
429 Mockito.verify(pool).getDefaultMaxPerRoute();
430
431 final HttpRoute route = new HttpRoute(new HttpHost("somehost", 80));
432 connman.getMaxPerRoute(route);
433 Mockito.verify(pool).getMaxPerRoute(route);
434
435 connman.setMaxTotal(200);
436 Mockito.verify(pool).setMaxTotal(200);
437
438 connman.setDefaultMaxPerRoute(100);
439 Mockito.verify(pool).setDefaultMaxPerRoute(100);
440
441 connman.setMaxPerRoute(route, 150);
442 Mockito.verify(pool).setMaxPerRoute(route, 150);
443
444 connman.getTotalStats();
445 Mockito.verify(pool).getTotalStats();
446
447 connman.getStats(route);
448 Mockito.verify(pool).getStats(route);
449 }
450
451 @Test
452 public void testInternalConnFactoryCreate() throws Exception {
453 final ConfigData configData = new ConfigData();
454 final InternalConnectionFactory internalConnFactory = new InternalConnectionFactory(
455 configData, connFactory);
456
457 final HttpRoute route = new HttpRoute(new HttpHost("somehost", 80));
458 internalConnFactory.create(route, iosession);
459
460 Mockito.verify(sslStrategy, Mockito.never()).upgrade(Mockito.eq(new HttpHost("somehost", 80)),
461 Mockito.<IOSession>any());
462 Mockito.verify(connFactory).create(Mockito.same(iosession), Mockito.<ConnectionConfig>any());
463 }
464
465 @Test
466 public void testInternalConnFactoryCreateViaProxy() throws Exception {
467 final ConfigData configData = new ConfigData();
468 final InternalConnectionFactory internalConnFactory = new InternalConnectionFactory(
469 configData, connFactory);
470
471 final HttpHost target = new HttpHost("somehost", 80);
472 final HttpHost proxy = new HttpHost("someproxy", 8888);
473 final HttpRoute route = new HttpRoute(target, null, proxy, false);
474
475 final ConnectionConfig config = ConnectionConfig.custom().build();
476 configData.setConnectionConfig(proxy, config);
477
478 internalConnFactory.create(route, iosession);
479
480 Mockito.verify(connFactory).create(iosession, config);
481 }
482
483 @Test
484 public void testInternalConnFactoryCreateDirect() throws Exception {
485 final ConfigData configData = new ConfigData();
486 final InternalConnectionFactory internalConnFactory = new InternalConnectionFactory(
487 configData, connFactory);
488
489 final HttpHost target = new HttpHost("somehost", 80);
490 final HttpRoute route = new HttpRoute(target);
491
492 final ConnectionConfig config = ConnectionConfig.custom().build();
493 configData.setConnectionConfig(target, config);
494
495 internalConnFactory.create(route, iosession);
496
497 Mockito.verify(connFactory).create(iosession, config);
498 }
499
500 @Test
501 public void testInternalConnFactoryCreateDefaultConfig() throws Exception {
502 final ConfigData configData = new ConfigData();
503 final InternalConnectionFactory internalConnFactory = new InternalConnectionFactory(
504 configData, connFactory);
505
506 final HttpHost target = new HttpHost("somehost", 80);
507 final HttpRoute route = new HttpRoute(target);
508
509 final ConnectionConfig config = ConnectionConfig.custom().build();
510 configData.setDefaultConnectionConfig(config);
511
512 internalConnFactory.create(route, iosession);
513
514 Mockito.verify(connFactory).create(iosession, config);
515 }
516
517 @Test
518 public void testInternalConnFactoryCreateGlobalDefaultConfig() throws Exception {
519 final ConfigData configData = new ConfigData();
520 final InternalConnectionFactory internalConnFactory = new InternalConnectionFactory(
521 configData, connFactory);
522
523 final HttpHost target = new HttpHost("somehost", 80);
524 final HttpRoute route = new HttpRoute(target);
525
526 configData.setDefaultConnectionConfig(null);
527
528 internalConnFactory.create(route, iosession);
529
530 Mockito.verify(connFactory).create(iosession, ConnectionConfig.DEFAULT);
531 }
532
533 @Test
534 public void testResolveLocalAddress() throws Exception {
535 final InternalAddressResolver addressResolver = new InternalAddressResolver(
536 schemePortResolver, dnsResolver);
537
538 final HttpHost target = new HttpHost("localhost");
539 final byte[] ip = new byte[] {10, 0, 0, 10};
540 final HttpRoute route = new HttpRoute(target, InetAddress.getByAddress(ip), false);
541 final InetSocketAddress address = (InetSocketAddress) addressResolver.resolveLocalAddress(route);
542
543 Assert.assertNotNull(address);
544 Assert.assertEquals(InetAddress.getByAddress(ip), address.getAddress());
545 Assert.assertEquals(0, address.getPort());
546 }
547
548 @Test
549 public void testResolveLocalAddressNull() throws Exception {
550 final InternalAddressResolver addressResolver = new InternalAddressResolver(
551 schemePortResolver, dnsResolver);
552
553 final HttpHost target = new HttpHost("localhost");
554 final HttpRoute route = new HttpRoute(target);
555 final InetSocketAddress address = (InetSocketAddress) addressResolver.resolveLocalAddress(route);
556
557 Assert.assertNull(address);
558 }
559
560 @Test
561 public void testResolveRemoteAddress() throws Exception {
562 final InternalAddressResolver addressResolver = new InternalAddressResolver(
563 schemePortResolver, dnsResolver);
564
565 final HttpHost target = new HttpHost("somehost", 80);
566 final HttpRoute route = new HttpRoute(target);
567
568 Mockito.when(schemePortResolver.resolve(target)).thenReturn(123);
569 final byte[] ip = new byte[] {10, 0, 0, 10};
570 Mockito.when(dnsResolver.resolve("somehost")).thenReturn(new InetAddress[] {InetAddress.getByAddress(ip)});
571
572 final InetSocketAddress address = (InetSocketAddress) addressResolver.resolveRemoteAddress(route);
573
574 Assert.assertNotNull(address);
575 Assert.assertEquals(InetAddress.getByAddress(ip), address.getAddress());
576 Assert.assertEquals(123, address.getPort());
577 }
578
579 @Test
580 public void testResolveRemoteAddressViaProxy() throws Exception {
581 final InternalAddressResolver addressResolver = new InternalAddressResolver(
582 schemePortResolver, dnsResolver);
583
584 final HttpHost target = new HttpHost("somehost", 80);
585 final HttpHost proxy = new HttpHost("someproxy");
586 final HttpRoute route = new HttpRoute(target, null, proxy, false);
587
588 Mockito.when(schemePortResolver.resolve(proxy)).thenReturn(8888);
589 final byte[] ip = new byte[] {10, 0, 0, 10};
590 Mockito.when(dnsResolver.resolve("someproxy")).thenReturn(new InetAddress[] {InetAddress.getByAddress(ip)});
591
592 final InetSocketAddress address = (InetSocketAddress) addressResolver.resolveRemoteAddress(route);
593
594 Assert.assertNotNull(address);
595 Assert.assertEquals(InetAddress.getByAddress(ip), address.getAddress());
596 Assert.assertEquals(8888, address.getPort());
597 }
598
599 }
0 /*
1 * ====================================================================
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 * ====================================================================
19 *
20 * This software consists of voluntary contributions made by many
21 * individuals on behalf of the Apache Software Foundation. For more
22 * information on the Apache Software Foundation, please see
23 * <http://www.apache.org/>.
24 *
25 */
26
27 package org.apache.http.localserver;
28
29 import java.net.InetSocketAddress;
30 import java.net.URL;
31 import java.util.concurrent.TimeUnit;
32
33 import javax.net.ssl.SSLContext;
34
35 import org.apache.commons.logging.Log;
36 import org.apache.commons.logging.LogFactory;
37 import org.apache.http.ExceptionLogger;
38 import org.apache.http.HttpHost;
39 import org.apache.http.config.Registry;
40 import org.apache.http.config.RegistryBuilder;
41 import org.apache.http.conn.ssl.DefaultHostnameVerifier;
42 import org.apache.http.impl.nio.bootstrap.HttpServer;
43 import org.apache.http.impl.nio.bootstrap.ServerBootstrap;
44 import org.apache.http.impl.nio.conn.PoolingNHttpClientConnectionManager;
45 import org.apache.http.impl.nio.reactor.DefaultConnectingIOReactor;
46 import org.apache.http.impl.nio.reactor.IOReactorConfig;
47 import org.apache.http.nio.conn.NoopIOSessionStrategy;
48 import org.apache.http.nio.conn.SchemeIOSessionStrategy;
49 import org.apache.http.nio.conn.ssl.SSLIOSessionStrategy;
50 import org.apache.http.nio.reactor.ListenerEndpoint;
51 import org.apache.http.ssl.SSLContextBuilder;
52 import org.junit.After;
53 import org.junit.Before;
54
55 public abstract class AbstractAsyncTest {
56
57 public enum ProtocolScheme { http, https };
58
59 protected final ProtocolScheme scheme;
60
61 protected ServerBootstrap serverBootstrap;
62 protected HttpServer server;
63 protected PoolingNHttpClientConnectionManager connMgr;
64
65 public AbstractAsyncTest(final ProtocolScheme scheme) {
66 this.scheme = scheme;
67 }
68
69 public AbstractAsyncTest() {
70 this(ProtocolScheme.http);
71 }
72
73 public String getSchemeName() {
74 return this.scheme.name();
75 }
76
77 protected SSLContext createServerSSLContext() throws Exception {
78 final URL keyStoreURL = getClass().getResource("/test.keystore");
79 final String storePassword = "nopassword";
80 return SSLContextBuilder.create()
81 .loadTrustMaterial(keyStoreURL, storePassword.toCharArray())
82 .loadKeyMaterial(keyStoreURL, storePassword.toCharArray(), storePassword.toCharArray())
83 .build();
84 }
85
86 protected SSLContext createClientSSLContext() throws Exception {
87 final URL keyStoreURL = getClass().getResource("/test.keystore");
88 final String storePassword = "nopassword";
89 return SSLContextBuilder.create()
90 .loadTrustMaterial(keyStoreURL, storePassword.toCharArray())
91 .build();
92 }
93
94 public HttpHost startServer() throws Exception {
95 this.server = this.serverBootstrap.create();
96 this.server.start();
97
98 final ListenerEndpoint endpoint = this.server.getEndpoint();
99 endpoint.waitFor();
100
101 final InetSocketAddress address = (InetSocketAddress) endpoint.getAddress();
102 return new HttpHost("localhost", address.getPort(), this.scheme.name());
103 }
104
105 @Before
106 public void setUp() throws Exception {
107 this.serverBootstrap = ServerBootstrap.bootstrap();
108 final IOReactorConfig ioReactorConfig = IOReactorConfig.custom()
109 .setSoTimeout(15000)
110 .build();
111 this.serverBootstrap.setServerInfo("TEST/1.1");
112 this.serverBootstrap.setIOReactorConfig(ioReactorConfig);
113 this.serverBootstrap.setExceptionLogger(new ExceptionLogger() {
114
115 private final Log log = LogFactory.getLog(AbstractAsyncTest.class);
116
117 @Override
118 public void log(final Exception ex) {
119 log.error(ex.getMessage(), ex);
120 }
121 });
122 if (this.scheme.equals(ProtocolScheme.https)) {
123 this.serverBootstrap.setSslContext(createServerSSLContext());
124 }
125
126 final RegistryBuilder<SchemeIOSessionStrategy> builder = RegistryBuilder.create();
127 builder.register("http", NoopIOSessionStrategy.INSTANCE);
128 if (this.scheme.equals(ProtocolScheme.https)) {
129 builder.register("https", new SSLIOSessionStrategy(
130 createClientSSLContext(),
131 new DefaultHostnameVerifier()));
132 }
133 final Registry<SchemeIOSessionStrategy> registry = builder.build();
134 final DefaultConnectingIOReactor ioReactor = new DefaultConnectingIOReactor(ioReactorConfig);
135 this.connMgr = new PoolingNHttpClientConnectionManager(ioReactor, registry);
136 }
137
138 @After
139 public void shutDown() throws Exception {
140 if (this.server != null) {
141 this.server.shutdown(10, TimeUnit.SECONDS);
142 }
143 }
144
145 }
0 /*
1 * ====================================================================
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 * ====================================================================
19 *
20 * This software consists of voluntary contributions made by many
21 * individuals on behalf of the Apache Software Foundation. For more
22 * information on the Apache Software Foundation, please see
23 * <http://www.apache.org/>.
24 *
25 */
26
27 package org.apache.http.localserver;
28
29 import org.apache.commons.codec.BinaryDecoder;
30 import org.apache.commons.codec.DecoderException;
31 import org.apache.commons.codec.binary.Base64;
32 import org.apache.http.Header;
33 import org.apache.http.HttpException;
34 import org.apache.http.HttpRequest;
35 import org.apache.http.ProtocolException;
36 import org.apache.http.auth.AUTH;
37 import org.apache.http.util.EncodingUtils;
38
39 public class BasicAuthTokenExtractor {
40
41 public String extract(final HttpRequest request) throws HttpException {
42 String auth = null;
43
44 final Header h = request.getFirstHeader(AUTH.WWW_AUTH_RESP);
45 if (h != null) {
46 final String s = h.getValue();
47 if (s != null) {
48 auth = s.trim();
49 }
50 }
51
52 if (auth != null) {
53 final int i = auth.indexOf(' ');
54 if (i == -1) {
55 throw new ProtocolException("Invalid Authorization header: " + auth);
56 }
57 final String authscheme = auth.substring(0, i);
58 if (authscheme.equalsIgnoreCase("basic")) {
59 final String s = auth.substring(i + 1).trim();
60 try {
61 final byte[] credsRaw = EncodingUtils.getAsciiBytes(s);
62 final BinaryDecoder codec = new Base64();
63 auth = EncodingUtils.getAsciiString(codec.decode(credsRaw));
64 } catch (final DecoderException ex) {
65 throw new ProtocolException("Malformed BASIC credentials");
66 }
67 }
68 }
69 return auth;
70 }
71
72 }
0 /*
1 * ====================================================================
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 * ====================================================================
19 *
20 * This software consists of voluntary contributions made by many
21 * individuals on behalf of the Apache Software Foundation. For more
22 * information on the Apache Software Foundation, please see
23 * <http://www.apache.org/>.
24 *
25 */
26
27 package org.apache.http.localserver;
28
29 import java.io.IOException;
30 import java.util.Locale;
31
32 import org.apache.http.HttpEntity;
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.MethodNotSupportedException;
38 import org.apache.http.nio.entity.NByteArrayEntity;
39 import org.apache.http.protocol.HttpContext;
40 import org.apache.http.protocol.HttpRequestHandler;
41 import org.apache.http.util.EntityUtils;
42
43 /**
44 * A handler that echos the incoming request entity.
45 */
46 public class EchoHandler
47 implements HttpRequestHandler {
48
49 // public default constructor
50
51 /**
52 * Handles a request by echoing the incoming request entity.
53 * If there is no request entity, an empty document is returned.
54 *
55 * @param request the request
56 * @param response the response
57 * @param context the context
58 *
59 * @throws HttpException in case of a problem
60 * @throws IOException in case of an IO problem
61 */
62 @Override
63 public void handle(final HttpRequest request,
64 final HttpResponse response,
65 final HttpContext context)
66 throws HttpException, IOException {
67
68 final String method = request.getRequestLine().getMethod().toUpperCase(Locale.ROOT);
69 if (!"GET".equals(method) &&
70 !"POST".equals(method) &&
71 !"PUT".equals(method)
72 ) {
73 throw new MethodNotSupportedException
74 (method + " not supported by " + getClass().getName());
75 }
76
77 HttpEntity entity = null;
78 if (request instanceof HttpEntityEnclosingRequest) {
79 entity = ((HttpEntityEnclosingRequest)request).getEntity();
80 }
81
82 // For some reason, just putting the incoming entity into
83 // the response will not work. We have to buffer the message.
84 final byte[] data;
85 if (entity == null) {
86 data = new byte [0];
87 } else {
88 data = EntityUtils.toByteArray(entity);
89 }
90
91 final NByteArrayEntity bae = new NByteArrayEntity(data);
92 if (entity != null) {
93 bae.setContentType(entity.getContentType());
94 }
95 response.setEntity(bae);
96 }
97
98 }
0 /*
1 * ====================================================================
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 * ====================================================================
19 *
20 * This software consists of voluntary contributions made by many
21 * individuals on behalf of the Apache Software Foundation. For more
22 * information on the Apache Software Foundation, please see
23 * <http://www.apache.org/>.
24 *
25 */
26
27 package org.apache.http.localserver;
28
29 import org.apache.http.HttpHost;
30 import org.apache.http.impl.nio.client.CloseableHttpAsyncClient;
31 import org.apache.http.impl.nio.client.HttpAsyncClientBuilder;
32 import org.junit.After;
33 import org.junit.Before;
34
35 public abstract class HttpAsyncTestBase extends AbstractAsyncTest{
36
37 protected HttpAsyncClientBuilder clientBuilder;
38 protected CloseableHttpAsyncClient httpclient;
39
40 public HttpAsyncTestBase() {
41 super();
42 }
43
44 public HttpAsyncTestBase(final ProtocolScheme scheme) {
45 super(scheme);
46 }
47
48 public HttpHost start() throws Exception {
49 final HttpHost serverEndpoint = startServer();
50
51 this.httpclient = this.clientBuilder.build();
52 this.httpclient.start();
53
54 return serverEndpoint;
55 }
56
57 @Before @Override
58 public void setUp() throws Exception {
59 super.setUp();
60 this.clientBuilder = HttpAsyncClientBuilder.create();
61 this.clientBuilder.setConnectionManager(this.connMgr);
62 }
63
64 @After @Override
65 public void shutDown() throws Exception {
66 if (this.httpclient != null) {
67 this.httpclient.close();
68 }
69 super.shutDown();
70 }
71
72 }
0 /*
1 * ====================================================================
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 * ====================================================================
19 *
20 * This software consists of voluntary contributions made by many
21 * individuals on behalf of the Apache Software Foundation. For more
22 * information on the Apache Software Foundation, please see
23 * <http://www.apache.org/>.
24 *
25 */
26
27 package org.apache.http.localserver;
28
29 import java.io.IOException;
30 import java.util.Locale;
31
32 import org.apache.http.Consts;
33 import org.apache.http.HttpException;
34 import org.apache.http.HttpRequest;
35 import org.apache.http.HttpResponse;
36 import org.apache.http.HttpStatus;
37 import org.apache.http.MethodNotSupportedException;
38 import org.apache.http.entity.ContentType;
39 import org.apache.http.nio.entity.NByteArrayEntity;
40 import org.apache.http.protocol.HttpContext;
41 import org.apache.http.protocol.HttpRequestHandler;
42
43 /**
44 * A handler that generates random data.
45 */
46 public class RandomHandler implements HttpRequestHandler {
47
48 private final static byte[] RANGE;
49 static {
50 RANGE = ("abcdefghijklmnopqrstuvwxyz" +
51 "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "0123456789"
52 ).getBytes(Consts.ASCII);
53 }
54
55 /**
56 * Handles a request by generating random data.
57 * The length of the response can be specified in the request URI
58 * as a number after the last /. For example /random/whatever/20
59 * will generate 20 random bytes in the printable ASCII range.
60 * If the request URI ends with /, a random number of random bytes
61 * is generated, but at least one.
62 *
63 * @param request the request
64 * @param response the response
65 * @param context the context
66 *
67 * @throws HttpException in case of a problem
68 * @throws IOException in case of an IO problem
69 */
70 @Override
71 public void handle(final HttpRequest request,
72 final HttpResponse response,
73 final HttpContext context)
74 throws HttpException, IOException {
75
76 final String method = request.getRequestLine().getMethod().toUpperCase(Locale.ROOT);
77 if (!"GET".equals(method) && !"HEAD".equals(method)) {
78 throw new MethodNotSupportedException
79 (method + " not supported by " + getClass().getName());
80 }
81
82 final String uri = request.getRequestLine().getUri();
83 final int slash = uri.lastIndexOf('/');
84 int length = -1;
85 if (slash < uri.length()-1) {
86 try {
87 // no more than Integer, 2 GB ought to be enough for anybody
88 length = Integer.parseInt(uri.substring(slash+1));
89
90 if (length < 0) {
91 response.setStatusCode(HttpStatus.SC_BAD_REQUEST);
92 response.setReasonPhrase("LENGTH " + length);
93 }
94 } catch (final NumberFormatException nfx) {
95 response.setStatusCode(HttpStatus.SC_BAD_REQUEST);
96 response.setReasonPhrase(nfx.toString());
97 }
98 } else {
99 // random length, but make sure at least something is sent
100 length = 1 + (int)(Math.random() * 79.0);
101 }
102
103 if (length >= 0) {
104 final byte[] data = new byte[length];
105 for (int i = 0; i < length; i++) {
106 double value = 0.0;
107 // we get 5 random characters out of one random value
108 if (i%5 == 0) {
109 value = Math.random();
110 }
111 value = value * RANGE.length;
112 final int d = (int) value;
113 value = value - d;
114 data[i] = RANGE[d];
115 }
116 final NByteArrayEntity bae = new NByteArrayEntity(data, ContentType.DEFAULT_TEXT);
117 response.setEntity(bae);
118 }
119 }
120
121 }
0 /*
1 * ====================================================================
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 * ====================================================================
19 *
20 * This software consists of voluntary contributions made by many
21 * individuals on behalf of the Apache Software Foundation. For more
22 * information on the Apache Software Foundation, please see
23 * <http://www.apache.org/>.
24 *
25 */
26
27 package org.apache.http.localserver;
28
29 import java.io.IOException;
30
31 import org.apache.http.HttpException;
32 import org.apache.http.HttpRequest;
33 import org.apache.http.HttpRequestInterceptor;
34 import org.apache.http.protocol.HttpContext;
35
36 public class RequestBasicAuth implements HttpRequestInterceptor {
37
38 private final BasicAuthTokenExtractor authTokenExtractor;
39
40 public RequestBasicAuth() {
41 super();
42 this.authTokenExtractor = new BasicAuthTokenExtractor();
43 }
44
45 @Override
46 public void process(
47 final HttpRequest request,
48 final HttpContext context) throws HttpException, IOException {
49 context.setAttribute("creds", this.authTokenExtractor.extract(request));
50 }
51
52 }
0 /*
1 * ====================================================================
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 * ====================================================================
19 *
20 * This software consists of voluntary contributions made by many
21 * individuals on behalf of the Apache Software Foundation. For more
22 * information on the Apache Software Foundation, please see
23 * <http://www.apache.org/>.
24 *
25 */
26
27 package org.apache.http.localserver;
28
29 import java.io.IOException;
30
31 import org.apache.http.HttpException;
32 import org.apache.http.HttpResponse;
33 import org.apache.http.HttpResponseInterceptor;
34 import org.apache.http.HttpStatus;
35 import org.apache.http.auth.AUTH;
36 import org.apache.http.protocol.HttpContext;
37
38 public class ResponseBasicUnauthorized implements HttpResponseInterceptor {
39
40 @Override
41 public void process(
42 final HttpResponse response,
43 final HttpContext context) throws HttpException, IOException {
44 if (response.getStatusLine().getStatusCode() == HttpStatus.SC_UNAUTHORIZED) {
45 response.addHeader(AUTH.WWW_AUTH, "Basic realm=\"test realm\"");
46 }
47 }
48
49 }
0 /*
1 * ====================================================================
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 * ====================================================================
19 *
20 * This software consists of voluntary contributions made by many
21 * individuals on behalf of the Apache Software Foundation. For more
22 * information on the Apache Software Foundation, please see
23 * <http://www.apache.org/>.
24 *
25 */
26 package org.apache.http.nio.client.integration;
27
28 import java.io.IOException;
29 import java.util.Arrays;
30 import java.util.Collection;
31 import java.util.concurrent.ExecutionException;
32 import java.util.concurrent.Future;
33
34 import org.apache.http.Consts;
35 import org.apache.http.localserver.HttpAsyncTestBase;
36 import org.apache.http.HttpEntity;
37 import org.apache.http.HttpException;
38 import org.apache.http.HttpHost;
39 import org.apache.http.HttpInetConnection;
40 import org.apache.http.HttpRequest;
41 import org.apache.http.HttpResponse;
42 import org.apache.http.HttpStatus;
43 import org.apache.http.HttpVersion;
44 import org.apache.http.ProtocolVersion;
45 import org.apache.http.auth.AuthScope;
46 import org.apache.http.auth.Credentials;
47 import org.apache.http.auth.UsernamePasswordCredentials;
48 import org.apache.http.client.CredentialsProvider;
49 import org.apache.http.client.config.RequestConfig;
50 import org.apache.http.client.methods.HttpGet;
51 import org.apache.http.client.methods.HttpPost;
52 import org.apache.http.client.methods.HttpPut;
53 import org.apache.http.client.protocol.HttpClientContext;
54 import org.apache.http.impl.client.BasicCredentialsProvider;
55 import org.apache.http.impl.client.TargetAuthenticationStrategy;
56 import org.apache.http.localserver.BasicAuthTokenExtractor;
57 import org.apache.http.localserver.RequestBasicAuth;
58 import org.apache.http.localserver.ResponseBasicUnauthorized;
59 import org.apache.http.message.BasicHeader;
60 import org.apache.http.message.BasicHttpResponse;
61 import org.apache.http.nio.entity.NByteArrayEntity;
62 import org.apache.http.nio.entity.NStringEntity;
63 import org.apache.http.nio.protocol.BasicAsyncRequestHandler;
64 import org.apache.http.nio.protocol.BasicAsyncResponseProducer;
65 import org.apache.http.nio.protocol.HttpAsyncExchange;
66 import org.apache.http.nio.protocol.HttpAsyncExpectationVerifier;
67 import org.apache.http.protocol.HTTP;
68 import org.apache.http.protocol.HttpContext;
69 import org.apache.http.protocol.HttpCoreContext;
70 import org.apache.http.protocol.HttpRequestHandler;
71 import org.junit.Assert;
72 import org.junit.Before;
73 import org.junit.Test;
74 import org.junit.runner.RunWith;
75 import org.junit.runners.Parameterized;
76
77 @RunWith(Parameterized.class)
78 public class TestClientAuthentication extends HttpAsyncTestBase {
79
80 @Parameterized.Parameters(name = "{0}")
81 public static Collection<Object[]> protocols() {
82 return Arrays.asList(new Object[][]{
83 {ProtocolScheme.http},
84 {ProtocolScheme.https},
85 });
86 }
87
88 public TestClientAuthentication(final ProtocolScheme scheme) {
89 super(scheme);
90 }
91
92 @Before @Override
93 public void setUp() throws Exception {
94 super.setUp();
95 this.serverBootstrap.addInterceptorFirst(new RequestBasicAuth());
96 this.serverBootstrap.addInterceptorLast(new ResponseBasicUnauthorized());
97 }
98
99 static class AuthHandler implements HttpRequestHandler {
100
101 private final boolean keepAlive;
102
103 AuthHandler(final boolean keepAlive) {
104 super();
105 this.keepAlive = keepAlive;
106 }
107
108 AuthHandler() {
109 this(true);
110 }
111
112 @Override
113 public void handle(
114 final HttpRequest request,
115 final HttpResponse response,
116 final HttpContext context) throws HttpException, IOException {
117 final String creds = (String) context.getAttribute("creds");
118 if (creds == null || !creds.equals("test:test")) {
119 response.setStatusCode(HttpStatus.SC_UNAUTHORIZED);
120 } else {
121 response.setStatusCode(HttpStatus.SC_OK);
122 final NStringEntity entity = new NStringEntity("success", Consts.ASCII);
123 response.setEntity(entity);
124 }
125 response.setHeader(HTTP.CONN_DIRECTIVE,
126 this.keepAlive ? HTTP.CONN_KEEP_ALIVE : HTTP.CONN_CLOSE);
127 }
128
129 }
130
131 static class TestTargetAuthenticationStrategy extends TargetAuthenticationStrategy {
132
133 private int count;
134
135 public TestTargetAuthenticationStrategy() {
136 super();
137 this.count = 0;
138 }
139
140 @Override
141 public boolean isAuthenticationRequested(
142 final HttpHost authhost,
143 final HttpResponse response,
144 final HttpContext context) {
145 final boolean res = super.isAuthenticationRequested(authhost, response, context);
146 if (res) {
147 synchronized (this) {
148 this.count++;
149 }
150 }
151 return res;
152 }
153
154 public int getCount() {
155 synchronized (this) {
156 return this.count;
157 }
158 }
159
160 }
161
162 static class AuthExpectationVerifier implements HttpAsyncExpectationVerifier {
163
164 private final BasicAuthTokenExtractor authTokenExtractor;
165
166 public AuthExpectationVerifier() {
167 super();
168 this.authTokenExtractor = new BasicAuthTokenExtractor();
169 }
170
171 @Override
172 public void verify(
173 final HttpAsyncExchange httpexchange,
174 final HttpContext context) throws HttpException, IOException {
175 final HttpRequest request = httpexchange.getRequest();
176 ProtocolVersion ver = request.getRequestLine().getProtocolVersion();
177 if (!ver.lessEquals(HttpVersion.HTTP_1_1)) {
178 ver = HttpVersion.HTTP_1_1;
179 }
180 final String creds = this.authTokenExtractor.extract(request);
181 if (creds == null || !creds.equals("test:test")) {
182 final HttpResponse response = new BasicHttpResponse(ver, HttpStatus.SC_UNAUTHORIZED, "UNAUTHORIZED");
183 httpexchange.submitResponse(new BasicAsyncResponseProducer(response));
184 } else {
185 httpexchange.submitResponse();
186 }
187 }
188
189 }
190
191 static class TestCredentialsProvider implements CredentialsProvider {
192
193 private final Credentials creds;
194 private AuthScope authscope;
195
196 TestCredentialsProvider(final Credentials creds) {
197 super();
198 this.creds = creds;
199 }
200
201 @Override
202 public void clear() {
203 }
204
205 @Override
206 public Credentials getCredentials(final AuthScope authscope) {
207 this.authscope = authscope;
208 return this.creds;
209 }
210
211 @Override
212 public void setCredentials(final AuthScope authscope, final Credentials credentials) {
213 }
214
215 public AuthScope getAuthScope() {
216 return this.authscope;
217 }
218
219 }
220
221 @Test
222 public void testBasicAuthenticationNoCreds() throws Exception {
223 this.serverBootstrap.registerHandler("*", new BasicAsyncRequestHandler(new AuthHandler()));
224 final HttpHost target = start();
225
226 final TestCredentialsProvider credsProvider = new TestCredentialsProvider(null);
227 final HttpClientContext context = HttpClientContext.create();
228 context.setCredentialsProvider(credsProvider);
229 final HttpGet httpget = new HttpGet("/");
230 final Future<HttpResponse> future = this.httpclient.execute(target, httpget, context, null);
231 final HttpResponse response = future.get();
232 Assert.assertNotNull(response);
233 Assert.assertEquals(HttpStatus.SC_UNAUTHORIZED, response.getStatusLine().getStatusCode());
234 final AuthScope authscope = credsProvider.getAuthScope();
235 Assert.assertNotNull(authscope);
236 Assert.assertEquals("test realm", authscope.getRealm());
237 }
238
239 @Test
240 public void testBasicAuthenticationFailure() throws Exception {
241 this.serverBootstrap.registerHandler("*", new BasicAsyncRequestHandler(new AuthHandler()));
242 final HttpHost target = start();
243
244 final TestCredentialsProvider credsProvider = new TestCredentialsProvider(
245 new UsernamePasswordCredentials("test", "all-wrong"));
246 final HttpClientContext context = HttpClientContext.create();
247 context.setCredentialsProvider(credsProvider);
248 final HttpGet httpget = new HttpGet("/");
249 final Future<HttpResponse> future = this.httpclient.execute(target, httpget, context, null);
250 final HttpResponse response = future.get();
251 Assert.assertNotNull(response);
252 Assert.assertEquals(HttpStatus.SC_UNAUTHORIZED, response.getStatusLine().getStatusCode());
253 final AuthScope authscope = credsProvider.getAuthScope();
254 Assert.assertNotNull(authscope);
255 Assert.assertEquals("test realm", authscope.getRealm());
256 }
257
258 @Test
259 public void testBasicAuthenticationSuccess() throws Exception {
260 this.serverBootstrap.registerHandler("*", new BasicAsyncRequestHandler(new AuthHandler()));
261 final HttpHost target = start();
262
263 final TestCredentialsProvider credsProvider = new TestCredentialsProvider(
264 new UsernamePasswordCredentials("test", "test"));
265 final HttpClientContext context = HttpClientContext.create();
266 context.setCredentialsProvider(credsProvider);
267 final HttpGet httpget = new HttpGet("/");
268 final Future<HttpResponse> future = this.httpclient.execute(target, httpget, context, null);
269 final HttpResponse response = future.get();
270 Assert.assertNotNull(response);
271 Assert.assertEquals(HttpStatus.SC_OK, response.getStatusLine().getStatusCode());
272 final AuthScope authscope = credsProvider.getAuthScope();
273 Assert.assertNotNull(authscope);
274 Assert.assertEquals("test realm", authscope.getRealm());
275 }
276
277 @Test
278 public void testBasicAuthenticationSuccessNonPersistentConnection() throws Exception {
279 this.serverBootstrap.registerHandler("*", new BasicAsyncRequestHandler(new AuthHandler(false)));
280 final HttpHost target = start();
281
282 final TestCredentialsProvider credsProvider = new TestCredentialsProvider(
283 new UsernamePasswordCredentials("test", "test"));
284 final HttpClientContext context = HttpClientContext.create();
285 context.setCredentialsProvider(credsProvider);
286
287 final HttpGet httpget = new HttpGet("/");
288 final Future<HttpResponse> future = this.httpclient.execute(target, httpget, context, null);
289 final HttpResponse response = future.get();
290 Assert.assertNotNull(response);
291 Assert.assertEquals(HttpStatus.SC_OK, response.getStatusLine().getStatusCode());
292 final AuthScope authscope = credsProvider.getAuthScope();
293 Assert.assertNotNull(authscope);
294 Assert.assertEquals("test realm", authscope.getRealm());
295 }
296
297 @Test
298 public void testBasicAuthenticationSuccessWithNonRepeatableExpectContinue() throws Exception {
299 this.serverBootstrap.registerHandler("*", new BasicAsyncRequestHandler(new AuthHandler()));
300 this.serverBootstrap.setExpectationVerifier(new AuthExpectationVerifier());
301 final HttpHost target = start();
302
303 final TestCredentialsProvider credsProvider = new TestCredentialsProvider(
304 new UsernamePasswordCredentials("test", "test"));
305 final HttpClientContext context = HttpClientContext.create();
306 context.setCredentialsProvider(credsProvider);
307 final HttpPut httpput = new HttpPut("/");
308
309 final NByteArrayEntity entity = new NByteArrayEntity(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 }) {
310
311 @Override
312 public boolean isRepeatable() {
313 return false;
314 }
315
316 };
317
318 httpput.setEntity(entity);
319 httpput.setConfig(RequestConfig.custom().setExpectContinueEnabled(true).build());
320
321 final Future<HttpResponse> future = this.httpclient.execute(target, httpput, context, null);
322 final HttpResponse response = future.get();
323 Assert.assertNotNull(response);
324 Assert.assertEquals(HttpStatus.SC_OK, response.getStatusLine().getStatusCode());
325 }
326
327 @Test(expected=ExecutionException.class)
328 public void testBasicAuthenticationFailureWithNonRepeatableEntityExpectContinueOff() throws Exception {
329 this.serverBootstrap.registerHandler("*", new BasicAsyncRequestHandler(new AuthHandler()));
330 final HttpHost target = start();
331
332 final TestCredentialsProvider credsProvider = new TestCredentialsProvider(
333 new UsernamePasswordCredentials("test", "test"));
334 final HttpClientContext context = HttpClientContext.create();
335 context.setCredentialsProvider(credsProvider);
336 final HttpPut httpput = new HttpPut("/");
337
338 final NByteArrayEntity requestEntity = new NByteArrayEntity(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 }) {
339
340 @Override
341 public boolean isRepeatable() {
342 return false;
343 }
344
345 };
346
347 httpput.setEntity(requestEntity);
348 httpput.setConfig(RequestConfig.custom().setExpectContinueEnabled(false).build());
349
350 try {
351 final Future<HttpResponse> future = this.httpclient.execute(target, httpput, context, null);
352 future.get();
353 Assert.fail("ExecutionException should have been thrown");
354 } catch (final ExecutionException ex) {
355 final Throwable cause = ex.getCause();
356 Assert.assertNotNull(cause);
357 throw ex;
358 }
359 }
360
361 @Test
362 public void testBasicAuthenticationSuccessOnRepeatablePost() throws Exception {
363 this.serverBootstrap.registerHandler("*", new BasicAsyncRequestHandler(new AuthHandler()));
364 final HttpHost target = start();
365
366 final TestCredentialsProvider credsProvider = new TestCredentialsProvider(
367 new UsernamePasswordCredentials("test", "test"));
368 final HttpClientContext context = HttpClientContext.create();
369 context.setCredentialsProvider(credsProvider);
370 final HttpPost httppost = new HttpPost("/");
371 httppost.setEntity(new NStringEntity("some important stuff", Consts.ISO_8859_1));
372
373 final Future<HttpResponse> future = this.httpclient.execute(target, httppost, context, null);
374 final HttpResponse response = future.get();
375 Assert.assertNotNull(response);
376 Assert.assertEquals(HttpStatus.SC_OK, response.getStatusLine().getStatusCode());
377 final AuthScope authscope = credsProvider.getAuthScope();
378 Assert.assertNotNull(authscope);
379 Assert.assertEquals("test realm", authscope.getRealm());
380 }
381
382 @Test
383 public void testBasicAuthenticationCredentialsCaching() throws Exception {
384 this.serverBootstrap.registerHandler("*", new BasicAsyncRequestHandler(new AuthHandler()));
385 final TestTargetAuthenticationStrategy authStrategy = new TestTargetAuthenticationStrategy();
386 this.clientBuilder.setTargetAuthenticationStrategy(authStrategy);
387 final HttpHost target = start();
388
389 final BasicCredentialsProvider credsProvider = new BasicCredentialsProvider();
390 credsProvider.setCredentials(AuthScope.ANY,
391 new UsernamePasswordCredentials("test", "test"));
392 final HttpClientContext context = HttpClientContext.create();
393 context.setCredentialsProvider(credsProvider);
394
395 final HttpGet httpget1 = new HttpGet("/");
396 final Future<HttpResponse> future1 = this.httpclient.execute(target, httpget1, context, null);
397 final HttpResponse response1 = future1.get();
398 Assert.assertNotNull(response1);
399 Assert.assertEquals(HttpStatus.SC_OK, response1.getStatusLine().getStatusCode());
400
401 final HttpGet httpget2 = new HttpGet("/");
402 final Future<HttpResponse> future2 = this.httpclient.execute(target, httpget2, context, null);
403 final HttpResponse response2 = future2.get();
404 Assert.assertNotNull(response2);
405 Assert.assertEquals(HttpStatus.SC_OK, response2.getStatusLine().getStatusCode());
406
407 Assert.assertEquals(1, authStrategy.getCount());
408 }
409
410 @Test
411 public void testAuthenticationUserinfoInRequestSuccess() throws Exception {
412 this.serverBootstrap.registerHandler("*", new BasicAsyncRequestHandler(new AuthHandler()));
413 final HttpHost target = start();
414
415 final HttpGet httpget = new HttpGet("http://test:test@" + target.toHostString() + "/");
416 final Future<HttpResponse> future = this.httpclient.execute(target, httpget, null);
417 final HttpResponse response = future.get();
418 Assert.assertNotNull(response);
419 final HttpEntity entity = response.getEntity();
420 Assert.assertEquals(HttpStatus.SC_OK, response.getStatusLine().getStatusCode());
421 Assert.assertNotNull(entity);
422 }
423
424 @Test
425 public void testAuthenticationUserinfoInRequestFailure() throws Exception {
426 this.serverBootstrap.registerHandler("*", new BasicAsyncRequestHandler(new AuthHandler()));
427 final HttpHost target = start();
428
429 final HttpGet httpget = new HttpGet("http://test:all-wrong@" + target.toHostString() + "/");
430
431 final Future<HttpResponse> future = this.httpclient.execute(target, httpget, null);
432 final HttpResponse response = future.get();
433 Assert.assertNotNull(response);
434 final HttpEntity entity = response.getEntity();
435 Assert.assertEquals(HttpStatus.SC_UNAUTHORIZED, response.getStatusLine().getStatusCode());
436 Assert.assertNotNull(entity);
437 }
438
439 private class RedirectHandler implements HttpRequestHandler {
440
441 public RedirectHandler() {
442 super();
443 }
444
445 @Override
446 public void handle(
447 final HttpRequest request,
448 final HttpResponse response,
449 final HttpContext context) throws HttpException, IOException {
450 final HttpInetConnection conn = (HttpInetConnection) context.getAttribute(HttpCoreContext.HTTP_CONNECTION);
451 final int port = conn.getLocalPort();
452 response.setStatusCode(HttpStatus.SC_MOVED_PERMANENTLY);
453 response.addHeader(new BasicHeader("Location", getSchemeName() + "://test:test@localhost:" + port + "/"));
454 }
455
456 }
457
458 @Test
459 public void testAuthenticationUserinfoInRedirectSuccess() throws Exception {
460 this.serverBootstrap.registerHandler("*", new BasicAsyncRequestHandler(new AuthHandler()));
461 this.serverBootstrap.registerHandler("/thatway", new BasicAsyncRequestHandler(new RedirectHandler()));
462 final HttpHost target = start();
463
464 final HttpGet httpget = new HttpGet(target.getSchemeName() + "://test:test@" + target.toHostString() + "/thatway");
465 final Future<HttpResponse> future = this.httpclient.execute(target, httpget, null);
466 final HttpResponse response = future.get();
467 Assert.assertNotNull(response);
468 final HttpEntity entity = response.getEntity();
469 Assert.assertEquals(HttpStatus.SC_OK, response.getStatusLine().getStatusCode());
470 Assert.assertNotNull(entity);
471 }
472
473 }
0 /*
1 * ====================================================================
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 * ====================================================================
19 *
20 * This software consists of voluntary contributions made by many
21 * individuals on behalf of the Apache Software Foundation. For more
22 * information on the Apache Software Foundation, please see
23 * <http://www.apache.org/>.
24 *
25 */
26 package org.apache.http.nio.client.integration;
27
28 import java.io.IOException;
29 import java.util.concurrent.Future;
30
31 import org.apache.http.Consts;
32 import org.apache.http.localserver.HttpAsyncTestBase;
33 import org.apache.http.HttpEntity;
34 import org.apache.http.HttpException;
35 import org.apache.http.HttpHost;
36 import org.apache.http.HttpRequest;
37 import org.apache.http.HttpResponse;
38 import org.apache.http.HttpResponseInterceptor;
39 import org.apache.http.HttpStatus;
40 import org.apache.http.auth.AUTH;
41 import org.apache.http.auth.AuthScope;
42 import org.apache.http.auth.Credentials;
43 import org.apache.http.auth.UsernamePasswordCredentials;
44 import org.apache.http.client.CredentialsProvider;
45 import org.apache.http.client.methods.HttpGet;
46 import org.apache.http.client.protocol.HttpClientContext;
47 import org.apache.http.entity.StringEntity;
48 import org.apache.http.localserver.RequestBasicAuth;
49 import org.apache.http.nio.protocol.BasicAsyncRequestHandler;
50 import org.apache.http.protocol.HttpContext;
51 import org.apache.http.protocol.HttpRequestHandler;
52 import org.apache.http.util.EntityUtils;
53 import org.junit.Assert;
54 import org.junit.Before;
55 import org.junit.Test;
56
57 public class TestClientAuthenticationFallBack extends HttpAsyncTestBase {
58
59 @Before
60 @Override
61 public void setUp() throws Exception {
62 super.setUp();
63 this.serverBootstrap.addInterceptorFirst(new RequestBasicAuth());
64 this.serverBootstrap.addInterceptorLast(new ResponseBasicUnauthorized());
65 }
66
67 public class ResponseBasicUnauthorized implements HttpResponseInterceptor {
68
69 @Override
70 public void process(
71 final HttpResponse response,
72 final HttpContext context) throws HttpException, IOException {
73 if (response.getStatusLine().getStatusCode() == HttpStatus.SC_UNAUTHORIZED) {
74 response.addHeader(AUTH.WWW_AUTH, "Digest realm=\"test realm\" invalid");
75 response.addHeader(AUTH.WWW_AUTH, "Basic realm=\"test realm\"");
76 }
77 }
78
79 }
80
81 static class AuthHandler implements HttpRequestHandler {
82
83 @Override
84 public void handle(
85 final HttpRequest request,
86 final HttpResponse response,
87 final HttpContext context) throws HttpException, IOException {
88 final String creds = (String) context.getAttribute("creds");
89 if (creds == null || !creds.equals("test:test")) {
90 response.setStatusCode(HttpStatus.SC_UNAUTHORIZED);
91 } else {
92 response.setStatusCode(HttpStatus.SC_OK);
93 final StringEntity entity = new StringEntity("success", Consts.ASCII);
94 response.setEntity(entity);
95 }
96 }
97
98 }
99
100 static class TestCredentialsProvider implements CredentialsProvider {
101
102 private final Credentials creds;
103 private AuthScope authscope;
104
105 TestCredentialsProvider(final Credentials creds) {
106 super();
107 this.creds = creds;
108 }
109
110 @Override
111 public void clear() {
112 }
113
114 @Override
115 public Credentials getCredentials(final AuthScope authscope) {
116 this.authscope = authscope;
117 return this.creds;
118 }
119
120 @Override
121 public void setCredentials(final AuthScope authscope, final Credentials credentials) {
122 }
123
124 public AuthScope getAuthScope() {
125 return this.authscope;
126 }
127
128 }
129
130 @Test
131 public void testBasicAuthenticationSuccess() throws Exception {
132 this.serverBootstrap.registerHandler("*", new BasicAsyncRequestHandler(new AuthHandler()));
133 final HttpHost target = start();
134
135 final TestCredentialsProvider credsProvider = new TestCredentialsProvider(
136 new UsernamePasswordCredentials("test", "test"));
137 final HttpClientContext context = HttpClientContext.create();
138 context.setCredentialsProvider(credsProvider);
139
140 final HttpGet httpget = new HttpGet("/");
141
142 final Future<HttpResponse> future = this.httpclient.execute(target, httpget, context, null);
143 final HttpResponse response = future.get();
144 Assert.assertNotNull(response);
145 final HttpEntity entity = response.getEntity();
146 Assert.assertEquals(HttpStatus.SC_OK, response.getStatusLine().getStatusCode());
147 Assert.assertNotNull(entity);
148 EntityUtils.consume(entity);
149 final AuthScope authscope = credsProvider.getAuthScope();
150 Assert.assertNotNull(authscope);
151 Assert.assertEquals("test realm", authscope.getRealm());
152 }
153
154 }
0 /*
1 * ====================================================================
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 * ====================================================================
19 *
20 * This software consists of voluntary contributions made by many
21 * individuals on behalf of the Apache Software Foundation. For more
22 * information on the Apache Software Foundation, please see
23 * <http://www.apache.org/>.
24 *
25 */
26 package org.apache.http.nio.client.integration;
27
28 import java.io.IOException;
29 import java.util.Arrays;
30 import java.util.concurrent.Future;
31 import java.util.concurrent.atomic.AtomicLong;
32
33 import org.apache.http.Consts;
34 import org.apache.http.localserver.HttpAsyncTestBase;
35 import org.apache.http.HttpEntity;
36 import org.apache.http.HttpException;
37 import org.apache.http.HttpHost;
38 import org.apache.http.HttpRequest;
39 import org.apache.http.HttpResponse;
40 import org.apache.http.HttpResponseInterceptor;
41 import org.apache.http.HttpStatus;
42 import org.apache.http.auth.AUTH;
43 import org.apache.http.auth.AuthScheme;
44 import org.apache.http.auth.AuthSchemeProvider;
45 import org.apache.http.auth.AuthScope;
46 import org.apache.http.auth.Credentials;
47 import org.apache.http.auth.UsernamePasswordCredentials;
48 import org.apache.http.client.CredentialsProvider;
49 import org.apache.http.client.config.RequestConfig;
50 import org.apache.http.client.methods.HttpGet;
51 import org.apache.http.client.protocol.HttpClientContext;
52 import org.apache.http.config.Registry;
53 import org.apache.http.config.RegistryBuilder;
54 import org.apache.http.entity.StringEntity;
55 import org.apache.http.impl.auth.BasicScheme;
56 import org.apache.http.impl.auth.BasicSchemeFactory;
57 import org.apache.http.impl.client.TargetAuthenticationStrategy;
58 import org.apache.http.localserver.RequestBasicAuth;
59 import org.apache.http.nio.protocol.BasicAsyncRequestHandler;
60 import org.apache.http.protocol.HttpContext;
61 import org.apache.http.protocol.HttpRequestHandler;
62 import org.apache.http.util.EntityUtils;
63 import org.junit.Assert;
64 import org.junit.Before;
65 import org.junit.Test;
66
67 public class TestClientReauthentication extends HttpAsyncTestBase {
68
69 @Before @Override
70 public void setUp() throws Exception {
71 super.setUp();
72 this.serverBootstrap.addInterceptorFirst(new RequestBasicAuth());
73 this.serverBootstrap.addInterceptorLast(new ResponseBasicUnauthorized());
74 }
75
76 public class ResponseBasicUnauthorized implements HttpResponseInterceptor {
77
78 @Override
79 public void process(
80 final HttpResponse response,
81 final HttpContext context) throws HttpException, IOException {
82 if (response.getStatusLine().getStatusCode() == HttpStatus.SC_UNAUTHORIZED) {
83 response.addHeader(AUTH.WWW_AUTH, "MyBasic realm=\"test realm\"");
84 }
85 }
86
87 }
88
89 static class AuthHandler implements HttpRequestHandler {
90
91 private final AtomicLong count = new AtomicLong(0);
92
93 @Override
94 public void handle(
95 final HttpRequest request,
96 final HttpResponse response,
97 final HttpContext context) throws HttpException, IOException {
98 final String creds = (String) context.getAttribute("creds");
99 if (creds == null || !creds.equals("test:test")) {
100 response.setStatusCode(HttpStatus.SC_UNAUTHORIZED);
101 } else {
102 // Make client re-authenticate on each fourth request
103 if (this.count.incrementAndGet() % 4 == 0) {
104 response.setStatusCode(HttpStatus.SC_UNAUTHORIZED);
105 } else {
106 response.setStatusCode(HttpStatus.SC_OK);
107 final StringEntity entity = new StringEntity("success", Consts.ASCII);
108 response.setEntity(entity);
109 }
110 }
111 }
112
113 }
114
115 static class TestCredentialsProvider implements CredentialsProvider {
116
117 private final Credentials creds;
118 private AuthScope authscope;
119
120 TestCredentialsProvider(final Credentials creds) {
121 super();
122 this.creds = creds;
123 }
124
125 @Override
126 public void clear() {
127 }
128
129 @Override
130 public Credentials getCredentials(final AuthScope authscope) {
131 this.authscope = authscope;
132 return this.creds;
133 }
134
135 @Override
136 public void setCredentials(final AuthScope authscope, final Credentials credentials) {
137 }
138
139 public AuthScope getAuthScope() {
140 return this.authscope;
141 }
142
143 }
144
145 @Test
146 public void testBasicAuthenticationSuccess() throws Exception {
147 this.serverBootstrap.registerHandler("*", new BasicAsyncRequestHandler(new AuthHandler()));
148
149 final BasicSchemeFactory myBasicAuthSchemeFactory = new BasicSchemeFactory() {
150
151 @Override
152 public AuthScheme create(final HttpContext context) {
153 return new BasicScheme() {
154 private static final long serialVersionUID = 1L;
155
156 @Override
157 public String getSchemeName() {
158 return "MyBasic";
159 }
160
161 };
162 }
163
164 };
165
166 final TargetAuthenticationStrategy myAuthStrategy = new TargetAuthenticationStrategy() {
167
168 @Override
169 protected boolean isCachable(final AuthScheme authScheme) {
170 return "MyBasic".equalsIgnoreCase(authScheme.getSchemeName());
171 }
172
173 };
174
175 final TestCredentialsProvider credsProvider = new TestCredentialsProvider(
176 new UsernamePasswordCredentials("test", "test"));
177
178 final Registry<AuthSchemeProvider> authSchemeRegistry = RegistryBuilder.<AuthSchemeProvider>create()
179 .register("MyBasic", myBasicAuthSchemeFactory)
180 .build();
181 this.clientBuilder.setDefaultAuthSchemeRegistry(authSchemeRegistry);
182 this.clientBuilder.setTargetAuthenticationStrategy(myAuthStrategy);
183 final HttpHost target = start();
184
185 final RequestConfig config = RequestConfig.custom()
186 .setTargetPreferredAuthSchemes(Arrays.asList("MyBasic"))
187 .build();
188 final HttpClientContext context = HttpClientContext.create();
189 context.setCredentialsProvider(credsProvider);
190
191 for (int i = 0; i < 10; i++) {
192 final HttpGet httpget = new HttpGet("/");
193 httpget.setConfig(config);
194 final Future<HttpResponse> future = this.httpclient.execute(target, httpget, context, null);
195 final HttpResponse response = future.get();
196 Assert.assertNotNull(response);
197 final HttpEntity entity = response.getEntity();
198 Assert.assertEquals(HttpStatus.SC_OK, response.getStatusLine().getStatusCode());
199 Assert.assertNotNull(entity);
200 EntityUtils.consume(entity);
201 }
202 }
203
204 }
0 /*
1 * ====================================================================
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 * ====================================================================
19 *
20 * This software consists of voluntary contributions made by many
21 * individuals on behalf of the Apache Software Foundation. For more
22 * information on the Apache Software Foundation, please see
23 * <http://www.apache.org/>.
24 *
25 */
26 package org.apache.http.nio.client.integration;
27
28 import java.io.IOException;
29 import java.util.Arrays;
30 import java.util.Collection;
31 import java.util.LinkedList;
32 import java.util.Queue;
33 import java.util.Random;
34 import java.util.concurrent.ExecutionException;
35 import java.util.concurrent.Future;
36
37 import org.apache.http.localserver.HttpAsyncTestBase;
38 import org.apache.http.HttpEntity;
39 import org.apache.http.HttpHost;
40 import org.apache.http.HttpResponse;
41 import org.apache.http.client.methods.HttpGet;
42 import org.apache.http.client.methods.HttpPost;
43 import org.apache.http.impl.nio.client.CloseableHttpAsyncClient;
44 import org.apache.http.impl.nio.client.HttpAsyncClients;
45 import org.apache.http.localserver.EchoHandler;
46 import org.apache.http.localserver.RandomHandler;
47 import org.apache.http.nio.ContentDecoder;
48 import org.apache.http.nio.IOControl;
49 import org.apache.http.nio.client.methods.HttpAsyncMethods;
50 import org.apache.http.nio.client.util.HttpAsyncClientUtils;
51 import org.apache.http.nio.entity.NByteArrayEntity;
52 import org.apache.http.nio.protocol.BasicAsyncRequestHandler;
53 import org.apache.http.nio.protocol.BasicAsyncResponseConsumer;
54 import org.apache.http.nio.protocol.HttpAsyncRequestProducer;
55 import org.apache.http.util.EntityUtils;
56 import org.junit.Assert;
57 import org.junit.Before;
58 import org.junit.Test;
59 import org.junit.runner.RunWith;
60 import org.junit.runners.Parameterized;
61
62 @RunWith(Parameterized.class)
63 public class TestHttpAsync extends HttpAsyncTestBase {
64
65 @Parameterized.Parameters(name = "{0}")
66 public static Collection<Object[]> protocols() {
67 return Arrays.asList(new Object[][]{
68 { ProtocolScheme.http },
69 { ProtocolScheme.https },
70 });
71 }
72
73 public TestHttpAsync(final ProtocolScheme scheme) {
74 super(scheme);
75 }
76
77 @Before @Override
78 public void setUp() throws Exception {
79 super.setUp();
80 this.serverBootstrap.registerHandler("/echo/*", new BasicAsyncRequestHandler(new EchoHandler()));
81 this.serverBootstrap.registerHandler("/random/*", new BasicAsyncRequestHandler(new RandomHandler()));
82 }
83
84 @Test
85 public void testSingleGet() throws Exception {
86 final HttpHost target = start();
87 final HttpGet httpget = new HttpGet("/random/2048");
88 final Future<HttpResponse> future = this.httpclient.execute(target, httpget, null);
89 final HttpResponse response = future.get();
90 Assert.assertNotNull(response);
91 Assert.assertEquals(200, response.getStatusLine().getStatusCode());
92 }
93
94 @Test
95 public void testSinglePost() throws Exception {
96 final HttpHost target = start();
97 final byte[] b1 = new byte[1024];
98 final Random rnd = new Random(System.currentTimeMillis());
99 rnd.nextBytes(b1);
100
101 final HttpPost httppost = new HttpPost("/echo/stuff");
102 httppost.setEntity(new NByteArrayEntity(b1));
103
104 final Future<HttpResponse> future = this.httpclient.execute(target, httppost, null);
105 final HttpResponse response = future.get();
106 Assert.assertNotNull(response);
107 Assert.assertEquals(200, response.getStatusLine().getStatusCode());
108 final HttpEntity entity = response.getEntity();
109 Assert.assertNotNull(entity);
110 final byte[] b2 = EntityUtils.toByteArray(entity);
111 Assert.assertArrayEquals(b1, b2);
112 }
113
114 @Test
115 public void testMultiplePostsOverMultipleConnections() throws Exception {
116 final HttpHost target = start();
117 final byte[] b1 = new byte[1024];
118 final Random rnd = new Random(System.currentTimeMillis());
119 rnd.nextBytes(b1);
120
121 final int reqCount = 20;
122
123 this.connMgr.setDefaultMaxPerRoute(reqCount);
124 this.connMgr.setMaxTotal(100);
125
126 final Queue<Future<HttpResponse>> queue = new LinkedList<Future<HttpResponse>>();
127
128 for (int i = 0; i < reqCount; i++) {
129 final HttpPost httppost = new HttpPost("/echo/stuff");
130 httppost.setEntity(new NByteArrayEntity(b1));
131 queue.add(this.httpclient.execute(target, httppost, null));
132 }
133
134 while (!queue.isEmpty()) {
135 final Future<HttpResponse> future = queue.remove();
136 final HttpResponse response = future.get();
137 Assert.assertNotNull(response);
138 Assert.assertEquals(200, response.getStatusLine().getStatusCode());
139 final HttpEntity entity = response.getEntity();
140 Assert.assertNotNull(entity);
141 final byte[] b2 = EntityUtils.toByteArray(entity);
142 Assert.assertArrayEquals(b1, b2);
143 }
144 }
145
146 @Test
147 public void testMultiplePostsOverSingleConnection() throws Exception {
148 final HttpHost target = start();
149 final byte[] b1 = new byte[1024];
150 final Random rnd = new Random(System.currentTimeMillis());
151 rnd.nextBytes(b1);
152
153 final int reqCount = 20;
154
155 this.connMgr.setDefaultMaxPerRoute(1);
156 this.connMgr.setMaxTotal(100);
157
158 final Queue<Future<HttpResponse>> queue = new LinkedList<Future<HttpResponse>>();
159
160 for (int i = 0; i < reqCount; i++) {
161 final HttpPost httppost = new HttpPost("/echo/stuff");
162 httppost.setEntity(new NByteArrayEntity(b1));
163 queue.add(this.httpclient.execute(target, httppost, null));
164 }
165
166 while (!queue.isEmpty()) {
167 final Future<HttpResponse> future = queue.remove();
168 final HttpResponse response = future.get();
169 Assert.assertNotNull(response);
170 Assert.assertEquals(200, response.getStatusLine().getStatusCode());
171 final HttpEntity entity = response.getEntity();
172 Assert.assertNotNull(entity);
173 final byte[] b2 = EntityUtils.toByteArray(entity);
174 Assert.assertArrayEquals(b1, b2);
175 }
176 }
177
178 @Test
179 public void testRequestFailure() throws Exception {
180 final HttpHost target = start();
181 final HttpGet httpget = new HttpGet("/random/2048");
182 final HttpAsyncRequestProducer requestProducer = HttpAsyncMethods.create(target, httpget) ;
183 final BasicAsyncResponseConsumer responseConsumer = new BasicAsyncResponseConsumer() {
184
185 @Override
186 public void onContentReceived(final ContentDecoder decoder, final IOControl ioctrl)
187 throws IOException {
188 throw new IOException("Kaboom");
189 }
190
191 };
192 final Future<HttpResponse> future = this.httpclient.execute(requestProducer, responseConsumer, null);
193 try {
194 future.get();
195 Assert.fail("ExecutionException expected");
196 } catch (final ExecutionException ex) {
197 final Throwable t = ex.getCause();
198 Assert.assertNotNull(t);
199 Assert.assertTrue(t instanceof IOException);
200 Assert.assertEquals("Kaboom", t.getMessage());
201 }
202 }
203
204 @Test
205 public void testSharedPool() throws Exception {
206 final HttpHost target = start();
207 final HttpGet httpget = new HttpGet("/random/2048");
208 final Future<HttpResponse> future = this.httpclient.execute(target, httpget, null);
209 final HttpResponse response = future.get();
210 Assert.assertNotNull(response);
211 Assert.assertEquals(200, response.getStatusLine().getStatusCode());
212
213
214 final CloseableHttpAsyncClient httpclient2 = HttpAsyncClients.custom()
215 .setConnectionManager(this.connMgr)
216 .setConnectionManagerShared(true)
217 .build();
218 try {
219 httpclient2.start();
220 final HttpGet httpget2 = new HttpGet("/random/2048");
221 final Future<HttpResponse> future2 = httpclient2.execute(target, httpget2, null);
222 final HttpResponse response2 = future2.get();
223 Assert.assertNotNull(response2);
224 Assert.assertEquals(200, response2.getStatusLine().getStatusCode());
225
226 } finally {
227 httpclient2.close();
228 }
229
230 final HttpGet httpget3 = new HttpGet("/random/2048");
231 final Future<HttpResponse> future3 = this.httpclient.execute(target, httpget3, null);
232 final HttpResponse response3 = future3.get();
233 Assert.assertNotNull(response3);
234 Assert.assertEquals(200, response3.getStatusLine().getStatusCode());
235 }
236
237 @Test
238 public void testClientCloseloseQuietly() throws Exception {
239 final HttpHost target = start();
240 final HttpGet httpget = new HttpGet("/random/2048");
241 final Future<HttpResponse> future = this.httpclient.execute(target, httpget, null);
242 final HttpResponse response = future.get();
243 Assert.assertNotNull(response);
244 Assert.assertEquals(200, response.getStatusLine().getStatusCode());
245
246 HttpAsyncClientUtils.closeQuietly(this.httpclient);
247 // Close it twice
248 HttpAsyncClientUtils.closeQuietly(this.httpclient);
249 }
250
251 }
0 /*
1 * ====================================================================
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 * ====================================================================
19 *
20 * This software consists of voluntary contributions made by many
21 * individuals on behalf of the Apache Software Foundation. For more
22 * information on the Apache Software Foundation, please see
23 * <http://www.apache.org/>.
24 *
25 */
26 package org.apache.http.nio.client.integration;
27
28 import java.util.Arrays;
29 import java.util.Collection;
30 import java.util.LinkedList;
31 import java.util.Queue;
32 import java.util.Random;
33 import java.util.concurrent.Future;
34
35 import org.apache.http.HttpEntity;
36 import org.apache.http.HttpHost;
37 import org.apache.http.HttpResponse;
38 import org.apache.http.client.methods.HttpGet;
39 import org.apache.http.client.methods.HttpPost;
40 import org.apache.http.impl.nio.client.CloseableHttpAsyncClient;
41 import org.apache.http.impl.nio.client.HttpAsyncClients;
42 import org.apache.http.localserver.AbstractAsyncTest;
43 import org.apache.http.localserver.EchoHandler;
44 import org.apache.http.localserver.RandomHandler;
45 import org.apache.http.nio.entity.NByteArrayEntity;
46 import org.apache.http.nio.protocol.BasicAsyncRequestHandler;
47 import org.apache.http.util.EntityUtils;
48 import org.junit.After;
49 import org.junit.Assert;
50 import org.junit.Before;
51 import org.junit.Test;
52 import org.junit.runner.RunWith;
53 import org.junit.runners.Parameterized;
54
55 @RunWith(Parameterized.class)
56 public class TestHttpAsyncMinimal extends AbstractAsyncTest {
57
58 @Parameterized.Parameters(name = "{0}")
59 public static Collection<Object[]> protocols() {
60 return Arrays.asList(new Object[][]{
61 {ProtocolScheme.http},
62 {ProtocolScheme.https},
63 });
64 }
65
66 protected CloseableHttpAsyncClient httpclient;
67
68 public TestHttpAsyncMinimal(final ProtocolScheme scheme) {
69 super(scheme);
70 }
71
72 @Before @Override
73 public void setUp() throws Exception {
74 super.setUp();
75 this.serverBootstrap.registerHandler("/echo/*", new BasicAsyncRequestHandler(new EchoHandler()));
76 this.serverBootstrap.registerHandler("/random/*", new BasicAsyncRequestHandler(new RandomHandler()));
77
78 this.httpclient = HttpAsyncClients.createMinimal(this.connMgr);
79 }
80
81 @After @Override
82 public void shutDown() throws Exception {
83 if (this.httpclient != null) {
84 this.httpclient.close();
85 }
86 super.shutDown();
87 }
88
89 public HttpHost start() throws Exception {
90 final HttpHost serverEndpoint = startServer();
91
92 this.httpclient.start();
93
94 return serverEndpoint;
95 }
96
97 @Test
98 public void testSingleGet() throws Exception {
99 final HttpHost target = start();
100 final HttpGet httpget = new HttpGet("/random/2048");
101 final Future<HttpResponse> future = this.httpclient.execute(target, httpget, null);
102 final HttpResponse response = future.get();
103 Assert.assertNotNull(response);
104 Assert.assertEquals(200, response.getStatusLine().getStatusCode());
105 }
106
107 @Test
108 public void testSinglePost() throws Exception {
109 final HttpHost target = start();
110 final byte[] b1 = new byte[1024];
111 final Random rnd = new Random(System.currentTimeMillis());
112 rnd.nextBytes(b1);
113
114 final HttpPost httppost = new HttpPost("/echo/stuff");
115 httppost.setEntity(new NByteArrayEntity(b1));
116
117 final Future<HttpResponse> future = this.httpclient.execute(target, httppost, null);
118 final HttpResponse response = future.get();
119 Assert.assertNotNull(response);
120 Assert.assertEquals(200, response.getStatusLine().getStatusCode());
121 final HttpEntity entity = response.getEntity();
122 Assert.assertNotNull(entity);
123 final byte[] b2 = EntityUtils.toByteArray(entity);
124 Assert.assertArrayEquals(b1, b2);
125 }
126
127 @Test
128 public void testMultiplePostsOverMultipleConnections() throws Exception {
129 final HttpHost target = start();
130 final byte[] b1 = new byte[1024];
131 final Random rnd = new Random(System.currentTimeMillis());
132 rnd.nextBytes(b1);
133
134 final int reqCount = 20;
135
136 this.connMgr.setDefaultMaxPerRoute(reqCount);
137 this.connMgr.setMaxTotal(100);
138
139 final Queue<Future<HttpResponse>> queue = new LinkedList<Future<HttpResponse>>();
140
141 for (int i = 0; i < reqCount; i++) {
142 final HttpPost httppost = new HttpPost("/echo/stuff");
143 httppost.setEntity(new NByteArrayEntity(b1));
144 queue.add(this.httpclient.execute(target, httppost, null));
145 }
146
147 while (!queue.isEmpty()) {
148 final Future<HttpResponse> future = queue.remove();
149 final HttpResponse response = future.get();
150 Assert.assertNotNull(response);
151 Assert.assertEquals(200, response.getStatusLine().getStatusCode());
152 final HttpEntity entity = response.getEntity();
153 Assert.assertNotNull(entity);
154 final byte[] b2 = EntityUtils.toByteArray(entity);
155 Assert.assertArrayEquals(b1, b2);
156 }
157 }
158
159 @Test
160 public void testMultiplePostsOverSingleConnection() throws Exception {
161 final HttpHost target = start();
162 final byte[] b1 = new byte[1024];
163 final Random rnd = new Random(System.currentTimeMillis());
164 rnd.nextBytes(b1);
165
166 final int reqCount = 20;
167
168 this.connMgr.setDefaultMaxPerRoute(1);
169 this.connMgr.setMaxTotal(100);
170
171 final Queue<Future<HttpResponse>> queue = new LinkedList<Future<HttpResponse>>();
172
173 for (int i = 0; i < reqCount; i++) {
174 final HttpPost httppost = new HttpPost("/echo/stuff");
175 httppost.setEntity(new NByteArrayEntity(b1));
176 queue.add(this.httpclient.execute(target, httppost, null));
177 }
178
179 while (!queue.isEmpty()) {
180 final Future<HttpResponse> future = queue.remove();
181 final HttpResponse response = future.get();
182 Assert.assertNotNull(response);
183 Assert.assertEquals(200, response.getStatusLine().getStatusCode());
184 final HttpEntity entity = response.getEntity();
185 Assert.assertNotNull(entity);
186 final byte[] b2 = EntityUtils.toByteArray(entity);
187 Assert.assertArrayEquals(b1, b2);
188 }
189 }
190
191 }
0 /*
1 * ====================================================================
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 * ====================================================================
19 *
20 * This software consists of voluntary contributions made by many
21 * individuals on behalf of the Apache Software Foundation. For more
22 * information on the Apache Software Foundation, please see
23 * <http://www.apache.org/>.
24 *
25 */
26 package org.apache.http.nio.client.integration;
27
28 import java.util.ArrayList;
29 import java.util.Arrays;
30 import java.util.Collection;
31 import java.util.List;
32 import java.util.Queue;
33 import java.util.concurrent.ConcurrentLinkedQueue;
34 import java.util.concurrent.ExecutionException;
35 import java.util.concurrent.Future;
36
37 import org.apache.http.ConnectionClosedException;
38 import org.apache.http.HttpEntityEnclosingRequest;
39 import org.apache.http.HttpHost;
40 import org.apache.http.HttpRequest;
41 import org.apache.http.HttpResponse;
42 import org.apache.http.client.methods.HttpGet;
43 import org.apache.http.client.methods.HttpPost;
44 import org.apache.http.entity.StringEntity;
45 import org.apache.http.impl.nio.client.CloseableHttpPipeliningClient;
46 import org.apache.http.impl.nio.client.HttpAsyncClients;
47 import org.apache.http.localserver.AbstractAsyncTest;
48 import org.apache.http.localserver.EchoHandler;
49 import org.apache.http.localserver.RandomHandler;
50 import org.apache.http.nio.client.methods.HttpAsyncMethods;
51 import org.apache.http.nio.protocol.BasicAsyncRequestHandler;
52 import org.apache.http.nio.protocol.HttpAsyncRequestProducer;
53 import org.apache.http.nio.protocol.HttpAsyncResponseConsumer;
54 import org.apache.http.util.EntityUtils;
55 import org.junit.After;
56 import org.junit.Assert;
57 import org.junit.Before;
58 import org.junit.Ignore;
59 import org.junit.Test;
60 import org.junit.runner.RunWith;
61 import org.junit.runners.Parameterized;
62
63 @RunWith(Parameterized.class)
64 public class TestHttpAsyncPipelining extends AbstractAsyncTest {
65
66 @Parameterized.Parameters(name = "{0}")
67 public static Collection<Object[]> protocols() {
68 return Arrays.asList(new Object[][]{
69 {ProtocolScheme.http},
70 {ProtocolScheme.https},
71 });
72 }
73
74 protected CloseableHttpPipeliningClient httpclient;
75
76 public TestHttpAsyncPipelining(final ProtocolScheme scheme) {
77 super(scheme);
78 }
79
80 @Before @Override
81 public void setUp() throws Exception {
82 super.setUp();
83 this.serverBootstrap.registerHandler("/echo/*", new BasicAsyncRequestHandler(new EchoHandler()));
84 this.serverBootstrap.registerHandler("/random/*", new BasicAsyncRequestHandler(new RandomHandler()));
85
86 this.httpclient = HttpAsyncClients.createPipelining(this.connMgr);
87 }
88
89 @After @Override
90 public void shutDown() throws Exception {
91 if (this.httpclient != null) {
92 this.httpclient.close();
93 }
94 super.shutDown();
95 }
96
97 public HttpHost start() throws Exception {
98 final HttpHost serverEndpoint = startServer();
99
100 this.connMgr.setDefaultMaxPerRoute(1);
101 this.httpclient.start();
102
103 return serverEndpoint;
104 }
105
106 @Test
107 public void testPipelinedGets() throws Exception {
108 final HttpHost target = start();
109
110 final Queue<Future<List<HttpResponse>>> queue = new ConcurrentLinkedQueue<Future<List<HttpResponse>>>();
111 for (int i = 0; i < 10; i++) {
112 final HttpRequest httpget1 = new HttpGet("/random/512");
113 final HttpRequest httpget2 = new HttpGet("/random/1024");
114 final HttpRequest httpget3 = new HttpGet("/random/2048");
115 queue.add(this.httpclient.execute(target, Arrays.asList(httpget1, httpget2, httpget3), null));
116 }
117
118 while (!queue.isEmpty()) {
119 final Future<List<HttpResponse>> future = queue.remove();
120 final List<HttpResponse> responses = future.get();
121 Assert.assertNotNull(responses);
122 Assert.assertEquals(3, responses.size());
123 final HttpResponse response1 = responses.get(0);
124 Assert.assertEquals(200, response1.getStatusLine().getStatusCode());
125 final byte[] bytes1 = EntityUtils.toByteArray(response1.getEntity());
126 Assert.assertNotNull(bytes1);
127 Assert.assertEquals(512, bytes1.length);
128 final HttpResponse response2 = responses.get(1);
129 Assert.assertEquals(200, response2.getStatusLine().getStatusCode());
130 final byte[] bytes2 = EntityUtils.toByteArray(response2.getEntity());
131 Assert.assertNotNull(bytes2);
132 Assert.assertEquals(1024, bytes2.length);
133 final HttpResponse response3 = responses.get(2);
134 Assert.assertEquals(200, response3.getStatusLine().getStatusCode());
135 final byte[] bytes3 = EntityUtils.toByteArray(response3.getEntity());
136 Assert.assertNotNull(bytes3);
137 Assert.assertEquals(2048, bytes3.length);
138 }
139
140 }
141
142 @Test
143 public void testPipelinedPostsAndGets() throws Exception {
144 final HttpHost target = start();
145
146 final Queue<Future<List<HttpResponse>>> queue = new ConcurrentLinkedQueue<Future<List<HttpResponse>>>();
147 for (int i = 0; i < 10; i++) {
148 final HttpEntityEnclosingRequest httppost1 = new HttpPost("/echo/");
149 httppost1.setEntity(new StringEntity("this and that"));
150 final HttpRequest httpget2 = new HttpGet("/echo/");
151 final HttpEntityEnclosingRequest httppost3 = new HttpPost("/echo/");
152 httppost3.setEntity(new StringEntity("all sorts of things"));
153 queue.add(this.httpclient.execute(target, Arrays.asList(httppost1, httpget2, httppost3), null));
154 }
155
156 while (!queue.isEmpty()) {
157 final Future<List<HttpResponse>> future = queue.remove();
158 final List<HttpResponse> responses = future.get();
159 Assert.assertNotNull(responses);
160 Assert.assertEquals(3, responses.size());
161 final HttpResponse response1 = responses.get(0);
162 Assert.assertEquals(200, response1.getStatusLine().getStatusCode());
163 final String s1 = EntityUtils.toString(response1.getEntity());
164 Assert.assertNotNull(s1);
165 Assert.assertEquals("this and that", s1);
166 final HttpResponse response2 = responses.get(1);
167 Assert.assertEquals(200, response2.getStatusLine().getStatusCode());
168 final String s2 = EntityUtils.toString(response2.getEntity());
169 Assert.assertNotNull(s2);
170 Assert.assertEquals("", s2);
171 final HttpResponse response3 = responses.get(2);
172 Assert.assertEquals(200, response3.getStatusLine().getStatusCode());
173 final String s3 = EntityUtils.toString(response3.getEntity());
174 Assert.assertNotNull(s3);
175 Assert.assertEquals("all sorts of things", s3);
176 }
177
178 }
179
180 @Test @Ignore(value = "Fails on Windows")
181 public void testPipelinedRequestsUnexpectedConnectionClosure() throws Exception {
182 final HttpHost target = start();
183
184 for (int i = 0; i < 20; i++) {
185 final HttpAsyncRequestProducer p1 = HttpAsyncMethods.create(target, new HttpGet("/random/512"));
186 final HttpAsyncRequestProducer p2 = HttpAsyncMethods.create(target, new HttpGet("/pampa"));
187 final HttpAsyncRequestProducer p3 = HttpAsyncMethods.create(target, new HttpGet("/random/512"));
188 final HttpAsyncRequestProducer p4 = HttpAsyncMethods.create(target, new HttpGet("/random/512"));
189 final List<HttpAsyncRequestProducer> requestProducers = new ArrayList<HttpAsyncRequestProducer>();
190 requestProducers.add(p1);
191 requestProducers.add(p2);
192 requestProducers.add(p3);
193 requestProducers.add(p4);
194
195 final HttpAsyncResponseConsumer<HttpResponse> c1 = HttpAsyncMethods.createConsumer();
196 final HttpAsyncResponseConsumer<HttpResponse> c2 = HttpAsyncMethods.createConsumer();
197 final HttpAsyncResponseConsumer<HttpResponse> c3 = HttpAsyncMethods.createConsumer();
198 final HttpAsyncResponseConsumer<HttpResponse> c4 = HttpAsyncMethods.createConsumer();
199 final List<HttpAsyncResponseConsumer<HttpResponse>> responseConsumers = new ArrayList<HttpAsyncResponseConsumer<HttpResponse>>();
200 responseConsumers.add(c1);
201 responseConsumers.add(c2);
202 responseConsumers.add(c3);
203 responseConsumers.add(c4);
204
205 final Future<List<HttpResponse>> future = this.httpclient.execute(
206 target,
207 requestProducers,
208 responseConsumers,
209 null, null);
210 try {
211 future.get();
212 } catch (ExecutionException ex) {
213 final Throwable cause = ex.getCause();
214 Assert.assertNotNull(cause);
215 Assert.assertTrue(cause instanceof ConnectionClosedException);
216 }
217 Assert.assertTrue(c1.isDone());
218 Assert.assertNotNull(c1.getResult());
219 Assert.assertTrue(c2.isDone());
220 Assert.assertNotNull(c2.getResult());
221 Assert.assertTrue(c3.isDone());
222 Assert.assertNull(c3.getResult());
223 Assert.assertTrue(c4.isDone());
224 Assert.assertNull(c4.getResult());
225 }
226
227 }
228
229 }
0 /*
1 * ====================================================================
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 * ====================================================================
19 *
20 * This software consists of voluntary contributions made by many
21 * individuals on behalf of the Apache Software Foundation. For more
22 * information on the Apache Software Foundation, please see
23 * <http://www.apache.org/>.
24 *
25 */
26 package org.apache.http.nio.client.integration;
27
28 import java.io.IOException;
29 import java.net.UnknownHostException;
30 import java.util.concurrent.CountDownLatch;
31 import java.util.concurrent.ExecutionException;
32 import java.util.concurrent.Future;
33 import java.util.concurrent.TimeUnit;
34 import java.util.concurrent.atomic.AtomicBoolean;
35 import java.util.concurrent.atomic.AtomicInteger;
36
37 import org.apache.http.HttpConnection;
38 import org.apache.http.HttpException;
39 import org.apache.http.HttpHost;
40 import org.apache.http.HttpRequest;
41 import org.apache.http.HttpResponse;
42 import org.apache.http.client.methods.HttpGet;
43 import org.apache.http.concurrent.FutureCallback;
44 import org.apache.http.entity.ContentType;
45 import org.apache.http.impl.nio.client.HttpAsyncClients;
46 import org.apache.http.localserver.EchoHandler;
47 import org.apache.http.localserver.HttpAsyncTestBase;
48 import org.apache.http.localserver.RandomHandler;
49 import org.apache.http.nio.ContentDecoder;
50 import org.apache.http.nio.ContentEncoder;
51 import org.apache.http.nio.IOControl;
52 import org.apache.http.nio.client.methods.HttpAsyncMethods;
53 import org.apache.http.nio.entity.NStringEntity;
54 import org.apache.http.nio.protocol.BasicAsyncRequestConsumer;
55 import org.apache.http.nio.protocol.BasicAsyncRequestHandler;
56 import org.apache.http.nio.protocol.BasicAsyncRequestProducer;
57 import org.apache.http.nio.protocol.BasicAsyncResponseProducer;
58 import org.apache.http.nio.protocol.HttpAsyncExchange;
59 import org.apache.http.nio.protocol.HttpAsyncRequestConsumer;
60 import org.apache.http.nio.protocol.HttpAsyncRequestHandler;
61 import org.apache.http.nio.protocol.HttpAsyncRequestProducer;
62 import org.apache.http.nio.protocol.HttpAsyncResponseConsumer;
63 import org.apache.http.protocol.HttpContext;
64 import org.apache.http.protocol.HttpCoreContext;
65 import org.junit.Assert;
66 import org.junit.Test;
67
68 public class TestHttpAsyncPrematureTermination extends HttpAsyncTestBase {
69
70 @Test
71 public void testConnectionTerminatedProcessingRequest() throws Exception {
72 this.serverBootstrap.registerHandler("*", new HttpAsyncRequestHandler<HttpRequest>() {
73
74 @Override
75 public HttpAsyncRequestConsumer<HttpRequest> processRequest(
76 final HttpRequest request,
77 final HttpContext context) throws HttpException, IOException {
78 final HttpConnection conn = (HttpConnection) context.getAttribute(
79 HttpCoreContext.HTTP_CONNECTION);
80 conn.shutdown();
81 return new BasicAsyncRequestConsumer();
82 }
83
84 @Override
85 public void handle(
86 final HttpRequest request,
87 final HttpAsyncExchange httpExchange,
88 final HttpContext context) throws HttpException, IOException {
89 final HttpResponse response = httpExchange.getResponse();
90 response.setEntity(new NStringEntity("all is well", ContentType.TEXT_PLAIN));
91 httpExchange.submitResponse();
92 }
93
94 });
95
96 final HttpHost target = start();
97 final HttpGet httpget = new HttpGet("/");
98
99 final CountDownLatch latch = new CountDownLatch(1);
100
101 final FutureCallback<HttpResponse> callback = new FutureCallback<HttpResponse>() {
102
103 @Override
104 public void cancelled() {
105 latch.countDown();
106 }
107
108 @Override
109 public void failed(final Exception ex) {
110 latch.countDown();
111 }
112
113 @Override
114 public void completed(final HttpResponse response) {
115 Assert.fail();
116 }
117
118 };
119
120 this.httpclient.execute(target, httpget, callback);
121 Assert.assertTrue(latch.await(5, TimeUnit.SECONDS));
122 }
123
124 @Test
125 public void testConnectionTerminatedHandlingRequest() throws Exception {
126 this.serverBootstrap.registerHandler("*", new HttpAsyncRequestHandler<HttpRequest>() {
127
128 @Override
129 public HttpAsyncRequestConsumer<HttpRequest> processRequest(
130 final HttpRequest request,
131 final HttpContext context) throws HttpException, IOException {
132 return new BasicAsyncRequestConsumer();
133 }
134
135 @Override
136 public void handle(
137 final HttpRequest request,
138 final HttpAsyncExchange httpExchange,
139 final HttpContext context) throws HttpException, IOException {
140 final HttpConnection conn = (HttpConnection) context.getAttribute(
141 HttpCoreContext.HTTP_CONNECTION);
142 conn.shutdown();
143 final HttpResponse response = httpExchange.getResponse();
144 response.setEntity(new NStringEntity("all is well", ContentType.TEXT_PLAIN));
145 httpExchange.submitResponse();
146 }
147
148 });
149
150 final HttpHost target = start();
151 final HttpGet httpget = new HttpGet("/");
152
153 final CountDownLatch latch = new CountDownLatch(1);
154
155 final FutureCallback<HttpResponse> callback = new FutureCallback<HttpResponse>() {
156
157 @Override
158 public void cancelled() {
159 latch.countDown();
160 }
161
162 @Override
163 public void failed(final Exception ex) {
164 latch.countDown();
165 }
166
167 @Override
168 public void completed(final HttpResponse response) {
169 Assert.fail();
170 }
171
172 };
173
174 this.httpclient.execute(target, httpget, callback);
175 Assert.assertTrue(latch.await(5, TimeUnit.SECONDS));
176 }
177
178 @Test
179 public void testConnectionTerminatedSendingResponse() throws Exception {
180 this.serverBootstrap.registerHandler("*", new HttpAsyncRequestHandler<HttpRequest>() {
181
182 @Override
183 public HttpAsyncRequestConsumer<HttpRequest> processRequest(
184 final HttpRequest request,
185 final HttpContext context) throws HttpException, IOException {
186 return new BasicAsyncRequestConsumer();
187 }
188
189 @Override
190 public void handle(
191 final HttpRequest request,
192 final HttpAsyncExchange httpExchange,
193 final HttpContext context) throws HttpException, IOException {
194 final HttpResponse response = httpExchange.getResponse();
195 response.setEntity(new NStringEntity("all is well", ContentType.TEXT_PLAIN));
196 httpExchange.submitResponse(new BasicAsyncResponseProducer(response) {
197
198 @Override
199 public synchronized void produceContent(
200 final ContentEncoder encoder,
201 final IOControl ioctrl) throws IOException {
202 ioctrl.shutdown();
203 }
204
205 });
206 }
207
208 });
209
210 final HttpHost target = start();
211 final HttpGet httpget = new HttpGet("/");
212
213 final CountDownLatch latch = new CountDownLatch(1);
214
215 final FutureCallback<HttpResponse> callback = new FutureCallback<HttpResponse>() {
216
217 @Override
218 public void cancelled() {
219 latch.countDown();
220 }
221
222 @Override
223 public void failed(final Exception ex) {
224 latch.countDown();
225 }
226
227 @Override
228 public void completed(final HttpResponse response) {
229 Assert.fail();
230 }
231
232 };
233
234 this.httpclient.execute(target, httpget, callback);
235 Assert.assertTrue(latch.await(5, TimeUnit.SECONDS));
236 }
237
238 @Test
239 public void testConnectionRequestFailure() throws Exception {
240 this.httpclient = HttpAsyncClients.custom()
241 .setConnectionManager(this.connMgr)
242 .build();
243 this.httpclient.start();
244
245 final HttpGet get = new HttpGet("http://stuff.invalid/");
246 final HttpAsyncRequestProducer producer = HttpAsyncMethods.create(get);
247
248 final AtomicBoolean closed = new AtomicBoolean(false);
249 final AtomicBoolean cancelled = new AtomicBoolean(false);
250 final AtomicBoolean failed = new AtomicBoolean(false);
251
252 final HttpAsyncResponseConsumer<?> consumer = new HttpAsyncResponseConsumer<Object>() {
253
254 @Override
255 public void close() throws IOException {
256 closed.set(true);
257 }
258
259 @Override
260 public boolean cancel() {
261 cancelled.set(true);
262 return false;
263 }
264
265 @Override
266 public void failed(final Exception ex) {
267 failed.set(true);
268 }
269
270 @Override
271 public void responseReceived(
272 final HttpResponse response) throws IOException, HttpException {
273 throw new IllegalStateException();
274 }
275
276 @Override
277 public void consumeContent(
278 final ContentDecoder decoder, final IOControl ioctrl) throws IOException {
279 throw new IllegalStateException();
280 }
281
282 @Override
283 public void responseCompleted(final HttpContext context) {
284 throw new IllegalStateException();
285 }
286
287 @Override
288 public Exception getException() {
289 return null;
290 }
291
292 @Override
293 public String getResult() {
294 return null;
295 }
296
297 @Override
298 public boolean isDone() {
299 return false;
300 }
301 };
302
303 final Future<?> future = this.httpclient.execute(producer, consumer, null, null);
304 try {
305 future.get();
306 Assert.fail();
307 } catch (ExecutionException e) {
308 Assert.assertTrue(e.getCause() instanceof UnknownHostException);
309 }
310 this.connMgr.shutdown(1000);
311
312 Assert.assertTrue(closed.get());
313 Assert.assertFalse(cancelled.get());
314 Assert.assertTrue(failed.get());
315 }
316
317 @Test
318 public void testConsumerIsDone() throws Exception {
319 this.serverBootstrap.registerHandler("/echo/*", new BasicAsyncRequestHandler(new EchoHandler()));
320 this.serverBootstrap.registerHandler("/random/*", new BasicAsyncRequestHandler(new RandomHandler()));
321
322 final HttpHost target = start();
323
324 final AtomicInteger producerClosed = new AtomicInteger(0);
325 final AtomicInteger consumerClosed = new AtomicInteger(0);
326
327 final HttpAsyncRequestProducer producer = new BasicAsyncRequestProducer(target, new HttpGet("/")) {
328
329 @Override
330 public synchronized void close() throws IOException {
331 producerClosed.incrementAndGet();
332 super.close();
333 }
334 };
335
336 final HttpAsyncResponseConsumer<?> consumer = new HttpAsyncResponseConsumer<Object>() {
337
338 @Override
339 public void close() throws IOException {
340 consumerClosed.incrementAndGet();
341 }
342
343 @Override
344 public boolean cancel() {
345 return false;
346 }
347
348 @Override
349 public void failed(final Exception ex) {
350 }
351
352 @Override
353 public void responseReceived(
354 final HttpResponse response) throws IOException, HttpException {
355 }
356
357 @Override
358 public void consumeContent(
359 final ContentDecoder decoder, final IOControl ioctrl) throws IOException {
360 }
361
362 @Override
363 public void responseCompleted(final HttpContext context) {
364 }
365
366 @Override
367 public Exception getException() {
368 return null;
369 }
370
371 @Override
372 public String getResult() {
373 return null;
374 }
375
376 @Override
377 public boolean isDone() {
378 return true; // cancels fetching the response-body
379 }
380 };
381
382 final Future<?> future = this.httpclient.execute(producer, consumer, null, null);
383 future.get();
384
385 connMgr.shutdown(1000);
386
387 Assert.assertTrue(future.isCancelled());
388 Assert.assertTrue(future.isCancelled());
389
390 Assert.assertEquals(1, producerClosed.get());
391 Assert.assertEquals(1, consumerClosed.get());
392 }
393
394 }
0 /*
1 * ====================================================================
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 * ====================================================================
19 *
20 * This software consists of voluntary contributions made by many
21 * individuals on behalf of the Apache Software Foundation. For more
22 * information on the Apache Software Foundation, please see
23 * <http://www.apache.org/>.
24 *
25 */
26 package org.apache.http.nio.client.integration;
27
28 import java.io.IOException;
29 import java.net.InetSocketAddress;
30 import java.net.URISyntaxException;
31 import java.util.ArrayList;
32 import java.util.Arrays;
33 import java.util.Collection;
34 import java.util.List;
35 import java.util.Queue;
36 import java.util.concurrent.ConcurrentLinkedQueue;
37 import java.util.concurrent.ExecutionException;
38 import java.util.concurrent.Future;
39 import java.util.concurrent.TimeUnit;
40
41 import org.apache.http.Header;
42 import org.apache.http.localserver.HttpAsyncTestBase;
43 import org.apache.http.HttpException;
44 import org.apache.http.HttpHost;
45 import org.apache.http.HttpInetConnection;
46 import org.apache.http.HttpRequest;
47 import org.apache.http.HttpResponse;
48 import org.apache.http.HttpStatus;
49 import org.apache.http.ProtocolException;
50 import org.apache.http.ProtocolVersion;
51 import org.apache.http.client.CircularRedirectException;
52 import org.apache.http.client.CookieStore;
53 import org.apache.http.client.RedirectException;
54 import org.apache.http.client.config.RequestConfig;
55 import org.apache.http.client.methods.HttpGet;
56 import org.apache.http.client.methods.HttpPost;
57 import org.apache.http.client.protocol.HttpClientContext;
58 import org.apache.http.client.utils.URIBuilder;
59 import org.apache.http.cookie.SM;
60 import org.apache.http.entity.StringEntity;
61 import org.apache.http.impl.client.BasicCookieStore;
62 import org.apache.http.impl.cookie.BasicClientCookie;
63 import org.apache.http.impl.nio.bootstrap.HttpServer;
64 import org.apache.http.localserver.RandomHandler;
65 import org.apache.http.message.BasicHeader;
66 import org.apache.http.nio.entity.NStringEntity;
67 import org.apache.http.nio.protocol.BasicAsyncRequestHandler;
68 import org.apache.http.nio.reactor.ListenerEndpoint;
69 import org.apache.http.protocol.HTTP;
70 import org.apache.http.protocol.HttpContext;
71 import org.apache.http.protocol.HttpCoreContext;
72 import org.apache.http.protocol.HttpRequestHandler;
73 import org.junit.Assert;
74 import org.junit.Test;
75 import org.junit.runner.RunWith;
76 import org.junit.runners.Parameterized;
77
78 /**
79 * Redirection test cases.
80 */
81 @RunWith(Parameterized.class)
82 public class TestRedirects extends HttpAsyncTestBase {
83
84 @Parameterized.Parameters(name = "{0}")
85 public static Collection<Object[]> protocols() {
86 return Arrays.asList(new Object[][]{
87 {ProtocolScheme.http},
88 {ProtocolScheme.https},
89 });
90 }
91
92 public TestRedirects(final ProtocolScheme scheme) {
93 super(scheme);
94 }
95
96 static class BasicRedirectService implements HttpRequestHandler {
97
98 private final String schemeName;
99 private final int statuscode;
100
101 public BasicRedirectService(final String schemeName, final int statuscode) {
102 super();
103 this.schemeName = schemeName;
104 this.statuscode = statuscode;
105 }
106
107 @Override
108 public void handle(
109 final HttpRequest request,
110 final HttpResponse response,
111 final HttpContext context) throws HttpException, IOException {
112 final HttpInetConnection conn = (HttpInetConnection) context.getAttribute(
113 HttpCoreContext.HTTP_CONNECTION);
114 final ProtocolVersion ver = request.getRequestLine().getProtocolVersion();
115 final String uri = request.getRequestLine().getUri();
116 if (uri.equals("/oldlocation/")) {
117 final String redirectUrl = this.schemeName + "://localhost:" + conn.getLocalPort() + "/newlocation/";
118 response.setStatusLine(ver, this.statuscode);
119 response.addHeader(new BasicHeader("Location", redirectUrl));
120 response.addHeader(new BasicHeader("Connection", "close"));
121 } else if (uri.equals("/newlocation/")) {
122 response.setStatusLine(ver, HttpStatus.SC_OK);
123 final StringEntity entity = new StringEntity("Successful redirect");
124 response.setEntity(entity);
125 } else {
126 response.setStatusLine(ver, HttpStatus.SC_NOT_FOUND);
127 }
128 }
129 }
130
131 static class CircularRedirectService implements HttpRequestHandler {
132
133 public CircularRedirectService() {
134 super();
135 }
136
137 @Override
138 public void handle(
139 final HttpRequest request,
140 final HttpResponse response,
141 final HttpContext context) throws HttpException, IOException {
142 final ProtocolVersion ver = request.getRequestLine().getProtocolVersion();
143 final String uri = request.getRequestLine().getUri();
144 if (uri.startsWith("/circular-oldlocation")) {
145 response.setStatusLine(ver, HttpStatus.SC_MOVED_TEMPORARILY);
146 response.addHeader(new BasicHeader("Location", "/circular-location2"));
147 } else if (uri.startsWith("/circular-location2")) {
148 response.setStatusLine(ver, HttpStatus.SC_MOVED_TEMPORARILY);
149 response.addHeader(new BasicHeader("Location", "/circular-oldlocation"));
150 } else {
151 response.setStatusLine(ver, HttpStatus.SC_NOT_FOUND);
152 }
153 }
154 }
155
156 static class RelativeRedirectService implements HttpRequestHandler {
157
158 public RelativeRedirectService() {
159 super();
160 }
161
162 @Override
163 public void handle(
164 final HttpRequest request,
165 final HttpResponse response,
166 final HttpContext context) throws HttpException, IOException {
167 final ProtocolVersion ver = request.getRequestLine().getProtocolVersion();
168 final String uri = request.getRequestLine().getUri();
169 if (uri.equals("/oldlocation/")) {
170 response.setStatusLine(ver, HttpStatus.SC_MOVED_TEMPORARILY);
171 response.addHeader(new BasicHeader("Location", "/relativelocation/"));
172 } else if (uri.equals("/relativelocation/")) {
173 response.setStatusLine(ver, HttpStatus.SC_OK);
174 final StringEntity entity = new StringEntity("Successful redirect");
175 response.setEntity(entity);
176 } else {
177 response.setStatusLine(ver, HttpStatus.SC_NOT_FOUND);
178 }
179 }
180 }
181
182 static class RelativeRedirectService2 implements HttpRequestHandler {
183
184 public RelativeRedirectService2() {
185 super();
186 }
187
188 @Override
189 public void handle(
190 final HttpRequest request,
191 final HttpResponse response,
192 final HttpContext context) throws HttpException, IOException {
193 final ProtocolVersion ver = request.getRequestLine().getProtocolVersion();
194 final String uri = request.getRequestLine().getUri();
195 if (uri.equals("/test/oldlocation")) {
196 response.setStatusLine(ver, HttpStatus.SC_MOVED_TEMPORARILY);
197 response.addHeader(new BasicHeader("Location", "relativelocation"));
198 } else if (uri.equals("/test/relativelocation")) {
199 response.setStatusLine(ver, HttpStatus.SC_OK);
200 final StringEntity entity = new StringEntity("Successful redirect");
201 response.setEntity(entity);
202 } else {
203 response.setStatusLine(ver, HttpStatus.SC_NOT_FOUND);
204 }
205 }
206 }
207
208 static class BogusRedirectService implements HttpRequestHandler {
209
210 private final String schemeName;
211 private final String url;
212 private final boolean absolute;
213
214 public BogusRedirectService(final String schemeName, final String url, final boolean absolute) {
215 super();
216 this.schemeName = schemeName;
217 this.url = url;
218 this.absolute = absolute;
219 }
220
221 @Override
222 public void handle(
223 final HttpRequest request,
224 final HttpResponse response,
225 final HttpContext context) throws HttpException, IOException {
226 final HttpInetConnection conn = (HttpInetConnection) context.getAttribute(
227 HttpCoreContext.HTTP_CONNECTION);
228 String redirectUrl = this.url;
229 if (!this.absolute) {
230 redirectUrl = this.schemeName + "://localhost:" + conn.getLocalPort() + redirectUrl;
231 }
232
233 final ProtocolVersion ver = request.getRequestLine().getProtocolVersion();
234 final String uri = request.getRequestLine().getUri();
235 if (uri.equals("/oldlocation/")) {
236 response.setStatusLine(ver, HttpStatus.SC_MOVED_TEMPORARILY);
237 response.addHeader(new BasicHeader("Location", redirectUrl));
238 } else if (uri.equals("/relativelocation/")) {
239 response.setStatusLine(ver, HttpStatus.SC_OK);
240 final StringEntity entity = new StringEntity("Successful redirect");
241 response.setEntity(entity);
242 } else {
243 response.setStatusLine(ver, HttpStatus.SC_NOT_FOUND);
244 }
245 }
246 }
247
248 private static class RomeRedirectService implements HttpRequestHandler {
249
250 public RomeRedirectService() {
251 super();
252 }
253
254 @Override
255 public void handle(
256 final HttpRequest request,
257 final HttpResponse response,
258 final HttpContext context) throws HttpException, IOException {
259 final String uri = request.getRequestLine().getUri();
260 if (uri.equals("/rome")) {
261 response.setStatusCode(HttpStatus.SC_OK);
262 final StringEntity entity = new StringEntity("Successful redirect");
263 response.setEntity(entity);
264 } else {
265 response.setStatusCode(HttpStatus.SC_MOVED_TEMPORARILY);
266 response.addHeader(new BasicHeader("Location", "/rome"));
267 }
268 }
269 }
270
271 @Test
272 public void testBasicRedirect300() throws Exception {
273 this.serverBootstrap.registerHandler("*", new BasicAsyncRequestHandler(
274 new BasicRedirectService(getSchemeName(), HttpStatus.SC_MULTIPLE_CHOICES)));
275 final HttpHost target = start();
276
277 final HttpClientContext context = HttpClientContext.create();
278
279 final HttpGet httpget = new HttpGet("/oldlocation/");
280
281 final Future<HttpResponse> future = this.httpclient.execute(target, httpget, context, null);
282 final HttpResponse response = future.get();
283 Assert.assertNotNull(response);
284
285 final HttpRequest reqWrapper = context.getRequest();
286
287 Assert.assertEquals(HttpStatus.SC_MULTIPLE_CHOICES, response.getStatusLine().getStatusCode());
288 Assert.assertEquals("/oldlocation/", reqWrapper.getRequestLine().getUri());
289 }
290
291 @Test
292 public void testBasicRedirect301() throws Exception {
293 this.serverBootstrap.registerHandler("*", new BasicAsyncRequestHandler(
294 new BasicRedirectService(getSchemeName(), HttpStatus.SC_MOVED_PERMANENTLY)));
295 final HttpHost target = start();
296
297 final HttpClientContext context = HttpClientContext.create();
298
299 final HttpGet httpget = new HttpGet("/oldlocation/");
300
301 final Future<HttpResponse> future = this.httpclient.execute(target, httpget, context, null);
302 final HttpResponse response = future.get();
303 Assert.assertNotNull(response);
304
305 final HttpRequest reqWrapper = context.getRequest();
306 final HttpHost host = context.getTargetHost();
307
308 Assert.assertEquals(HttpStatus.SC_OK, response.getStatusLine().getStatusCode());
309 Assert.assertEquals("/newlocation/", reqWrapper.getRequestLine().getUri());
310 Assert.assertEquals(target, host);
311 }
312
313 @Test
314 public void testBasicRedirect302() throws Exception {
315 this.serverBootstrap.registerHandler("*", new BasicAsyncRequestHandler(
316 new BasicRedirectService(getSchemeName(), HttpStatus.SC_MOVED_TEMPORARILY)));
317 final HttpHost target = start();
318
319 final HttpClientContext context = HttpClientContext.create();
320
321 final HttpGet httpget = new HttpGet("/oldlocation/");
322
323 final Future<HttpResponse> future = this.httpclient.execute(target, httpget, context, null);
324 final HttpResponse response = future.get();
325 Assert.assertNotNull(response);
326
327 final HttpRequest reqWrapper = context.getRequest();
328 final HttpHost host = context.getTargetHost();
329
330 Assert.assertEquals(HttpStatus.SC_OK, response.getStatusLine().getStatusCode());
331 Assert.assertEquals("/newlocation/", reqWrapper.getRequestLine().getUri());
332 Assert.assertEquals(target, host);
333 }
334
335 @Test
336 public void testBasicRedirect302NoLocation() throws Exception {
337 this.serverBootstrap.registerHandler("*", new BasicAsyncRequestHandler(new HttpRequestHandler() {
338
339 @Override
340 public void handle(
341 final HttpRequest request,
342 final HttpResponse response,
343 final HttpContext context) throws HttpException, IOException {
344 response.setStatusCode(HttpStatus.SC_MOVED_TEMPORARILY);
345 }
346
347 }));
348 final HttpHost target = start();
349
350 final HttpClientContext context = HttpClientContext.create();
351
352 final HttpGet httpget = new HttpGet("/oldlocation/");
353
354 final Future<HttpResponse> future = this.httpclient.execute(target, httpget, context, null);
355 final HttpResponse response = future.get();
356 Assert.assertNotNull(response);
357
358 final HttpRequest reqWrapper = context.getRequest();
359 final HttpHost host = context.getTargetHost();
360
361 Assert.assertEquals(HttpStatus.SC_MOVED_TEMPORARILY, response.getStatusLine().getStatusCode());
362 Assert.assertEquals("/oldlocation/", reqWrapper.getRequestLine().getUri());
363 Assert.assertEquals(target, host);
364 }
365
366 @Test
367 public void testBasicRedirect303() throws Exception {
368 this.serverBootstrap.registerHandler("*", new BasicAsyncRequestHandler(
369 new BasicRedirectService(getSchemeName(), HttpStatus.SC_SEE_OTHER)));
370 final HttpHost target = start();
371
372 final HttpClientContext context = HttpClientContext.create();
373
374 final HttpGet httpget = new HttpGet("/oldlocation/");
375
376 final Future<HttpResponse> future = this.httpclient.execute(target, httpget, context, null);
377 final HttpResponse response = future.get();
378 Assert.assertNotNull(response);
379
380 final HttpRequest reqWrapper = context.getRequest();
381 final HttpHost host = context.getTargetHost();
382
383 Assert.assertEquals(HttpStatus.SC_OK, response.getStatusLine().getStatusCode());
384 Assert.assertEquals("/newlocation/", reqWrapper.getRequestLine().getUri());
385 Assert.assertEquals(target, host);
386 }
387
388 @Test
389 public void testBasicRedirect304() throws Exception {
390 this.serverBootstrap.registerHandler("*", new BasicAsyncRequestHandler(
391 new BasicRedirectService(getSchemeName(), HttpStatus.SC_NOT_MODIFIED)));
392 final HttpHost target = start();
393
394 final HttpClientContext context = HttpClientContext.create();
395
396 final HttpGet httpget = new HttpGet("/oldlocation/");
397
398 final Future<HttpResponse> future = this.httpclient.execute(target, httpget, context, null);
399 final HttpResponse response = future.get();
400 Assert.assertNotNull(response);
401
402 final HttpRequest reqWrapper = context.getRequest();
403
404 Assert.assertEquals(HttpStatus.SC_NOT_MODIFIED, response.getStatusLine().getStatusCode());
405 Assert.assertEquals("/oldlocation/", reqWrapper.getRequestLine().getUri());
406 }
407
408 @Test
409 public void testBasicRedirect305() throws Exception {
410 this.serverBootstrap.registerHandler("*", new BasicAsyncRequestHandler(
411 new BasicRedirectService(getSchemeName(), HttpStatus.SC_USE_PROXY)));
412 final HttpHost target = start();
413
414 final HttpClientContext context = HttpClientContext.create();
415
416 final HttpGet httpget = new HttpGet("/oldlocation/");
417
418 final Future<HttpResponse> future = this.httpclient.execute(target, httpget, context, null);
419 final HttpResponse response = future.get();
420 Assert.assertNotNull(response);
421
422 final HttpRequest reqWrapper = context.getRequest();
423
424 Assert.assertEquals(HttpStatus.SC_USE_PROXY, response.getStatusLine().getStatusCode());
425 Assert.assertEquals("/oldlocation/", reqWrapper.getRequestLine().getUri());
426 }
427
428 @Test
429 public void testBasicRedirect307() throws Exception {
430 this.serverBootstrap.registerHandler("*", new BasicAsyncRequestHandler(
431 new BasicRedirectService(getSchemeName(), HttpStatus.SC_TEMPORARY_REDIRECT)));
432 final HttpHost target = start();
433
434 final HttpClientContext context = HttpClientContext.create();
435
436 final HttpGet httpget = new HttpGet("/oldlocation/");
437
438 final Future<HttpResponse> future = this.httpclient.execute(target, httpget, context, null);
439 final HttpResponse response = future.get();
440 Assert.assertNotNull(response);
441
442 final HttpRequest reqWrapper = context.getRequest();
443 final HttpHost host = context.getTargetHost();
444
445 Assert.assertEquals(HttpStatus.SC_OK, response.getStatusLine().getStatusCode());
446 Assert.assertEquals("/newlocation/", reqWrapper.getRequestLine().getUri());
447 Assert.assertEquals(target, host);
448 }
449
450 @Test(expected=ExecutionException.class)
451 public void testMaxRedirectCheck() throws Exception {
452 this.serverBootstrap.registerHandler("*", new BasicAsyncRequestHandler(new CircularRedirectService()));
453 final HttpHost target = start();
454
455 final RequestConfig config = RequestConfig.custom()
456 .setCircularRedirectsAllowed(true)
457 .setMaxRedirects(5).build();
458
459 final HttpGet httpget = new HttpGet("/circular-oldlocation/");
460 httpget.setConfig(config);
461 try {
462 final Future<HttpResponse> future = this.httpclient.execute(target, httpget, null);
463 future.get();
464 } catch (final ExecutionException e) {
465 Assert.assertTrue(e.getCause() instanceof RedirectException);
466 throw e;
467 }
468 }
469
470 @Test(expected=ExecutionException.class)
471 public void testCircularRedirect() throws Exception {
472 this.serverBootstrap.registerHandler("*", new BasicAsyncRequestHandler(new CircularRedirectService()));
473 final HttpHost target = start();
474
475 final RequestConfig config = RequestConfig.custom()
476 .setCircularRedirectsAllowed(false)
477 .setRelativeRedirectsAllowed(true)
478 .build();
479
480 final HttpGet httpget = new HttpGet("/circular-oldlocation/");
481 httpget.setConfig(config);
482 try {
483 final Future<HttpResponse> future = this.httpclient.execute(target, httpget, null);
484 future.get();
485 } catch (final ExecutionException e) {
486 Assert.assertTrue(e.getCause() instanceof CircularRedirectException);
487 throw e;
488 }
489 }
490
491 @Test
492 public void testPostNoRedirect() throws Exception {
493 this.serverBootstrap.registerHandler("*", new BasicAsyncRequestHandler(
494 new BasicRedirectService(getSchemeName(), HttpStatus.SC_MOVED_TEMPORARILY)));
495 final HttpHost target = start();
496
497 final HttpClientContext context = HttpClientContext.create();
498
499 final HttpPost httppost = new HttpPost("/oldlocation/");
500 httppost.setEntity(new NStringEntity("stuff"));
501
502 final Future<HttpResponse> future = this.httpclient.execute(target, httppost, context, null);
503 final HttpResponse response = future.get();
504 Assert.assertNotNull(response);
505
506 final HttpRequest reqWrapper = context.getRequest();
507
508 Assert.assertEquals(HttpStatus.SC_MOVED_TEMPORARILY, response.getStatusLine().getStatusCode());
509 Assert.assertEquals("/oldlocation/", reqWrapper.getRequestLine().getUri());
510 Assert.assertEquals("POST", reqWrapper.getRequestLine().getMethod());
511 }
512
513 @Test
514 public void testPostRedirectSeeOther() throws Exception {
515 this.serverBootstrap.registerHandler("*", new BasicAsyncRequestHandler(
516 new BasicRedirectService(getSchemeName(), HttpStatus.SC_SEE_OTHER)));
517 final HttpHost target = start();
518
519 final HttpClientContext context = HttpClientContext.create();
520
521 final HttpPost httppost = new HttpPost("/oldlocation/");
522 httppost.setEntity(new NStringEntity("stuff"));
523
524 final Future<HttpResponse> future = this.httpclient.execute(target, httppost, context, null);
525 final HttpResponse response = future.get();
526 Assert.assertNotNull(response);
527
528 final HttpRequest reqWrapper = context.getRequest();
529
530 Assert.assertEquals(HttpStatus.SC_OK, response.getStatusLine().getStatusCode());
531 Assert.assertEquals("/newlocation/", reqWrapper.getRequestLine().getUri());
532 Assert.assertEquals("GET", reqWrapper.getRequestLine().getMethod());
533 }
534
535 @Test
536 public void testRelativeRedirect() throws Exception {
537 this.serverBootstrap.registerHandler("*", new BasicAsyncRequestHandler(new RelativeRedirectService()));
538 final HttpHost target = start();
539
540 final HttpClientContext context = HttpClientContext.create();
541
542 final RequestConfig config = RequestConfig.custom()
543 .setRelativeRedirectsAllowed(true)
544 .build();
545
546 final HttpGet httpget = new HttpGet("/oldlocation/");
547 httpget.setConfig(config);
548
549 final Future<HttpResponse> future = this.httpclient.execute(target, httpget, context, null);
550 final HttpResponse response = future.get();
551 Assert.assertNotNull(response);
552
553 final HttpRequest reqWrapper = context.getRequest();
554 final HttpHost host = context.getTargetHost();
555
556 Assert.assertEquals(HttpStatus.SC_OK, response.getStatusLine().getStatusCode());
557 Assert.assertEquals("/relativelocation/", reqWrapper.getRequestLine().getUri());
558 Assert.assertEquals(target, host);
559 }
560
561 @Test
562 public void testRelativeRedirect2() throws Exception {
563 this.serverBootstrap.registerHandler("*", new BasicAsyncRequestHandler(new RelativeRedirectService2()));
564 final HttpHost target = start();
565
566 final HttpClientContext context = HttpClientContext.create();
567
568 final RequestConfig config = RequestConfig.custom()
569 .setRelativeRedirectsAllowed(true)
570 .build();
571
572 final HttpGet httpget = new HttpGet("/test/oldlocation");
573 httpget.setConfig(config);
574
575 final Future<HttpResponse> future = this.httpclient.execute(target, httpget, context, null);
576 final HttpResponse response = future.get();
577 Assert.assertNotNull(response);
578
579 final HttpRequest reqWrapper = context.getRequest();
580 final HttpHost host = context.getTargetHost();
581
582 Assert.assertEquals(HttpStatus.SC_OK, response.getStatusLine().getStatusCode());
583 Assert.assertEquals("/test/relativelocation", reqWrapper.getRequestLine().getUri());
584 Assert.assertEquals(target, host);
585 }
586
587 @Test(expected=ExecutionException.class)
588 public void testRejectRelativeRedirect() throws Exception {
589 this.serverBootstrap.registerHandler("*", new BasicAsyncRequestHandler(new RelativeRedirectService()));
590 final HttpHost target = start();
591
592 final RequestConfig config = RequestConfig.custom()
593 .setRelativeRedirectsAllowed(false)
594 .build();
595
596 final HttpGet httpget = new HttpGet("/oldlocation/");
597 httpget.setConfig(config);
598 try {
599 final Future<HttpResponse> future = this.httpclient.execute(target, httpget, null);
600 future.get();
601 } catch (final ExecutionException e) {
602 Assert.assertTrue(e.getCause() instanceof ProtocolException);
603 throw e;
604 }
605 }
606
607 @Test(expected=ExecutionException.class)
608 public void testRejectBogusRedirectLocation() throws Exception {
609 this.serverBootstrap.registerHandler("*", new BasicAsyncRequestHandler(
610 new BogusRedirectService(getSchemeName(), "xxx://bogus", true)));
611 final HttpHost target = start();
612
613 final HttpGet httpget = new HttpGet("/oldlocation/");
614
615 try {
616 final Future<HttpResponse> future = this.httpclient.execute(target, httpget, null);
617 future.get();
618 } catch (final ExecutionException ex) {
619 Assert.assertTrue(ex.getCause() instanceof HttpException);
620 throw ex;
621 }
622 }
623
624 @Test(expected=ExecutionException.class)
625 public void testRejectInvalidRedirectLocation() throws Exception {
626 this.serverBootstrap.registerHandler("*", new BasicAsyncRequestHandler(
627 new BogusRedirectService(getSchemeName(), "/newlocation/?p=I have spaces", false)));
628 final HttpHost target = start();
629
630 final HttpGet httpget = new HttpGet("/oldlocation/");
631 try {
632 final Future<HttpResponse> future = this.httpclient.execute(target, httpget, null);
633 future.get();
634 } catch (final ExecutionException e) {
635 Assert.assertTrue(e.getCause() instanceof ProtocolException);
636 throw e;
637 }
638 }
639
640 @Test
641 public void testRedirectWithCookie() throws Exception {
642 this.serverBootstrap.registerHandler("*", new BasicAsyncRequestHandler(
643 new BasicRedirectService(getSchemeName(), HttpStatus.SC_MOVED_TEMPORARILY)));
644 final HttpHost target = start();
645
646 final CookieStore cookieStore = new BasicCookieStore();
647 final HttpClientContext context = HttpClientContext.create();
648 context.setCookieStore(cookieStore);
649
650 final BasicClientCookie cookie = new BasicClientCookie("name", "value");
651 cookie.setDomain(target.getHostName());
652 cookie.setPath("/");
653
654 cookieStore.addCookie(cookie);
655
656 final HttpGet httpget = new HttpGet("/oldlocation/");
657
658 final Future<HttpResponse> future = this.httpclient.execute(target, httpget, context, null);
659 final HttpResponse response = future.get();
660 Assert.assertNotNull(response);
661
662 final HttpRequest reqWrapper = context.getRequest();
663
664 Assert.assertEquals(HttpStatus.SC_OK, response.getStatusLine().getStatusCode());
665 Assert.assertEquals("/newlocation/", reqWrapper.getRequestLine().getUri());
666
667 final Header[] headers = reqWrapper.getHeaders(SM.COOKIE);
668 Assert.assertEquals("There can only be one (cookie)", 1, headers.length);
669 }
670
671 @Test
672 public void testDefaultHeadersRedirect() throws Exception {
673 this.serverBootstrap.registerHandler("*", new BasicAsyncRequestHandler(
674 new BasicRedirectService(getSchemeName(), HttpStatus.SC_MOVED_TEMPORARILY)));
675
676 final List<Header> defaultHeaders = new ArrayList<Header>(1);
677 defaultHeaders.add(new BasicHeader(HTTP.USER_AGENT, "my-test-client"));
678 this.clientBuilder.setDefaultHeaders(defaultHeaders);
679
680 final HttpHost target = start();
681
682 final HttpClientContext context = HttpClientContext.create();
683
684 final HttpGet httpget = new HttpGet("/oldlocation/");
685
686 final Future<HttpResponse> future = this.httpclient.execute(target, httpget, context, null);
687 final HttpResponse response = future.get();
688 Assert.assertNotNull(response);
689
690 final HttpRequest reqWrapper = context.getRequest();
691
692 Assert.assertEquals(HttpStatus.SC_OK, response.getStatusLine().getStatusCode());
693 Assert.assertEquals("/newlocation/", reqWrapper.getRequestLine().getUri());
694
695 final Header header = reqWrapper.getFirstHeader(HTTP.USER_AGENT);
696 Assert.assertEquals("my-test-client", header.getValue());
697 }
698
699 static class CrossSiteRedirectService implements HttpRequestHandler {
700
701 private final HttpHost host;
702
703 public CrossSiteRedirectService(final HttpHost host) {
704 super();
705 this.host = host;
706 }
707
708 @Override
709 public void handle(
710 final HttpRequest request,
711 final HttpResponse response,
712 final HttpContext context) throws HttpException, IOException {
713 final ProtocolVersion ver = request.getRequestLine().getProtocolVersion();
714 final String location;
715 try {
716 final URIBuilder uribuilder = new URIBuilder(request.getRequestLine().getUri());
717 uribuilder.setScheme(this.host.getSchemeName());
718 uribuilder.setHost(this.host.getHostName());
719 uribuilder.setPort(this.host.getPort());
720 uribuilder.setPath("/random/1024");
721 location = uribuilder.build().toASCIIString();
722 } catch (final URISyntaxException ex) {
723 throw new ProtocolException("Invalid request URI", ex);
724 }
725 response.setStatusLine(ver, HttpStatus.SC_TEMPORARY_REDIRECT);
726 response.addHeader(new BasicHeader("Location", location));
727 }
728 }
729
730 @Test
731 public void testCrossSiteRedirect() throws Exception {
732 this.serverBootstrap.registerHandler("/random/*", new BasicAsyncRequestHandler(
733 new RandomHandler()));
734 final HttpHost redirectTarget = start();
735
736 this.serverBootstrap.registerHandler("/redirect/*", new BasicAsyncRequestHandler(
737 new CrossSiteRedirectService(redirectTarget)));
738
739 final HttpServer secondServer = this.serverBootstrap.create();
740 try {
741 secondServer.start();
742 final ListenerEndpoint endpoint2 = secondServer.getEndpoint();
743 endpoint2.waitFor();
744
745 final InetSocketAddress address2 = (InetSocketAddress) endpoint2.getAddress();
746 final HttpHost initialTarget = new HttpHost("localhost", address2.getPort(), getSchemeName());
747
748 final Queue<Future<HttpResponse>> queue = new ConcurrentLinkedQueue<Future<HttpResponse>>();
749 for (int i = 0; i < 4; i++) {
750 final HttpClientContext context = HttpClientContext.create();
751 final HttpGet httpget = new HttpGet("/redirect/anywhere");
752 queue.add(this.httpclient.execute(initialTarget, httpget, context, null));
753 }
754 while (!queue.isEmpty()) {
755 final Future<HttpResponse> future = queue.remove();
756 final HttpResponse response = future.get();
757 Assert.assertNotNull(response);
758 Assert.assertEquals(200, response.getStatusLine().getStatusCode());
759 }
760 } finally {
761 this.server.shutdown(10, TimeUnit.SECONDS);
762 }
763 }
764
765 @Test
766 public void testRepeatRequest() throws Exception {
767 this.serverBootstrap.registerHandler("*", new BasicAsyncRequestHandler(new RomeRedirectService()));
768 final HttpHost target = start();
769
770 final HttpClientContext context = HttpClientContext.create();
771
772 final RequestConfig config = RequestConfig.custom().setRelativeRedirectsAllowed(true).build();
773 final HttpGet first = new HttpGet("/rome");
774 first.setConfig(config);
775
776 final Future<HttpResponse> future1 = this.httpclient.execute(target, first, context, null);
777 final HttpResponse response1 = future1.get();
778 Assert.assertNotNull(response1);
779
780 final HttpGet second = new HttpGet("/rome");
781 second.setConfig(config);
782
783 final Future<HttpResponse> future2 = this.httpclient.execute(target, second, context, null);
784 final HttpResponse response2 = future2.get();
785 Assert.assertNotNull(response2);
786
787 final HttpRequest reqWrapper = context.getRequest();
788 final HttpHost host = context.getTargetHost();
789
790 Assert.assertEquals(HttpStatus.SC_OK, response2.getStatusLine().getStatusCode());
791 Assert.assertEquals("/rome", reqWrapper.getRequestLine().getUri());
792 Assert.assertEquals(host, target);
793 }
794
795 @Test
796 public void testRepeatRequestRedirect() throws Exception {
797 this.serverBootstrap.registerHandler("*", new BasicAsyncRequestHandler(new RomeRedirectService()));
798 final HttpHost target = start();
799
800 final HttpClientContext context = HttpClientContext.create();
801
802 final RequestConfig config = RequestConfig.custom().setRelativeRedirectsAllowed(true).build();
803 final HttpGet first = new HttpGet("/lille");
804 first.setConfig(config);
805
806 final Future<HttpResponse> future1 = this.httpclient.execute(target, first, context, null);
807 final HttpResponse response1 = future1.get();
808 Assert.assertNotNull(response1);
809
810 final HttpGet second = new HttpGet("/lille");
811 second.setConfig(config);
812
813 final Future<HttpResponse> future2 = this.httpclient.execute(target, second, context, null);
814 final HttpResponse response2 = future2.get();
815 Assert.assertNotNull(response2);
816
817 final HttpRequest reqWrapper = context.getRequest();
818 final HttpHost host = context.getTargetHost();
819
820 Assert.assertEquals(HttpStatus.SC_OK, response2.getStatusLine().getStatusCode());
821 Assert.assertEquals("/rome", reqWrapper.getRequestLine().getUri());
822 Assert.assertEquals(host, target);
823 }
824
825 @Test
826 public void testDifferentRequestSameRedirect() throws Exception {
827 this.serverBootstrap.registerHandler("*", new BasicAsyncRequestHandler(new RomeRedirectService()));
828 final HttpHost target = start();
829
830 final HttpClientContext context = HttpClientContext.create();
831
832 final RequestConfig config = RequestConfig.custom().setRelativeRedirectsAllowed(true).build();
833 final HttpGet first = new HttpGet("/alian");
834 first.setConfig(config);
835
836 final Future<HttpResponse> future1 = this.httpclient.execute(target, first, context, null);
837 final HttpResponse response1 = future1.get();
838 Assert.assertNotNull(response1);
839
840 final HttpGet second = new HttpGet("/lille");
841 second.setConfig(config);
842
843 final Future<HttpResponse> future2 = this.httpclient.execute(target, second, context, null);
844 final HttpResponse response2 = future2.get();
845 Assert.assertNotNull(response2);
846
847 final HttpRequest reqWrapper = context.getRequest();
848 final HttpHost host = context.getTargetHost();
849
850 Assert.assertEquals(HttpStatus.SC_OK, response2.getStatusLine().getStatusCode());
851 Assert.assertEquals("/rome", reqWrapper.getRequestLine().getUri());
852 Assert.assertEquals(host, target);
853 }
854
855 }
0 /*
1 * ====================================================================
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 * ====================================================================
19 *
20 * This software consists of voluntary contributions made by many
21 * individuals on behalf of the Apache Software Foundation. For more
22 * information on the Apache Software Foundation, please see
23 * <http://www.apache.org/>.
24 *
25 */
26 package org.apache.http.nio.client.integration;
27
28 import java.io.IOException;
29 import java.nio.ByteBuffer;
30 import java.util.concurrent.Future;
31
32 import org.apache.http.localserver.HttpAsyncTestBase;
33 import org.apache.http.HttpEntity;
34 import org.apache.http.HttpException;
35 import org.apache.http.HttpHost;
36 import org.apache.http.HttpRequest;
37 import org.apache.http.HttpResponse;
38 import org.apache.http.HttpStatus;
39 import org.apache.http.client.UserTokenHandler;
40 import org.apache.http.client.methods.HttpGet;
41 import org.apache.http.entity.ContentType;
42 import org.apache.http.impl.nio.conn.CPoolUtils;
43 import org.apache.http.nio.ContentDecoder;
44 import org.apache.http.nio.IOControl;
45 import org.apache.http.nio.NHttpClientConnection;
46 import org.apache.http.nio.client.HttpAsyncClient;
47 import org.apache.http.nio.entity.NStringEntity;
48 import org.apache.http.nio.protocol.AbstractAsyncResponseConsumer;
49 import org.apache.http.nio.protocol.BasicAsyncRequestHandler;
50 import org.apache.http.nio.protocol.BasicAsyncRequestProducer;
51 import org.apache.http.nio.reactor.IOEventDispatch;
52 import org.apache.http.pool.PoolEntry;
53 import org.apache.http.protocol.BasicHttpContext;
54 import org.apache.http.protocol.HttpContext;
55 import org.apache.http.protocol.HttpRequestHandler;
56 import org.junit.Assert;
57 import org.junit.Test;
58
59 public class TestStatefulConnManagement extends HttpAsyncTestBase {
60
61 static class SimpleService implements HttpRequestHandler {
62
63 public SimpleService() {
64 super();
65 }
66
67 @Override
68 public void handle(
69 final HttpRequest request,
70 final HttpResponse response,
71 final HttpContext context) throws HttpException, IOException {
72 response.setStatusCode(HttpStatus.SC_OK);
73 final NStringEntity entity = new NStringEntity("Whatever");
74 response.setEntity(entity);
75 }
76 }
77
78 @Test
79 public void testStatefulConnections() throws Exception {
80 this.serverBootstrap.registerHandler("*", new BasicAsyncRequestHandler(new SimpleService()));
81
82 final UserTokenHandler userTokenHandler = new UserTokenHandler() {
83
84 @Override
85 public Object getUserToken(final HttpContext context) {
86 return context.getAttribute("user");
87 }
88
89 };
90 this.clientBuilder.setUserTokenHandler(userTokenHandler);
91 final HttpHost target = start();
92
93 final int workerCount = 2;
94 final int requestCount = 5;
95
96 final HttpContext[] contexts = new HttpContext[workerCount];
97 final HttpWorker[] workers = new HttpWorker[workerCount];
98 for (int i = 0; i < contexts.length; i++) {
99 final HttpContext context = new BasicHttpContext();
100 final Object token = Integer.valueOf(i);
101 context.setAttribute("user", token);
102 contexts[i] = context;
103 workers[i] = new HttpWorker(context, requestCount, target, this.httpclient);
104 }
105
106 for (final HttpWorker worker : workers) {
107 worker.start();
108 }
109 for (final HttpWorker worker : workers) {
110 worker.join(10000);
111 }
112 for (final HttpWorker worker : workers) {
113 final Exception ex = worker.getException();
114 if (ex != null) {
115 throw ex;
116 }
117 Assert.assertEquals(requestCount, worker.getCount());
118 }
119
120 for (final HttpContext context : contexts) {
121 final Integer id = (Integer) context.getAttribute("user");
122
123 for (int r = 1; r < requestCount; r++) {
124 final Integer state = (Integer) context.getAttribute("r" + r);
125 Assert.assertEquals(id, state);
126 }
127 }
128
129 }
130
131 static class HttpWorker extends Thread {
132
133 private final HttpContext context;
134 private final int requestCount;
135 private final HttpHost target;
136 private final HttpAsyncClient httpclient;
137
138 private volatile Exception exception;
139 private volatile int count;
140
141 public HttpWorker(
142 final HttpContext context,
143 final int requestCount,
144 final HttpHost target,
145 final HttpAsyncClient httpclient) {
146 super();
147 this.context = context;
148 this.requestCount = requestCount;
149 this.target = target;
150 this.httpclient = httpclient;
151 this.count = 0;
152 }
153
154 public int getCount() {
155 return this.count;
156 }
157
158 public Exception getException() {
159 return this.exception;
160 }
161
162 @Override
163 public void run() {
164 try {
165 for (int r = 0; r < this.requestCount; r++) {
166 final HttpGet httpget = new HttpGet("/");
167 final Future<Object> future = this.httpclient.execute(
168 new BasicAsyncRequestProducer(this.target, httpget),
169 new AbstractAsyncResponseConsumer<Object>() {
170
171 @Override
172 protected void onResponseReceived(final HttpResponse response) {
173 }
174
175 @Override
176 protected void onEntityEnclosed(
177 final HttpEntity entity,
178 final ContentType contentType) throws IOException {
179 }
180
181 @Override
182 protected void onContentReceived(
183 final ContentDecoder decoder,
184 final IOControl ioctrl) throws IOException {
185 final ByteBuffer buf = ByteBuffer.allocate(2048);
186 decoder.read(buf);
187 }
188
189 @Override
190 protected Object buildResult(final HttpContext context) throws Exception {
191 final NHttpClientConnection conn = (NHttpClientConnection) context.getAttribute(
192 IOEventDispatch.CONNECTION_KEY);
193
194 final PoolEntry<?, ?> entry = CPoolUtils.getPoolEntry(conn);
195 return entry.getState();
196 }
197
198 @Override
199 protected void releaseResources() {
200 }
201
202 },
203 this.context,
204 null);
205 this.count++;
206 final Object state = future.get();
207 this.context.setAttribute("r" + r, state);
208 }
209
210 } catch (final Exception ex) {
211 this.exception = ex;
212 }
213 }
214
215 }
216
217 @Test
218 public void testRouteSpecificPoolRecylcing() throws Exception {
219 this.serverBootstrap.registerHandler("*", new BasicAsyncRequestHandler(new SimpleService()));
220 // This tests what happens when a maxed connection pool needs
221 // to kill the last idle connection to a route to build a new
222 // one to the same route.
223 final UserTokenHandler userTokenHandler = new UserTokenHandler() {
224
225 @Override
226 public Object getUserToken(final HttpContext context) {
227 return context.getAttribute("user");
228 }
229
230 };
231 this.clientBuilder.setUserTokenHandler(userTokenHandler);
232
233 final HttpHost target = start();
234 final int maxConn = 2;
235 // We build a client with 2 max active // connections, and 2 max per route.
236 this.connMgr.setMaxTotal(maxConn);
237 this.connMgr.setDefaultMaxPerRoute(maxConn);
238
239 // Bottom of the pool : a *keep alive* connection to Route 1.
240 final HttpContext context1 = new BasicHttpContext();
241 context1.setAttribute("user", "stuff");
242
243 final Future<HttpResponse> future1 = this.httpclient.execute(
244 target, new HttpGet("/"), context1, null);
245 final HttpResponse response1 = future1.get();
246 Assert.assertNotNull(response1);
247 Assert.assertEquals(200, response1.getStatusLine().getStatusCode());
248
249 // The ConnPoolByRoute now has 1 free connection, out of 2 max
250 // The ConnPoolByRoute has one RouteSpcfcPool, that has one free connection
251 // for [localhost][stuff]
252
253 Thread.sleep(100);
254
255 // Send a very simple HTTP get (it MUST be simple, no auth, no proxy, no 302, no 401, ...)
256 // Send it to another route. Must be a keepalive.
257 final HttpContext context2 = new BasicHttpContext();
258
259 final Future<HttpResponse> future2 = this.httpclient.execute(
260 new HttpHost("127.0.0.1", target.getPort(), target.getSchemeName()),
261 new HttpGet("/"), context2, null);
262 final HttpResponse response2 = future2.get();
263 Assert.assertNotNull(response2);
264 Assert.assertEquals(200, response2.getStatusLine().getStatusCode());
265
266 // ConnPoolByRoute now has 2 free connexions, out of its 2 max.
267 // The [localhost][stuff] RouteSpcfcPool is the same as earlier
268 // And there is a [127.0.0.1][null] pool with 1 free connection
269
270 Thread.sleep(100);
271
272 // This will put the ConnPoolByRoute to the targeted state :
273 // [localhost][stuff] will not get reused because this call is [localhost][null]
274 // So the ConnPoolByRoute will need to kill one connection (it is maxed out globally).
275 // The killed conn is the oldest, which means the first HTTPGet ([localhost][stuff]).
276 // When this happens, the RouteSpecificPool becomes empty.
277 final HttpContext context3 = new BasicHttpContext();
278 final Future<HttpResponse> future3 = this.httpclient.execute(
279 target, new HttpGet("/"), context3, null);
280 final HttpResponse response3 = future3.get();
281 Assert.assertNotNull(response3);
282 Assert.assertEquals(200, response3.getStatusLine().getStatusCode());
283 }
284
285 }
0 /*
1 * ====================================================================
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 * ====================================================================
19 *
20 * This software consists of voluntary contributions made by many
21 * individuals on behalf of the Apache Software Foundation. For more
22 * information on the Apache Software Foundation, please see
23 * <http://www.apache.org/>.
24 *
25 */
26 package org.apache.http.nio.client.methods;
27
28 import java.io.IOException;
29 import java.nio.ByteBuffer;
30 import java.nio.CharBuffer;
31 import java.util.concurrent.ExecutionException;
32 import java.util.concurrent.Future;
33 import java.util.concurrent.atomic.AtomicLong;
34
35 import org.apache.http.Consts;
36 import org.apache.http.localserver.HttpAsyncTestBase;
37 import org.apache.http.HttpException;
38 import org.apache.http.HttpHost;
39 import org.apache.http.HttpResponse;
40 import org.apache.http.entity.ContentType;
41 import org.apache.http.localserver.EchoHandler;
42 import org.apache.http.localserver.RandomHandler;
43 import org.apache.http.nio.IOControl;
44 import org.apache.http.nio.protocol.BasicAsyncRequestHandler;
45 import org.apache.http.nio.protocol.HttpAsyncRequestProducer;
46 import org.apache.http.protocol.HttpContext;
47 import org.junit.Assert;
48 import org.junit.Before;
49 import org.junit.Test;
50 import org.mockito.Mockito;
51
52 public class TestAsyncConsumers extends HttpAsyncTestBase {
53
54 @Before @Override
55 public void setUp() throws Exception {
56 super.setUp();
57 this.serverBootstrap.registerHandler("/echo/*", new BasicAsyncRequestHandler(new EchoHandler()));
58 this.serverBootstrap.registerHandler("/random/*", new BasicAsyncRequestHandler(new RandomHandler()));
59 }
60
61 static class ByteCountingConsumer extends AsyncByteConsumer<Long> {
62
63 public ByteCountingConsumer() {
64 super();
65 }
66
67 public ByteCountingConsumer(final int bufSize) {
68 super(bufSize);
69 }
70
71 private final AtomicLong count = new AtomicLong(0);
72
73 @Override
74 protected void onResponseReceived(final HttpResponse response) {
75 }
76
77 @Override
78 protected void onByteReceived(final ByteBuffer buf, final IOControl ioctrl) {
79 this.count.addAndGet(buf.remaining());
80 }
81
82 @Override
83 protected Long buildResult(final HttpContext context) throws Exception {
84 return count.get();
85 }
86
87 }
88
89 @Test
90 public void testByteConsumer() throws Exception {
91 final HttpHost target = start();
92 for (int i = 0; i < 5; i++) {
93 final HttpAsyncRequestProducer httpget = HttpAsyncMethods.createGet(target.toURI() + "/random/20480");
94 final AsyncByteConsumer<Long> consumer = new ByteCountingConsumer();
95 final Future<Long> future = this.httpclient.execute(httpget, consumer, null);
96 final Long count = future.get();
97 Assert.assertEquals(20480, count.longValue());
98 }
99 }
100
101 @Test
102 public void testByteConsumerSmallBufffer() throws Exception {
103 final HttpHost target = start();
104 for (int i = 0; i < 5; i++) {
105 final HttpAsyncRequestProducer httpget = HttpAsyncMethods.createGet(target.toURI() + "/random/20480");
106 final AsyncByteConsumer<Long> consumer = new ByteCountingConsumer(512);
107 final Future<Long> future = this.httpclient.execute(httpget, consumer, null);
108 final Long count = future.get();
109 Assert.assertEquals(20480, count.longValue());
110 }
111 }
112
113 static class BufferingCharConsumer extends AsyncCharConsumer<String> {
114
115 public BufferingCharConsumer() {
116 super();
117 }
118
119 public BufferingCharConsumer(final int bufSize) {
120 super(bufSize);
121 }
122
123 private final StringBuilder sb = new StringBuilder();
124
125 @Override
126 public void onResponseReceived(final HttpResponse response) {
127 }
128
129 @Override
130 protected void onCharReceived(final CharBuffer buf, final IOControl ioctrl) throws IOException {
131 while (buf.hasRemaining()) {
132 this.sb.append(buf.get());
133 }
134 }
135
136 @Override
137 protected void releaseResources() {
138 super.releaseResources();
139 this.sb.setLength(0);
140 }
141
142 @Override
143 protected String buildResult(final HttpContext context) throws Exception {
144 return this.sb.toString();
145 }
146
147 }
148
149 @Test
150 public void testCharConsumer() throws Exception {
151 final HttpHost target = start();
152 final StringBuilder sb = new StringBuilder();
153 for (int i= 0; i < 25; i++) {
154 sb.append("blah blah blah blah\r\n");
155 sb.append("yada yada yada yada\r\n");
156 }
157 final String s = sb.toString();
158
159 for (int i = 0; i < 5; i++) {
160 final HttpAsyncRequestProducer httppost = HttpAsyncMethods.createPost(
161 target.toURI() + "/echo/stuff", s,
162 ContentType.create("text/plain", Consts.ASCII));
163 final AsyncCharConsumer<String> consumer = new BufferingCharConsumer();
164 final Future<String> future = this.httpclient.execute(httppost, consumer, null);
165 final String result = future.get();
166 Assert.assertEquals(s, result);
167 }
168 }
169
170 @Test
171 public void testCharConsumerSmallBufffer() throws Exception {
172 final HttpHost target = start();
173 final StringBuilder sb = new StringBuilder();
174 for (int i= 0; i < 25; i++) {
175 sb.append("blah blah blah blah\r\n");
176 sb.append("yada yada yada yada\r\n");
177 }
178 final String s = sb.toString();
179
180 for (int i = 0; i < 5; i++) {
181 final HttpAsyncRequestProducer httppost = HttpAsyncMethods.createPost(
182 target.toURI() + "/echo/stuff", s,
183 ContentType.create("text/plain", Consts.ASCII));
184 final AsyncCharConsumer<String> consumer = new BufferingCharConsumer(512);
185 final Future<String> future = this.httpclient.execute(httppost, consumer, null);
186 final String result = future.get();
187 Assert.assertEquals(s, result);
188 }
189 }
190
191 @Test
192 public void testResourceReleaseOnSuccess() throws Exception {
193 final HttpHost target = start();
194 final StringBuilder sb = new StringBuilder();
195 for (int i= 0; i < 25; i++) {
196 sb.append("blah blah blah blah\r\n");
197 sb.append("yada yada yada yada\r\n");
198 }
199 final String s = sb.toString();
200
201 final HttpAsyncRequestProducer httppost = HttpAsyncMethods.createPost(
202 target.toURI() + "/echo/stuff", s,
203 ContentType.create("text/plain", Consts.ASCII));
204 final BufferingCharConsumer consumer = Mockito.spy(new BufferingCharConsumer());
205 final Future<String> future = this.httpclient.execute(httppost, consumer, null);
206 final String result = future.get();
207 Assert.assertEquals(s, result);
208 Mockito.verify(consumer).buildResult(Mockito.any(HttpContext.class));
209 Mockito.verify(consumer).releaseResources();
210 }
211
212 @Test
213 public void testResourceReleaseOnException() throws Exception {
214 final HttpHost target = start();
215 final HttpAsyncRequestProducer httppost = HttpAsyncMethods.createPost(
216 target.toURI() + "/echo/stuff", "stuff",
217 ContentType.create("text/plain", Consts.ASCII));
218 final AsyncCharConsumer<String> consumer = Mockito.spy(new BufferingCharConsumer());
219 Mockito.doThrow(new IOException("Kaboom")).when(consumer).onCharReceived(
220 Mockito.any(CharBuffer.class), Mockito.any(IOControl.class));
221
222 final Future<String> future = this.httpclient.execute(httppost, consumer, null);
223 try {
224 future.get();
225 Assert.fail("ExecutionException expected");
226 } catch (final ExecutionException ex) {
227 final Throwable t = ex.getCause();
228 Assert.assertNotNull(t);
229 Assert.assertTrue(t instanceof IOException);
230 Assert.assertEquals("Kaboom", t.getMessage());
231 }
232 Mockito.verify(consumer).releaseResources();
233 }
234
235 @Test
236 public void testResourceReleaseOnBuildFailure() throws Exception {
237 final HttpHost target = start();
238 final HttpAsyncRequestProducer httppost = HttpAsyncMethods.createPost(
239 target.toURI() + "/echo/stuff", "stuff",
240 ContentType.create("text/plain", Consts.ASCII));
241 final BufferingCharConsumer consumer = Mockito.spy(new BufferingCharConsumer());
242 Mockito.doThrow(new HttpException("Kaboom")).when(consumer).buildResult(Mockito.any(HttpContext.class));
243
244 final Future<String> future = this.httpclient.execute(httppost, consumer, null);
245 try {
246 future.get();
247 Assert.fail("ExecutionException expected");
248 } catch (final ExecutionException ex) {
249 final Throwable t = ex.getCause();
250 Assert.assertNotNull(t);
251 Assert.assertTrue(t instanceof HttpException);
252 Assert.assertEquals("Kaboom", t.getMessage());
253 }
254 Mockito.verify(consumer).releaseResources();
255 }
256
257 }
0 /*
1 * ====================================================================
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 * ====================================================================
19 *
20 * This software consists of voluntary contributions made by many
21 * individuals on behalf of the Apache Software Foundation. For more
22 * information on the Apache Software Foundation, please see
23 * <http://www.apache.org/>.
24 *
25 */
26 package org.apache.http.nio.client.methods;
27
28 import java.io.File;
29 import java.io.FileInputStream;
30 import java.io.FileNotFoundException;
31 import java.io.IOException;
32 import java.io.InputStream;
33 import java.net.URI;
34 import java.nio.charset.Charset;
35 import java.util.concurrent.Future;
36
37 import org.apache.commons.io.FileUtils;
38 import org.apache.commons.io.IOUtils;
39 import org.apache.commons.io.LineIterator;
40 import org.apache.commons.io.output.FileWriterWithEncoding;
41 import org.apache.http.Consts;
42 import org.apache.http.localserver.HttpAsyncTestBase;
43 import org.apache.http.HttpEntity;
44 import org.apache.http.HttpEntityEnclosingRequest;
45 import org.apache.http.HttpException;
46 import org.apache.http.HttpHost;
47 import org.apache.http.HttpRequest;
48 import org.apache.http.HttpResponse;
49 import org.apache.http.HttpStatus;
50 import org.apache.http.client.methods.HttpPost;
51 import org.apache.http.entity.BasicHttpEntity;
52 import org.apache.http.entity.ContentType;
53 import org.apache.http.nio.entity.NFileEntity;
54 import org.apache.http.nio.entity.NStringEntity;
55 import org.apache.http.nio.protocol.BasicAsyncRequestHandler;
56 import org.apache.http.protocol.HttpContext;
57 import org.apache.http.protocol.HttpRequestHandler;
58 import org.junit.After;
59 import org.junit.AfterClass;
60 import org.junit.Assert;
61 import org.junit.BeforeClass;
62 import org.junit.Test;
63
64 public class TestZeroCopy extends HttpAsyncTestBase {
65
66 private static final String[] TEXT = {
67 "blah blah blah blah blah blah blah blah blah blah blah blah blah blah",
68 "yada yada yada yada yada yada yada yada yada yada yada yada yada yada",
69 "da da da da da da da da da da da da da da da da da da da da da da da da",
70 "nyet nyet nyet nyet nyet nyet nyet nyet nyet nyet nyet nyet nyet nyet"
71 };
72
73 private static final Charset ASCII = Charset.forName("ascii");
74 private static File TEST_FILE;
75 private File tmpfile;
76
77 @BeforeClass
78 public static void createSrcFile() throws Exception {
79 final File tmpdir = FileUtils.getTempDirectory();
80 TEST_FILE = new File(tmpdir, "src.test");
81 final FileWriterWithEncoding out = new FileWriterWithEncoding(TEST_FILE, ASCII);
82 try {
83 for (int i = 0; i < 500; i++) {
84 for (final String line: TEXT) {
85 out.write(line);
86 out.write("\r\n");
87 }
88 }
89 } finally {
90 out.close();
91 }
92 }
93
94 @AfterClass
95 public static void deleteSrcFile() throws Exception {
96 if (TEST_FILE != null) {
97 TEST_FILE.delete();
98 TEST_FILE = null;
99 }
100 }
101
102 @After
103 public void cleanUp() throws Exception {
104 if (this.tmpfile != null && this.tmpfile.exists()) {
105 this.tmpfile.delete();
106 }
107 }
108
109 static class TestZeroCopyPost extends BaseZeroCopyRequestProducer {
110
111 private final boolean forceChunking;
112
113 protected TestZeroCopyPost(
114 final String requestURI,
115 final boolean forceChunking) throws FileNotFoundException {
116 super(URI.create(requestURI), TEST_FILE, ContentType.create("text/plain"));
117 this.forceChunking = forceChunking;
118 }
119
120 @Override
121 protected HttpEntityEnclosingRequest createRequest(final URI requestURI, final HttpEntity entity) {
122 final HttpPost httppost = new HttpPost(requestURI);
123 if (this.forceChunking) {
124 final BasicHttpEntity chunkedEntity = new BasicHttpEntity();
125 chunkedEntity.setChunked(true);
126 httppost.setEntity(chunkedEntity);
127 } else {
128 httppost.setEntity(entity);
129 }
130 return httppost;
131 }
132
133 }
134
135 static class TestZeroCopyConsumer extends ZeroCopyConsumer<Integer> {
136
137 public TestZeroCopyConsumer(final File file) throws FileNotFoundException {
138 super(file);
139 }
140
141 @Override
142 protected Integer process(
143 final HttpResponse response,
144 final File file,
145 final ContentType contentType) {
146 return response.getStatusLine().getStatusCode();
147 }
148
149 }
150
151 static class TestHandler implements HttpRequestHandler {
152
153 private final boolean forceChunking;
154
155 TestHandler(final boolean forceChunking) {
156 super();
157 this.forceChunking = forceChunking;
158 }
159
160 @Override
161 public void handle(
162 final HttpRequest request,
163 final HttpResponse response,
164 final HttpContext context) throws HttpException, IOException {
165 HttpEntity requestEntity = null;
166 if (request instanceof HttpEntityEnclosingRequest) {
167 requestEntity = ((HttpEntityEnclosingRequest) request).getEntity();
168 }
169 if (requestEntity == null) {
170 response.setEntity(new NStringEntity("Empty content"));
171 return;
172 }
173
174 boolean ok = true;
175
176 final InputStream instream = requestEntity.getContent();
177 try {
178 final ContentType contentType = ContentType.getOrDefault(requestEntity);
179 Charset charset = contentType.getCharset();
180 if (charset == null) {
181 charset = Consts.ISO_8859_1;
182 }
183 final LineIterator it = IOUtils.lineIterator(instream, charset.name());
184 int count = 0;
185 while (it.hasNext()) {
186 final String line = it.next();
187 final int i = count % TEXT.length;
188 final String expected = TEXT[i];
189 if (!line.equals(expected)) {
190 ok = false;
191 break;
192 }
193 count++;
194 }
195 } finally {
196 instream.close();
197 }
198 if (ok) {
199 final NFileEntity responseEntity = new NFileEntity(TEST_FILE,
200 ContentType.create("text/plian"));
201 if (this.forceChunking) {
202 responseEntity.setChunked(true);
203 }
204 response.setEntity(responseEntity);
205 } else {
206 response.setEntity(new NStringEntity("Invalid content"));
207 }
208 }
209 }
210
211 @Test
212 public void testTwoWayZeroCopy() throws Exception {
213 this.serverBootstrap.registerHandler("*", new BasicAsyncRequestHandler(new TestHandler(false)));
214 final HttpHost target = start();
215
216 final File tmpdir = FileUtils.getTempDirectory();
217 this.tmpfile = new File(tmpdir, "dst.test");
218 final TestZeroCopyPost httppost = new TestZeroCopyPost(target.toURI() + "/bounce", false);
219 final TestZeroCopyConsumer consumer = new TestZeroCopyConsumer(this.tmpfile);
220 final Future<Integer> future = this.httpclient.execute(httppost, consumer, null);
221 final Integer status = future.get();
222 Assert.assertNotNull(status);
223 Assert.assertEquals(HttpStatus.SC_OK, status.intValue());
224 final InputStream instream = new FileInputStream(this.tmpfile);
225 try {
226 final LineIterator it = IOUtils.lineIterator(instream, ASCII.name());
227 int count = 0;
228 while (it.hasNext()) {
229 final String line = it.next();
230 final int i = count % TEXT.length;
231 final String expected = TEXT[i];
232 Assert.assertEquals(expected, line);
233 count++;
234 }
235 } finally {
236 instream.close();
237 }
238 }
239
240 @Test
241 public void testZeroCopyFallback() throws Exception {
242 this.serverBootstrap.registerHandler("*", new BasicAsyncRequestHandler(new TestHandler(true)));
243 final HttpHost target = start();
244 final File tmpdir = FileUtils.getTempDirectory();
245 this.tmpfile = new File(tmpdir, "dst.test");
246 final TestZeroCopyPost httppost = new TestZeroCopyPost(target.toURI() + "/bounce", true);
247 final TestZeroCopyConsumer consumer = new TestZeroCopyConsumer(this.tmpfile);
248 final Future<Integer> future = this.httpclient.execute(httppost, consumer, null);
249 final Integer status = future.get();
250 Assert.assertNotNull(status);
251 Assert.assertEquals(HttpStatus.SC_OK, status.intValue());
252 final InputStream instream = new FileInputStream(this.tmpfile);
253 try {
254 final LineIterator it = IOUtils.lineIterator(instream, ASCII.name());
255 int count = 0;
256 while (it.hasNext()) {
257 final String line = it.next();
258 final int i = count % TEXT.length;
259 final String expected = TEXT[i];
260 Assert.assertEquals(expected, line);
261 count++;
262 }
263 } finally {
264 instream.close();
265 }
266 }
267
268 }
0 # ====================================================================
1 # Licensed to the Apache Software Foundation (ASF) under one
2 # or more contributor license agreements. See the NOTICE file
3 # distributed with this work for additional information
4 # regarding copyright ownership. The ASF licenses this file
5 # to you under the Apache License, Version 2.0 (the
6 # "License"); you may not use this file except in compliance
7 # with the License. You may obtain a copy of the License at
8 #
9 # http://www.apache.org/licenses/LICENSE-2.0
10 #
11 # Unless required by applicable law or agreed to in writing,
12 # software distributed under the License is distributed on an
13 # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14 # KIND, either express or implied. See the License for the
15 # specific language governing permissions and limitations
16 # under the License.
17 # ====================================================================
18 #
19 # This software consists of voluntary contributions made by many
20 # individuals on behalf of the Apache Software Foundation. For more
21 # information on the Apache Software Foundation, please see
22 # <http://www.apache.org/>.
23
24 # Disable logging for unit tests
25 org.apache.commons.logging.Log=org.apache.commons.logging.impl.NoOpLog
0 <?xml version="1.0" encoding="UTF-8"?>
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 --><project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
26 <modelVersion>4.0.0</modelVersion>
27 <parent>
28 <groupId>org.apache.httpcomponents</groupId>
29 <artifactId>httpcomponents-asyncclient</artifactId>
30 <version>4.1</version>
31 </parent>
32 <artifactId>httpasyncclient-cache</artifactId>
33 <name>Apache HttpAsyncClient Cache</name>
34 <description>
35 Apache HttpComponents AsyncClient Cache
36 </description>
37 <url>http://hc.apache.org/httpcomponents-asyncclient</url>
38 <packaging>jar</packaging>
39
40 <dependencies>
41 <dependency>
42 <groupId>org.apache.httpcomponents</groupId>
43 <artifactId>httpasyncclient</artifactId>
44 <version>${project.version}</version>
45 <scope>compile</scope>
46 </dependency>
47 <dependency>
48 <groupId>org.apache.httpcomponents</groupId>
49 <artifactId>httpclient-cache</artifactId>
50 <scope>compile</scope>
51 </dependency>
52 <dependency>
53 <groupId>org.apache.httpcomponents</groupId>
54 <artifactId>httpclient-cache</artifactId>
55 <type>test-jar</type>
56 <scope>test</scope>
57 </dependency>
58 <dependency>
59 <groupId>junit</groupId>
60 <artifactId>junit</artifactId>
61 <scope>test</scope>
62 </dependency>
63 <dependency>
64 <groupId>org.mockito</groupId>
65 <artifactId>mockito-core</artifactId>
66 <scope>test</scope>
67 </dependency>
68 <dependency>
69 <groupId>org.easymock</groupId>
70 <artifactId>easymock</artifactId>
71 <scope>test</scope>
72 </dependency>
73 <dependency>
74 <groupId>org.easymock</groupId>
75 <artifactId>easymockclassextension</artifactId>
76 <scope>test</scope>
77 </dependency>
78 </dependencies>
79
80 <build>
81 <resources>
82 <resource>
83 <directory>src/main/resources</directory>
84 <filtering>true</filtering>
85 <includes>
86 <include>**/*.properties</include>
87 </includes>
88 </resource>
89 </resources>
90 </build>
91
92 <reporting>
93 <plugins>
94
95 <plugin>
96 <artifactId>maven-javadoc-plugin</artifactId>
97 <version>${hc.javadoc.version}</version>
98 <configuration>
99 <source>${maven.compiler.source}</source>
100 <links>
101 <link>http://download.oracle.com/javase/1.5.0/docs/api/</link>
102 <link>http://hc.apache.org/httpcomponents-core-ga/httpcore/apidocs/</link>
103 <link>http://hc.apache.org/httpcomponents-client-ga/httpclient/apidocs/</link>
104 </links>
105 </configuration>
106 <reportSets>
107 <reportSet>
108 <reports>
109 <report>javadoc</report>
110 </reports>
111 </reportSet>
112 </reportSets>
113 </plugin>
114
115 <plugin>
116 <artifactId>maven-project-info-reports-plugin</artifactId>
117 <version>${hc.project-info.version}</version>
118 <inherited>false</inherited>
119 <reportSets>
120 <reportSet>
121 <reports>
122 <report>dependencies</report>
123 <report>dependency-info</report>
124 <report>summary</report>
125 </reports>
126 </reportSet>
127 </reportSets>
128 </plugin>
129
130 <plugin>
131 <artifactId>maven-jxr-plugin</artifactId>
132 <version>${hc.jxr.version}</version>
133 </plugin>
134
135 <plugin>
136 <artifactId>maven-surefire-report-plugin</artifactId>
137 <version>${hc.surefire-report.version}</version>
138 </plugin>
139
140 </plugins>
141 </reporting>
142
143 </project>
0 /*
1 * ====================================================================
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 * ====================================================================
19 *
20 * This software consists of voluntary contributions made by many
21 * individuals on behalf of the Apache Software Foundation. For more
22 * information on the Apache Software Foundation, please see
23 * <http://www.apache.org/>.
24 *
25 */
26 package org.apache.http.impl.client.cache;
27
28 import java.util.concurrent.ExecutionException;
29
30 import org.apache.commons.logging.Log;
31 import org.apache.commons.logging.LogFactory;
32 import org.apache.http.HttpHost;
33 import org.apache.http.HttpResponse;
34 import org.apache.http.ProtocolException;
35 import org.apache.http.client.cache.HttpCacheContext;
36 import org.apache.http.client.cache.HttpCacheEntry;
37 import org.apache.http.client.methods.HttpRequestWrapper;
38 import org.apache.http.concurrent.BasicFuture;
39 import org.apache.http.concurrent.FutureCallback;
40
41 /**
42 * Class used to represent an asynchronous revalidation event, such as with
43 * "stale-while-revalidate"
44 */
45 class AsynchronousAsyncValidationRequest implements Runnable {
46 private final AsynchronousAsyncValidator parent;
47 private final CachingHttpAsyncClient cachingAsyncClient;
48 private final HttpHost target;
49 private final HttpRequestWrapper request;
50 private final HttpCacheContext clientContext;
51 private final HttpCacheEntry cacheEntry;
52 private final String identifier;
53
54 private final Log log = LogFactory.getLog(getClass());
55
56 /**
57 * Used internally by {@link AsynchronousValidator} to schedule a
58 * revalidation.
59 */
60 AsynchronousAsyncValidationRequest(final AsynchronousAsyncValidator parent,
61 final CachingHttpAsyncClient cachingClient, final HttpHost target, final HttpRequestWrapper request,
62 final HttpCacheContext clientContext, final HttpCacheEntry cacheEntry, final String identifier) {
63 this.parent = parent;
64 this.cachingAsyncClient = cachingClient;
65 this.target = target;
66 this.request = request;
67 this.clientContext = clientContext;
68 this.cacheEntry = cacheEntry;
69 this.identifier = identifier;
70 }
71
72 @Override
73 public void run() {
74 try {
75 final FutureCallback<HttpResponse> callback = new FutureCallback<HttpResponse>() {
76
77 @Override
78 public void cancelled() {
79 }
80
81 @Override
82 public void completed(final HttpResponse httpResponse) {
83 }
84
85 @Override
86 public void failed(final Exception e) {
87 log.debug("Asynchronous revalidation failed", e);
88 }
89 };
90 final BasicFuture<HttpResponse> future = new BasicFuture<HttpResponse>(callback);
91 this.cachingAsyncClient.revalidateCacheEntry(future, this.target, this.request,
92 this.clientContext, this.cacheEntry);
93 future.get();
94 } catch (final ProtocolException pe) {
95 this.log.error("ProtocolException thrown during asynchronous revalidation", pe);
96 } catch (ExecutionException e) {
97 this.log.error("Exception thrown during asynchronous revalidation", e.getCause());
98 } catch (InterruptedException e) {
99 Thread.currentThread().interrupt();
100 } finally {
101 this.parent.markComplete(this.identifier);
102 }
103 }
104
105 String getIdentifier() {
106 return this.identifier;
107 }
108
109 }
0 /*
1 * ====================================================================
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 * ====================================================================
19 *
20 * This software consists of voluntary contributions made by many
21 * individuals on behalf of the Apache Software Foundation. For more
22 * information on the Apache Software Foundation, please see
23 * <http://www.apache.org/>.
24 *
25 */
26 package org.apache.http.impl.client.cache;
27
28 import java.util.Collections;
29 import java.util.HashSet;
30 import java.util.Set;
31 import java.util.concurrent.ArrayBlockingQueue;
32 import java.util.concurrent.ExecutorService;
33 import java.util.concurrent.RejectedExecutionException;
34 import java.util.concurrent.ThreadPoolExecutor;
35 import java.util.concurrent.TimeUnit;
36
37 import org.apache.commons.logging.Log;
38 import org.apache.commons.logging.LogFactory;
39 import org.apache.http.HttpHost;
40 import org.apache.http.client.cache.HttpCacheContext;
41 import org.apache.http.client.cache.HttpCacheEntry;
42 import org.apache.http.client.methods.HttpRequestWrapper;
43
44 /**
45 * Class used for asynchronous revalidations to be used when the "stale-
46 * while-revalidate" directive is present
47 */
48 class AsynchronousAsyncValidator {
49 private final CachingHttpAsyncClient cachingAsyncClient;
50 private final ExecutorService executor;
51 private final Set<String> queued;
52 private final CacheKeyGenerator cacheKeyGenerator;
53
54 private final Log log = LogFactory.getLog(getClass());
55
56 /**
57 * Create AsynchronousValidator which will make revalidation requests using
58 * the supplied {@link CachingHttpAsyncClient}, and a {@link ThreadPoolExecutor}
59 * generated according to the thread pool settings provided in the given
60 * {@link CacheConfig}.
61 *
62 * @param cachingClient
63 * used to execute asynchronous requests
64 * @param config
65 * specifies thread pool settings. See
66 * {@link CacheConfig#getAsynchronousWorkersMax()},
67 * {@link CacheConfig#getAsynchronousWorkersCore()},
68 * {@link CacheConfig#getAsynchronousWorkerIdleLifetimeSecs()},
69 * and {@link CacheConfig#getRevalidationQueueSize()}.
70 */
71 public AsynchronousAsyncValidator(final CachingHttpAsyncClient cachingClient, final CacheConfig config) {
72 this(cachingClient, new ThreadPoolExecutor(config.getAsynchronousWorkersCore(),
73 config.getAsynchronousWorkersMax(), config.getAsynchronousWorkerIdleLifetimeSecs(),
74 TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(
75 config.getRevalidationQueueSize())));
76 }
77
78 /**
79 * Create AsynchronousValidator which will make revalidation requests using
80 * the supplied {@link CachingHttpAsyncClient} and {@link ExecutorService}.
81 *
82 * @param cachingClient
83 * used to execute asynchronous requests
84 * @param executor
85 * used to manage a thread pool of revalidation workers
86 */
87 AsynchronousAsyncValidator(final CachingHttpAsyncClient cachingClient, final ExecutorService executor) {
88 this.cachingAsyncClient = cachingClient;
89 this.executor = executor;
90 this.queued = new HashSet<String>();
91 this.cacheKeyGenerator = new CacheKeyGenerator();
92 }
93
94 /**
95 * Schedules an asynchronous revalidation
96 */
97 public synchronized void revalidateCacheEntry(final HttpHost target, final HttpRequestWrapper request,
98 final HttpCacheContext clientContext, final HttpCacheEntry entry) {
99 // getVariantURI will fall back on getURI if no variants exist
100 final String uri = this.cacheKeyGenerator.getVariantURI(target, request, entry);
101
102 if (!this.queued.contains(uri)) {
103 final AsynchronousAsyncValidationRequest asyncRevalidationRequest = new AsynchronousAsyncValidationRequest(
104 this, this.cachingAsyncClient, target, request, clientContext, entry, uri);
105
106 try {
107 this.executor.execute(asyncRevalidationRequest);
108 this.queued.add(uri);
109 } catch (final RejectedExecutionException ree) {
110 this.log.debug("Revalidation for [" + uri + "] not scheduled: " + ree);
111 }
112 }
113 }
114
115 /**
116 * Removes an identifier from the internal list of revalidation jobs in
117 * progress. This is meant to be called by
118 * {@link AsynchronousValidationRequest#run()} once the revalidation is
119 * complete, using the identifier passed in during constructions.
120 */
121 synchronized void markComplete(final String identifier) {
122 this.queued.remove(identifier);
123 }
124
125 Set<String> getScheduledIdentifiers() {
126 return Collections.unmodifiableSet(this.queued);
127 }
128
129 ExecutorService getExecutor() {
130 return this.executor;
131 }
132
133 }
0 /*
1 * ====================================================================
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 * ====================================================================
19 *
20 * This software consists of voluntary contributions made by many
21 * individuals on behalf of the Apache Software Foundation. For more
22 * information on the Apache Software Foundation, please see
23 * <http://www.apache.org/>.
24 *
25 */
26 package org.apache.http.impl.client.cache;
27
28 import java.io.IOException;
29 import java.net.URI;
30 import java.util.Date;
31 import java.util.HashMap;
32 import java.util.List;
33 import java.util.Map;
34 import java.util.concurrent.Future;
35 import java.util.concurrent.atomic.AtomicLong;
36
37 import org.apache.commons.logging.Log;
38 import org.apache.commons.logging.LogFactory;
39 import org.apache.http.Header;
40 import org.apache.http.HeaderElement;
41 import org.apache.http.HttpHost;
42 import org.apache.http.HttpMessage;
43 import org.apache.http.HttpRequest;
44 import org.apache.http.HttpResponse;
45 import org.apache.http.HttpStatus;
46 import org.apache.http.HttpVersion;
47 import org.apache.http.ProtocolException;
48 import org.apache.http.ProtocolVersion;
49 import org.apache.http.RequestLine;
50 import org.apache.http.annotation.ThreadSafe;
51 import org.apache.http.client.ClientProtocolException;
52 import org.apache.http.client.cache.CacheResponseStatus;
53 import org.apache.http.client.cache.HeaderConstants;
54 import org.apache.http.client.cache.HttpCacheContext;
55 import org.apache.http.client.cache.HttpCacheEntry;
56 import org.apache.http.client.cache.HttpCacheStorage;
57 import org.apache.http.client.cache.ResourceFactory;
58 import org.apache.http.client.methods.CloseableHttpResponse;
59 import org.apache.http.client.methods.HttpRequestWrapper;
60 import org.apache.http.client.methods.HttpUriRequest;
61 import org.apache.http.client.protocol.HttpClientContext;
62 import org.apache.http.client.utils.DateUtils;
63 import org.apache.http.concurrent.BasicFuture;
64 import org.apache.http.concurrent.FutureCallback;
65 import org.apache.http.conn.routing.HttpRoute;
66 import org.apache.http.impl.nio.client.HttpAsyncClients;
67 import org.apache.http.message.BasicHttpResponse;
68 import org.apache.http.nio.client.HttpAsyncClient;
69 import org.apache.http.nio.protocol.HttpAsyncRequestProducer;
70 import org.apache.http.nio.protocol.HttpAsyncResponseConsumer;
71 import org.apache.http.nio.reactor.IOReactorException;
72 import org.apache.http.protocol.HTTP;
73 import org.apache.http.protocol.HttpContext;
74 import org.apache.http.util.Args;
75 import org.apache.http.util.EntityUtils;
76 import org.apache.http.util.VersionInfo;
77
78 @ThreadSafe // So long as the responseCache implementation is threadsafe
79 public class CachingHttpAsyncClient implements HttpAsyncClient {
80
81 private final static boolean SUPPORTS_RANGE_AND_CONTENT_RANGE_HEADERS = false;
82
83 private final AtomicLong cacheHits = new AtomicLong();
84 private final AtomicLong cacheMisses = new AtomicLong();
85 private final AtomicLong cacheUpdates = new AtomicLong();
86
87 private final Map<ProtocolVersion, String> viaHeaders = new HashMap<ProtocolVersion, String>(4);
88
89 private final HttpAsyncClient backend;
90 private final HttpCache responseCache;
91 private final CacheValidityPolicy validityPolicy;
92 private final ResponseCachingPolicy responseCachingPolicy;
93 private final CachedHttpResponseGenerator responseGenerator;
94 private final CacheableRequestPolicy cacheableRequestPolicy;
95 private final CachedResponseSuitabilityChecker suitabilityChecker;
96
97 private final ConditionalRequestBuilder conditionalRequestBuilder;
98
99 private final long maxObjectSizeBytes;
100 private final boolean sharedCache;
101
102 private final ResponseProtocolCompliance responseCompliance;
103 private final RequestProtocolCompliance requestCompliance;
104
105 private final AsynchronousAsyncValidator asynchAsyncRevalidator;
106
107 private final Log log = LogFactory.getLog(getClass());
108
109 CachingHttpAsyncClient(
110 final HttpAsyncClient client,
111 final HttpCache cache,
112 final CacheConfig config) {
113 super();
114 Args.notNull(client, "HttpClient");
115 Args.notNull(cache, "HttpCache");
116 Args.notNull(config, "CacheConfig");
117 this.maxObjectSizeBytes = config.getMaxObjectSize();
118 this.sharedCache = config.isSharedCache();
119 this.backend = client;
120 this.responseCache = cache;
121 this.validityPolicy = new CacheValidityPolicy();
122 this.responseCachingPolicy = new ResponseCachingPolicy(this.maxObjectSizeBytes, this.sharedCache, false, config.is303CachingEnabled());
123 this.responseGenerator = new CachedHttpResponseGenerator(this.validityPolicy);
124 this.cacheableRequestPolicy = new CacheableRequestPolicy();
125 this.suitabilityChecker = new CachedResponseSuitabilityChecker(this.validityPolicy, config);
126 this.conditionalRequestBuilder = new ConditionalRequestBuilder();
127
128 this.responseCompliance = new ResponseProtocolCompliance();
129 this.requestCompliance = new RequestProtocolCompliance(config.isWeakETagOnPutDeleteAllowed());
130
131 this.asynchAsyncRevalidator = makeAsynchronousValidator(config);
132 }
133
134 public CachingHttpAsyncClient() throws IOReactorException {
135 this(HttpAsyncClients.createDefault(),
136 new BasicHttpCache(),
137 CacheConfig.DEFAULT);
138 }
139
140 public CachingHttpAsyncClient(final CacheConfig config) throws IOReactorException {
141 this(HttpAsyncClients.createDefault(),
142 new BasicHttpCache(config),
143 config);
144 }
145
146 public CachingHttpAsyncClient(final HttpAsyncClient client) {
147 this(client,
148 new BasicHttpCache(),
149 CacheConfig.DEFAULT);
150 }
151
152 public CachingHttpAsyncClient(final HttpAsyncClient client, final CacheConfig config) {
153 this(client,
154 new BasicHttpCache(config),
155 config);
156 }
157
158 public CachingHttpAsyncClient(
159 final HttpAsyncClient client,
160 final ResourceFactory resourceFactory,
161 final HttpCacheStorage storage,
162 final CacheConfig config) {
163 this(client,
164 new BasicHttpCache(resourceFactory, storage, config),
165 config);
166 }
167
168 public CachingHttpAsyncClient(
169 final HttpAsyncClient client,
170 final HttpCacheStorage storage,
171 final CacheConfig config) {
172 this(client,
173 new BasicHttpCache(new HeapResourceFactory(), storage, config),
174 config);
175 }
176
177 CachingHttpAsyncClient(
178 final HttpAsyncClient backend,
179 final CacheValidityPolicy validityPolicy,
180 final ResponseCachingPolicy responseCachingPolicy,
181 final HttpCache responseCache,
182 final CachedHttpResponseGenerator responseGenerator,
183 final CacheableRequestPolicy cacheableRequestPolicy,
184 final CachedResponseSuitabilityChecker suitabilityChecker,
185 final ConditionalRequestBuilder conditionalRequestBuilder,
186 final ResponseProtocolCompliance responseCompliance,
187 final RequestProtocolCompliance requestCompliance) {
188 final CacheConfig config = CacheConfig.DEFAULT;
189 this.maxObjectSizeBytes = config.getMaxObjectSize();
190 this.sharedCache = config.isSharedCache();
191 this.backend = backend;
192 this.validityPolicy = validityPolicy;
193 this.responseCachingPolicy = responseCachingPolicy;
194 this.responseCache = responseCache;
195 this.responseGenerator = responseGenerator;
196 this.cacheableRequestPolicy = cacheableRequestPolicy;
197 this.suitabilityChecker = suitabilityChecker;
198 this.conditionalRequestBuilder = conditionalRequestBuilder;
199 this.responseCompliance = responseCompliance;
200 this.requestCompliance = requestCompliance;
201 this.asynchAsyncRevalidator = makeAsynchronousValidator(config);
202 }
203
204 private AsynchronousAsyncValidator makeAsynchronousValidator(
205 final CacheConfig config) {
206 if (config.getAsynchronousWorkersMax() > 0) {
207 return new AsynchronousAsyncValidator(this, config);
208 }
209 return null;
210 }
211
212 /**
213 * Reports the number of times that the cache successfully responded
214 * to an {@link HttpRequest} without contacting the origin server.
215 * @return the number of cache hits
216 */
217 public long getCacheHits() {
218 return this.cacheHits.get();
219 }
220
221 /**
222 * Reports the number of times that the cache contacted the origin
223 * server because it had no appropriate response cached.
224 * @return the number of cache misses
225 */
226 public long getCacheMisses() {
227 return this.cacheMisses.get();
228 }
229
230 /**
231 * Reports the number of times that the cache was able to satisfy
232 * a response by revalidating an existing but stale cache entry.
233 * @return the number of cache revalidations
234 */
235 public long getCacheUpdates() {
236 return this.cacheUpdates.get();
237 }
238
239 @Override
240 public Future<HttpResponse> execute(
241 final HttpHost target,
242 final HttpRequest request,
243 final FutureCallback<HttpResponse> callback) {
244 return execute(target, request, null, callback);
245 }
246
247 @Override
248 public <T> Future<T> execute(
249 final HttpAsyncRequestProducer requestProducer,
250 final HttpAsyncResponseConsumer<T> responseConsumer,
251 final FutureCallback<T> callback) {
252 return execute(requestProducer, responseConsumer, null, callback);
253 }
254
255 @Override
256 public <T> Future<T> execute(
257 final HttpAsyncRequestProducer requestProducer,
258 final HttpAsyncResponseConsumer<T> responseConsumer,
259 final HttpContext context,
260 final FutureCallback<T> callback) {
261 this.log.warn("CachingHttpAsyncClient does not support caching for streaming HTTP exchanges");
262 return this.backend.execute(requestProducer, responseConsumer, context, callback);
263 }
264
265 @Override
266 public Future<HttpResponse> execute(
267 final HttpUriRequest request,
268 final FutureCallback<HttpResponse> callback) {
269 return execute(request, null, callback);
270 }
271
272 @Override
273 public Future<HttpResponse> execute(
274 final HttpUriRequest request,
275 final HttpContext context,
276 final FutureCallback<HttpResponse> callback) {
277 final URI uri = request.getURI();
278 final HttpHost httpHost = new HttpHost(uri.getHost(), uri.getPort(), uri.getScheme());
279 return execute(httpHost, request, context, callback);
280 }
281
282 @Override
283 public Future<HttpResponse> execute(
284 final HttpHost target,
285 final HttpRequest originalRequest,
286 final HttpContext context,
287 final FutureCallback<HttpResponse> futureCallback) {
288 final BasicFuture<HttpResponse> future = new BasicFuture<HttpResponse>(futureCallback);
289 final HttpRequestWrapper request = HttpRequestWrapper.wrap(originalRequest);
290 final HttpCacheContext clientContext = HttpCacheContext.adapt(context);
291 // default response context
292 setResponseStatus(clientContext, CacheResponseStatus.CACHE_MISS);
293
294 final String via = generateViaHeader(request);
295
296 if (clientRequestsOurOptions(request)) {
297 setResponseStatus(clientContext, CacheResponseStatus.CACHE_MODULE_RESPONSE);
298 future.completed(new OptionsHttp11Response());
299 return future;
300 }
301
302 final HttpResponse fatalErrorResponse = getFatallyNoncompliantResponse(
303 request, clientContext);
304 if (fatalErrorResponse != null) {
305 future.completed(fatalErrorResponse);
306 return future;
307 }
308
309 try {
310 this.requestCompliance.makeRequestCompliant(request);
311 } catch (final ClientProtocolException e) {
312 future.failed(e);
313 return future;
314 }
315 request.addHeader(HeaderConstants.VIA,via);
316
317 flushEntriesInvalidatedByRequest(target, request);
318
319 if (!this.cacheableRequestPolicy.isServableFromCache(request)) {
320 log.debug("Request is not servable from cache");
321 callBackend(future, target, request, clientContext);
322 return future;
323 }
324
325 final HttpCacheEntry entry = satisfyFromCache(target, request);
326 if (entry == null) {
327 log.debug("Cache miss");
328 handleCacheMiss(future, target, request, clientContext);
329 } else {
330 try {
331 handleCacheHit(future, target, request, clientContext, entry);
332 } catch (final IOException e) {
333 future.failed(e);
334 }
335 }
336 return future;
337 }
338
339 private void handleCacheHit(
340 final BasicFuture<HttpResponse> future,
341 final HttpHost target,
342 final HttpRequestWrapper request,
343 final HttpCacheContext clientContext,
344 final HttpCacheEntry entry) throws IOException {
345 recordCacheHit(target, request);
346 final HttpResponse out;
347 final Date now = getCurrentDate();
348 if (this.suitabilityChecker.canCachedResponseBeUsed(target, request, entry, now)) {
349 log.debug("Cache hit");
350 out = generateCachedResponse(request, clientContext, entry, now);
351 } else if (!mayCallBackend(request)) {
352 log.debug("Cache entry not suitable but only-if-cached requested");
353 out = generateGatewayTimeout(clientContext);
354 } else if (validityPolicy.isRevalidatable(entry)
355 && !(entry.getStatusCode() == HttpStatus.SC_NOT_MODIFIED
356 && !suitabilityChecker.isConditional(request))) {
357 log.debug("Revalidating cache entry");
358 revalidateCacheEntry(future, target, request, clientContext, entry, now);
359 return;
360 } else {
361 log.debug("Cache entry not usable; calling backend");
362 callBackend(future, target, request, clientContext);
363 return;
364 }
365 clientContext.setAttribute(HttpClientContext.HTTP_ROUTE, new HttpRoute(target));
366 clientContext.setAttribute(HttpClientContext.HTTP_TARGET_HOST, target);
367 clientContext.setAttribute(HttpClientContext.HTTP_REQUEST, request);
368 clientContext.setAttribute(HttpClientContext.HTTP_RESPONSE, out);
369 clientContext.setAttribute(HttpClientContext.HTTP_REQ_SENT, Boolean.TRUE);
370 future.completed(out);
371 }
372
373 private void revalidateCacheEntry(
374 final BasicFuture<HttpResponse> future,
375 final HttpHost target,
376 final HttpRequestWrapper request,
377 final HttpCacheContext clientContext,
378 final HttpCacheEntry entry,
379 final Date now) throws ClientProtocolException {
380
381 try {
382 if (this.asynchAsyncRevalidator != null
383 && !staleResponseNotAllowed(request, entry, now)
384 && this.validityPolicy.mayReturnStaleWhileRevalidating(entry, now)) {
385 this.log.debug("Serving stale with asynchronous revalidation");
386 final HttpResponse resp = this.responseGenerator.generateResponse(request, entry);
387 resp.addHeader(HeaderConstants.WARNING, "110 localhost \"Response is stale\"");
388
389 this.asynchAsyncRevalidator.revalidateCacheEntry(target, request, clientContext, entry);
390
391 future.completed(resp);
392 return;
393 }
394
395 final ChainedFutureCallback<HttpResponse> chainedFutureCallback = new ChainedFutureCallback<HttpResponse>(future) {
396
397 @Override
398 public void failed(final Exception ex) {
399 if(ex instanceof IOException) {
400 super.completed(handleRevalidationFailure(request, clientContext, entry, now));
401 } else {
402 super.failed(ex);
403 }
404 }
405
406 };
407
408 final BasicFuture<HttpResponse> compositeFuture = new BasicFuture<HttpResponse>(chainedFutureCallback);
409 revalidateCacheEntry(compositeFuture, target, request, clientContext, entry);
410 } catch (final ProtocolException e) {
411 throw new ClientProtocolException(e);
412 }
413 }
414
415 private void handleCacheMiss(
416 final BasicFuture<HttpResponse> future,
417 final HttpHost target,
418 final HttpRequestWrapper request,
419 final HttpCacheContext clientContext) {
420 recordCacheMiss(target, request);
421
422 if (!mayCallBackend(request)) {
423 future.completed(new BasicHttpResponse(HttpVersion.HTTP_1_1, HttpStatus.SC_GATEWAY_TIMEOUT, "Gateway Timeout"));
424 return;
425 }
426
427 final Map<String, Variant> variants = getExistingCacheVariants(target, request);
428 if (variants != null && variants.size() > 0) {
429 negotiateResponseFromVariants(future, target, request, clientContext, variants);
430 return;
431 }
432
433 callBackend(future, target, request, clientContext);
434 }
435
436 private HttpCacheEntry satisfyFromCache(
437 final HttpHost target,
438 final HttpRequest request) {
439 HttpCacheEntry entry = null;
440 try {
441 entry = this.responseCache.getCacheEntry(target, request);
442 } catch (final IOException ioe) {
443 this.log.warn("Unable to retrieve entries from cache", ioe);
444 }
445 return entry;
446 }
447
448 private HttpResponse getFatallyNoncompliantResponse(
449 final HttpRequest request,
450 final HttpCacheContext clientContext) {
451 HttpResponse fatalErrorResponse = null;
452 final List<RequestProtocolError> fatalError = this.requestCompliance.requestIsFatallyNonCompliant(request);
453
454 for (final RequestProtocolError error : fatalError) {
455 setResponseStatus(clientContext, CacheResponseStatus.CACHE_MODULE_RESPONSE);
456 fatalErrorResponse = this.requestCompliance.getErrorForRequest(error);
457 }
458 return fatalErrorResponse;
459 }
460
461 private Map<String, Variant> getExistingCacheVariants(
462 final HttpHost target,
463 final HttpRequest request) {
464 Map<String,Variant> variants = null;
465 try {
466 variants = this.responseCache.getVariantCacheEntriesWithEtags(target, request);
467 } catch (final IOException ioe) {
468 this.log.warn("Unable to retrieve variant entries from cache", ioe);
469 }
470 return variants;
471 }
472
473 private void recordCacheMiss(final HttpHost target, final HttpRequest request) {
474 this.cacheMisses.getAndIncrement();
475 if (this.log.isDebugEnabled()) {
476 final RequestLine rl = request.getRequestLine();
477 this.log.debug("Cache miss [host: " + target + "; uri: " + rl.getUri() + "]");
478 }
479 }
480
481 private void recordCacheHit(final HttpHost target, final HttpRequest request) {
482 this.cacheHits.getAndIncrement();
483 if (this.log.isDebugEnabled()) {
484 final RequestLine rl = request.getRequestLine();
485 this.log.debug("Cache hit [host: " + target + "; uri: " + rl.getUri() + "]");
486 }
487 }
488
489 private void recordCacheUpdate(final HttpCacheContext clientContext) {
490 this.cacheUpdates.getAndIncrement();
491 setResponseStatus(clientContext, CacheResponseStatus.VALIDATED);
492 }
493
494 private void flushEntriesInvalidatedByRequest(final HttpHost target,
495 final HttpRequest request) {
496 try {
497 this.responseCache.flushInvalidatedCacheEntriesFor(target, request);
498 } catch (final IOException ioe) {
499 this.log.warn("Unable to flush invalidated entries from cache", ioe);
500 }
501 }
502
503 private HttpResponse generateCachedResponse(
504 final HttpRequestWrapper request,
505 final HttpCacheContext clientContext,
506 final HttpCacheEntry entry,
507 final Date now) {
508 final HttpResponse cachedResponse;
509 if (request.containsHeader(HeaderConstants.IF_NONE_MATCH)
510 || request.containsHeader(HeaderConstants.IF_MODIFIED_SINCE)) {
511 cachedResponse = this.responseGenerator.generateNotModifiedResponse(entry);
512 } else {
513 cachedResponse = this.responseGenerator.generateResponse(request, entry);
514 }
515 setResponseStatus(clientContext, CacheResponseStatus.CACHE_HIT);
516 if (this.validityPolicy.getStalenessSecs(entry, now) > 0L) {
517 cachedResponse.addHeader("Warning","110 localhost \"Response is stale\"");
518 }
519 return cachedResponse;
520 }
521
522 private HttpResponse handleRevalidationFailure(
523 final HttpRequestWrapper request,
524 final HttpCacheContext clientContext,
525 final HttpCacheEntry entry,
526 final Date now) {
527 if (staleResponseNotAllowed(request, entry, now)) {
528 return generateGatewayTimeout(clientContext);
529 }
530 return unvalidatedCacheHit(clientContext, request, entry);
531 }
532
533 private HttpResponse generateGatewayTimeout(final HttpCacheContext clientContext) {
534 setResponseStatus(clientContext, CacheResponseStatus.CACHE_MODULE_RESPONSE);
535 return new BasicHttpResponse(HttpVersion.HTTP_1_1,
536 HttpStatus.SC_GATEWAY_TIMEOUT, "Gateway Timeout");
537 }
538
539 private HttpResponse unvalidatedCacheHit(
540 final HttpCacheContext clientContext,
541 final HttpRequestWrapper request,
542 final HttpCacheEntry entry) {
543 final HttpResponse cachedResponse = this.responseGenerator.generateResponse(request, entry);
544 setResponseStatus(clientContext, CacheResponseStatus.CACHE_HIT);
545 cachedResponse.addHeader(HeaderConstants.WARNING, "111 localhost \"Revalidation failed\"");
546 return cachedResponse;
547 }
548
549 private boolean staleResponseNotAllowed(
550 final HttpRequest request,
551 final HttpCacheEntry entry,
552 final Date now) {
553 return this.validityPolicy.mustRevalidate(entry)
554 || (isSharedCache() && this.validityPolicy.proxyRevalidate(entry))
555 || explicitFreshnessRequest(request, entry, now);
556 }
557
558 private boolean mayCallBackend(final HttpRequest request) {
559 for (final Header h: request.getHeaders(HeaderConstants.CACHE_CONTROL)) {
560 for (final HeaderElement elt : h.getElements()) {
561 if ("only-if-cached".equals(elt.getName())) {
562 this.log.debug("Request marked only-if-cached");
563 return false;
564 }
565 }
566 }
567 return true;
568 }
569
570 private boolean explicitFreshnessRequest(
571 final HttpRequest request,
572 final HttpCacheEntry entry,
573 final Date now) {
574 for(final Header h : request.getHeaders(HeaderConstants.CACHE_CONTROL)) {
575 for(final HeaderElement elt : h.getElements()) {
576 if (HeaderConstants.CACHE_CONTROL_MAX_STALE.equals(elt.getName())) {
577 try {
578 final int maxstale = Integer.parseInt(elt.getValue());
579 final long age = this.validityPolicy.getCurrentAgeSecs(entry, now);
580 final long lifetime = this.validityPolicy.getFreshnessLifetimeSecs(entry);
581 if (age - lifetime > maxstale) {
582 return true;
583 }
584 } catch (final NumberFormatException nfe) {
585 return true;
586 }
587 } else if (HeaderConstants.CACHE_CONTROL_MIN_FRESH.equals(elt.getName())
588 || HeaderConstants.CACHE_CONTROL_MAX_AGE.equals(elt.getName())) {
589 return true;
590 }
591 }
592 }
593 return false;
594 }
595
596 private String generateViaHeader(final HttpMessage msg) {
597
598 final ProtocolVersion pv = msg.getProtocolVersion();
599 final String existingEntry = viaHeaders.get(pv);
600 if (existingEntry != null) {
601 return existingEntry;
602 }
603
604 final VersionInfo vi = VersionInfo.loadVersionInfo("org.apache.http.client", getClass().getClassLoader());
605 final String release = (vi != null) ? vi.getRelease() : VersionInfo.UNAVAILABLE;
606
607 final String value;
608 if ("http".equalsIgnoreCase(pv.getProtocol())) {
609 value = String.format("%d.%d localhost (Apache-HttpClient/%s (cache))", pv.getMajor(), pv.getMinor(),
610 release);
611 } else {
612 value = String.format("%s/%d.%d localhost (Apache-HttpClient/%s (cache))", pv.getProtocol(), pv.getMajor(),
613 pv.getMinor(), release);
614 }
615 viaHeaders.put(pv, value);
616
617 return value;
618 }
619
620 private void setResponseStatus(final HttpCacheContext clientContext, final CacheResponseStatus value) {
621 if (clientContext != null) {
622 clientContext.setAttribute(HttpCacheContext.CACHE_RESPONSE_STATUS, value);
623 }
624 }
625
626 /**
627 * Reports whether this {@code CachingHttpClient} implementation
628 * supports byte-range requests as specified by the {@code Range}
629 * and {@code Content-Range} headers.
630 * @return {@code true} if byte-range requests are supported
631 */
632 public boolean supportsRangeAndContentRangeHeaders() {
633 return SUPPORTS_RANGE_AND_CONTENT_RANGE_HEADERS;
634 }
635
636 /**
637 * Reports whether this {@code CachingHttpClient} is configured as
638 * a shared (public) or non-shared (private) cache. See {@link
639 * CacheConfig#setSharedCache(boolean)}.
640 * @return {@code true} if we are behaving as a shared (public)
641 * cache
642 */
643 public boolean isSharedCache() {
644 return this.sharedCache;
645 }
646
647 Date getCurrentDate() {
648 return new Date();
649 }
650
651 boolean clientRequestsOurOptions(final HttpRequest request) {
652 final RequestLine line = request.getRequestLine();
653
654 if (!HeaderConstants.OPTIONS_METHOD.equals(line.getMethod())) {
655 return false;
656 }
657
658 if (!"*".equals(line.getUri())) {
659 return false;
660 }
661 return "0".equals(request.getFirstHeader(HeaderConstants.MAX_FORWARDS).getValue());
662 }
663
664 void callBackend(
665 final BasicFuture<HttpResponse> future,
666 final HttpHost target,
667 final HttpRequestWrapper request,
668 final HttpCacheContext clientContext) {
669 final Date requestDate = getCurrentDate();
670 this.log.trace("Calling the backend");
671
672 final ChainedFutureCallback<HttpResponse> chainedFutureCallback = new ChainedFutureCallback<HttpResponse>(future) {
673
674 @Override
675 public void completed(final HttpResponse httpResponse) {
676 httpResponse.addHeader(HeaderConstants.VIA, generateViaHeader(httpResponse));
677 try {
678 final CloseableHttpResponse backendResponse = handleBackendResponse(
679 target, request, requestDate, getCurrentDate(),
680 Proxies.enhanceResponse(httpResponse));
681 super.completed(backendResponse);
682 } catch (final IOException e) {
683 super.failed(e);
684 }
685
686 }
687
688 };
689 this.backend.execute(target, request, clientContext, chainedFutureCallback);
690 }
691
692 private boolean revalidationResponseIsTooOld(
693 final HttpResponse backendResponse,
694 final HttpCacheEntry cacheEntry) {
695 final Header entryDateHeader = cacheEntry.getFirstHeader(HTTP.DATE_HEADER);
696 final Header responseDateHeader = backendResponse.getFirstHeader(HTTP.DATE_HEADER);
697 if (entryDateHeader != null && responseDateHeader != null) {
698 final Date entryDate = DateUtils.parseDate(entryDateHeader.getValue());
699 final Date respDate = DateUtils.parseDate(responseDateHeader.getValue());
700 if (respDate != null && respDate.before(entryDate)) {
701 return true;
702 }
703 }
704 return false;
705 }
706
707 void negotiateResponseFromVariants(
708 final BasicFuture<HttpResponse> future,
709 final HttpHost target,
710 final HttpRequestWrapper request,
711 final HttpCacheContext clientContext,
712 final Map<String, Variant> variants) {
713 final HttpRequest conditionalRequest = this.conditionalRequestBuilder.buildConditionalRequestFromVariants(request, variants);
714
715 final Date requestDate = getCurrentDate();
716
717 final ChainedFutureCallback<HttpResponse> chainedFutureCallback = new ChainedFutureCallback<HttpResponse>(future) {
718
719 @Override
720 public void completed(final HttpResponse httpResponse) {
721 final Date responseDate = getCurrentDate();
722
723 httpResponse.addHeader(HeaderConstants.VIA, generateViaHeader(httpResponse));
724
725 if (httpResponse.getStatusLine().getStatusCode() != HttpStatus.SC_NOT_MODIFIED) {
726 try {
727 future.completed(handleBackendResponse(
728 target, request, requestDate, responseDate,
729 Proxies.enhanceResponse(httpResponse)));
730 return;
731 } catch (final IOException e) {
732 future.failed(e);
733 return;
734 }
735 }
736
737 final Header resultEtagHeader = httpResponse.getFirstHeader(HeaderConstants.ETAG);
738 if (resultEtagHeader == null) {
739 CachingHttpAsyncClient.this.log.warn("304 response did not contain ETag");
740 callBackend(future, target, request, clientContext);
741 return;
742 }
743
744 final String resultEtag = resultEtagHeader.getValue();
745 final Variant matchingVariant = variants.get(resultEtag);
746 if (matchingVariant == null) {
747 CachingHttpAsyncClient.this.log.debug("304 response did not contain ETag matching one sent in If-None-Match");
748 callBackend(future, target, request, clientContext);
749 }
750
751 final HttpCacheEntry matchedEntry = matchingVariant.getEntry();
752
753 if (revalidationResponseIsTooOld(httpResponse, matchedEntry)) {
754 EntityUtils.consumeQuietly(httpResponse.getEntity());
755 retryRequestUnconditionally(future, target, request, clientContext, matchedEntry);
756 return;
757 }
758
759 recordCacheUpdate(clientContext);
760
761 final HttpCacheEntry responseEntry = getUpdatedVariantEntry(target,
762 conditionalRequest, requestDate, responseDate, httpResponse,
763 matchingVariant, matchedEntry);
764
765 final HttpResponse resp = CachingHttpAsyncClient.this.responseGenerator.generateResponse(request, responseEntry);
766 tryToUpdateVariantMap(target, request, matchingVariant);
767
768 if (shouldSendNotModifiedResponse(request, responseEntry)) {
769 future.completed(CachingHttpAsyncClient.this.responseGenerator.generateNotModifiedResponse(responseEntry));
770 return;
771 }
772
773 future.completed(resp);
774 }
775
776 };
777
778 this.backend.execute(target, conditionalRequest, clientContext, chainedFutureCallback);
779 }
780
781 private void retryRequestUnconditionally(
782 final BasicFuture<HttpResponse> future,
783 final HttpHost target,
784 final HttpRequestWrapper request,
785 final HttpCacheContext clientContext,
786 final HttpCacheEntry matchedEntry) {
787 final HttpRequestWrapper unconditional = this.conditionalRequestBuilder
788 .buildUnconditionalRequest(request, matchedEntry);
789 callBackend(future, target, unconditional, clientContext);
790 }
791
792 private HttpCacheEntry getUpdatedVariantEntry(
793 final HttpHost target,
794 final HttpRequest conditionalRequest,
795 final Date requestDate,
796 final Date responseDate,
797 final HttpResponse backendResponse,
798 final Variant matchingVariant,
799 final HttpCacheEntry matchedEntry) {
800 HttpCacheEntry responseEntry = matchedEntry;
801 try {
802 responseEntry = this.responseCache.updateVariantCacheEntry(target, conditionalRequest,
803 matchedEntry, backendResponse, requestDate, responseDate, matchingVariant.getCacheKey());
804 } catch (final IOException ioe) {
805 this.log.warn("Could not update cache entry", ioe);
806 }
807 return responseEntry;
808 }
809
810 private void tryToUpdateVariantMap(
811 final HttpHost target,
812 final HttpRequest request,
813 final Variant matchingVariant) {
814 try {
815 this.responseCache.reuseVariantEntryFor(target, request, matchingVariant);
816 } catch (final IOException ioe) {
817 this.log.warn("Could not update cache entry to reuse variant", ioe);
818 }
819 }
820
821 private boolean shouldSendNotModifiedResponse(
822 final HttpRequest request,
823 final HttpCacheEntry responseEntry) {
824 return (this.suitabilityChecker.isConditional(request)
825 && this.suitabilityChecker.allConditionalsMatch(request, responseEntry, new Date()));
826 }
827
828 void revalidateCacheEntry(
829 final BasicFuture<HttpResponse> future,
830 final HttpHost target,
831 final HttpRequestWrapper request,
832 final HttpCacheContext clientContext,
833 final HttpCacheEntry cacheEntry) throws ProtocolException {
834
835 final HttpRequestWrapper conditionalRequest = this.conditionalRequestBuilder.buildConditionalRequest(request, cacheEntry);
836 final Date requestDate = getCurrentDate();
837
838 final ChainedFutureCallback<HttpResponse> chainedFutureCallback = new ChainedFutureCallback<HttpResponse>(future) {
839
840 @Override
841 public void completed(final HttpResponse httpResponse) {
842 final Date responseDate = getCurrentDate();
843
844 if (revalidationResponseIsTooOld(httpResponse, cacheEntry)) {
845 final HttpRequest unconditional = CachingHttpAsyncClient.this.conditionalRequestBuilder.buildUnconditionalRequest(request, cacheEntry);
846 final Date innerRequestDate = getCurrentDate();
847
848 final ChainedFutureCallback<HttpResponse> chainedFutureCallback2 = new ChainedFutureCallback<HttpResponse>(future) {
849
850 @Override
851 public void completed(final HttpResponse innerHttpResponse) {
852 final Date innerResponseDate = getCurrentDate();
853 revalidateCacheEntryCompleted(future,
854 target, request, clientContext, cacheEntry,
855 conditionalRequest, innerRequestDate,
856 innerHttpResponse, innerResponseDate);
857 }
858
859 };
860 CachingHttpAsyncClient.this.backend.execute(
861 target, unconditional, clientContext, chainedFutureCallback2);
862 }
863
864 revalidateCacheEntryCompleted(future,
865 target, request, clientContext, cacheEntry,
866 conditionalRequest, requestDate,
867 httpResponse, responseDate);
868 }
869
870 };
871
872 this.backend.execute(target, conditionalRequest, clientContext, chainedFutureCallback);
873 }
874
875 private void revalidateCacheEntryCompleted(
876 final BasicFuture<HttpResponse> future,
877 final HttpHost target,
878 final HttpRequestWrapper request,
879 final HttpCacheContext clientContext,
880 final HttpCacheEntry cacheEntry,
881 final HttpRequestWrapper conditionalRequest,
882 final Date requestDate,
883 final HttpResponse httpResponse,
884 final Date responseDate) {
885
886 httpResponse.addHeader(HeaderConstants.VIA, generateViaHeader(httpResponse));
887
888 final int statusCode = httpResponse.getStatusLine().getStatusCode();
889 if (statusCode == HttpStatus.SC_NOT_MODIFIED || statusCode == HttpStatus.SC_OK) {
890 recordCacheUpdate(clientContext);
891 }
892
893 if (statusCode == HttpStatus.SC_NOT_MODIFIED) {
894 final HttpCacheEntry updatedEntry;
895 try {
896 updatedEntry = CachingHttpAsyncClient.this.responseCache.updateCacheEntry(target, request, cacheEntry,
897 httpResponse, requestDate, responseDate);
898 } catch (final IOException e) {
899 future.failed(e);
900 return;
901 }
902 if (CachingHttpAsyncClient.this.suitabilityChecker.isConditional(request)
903 && CachingHttpAsyncClient.this.suitabilityChecker.allConditionalsMatch(request, updatedEntry, new Date())) {
904 future.completed(CachingHttpAsyncClient.this.responseGenerator.generateNotModifiedResponse(updatedEntry));
905 return;
906 }
907 future.completed(CachingHttpAsyncClient.this.responseGenerator.generateResponse(request, updatedEntry));
908 return;
909 }
910
911 if (staleIfErrorAppliesTo(statusCode)
912 && !staleResponseNotAllowed(request, cacheEntry, getCurrentDate())
913 && CachingHttpAsyncClient.this.validityPolicy.mayReturnStaleIfError(request, cacheEntry, responseDate)) {
914 final HttpResponse cachedResponse = CachingHttpAsyncClient.this.responseGenerator.generateResponse(request, cacheEntry);
915 cachedResponse.addHeader(HeaderConstants.WARNING, "110 localhost \"Response is stale\"");
916 future.completed(cachedResponse);
917 return;
918 }
919
920 try {
921 final CloseableHttpResponse backendResponse = handleBackendResponse(
922 target, conditionalRequest, requestDate, responseDate,
923 Proxies.enhanceResponse(httpResponse));
924 future.completed(backendResponse);
925 } catch (final IOException e) {
926 future.failed(e);
927 }
928 }
929
930 private boolean staleIfErrorAppliesTo(final int statusCode) {
931 return statusCode == HttpStatus.SC_INTERNAL_SERVER_ERROR
932 || statusCode == HttpStatus.SC_BAD_GATEWAY
933 || statusCode == HttpStatus.SC_SERVICE_UNAVAILABLE
934 || statusCode == HttpStatus.SC_GATEWAY_TIMEOUT;
935 }
936
937 CloseableHttpResponse handleBackendResponse(
938 final HttpHost target,
939 final HttpRequestWrapper request,
940 final Date requestDate,
941 final Date responseDate,
942 final CloseableHttpResponse backendResponse) throws IOException {
943
944 this.log.debug("Handling Backend response");
945 this.responseCompliance.ensureProtocolCompliance(request, backendResponse);
946
947 final boolean cacheable = this.responseCachingPolicy.isResponseCacheable(request, backendResponse);
948 this.responseCache.flushInvalidatedCacheEntriesFor(target, request, backendResponse);
949 if (cacheable &&
950 !alreadyHaveNewerCacheEntry(target, request, backendResponse)) {
951 storeRequestIfModifiedSinceFor304Response(request, backendResponse);
952 return this.responseCache.cacheAndReturnResponse(target, request, backendResponse, requestDate,
953 responseDate);
954 }
955 if (!cacheable) {
956 try {
957 this.responseCache.flushCacheEntriesFor(target, request);
958 } catch (final IOException ioe) {
959 this.log.warn("Unable to flush invalid cache entries", ioe);
960 }
961 }
962 return backendResponse;
963 }
964
965 /**
966 * For 304 Not modified responses, adds a "Last-Modified" header with the
967 * value of the "If-Modified-Since" header passed in the request. This
968 * header is required to be able to reuse match the cache entry for
969 * subsequent requests but as defined in http specifications it is not
970 * included in 304 responses by backend servers. This header will not be
971 * included in the resulting response.
972 */
973 private void storeRequestIfModifiedSinceFor304Response(
974 final HttpRequest request,
975 final HttpResponse backendResponse) {
976 if (backendResponse.getStatusLine().getStatusCode() == HttpStatus.SC_NOT_MODIFIED) {
977 final Header h = request.getFirstHeader("If-Modified-Since");
978 if (h != null) {
979 backendResponse.addHeader("Last-Modified", h.getValue());
980 }
981 }
982 }
983
984 private boolean alreadyHaveNewerCacheEntry(
985 final HttpHost target,
986 final HttpRequest request,
987 final HttpResponse backendResponse) {
988 HttpCacheEntry existing = null;
989 try {
990 existing = this.responseCache.getCacheEntry(target, request);
991 } catch (final IOException ioe) {
992 // nop
993 }
994 if (existing == null) {
995 return false;
996 }
997 final Header entryDateHeader = existing.getFirstHeader(HTTP.DATE_HEADER);
998 if (entryDateHeader == null) {
999 return false;
1000 }
1001 final Header responseDateHeader = backendResponse.getFirstHeader(HTTP.DATE_HEADER);
1002 if (responseDateHeader == null) {
1003 return false;
1004 }
1005 final Date entryDate = DateUtils.parseDate(entryDateHeader.getValue());
1006 final Date responseDate = DateUtils.parseDate(responseDateHeader.getValue());
1007 return responseDate != null && responseDate.before(entryDate);
1008 }
1009
1010 }
0 /*
1 * ====================================================================
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 * ====================================================================
19 *
20 * This software consists of voluntary contributions made by many
21 * individuals on behalf of the Apache Software Foundation. For more
22 * information on the Apache Software Foundation, please see
23 * <http://www.apache.org/>.
24 *
25 */
26 package org.apache.http.impl.client.cache;
27
28 import org.apache.http.concurrent.BasicFuture;
29 import org.apache.http.concurrent.FutureCallback;
30
31 class ChainedFutureCallback<T> implements FutureCallback<T> {
32
33 private final BasicFuture<T> wrapped;
34
35 public ChainedFutureCallback(final BasicFuture<T> delegate) {
36 this.wrapped = delegate;
37 }
38
39 @Override
40 public void completed(final T result) {
41 this.wrapped.completed(result);
42 }
43
44 @Override
45 public void failed(final Exception ex) {
46 this.wrapped.failed(ex);
47 }
48
49 @Override
50 public void cancelled() {
51 this.wrapped.cancel();
52 }
53
54 }
0 /*
1 * ====================================================================
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 * ====================================================================
19 *
20 * This software consists of voluntary contributions made by many
21 * individuals on behalf of the Apache Software Foundation. For more
22 * information on the Apache Software Foundation, please see
23 * <http://www.apache.org/>.
24 *
25 */
26
27 /**
28 * HTTP/1.1 client-side caching.
29 */
30 package org.apache.http.impl.client.cache;
0 /*
1 * ====================================================================
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 * ====================================================================
19 *
20 * This software consists of voluntary contributions made by many
21 * individuals on behalf of the Apache Software Foundation. For more
22 * information on the Apache Software Foundation, please see
23 * <http://www.apache.org/>.
24 *
25 */
26 package org.apache.http.impl.client.cache;
27
28 import java.io.IOException;
29 import java.lang.reflect.UndeclaredThrowableException;
30 import java.util.concurrent.ExecutionException;
31 import java.util.concurrent.Future;
32
33 import org.apache.http.HttpException;
34 import org.apache.http.HttpResponse;
35 import org.apache.http.client.methods.CloseableHttpResponse;
36 import org.apache.http.client.methods.HttpExecutionAware;
37 import org.apache.http.client.methods.HttpRequestWrapper;
38 import org.apache.http.client.protocol.HttpClientContext;
39 import org.apache.http.conn.routing.HttpRoute;
40 import org.apache.http.impl.execchain.ClientExecChain;
41
42 public class CachingHttpAsyncClientExecChain implements ClientExecChain {
43
44 private final CachingHttpAsyncClient client;
45
46 public CachingHttpAsyncClientExecChain(final ClientExecChain backend) {
47 this(backend, new BasicHttpCache(), CacheConfig.DEFAULT);
48 }
49
50 public CachingHttpAsyncClientExecChain(
51 final ClientExecChain backend,
52 final HttpCache cache,
53 final CacheConfig config) {
54 this.client = new CachingHttpAsyncClient(
55 new ClientExecChainAsyncClient(backend), cache, config);
56 }
57
58 CachingHttpAsyncClientExecChain(
59 final ClientExecChain backend, final HttpCache responseCache,
60 final CacheValidityPolicy validityPolicy,
61 final ResponseCachingPolicy responseCachingPolicy,
62 final CachedHttpResponseGenerator responseGenerator,
63 final CacheableRequestPolicy cacheableRequestPolicy,
64 final CachedResponseSuitabilityChecker suitabilityChecker,
65 final ConditionalRequestBuilder conditionalRequestBuilder,
66 final ResponseProtocolCompliance responseCompliance,
67 final RequestProtocolCompliance requestCompliance) {
68 this.client = new CachingHttpAsyncClient(
69 new ClientExecChainAsyncClient(backend), validityPolicy,
70 responseCachingPolicy, responseCache, responseGenerator,
71 cacheableRequestPolicy, suitabilityChecker,
72 conditionalRequestBuilder, responseCompliance,
73 requestCompliance);
74 }
75
76 public boolean supportsRangeAndContentRangeHeaders() {
77 return client.supportsRangeAndContentRangeHeaders();
78 }
79
80 public CloseableHttpResponse execute(
81 final HttpRoute route,
82 final HttpRequestWrapper request) throws IOException, HttpException {
83 return execute(route, request, HttpClientContext.create(), null);
84 }
85
86 public CloseableHttpResponse execute(
87 final HttpRoute route,
88 final HttpRequestWrapper request,
89 final HttpClientContext context) throws IOException, HttpException {
90 return execute(route, request, context, null);
91 }
92
93 @Override
94 public CloseableHttpResponse execute(
95 final HttpRoute route,
96 final HttpRequestWrapper request,
97 final HttpClientContext context,
98 final HttpExecutionAware execAware) throws IOException, HttpException {
99 try {
100 final Future<HttpResponse> future = client.execute(route.getTargetHost(), request, context, null);
101 return Proxies.enhanceResponse(future.get());
102 } catch (InterruptedException e) {
103 Thread.currentThread().interrupt();
104 return null;
105 } catch (ExecutionException e) {
106 try {
107 throw e.getCause();
108 } catch (IOException ex) {
109 throw ex;
110 } catch (HttpException ex) {
111 throw ex;
112 } catch (RuntimeException ex) {
113 throw ex;
114 } catch (Error ex) {
115 throw ex;
116 } catch (Throwable ex) {
117 throw new UndeclaredThrowableException(ex);
118 }
119 }
120 }
121
122 public long getCacheHits() {
123 return client.getCacheHits();
124 }
125
126 public long getCacheMisses() {
127 return client.getCacheMisses();
128 }
129
130 public long getCacheUpdates() {
131 return client.getCacheUpdates();
132 }
133
134 }
0 /*
1 * ====================================================================
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 * ====================================================================
19 *
20 * This software consists of voluntary contributions made by many
21 * individuals on behalf of the Apache Software Foundation. For more
22 * information on the Apache Software Foundation, please see
23 * <http://www.apache.org/>.
24 *
25 */
26 package org.apache.http.impl.client.cache;
27
28 import org.apache.http.HttpException;
29 import org.apache.http.HttpHost;
30 import org.apache.http.HttpRequest;
31 import org.apache.http.HttpResponse;
32 import org.apache.http.client.methods.HttpRequestWrapper;
33 import org.apache.http.client.protocol.HttpClientContext;
34 import org.apache.http.concurrent.BasicFuture;
35 import org.apache.http.concurrent.FutureCallback;
36 import org.apache.http.conn.routing.HttpRoute;
37 import org.apache.http.impl.execchain.ClientExecChain;
38 import org.apache.http.impl.nio.client.CloseableHttpAsyncClient;
39 import org.apache.http.nio.conn.ClientAsyncConnectionManager;
40 import org.apache.http.nio.protocol.HttpAsyncRequestProducer;
41 import org.apache.http.nio.protocol.HttpAsyncResponseConsumer;
42 import org.apache.http.nio.reactor.IOReactorStatus;
43 import org.apache.http.params.HttpParams;
44 import org.apache.http.protocol.HttpContext;
45
46 import java.io.IOException;
47 import java.util.concurrent.Future;
48
49 public class ClientExecChainAsyncClient extends CloseableHttpAsyncClient {
50
51 private final ClientExecChain backend;
52
53 public ClientExecChainAsyncClient(final ClientExecChain backend) {
54 super();
55 this.backend = backend;
56 }
57
58 @Override
59 public void start() {
60 // no-op
61 }
62
63 @Override
64 public boolean isRunning() {
65 return true;
66 }
67
68 public void shutdown() throws InterruptedException {
69 // no-op
70 }
71
72 public IOReactorStatus getStatus() {
73 return null;
74 }
75
76 @SuppressWarnings("deprecation")
77 public ClientAsyncConnectionManager getConnectionManager() {
78 return null;
79 }
80
81 @SuppressWarnings("deprecation")
82 public HttpParams getParams() {
83 return null;
84 }
85
86 @Override
87 public void close() throws IOException {
88 // no-op
89 }
90
91 @Override
92 public <T> Future<T> execute(
93 final HttpAsyncRequestProducer requestProducer,
94 final HttpAsyncResponseConsumer<T> responseConsumer,
95 final HttpContext context,
96 final FutureCallback<T> callback) {
97 throw new UnsupportedOperationException();
98 }
99
100 @Override
101 public Future<HttpResponse> execute(
102 final HttpHost target,
103 final HttpRequest request,
104 final HttpContext context,
105 final FutureCallback<HttpResponse> callback) {
106 final BasicFuture<HttpResponse> future = new BasicFuture<HttpResponse>(
107 callback);
108 try {
109 final HttpResponse result = backend.execute(new HttpRoute(target),
110 HttpRequestWrapper.wrap(request),
111 HttpClientContext.adapt(context), null);
112 future.completed(result);
113 } catch (IOException e) {
114 future.failed(e);
115 } catch (HttpException e) {
116 future.failed(e);
117 }
118 return future;
119 }
120
121 }
0 /*
1 * ====================================================================
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 * ====================================================================
19 *
20 * This software consists of voluntary contributions made by many
21 * individuals on behalf of the Apache Software Foundation. For more
22 * information on the Apache Software Foundation, please see
23 * <http://www.apache.org/>.
24 *
25 */
26 package org.apache.http.impl.client.cache;
27
28 import org.apache.http.impl.execchain.ClientExecChain;
29
30 /**
31 * This class tests behavior that is allowed (MAY) by the HTTP/1.1 protocol specification and for
32 * which we have implemented the behavior in the caching HTTP client.
33 */
34 public class TestAsyncProtocolAllowedBehavior extends TestProtocolAllowedBehavior {
35
36 @Override
37 protected ClientExecChain createCachingExecChain(
38 final ClientExecChain backend,
39 final HttpCache cache,
40 final CacheConfig config) {
41 return new CachingHttpAsyncClientExecChain(backend, cache, config);
42 }
43
44 @Override
45 protected boolean supportsRangeAndContentRangeHeaders(final ClientExecChain impl) {
46 return impl instanceof CachingHttpAsyncClientExecChain
47 && ((CachingHttpAsyncClientExecChain) impl)
48 .supportsRangeAndContentRangeHeaders();
49 }
50
51 }
0 /*
1 * ====================================================================
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 * ====================================================================
19 *
20 * This software consists of voluntary contributions made by many
21 * individuals on behalf of the Apache Software Foundation. For more
22 * information on the Apache Software Foundation, please see
23 * <http://www.apache.org/>.
24 *
25 */
26 package org.apache.http.impl.client.cache;
27
28 import org.apache.http.impl.execchain.ClientExecChain;
29
30 /**
31 * We are a conditionally-compliant HTTP/1.1 client with a cache. However, a lot of the rules for
32 * proxies apply to us, as far as proper operation of the requests that pass through us. Generally
33 * speaking, we want to make sure that any response returned from our HttpClient.execute() methods
34 * is conditionally compliant with the rules for an HTTP/1.1 server, and that any requests we pass
35 * downstream to the backend HttpClient are are conditionally compliant with the rules for an
36 * HTTP/1.1 client.
37 * <p>
38 * There are some cases where strictly behaving as a compliant caching proxy would result in strange
39 * behavior, since we're attached as part of a client and are expected to be a drop-in replacement.
40 * The test cases captured here document the places where we differ from the HTTP RFC.
41 */
42 public class TestAsyncProtocolDeviations extends TestProtocolDeviations {
43
44 @Override
45 protected ClientExecChain createCachingExecChain(
46 final ClientExecChain backend,
47 final HttpCache cache,
48 final CacheConfig config) {
49 return new CachingHttpAsyncClientExecChain(backend, cache, config);
50 }
51 }
0 /*
1 * ====================================================================
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 * ====================================================================
19 *
20 * This software consists of voluntary contributions made by many
21 * individuals on behalf of the Apache Software Foundation. For more
22 * information on the Apache Software Foundation, please see
23 * <http://www.apache.org/>.
24 *
25 */
26 package org.apache.http.impl.client.cache;
27
28 import org.apache.http.impl.execchain.ClientExecChain;
29
30 /**
31 * We are a conditionally-compliant HTTP/1.1 client with a cache. However, a lot of the rules for
32 * proxies apply to us, as far as proper operation of the requests that pass through us. Generally
33 * speaking, we want to make sure that any response returned from our HttpClient.execute() methods
34 * is conditionally compliant with the rules for an HTTP/1.1 server, and that any requests we pass
35 * downstream to the backend HttpClient are are conditionally compliant with the rules for an
36 * HTTP/1.1 client.
37 */
38 public class TestAsyncProtocolRequirements extends TestProtocolRequirements {
39
40 @Override
41 protected ClientExecChain createCachingExecChain(
42 final ClientExecChain backend,
43 final HttpCache cache,
44 final CacheConfig config) {
45 return new CachingHttpAsyncClientExecChain(backend, cache, config);
46 }
47
48 @Override
49 protected boolean supportsRangeAndContentRangeHeaders(final ClientExecChain impl) {
50 return impl instanceof CachingHttpAsyncClientExecChain
51 && ((CachingHttpAsyncClientExecChain) impl)
52 .supportsRangeAndContentRangeHeaders();
53 }
54 }
0 /*
1 * ====================================================================
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 * ====================================================================
19 *
20 * This software consists of voluntary contributions made by many
21 * individuals on behalf of the Apache Software Foundation. For more
22 * information on the Apache Software Foundation, please see
23 * <http://www.apache.org/>.
24 *
25 */
26 package org.apache.http.impl.client.cache;
27
28 import org.apache.http.impl.execchain.ClientExecChain;
29 import org.junit.Ignore;
30 import org.junit.Test;
31
32 public class TestCachingHttpAsyncClient extends TestCachingExecChain {
33
34 @Override
35 public ClientExecChain createCachingExecChain(
36 final ClientExecChain backend,
37 final HttpCache responseCache,
38 final CacheValidityPolicy validityPolicy,
39 final ResponseCachingPolicy responseCachingPolicy,
40 final CachedHttpResponseGenerator responseGenerator,
41 final CacheableRequestPolicy cacheableRequestPolicy,
42 final CachedResponseSuitabilityChecker suitabilityChecker,
43 final ConditionalRequestBuilder conditionalRequestBuilder,
44 final ResponseProtocolCompliance responseCompliance,
45 final RequestProtocolCompliance requestCompliance,
46 final CacheConfig config,
47 final AsynchronousValidator asynchRevalidator) {
48 return new CachingHttpAsyncClientExecChain(backend, responseCache, validityPolicy,
49 responseCachingPolicy, responseGenerator,
50 cacheableRequestPolicy, suitabilityChecker,
51 conditionalRequestBuilder, responseCompliance,
52 requestCompliance);
53 }
54
55 @Override
56 public ClientExecChain createCachingExecChain(
57 final ClientExecChain backend,
58 final HttpCache cache,
59 final CacheConfig config) {
60 return new CachingHttpAsyncClientExecChain(backend, cache, config);
61 }
62
63 @Override @Test @Ignore // TODO: virtual host support is presently broken
64 public void testUsesVirtualHostForCacheKey() throws Exception {
65 super.testUsesVirtualHostForCacheKey();
66 }
67
68 }
0 /*
1 * ====================================================================
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 * ====================================================================
19 *
20 * This software consists of voluntary contributions made by many
21 * individuals on behalf of the Apache Software Foundation. For more
22 * information on the Apache Software Foundation, please see
23 * <http://www.apache.org/>.
24 *
25 */
26 package org.apache.http.impl.client.cache;
27
28 import org.apache.http.impl.execchain.ClientExecChain;
29
30 public class TestHttpAsyncCacheJiraNumber1147 extends TestHttpCacheJiraNumber1147 {
31
32 @Override
33 protected ClientExecChain createCachingExecChain(
34 final ClientExecChain backend,
35 final BasicHttpCache cache,
36 final CacheConfig config) {
37 return new CachingHttpAsyncClientExecChain(backend, cache, config);
38 }
39
40 }
0 # ====================================================================
1 # Licensed to the Apache Software Foundation (ASF) under one
2 # or more contributor license agreements. See the NOTICE file
3 # distributed with this work for additional information
4 # regarding copyright ownership. The ASF licenses this file
5 # to you under the Apache License, Version 2.0 (the
6 # "License"); you may not use this file except in compliance
7 # with the License. You may obtain a copy of the License at
8 #
9 # http://www.apache.org/licenses/LICENSE-2.0
10 #
11 # Unless required by applicable law or agreed to in writing,
12 # software distributed under the License is distributed on an
13 # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14 # KIND, either express or implied. See the License for the
15 # specific language governing permissions and limitations
16 # under the License.
17 # ====================================================================
18 #
19 # This software consists of voluntary contributions made by many
20 # individuals on behalf of the Apache Software Foundation. For more
21 # information on the Apache Software Foundation, please see
22 # <http://www.apache.org/>.
23
24 # Disable logging for unit tests
25 org.apache.commons.logging.Log=org.apache.commons.logging.impl.NoOpLog
0 <?xml version="1.0" encoding="UTF-8"?>
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 --><project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
26 <modelVersion>4.0.0</modelVersion>
27 <parent>
28 <groupId>org.apache.httpcomponents</groupId>
29 <artifactId>httpcomponents-asyncclient</artifactId>
30 <version>4.1</version>
31 </parent>
32 <artifactId>httpasyncclient-osgi</artifactId>
33 <name>Apache HttpAsyncClient OSGi bundle</name>
34 <description>
35 Apache HttpComponents AsyncClient (OSGi bundle)
36 </description>
37 <url>http://hc.apache.org/httpcomponents-asyncclient</url>
38 <packaging>bundle</packaging>
39
40 <properties>
41 <httpcore.osgi.import.version>"[4.4.0, 4.5.0)"</httpcore.osgi.import.version>
42 <httpclient.osgi.import.version>"[4.4.0, 4.5.0)"</httpclient.osgi.import.version>
43 <commons-logging.osgi.import.version>"[1.1.0, 1.2.0)"</commons-logging.osgi.import.version>
44 </properties>
45
46 <dependencies>
47 <dependency>
48 <groupId>org.apache.httpcomponents</groupId>
49 <artifactId>httpasyncclient</artifactId>
50 <version>${project.version}</version>
51 <scope>compile</scope>
52 </dependency>
53 </dependencies>
54
55 <build>
56 <plugins>
57 <plugin>
58 <groupId>org.apache.felix</groupId>
59 <artifactId>maven-bundle-plugin</artifactId>
60 <extensions>true</extensions>
61 <configuration>
62 <instructions>
63 <Bundle-Name>Apache ${project.name}</Bundle-Name>
64 <Bundle-SymbolicName>${project.groupId}.httpasyncclient</Bundle-SymbolicName>
65 <_exportcontents>
66 org.apache.http.nio.client.*;version=${project.version},
67 org.apache.http.nio.conn.*;version=${project.version},
68 org.apache.http.impl.nio.client.*;version=${project.version},
69 org.apache.http.impl.nio.conn.*;version=${project.version}
70 </_exportcontents>
71 <Embed-Dependency>*;scope=compile|runtime;inline=true</Embed-Dependency>
72 <Import-Package>
73 javax.crypto,
74 javax.crypto.spec,
75 javax.net.ssl,
76 javax.security.auth.x500,
77 org.ietf.jgss,
78 org.apache.commons.logging;version=${commons-logging.osgi.import.version},
79 org.apache.http;version=${httpcore.osgi.import.version},
80 org.apache.http.entity;version=${httpcore.osgi.import.version},
81 org.apache.http.concurrent;version=${httpcore.osgi.import.version},
82 org.apache.http.config;version=${httpcore.osgi.import.version},
83 org.apache.http.io;version=${httpcore.osgi.import.version},
84 org.apache.http.message;version=${httpcore.osgi.import.version},
85 org.apache.http.params;version=${httpcore.osgi.import.version},
86 org.apache.http.pool;version=${httpcore.osgi.import.version},
87 org.apache.http.protocol;version=${httpcore.osgi.import.version},
88 org.apache.http.util;version=${httpcore.osgi.import.version},
89 org.apache.http.impl;version=${httpcore.osgi.import.version},
90 org.apache.http.nio;version=${httpcore.osgi.import.version},
91 org.apache.http.nio.entity;version=${httpcore.osgi.import.version},
92 org.apache.http.nio.params;version=${httpcore.osgi.import.version},
93 org.apache.http.nio.pool;version=${httpcore.osgi.import.version},
94 org.apache.http.nio.protocol;version=${httpcore.osgi.import.version},
95 org.apache.http.nio.reactor;version=${httpcore.osgi.import.version},
96 org.apache.http.nio.reactor.ssl;version=${httpcore.osgi.import.version},
97 org.apache.http.nio.util;version=${httpcore.osgi.import.version},
98 org.apache.http.impl.nio.codecs;version=${httpcore.osgi.import.version},
99 org.apache.http.impl.nio;version=${httpcore.osgi.import.version},
100 org.apache.http.impl.nio.reactor;version=${httpcore.osgi.import.version},
101 org.apache.http.auth;version=${httpclient.osgi.import.version},
102 org.apache.http.cookie;version=${httpclient.osgi.import.version},
103 org.apache.http.conn;version=${httpclient.osgi.import.version},
104 org.apache.http.conn.params;version=${httpclient.osgi.import.version},
105 org.apache.http.conn.routing;version=${httpclient.osgi.import.version},
106 org.apache.http.conn.ssl;version=${httpclient.osgi.import.version},
107 org.apache.http.conn.util;version=${httpclient.osgi.import.version},
108 org.apache.http.client;version=${httpclient.osgi.import.version},
109 org.apache.http.client.config;version=${httpcore.osgi.import.version},
110 org.apache.http.client.methods;version=${httpclient.osgi.import.version},
111 org.apache.http.client.params;version=${httpclient.osgi.import.version},
112 org.apache.http.client.protocol;version=${httpclient.osgi.import.version},
113 org.apache.http.client.utils;version=${httpclient.osgi.import.version},
114 org.apache.http.impl.auth;version=${httpclient.osgi.import.version},
115 org.apache.http.impl.cookie;version=${httpclient.osgi.import.version},
116 org.apache.http.impl.conn;version=${httpclient.osgi.import.version},
117 org.apache.http.impl.client;version=${httpclient.osgi.import.version},
118 org.apache.http.impl.execchain;version=${httpclient.osgi.import.version}
119 </Import-Package>
120 <Include-Resource />
121 <!-- Stop the JAVA_1_n_HOME variables from being treated as headers by Bnd -->
122 <_removeheaders>JAVA_1_3_HOME,JAVA_1_4_HOME</_removeheaders>
123 </instructions>
124 </configuration>
125 </plugin>
126 <plugin>
127 <groupId>org.codehaus.mojo</groupId>
128 <artifactId>clirr-maven-plugin</artifactId>
129 <configuration>
130 <skip>true</skip>
131 </configuration>
132 </plugin>
133 </plugins>
134 <finalName>org.apache.httpcomponents.httpasyncclient_${project.version}</finalName>
135 </build>
136
137 <reporting>
138 <plugins>
139 <plugin>
140 <groupId>org.codehaus.mojo</groupId>
141 <artifactId>clirr-maven-plugin</artifactId>
142 <version>${hc.clirr.version}</version>
143 <configuration>
144 <skip>true</skip>
145 </configuration>
146 </plugin>
147 <plugin>
148 <artifactId>maven-project-info-reports-plugin</artifactId>
149 <version>${hc.project-info.version}</version>
150 <inherited>false</inherited>
151 <reportSets>
152 <reportSet>
153 <reports>
154 <report>dependencies</report>
155 <report>dependency-info</report>
156 <report>summary</report>
157 </reports>
158 </reportSet>
159 </reportSets>
160 </plugin>
161
162 </plugins>
163 </reporting>
164
165 </project>
0 <?xml version="1.0" encoding="UTF-8"?>
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 --><project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
26 <parent>
27 <artifactId>project</artifactId>
28 <groupId>org.apache.httpcomponents</groupId>
29 <version>7</version>
30 <relativePath>../project/pom.xml</relativePath>
31 </parent>
32 <modelVersion>4.0.0</modelVersion>
33 <artifactId>httpcomponents-asyncclient</artifactId>
34 <name>Apache HttpComponents AsyncClient</name>
35 <version>4.1</version>
36 <description>Apache components to build asynchronous client side HTTP services</description>
37 <url>http://hc.apache.org/httpcomponents-asyncclient</url>
38 <inceptionYear>2010</inceptionYear>
39 <packaging>pom</packaging>
40
41 <organization>
42 <name>The Apache Software Foundation</name>
43 <url>http://www.apache.org/</url>
44 </organization>
45
46 <licenses>
47 <license>
48 <name>Apache License, Version 2.0</name>
49 <url>LICENSE.txt</url>
50 <distribution>repo</distribution>
51 </license>
52 </licenses>
53
54 <issueManagement>
55 <system>Jira</system>
56 <url>http://issues.apache.org/jira/browse/HTTPASYNC</url>
57 </issueManagement>
58
59 <scm>
60 <connection>scm:svn:https://svn.apache.org/repos/asf/httpcomponents/httpasyncclient/tags/4.1</connection>
61 <developerConnection>scm:svn:https://svn.apache.org/repos/asf/httpcomponents/httpasyncclient/tags/4.1</developerConnection>
62 <url>https://svn.apache.org/repos/asf/httpcomponents/httpasyncclient/tags/4.1</url>
63 </scm>
64
65 <properties>
66 <maven.compiler.source>1.6</maven.compiler.source>
67 <maven.compiler.target>1.6</maven.compiler.target>
68 <httpcore.version>4.4.1</httpcore.version>
69 <httpclient.version>4.4.1</httpclient.version>
70 <commons-logging.version>1.2</commons-logging.version>
71 <commons-io.version>2.4</commons-io.version>
72 <junit.version>4.11</junit.version>
73 <easymock.version>2.5.2</easymock.version>
74 <mockito.version>1.8.5</mockito.version>
75 <hc.stylecheck.version>1</hc.stylecheck.version>
76 <api.comparison.version>4.0</api.comparison.version>
77 </properties>
78
79 <dependencyManagement>
80 <dependencies>
81 <dependency>
82 <groupId>org.apache.httpcomponents</groupId>
83 <artifactId>httpcore</artifactId>
84 <version>${httpcore.version}</version>
85 </dependency>
86 <dependency>
87 <groupId>org.apache.httpcomponents</groupId>
88 <artifactId>httpcore-nio</artifactId>
89 <version>${httpcore.version}</version>
90 </dependency>
91 <dependency>
92 <groupId>org.apache.httpcomponents</groupId>
93 <artifactId>httpclient</artifactId>
94 <version>${httpclient.version}</version>
95 </dependency>
96 <dependency>
97 <groupId>org.apache.httpcomponents</groupId>
98 <artifactId>httpclient-cache</artifactId>
99 <version>${httpclient.version}</version>
100 </dependency>
101 <dependency>
102 <groupId>commons-logging</groupId>
103 <artifactId>commons-logging</artifactId>
104 <version>${commons-logging.version}</version>
105 </dependency>
106 <dependency>
107 <groupId>junit</groupId>
108 <artifactId>junit</artifactId>
109 <version>${junit.version}</version>
110 <scope>test</scope>
111 </dependency>
112 <dependency>
113 <groupId>org.mockito</groupId>
114 <artifactId>mockito-core</artifactId>
115 <version>${mockito.version}</version>
116 <scope>test</scope>
117 </dependency>
118 <dependency>
119 <groupId>org.easymock</groupId>
120 <artifactId>easymock</artifactId>
121 <version>${easymock.version}</version>
122 <scope>test</scope>
123 </dependency>
124 <dependency>
125 <groupId>org.easymock</groupId>
126 <artifactId>easymockclassextension</artifactId>
127 <version>${easymock.version}</version>
128 <scope>test</scope>
129 </dependency>
130 <dependency>
131 <groupId>commons-io</groupId>
132 <artifactId>commons-io</artifactId>
133 <version>${commons-io.version}</version>
134 <scope>test</scope>
135 </dependency>
136 <dependency>
137 <groupId>org.apache.httpcomponents</groupId>
138 <artifactId>httpclient-cache</artifactId>
139 <version>${httpclient.version}</version>
140 <type>test-jar</type>
141 <scope>test</scope>
142 </dependency>
143 </dependencies>
144 </dependencyManagement>
145
146 <modules>
147 <module>httpasyncclient</module>
148 <module>httpasyncclient-cache</module>
149 <module>httpasyncclient-osgi</module>
150 </modules>
151
152 <build>
153 <plugins>
154 <plugin>
155 <artifactId>maven-jar-plugin</artifactId>
156 <configuration>
157 <archive>
158 <manifestEntries>
159 <Specification-Title>HttpComponents ${project.name}</Specification-Title>
160 <Specification-Version>${project.version}</Specification-Version>
161 <Specification-Vendor>The Apache Software Foundation</Specification-Vendor>
162 <Implementation-Title>HttpComponents ${project.name}</Implementation-Title>
163 <Implementation-Version>${project.version}</Implementation-Version>
164 <Implementation-Vendor>The Apache Software Foundation</Implementation-Vendor>
165 <Implementation-Vendor-Id>org.apache</Implementation-Vendor-Id>
166 <url>${project.url}</url>
167 </manifestEntries>
168 </archive>
169 </configuration>
170 </plugin>
171 <plugin>
172 <artifactId>maven-source-plugin</artifactId>
173 <executions>
174 <execution>
175 <id>attach-sources</id>
176 <goals>
177 <goal>jar</goal>
178 </goals>
179 </execution>
180 </executions>
181 </plugin>
182 <plugin>
183 <artifactId>maven-javadoc-plugin</artifactId>
184 <configuration>
185 <source>${maven.compiler.source}</source>
186 <links>
187 <link>http://docs.oracle.com/javase/6/docs/api/</link>
188 <link>http://hc.apache.org/httpcomponents-core-ga/httpcore/apidocs/</link>
189 <link>http://hc.apache.org/httpcomponents-client-ga/httpclient/apidocs/</link>
190 </links>
191 </configuration>
192 </plugin>
193 <plugin>
194 <artifactId>maven-site-plugin</artifactId>
195 </plugin>
196 <plugin>
197 <groupId>org.apache.maven.plugins</groupId>
198 <artifactId>maven-checkstyle-plugin</artifactId>
199 <version>2.9.1</version>
200 <dependencies>
201 <dependency>
202 <groupId>org.apache.httpcomponents</groupId>
203 <artifactId>hc-stylecheck</artifactId>
204 <version>${hc.stylecheck.version}</version>
205 </dependency>
206 </dependencies>
207 <configuration>
208 <encoding>UTF-8</encoding>
209 </configuration>
210 <executions>
211 <execution>
212 <id>validate-main</id>
213 <phase>validate</phase>
214 <configuration>
215 <configLocation>hc-stylecheck/default.xml</configLocation>
216 <headerLocation>hc-stylecheck/asl2.header</headerLocation>
217 <consoleOutput>true</consoleOutput>
218 <failsOnError>true</failsOnError>
219 <linkXRef>false</linkXRef>
220 <sourceDirectory>${basedir}/src/main</sourceDirectory>
221 </configuration>
222 <goals>
223 <goal>checkstyle</goal>
224 </goals>
225 </execution>
226 <execution>
227 <id>validate-test</id>
228 <phase>validate</phase>
229 <configuration>
230 <configLocation>hc-stylecheck/default.xml</configLocation>
231 <headerLocation>hc-stylecheck/asl2.header</headerLocation>
232 <consoleOutput>true</consoleOutput>
233 <failsOnError>true</failsOnError>
234 <linkXRef>false</linkXRef>
235 <sourceDirectory>${basedir}/src/test</sourceDirectory>
236 </configuration>
237 <goals>
238 <goal>checkstyle</goal>
239 </goals>
240 </execution>
241 <execution>
242 <id>validate-examples</id>
243 <phase>validate</phase>
244 <configuration>
245 <configLocation>hc-stylecheck/minimal.xml</configLocation>
246 <headerLocation>hc-stylecheck/asl2.header</headerLocation>
247 <consoleOutput>true</consoleOutput>
248 <failsOnError>true</failsOnError>
249 <linkXRef>false</linkXRef>
250 <sourceDirectory>${basedir}/src/examples</sourceDirectory>
251 </configuration>
252 <goals>
253 <goal>checkstyle</goal>
254 </goals>
255 </execution>
256 </executions>
257 </plugin>
258 <plugin>
259 <groupId>org.codehaus.mojo</groupId>
260 <artifactId>clirr-maven-plugin</artifactId>
261 <version>${hc.clirr.version}</version>
262 <configuration>
263 <comparisonVersion>${api.comparison.version}</comparisonVersion>
264 </configuration>
265 </plugin>
266 <plugin>
267 <groupId>org.apache.rat</groupId>
268 <artifactId>apache-rat-plugin</artifactId>
269 <version>0.11</version>
270 <executions>
271 <execution>
272 <phase>verify</phase>
273 <goals>
274 <goal>check</goal>
275 </goals>
276 </execution>
277 </executions>
278 <configuration>
279 <excludes>
280 <exclude>src/test/resources/*.truststore</exclude>
281 </excludes>
282 </configuration>
283 </plugin>
284 </plugins>
285 </build>
286
287 <reporting>
288 <plugins>
289
290 <plugin>
291 <artifactId>maven-project-info-reports-plugin</artifactId>
292 <version>${hc.project-info.version}</version>
293 <inherited>false</inherited>
294 <reportSets>
295 <reportSet>
296 <reports>
297 <report>dependency-management</report>
298 <report>issue-tracking</report>
299 <report>license</report>
300 <report>scm</report>
301 <report>summary</report>
302 </reports>
303 </reportSet>
304 </reportSets>
305 </plugin>
306
307 </plugins>
308 </reporting>
309
310 </project>