Merge branch 'master' into release-9
This commit is contained in:
commit
0d78b07595
|
@ -1,9 +0,0 @@
|
|||
BUILDING JETTY
|
||||
--------------
|
||||
|
||||
Jetty is built with maven 3.x+
|
||||
|
||||
$ cd /my/work/directory/jetty-7
|
||||
$ mvn clean install
|
||||
|
||||
|
|
@ -1,202 +0,0 @@
|
|||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
|
@ -6,7 +6,7 @@
|
|||
<meta name="Generator" content="Microsoft Word 9">
|
||||
<meta name="Originator" content="Microsoft Word 9">
|
||||
<link rel="File-List" href="http://www.eclipse.org/legal/Eclipse%20EPL%202003_11_10%20Final_files/filelist.xml">
|
||||
<title>Eclipse Public License - Version 1.0</title>
|
||||
<title>Eclipse Public License - Version 1.0 / Apache License - Version 2.0</title>
|
||||
<!--[if gte mso 9]><xml>
|
||||
<o:DocumentProperties>
|
||||
<o:Revision>2</o:Revision>
|
||||
|
@ -317,4 +317,260 @@ its rights to a jury trial in any resulting litigation.</span> </p>
|
|||
|
||||
</div>
|
||||
|
||||
<div class="Section2">
|
||||
|
||||
<p style="text-align: center;" align="center"><b>Apache License</b></br>
|
||||
Version 2.0, January 2004<br/>
|
||||
http://www.apache.org/licenses/<br/>
|
||||
</p>
|
||||
<p><span style="font-size: 10pt;">TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION</spam></p>
|
||||
<p><b><span style="font-size: 10pt;">1. Definitions.</span></b> </p>
|
||||
<p><span style="font-size: 10pt;">
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.</span></p>
|
||||
<p><span style="font-size: 10pt;">
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.</span></p>
|
||||
<p><span style="font-size: 10pt;">
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.</span></p>
|
||||
<p><span style="font-size: 10pt;">
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.</span></p>
|
||||
<p><span style="font-size: 10pt;">
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.</span></p>
|
||||
<p><span style="font-size: 10pt;">
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.</span></p>
|
||||
<p><span style="font-size: 10pt;">
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).</span></p>
|
||||
<p><span style="font-size: 10pt;">
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.</span></p>
|
||||
<p><span style="font-size: 10pt;">
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."</span></p>
|
||||
<p><span style="font-size: 10pt;">
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.</span></p>
|
||||
|
||||
<p><b><span style="font-size: 10pt;">2. Grant of Copyright License.</span></b> </p>
|
||||
<p><span style="font-size: 10pt;">
|
||||
Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.</span></p>
|
||||
|
||||
|
||||
<p><b><span style="font-size: 10pt;">3. Grant of Patent License.</span></b><p>
|
||||
|
||||
<p><span style="font-size: 10pt;">
|
||||
Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
</span></p>
|
||||
<p><b><span style="font-size: 10pt;">
|
||||
4. Redistribution.
|
||||
</span></b></p>
|
||||
|
||||
<p><span style="font-size: 10pt;">You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:</span><p>
|
||||
<ul>
|
||||
<li><span style="font-size: 10pt;">
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and</span><p>
|
||||
</li>
|
||||
<li><span style="font-size: 10pt;">
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and</span><p>
|
||||
</li>
|
||||
</li><span style="font-size: 10pt;">
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and</span><p>
|
||||
</li>
|
||||
<li><span style="font-size: 10pt;">
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.</span><p>
|
||||
</li>
|
||||
</ul>
|
||||
</span></p>
|
||||
|
||||
<p><span style="font-size: 10pt;">
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
</span></p>
|
||||
<p><b><span style="font-size: 10pt;">
|
||||
5. Submission of Contributions.
|
||||
</span></b></p>
|
||||
|
||||
<p><span style="font-size: 10pt;">Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
</span></p>
|
||||
<p><b><span style="font-size: 10pt;">
|
||||
6. Trademarks.
|
||||
</span></b></p>
|
||||
|
||||
<p><span style="font-size: 10pt;">This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
</span></p>
|
||||
<p><b><span style="font-size: 10pt;">
|
||||
7. Disclaimer of Warranty.
|
||||
</span></b></p>
|
||||
|
||||
<p><span style="font-size: 10pt;">Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
</span></p>
|
||||
<p><b><span style="font-size: 10pt;">
|
||||
8. Limitation of Liability.
|
||||
</span></b></p>
|
||||
|
||||
<p><span style="font-size: 10pt;">In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
</span></p>
|
||||
<p><b><span style="font-size: 10pt;">
|
||||
9. Accepting Warranty or Additional Liability.
|
||||
</span></b></p>
|
||||
<p><span style="font-size: 10pt;">While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
</span></p>
|
||||
|
||||
<p><span style="font-size: 10pt;">
|
||||
END OF TERMS AND CONDITIONS
|
||||
</span></p>
|
||||
|
||||
<p><span style="font-size: 10pt;">
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
</span></p>
|
||||
|
||||
<p><span style="font-size: 10pt;">
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
</span></p>
|
||||
|
||||
<p><span style="font-size: 10pt;">
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
</span></p>
|
||||
|
||||
<p><span style="font-size: 10pt;">
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
</span></p>
|
||||
|
||||
<p><span style="font-size: 10pt;">
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
</span></p>
|
||||
|
||||
<p><span style="font-size: 10pt;">
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
</span></p>
|
||||
|
||||
</div>
|
||||
</body></html>
|
|
@ -1,4 +1,3 @@
|
|||
|
||||
This is a source checkout of the Jetty webserver.
|
||||
|
||||
To build, use:
|
||||
|
|
3632
VERSION.txt
3632
VERSION.txt
File diff suppressed because it is too large
Load Diff
|
@ -1,8 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<templates>
|
||||
<template autoinsert="true" context="java" deleted="false" description="Create Jetty Logger constant" enabled="true" name="logjetty">${:import(
|
||||
org.eclipse.jetty.util.log.Log,
|
||||
org.eclipse.jetty.util.log.Logger)
|
||||
}private static final Logger LOG = Log.getLogger(${enclosing_type}.class);
|
||||
</template>
|
||||
</templates>
|
Before Width: | Height: | Size: 166 B After Width: | Height: | Size: 166 B |
Before Width: | Height: | Size: 164 B After Width: | Height: | Size: 164 B |
|
@ -16,30 +16,34 @@
|
|||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.nested;
|
||||
package org.eclipse.jetty.embedded;
|
||||
|
||||
import org.eclipse.jetty.server.Connector;
|
||||
import org.eclipse.jetty.server.Handler;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.server.nio.SelectChannelConnector;
|
||||
import org.eclipse.jetty.webapp.WebAppContext;
|
||||
import org.eclipse.jetty.server.ServerConnector;
|
||||
import org.eclipse.jetty.server.handler.DefaultHandler;
|
||||
import org.eclipse.jetty.server.handler.HandlerCollection;
|
||||
import org.eclipse.jetty.servlet.ServletContextHandler;
|
||||
|
||||
public class NestedServer
|
||||
public class ExampleServer
|
||||
{
|
||||
public static void main(String[] args) throws Exception
|
||||
{
|
||||
Server server = new Server();
|
||||
|
||||
Connector connector = new SelectChannelConnector();
|
||||
connector.setPort(Integer.getInteger("jetty.port",8080).intValue());
|
||||
server.setConnectors(new Connector[]
|
||||
{ connector });
|
||||
ServerConnector connector=new ServerConnector(server);
|
||||
connector.setPort(8080);
|
||||
server.setConnectors(new Connector[]{connector});
|
||||
|
||||
ServletContextHandler context = new ServletContextHandler();
|
||||
context.setContextPath("/hello");
|
||||
context.addServlet(HelloServlet.class,"/");
|
||||
|
||||
WebAppContext webapp = new WebAppContext();
|
||||
webapp.setContextPath("/jnest");
|
||||
webapp.setWar("src/main/webapp");
|
||||
webapp.setParentLoaderPriority(true);
|
||||
server.setHandler(webapp);
|
||||
HandlerCollection handlers = new HandlerCollection();
|
||||
handlers.setHandlers(new Handler[]{context,new DefaultHandler()});
|
||||
server.setHandler(handlers);
|
||||
|
||||
|
||||
server.start();
|
||||
server.join();
|
|
@ -16,15 +16,16 @@
|
|||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.client;
|
||||
package org.eclipse.jetty.embedded;
|
||||
|
||||
public class SelectConnectionTest extends AbstractConnectionTest
|
||||
import org.eclipse.jetty.util.resource.Resource;
|
||||
import org.eclipse.jetty.xml.XmlConfiguration;
|
||||
|
||||
public class ExampleServerXml
|
||||
{
|
||||
protected HttpClient newHttpClient()
|
||||
public static void main(String[] args) throws Exception
|
||||
{
|
||||
HttpClient httpClient = new HttpClient();
|
||||
httpClient.setConnectorType(HttpClient.CONNECTOR_SELECT_CHANNEL);
|
||||
httpClient.setConnectBlocking(true);
|
||||
return httpClient;
|
||||
Resource fileserver_xml = Resource.newSystemResource("exampleserver.xml");
|
||||
XmlConfiguration.main(fileserver_xml.getFile().getAbsolutePath());
|
||||
}
|
||||
}
|
|
@ -41,7 +41,7 @@ public class LikeJettyXml
|
|||
{
|
||||
public static void main(String[] args) throws Exception
|
||||
{
|
||||
String jetty_home = System.getProperty("jetty.home","../jetty-distribution/target/distribution");
|
||||
String jetty_home = System.getProperty("jetty.home","../../jetty-distribution/target/distribution");
|
||||
System.setProperty("jetty.home",jetty_home);
|
||||
|
||||
// Setup Threadpool
|
||||
|
@ -59,7 +59,7 @@ public class LikeJettyXml
|
|||
|
||||
// Setup Connectors
|
||||
HttpConnectionFactory http = new HttpConnectionFactory();
|
||||
http.getHttpChannelConfig().setSecurePort(8443);
|
||||
http.getHttpConfiguration().setSecurePort(8443);
|
||||
ServerConnector connector = new ServerConnector(server,http);
|
||||
connector.setPort(8080);
|
||||
connector.setIdleTimeout(30000);
|
|
@ -22,7 +22,7 @@ import org.eclipse.jetty.io.ArrayByteBufferPool;
|
|||
import org.eclipse.jetty.io.ByteBufferPool;
|
||||
import org.eclipse.jetty.server.Connector;
|
||||
import org.eclipse.jetty.server.ForwardedRequestCustomizer;
|
||||
import org.eclipse.jetty.server.HttpChannelConfig;
|
||||
import org.eclipse.jetty.server.HttpConfiguration;
|
||||
import org.eclipse.jetty.server.HttpConnectionFactory;
|
||||
import org.eclipse.jetty.server.SecureRequestCustomizer;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
|
@ -67,7 +67,7 @@ public class ManyConnectors
|
|||
|
||||
// A verbosely fully configured connector with SSL, SPDY and HTTP
|
||||
|
||||
HttpChannelConfig config = new HttpChannelConfig();
|
||||
HttpConfiguration config = new HttpConfiguration();
|
||||
config.setSecureScheme("https");
|
||||
config.setSecurePort(8443);
|
||||
config.setOutputBufferSize(32768);
|
|
@ -21,13 +21,6 @@ package org.eclipse.jetty.embedded;
|
|||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.server.handler.ContextHandler;
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* A {@link ContextHandler} provides a common environment for multiple Handlers,
|
||||
* such as: URI context path, class loader, static resource base.
|
||||
*
|
||||
* Typically a ContextHandler is used only when multiple contexts are likely.
|
||||
*/
|
||||
public class OneContext
|
||||
{
|
||||
public static void main(String[] args) throws Exception
|
||||
|
@ -38,10 +31,10 @@ public class OneContext
|
|||
context.setContextPath("/");
|
||||
context.setResourceBase(".");
|
||||
context.setClassLoader(Thread.currentThread().getContextClassLoader());
|
||||
server.setHandler(context);
|
||||
|
||||
context.setHandler(new HelloHandler());
|
||||
|
||||
server.setHandler(context);
|
||||
|
||||
server.start();
|
||||
server.join();
|
||||
}
|
|
@ -22,15 +22,11 @@ import java.lang.management.ManagementFactory;
|
|||
|
||||
import org.eclipse.jetty.deploy.DeploymentManager;
|
||||
import org.eclipse.jetty.deploy.providers.WebAppProvider;
|
||||
import org.eclipse.jetty.io.ArrayByteBufferPool;
|
||||
import org.eclipse.jetty.io.ByteBufferPool;
|
||||
import org.eclipse.jetty.io.FilterConnection;
|
||||
import org.eclipse.jetty.jmx.MBeanContainer;
|
||||
import org.eclipse.jetty.security.HashLoginService;
|
||||
import org.eclipse.jetty.server.FilterConnectionFactory;
|
||||
import org.eclipse.jetty.server.ForwardedRequestCustomizer;
|
||||
import org.eclipse.jetty.server.Handler;
|
||||
import org.eclipse.jetty.server.HttpChannelConfig;
|
||||
import org.eclipse.jetty.server.HttpConfiguration;
|
||||
import org.eclipse.jetty.server.HttpConnectionFactory;
|
||||
import org.eclipse.jetty.server.NCSARequestLog;
|
||||
import org.eclipse.jetty.server.SecureRequestCustomizer;
|
||||
|
@ -49,13 +45,12 @@ import org.eclipse.jetty.spdy.server.http.PushStrategy;
|
|||
import org.eclipse.jetty.spdy.server.http.ReferrerPushStrategy;
|
||||
import org.eclipse.jetty.util.ssl.SslContextFactory;
|
||||
import org.eclipse.jetty.util.thread.QueuedThreadPool;
|
||||
import org.eclipse.jetty.util.thread.TimerScheduler;
|
||||
|
||||
public class SpdyServer
|
||||
{
|
||||
public static void main(String[] args) throws Exception
|
||||
{
|
||||
String jetty_home = System.getProperty("jetty.home","../jetty-distribution/target/distribution");
|
||||
String jetty_home = System.getProperty("jetty.home","../../jetty-distribution/target/distribution");
|
||||
System.setProperty("jetty.home",jetty_home);
|
||||
|
||||
// Setup Threadpool
|
||||
|
@ -73,7 +68,7 @@ public class SpdyServer
|
|||
|
||||
|
||||
// Common HTTP configuration
|
||||
HttpChannelConfig config = new HttpChannelConfig();
|
||||
HttpConfiguration config = new HttpConfiguration();
|
||||
config.setSecurePort(8443);
|
||||
config.addCustomizer(new ForwardedRequestCustomizer());
|
||||
config.addCustomizer(new SecureRequestCustomizer());
|
||||
|
@ -81,15 +76,13 @@ public class SpdyServer
|
|||
|
||||
// Http Connector
|
||||
HttpConnectionFactory http = new HttpConnectionFactory(config);
|
||||
FilterConnectionFactory filter = new FilterConnectionFactory(http.getProtocol());
|
||||
filter.addFilter(new FilterConnection.DumpToFileFilter("http-"));
|
||||
ServerConnector httpConnector = new ServerConnector(server,filter,http);
|
||||
ServerConnector httpConnector = new ServerConnector(server,http);
|
||||
httpConnector.setPort(8080);
|
||||
httpConnector.setIdleTimeout(30000);
|
||||
|
||||
httpConnector.setIdleTimeout(10000);
|
||||
server.addConnector(httpConnector);
|
||||
|
||||
|
||||
|
||||
// SSL configurations
|
||||
SslContextFactory sslContextFactory = new SslContextFactory();
|
||||
sslContextFactory.setKeyStorePath(jetty_home + "/etc/keystore");
|
||||
|
@ -123,15 +116,10 @@ public class SpdyServer
|
|||
NPNServerConnectionFactory npn = new NPNServerConnectionFactory(spdy3.getProtocol(),spdy2.getProtocol(),http.getProtocol());
|
||||
npn.setDefaultProtocol(http.getProtocol());
|
||||
npn.setInputBufferSize(1024);
|
||||
|
||||
FilterConnectionFactory npn_filter = new FilterConnectionFactory(npn.getProtocol());
|
||||
npn_filter.addFilter(new FilterConnection.DumpToFileFilter("npn-"));
|
||||
|
||||
SslConnectionFactory ssl = new SslConnectionFactory(sslContextFactory,npn_filter.getProtocol());
|
||||
FilterConnectionFactory ssl_filter = new FilterConnectionFactory(ssl.getProtocol());
|
||||
ssl_filter.addFilter(new FilterConnection.DumpToFileFilter("ssl-"));
|
||||
|
||||
ServerConnector spdyConnector = new ServerConnector(server,ssl_filter,ssl,npn_filter,npn,spdy3,spdy2,http);
|
||||
|
||||
SslConnectionFactory ssl = new SslConnectionFactory(sslContextFactory,npn.getProtocol());
|
||||
|
||||
ServerConnector spdyConnector = new ServerConnector(server,ssl,npn,spdy3,spdy2,http);
|
||||
spdyConnector.setPort(8443);
|
||||
|
||||
server.addConnector(spdyConnector);
|
|
@ -0,0 +1,39 @@
|
|||
<?xml version="1.0"?>
|
||||
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure.dtd">
|
||||
|
||||
<Configure id="ExampleServer" class="org.eclipse.jetty.server.Server">
|
||||
|
||||
<Set name="connectors">
|
||||
<Array type="org.eclipse.jetty.server.Connector">
|
||||
<Item>
|
||||
<New class="org.eclipse.jetty.server.ServerConnector">
|
||||
<Arg><Ref id="ExampleServer"/></Arg>
|
||||
<Set name="port">8080</Set>
|
||||
</New>
|
||||
</Item>
|
||||
</Array>
|
||||
</Set>
|
||||
|
||||
<New id="context" class="org.eclipse.jetty.servlet.ServletContextHandler">
|
||||
<Set name="contextPath">/hello</Set>
|
||||
<Call name="addServlet">
|
||||
<Arg>org.eclipse.jetty.embedded.HelloServlet</Arg>
|
||||
<Arg>/</Arg>
|
||||
</Call>
|
||||
</New>
|
||||
|
||||
<Set name="handler">
|
||||
<New class="org.eclipse.jetty.server.handler.HandlerCollection">
|
||||
<Set name="handlers">
|
||||
<Array type="org.eclipse.jetty.server.Handler">
|
||||
<Item>
|
||||
<Ref id="context" />
|
||||
</Item>
|
||||
<Item>
|
||||
<New class="org.eclipse.jetty.server.handler.DefaultHandler" />
|
||||
</Item>
|
||||
</Array>
|
||||
</Set>
|
||||
</New>
|
||||
</Set>
|
||||
</Configure>
|
|
@ -5,7 +5,8 @@
|
|||
|
||||
<Call name="addConnector">
|
||||
<Arg>
|
||||
<New class="org.eclipse.jetty.server.nio.ServerConnector">
|
||||
<New class="org.eclipse.jetty.server.ServerConnector">
|
||||
<Arg><Ref id="ExampleServer"/></Arg>
|
||||
<Set name="port">8080</Set>
|
||||
</New>
|
||||
</Arg>
|
|
@ -0,0 +1,9 @@
|
|||
org.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.StdErrLog
|
||||
org.eclipse.jetty.LEVEL=INFO
|
||||
org.eclipse.jetty.STACKS=true
|
||||
org.eclipse.jetty.SOURCE=false
|
||||
#org.eclipse.jetty.STACKS=false
|
||||
#org.eclipse.jetty.spdy.LEVEL=DEBUG
|
||||
#org.eclipse.jetty.server.LEVEL=DEBUG
|
||||
#org.eclipse.jetty.io.ssl.LEVEL=DEBUG
|
||||
#org.eclipse.jetty.spdy.server.LEVEL=DEBUG
|
|
@ -25,10 +25,8 @@ import java.net.URL;
|
|||
import java.net.URLClassLoader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Locale;
|
||||
import java.util.jar.JarEntry;
|
||||
|
||||
import org.eclipse.jetty.util.Loader;
|
||||
|
@ -105,11 +103,13 @@ public class AnnotationParser
|
|||
{
|
||||
_val=val;
|
||||
}
|
||||
@Override
|
||||
public Object getValue()
|
||||
{
|
||||
return _val;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return "("+getName()+":"+_val+")";
|
||||
|
@ -126,6 +126,7 @@ public class AnnotationParser
|
|||
_val = new ArrayList<Value>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getValue()
|
||||
{
|
||||
return _val;
|
||||
|
@ -146,6 +147,7 @@ public class AnnotationParser
|
|||
return _val.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
StringBuffer buff = new StringBuffer();
|
||||
|
@ -300,6 +302,7 @@ public class AnnotationParser
|
|||
* Visit a single-valued (name,value) pair for this annotation
|
||||
* @see org.objectweb.asm.AnnotationVisitor#visit(java.lang.String, java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public void visit(String aname, Object avalue)
|
||||
{
|
||||
SimpleValue v = new SimpleValue(aname);
|
||||
|
@ -311,6 +314,7 @@ public class AnnotationParser
|
|||
* Visit a (name,value) pair whose value is another Annotation
|
||||
* @see org.objectweb.asm.AnnotationVisitor#visitAnnotation(java.lang.String, java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public AnnotationVisitor visitAnnotation(String name, String desc)
|
||||
{
|
||||
String s = normalize(desc);
|
||||
|
@ -324,6 +328,7 @@ public class AnnotationParser
|
|||
* Visit an array valued (name, value) pair for this annotation
|
||||
* @see org.objectweb.asm.AnnotationVisitor#visitArray(java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public AnnotationVisitor visitArray(String name)
|
||||
{
|
||||
ListValue v = new ListValue(name);
|
||||
|
@ -336,11 +341,13 @@ public class AnnotationParser
|
|||
* Visit a enum-valued (name,value) pair for this annotation
|
||||
* @see org.objectweb.asm.AnnotationVisitor#visitEnum(java.lang.String, java.lang.String, java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public void visitEnum(String name, String desc, String value)
|
||||
{
|
||||
//TODO
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitEnd()
|
||||
{
|
||||
}
|
||||
|
@ -364,6 +371,7 @@ public class AnnotationParser
|
|||
int _version;
|
||||
|
||||
|
||||
@Override
|
||||
public void visit (int version,
|
||||
final int access,
|
||||
final String name,
|
||||
|
@ -398,10 +406,12 @@ public class AnnotationParser
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public AnnotationVisitor visitAnnotation (String desc, boolean visible)
|
||||
{
|
||||
MyAnnotationVisitor visitor = new MyAnnotationVisitor(normalize(desc), new ArrayList<Value>())
|
||||
{
|
||||
@Override
|
||||
public void visitEnd()
|
||||
{
|
||||
super.visitEnd();
|
||||
|
@ -422,6 +432,7 @@ public class AnnotationParser
|
|||
return visitor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MethodVisitor visitMethod (final int access,
|
||||
final String name,
|
||||
final String methodDesc,
|
||||
|
@ -431,10 +442,12 @@ public class AnnotationParser
|
|||
|
||||
return new EmptyVisitor ()
|
||||
{
|
||||
@Override
|
||||
public AnnotationVisitor visitAnnotation(String desc, boolean visible)
|
||||
{
|
||||
MyAnnotationVisitor visitor = new MyAnnotationVisitor (normalize(desc), new ArrayList<Value>())
|
||||
{
|
||||
@Override
|
||||
public void visitEnd()
|
||||
{
|
||||
super.visitEnd();
|
||||
|
@ -456,6 +469,7 @@ public class AnnotationParser
|
|||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public FieldVisitor visitField (final int access,
|
||||
final String fieldName,
|
||||
final String fieldType,
|
||||
|
@ -465,10 +479,12 @@ public class AnnotationParser
|
|||
|
||||
return new EmptyVisitor ()
|
||||
{
|
||||
@Override
|
||||
public AnnotationVisitor visitAnnotation(String desc, boolean visible)
|
||||
{
|
||||
MyAnnotationVisitor visitor = new MyAnnotationVisitor(normalize(desc), new ArrayList<Value>())
|
||||
{
|
||||
@Override
|
||||
public void visitEnd()
|
||||
{
|
||||
super.visitEnd();
|
||||
|
@ -498,6 +514,7 @@ public class AnnotationParser
|
|||
* @param annotationName
|
||||
* @param handler
|
||||
*/
|
||||
@Deprecated
|
||||
public void registerAnnotationHandler (String annotationName, DiscoverableAnnotationHandler handler)
|
||||
{
|
||||
_handlers.add(handler);
|
||||
|
@ -509,6 +526,7 @@ public class AnnotationParser
|
|||
* @param annotationName
|
||||
* @return
|
||||
*/
|
||||
@Deprecated
|
||||
public List<DiscoverableAnnotationHandler> getAnnotationHandlers(String annotationName)
|
||||
{
|
||||
List<DiscoverableAnnotationHandler> handlers = new ArrayList<DiscoverableAnnotationHandler>();
|
||||
|
@ -529,6 +547,7 @@ public class AnnotationParser
|
|||
* @deprecated
|
||||
* @return
|
||||
*/
|
||||
@Deprecated
|
||||
public List<DiscoverableAnnotationHandler> getAnnotationHandlers()
|
||||
{
|
||||
List<DiscoverableAnnotationHandler> allAnnotationHandlers = new ArrayList<DiscoverableAnnotationHandler>();
|
||||
|
@ -544,6 +563,7 @@ public class AnnotationParser
|
|||
* @deprecated see registerHandler(Handler)
|
||||
* @param handler
|
||||
*/
|
||||
@Deprecated
|
||||
public void registerClassHandler (ClassHandler handler)
|
||||
{
|
||||
_handlers.add(handler);
|
||||
|
@ -649,10 +669,10 @@ public class AnnotationParser
|
|||
* @param visitSuperClasses
|
||||
* @throws Exception
|
||||
*/
|
||||
public void parse (Class clazz, ClassNameResolver resolver, boolean visitSuperClasses)
|
||||
public void parse (Class<?> clazz, ClassNameResolver resolver, boolean visitSuperClasses)
|
||||
throws Exception
|
||||
{
|
||||
Class cz = clazz;
|
||||
Class<?> cz = clazz;
|
||||
while (cz != null)
|
||||
{
|
||||
if (!resolver.isExcluded(cz.getName()))
|
||||
|
@ -782,12 +802,13 @@ public class AnnotationParser
|
|||
|
||||
JarScanner scanner = new JarScanner()
|
||||
{
|
||||
@Override
|
||||
public void processEntry(URI jarUri, JarEntry entry)
|
||||
{
|
||||
try
|
||||
{
|
||||
String name = entry.getName();
|
||||
if (name.toLowerCase().endsWith(".class"))
|
||||
if (name.toLowerCase(Locale.ENGLISH).endsWith(".class"))
|
||||
{
|
||||
String shortName = name.replace('/', '.').substring(0,name.length()-6);
|
||||
if ((resolver == null)
|
||||
|
@ -827,12 +848,13 @@ public class AnnotationParser
|
|||
|
||||
JarScanner scanner = new JarScanner()
|
||||
{
|
||||
@Override
|
||||
public void processEntry(URI jarUri, JarEntry entry)
|
||||
{
|
||||
try
|
||||
{
|
||||
String name = entry.getName();
|
||||
if (name.toLowerCase().endsWith(".class"))
|
||||
if (name.toLowerCase(Locale.ENGLISH).endsWith(".class"))
|
||||
{
|
||||
String shortName = name.replace('/', '.').substring(0,name.length()-6);
|
||||
|
||||
|
|
|
@ -21,6 +21,7 @@ package org.eclipse.jetty.annotations;
|
|||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.Locale;
|
||||
import javax.annotation.Resource;
|
||||
import javax.naming.InitialContext;
|
||||
import javax.naming.NameNotFoundException;
|
||||
|
@ -261,7 +262,7 @@ public class ResourceAnnotationHandler extends AbstractIntrospectableAnnotationH
|
|||
|
||||
//default name is the javabean property name
|
||||
String name = method.getName().substring(3);
|
||||
name = name.substring(0,1).toLowerCase()+name.substring(1);
|
||||
name = name.substring(0,1).toLowerCase(Locale.ENGLISH)+name.substring(1);
|
||||
name = clazz.getCanonicalName()+"/"+name;
|
||||
|
||||
name = (resource.name()!=null && !resource.name().trim().equals("")? resource.name(): name);
|
||||
|
|
|
@ -90,30 +90,27 @@ public class ResourceA implements javax.servlet.Servlet
|
|||
{
|
||||
System.err.println("ResourceA.x");
|
||||
}
|
||||
@Override
|
||||
public void destroy()
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
@Override
|
||||
public ServletConfig getServletConfig()
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
@Override
|
||||
public String getServletInfo()
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
@Override
|
||||
public void init(ServletConfig arg0) throws ServletException
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
@Override
|
||||
public void service(ServletRequest arg0, ServletResponse arg1)
|
||||
throws ServletException, IOException
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,122 +0,0 @@
|
|||
<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">
|
||||
<parent>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-project</artifactId>
|
||||
<version>9.0.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>jetty-client</artifactId>
|
||||
<name>Jetty :: Asynchronous HTTP Client</name>
|
||||
<url>{$jetty.url}</url>
|
||||
|
||||
<properties>
|
||||
<bundle-symbolic-name>${project.groupId}.client</bundle-symbolic-name>
|
||||
<jetty.test.policy.loc>target/test-policy</jetty.test.policy.loc>
|
||||
</properties>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.felix</groupId>
|
||||
<artifactId>maven-bundle-plugin</artifactId>
|
||||
<extensions>true</extensions>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>manifest</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<instructions>
|
||||
<Import-Package>javax.net.*,*</Import-Package>
|
||||
</instructions>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<!--
|
||||
Required for OSGI
|
||||
-->
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-jar-plugin</artifactId>
|
||||
<configuration>
|
||||
<archive>
|
||||
<manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile>
|
||||
</archive>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>findbugs-maven-plugin</artifactId>
|
||||
<configuration>
|
||||
<onlyAnalyze>org.eclipse.jetty.client.*</onlyAnalyze>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-dependency-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>unpack</id>
|
||||
<phase>generate-test-resources</phase>
|
||||
<goals>
|
||||
<goal>unpack</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<artifactItems>
|
||||
<artifactItem>
|
||||
<groupId>org.eclipse.jetty.toolchain</groupId>
|
||||
<artifactId>jetty-test-policy</artifactId>
|
||||
<version>${jetty-test-policy-version}</version>
|
||||
<type>jar</type>
|
||||
<overWrite>true</overWrite>
|
||||
<includes>**/*.keystore,**/*.pem</includes>
|
||||
<outputDirectory>${jetty.test.policy.loc}</outputDirectory>
|
||||
</artifactItem>
|
||||
</artifactItems>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-http</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-server</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-security</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-servlet</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<!--
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-websocket</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>-->
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty.toolchain</groupId>
|
||||
<artifactId>jetty-test-helper</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
|
@ -1,570 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2012 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.client;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Collections;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import org.eclipse.jetty.client.security.Authentication;
|
||||
import org.eclipse.jetty.http.HttpFields;
|
||||
import org.eclipse.jetty.http.HttpGenerator;
|
||||
import org.eclipse.jetty.http.HttpHeaderValue;
|
||||
import org.eclipse.jetty.http.HttpHeader;
|
||||
import org.eclipse.jetty.http.HttpMethod;
|
||||
import org.eclipse.jetty.http.HttpParser;
|
||||
import org.eclipse.jetty.http.HttpScheme;
|
||||
import org.eclipse.jetty.http.HttpStatus;
|
||||
import org.eclipse.jetty.http.HttpVersion;
|
||||
import org.eclipse.jetty.io.AbstractConnection;
|
||||
|
||||
import org.eclipse.jetty.io.Buffers;
|
||||
import org.eclipse.jetty.io.ByteArrayBuffer;
|
||||
import org.eclipse.jetty.io.Connection;
|
||||
import org.eclipse.jetty.io.EndPoint;
|
||||
import org.eclipse.jetty.io.EofException;
|
||||
import org.eclipse.jetty.io.View;
|
||||
import org.eclipse.jetty.util.component.AggregateLifeCycle;
|
||||
import org.eclipse.jetty.util.component.Dumpable;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
import org.eclipse.jetty.util.thread.Timeout;
|
||||
|
||||
/**
|
||||
*
|
||||
* @version $Revision: 879 $ $Date: 2009-09-11 16:13:28 +0200 (Fri, 11 Sep 2009) $
|
||||
*/
|
||||
public abstract class AbstractHttpConnection extends AbstractConnection implements Dumpable
|
||||
{
|
||||
private static final Logger LOG = Log.getLogger(AbstractHttpConnection.class);
|
||||
|
||||
protected HttpDestination _destination;
|
||||
protected HttpGenerator _generator;
|
||||
protected HttpParser _parser;
|
||||
protected boolean _http11 = true;
|
||||
protected int _status;
|
||||
protected ByteBuffer _connectionHeader;
|
||||
protected boolean _reserved;
|
||||
|
||||
// The current exchange waiting for a response
|
||||
protected volatile HttpExchange _exchange;
|
||||
protected HttpExchange _pipeline;
|
||||
private final Timeout.Task _idleTimeout = new ConnectionIdleTask();
|
||||
private AtomicBoolean _idle = new AtomicBoolean(false);
|
||||
|
||||
|
||||
AbstractHttpConnection(Buffers requestBuffers, Buffers responseBuffers, EndPoint endp)
|
||||
{
|
||||
super(endp);
|
||||
|
||||
_generator = new HttpGenerator(requestBuffers,endp);
|
||||
_parser = new HttpParser(responseBuffers,endp,new Handler());
|
||||
}
|
||||
|
||||
public void setReserved (boolean reserved)
|
||||
{
|
||||
_reserved = reserved;
|
||||
}
|
||||
|
||||
public boolean isReserved()
|
||||
{
|
||||
return _reserved;
|
||||
}
|
||||
|
||||
public HttpDestination getDestination()
|
||||
{
|
||||
return _destination;
|
||||
}
|
||||
|
||||
public void setDestination(HttpDestination destination)
|
||||
{
|
||||
_destination = destination;
|
||||
}
|
||||
|
||||
public boolean send(HttpExchange ex) throws IOException
|
||||
{
|
||||
LOG.debug("Send {} on {}",ex,this);
|
||||
synchronized (this)
|
||||
{
|
||||
if (_exchange != null)
|
||||
{
|
||||
if (_pipeline != null)
|
||||
throw new IllegalStateException(this + " PIPELINED!!! _exchange=" + _exchange);
|
||||
_pipeline = ex;
|
||||
return true;
|
||||
}
|
||||
|
||||
_exchange = ex;
|
||||
_exchange.associate(this);
|
||||
|
||||
// The call to associate() may have closed the connection, check if it's the case
|
||||
if (!_endp.isOpen())
|
||||
{
|
||||
_exchange.disassociate();
|
||||
_exchange = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
_exchange.setStatus(HttpExchange.STATUS_WAITING_FOR_COMMIT);
|
||||
|
||||
adjustIdleTimeout();
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
private void adjustIdleTimeout() throws IOException
|
||||
{
|
||||
// Adjusts the idle timeout in case the default or exchange timeout
|
||||
// are greater. This is needed for long polls, where one wants an
|
||||
// aggressive releasing of idle connections (so idle timeout is small)
|
||||
// but still allow long polls to complete normally
|
||||
|
||||
long timeout = _exchange.getTimeout();
|
||||
if (timeout <= 0)
|
||||
timeout = _destination.getHttpClient().getTimeout();
|
||||
|
||||
long endPointTimeout = _endp.getMaxIdleTime();
|
||||
|
||||
if (timeout > 0 && timeout > endPointTimeout)
|
||||
{
|
||||
// Make it larger than the exchange timeout so that there are
|
||||
// no races between the idle timeout and the exchange timeout
|
||||
// when trying to close the endpoint
|
||||
_endp.setMaxIdleTime(2 * (int)timeout);
|
||||
}
|
||||
}
|
||||
|
||||
public abstract Connection handle() throws IOException;
|
||||
|
||||
|
||||
public boolean isIdle()
|
||||
{
|
||||
synchronized (this)
|
||||
{
|
||||
return _exchange == null;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isSuspended()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public void onClose()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws IOException
|
||||
*/
|
||||
protected void commitRequest() throws IOException
|
||||
{
|
||||
synchronized (this)
|
||||
{
|
||||
_status=0;
|
||||
if (_exchange.getStatus() != HttpExchange.STATUS_WAITING_FOR_COMMIT)
|
||||
throw new IllegalStateException();
|
||||
|
||||
_exchange.setStatus(HttpExchange.STATUS_SENDING_REQUEST);
|
||||
_generator.setVersion(_exchange.getVersion());
|
||||
|
||||
String method=_exchange.getMethod();
|
||||
String uri = _exchange.getRequestURI();
|
||||
if (_destination.isProxied())
|
||||
{
|
||||
if (!HttpMethod.CONNECT.equals(method) && uri.startsWith("/"))
|
||||
{
|
||||
boolean secure = _destination.isSecure();
|
||||
String host = _destination.getAddress().getHost();
|
||||
int port = _destination.getAddress().getPort();
|
||||
StringBuilder absoluteURI = new StringBuilder();
|
||||
absoluteURI.append(secure ? HttpScheme.HTTPS : HttpScheme.HTTP);
|
||||
absoluteURI.append("://");
|
||||
absoluteURI.append(host);
|
||||
// Avoid adding default ports
|
||||
if (!(secure && port == 443 || !secure && port == 80))
|
||||
absoluteURI.append(":").append(port);
|
||||
absoluteURI.append(uri);
|
||||
uri = absoluteURI.toString();
|
||||
}
|
||||
Authentication auth = _destination.getProxyAuthentication();
|
||||
if (auth != null)
|
||||
auth.setCredentials(_exchange);
|
||||
}
|
||||
|
||||
_generator.setRequest(method, uri);
|
||||
_parser.setHeadResponse(HttpMethod.HEAD.equalsIgnoreCase(method));
|
||||
|
||||
HttpFields requestHeaders = _exchange.getRequestFields();
|
||||
if (_exchange.getVersion() >= HttpVersion.HTTP_1_1_ORDINAL)
|
||||
{
|
||||
if (!requestHeaders.containsKey(HttpHeader.HOST_BUFFER))
|
||||
requestHeaders.add(HttpHeader.HOST_BUFFER,_destination.getHostHeader());
|
||||
}
|
||||
|
||||
ByteBuffer requestContent = _exchange.getRequestContent();
|
||||
if (requestContent != null)
|
||||
{
|
||||
requestHeaders.putLongField(HttpHeader.CONTENT_LENGTH, requestContent.length());
|
||||
_generator.completeHeader(requestHeaders,false);
|
||||
_generator.addContent(new View(requestContent),true);
|
||||
_exchange.setStatus(HttpExchange.STATUS_WAITING_FOR_RESPONSE);
|
||||
}
|
||||
else
|
||||
{
|
||||
InputStream requestContentStream = _exchange.getRequestContentSource();
|
||||
if (requestContentStream != null)
|
||||
{
|
||||
_generator.completeHeader(requestHeaders, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
requestHeaders.remove(HttpHeader.CONTENT_LENGTH);
|
||||
_generator.completeHeader(requestHeaders, true);
|
||||
_exchange.setStatus(HttpExchange.STATUS_WAITING_FOR_RESPONSE);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void reset() throws IOException
|
||||
{
|
||||
_connectionHeader = null;
|
||||
_parser.reset();
|
||||
_generator.reset();
|
||||
_http11 = true;
|
||||
}
|
||||
|
||||
|
||||
private class Handler extends HttpParser.EventHandler
|
||||
{
|
||||
@Override
|
||||
public void startRequest(ByteBuffer method, ByteBuffer url, ByteBuffer version) throws IOException
|
||||
{
|
||||
// System.out.println( method.toString() + "///" + url.toString() +
|
||||
// "///" + version.toString() );
|
||||
// TODO validate this is acceptable, the <!DOCTYPE goop was coming
|
||||
// out here
|
||||
// throw new IllegalStateException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startResponse(ByteBuffer version, int status, ByteBuffer reason) throws IOException
|
||||
{
|
||||
HttpExchange exchange = _exchange;
|
||||
if (exchange==null)
|
||||
{
|
||||
LOG.warn("No exchange for response");
|
||||
_endp.close();
|
||||
return;
|
||||
}
|
||||
|
||||
switch(status)
|
||||
{
|
||||
case HttpStatus.CONTINUE_100:
|
||||
case HttpStatus.PROCESSING_102:
|
||||
// TODO check if appropriate expect was sent in the request.
|
||||
exchange.setEventListener(new NonFinalResponseListener(exchange));
|
||||
break;
|
||||
|
||||
case HttpStatus.OK_200:
|
||||
// handle special case for CONNECT 200 responses
|
||||
if (HttpMethod.CONNECT.equalsIgnoreCase(exchange.getMethod()))
|
||||
_parser.setHeadResponse(true);
|
||||
break;
|
||||
}
|
||||
|
||||
_http11 = HttpVersion.HTTP_1_1_BUFFER.equals(version);
|
||||
_status=status;
|
||||
exchange.getEventListener().onResponseStatus(version,status,reason);
|
||||
exchange.setStatus(HttpExchange.STATUS_PARSING_HEADERS);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void parsedHeader(ByteBuffer name, ByteBuffer value) throws IOException
|
||||
{
|
||||
HttpExchange exchange = _exchange;
|
||||
if (exchange!=null)
|
||||
{
|
||||
if (HttpHeader.CACHE.getOrdinal(name) == HttpHeader.CONNECTION_ORDINAL)
|
||||
{
|
||||
_connectionHeader = HttpHeaderValue.CACHE.lookup(value);
|
||||
}
|
||||
exchange.getEventListener().onResponseHeader(name,value);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void headerComplete() throws IOException
|
||||
{
|
||||
HttpExchange exchange = _exchange;
|
||||
if (exchange!=null)
|
||||
exchange.setStatus(HttpExchange.STATUS_PARSING_CONTENT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void content(ByteBuffer ref) throws IOException
|
||||
{
|
||||
HttpExchange exchange = _exchange;
|
||||
if (exchange!=null)
|
||||
exchange.getEventListener().onResponseContent(ref);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void messageComplete(long contextLength) throws IOException
|
||||
{
|
||||
HttpExchange exchange = _exchange;
|
||||
if (exchange!=null)
|
||||
exchange.setStatus(HttpExchange.STATUS_COMPLETED);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void earlyEOF()
|
||||
{
|
||||
HttpExchange exchange = _exchange;
|
||||
if (exchange!=null)
|
||||
{
|
||||
if (!exchange.isDone())
|
||||
{
|
||||
if (exchange.setStatus(HttpExchange.STATUS_EXCEPTED))
|
||||
exchange.getEventListener().onException(new EofException("early EOF"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return String.format("%s %s g=%s p=%s",
|
||||
super.toString(),
|
||||
_destination == null ? "?.?.?.?:??" : _destination.getAddress(),
|
||||
_generator,
|
||||
_parser);
|
||||
}
|
||||
|
||||
public String toDetailString()
|
||||
{
|
||||
return toString() + " ex=" + _exchange + " idle for " + _idleTimeout.getAge();
|
||||
}
|
||||
|
||||
public void close() throws IOException
|
||||
{
|
||||
//if there is a live, unfinished exchange, set its status to be
|
||||
//excepted and wake up anyone waiting on waitForDone()
|
||||
|
||||
HttpExchange exchange = _exchange;
|
||||
if (exchange != null && !exchange.isDone())
|
||||
{
|
||||
switch (exchange.getStatus())
|
||||
{
|
||||
case HttpExchange.STATUS_CANCELLED:
|
||||
case HttpExchange.STATUS_CANCELLING:
|
||||
case HttpExchange.STATUS_COMPLETED:
|
||||
case HttpExchange.STATUS_EXCEPTED:
|
||||
case HttpExchange.STATUS_EXPIRED:
|
||||
break;
|
||||
case HttpExchange.STATUS_PARSING_CONTENT:
|
||||
if (_endp.isInputShutdown() && _parser.isState(HttpParser.STATE_EOF_CONTENT))
|
||||
break;
|
||||
default:
|
||||
String exch= exchange.toString();
|
||||
String reason = _endp.isOpen()?(_endp.isInputShutdown()?"half closed: ":"local close: "):"closed: ";
|
||||
if (exchange.setStatus(HttpExchange.STATUS_EXCEPTED))
|
||||
exchange.getEventListener().onException(new EofException(reason+exch));
|
||||
}
|
||||
}
|
||||
|
||||
if (_endp.isOpen())
|
||||
{
|
||||
_endp.close();
|
||||
_destination.returnConnection(this, true);
|
||||
}
|
||||
}
|
||||
|
||||
public void setIdleTimeout()
|
||||
{
|
||||
synchronized (this)
|
||||
{
|
||||
if (_idle.compareAndSet(false, true))
|
||||
_destination.getHttpClient().scheduleIdle(_idleTimeout);
|
||||
else
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean cancelIdleTimeout()
|
||||
{
|
||||
synchronized (this)
|
||||
{
|
||||
if (_idle.compareAndSet(true, false))
|
||||
{
|
||||
_destination.getHttpClient().cancel(_idleTimeout);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
protected void exchangeExpired(HttpExchange exchange)
|
||||
{
|
||||
synchronized (this)
|
||||
{
|
||||
// We are expiring an exchange, but the exchange is pending
|
||||
// Cannot reuse the connection because the reply may arrive, so close it
|
||||
if (_exchange == exchange)
|
||||
{
|
||||
try
|
||||
{
|
||||
_destination.returnConnection(this, true);
|
||||
}
|
||||
catch (IOException x)
|
||||
{
|
||||
LOG.ignore(x);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @see org.eclipse.jetty.util.component.Dumpable#dump()
|
||||
*/
|
||||
public String dump()
|
||||
{
|
||||
return AggregateLifeCycle.dump(this);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @see org.eclipse.jetty.util.component.Dumpable#dump(java.lang.Appendable, java.lang.String)
|
||||
*/
|
||||
public void dump(Appendable out, String indent) throws IOException
|
||||
{
|
||||
synchronized (this)
|
||||
{
|
||||
out.append(String.valueOf(this)).append("\n");
|
||||
AggregateLifeCycle.dump(out,indent,Collections.singletonList(_endp));
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
private class ConnectionIdleTask extends Timeout.Task
|
||||
{
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
public void expired()
|
||||
{
|
||||
// Connection idle, close it
|
||||
if (_idle.compareAndSet(true, false))
|
||||
{
|
||||
_destination.returnIdleConnection(AbstractHttpConnection.this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
private class NonFinalResponseListener implements HttpEventListener
|
||||
{
|
||||
final HttpExchange _exchange;
|
||||
final HttpEventListener _next;
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public NonFinalResponseListener(HttpExchange exchange)
|
||||
{
|
||||
_exchange=exchange;
|
||||
_next=exchange.getEventListener();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public void onRequestCommitted() throws IOException
|
||||
{
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public void onRequestComplete() throws IOException
|
||||
{
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public void onResponseStatus(ByteBuffer version, int status, ByteBuffer reason) throws IOException
|
||||
{
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public void onResponseHeader(ByteBuffer name, ByteBuffer value) throws IOException
|
||||
{
|
||||
_next.onResponseHeader(name,value);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public void onResponseHeaderComplete() throws IOException
|
||||
{
|
||||
_next.onResponseHeaderComplete();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public void onResponseContent(ByteBuffer content) throws IOException
|
||||
{
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public void onResponseComplete() throws IOException
|
||||
{
|
||||
_exchange.setEventListener(_next);
|
||||
_exchange.setStatus(HttpExchange.STATUS_WAITING_FOR_RESPONSE);
|
||||
_parser.reset();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public void onConnectionFailed(Throwable ex)
|
||||
{
|
||||
_exchange.setEventListener(_next);
|
||||
_next.onConnectionFailed(ex);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public void onException(Throwable ex)
|
||||
{
|
||||
_exchange.setEventListener(_next);
|
||||
_next.onException(ex);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public void onExpire()
|
||||
{
|
||||
_exchange.setEventListener(_next);
|
||||
_next.onExpire();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public void onRetry()
|
||||
{
|
||||
_exchange.setEventListener(_next);
|
||||
_next.onRetry();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,96 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2012 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.client;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
|
||||
/**
|
||||
* @version $Revision: 4135 $ $Date: 2008-12-02 11:57:07 +0100 (Tue, 02 Dec 2008) $
|
||||
*/
|
||||
public class Address
|
||||
{
|
||||
private final String host;
|
||||
private final int port;
|
||||
|
||||
public static Address from(String hostAndPort)
|
||||
{
|
||||
String host;
|
||||
int port;
|
||||
int colon = hostAndPort.indexOf(':');
|
||||
if (colon >= 0)
|
||||
{
|
||||
host = hostAndPort.substring(0, colon);
|
||||
port = Integer.parseInt(hostAndPort.substring(colon + 1));
|
||||
}
|
||||
else
|
||||
{
|
||||
host = hostAndPort;
|
||||
port = 0;
|
||||
}
|
||||
return new Address(host, port);
|
||||
}
|
||||
|
||||
public Address(String host, int port)
|
||||
{
|
||||
if (host == null)
|
||||
throw new IllegalArgumentException("Host is null");
|
||||
|
||||
this.host = host.trim();
|
||||
this.port = port;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj)
|
||||
{
|
||||
if (this == obj) return true;
|
||||
if (obj == null || getClass() != obj.getClass()) return false;
|
||||
Address that = (Address)obj;
|
||||
if (!host.equals(that.host)) return false;
|
||||
return port == that.port;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode()
|
||||
{
|
||||
int result = host.hashCode();
|
||||
result = 31 * result + port;
|
||||
return result;
|
||||
}
|
||||
|
||||
public String getHost()
|
||||
{
|
||||
return host;
|
||||
}
|
||||
|
||||
public int getPort()
|
||||
{
|
||||
return port;
|
||||
}
|
||||
|
||||
public InetSocketAddress toSocketAddress()
|
||||
{
|
||||
return new InetSocketAddress(getHost(), getPort());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return host + ":" + port;
|
||||
}
|
||||
}
|
|
@ -1,267 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2012 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.client;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.eclipse.jetty.http.AbstractGenerator;
|
||||
import org.eclipse.jetty.http.HttpStatus;
|
||||
import org.eclipse.jetty.io.AsyncEndPoint;
|
||||
|
||||
import org.eclipse.jetty.io.Buffers;
|
||||
import org.eclipse.jetty.io.Connection;
|
||||
import org.eclipse.jetty.io.EndPoint;
|
||||
import org.eclipse.jetty.io.nio.AsyncConnection;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Asynchronous Client HTTP Connection
|
||||
*/
|
||||
public class AsyncHttpConnection extends AbstractHttpConnection implements AsyncConnection
|
||||
{
|
||||
private static final Logger LOG = Log.getLogger(AsyncHttpConnection.class);
|
||||
|
||||
private boolean _requestComplete;
|
||||
private ByteBuffer _requestContentChunk;
|
||||
private final AsyncEndPoint _asyncEndp;
|
||||
|
||||
AsyncHttpConnection(Buffers requestBuffers, Buffers responseBuffers, EndPoint endp)
|
||||
{
|
||||
super(requestBuffers,responseBuffers,endp);
|
||||
_asyncEndp=(AsyncEndPoint)endp;
|
||||
}
|
||||
|
||||
protected void reset() throws IOException
|
||||
{
|
||||
_requestComplete = false;
|
||||
super.reset();
|
||||
}
|
||||
|
||||
public Connection handle() throws IOException
|
||||
{
|
||||
Connection connection = this;
|
||||
boolean progress=true;
|
||||
|
||||
try
|
||||
{
|
||||
boolean failed = false;
|
||||
|
||||
// While we are making progress and have not changed connection
|
||||
while (progress && connection==this)
|
||||
{
|
||||
LOG.debug("while open={} more={} progress={}",_endp.isOpen(),_parser.isMoreInBuffer(),progress);
|
||||
|
||||
progress=false;
|
||||
HttpExchange exchange=_exchange;
|
||||
|
||||
LOG.debug("exchange {} on {}",exchange,this);
|
||||
|
||||
try
|
||||
{
|
||||
// Should we commit the request?
|
||||
if (!_generator.isCommitted() && exchange!=null && exchange.getStatus() == HttpExchange.STATUS_WAITING_FOR_COMMIT)
|
||||
{
|
||||
LOG.debug("commit {}",exchange);
|
||||
progress=true;
|
||||
commitRequest();
|
||||
}
|
||||
|
||||
// Generate output
|
||||
if (_generator.isCommitted() && !_generator.isComplete())
|
||||
{
|
||||
if (_generator.flushBuffer()>0)
|
||||
{
|
||||
LOG.debug("flushed");
|
||||
progress=true;
|
||||
}
|
||||
|
||||
// Is there more content to send or should we complete the generator
|
||||
if (_generator.isState(AbstractGenerator.STATE_CONTENT))
|
||||
{
|
||||
// Look for more content to send.
|
||||
if (_requestContentChunk==null)
|
||||
_requestContentChunk = exchange.getRequestContentChunk(null);
|
||||
|
||||
if (_requestContentChunk==null)
|
||||
{
|
||||
LOG.debug("complete {}",exchange);
|
||||
progress=true;
|
||||
_generator.complete();
|
||||
}
|
||||
else if (_generator.isEmpty())
|
||||
{
|
||||
LOG.debug("addChunk");
|
||||
progress=true;
|
||||
ByteBuffer chunk=_requestContentChunk;
|
||||
_requestContentChunk=exchange.getRequestContentChunk(null);
|
||||
_generator.addContent(chunk,_requestContentChunk==null);
|
||||
if (_requestContentChunk==null)
|
||||
exchange.setStatus(HttpExchange.STATUS_WAITING_FOR_RESPONSE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Signal request completion
|
||||
if (_generator.isComplete() && !_requestComplete)
|
||||
{
|
||||
LOG.debug("requestComplete {}",exchange);
|
||||
progress=true;
|
||||
_requestComplete = true;
|
||||
exchange.getEventListener().onRequestComplete();
|
||||
}
|
||||
|
||||
// Read any input that is available
|
||||
if (!_parser.isComplete() && _parser.parseAvailable())
|
||||
{
|
||||
LOG.debug("parsed {}",exchange);
|
||||
progress=true;
|
||||
}
|
||||
|
||||
// Flush output
|
||||
_endp.flush();
|
||||
|
||||
// Has any IO been done by the endpoint itself since last loop
|
||||
if (_asyncEndp.hasProgressed())
|
||||
{
|
||||
LOG.debug("hasProgressed {}",exchange);
|
||||
progress=true;
|
||||
}
|
||||
}
|
||||
catch (Throwable e)
|
||||
{
|
||||
LOG.debug("Failure on " + _exchange, e);
|
||||
|
||||
failed = true;
|
||||
|
||||
synchronized (this)
|
||||
{
|
||||
if (exchange != null)
|
||||
{
|
||||
// Cancelling the exchange causes an exception as we close the connection,
|
||||
// but we don't report it as it is normal cancelling operation
|
||||
if (exchange.getStatus() != HttpExchange.STATUS_CANCELLING &&
|
||||
exchange.getStatus() != HttpExchange.STATUS_CANCELLED &&
|
||||
!exchange.isDone())
|
||||
{
|
||||
if (exchange.setStatus(HttpExchange.STATUS_EXCEPTED))
|
||||
exchange.getEventListener().onException(e);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (e instanceof IOException)
|
||||
throw (IOException)e;
|
||||
if (e instanceof Error)
|
||||
throw (Error)e;
|
||||
if (e instanceof RuntimeException)
|
||||
throw (RuntimeException)e;
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
LOG.debug("finally {} on {} progress={} {}",exchange,this,progress,_endp);
|
||||
|
||||
boolean complete = failed || _generator.isComplete() && _parser.isComplete();
|
||||
|
||||
if (complete)
|
||||
{
|
||||
boolean persistent = !failed && _parser.isPersistent() && _generator.isPersistent();
|
||||
_generator.setPersistent(persistent);
|
||||
reset();
|
||||
if (persistent)
|
||||
_endp.setMaxIdleTime((int)_destination.getHttpClient().getIdleTimeout());
|
||||
|
||||
synchronized (this)
|
||||
{
|
||||
exchange=_exchange;
|
||||
_exchange = null;
|
||||
|
||||
// Cancel the exchange
|
||||
if (exchange!=null)
|
||||
{
|
||||
exchange.cancelTimeout(_destination.getHttpClient());
|
||||
|
||||
// TODO should we check the exchange is done?
|
||||
}
|
||||
|
||||
// handle switched protocols
|
||||
if (_status==HttpStatus.SWITCHING_PROTOCOLS_101)
|
||||
{
|
||||
Connection switched=exchange.onSwitchProtocol(_endp);
|
||||
if (switched!=null)
|
||||
{
|
||||
// switched protocol!
|
||||
if (_pipeline!=null)
|
||||
{
|
||||
_destination.send(_pipeline);
|
||||
}
|
||||
_pipeline = null;
|
||||
|
||||
connection=switched;
|
||||
}
|
||||
}
|
||||
|
||||
// handle pipelined requests
|
||||
if (_pipeline!=null)
|
||||
{
|
||||
if (!persistent || connection!=this)
|
||||
_destination.send(_pipeline);
|
||||
else
|
||||
_exchange=_pipeline;
|
||||
_pipeline=null;
|
||||
}
|
||||
|
||||
if (_exchange==null && !isReserved()) // TODO how do we return switched connections?
|
||||
_destination.returnConnection(this, !persistent);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
_parser.returnBuffers();
|
||||
_generator.returnBuffers();
|
||||
LOG.debug("unhandle {} on {}",_exchange,_endp);
|
||||
}
|
||||
|
||||
return connection;
|
||||
}
|
||||
|
||||
public void onInputShutdown() throws IOException
|
||||
{
|
||||
if (_generator.isIdle())
|
||||
_endp.shutdownOutput();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean send(HttpExchange ex) throws IOException
|
||||
{
|
||||
boolean sent=super.send(ex);
|
||||
if (sent)
|
||||
_asyncEndp.asyncDispatch();
|
||||
return sent;
|
||||
}
|
||||
}
|
|
@ -1,264 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2012 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.client;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InterruptedIOException;
|
||||
|
||||
import org.eclipse.jetty.http.AbstractGenerator;
|
||||
import org.eclipse.jetty.http.HttpStatus;
|
||||
|
||||
import org.eclipse.jetty.io.Buffers;
|
||||
import org.eclipse.jetty.io.Connection;
|
||||
import org.eclipse.jetty.io.EndPoint;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Blocking HTTP Connection
|
||||
*/
|
||||
public class BlockingHttpConnection extends AbstractHttpConnection
|
||||
{
|
||||
private static final Logger LOG = Log.getLogger(BlockingHttpConnection.class);
|
||||
|
||||
private boolean _requestComplete;
|
||||
private ByteBuffer _requestContentChunk;
|
||||
|
||||
BlockingHttpConnection(Buffers requestBuffers, Buffers responseBuffers, EndPoint endPoint)
|
||||
{
|
||||
super(requestBuffers, responseBuffers, endPoint);
|
||||
}
|
||||
|
||||
protected void reset() throws IOException
|
||||
{
|
||||
_requestComplete = false;
|
||||
super.reset();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Connection handle() throws IOException
|
||||
{
|
||||
Connection connection = this;
|
||||
|
||||
try
|
||||
{
|
||||
boolean failed = false;
|
||||
|
||||
|
||||
// While we are making progress and have not changed connection
|
||||
while (_endp.isOpen() && connection==this)
|
||||
{
|
||||
LOG.debug("open={} more={}",_endp.isOpen(),_parser.isMoreInBuffer());
|
||||
|
||||
HttpExchange exchange;
|
||||
synchronized (this)
|
||||
{
|
||||
exchange=_exchange;
|
||||
|
||||
while (exchange == null)
|
||||
{
|
||||
try
|
||||
{
|
||||
this.wait();
|
||||
exchange=_exchange;
|
||||
}
|
||||
catch (InterruptedException e)
|
||||
{
|
||||
throw new InterruptedIOException();
|
||||
}
|
||||
}
|
||||
}
|
||||
LOG.debug("exchange {}",exchange);
|
||||
|
||||
try
|
||||
{
|
||||
// Should we commit the request?
|
||||
if (!_generator.isCommitted() && exchange!=null && exchange.getStatus() == HttpExchange.STATUS_WAITING_FOR_COMMIT)
|
||||
{
|
||||
LOG.debug("commit");
|
||||
commitRequest();
|
||||
}
|
||||
|
||||
// Generate output
|
||||
while (_generator.isCommitted() && !_generator.isComplete())
|
||||
{
|
||||
if (_generator.flushBuffer()>0)
|
||||
{
|
||||
LOG.debug("flushed");
|
||||
}
|
||||
|
||||
// Is there more content to send or should we complete the generator
|
||||
if (_generator.isState(AbstractGenerator.STATE_CONTENT))
|
||||
{
|
||||
// Look for more content to send.
|
||||
if (_requestContentChunk==null)
|
||||
_requestContentChunk = exchange.getRequestContentChunk(null);
|
||||
|
||||
if (_requestContentChunk==null)
|
||||
{
|
||||
LOG.debug("complete");
|
||||
_generator.complete();
|
||||
}
|
||||
else if (_generator.isEmpty())
|
||||
{
|
||||
LOG.debug("addChunk");
|
||||
ByteBuffer chunk=_requestContentChunk;
|
||||
_requestContentChunk=exchange.getRequestContentChunk(null);
|
||||
_generator.addContent(chunk,_requestContentChunk==null);
|
||||
if (_requestContentChunk==null)
|
||||
exchange.setStatus(HttpExchange.STATUS_WAITING_FOR_RESPONSE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Signal request completion
|
||||
if (_generator.isComplete() && !_requestComplete)
|
||||
{
|
||||
LOG.debug("requestComplete");
|
||||
_requestComplete = true;
|
||||
exchange.getEventListener().onRequestComplete();
|
||||
}
|
||||
|
||||
// Read any input that is available
|
||||
if (!_parser.isComplete() && _parser.parseAvailable())
|
||||
{
|
||||
LOG.debug("parsed");
|
||||
}
|
||||
|
||||
// Flush output
|
||||
_endp.flush();
|
||||
}
|
||||
catch (Throwable e)
|
||||
{
|
||||
LOG.debug("Failure on " + _exchange, e);
|
||||
|
||||
failed = true;
|
||||
|
||||
synchronized (this)
|
||||
{
|
||||
if (exchange != null)
|
||||
{
|
||||
// Cancelling the exchange causes an exception as we close the connection,
|
||||
// but we don't report it as it is normal cancelling operation
|
||||
if (exchange.getStatus() != HttpExchange.STATUS_CANCELLING &&
|
||||
exchange.getStatus() != HttpExchange.STATUS_CANCELLED &&
|
||||
!exchange.isDone())
|
||||
{
|
||||
if(exchange.setStatus(HttpExchange.STATUS_EXCEPTED))
|
||||
exchange.getEventListener().onException(e);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (e instanceof IOException)
|
||||
throw (IOException)e;
|
||||
if (e instanceof Error)
|
||||
throw (Error)e;
|
||||
if (e instanceof RuntimeException)
|
||||
throw (RuntimeException)e;
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
LOG.debug("{} {}",_generator, _parser);
|
||||
LOG.debug("{}",_endp);
|
||||
|
||||
boolean complete = failed || _generator.isComplete() && _parser.isComplete();
|
||||
|
||||
if (complete)
|
||||
{
|
||||
boolean persistent = !failed && _parser.isPersistent() && _generator.isPersistent();
|
||||
_generator.setPersistent(persistent);
|
||||
reset();
|
||||
if (persistent)
|
||||
_endp.setMaxIdleTime((int)_destination.getHttpClient().getIdleTimeout());
|
||||
|
||||
synchronized (this)
|
||||
{
|
||||
exchange=_exchange;
|
||||
_exchange = null;
|
||||
|
||||
// Cancel the exchange
|
||||
if (exchange!=null)
|
||||
{
|
||||
exchange.cancelTimeout(_destination.getHttpClient());
|
||||
|
||||
// TODO should we check the exchange is done?
|
||||
}
|
||||
|
||||
// handle switched protocols
|
||||
if (_status==HttpStatus.SWITCHING_PROTOCOLS_101)
|
||||
{
|
||||
Connection switched=exchange.onSwitchProtocol(_endp);
|
||||
if (switched!=null)
|
||||
connection=switched;
|
||||
{
|
||||
// switched protocol!
|
||||
_pipeline = null;
|
||||
if (_pipeline!=null)
|
||||
_destination.send(_pipeline);
|
||||
_pipeline = null;
|
||||
|
||||
connection=switched;
|
||||
}
|
||||
}
|
||||
|
||||
// handle pipelined requests
|
||||
if (_pipeline!=null)
|
||||
{
|
||||
if (!persistent || connection!=this)
|
||||
_destination.send(_pipeline);
|
||||
else
|
||||
_exchange=_pipeline;
|
||||
_pipeline=null;
|
||||
}
|
||||
|
||||
if (_exchange==null && !isReserved()) // TODO how do we return switched connections?
|
||||
_destination.returnConnection(this, !persistent);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
_parser.returnBuffers();
|
||||
_generator.returnBuffers();
|
||||
}
|
||||
|
||||
return connection;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean send(HttpExchange ex) throws IOException
|
||||
{
|
||||
boolean sent=super.send(ex);
|
||||
if (sent)
|
||||
{
|
||||
synchronized (this)
|
||||
{
|
||||
notifyAll();
|
||||
}
|
||||
}
|
||||
return sent;
|
||||
}
|
||||
}
|
|
@ -1,75 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2012 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.client;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.eclipse.jetty.http.HttpFields;
|
||||
|
||||
|
||||
/**
|
||||
* An exchange that retains response status and response headers for later use.
|
||||
*/
|
||||
public class CachedExchange extends HttpExchange
|
||||
{
|
||||
private final HttpFields _responseFields;
|
||||
private volatile int _responseStatus;
|
||||
|
||||
/**
|
||||
* Creates a new CachedExchange.
|
||||
*
|
||||
* @param cacheHeaders true to cache response headers, false to not cache them
|
||||
*/
|
||||
public CachedExchange(boolean cacheHeaders)
|
||||
{
|
||||
_responseFields = cacheHeaders ? new HttpFields() : null;
|
||||
}
|
||||
|
||||
public synchronized int getResponseStatus()
|
||||
{
|
||||
if (getStatus() < HttpExchange.STATUS_PARSING_HEADERS)
|
||||
throw new IllegalStateException("Response not received yet");
|
||||
return _responseStatus;
|
||||
}
|
||||
|
||||
public synchronized HttpFields getResponseFields()
|
||||
{
|
||||
if (getStatus() < HttpExchange.STATUS_PARSING_CONTENT)
|
||||
throw new IllegalStateException("Headers not completely received yet");
|
||||
return _responseFields;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected synchronized void onResponseStatus(ByteBuffer version, int status, ByteBuffer reason) throws IOException
|
||||
{
|
||||
_responseStatus = status;
|
||||
super.onResponseStatus(version, status, reason);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected synchronized void onResponseHeader(ByteBuffer name, ByteBuffer value) throws IOException
|
||||
{
|
||||
if (_responseFields != null)
|
||||
{
|
||||
_responseFields.add(name, value.asImmutableBuffer());
|
||||
}
|
||||
|
||||
super.onResponseHeader(name, value);
|
||||
}
|
||||
}
|
|
@ -1,135 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2012 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.client;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
|
||||
import org.eclipse.jetty.http.HttpHeader;
|
||||
|
||||
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
|
||||
/**
|
||||
* A exchange that retains response content for later use.
|
||||
*/
|
||||
public class ContentExchange extends CachedExchange
|
||||
{
|
||||
private int _bufferSize = 4096;
|
||||
private String _encoding = "utf-8";
|
||||
private ByteArrayOutputStream _responseContent;
|
||||
private File _fileForUpload;
|
||||
|
||||
public ContentExchange()
|
||||
{
|
||||
super(false);
|
||||
}
|
||||
|
||||
public ContentExchange(boolean cacheFields)
|
||||
{
|
||||
super(cacheFields);
|
||||
}
|
||||
|
||||
public synchronized String getResponseContent() throws UnsupportedEncodingException
|
||||
{
|
||||
if (_responseContent != null)
|
||||
return _responseContent.toString(_encoding);
|
||||
return null;
|
||||
}
|
||||
|
||||
public synchronized byte[] getResponseContentBytes()
|
||||
{
|
||||
if (_responseContent != null)
|
||||
return _responseContent.toByteArray();
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected synchronized void onResponseStatus(ByteBuffer version, int status, ByteBuffer reason) throws IOException
|
||||
{
|
||||
if (_responseContent!=null)
|
||||
_responseContent.reset();
|
||||
super.onResponseStatus(version,status,reason);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected synchronized void onResponseHeader(ByteBuffer name, ByteBuffer value) throws IOException
|
||||
{
|
||||
super.onResponseHeader(name, value);
|
||||
int header = HttpHeader.CACHE.getOrdinal(name);
|
||||
switch (header)
|
||||
{
|
||||
case HttpHeader.CONTENT_LENGTH_ORDINAL:
|
||||
_bufferSize = BufferUtil.toInt(value);
|
||||
break;
|
||||
case HttpHeader.CONTENT_TYPE_ORDINAL:
|
||||
String mime = StringUtil.asciiToLowerCase(value.toString());
|
||||
int i = mime.indexOf("charset=");
|
||||
if (i > 0)
|
||||
{
|
||||
_encoding = mime.substring(i + 8);
|
||||
i = _encoding.indexOf(';');
|
||||
if (i > 0)
|
||||
_encoding = _encoding.substring(0, i);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected synchronized void onResponseContent(ByteBuffer content) throws IOException
|
||||
{
|
||||
super.onResponseContent(content);
|
||||
if (_responseContent == null)
|
||||
_responseContent = new ByteArrayOutputStream(_bufferSize);
|
||||
content.writeTo(_responseContent);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected synchronized void onRetry() throws IOException
|
||||
{
|
||||
if (_fileForUpload != null)
|
||||
{
|
||||
setRequestContent(null);
|
||||
setRequestContentSource(getInputStream());
|
||||
}
|
||||
else
|
||||
super.onRetry();
|
||||
}
|
||||
|
||||
private synchronized InputStream getInputStream() throws IOException
|
||||
{
|
||||
return new FileInputStream(_fileForUpload);
|
||||
}
|
||||
|
||||
public synchronized File getFileForUpload()
|
||||
{
|
||||
return _fileForUpload;
|
||||
}
|
||||
|
||||
public synchronized void setFileForUpload(File fileForUpload) throws IOException
|
||||
{
|
||||
this._fileForUpload = fileForUpload;
|
||||
setRequestContentSource(getInputStream());
|
||||
}
|
||||
}
|
|
@ -1,906 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2012 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.client;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.Enumeration;
|
||||
import java.util.LinkedList;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
import javax.net.ssl.SSLContext;
|
||||
|
||||
import org.eclipse.jetty.client.security.Authentication;
|
||||
import org.eclipse.jetty.client.security.RealmResolver;
|
||||
import org.eclipse.jetty.client.security.SecurityListener;
|
||||
import org.eclipse.jetty.http.HttpBuffers;
|
||||
import org.eclipse.jetty.http.HttpBuffersImpl;
|
||||
import org.eclipse.jetty.http.HttpScheme;
|
||||
import org.eclipse.jetty.io.Buffers;
|
||||
import org.eclipse.jetty.io.Buffers.Type;
|
||||
import org.eclipse.jetty.util.Attributes;
|
||||
import org.eclipse.jetty.util.AttributesMap;
|
||||
import org.eclipse.jetty.util.component.AggregateLifeCycle;
|
||||
import org.eclipse.jetty.util.component.Dumpable;
|
||||
import org.eclipse.jetty.util.component.LifeCycle;
|
||||
import org.eclipse.jetty.util.ssl.SslContextFactory;
|
||||
import org.eclipse.jetty.util.thread.QueuedThreadPool;
|
||||
import org.eclipse.jetty.util.thread.ThreadPool;
|
||||
import org.eclipse.jetty.util.thread.Timeout;
|
||||
|
||||
/**
|
||||
* Http Client.
|
||||
* <p/>
|
||||
* HttpClient is the main active component of the client API implementation.
|
||||
* It is the opposite of the Connectors in standard Jetty, in that it listens
|
||||
* for responses rather than requests. Just like the connectors, there is a
|
||||
* blocking socket version and a non-blocking NIO version (implemented as nested classes
|
||||
* selected by {@link #setConnectorType(int)}).
|
||||
* <p/>
|
||||
* The an instance of {@link HttpExchange} is passed to the {@link #send(HttpExchange)} method
|
||||
* to send a request. The exchange contains both the headers and content (source) of the request
|
||||
* plus the callbacks to handle responses. A HttpClient can have many exchanges outstanding
|
||||
* and they may be queued on the {@link HttpDestination} waiting for a {@link AbstractHttpConnection},
|
||||
* queued in the {@link AbstractHttpConnection} waiting to be transmitted or pipelined on the actual
|
||||
* TCP/IP connection waiting for a response.
|
||||
* <p/>
|
||||
* The {@link HttpDestination} class is an aggregation of {@link AbstractHttpConnection}s for the
|
||||
* same host, port and protocol. A destination may limit the number of connections
|
||||
* open and they provide a pool of open connections that may be reused. Connections may also
|
||||
* be allocated from a destination, so that multiple request sources are not multiplexed
|
||||
* over the same connection.
|
||||
*
|
||||
* @see HttpExchange
|
||||
* @see HttpDestination
|
||||
*/
|
||||
public class HttpClient extends AggregateLifeCycle implements HttpBuffers, Attributes, Dumpable
|
||||
{
|
||||
public static final int CONNECTOR_SOCKET = 0;
|
||||
public static final int CONNECTOR_SELECT_CHANNEL = 2;
|
||||
|
||||
private int _connectorType = CONNECTOR_SELECT_CHANNEL;
|
||||
private boolean _useDirectBuffers = true;
|
||||
private boolean _connectBlocking = true;
|
||||
private int _maxConnectionsPerAddress = Integer.MAX_VALUE;
|
||||
private int _maxQueueSizePerAddress = Integer.MAX_VALUE;
|
||||
private ConcurrentMap<Address, HttpDestination> _destinations = new ConcurrentHashMap<Address, HttpDestination>();
|
||||
ThreadPool _threadPool;
|
||||
Connector _connector;
|
||||
private long _idleTimeout = 20000;
|
||||
private long _timeout = 320000;
|
||||
private int _connectTimeout = 75000;
|
||||
private Timeout _timeoutQ = new Timeout();
|
||||
private Timeout _idleTimeoutQ = new Timeout();
|
||||
private Address _proxy;
|
||||
private Authentication _proxyAuthentication;
|
||||
private Set<String> _noProxy;
|
||||
private int _maxRetries = 3;
|
||||
private int _maxRedirects = 20;
|
||||
private LinkedList<String> _registeredListeners;
|
||||
|
||||
private final SslContextFactory _sslContextFactory;
|
||||
|
||||
private RealmResolver _realmResolver;
|
||||
|
||||
private AttributesMap _attributes=new AttributesMap();
|
||||
|
||||
private final HttpBuffersImpl _buffers= new HttpBuffersImpl();
|
||||
|
||||
/* ------------------------------------------------------------------------------- */
|
||||
private void setBufferTypes()
|
||||
{
|
||||
if (_connectorType==CONNECTOR_SOCKET)
|
||||
{
|
||||
_buffers.setRequestBufferType(Type.BYTE_ARRAY);
|
||||
_buffers.setRequestHeaderType(Type.BYTE_ARRAY);
|
||||
_buffers.setResponseBufferType(Type.BYTE_ARRAY);
|
||||
_buffers.setResponseHeaderType(Type.BYTE_ARRAY);
|
||||
}
|
||||
else
|
||||
{
|
||||
_buffers.setRequestBufferType(Type.DIRECT);
|
||||
_buffers.setRequestHeaderType(_useDirectBuffers?Type.DIRECT:Type.INDIRECT);
|
||||
_buffers.setResponseBufferType(Type.DIRECT);
|
||||
_buffers.setResponseHeaderType(_useDirectBuffers?Type.DIRECT:Type.INDIRECT);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------------- */
|
||||
public HttpClient()
|
||||
{
|
||||
this(new SslContextFactory());
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------------- */
|
||||
public HttpClient(SslContextFactory sslContextFactory)
|
||||
{
|
||||
_sslContextFactory = sslContextFactory;
|
||||
addBean(_sslContextFactory);
|
||||
addBean(_buffers);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------------- */
|
||||
/**
|
||||
* @return True if connects will be in blocking mode.
|
||||
*/
|
||||
public boolean isConnectBlocking()
|
||||
{
|
||||
return _connectBlocking;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------------- */
|
||||
/**
|
||||
* @param connectBlocking True if connects will be in blocking mode.
|
||||
*/
|
||||
public void setConnectBlocking(boolean connectBlocking)
|
||||
{
|
||||
_connectBlocking = connectBlocking;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------------- */
|
||||
public void send(HttpExchange exchange) throws IOException
|
||||
{
|
||||
boolean ssl = HttpScheme.HTTPS_BUFFER.equalsIgnoreCase(exchange.getScheme());
|
||||
exchange.setStatus(HttpExchange.STATUS_WAITING_FOR_CONNECTION);
|
||||
HttpDestination destination = getDestination(exchange.getAddress(), ssl);
|
||||
destination.send(exchange);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @return the threadpool
|
||||
*/
|
||||
public ThreadPool getThreadPool()
|
||||
{
|
||||
return _threadPool;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Set the ThreadPool.
|
||||
* The threadpool passed is added via {@link #addBean(Object)} so that
|
||||
* it's lifecycle may be managed as a {@link AggregateLifeCycle}.
|
||||
* @param threadPool the threadPool to set
|
||||
*/
|
||||
public void setThreadPool(ThreadPool threadPool)
|
||||
{
|
||||
removeBean(_threadPool);
|
||||
_threadPool = threadPool;
|
||||
addBean(_threadPool);
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @param name
|
||||
* @return Attribute associated with client
|
||||
*/
|
||||
public Object getAttribute(String name)
|
||||
{
|
||||
return _attributes.getAttribute(name);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @return names of attributes associated with client
|
||||
*/
|
||||
public Enumeration getAttributeNames()
|
||||
{
|
||||
return _attributes.getAttributeNames();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @param name
|
||||
*/
|
||||
public void removeAttribute(String name)
|
||||
{
|
||||
_attributes.removeAttribute(name);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Set an attribute on the HttpClient.
|
||||
* Attributes are not used by the client, but are provided for
|
||||
* so that users of a shared HttpClient may share other structures.
|
||||
* @param name
|
||||
* @param attribute
|
||||
*/
|
||||
public void setAttribute(String name, Object attribute)
|
||||
{
|
||||
_attributes.setAttribute(name,attribute);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public void clearAttributes()
|
||||
{
|
||||
_attributes.clearAttributes();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------------- */
|
||||
public HttpDestination getDestination(Address remote, boolean ssl) throws IOException
|
||||
{
|
||||
if (remote == null)
|
||||
throw new UnknownHostException("Remote socket address cannot be null.");
|
||||
|
||||
HttpDestination destination = _destinations.get(remote);
|
||||
if (destination == null)
|
||||
{
|
||||
destination = new HttpDestination(this, remote, ssl);
|
||||
if (_proxy != null && (_noProxy == null || !_noProxy.contains(remote.getHost())))
|
||||
{
|
||||
destination.setProxy(_proxy);
|
||||
if (_proxyAuthentication != null)
|
||||
destination.setProxyAuthentication(_proxyAuthentication);
|
||||
}
|
||||
HttpDestination other =_destinations.putIfAbsent(remote, destination);
|
||||
if (other!=null)
|
||||
destination=other;
|
||||
}
|
||||
return destination;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public void schedule(Timeout.Task task)
|
||||
{
|
||||
_timeoutQ.schedule(task);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public void schedule(Timeout.Task task, long timeout)
|
||||
{
|
||||
_timeoutQ.schedule(task, timeout - _timeoutQ.getDuration());
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public void scheduleIdle(Timeout.Task task)
|
||||
{
|
||||
_idleTimeoutQ.schedule(task);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public void cancel(Timeout.Task task)
|
||||
{
|
||||
task.cancel();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Get whether the connector can use direct NIO buffers.
|
||||
*/
|
||||
public boolean getUseDirectBuffers()
|
||||
{
|
||||
return _useDirectBuffers;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Set a RealmResolver for client Authentication.
|
||||
* If a realmResolver is set, then the HttpDestinations created by
|
||||
* this client will instantiate a {@link SecurityListener} so that
|
||||
* BASIC and DIGEST authentication can be performed.
|
||||
* @param resolver
|
||||
*/
|
||||
public void setRealmResolver(RealmResolver resolver)
|
||||
{
|
||||
_realmResolver = resolver;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* returns the SecurityRealmResolver reg_realmResolveristered with the HttpClient or null
|
||||
*
|
||||
* @return the SecurityRealmResolver reg_realmResolveristered with the HttpClient or null
|
||||
*/
|
||||
public RealmResolver getRealmResolver()
|
||||
{
|
||||
return _realmResolver;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public boolean hasRealms()
|
||||
{
|
||||
return _realmResolver == null ? false : true;
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Registers a listener that can listen to the stream of execution between the client and the
|
||||
* server and influence events. Sequential calls to the method wrapper sequentially wrap the preceding
|
||||
* listener in a delegation model.
|
||||
* <p/>
|
||||
* NOTE: the SecurityListener is a special listener which doesn't need to be added via this
|
||||
* mechanic, if you register security realms then it will automatically be added as the top listener of the
|
||||
* delegation stack.
|
||||
*
|
||||
* @param listenerClass
|
||||
*/
|
||||
public void registerListener(String listenerClass)
|
||||
{
|
||||
if (_registeredListeners == null)
|
||||
{
|
||||
_registeredListeners = new LinkedList<String>();
|
||||
}
|
||||
_registeredListeners.add(listenerClass);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public LinkedList<String> getRegisteredListeners()
|
||||
{
|
||||
return _registeredListeners;
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Set to use NIO direct buffers.
|
||||
*
|
||||
* @param direct If True (the default), the connector can use NIO direct
|
||||
* buffers. Some JVMs have memory management issues (bugs) with
|
||||
* direct buffers.
|
||||
*/
|
||||
public void setUseDirectBuffers(boolean direct)
|
||||
{
|
||||
_useDirectBuffers = direct;
|
||||
setBufferTypes();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Get the type of connector (socket, blocking or select) in use.
|
||||
*/
|
||||
public int getConnectorType()
|
||||
{
|
||||
return _connectorType;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public void setConnectorType(int connectorType)
|
||||
{
|
||||
this._connectorType = connectorType;
|
||||
setBufferTypes();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public int getMaxConnectionsPerAddress()
|
||||
{
|
||||
return _maxConnectionsPerAddress;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public void setMaxConnectionsPerAddress(int maxConnectionsPerAddress)
|
||||
{
|
||||
_maxConnectionsPerAddress = maxConnectionsPerAddress;
|
||||
}
|
||||
|
||||
public int getMaxQueueSizePerAddress()
|
||||
{
|
||||
return _maxQueueSizePerAddress;
|
||||
}
|
||||
|
||||
public void setMaxQueueSizePerAddress(int maxQueueSizePerAddress)
|
||||
{
|
||||
this._maxQueueSizePerAddress = maxQueueSizePerAddress;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
protected void doStart() throws Exception
|
||||
{
|
||||
setBufferTypes();
|
||||
|
||||
_timeoutQ.setDuration(_timeout);
|
||||
_timeoutQ.setNow();
|
||||
_idleTimeoutQ.setDuration(_idleTimeout);
|
||||
_idleTimeoutQ.setNow();
|
||||
|
||||
if (_threadPool==null)
|
||||
{
|
||||
QueuedThreadPool pool = new LocalQueuedThreadPool();
|
||||
pool.setMaxThreads(16);
|
||||
pool.setDaemon(true);
|
||||
pool.setName("HttpClient");
|
||||
_threadPool = pool;
|
||||
addBean(_threadPool,true);
|
||||
}
|
||||
|
||||
_connector=(_connectorType == CONNECTOR_SELECT_CHANNEL)?new SelectConnector(this):new SocketConnector(this);
|
||||
addBean(_connector,true);
|
||||
|
||||
super.doStart();
|
||||
|
||||
_threadPool.dispatch(new Runnable()
|
||||
{
|
||||
public void run()
|
||||
{
|
||||
while (isRunning())
|
||||
{
|
||||
_timeoutQ.tick(System.currentTimeMillis());
|
||||
_idleTimeoutQ.tick(_timeoutQ.getNow());
|
||||
try
|
||||
{
|
||||
Thread.sleep(200);
|
||||
}
|
||||
catch (InterruptedException ignored)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
protected void doStop() throws Exception
|
||||
{
|
||||
for (HttpDestination destination : _destinations.values())
|
||||
destination.close();
|
||||
|
||||
_timeoutQ.cancelAll();
|
||||
_idleTimeoutQ.cancelAll();
|
||||
|
||||
super.doStop();
|
||||
|
||||
if (_threadPool instanceof LocalQueuedThreadPool)
|
||||
{
|
||||
removeBean(_threadPool);
|
||||
_threadPool = null;
|
||||
}
|
||||
|
||||
removeBean(_connector);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
interface Connector extends LifeCycle
|
||||
{
|
||||
public void startConnection(HttpDestination destination) throws IOException;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* if a keystore location has been provided then client will attempt to use it as the keystore,
|
||||
* otherwise we simply ignore certificates and run with a loose ssl context.
|
||||
*
|
||||
* @return the SSL context
|
||||
*/
|
||||
protected SSLContext getSSLContext()
|
||||
{
|
||||
return _sslContextFactory.getSslContext();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @return the instance of SslContextFactory associated with the client
|
||||
*/
|
||||
public SslContextFactory getSslContextFactory()
|
||||
{
|
||||
return _sslContextFactory;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @return the period in milliseconds a {@link AbstractHttpConnection} can be idle for before it is closed.
|
||||
*/
|
||||
public long getIdleTimeout()
|
||||
{
|
||||
return _idleTimeout;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @param ms the period in milliseconds a {@link AbstractHttpConnection} can be idle for before it is closed.
|
||||
*/
|
||||
public void setIdleTimeout(long ms)
|
||||
{
|
||||
_idleTimeout = ms;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @return the period in ms that an exchange will wait for a response from the server.
|
||||
* @deprecated use {@link #getTimeout()} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
public int getSoTimeout()
|
||||
{
|
||||
return Long.valueOf(getTimeout()).intValue();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @deprecated use {@link #setTimeout(long)} instead.
|
||||
* @param timeout the period in ms that an exchange will wait for a response from the server.
|
||||
*/
|
||||
@Deprecated
|
||||
public void setSoTimeout(int timeout)
|
||||
{
|
||||
setTimeout(timeout);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @return the period in ms that an exchange will wait for a response from the server.
|
||||
*/
|
||||
public long getTimeout()
|
||||
{
|
||||
return _timeout;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @param timeout the period in ms that an exchange will wait for a response from the server.
|
||||
*/
|
||||
public void setTimeout(long timeout)
|
||||
{
|
||||
_timeout = timeout;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @return the period in ms before timing out an attempt to connect
|
||||
*/
|
||||
public int getConnectTimeout()
|
||||
{
|
||||
return _connectTimeout;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @param connectTimeout the period in ms before timing out an attempt to connect
|
||||
*/
|
||||
public void setConnectTimeout(int connectTimeout)
|
||||
{
|
||||
this._connectTimeout = connectTimeout;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public Address getProxy()
|
||||
{
|
||||
return _proxy;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public void setProxy(Address proxy)
|
||||
{
|
||||
this._proxy = proxy;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public Authentication getProxyAuthentication()
|
||||
{
|
||||
return _proxyAuthentication;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public void setProxyAuthentication(Authentication authentication)
|
||||
{
|
||||
_proxyAuthentication = authentication;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public boolean isProxied()
|
||||
{
|
||||
return this._proxy != null;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public Set<String> getNoProxy()
|
||||
{
|
||||
return _noProxy;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public void setNoProxy(Set<String> noProxyAddresses)
|
||||
{
|
||||
_noProxy = noProxyAddresses;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public int maxRetries()
|
||||
{
|
||||
return _maxRetries;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public void setMaxRetries(int retries)
|
||||
{
|
||||
_maxRetries = retries;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public int maxRedirects()
|
||||
{
|
||||
return _maxRedirects;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public void setMaxRedirects(int redirects)
|
||||
{
|
||||
_maxRedirects = redirects;
|
||||
}
|
||||
|
||||
public int getRequestBufferSize()
|
||||
{
|
||||
return _buffers.getRequestBufferSize();
|
||||
}
|
||||
|
||||
public void setRequestBufferSize(int requestBufferSize)
|
||||
{
|
||||
_buffers.setRequestBufferSize(requestBufferSize);
|
||||
}
|
||||
|
||||
public int getRequestHeaderSize()
|
||||
{
|
||||
return _buffers.getRequestHeaderSize();
|
||||
}
|
||||
|
||||
public void setRequestHeaderSize(int requestHeaderSize)
|
||||
{
|
||||
_buffers.setRequestHeaderSize(requestHeaderSize);
|
||||
}
|
||||
|
||||
public int getResponseBufferSize()
|
||||
{
|
||||
return _buffers.getResponseBufferSize();
|
||||
}
|
||||
|
||||
public void setResponseBufferSize(int responseBufferSize)
|
||||
{
|
||||
_buffers.setResponseBufferSize(responseBufferSize);
|
||||
}
|
||||
|
||||
public int getResponseHeaderSize()
|
||||
{
|
||||
return _buffers.getResponseHeaderSize();
|
||||
}
|
||||
|
||||
public void setResponseHeaderSize(int responseHeaderSize)
|
||||
{
|
||||
_buffers.setResponseHeaderSize(responseHeaderSize);
|
||||
}
|
||||
|
||||
public Type getRequestBufferType()
|
||||
{
|
||||
return _buffers.getRequestBufferType();
|
||||
}
|
||||
|
||||
public Type getRequestHeaderType()
|
||||
{
|
||||
return _buffers.getRequestHeaderType();
|
||||
}
|
||||
|
||||
public Type getResponseBufferType()
|
||||
{
|
||||
return _buffers.getResponseBufferType();
|
||||
}
|
||||
|
||||
public Type getResponseHeaderType()
|
||||
{
|
||||
return _buffers.getResponseHeaderType();
|
||||
}
|
||||
|
||||
public void setRequestBuffers(Buffers requestBuffers)
|
||||
{
|
||||
_buffers.setRequestBuffers(requestBuffers);
|
||||
}
|
||||
|
||||
public void setResponseBuffers(Buffers responseBuffers)
|
||||
{
|
||||
_buffers.setResponseBuffers(responseBuffers);
|
||||
}
|
||||
|
||||
public Buffers getRequestBuffers()
|
||||
{
|
||||
return _buffers.getRequestBuffers();
|
||||
}
|
||||
|
||||
public Buffers getResponseBuffers()
|
||||
{
|
||||
return _buffers.getResponseBuffers();
|
||||
}
|
||||
|
||||
public void setMaxBuffers(int maxBuffers)
|
||||
{
|
||||
_buffers.setMaxBuffers(maxBuffers);
|
||||
}
|
||||
|
||||
public int getMaxBuffers()
|
||||
{
|
||||
return _buffers.getMaxBuffers();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Deprecated
|
||||
public String getTrustStoreLocation()
|
||||
{
|
||||
return _sslContextFactory.getTrustStore();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Deprecated
|
||||
public void setTrustStoreLocation(String trustStoreLocation)
|
||||
{
|
||||
_sslContextFactory.setTrustStore(trustStoreLocation);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Deprecated
|
||||
public InputStream getTrustStoreInputStream()
|
||||
{
|
||||
return _sslContextFactory.getTrustStoreInputStream();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Deprecated
|
||||
public void setTrustStoreInputStream(InputStream trustStoreInputStream)
|
||||
{
|
||||
_sslContextFactory.setTrustStoreInputStream(trustStoreInputStream);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Deprecated
|
||||
public String getKeyStoreLocation()
|
||||
{
|
||||
return _sslContextFactory.getKeyStorePath();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Deprecated
|
||||
public void setKeyStoreLocation(String keyStoreLocation)
|
||||
{
|
||||
_sslContextFactory.setKeyStorePath(keyStoreLocation);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public InputStream getKeyStoreInputStream()
|
||||
{
|
||||
return _sslContextFactory.getKeyStoreInputStream();
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public void setKeyStoreInputStream(InputStream keyStoreInputStream)
|
||||
{
|
||||
_sslContextFactory.setKeyStoreInputStream(keyStoreInputStream);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Deprecated
|
||||
public void setKeyStorePassword(String keyStorePassword)
|
||||
{
|
||||
_sslContextFactory.setKeyStorePassword(keyStorePassword);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Deprecated
|
||||
public void setKeyManagerPassword(String keyManagerPassword)
|
||||
{
|
||||
_sslContextFactory.setKeyManagerPassword(keyManagerPassword);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Deprecated
|
||||
public void setTrustStorePassword(String trustStorePassword)
|
||||
{
|
||||
_sslContextFactory.setTrustStorePassword(trustStorePassword);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Deprecated
|
||||
public String getKeyStoreType()
|
||||
{
|
||||
return _sslContextFactory.getKeyStoreType();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Deprecated
|
||||
public void setKeyStoreType(String keyStoreType)
|
||||
{
|
||||
_sslContextFactory.setKeyStoreType(keyStoreType);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Deprecated
|
||||
public String getTrustStoreType()
|
||||
{
|
||||
return _sslContextFactory.getTrustStoreType();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Deprecated
|
||||
public void setTrustStoreType(String trustStoreType)
|
||||
{
|
||||
_sslContextFactory.setTrustStoreType(trustStoreType);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Deprecated
|
||||
public String getKeyManagerAlgorithm()
|
||||
{
|
||||
return _sslContextFactory.getSslKeyManagerFactoryAlgorithm();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Deprecated
|
||||
public void setKeyManagerAlgorithm(String keyManagerAlgorithm)
|
||||
{
|
||||
_sslContextFactory.setSslKeyManagerFactoryAlgorithm(keyManagerAlgorithm);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Deprecated
|
||||
public String getTrustManagerAlgorithm()
|
||||
{
|
||||
return _sslContextFactory.getTrustManagerFactoryAlgorithm();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Deprecated
|
||||
public void setTrustManagerAlgorithm(String trustManagerAlgorithm)
|
||||
{
|
||||
_sslContextFactory.setTrustManagerFactoryAlgorithm(trustManagerAlgorithm);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Deprecated
|
||||
public String getProtocol()
|
||||
{
|
||||
return _sslContextFactory.getProtocol();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Deprecated
|
||||
public void setProtocol(String protocol)
|
||||
{
|
||||
_sslContextFactory.setProtocol(protocol);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Deprecated
|
||||
public String getProvider()
|
||||
{
|
||||
return _sslContextFactory.getProvider();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Deprecated
|
||||
public void setProvider(String provider)
|
||||
{
|
||||
_sslContextFactory.setProvider(provider);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Deprecated
|
||||
public String getSecureRandomAlgorithm()
|
||||
{
|
||||
return _sslContextFactory.getSecureRandomAlgorithm();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Deprecated
|
||||
public void setSecureRandomAlgorithm(String secureRandomAlgorithm)
|
||||
{
|
||||
_sslContextFactory.setSecureRandomAlgorithm(secureRandomAlgorithm);
|
||||
}
|
||||
|
||||
private static class LocalQueuedThreadPool extends QueuedThreadPool
|
||||
{
|
||||
}
|
||||
}
|
|
@ -1,734 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2012 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.client;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.net.ProtocolException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ArrayBlockingQueue;
|
||||
import java.util.concurrent.BlockingQueue;
|
||||
import java.util.concurrent.RejectedExecutionException;
|
||||
|
||||
import org.eclipse.jetty.client.HttpClient.Connector;
|
||||
import org.eclipse.jetty.client.security.Authentication;
|
||||
import org.eclipse.jetty.client.security.SecurityListener;
|
||||
import org.eclipse.jetty.http.HttpCookie;
|
||||
import org.eclipse.jetty.http.HttpHeader;
|
||||
import org.eclipse.jetty.http.HttpMethod;
|
||||
import org.eclipse.jetty.http.HttpStatus;
|
||||
import org.eclipse.jetty.http.PathMap;
|
||||
|
||||
import org.eclipse.jetty.io.ByteArrayBuffer;
|
||||
import org.eclipse.jetty.io.Connection;
|
||||
import org.eclipse.jetty.io.EndPoint;
|
||||
import org.eclipse.jetty.util.component.AggregateLifeCycle;
|
||||
import org.eclipse.jetty.util.component.Dumpable;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
|
||||
/**
|
||||
* @version $Revision: 879 $ $Date: 2009-09-11 16:13:28 +0200 (Fri, 11 Sep 2009) $
|
||||
*/
|
||||
public class HttpDestination implements Dumpable
|
||||
{
|
||||
private static final Logger LOG = Log.getLogger(HttpDestination.class);
|
||||
|
||||
private final List<HttpExchange> _queue = new LinkedList<HttpExchange>();
|
||||
private final List<AbstractHttpConnection> _connections = new LinkedList<AbstractHttpConnection>();
|
||||
private final BlockingQueue<Object> _newQueue = new ArrayBlockingQueue<Object>(10, true);
|
||||
private final List<AbstractHttpConnection> _idle = new ArrayList<AbstractHttpConnection>();
|
||||
private final HttpClient _client;
|
||||
private final Address _address;
|
||||
private final boolean _ssl;
|
||||
private final ByteArrayBuffer _hostHeader;
|
||||
private volatile int _maxConnections;
|
||||
private volatile int _maxQueueSize;
|
||||
private int _pendingConnections = 0;
|
||||
private int _newConnection = 0;
|
||||
private volatile Address _proxy;
|
||||
private Authentication _proxyAuthentication;
|
||||
private PathMap _authorizations;
|
||||
private List<HttpCookie> _cookies;
|
||||
|
||||
|
||||
|
||||
HttpDestination(HttpClient client, Address address, boolean ssl)
|
||||
{
|
||||
_client = client;
|
||||
_address = address;
|
||||
_ssl = ssl;
|
||||
_maxConnections = _client.getMaxConnectionsPerAddress();
|
||||
_maxQueueSize = _client.getMaxQueueSizePerAddress();
|
||||
String addressString = address.getHost();
|
||||
if (address.getPort() != (_ssl ? 443 : 80))
|
||||
addressString += ":" + address.getPort();
|
||||
_hostHeader = new ByteArrayBuffer(addressString);
|
||||
}
|
||||
|
||||
public HttpClient getHttpClient()
|
||||
{
|
||||
return _client;
|
||||
}
|
||||
|
||||
public Address getAddress()
|
||||
{
|
||||
return _address;
|
||||
}
|
||||
|
||||
public boolean isSecure()
|
||||
{
|
||||
return _ssl;
|
||||
}
|
||||
|
||||
public ByteBuffer getHostHeader()
|
||||
{
|
||||
return _hostHeader;
|
||||
}
|
||||
|
||||
public int getMaxConnections()
|
||||
{
|
||||
return _maxConnections;
|
||||
}
|
||||
|
||||
public void setMaxConnections(int maxConnections)
|
||||
{
|
||||
this._maxConnections = maxConnections;
|
||||
}
|
||||
|
||||
public int getMaxQueueSize()
|
||||
{
|
||||
return _maxQueueSize;
|
||||
}
|
||||
|
||||
public void setMaxQueueSize(int maxQueueSize)
|
||||
{
|
||||
this._maxQueueSize = maxQueueSize;
|
||||
}
|
||||
|
||||
public int getConnections()
|
||||
{
|
||||
synchronized (this)
|
||||
{
|
||||
return _connections.size();
|
||||
}
|
||||
}
|
||||
|
||||
public int getIdleConnections()
|
||||
{
|
||||
synchronized (this)
|
||||
{
|
||||
return _idle.size();
|
||||
}
|
||||
}
|
||||
|
||||
public void addAuthorization(String pathSpec, Authentication authorization)
|
||||
{
|
||||
synchronized (this)
|
||||
{
|
||||
if (_authorizations == null)
|
||||
_authorizations = new PathMap();
|
||||
_authorizations.put(pathSpec, authorization);
|
||||
}
|
||||
|
||||
// TODO query and remove methods
|
||||
}
|
||||
|
||||
public void addCookie(HttpCookie cookie)
|
||||
{
|
||||
synchronized (this)
|
||||
{
|
||||
if (_cookies == null)
|
||||
_cookies = new ArrayList<HttpCookie>();
|
||||
_cookies.add(cookie);
|
||||
}
|
||||
|
||||
// TODO query, remove and age methods
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a connection. We either get an idle connection if one is available, or
|
||||
* we make a new connection, if we have not yet reached maxConnections. If we
|
||||
* have reached maxConnections, we wait until the number reduces.
|
||||
*
|
||||
* @param timeout max time prepared to block waiting to be able to get a connection
|
||||
* @return a HttpConnection for this destination
|
||||
* @throws IOException if an I/O error occurs
|
||||
*/
|
||||
private AbstractHttpConnection getConnection(long timeout) throws IOException
|
||||
{
|
||||
AbstractHttpConnection connection = null;
|
||||
|
||||
while ((connection == null) && (connection = getIdleConnection()) == null && timeout > 0)
|
||||
{
|
||||
boolean startConnection = false;
|
||||
synchronized (this)
|
||||
{
|
||||
int totalConnections = _connections.size() + _pendingConnections;
|
||||
if (totalConnections < _maxConnections)
|
||||
{
|
||||
_newConnection++;
|
||||
startConnection = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (startConnection)
|
||||
{
|
||||
startNewConnection();
|
||||
try
|
||||
{
|
||||
Object o = _newQueue.take();
|
||||
if (o instanceof AbstractHttpConnection)
|
||||
{
|
||||
connection = (AbstractHttpConnection)o;
|
||||
}
|
||||
else
|
||||
throw (IOException)o;
|
||||
}
|
||||
catch (InterruptedException e)
|
||||
{
|
||||
LOG.ignore(e);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
Thread.currentThread();
|
||||
Thread.sleep(200);
|
||||
timeout -= 200;
|
||||
}
|
||||
catch (InterruptedException e)
|
||||
{
|
||||
LOG.ignore(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
return connection;
|
||||
}
|
||||
|
||||
public AbstractHttpConnection reserveConnection(long timeout) throws IOException
|
||||
{
|
||||
AbstractHttpConnection connection = getConnection(timeout);
|
||||
if (connection != null)
|
||||
connection.setReserved(true);
|
||||
return connection;
|
||||
}
|
||||
|
||||
public AbstractHttpConnection getIdleConnection() throws IOException
|
||||
{
|
||||
AbstractHttpConnection connection = null;
|
||||
while (true)
|
||||
{
|
||||
synchronized (this)
|
||||
{
|
||||
if (connection != null)
|
||||
{
|
||||
_connections.remove(connection);
|
||||
connection.close();
|
||||
connection = null;
|
||||
}
|
||||
if (_idle.size() > 0)
|
||||
connection = _idle.remove(_idle.size() - 1);
|
||||
}
|
||||
|
||||
if (connection == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
// Check if the connection was idle,
|
||||
// but it expired just a moment ago
|
||||
if (connection.cancelIdleTimeout())
|
||||
{
|
||||
return connection;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void startNewConnection()
|
||||
{
|
||||
try
|
||||
{
|
||||
synchronized (this)
|
||||
{
|
||||
_pendingConnections++;
|
||||
}
|
||||
final Connector connector = _client._connector;
|
||||
if (connector != null)
|
||||
connector.startConnection(this);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LOG.debug(e);
|
||||
onConnectionFailed(e);
|
||||
}
|
||||
}
|
||||
|
||||
public void onConnectionFailed(Throwable throwable)
|
||||
{
|
||||
Throwable connect_failure = null;
|
||||
|
||||
boolean startConnection = false;
|
||||
synchronized (this)
|
||||
{
|
||||
_pendingConnections--;
|
||||
if (_newConnection > 0)
|
||||
{
|
||||
connect_failure = throwable;
|
||||
_newConnection--;
|
||||
}
|
||||
else if (_queue.size() > 0)
|
||||
{
|
||||
HttpExchange ex = _queue.remove(0);
|
||||
if (ex.setStatus(HttpExchange.STATUS_EXCEPTED))
|
||||
ex.getEventListener().onConnectionFailed(throwable);
|
||||
|
||||
// Since an existing connection had failed, we need to create a
|
||||
// connection if the queue is not empty and client is running.
|
||||
if (!_queue.isEmpty() && _client.isStarted())
|
||||
startConnection = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (startConnection)
|
||||
startNewConnection();
|
||||
|
||||
if (connect_failure != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
_newQueue.put(connect_failure);
|
||||
}
|
||||
catch (InterruptedException e)
|
||||
{
|
||||
LOG.ignore(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void onException(Throwable throwable)
|
||||
{
|
||||
synchronized (this)
|
||||
{
|
||||
_pendingConnections--;
|
||||
if (_queue.size() > 0)
|
||||
{
|
||||
HttpExchange ex = _queue.remove(0);
|
||||
if(ex.setStatus(HttpExchange.STATUS_EXCEPTED))
|
||||
ex.getEventListener().onException(throwable);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void onNewConnection(final AbstractHttpConnection connection) throws IOException
|
||||
{
|
||||
Connection q_connection = null;
|
||||
|
||||
synchronized (this)
|
||||
{
|
||||
_pendingConnections--;
|
||||
_connections.add(connection);
|
||||
|
||||
if (_newConnection > 0)
|
||||
{
|
||||
q_connection = connection;
|
||||
_newConnection--;
|
||||
}
|
||||
else if (_queue.size() == 0)
|
||||
{
|
||||
connection.setIdleTimeout();
|
||||
_idle.add(connection);
|
||||
}
|
||||
else
|
||||
{
|
||||
EndPoint endPoint = connection.getEndPoint();
|
||||
if (isProxied() && endPoint instanceof SelectConnector.UpgradableEndPoint)
|
||||
{
|
||||
SelectConnector.UpgradableEndPoint proxyEndPoint = (SelectConnector.UpgradableEndPoint)endPoint;
|
||||
HttpExchange exchange = _queue.get(0);
|
||||
ConnectExchange connect = new ConnectExchange(getAddress(), proxyEndPoint, exchange);
|
||||
connect.setAddress(getProxy());
|
||||
send(connection, connect);
|
||||
}
|
||||
else
|
||||
{
|
||||
HttpExchange exchange = _queue.remove(0);
|
||||
send(connection, exchange);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (q_connection != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
_newQueue.put(q_connection);
|
||||
}
|
||||
catch (InterruptedException e)
|
||||
{
|
||||
LOG.ignore(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void returnConnection(AbstractHttpConnection connection, boolean close) throws IOException
|
||||
{
|
||||
if (connection.isReserved())
|
||||
connection.setReserved(false);
|
||||
|
||||
if (close)
|
||||
{
|
||||
try
|
||||
{
|
||||
connection.close();
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
LOG.ignore(e);
|
||||
}
|
||||
}
|
||||
|
||||
if (!_client.isStarted())
|
||||
return;
|
||||
|
||||
if (!close && connection.getEndPoint().isOpen())
|
||||
{
|
||||
synchronized (this)
|
||||
{
|
||||
if (_queue.size() == 0)
|
||||
{
|
||||
connection.setIdleTimeout();
|
||||
_idle.add(connection);
|
||||
}
|
||||
else
|
||||
{
|
||||
HttpExchange ex = _queue.remove(0);
|
||||
send(connection, ex);
|
||||
}
|
||||
this.notifyAll();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
boolean startConnection = false;
|
||||
synchronized (this)
|
||||
{
|
||||
_connections.remove(connection);
|
||||
if (!_queue.isEmpty())
|
||||
startConnection = true;
|
||||
}
|
||||
|
||||
if (startConnection)
|
||||
startNewConnection();
|
||||
}
|
||||
}
|
||||
|
||||
public void returnIdleConnection(AbstractHttpConnection connection)
|
||||
{
|
||||
// TODO work out the real idle time;
|
||||
long idleForMs=connection!=null&&connection.getEndPoint()!=null?connection.getEndPoint().getMaxIdleTime():-1;
|
||||
connection.onIdleExpired(idleForMs);
|
||||
|
||||
boolean startConnection = false;
|
||||
synchronized (this)
|
||||
{
|
||||
_idle.remove(connection);
|
||||
_connections.remove(connection);
|
||||
|
||||
if (!_queue.isEmpty() && _client.isStarted())
|
||||
startConnection = true;
|
||||
}
|
||||
|
||||
if (startConnection)
|
||||
startNewConnection();
|
||||
}
|
||||
|
||||
public void send(HttpExchange ex) throws IOException
|
||||
{
|
||||
LinkedList<String> listeners = _client.getRegisteredListeners();
|
||||
|
||||
if (listeners != null)
|
||||
{
|
||||
// Add registered listeners, fail if we can't load them
|
||||
for (int i = listeners.size(); i > 0; --i)
|
||||
{
|
||||
String listenerClass = listeners.get(i - 1);
|
||||
|
||||
try
|
||||
{
|
||||
Class listener = Class.forName(listenerClass);
|
||||
Constructor constructor = listener.getDeclaredConstructor(HttpDestination.class, HttpExchange.class);
|
||||
HttpEventListener elistener = (HttpEventListener)constructor.newInstance(this, ex);
|
||||
ex.setEventListener(elistener);
|
||||
}
|
||||
catch (final Exception e)
|
||||
{
|
||||
throw new IOException("Unable to instantiate registered listener for destination: " + listenerClass)
|
||||
{
|
||||
{initCause(e);}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Security is supported by default and should be the first consulted
|
||||
if (_client.hasRealms())
|
||||
{
|
||||
ex.setEventListener(new SecurityListener(this, ex));
|
||||
}
|
||||
|
||||
doSend(ex);
|
||||
}
|
||||
|
||||
public void resend(HttpExchange ex) throws IOException
|
||||
{
|
||||
ex.getEventListener().onRetry();
|
||||
ex.reset();
|
||||
doSend(ex);
|
||||
}
|
||||
|
||||
protected void doSend(HttpExchange ex) throws IOException
|
||||
{
|
||||
// add cookies
|
||||
// TODO handle max-age etc.
|
||||
if (_cookies != null)
|
||||
{
|
||||
StringBuilder buf = null;
|
||||
for (HttpCookie cookie : _cookies)
|
||||
{
|
||||
if (buf == null)
|
||||
buf = new StringBuilder();
|
||||
else
|
||||
buf.append("; ");
|
||||
buf.append(cookie.getName()); // TODO quotes
|
||||
buf.append("=");
|
||||
buf.append(cookie.getValue()); // TODO quotes
|
||||
}
|
||||
if (buf != null)
|
||||
ex.addRequestHeader(HttpHeader.COOKIE, buf.toString());
|
||||
}
|
||||
|
||||
// Add any known authorizations
|
||||
if (_authorizations != null)
|
||||
{
|
||||
Authentication auth = (Authentication)_authorizations.match(ex.getRequestURI());
|
||||
if (auth != null)
|
||||
(auth).setCredentials(ex);
|
||||
}
|
||||
|
||||
// Schedule the timeout here, before we queue the exchange
|
||||
// so that we count also the queue time in the timeout
|
||||
ex.scheduleTimeout(this);
|
||||
|
||||
AbstractHttpConnection connection = getIdleConnection();
|
||||
if (connection != null)
|
||||
{
|
||||
send(connection, ex);
|
||||
}
|
||||
else
|
||||
{
|
||||
boolean startConnection = false;
|
||||
synchronized (this)
|
||||
{
|
||||
if (_queue.size() == _maxQueueSize)
|
||||
throw new RejectedExecutionException("Queue full for address " + _address);
|
||||
|
||||
_queue.add(ex);
|
||||
if (_connections.size() + _pendingConnections < _maxConnections)
|
||||
startConnection = true;
|
||||
}
|
||||
|
||||
if (startConnection)
|
||||
startNewConnection();
|
||||
}
|
||||
}
|
||||
|
||||
protected void exchangeExpired(HttpExchange exchange)
|
||||
{
|
||||
// The exchange may expire while waiting in the
|
||||
// destination queue, make sure it is removed
|
||||
synchronized (this)
|
||||
{
|
||||
_queue.remove(exchange);
|
||||
}
|
||||
}
|
||||
|
||||
protected void send(AbstractHttpConnection connection, HttpExchange exchange) throws IOException
|
||||
{
|
||||
synchronized (this)
|
||||
{
|
||||
// If server closes the connection, put the exchange back
|
||||
// to the exchange queue and recycle the connection
|
||||
if (!connection.send(exchange))
|
||||
{
|
||||
if (exchange.getStatus() <= HttpExchange.STATUS_WAITING_FOR_CONNECTION)
|
||||
_queue.add(0, exchange);
|
||||
returnIdleConnection(connection);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized String toString()
|
||||
{
|
||||
return String.format("HttpDestination@%x//%s:%d(%d/%d,%d,%d/%d)%n",hashCode(),_address.getHost(),_address.getPort(),_connections.size(),_maxConnections,_idle.size(),_queue.size(),_maxQueueSize);
|
||||
}
|
||||
|
||||
public synchronized String toDetailString()
|
||||
{
|
||||
StringBuilder b = new StringBuilder();
|
||||
b.append(toString());
|
||||
b.append('\n');
|
||||
synchronized (this)
|
||||
{
|
||||
for (AbstractHttpConnection connection : _connections)
|
||||
{
|
||||
b.append(connection.toDetailString());
|
||||
if (_idle.contains(connection))
|
||||
b.append(" IDLE");
|
||||
b.append('\n');
|
||||
}
|
||||
}
|
||||
b.append("--");
|
||||
b.append('\n');
|
||||
|
||||
return b.toString();
|
||||
}
|
||||
|
||||
public void setProxy(Address proxy)
|
||||
{
|
||||
_proxy = proxy;
|
||||
}
|
||||
|
||||
public Address getProxy()
|
||||
{
|
||||
return _proxy;
|
||||
}
|
||||
|
||||
public Authentication getProxyAuthentication()
|
||||
{
|
||||
return _proxyAuthentication;
|
||||
}
|
||||
|
||||
public void setProxyAuthentication(Authentication authentication)
|
||||
{
|
||||
_proxyAuthentication = authentication;
|
||||
}
|
||||
|
||||
public boolean isProxied()
|
||||
{
|
||||
return _proxy != null;
|
||||
}
|
||||
|
||||
public void close() throws IOException
|
||||
{
|
||||
synchronized (this)
|
||||
{
|
||||
for (AbstractHttpConnection connection : _connections)
|
||||
{
|
||||
connection.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @see org.eclipse.jetty.util.component.Dumpable#dump()
|
||||
*/
|
||||
public String dump()
|
||||
{
|
||||
return AggregateLifeCycle.dump(this);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @see org.eclipse.jetty.util.component.Dumpable#dump(java.lang.Appendable, java.lang.String)
|
||||
*/
|
||||
public void dump(Appendable out, String indent) throws IOException
|
||||
{
|
||||
synchronized (this)
|
||||
{
|
||||
out.append(String.valueOf(this)+"idle="+_idle.size()+" pending="+_pendingConnections).append("\n");
|
||||
AggregateLifeCycle.dump(out,indent,_connections);
|
||||
}
|
||||
}
|
||||
|
||||
private class ConnectExchange extends ContentExchange
|
||||
{
|
||||
private final SelectConnector.UpgradableEndPoint proxyEndPoint;
|
||||
private final HttpExchange exchange;
|
||||
|
||||
public ConnectExchange(Address serverAddress, SelectConnector.UpgradableEndPoint proxyEndPoint, HttpExchange exchange)
|
||||
{
|
||||
this.proxyEndPoint = proxyEndPoint;
|
||||
this.exchange = exchange;
|
||||
setMethod(HttpMethod.CONNECT);
|
||||
setVersion(exchange.getVersion());
|
||||
String serverHostAndPort = serverAddress.toString();
|
||||
setRequestURI(serverHostAndPort);
|
||||
addRequestHeader(HttpHeader.HOST, serverHostAndPort);
|
||||
addRequestHeader(HttpHeader.PROXY_CONNECTION, "keep-alive");
|
||||
addRequestHeader(HttpHeader.USER_AGENT, "Jetty-Client");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResponseComplete() throws IOException
|
||||
{
|
||||
int responseStatus = getResponseStatus();
|
||||
if (responseStatus == HttpStatus.OK_200)
|
||||
{
|
||||
proxyEndPoint.upgrade();
|
||||
}
|
||||
else if(responseStatus == HttpStatus.GATEWAY_TIMEOUT_504)
|
||||
{
|
||||
onExpire();
|
||||
}
|
||||
else
|
||||
{
|
||||
onException(new ProtocolException("Proxy: " + proxyEndPoint.getRemoteAddr() +":" + proxyEndPoint.getRemotePort() + " didn't return http return code 200, but " + responseStatus + " while trying to request: " + exchange.getAddress().toString()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onConnectionFailed(Throwable x)
|
||||
{
|
||||
HttpDestination.this.onConnectionFailed(x);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onException(Throwable x)
|
||||
{
|
||||
_queue.remove(exchange);
|
||||
if (exchange.setStatus(STATUS_EXCEPTED))
|
||||
exchange.getEventListener().onException(x);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onExpire()
|
||||
{
|
||||
_queue.remove(exchange);
|
||||
if (exchange.setStatus(STATUS_EXPIRED))
|
||||
exchange.getEventListener().onExpire();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -1,68 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2012 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.client;
|
||||
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
public interface HttpEventListener
|
||||
{
|
||||
|
||||
// TODO review the methods here, we can probably trim these down on what to expose
|
||||
|
||||
public void onRequestCommitted() throws IOException;
|
||||
|
||||
|
||||
public void onRequestComplete() throws IOException;
|
||||
|
||||
|
||||
public void onResponseStatus(ByteBuffer version, int status, ByteBuffer reason) throws IOException;
|
||||
|
||||
|
||||
public void onResponseHeader(ByteBuffer name, ByteBuffer value) throws IOException;
|
||||
|
||||
|
||||
public void onResponseHeaderComplete() throws IOException;
|
||||
|
||||
|
||||
public void onResponseContent(ByteBuffer content) throws IOException;
|
||||
|
||||
|
||||
public void onResponseComplete() throws IOException;
|
||||
|
||||
|
||||
public void onConnectionFailed(Throwable ex);
|
||||
|
||||
|
||||
public void onException(Throwable ex);
|
||||
|
||||
|
||||
public void onExpire();
|
||||
|
||||
public void onRetry();
|
||||
|
||||
|
||||
}
|
|
@ -1,167 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2012 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
|
||||
package org.eclipse.jetty.client;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
|
||||
|
||||
public class HttpEventListenerWrapper implements HttpEventListener
|
||||
{
|
||||
HttpEventListener _listener;
|
||||
boolean _delegatingRequests;
|
||||
boolean _delegatingResponses;
|
||||
boolean _delegationResult = true;
|
||||
private ByteBuffer _version;
|
||||
private int _status;
|
||||
private ByteBuffer _reason;
|
||||
|
||||
public HttpEventListenerWrapper()
|
||||
{
|
||||
_listener=null;
|
||||
_delegatingRequests=false;
|
||||
_delegatingResponses=false;
|
||||
}
|
||||
|
||||
public HttpEventListenerWrapper(HttpEventListener eventListener,boolean delegating)
|
||||
{
|
||||
_listener=eventListener;
|
||||
_delegatingRequests=delegating;
|
||||
_delegatingResponses=delegating;
|
||||
}
|
||||
|
||||
public HttpEventListener getEventListener()
|
||||
{
|
||||
return _listener;
|
||||
}
|
||||
|
||||
public void setEventListener(HttpEventListener listener)
|
||||
{
|
||||
_listener = listener;
|
||||
}
|
||||
|
||||
public boolean isDelegatingRequests()
|
||||
{
|
||||
return _delegatingRequests;
|
||||
}
|
||||
|
||||
public boolean isDelegatingResponses()
|
||||
{
|
||||
return _delegatingResponses;
|
||||
}
|
||||
|
||||
public void setDelegatingRequests(boolean delegating)
|
||||
{
|
||||
_delegatingRequests = delegating;
|
||||
}
|
||||
|
||||
public void setDelegatingResponses(boolean delegating)
|
||||
{
|
||||
_delegatingResponses = delegating;
|
||||
}
|
||||
|
||||
public void setDelegationResult( boolean result )
|
||||
{
|
||||
_delegationResult = result;
|
||||
}
|
||||
|
||||
public void onConnectionFailed(Throwable ex)
|
||||
{
|
||||
if (_delegatingRequests)
|
||||
_listener.onConnectionFailed(ex);
|
||||
}
|
||||
|
||||
public void onException(Throwable ex)
|
||||
{
|
||||
if (_delegatingRequests||_delegatingResponses)
|
||||
_listener.onException(ex);
|
||||
}
|
||||
|
||||
public void onExpire()
|
||||
{
|
||||
if (_delegatingRequests||_delegatingResponses)
|
||||
_listener.onExpire();
|
||||
}
|
||||
|
||||
public void onRequestCommitted() throws IOException
|
||||
{
|
||||
if (_delegatingRequests)
|
||||
_listener.onRequestCommitted();
|
||||
}
|
||||
|
||||
public void onRequestComplete() throws IOException
|
||||
{
|
||||
if (_delegatingRequests)
|
||||
_listener.onRequestComplete();
|
||||
}
|
||||
|
||||
public void onResponseComplete() throws IOException
|
||||
{
|
||||
if (_delegatingResponses)
|
||||
{
|
||||
if (_delegationResult == false)
|
||||
{
|
||||
_listener.onResponseStatus(_version,_status,_reason);
|
||||
}
|
||||
_listener.onResponseComplete();
|
||||
}
|
||||
}
|
||||
|
||||
public void onResponseContent(ByteBuffer content) throws IOException
|
||||
{
|
||||
if (_delegatingResponses)
|
||||
_listener.onResponseContent(content);
|
||||
}
|
||||
|
||||
public void onResponseHeader(ByteBuffer name, ByteBuffer value) throws IOException
|
||||
{
|
||||
if (_delegatingResponses)
|
||||
_listener.onResponseHeader(name,value);
|
||||
}
|
||||
|
||||
public void onResponseHeaderComplete() throws IOException
|
||||
{
|
||||
if (_delegatingResponses)
|
||||
_listener.onResponseHeaderComplete();
|
||||
}
|
||||
|
||||
public void onResponseStatus(ByteBuffer version, int status, ByteBuffer reason) throws IOException
|
||||
{
|
||||
if (_delegatingResponses)
|
||||
{
|
||||
_listener.onResponseStatus(version,status,reason);
|
||||
}
|
||||
else
|
||||
{
|
||||
_version = version;
|
||||
_status = status;
|
||||
_reason = reason;
|
||||
}
|
||||
}
|
||||
|
||||
public void onRetry()
|
||||
{
|
||||
if (_delegatingRequests)
|
||||
_listener.onRetry();
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -1,212 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2012 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.client;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.eclipse.jetty.http.HttpHeader;
|
||||
import org.eclipse.jetty.http.HttpScheme;
|
||||
import org.eclipse.jetty.http.HttpStatus;
|
||||
|
||||
|
||||
/**
|
||||
* RedirectListener
|
||||
*
|
||||
* Detect and handle the redirect responses
|
||||
*/
|
||||
public class RedirectListener extends HttpEventListenerWrapper
|
||||
{
|
||||
private final HttpExchange _exchange;
|
||||
private HttpDestination _destination;
|
||||
private String _location;
|
||||
private int _attempts;
|
||||
private boolean _requestComplete;
|
||||
private boolean _responseComplete;
|
||||
private boolean _redirected;
|
||||
|
||||
public RedirectListener(HttpDestination destination, HttpExchange ex)
|
||||
{
|
||||
// Start of sending events through to the wrapped listener
|
||||
// Next decision point is the onResponseStatus
|
||||
super(ex.getEventListener(),true);
|
||||
|
||||
_destination = destination;
|
||||
_exchange = ex;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResponseStatus( ByteBuffer version, int status, ByteBuffer reason )
|
||||
throws IOException
|
||||
{
|
||||
_redirected = ((status == HttpStatus.MOVED_PERMANENTLY_301 ||
|
||||
status == HttpStatus.MOVED_TEMPORARILY_302) &&
|
||||
_attempts < _destination.getHttpClient().maxRedirects());
|
||||
|
||||
if (_redirected)
|
||||
{
|
||||
setDelegatingRequests(false);
|
||||
setDelegatingResponses(false);
|
||||
}
|
||||
|
||||
super.onResponseStatus(version,status,reason);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onResponseHeader( ByteBuffer name, ByteBuffer value )
|
||||
throws IOException
|
||||
{
|
||||
if (_redirected)
|
||||
{
|
||||
int header = HttpHeader.CACHE.getOrdinal(name);
|
||||
switch (header)
|
||||
{
|
||||
case HttpHeader.LOCATION_ORDINAL:
|
||||
_location = value.toString();
|
||||
break;
|
||||
}
|
||||
}
|
||||
super.onResponseHeader(name,value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRequestComplete() throws IOException
|
||||
{
|
||||
_requestComplete = true;
|
||||
|
||||
if (checkExchangeComplete())
|
||||
{
|
||||
super.onRequestComplete();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResponseComplete() throws IOException
|
||||
{
|
||||
_responseComplete = true;
|
||||
|
||||
if (checkExchangeComplete())
|
||||
{
|
||||
super.onResponseComplete();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean checkExchangeComplete()
|
||||
throws IOException
|
||||
{
|
||||
if (_redirected && _requestComplete && _responseComplete)
|
||||
{
|
||||
if (_location != null)
|
||||
{
|
||||
if (_location.indexOf("://")>0)
|
||||
{
|
||||
_exchange.setURL(_location);
|
||||
}
|
||||
else
|
||||
{
|
||||
_exchange.setRequestURI(_location);
|
||||
}
|
||||
|
||||
// destination may have changed
|
||||
boolean isHttps = HttpScheme.HTTPS.equals(String.valueOf(_exchange.getScheme()));
|
||||
HttpDestination destination=_destination.getHttpClient().getDestination(_exchange.getAddress(),isHttps);
|
||||
|
||||
if (_destination==destination)
|
||||
{
|
||||
_destination.resend(_exchange);
|
||||
}
|
||||
else
|
||||
{
|
||||
// unwrap to find ultimate listener.
|
||||
HttpEventListener listener=this;
|
||||
while(listener instanceof HttpEventListenerWrapper)
|
||||
{
|
||||
listener=((HttpEventListenerWrapper)listener).getEventListener();
|
||||
}
|
||||
|
||||
//reset the listener
|
||||
_exchange.getEventListener().onRetry();
|
||||
_exchange.reset();
|
||||
_exchange.setEventListener(listener);
|
||||
|
||||
// Set the new Host header
|
||||
Address address = _exchange.getAddress();
|
||||
int port = address.getPort();
|
||||
StringBuilder hostHeader = new StringBuilder( 64 );
|
||||
hostHeader.append( address.getHost() );
|
||||
if( !( ( port == 80 && !isHttps ) || ( port == 443 && isHttps ) ) )
|
||||
{
|
||||
hostHeader.append( ':' );
|
||||
hostHeader.append( port );
|
||||
}
|
||||
|
||||
_exchange.setRequestHeader( HttpHeader.HOST, hostHeader.toString() );
|
||||
|
||||
destination.send(_exchange);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
setDelegationResult(false);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public void onRetry()
|
||||
{
|
||||
_redirected=false;
|
||||
_attempts++;
|
||||
|
||||
setDelegatingRequests(true);
|
||||
setDelegatingResponses(true);
|
||||
|
||||
_requestComplete=false;
|
||||
_responseComplete=false;
|
||||
|
||||
super.onRetry();
|
||||
}
|
||||
|
||||
/**
|
||||
* Delegate failed connection
|
||||
*/
|
||||
@Override
|
||||
public void onConnectionFailed( Throwable ex )
|
||||
{
|
||||
setDelegatingRequests(true);
|
||||
setDelegatingResponses(true);
|
||||
|
||||
super.onConnectionFailed( ex );
|
||||
}
|
||||
|
||||
/**
|
||||
* Delegate onException
|
||||
*/
|
||||
@Override
|
||||
public void onException( Throwable ex )
|
||||
{
|
||||
setDelegatingRequests(true);
|
||||
setDelegatingResponses(true);
|
||||
|
||||
super.onException( ex );
|
||||
}
|
||||
}
|
|
@ -1,444 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2012 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.client;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.SocketTimeoutException;
|
||||
import java.nio.channels.SelectionKey;
|
||||
import java.nio.channels.SocketChannel;
|
||||
import java.nio.channels.UnresolvedAddressException;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import javax.net.ssl.SSLEngine;
|
||||
|
||||
import org.eclipse.jetty.io.AsyncEndPoint;
|
||||
|
||||
import org.eclipse.jetty.io.ConnectedEndPoint;
|
||||
import org.eclipse.jetty.io.Connection;
|
||||
import org.eclipse.jetty.io.nio.AsyncConnection;
|
||||
import org.eclipse.jetty.io.nio.SelectChannelEndPoint;
|
||||
import org.eclipse.jetty.io.nio.SelectorManager;
|
||||
import org.eclipse.jetty.io.nio.SslConnection;
|
||||
import org.eclipse.jetty.util.component.AggregateLifeCycle;
|
||||
import org.eclipse.jetty.util.component.Dumpable;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
import org.eclipse.jetty.util.ssl.SslContextFactory;
|
||||
import org.eclipse.jetty.util.thread.Timeout;
|
||||
import org.eclipse.jetty.util.thread.Timeout.Task;
|
||||
|
||||
class SelectConnector extends AggregateLifeCycle implements HttpClient.Connector, Dumpable
|
||||
{
|
||||
private static final Logger LOG = Log.getLogger(SelectConnector.class);
|
||||
|
||||
private final HttpClient _httpClient;
|
||||
private final Manager _selectorManager=new Manager();
|
||||
private final Map<SocketChannel, Timeout.Task> _connectingChannels = new ConcurrentHashMap<SocketChannel, Timeout.Task>();
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @param httpClient the HttpClient this connector is associated to. It is
|
||||
* added via the {@link #addBean(Object, boolean)} as an unmanaged bean.
|
||||
*/
|
||||
SelectConnector(HttpClient httpClient)
|
||||
{
|
||||
_httpClient = httpClient;
|
||||
addBean(_httpClient,false);
|
||||
addBean(_selectorManager,true);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public void startConnection( HttpDestination destination )
|
||||
throws IOException
|
||||
{
|
||||
SocketChannel channel = null;
|
||||
try
|
||||
{
|
||||
channel = SocketChannel.open();
|
||||
Address address = destination.isProxied() ? destination.getProxy() : destination.getAddress();
|
||||
channel.socket().setTcpNoDelay(true);
|
||||
|
||||
if (_httpClient.isConnectBlocking())
|
||||
{
|
||||
channel.socket().connect(address.toSocketAddress(), _httpClient.getConnectTimeout());
|
||||
channel.configureBlocking(false);
|
||||
_selectorManager.register( channel, destination );
|
||||
}
|
||||
else
|
||||
{
|
||||
channel.configureBlocking(false);
|
||||
channel.connect(address.toSocketAddress());
|
||||
_selectorManager.register(channel,destination);
|
||||
ConnectTimeout connectTimeout = new ConnectTimeout(channel,destination);
|
||||
_httpClient.schedule(connectTimeout,_httpClient.getConnectTimeout());
|
||||
_connectingChannels.put(channel,connectTimeout);
|
||||
}
|
||||
}
|
||||
catch (UnresolvedAddressException ex)
|
||||
{
|
||||
if (channel != null)
|
||||
channel.close();
|
||||
destination.onConnectionFailed(ex);
|
||||
}
|
||||
catch(IOException ex)
|
||||
{
|
||||
if (channel != null)
|
||||
channel.close();
|
||||
destination.onConnectionFailed(ex);
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
class Manager extends SelectorManager
|
||||
{
|
||||
Logger LOG = SelectConnector.LOG;
|
||||
|
||||
@Override
|
||||
public boolean dispatch(Runnable task)
|
||||
{
|
||||
return _httpClient._threadPool.dispatch(task);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void endPointOpened(SelectChannelEndPoint endpoint)
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void endPointClosed(SelectChannelEndPoint endpoint)
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void endPointUpgraded(ConnectedEndPoint endpoint, Connection oldConnection)
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public AsyncConnection newConnection(SocketChannel channel, AsyncEndPoint endpoint, Object attachment)
|
||||
{
|
||||
return new AsyncHttpConnection(_httpClient.getRequestBuffers(),_httpClient.getResponseBuffers(),endpoint);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected SelectChannelEndPoint newEndPoint(SocketChannel channel, SelectSet selectSet, SelectionKey key) throws IOException
|
||||
{
|
||||
// We're connected, cancel the connect timeout
|
||||
Timeout.Task connectTimeout = _connectingChannels.remove(channel);
|
||||
if (connectTimeout != null)
|
||||
connectTimeout.cancel();
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("Channels with connection pending: {}", _connectingChannels.size());
|
||||
|
||||
// key should have destination at this point (will be replaced by endpoint after this call)
|
||||
HttpDestination dest=(HttpDestination)key.attachment();
|
||||
|
||||
SelectChannelEndPoint scep = new SelectChannelEndPoint(channel, selectSet, key, (int)_httpClient.getIdleTimeout());
|
||||
AsyncEndPoint ep = scep;
|
||||
|
||||
if (dest.isSecure())
|
||||
{
|
||||
LOG.debug("secure to {}, proxied={}",channel,dest.isProxied());
|
||||
ep = new UpgradableEndPoint(ep,newSslEngine(channel));
|
||||
}
|
||||
|
||||
AsyncConnection connection = selectSet.getManager().newConnection(channel,ep, key.attachment());
|
||||
ep.setConnection(connection);
|
||||
|
||||
AbstractHttpConnection httpConnection=(AbstractHttpConnection)connection;
|
||||
httpConnection.setDestination(dest);
|
||||
|
||||
if (dest.isSecure() && !dest.isProxied())
|
||||
((UpgradableEndPoint)ep).upgrade();
|
||||
|
||||
dest.onNewConnection(httpConnection);
|
||||
|
||||
return scep;
|
||||
}
|
||||
|
||||
private synchronized SSLEngine newSslEngine(SocketChannel channel) throws IOException
|
||||
{
|
||||
SslContextFactory sslContextFactory = _httpClient.getSslContextFactory();
|
||||
SSLEngine sslEngine;
|
||||
if (channel != null)
|
||||
{
|
||||
String peerHost = channel.socket().getInetAddress().getHostAddress();
|
||||
int peerPort = channel.socket().getPort();
|
||||
sslEngine = sslContextFactory.newSslEngine(peerHost, peerPort);
|
||||
}
|
||||
else
|
||||
{
|
||||
sslEngine = sslContextFactory.newSslEngine();
|
||||
}
|
||||
sslEngine.setUseClientMode(true);
|
||||
sslEngine.beginHandshake();
|
||||
|
||||
return sslEngine;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/* (non-Javadoc)
|
||||
* @see org.eclipse.io.nio.SelectorManager#connectionFailed(java.nio.channels.SocketChannel, java.lang.Throwable, java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
protected void connectionFailed(SocketChannel channel, Throwable ex, Object attachment)
|
||||
{
|
||||
Timeout.Task connectTimeout = _connectingChannels.remove(channel);
|
||||
if (connectTimeout != null)
|
||||
connectTimeout.cancel();
|
||||
|
||||
if (attachment instanceof HttpDestination)
|
||||
((HttpDestination)attachment).onConnectionFailed(ex);
|
||||
else
|
||||
super.connectionFailed(channel,ex,attachment);
|
||||
}
|
||||
}
|
||||
|
||||
private class ConnectTimeout extends Timeout.Task
|
||||
{
|
||||
private final SocketChannel channel;
|
||||
private final HttpDestination destination;
|
||||
|
||||
public ConnectTimeout(SocketChannel channel, HttpDestination destination)
|
||||
{
|
||||
this.channel = channel;
|
||||
this.destination = destination;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void expired()
|
||||
{
|
||||
if (channel.isConnectionPending())
|
||||
{
|
||||
LOG.debug("Channel {} timed out while connecting, closing it", channel);
|
||||
try
|
||||
{
|
||||
// This will unregister the channel from the selector
|
||||
channel.close();
|
||||
}
|
||||
catch (IOException x)
|
||||
{
|
||||
LOG.ignore(x);
|
||||
}
|
||||
destination.onConnectionFailed(new SocketTimeoutException());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class UpgradableEndPoint implements AsyncEndPoint
|
||||
{
|
||||
AsyncEndPoint _endp;
|
||||
SSLEngine _engine;
|
||||
|
||||
public UpgradableEndPoint(AsyncEndPoint endp, SSLEngine engine) throws IOException
|
||||
{
|
||||
_engine=engine;
|
||||
_endp=endp;
|
||||
}
|
||||
|
||||
public void upgrade()
|
||||
{
|
||||
AsyncHttpConnection connection = (AsyncHttpConnection)_endp.getConnection();
|
||||
|
||||
SslConnection sslConnection = new SslConnection(_engine,_endp);
|
||||
_endp.setConnection(sslConnection);
|
||||
|
||||
_endp=sslConnection.getSslEndPoint();
|
||||
sslConnection.getSslEndPoint().setConnection(connection);
|
||||
|
||||
LOG.debug("upgrade {} to {} for {}",this,sslConnection,connection);
|
||||
}
|
||||
|
||||
|
||||
public Connection getConnection()
|
||||
{
|
||||
return _endp.getConnection();
|
||||
}
|
||||
|
||||
public void setConnection(Connection connection)
|
||||
{
|
||||
_endp.setConnection(connection);
|
||||
}
|
||||
|
||||
public void shutdownOutput() throws IOException
|
||||
{
|
||||
_endp.shutdownOutput();
|
||||
}
|
||||
|
||||
public void dispatch()
|
||||
{
|
||||
_endp.asyncDispatch();
|
||||
}
|
||||
|
||||
public void asyncDispatch()
|
||||
{
|
||||
_endp.asyncDispatch();
|
||||
}
|
||||
|
||||
public boolean isOutputShutdown()
|
||||
{
|
||||
return _endp.isOutputShutdown();
|
||||
}
|
||||
|
||||
public void shutdownInput() throws IOException
|
||||
{
|
||||
_endp.shutdownInput();
|
||||
}
|
||||
|
||||
public void scheduleWrite()
|
||||
{
|
||||
_endp.scheduleWrite();
|
||||
}
|
||||
|
||||
public boolean isInputShutdown()
|
||||
{
|
||||
return _endp.isInputShutdown();
|
||||
}
|
||||
|
||||
public void close() throws IOException
|
||||
{
|
||||
_endp.close();
|
||||
}
|
||||
|
||||
public int fill(ByteBuffer buffer) throws IOException
|
||||
{
|
||||
return _endp.fill(buffer);
|
||||
}
|
||||
|
||||
public boolean isWritable()
|
||||
{
|
||||
return _endp.isWritable();
|
||||
}
|
||||
|
||||
public boolean hasProgressed()
|
||||
{
|
||||
return _endp.hasProgressed();
|
||||
}
|
||||
|
||||
public int flush(ByteBuffer buffer) throws IOException
|
||||
{
|
||||
return _endp.flush(buffer);
|
||||
}
|
||||
|
||||
public void scheduleTimeout(Task task, long timeoutMs)
|
||||
{
|
||||
_endp.scheduleTimeout(task,timeoutMs);
|
||||
}
|
||||
|
||||
public void cancelTimeout(Task task)
|
||||
{
|
||||
_endp.cancelTimeout(task);
|
||||
}
|
||||
|
||||
public int flush(ByteBuffer header, ByteBuffer buffer, ByteBuffer trailer) throws IOException
|
||||
{
|
||||
return _endp.flush(header,buffer,trailer);
|
||||
}
|
||||
|
||||
public String getLocalAddr()
|
||||
{
|
||||
return _endp.getLocalAddr();
|
||||
}
|
||||
|
||||
public String getLocalHost()
|
||||
{
|
||||
return _endp.getLocalHost();
|
||||
}
|
||||
|
||||
public int getLocalPort()
|
||||
{
|
||||
return _endp.getLocalPort();
|
||||
}
|
||||
|
||||
public String getRemoteAddr()
|
||||
{
|
||||
return _endp.getRemoteAddr();
|
||||
}
|
||||
|
||||
public String getRemoteHost()
|
||||
{
|
||||
return _endp.getRemoteHost();
|
||||
}
|
||||
|
||||
public int getRemotePort()
|
||||
{
|
||||
return _endp.getRemotePort();
|
||||
}
|
||||
|
||||
public boolean isBlocking()
|
||||
{
|
||||
return _endp.isBlocking();
|
||||
}
|
||||
|
||||
public boolean blockReadable(long millisecs) throws IOException
|
||||
{
|
||||
return _endp.blockReadable(millisecs);
|
||||
}
|
||||
|
||||
public boolean blockWritable(long millisecs) throws IOException
|
||||
{
|
||||
return _endp.blockWritable(millisecs);
|
||||
}
|
||||
|
||||
public boolean isOpen()
|
||||
{
|
||||
return _endp.isOpen();
|
||||
}
|
||||
|
||||
public Object getTransport()
|
||||
{
|
||||
return _endp.getTransport();
|
||||
}
|
||||
|
||||
public void flush() throws IOException
|
||||
{
|
||||
_endp.flush();
|
||||
}
|
||||
|
||||
public int getMaxIdleTime()
|
||||
{
|
||||
return _endp.getMaxIdleTime();
|
||||
}
|
||||
|
||||
public void setMaxIdleTime(int timeMs) throws IOException
|
||||
{
|
||||
_endp.setMaxIdleTime(timeMs);
|
||||
}
|
||||
|
||||
public void onIdleExpired(long idleForMs)
|
||||
{
|
||||
_endp.onIdleExpired(idleForMs);
|
||||
}
|
||||
|
||||
public void setCheckForIdle(boolean check)
|
||||
{
|
||||
_endp.setCheckForIdle(check);
|
||||
}
|
||||
|
||||
public boolean isCheckForIdle()
|
||||
{
|
||||
return _endp.isCheckForIdle();
|
||||
}
|
||||
|
||||
public String toString()
|
||||
{
|
||||
return "Upgradable:"+_endp.toString();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,111 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2012 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.client;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InterruptedIOException;
|
||||
import java.net.Socket;
|
||||
|
||||
import javax.net.SocketFactory;
|
||||
|
||||
import org.eclipse.jetty.io.Connection;
|
||||
import org.eclipse.jetty.io.EndPoint;
|
||||
import org.eclipse.jetty.io.bio.SocketEndPoint;
|
||||
import org.eclipse.jetty.util.component.AbstractLifeCycle;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
|
||||
class SocketConnector extends AbstractLifeCycle implements HttpClient.Connector
|
||||
{
|
||||
private static final Logger LOG = Log.getLogger(SocketConnector.class);
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private final HttpClient _httpClient;
|
||||
|
||||
/**
|
||||
* @param httpClient
|
||||
*/
|
||||
SocketConnector(HttpClient httpClient)
|
||||
{
|
||||
_httpClient = httpClient;
|
||||
}
|
||||
|
||||
public void startConnection(final HttpDestination destination) throws IOException
|
||||
{
|
||||
Socket socket= destination.isSecure()
|
||||
?_httpClient.getSslContextFactory().newSslSocket()
|
||||
:SocketFactory.getDefault().createSocket();
|
||||
|
||||
socket.setSoTimeout(0);
|
||||
socket.setTcpNoDelay(true);
|
||||
|
||||
Address address = destination.isProxied() ? destination.getProxy() : destination.getAddress();
|
||||
socket.connect(address.toSocketAddress(), _httpClient.getConnectTimeout());
|
||||
|
||||
final EndPoint endpoint=new SocketEndPoint(socket);
|
||||
|
||||
final AbstractHttpConnection connection=new BlockingHttpConnection(_httpClient.getRequestBuffers(),_httpClient.getResponseBuffers(),endpoint);
|
||||
connection.setDestination(destination);
|
||||
destination.onNewConnection(connection);
|
||||
_httpClient.getThreadPool().dispatch(new Runnable()
|
||||
{
|
||||
public void run()
|
||||
{
|
||||
try
|
||||
{
|
||||
Connection con = connection;
|
||||
while(true)
|
||||
{
|
||||
final Connection next = con.handle();
|
||||
if (next!=con)
|
||||
{
|
||||
con=next;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
if (e instanceof InterruptedIOException)
|
||||
LOG.ignore(e);
|
||||
else
|
||||
{
|
||||
LOG.debug(e);
|
||||
destination.onException(e);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
try
|
||||
{
|
||||
destination.returnConnection(connection,true);
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
LOG.debug(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
}
|
|
@ -1,57 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2012 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.client.security;
|
||||
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.eclipse.jetty.client.HttpExchange;
|
||||
import org.eclipse.jetty.http.HttpHeader;
|
||||
|
||||
import org.eclipse.jetty.io.ByteArrayBuffer;
|
||||
import org.eclipse.jetty.util.B64Code;
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
|
||||
/**
|
||||
* Sets authentication headers for BASIC authentication challenges
|
||||
*
|
||||
*
|
||||
*/
|
||||
public class BasicAuthentication implements Authentication
|
||||
{
|
||||
private ByteBuffer _authorization;
|
||||
|
||||
public BasicAuthentication(Realm realm) throws IOException
|
||||
{
|
||||
String authenticationString = "Basic " + B64Code.encode( realm.getPrincipal() + ":" + realm.getCredentials(), StringUtil.__ISO_8859_1);
|
||||
_authorization= new ByteArrayBuffer(authenticationString);
|
||||
}
|
||||
|
||||
/**
|
||||
* BASIC authentication is of the form
|
||||
*
|
||||
* encoded credentials are of the form: username:password
|
||||
*
|
||||
*
|
||||
*/
|
||||
public void setCredentials( HttpExchange exchange ) throws IOException
|
||||
{
|
||||
exchange.setRequestHeader( HttpHeader.AUTHORIZATION_BUFFER, _authorization);
|
||||
}
|
||||
}
|
|
@ -1,141 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2012 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.client.security;
|
||||
|
||||
|
||||
import java.io.IOException;
|
||||
import java.security.MessageDigest;
|
||||
import java.util.Map;
|
||||
|
||||
import org.eclipse.jetty.client.HttpExchange;
|
||||
import org.eclipse.jetty.http.HttpHeader;
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
import org.eclipse.jetty.util.TypeUtil;
|
||||
|
||||
public class DigestAuthentication implements Authentication
|
||||
{
|
||||
private static final String NC = "00000001";
|
||||
Realm securityRealm;
|
||||
Map details;
|
||||
|
||||
public DigestAuthentication(Realm realm, Map details)
|
||||
{
|
||||
this.securityRealm=realm;
|
||||
this.details=details;
|
||||
}
|
||||
|
||||
|
||||
public void setCredentials( HttpExchange exchange )
|
||||
throws IOException
|
||||
{
|
||||
StringBuilder buffer = new StringBuilder().append("Digest");
|
||||
|
||||
buffer.append(" ").append("username").append('=').append('"').append(securityRealm.getPrincipal()).append('"');
|
||||
|
||||
buffer.append(", ").append("realm").append('=').append('"').append(String.valueOf(details.get("realm"))).append('"');
|
||||
|
||||
buffer.append(", ").append("nonce").append('=').append('"').append(String.valueOf(details.get("nonce"))).append('"');
|
||||
|
||||
buffer.append(", ").append("uri").append('=').append('"').append(exchange.getURI()).append('"');
|
||||
|
||||
buffer.append(", ").append("algorithm").append('=').append(String.valueOf(details.get("algorithm")));
|
||||
|
||||
String cnonce = newCnonce(exchange, securityRealm, details);
|
||||
|
||||
buffer.append(", ").append("response").append('=').append('"').append(newResponse(cnonce,
|
||||
exchange, securityRealm, details)).append('"');
|
||||
|
||||
buffer.append(", ").append("qop").append('=').append(String.valueOf(details.get("qop")));
|
||||
|
||||
|
||||
buffer.append(", ").append("nc").append('=').append(NC);
|
||||
|
||||
buffer.append(", ").append("cnonce").append('=').append('"').append(cnonce).append('"');
|
||||
|
||||
exchange.setRequestHeader( HttpHeader.AUTHORIZATION,
|
||||
new String(buffer.toString().getBytes(StringUtil.__ISO_8859_1)));
|
||||
}
|
||||
|
||||
protected String newResponse(String cnonce, HttpExchange exchange, Realm securityRealm, Map details)
|
||||
{
|
||||
try{
|
||||
MessageDigest md = MessageDigest.getInstance("MD5");
|
||||
|
||||
// calc A1 digest
|
||||
md.update(securityRealm.getPrincipal().getBytes(StringUtil.__ISO_8859_1));
|
||||
md.update((byte)':');
|
||||
md.update(String.valueOf(details.get("realm")).getBytes(StringUtil.__ISO_8859_1));
|
||||
md.update((byte)':');
|
||||
md.update(securityRealm.getCredentials().getBytes(StringUtil.__ISO_8859_1));
|
||||
byte[] ha1 = md.digest();
|
||||
// calc A2 digest
|
||||
md.reset();
|
||||
md.update(exchange.getMethod().getBytes(StringUtil.__ISO_8859_1));
|
||||
md.update((byte)':');
|
||||
md.update(exchange.getURI().getBytes(StringUtil.__ISO_8859_1));
|
||||
byte[] ha2=md.digest();
|
||||
|
||||
md.update(TypeUtil.toString(ha1,16).getBytes(StringUtil.__ISO_8859_1));
|
||||
md.update((byte)':');
|
||||
md.update(String.valueOf(details.get("nonce")).getBytes(StringUtil.__ISO_8859_1));
|
||||
md.update((byte)':');
|
||||
md.update(NC.getBytes(StringUtil.__ISO_8859_1));
|
||||
md.update((byte)':');
|
||||
md.update(cnonce.getBytes(StringUtil.__ISO_8859_1));
|
||||
md.update((byte)':');
|
||||
md.update(String.valueOf(details.get("qop")).getBytes(StringUtil.__ISO_8859_1));
|
||||
md.update((byte)':');
|
||||
md.update(TypeUtil.toString(ha2,16).getBytes(StringUtil.__ISO_8859_1));
|
||||
byte[] digest=md.digest();
|
||||
|
||||
// check digest
|
||||
return encode(digest);
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
protected String newCnonce(HttpExchange exchange, Realm securityRealm, Map details)
|
||||
{
|
||||
try
|
||||
{
|
||||
MessageDigest md = MessageDigest.getInstance("MD5");
|
||||
byte[] b= md.digest(String.valueOf(System.currentTimeMillis()).getBytes(StringUtil.__ISO_8859_1));
|
||||
return encode(b);
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private static String encode(byte[] data)
|
||||
{
|
||||
StringBuilder buffer = new StringBuilder();
|
||||
for (int i=0; i<data.length; i++)
|
||||
{
|
||||
buffer.append(Integer.toHexString((data[i] & 0xf0) >>> 4));
|
||||
buffer.append(Integer.toHexString(data[i] & 0x0f));
|
||||
}
|
||||
return buffer.toString();
|
||||
}
|
||||
|
||||
}
|
|
@ -1,57 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2012 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.client.security;
|
||||
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.eclipse.jetty.client.HttpExchange;
|
||||
import org.eclipse.jetty.http.HttpHeader;
|
||||
|
||||
import org.eclipse.jetty.io.ByteArrayBuffer;
|
||||
import org.eclipse.jetty.util.B64Code;
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
|
||||
/**
|
||||
* Sets proxy authentication headers for BASIC authentication challenges
|
||||
*
|
||||
*
|
||||
*/
|
||||
public class ProxyAuthorization implements Authentication
|
||||
{
|
||||
private ByteBuffer _authorization;
|
||||
|
||||
public ProxyAuthorization(String username,String password) throws IOException
|
||||
{
|
||||
String authenticationString = "Basic " + B64Code.encode( username + ":" + password, StringUtil.__ISO_8859_1);
|
||||
_authorization= new ByteArrayBuffer(authenticationString);
|
||||
}
|
||||
|
||||
/**
|
||||
* BASIC proxy authentication is of the form
|
||||
*
|
||||
* encoded credentials are of the form: username:password
|
||||
*
|
||||
*
|
||||
*/
|
||||
public void setCredentials( HttpExchange exchange ) throws IOException
|
||||
{
|
||||
exchange.setRequestHeader( HttpHeader.PROXY_AUTHORIZATION_BUFFER, _authorization);
|
||||
}
|
||||
}
|
|
@ -1,276 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2012 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.client.security;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
import org.eclipse.jetty.client.HttpDestination;
|
||||
import org.eclipse.jetty.client.HttpEventListenerWrapper;
|
||||
import org.eclipse.jetty.client.HttpExchange;
|
||||
import org.eclipse.jetty.http.HttpHeader;
|
||||
import org.eclipse.jetty.http.HttpStatus;
|
||||
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
|
||||
|
||||
/**
|
||||
* SecurityListener
|
||||
*
|
||||
* Allow for insertion of security dialog when performing an
|
||||
* HttpExchange.
|
||||
*/
|
||||
public class SecurityListener extends HttpEventListenerWrapper
|
||||
{
|
||||
private static final Logger LOG = Log.getLogger(SecurityListener.class);
|
||||
|
||||
private HttpDestination _destination;
|
||||
private HttpExchange _exchange;
|
||||
private boolean _requestComplete;
|
||||
private boolean _responseComplete;
|
||||
private boolean _needIntercept;
|
||||
|
||||
private int _attempts = 0; // TODO remember to settle on winning solution
|
||||
|
||||
public SecurityListener(HttpDestination destination, HttpExchange ex)
|
||||
{
|
||||
// Start of sending events through to the wrapped listener
|
||||
// Next decision point is the onResponseStatus
|
||||
super(ex.getEventListener(),true);
|
||||
_destination=destination;
|
||||
_exchange=ex;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* scrapes an authentication type from the authString
|
||||
*
|
||||
* @param authString
|
||||
* @return the authentication type
|
||||
*/
|
||||
protected String scrapeAuthenticationType( String authString )
|
||||
{
|
||||
String authType;
|
||||
|
||||
if ( authString.indexOf( " " ) == -1 )
|
||||
{
|
||||
authType = authString.toString().trim();
|
||||
}
|
||||
else
|
||||
{
|
||||
String authResponse = authString.toString();
|
||||
authType = authResponse.substring( 0, authResponse.indexOf( " " ) ).trim();
|
||||
}
|
||||
return authType;
|
||||
}
|
||||
|
||||
/**
|
||||
* scrapes a set of authentication details from the authString
|
||||
*
|
||||
* @param authString
|
||||
* @return the authentication details
|
||||
*/
|
||||
protected Map<String, String> scrapeAuthenticationDetails( String authString )
|
||||
{
|
||||
Map<String, String> authenticationDetails = new HashMap<String, String>();
|
||||
authString = authString.substring( authString.indexOf( " " ) + 1, authString.length() );
|
||||
StringTokenizer strtok = new StringTokenizer( authString, ",");
|
||||
|
||||
while ( strtok.hasMoreTokens() )
|
||||
{
|
||||
String token = strtok.nextToken();
|
||||
String[] pair = token.split( "=" );
|
||||
|
||||
// authentication details ought to come in two parts, if not then just skip
|
||||
if ( pair.length == 2 )
|
||||
{
|
||||
String itemName = pair[0].trim();
|
||||
String itemValue = pair[1].trim();
|
||||
|
||||
itemValue = StringUtil.unquote( itemValue );
|
||||
|
||||
authenticationDetails.put( itemName, itemValue );
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG.debug("SecurityListener: missed scraping authentication details - " + token );
|
||||
}
|
||||
}
|
||||
return authenticationDetails;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onResponseStatus( ByteBuffer version, int status, ByteBuffer reason )
|
||||
throws IOException
|
||||
{
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("SecurityListener:Response Status: " + status );
|
||||
|
||||
if ( status == HttpStatus.UNAUTHORIZED_401 && _attempts<_destination.getHttpClient().maxRetries())
|
||||
{
|
||||
// Let's absorb events until we have done some retries
|
||||
setDelegatingResponses(false);
|
||||
_needIntercept = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
setDelegatingResponses(true);
|
||||
setDelegatingRequests(true);
|
||||
_needIntercept = false;
|
||||
}
|
||||
super.onResponseStatus(version,status,reason);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onResponseHeader( ByteBuffer name, ByteBuffer value )
|
||||
throws IOException
|
||||
{
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug( "SecurityListener:Header: " + name.toString() + " / " + value.toString() );
|
||||
|
||||
|
||||
if (!isDelegatingResponses())
|
||||
{
|
||||
int header = HttpHeader.CACHE.getOrdinal(name);
|
||||
switch (header)
|
||||
{
|
||||
case HttpHeader.WWW_AUTHENTICATE_ORDINAL:
|
||||
|
||||
// TODO don't hard code this bit.
|
||||
String authString = value.toString();
|
||||
String type = scrapeAuthenticationType( authString );
|
||||
|
||||
// TODO maybe avoid this map creation
|
||||
Map<String,String> details = scrapeAuthenticationDetails( authString );
|
||||
String pathSpec="/"; // TODO work out the real path spec
|
||||
RealmResolver realmResolver = _destination.getHttpClient().getRealmResolver();
|
||||
|
||||
if ( realmResolver == null )
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
Realm realm = realmResolver.getRealm( details.get("realm"), _destination, pathSpec ); // TODO work our realm correctly
|
||||
|
||||
if ( realm == null )
|
||||
{
|
||||
LOG.warn( "Unknown Security Realm: " + details.get("realm") );
|
||||
}
|
||||
else if ("digest".equalsIgnoreCase(type))
|
||||
{
|
||||
_destination.addAuthorization("/",new DigestAuthentication(realm,details));
|
||||
|
||||
}
|
||||
else if ("basic".equalsIgnoreCase(type))
|
||||
{
|
||||
_destination.addAuthorization(pathSpec,new BasicAuthentication(realm));
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
super.onResponseHeader(name,value);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onRequestComplete() throws IOException
|
||||
{
|
||||
_requestComplete = true;
|
||||
|
||||
if (_needIntercept)
|
||||
{
|
||||
if (_requestComplete && _responseComplete)
|
||||
{
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("onRequestComplete, Both complete: Resending from onResponseComplete "+_exchange);
|
||||
_responseComplete = false;
|
||||
_requestComplete = false;
|
||||
setDelegatingRequests(true);
|
||||
setDelegatingResponses(true);
|
||||
_destination.resend(_exchange);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("onRequestComplete, Response not yet complete onRequestComplete, calling super for "+_exchange);
|
||||
super.onRequestComplete();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("onRequestComplete, delegating to super with Request complete="+_requestComplete+", response complete="+_responseComplete+" "+_exchange);
|
||||
super.onRequestComplete();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onResponseComplete() throws IOException
|
||||
{
|
||||
_responseComplete = true;
|
||||
if (_needIntercept)
|
||||
{
|
||||
if (_requestComplete && _responseComplete)
|
||||
{
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("onResponseComplete, Both complete: Resending from onResponseComplete"+_exchange);
|
||||
_responseComplete = false;
|
||||
_requestComplete = false;
|
||||
setDelegatingResponses(true);
|
||||
setDelegatingRequests(true);
|
||||
_destination.resend(_exchange);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("onResponseComplete, Request not yet complete from onResponseComplete, calling super "+_exchange);
|
||||
super.onResponseComplete();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("OnResponseComplete, delegating to super with Request complete="+_requestComplete+", response complete="+_responseComplete+" "+_exchange);
|
||||
super.onResponseComplete();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRetry()
|
||||
{
|
||||
_attempts++;
|
||||
setDelegatingRequests(true);
|
||||
setDelegatingResponses(true);
|
||||
_requestComplete=false;
|
||||
_responseComplete=false;
|
||||
_needIntercept=false;
|
||||
super.onRetry();
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -1,64 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2012 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.client.webdav;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.eclipse.jetty.client.CachedExchange;
|
||||
import org.eclipse.jetty.http.HttpStatus;
|
||||
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
|
||||
|
||||
public class MkcolExchange extends CachedExchange
|
||||
{
|
||||
private static final Logger LOG = Log.getLogger(MkcolExchange.class);
|
||||
|
||||
boolean exists = false;
|
||||
|
||||
public MkcolExchange()
|
||||
{
|
||||
super(true);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
protected void onResponseStatus(ByteBuffer version, int status, ByteBuffer reason) throws IOException
|
||||
{
|
||||
if ( status == HttpStatus.CREATED_201 )
|
||||
{
|
||||
LOG.debug( "MkcolExchange:Status: Successfully created resource" );
|
||||
exists = true;
|
||||
}
|
||||
|
||||
if ( status == HttpStatus.METHOD_NOT_ALLOWED_405 ) // returned when resource exists
|
||||
{
|
||||
LOG.debug( "MkcolExchange:Status: Resource must exist" );
|
||||
exists = true;
|
||||
}
|
||||
|
||||
super.onResponseStatus(version, status, reason);
|
||||
}
|
||||
|
||||
public boolean exists()
|
||||
{
|
||||
return exists;
|
||||
}
|
||||
}
|
|
@ -1,57 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2012 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.client.webdav;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.eclipse.jetty.client.HttpExchange;
|
||||
import org.eclipse.jetty.http.HttpStatus;
|
||||
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
|
||||
|
||||
public class PropfindExchange extends HttpExchange
|
||||
{
|
||||
private static final Logger LOG = Log.getLogger(PropfindExchange.class);
|
||||
|
||||
boolean _propertyExists = false;
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
protected void onResponseStatus(ByteBuffer version, int status, ByteBuffer reason) throws IOException
|
||||
{
|
||||
if ( status == HttpStatus.OK_200 )
|
||||
{
|
||||
LOG.debug( "PropfindExchange:Status: Exists" );
|
||||
_propertyExists = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG.debug( "PropfindExchange:Status: Not Exists" );
|
||||
}
|
||||
|
||||
super.onResponseStatus(version, status, reason);
|
||||
}
|
||||
|
||||
public boolean exists()
|
||||
{
|
||||
return _propertyExists;
|
||||
}
|
||||
}
|
|
@ -1,332 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2012 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
|
||||
package org.eclipse.jetty.client.webdav;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.eclipse.jetty.client.HttpDestination;
|
||||
import org.eclipse.jetty.client.HttpEventListenerWrapper;
|
||||
import org.eclipse.jetty.client.HttpExchange;
|
||||
import org.eclipse.jetty.client.security.SecurityListener;
|
||||
import org.eclipse.jetty.http.HttpMethod;
|
||||
import org.eclipse.jetty.http.HttpStatus;
|
||||
|
||||
import org.eclipse.jetty.util.URIUtil;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
|
||||
/**
|
||||
* WebdavListener
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
public class WebdavListener extends HttpEventListenerWrapper
|
||||
{
|
||||
private static final Logger LOG = Log.getLogger(WebdavListener.class);
|
||||
|
||||
private HttpDestination _destination;
|
||||
private HttpExchange _exchange;
|
||||
private boolean _requestComplete;
|
||||
private boolean _responseComplete;
|
||||
private boolean _webdavEnabled;
|
||||
private boolean _needIntercept;
|
||||
|
||||
public WebdavListener(HttpDestination destination, HttpExchange ex)
|
||||
{
|
||||
// Start of sending events through to the wrapped listener
|
||||
// Next decision point is the onResponseStatus
|
||||
super(ex.getEventListener(),true);
|
||||
_destination=destination;
|
||||
_exchange=ex;
|
||||
|
||||
// We'll only enable webdav if this is a PUT request
|
||||
if ( HttpMethod.PUT.asString().equalsIgnoreCase( _exchange.getMethod() ) )
|
||||
{
|
||||
_webdavEnabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResponseStatus(ByteBuffer version, int status, ByteBuffer reason) throws IOException
|
||||
{
|
||||
if ( !_webdavEnabled )
|
||||
{
|
||||
_needIntercept = false;
|
||||
super.onResponseStatus(version, status, reason);
|
||||
return;
|
||||
}
|
||||
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("WebdavListener:Response Status: " + status );
|
||||
|
||||
// The dav spec says that CONFLICT should be returned when the parent collection doesn't exist but I am seeing
|
||||
// FORBIDDEN returned instead so running with that.
|
||||
if ( status == HttpStatus.FORBIDDEN_403 || status == HttpStatus.CONFLICT_409 )
|
||||
{
|
||||
if ( _webdavEnabled )
|
||||
{
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("WebdavListener:Response Status: dav enabled, taking a stab at resolving put issue" );
|
||||
setDelegatingResponses( false ); // stop delegating, we can try and fix this request
|
||||
_needIntercept = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("WebdavListener:Response Status: Webdav Disabled" );
|
||||
setDelegatingResponses( true ); // just make sure we delegate
|
||||
setDelegatingRequests( true );
|
||||
_needIntercept = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_needIntercept = false;
|
||||
setDelegatingResponses( true );
|
||||
setDelegatingRequests( true );
|
||||
}
|
||||
|
||||
super.onResponseStatus(version, status, reason);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResponseComplete() throws IOException
|
||||
{
|
||||
_responseComplete = true;
|
||||
if (_needIntercept)
|
||||
{
|
||||
if ( _requestComplete && _responseComplete)
|
||||
{
|
||||
try
|
||||
{
|
||||
// we have some work to do before retrying this
|
||||
if ( resolveCollectionIssues() )
|
||||
{
|
||||
setDelegatingRequests( true );
|
||||
setDelegatingResponses(true);
|
||||
_requestComplete = false;
|
||||
_responseComplete = false;
|
||||
_destination.resend(_exchange);
|
||||
}
|
||||
else
|
||||
{
|
||||
// admit defeat but retry because someone else might have
|
||||
setDelegationResult(false);
|
||||
setDelegatingRequests( true );
|
||||
setDelegatingResponses(true);
|
||||
super.onResponseComplete();
|
||||
}
|
||||
}
|
||||
catch ( IOException ioe )
|
||||
{
|
||||
LOG.debug("WebdavListener:Complete:IOException: might not be dealing with dav server, delegate");
|
||||
super.onResponseComplete();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("WebdavListener:Not ready, calling super");
|
||||
super.onResponseComplete();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
super.onResponseComplete();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public void onRequestComplete () throws IOException
|
||||
{
|
||||
_requestComplete = true;
|
||||
if (_needIntercept)
|
||||
{
|
||||
if ( _requestComplete && _responseComplete)
|
||||
{
|
||||
try
|
||||
{
|
||||
// we have some work to do before retrying this
|
||||
if ( resolveCollectionIssues() )
|
||||
{
|
||||
setDelegatingRequests( true );
|
||||
setDelegatingResponses(true);
|
||||
_requestComplete = false;
|
||||
_responseComplete = false;
|
||||
_destination.resend(_exchange);
|
||||
}
|
||||
else
|
||||
{
|
||||
// admit defeat but retry because someone else might have
|
||||
setDelegatingRequests( true );
|
||||
setDelegatingResponses(true);
|
||||
super.onRequestComplete();
|
||||
}
|
||||
}
|
||||
catch ( IOException ioe )
|
||||
{
|
||||
LOG.debug("WebdavListener:Complete:IOException: might not be dealing with dav server, delegate");
|
||||
super.onRequestComplete();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("WebdavListener:Not ready, calling super");
|
||||
super.onRequestComplete();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
super.onRequestComplete();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* walk through the steps to try and resolve missing parent collection issues via webdav
|
||||
*
|
||||
* TODO this really ought to use URI itself for this resolution
|
||||
*
|
||||
* @return
|
||||
* @throws IOException
|
||||
*/
|
||||
private boolean resolveCollectionIssues() throws IOException
|
||||
{
|
||||
|
||||
String uri = _exchange.getURI();
|
||||
String[] uriCollection = _exchange.getURI().split("/");
|
||||
int checkNum = uriCollection.length;
|
||||
int rewind = 0;
|
||||
|
||||
String parentUri = URIUtil.parentPath( uri );
|
||||
while ( parentUri != null && !checkExists(parentUri) )
|
||||
{
|
||||
++rewind;
|
||||
parentUri = URIUtil.parentPath( parentUri );
|
||||
}
|
||||
|
||||
// confirm webdav is supported for this collection
|
||||
if ( checkWebdavSupported() )
|
||||
{
|
||||
for (int i = 0; i < rewind;)
|
||||
{
|
||||
makeCollection(parentUri + "/" + uriCollection[checkNum - rewind - 1]);
|
||||
parentUri = parentUri + "/" + uriCollection[checkNum - rewind - 1];
|
||||
--rewind;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean checkExists( String uri ) throws IOException
|
||||
{
|
||||
if (uri == null)
|
||||
{
|
||||
System.out.println("have failed miserably");
|
||||
return false;
|
||||
}
|
||||
|
||||
PropfindExchange propfindExchange = new PropfindExchange();
|
||||
propfindExchange.setAddress( _exchange.getAddress() );
|
||||
propfindExchange.setMethod( HttpMethod.GET ); // PROPFIND acts wonky, just use get
|
||||
propfindExchange.setScheme( _exchange.getScheme() );
|
||||
propfindExchange.setEventListener( new SecurityListener( _destination, propfindExchange ) );
|
||||
propfindExchange.setConfigureListeners( false );
|
||||
propfindExchange.setRequestURI( uri );
|
||||
|
||||
_destination.send( propfindExchange );
|
||||
|
||||
try
|
||||
{
|
||||
propfindExchange.waitForDone();
|
||||
|
||||
return propfindExchange.exists();
|
||||
}
|
||||
catch ( InterruptedException ie )
|
||||
{
|
||||
LOG.ignore( ie );
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean makeCollection( String uri ) throws IOException
|
||||
{
|
||||
MkcolExchange mkcolExchange = new MkcolExchange();
|
||||
mkcolExchange.setAddress( _exchange.getAddress() );
|
||||
mkcolExchange.setMethod( "MKCOL " + uri + " HTTP/1.1" );
|
||||
mkcolExchange.setScheme( _exchange.getScheme() );
|
||||
mkcolExchange.setEventListener( new SecurityListener( _destination, mkcolExchange ) );
|
||||
mkcolExchange.setConfigureListeners( false );
|
||||
mkcolExchange.setRequestURI( uri );
|
||||
|
||||
_destination.send( mkcolExchange );
|
||||
|
||||
try
|
||||
{
|
||||
mkcolExchange.waitForDone();
|
||||
|
||||
return mkcolExchange.exists();
|
||||
}
|
||||
catch ( InterruptedException ie )
|
||||
{
|
||||
LOG.ignore( ie );
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private boolean checkWebdavSupported() throws IOException
|
||||
{
|
||||
WebdavSupportedExchange supportedExchange = new WebdavSupportedExchange();
|
||||
supportedExchange.setAddress( _exchange.getAddress() );
|
||||
supportedExchange.setMethod( HttpMethod.OPTIONS );
|
||||
supportedExchange.setScheme( _exchange.getScheme() );
|
||||
supportedExchange.setEventListener( new SecurityListener( _destination, supportedExchange ) );
|
||||
supportedExchange.setConfigureListeners( false );
|
||||
supportedExchange.setRequestURI( _exchange.getURI() );
|
||||
|
||||
_destination.send( supportedExchange );
|
||||
|
||||
try
|
||||
{
|
||||
supportedExchange.waitTilCompletion();
|
||||
return supportedExchange.isWebdavSupported();
|
||||
}
|
||||
catch (InterruptedException ie )
|
||||
{
|
||||
LOG.ignore( ie );
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -1,75 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2012 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.client.webdav;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.eclipse.jetty.client.HttpExchange;
|
||||
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
|
||||
|
||||
public class WebdavSupportedExchange extends HttpExchange
|
||||
{
|
||||
private static final Logger LOG = Log.getLogger(WebdavSupportedExchange.class);
|
||||
|
||||
private boolean _webdavSupported = false;
|
||||
private boolean _isComplete = false;
|
||||
|
||||
@Override
|
||||
protected void onResponseHeader(ByteBuffer name, ByteBuffer value) throws IOException
|
||||
{
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("WebdavSupportedExchange:Header:" + name.toString() + " / " + value.toString() );
|
||||
if ( "DAV".equals( name.toString() ) )
|
||||
{
|
||||
if ( value.toString().indexOf( "1" ) >= 0 || value.toString().indexOf( "2" ) >= 0 )
|
||||
{
|
||||
_webdavSupported = true;
|
||||
}
|
||||
}
|
||||
|
||||
super.onResponseHeader(name, value);
|
||||
}
|
||||
|
||||
public void waitTilCompletion() throws InterruptedException
|
||||
{
|
||||
synchronized (this)
|
||||
{
|
||||
while ( !_isComplete)
|
||||
{
|
||||
this.wait();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResponseComplete() throws IOException
|
||||
{
|
||||
_isComplete = true;
|
||||
|
||||
super.onResponseComplete();
|
||||
}
|
||||
|
||||
public boolean isWebdavSupported()
|
||||
{
|
||||
return _webdavSupported;
|
||||
}
|
||||
}
|
|
@ -1,443 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2012 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.client;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStream;
|
||||
import java.net.ServerSocket;
|
||||
import java.net.Socket;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* @version $Revision$ $Date$
|
||||
*/
|
||||
public abstract class AbstractConnectionTest
|
||||
{
|
||||
protected HttpClient newHttpClient()
|
||||
{
|
||||
HttpClient httpClient = new HttpClient();
|
||||
|
||||
// httpClient.setConnectorType(HttpClient.CONNECTOR_SOCKET);
|
||||
return httpClient;
|
||||
}
|
||||
|
||||
|
||||
protected ServerSocket newServerSocket() throws IOException
|
||||
{
|
||||
ServerSocket serverSocket=new ServerSocket();
|
||||
serverSocket.bind(null);
|
||||
return serverSocket;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testServerClosedConnection() throws Exception
|
||||
{
|
||||
ServerSocket serverSocket = new ServerSocket();
|
||||
serverSocket.bind(null);
|
||||
int port=serverSocket.getLocalPort();
|
||||
|
||||
HttpClient httpClient = newHttpClient();
|
||||
httpClient.setMaxConnectionsPerAddress(1);
|
||||
httpClient.start();
|
||||
try
|
||||
{
|
||||
CountDownLatch latch = new CountDownLatch(1);
|
||||
HttpExchange exchange = new ConnectionExchange(latch);
|
||||
exchange.setAddress(new Address("localhost", port));
|
||||
exchange.setRequestURI("/");
|
||||
httpClient.send(exchange);
|
||||
|
||||
Socket remote = serverSocket.accept();
|
||||
|
||||
// HttpClient.send() above is async, so if we write the response immediately
|
||||
// there is a chance that it arrives before the request is being sent, so we
|
||||
// read the request before sending the response to avoid the race
|
||||
InputStream input = remote.getInputStream();
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(input, "UTF-8"));
|
||||
String line;
|
||||
while ((line = reader.readLine()) != null)
|
||||
{
|
||||
if (line.length() == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
OutputStream output = remote.getOutputStream();
|
||||
output.write("HTTP/1.1 200 OK\r\n".getBytes("UTF-8"));
|
||||
output.write("Content-Length: 0\r\n".getBytes("UTF-8"));
|
||||
output.write("\r\n".getBytes("UTF-8"));
|
||||
output.flush();
|
||||
|
||||
assertEquals(HttpExchange.STATUS_COMPLETED, exchange.waitForDone());
|
||||
|
||||
remote.close();
|
||||
|
||||
// Need to wait a bit to allow the client to detect
|
||||
// that the server has closed the connection
|
||||
Thread.sleep(500);
|
||||
|
||||
// The server has closed the connection and another attempt to send
|
||||
// with the same connection would fail because the connection has been
|
||||
// closed by the client as well.
|
||||
// The client must open a new connection in this case, and we check
|
||||
// that the new request completes correctly
|
||||
exchange.reset();
|
||||
httpClient.send(exchange);
|
||||
|
||||
remote = serverSocket.accept();
|
||||
|
||||
input = remote.getInputStream();
|
||||
reader = new BufferedReader(new InputStreamReader(input, "UTF-8"));
|
||||
while ((line = reader.readLine()) != null)
|
||||
{
|
||||
if (line.length() == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
output = remote.getOutputStream();
|
||||
output.write("HTTP/1.1 200 OK\r\n".getBytes("UTF-8"));
|
||||
output.write("Content-Length: 0\r\n".getBytes("UTF-8"));
|
||||
output.write("\r\n".getBytes("UTF-8"));
|
||||
output.flush();
|
||||
|
||||
assertEquals(HttpExchange.STATUS_COMPLETED, exchange.waitForDone());
|
||||
}
|
||||
finally
|
||||
{
|
||||
httpClient.stop();
|
||||
}
|
||||
}
|
||||
|
||||
protected String getScheme()
|
||||
{
|
||||
return "http";
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testServerClosedIncomplete() throws Exception
|
||||
{
|
||||
ServerSocket serverSocket = newServerSocket();
|
||||
int port=serverSocket.getLocalPort();
|
||||
|
||||
HttpClient httpClient = newHttpClient();
|
||||
httpClient.setMaxConnectionsPerAddress(1);
|
||||
httpClient.start();
|
||||
try
|
||||
{
|
||||
CountDownLatch latch = new CountDownLatch(1);
|
||||
HttpExchange exchange = new ConnectionExchange(latch);
|
||||
exchange.setScheme(getScheme());
|
||||
exchange.setAddress(new Address("localhost", port));
|
||||
exchange.setRequestURI("/");
|
||||
httpClient.send(exchange);
|
||||
|
||||
Socket remote = serverSocket.accept();
|
||||
|
||||
// HttpClient.send() above is async, so if we write the response immediately
|
||||
// there is a chance that it arrives before the request is being sent, so we
|
||||
// read the request before sending the response to avoid the race
|
||||
InputStream input = remote.getInputStream();
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(input, "UTF-8"));
|
||||
String line;
|
||||
while ((line = reader.readLine()) != null)
|
||||
{
|
||||
if (line.length() == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
OutputStream output = remote.getOutputStream();
|
||||
output.write("HTTP/1.1 200 OK\r\n".getBytes("UTF-8"));
|
||||
output.write("Content-Length: 10\r\n".getBytes("UTF-8"));
|
||||
output.write("\r\n".getBytes("UTF-8"));
|
||||
output.flush();
|
||||
|
||||
remote.close();
|
||||
|
||||
int status = exchange.waitForDone();
|
||||
|
||||
assertEquals(HttpExchange.STATUS_EXCEPTED, status);
|
||||
|
||||
}
|
||||
finally
|
||||
{
|
||||
httpClient.stop();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testServerHalfClosedIncomplete() throws Exception
|
||||
{
|
||||
ServerSocket serverSocket = new ServerSocket();
|
||||
serverSocket.bind(null);
|
||||
int port=serverSocket.getLocalPort();
|
||||
|
||||
HttpClient httpClient = newHttpClient();
|
||||
httpClient.setIdleTimeout(10000);
|
||||
httpClient.setMaxConnectionsPerAddress(1);
|
||||
httpClient.start();
|
||||
try
|
||||
{
|
||||
CountDownLatch latch = new CountDownLatch(1);
|
||||
HttpExchange exchange = new ConnectionExchange(latch);
|
||||
exchange.setAddress(new Address("localhost", port));
|
||||
exchange.setRequestURI("/");
|
||||
httpClient.send(exchange);
|
||||
|
||||
Socket remote = serverSocket.accept();
|
||||
|
||||
// HttpClient.send() above is async, so if we write the response immediately
|
||||
// there is a chance that it arrives before the request is being sent, so we
|
||||
// read the request before sending the response to avoid the race
|
||||
InputStream input = remote.getInputStream();
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(input, "UTF-8"));
|
||||
String line;
|
||||
while ((line = reader.readLine()) != null)
|
||||
{
|
||||
if (line.length() == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
OutputStream output = remote.getOutputStream();
|
||||
output.write("HTTP/1.1 200 OK\r\n".getBytes("UTF-8"));
|
||||
output.write("Content-Length: 10\r\n".getBytes("UTF-8"));
|
||||
output.write("\r\n".getBytes("UTF-8"));
|
||||
output.flush();
|
||||
|
||||
remote.shutdownOutput();
|
||||
|
||||
assertEquals(HttpExchange.STATUS_EXCEPTED, exchange.waitForDone());
|
||||
|
||||
}
|
||||
finally
|
||||
{
|
||||
httpClient.stop();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConnectionFailed() throws Exception
|
||||
{
|
||||
ServerSocket serverSocket = new ServerSocket();
|
||||
serverSocket.bind(null);
|
||||
int port=serverSocket.getLocalPort();
|
||||
serverSocket.close();
|
||||
|
||||
HttpClient httpClient = newHttpClient();
|
||||
httpClient.start();
|
||||
try
|
||||
{
|
||||
CountDownLatch latch = new CountDownLatch(1);
|
||||
HttpExchange exchange = new ConnectionExchange(latch);
|
||||
exchange.setAddress(new Address("localhost", port));
|
||||
exchange.setRequestURI("/");
|
||||
httpClient.send(exchange);
|
||||
|
||||
boolean passed = latch.await(4000, TimeUnit.MILLISECONDS);
|
||||
assertTrue(passed);
|
||||
|
||||
long wait = 100;
|
||||
long maxWait = 10 * wait;
|
||||
long curWait = wait;
|
||||
while (curWait < maxWait && !exchange.isDone())
|
||||
{
|
||||
Thread.sleep(wait);
|
||||
curWait += wait;
|
||||
}
|
||||
|
||||
assertEquals(HttpExchange.STATUS_EXCEPTED, exchange.getStatus());
|
||||
}
|
||||
finally
|
||||
{
|
||||
httpClient.stop();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMultipleConnectionsFailed() throws Exception
|
||||
{
|
||||
ServerSocket serverSocket = new ServerSocket();
|
||||
serverSocket.bind(null);
|
||||
int port=serverSocket.getLocalPort();
|
||||
serverSocket.close();
|
||||
|
||||
HttpClient httpClient = newHttpClient();
|
||||
httpClient.setMaxConnectionsPerAddress(1);
|
||||
httpClient.start();
|
||||
try
|
||||
{
|
||||
HttpExchange[] exchanges = new HttpExchange[20];
|
||||
final CountDownLatch latch = new CountDownLatch(exchanges.length);
|
||||
for (int i = 0; i < exchanges.length; ++i)
|
||||
{
|
||||
HttpExchange exchange = new HttpExchange()
|
||||
{
|
||||
@Override
|
||||
protected void onConnectionFailed(Throwable x)
|
||||
{
|
||||
latch.countDown();
|
||||
}
|
||||
};
|
||||
exchange.setAddress(new Address("localhost", port));
|
||||
exchange.setRequestURI("/");
|
||||
exchanges[i] = exchange;
|
||||
}
|
||||
|
||||
for (HttpExchange exchange : exchanges)
|
||||
httpClient.send(exchange);
|
||||
|
||||
for (HttpExchange exchange : exchanges)
|
||||
assertEquals(HttpExchange.STATUS_EXCEPTED, exchange.waitForDone());
|
||||
|
||||
assertTrue(latch.await(1000, TimeUnit.MILLISECONDS));
|
||||
}
|
||||
finally
|
||||
{
|
||||
httpClient.stop();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConnectionTimeout() throws Exception
|
||||
{
|
||||
HttpClient httpClient = newHttpClient();
|
||||
int connectTimeout = 5000;
|
||||
httpClient.setConnectTimeout(connectTimeout);
|
||||
httpClient.start();
|
||||
try
|
||||
{
|
||||
CountDownLatch latch = new CountDownLatch(1);
|
||||
HttpExchange exchange = new ConnectionExchange(latch);
|
||||
// Using a IP address has a different behavior than using a host name
|
||||
exchange.setAddress(new Address("127.0.0.1", 1));
|
||||
exchange.setRequestURI("/");
|
||||
httpClient.send(exchange);
|
||||
|
||||
boolean passed = latch.await(connectTimeout * 2L, TimeUnit.MILLISECONDS);
|
||||
assertTrue(passed);
|
||||
|
||||
int status = exchange.waitForDone();
|
||||
assertEquals(HttpExchange.STATUS_EXCEPTED, status);
|
||||
}
|
||||
finally
|
||||
{
|
||||
httpClient.stop();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIdleConnection() throws Exception
|
||||
{
|
||||
ServerSocket serverSocket = new ServerSocket();
|
||||
serverSocket.bind(null);
|
||||
int port=serverSocket.getLocalPort();
|
||||
|
||||
HttpClient httpClient = newHttpClient();
|
||||
httpClient.setIdleTimeout(700);
|
||||
httpClient.start();
|
||||
try
|
||||
{
|
||||
HttpExchange exchange = new ConnectionExchange();
|
||||
exchange.setAddress(new Address("localhost", port));
|
||||
exchange.setRequestURI("/");
|
||||
HttpDestination dest = httpClient.getDestination(new Address("localhost", port),false);
|
||||
|
||||
httpClient.send(exchange);
|
||||
Socket server = serverSocket.accept();
|
||||
server.setSoTimeout(5000);
|
||||
byte[] buf = new byte[4096];
|
||||
|
||||
int len=server.getInputStream().read(buf);
|
||||
assertEquals(1,dest.getConnections());
|
||||
assertEquals(0,dest.getIdleConnections());
|
||||
|
||||
server.getOutputStream().write("HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n".getBytes());
|
||||
|
||||
assertEquals(HttpExchange.STATUS_COMPLETED,exchange.waitForDone());
|
||||
Thread.sleep(200); // TODO get rid of this
|
||||
assertEquals(1,dest.getConnections());
|
||||
assertEquals(1,dest.getIdleConnections());
|
||||
|
||||
exchange = new ConnectionExchange();
|
||||
exchange.setAddress(new Address("localhost", port));
|
||||
exchange.setRequestURI("/");
|
||||
httpClient.send(exchange);
|
||||
assertEquals(1,dest.getConnections());
|
||||
assertEquals(0,dest.getIdleConnections());
|
||||
|
||||
|
||||
len=server.getInputStream().read(buf);
|
||||
assertEquals(1,dest.getConnections());
|
||||
assertEquals(0,dest.getIdleConnections());
|
||||
server.getOutputStream().write("HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n".getBytes());
|
||||
|
||||
Thread.sleep(500);
|
||||
|
||||
assertEquals(1,dest.getConnections());
|
||||
assertEquals(1,dest.getIdleConnections());
|
||||
|
||||
Thread.sleep(500);
|
||||
|
||||
assertEquals(0,dest.getConnections());
|
||||
assertEquals(0,dest.getIdleConnections());
|
||||
|
||||
serverSocket.close();
|
||||
}
|
||||
finally
|
||||
{
|
||||
httpClient.stop();
|
||||
}
|
||||
}
|
||||
|
||||
protected class ConnectionExchange extends HttpExchange
|
||||
{
|
||||
private final CountDownLatch latch;
|
||||
|
||||
protected ConnectionExchange()
|
||||
{
|
||||
this.latch = null;
|
||||
}
|
||||
|
||||
protected ConnectionExchange(CountDownLatch latch)
|
||||
{
|
||||
this.latch = latch;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onConnectionFailed(Throwable ex)
|
||||
{
|
||||
if (latch!=null)
|
||||
latch.countDown();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onException(Throwable x)
|
||||
{
|
||||
if (latch!=null)
|
||||
latch.countDown();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,500 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2012 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.client;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.SocketTimeoutException;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.ServletOutputStream;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
|
||||
import org.eclipse.jetty.server.AbstractHttpConnection;
|
||||
import org.eclipse.jetty.server.Connector;
|
||||
import org.eclipse.jetty.server.Request;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.server.handler.AbstractHandler;
|
||||
import org.eclipse.jetty.server.nio.SelectChannelConnector;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.StdErrLog;
|
||||
import org.junit.After;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
/**
|
||||
*/
|
||||
public abstract class AbstractHttpExchangeCancelTest
|
||||
{
|
||||
private Server server;
|
||||
private Connector connector;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception
|
||||
{
|
||||
server = new Server();
|
||||
connector = new SelectChannelConnector();
|
||||
server.addConnector(connector);
|
||||
server.setHandler(new EmptyHandler());
|
||||
server.start();
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() throws Exception
|
||||
{
|
||||
server.stop();
|
||||
server.join();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Test
|
||||
public void testHttpExchangeCancelOnSend1() throws Exception
|
||||
{
|
||||
// One of the first things that HttpClient.send() does
|
||||
// is to change the status of the exchange
|
||||
// We exploit that to be sure the exchange is canceled
|
||||
// without race conditions
|
||||
TestHttpExchange exchange = new TestHttpExchange()
|
||||
{
|
||||
@Override
|
||||
boolean setStatus(int status)
|
||||
{
|
||||
// Cancel before setting the new status
|
||||
if (getStatus() == HttpExchange.STATUS_START &&
|
||||
status == STATUS_WAITING_FOR_CONNECTION)
|
||||
cancel();
|
||||
return super.setStatus(status);
|
||||
}
|
||||
};
|
||||
exchange.setAddress(newAddress());
|
||||
exchange.setRequestURI("/");
|
||||
|
||||
getHttpClient().send(exchange);
|
||||
// Cancelling here is wrong and makes the test fail spuriously
|
||||
// due to a race condition with send(): the send() can complete
|
||||
// before the exchange is canceled so it will be in STATUS_COMPLETE
|
||||
// which will fail the test.
|
||||
// exchange.cancel();
|
||||
|
||||
int status = exchange.waitForDone();
|
||||
assertEquals(HttpExchange.STATUS_CANCELLED, status);
|
||||
assertFalse(exchange.isResponseCompleted());
|
||||
assertFalse(exchange.isFailed());
|
||||
assertFalse(exchange.isAssociated());
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Test
|
||||
public void testHttpExchangeCancelOnSend2() throws Exception
|
||||
{
|
||||
// One of the first things that HttpClient.send() does
|
||||
// is to change the status of the exchange
|
||||
// We exploit that to be sure the exchange is canceled
|
||||
// without race conditions
|
||||
TestHttpExchange exchange = new TestHttpExchange()
|
||||
{
|
||||
@Override
|
||||
boolean setStatus(int status)
|
||||
{
|
||||
// Cancel after setting the new status
|
||||
int oldStatus = getStatus();
|
||||
boolean set = super.setStatus(status);
|
||||
if (oldStatus == STATUS_START &&
|
||||
getStatus() == HttpExchange.STATUS_WAITING_FOR_CONNECTION)
|
||||
cancel();
|
||||
return set;
|
||||
}
|
||||
};
|
||||
exchange.setAddress(newAddress());
|
||||
exchange.setRequestURI("/");
|
||||
|
||||
getHttpClient().send(exchange);
|
||||
// Cancelling here is wrong and makes the test fail spuriously
|
||||
// due to a race condition with send(): the send() can complete
|
||||
// before the exchange is canceled so it will be in STATUS_COMPLETE
|
||||
// which will fail the test.
|
||||
// exchange.cancel();
|
||||
|
||||
int status = exchange.waitForDone();
|
||||
assertEquals(HttpExchange.STATUS_CANCELLED, status);
|
||||
assertFalse(exchange.isResponseCompleted());
|
||||
assertFalse(exchange.isFailed());
|
||||
assertFalse(exchange.isAssociated());
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Test
|
||||
public void testHttpExchangeCancelOnRequestCommitted() throws Exception
|
||||
{
|
||||
TestHttpExchange exchange = new TestHttpExchange()
|
||||
{
|
||||
@Override
|
||||
protected void onRequestCommitted() throws IOException
|
||||
{
|
||||
super.onRequestCommitted();
|
||||
cancel();
|
||||
}
|
||||
};
|
||||
exchange.setAddress(newAddress());
|
||||
exchange.setRequestURI("/");
|
||||
|
||||
getHttpClient().send(exchange);
|
||||
|
||||
int status = exchange.waitForDone();
|
||||
assertEquals(HttpExchange.STATUS_CANCELLED, status);
|
||||
assertFalse(exchange.isResponseCompleted());
|
||||
assertFalse(exchange.isFailed());
|
||||
assertFalse(exchange.isAssociated());
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Test
|
||||
public void testHttpExchangeCancelOnRequestComplete() throws Exception
|
||||
{
|
||||
TestHttpExchange exchange = new TestHttpExchange()
|
||||
{
|
||||
@Override
|
||||
protected void onRequestComplete() throws IOException
|
||||
{
|
||||
super.onRequestComplete();
|
||||
cancel();
|
||||
}
|
||||
};
|
||||
exchange.setAddress(newAddress());
|
||||
exchange.setRequestURI("/");
|
||||
|
||||
getHttpClient().send(exchange);
|
||||
|
||||
int status = exchange.waitForDone();
|
||||
assertThat("Exchange Status", status, is(HttpExchange.STATUS_CANCELLED));
|
||||
assertThat("Exchange.isResponseCompleted", exchange.isResponseCompleted(), is(false));
|
||||
assertThat("Exchange.isFailed", exchange.isFailed(), is(false));
|
||||
assertThat("Exchange.isAssociated", exchange.isAssociated(), is(false));
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Test
|
||||
public void testHttpExchangeCancelOnResponseStatus() throws Exception
|
||||
{
|
||||
TestHttpExchange exchange = new TestHttpExchange()
|
||||
{
|
||||
@Override
|
||||
protected void onResponseStatus(ByteBuffer version, int status, ByteBuffer reason) throws IOException
|
||||
{
|
||||
super.onResponseStatus(version, status, reason);
|
||||
cancel();
|
||||
}
|
||||
};
|
||||
exchange.setAddress(newAddress());
|
||||
exchange.setRequestURI("/");
|
||||
|
||||
getHttpClient().send(exchange);
|
||||
|
||||
int status = exchange.waitForDone();
|
||||
assertEquals(HttpExchange.STATUS_CANCELLED, status);
|
||||
assertFalse(exchange.isResponseCompleted());
|
||||
assertFalse(exchange.isFailed());
|
||||
assertFalse(exchange.isAssociated());
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Test
|
||||
public void testHttpExchangeCancelOnResponseHeader() throws Exception
|
||||
{
|
||||
TestHttpExchange exchange = new TestHttpExchange()
|
||||
{
|
||||
@Override
|
||||
protected void onResponseHeader(ByteBuffer name, ByteBuffer value) throws IOException
|
||||
{
|
||||
super.onResponseHeader(name, value);
|
||||
cancel();
|
||||
}
|
||||
};
|
||||
exchange.setAddress(newAddress());
|
||||
exchange.setRequestURI("/");
|
||||
|
||||
getHttpClient().send(exchange);
|
||||
|
||||
int status = exchange.waitForDone();
|
||||
assertEquals(HttpExchange.STATUS_CANCELLED, status);
|
||||
assertFalse(exchange.isResponseCompleted());
|
||||
assertFalse(exchange.isFailed());
|
||||
assertFalse(exchange.isAssociated());
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Test
|
||||
public void testHttpExchangeCancelOnResponseHeadersComplete() throws Exception
|
||||
{
|
||||
TestHttpExchange exchange = new TestHttpExchange()
|
||||
{
|
||||
@Override
|
||||
protected void onResponseHeaderComplete() throws IOException
|
||||
{
|
||||
super.onResponseHeaderComplete();
|
||||
cancel();
|
||||
}
|
||||
};
|
||||
exchange.setAddress(newAddress());
|
||||
exchange.setRequestURI("/");
|
||||
|
||||
getHttpClient().send(exchange);
|
||||
|
||||
int status = exchange.waitForDone();
|
||||
assertEquals(HttpExchange.STATUS_CANCELLED, status);
|
||||
assertFalse(exchange.isResponseCompleted());
|
||||
assertFalse(exchange.isFailed());
|
||||
assertFalse(exchange.isAssociated());
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Test
|
||||
public void testHttpExchangeCancelOnResponseContent() throws Exception
|
||||
{
|
||||
TestHttpExchange exchange = new TestHttpExchange()
|
||||
{
|
||||
@Override
|
||||
protected void onResponseContent(ByteBuffer content) throws IOException
|
||||
{
|
||||
super.onResponseContent(content);
|
||||
cancel();
|
||||
}
|
||||
};
|
||||
exchange.setAddress(newAddress());
|
||||
exchange.setRequestURI("/?action=body");
|
||||
|
||||
getHttpClient().send(exchange);
|
||||
|
||||
int status = exchange.waitForDone();
|
||||
assertEquals(HttpExchange.STATUS_CANCELLED, status);
|
||||
assertFalse(exchange.isResponseCompleted());
|
||||
assertFalse(exchange.isFailed());
|
||||
assertFalse(exchange.isAssociated());
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Test
|
||||
public void testHttpExchangeCancelOnResponseComplete() throws Exception
|
||||
{
|
||||
TestHttpExchange exchange = new TestHttpExchange()
|
||||
{
|
||||
@Override
|
||||
protected void onResponseComplete() throws IOException
|
||||
{
|
||||
super.onResponseComplete();
|
||||
cancel();
|
||||
}
|
||||
};
|
||||
exchange.setAddress(newAddress());
|
||||
exchange.setRequestURI("/");
|
||||
|
||||
getHttpClient().send(exchange);
|
||||
|
||||
int status = exchange.waitForDone();
|
||||
assertTrue(exchange.isResponseCompleted());
|
||||
assertFalse(exchange.isFailed());
|
||||
assertFalse(exchange.isAssociated());
|
||||
assertEquals(HttpExchange.STATUS_COMPLETED, status);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Test
|
||||
public void testHttpExchangeOnServerException() throws Exception
|
||||
{
|
||||
try
|
||||
{
|
||||
((StdErrLog)Log.getLogger(AbstractHttpConnection.class)).setHideStacks(true);
|
||||
TestHttpExchange exchange = new TestHttpExchange();
|
||||
exchange.setAddress(newAddress());
|
||||
exchange.setRequestURI("/?action=throw");
|
||||
|
||||
getHttpClient().send(exchange);
|
||||
|
||||
int status = exchange.waitForDone();
|
||||
assertEquals(HttpExchange.STATUS_COMPLETED, status);
|
||||
assertTrue(exchange.isResponseCompleted());
|
||||
assertFalse(exchange.isFailed());
|
||||
assertFalse(exchange.isAssociated());
|
||||
}
|
||||
finally
|
||||
{
|
||||
((StdErrLog)Log.getLogger(AbstractHttpConnection.class)).setHideStacks(false);
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Test
|
||||
public void testHttpExchangeOnExpire() throws Exception
|
||||
{
|
||||
HttpClient httpClient = getHttpClient();
|
||||
httpClient.stop();
|
||||
httpClient.setTimeout(1000);
|
||||
httpClient.start();
|
||||
|
||||
TestHttpExchange exchange = new TestHttpExchange();
|
||||
exchange.setAddress(newAddress());
|
||||
exchange.setRequestURI("/?action=wait5000");
|
||||
|
||||
long start = System.currentTimeMillis();
|
||||
httpClient.send(exchange);
|
||||
|
||||
int status = exchange.waitForDone();
|
||||
long end = System.currentTimeMillis();
|
||||
|
||||
assertTrue(HttpExchange.STATUS_EXPIRED==status||HttpExchange.STATUS_EXCEPTED==status);
|
||||
assertFalse(exchange.isResponseCompleted());
|
||||
assertTrue(end-start<4000);
|
||||
assertTrue(exchange.isExpired());
|
||||
assertFalse(exchange.isFailed());
|
||||
assertFalse(exchange.isAssociated());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHttpExchangeCancelReturnsConnection() throws Exception
|
||||
{
|
||||
TestHttpExchange exchange = new TestHttpExchange();
|
||||
Address address = newAddress();
|
||||
exchange.setAddress(address);
|
||||
long delay = 5000;
|
||||
exchange.setRequestURI("/?action=wait" + delay);
|
||||
|
||||
HttpClient httpClient = getHttpClient();
|
||||
HttpDestination destination = httpClient.getDestination(address, false);
|
||||
int connections = destination.getConnections();
|
||||
httpClient.send(exchange);
|
||||
Thread.sleep(delay / 2);
|
||||
Assert.assertEquals(connections + 1, destination.getConnections());
|
||||
|
||||
exchange.cancel();
|
||||
Assert.assertEquals(connections, destination.getConnections());
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
protected abstract HttpClient getHttpClient();
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
protected Address newAddress()
|
||||
{
|
||||
return new Address("localhost", connector.getLocalPort());
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
private static class EmptyHandler extends AbstractHandler
|
||||
{
|
||||
/* ------------------------------------------------------------ */
|
||||
public void handle(String path, Request request, HttpServletRequest httpRequest, HttpServletResponse httpResponse) throws IOException, ServletException
|
||||
{
|
||||
request.setHandled(true);
|
||||
String action = httpRequest.getParameter("action");
|
||||
if (action != null)
|
||||
{
|
||||
if ("body".equals(action))
|
||||
{
|
||||
ServletOutputStream output = httpResponse.getOutputStream();
|
||||
output.write("body".getBytes("UTF-8"));
|
||||
// output.flush();
|
||||
}
|
||||
else if ("throw".equals(action))
|
||||
{
|
||||
throw new ServletException();
|
||||
}
|
||||
else if (action.startsWith("wait"))
|
||||
{
|
||||
long sleep = Long.valueOf(action.substring("wait".length()));
|
||||
long start=System.currentTimeMillis();
|
||||
try
|
||||
{
|
||||
Thread.sleep(sleep);
|
||||
long end=System.currentTimeMillis();
|
||||
assertTrue("Duration "+(end-start)+" >~ "+sleep,(end-start)>sleep-100);
|
||||
}
|
||||
catch (InterruptedException x)
|
||||
{
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
protected static class TestHttpExchange extends ContentExchange
|
||||
{
|
||||
private boolean responseCompleted;
|
||||
private boolean failed = false;
|
||||
private boolean expired = false;
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
protected TestHttpExchange()
|
||||
{
|
||||
super(true);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
protected synchronized void onResponseComplete() throws IOException
|
||||
{
|
||||
this.responseCompleted = true;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public synchronized boolean isResponseCompleted()
|
||||
{
|
||||
return responseCompleted;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
protected synchronized void onException(Throwable ex)
|
||||
{
|
||||
LOG.debug(ex);
|
||||
if (ex instanceof SocketTimeoutException ||
|
||||
ex.getCause() instanceof SocketTimeoutException)
|
||||
expired=true;
|
||||
else
|
||||
failed = true;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public synchronized boolean isFailed()
|
||||
{
|
||||
return failed;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
protected synchronized void onExpire()
|
||||
{
|
||||
this.expired = true;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public synchronized boolean isExpired()
|
||||
{
|
||||
return expired;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,110 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2012 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.client;
|
||||
|
||||
import static org.junit.Assert.assertNull;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @version $Revision$ $Date$
|
||||
*/
|
||||
public class AsyncCallbackHttpExchangeTest
|
||||
{
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* If the HttpExchange callbacks are called holding the lock on HttpExchange,
|
||||
* it will be impossible for the callback to perform some work asynchronously
|
||||
* and contemporarly accessing the HttpExchange instance synchronized state.
|
||||
* This test verifies that this situation does not happen.
|
||||
*
|
||||
* @throws Exception if the test fails
|
||||
*/
|
||||
@Test
|
||||
public void testAsyncCallback() throws Exception
|
||||
{
|
||||
ExecutorService executor = Executors.newCachedThreadPool();
|
||||
try
|
||||
{
|
||||
AtomicReference<Exception> failure = new AtomicReference<Exception>();
|
||||
TestHttpExchange exchange = new TestHttpExchange(executor, failure);
|
||||
exchange.setStatus(HttpExchange.STATUS_WAITING_FOR_COMMIT);
|
||||
exchange.setStatus(HttpExchange.STATUS_SENDING_REQUEST);
|
||||
// This status change triggers onRequestCommitted()
|
||||
exchange.setStatus(HttpExchange.STATUS_WAITING_FOR_RESPONSE);
|
||||
assertNull(failure.get());
|
||||
}
|
||||
finally
|
||||
{
|
||||
executor.shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
private class TestHttpExchange extends HttpExchange
|
||||
{
|
||||
private final ExecutorService executor;
|
||||
private final AtomicReference<Exception> failure;
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
private TestHttpExchange(ExecutorService executor, AtomicReference<Exception> failure)
|
||||
{
|
||||
this.executor = executor;
|
||||
this.failure = failure;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
protected void onRequestCommitted() throws IOException
|
||||
{
|
||||
Future<Integer> future = executor.submit(new Callable<Integer>()
|
||||
{
|
||||
/* ------------------------------------------------------------ */
|
||||
public Integer call() throws Exception
|
||||
{
|
||||
// Method getStatus() reads synchronized state
|
||||
return TestHttpExchange.this.getStatus();
|
||||
}
|
||||
});
|
||||
|
||||
// We're waiting for the future to complete, thus never exiting
|
||||
// this method; if this method is called with the lock held,
|
||||
// this method never completes
|
||||
try
|
||||
{
|
||||
future.get(1000, TimeUnit.MILLISECONDS);
|
||||
// Test green here
|
||||
}
|
||||
catch (Exception x)
|
||||
{
|
||||
// Timed out, the test did not pass
|
||||
failure.set(x);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,73 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2012 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.client;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.ServerSocket;
|
||||
|
||||
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
|
||||
import org.eclipse.jetty.util.ssl.SslContextFactory;
|
||||
import org.junit.BeforeClass;
|
||||
|
||||
public class AsyncSelectConnectionTest extends AbstractConnectionTest
|
||||
{
|
||||
protected HttpClient newHttpClient()
|
||||
{
|
||||
HttpClient httpClient = new HttpClient();
|
||||
httpClient.setConnectorType(HttpClient.CONNECTOR_SELECT_CHANNEL);
|
||||
httpClient.setConnectBlocking(false);
|
||||
return httpClient;
|
||||
}
|
||||
|
||||
static SslContextFactory ctx = new SslContextFactory(MavenTestingUtils.getTestResourceFile("keystore").getAbsolutePath());
|
||||
|
||||
@BeforeClass
|
||||
public static void initKS() throws Exception
|
||||
{
|
||||
ctx.setKeyStorePassword("storepwd");
|
||||
ctx.setKeyManagerPassword("keypwd");
|
||||
ctx.start();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getScheme()
|
||||
{
|
||||
return "https";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ServerSocket newServerSocket() throws IOException
|
||||
{
|
||||
return ctx.newSslServerSocket(null,0,100);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void testServerHalfClosedIncomplete() throws Exception
|
||||
{
|
||||
// SSL doesn't do half closes
|
||||
}
|
||||
|
||||
@Override
|
||||
public void testServerClosedIncomplete() throws Exception
|
||||
{
|
||||
super.testServerClosedIncomplete();
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -1,53 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2012 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.client;
|
||||
|
||||
import org.eclipse.jetty.client.helperClasses.AsyncSslServerAndClientCreator;
|
||||
import org.eclipse.jetty.client.helperClasses.ServerAndClientCreator;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
public class AsyncSslHttpExchangeTest extends SslHttpExchangeTest
|
||||
{
|
||||
private static ServerAndClientCreator serverAndClientCreator = new AsyncSslServerAndClientCreator();
|
||||
|
||||
@Before
|
||||
public void setUpOnce() throws Exception
|
||||
{
|
||||
_scheme="https";
|
||||
_server = serverAndClientCreator.createServer();
|
||||
_httpClient = serverAndClientCreator.createClient(3000L,3500L,2000);
|
||||
_port = _server.getConnectors()[0].getLocalPort();
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testPerf1() throws Exception
|
||||
{
|
||||
sender(1,true);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void testBigPostWithContentExchange() throws Exception
|
||||
{
|
||||
super.testBigPostWithContentExchange();
|
||||
}
|
||||
|
||||
}
|
|
@ -1,60 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2012 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.client;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @version $Revision$ $Date$
|
||||
*/
|
||||
public class BlockingHttpExchangeCancelTest extends AbstractHttpExchangeCancelTest
|
||||
{
|
||||
private HttpClient httpClient;
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Before
|
||||
@Override
|
||||
public void setUp() throws Exception
|
||||
{
|
||||
super.setUp();
|
||||
httpClient = new HttpClient();
|
||||
httpClient.setConnectorType(HttpClient.CONNECTOR_SOCKET);
|
||||
httpClient.start();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@After
|
||||
@Override
|
||||
public void tearDown() throws Exception
|
||||
{
|
||||
httpClient.stop();
|
||||
super.tearDown();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
protected HttpClient getHttpClient()
|
||||
{
|
||||
return httpClient;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,140 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2012 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.client;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Enumeration;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.eclipse.jetty.http.HttpStatus;
|
||||
import org.eclipse.jetty.server.Connector;
|
||||
import org.eclipse.jetty.server.Request;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.server.handler.AbstractHandler;
|
||||
import org.eclipse.jetty.server.nio.SelectChannelConnector;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public class CachedHeadersIsolationTest
|
||||
{
|
||||
|
||||
Server server;
|
||||
HttpClient client;
|
||||
int port;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception
|
||||
{
|
||||
server = new Server();
|
||||
|
||||
Connector connector = new SelectChannelConnector();
|
||||
|
||||
server.addConnector(connector);
|
||||
|
||||
server.setHandler(new AbstractHandler()
|
||||
{
|
||||
/* ------------------------------------------------------------ */
|
||||
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException,
|
||||
ServletException
|
||||
{
|
||||
response.setStatus(HttpStatus.OK_200);
|
||||
response.addHeader("For",request.getQueryString());
|
||||
response.addHeader("Name","Value");
|
||||
response.getOutputStream().print("blah");
|
||||
response.flushBuffer();
|
||||
}
|
||||
});
|
||||
|
||||
server.start();
|
||||
|
||||
port = server.getConnectors()[0].getLocalPort();
|
||||
|
||||
client = new HttpClient();
|
||||
client.setConnectorType(HttpClient.CONNECTOR_SELECT_CHANNEL);
|
||||
client.setConnectTimeout(5);
|
||||
client.start();
|
||||
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@After
|
||||
public void tearDown() throws Exception
|
||||
{
|
||||
server.stop();
|
||||
client.stop();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Test
|
||||
public void testHeaderWhenReadEarly() throws Exception
|
||||
{
|
||||
|
||||
CachedExchange e1 = new CachedExchange(true);
|
||||
CachedExchange e2 = new CachedExchange(true);
|
||||
|
||||
e1.setURL("http://localhost:" + port + "/?a=short");
|
||||
e2.setURL("http://localhost:" + port + "/?a=something_longer");
|
||||
|
||||
client.send(e1);
|
||||
while (!e1.isDone())
|
||||
Thread.sleep(100);
|
||||
|
||||
assertEquals("Read buffer","Value",e1.getResponseFields().getStringField("Name"));
|
||||
|
||||
client.send(e2);
|
||||
while (!e2.isDone())
|
||||
Thread.sleep(100);
|
||||
|
||||
assertEquals("Overwritten buffer","Value",e1.getResponseFields().getStringField("Name"));
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Test
|
||||
public void testHeaderWhenReadLate() throws Exception
|
||||
{
|
||||
|
||||
CachedExchange e1 = new CachedExchange(true);
|
||||
CachedExchange e2 = new CachedExchange(true);
|
||||
|
||||
e1.setURL("http://localhost:" + port + "/?a=short");
|
||||
e2.setURL("http://localhost:" + port + "/?a=something_longer");
|
||||
|
||||
client.send(e1);
|
||||
while (!e1.isDone())
|
||||
Thread.sleep(100);
|
||||
|
||||
client.send(e2);
|
||||
while (!e2.isDone())
|
||||
Thread.sleep(100);
|
||||
|
||||
for ( Enumeration<String> e = e1.getResponseFields().getValues("Name"); e.hasMoreElements();)
|
||||
{
|
||||
System.out.println(e.nextElement());
|
||||
}
|
||||
|
||||
assertEquals("Overwritten buffer","Value",e1.getResponseFields().getStringField("Name"));
|
||||
}
|
||||
}
|
|
@ -1,389 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2012 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.client;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.net.URLDecoder;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.ServletInputStream;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.eclipse.jetty.client.security.Realm;
|
||||
import org.eclipse.jetty.client.security.SimpleRealmResolver;
|
||||
import org.eclipse.jetty.http.HttpMethod;
|
||||
import org.eclipse.jetty.http.HttpStatus;
|
||||
import org.eclipse.jetty.io.ByteArrayBuffer;
|
||||
import org.eclipse.jetty.io.EofException;
|
||||
import org.eclipse.jetty.server.Handler;
|
||||
import org.eclipse.jetty.server.Request;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.server.handler.AbstractHandler;
|
||||
import org.eclipse.jetty.server.handler.HandlerCollection;
|
||||
import org.eclipse.jetty.server.nio.SelectChannelConnector;
|
||||
import org.eclipse.jetty.servlet.DefaultServlet;
|
||||
import org.eclipse.jetty.servlet.ServletContextHandler;
|
||||
import org.eclipse.jetty.servlet.ServletHolder;
|
||||
import org.eclipse.jetty.util.IO;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
public class ContentExchangeTest
|
||||
{
|
||||
private static String _content =
|
||||
"Lorem ipsum dolor sit amet, consectetur adipiscing elit. In quis felis nunc. "+
|
||||
"Quisque suscipit mauris et ante auctor ornare rhoncus lacus aliquet. Pellentesque "+
|
||||
"habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. "+
|
||||
"Vestibulum sit amet felis augue, vel convallis dolor. Cras accumsan vehicula diam "+
|
||||
"at faucibus. Etiam in urna turpis, sed congue mi. Morbi et lorem eros. Donec vulputate "+
|
||||
"velit in risus suscipit lobortis. Aliquam id urna orci, nec sollicitudin ipsum. "+
|
||||
"Cras a orci turpis. Donec suscipit vulputate cursus. Mauris nunc tellus, fermentum "+
|
||||
"eu auctor ut, mollis at diam. Quisque porttitor ultrices metus, vitae tincidunt massa "+
|
||||
"sollicitudin a. Vivamus porttitor libero eget purus hendrerit cursus. Integer aliquam "+
|
||||
"consequat mauris quis luctus. Cras enim nibh, dignissim eu faucibus ac, mollis nec neque. "+
|
||||
"Aliquam purus mauris, consectetur nec convallis lacinia, porta sed ante. Suspendisse "+
|
||||
"et cursus magna. Donec orci enim, molestie a lobortis eu, imperdiet vitae neque.";
|
||||
|
||||
private File _docRoot;
|
||||
private Server _server;
|
||||
private HttpClient _client;
|
||||
private Realm _realm;
|
||||
private String _protocol;
|
||||
private String _baseUrl;
|
||||
private String _requestContent;
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Before
|
||||
public void setUp()
|
||||
throws Exception
|
||||
{
|
||||
_docRoot = new File("target/test-output/docroot/");
|
||||
_docRoot.mkdirs();
|
||||
_docRoot.deleteOnExit();
|
||||
|
||||
File content = new File(_docRoot,"input.txt");
|
||||
FileOutputStream out = new FileOutputStream(content);
|
||||
out.write(_content.getBytes("utf-8"));
|
||||
out.close();
|
||||
|
||||
_server = new Server();
|
||||
configureServer(_server);
|
||||
_server.start();
|
||||
|
||||
int port = _server.getConnectors()[0].getLocalPort();
|
||||
_baseUrl = _protocol+"://localhost:"+port+ "/";
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@After
|
||||
public void tearDown()
|
||||
throws Exception
|
||||
{
|
||||
if (_server != null)
|
||||
{
|
||||
_server.stop();
|
||||
_server = null;
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Test
|
||||
public void testPut() throws Exception
|
||||
{
|
||||
startClient(_realm);
|
||||
|
||||
ContentExchange putExchange = new ContentExchange();
|
||||
putExchange.setURL(getBaseUrl() + "output.txt");
|
||||
putExchange.setMethod(HttpMethod.PUT);
|
||||
putExchange.setRequestContent(new ByteArrayBuffer(_content.getBytes()));
|
||||
|
||||
_client.send(putExchange);
|
||||
int state = putExchange.waitForDone();
|
||||
|
||||
int responseStatus = putExchange.getResponseStatus();
|
||||
|
||||
stopClient();
|
||||
|
||||
boolean statusOk = (responseStatus == 200 || responseStatus == 201);
|
||||
assertTrue(statusOk);
|
||||
|
||||
String content = IO.toString(new FileInputStream(new File(_docRoot,"output.txt")));
|
||||
assertEquals(_content,content);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Test
|
||||
public void testGet() throws Exception
|
||||
{
|
||||
startClient(_realm);
|
||||
|
||||
ContentExchange getExchange = new ContentExchange();
|
||||
getExchange.setURL(getBaseUrl() + "input.txt");
|
||||
getExchange.setMethod(HttpMethod.GET);
|
||||
|
||||
_client.send(getExchange);
|
||||
int state = getExchange.waitForDone();
|
||||
|
||||
String content = "";
|
||||
int responseStatus = getExchange.getResponseStatus();
|
||||
if (responseStatus == HttpStatus.OK_200)
|
||||
{
|
||||
content = getExchange.getResponseContent();
|
||||
}
|
||||
|
||||
stopClient();
|
||||
|
||||
assertEquals(HttpStatus.OK_200,responseStatus);
|
||||
assertEquals(_content,content);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Test
|
||||
public void testHead() throws Exception
|
||||
{
|
||||
startClient(_realm);
|
||||
|
||||
ContentExchange getExchange = new ContentExchange();
|
||||
getExchange.setURL(getBaseUrl() + "input.txt");
|
||||
getExchange.setMethod(HttpMethod.HEAD);
|
||||
|
||||
_client.send(getExchange);
|
||||
getExchange.waitForDone();
|
||||
|
||||
int responseStatus = getExchange.getResponseStatus();
|
||||
|
||||
stopClient();
|
||||
|
||||
assertEquals(HttpStatus.OK_200,responseStatus);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Test
|
||||
public void testPost() throws Exception
|
||||
{
|
||||
startClient(_realm);
|
||||
|
||||
ContentExchange postExchange = new ContentExchange();
|
||||
postExchange.setURL(getBaseUrl() + "test");
|
||||
postExchange.setMethod(HttpMethod.POST);
|
||||
postExchange.setRequestContent(new ByteArrayBuffer(_content.getBytes()));
|
||||
|
||||
_client.send(postExchange);
|
||||
int state = postExchange.waitForDone();
|
||||
|
||||
int responseStatus = postExchange.getResponseStatus();
|
||||
|
||||
stopClient();
|
||||
|
||||
assertEquals(HttpStatus.OK_200,responseStatus);
|
||||
assertEquals(_content,_requestContent);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
protected void configureServer(Server server)
|
||||
throws Exception
|
||||
{
|
||||
setProtocol("http");
|
||||
|
||||
SelectChannelConnector connector = new SelectChannelConnector();
|
||||
server.addConnector(connector);
|
||||
|
||||
Handler handler = new TestHandler(getBasePath());
|
||||
|
||||
ServletContextHandler root = new ServletContextHandler();
|
||||
root.setContextPath("/");
|
||||
root.setResourceBase(_docRoot.getAbsolutePath());
|
||||
ServletHolder servletHolder = new ServletHolder( new DefaultServlet() );
|
||||
servletHolder.setInitParameter( "gzip", "true" );
|
||||
root.addServlet( servletHolder, "/*" );
|
||||
|
||||
HandlerCollection handlers = new HandlerCollection();
|
||||
handlers.setHandlers(new Handler[]{handler, root});
|
||||
server.setHandler( handlers );
|
||||
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
protected void startClient(Realm realm)
|
||||
throws Exception
|
||||
{
|
||||
_client = new HttpClient();
|
||||
configureClient(_client);
|
||||
|
||||
if (realm != null)
|
||||
_client.setRealmResolver(new SimpleRealmResolver(realm));
|
||||
|
||||
_client.start();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
protected void configureClient(HttpClient client)
|
||||
throws Exception
|
||||
{
|
||||
client.setConnectorType(HttpClient.CONNECTOR_SELECT_CHANNEL);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
protected void stopClient()
|
||||
throws Exception
|
||||
{
|
||||
if (_client != null)
|
||||
{
|
||||
_client.stop();
|
||||
_client = null;
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
protected String getBasePath()
|
||||
{
|
||||
return _docRoot.getAbsolutePath();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
protected String getBaseUrl()
|
||||
{
|
||||
return _baseUrl;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
protected HttpClient getClient()
|
||||
{
|
||||
return _client;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
protected Realm getRealm()
|
||||
{
|
||||
return _realm;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
protected String getContent()
|
||||
{
|
||||
return _content;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
protected void setProtocol(String protocol)
|
||||
{
|
||||
_protocol = protocol;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
protected void setRealm(Realm realm)
|
||||
{
|
||||
_realm = realm;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public static void copyStream(InputStream in, OutputStream out)
|
||||
{
|
||||
try
|
||||
{
|
||||
byte[] buffer=new byte[1024];
|
||||
int len;
|
||||
while ((len=in.read(buffer))>=0)
|
||||
{
|
||||
out.write(buffer,0,len);
|
||||
}
|
||||
}
|
||||
catch (EofException e)
|
||||
{
|
||||
System.err.println(e);
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
protected class TestHandler extends AbstractHandler {
|
||||
private final String resourcePath;
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public TestHandler(String repositoryPath) {
|
||||
this.resourcePath = repositoryPath;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public void handle(String target, Request baseRequest,
|
||||
HttpServletRequest request, HttpServletResponse response)
|
||||
throws IOException, ServletException
|
||||
{
|
||||
if (baseRequest.isHandled())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
OutputStream out = null;
|
||||
|
||||
if (baseRequest.getMethod().equals("PUT"))
|
||||
{
|
||||
baseRequest.setHandled(true);
|
||||
|
||||
File file = new File(resourcePath, URLDecoder.decode(request.getPathInfo()));
|
||||
file.getParentFile().mkdirs();
|
||||
file.deleteOnExit();
|
||||
|
||||
out = new FileOutputStream(file);
|
||||
|
||||
response.setStatus(HttpServletResponse.SC_CREATED);
|
||||
}
|
||||
|
||||
if (baseRequest.getMethod().equals("POST"))
|
||||
{
|
||||
baseRequest.setHandled(true);
|
||||
out = new ByteArrayOutputStream();
|
||||
|
||||
response.setStatus(HttpServletResponse.SC_OK);
|
||||
}
|
||||
|
||||
if (out != null)
|
||||
{
|
||||
ServletInputStream in = request.getInputStream();
|
||||
try
|
||||
{
|
||||
copyStream( in, out );
|
||||
}
|
||||
finally
|
||||
{
|
||||
in.close();
|
||||
out.close();
|
||||
}
|
||||
|
||||
if (!(out instanceof FileOutputStream))
|
||||
_requestContent = out.toString();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,200 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2012 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.client;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import org.eclipse.jetty.http.HttpMethod;
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** A simple test http client like curl.
|
||||
* <p>
|
||||
* Usage is java -cp $CLASSPATH org.eclipse.jetty.client.Curl [ option | URL ] ...
|
||||
* Options supported are: <ul>
|
||||
* <li>--async : The following URLs are fetched in parallel (default)
|
||||
* <li>--sync : The following URLs are fetched in sequence
|
||||
* <li>--dump : The content is dumped to stdout
|
||||
* <li>--nodump : The content is suppressed (default)
|
||||
* </ul>
|
||||
*/
|
||||
public class Curl
|
||||
{
|
||||
public static void main(String[] args)
|
||||
throws Exception
|
||||
{
|
||||
if (args.length==0)
|
||||
args=new String[]
|
||||
{ "--sync", "http://www.sun.com/robots.txt", "http://www.sun.com/favicon.ico" , "--dump", "http://www.sun.com/robots.txt"};
|
||||
|
||||
HttpClient client = new HttpClient();
|
||||
client.setIdleTimeout(2000);
|
||||
client.start();
|
||||
boolean async=true;
|
||||
boolean dump= false;
|
||||
boolean verbose= false;
|
||||
|
||||
|
||||
int urls=0;
|
||||
for (String arg : args)
|
||||
{
|
||||
if (!arg.startsWith("-"))
|
||||
urls++;
|
||||
}
|
||||
|
||||
final CountDownLatch latch = new CountDownLatch(urls);
|
||||
|
||||
for (String arg : args)
|
||||
{
|
||||
if ("--verbose".equals(arg))
|
||||
{
|
||||
verbose=true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if ("--sync".equals(arg))
|
||||
{
|
||||
async=false;
|
||||
continue;
|
||||
}
|
||||
|
||||
if ("--async".equals(arg))
|
||||
{
|
||||
async=true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if ("--dump".equals(arg))
|
||||
{
|
||||
dump=true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if ("--nodump".equals(arg))
|
||||
{
|
||||
dump=false;
|
||||
continue;
|
||||
}
|
||||
|
||||
final boolean d = dump;
|
||||
final boolean v = verbose;
|
||||
HttpExchange ex = new HttpExchange()
|
||||
{
|
||||
AtomicBoolean counted=new AtomicBoolean(false);
|
||||
|
||||
@Override
|
||||
protected void onConnectionFailed(Throwable ex)
|
||||
{
|
||||
if (!counted.getAndSet(true))
|
||||
latch.countDown();
|
||||
super.onConnectionFailed(ex);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onException(Throwable ex)
|
||||
{
|
||||
if (!counted.getAndSet(true))
|
||||
latch.countDown();
|
||||
super.onException(ex);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onExpire()
|
||||
{
|
||||
if (!counted.getAndSet(true))
|
||||
latch.countDown();
|
||||
super.onExpire();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResponseComplete() throws IOException
|
||||
{
|
||||
if (!counted.getAndSet(true))
|
||||
latch.countDown();
|
||||
super.onResponseComplete();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResponseContent(ByteBuffer content) throws IOException
|
||||
{
|
||||
super.onResponseContent(content);
|
||||
if (d)
|
||||
System.out.print(content.toString());
|
||||
if (v)
|
||||
System.err.println("got "+content.length());
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @see org.eclipse.jetty.client.HttpExchange#onResponseHeader(org.eclipse.jetty.io.ByteBuffer, org.eclipse.jetty.io.ByteBuffer)
|
||||
*/
|
||||
@Override
|
||||
protected void onResponseHeader(ByteBuffer name, ByteBuffer value) throws IOException
|
||||
{
|
||||
super.onResponseHeader(name,value);
|
||||
if (v)
|
||||
System.err.println(name+": "+value);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @see org.eclipse.jetty.client.HttpExchange#onResponseHeaderComplete()
|
||||
*/
|
||||
@Override
|
||||
protected void onResponseHeaderComplete() throws IOException
|
||||
{
|
||||
super.onResponseHeaderComplete();
|
||||
if (v)
|
||||
System.err.println();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @see org.eclipse.jetty.client.HttpExchange#onResponseStatus(org.eclipse.jetty.io.ByteBuffer, int, org.eclipse.jetty.io.ByteBuffer)
|
||||
*/
|
||||
@Override
|
||||
protected void onResponseStatus(ByteBuffer version, int status, ByteBuffer reason) throws IOException
|
||||
{
|
||||
super.onResponseStatus(version,status,reason);
|
||||
if (v)
|
||||
System.err.println(version+" "+status+" "+reason);
|
||||
}
|
||||
};
|
||||
|
||||
ex.setMethod(HttpMethod.GET);
|
||||
ex.setURL(arg);
|
||||
|
||||
System.err.println("\nSending "+ex);
|
||||
client.send(ex);
|
||||
|
||||
if (!async)
|
||||
{
|
||||
System.err.println("waiting...");
|
||||
ex.waitForDone();
|
||||
System.err.println("Done");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
latch.await();
|
||||
}
|
||||
}
|
|
@ -1,276 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2012 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.client;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.eclipse.jetty.http.HttpMethod;
|
||||
import org.eclipse.jetty.http.HttpStatus;
|
||||
import org.eclipse.jetty.io.ByteArrayBuffer;
|
||||
import org.eclipse.jetty.server.Handler;
|
||||
import org.eclipse.jetty.server.Request;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.server.handler.AbstractHandler;
|
||||
import org.eclipse.jetty.server.handler.HandlerCollection;
|
||||
import org.eclipse.jetty.server.nio.SelectChannelConnector;
|
||||
import org.eclipse.jetty.servlet.DefaultServlet;
|
||||
import org.eclipse.jetty.servlet.ServletContextHandler;
|
||||
import org.eclipse.jetty.servlet.ServletHolder;
|
||||
import org.junit.Test;
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public class ErrorStatusTest
|
||||
extends ContentExchangeTest
|
||||
{
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Test
|
||||
public void testPutBadRequest()
|
||||
throws Exception
|
||||
{
|
||||
doPutFail(HttpStatus.BAD_REQUEST_400);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Test
|
||||
public void testPutUnauthorized()
|
||||
throws Exception
|
||||
{
|
||||
doPutFail(HttpStatus.UNAUTHORIZED_401);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Test
|
||||
public void testPutForbidden()
|
||||
throws Exception
|
||||
{
|
||||
doPutFail(HttpStatus.FORBIDDEN_403);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Test
|
||||
public void testPutNotFound()
|
||||
throws Exception
|
||||
{
|
||||
doPutFail(HttpStatus.NOT_FOUND_404);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Test
|
||||
public void testPutServerError()
|
||||
throws Exception
|
||||
{
|
||||
doPutFail(HttpStatus.INTERNAL_SERVER_ERROR_500);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Test
|
||||
public void testGetBadRequest()
|
||||
throws Exception
|
||||
{
|
||||
doGetFail(HttpStatus.BAD_REQUEST_400);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Test
|
||||
public void testGetUnauthorized()
|
||||
throws Exception
|
||||
{
|
||||
doGetFail(HttpStatus.UNAUTHORIZED_401);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Test
|
||||
public void testGetNotFound()
|
||||
throws Exception
|
||||
{
|
||||
doGetFail(HttpStatus.NOT_FOUND_404);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Test
|
||||
public void testGetServerError()
|
||||
throws Exception
|
||||
{
|
||||
doGetFail(HttpStatus.INTERNAL_SERVER_ERROR_500);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Test
|
||||
public void testPostBadRequest()
|
||||
throws Exception
|
||||
{
|
||||
doPostFail(HttpStatus.BAD_REQUEST_400);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Test
|
||||
public void testPostUnauthorized()
|
||||
throws Exception
|
||||
{
|
||||
doPostFail(HttpStatus.UNAUTHORIZED_401);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Test
|
||||
public void testPostForbidden()
|
||||
throws Exception
|
||||
{
|
||||
doPostFail(HttpStatus.FORBIDDEN_403);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Test
|
||||
public void testPostNotFound()
|
||||
throws Exception
|
||||
{
|
||||
doPostFail(HttpStatus.NOT_FOUND_404);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Test
|
||||
public void testPostServerError()
|
||||
throws Exception
|
||||
{
|
||||
doPostFail(HttpStatus.INTERNAL_SERVER_ERROR_500);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
protected void doPutFail(int status)
|
||||
throws Exception
|
||||
{
|
||||
startClient(getRealm());
|
||||
|
||||
ContentExchange putExchange = new ContentExchange();
|
||||
putExchange.setURL(getBaseUrl() + "output.txt");
|
||||
putExchange.setMethod(HttpMethod.PUT);
|
||||
putExchange.setRequestHeader("X-Response-Status",Integer.toString(status));
|
||||
putExchange.setRequestContent(new ByteArrayBuffer(getContent().getBytes()));
|
||||
|
||||
getClient().send(putExchange);
|
||||
int state = putExchange.waitForDone();
|
||||
|
||||
int responseStatus = putExchange.getResponseStatus();
|
||||
|
||||
stopClient();
|
||||
|
||||
assertEquals(status, responseStatus);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
protected void doGetFail(int status)
|
||||
throws Exception
|
||||
{
|
||||
startClient(getRealm());
|
||||
|
||||
ContentExchange getExchange = new ContentExchange();
|
||||
getExchange.setURL(getBaseUrl() + "input.txt");
|
||||
getExchange.setMethod(HttpMethod.GET);
|
||||
getExchange.setRequestHeader("X-Response-Status",Integer.toString(status));
|
||||
|
||||
getClient().send(getExchange);
|
||||
int state = getExchange.waitForDone();
|
||||
|
||||
String content;
|
||||
int responseStatus = getExchange.getResponseStatus();
|
||||
if (responseStatus == HttpStatus.OK_200) {
|
||||
content = getExchange.getResponseContent();
|
||||
}
|
||||
|
||||
stopClient();
|
||||
|
||||
assertEquals(status, responseStatus);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
protected void doPostFail(int status)
|
||||
throws Exception
|
||||
{
|
||||
startClient(getRealm());
|
||||
|
||||
ContentExchange postExchange = new ContentExchange();
|
||||
postExchange.setURL(getBaseUrl() + "test");
|
||||
postExchange.setMethod(HttpMethod.POST);
|
||||
postExchange.setRequestHeader("X-Response-Status",Integer.toString(status));
|
||||
postExchange.setRequestContent(new ByteArrayBuffer(getContent().getBytes()));
|
||||
|
||||
getClient().send(postExchange);
|
||||
int state = postExchange.waitForDone();
|
||||
|
||||
int responseStatus = postExchange.getResponseStatus();
|
||||
|
||||
stopClient();
|
||||
|
||||
assertEquals(status, responseStatus);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
protected void configureServer(Server server)
|
||||
throws Exception
|
||||
{
|
||||
setProtocol("http");
|
||||
|
||||
SelectChannelConnector connector = new SelectChannelConnector();
|
||||
server.addConnector(connector);
|
||||
|
||||
ServletContextHandler root = new ServletContextHandler();
|
||||
root.setContextPath("/");
|
||||
root.setResourceBase(getBasePath());
|
||||
ServletHolder servletHolder = new ServletHolder( new DefaultServlet() );
|
||||
servletHolder.setInitParameter( "gzip", "true" );
|
||||
root.addServlet( servletHolder, "/*" );
|
||||
|
||||
Handler status = new StatusHandler();
|
||||
Handler test = new TestHandler(getBasePath());
|
||||
|
||||
HandlerCollection handlers = new HandlerCollection();
|
||||
handlers.setHandlers(new Handler[]{status, test, root});
|
||||
server.setHandler( handlers );
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
protected static class StatusHandler extends AbstractHandler {
|
||||
/* ------------------------------------------------------------ */
|
||||
public void handle(String target, Request baseRequest,
|
||||
HttpServletRequest request, HttpServletResponse response)
|
||||
throws IOException, ServletException
|
||||
{
|
||||
if (baseRequest.isHandled())
|
||||
return;
|
||||
|
||||
int statusValue = 0;
|
||||
String statusHeader = request.getHeader("X-Response-Status");
|
||||
if (statusHeader != null)
|
||||
{
|
||||
statusValue = Integer.parseInt(statusHeader);
|
||||
}
|
||||
if (statusValue != 0)
|
||||
{
|
||||
response.setStatus(statusValue);
|
||||
baseRequest.setHandled(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,197 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2012 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.client;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStream;
|
||||
import java.net.ServerSocket;
|
||||
import java.net.Socket;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.junit.Ignore;
|
||||
|
||||
public class ExpirationWithLimitedConnectionsTest
|
||||
{
|
||||
@Ignore
|
||||
public void testExpirationWithMaxConnectionPerAddressReached() throws Exception
|
||||
{
|
||||
final Logger logger = Log.getLogger("org.eclipse.jetty.client");
|
||||
logger.setDebugEnabled(true);
|
||||
|
||||
HttpClient client = new HttpClient();
|
||||
int maxConnectionsPerAddress = 10;
|
||||
client.setMaxConnectionsPerAddress(maxConnectionsPerAddress);
|
||||
long timeout = 1000;
|
||||
client.setTimeout(timeout);
|
||||
client.start();
|
||||
|
||||
final List<Socket> sockets = new CopyOnWriteArrayList<Socket>();
|
||||
final List<Exception> failures = new CopyOnWriteArrayList<Exception>();
|
||||
final AtomicLong processingDelay = new AtomicLong(200);
|
||||
|
||||
final ExecutorService threadPool = Executors.newCachedThreadPool();
|
||||
final ServerSocket server = new ServerSocket(0);
|
||||
threadPool.submit(new Runnable()
|
||||
{
|
||||
public void run()
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
try
|
||||
{
|
||||
final Socket socket = server.accept();
|
||||
sockets.add(socket);
|
||||
logger.debug("CONNECTION {}", socket.getRemoteSocketAddress());
|
||||
threadPool.submit(new Runnable()
|
||||
{
|
||||
public void run()
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
try
|
||||
{
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream(), "UTF-8"));
|
||||
String firstLine = reader.readLine();
|
||||
String line = firstLine;
|
||||
while (line != null)
|
||||
{
|
||||
if (line.length() == 0)
|
||||
break;
|
||||
line = reader.readLine();
|
||||
}
|
||||
|
||||
if (line == null)
|
||||
break;
|
||||
|
||||
long sleep = processingDelay.get();
|
||||
logger.debug("{} {} {} ms", firstLine, socket.getRemoteSocketAddress(), sleep);
|
||||
TimeUnit.MILLISECONDS.sleep(sleep);
|
||||
|
||||
String response = "" +
|
||||
"HTTP/1.1 200 OK\r\n" +
|
||||
"Content-Length: 0\r\n" +
|
||||
"\r\n";
|
||||
OutputStream output = socket.getOutputStream();
|
||||
output.write(response.getBytes("UTF-8"));
|
||||
output.flush();
|
||||
}
|
||||
catch (Exception x)
|
||||
{
|
||||
failures.add(x);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
catch (Exception x)
|
||||
{
|
||||
failures.add(x);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
List<ContentExchange> exchanges = new ArrayList<ContentExchange>();
|
||||
|
||||
final AtomicBoolean firstExpired = new AtomicBoolean();
|
||||
int count = 0;
|
||||
int maxAdditionalRequest = 100;
|
||||
int additionalRequests = 0;
|
||||
while (true)
|
||||
{
|
||||
TimeUnit.MILLISECONDS.sleep(1); // Just avoid being too fast
|
||||
ContentExchange exchange = new ContentExchange(true)
|
||||
{
|
||||
@Override
|
||||
protected void onResponseComplete() throws IOException
|
||||
{
|
||||
logger.debug("{} {} OK", getMethod(), getRequestURI());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onExpire()
|
||||
{
|
||||
logger.debug("{} {} EXPIRED {}", getMethod(), getRequestURI(), this);
|
||||
firstExpired.compareAndSet(false, true);
|
||||
}
|
||||
};
|
||||
exchanges.add(exchange);
|
||||
Address address = new Address("localhost", server.getLocalPort());
|
||||
exchange.setAddress(address);
|
||||
exchange.setMethod("GET");
|
||||
exchange.setRequestURI("/" + count);
|
||||
exchange.setVersion("HTTP/1.1");
|
||||
exchange.setRequestHeader("Host", address.toString());
|
||||
logger.debug("{} {} SENT", exchange.getMethod(), exchange.getRequestURI());
|
||||
client.send(exchange);
|
||||
++count;
|
||||
|
||||
if (processingDelay.get() > 0)
|
||||
{
|
||||
if (client.getDestination(address, false).getConnections() == maxConnectionsPerAddress)
|
||||
{
|
||||
if (firstExpired.get())
|
||||
{
|
||||
++additionalRequests;
|
||||
if (additionalRequests == maxAdditionalRequest)
|
||||
processingDelay.set(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
++additionalRequests;
|
||||
if (additionalRequests == 2 * maxAdditionalRequest)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (ContentExchange exchange : exchanges)
|
||||
{
|
||||
int status = exchange.waitForDone();
|
||||
Assert.assertTrue(status == HttpExchange.STATUS_COMPLETED || status == HttpExchange.STATUS_EXPIRED);
|
||||
}
|
||||
|
||||
client.stop();
|
||||
|
||||
Assert.assertTrue(failures.isEmpty());
|
||||
|
||||
for (Socket socket : sockets)
|
||||
socket.close();
|
||||
server.close();
|
||||
|
||||
threadPool.shutdown();
|
||||
threadPool.awaitTermination(5, TimeUnit.SECONDS);
|
||||
}
|
||||
}
|
|
@ -1,117 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2012 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.client;
|
||||
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.eclipse.jetty.server.Request;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.server.handler.AbstractHandler;
|
||||
import org.eclipse.jetty.server.nio.SelectChannelConnector;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* Test contributed by: Michiel Thuys for JETTY-806
|
||||
*/
|
||||
public class ExpireTest
|
||||
{
|
||||
private Server server;
|
||||
private HttpClient client;
|
||||
private int port;
|
||||
|
||||
@Before
|
||||
public void init() throws Exception
|
||||
{
|
||||
server = new Server();
|
||||
SelectChannelConnector connector = new SelectChannelConnector();
|
||||
connector.setHost("localhost");
|
||||
connector.setPort(0);
|
||||
server.addConnector(connector);
|
||||
server.setHandler(new AbstractHandler()
|
||||
{
|
||||
public void handle(String target, Request request, HttpServletRequest httpRequest, HttpServletResponse httpResponse)
|
||||
throws IOException, ServletException
|
||||
{
|
||||
request.setHandled(true);
|
||||
try
|
||||
{
|
||||
Thread.sleep(2000);
|
||||
}
|
||||
catch (InterruptedException x)
|
||||
{
|
||||
}
|
||||
}
|
||||
});
|
||||
server.start();
|
||||
port = connector.getLocalPort();
|
||||
|
||||
client = new HttpClient();
|
||||
client.setConnectorType(HttpClient.CONNECTOR_SELECT_CHANNEL);
|
||||
client.setTimeout(200);
|
||||
client.setMaxRetries(0);
|
||||
client.setMaxConnectionsPerAddress(100);
|
||||
client.start();
|
||||
}
|
||||
|
||||
@After
|
||||
public void destroy() throws Exception
|
||||
{
|
||||
client.stop();
|
||||
server.stop();
|
||||
server.join();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExpire() throws Exception
|
||||
{
|
||||
String baseUrl = "http://" + "localhost" + ":" + port + "/";
|
||||
|
||||
int count = 200;
|
||||
final CountDownLatch expires = new CountDownLatch(count);
|
||||
|
||||
for (int i=0;i<count;i++)
|
||||
{
|
||||
final ContentExchange exchange = new ContentExchange()
|
||||
{
|
||||
@Override
|
||||
protected void onExpire()
|
||||
{
|
||||
expires.countDown();
|
||||
}
|
||||
};
|
||||
exchange.setMethod("GET");
|
||||
exchange.setURL(baseUrl);
|
||||
|
||||
client.send(exchange);
|
||||
}
|
||||
|
||||
// Wait to be sure that all exchanges have expired
|
||||
assertTrue(expires.await(5, TimeUnit.SECONDS));
|
||||
}
|
||||
}
|
|
@ -1,37 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2012 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.client;
|
||||
|
||||
import org.eclipse.jetty.client.helperClasses.ExternalKeyStoreAsyncSslServerAndClientCreator;
|
||||
import org.eclipse.jetty.client.helperClasses.ServerAndClientCreator;
|
||||
import org.junit.Before;
|
||||
|
||||
public class ExternalKeyStoreAsyncSslHttpExchangeTest extends SslHttpExchangeTest
|
||||
{
|
||||
private static ServerAndClientCreator serverAndClientCreator = new ExternalKeyStoreAsyncSslServerAndClientCreator();
|
||||
|
||||
@Before
|
||||
public void setUpOnce() throws Exception
|
||||
{
|
||||
_scheme="https";
|
||||
_server = serverAndClientCreator.createServer();
|
||||
_httpClient = serverAndClientCreator.createClient(3000L,3500L,2000);
|
||||
_port = _server.getConnectors()[0].getLocalPort();
|
||||
}
|
||||
}
|
|
@ -1,245 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2012 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
|
||||
package org.eclipse.jetty.client;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.eclipse.jetty.http.HttpMethod;
|
||||
import org.eclipse.jetty.http.HttpStatus;
|
||||
import org.eclipse.jetty.server.Connector;
|
||||
import org.eclipse.jetty.server.Request;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.server.handler.AbstractHandler;
|
||||
import org.eclipse.jetty.server.nio.SelectChannelConnector;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public class Http100ContinueTest
|
||||
{
|
||||
private static final int TIMEOUT = 500;
|
||||
|
||||
private static final String CONTENT = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. In quis felis nunc. "
|
||||
+ "Quisque suscipit mauris et ante auctor ornare rhoncus lacus aliquet. Pellentesque "
|
||||
+ "habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. "
|
||||
+ "Vestibulum sit amet felis augue, vel convallis dolor. Cras accumsan vehicula diam "
|
||||
+ "at faucibus. Etiam in urna turpis, sed congue mi. Morbi et lorem eros. Donec vulputate "
|
||||
+ "velit in risus suscipit lobortis. Aliquam id urna orci, nec sollicitudin ipsum. "
|
||||
+ "Cras a orci turpis. Donec suscipit vulputate cursus. Mauris nunc tellus, fermentum "
|
||||
+ "eu auctor ut, mollis at diam. Quisque porttitor ultrices metus, vitae tincidunt massa "
|
||||
+ "sollicitudin a. Vivamus porttitor libero eget purus hendrerit cursus. Integer aliquam "
|
||||
+ "consequat mauris quis luctus. Cras enim nibh, dignissim eu faucibus ac, mollis nec neque. "
|
||||
+ "Aliquam purus mauris, consectetur nec convallis lacinia, porta sed ante. Suspendisse "
|
||||
+ "et cursus magna. Donec orci enim, molestie a lobortis eu, imperdiet vitae neque.";
|
||||
|
||||
private static TestFeature _feature;
|
||||
|
||||
private static Server _server;
|
||||
private static TestHandler _handler;
|
||||
private static HttpClient _client;
|
||||
private static String _requestUrl;
|
||||
|
||||
@BeforeClass
|
||||
public static void init() throws Exception
|
||||
{
|
||||
File docRoot = new File("target/test-output/docroot/");
|
||||
if (!docRoot.exists())
|
||||
assertTrue(docRoot.mkdirs());
|
||||
docRoot.deleteOnExit();
|
||||
|
||||
_server = new Server();
|
||||
Connector connector = new SelectChannelConnector();
|
||||
_server.addConnector(connector);
|
||||
|
||||
_handler = new TestHandler();
|
||||
_server.setHandler(_handler);
|
||||
|
||||
_server.start();
|
||||
|
||||
_client = new HttpClient();
|
||||
_client.setConnectorType(HttpClient.CONNECTOR_SELECT_CHANNEL);
|
||||
_client.setTimeout(TIMEOUT);
|
||||
_client.setMaxRetries(0);
|
||||
_client.start();
|
||||
|
||||
_requestUrl = "http://localhost:" + connector.getLocalPort() + "/";
|
||||
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void destroy() throws Exception
|
||||
{
|
||||
_client.stop();
|
||||
|
||||
_server.stop();
|
||||
_server.join();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess() throws Exception
|
||||
{
|
||||
// Handler to send CONTINUE 100
|
||||
_feature = TestFeature.CONTINUE;
|
||||
|
||||
ContentExchange exchange = sendExchange();
|
||||
|
||||
int state = exchange.waitForDone();
|
||||
assertEquals(HttpExchange.STATUS_COMPLETED, state);
|
||||
|
||||
int responseStatus = exchange.getResponseStatus();
|
||||
assertEquals(HttpStatus.OK_200,responseStatus);
|
||||
|
||||
String content = exchange.getResponseContent();
|
||||
assertEquals(Http100ContinueTest.CONTENT,content);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMissingContinue() throws Exception
|
||||
{
|
||||
// Handler does not send CONTINUE 100
|
||||
_feature = TestFeature.NORMAL;
|
||||
|
||||
ContentExchange exchange = sendExchange();
|
||||
|
||||
int state = exchange.waitForDone();
|
||||
assertEquals(HttpExchange.STATUS_COMPLETED, state);
|
||||
|
||||
int responseStatus = exchange.getResponseStatus();
|
||||
assertEquals(HttpStatus.OK_200,responseStatus);
|
||||
|
||||
String content = exchange.getResponseContent();
|
||||
assertEquals(Http100ContinueTest.CONTENT,content);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testError() throws Exception
|
||||
{
|
||||
// Handler sends NOT FOUND 404 response
|
||||
_feature = TestFeature.NOTFOUND;
|
||||
|
||||
ContentExchange exchange = sendExchange();
|
||||
|
||||
int state = exchange.waitForDone();
|
||||
assertEquals(HttpExchange.STATUS_COMPLETED, state);
|
||||
|
||||
int responseStatus = exchange.getResponseStatus();
|
||||
assertEquals(HttpStatus.NOT_FOUND_404,responseStatus);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTimeout() throws Exception
|
||||
{
|
||||
// Handler delays response till client times out
|
||||
_feature = TestFeature.TIMEOUT;
|
||||
|
||||
final CountDownLatch expires = new CountDownLatch(1);
|
||||
ContentExchange exchange = new ContentExchange()
|
||||
{
|
||||
@Override
|
||||
protected void onExpire()
|
||||
{
|
||||
expires.countDown();
|
||||
}
|
||||
};
|
||||
|
||||
configureExchange(exchange);
|
||||
_client.send(exchange);
|
||||
|
||||
assertTrue(expires.await(TIMEOUT*10,TimeUnit.MILLISECONDS));
|
||||
}
|
||||
|
||||
public ContentExchange sendExchange() throws Exception
|
||||
{
|
||||
ContentExchange exchange = new ContentExchange();
|
||||
|
||||
configureExchange(exchange);
|
||||
_client.send(exchange);
|
||||
|
||||
return exchange;
|
||||
}
|
||||
|
||||
public void configureExchange(ContentExchange exchange)
|
||||
{
|
||||
exchange.setURL(_requestUrl);
|
||||
exchange.setMethod(HttpMethod.GET);
|
||||
exchange.addRequestHeader("User-Agent","Jetty-Client/7.0");
|
||||
exchange.addRequestHeader("Expect","100-continue"); //server to send CONTINUE 100
|
||||
}
|
||||
|
||||
private static class TestHandler extends AbstractHandler
|
||||
{
|
||||
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
||||
{
|
||||
if (baseRequest.isHandled())
|
||||
return;
|
||||
|
||||
baseRequest.setHandled(true);
|
||||
|
||||
switch (_feature)
|
||||
{
|
||||
case CONTINUE:
|
||||
// force 100 Continue response to be sent
|
||||
request.getInputStream();
|
||||
// next send data
|
||||
|
||||
case NORMAL:
|
||||
response.setContentType("text/plain");
|
||||
response.setStatus(HttpServletResponse.SC_OK);
|
||||
response.getWriter().print(CONTENT);
|
||||
break;
|
||||
|
||||
case NOTFOUND:
|
||||
response.setStatus(HttpServletResponse.SC_NOT_FOUND);
|
||||
break;
|
||||
|
||||
case TIMEOUT:
|
||||
try
|
||||
{
|
||||
Thread.sleep(TIMEOUT*4);
|
||||
}
|
||||
catch (InterruptedException ex)
|
||||
{
|
||||
Log.ignore(ex);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum TestFeature {
|
||||
CONTINUE,
|
||||
NORMAL,
|
||||
NOTFOUND,
|
||||
TIMEOUT
|
||||
}
|
||||
}
|
|
@ -1,47 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2012 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.client;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.jetty.http.HttpFields;
|
||||
import org.junit.Assert;
|
||||
|
||||
public final class HttpAsserts
|
||||
{
|
||||
public static void assertContainsHeaderKey(String expectedKey, HttpFields headers)
|
||||
{
|
||||
if (headers.containsKey(expectedKey))
|
||||
{
|
||||
return;
|
||||
}
|
||||
List<String> names = Collections.list(headers.getFieldNames());
|
||||
StringBuilder err = new StringBuilder();
|
||||
err.append("Missing expected header key [").append(expectedKey);
|
||||
err.append("] (of ").append(names.size()).append(" header fields)");
|
||||
for (int i = 0; i < names.size(); i++)
|
||||
{
|
||||
String value = headers.getStringField(names.get(i));
|
||||
err.append("\n").append(i).append("] ").append(names.get(i));
|
||||
err.append(": ").append(value);
|
||||
}
|
||||
Assert.fail(err.toString());
|
||||
}
|
||||
}
|
|
@ -1,225 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2012 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.client;
|
||||
|
||||
import java.net.ServerSocket;
|
||||
import java.net.Socket;
|
||||
import java.util.concurrent.RejectedExecutionException;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
public class HttpDestinationQueueTest
|
||||
{
|
||||
private static HttpClient _httpClient;
|
||||
private static long _timeout = 200;
|
||||
|
||||
@BeforeClass
|
||||
public static void beforeOnce() throws Exception
|
||||
{
|
||||
_httpClient = new HttpClient();
|
||||
_httpClient.setMaxConnectionsPerAddress(1);
|
||||
_httpClient.setMaxQueueSizePerAddress(1);
|
||||
_httpClient.setTimeout(_timeout);
|
||||
_httpClient.start();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDestinationMaxQueueSize() throws Exception
|
||||
{
|
||||
ServerSocket server = new ServerSocket(0);
|
||||
|
||||
// This will keep the connection busy
|
||||
HttpExchange exchange1 = new HttpExchange();
|
||||
exchange1.setMethod("GET");
|
||||
exchange1.setURL("http://localhost:" + server.getLocalPort() + "/exchange1");
|
||||
_httpClient.send(exchange1);
|
||||
|
||||
// Read request so we are sure that this exchange is out of the queue
|
||||
Socket socket = server.accept();
|
||||
byte[] buffer = new byte[1024];
|
||||
StringBuilder request = new StringBuilder();
|
||||
while (true)
|
||||
{
|
||||
int read = socket.getInputStream().read(buffer);
|
||||
request.append(new String(buffer,0,read,"UTF-8"));
|
||||
if (request.toString().endsWith("\r\n\r\n"))
|
||||
break;
|
||||
}
|
||||
Assert.assertTrue(request.toString().contains("exchange1"));
|
||||
|
||||
// This will be queued
|
||||
HttpExchange exchange2 = new HttpExchange();
|
||||
exchange2.setMethod("GET");
|
||||
exchange2.setURL("http://localhost:" + server.getLocalPort() + "/exchange2");
|
||||
_httpClient.send(exchange2);
|
||||
|
||||
// This will be rejected, since the connection is busy and the queue is full
|
||||
HttpExchange exchange3 = new HttpExchange();
|
||||
exchange3.setMethod("GET");
|
||||
exchange3.setURL("http://localhost:" + server.getLocalPort() + "/exchange3");
|
||||
try
|
||||
{
|
||||
_httpClient.send(exchange3);
|
||||
Assert.fail();
|
||||
}
|
||||
catch (RejectedExecutionException x)
|
||||
{
|
||||
// Expected
|
||||
}
|
||||
|
||||
// Send the response to avoid exceptions in the console
|
||||
socket.getOutputStream().write("HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n".getBytes("UTF-8"));
|
||||
Assert.assertEquals(HttpExchange.STATUS_COMPLETED,exchange1.waitForDone());
|
||||
|
||||
// Be sure that the second exchange can be sent
|
||||
request.setLength(0);
|
||||
while (true)
|
||||
{
|
||||
int read = socket.getInputStream().read(buffer);
|
||||
request.append(new String(buffer,0,read,"UTF-8"));
|
||||
if (request.toString().endsWith("\r\n\r\n"))
|
||||
break;
|
||||
}
|
||||
Assert.assertTrue(request.toString().contains("exchange2"));
|
||||
|
||||
socket.getOutputStream().write("HTTP/1.1 200 OK\r\nConnection: close\r\n\r\n".getBytes("UTF-8"));
|
||||
socket.close();
|
||||
Assert.assertEquals(HttpExchange.STATUS_COMPLETED,exchange2.waitForDone());
|
||||
|
||||
server.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDefaultTimeoutIncludesQueuingExchangeExpiresInQueue() throws Exception
|
||||
{
|
||||
|
||||
ServerSocket server = new ServerSocket(0);
|
||||
|
||||
// This will keep the connection busy
|
||||
HttpExchange exchange1 = new HttpExchange();
|
||||
exchange1.setTimeout(_timeout * 3); // Be sure it does not expire
|
||||
exchange1.setMethod("GET");
|
||||
exchange1.setURL("http://localhost:" + server.getLocalPort() + "/exchange1");
|
||||
_httpClient.send(exchange1);
|
||||
|
||||
// Read request so we are sure that this exchange is out of the queue
|
||||
Socket socket = server.accept();
|
||||
byte[] buffer = new byte[1024];
|
||||
StringBuilder request = new StringBuilder();
|
||||
while (true)
|
||||
{
|
||||
int read = socket.getInputStream().read(buffer);
|
||||
request.append(new String(buffer,0,read,"UTF-8"));
|
||||
if (request.toString().endsWith("\r\n\r\n"))
|
||||
break;
|
||||
}
|
||||
Assert.assertTrue(request.toString().contains("exchange1"));
|
||||
|
||||
// This will be queued
|
||||
HttpExchange exchange2 = new HttpExchange();
|
||||
exchange2.setMethod("GET");
|
||||
exchange2.setURL("http://localhost:" + server.getLocalPort() + "/exchange2");
|
||||
_httpClient.send(exchange2);
|
||||
|
||||
// Wait until the queued exchange times out in the queue
|
||||
Thread.sleep(_timeout * 2);
|
||||
|
||||
Assert.assertEquals(HttpExchange.STATUS_EXPIRED,exchange2.getStatus());
|
||||
|
||||
// Send the response to the first exchange to avoid exceptions in the console
|
||||
socket.getOutputStream().write("HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n".getBytes("UTF-8"));
|
||||
Assert.assertEquals(HttpExchange.STATUS_COMPLETED,exchange1.waitForDone());
|
||||
socket.close();
|
||||
|
||||
server.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDefaultTimeoutIncludesQueuingExchangeExpiresDuringRequest() throws Exception
|
||||
{
|
||||
ServerSocket server = new ServerSocket(0);
|
||||
|
||||
HttpExchange exchange1 = new HttpExchange();
|
||||
exchange1.setMethod("GET");
|
||||
exchange1.setURL("http://localhost:" + server.getLocalPort() + "/exchange1");
|
||||
_httpClient.send(exchange1);
|
||||
|
||||
// Read request so we are sure that this exchange is out of the queue
|
||||
Socket socket = server.accept();
|
||||
byte[] buffer = new byte[1024];
|
||||
StringBuilder request = new StringBuilder();
|
||||
while (true)
|
||||
{
|
||||
int read = socket.getInputStream().read(buffer);
|
||||
request.append(new String(buffer,0,read,"UTF-8"));
|
||||
if (request.toString().endsWith("\r\n\r\n"))
|
||||
break;
|
||||
}
|
||||
Assert.assertTrue(request.toString().contains("exchange1"));
|
||||
|
||||
// Wait until the exchange times out during the request
|
||||
Thread.sleep(_timeout * 2);
|
||||
|
||||
Assert.assertEquals(HttpExchange.STATUS_EXPIRED,exchange1.getStatus());
|
||||
|
||||
socket.close();
|
||||
|
||||
server.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExchangeTimeoutIncludesQueuingExchangeExpiresDuringResponse() throws Exception
|
||||
{
|
||||
ServerSocket server = new ServerSocket(0);
|
||||
|
||||
long timeout = 1000;
|
||||
HttpExchange exchange1 = new HttpExchange();
|
||||
exchange1.setTimeout(timeout);
|
||||
exchange1.setMethod("GET");
|
||||
exchange1.setURL("http://localhost:" + server.getLocalPort() + "/exchange1");
|
||||
_httpClient.send(exchange1);
|
||||
|
||||
// Read request so we are sure that this exchange is out of the queue
|
||||
Socket socket = server.accept();
|
||||
byte[] buffer = new byte[1024];
|
||||
StringBuilder request = new StringBuilder();
|
||||
while (true)
|
||||
{
|
||||
int read = socket.getInputStream().read(buffer);
|
||||
request.append(new String(buffer,0,read,"UTF-8"));
|
||||
if (request.toString().endsWith("\r\n\r\n"))
|
||||
break;
|
||||
}
|
||||
Assert.assertTrue(request.toString().contains("exchange1"));
|
||||
|
||||
// Write part of the response
|
||||
socket.getOutputStream().write("HTTP/1.1 200 OK\r\nContent-Type: application/octet-stream\r\nContent-Length: 1\r\n\r\n".getBytes("UTF-8"));
|
||||
|
||||
// Wait until the exchange times out during the response
|
||||
Thread.sleep(timeout * 2);
|
||||
|
||||
Assert.assertEquals(HttpExchange.STATUS_EXPIRED,exchange1.getStatus());
|
||||
|
||||
socket.close();
|
||||
|
||||
server.close();
|
||||
}
|
||||
}
|
|
@ -1,699 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2012 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.client;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.matchers.JUnitMatchers.containsString;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.net.URI;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import org.eclipse.jetty.client.helperClasses.HttpServerAndClientCreator;
|
||||
import org.eclipse.jetty.client.helperClasses.ServerAndClientCreator;
|
||||
import org.eclipse.jetty.client.security.ProxyAuthorization;
|
||||
import org.eclipse.jetty.http.HttpFields;
|
||||
import org.eclipse.jetty.http.HttpMethod;
|
||||
import org.eclipse.jetty.http.HttpStatus;
|
||||
|
||||
import org.eclipse.jetty.io.ByteArrayBuffer;
|
||||
import org.eclipse.jetty.io.Connection;
|
||||
import org.eclipse.jetty.io.EofException;
|
||||
import org.eclipse.jetty.io.nio.DirectNIOBuffer;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.toolchain.test.Stress;
|
||||
import org.eclipse.jetty.util.component.AbstractLifeCycle;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Functional testing for HttpExchange.
|
||||
*/
|
||||
public class HttpExchangeTest
|
||||
{
|
||||
final static boolean verbose=HttpExchange.LOG.isDebugEnabled();
|
||||
protected static int _maxConnectionsPerAddress = 2;
|
||||
protected static String _scheme = "http";
|
||||
protected static Server _server;
|
||||
protected static int _port;
|
||||
protected static HttpClient _httpClient;
|
||||
protected static AtomicInteger _count = new AtomicInteger();
|
||||
protected static ServerAndClientCreator serverAndClientCreator = new HttpServerAndClientCreator();
|
||||
|
||||
protected static URI getBaseURI()
|
||||
{
|
||||
return URI.create(_scheme + "://localhost:" + _port + "/");
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
// TODO work out why BeforeClass does not work here?
|
||||
@Before
|
||||
public void setUpOnce() throws Exception
|
||||
{
|
||||
_scheme = "http";
|
||||
_server = serverAndClientCreator.createServer();
|
||||
_httpClient = serverAndClientCreator.createClient(3000L,3500L,2000);
|
||||
_port = _server.getConnectors()[0].getLocalPort();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@After
|
||||
public void tearDownOnce() throws Exception
|
||||
{
|
||||
_httpClient.stop();
|
||||
long startTime = System.currentTimeMillis();
|
||||
while (!_httpClient.getState().equals(AbstractLifeCycle.STOPPED))
|
||||
{
|
||||
if (System.currentTimeMillis() - startTime > 1000)
|
||||
break;
|
||||
Thread.sleep(5);
|
||||
}
|
||||
_server.stop();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Test
|
||||
public void testResetNewExchange() throws Exception
|
||||
{
|
||||
HttpExchange exchange = new HttpExchange();
|
||||
exchange.reset();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Test
|
||||
public void testPerf() throws Exception
|
||||
{
|
||||
sender(1,false);
|
||||
sender(1,true);
|
||||
sender(10,false);
|
||||
sender(10,true);
|
||||
|
||||
if (Stress.isEnabled())
|
||||
{
|
||||
sender(100,false);
|
||||
sender(100,true);
|
||||
sender(10000,false);
|
||||
sender(10000,true);
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Test sending data through the exchange.
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
public void sender(final int nb, final boolean close) throws Exception
|
||||
{
|
||||
// System.err.printf("%nSENDER %d %s%n",nb,close);
|
||||
_count.set(0);
|
||||
final CountDownLatch complete = new CountDownLatch(nb);
|
||||
final AtomicInteger allcontent = new AtomicInteger(nb);
|
||||
HttpExchange[] httpExchange = new HttpExchange[nb];
|
||||
long start = System.currentTimeMillis();
|
||||
for (int i = 0; i < nb; i++)
|
||||
{
|
||||
final int n = i;
|
||||
|
||||
httpExchange[n] = new HttpExchange()
|
||||
{
|
||||
String result = "pending";
|
||||
int len = 0;
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
protected void onRequestCommitted()
|
||||
{
|
||||
if (verbose)
|
||||
System.err.println(n+" [ "+this);
|
||||
result = "committed";
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
protected void onRequestComplete() throws IOException
|
||||
{
|
||||
if (verbose)
|
||||
System.err.println(n+" [ ==");
|
||||
result = "sent";
|
||||
}
|
||||
|
||||
@Override
|
||||
/* ------------------------------------------------------------ */
|
||||
protected void onResponseStatus(ByteBuffer version, int status, ByteBuffer reason)
|
||||
{
|
||||
if (verbose)
|
||||
System.err.println(n+" ] "+version+" "+status+" "+reason);
|
||||
result = "status";
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
protected void onResponseHeader(ByteBuffer name, ByteBuffer value)
|
||||
{
|
||||
if (verbose)
|
||||
System.err.println(n+" ] "+name+": "+value);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
protected void onResponseHeaderComplete() throws IOException
|
||||
{
|
||||
if (verbose)
|
||||
System.err.println(n+" ] -");
|
||||
result = "content";
|
||||
super.onResponseHeaderComplete();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
protected void onResponseContent(ByteBuffer content)
|
||||
{
|
||||
len += content.length();
|
||||
if (verbose)
|
||||
System.err.println(n+" ] "+content.length()+" -> "+len);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
protected void onResponseComplete()
|
||||
{
|
||||
if (verbose)
|
||||
System.err.println(n+" ] == "+len+" "+complete.getCount()+"/"+nb);
|
||||
result = "complete";
|
||||
if (len == 2009)
|
||||
allcontent.decrementAndGet();
|
||||
else
|
||||
System.err.println(n+ " ONLY " + len+ "/2009");
|
||||
complete.countDown();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
protected void onConnectionFailed(Throwable ex)
|
||||
{
|
||||
if (verbose)
|
||||
System.err.println(n+" ] "+ex);
|
||||
complete.countDown();
|
||||
result = "failed";
|
||||
System.err.println(n+ " FAILED " + ex);
|
||||
super.onConnectionFailed(ex);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
protected void onException(Throwable ex)
|
||||
{
|
||||
if (verbose)
|
||||
System.err.println(n+" ] "+ex);
|
||||
complete.countDown();
|
||||
result = "excepted";
|
||||
System.err.println(n+ " EXCEPTED " + ex);
|
||||
super.onException(ex);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
protected void onExpire()
|
||||
{
|
||||
if (verbose)
|
||||
System.err.println(n+" ] expired");
|
||||
complete.countDown();
|
||||
result = "expired";
|
||||
System.err.println(n + " EXPIRED " + len);
|
||||
super.onExpire();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return n+"/"+result+"/"+len+"/"+super.toString();
|
||||
}
|
||||
};
|
||||
|
||||
httpExchange[n].setURI(getBaseURI().resolve("/" + n));
|
||||
httpExchange[n].addRequestHeader("arbitrary","value");
|
||||
if (close)
|
||||
httpExchange[n].setRequestHeader("Connection","close");
|
||||
|
||||
_httpClient.send(httpExchange[n]);
|
||||
}
|
||||
|
||||
if (!complete.await(2,TimeUnit.SECONDS))
|
||||
System.err.println(_httpClient.dump());
|
||||
|
||||
assertTrue(complete.await(20,TimeUnit.SECONDS));
|
||||
|
||||
assertEquals("nb="+nb+" close="+close,0,allcontent.get());
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Test
|
||||
public void testPostWithContentExchange() throws Exception
|
||||
{
|
||||
for (int i=0;i<20;i++)
|
||||
{
|
||||
ContentExchange httpExchange=new ContentExchange();
|
||||
httpExchange.setURI(getBaseURI());
|
||||
httpExchange.setMethod(HttpMethod.POST);
|
||||
httpExchange.setRequestContent(new ByteArrayBuffer("<hello />"));
|
||||
_httpClient.send(httpExchange);
|
||||
int status = httpExchange.waitForDone();
|
||||
//httpExchange.waitForStatus(HttpExchange.STATUS_COMPLETED);
|
||||
String result=httpExchange.getResponseContent();
|
||||
assertEquals(HttpExchange.STATUS_COMPLETED, status);
|
||||
assertEquals("i="+i,"<hello />",result);
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Test
|
||||
public void testGetWithContentExchange() throws Exception
|
||||
{
|
||||
for (int i=0;i<10;i++)
|
||||
{
|
||||
ContentExchange httpExchange=new ContentExchange();
|
||||
URI uri = getBaseURI().resolve("?i=" + i);
|
||||
httpExchange.setURI(uri);
|
||||
httpExchange.setMethod(HttpMethod.GET);
|
||||
_httpClient.send(httpExchange);
|
||||
int status = httpExchange.waitForDone();
|
||||
//httpExchange.waitForStatus(HttpExchange.STATUS_COMPLETED);
|
||||
String result=httpExchange.getResponseContent();
|
||||
assertNotNull("Should have received response content", result);
|
||||
assertEquals("i="+i,0,result.indexOf("<hello>"));
|
||||
assertEquals("i="+i,result.length()-10,result.indexOf("</hello>"));
|
||||
assertEquals(HttpExchange.STATUS_COMPLETED, status);
|
||||
Thread.sleep(5);
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Test
|
||||
public void testLocalAddressAvailabilityWithContentExchange() throws Exception
|
||||
{
|
||||
for (int i=0;i<10;i++)
|
||||
{
|
||||
ContentExchange httpExchange=new ContentExchange();
|
||||
URI uri = getBaseURI().resolve("?i=" + i);
|
||||
httpExchange.setURI(uri);
|
||||
httpExchange.setMethod(HttpMethod.GET);
|
||||
_httpClient.send(httpExchange);
|
||||
int status = httpExchange.waitForDone();
|
||||
|
||||
assertNotNull(httpExchange.getLocalAddress());
|
||||
|
||||
String result=httpExchange.getResponseContent();
|
||||
assertNotNull("Should have received response content", result);
|
||||
assertEquals("i="+i,0,result.indexOf("<hello>"));
|
||||
assertEquals("i="+i,result.length()-10,result.indexOf("</hello>"));
|
||||
assertEquals(HttpExchange.STATUS_COMPLETED, status);
|
||||
Thread.sleep(5);
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Test
|
||||
public void testShutdownWithExchange() throws Exception
|
||||
{
|
||||
final AtomicReference<Throwable> throwable=new AtomicReference<Throwable>();
|
||||
|
||||
HttpExchange httpExchange=new HttpExchange()
|
||||
{
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @see org.eclipse.jetty.client.HttpExchange#onException(java.lang.Throwable)
|
||||
*/
|
||||
@Override
|
||||
protected void onException(Throwable x)
|
||||
{
|
||||
throwable.set(x);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @see org.eclipse.jetty.client.HttpExchange#onConnectionFailed(java.lang.Throwable)
|
||||
*/
|
||||
@Override
|
||||
protected void onConnectionFailed(Throwable x)
|
||||
{
|
||||
throwable.set(x);
|
||||
}
|
||||
};
|
||||
httpExchange.setURI(getBaseURI());
|
||||
httpExchange.setMethod("SLEEP");
|
||||
_httpClient.send(httpExchange);
|
||||
new Thread()
|
||||
{
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
try {
|
||||
Thread.sleep(500);
|
||||
_httpClient.stop();
|
||||
} catch(Exception e) {e.printStackTrace();}
|
||||
}
|
||||
}.start();
|
||||
int status = httpExchange.waitForDone();
|
||||
|
||||
System.err.println(throwable.get());
|
||||
assertTrue(throwable.get().toString().indexOf("close")>=0);
|
||||
assertEquals(HttpExchange.STATUS_EXCEPTED, status);
|
||||
_httpClient.start();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Test
|
||||
public void testBigPostWithContentExchange() throws Exception
|
||||
{
|
||||
int size =32;
|
||||
ContentExchange httpExchange=new ContentExchange()
|
||||
{
|
||||
int total;
|
||||
|
||||
@Override
|
||||
protected synchronized void onResponseStatus(ByteBuffer version, int status, ByteBuffer reason) throws IOException
|
||||
{
|
||||
if (verbose)
|
||||
System.err.println("] "+version+" "+status+" "+reason);
|
||||
super.onResponseStatus(version,status,reason);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected synchronized void onResponseHeader(ByteBuffer name, ByteBuffer value) throws IOException
|
||||
{
|
||||
if (verbose)
|
||||
System.err.println("] "+name+": "+value);
|
||||
super.onResponseHeader(name,value);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected synchronized void onResponseContent(ByteBuffer content) throws IOException
|
||||
{
|
||||
if (verbose)
|
||||
{
|
||||
total+=content.length();
|
||||
System.err.println("] "+content.length()+" -> "+total);
|
||||
}
|
||||
super.onResponseContent(content);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onRequestComplete() throws IOException
|
||||
{
|
||||
if (verbose)
|
||||
System.err.println("] ==");
|
||||
super.onRequestComplete();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResponseHeaderComplete() throws IOException
|
||||
{
|
||||
if (verbose)
|
||||
System.err.println("] --");
|
||||
super.onResponseHeaderComplete();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
ByteBuffer babuf = new ByteArrayBuffer(size*36*1024);
|
||||
ByteBuffer niobuf = new DirectNIOBuffer(size*36*1024);
|
||||
|
||||
byte[] bytes="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ".getBytes();
|
||||
|
||||
for (int i=0;i<size*1024;i++)
|
||||
{
|
||||
babuf.put(bytes);
|
||||
niobuf.put(bytes);
|
||||
}
|
||||
|
||||
httpExchange.setURI(getBaseURI());
|
||||
httpExchange.setMethod(HttpMethod.POST);
|
||||
httpExchange.setRequestContentType("application/data");
|
||||
httpExchange.setRequestContent(babuf);
|
||||
_httpClient.send(httpExchange);
|
||||
|
||||
long start=System.currentTimeMillis();
|
||||
while(!httpExchange.isDone())
|
||||
{
|
||||
long now=System.currentTimeMillis();
|
||||
if ((now-start)>=10000)
|
||||
{
|
||||
System.err.println("TEST IS TAKING TOOOOO LONG!!!!!!!!!!!!!!!!!!!!");
|
||||
System.err.println("CLIENT:");
|
||||
System.err.println(_httpClient.dump());
|
||||
System.err.println("SERVER:");
|
||||
_server.dumpStdErr();
|
||||
break;
|
||||
}
|
||||
Thread.sleep(100);
|
||||
}
|
||||
int status = httpExchange.waitForDone();
|
||||
assertEquals(HttpExchange.STATUS_COMPLETED,status);
|
||||
String result=httpExchange.getResponseContent();
|
||||
assertEquals(babuf.length(),result.length());
|
||||
|
||||
httpExchange.reset();
|
||||
httpExchange.setURI(getBaseURI());
|
||||
httpExchange.setMethod(HttpMethod.POST);
|
||||
httpExchange.setRequestContentType("application/data");
|
||||
httpExchange.setRequestContent(niobuf);
|
||||
_httpClient.send(httpExchange);
|
||||
|
||||
start=System.currentTimeMillis();
|
||||
while(!httpExchange.isDone())
|
||||
{
|
||||
long now=System.currentTimeMillis();
|
||||
if ((now-start)>=10000)
|
||||
{
|
||||
System.err.println("TEST IS TAKING TOOOOO LONG!!!!!!!!!!!!!!!!!!!!");
|
||||
System.err.println("CLIENT:");
|
||||
System.err.println(_httpClient.dump());
|
||||
System.err.println("SERVER:");
|
||||
_server.dumpStdErr();
|
||||
break;
|
||||
}
|
||||
Thread.sleep(100);
|
||||
}
|
||||
status = httpExchange.waitForDone();
|
||||
assertEquals(HttpExchange.STATUS_COMPLETED, status);
|
||||
result=httpExchange.getResponseContent();
|
||||
assertEquals(niobuf.length(),result.length());
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Test
|
||||
public void testSlowPost() throws Exception
|
||||
{
|
||||
ContentExchange httpExchange=new ContentExchange();
|
||||
httpExchange.setURI(getBaseURI());
|
||||
httpExchange.setMethod(HttpMethod.POST);
|
||||
|
||||
final String data="012345678901234567890123456789012345678901234567890123456789";
|
||||
|
||||
InputStream content = new InputStream()
|
||||
{
|
||||
int _index=0;
|
||||
|
||||
@Override
|
||||
public int read() throws IOException
|
||||
{
|
||||
// System.err.printf("reading 1 of %d/%d%n",_index,data.length());
|
||||
if (_index>=data.length())
|
||||
return -1;
|
||||
|
||||
try
|
||||
{
|
||||
Thread.sleep(5);
|
||||
}
|
||||
catch (InterruptedException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
// System.err.printf("read 1%n");
|
||||
return data.charAt(_index++);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read(byte[] b, int off, int len) throws IOException
|
||||
{
|
||||
// System.err.printf("reading %d of %d/%d%n",len,_index,data.length());
|
||||
if (_index >= data.length())
|
||||
return -1;
|
||||
|
||||
try
|
||||
{
|
||||
Thread.sleep(25);
|
||||
}
|
||||
catch (InterruptedException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
int l = 0;
|
||||
|
||||
while (l < 5 && _index < data.length() && l < len)
|
||||
b[off + l++] = (byte)data.charAt(_index++);
|
||||
// System.err.printf("read %d%n",l);
|
||||
return l;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
httpExchange.setRequestContentSource(content);
|
||||
|
||||
_httpClient.send(httpExchange);
|
||||
|
||||
int status = httpExchange.waitForDone();
|
||||
String result = httpExchange.getResponseContent();
|
||||
assertEquals(HttpExchange.STATUS_COMPLETED,status);
|
||||
assertEquals(data,result);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Test
|
||||
public void testProxy() throws Exception
|
||||
{
|
||||
if (_scheme.equals("https"))
|
||||
return;
|
||||
try
|
||||
{
|
||||
_httpClient.setProxy(new Address("127.0.0.1",_port));
|
||||
_httpClient.setProxyAuthentication(new ProxyAuthorization("user","password"));
|
||||
|
||||
ContentExchange httpExchange=new ContentExchange();
|
||||
httpExchange.setAddress(new Address("jetty.eclipse.org",8080));
|
||||
httpExchange.setMethod(HttpMethod.GET);
|
||||
httpExchange.setRequestURI("/jetty-6");
|
||||
_httpClient.send(httpExchange);
|
||||
int status = httpExchange.waitForDone();
|
||||
//httpExchange.waitForStatus(HttpExchange.STATUS_COMPLETED);
|
||||
String result=httpExchange.getResponseContent();
|
||||
assertNotNull("Should have received response content", result);
|
||||
result=result.trim();
|
||||
assertEquals(HttpExchange.STATUS_COMPLETED, status);
|
||||
assertTrue(result.startsWith("Proxy request: http://jetty.eclipse.org:8080/jetty-6"));
|
||||
assertTrue(result.endsWith("Basic dXNlcjpwYXNzd29yZA=="));
|
||||
}
|
||||
finally
|
||||
{
|
||||
_httpClient.setProxy(null);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Test
|
||||
public void testReserveConnections () throws Exception
|
||||
{
|
||||
_httpClient = serverAndClientCreator.createClient(3000L,3500L,2000);
|
||||
final HttpDestination destination = _httpClient.getDestination(new Address("localhost",_port),_scheme.equalsIgnoreCase("https"));
|
||||
final org.eclipse.jetty.client.AbstractHttpConnection[] connections = new org.eclipse.jetty.client.AbstractHttpConnection[_maxConnectionsPerAddress];
|
||||
for (int i = 0; i < _maxConnectionsPerAddress; i++)
|
||||
{
|
||||
connections[i] = destination.reserveConnection(200);
|
||||
assertNotNull(connections[i]);
|
||||
HttpExchange ex = new ContentExchange();
|
||||
ex.setURI(getBaseURI().resolve("?i=" + i));
|
||||
ex.setMethod(HttpMethod.GET);
|
||||
connections[i].send(ex);
|
||||
}
|
||||
|
||||
// try to get a connection, and only wait 500ms, as we have
|
||||
// already reserved the max, should return null
|
||||
Connection c = destination.reserveConnection(500);
|
||||
assertNull(c);
|
||||
|
||||
// unreserve first connection
|
||||
destination.returnConnection(connections[0],false);
|
||||
|
||||
// reserving one should now work
|
||||
c = destination.reserveConnection(500);
|
||||
assertNotNull(c);
|
||||
|
||||
// release connections
|
||||
for (AbstractHttpConnection httpConnection : connections){
|
||||
destination.returnConnection(httpConnection,false);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOptionsWithExchange() throws Exception
|
||||
{
|
||||
ContentExchange httpExchange = new ContentExchange(true);
|
||||
httpExchange.setURL(getBaseURI().toASCIIString());
|
||||
httpExchange.setRequestURI("*");
|
||||
httpExchange.setMethod(HttpMethod.OPTIONS);
|
||||
// httpExchange.setRequestHeader("Connection","close");
|
||||
_httpClient.send(httpExchange);
|
||||
|
||||
int state = httpExchange.waitForDone();
|
||||
assertEquals(HttpExchange.STATUS_COMPLETED, state);
|
||||
assertEquals(HttpStatus.OK_200,httpExchange.getResponseStatus());
|
||||
|
||||
HttpFields headers = httpExchange.getResponseFields();
|
||||
HttpAsserts.assertContainsHeaderKey("Content-Length", headers);
|
||||
assertEquals("Content-Length header value", 0, headers.getLongField("Content-Length"));
|
||||
|
||||
HttpAsserts.assertContainsHeaderKey("Allow",headers);
|
||||
String allow = headers.getStringField("Allow");
|
||||
String expectedMethods[] =
|
||||
{ "GET", "HEAD", "POST", "PUT", "DELETE", "MOVE", "OPTIONS", "TRACE" };
|
||||
for (String expectedMethod : expectedMethods)
|
||||
{
|
||||
assertThat(allow,containsString(expectedMethod));
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public static void copyStream(InputStream in, OutputStream out)
|
||||
{
|
||||
try
|
||||
{
|
||||
byte[] buffer = new byte[1024];
|
||||
int len;
|
||||
while ((len = in.read(buffer)) >= 0)
|
||||
{
|
||||
out.write(buffer,0,len);
|
||||
}
|
||||
}
|
||||
catch (EofException e)
|
||||
{
|
||||
System.err.println("HttpExchangeTest#copyStream: " + e);
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,237 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2012 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.client;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.eclipse.jetty.client.security.Realm;
|
||||
import org.eclipse.jetty.client.security.SimpleRealmResolver;
|
||||
import org.eclipse.jetty.http.HttpMethod;
|
||||
import org.eclipse.jetty.http.HttpStatus;
|
||||
import org.eclipse.jetty.server.Request;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.server.handler.AbstractHandler;
|
||||
import org.eclipse.jetty.server.nio.SelectChannelConnector;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public class HttpGetRedirectTest
|
||||
{
|
||||
private static String _content =
|
||||
"Lorem ipsum dolor sit amet, consectetur adipiscing elit. In quis felis nunc. "+
|
||||
"Quisque suscipit mauris et ante auctor ornare rhoncus lacus aliquet. Pellentesque "+
|
||||
"habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. "+
|
||||
"Vestibulum sit amet felis augue, vel convallis dolor. Cras accumsan vehicula diam "+
|
||||
"at faucibus. Etiam in urna turpis, sed congue mi. Morbi et lorem eros. Donec vulputate "+
|
||||
"velit in risus suscipit lobortis. Aliquam id urna orci, nec sollicitudin ipsum. "+
|
||||
"Cras a orci turpis. Donec suscipit vulputate cursus. Mauris nunc tellus, fermentum "+
|
||||
"eu auctor ut, mollis at diam. Quisque porttitor ultrices metus, vitae tincidunt massa "+
|
||||
"sollicitudin a. Vivamus porttitor libero eget purus hendrerit cursus. Integer aliquam "+
|
||||
"consequat mauris quis luctus. Cras enim nibh, dignissim eu faucibus ac, mollis nec neque. "+
|
||||
"Aliquam purus mauris, consectetur nec convallis lacinia, porta sed ante. Suspendisse "+
|
||||
"et cursus magna. Donec orci enim, molestie a lobortis eu, imperdiet vitae neque.";
|
||||
|
||||
private File _docRoot;
|
||||
private Server _server;
|
||||
private HttpClient _client;
|
||||
private Realm _realm;
|
||||
private String _protocol;
|
||||
private String _requestUrl;
|
||||
private String _requestUrl2;
|
||||
private RedirectHandler _handler;
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Before
|
||||
public void setUp()
|
||||
throws Exception
|
||||
{
|
||||
_docRoot = new File("target/test-output/docroot/");
|
||||
_docRoot.mkdirs();
|
||||
_docRoot.deleteOnExit();
|
||||
|
||||
_server = new Server();
|
||||
configureServer(_server);
|
||||
org.eclipse.jetty.server.bio.SocketConnector connector = new org.eclipse.jetty.server.bio.SocketConnector();
|
||||
_server.addConnector(connector);
|
||||
_server.start();
|
||||
|
||||
int port = _server.getConnectors()[0].getLocalPort();
|
||||
_requestUrl = _protocol+"://localhost:"+port+ "/content.txt";
|
||||
|
||||
_handler._toURL=_protocol+"://localhost:"+connector.getLocalPort()+ "/moved.txt";
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@After
|
||||
public void tearDown()
|
||||
throws Exception
|
||||
{
|
||||
if (_server != null)
|
||||
{
|
||||
_server.stop();
|
||||
_server = null;
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Test
|
||||
public void testGet() throws Exception
|
||||
{
|
||||
startClient(_realm);
|
||||
|
||||
ContentExchange getExchange = new ContentExchange();
|
||||
getExchange.setURL(_requestUrl);
|
||||
getExchange.setMethod(HttpMethod.GET);
|
||||
|
||||
_client.send(getExchange);
|
||||
int state = getExchange.waitForDone();
|
||||
|
||||
String content = "";
|
||||
int responseStatus = getExchange.getResponseStatus();
|
||||
if (responseStatus == HttpStatus.OK_200)
|
||||
{
|
||||
content = getExchange.getResponseContent();
|
||||
}
|
||||
|
||||
assertEquals(HttpStatus.OK_200,responseStatus);
|
||||
assertEquals(_content,content);
|
||||
|
||||
stopClient();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
protected void configureServer(Server server)
|
||||
throws Exception
|
||||
{
|
||||
setProtocol("http");
|
||||
|
||||
SelectChannelConnector connector = new SelectChannelConnector();
|
||||
server.addConnector(connector);
|
||||
|
||||
_handler = new RedirectHandler(HttpStatus.MOVED_PERMANENTLY_301, "/content.txt", "WAIT FOR IT", 2);
|
||||
server.setHandler( _handler );
|
||||
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
protected void startClient(Realm realm)
|
||||
throws Exception
|
||||
{
|
||||
_client = new HttpClient();
|
||||
_client.setConnectorType(HttpClient.CONNECTOR_SELECT_CHANNEL);
|
||||
_client.registerListener("org.eclipse.jetty.client.RedirectListener");
|
||||
if (realm != null)
|
||||
_client.setRealmResolver(new SimpleRealmResolver(realm));
|
||||
_client.start();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
protected void stopClient()
|
||||
throws Exception
|
||||
{
|
||||
if (_client != null)
|
||||
{
|
||||
_client.stop();
|
||||
_client = null;
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
protected String getBasePath()
|
||||
{
|
||||
return _docRoot.getAbsolutePath();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
protected void setProtocol(String protocol)
|
||||
{
|
||||
_protocol = protocol;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
protected void setRealm(Realm realm)
|
||||
{
|
||||
_realm = realm;
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
private static class RedirectHandler
|
||||
extends AbstractHandler
|
||||
{
|
||||
private final String _fromURI;
|
||||
private final int _code;
|
||||
private final int _maxRedirects;
|
||||
private int _redirectCount = 0;
|
||||
private String _toURL;
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public RedirectHandler( final int code, final String fromURI, final String toURL, final int maxRedirects )
|
||||
{
|
||||
this._code = code;
|
||||
this._fromURI = fromURI;
|
||||
this._toURL = toURL;
|
||||
this._maxRedirects = maxRedirects;
|
||||
|
||||
if (_fromURI==null || _toURL==null)
|
||||
throw new IllegalArgumentException();
|
||||
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response)
|
||||
throws IOException, ServletException
|
||||
{
|
||||
if ( baseRequest.isHandled() )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (request.getRequestURI().equals(_fromURI))
|
||||
{
|
||||
_redirectCount++;
|
||||
|
||||
String location = ( _redirectCount <= _maxRedirects )?_fromURI:_toURL;
|
||||
|
||||
response.setStatus( _code );
|
||||
response.setHeader( "Location", location );
|
||||
|
||||
( (Request) request ).setHandled( true );
|
||||
}
|
||||
else
|
||||
{
|
||||
PrintWriter out = response.getWriter();
|
||||
out.write(_content);
|
||||
|
||||
baseRequest.setHandled( true );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,193 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2012 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.client;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.eclipse.jetty.http.HttpMethod;
|
||||
import org.eclipse.jetty.http.HttpStatus;
|
||||
import org.eclipse.jetty.server.Connector;
|
||||
import org.eclipse.jetty.server.Request;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.server.handler.AbstractHandler;
|
||||
import org.eclipse.jetty.server.nio.SelectChannelConnector;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
public class HttpHeadersTest
|
||||
{
|
||||
private static final Logger LOG = Log.getLogger(HttpHeadersTest.class);
|
||||
|
||||
private static final String CONTENT = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. In quis felis nunc. "
|
||||
+ "Quisque suscipit mauris et ante auctor ornare rhoncus lacus aliquet. Pellentesque "
|
||||
+ "habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. "
|
||||
+ "Vestibulum sit amet felis augue, vel convallis dolor. Cras accumsan vehicula diam "
|
||||
+ "at faucibus. Etiam in urna turpis, sed congue mi. Morbi et lorem eros. Donec vulputate "
|
||||
+ "velit in risus suscipit lobortis. Aliquam id urna orci, nec sollicitudin ipsum. "
|
||||
+ "Cras a orci turpis. Donec suscipit vulputate cursus. Mauris nunc tellus, fermentum "
|
||||
+ "eu auctor ut, mollis at diam. Quisque porttitor ultrices metus, vitae tincidunt massa "
|
||||
+ "sollicitudin a. Vivamus porttitor libero eget purus hendrerit cursus. Integer aliquam "
|
||||
+ "consequat mauris quis luctus. Cras enim nibh, dignissim eu faucibus ac, mollis nec neque. "
|
||||
+ "Aliquam purus mauris, consectetur nec convallis lacinia, porta sed ante. Suspendisse "
|
||||
+ "et cursus magna. Donec orci enim, molestie a lobortis eu, imperdiet vitae neque.";
|
||||
|
||||
private Server _server;
|
||||
private TestHeaderHandler _handler;
|
||||
private int _port;
|
||||
|
||||
@Before
|
||||
public void init() throws Exception
|
||||
{
|
||||
File docRoot = new File("target/test-output/docroot/");
|
||||
if (!docRoot.exists())
|
||||
assertTrue(docRoot.mkdirs());
|
||||
docRoot.deleteOnExit();
|
||||
|
||||
_server = new Server();
|
||||
Connector connector = new SelectChannelConnector();
|
||||
_server.addConnector(connector);
|
||||
|
||||
_handler = new TestHeaderHandler();
|
||||
_server.setHandler(_handler);
|
||||
|
||||
_server.start();
|
||||
|
||||
_port = connector.getLocalPort();
|
||||
}
|
||||
|
||||
@After
|
||||
public void destroy() throws Exception
|
||||
{
|
||||
_server.stop();
|
||||
_server.join();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHttpHeaders() throws Exception
|
||||
{
|
||||
HttpClient httpClient = new HttpClient();
|
||||
httpClient.setConnectorType(HttpClient.CONNECTOR_SELECT_CHANNEL);
|
||||
httpClient.start();
|
||||
try
|
||||
{
|
||||
String requestUrl = "http://localhost:" + _port + "/header";
|
||||
|
||||
ContentExchange exchange = new ContentExchange();
|
||||
exchange.setURL(requestUrl);
|
||||
exchange.setMethod(HttpMethod.GET);
|
||||
exchange.addRequestHeader("User-Agent","Jetty-Client/7.0");
|
||||
|
||||
httpClient.send(exchange);
|
||||
|
||||
int state = exchange.waitForDone();
|
||||
assertEquals(HttpExchange.STATUS_COMPLETED, state);
|
||||
int responseStatus = exchange.getResponseStatus();
|
||||
assertEquals(HttpStatus.OK_200,responseStatus);
|
||||
|
||||
String content = exchange.getResponseContent();
|
||||
|
||||
assertEquals(HttpHeadersTest.CONTENT,content);
|
||||
assertEquals("Jetty-Client/7.0",_handler.headers.get("User-Agent"));
|
||||
}
|
||||
finally
|
||||
{
|
||||
httpClient.stop();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHttpHeadersSize() throws Exception
|
||||
{
|
||||
HttpClient httpClient = new HttpClient();
|
||||
httpClient.setConnectorType(HttpClient.CONNECTOR_SELECT_CHANNEL);
|
||||
httpClient.start();
|
||||
try
|
||||
{
|
||||
String requestUrl = "http://localhost:" + _port + "/header";
|
||||
|
||||
ContentExchange exchange = new ContentExchange()
|
||||
{
|
||||
@Override
|
||||
protected void onException(Throwable x)
|
||||
{
|
||||
// suppress exception
|
||||
LOG.ignore(x);
|
||||
}
|
||||
};
|
||||
exchange.setURL(requestUrl);
|
||||
exchange.setMethod(HttpMethod.GET);
|
||||
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
for (int j = 0; j < 1024; j++)
|
||||
{
|
||||
exchange.addRequestHeader("header" + i + "-" + j,"v");
|
||||
}
|
||||
}
|
||||
|
||||
httpClient.send(exchange);
|
||||
|
||||
int state = exchange.waitForDone();
|
||||
assertEquals(HttpExchange.STATUS_EXCEPTED, state);
|
||||
}
|
||||
finally
|
||||
{
|
||||
httpClient.stop();
|
||||
}
|
||||
}
|
||||
|
||||
private static class TestHeaderHandler extends AbstractHandler
|
||||
{
|
||||
protected Map<String, String> headers;
|
||||
|
||||
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
||||
{
|
||||
if (baseRequest.isHandled())
|
||||
return;
|
||||
|
||||
headers = new HashMap<String, String>();
|
||||
for (Enumeration e = request.getHeaderNames(); e.hasMoreElements();)
|
||||
{
|
||||
String name = (String)e.nextElement();
|
||||
headers.put(name,request.getHeader(name));
|
||||
}
|
||||
|
||||
response.setContentType("text/plain");
|
||||
response.setStatus(HttpServletResponse.SC_OK);
|
||||
response.getWriter().print(CONTENT);
|
||||
|
||||
baseRequest.setHandled(true);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -1,123 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2012 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.client;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.Socket;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.eclipse.jetty.client.security.Authentication;
|
||||
import org.eclipse.jetty.client.security.BasicAuthentication;
|
||||
import org.eclipse.jetty.client.security.Realm;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.server.handler.ConnectHandler;
|
||||
import org.eclipse.jetty.server.nio.SelectChannelConnector;
|
||||
import org.junit.After;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Assume;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
public class HttpsProxyAuthenticationTest
|
||||
{
|
||||
private Server _proxy = new Server();
|
||||
private HttpClient _client = new HttpClient();
|
||||
private boolean authHandlerSend;
|
||||
|
||||
@Before
|
||||
public void init() throws Exception
|
||||
{
|
||||
SelectChannelConnector connector = new SelectChannelConnector();
|
||||
_proxy.addConnector(connector);
|
||||
_proxy.setHandler(new ConnectHandler()
|
||||
{
|
||||
@Override
|
||||
protected boolean handleAuthentication(HttpServletRequest request, HttpServletResponse response, String address) throws ServletException, IOException
|
||||
{
|
||||
String authHeader = request.getHeader("Authorization");
|
||||
if (authHeader != null && authHeader.length() > 0)
|
||||
authHandlerSend = true;
|
||||
return super.handleAuthentication(request,response,address);
|
||||
}
|
||||
});
|
||||
_proxy.start();
|
||||
int proxyPort = connector.getLocalPort();
|
||||
|
||||
Authentication authentication = new BasicAuthentication(new Realm()
|
||||
{
|
||||
public String getId()
|
||||
{
|
||||
return "MyRealm";
|
||||
}
|
||||
|
||||
public String getPrincipal()
|
||||
{
|
||||
return "jetty";
|
||||
}
|
||||
|
||||
public String getCredentials()
|
||||
{
|
||||
return "jetty";
|
||||
}
|
||||
});
|
||||
|
||||
_client.setProxy(new Address("localhost", proxyPort));
|
||||
_client.setProxyAuthentication(authentication);
|
||||
_client.start();
|
||||
}
|
||||
|
||||
@After
|
||||
public void destroy() throws Exception
|
||||
{
|
||||
_client.stop();
|
||||
_proxy.stop();
|
||||
_proxy.join();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void httpsViaProxyThatReturns504ErrorTest() throws Exception
|
||||
{
|
||||
// Assume that we can connect to google
|
||||
String host = "google.com";
|
||||
int port = 443;
|
||||
Socket socket = new Socket();
|
||||
try
|
||||
{
|
||||
socket.connect(new InetSocketAddress(host, port), 1000);
|
||||
}
|
||||
catch (IOException x)
|
||||
{
|
||||
Assume.assumeNoException(x);
|
||||
}
|
||||
finally
|
||||
{
|
||||
socket.close();
|
||||
}
|
||||
|
||||
HttpExchange exchange = new ContentExchange();
|
||||
exchange.setURL("https://" + host + ":" + port);
|
||||
exchange.addRequestHeader("behaviour", "google");
|
||||
_client.send(exchange);
|
||||
Assert.assertEquals(HttpExchange.STATUS_COMPLETED, exchange.waitForDone());
|
||||
Assert.assertTrue("Authorization header not set!", authHandlerSend);
|
||||
}
|
||||
}
|
|
@ -1,141 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2012 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.client;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.ProtocolException;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.eclipse.jetty.http.HttpStatus;
|
||||
import org.eclipse.jetty.server.AbstractHttpConnection;
|
||||
import org.eclipse.jetty.server.Request;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.server.handler.ConnectHandler;
|
||||
import org.eclipse.jetty.server.nio.SelectChannelConnector;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* This UnitTest class executes two tests. Both will send a http request to https://google.com through a misbehaving proxy server.
|
||||
* <p/>
|
||||
* The first test runs against a proxy which simply closes the connection (as nginx does) for a connect request. The second proxy server always responds with a
|
||||
* 500 error.
|
||||
* <p/>
|
||||
* The expected result for both tests is an exception and the HttpExchange should have status HttpExchange.STATUS_EXCEPTED.
|
||||
*/
|
||||
public class HttpsViaBrokenHttpProxyTest
|
||||
{
|
||||
private Server _proxy = new Server();
|
||||
private HttpClient _client = new HttpClient();
|
||||
|
||||
@Before
|
||||
public void init() throws Exception
|
||||
{
|
||||
// setup proxies with different behaviour
|
||||
_proxy.addConnector(new SelectChannelConnector());
|
||||
_proxy.setHandler(new BadBehavingConnectHandler());
|
||||
_proxy.start();
|
||||
int proxyClosingConnectionPort = _proxy.getConnectors()[0].getLocalPort();
|
||||
|
||||
_client.setProxy(new Address("localhost", proxyClosingConnectionPort));
|
||||
_client.start();
|
||||
}
|
||||
|
||||
@After
|
||||
public void destroy() throws Exception
|
||||
{
|
||||
_client.stop();
|
||||
_proxy.stop();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void httpsViaProxyThatClosesConnectionOnConnectRequestTest() throws Exception
|
||||
{
|
||||
sendRequestThroughProxy(new ContentExchange()
|
||||
{
|
||||
|
||||
@Override
|
||||
protected void onException(Throwable x)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
}, "close", 9);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void httpsViaProxyThatReturns500ErrorTest() throws Exception
|
||||
{
|
||||
HttpExchange exchange = new ContentExchange()
|
||||
{
|
||||
@Override
|
||||
protected void onException(Throwable x)
|
||||
{
|
||||
// Suppress logging for expected exception
|
||||
if (!(x instanceof ProtocolException))
|
||||
super.onException(x);
|
||||
}
|
||||
};
|
||||
sendRequestThroughProxy(exchange, "error500", 9);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void httpsViaProxyThatReturns504ErrorTest() throws Exception
|
||||
{
|
||||
sendRequestThroughProxy(new ContentExchange(), "error504", 8);
|
||||
}
|
||||
|
||||
private void sendRequestThroughProxy(HttpExchange exchange, String desiredBehaviour, int exptectedStatus) throws Exception
|
||||
{
|
||||
String url = "https://" + desiredBehaviour + ".com/";
|
||||
exchange.setURL(url);
|
||||
exchange.addRequestHeader("behaviour", desiredBehaviour);
|
||||
_client.send(exchange);
|
||||
assertEquals(HttpExchange.toState(exptectedStatus) + " status awaited", exptectedStatus, exchange.waitForDone());
|
||||
}
|
||||
|
||||
private class BadBehavingConnectHandler extends ConnectHandler
|
||||
{
|
||||
@Override
|
||||
protected void handleConnect(Request baseRequest, HttpServletRequest request, HttpServletResponse response, String serverAddress)
|
||||
throws ServletException, IOException
|
||||
{
|
||||
if (serverAddress.contains("close"))
|
||||
{
|
||||
AbstractHttpConnection.getCurrentConnection().getEndPoint().close();
|
||||
}
|
||||
else if (serverAddress.contains("error500"))
|
||||
{
|
||||
response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR_500);
|
||||
}
|
||||
else if (serverAddress.contains("error504"))
|
||||
{
|
||||
response.setStatus(HttpStatus.GATEWAY_TIMEOUT_504);
|
||||
}
|
||||
baseRequest.setHandled(true);
|
||||
}
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue