diff --git a/BUILDING.txt b/BUILDING.txt deleted file mode 100644 index ff168133e48..00000000000 --- a/BUILDING.txt +++ /dev/null @@ -1,9 +0,0 @@ -BUILDING JETTY --------------- - -Jetty is built with maven 3.x+ - - $ cd /my/work/directory/jetty-7 - $ mvn clean install - - diff --git a/LICENSE-APACHE-2.0.txt b/LICENSE-APACHE-2.0.txt deleted file mode 100644 index d6456956733..00000000000 --- a/LICENSE-APACHE-2.0.txt +++ /dev/null @@ -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. diff --git a/LICENSE-ECLIPSE-1.0.html b/LICENSE-eplv10-aslv20.html similarity index 55% rename from LICENSE-ECLIPSE-1.0.html rename to LICENSE-eplv10-aslv20.html index 9320c9f37cf..48addaaddf7 100644 --- a/LICENSE-ECLIPSE-1.0.html +++ b/LICENSE-eplv10-aslv20.html @@ -6,7 +6,7 @@ -Eclipse Public License - Version 1.0 +Eclipse Public License - Version 1.0 / Apache License - Version 2.0 - org.apache.maven.plugins - maven-jar-plugin - - - ${project.build.outputDirectory}/META-INF/MANIFEST.MF - - - - - org.codehaus.mojo - findbugs-maven-plugin - - org.eclipse.jetty.client.* - - - - org.apache.maven.plugins - maven-dependency-plugin - - - unpack - generate-test-resources - - unpack - - - - - org.eclipse.jetty.toolchain - jetty-test-policy - ${jetty-test-policy-version} - jar - true - **/*.keystore,**/*.pem - ${jetty.test.policy.loc} - - - - - - - - - - - - org.eclipse.jetty - jetty-http - ${project.version} - - - org.eclipse.jetty - jetty-server - ${project.version} - test - - - org.eclipse.jetty - jetty-security - ${project.version} - test - - - org.eclipse.jetty - jetty-servlet - ${project.version} - test - - - - org.eclipse.jetty.toolchain - jetty-test-helper - test - - - diff --git a/jetty-client-old/src/main/java/org/eclipse/jetty/client/AbstractHttpConnection.java b/jetty-client-old/src/main/java/org/eclipse/jetty/client/AbstractHttpConnection.java deleted file mode 100644 index 83960b87a39..00000000000 --- a/jetty-client-old/src/main/java/org/eclipse/jetty/client/AbstractHttpConnection.java +++ /dev/null @@ -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 = 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; - } -} diff --git a/jetty-client-old/src/main/java/org/eclipse/jetty/client/AsyncHttpConnection.java b/jetty-client-old/src/main/java/org/eclipse/jetty/client/AsyncHttpConnection.java deleted file mode 100644 index 8c95ceab571..00000000000 --- a/jetty-client-old/src/main/java/org/eclipse/jetty/client/AsyncHttpConnection.java +++ /dev/null @@ -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; - } -} diff --git a/jetty-client-old/src/main/java/org/eclipse/jetty/client/BlockingHttpConnection.java b/jetty-client-old/src/main/java/org/eclipse/jetty/client/BlockingHttpConnection.java deleted file mode 100644 index 22f61346efe..00000000000 --- a/jetty-client-old/src/main/java/org/eclipse/jetty/client/BlockingHttpConnection.java +++ /dev/null @@ -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; - } -} diff --git a/jetty-client-old/src/main/java/org/eclipse/jetty/client/CachedExchange.java b/jetty-client-old/src/main/java/org/eclipse/jetty/client/CachedExchange.java deleted file mode 100644 index fa9094bb815..00000000000 --- a/jetty-client-old/src/main/java/org/eclipse/jetty/client/CachedExchange.java +++ /dev/null @@ -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); - } -} diff --git a/jetty-client-old/src/main/java/org/eclipse/jetty/client/ContentExchange.java b/jetty-client-old/src/main/java/org/eclipse/jetty/client/ContentExchange.java deleted file mode 100644 index 532c2331745..00000000000 --- a/jetty-client-old/src/main/java/org/eclipse/jetty/client/ContentExchange.java +++ /dev/null @@ -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()); - } -} diff --git a/jetty-client-old/src/main/java/org/eclipse/jetty/client/HttpClient.java b/jetty-client-old/src/main/java/org/eclipse/jetty/client/HttpClient.java deleted file mode 100644 index 704e289c552..00000000000 --- a/jetty-client-old/src/main/java/org/eclipse/jetty/client/HttpClient.java +++ /dev/null @@ -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. - *

- * 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)}). - *

- * 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. - *

- * 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 _destinations = new ConcurrentHashMap(); - 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 _noProxy; - private int _maxRetries = 3; - private int _maxRedirects = 20; - private LinkedList _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. - *

- * 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(); - } - _registeredListeners.add(listenerClass); - } - - /* ------------------------------------------------------------ */ - public LinkedList 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 getNoProxy() - { - return _noProxy; - } - - /* ------------------------------------------------------------ */ - public void setNoProxy(Set 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 - { - } -} diff --git a/jetty-client-old/src/main/java/org/eclipse/jetty/client/HttpDestination.java b/jetty-client-old/src/main/java/org/eclipse/jetty/client/HttpDestination.java deleted file mode 100644 index 5541582aa40..00000000000 --- a/jetty-client-old/src/main/java/org/eclipse/jetty/client/HttpDestination.java +++ /dev/null @@ -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 _queue = new LinkedList(); - private final List _connections = new LinkedList(); - private final BlockingQueue _newQueue = new ArrayBlockingQueue(10, true); - private final List _idle = new ArrayList(); - 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 _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(); - _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 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(); - } - - } -} diff --git a/jetty-client-old/src/main/java/org/eclipse/jetty/client/HttpEventListener.java b/jetty-client-old/src/main/java/org/eclipse/jetty/client/HttpEventListener.java deleted file mode 100644 index 494b8a67a5b..00000000000 --- a/jetty-client-old/src/main/java/org/eclipse/jetty/client/HttpEventListener.java +++ /dev/null @@ -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(); - - -} diff --git a/jetty-client-old/src/main/java/org/eclipse/jetty/client/HttpEventListenerWrapper.java b/jetty-client-old/src/main/java/org/eclipse/jetty/client/HttpEventListenerWrapper.java deleted file mode 100644 index 521b4d0a476..00000000000 --- a/jetty-client-old/src/main/java/org/eclipse/jetty/client/HttpEventListenerWrapper.java +++ /dev/null @@ -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(); - } - - - -} diff --git a/jetty-client-old/src/main/java/org/eclipse/jetty/client/HttpExchange.java b/jetty-client-old/src/main/java/org/eclipse/jetty/client/HttpExchange.java deleted file mode 100644 index bd0d8381322..00000000000 --- a/jetty-client-old/src/main/java/org/eclipse/jetty/client/HttpExchange.java +++ /dev/null @@ -1,1171 +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.URI; -import java.nio.ByteBuffer; -import java.util.concurrent.atomic.AtomicInteger; - -import org.eclipse.jetty.client.security.SecurityListener; -import org.eclipse.jetty.http.HttpFields; -import org.eclipse.jetty.http.HttpHeader; -import org.eclipse.jetty.http.HttpMethod; -import org.eclipse.jetty.http.HttpScheme; -import org.eclipse.jetty.http.HttpURI; -import org.eclipse.jetty.http.HttpVersion; - -import org.eclipse.jetty.io.EndPoint; -import org.eclipse.jetty.util.log.Log; -import org.eclipse.jetty.util.log.Logger; -import org.eclipse.jetty.util.thread.Timeout; - -/** - *

- * An HTTP client API that encapsulates an exchange (a request and its response) with a HTTP server. - *

- * - * This object encapsulates: - *
    - *
  • The HTTP server address, see {@link #setAddress(Address)}, or {@link #setURI(URI)}, or {@link #setURL(String)}) - *
  • The HTTP request method, URI and HTTP version (see {@link #setMethod(String)}, {@link #setRequestURI(String)}, and {@link #setVersion(int)}) - *
  • The request headers (see {@link #addRequestHeader(String, String)} or {@link #setRequestHeader(String, String)}) - *
  • The request content (see {@link #setRequestContent(ByteBuffer)} or {@link #setRequestContentSource(InputStream)}) - *
  • The status of the exchange (see {@link #getStatus()}) - *
  • Callbacks to handle state changes (see the onXxx methods such as {@link #onRequestComplete()} or {@link #onResponseComplete()}) - *
  • The ability to intercept callbacks (see {@link #setEventListener(HttpEventListener)} - *
- * - *

- * The HttpExchange class is intended to be used by a developer wishing to have close asynchronous interaction with the the exchange.
- * Typically a developer will extend the HttpExchange class with a derived class that overrides some or all of the onXxx callbacks.
- * There are also some predefined HttpExchange subtypes that can be used as a basis, see {@link org.eclipse.jetty.client.ContentExchange} and - * {@link org.eclipse.jetty.client.CachedExchange}. - *

- * - *

- * Typically the HttpExchange is passed to the {@link HttpClient#send(HttpExchange)} method, which in turn selects a {@link HttpDestination} and calls its - * {@link HttpDestination#send(HttpExchange)}, which then creates or selects a {@link AbstractHttpConnection} and calls its {@link AbstractHttpConnection#send(HttpExchange)}. A - * developer may wish to directly call send on the destination or connection if they wish to bypass some handling provided (eg Cookie handling in the - * HttpDestination). - *

- * - *

- * In some circumstances, the HttpClient or HttpDestination may wish to retry a HttpExchange (eg. failed pipeline request, authentication retry or redirection). - * In such cases, the HttpClient and/or HttpDestination may insert their own HttpExchangeListener to intercept and filter the call backs intended for the - * HttpExchange. - *

- */ -public class HttpExchange -{ - static final Logger LOG = Log.getLogger(HttpExchange.class); - - public static final int STATUS_START = 0; - public static final int STATUS_WAITING_FOR_CONNECTION = 1; - public static final int STATUS_WAITING_FOR_COMMIT = 2; - public static final int STATUS_SENDING_REQUEST = 3; - public static final int STATUS_WAITING_FOR_RESPONSE = 4; - public static final int STATUS_PARSING_HEADERS = 5; - public static final int STATUS_PARSING_CONTENT = 6; - public static final int STATUS_COMPLETED = 7; - public static final int STATUS_EXPIRED = 8; - public static final int STATUS_EXCEPTED = 9; - public static final int STATUS_CANCELLING = 10; - public static final int STATUS_CANCELLED = 11; - - // HTTP protocol fields - private String _method = HttpMethod.GET.asString(); - private String _scheme = HttpScheme.HTTP.asString(); - private String _uri; - private HttpVersion _version = HttpVersion.HTTP_1_1; - private Address _address; - private final HttpFields _requestFields = new HttpFields(); - private ByteBuffer _requestContent; - private InputStream _requestContentSource; - - private AtomicInteger _status = new AtomicInteger(STATUS_START); - private boolean _retryStatus = false; - // controls if the exchange will have listeners autoconfigured by the destination - private boolean _configureListeners = true; - private HttpEventListener _listener = new Listener(); - private volatile AbstractHttpConnection _connection; - - private Address _localAddress = null; - - // a timeout for this exchange - private long _timeout = -1; - private volatile Timeout.Task _timeoutTask; - private long _lastStateChange=System.currentTimeMillis(); - private long _sent=-1; - private int _lastState=-1; - private int _lastStatePeriod=-1; - - boolean _onRequestCompleteDone; - boolean _onResponseCompleteDone; - boolean _onDone; // == onConnectionFail || onException || onExpired || onCancelled || onResponseCompleted && onRequestCompleted - - protected void expire(HttpDestination destination) - { - if (getStatus() < HttpExchange.STATUS_COMPLETED) - setStatus(HttpExchange.STATUS_EXPIRED); - destination.exchangeExpired(this); - AbstractHttpConnection connection = _connection; - if (connection != null) - connection.exchangeExpired(this); - } - - public int getStatus() - { - return _status.get(); - } - - /** - * @param status - * the status to wait for - * @throws InterruptedException - * if the waiting thread is interrupted - * @deprecated Use {@link #waitForDone()} instead - */ - @Deprecated - public void waitForStatus(int status) throws InterruptedException - { - throw new UnsupportedOperationException(); - } - - /** - * Wait until the exchange is "done". Done is defined as when a final state has been passed to the HttpExchange via the associated onXxx call. Note that an - * exchange can transit a final state when being used as part of a dialog (eg {@link SecurityListener}. Done status is thus defined as: - * - *
-     * done == onConnectionFailed || onException || onExpire || onRequestComplete && onResponseComplete
-     * 
- * - * @return the done status - * @throws InterruptedException - */ - public int waitForDone() throws InterruptedException - { - synchronized (this) - { - while (!isDone()) - this.wait(); - return _status.get(); - } - } - - public void reset() - { - // TODO - this should do a cancel and wakeup everybody that was waiting. - // might need a version number concept - synchronized (this) - { - _timeoutTask = null; - _onRequestCompleteDone = false; - _onResponseCompleteDone = false; - _onDone = false; - setStatus(STATUS_START); - } - } - - /* ------------------------------------------------------------ */ - /** - * @param newStatus - * @return True if the status was actually set. - */ - boolean setStatus(int newStatus) - { - boolean set = false; - try - { - int oldStatus = _status.get(); - boolean ignored = false; - if (oldStatus != newStatus) - { - long now = System.currentTimeMillis(); - _lastStatePeriod=(int)(now-_lastStateChange); - _lastState=oldStatus; - _lastStateChange=now; - if (newStatus==STATUS_SENDING_REQUEST) - _sent=_lastStateChange; - } - - // State machine: from which old status you can go into which new status - switch (oldStatus) - { - case STATUS_START: - switch (newStatus) - { - case STATUS_START: - case STATUS_WAITING_FOR_CONNECTION: - case STATUS_WAITING_FOR_COMMIT: - case STATUS_CANCELLING: - case STATUS_EXCEPTED: - set = _status.compareAndSet(oldStatus,newStatus); - break; - case STATUS_EXPIRED: - set = setStatusExpired(newStatus,oldStatus); - break; - } - break; - case STATUS_WAITING_FOR_CONNECTION: - switch (newStatus) - { - case STATUS_WAITING_FOR_COMMIT: - case STATUS_CANCELLING: - case STATUS_EXCEPTED: - set = _status.compareAndSet(oldStatus,newStatus); - break; - case STATUS_EXPIRED: - set = setStatusExpired(newStatus,oldStatus); - break; - } - break; - case STATUS_WAITING_FOR_COMMIT: - switch (newStatus) - { - case STATUS_SENDING_REQUEST: - case STATUS_CANCELLING: - case STATUS_EXCEPTED: - set = _status.compareAndSet(oldStatus,newStatus); - break; - case STATUS_EXPIRED: - set = setStatusExpired(newStatus,oldStatus); - break; - } - break; - case STATUS_SENDING_REQUEST: - switch (newStatus) - { - case STATUS_WAITING_FOR_RESPONSE: - if (set = _status.compareAndSet(oldStatus,newStatus)) - getEventListener().onRequestCommitted(); - break; - case STATUS_CANCELLING: - case STATUS_EXCEPTED: - set = _status.compareAndSet(oldStatus,newStatus); - break; - case STATUS_EXPIRED: - set = setStatusExpired(newStatus,oldStatus); - break; - } - break; - case STATUS_WAITING_FOR_RESPONSE: - switch (newStatus) - { - case STATUS_PARSING_HEADERS: - case STATUS_CANCELLING: - case STATUS_EXCEPTED: - set = _status.compareAndSet(oldStatus,newStatus); - break; - case STATUS_EXPIRED: - set = setStatusExpired(newStatus,oldStatus); - break; - } - break; - case STATUS_PARSING_HEADERS: - switch (newStatus) - { - case STATUS_PARSING_CONTENT: - if (set = _status.compareAndSet(oldStatus,newStatus)) - getEventListener().onResponseHeaderComplete(); - break; - case STATUS_CANCELLING: - case STATUS_EXCEPTED: - set = _status.compareAndSet(oldStatus,newStatus); - break; - case STATUS_EXPIRED: - set = setStatusExpired(newStatus,oldStatus); - break; - } - break; - case STATUS_PARSING_CONTENT: - switch (newStatus) - { - case STATUS_COMPLETED: - if (set = _status.compareAndSet(oldStatus,newStatus)) - getEventListener().onResponseComplete(); - break; - case STATUS_CANCELLING: - case STATUS_EXCEPTED: - set = _status.compareAndSet(oldStatus,newStatus); - break; - case STATUS_EXPIRED: - set = setStatusExpired(newStatus,oldStatus); - break; - } - break; - case STATUS_COMPLETED: - switch (newStatus) - { - case STATUS_START: - case STATUS_EXCEPTED: - case STATUS_WAITING_FOR_RESPONSE: - set = _status.compareAndSet(oldStatus,newStatus); - break; - case STATUS_CANCELLING: - case STATUS_EXPIRED: - // Don't change the status, it's too late - ignored = true; - break; - } - break; - case STATUS_CANCELLING: - switch (newStatus) - { - case STATUS_EXCEPTED: - case STATUS_CANCELLED: - if (set = _status.compareAndSet(oldStatus,newStatus)) - done(); - break; - default: - // Ignore other statuses, we're cancelling - ignored = true; - break; - } - break; - case STATUS_EXCEPTED: - case STATUS_EXPIRED: - case STATUS_CANCELLED: - switch (newStatus) - { - case STATUS_START: - set = _status.compareAndSet(oldStatus,newStatus); - break; - - case STATUS_COMPLETED: - ignored = true; - done(); - break; - - default: - ignored = true; - break; - } - break; - default: - // Here means I allowed to set a state that I don't recognize - throw new AssertionError(oldStatus + " => " + newStatus); - } - - if (!set && !ignored) - throw new IllegalStateException(toState(oldStatus) + " => " + toState(newStatus)); - LOG.debug("setStatus {} {}",newStatus,this); - } - catch (IOException x) - { - LOG.warn(x); - } - return set; - } - - private boolean setStatusExpired(int newStatus, int oldStatus) - { - boolean set; - if (set = _status.compareAndSet(oldStatus,newStatus)) - getEventListener().onExpire(); - return set; - } - - public boolean isDone() - { - synchronized (this) - { - return _onDone; - } - } - - /** - * @deprecated - */ - @Deprecated - public boolean isDone(int status) - { - return isDone(); - } - - public HttpEventListener getEventListener() - { - return _listener; - } - - public void setEventListener(HttpEventListener listener) - { - _listener = listener; - } - - public void setTimeout(long timeout) - { - _timeout = timeout; - } - - public long getTimeout() - { - return _timeout; - } - - /** - * @param url - * an absolute URL (for example 'http://localhost/foo/bar?a=1') - */ - public void setURL(String url) - { - setURI(URI.create(url)); - } - - /** - * @param address - * the address of the server - */ - public void setAddress(Address address) - { - _address = address; - } - - /** - * @return the address of the server - */ - public Address getAddress() - { - return _address; - } - - /** - * the local address used by the connection - * - * Note: this method will not be populated unless the exchange has been executed by the HttpClient - * - * @return the local address used for the running of the exchange if available, null otherwise. - */ - public Address getLocalAddress() - { - return _localAddress; - } - - /** - * @param scheme - * the scheme of the URL (for example 'http') - */ - public void setScheme(String scheme) - { - _scheme = scheme; - } - - - /** - * @return the scheme of the URL - */ - public String getScheme() - { - return _scheme; - } - - /** - * @param version - * the HTTP protocol version as integer, 9, 10 or 11 for 0.9, 1.0 or 1.1 - */ - public void setVersion(HttpVersion version) - { - _version = version; - } - - /** - * @return the HTTP protocol version as integer - * @see #setVersion(int) - */ - public HttpVersion getVersion() - { - return _version; - } - - /** - * @param method - * the HTTP method (for example 'GET') - */ - public void setMethod(String method) - { - _method = method; - } - - /** - * @return the HTTP method - */ - public String getMethod() - { - return _method; - } - - /** - * @return request URI - * @see #getRequestURI() - * @deprecated - */ - @Deprecated - public String getURI() - { - return getRequestURI(); - } - - /** - * @return request URI - */ - public String getRequestURI() - { - return _uri; - } - - /** - * Set the request URI - * - * @param uri - * new request URI - * @see #setRequestURI(String) - * @deprecated - */ - @Deprecated - public void setURI(String uri) - { - setRequestURI(uri); - } - - /** - * Set the request URI - * - * Per RFC 2616 sec5, Request-URI = "*" | absoluteURI | abs_path | authority
- * where:
- *
- * "*" - request applies to server itself
- * absoluteURI - required for proxy requests, e.g. http://localhost:8080/context
- * (this form is generated automatically by HttpClient)
- * abs_path - used for most methods, e.g. /context
- * authority - used for CONNECT method only, e.g. localhost:8080
- *
- * For complete definition of URI components, see RFC 2396 sec3.
- * - * @param uri - * new request URI - */ - public void setRequestURI(String uri) - { - _uri = uri; - } - - /* ------------------------------------------------------------ */ - /** - * @param uri - * an absolute URI (for example 'http://localhost/foo/bar?a=1') - */ - public void setURI(URI uri) - { - if (!uri.isAbsolute()) - throw new IllegalArgumentException("!Absolute URI: " + uri); - - if (uri.isOpaque()) - throw new IllegalArgumentException("Opaque URI: " + uri); - - if (LOG.isDebugEnabled()) - LOG.debug("URI = {}",uri.toASCIIString()); - - String scheme = uri.getScheme(); - int port = uri.getPort(); - if (port <= 0) - port = "https".equalsIgnoreCase(scheme)?443:80; - - setScheme(scheme); - setAddress(new Address(uri.getHost(),port)); - - HttpURI httpUri = new HttpURI(uri); - String completePath = httpUri.getCompletePath(); - setRequestURI(completePath == null?"/":completePath); - } - - /** - * Adds the specified request header - * - * @param name - * the header name - * @param value - * the header value - */ - public void addRequestHeader(String name, String value) - { - getRequestFields().add(name,value); - } - - /** - * Sets the specified request header - * - * @param name - * the header name - * @param value - * the header value - */ - public void setRequestHeader(String name, String value) - { - getRequestFields().put(name,value); - } - - /** - * @param value - * the content type of the request - */ - public void setRequestContentType(String value) - { - getRequestFields().put(HttpHeader.CONTENT_TYPE,value); - } - - /** - * @return the request headers - */ - public HttpFields getRequestFields() - { - return _requestFields; - } - - /** - * @param requestContent - * the request content - */ - public void setRequestContent(ByteBuffer requestContent) - { - _requestContent = requestContent; - } - - /** - * @param stream - * the request content as a stream - */ - public void setRequestContentSource(InputStream stream) - { - _requestContentSource = stream; - if (_requestContentSource != null && _requestContentSource.markSupported()) - _requestContentSource.mark(Integer.MAX_VALUE); - } - - /** - * @return the request content as a stream - */ - public InputStream getRequestContentSource() - { - return _requestContentSource; - } - - public ByteBuffer getRequestContentChunk(ByteBuffer buffer) throws IOException - { - synchronized (this) - { - if (_requestContentSource!=null) - { - if (buffer == null) - buffer = new ByteArrayBuffer(8192); // TODO configure - - int space = buffer.space(); - int length = _requestContentSource.read(buffer.array(),buffer.putIndex(),space); - if (length >= 0) - { - buffer.setPutIndex(buffer.putIndex()+length); - return buffer; - } - } - return null; - } - } - - /** - * @return the request content - */ - public ByteBuffer getRequestContent() - { - return _requestContent; - } - - /** - * @return whether a retry will be attempted or not - */ - public boolean getRetryStatus() - { - return _retryStatus; - } - - /** - * @param retryStatus - * whether a retry will be attempted or not - */ - public void setRetryStatus(boolean retryStatus) - { - _retryStatus = retryStatus; - } - - /** - * Initiates the cancelling of this exchange. The status of the exchange is set to {@link #STATUS_CANCELLING}. Cancelling the exchange is an asynchronous - * operation with respect to the request/response, and as such checking the request/response status of a cancelled exchange may return undefined results - * (for example it may have only some of the response headers being sent by the server). The cancelling of the exchange is completed when the exchange - * status (see {@link #getStatus()}) is {@link #STATUS_CANCELLED}, and this can be waited using {@link #waitForDone()}. - */ - public void cancel() - { - setStatus(STATUS_CANCELLING); - abort(); - } - - private void done() - { - synchronized (this) - { - disassociate(); - _onDone = true; - notifyAll(); - } - } - - private void abort() - { - AbstractHttpConnection httpConnection = _connection; - if (httpConnection != null) - { - try - { - // Closing the connection here will cause the connection - // to be returned in HttpConnection.handle() - httpConnection.close(); - } - catch (IOException x) - { - LOG.debug(x); - } - finally - { - disassociate(); - } - } - } - - void associate(AbstractHttpConnection connection) - { - if (connection.getEndPoint().getLocalAddr() != null) - _localAddress = new Address(connection.getEndPoint().getLocalAddr(),connection.getEndPoint().getLocalPort()); - - _connection = connection; - if (getStatus() == STATUS_CANCELLING) - abort(); - } - - boolean isAssociated() - { - return this._connection != null; - } - - AbstractHttpConnection disassociate() - { - AbstractHttpConnection result = _connection; - this._connection = null; - if (getStatus() == STATUS_CANCELLING) - setStatus(STATUS_CANCELLED); - return result; - } - - public static String toState(int s) - { - String state; - switch (s) - { - case STATUS_START: - state = "START"; - break; - case STATUS_WAITING_FOR_CONNECTION: - state = "CONNECTING"; - break; - case STATUS_WAITING_FOR_COMMIT: - state = "CONNECTED"; - break; - case STATUS_SENDING_REQUEST: - state = "SENDING"; - break; - case STATUS_WAITING_FOR_RESPONSE: - state = "WAITING"; - break; - case STATUS_PARSING_HEADERS: - state = "HEADERS"; - break; - case STATUS_PARSING_CONTENT: - state = "CONTENT"; - break; - case STATUS_COMPLETED: - state = "COMPLETED"; - break; - case STATUS_EXPIRED: - state = "EXPIRED"; - break; - case STATUS_EXCEPTED: - state = "EXCEPTED"; - break; - case STATUS_CANCELLING: - state = "CANCELLING"; - break; - case STATUS_CANCELLED: - state = "CANCELLED"; - break; - default: - state = "UNKNOWN"; - } - return state; - } - - @Override - public String toString() - { - String state=toState(getStatus()); - long now=System.currentTimeMillis(); - long forMs = now -_lastStateChange; - String s= _lastState>=0 - ?String.format("%s@%x=%s//%s%s#%s(%dms)->%s(%dms)",getClass().getSimpleName(),hashCode(),_method,_address,_uri,toState(_lastState),_lastStatePeriod,state,forMs) - :String.format("%s@%x=%s//%s%s#%s(%dms)",getClass().getSimpleName(),hashCode(),_method,_address,_uri,state,forMs); - if (getStatus()>=STATUS_SENDING_REQUEST && _sent>0) - s+="sent="+(now-_sent)+"ms"; - return s; - } - - /** - */ - protected Connection onSwitchProtocol(EndPoint endp) throws IOException - { - return null; - } - - /** - * Callback called when the request headers have been sent to the server. This implementation does nothing. - * - * @throws IOException - * allowed to be thrown by overriding code - */ - protected void onRequestCommitted() throws IOException - { - } - - /** - * Callback called when the request and its body have been sent to the server. This implementation does nothing. - * - * @throws IOException - * allowed to be thrown by overriding code - */ - protected void onRequestComplete() throws IOException - { - } - - /** - * Callback called when a response status line has been received from the server. This implementation does nothing. - * - * @param version - * the HTTP version - * @param status - * the HTTP status code - * @param reason - * the HTTP status reason string - * @throws IOException - * allowed to be thrown by overriding code - */ - protected void onResponseStatus(ByteBuffer version, int status, ByteBuffer reason) throws IOException - { - } - - /** - * Callback called for each response header received from the server. This implementation does nothing. - * - * @param name - * the header name - * @param value - * the header value - * @throws IOException - * allowed to be thrown by overriding code - */ - protected void onResponseHeader(ByteBuffer name, ByteBuffer value) throws IOException - { - } - - /** - * Callback called when the response headers have been completely received from the server. This implementation does nothing. - * - * @throws IOException - * allowed to be thrown by overriding code - */ - protected void onResponseHeaderComplete() throws IOException - { - } - - /** - * Callback called for each chunk of the response content received from the server. This implementation does nothing. - * - * @param content - * the buffer holding the content chunk - * @throws IOException - * allowed to be thrown by overriding code - */ - protected void onResponseContent(ByteBuffer content) throws IOException - { - } - - /** - * Callback called when the entire response has been received from the server This implementation does nothing. - * - * @throws IOException - * allowed to be thrown by overriding code - */ - protected void onResponseComplete() throws IOException - { - } - - /** - * Callback called when an exception was thrown during an attempt to establish the connection with the server (for example the server is not listening). - * This implementation logs a warning. - * - * @param x - * the exception thrown attempting to establish the connection with the server - */ - protected void onConnectionFailed(Throwable x) - { - LOG.warn("CONNECTION FAILED " + this,x); - } - - /** - * Callback called when any other exception occurs during the handling of this exchange. This implementation logs a warning. - * - * @param x - * the exception thrown during the handling of this exchange - */ - protected void onException(Throwable x) - { - LOG.warn("EXCEPTION " + this,x); - } - - /** - * Callback called when no response has been received within the timeout. This implementation logs a warning. - */ - protected void onExpire() - { - LOG.warn("EXPIRED " + this); - } - - /** - * Callback called when the request is retried (due to failures or authentication). Implementations must reset any consumable content that needs to be sent. - * - * @throws IOException - * allowed to be thrown by overriding code - */ - protected void onRetry() throws IOException - { - if (_requestContentSource != null) - { - if (_requestContentSource.markSupported()) - { - _requestContent = null; - _requestContentSource.reset(); - } - else - { - throw new IOException("Unsupported retry attempt"); - } - } - } - - /** - * @return true if the exchange should have listeners configured for it by the destination, false if this is being managed elsewhere - * @see #setConfigureListeners(boolean) - */ - public boolean configureListeners() - { - return _configureListeners; - } - - /** - * @param autoConfigure - * whether the listeners are configured by the destination or elsewhere - */ - public void setConfigureListeners(boolean autoConfigure) - { - this._configureListeners = autoConfigure; - } - - protected void scheduleTimeout(final HttpDestination destination) - { - assert _timeoutTask == null; - - _timeoutTask = new Timeout.Task() - { - @Override - public void expired() - { - HttpExchange.this.expire(destination); - } - }; - - HttpClient httpClient = destination.getHttpClient(); - long timeout = getTimeout(); - if (timeout > 0) - httpClient.schedule(_timeoutTask,timeout); - else - httpClient.schedule(_timeoutTask); - } - - protected void cancelTimeout(HttpClient httpClient) - { - Timeout.Task task = _timeoutTask; - if (task != null) - httpClient.cancel(task); - _timeoutTask = null; - } - - private class Listener implements HttpEventListener - { - public void onConnectionFailed(Throwable ex) - { - try - { - HttpExchange.this.onConnectionFailed(ex); - } - finally - { - done(); - } - } - - public void onException(Throwable ex) - { - try - { - HttpExchange.this.onException(ex); - } - finally - { - done(); - } - } - - public void onExpire() - { - try - { - HttpExchange.this.onExpire(); - } - finally - { - done(); - } - } - - public void onRequestCommitted() throws IOException - { - HttpExchange.this.onRequestCommitted(); - } - - public void onRequestComplete() throws IOException - { - try - { - HttpExchange.this.onRequestComplete(); - } - finally - { - synchronized (HttpExchange.this) - { - _onRequestCompleteDone = true; - // Member _onDone may already be true, for example - // because the exchange expired or has been canceled - _onDone |= _onResponseCompleteDone; - if (_onDone) - disassociate(); - HttpExchange.this.notifyAll(); - } - } - } - - public void onResponseComplete() throws IOException - { - try - { - HttpExchange.this.onResponseComplete(); - } - finally - { - synchronized (HttpExchange.this) - { - _onResponseCompleteDone = true; - // Member _onDone may already be true, for example - // because the exchange expired or has been canceled - _onDone |= _onRequestCompleteDone; - if (_onDone) - disassociate(); - HttpExchange.this.notifyAll(); - } - } - } - - public void onResponseContent(ByteBuffer content) throws IOException - { - HttpExchange.this.onResponseContent(content); - } - - public void onResponseHeader(ByteBuffer name, ByteBuffer value) throws IOException - { - HttpExchange.this.onResponseHeader(name,value); - } - - public void onResponseHeaderComplete() throws IOException - { - HttpExchange.this.onResponseHeaderComplete(); - } - - public void onResponseStatus(ByteBuffer version, int status, ByteBuffer reason) throws IOException - { - HttpExchange.this.onResponseStatus(version,status,reason); - } - - public void onRetry() - { - HttpExchange.this.setRetryStatus(true); - try - { - HttpExchange.this.onRetry(); - } - catch (IOException e) - { - LOG.debug(e); - } - } - } - - /** - * @deprecated use {@link org.eclipse.jetty.client.CachedExchange} instead - */ - @Deprecated - public static class CachedExchange extends org.eclipse.jetty.client.CachedExchange - { - public CachedExchange(boolean cacheFields) - { - super(cacheFields); - } - } - - /** - * @deprecated use {@link org.eclipse.jetty.client.ContentExchange} instead - */ - @Deprecated - public static class ContentExchange extends org.eclipse.jetty.client.ContentExchange - { - } -} diff --git a/jetty-client-old/src/main/java/org/eclipse/jetty/client/RedirectListener.java b/jetty-client-old/src/main/java/org/eclipse/jetty/client/RedirectListener.java deleted file mode 100644 index eef08d3b967..00000000000 --- a/jetty-client-old/src/main/java/org/eclipse/jetty/client/RedirectListener.java +++ /dev/null @@ -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 ); - } -} diff --git a/jetty-client-old/src/main/java/org/eclipse/jetty/client/SelectConnector.java b/jetty-client-old/src/main/java/org/eclipse/jetty/client/SelectConnector.java deleted file mode 100644 index 9047d5db4a7..00000000000 --- a/jetty-client-old/src/main/java/org/eclipse/jetty/client/SelectConnector.java +++ /dev/null @@ -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 _connectingChannels = new ConcurrentHashMap(); - - /* ------------------------------------------------------------ */ - /** - * @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(); - } - } -} diff --git a/jetty-client-old/src/main/java/org/eclipse/jetty/client/SocketConnector.java b/jetty-client-old/src/main/java/org/eclipse/jetty/client/SocketConnector.java deleted file mode 100644 index 223e937c7cb..00000000000 --- a/jetty-client-old/src/main/java/org/eclipse/jetty/client/SocketConnector.java +++ /dev/null @@ -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); - } - } - } - }); - - } -} diff --git a/jetty-client-old/src/main/java/org/eclipse/jetty/client/security/BasicAuthentication.java b/jetty-client-old/src/main/java/org/eclipse/jetty/client/security/BasicAuthentication.java deleted file mode 100644 index 8a018b2ecd3..00000000000 --- a/jetty-client-old/src/main/java/org/eclipse/jetty/client/security/BasicAuthentication.java +++ /dev/null @@ -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); - } -} diff --git a/jetty-client-old/src/main/java/org/eclipse/jetty/client/security/DigestAuthentication.java b/jetty-client-old/src/main/java/org/eclipse/jetty/client/security/DigestAuthentication.java deleted file mode 100644 index cf48d968e6b..00000000000 --- a/jetty-client-old/src/main/java/org/eclipse/jetty/client/security/DigestAuthentication.java +++ /dev/null @@ -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>> 4)); - buffer.append(Integer.toHexString(data[i] & 0x0f)); - } - return buffer.toString(); - } - -} diff --git a/jetty-client-old/src/main/java/org/eclipse/jetty/client/security/ProxyAuthorization.java b/jetty-client-old/src/main/java/org/eclipse/jetty/client/security/ProxyAuthorization.java deleted file mode 100644 index 2606cea66d6..00000000000 --- a/jetty-client-old/src/main/java/org/eclipse/jetty/client/security/ProxyAuthorization.java +++ /dev/null @@ -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); - } -} diff --git a/jetty-client-old/src/main/java/org/eclipse/jetty/client/security/SecurityListener.java b/jetty-client-old/src/main/java/org/eclipse/jetty/client/security/SecurityListener.java deleted file mode 100644 index cd343182762..00000000000 --- a/jetty-client-old/src/main/java/org/eclipse/jetty/client/security/SecurityListener.java +++ /dev/null @@ -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 scrapeAuthenticationDetails( String authString ) - { - Map authenticationDetails = new HashMap(); - 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 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(); - } - - -} diff --git a/jetty-client-old/src/main/java/org/eclipse/jetty/client/webdav/MkcolExchange.java b/jetty-client-old/src/main/java/org/eclipse/jetty/client/webdav/MkcolExchange.java deleted file mode 100644 index c6a25fc022b..00000000000 --- a/jetty-client-old/src/main/java/org/eclipse/jetty/client/webdav/MkcolExchange.java +++ /dev/null @@ -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; - } -} diff --git a/jetty-client-old/src/main/java/org/eclipse/jetty/client/webdav/PropfindExchange.java b/jetty-client-old/src/main/java/org/eclipse/jetty/client/webdav/PropfindExchange.java deleted file mode 100644 index f1c9f7436fd..00000000000 --- a/jetty-client-old/src/main/java/org/eclipse/jetty/client/webdav/PropfindExchange.java +++ /dev/null @@ -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; - } -} diff --git a/jetty-client-old/src/main/java/org/eclipse/jetty/client/webdav/WebdavListener.java b/jetty-client-old/src/main/java/org/eclipse/jetty/client/webdav/WebdavListener.java deleted file mode 100644 index 4be5c645a8e..00000000000 --- a/jetty-client-old/src/main/java/org/eclipse/jetty/client/webdav/WebdavListener.java +++ /dev/null @@ -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; - } - - } - -} diff --git a/jetty-client-old/src/main/java/org/eclipse/jetty/client/webdav/WebdavSupportedExchange.java b/jetty-client-old/src/main/java/org/eclipse/jetty/client/webdav/WebdavSupportedExchange.java deleted file mode 100644 index 6db67b3e843..00000000000 --- a/jetty-client-old/src/main/java/org/eclipse/jetty/client/webdav/WebdavSupportedExchange.java +++ /dev/null @@ -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; - } -} diff --git a/jetty-client-old/src/test/java/org/eclipse/jetty/client/AbstractConnectionTest.java b/jetty-client-old/src/test/java/org/eclipse/jetty/client/AbstractConnectionTest.java deleted file mode 100644 index d3261feb1a3..00000000000 --- a/jetty-client-old/src/test/java/org/eclipse/jetty/client/AbstractConnectionTest.java +++ /dev/null @@ -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(); - } - } -} diff --git a/jetty-client-old/src/test/java/org/eclipse/jetty/client/AbstractHttpExchangeCancelTest.java b/jetty-client-old/src/test/java/org/eclipse/jetty/client/AbstractHttpExchangeCancelTest.java deleted file mode 100644 index dddbdf7e363..00000000000 --- a/jetty-client-old/src/test/java/org/eclipse/jetty/client/AbstractHttpExchangeCancelTest.java +++ /dev/null @@ -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; - } - } -} diff --git a/jetty-client-old/src/test/java/org/eclipse/jetty/client/AsyncCallbackHttpExchangeTest.java b/jetty-client-old/src/test/java/org/eclipse/jetty/client/AsyncCallbackHttpExchangeTest.java deleted file mode 100644 index bd65788a0f2..00000000000 --- a/jetty-client-old/src/test/java/org/eclipse/jetty/client/AsyncCallbackHttpExchangeTest.java +++ /dev/null @@ -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 failure = new AtomicReference(); - 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 failure; - - /* ------------------------------------------------------------ */ - private TestHttpExchange(ExecutorService executor, AtomicReference failure) - { - this.executor = executor; - this.failure = failure; - } - - /* ------------------------------------------------------------ */ - @Override - protected void onRequestCommitted() throws IOException - { - Future future = executor.submit(new Callable() - { - /* ------------------------------------------------------------ */ - 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); - } - } - } -} diff --git a/jetty-client-old/src/test/java/org/eclipse/jetty/client/AsyncSelectConnectionTest.java b/jetty-client-old/src/test/java/org/eclipse/jetty/client/AsyncSelectConnectionTest.java deleted file mode 100644 index af139ead28a..00000000000 --- a/jetty-client-old/src/test/java/org/eclipse/jetty/client/AsyncSelectConnectionTest.java +++ /dev/null @@ -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(); - } - - -} diff --git a/jetty-client-old/src/test/java/org/eclipse/jetty/client/AsyncSslHttpExchangeTest.java b/jetty-client-old/src/test/java/org/eclipse/jetty/client/AsyncSslHttpExchangeTest.java deleted file mode 100644 index 08c9b27fa5e..00000000000 --- a/jetty-client-old/src/test/java/org/eclipse/jetty/client/AsyncSslHttpExchangeTest.java +++ /dev/null @@ -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(); - } - -} diff --git a/jetty-client-old/src/test/java/org/eclipse/jetty/client/BlockingHttpExchangeCancelTest.java b/jetty-client-old/src/test/java/org/eclipse/jetty/client/BlockingHttpExchangeCancelTest.java deleted file mode 100644 index 58655f302ba..00000000000 --- a/jetty-client-old/src/test/java/org/eclipse/jetty/client/BlockingHttpExchangeCancelTest.java +++ /dev/null @@ -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; - } - -} diff --git a/jetty-client-old/src/test/java/org/eclipse/jetty/client/CachedHeadersIsolationTest.java b/jetty-client-old/src/test/java/org/eclipse/jetty/client/CachedHeadersIsolationTest.java deleted file mode 100644 index 10a7f5ff3b9..00000000000 --- a/jetty-client-old/src/test/java/org/eclipse/jetty/client/CachedHeadersIsolationTest.java +++ /dev/null @@ -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 e = e1.getResponseFields().getValues("Name"); e.hasMoreElements();) - { - System.out.println(e.nextElement()); - } - - assertEquals("Overwritten buffer","Value",e1.getResponseFields().getStringField("Name")); - } -} \ No newline at end of file diff --git a/jetty-client-old/src/test/java/org/eclipse/jetty/client/ContentExchangeTest.java b/jetty-client-old/src/test/java/org/eclipse/jetty/client/ContentExchangeTest.java deleted file mode 100644 index 7114d9f88e9..00000000000 --- a/jetty-client-old/src/test/java/org/eclipse/jetty/client/ContentExchangeTest.java +++ /dev/null @@ -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(); - } - - } - } -} diff --git a/jetty-client-old/src/test/java/org/eclipse/jetty/client/Curl.java b/jetty-client-old/src/test/java/org/eclipse/jetty/client/Curl.java deleted file mode 100644 index 3a405e8d3a7..00000000000 --- a/jetty-client-old/src/test/java/org/eclipse/jetty/client/Curl.java +++ /dev/null @@ -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. - *

- * Usage is java -cp $CLASSPATH org.eclipse.jetty.client.Curl [ option | URL ] ... - * Options supported are:

    - *
  • --async : The following URLs are fetched in parallel (default) - *
  • --sync : The following URLs are fetched in sequence - *
  • --dump : The content is dumped to stdout - *
  • --nodump : The content is suppressed (default) - *
- */ -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(); - } -} diff --git a/jetty-client-old/src/test/java/org/eclipse/jetty/client/ErrorStatusTest.java b/jetty-client-old/src/test/java/org/eclipse/jetty/client/ErrorStatusTest.java deleted file mode 100644 index 9485fa13ea9..00000000000 --- a/jetty-client-old/src/test/java/org/eclipse/jetty/client/ErrorStatusTest.java +++ /dev/null @@ -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); - } - } - } -} diff --git a/jetty-client-old/src/test/java/org/eclipse/jetty/client/ExpirationWithLimitedConnectionsTest.java b/jetty-client-old/src/test/java/org/eclipse/jetty/client/ExpirationWithLimitedConnectionsTest.java deleted file mode 100644 index cf7355b7ec9..00000000000 --- a/jetty-client-old/src/test/java/org/eclipse/jetty/client/ExpirationWithLimitedConnectionsTest.java +++ /dev/null @@ -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 sockets = new CopyOnWriteArrayList(); - final List failures = new CopyOnWriteArrayList(); - 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 exchanges = new ArrayList(); - - 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); - } -} diff --git a/jetty-client-old/src/test/java/org/eclipse/jetty/client/ExpireTest.java b/jetty-client-old/src/test/java/org/eclipse/jetty/client/ExpireTest.java deleted file mode 100644 index a5558354c56..00000000000 --- a/jetty-client-old/src/test/java/org/eclipse/jetty/client/ExpireTest.java +++ /dev/null @@ -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 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()); - } -} diff --git a/jetty-client-old/src/test/java/org/eclipse/jetty/client/HttpDestinationQueueTest.java b/jetty-client-old/src/test/java/org/eclipse/jetty/client/HttpDestinationQueueTest.java deleted file mode 100644 index e8744f2c768..00000000000 --- a/jetty-client-old/src/test/java/org/eclipse/jetty/client/HttpDestinationQueueTest.java +++ /dev/null @@ -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(); - } -} \ No newline at end of file diff --git a/jetty-client-old/src/test/java/org/eclipse/jetty/client/HttpExchangeTest.java b/jetty-client-old/src/test/java/org/eclipse/jetty/client/HttpExchangeTest.java deleted file mode 100644 index d96e188a7c2..00000000000 --- a/jetty-client-old/src/test/java/org/eclipse/jetty/client/HttpExchangeTest.java +++ /dev/null @@ -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("")); - _httpClient.send(httpExchange); - int status = httpExchange.waitForDone(); - //httpExchange.waitForStatus(HttpExchange.STATUS_COMPLETED); - String result=httpExchange.getResponseContent(); - assertEquals(HttpExchange.STATUS_COMPLETED, status); - assertEquals("i="+i,"",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("")); - assertEquals("i="+i,result.length()-10,result.indexOf("")); - 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("")); - assertEquals("i="+i,result.length()-10,result.indexOf("")); - assertEquals(HttpExchange.STATUS_COMPLETED, status); - Thread.sleep(5); - } - } - - /* ------------------------------------------------------------ */ - @Test - public void testShutdownWithExchange() throws Exception - { - final AtomicReference throwable=new AtomicReference(); - - 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=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(); - } - } -} diff --git a/jetty-client-old/src/test/java/org/eclipse/jetty/client/HttpGetRedirectTest.java b/jetty-client-old/src/test/java/org/eclipse/jetty/client/HttpGetRedirectTest.java deleted file mode 100644 index c4fc96792bd..00000000000 --- a/jetty-client-old/src/test/java/org/eclipse/jetty/client/HttpGetRedirectTest.java +++ /dev/null @@ -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 ); - } - } - } -} diff --git a/jetty-client-old/src/test/java/org/eclipse/jetty/client/HttpHeadersTest.java b/jetty-client-old/src/test/java/org/eclipse/jetty/client/HttpHeadersTest.java deleted file mode 100644 index 97f528675fc..00000000000 --- a/jetty-client-old/src/test/java/org/eclipse/jetty/client/HttpHeadersTest.java +++ /dev/null @@ -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 headers; - - public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException - { - if (baseRequest.isHandled()) - return; - - headers = new HashMap(); - 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); - } - - } -} diff --git a/jetty-client-old/src/test/java/org/eclipse/jetty/client/HttpsProxyAuthenticationTest.java b/jetty-client-old/src/test/java/org/eclipse/jetty/client/HttpsProxyAuthenticationTest.java deleted file mode 100644 index f4fe7015d3e..00000000000 --- a/jetty-client-old/src/test/java/org/eclipse/jetty/client/HttpsProxyAuthenticationTest.java +++ /dev/null @@ -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); - } -} diff --git a/jetty-client-old/src/test/java/org/eclipse/jetty/client/HttpsViaBrokenHttpProxyTest.java b/jetty-client-old/src/test/java/org/eclipse/jetty/client/HttpsViaBrokenHttpProxyTest.java deleted file mode 100644 index 26e785898cb..00000000000 --- a/jetty-client-old/src/test/java/org/eclipse/jetty/client/HttpsViaBrokenHttpProxyTest.java +++ /dev/null @@ -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. - *

- * 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. - *

- * 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); - } - } -} diff --git a/jetty-client-old/src/test/java/org/eclipse/jetty/client/NonBlockingHttpExchangeCancelTest.java b/jetty-client-old/src/test/java/org/eclipse/jetty/client/NonBlockingHttpExchangeCancelTest.java deleted file mode 100644 index c607685faba..00000000000 --- a/jetty-client-old/src/test/java/org/eclipse/jetty/client/NonBlockingHttpExchangeCancelTest.java +++ /dev/null @@ -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; - -import org.junit.After; -import org.junit.Before; - -/* ------------------------------------------------------------ */ -/** - * @version $Revision$ $Date$ - */ -public class NonBlockingHttpExchangeCancelTest extends AbstractHttpExchangeCancelTest -{ - private HttpClient httpClient; - - /* ------------------------------------------------------------ */ - @Before - @Override - public void setUp() throws Exception - { - super.setUp(); - httpClient = new HttpClient(); - httpClient.setConnectorType(HttpClient.CONNECTOR_SELECT_CHANNEL); - httpClient.start(); - } - - /* ------------------------------------------------------------ */ - @After - @Override - public void tearDown() throws Exception - { - httpClient.stop(); - super.tearDown(); - } - - /* ------------------------------------------------------------ */ - @Override - protected HttpClient getHttpClient() - { - return httpClient; - } - - /* ------------------------------------------------------------ */ - public void testHttpExchangeCancelOnRequestComplete() throws Exception - { - super.testHttpExchangeCancelOnRequestComplete(); - } -} diff --git a/jetty-client-old/src/test/java/org/eclipse/jetty/client/ProxyFakeTunnelTest.java b/jetty-client-old/src/test/java/org/eclipse/jetty/client/ProxyFakeTunnelTest.java deleted file mode 100644 index 870c5960ec8..00000000000 --- a/jetty-client-old/src/test/java/org/eclipse/jetty/client/ProxyFakeTunnelTest.java +++ /dev/null @@ -1,228 +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.io.OutputStream; -import java.net.ServerSocket; -import java.net.Socket; - -import org.eclipse.jetty.toolchain.test.IO; - - -public class ProxyFakeTunnelTest extends ProxyTunnellingTest -{ - ServerSocket _proxySocket; - Thread _proxyThread; - - protected int proxyPort() - { - return _proxySocket.getLocalPort(); - } - - - protected void startProxy() throws Exception - { - _proxySocket = new ServerSocket(0); - - _proxyThread = new Thread() - { - @Override - public void run() - { - while (!_proxySocket.isClosed()) - { - try - { - Socket socket=_proxySocket.accept(); - System.err.println("accepted "+socket); - new FakeProxy(socket).start(); - } - catch (IOException e) - { - } - } - } - }; - _proxyThread.setDaemon(true); - _proxyThread.start(); - - } - - protected void stopProxy() throws Exception - { - _proxySocket.close(); - _proxyThread.interrupt(); - } - - static class FakeProxy extends Thread - { - Socket _socket; - - public FakeProxy(Socket socket) - { - _socket=socket; - } - - public void run() - { - - Socket toserver=null; - final InputStream in; - final OutputStream out; - try - { - in = _socket.getInputStream(); - out = _socket.getOutputStream(); - - String address=""; - int state=0; - - for (int b=in.read();b>=0;b=in.read()) - { - switch(state) - { - case 0: - if (' '==b) - state=1; - break; - - case 1: - if (' '==b) - state=2; - else - address+=(char)b; - break; - - case 2: - if ('\r'==b) - state=3; - break; - - case 3: - if ('\n'==b) - state=4; - else - state=2; - break; - - case 4: - if ('\r'==b) - state=5; - else - state=2; - break; - - case 5: - if ('\n'==b) - { - state=6; - System.err.println("address="+address); - String[] parts=address.split(":"); - try - { - toserver = new Socket(parts[0],Integer.parseInt(parts[1])); - out.write(( - "HTTP/1.1 200 OK\r\n"+ - "Server: fake\r\n"+ - // "Content-Length: 0\r\n"+ - "\r\n" - ).getBytes()); - } - catch(IOException e) - { - out.write(( - "HTTP/1.1 503 Unavailable\r\n"+ - "Server: fake\r\n"+ - "Content-Length: 0\r\n"+ - "\r\n" - ).getBytes()); - } - out.flush(); - - if (toserver!=null) - { - final InputStream from = toserver.getInputStream(); - - Thread copy = new Thread() - { - public void run() - { - try - { - IO.copy(from,out); - out.close(); - } - catch (IOException e) - { - } - finally - { - try - { - out.close(); - } - catch (IOException e) - { - } - } - } - }; - copy.setDaemon(true); - copy.start(); - } - - } - else - state=2; - break; - - case 6: - toserver.getOutputStream().write((byte)b); - - } - } - - - } - catch (IOException e) - { - e.printStackTrace(); - } - finally - { - if (toserver!=null) - { - try - { - toserver.close(); - } - catch (IOException e) - { - e.printStackTrace(); - } - } - } - } - - } - - -} diff --git a/jetty-client-old/src/test/java/org/eclipse/jetty/client/ProxyTunnellingTest.java b/jetty-client-old/src/test/java/org/eclipse/jetty/client/ProxyTunnellingTest.java deleted file mode 100644 index 1567053ef3a..00000000000 --- a/jetty-client-old/src/test/java/org/eclipse/jetty/client/ProxyTunnellingTest.java +++ /dev/null @@ -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.*; - -import java.io.IOException; -import java.net.URLEncoder; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; - -import javax.servlet.ServletException; -import javax.servlet.ServletOutputStream; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -import org.eclipse.jetty.http.HttpHeader; -import org.eclipse.jetty.http.HttpMethod; -import org.eclipse.jetty.http.MimeTypes; -import org.eclipse.jetty.io.ByteArrayBuffer; -import org.eclipse.jetty.server.Connector; -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.ConnectHandler; -import org.eclipse.jetty.server.nio.SelectChannelConnector; -import org.eclipse.jetty.server.ssl.SslSelectChannelConnector; -import org.eclipse.jetty.toolchain.test.MavenTestingUtils; -import org.eclipse.jetty.util.ssl.SslContextFactory; -import org.junit.After; -import org.junit.Test; - -public class ProxyTunnellingTest -{ - private Server server; - private Connector serverConnector; - private Server proxy; - private Connector proxyConnector; - private int serverConnectTimeout = 1000; - - protected int proxyPort() - { - return proxyConnector.getLocalPort(); - } - - protected void startSSLServer(Handler handler) throws Exception - { - SslSelectChannelConnector connector = new SslSelectChannelConnector(); - String keyStorePath = MavenTestingUtils.getTestResourceFile("keystore").getAbsolutePath(); - SslContextFactory cf = connector.getSslContextFactory(); - cf.setKeyStorePath(keyStorePath); - cf.setKeyStorePassword("storepwd"); - cf.setKeyManagerPassword("keypwd"); - startServer(connector, handler); - } - - protected void startServer(Connector connector, Handler handler) throws Exception - { - server = new Server(); - serverConnector = connector; - server.addConnector(serverConnector); - server.setHandler(handler); - server.start(); - } - - protected void startProxy() throws Exception - { - proxy = new Server(); - proxyConnector = new SelectChannelConnector(); - proxy.addConnector(proxyConnector); - ConnectHandler connectHandler = new ConnectHandler(); - // Under Windows, it takes a while to detect that a connection - // attempt fails, so use an explicit timeout - connectHandler.setConnectTimeout(serverConnectTimeout); - proxy.setHandler(connectHandler); - proxy.start(); - } - - @After - public void stop() throws Exception - { - stopProxy(); - stopServer(); - } - - protected void stopServer() throws Exception - { - server.stop(); - server.join(); - } - - protected void stopProxy() throws Exception - { - proxy.stop(); - proxy.join(); - } - - @Test - public void testOneMessageSSL() throws Exception - { - startSSLServer(new ServerHandler()); - startProxy(); - - HttpClient httpClient = new HttpClient(); - httpClient.setProxy(new Address("localhost", proxyPort())); - httpClient.start(); - - try - { - ContentExchange exchange = new ContentExchange(true); - exchange.setMethod(HttpMethod.GET); - String body = "BODY"; - exchange.setURL("https://localhost:" + serverConnector.getLocalPort() + "/echo?body=" + URLEncoder.encode(body, "UTF-8")); - - httpClient.send(exchange); - assertEquals(HttpExchange.STATUS_COMPLETED, exchange.waitForDone()); - String content = exchange.getResponseContent(); - assertEquals(body, content); - } - finally - { - httpClient.stop(); - } - } - - @Test - public void testTwoMessagesSSL() throws Exception - { - startSSLServer(new ServerHandler()); - startProxy(); - - HttpClient httpClient = new HttpClient(); - httpClient.setProxy(new Address("localhost", proxyPort())); - httpClient.start(); - - try - { - ContentExchange exchange = new ContentExchange(true); - exchange.setMethod(HttpMethod.GET); - String body = "BODY"; - exchange.setURL("https://localhost:" + serverConnector.getLocalPort() + "/echo?body=" + URLEncoder.encode(body, "UTF-8")); - - httpClient.send(exchange); - assertEquals(HttpExchange.STATUS_COMPLETED, exchange.waitForDone()); - String content = exchange.getResponseContent(); - assertEquals(body, content); - - exchange = new ContentExchange(true); - exchange.setMethod(HttpMethod.POST); - exchange.setURL("https://localhost:" + serverConnector.getLocalPort() + "/echo"); - exchange.setRequestHeader(HttpHeader.CONTENT_TYPE, MimeTypes.FORM_ENCODED); - content = "body=" + body; - exchange.setRequestHeader(HttpHeader.CONTENT_LENGTH, String.valueOf(content.length())); - exchange.setRequestContent(new ByteArrayBuffer(content, "UTF-8")); - - httpClient.send(exchange); - assertEquals(HttpExchange.STATUS_COMPLETED, exchange.waitForDone()); - content = exchange.getResponseContent(); - assertEquals(body, content); - } - finally - { - httpClient.stop(); - } - } - - @Test - public void testProxyDown() throws Exception - { - startSSLServer(new ServerHandler()); - startProxy(); - int proxyPort = proxyPort(); - stopProxy(); - - HttpClient httpClient = new HttpClient(); - httpClient.setProxy(new Address("localhost", proxyPort)); - httpClient.start(); - - try - { - final CountDownLatch latch = new CountDownLatch(1); - ContentExchange exchange = new ContentExchange(true) - { - @Override - protected void onConnectionFailed(Throwable x) - { - latch.countDown(); - } - }; - exchange.setMethod(HttpMethod.GET); - String body = "BODY"; - exchange.setURL("https://localhost:" + serverConnector.getLocalPort() + "/echo?body=" + URLEncoder.encode(body, "UTF-8")); - - httpClient.send(exchange); - assertTrue(latch.await(1000, TimeUnit.MILLISECONDS)); - } - finally - { - httpClient.stop(); - } - } - - @Test - public void testServerDown() throws Exception - { - startSSLServer(new ServerHandler()); - int serverPort = serverConnector.getLocalPort(); - stopServer(); - startProxy(); - - HttpClient httpClient = new HttpClient(); - httpClient.setProxy(new Address("localhost", proxyPort())); - httpClient.start(); - - try - { - final CountDownLatch latch = new CountDownLatch(1); - ContentExchange exchange = new ContentExchange(true) - { - @Override - protected void onException(Throwable x) - { - latch.countDown(); - } - - }; - exchange.setMethod(HttpMethod.GET); - String body = "BODY"; - exchange.setURL("https://localhost:" + serverPort + "/echo?body=" + URLEncoder.encode(body, "UTF-8")); - - httpClient.send(exchange); - assertTrue("Server connect exception should have occurred", latch.await(serverConnectTimeout * 2, TimeUnit.MILLISECONDS)); - } - finally - { - httpClient.stop(); - } - } - - private static class ServerHandler extends AbstractHandler - { - public void handle(String target, Request request, HttpServletRequest httpRequest, HttpServletResponse httpResponse) throws IOException, ServletException - { - request.setHandled(true); - - String uri = httpRequest.getRequestURI(); - if ("/echo".equals(uri)) - { - String body = httpRequest.getParameter("body"); - ServletOutputStream output = httpResponse.getOutputStream(); - output.print(body); - } - else - { - throw new ServletException(); - } - } - } -} diff --git a/jetty-client-old/src/test/java/org/eclipse/jetty/client/SecuredContentExchangeTest.java b/jetty-client-old/src/test/java/org/eclipse/jetty/client/SecuredContentExchangeTest.java deleted file mode 100644 index 81683c7ed46..00000000000 --- a/jetty-client-old/src/test/java/org/eclipse/jetty/client/SecuredContentExchangeTest.java +++ /dev/null @@ -1,108 +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.File; -import java.util.Collections; -import java.util.HashSet; -import java.util.Set; - -import org.eclipse.jetty.client.security.Realm; -import org.eclipse.jetty.security.ConstraintMapping; -import org.eclipse.jetty.security.ConstraintSecurityHandler; -import org.eclipse.jetty.security.HashLoginService; -import org.eclipse.jetty.security.LoginService; -import org.eclipse.jetty.security.authentication.BasicAuthenticator; -import org.eclipse.jetty.server.Handler; -import org.eclipse.jetty.server.Server; -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.toolchain.test.MavenTestingUtils; -import org.eclipse.jetty.util.security.Constraint; - -public class SecuredContentExchangeTest - extends ContentExchangeTest -{ - protected void configureServer(Server server) - throws Exception - { - setProtocol("http"); - setRealm(new Realm() - { - public String getId() - { - return "MyRealm"; - } - - public String getPrincipal() - { - return "jetty"; - } - - public String getCredentials() - { - return "jetty"; - } - }); - - SelectChannelConnector connector = new SelectChannelConnector(); - server.addConnector(connector); - - File realmPropFile = MavenTestingUtils.getTestResourceFile("realm.properties"); - LoginService loginService = new HashLoginService("MyRealm",realmPropFile.getAbsolutePath()); - server.addBean(loginService); - - ConstraintSecurityHandler security = new ConstraintSecurityHandler(); - server.setHandler(security); - - Constraint constraint = new Constraint(); - constraint.setName("auth"); - constraint.setAuthenticate( true ); - constraint.setRoles(new String[]{"user", "admin"}); - - ConstraintMapping mapping = new ConstraintMapping(); - mapping.setPathSpec( "/*" ); - mapping.setConstraint( constraint ); - - Set knownRoles = new HashSet(); - knownRoles.add("user"); - knownRoles.add("admin"); - - security.setConstraintMappings(Collections.singletonList(mapping), knownRoles); - security.setAuthenticator(new BasicAuthenticator()); - security.setLoginService(loginService); - security.setStrict(false); - - ServletContextHandler root = new ServletContextHandler(); - root.setContextPath("/"); - root.setResourceBase(getBasePath()); - ServletHolder servletHolder = new ServletHolder( new DefaultServlet() ); - servletHolder.setInitParameter( "gzip", "true" ); - root.addServlet( servletHolder, "/*" ); - - Handler handler = new TestHandler(getBasePath()); - - HandlerCollection handlers = new HandlerCollection(); - handlers.setHandlers(new Handler[]{handler, root}); - security.setHandler(handlers); - } -} diff --git a/jetty-client-old/src/test/java/org/eclipse/jetty/client/SecuredErrorStatusTest.java b/jetty-client-old/src/test/java/org/eclipse/jetty/client/SecuredErrorStatusTest.java deleted file mode 100644 index 147c3c9894f..00000000000 --- a/jetty-client-old/src/test/java/org/eclipse/jetty/client/SecuredErrorStatusTest.java +++ /dev/null @@ -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 java.io.File; -import java.util.Collections; -import java.util.HashSet; -import java.util.Set; - -import org.eclipse.jetty.client.security.Realm; -import org.eclipse.jetty.http.HttpStatus; -import org.eclipse.jetty.security.ConstraintMapping; -import org.eclipse.jetty.security.ConstraintSecurityHandler; -import org.eclipse.jetty.security.HashLoginService; -import org.eclipse.jetty.security.LoginService; -import org.eclipse.jetty.security.authentication.BasicAuthenticator; -import org.eclipse.jetty.server.Handler; -import org.eclipse.jetty.server.Server; -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.toolchain.test.MavenTestingUtils; -import org.eclipse.jetty.util.security.Constraint; -import org.junit.Test; - -public class SecuredErrorStatusTest - extends ErrorStatusTest -{ - private Realm _testRealm; - private Realm _dummyRealm; - - /* ------------------------------------------------------------ */ - @Test - @Override - public void testPutUnauthorized() - throws Exception - { - setRealm(null); - - doPutFail(HttpStatus.UNAUTHORIZED_401); - - setRealm(_testRealm); - } - - /* ------------------------------------------------------------ */ - @Test - public void testPutWrongPassword() - throws Exception - { - setRealm(_dummyRealm); - - doPutFail(HttpStatus.UNAUTHORIZED_401); - - setRealm(_testRealm); - } - - /* ------------------------------------------------------------ */ - @Test - @Override - public void testGetUnauthorized() - throws Exception - { - setRealm(null); - - doGetFail(HttpStatus.UNAUTHORIZED_401); - - setRealm(_testRealm); - } - - /* ------------------------------------------------------------ */ - @Test - public void testGetWrongPassword() - throws Exception - { - setRealm(_dummyRealm); - - doGetFail(HttpStatus.UNAUTHORIZED_401); - - setRealm(_testRealm); - } - - /* ------------------------------------------------------------ */ - @Override - protected void configureServer(Server server) - throws Exception - { - setProtocol("http"); - - _testRealm = new Realm() - { - /* ------------------------------------------------------------ */ - public String getId() - { - return "MyRealm"; - } - - /* ------------------------------------------------------------ */ - public String getPrincipal() - { - return "jetty"; - } - - /* ------------------------------------------------------------ */ - public String getCredentials() - { - return "jetty"; - } - }; - - _dummyRealm = new Realm() - { - /* ------------------------------------------------------------ */ - public String getId() - { - return "MyRealm"; - } - - /* ------------------------------------------------------------ */ - public String getPrincipal() - { - return "jetty"; - } - - /* ------------------------------------------------------------ */ - public String getCredentials() - { - return "dummy"; - } - }; - - setRealm(_testRealm); - - SelectChannelConnector connector = new SelectChannelConnector(); - server.addConnector(connector); - - File realmPropFile = MavenTestingUtils.getTestResourceFile("realm.properties"); - LoginService loginService = new HashLoginService("MyRealm",realmPropFile.getAbsolutePath()); - server.addBean(loginService); - - ConstraintSecurityHandler security = new ConstraintSecurityHandler(); - server.setHandler(security); - - Constraint constraint = new Constraint(); - constraint.setName("auth"); - constraint.setAuthenticate( true ); - constraint.setRoles(new String[]{"user", "admin"}); - - ConstraintMapping mapping = new ConstraintMapping(); - mapping.setPathSpec( "/*" ); - mapping.setConstraint( constraint ); - - Set knownRoles = new HashSet(); - knownRoles.add("user"); - knownRoles.add("admin"); - - security.setConstraintMappings(Collections.singletonList(mapping), knownRoles); - security.setAuthenticator(new BasicAuthenticator()); - security.setLoginService(loginService); - security.setStrict(false); - - 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}); - security.setHandler(handlers); - } -} diff --git a/jetty-client-old/src/test/java/org/eclipse/jetty/client/SecurityListenerTest.java b/jetty-client-old/src/test/java/org/eclipse/jetty/client/SecurityListenerTest.java deleted file mode 100644 index 4503545ab6a..00000000000 --- a/jetty-client-old/src/test/java/org/eclipse/jetty/client/SecurityListenerTest.java +++ /dev/null @@ -1,355 +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.assertFalse; - -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.CyclicBarrier; -import java.util.concurrent.TimeUnit; - -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.io.EofException; -import org.eclipse.jetty.security.ConstraintMapping; -import org.eclipse.jetty.security.ConstraintSecurityHandler; -import org.eclipse.jetty.security.HashLoginService; -import org.eclipse.jetty.security.LoginService; -import org.eclipse.jetty.security.authentication.BasicAuthenticator; -import org.eclipse.jetty.server.Connector; -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.nio.SelectChannelConnector; -import org.eclipse.jetty.toolchain.test.MavenTestingUtils; -import org.eclipse.jetty.util.security.Constraint; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; - -/* ------------------------------------------------------------ */ -/** - * Functional testing for HttpExchange. - */ -public class SecurityListenerTest -{ - private Server _server; - private int _port; - private HttpClient _httpClient; - - private Realm _jettyRealm; - private static final String APP_CONTEXT = "localhost /"; - - /* ------------------------------------------------------------ */ - @Before - public void setUp() throws Exception - { - startServer(); - _httpClient=new HttpClient(); - _httpClient.setConnectorType(HttpClient.CONNECTOR_SELECT_CHANNEL); - _httpClient.setMaxConnectionsPerAddress(2); - _httpClient.start(); - - _jettyRealm = new Realm() - { - public String getId() - { - return "MyRealm"; - } - - public String getPrincipal() - { - return "jetty"; - } - - public String getCredentials() - { - return "jetty"; - } - }; - - _httpClient.setRealmResolver( new SimpleRealmResolver(_jettyRealm) ); - } - - /* ------------------------------------------------------------ */ - @After - public void tearDown() throws Exception - { - stopServer(); - _httpClient.stop(); - } - - /* ------------------------------------------------------------ */ -// @Test - public void xtestPerf() throws Exception - { - sender(1); - Thread.sleep(200); - sender(10); - Thread.sleep(200); - sender(100); - Thread.sleep(200); - sender(1000); - Thread.sleep(200); - sender(10000); - } - - /* ------------------------------------------------------------ */ - public void sender(final int nb) throws Exception - { - final CountDownLatch latch=new CountDownLatch(nb); - long l0=System.currentTimeMillis(); - for (int i=0; i0) - { - // System.err.println("waiting for "+last+" sent "+(System.currentTimeMillis()-l0)/1000 + "s ago ..."); - latch.await(5,TimeUnit.SECONDS); - long next=latch.getCount(); - if (last==next) - break; - last=next; - } - // System.err.println("missed "+latch.getCount()+" sent "+(System.currentTimeMillis()-l0)/1000 + "s ago."); - assertEquals(0,latch.getCount()); - long l1=System.currentTimeMillis(); - } - - //TODO jaspi hangs ??? -// public void testGetWithContentExchange() throws Exception -// { -// int i = 1; -// -// final CyclicBarrier barrier = new CyclicBarrier(2); -// ContentExchange httpExchange = new ContentExchange() -// { -// protected void onResponseComplete() throws IOException -// { -// super.onResponseComplete(); -// try{barrier.await();}catch(Exception e){} -// } -// }; -// httpExchange.setURL("http://localhost:" + _port + "/?i=" + i); -// httpExchange.setMethod(HttpMethods.GET); -// -// _httpClient.send(httpExchange); -// -// try{barrier.await();}catch(Exception e){} -// -// } - - - /* ------------------------------------------------------------ */ - @Test - public void testDestinationSecurityCaching() throws Exception - { - final CyclicBarrier barrier = new CyclicBarrier(2); - - ContentExchange httpExchange = new ContentExchange() - { - @Override - protected void onResponseComplete() throws IOException - { - super.onResponseComplete(); - try{barrier.await();}catch(Exception e){} - } - }; - - httpExchange.setURL("http://localhost:" + _port + "/?i=1"); - httpExchange.setMethod(HttpMethod.GET); - - _httpClient.send(httpExchange); - - try{barrier.await();}catch(Exception e){} - - - barrier.reset(); - ContentExchange httpExchange2 = new ContentExchange() - { - @Override - protected void onResponseComplete() throws IOException - { - super.onResponseComplete(); - try{barrier.await();}catch(Exception e){} - } - }; - - httpExchange2.setURL("http://localhost:" + _port + "/?i=2"); - httpExchange2.setMethod(HttpMethod.GET); - - _httpClient.send(httpExchange2); - - try{barrier.await();}catch(Exception e){} - - assertFalse( "exchange was retried", httpExchange2.getRetryStatus() ); - - } - - /* ------------------------------------------------------------ */ - 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(); - } - } - - /* ------------------------------------------------------------ */ - private void startServer() throws Exception - { - _server = new Server(); - _server.setGracefulShutdown(500); - Connector connector = new SelectChannelConnector(); - - connector.setPort(0); - _server.setConnectors(new Connector[]{connector}); - - Constraint constraint = new Constraint(); - constraint.setName("Need User or Admin"); - constraint.setRoles(new String[]{"user", "admin"}); - constraint.setAuthenticate(true); - - ConstraintMapping cm = new ConstraintMapping(); - cm.setConstraint(constraint); - cm.setPathSpec("/*"); - - File realmPropFile = MavenTestingUtils.getTestResourceFile("realm.properties"); - LoginService loginService = new HashLoginService("MyRealm",realmPropFile.getAbsolutePath()); - ConstraintSecurityHandler sh = new ConstraintSecurityHandler(); - sh.setLoginService(loginService); - sh.setAuthenticator(new BasicAuthenticator()); - - //ServerAuthentication serverAuthentication = new BasicServerAuthentication(loginService, "MyRealm"); - //sh.setServerAuthentication(serverAuthentication); - _server.setHandler(sh); - - Handler testHandler = new AbstractHandler() - { - public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException - { - // System.out.println("passed authentication!"); - baseRequest.setHandled(true); - response.setStatus(200); - if (request.getServerName().equals("jetty.eclipse.org")) - { - response.getOutputStream().println("Proxy request: "+request.getRequestURL()); - } - else if (request.getMethod().equalsIgnoreCase("GET")) - { - response.getOutputStream().println(""); - for (int i=0; i<100; i++) - { - response.getOutputStream().println(" "+i+""); - if (i%20==0) - response.getOutputStream().flush(); - } - response.getOutputStream().println(""); - } - else - { - copyStream(request.getInputStream(),response.getOutputStream()); - } - } - }; - - sh.setHandler(testHandler); - - _server.start(); - _port = connector.getLocalPort(); - } - - /* ------------------------------------------------------------ */ - private void stopServer() throws Exception - { - _server.stop(); - } -} diff --git a/jetty-client-old/src/test/java/org/eclipse/jetty/client/Siege.java b/jetty-client-old/src/test/java/org/eclipse/jetty/client/Siege.java deleted file mode 100644 index 1383fba655c..00000000000 --- a/jetty-client-old/src/test/java/org/eclipse/jetty/client/Siege.java +++ /dev/null @@ -1,229 +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.ArrayList; -import java.util.List; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.atomic.AtomicBoolean; - -import org.eclipse.jetty.http.HttpMethod; - -import org.eclipse.jetty.util.thread.QueuedThreadPool; - - -/* ------------------------------------------------------------ */ -/** - */ -public class Siege -{ - private static final class ConcurrentExchange extends HttpExchange - { - private final long _start=System.currentTimeMillis(); - private final HttpClient _client; - private final CountDownLatch _latch; - volatile int _status; - volatile int _count; - volatile long _bytes; - final List _uris; - final int _repeats; - int _u; - int _r; - - AtomicBoolean counted=new AtomicBoolean(false); - - public ConcurrentExchange(HttpClient client,CountDownLatch latch, List uris, int repeats) - { - _client = client; - _latch = latch; - _uris = uris; - _repeats = repeats; - } - - @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 (_status==200) - _count++; - if (!next() && !counted.getAndSet(true)) - { - _latch.countDown(); - long duration=System.currentTimeMillis()-_start; - System.err.printf("Got %d/%d with %dB in %dms %d%n",_count,_uris.size()*_repeats,_bytes,duration,_latch.getCount()); - } - } - - - /* ------------------------------------------------------------ */ - @Override - protected void onResponseContent(ByteBuffer content) throws IOException - { - _bytes+=content.length(); - super.onResponseContent(content); - } - - /* ------------------------------------------------------------ */ - /** - * @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 ("Set-Cookie".equalsIgnoreCase(name.toString())) - { - String v=value.toString(); - int c = v.indexOf(';'); - if (c>=0) - v=v.substring(0,c); - addRequestHeader("Cookie",v); - } - } - - /* ------------------------------------------------------------ */ - /** - * @see org.eclipse.jetty.client.HttpExchange#onResponseHeaderComplete() - */ - @Override - protected void onResponseHeaderComplete() throws IOException - { - super.onResponseHeaderComplete(); - } - - /* ------------------------------------------------------------ */ - /** - * @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 - { - _status=status; - super.onResponseStatus(version,status,reason); - } - - public boolean next() - { - if (_u>=_uris.size()) - { - _u=0; - _r++; - if (_r>=_repeats) - return false; - } - - String uri=_uris.get(_u++); - - reset(); - setMethod(HttpMethod.GET); - setURL(uri); - - try - { - _client.send(this); - } - catch(IOException e) - { - e.printStackTrace(); - return false; - } - return true; - } - } - - public static void main(String[] args) - throws Exception - { - if (args.length==0) - args=new String[] - { "-c", "2", "-r", "2", "http://localhost:8080/dump", "http://localhost:8080/d.txt"}; - - int concurrent=1; - int repeats=1; - final List uris = new ArrayList(); - - for (int i=0; i accumulatedRequest; - - public SluggishHandler(int requestSize) - { - accumulatedRequest = new ArrayList(requestSize); - } - - public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException - { - accumulatedRequest.clear(); - ServletInputStream input = request.getInputStream(); - byte[] buffer = new byte[16384]; - int bytesAvailable; - while ((bytesAvailable = input.read(buffer,0,buffer.length)) > 0) - { - //System.err.println("AVAILABLE FOR READ = " + bytesAvailable); - for (int n = 0; n < bytesAvailable; ++n) - { - accumulatedRequest.add(buffer[n]); - } - try - { - Thread.sleep(READ_DELAY); - } - catch (InterruptedException e) - { - e.printStackTrace(); - } - } - response.setStatus(HttpServletResponse.SC_OK); - baseRequest.setHandled(true); - //System.err.println("HANDLED"); - } - - public byte[] getAccumulatedRequest() - { - byte[] buffer = new byte[accumulatedRequest.size()]; - int pos = 0; - for (Byte b : accumulatedRequest) - { - buffer[pos++] = b; - } - return buffer; - } - } - - private static boolean compareBuffers(byte[] sent, byte[] received) - { - if (sent.length != received.length) - { - System.err.format("Mismatch in sent/received lengths: sent=%d received=%d\n",sent.length,received.length); - return false; - } - else - { - for (int n = 0; n < sent.length; ++n) - { - if (sent[n] != received[n]) - { - System.err.format("Mismatch at offset %d: request=%d response=%d\n",n,sent[n],received[n]); - return false; - } - } - } - return true; - } - - @Test - public void test0() throws Exception - { - goSlow(20000,10); - } - - @Test - public void test1() throws Exception - { - goSlow(200000,5); - } - - @Test - public void test2() throws Exception - { - goSlow(2000000,2); - } - - void goSlow(int requestSize,int iterations) throws Exception - { - Server server = new Server(); - SocketConnector connector = new SocketConnector(); - server.addConnector(connector); - SluggishHandler handler = new SluggishHandler(requestSize); - server.setHandler(handler); - server.start(); - int port = connector.getLocalPort(); - - HttpClient client = new HttpClient(); - client.setConnectorType(HttpClient.CONNECTOR_SELECT_CHANNEL); - client.setConnectTimeout(5000); - client.setIdleTimeout(60000); - client.start(); - - try - { - for (int i = 0; i < iterations; ++i) - { - //System.err.format("-------------- ITERATION %d ------------------\n",i); - SluggishExchange exchange = new SluggishExchange(port,requestSize); - long startTime = System.currentTimeMillis(); - client.send(exchange); - exchange.waitForDone(); - long endTime = System.currentTimeMillis(); - //System.err.println("EXCHANGE STATUS = " + exchange); - //System.err.println("ELAPSED MSEC = " + (endTime - startTime)); - Assert.assertTrue(compareBuffers(exchange.getRequestBody(),handler.getAccumulatedRequest())); - } - } - finally - { - server.stop(); - server.join(); - } - } -} diff --git a/jetty-client-old/src/test/java/org/eclipse/jetty/client/SocketConnectionTest.java b/jetty-client-old/src/test/java/org/eclipse/jetty/client/SocketConnectionTest.java deleted file mode 100644 index 41191e528ce..00000000000 --- a/jetty-client-old/src/test/java/org/eclipse/jetty/client/SocketConnectionTest.java +++ /dev/null @@ -1,101 +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.BufferedReader; -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; - -public class SocketConnectionTest extends AbstractConnectionTest -{ - protected HttpClient newHttpClient() - { - HttpClient httpClient = new HttpClient(); - httpClient.setConnectorType(HttpClient.CONNECTOR_SOCKET); - return httpClient; - } - - @Override - public void testServerClosedConnection() throws Exception - { - // Differently from the SelectConnector, the SocketConnector cannot detect server closes. - // Therefore, upon a second send, the exchange will fail. - // Applications needs to retry it explicitly. - - ServerSocket serverSocket = new ServerSocket(); - serverSocket.bind(null); - int port=serverSocket.getLocalPort(); - - HttpClient httpClient = this.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(); - - exchange.reset(); - httpClient.send(exchange); - - assertEquals(HttpExchange.STATUS_EXCEPTED, exchange.waitForDone()); - } - finally - { - httpClient.stop(); - } - } - - public void testIdleConnection() throws Exception - { - super.testIdleConnection(); - } -} diff --git a/jetty-client-old/src/test/java/org/eclipse/jetty/client/SslBytesClientTest.java b/jetty-client-old/src/test/java/org/eclipse/jetty/client/SslBytesClientTest.java deleted file mode 100644 index 9ea169b9899..00000000000 --- a/jetty-client-old/src/test/java/org/eclipse/jetty/client/SslBytesClientTest.java +++ /dev/null @@ -1,166 +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.File; -import java.io.InputStreamReader; -import java.io.OutputStream; -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 javax.net.ssl.SSLContext; -import javax.net.ssl.SSLServerSocket; -import javax.net.ssl.SSLSocket; - -import org.eclipse.jetty.http.HttpMethod; -import org.eclipse.jetty.http.HttpStatus; -import org.eclipse.jetty.toolchain.test.MavenTestingUtils; -import org.eclipse.jetty.util.ssl.SslContextFactory; -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; - -public class SslBytesClientTest extends SslBytesTest -{ - private ExecutorService threadPool; - private HttpClient client; - private SimpleProxy proxy; - private SSLServerSocket acceptor; - - @Before - public void init() throws Exception - { - threadPool = Executors.newCachedThreadPool(); - - client = new HttpClient(); - client.setMaxConnectionsPerAddress(1); - client.setConnectorType(HttpClient.CONNECTOR_SELECT_CHANNEL); - File keyStore = MavenTestingUtils.getTestResourceFile("keystore"); - SslContextFactory cf = client.getSslContextFactory(); - cf.setKeyStorePath(keyStore.getAbsolutePath()); - cf.setKeyStorePassword("storepwd"); - cf.setKeyManagerPassword("keypwd"); - client.start(); - - SSLContext sslContext = cf.getSslContext(); - acceptor = (SSLServerSocket)sslContext.getServerSocketFactory().createServerSocket(0); - - int serverPort = acceptor.getLocalPort(); - - proxy = new SimpleProxy(threadPool, "localhost", serverPort); - proxy.start(); - logger.debug(":{} <==> :{}", proxy.getPort(), serverPort); - } - - @After - public void destroy() throws Exception - { - if (acceptor != null) - acceptor.close(); - if (proxy != null) - proxy.stop(); - if (client != null) - client.stop(); - if (threadPool != null) - threadPool.shutdownNow(); - } - - @Test - public void testHandshake() throws Exception - { - ContentExchange exchange = new ContentExchange(true); - exchange.setURL("https://localhost:" + proxy.getPort()); - String method = HttpMethod.GET; - exchange.setMethod(method); - client.send(exchange); - Assert.assertTrue(proxy.awaitClient(5, TimeUnit.SECONDS)); - - final SSLSocket server = (SSLSocket)acceptor.accept(); - server.setUseClientMode(false); - - Future handshake = threadPool.submit(new Callable() - { - public Object call() throws Exception - { - server.startHandshake(); - return null; - } - }); - - // Client Hello - TLSRecord record = proxy.readFromClient(); - Assert.assertEquals(TLSRecord.Type.HANDSHAKE, record.getType()); - proxy.flushToServer(record); - - // Server Hello + Certificate + Server Done - record = proxy.readFromServer(); - Assert.assertEquals(TLSRecord.Type.HANDSHAKE, record.getType()); - proxy.flushToClient(record); - - // Client Key Exchange - record = proxy.readFromClient(); - Assert.assertEquals(TLSRecord.Type.HANDSHAKE, record.getType()); - proxy.flushToServer(record); - - // Change Cipher Spec - record = proxy.readFromClient(); - Assert.assertEquals(TLSRecord.Type.CHANGE_CIPHER_SPEC, record.getType()); - proxy.flushToServer(record); - - // Client Done - record = proxy.readFromClient(); - Assert.assertEquals(TLSRecord.Type.HANDSHAKE, record.getType()); - proxy.flushToServer(record); - - // Change Cipher Spec - record = proxy.readFromServer(); - Assert.assertEquals(TLSRecord.Type.CHANGE_CIPHER_SPEC, record.getType()); - proxy.flushToClient(record); - - // Server Done - record = proxy.readFromServer(); - Assert.assertEquals(TLSRecord.Type.HANDSHAKE, record.getType()); - proxy.flushToClient(record); - - Assert.assertNull(handshake.get(5, TimeUnit.SECONDS)); - - SimpleProxy.AutomaticFlow automaticProxyFlow = proxy.startAutomaticFlow(); - // Read request - BufferedReader reader = new BufferedReader(new InputStreamReader(server.getInputStream(), "UTF-8")); - String line = reader.readLine(); - Assert.assertTrue(line.startsWith(method)); - while (line.length() > 0) - line = reader.readLine(); - // Write response - OutputStream output = server.getOutputStream(); - output.write(("HTTP/1.1 200 OK\r\n" + - "Content-Length: 0\r\n" + - "\r\n").getBytes("UTF-8")); - output.flush(); - Assert.assertTrue(automaticProxyFlow.stop(5, TimeUnit.SECONDS)); - - Assert.assertEquals(HttpExchange.STATUS_COMPLETED, exchange.waitForDone()); - Assert.assertEquals(HttpStatus.OK_200, exchange.getResponseStatus()); - } -} diff --git a/jetty-client-old/src/test/java/org/eclipse/jetty/client/SslBytesServerTest.java b/jetty-client-old/src/test/java/org/eclipse/jetty/client/SslBytesServerTest.java deleted file mode 100644 index bb6458077f5..00000000000 --- a/jetty-client-old/src/test/java/org/eclipse/jetty/client/SslBytesServerTest.java +++ /dev/null @@ -1,1775 +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.hamcrest.Matchers.*; - -import java.io.BufferedReader; -import java.io.EOFException; -import java.io.File; -import java.io.IOException; -import java.io.InputStreamReader; -import java.io.OutputStream; -import java.net.SocketTimeoutException; -import java.nio.channels.SocketChannel; -import java.util.Arrays; -import java.util.concurrent.Callable; -import java.util.concurrent.CountDownLatch; -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.AtomicInteger; -import java.util.concurrent.atomic.AtomicReference; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import javax.net.ssl.SSLContext; -import javax.net.ssl.SSLEngine; -import javax.net.ssl.SSLSocket; -import javax.servlet.ServletException; -import javax.servlet.ServletInputStream; -import javax.servlet.ServletOutputStream; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -import org.eclipse.jetty.http.HttpParser; -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.io.nio.SslConnection; -import org.eclipse.jetty.server.AsyncHttpConnection; -import org.eclipse.jetty.server.Request; -import org.eclipse.jetty.server.Server; -import org.eclipse.jetty.server.handler.AbstractHandler; -import org.eclipse.jetty.server.ssl.SslSelectChannelConnector; -import org.eclipse.jetty.toolchain.test.MavenTestingUtils; -import org.eclipse.jetty.toolchain.test.OS; -import org.eclipse.jetty.util.component.Dumpable; -import org.eclipse.jetty.util.ssl.SslContextFactory; -import org.junit.After; -import org.junit.Assert; -import org.junit.Assume; -import org.junit.Before; -import org.junit.Test; - -public class SslBytesServerTest extends SslBytesTest -{ - private final AtomicInteger sslHandles = new AtomicInteger(); - private final AtomicInteger sslFlushes = new AtomicInteger(); - private final AtomicInteger httpParses = new AtomicInteger(); - private final AtomicReference serverEndPoint = new AtomicReference(); - private final int idleTimeout = 2000; - private ExecutorService threadPool; - private Server server; - private int serverPort; - private SSLContext sslContext; - private SimpleProxy proxy; - private Runnable idleHook; - - @Before - public void init() throws Exception - { - threadPool = Executors.newCachedThreadPool(); - server = new Server(); - - SslSelectChannelConnector connector = new SslSelectChannelConnector() - { - @Override - protected SslConnection newSslConnection(AsyncEndPoint endPoint, SSLEngine engine) - { - serverEndPoint.set(endPoint); - return new SslConnection(engine, endPoint) - { - @Override - public Connection handle() throws IOException - { - sslHandles.incrementAndGet(); - return super.handle(); - } - - @Override - protected SslEndPoint newSslEndPoint() - { - return new SslEndPoint() - { - @Override - public int flush(ByteBuffer buffer) throws IOException - { - sslFlushes.incrementAndGet(); - return super.flush(buffer); - } - }; - } - - @Override - public void onIdleExpired(long idleForMs) - { - final Runnable idleHook = SslBytesServerTest.this.idleHook; - if (idleHook != null) - idleHook.run(); - super.onIdleExpired(idleForMs); - } - }; - } - - @Override - protected AsyncConnection newPlainConnection(SocketChannel channel, AsyncEndPoint endPoint) - { - return new AsyncHttpConnection(this, endPoint, getServer()) - { - @Override - protected HttpParser newHttpParser(Buffers requestBuffers, EndPoint endPoint, HttpParser.EventHandler requestHandler) - { - return new HttpParser(requestBuffers, endPoint, requestHandler) - { - @Override - public int parseNext() throws IOException - { - httpParses.incrementAndGet(); - return super.parseNext(); - } - }; - } - }; - } - }; - connector.setMaxIdleTime(idleTimeout); - -// connector.setPort(5870); - connector.setPort(0); - - File keyStore = MavenTestingUtils.getTestResourceFile("keystore"); - SslContextFactory cf = connector.getSslContextFactory(); - cf.setKeyStorePath(keyStore.getAbsolutePath()); - cf.setKeyStorePassword("storepwd"); - cf.setKeyManagerPassword("keypwd"); - server.addConnector(connector); - server.setHandler(new AbstractHandler() - { - public void handle(String target, Request request, HttpServletRequest httpRequest, HttpServletResponse httpResponse) throws IOException, ServletException - { - try - { - request.setHandled(true); - String contentLength = request.getHeader("Content-Length"); - if (contentLength != null) - { - int length = Integer.parseInt(contentLength); - ServletInputStream input = httpRequest.getInputStream(); - ServletOutputStream output = httpResponse.getOutputStream(); - byte[] buffer = new byte[32 * 1024]; - while (length > 0) - { - int read = input.read(buffer); - if (read < 0) - throw new EOFException(); - length -= read; - if (target.startsWith("/echo")) - output.write(buffer, 0, read); - } - } - } - catch (IOException x) - { - if (!(target.endsWith("suppress_exception"))) - throw x; - } - } - }); - server.start(); - serverPort = connector.getLocalPort(); - - sslContext = cf.getSslContext(); - - proxy = new SimpleProxy(threadPool, "localhost", serverPort); - proxy.start(); - logger.debug(":{} <==> :{}", proxy.getPort(), serverPort); - } - - @After - public void destroy() throws Exception - { - if (proxy != null) - proxy.stop(); - if (server != null) - server.stop(); - if (threadPool != null) - threadPool.shutdownNow(); - } - - @Test - public void testHandshake() throws Exception - { - final SSLSocket client = newClient(); - - Future handshake = threadPool.submit(new Callable() - { - public Object call() throws Exception - { - client.startHandshake(); - return null; - } - }); - - // Client Hello - TLSRecord record = proxy.readFromClient(); - Assert.assertNotNull(record); - proxy.flushToServer(record); - - // Server Hello + Certificate + Server Done - record = proxy.readFromServer(); - Assert.assertNotNull(record); - proxy.flushToClient(record); - - // Client Key Exchange - record = proxy.readFromClient(); - Assert.assertNotNull(record); - proxy.flushToServer(record); - - // Change Cipher Spec - record = proxy.readFromClient(); - Assert.assertNotNull(record); - proxy.flushToServer(record); - - // Client Done - record = proxy.readFromClient(); - Assert.assertNotNull(record); - proxy.flushToServer(record); - - // Change Cipher Spec - record = proxy.readFromServer(); - Assert.assertNotNull(record); - proxy.flushToClient(record); - - // Server Done - record = proxy.readFromServer(); - Assert.assertNotNull(record); - proxy.flushToClient(record); - - Assert.assertNull(handshake.get(5, TimeUnit.SECONDS)); - - // Check that we did not spin - TimeUnit.MILLISECONDS.sleep(500); - Assert.assertThat(sslHandles.get(), lessThan(20)); - Assert.assertThat(sslFlushes.get(), lessThan(20)); - Assert.assertThat(httpParses.get(), lessThan(50)); - - closeClient(client); - } - - @Test - public void testHandshakeWithSplitBoundary() throws Exception - { - final SSLSocket client = newClient(); - - Future handshake = threadPool.submit(new Callable() - { - public Object call() throws Exception - { - client.startHandshake(); - return null; - } - }); - - // Client Hello - TLSRecord record = proxy.readFromClient(); - byte[] bytes = record.getBytes(); - byte[] chunk1 = new byte[2 * bytes.length / 3]; - System.arraycopy(bytes, 0, chunk1, 0, chunk1.length); - byte[] chunk2 = new byte[bytes.length - chunk1.length]; - System.arraycopy(bytes, chunk1.length, chunk2, 0, chunk2.length); - proxy.flushToServer(100, chunk1); - proxy.flushToServer(100, chunk2); - - // Server Hello + Certificate + Server Done - record = proxy.readFromServer(); - proxy.flushToClient(record); - - // Client Key Exchange - record = proxy.readFromClient(); - bytes = record.getBytes(); - chunk1 = new byte[2 * bytes.length / 3]; - System.arraycopy(bytes, 0, chunk1, 0, chunk1.length); - chunk2 = new byte[bytes.length - chunk1.length]; - System.arraycopy(bytes, chunk1.length, chunk2, 0, chunk2.length); - proxy.flushToServer(100, chunk1); - proxy.flushToServer(100, chunk2); - - // Change Cipher Spec - record = proxy.readFromClient(); - bytes = record.getBytes(); - chunk1 = new byte[2 * bytes.length / 3]; - System.arraycopy(bytes, 0, chunk1, 0, chunk1.length); - chunk2 = new byte[bytes.length - chunk1.length]; - System.arraycopy(bytes, chunk1.length, chunk2, 0, chunk2.length); - proxy.flushToServer(100, chunk1); - proxy.flushToServer(100, chunk2); - - // Client Done - record = proxy.readFromClient(); - bytes = record.getBytes(); - chunk1 = new byte[2 * bytes.length / 3]; - System.arraycopy(bytes, 0, chunk1, 0, chunk1.length); - chunk2 = new byte[bytes.length - chunk1.length]; - System.arraycopy(bytes, chunk1.length, chunk2, 0, chunk2.length); - proxy.flushToServer(100, chunk1); - proxy.flushToServer(100, chunk2); - - // Change Cipher Spec - record = proxy.readFromServer(); - Assert.assertNotNull(record); - proxy.flushToClient(record); - - // Server Done - record = proxy.readFromServer(); - Assert.assertNotNull(record); - proxy.flushToClient(record); - - Assert.assertNull(handshake.get(5, TimeUnit.SECONDS)); - - // Check that we did not spin - TimeUnit.MILLISECONDS.sleep(500); - Assert.assertThat(sslHandles.get(), lessThan(20)); - Assert.assertThat(sslFlushes.get(), lessThan(20)); - Assert.assertThat(httpParses.get(), lessThan(50)); - - client.close(); - - // Close Alert - record = proxy.readFromClient(); - bytes = record.getBytes(); - chunk1 = new byte[2 * bytes.length / 3]; - System.arraycopy(bytes, 0, chunk1, 0, chunk1.length); - chunk2 = new byte[bytes.length - chunk1.length]; - System.arraycopy(bytes, chunk1.length, chunk2, 0, chunk2.length); - proxy.flushToServer(100, chunk1); - proxy.flushToServer(100, chunk2); - // Socket close - record = proxy.readFromClient(); - Assert.assertNull(String.valueOf(record), record); - proxy.flushToServer(record); - - // Close Alert - record = proxy.readFromServer(); - proxy.flushToClient(record); - // Socket close - record = proxy.readFromServer(); - Assert.assertNull(String.valueOf(record), record); - proxy.flushToClient(record); - } - - @Test - public void testClientHelloIncompleteThenReset() throws Exception - { - final SSLSocket client = newClient(); - - threadPool.submit(new Callable() - { - public Object call() throws Exception - { - client.startHandshake(); - return null; - } - }); - - // Client Hello - TLSRecord record = proxy.readFromClient(); - byte[] bytes = record.getBytes(); - byte[] chunk1 = new byte[2 * bytes.length / 3]; - System.arraycopy(bytes, 0, chunk1, 0, chunk1.length); - proxy.flushToServer(100, chunk1); - - proxy.sendRSTToServer(); - - // Wait a while to detect spinning - TimeUnit.MILLISECONDS.sleep(500); - Assert.assertThat(sslHandles.get(), lessThan(20)); - Assert.assertThat(sslFlushes.get(), lessThan(20)); - Assert.assertThat(httpParses.get(), lessThan(50)); - - client.close(); - } - - @Test - public void testClientHelloThenReset() throws Exception - { - final SSLSocket client = newClient(); - - threadPool.submit(new Callable() - { - public Object call() throws Exception - { - client.startHandshake(); - return null; - } - }); - - // Client Hello - TLSRecord record = proxy.readFromClient(); - Assert.assertNotNull(record); - proxy.flushToServer(record); - - proxy.sendRSTToServer(); - - // Wait a while to detect spinning - TimeUnit.MILLISECONDS.sleep(500); - Assert.assertThat(sslHandles.get(), lessThan(20)); - Assert.assertThat(sslFlushes.get(), lessThan(20)); - Assert.assertThat(httpParses.get(), lessThan(50)); - - client.close(); - } - - @Test - public void testHandshakeThenReset() throws Exception - { - final SSLSocket client = newClient(); - - SimpleProxy.AutomaticFlow automaticProxyFlow = proxy.startAutomaticFlow(); - client.startHandshake(); - Assert.assertTrue(automaticProxyFlow.stop(5, TimeUnit.SECONDS)); - - proxy.sendRSTToServer(); - - // Wait a while to detect spinning - TimeUnit.MILLISECONDS.sleep(500); - Assert.assertThat(sslHandles.get(), lessThan(20)); - Assert.assertThat(sslFlushes.get(), lessThan(20)); - Assert.assertThat(httpParses.get(), lessThan(50)); - - client.close(); - } - - @Test - public void testRequestIncompleteThenReset() throws Exception - { - final SSLSocket client = newClient(); - - SimpleProxy.AutomaticFlow automaticProxyFlow = proxy.startAutomaticFlow(); - client.startHandshake(); - Assert.assertTrue(automaticProxyFlow.stop(5, TimeUnit.SECONDS)); - - threadPool.submit(new Callable() - { - public Object call() throws Exception - { - OutputStream clientOutput = client.getOutputStream(); - clientOutput.write(("" + - "GET / HTTP/1.1\r\n" + - "Host: localhost\r\n" + - "\r\n").getBytes("UTF-8")); - clientOutput.flush(); - return null; - } - }); - - // Application data - TLSRecord record = proxy.readFromClient(); - byte[] bytes = record.getBytes(); - byte[] chunk1 = new byte[2 * bytes.length / 3]; - System.arraycopy(bytes, 0, chunk1, 0, chunk1.length); - proxy.flushToServer(100, chunk1); - - proxy.sendRSTToServer(); - - // Wait a while to detect spinning - TimeUnit.MILLISECONDS.sleep(500); - Assert.assertThat(sslHandles.get(), lessThan(20)); - Assert.assertThat(sslFlushes.get(), lessThan(20)); - Assert.assertThat(httpParses.get(), lessThan(50)); - - client.close(); - } - - @Test - public void testRequestResponse() throws Exception - { - final SSLSocket client = newClient(); - - SimpleProxy.AutomaticFlow automaticProxyFlow = proxy.startAutomaticFlow(); - client.startHandshake(); - Assert.assertTrue(automaticProxyFlow.stop(5, TimeUnit.SECONDS)); - - Future request = threadPool.submit(new Callable() - { - public Object call() throws Exception - { - OutputStream clientOutput = client.getOutputStream(); - clientOutput.write(("" + - "GET / HTTP/1.1\r\n" + - "Host: localhost\r\n" + - "\r\n").getBytes("UTF-8")); - clientOutput.flush(); - return null; - } - }); - - // Application data - TLSRecord record = proxy.readFromClient(); - proxy.flushToServer(record); - Assert.assertNull(request.get(5, TimeUnit.SECONDS)); - - // Application data - record = proxy.readFromServer(); - Assert.assertEquals(TLSRecord.Type.APPLICATION, record.getType()); - proxy.flushToClient(record); - - BufferedReader reader = new BufferedReader(new InputStreamReader(client.getInputStream(), "UTF-8")); - String line = reader.readLine(); - Assert.assertNotNull(line); - Assert.assertTrue(line.startsWith("HTTP/1.1 200 ")); - while ((line = reader.readLine()) != null) - { - if (line.trim().length() == 0) - break; - } - - // Check that we did not spin - TimeUnit.MILLISECONDS.sleep(500); - Assert.assertThat(sslHandles.get(), lessThan(20)); - Assert.assertThat(sslFlushes.get(), lessThan(20)); - Assert.assertThat(httpParses.get(), lessThan(50)); - - closeClient(client); - } - - @Test - public void testHandshakeAndRequestOneByteAtATime() throws Exception - { - final SSLSocket client = newClient(); - - Future handshake = threadPool.submit(new Callable() - { - public Object call() throws Exception - { - client.startHandshake(); - return null; - } - }); - - // Client Hello - TLSRecord record = proxy.readFromClient(); - for (byte b : record.getBytes()) - proxy.flushToServer(50, b); - - // Server Hello + Certificate + Server Done - record = proxy.readFromServer(); - proxy.flushToClient(record); - - // Client Key Exchange - record = proxy.readFromClient(); - for (byte b : record.getBytes()) - proxy.flushToServer(50, b); - - // Change Cipher Spec - record = proxy.readFromClient(); - for (byte b : record.getBytes()) - proxy.flushToServer(50, b); - - // Client Done - record = proxy.readFromClient(); - for (byte b : record.getBytes()) - proxy.flushToServer(50, b); - - // Change Cipher Spec - record = proxy.readFromServer(); - proxy.flushToClient(record); - - // Server Done - record = proxy.readFromServer(); - proxy.flushToClient(record); - - Assert.assertNull(handshake.get(5, TimeUnit.SECONDS)); - - Future request = threadPool.submit(new Callable() - { - public Object call() throws Exception - { - OutputStream clientOutput = client.getOutputStream(); - clientOutput.write(("" + - "GET / HTTP/1.1\r\n" + - "Host: localhost\r\n" + - "\r\n").getBytes("UTF-8")); - clientOutput.flush(); - return null; - } - }); - - // Application data - record = proxy.readFromClient(); - for (byte b : record.getBytes()) - proxy.flushToServer(50, b); - Assert.assertNull(request.get(5, TimeUnit.SECONDS)); - - // Application data - record = proxy.readFromServer(); - Assert.assertEquals(TLSRecord.Type.APPLICATION, record.getType()); - proxy.flushToClient(record); - - BufferedReader reader = new BufferedReader(new InputStreamReader(client.getInputStream(), "UTF-8")); - String line = reader.readLine(); - Assert.assertNotNull(line); - Assert.assertTrue(line.startsWith("HTTP/1.1 200 ")); - while ((line = reader.readLine()) != null) - { - if (line.trim().length() == 0) - break; - } - - // Check that we did not spin - TimeUnit.MILLISECONDS.sleep(1000); - Assert.assertThat(sslHandles.get(), lessThan(750)); - Assert.assertThat(sslFlushes.get(), lessThan(750)); - // An average of 958 httpParses is seen in standard Oracle JDK's - // An average of 1183 httpParses is seen in OpenJDK JVMs. - Assert.assertThat(httpParses.get(), lessThan(1500)); - - client.close(); - - // Close Alert - record = proxy.readFromClient(); - for (byte b : record.getBytes()) - proxy.flushToServer(50, b); - // Socket close - record = proxy.readFromClient(); - Assert.assertNull(String.valueOf(record), record); - proxy.flushToServer(record); - - // Close Alert - record = proxy.readFromServer(); - proxy.flushToClient(record); - // Socket close - record = proxy.readFromServer(); - Assert.assertNull(String.valueOf(record), record); - proxy.flushToClient(record); - } - - @Test - public void testRequestWithCloseAlertAndShutdown() throws Exception - { - // See next test on why we only run in Linux - Assume.assumeTrue(OS.IS_LINUX); - - final SSLSocket client = newClient(); - - SimpleProxy.AutomaticFlow automaticProxyFlow = proxy.startAutomaticFlow(); - client.startHandshake(); - Assert.assertTrue(automaticProxyFlow.stop(5, TimeUnit.SECONDS)); - - Future request = threadPool.submit(new Callable() - { - public Object call() throws Exception - { - OutputStream clientOutput = client.getOutputStream(); - clientOutput.write(("" + - "GET / HTTP/1.1\r\n" + - "Host: localhost\r\n" + - "\r\n").getBytes("UTF-8")); - clientOutput.flush(); - return null; - } - }); - - // Application data - TLSRecord record = proxy.readFromClient(); - proxy.flushToServer(record); - Assert.assertNull(request.get(5, TimeUnit.SECONDS)); - - client.close(); - - // Close Alert - record = proxy.readFromClient(); - proxy.flushToServer(record); - // Socket close - record = proxy.readFromClient(); - Assert.assertNull(String.valueOf(record), record); - proxy.flushToServer(record); - - // Expect response from server - // SSLSocket is limited and we cannot read the response, but we make sure - // it is application data and not a close alert - record = proxy.readFromServer(); - Assert.assertNotNull(record); - Assert.assertEquals(TLSRecord.Type.APPLICATION, record.getType()); - proxy.flushToClient(record); - - // Close Alert - record = proxy.readFromServer(); - Assert.assertNotNull(record); - Assert.assertEquals(TLSRecord.Type.ALERT, record.getType()); - // We can't forward to the client, its socket is already closed - - // Check that we did not spin - TimeUnit.MILLISECONDS.sleep(500); - Assert.assertThat(sslHandles.get(), lessThan(20)); - Assert.assertThat(sslFlushes.get(), lessThan(20)); - Assert.assertThat(httpParses.get(), lessThan(50)); - - // Socket close - record = proxy.readFromServer(); - Assert.assertNull(String.valueOf(record), record); - proxy.flushToClient(record); - } - - @Test - public void testRequestWithCloseAlert() throws Exception - { - // Currently we are ignoring this test on anything other then linux - // http://tools.ietf.org/html/rfc2246#section-7.2.1 - - // TODO (react to this portion which seems to allow win/mac behavior) - // It is required that the other party respond with a close_notify alert of its own - // and close down the connection immediately, discarding any pending writes. It is not - // required for the initiator of the close to wait for the responding - // close_notify alert before closing the read side of the connection. - Assume.assumeTrue(OS.IS_LINUX); - - final SSLSocket client = newClient(); - - SimpleProxy.AutomaticFlow automaticProxyFlow = proxy.startAutomaticFlow(); - client.startHandshake(); - Assert.assertTrue(automaticProxyFlow.stop(5, TimeUnit.SECONDS)); - - Future request = threadPool.submit(new Callable() - { - public Object call() throws Exception - { - OutputStream clientOutput = client.getOutputStream(); - clientOutput.write(("" + - "GET / HTTP/1.1\r\n" + - "Host: localhost\r\n" + - "\r\n").getBytes("UTF-8")); - clientOutput.flush(); - return null; - } - }); - - // Application data - TLSRecord record = proxy.readFromClient(); - Assert.assertEquals(TLSRecord.Type.APPLICATION, record.getType()); - proxy.flushToServer(record); - Assert.assertNull(request.get(5, TimeUnit.SECONDS)); - - client.close(); - - // Close Alert - record = proxy.readFromClient(); - Assert.assertEquals(TLSRecord.Type.ALERT, record.getType()); - proxy.flushToServer(record); - - // Do not close the raw socket yet - - // Expect response from server - // SSLSocket is limited and we cannot read the response, but we make sure - // it is application data and not a close alert - record = proxy.readFromServer(); - Assert.assertNotNull(record); - Assert.assertEquals(TLSRecord.Type.APPLICATION, record.getType()); - proxy.flushToClient(record); - - // Close Alert - record = proxy.readFromServer(); - Assert.assertNotNull(record); - Assert.assertEquals(TLSRecord.Type.ALERT, record.getType()); - // We can't forward to the client, its socket is already closed - - // Check that we did not spin - TimeUnit.MILLISECONDS.sleep(500); - Assert.assertThat(sslHandles.get(), lessThan(20)); - Assert.assertThat(sslFlushes.get(), lessThan(20)); - Assert.assertThat(httpParses.get(), lessThan(50)); - - // Socket close - record = proxy.readFromClient(); - Assert.assertNull(String.valueOf(record), record); - proxy.flushToServer(record); - - // Socket close - record = proxy.readFromServer(); - Assert.assertNull(String.valueOf(record), record); - proxy.flushToClient(record); - } - - @Test - public void testRequestWithRawClose() throws Exception - { - final SSLSocket client = newClient(); - - SimpleProxy.AutomaticFlow automaticProxyFlow = proxy.startAutomaticFlow(); - client.startHandshake(); - Assert.assertTrue(automaticProxyFlow.stop(5, TimeUnit.SECONDS)); - - Future request = threadPool.submit(new Callable() - { - public Object call() throws Exception - { - OutputStream clientOutput = client.getOutputStream(); - clientOutput.write(("" + - "GET / HTTP/1.1\r\n" + - "Host: localhost\r\n" + - "\r\n").getBytes("UTF-8")); - clientOutput.flush(); - return null; - } - }); - - // Application data - TLSRecord record = proxy.readFromClient(); - Assert.assertEquals(TLSRecord.Type.APPLICATION, record.getType()); - proxy.flushToServer(record); - Assert.assertNull(request.get(5, TimeUnit.SECONDS)); - - // Application data - record = proxy.readFromServer(); - Assert.assertEquals(TLSRecord.Type.APPLICATION, record.getType()); - proxy.flushToClient(record); - - // Close the raw socket, this generates a truncation attack - proxy.flushToServer((TLSRecord)null); - - // Expect raw close from server - record = proxy.readFromServer(); - Assert.assertNull(String.valueOf(record), record); - proxy.flushToClient(record); - - // Check that we did not spin - TimeUnit.MILLISECONDS.sleep(500); - Assert.assertThat(sslHandles.get(), lessThan(20)); - Assert.assertThat(sslFlushes.get(), lessThan(20)); - Assert.assertThat(httpParses.get(), lessThan(50)); - - client.close(); - } - - @Test - public void testRequestWithBigContentWriteBlockedThenReset() throws Exception - { - final SSLSocket client = newClient(); - - SimpleProxy.AutomaticFlow automaticProxyFlow = proxy.startAutomaticFlow(); - client.startHandshake(); - Assert.assertTrue(automaticProxyFlow.stop(5, TimeUnit.SECONDS)); - - byte[] data = new byte[128 * 1024]; - Arrays.fill(data, (byte)'X'); - final String content = new String(data, "UTF-8"); - Future request = threadPool.submit(new Callable() - { - public Object call() throws Exception - { - OutputStream clientOutput = client.getOutputStream(); - clientOutput.write(("" + - "GET /echo HTTP/1.1\r\n" + - "Host: localhost\r\n" + - "Content-Length: " + content.length() + "\r\n" + - "\r\n" + - content).getBytes("UTF-8")); - clientOutput.flush(); - return null; - } - }); - - // Nine TLSRecords will be generated for the request - for (int i = 0; i < 9; ++i) - { - // Application data - TLSRecord record = proxy.readFromClient(); - Assert.assertEquals(TLSRecord.Type.APPLICATION, record.getType()); - proxy.flushToServer(record, 0); - } - Assert.assertNull(request.get(5, TimeUnit.SECONDS)); - - // We asked the server to echo back the data we sent - // but we do not read it, thus causing a write interest - // on the server. - // However, we then simulate that the client resets the - // connection, and this will cause an exception in the - // server that is trying to write the data - - TimeUnit.MILLISECONDS.sleep(500); - proxy.sendRSTToServer(); - - // Wait a while to detect spinning - TimeUnit.MILLISECONDS.sleep(500); - Assert.assertThat(sslHandles.get(), lessThan(20)); - Assert.assertThat(sslFlushes.get(), lessThan(20)); - Assert.assertThat(httpParses.get(), lessThan(50)); - - client.close(); - } - - @Test - public void testRequestWithBigContentReadBlockedThenReset() throws Exception - { - final SSLSocket client = newClient(); - - SimpleProxy.AutomaticFlow automaticProxyFlow = proxy.startAutomaticFlow(); - client.startHandshake(); - Assert.assertTrue(automaticProxyFlow.stop(5, TimeUnit.SECONDS)); - - byte[] data = new byte[128 * 1024]; - Arrays.fill(data, (byte)'X'); - final String content = new String(data, "UTF-8"); - Future request = threadPool.submit(new Callable() - { - public Object call() throws Exception - { - OutputStream clientOutput = client.getOutputStream(); - clientOutput.write(("" + - "GET /echo_suppress_exception HTTP/1.1\r\n" + - "Host: localhost\r\n" + - "Content-Length: " + content.length() + "\r\n" + - "\r\n" + - content).getBytes("UTF-8")); - clientOutput.flush(); - return null; - } - }); - - // Nine TLSRecords will be generated for the request, - // but we write only 5 of them, so the server goes in read blocked state - for (int i = 0; i < 5; ++i) - { - // Application data - TLSRecord record = proxy.readFromClient(); - Assert.assertEquals(TLSRecord.Type.APPLICATION, record.getType()); - proxy.flushToServer(record, 0); - } - Assert.assertNull(request.get(5, TimeUnit.SECONDS)); - - // The server should be read blocked, and we send a RST - TimeUnit.MILLISECONDS.sleep(500); - proxy.sendRSTToServer(); - - // Wait a while to detect spinning - TimeUnit.MILLISECONDS.sleep(500); - Assert.assertThat(sslHandles.get(), lessThan(20)); - Assert.assertThat(sslFlushes.get(), lessThan(20)); - Assert.assertThat(httpParses.get(), lessThan(50)); - - client.close(); - } - - @Test - public void testRequestWithCloseAlertWithSplitBoundary() throws Exception - { - if ( !OS.IS_LINUX ) - { - // currently we are ignoring this test on anything other then linux - - //http://tools.ietf.org/html/rfc2246#section-7.2.1 - - // TODO (react to this portion which seems to allow win/mac behavior) - //It is required that the other party respond with a close_notify alert of its own - //and close down the connection immediately, discarding any pending writes. It is not - //required for the initiator of the close to wait for the responding - //close_notify alert before closing the read side of the connection. - return; - } - - final SSLSocket client = newClient(); - - SimpleProxy.AutomaticFlow automaticProxyFlow = proxy.startAutomaticFlow(); - client.startHandshake(); - Assert.assertTrue(automaticProxyFlow.stop(5, TimeUnit.SECONDS)); - - Future request = threadPool.submit(new Callable() - { - public Object call() throws Exception - { - OutputStream clientOutput = client.getOutputStream(); - clientOutput.write(("" + - "GET / HTTP/1.1\r\n" + - "Host: localhost\r\n" + - "\r\n").getBytes("UTF-8")); - clientOutput.flush(); - return null; - } - }); - - // Application data - TLSRecord dataRecord = proxy.readFromClient(); - Assert.assertNull(request.get(5, TimeUnit.SECONDS)); - - client.close(); - - // Close Alert - TLSRecord closeRecord = proxy.readFromClient(); - - // Send request and half of the close alert bytes - byte[] dataBytes = dataRecord.getBytes(); - byte[] closeBytes = closeRecord.getBytes(); - byte[] bytes = new byte[dataBytes.length + closeBytes.length / 2]; - System.arraycopy(dataBytes, 0, bytes, 0, dataBytes.length); - System.arraycopy(closeBytes, 0, bytes, dataBytes.length, closeBytes.length / 2); - proxy.flushToServer(100, bytes); - - bytes = new byte[closeBytes.length - closeBytes.length / 2]; - System.arraycopy(closeBytes, closeBytes.length / 2, bytes, 0, bytes.length); - proxy.flushToServer(100, bytes); - - // Do not close the raw socket yet - - // Expect response from server - // SSLSocket is limited and we cannot read the response, but we make sure - // it is application data and not a close alert - TLSRecord record = proxy.readFromServer(); - Assert.assertNotNull(record); - Assert.assertEquals(TLSRecord.Type.APPLICATION, record.getType()); - proxy.flushToClient(record); - - // Close Alert - record = proxy.readFromServer(); - Assert.assertNotNull(record); - Assert.assertEquals(TLSRecord.Type.ALERT, record.getType()); - // We can't forward to the client, its socket is already closed - - // Check that we did not spin - TimeUnit.MILLISECONDS.sleep(500); - Assert.assertThat(sslHandles.get(), lessThan(20)); - Assert.assertThat(sslFlushes.get(), lessThan(20)); - Assert.assertThat(httpParses.get(), lessThan(50)); - - // Socket close - record = proxy.readFromClient(); - Assert.assertNull(String.valueOf(record), record); - proxy.flushToServer(record); - - // Socket close - record = proxy.readFromServer(); - Assert.assertNull(String.valueOf(record), record); - proxy.flushToClient(record); - } - - @Test - public void testRequestWithContentWithSplitBoundary() throws Exception - { - final SSLSocket client = newClient(); - - SimpleProxy.AutomaticFlow automaticProxyFlow = proxy.startAutomaticFlow(); - client.startHandshake(); - Assert.assertTrue(automaticProxyFlow.stop(5, TimeUnit.SECONDS)); - - final String content = "0123456789ABCDEF"; - - Future request = threadPool.submit(new Callable() - { - public Object call() throws Exception - { - OutputStream clientOutput = client.getOutputStream(); - clientOutput.write(("" + - "POST / HTTP/1.1\r\n" + - "Host: localhost\r\n" + - "Content-Type: text/plain\r\n" + - "Content-Length: " + content.length() + "\r\n" + - "\r\n" + - content).getBytes("UTF-8")); - clientOutput.flush(); - return null; - } - }); - - // Application data - TLSRecord record = proxy.readFromClient(); - Assert.assertNull(request.get(5, TimeUnit.SECONDS)); - byte[] chunk1 = new byte[2 * record.getBytes().length / 3]; - System.arraycopy(record.getBytes(), 0, chunk1, 0, chunk1.length); - proxy.flushToServer(100, chunk1); - - byte[] chunk2 = new byte[record.getBytes().length - chunk1.length]; - System.arraycopy(record.getBytes(), chunk1.length, chunk2, 0, chunk2.length); - proxy.flushToServer(100, chunk2); - - record = proxy.readFromServer(); - Assert.assertEquals(TLSRecord.Type.APPLICATION, record.getType()); - proxy.flushToClient(record); - - BufferedReader reader = new BufferedReader(new InputStreamReader(client.getInputStream(), "UTF-8")); - String line = reader.readLine(); - Assert.assertNotNull(line); - Assert.assertTrue(line.startsWith("HTTP/1.1 200 ")); - while ((line = reader.readLine()) != null) - { - if (line.trim().length() == 0) - break; - } - - // Check that we did not spin - TimeUnit.MILLISECONDS.sleep(500); - Assert.assertThat(sslHandles.get(), lessThan(20)); - Assert.assertThat(sslFlushes.get(), lessThan(20)); - Assert.assertThat(httpParses.get(), lessThan(50)); - - closeClient(client); - } - - @Test - public void testRequestWithBigContentWithSplitBoundary() throws Exception - { - final SSLSocket client = newClient(); - - SimpleProxy.AutomaticFlow automaticProxyFlow = proxy.startAutomaticFlow(); - client.startHandshake(); - Assert.assertTrue(automaticProxyFlow.stop(5, TimeUnit.SECONDS)); - - // Use a content that is larger than the TLS record which is 2^14 (around 16k) - byte[] data = new byte[128 * 1024]; - Arrays.fill(data, (byte)'X'); - final String content = new String(data, "UTF-8"); - - Future request = threadPool.submit(new Callable() - { - public Object call() throws Exception - { - OutputStream clientOutput = client.getOutputStream(); - clientOutput.write(("" + - "POST / HTTP/1.1\r\n" + - "Host: localhost\r\n" + - "Content-Type: text/plain\r\n" + - "Content-Length: " + content.length() + "\r\n" + - "\r\n" + - content).getBytes("UTF-8")); - clientOutput.flush(); - return null; - } - }); - - // Nine TLSRecords will be generated for the request - for (int i = 0; i < 9; ++i) - { - // Application data - TLSRecord record = proxy.readFromClient(); - byte[] bytes = record.getBytes(); - byte[] chunk1 = new byte[2 * bytes.length / 3]; - System.arraycopy(bytes, 0, chunk1, 0, chunk1.length); - byte[] chunk2 = new byte[bytes.length - chunk1.length]; - System.arraycopy(bytes, chunk1.length, chunk2, 0, chunk2.length); - proxy.flushToServer(100, chunk1); - proxy.flushToServer(100, chunk2); - } - - // Check that we did not spin - TimeUnit.MILLISECONDS.sleep(500); - Assert.assertThat(sslHandles.get(), lessThan(20)); - Assert.assertThat(sslFlushes.get(), lessThan(20)); - Assert.assertThat(httpParses.get(), lessThan(150)); - - Assert.assertNull(request.get(5, TimeUnit.SECONDS)); - - TLSRecord record = proxy.readFromServer(); - Assert.assertEquals(TLSRecord.Type.APPLICATION, record.getType()); - proxy.flushToClient(record); - - BufferedReader reader = new BufferedReader(new InputStreamReader(client.getInputStream(), "UTF-8")); - String line = reader.readLine(); - Assert.assertNotNull(line); - Assert.assertTrue(line.startsWith("HTTP/1.1 200 ")); - while ((line = reader.readLine()) != null) - { - if (line.trim().length() == 0) - break; - } - - // Check that we did not spin - TimeUnit.MILLISECONDS.sleep(500); - Assert.assertThat(sslHandles.get(), lessThan(20)); - Assert.assertThat(sslFlushes.get(), lessThan(20)); - Assert.assertThat(httpParses.get(), lessThan(150)); - - closeClient(client); - } - - @Test - public void testRequestWithBigContentWithRenegotiationInMiddleOfContent() throws Exception - { - assumeJavaVersionSupportsTLSRenegotiations(); - - final SSLSocket client = newClient(); - final OutputStream clientOutput = client.getOutputStream(); - - SimpleProxy.AutomaticFlow automaticProxyFlow = proxy.startAutomaticFlow(); - client.startHandshake(); - Assert.assertTrue(automaticProxyFlow.stop(5, TimeUnit.SECONDS)); - - // Use a content that is larger than the TLS record which is 2^14 (around 16k) - byte[] data1 = new byte[80 * 1024]; - Arrays.fill(data1, (byte)'X'); - String content1 = new String(data1, "UTF-8"); - byte[] data2 = new byte[48 * 1024]; - Arrays.fill(data2, (byte)'Y'); - final String content2 = new String(data2, "UTF-8"); - - // Write only part of the body - automaticProxyFlow = proxy.startAutomaticFlow(); - clientOutput.write(("" + - "POST / HTTP/1.1\r\n" + - "Host: localhost\r\n" + - "Content-Type: text/plain\r\n" + - "Content-Length: " + (content1.length() + content2.length()) + "\r\n" + - "\r\n" + - content1).getBytes("UTF-8")); - clientOutput.flush(); - Assert.assertTrue(automaticProxyFlow.stop(5, TimeUnit.SECONDS)); - - // Renegotiate - Future renegotiation = threadPool.submit(new Callable() - { - public Object call() throws Exception - { - client.startHandshake(); - return null; - } - }); - - // Renegotiation Handshake - TLSRecord record = proxy.readFromClient(); - Assert.assertEquals(TLSRecord.Type.HANDSHAKE, record.getType()); - proxy.flushToServer(record); - - // Renegotiation Handshake - record = proxy.readFromServer(); - Assert.assertEquals(TLSRecord.Type.HANDSHAKE, record.getType()); - proxy.flushToClient(record); - - // Renegotiation Change Cipher - record = proxy.readFromServer(); - Assert.assertEquals(TLSRecord.Type.CHANGE_CIPHER_SPEC, record.getType()); - proxy.flushToClient(record); - - // Renegotiation Handshake - record = proxy.readFromServer(); - Assert.assertEquals(TLSRecord.Type.HANDSHAKE, record.getType()); - proxy.flushToClient(record); - - // Trigger a read to have the client write the final renegotiation steps - client.setSoTimeout(100); - try - { - client.getInputStream().read(); - Assert.fail(); - } - catch (SocketTimeoutException x) - { - // Expected - } - - // Renegotiation Change Cipher - record = proxy.readFromClient(); - Assert.assertEquals(TLSRecord.Type.CHANGE_CIPHER_SPEC, record.getType()); - proxy.flushToServer(record); - - // Renegotiation Handshake - record = proxy.readFromClient(); - Assert.assertEquals(TLSRecord.Type.HANDSHAKE, record.getType()); - proxy.flushToServer(record); - - Assert.assertNull(renegotiation.get(5, TimeUnit.SECONDS)); - - // Write the rest of the request - Future request = threadPool.submit(new Callable() - { - public Object call() throws Exception - { - clientOutput.write(content2.getBytes("UTF-8")); - clientOutput.flush(); - return null; - } - }); - - // Three TLSRecords will be generated for the remainder of the content - for (int i = 0; i < 3; ++i) - { - // Application data - record = proxy.readFromClient(); - proxy.flushToServer(record); - } - - Assert.assertNull(request.get(5, TimeUnit.SECONDS)); - - // Read response - // Application Data - record = proxy.readFromServer(); - Assert.assertEquals(TLSRecord.Type.APPLICATION, record.getType()); - proxy.flushToClient(record); - - BufferedReader reader = new BufferedReader(new InputStreamReader(client.getInputStream(), "UTF-8")); - String line = reader.readLine(); - Assert.assertNotNull(line); - Assert.assertTrue(line.startsWith("HTTP/1.1 200 ")); - while ((line = reader.readLine()) != null) - { - if (line.trim().length() == 0) - break; - } - - // Check that we did not spin - TimeUnit.MILLISECONDS.sleep(500); - Assert.assertThat(sslHandles.get(), lessThan(20)); - Assert.assertThat(sslFlushes.get(), lessThan(20)); - Assert.assertThat(httpParses.get(), lessThan(50)); - - closeClient(client); - } - - @Test - public void testRequestWithBigContentWithRenegotiationInMiddleOfContentWithSplitBoundary() throws Exception - { - assumeJavaVersionSupportsTLSRenegotiations(); - - final SSLSocket client = newClient(); - final OutputStream clientOutput = client.getOutputStream(); - - SimpleProxy.AutomaticFlow automaticProxyFlow = proxy.startAutomaticFlow(); - client.startHandshake(); - Assert.assertTrue(automaticProxyFlow.stop(5, TimeUnit.SECONDS)); - - // Use a content that is larger than the TLS record which is 2^14 (around 16k) - byte[] data1 = new byte[80 * 1024]; - Arrays.fill(data1, (byte)'X'); - String content1 = new String(data1, "UTF-8"); - byte[] data2 = new byte[48 * 1024]; - Arrays.fill(data2, (byte)'Y'); - final String content2 = new String(data2, "UTF-8"); - - // Write only part of the body - automaticProxyFlow = proxy.startAutomaticFlow(); - clientOutput.write(("" + - "POST / HTTP/1.1\r\n" + - "Host: localhost\r\n" + - "Content-Type: text/plain\r\n" + - "Content-Length: " + (content1.length() + content2.length()) + "\r\n" + - "\r\n" + - content1).getBytes("UTF-8")); - clientOutput.flush(); - Assert.assertTrue(automaticProxyFlow.stop(5, TimeUnit.SECONDS)); - - // Renegotiate - Future renegotiation = threadPool.submit(new Callable() - { - public Object call() throws Exception - { - client.startHandshake(); - return null; - } - }); - - // Renegotiation Handshake - TLSRecord record = proxy.readFromClient(); - Assert.assertEquals(TLSRecord.Type.HANDSHAKE, record.getType()); - byte[] bytes = record.getBytes(); - byte[] chunk1 = new byte[2 * bytes.length / 3]; - System.arraycopy(bytes, 0, chunk1, 0, chunk1.length); - byte[] chunk2 = new byte[bytes.length - chunk1.length]; - System.arraycopy(bytes, chunk1.length, chunk2, 0, chunk2.length); - proxy.flushToServer(100, chunk1); - proxy.flushToServer(100, chunk2); - - // Renegotiation Handshake - record = proxy.readFromServer(); - Assert.assertEquals(TLSRecord.Type.HANDSHAKE, record.getType()); - proxy.flushToClient(record); - - // Renegotiation Change Cipher - record = proxy.readFromServer(); - Assert.assertEquals(TLSRecord.Type.CHANGE_CIPHER_SPEC, record.getType()); - proxy.flushToClient(record); - - // Renegotiation Handshake - record = proxy.readFromServer(); - Assert.assertEquals(TLSRecord.Type.HANDSHAKE, record.getType()); - proxy.flushToClient(record); - - // Trigger a read to have the client write the final renegotiation steps - client.setSoTimeout(100); - try - { - client.getInputStream().read(); - Assert.fail(); - } - catch (SocketTimeoutException x) - { - // Expected - } - - // Renegotiation Change Cipher - record = proxy.readFromClient(); - Assert.assertEquals(TLSRecord.Type.CHANGE_CIPHER_SPEC, record.getType()); - bytes = record.getBytes(); - chunk1 = new byte[2 * bytes.length / 3]; - System.arraycopy(bytes, 0, chunk1, 0, chunk1.length); - chunk2 = new byte[bytes.length - chunk1.length]; - System.arraycopy(bytes, chunk1.length, chunk2, 0, chunk2.length); - proxy.flushToServer(100, chunk1); - proxy.flushToServer(100, chunk2); - - // Renegotiation Handshake - record = proxy.readFromClient(); - Assert.assertEquals(TLSRecord.Type.HANDSHAKE, record.getType()); - bytes = record.getBytes(); - chunk1 = new byte[2 * bytes.length / 3]; - System.arraycopy(bytes, 0, chunk1, 0, chunk1.length); - chunk2 = new byte[bytes.length - chunk1.length]; - System.arraycopy(bytes, chunk1.length, chunk2, 0, chunk2.length); - proxy.flushToServer(100, chunk1); - // Do not write the second chunk now, but merge it with content, see below - - Assert.assertNull(renegotiation.get(5, TimeUnit.SECONDS)); - - // Write the rest of the request - Future request = threadPool.submit(new Callable() - { - public Object call() throws Exception - { - clientOutput.write(content2.getBytes("UTF-8")); - clientOutput.flush(); - return null; - } - }); - - // Three TLSRecords will be generated for the remainder of the content - // Merge the last chunk of the renegotiation with the first data record - record = proxy.readFromClient(); - Assert.assertEquals(TLSRecord.Type.APPLICATION, record.getType()); - byte[] dataBytes = record.getBytes(); - byte[] mergedBytes = new byte[chunk2.length + dataBytes.length]; - System.arraycopy(chunk2, 0, mergedBytes, 0, chunk2.length); - System.arraycopy(dataBytes, 0, mergedBytes, chunk2.length, dataBytes.length); - proxy.flushToServer(100, mergedBytes); - // Write the remaining 2 TLS records - for (int i = 0; i < 2; ++i) - { - // Application data - record = proxy.readFromClient(); - Assert.assertEquals(TLSRecord.Type.APPLICATION, record.getType()); - proxy.flushToServer(record); - } - - Assert.assertNull(request.get(5, TimeUnit.SECONDS)); - - // Read response - // Application Data - record = proxy.readFromServer(); - Assert.assertEquals(TLSRecord.Type.APPLICATION, record.getType()); - proxy.flushToClient(record); - - BufferedReader reader = new BufferedReader(new InputStreamReader(client.getInputStream(), "UTF-8")); - String line = reader.readLine(); - Assert.assertNotNull(line); - Assert.assertTrue(line.startsWith("HTTP/1.1 200 ")); - while ((line = reader.readLine()) != null) - { - if (line.trim().length() == 0) - break; - } - - // Check that we did not spin - TimeUnit.MILLISECONDS.sleep(500); - Assert.assertThat(sslHandles.get(), lessThan(20)); - Assert.assertThat(sslFlushes.get(), lessThan(20)); - Assert.assertThat(httpParses.get(), lessThan(100)); - - closeClient(client); - } - - @Test - public void testServerShutdownOutputClientDoesNotCloseServerCloses() throws Exception - { - final SSLSocket client = newClient(); - final OutputStream clientOutput = client.getOutputStream(); - - SimpleProxy.AutomaticFlow automaticProxyFlow = proxy.startAutomaticFlow(); - client.startHandshake(); - Assert.assertTrue(automaticProxyFlow.stop(5, TimeUnit.SECONDS)); - - byte[] data = new byte[3 * 1024]; - Arrays.fill(data, (byte)'Y'); - String content = new String(data, "UTF-8"); - automaticProxyFlow = proxy.startAutomaticFlow(); - clientOutput.write(("" + - "POST / HTTP/1.1\r\n" + - "Host: localhost\r\n" + - "Content-Type: text/plain\r\n" + - "Content-Length: " + content.length() + "\r\n" + - "Connection: close\r\n" + - "\r\n" + - content).getBytes("UTF-8")); - clientOutput.flush(); - - BufferedReader reader = new BufferedReader(new InputStreamReader(client.getInputStream(), "UTF-8")); - String line = reader.readLine(); - Assert.assertNotNull(line); - Assert.assertTrue(line.startsWith("HTTP/1.1 200 ")); - while ((line = reader.readLine()) != null) - { - if (line.trim().length() == 0) - break; - } - Assert.assertTrue(automaticProxyFlow.stop(5, TimeUnit.SECONDS)); - - // Check client is at EOF - Assert.assertEquals(-1,client.getInputStream().read()); - - // Client should close the socket, but let's hold it open. - - // Check that we did not spin - TimeUnit.MILLISECONDS.sleep(500); - Assert.assertThat(sslHandles.get(), lessThan(20)); - Assert.assertThat(sslFlushes.get(), lessThan(20)); - Assert.assertThat(httpParses.get(), lessThan(50)); - - // The server has shutdown the output since the client sent a Connection: close - // but the client does not close, so the server must idle timeout the endPoint. - - TimeUnit.MILLISECONDS.sleep(idleTimeout + idleTimeout/2); - - Assert.assertFalse(serverEndPoint.get().isOpen()); - } - - @Test - public void testPlainText() throws Exception - { - final SSLSocket client = newClient(); - - threadPool.submit(new Callable() - { - public Object call() throws Exception - { - client.startHandshake(); - return null; - } - }); - - // Instead of passing the Client Hello, we simulate plain text was passed in - proxy.flushToServer(0, "GET / HTTP/1.1\r\n".getBytes("UTF-8")); - - // We expect that the server closes the connection immediately - TLSRecord record = proxy.readFromServer(); - Assert.assertNull(String.valueOf(record), record); - - // Check that we did not spin - TimeUnit.MILLISECONDS.sleep(500); - Assert.assertThat(sslHandles.get(), lessThan(20)); - Assert.assertThat(sslFlushes.get(), lessThan(20)); - Assert.assertThat(httpParses.get(), lessThan(50)); - - client.close(); - } - - @Test - public void testRequestConcurrentWithIdleExpiration() throws Exception - { - final SSLSocket client = newClient(); - final OutputStream clientOutput = client.getOutputStream(); - final CountDownLatch latch = new CountDownLatch(1); - - idleHook = new Runnable() - { - public void run() - { - if (latch.getCount()==0) - return; - try - { - // Send request - clientOutput.write(("" + - "GET / HTTP/1.1\r\n" + - "Host: localhost\r\n" + - "\r\n").getBytes("UTF-8")); - clientOutput.flush(); - latch.countDown(); - } - catch (Exception x) - { - // Latch won't trigger and test will fail - x.printStackTrace(); - } - } - }; - - SimpleProxy.AutomaticFlow automaticProxyFlow = proxy.startAutomaticFlow(); - client.startHandshake(); - Assert.assertTrue(automaticProxyFlow.stop(5, TimeUnit.SECONDS)); - - Assert.assertTrue(latch.await(idleTimeout * 2, TimeUnit.MILLISECONDS)); - - // Be sure that the server sent a SSL close alert - TLSRecord record = proxy.readFromServer(); - Assert.assertNotNull(record); - Assert.assertEquals(TLSRecord.Type.ALERT, record.getType()); - - // Write the request to the server, to simulate a request - // concurrent with the SSL close alert - record = proxy.readFromClient(); - Assert.assertEquals(TLSRecord.Type.APPLICATION, record.getType()); - proxy.flushToServer(record, 0); - - // Check that we did not spin - TimeUnit.MILLISECONDS.sleep(500); - Assert.assertThat(sslHandles.get(), lessThan(20)); - Assert.assertThat(sslFlushes.get(), lessThan(20)); - Assert.assertThat(httpParses.get(), lessThan(50)); - - //System.err.println(((Dumpable)server.getConnectors()[0]).dump()); - Assert.assertThat(((Dumpable)server.getConnectors()[0]).dump(),containsString("SCEP@")); - - completeClose(client); - - TimeUnit.MILLISECONDS.sleep(200); - //System.err.println(((Dumpable)server.getConnectors()[0]).dump()); - Assert.assertThat(((Dumpable)server.getConnectors()[0]).dump(),not(containsString("SCEP@"))); - - } -/* - @Test - public void testRequestWriteBlockedWithPipelinedRequest() throws Exception - { - final SSLSocket client = newClient(); - final OutputStream clientOutput = client.getOutputStream(); - - SimpleProxy.AutomaticFlow automaticProxyFlow = proxy.startAutomaticFlow(); - client.startHandshake(); - Assert.assertTrue(automaticProxyFlow.stop(5, TimeUnit.SECONDS)); - - byte[] data = new byte[128 * 1024]; - Arrays.fill(data, (byte)'X'); - final String content = new String(data, "UTF-8"); - Future request = threadPool.submit(new Callable() - { - public Object call() throws Exception - { - clientOutput.write(("" + - "POST /echo HTTP/1.1\r\n" + - "Host: localhost\r\n" + - "Content-Length: " + content.length() + "\r\n" + - "\r\n" + - content).getBytes("UTF-8")); - clientOutput.flush(); - return null; - } - }); - - // Nine TLSRecords will be generated for the request - for (int i = 0; i < 9; ++i) - { - // Application data - TLSRecord record = proxy.readFromClient(); - Assert.assertEquals(TLSRecord.Type.APPLICATION, record.getType()); - proxy.flushToServer(record, 0); - } - Assert.assertNull(request.get(5, TimeUnit.SECONDS)); - - // We do not read the big request to cause a write blocked on the server - TimeUnit.MILLISECONDS.sleep(500); - - // Now send the pipelined request - Future pipelined = threadPool.submit(new Callable() - { - public Object call() throws Exception - { - clientOutput.write(("" + - "GET /pipelined HTTP/1.1\r\n" + - "Host: localhost\r\n" + - "\r\n").getBytes("UTF-8")); - clientOutput.flush(); - return null; - } - }); - - TLSRecord record = proxy.readFromClient(); - Assert.assertEquals(TLSRecord.Type.APPLICATION, record.getType()); - proxy.flushToServer(record, 0); - Assert.assertNull(pipelined.get(5, TimeUnit.SECONDS)); - - // Check that we did not spin - TimeUnit.MILLISECONDS.sleep(500); - Assert.assertThat(sslHandles.get(), lessThan(20)); - Assert.assertThat(sslFlushes.get(), lessThan(20)); - Assert.assertThat(httpParses.get(), lessThan(50)); - - Thread.sleep(5000); - -// closeClient(client); - } -*/ - private void assumeJavaVersionSupportsTLSRenegotiations() - { - // Due to a security bug, TLS renegotiations were disabled in JDK 1.6.0_19-21 - // so we check the java version in order to avoid to fail the test. - String javaVersion = System.getProperty("java.version"); - Pattern regexp = Pattern.compile("1\\.6\\.0_(\\d{2})"); - Matcher matcher = regexp.matcher(javaVersion); - if (matcher.matches()) - { - String nano = matcher.group(1); - Assume.assumeThat(Integer.parseInt(nano), greaterThan(21)); - } - } - - private SSLSocket newClient() throws IOException, InterruptedException - { - SSLSocket client = (SSLSocket)sslContext.getSocketFactory().createSocket("localhost", proxy.getPort()); - client.setUseClientMode(true); - Assert.assertTrue(proxy.awaitClient(5, TimeUnit.SECONDS)); - return client; - } - - private void closeClient(SSLSocket client) throws Exception - { - client.close(); - - // Close Alert - TLSRecord record = proxy.readFromClient(); - proxy.flushToServer(record); - // Socket close - record = proxy.readFromClient(); - Assert.assertNull(String.valueOf(record), record); - proxy.flushToServer(record); - - // Close Alert - record = proxy.readFromServer(); - proxy.flushToClient(record); - - // Socket close - record = proxy.readFromServer(); - Assert.assertNull(String.valueOf(record), record); - proxy.flushToClient(record); - } - - private void completeClose(SSLSocket client) throws Exception - { - client.close(); - - // Close Alert - TLSRecord record = proxy.readFromClient(); - proxy.flushToServer(record); - // Socket close - record = proxy.readFromClient(); - Assert.assertNull(String.valueOf(record), record); - proxy.flushToServer(record); - - // Close Alert - record = proxy.readFromServer(); - proxy.flushToClient(record); - - } -} diff --git a/jetty-client-old/src/test/java/org/eclipse/jetty/client/SslBytesTest.java b/jetty-client-old/src/test/java/org/eclipse/jetty/client/SslBytesTest.java deleted file mode 100644 index ec5ebca95e1..00000000000 --- a/jetty-client-old/src/test/java/org/eclipse/jetty/client/SslBytesTest.java +++ /dev/null @@ -1,371 +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.EOFException; -import java.io.IOException; -import java.io.InputStream; -import java.io.InterruptedIOException; -import java.io.OutputStream; -import java.net.ServerSocket; -import java.net.Socket; -import java.net.SocketTimeoutException; -import java.util.HashMap; -import java.util.Map; -import java.util.concurrent.Callable; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Future; -import java.util.concurrent.TimeUnit; - -import org.eclipse.jetty.util.log.Log; -import org.eclipse.jetty.util.log.Logger; -import org.junit.Assert; - -public abstract class SslBytesTest -{ - protected final Logger logger = Log.getLogger(getClass()); - - public static class TLSRecord - { - private final SslBytesServerTest.TLSRecord.Type type; - private final byte[] bytes; - - public TLSRecord(SslBytesServerTest.TLSRecord.Type type, byte[] bytes) - { - this.type = type; - this.bytes = bytes; - } - - public SslBytesServerTest.TLSRecord.Type getType() - { - return type; - } - - public byte[] getBytes() - { - return bytes; - } - - @Override - public String toString() - { - return "TLSRecord [" + type + "] " + bytes.length + " bytes"; - } - - public enum Type - { - CHANGE_CIPHER_SPEC(20), ALERT(21), HANDSHAKE(22), APPLICATION(23); - - private int code; - - private Type(int code) - { - this.code = code; - SslBytesServerTest.TLSRecord.Type.Mapper.codes.put(this.code, this); - } - - public static SslBytesServerTest.TLSRecord.Type from(int code) - { - SslBytesServerTest.TLSRecord.Type result = SslBytesServerTest.TLSRecord.Type.Mapper.codes.get(code); - if (result == null) - throw new IllegalArgumentException("Invalid TLSRecord.Type " + code); - return result; - } - - private static class Mapper - { - private static final Map codes = new HashMap(); - } - } - } - - public class SimpleProxy implements Runnable - { - private final CountDownLatch latch = new CountDownLatch(1); - private final ExecutorService threadPool; - private final String serverHost; - private final int serverPort; - private volatile ServerSocket serverSocket; - private volatile Socket server; - private volatile Socket client; - - public SimpleProxy(ExecutorService threadPool, String serverHost, int serverPort) - { - this.threadPool = threadPool; - this.serverHost = serverHost; - this.serverPort = serverPort; - } - - public void start() throws Exception - { -// serverSocket = new ServerSocket(5871); - serverSocket = new ServerSocket(0); - Thread acceptor = new Thread(this); - acceptor.start(); - server = new Socket(serverHost, serverPort); - } - - public void stop() throws Exception - { - serverSocket.close(); - } - - public void run() - { - try - { - client = serverSocket.accept(); - latch.countDown(); - } - catch (IOException x) - { - x.printStackTrace(); - } - } - - public int getPort() - { - return serverSocket.getLocalPort(); - } - - public TLSRecord readFromClient() throws IOException - { - TLSRecord record = read(client); - logger.debug("C --> P {}", record); - return record; - } - - private TLSRecord read(Socket socket) throws IOException - { - InputStream input = socket.getInputStream(); - int first = -2; - while (true) - { - try - { - socket.setSoTimeout(500); - first = input.read(); - break; - } - catch (SocketTimeoutException x) - { - if (Thread.currentThread().isInterrupted()) - break; - } - } - if (first == -2) - throw new InterruptedIOException(); - else if (first == -1) - return null; - - if (first >= 0x80) - { - // SSLv2 Record - int hiLength = first & 0x3F; - int loLength = input.read(); - int length = (hiLength << 8) + loLength; - byte[] bytes = new byte[2 + length]; - bytes[0] = (byte)first; - bytes[1] = (byte)loLength; - return read(TLSRecord.Type.HANDSHAKE, input, bytes, 2, length); - } - else - { - // TLS Record - int major = input.read(); - int minor = input.read(); - int hiLength = input.read(); - int loLength = input.read(); - int length = (hiLength << 8) + loLength; - byte[] bytes = new byte[1 + 2 + 2 + length]; - bytes[0] = (byte)first; - bytes[1] = (byte)major; - bytes[2] = (byte)minor; - bytes[3] = (byte)hiLength; - bytes[4] = (byte)loLength; - return read(TLSRecord.Type.from(first), input, bytes, 5, length); - } - } - - private TLSRecord read(SslBytesServerTest.TLSRecord.Type type, InputStream input, byte[] bytes, int offset, int length) throws IOException - { - while (length > 0) - { - int read = input.read(bytes, offset, length); - if (read < 0) - throw new EOFException(); - offset += read; - length -= read; - } - return new TLSRecord(type, bytes); - } - - public void flushToServer(TLSRecord record) throws Exception - { - flushToServer(record, 100); - } - - public void flushToServer(TLSRecord record, long sleep) throws Exception - { - if (record == null) - { - server.shutdownOutput(); - if (client.isOutputShutdown()) - { - client.close(); - server.close(); - } - } - else - { - flush(sleep, server, record.getBytes()); - } - } - - public void flushToServer(long sleep, byte... bytes) throws Exception - { - flush(sleep, server, bytes); - } - - private void flush(long sleep, Socket socket, byte... bytes) throws Exception - { - OutputStream output = socket.getOutputStream(); - output.write(bytes); - output.flush(); - if (sleep > 0) - TimeUnit.MILLISECONDS.sleep(sleep); - } - - public TLSRecord readFromServer() throws IOException - { - TLSRecord record = read(server); - logger.debug("P <-- S {}", record); - return record; - } - - public void flushToClient(TLSRecord record) throws Exception - { - if (record == null) - { - client.shutdownOutput(); - if (server.isOutputShutdown()) - { - server.close(); - client.close(); - } - } - else - { - flush(0, client, record.getBytes()); - } - } - - public SslBytesServerTest.SimpleProxy.AutomaticFlow startAutomaticFlow() throws InterruptedException - { - final CountDownLatch startLatch = new CountDownLatch(2); - final CountDownLatch stopLatch = new CountDownLatch(2); - Future clientToServer = threadPool.submit(new Callable() - { - public Object call() throws Exception - { - startLatch.countDown(); - logger.debug("Automatic flow C --> S started"); - try - { - while (true) - { - flushToServer(readFromClient(), 0); - } - } - catch (InterruptedIOException x) - { - return null; - } - finally - { - stopLatch.countDown(); - logger.debug("Automatic flow C --> S finished"); - } - } - }); - Future serverToClient = threadPool.submit(new Callable() - { - public Object call() throws Exception - { - startLatch.countDown(); - logger.debug("Automatic flow C <-- S started"); - try - { - while (true) - { - flushToClient(readFromServer()); - } - } - catch (InterruptedIOException x) - { - return null; - } - finally - { - stopLatch.countDown(); - logger.debug("Automatic flow C <-- S finished"); - } - } - }); - Assert.assertTrue(startLatch.await(5, TimeUnit.SECONDS)); - return new SslBytesServerTest.SimpleProxy.AutomaticFlow(stopLatch, clientToServer, serverToClient); - } - - public boolean awaitClient(int time, TimeUnit unit) throws InterruptedException - { - return latch.await(time, unit); - } - - public void sendRSTToServer() throws IOException - { - // Calling setSoLinger(true, 0) causes close() - // to send a RST instead of a FIN, causing an - // exception to be thrown on the other end - server.setSoLinger(true, 0); - server.close(); - } - - public class AutomaticFlow - { - private final CountDownLatch stopLatch; - private final Future clientToServer; - private final Future serverToClient; - - public AutomaticFlow(CountDownLatch stopLatch, Future clientToServer, Future serverToClient) - { - this.stopLatch = stopLatch; - this.clientToServer = clientToServer; - this.serverToClient = serverToClient; - } - - public boolean stop(long time, TimeUnit unit) throws InterruptedException - { - clientToServer.cancel(true); - serverToClient.cancel(true); - return stopLatch.await(time, unit); - } - } - } -} diff --git a/jetty-client-old/src/test/java/org/eclipse/jetty/client/SslCertSecuredExchangeTest.java b/jetty-client-old/src/test/java/org/eclipse/jetty/client/SslCertSecuredExchangeTest.java deleted file mode 100644 index ff2e325efee..00000000000 --- a/jetty-client-old/src/test/java/org/eclipse/jetty/client/SslCertSecuredExchangeTest.java +++ /dev/null @@ -1,174 +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.security.Principal; -import java.util.Collections; -import java.util.HashSet; -import java.util.Set; - -import javax.security.auth.Subject; - -import org.eclipse.jetty.security.ConstraintMapping; -import org.eclipse.jetty.security.ConstraintSecurityHandler; -import org.eclipse.jetty.security.IdentityService; -import org.eclipse.jetty.security.LoginService; -import org.eclipse.jetty.security.MappedLoginService.KnownUser; -import org.eclipse.jetty.security.authentication.ClientCertAuthenticator; -import org.eclipse.jetty.server.Handler; -import org.eclipse.jetty.server.Server; -import org.eclipse.jetty.server.UserIdentity; -import org.eclipse.jetty.server.handler.HandlerCollection; -import org.eclipse.jetty.server.ssl.SslSelectChannelConnector; -import org.eclipse.jetty.servlet.DefaultServlet; -import org.eclipse.jetty.servlet.ServletContextHandler; -import org.eclipse.jetty.servlet.ServletHolder; -import org.eclipse.jetty.toolchain.test.MavenTestingUtils; -import org.eclipse.jetty.util.security.Constraint; -import org.eclipse.jetty.util.security.Credential; -import org.eclipse.jetty.util.ssl.SslContextFactory; - -public class SslCertSecuredExchangeTest// extends ContentExchangeTest -{ - // certificate is valid until Jan 1, 2050 - private String _keypath = MavenTestingUtils.getTargetFile("test-policy/validation/jetty-valid.keystore").getAbsolutePath(); - private String _trustpath = MavenTestingUtils.getTargetFile("test-policy/validation/jetty-trust.keystore").getAbsolutePath(); - private String _clientpath = MavenTestingUtils.getTargetFile("test-policy/validation/jetty-client.keystore").getAbsolutePath(); - private String _crlpath = MavenTestingUtils.getTargetFile("test-policy/validation/crlfile.pem").getAbsolutePath(); - private String _password = "OBF:1wnl1sw01ta01z0f1tae1svy1wml"; - - protected void configureServer(Server server) - throws Exception - { - //setProtocol("https"); - - SslSelectChannelConnector connector = new SslSelectChannelConnector(); - SslContextFactory cf = connector.getSslContextFactory(); - cf.setValidateCerts(true); - cf.setCrlPath(_crlpath); - cf.setNeedClientAuth(true); - cf.setKeyStorePath(_keypath); - cf.setKeyStorePassword(_password); - cf.setKeyManagerPassword(_password); - cf.setTrustStore(_trustpath); - cf.setTrustStorePassword(_password); - server.addConnector(connector); - - LoginService loginService = new LoginService() { - public String getName() - { - return "MyLoginService"; - } - - public UserIdentity login(String username, Object credentials) - { - return new UserIdentity() { - public Subject getSubject() - { - Subject subject = new Subject(); - subject.getPrincipals().add(getUserPrincipal()); - subject.setReadOnly(); - return subject; - } - - public Principal getUserPrincipal() - { - return new KnownUser("client", new Credential() { - @Override - public boolean check(Object credentials) - { - return true; - } - }); - } - - public boolean isUserInRole(String role, Scope scope) { return true; } - }; - } - - public boolean validate(UserIdentity user) { return true; } - - public IdentityService getIdentityService() { return null; } - - public void setIdentityService(IdentityService service) {} - - public void logout(UserIdentity user) {} - - }; - server.addBean(loginService); - - ConstraintSecurityHandler security = new ConstraintSecurityHandler(); - server.setHandler(security); - - Constraint constraint = new Constraint(); - constraint.setName("auth"); - constraint.setAuthenticate( true ); - constraint.setRoles(new String[]{"user", "admin"}); - - ConstraintMapping mapping = new ConstraintMapping(); - mapping.setPathSpec( "/*" ); - mapping.setConstraint( constraint ); - - Set knownRoles = new HashSet(); - knownRoles.add("user"); - knownRoles.add("admin"); - - security.setConstraintMappings(Collections.singletonList(mapping), knownRoles); - security.setLoginService(loginService); - - ClientCertAuthenticator auth = new ClientCertAuthenticator(); - auth.setValidateCerts(true); - auth.setCrlPath(_crlpath); - auth.setTrustStore(_trustpath); - auth.setTrustStorePassword(_password); - security.setAuthenticator(auth); - security.setAuthMethod(auth.getAuthMethod()); - security.setRealmName("MyRealm"); - security.setStrict(true); - - ServletContextHandler root = new ServletContextHandler(); - root.setContextPath("/"); - // root.setResourceBase(getBasePath()); - ServletHolder servletHolder = new ServletHolder( new DefaultServlet() ); - servletHolder.setInitParameter( "gzip", "true" ); - root.addServlet( servletHolder, "/*" ); - - // Handler handler = new TestHandler(getBasePath()); - - HandlerCollection handlers = new HandlerCollection(); - // handlers.setHandlers(new Handler[]{handler, root}); - security.setHandler(handlers); - } - -// @Override -// protected void configureClient(HttpClient client) throws Exception -// { -// SslContextFactory cf = client.getSslContextFactory(); -// cf.setValidateCerts(true); -// cf.setCrlPath(_crlpath); -// -// cf.setCertAlias("client"); -// cf.setKeyStorePath(_clientpath); -// cf.setKeyStorePassword(_password); -// cf.setKeyManagerPassword(_password); -// -// cf.setTrustStore(_trustpath); -// cf.setTrustStorePassword(_password); -// } -} diff --git a/jetty-client-old/src/test/java/org/eclipse/jetty/client/SslContentExchangeTest.java b/jetty-client-old/src/test/java/org/eclipse/jetty/client/SslContentExchangeTest.java deleted file mode 100644 index d89db9b485c..00000000000 --- a/jetty-client-old/src/test/java/org/eclipse/jetty/client/SslContentExchangeTest.java +++ /dev/null @@ -1,74 +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.File; - -import org.eclipse.jetty.server.Handler; -import org.eclipse.jetty.server.Server; -import org.eclipse.jetty.server.handler.HandlerCollection; -import org.eclipse.jetty.server.ssl.SslSelectChannelConnector; -import org.eclipse.jetty.servlet.DefaultServlet; -import org.eclipse.jetty.servlet.ServletContextHandler; -import org.eclipse.jetty.servlet.ServletHolder; -import org.eclipse.jetty.toolchain.test.MavenTestingUtils; -import org.eclipse.jetty.util.ssl.SslContextFactory; - -public class SslContentExchangeTest - extends ContentExchangeTest -{ - - protected void configureServer(Server server) - throws Exception - { - setProtocol("https"); - - SslSelectChannelConnector connector = new SslSelectChannelConnector(); - File keystore = MavenTestingUtils.getTestResourceFile("keystore"); - SslContextFactory cf = connector.getSslContextFactory(); - cf.setKeyStorePath(keystore.getAbsolutePath()); - cf.setKeyStorePassword("storepwd"); - cf.setKeyManagerPassword("keypwd"); - cf.setSessionCachingEnabled(true); - server.addConnector(connector); - - Handler handler = new TestHandler(getBasePath()); - - ServletContextHandler root = new ServletContextHandler(); - root.setContextPath("/"); - root.setResourceBase(getBasePath()); - 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 ); - } - - @Override - protected void configureClient(HttpClient client) - throws Exception - { - client.setConnectorType(HttpClient.CONNECTOR_SELECT_CHANNEL); - - SslContextFactory cf = client.getSslContextFactory(); - cf.setSessionCachingEnabled(true); - } -} diff --git a/jetty-client-old/src/test/java/org/eclipse/jetty/client/SslHttpExchangeTest.java b/jetty-client-old/src/test/java/org/eclipse/jetty/client/SslHttpExchangeTest.java deleted file mode 100644 index 0aa29202d76..00000000000 --- a/jetty-client-old/src/test/java/org/eclipse/jetty/client/SslHttpExchangeTest.java +++ /dev/null @@ -1,108 +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.hamcrest.Matchers.containsString; -import static org.hamcrest.Matchers.not; - -import org.eclipse.jetty.client.helperClasses.ServerAndClientCreator; -import org.eclipse.jetty.client.helperClasses.SslServerAndClientCreator; -import org.eclipse.jetty.server.Connector; -import org.junit.Assume; -import org.junit.Before; -import org.junit.Test; - -/** - * Functional testing for HttpExchange. - */ -public class SslHttpExchangeTest extends HttpExchangeTest -{ - protected static ServerAndClientCreator serverAndClientCreator = new SslServerAndClientCreator(); - - /* ------------------------------------------------------------ */ - @Before - public void setUpOnce() throws Exception - { - _scheme="https"; - _server = serverAndClientCreator.createServer(); - _httpClient = serverAndClientCreator.createClient(3000L,3500L,2000); - Connector[] connectors = _server.getConnectors(); - _port = connectors[0].getLocalPort(); - } - - /* ------------------------------------------------------------ */ - private void IgnoreTestOnBuggyIBM() - { - // Use Junit 4.x to flag test as ignored if encountering IBM JVM - // Will show up in various junit reports as an ignored test as well. - Assume.assumeThat(System.getProperty("java.vendor").toLowerCase(),not(containsString("ibm"))); - } - - /* ------------------------------------------------------------ */ - /** - * @see org.eclipse.jetty.client.HttpExchangeTest#testGetWithContentExchange() - */ - @Test - @Override - public void testGetWithContentExchange() throws Exception - { - // TODO Resolve problems on IBM JVM https://bugs.eclipse.org/bugs/show_bug.cgi?id=304532 - IgnoreTestOnBuggyIBM(); - super.testGetWithContentExchange(); - } - - /* ------------------------------------------------------------ */ - /** - * @see org.eclipse.jetty.client.HttpExchangeTest#testPerf() - */ - @Test - @Override - public void testPerf() throws Exception - { - // TODO Resolve problems on IBM JVM https://bugs.eclipse.org/bugs/show_bug.cgi?id=304532 - IgnoreTestOnBuggyIBM(); - super.testPerf(); - } - - /* ------------------------------------------------------------ */ - /** - * @see org.eclipse.jetty.client.HttpExchangeTest#testPostWithContentExchange() - */ - @Test - @Override - public void testPostWithContentExchange() throws Exception - { - // TODO Resolve problems on IBM JVM https://bugs.eclipse.org/bugs/show_bug.cgi?id=304532 - IgnoreTestOnBuggyIBM(); - super.testPostWithContentExchange(); - } - - /* ------------------------------------------------------------ */ - /** - * @see org.eclipse.jetty.client.HttpExchangeTest#testReserveConnections() - */ - @Test - @Override - public void testReserveConnections() throws Exception - { - // TODO Resolve problems on IBM JVM https://bugs.eclipse.org/bugs/show_bug.cgi?id=304532 - IgnoreTestOnBuggyIBM(); - super.testReserveConnections(); - } -} diff --git a/jetty-client-old/src/test/java/org/eclipse/jetty/client/SslSecuredContentExchangeTest.java b/jetty-client-old/src/test/java/org/eclipse/jetty/client/SslSecuredContentExchangeTest.java deleted file mode 100644 index 435d9bd0c89..00000000000 --- a/jetty-client-old/src/test/java/org/eclipse/jetty/client/SslSecuredContentExchangeTest.java +++ /dev/null @@ -1,114 +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.File; -import java.util.Collections; -import java.util.HashSet; -import java.util.Set; - -import org.eclipse.jetty.client.security.Realm; -import org.eclipse.jetty.security.ConstraintMapping; -import org.eclipse.jetty.security.ConstraintSecurityHandler; -import org.eclipse.jetty.security.HashLoginService; -import org.eclipse.jetty.security.LoginService; -import org.eclipse.jetty.security.authentication.BasicAuthenticator; -import org.eclipse.jetty.server.Handler; -import org.eclipse.jetty.server.Server; -import org.eclipse.jetty.server.handler.HandlerCollection; -import org.eclipse.jetty.server.ssl.SslSelectChannelConnector; -import org.eclipse.jetty.servlet.DefaultServlet; -import org.eclipse.jetty.servlet.ServletContextHandler; -import org.eclipse.jetty.servlet.ServletHolder; -import org.eclipse.jetty.toolchain.test.MavenTestingUtils; -import org.eclipse.jetty.util.security.Constraint; -import org.eclipse.jetty.util.ssl.SslContextFactory; - -public class SslSecuredContentExchangeTest -extends ContentExchangeTest -{ - protected void configureServer(Server server) - throws Exception - { - setProtocol("https"); - setRealm(new Realm() - { - public String getId() - { - return "MyRealm"; - } - - public String getPrincipal() - { - return "jetty"; - } - - public String getCredentials() - { - return "jetty"; - } - }); - - SslSelectChannelConnector connector = new SslSelectChannelConnector(); - File keystore = MavenTestingUtils.getTestResourceFile("keystore"); - SslContextFactory cf = connector.getSslContextFactory(); - cf.setKeyStorePath(keystore.getAbsolutePath()); - cf.setKeyStorePassword("storepwd"); - cf.setKeyManagerPassword("keypwd"); - server.addConnector(connector); - - File realmPropFile = MavenTestingUtils.getTestResourceFile("realm.properties"); - LoginService loginService = new HashLoginService("MyRealm",realmPropFile.getAbsolutePath()); - server.addBean(loginService); - - ConstraintSecurityHandler security = new ConstraintSecurityHandler(); - server.setHandler(security); - - Constraint constraint = new Constraint(); - constraint.setName("auth"); - constraint.setAuthenticate( true ); - constraint.setRoles(new String[]{"user", "admin"}); - - ConstraintMapping mapping = new ConstraintMapping(); - mapping.setPathSpec( "/*" ); - mapping.setConstraint( constraint ); - - Set knownRoles = new HashSet(); - knownRoles.add("user"); - knownRoles.add("admin"); - - security.setConstraintMappings(Collections.singletonList(mapping), knownRoles); - security.setAuthenticator(new BasicAuthenticator()); - security.setLoginService(loginService); - security.setStrict(false); - - ServletContextHandler root = new ServletContextHandler(); - root.setContextPath("/"); - root.setResourceBase(getBasePath()); - ServletHolder servletHolder = new ServletHolder( new DefaultServlet() ); - servletHolder.setInitParameter( "gzip", "true" ); - root.addServlet( servletHolder, "/*" ); - - Handler handler = new TestHandler(getBasePath()); - - HandlerCollection handlers = new HandlerCollection(); - handlers.setHandlers(new Handler[]{handler, root}); - security.setHandler(handlers); - } -} diff --git a/jetty-client-old/src/test/java/org/eclipse/jetty/client/SslSecuredErrorStatusTest.java b/jetty-client-old/src/test/java/org/eclipse/jetty/client/SslSecuredErrorStatusTest.java deleted file mode 100644 index a916f4b6e12..00000000000 --- a/jetty-client-old/src/test/java/org/eclipse/jetty/client/SslSecuredErrorStatusTest.java +++ /dev/null @@ -1,191 +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.File; -import java.util.Collections; -import java.util.HashSet; -import java.util.Set; - -import org.eclipse.jetty.client.security.Realm; -import org.eclipse.jetty.http.HttpStatus; -import org.eclipse.jetty.security.ConstraintMapping; -import org.eclipse.jetty.security.ConstraintSecurityHandler; -import org.eclipse.jetty.security.HashLoginService; -import org.eclipse.jetty.security.LoginService; -import org.eclipse.jetty.security.authentication.BasicAuthenticator; -import org.eclipse.jetty.server.Handler; -import org.eclipse.jetty.server.Server; -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.toolchain.test.MavenTestingUtils; -import org.eclipse.jetty.util.security.Constraint; -import org.junit.Test; - -/* ------------------------------------------------------------ */ -public class SslSecuredErrorStatusTest - extends ErrorStatusTest -{ - private Realm _testRealm; - private Realm _dummyRealm; - - /* ------------------------------------------------------------ */ - @Test - public void testPutUnauthorized() - throws Exception - { - setRealm(null); - - doPutFail(HttpStatus.UNAUTHORIZED_401); - - setRealm(_testRealm); - } - - /* ------------------------------------------------------------ */ - @Test - public void testPutWrongPassword() - throws Exception - { - setRealm(_dummyRealm); - - doPutFail(HttpStatus.UNAUTHORIZED_401); - - setRealm(_testRealm); - } - - /* ------------------------------------------------------------ */ - @Test - public void testGetUnauthorized() - throws Exception - { - setRealm(null); - - doGetFail(HttpStatus.UNAUTHORIZED_401); - - setRealm(_testRealm); - } - - /* ------------------------------------------------------------ */ - @Test - public void testGetWrongPassword() - throws Exception - { - setRealm(_dummyRealm); - - doGetFail(HttpStatus.UNAUTHORIZED_401); - - setRealm(_testRealm); - } - - /* ------------------------------------------------------------ */ - protected void configureServer(Server server) - throws Exception - { - setProtocol("http"); - - _testRealm = new Realm() - { - /* ------------------------------------------------------------ */ - public String getId() - { - return "MyRealm"; - } - - /* ------------------------------------------------------------ */ - public String getPrincipal() - { - return "jetty"; - } - - /* ------------------------------------------------------------ */ - public String getCredentials() - { - return "jetty"; - } - }; - - _dummyRealm = new Realm() - { - /* ------------------------------------------------------------ */ - public String getId() - { - return "MyRealm"; - } - - /* ------------------------------------------------------------ */ - public String getPrincipal() - { - return "jetty"; - } - - /* ------------------------------------------------------------ */ - public String getCredentials() - { - return "dummy"; - } - }; - - setRealm(_testRealm); - - SelectChannelConnector connector = new SelectChannelConnector(); - server.addConnector(connector); - - File realmPropFile = MavenTestingUtils.getTestResourceFile("realm.properties"); - LoginService loginService = new HashLoginService("MyRealm",realmPropFile.getAbsolutePath()); - server.addBean(loginService); - - ConstraintSecurityHandler security = new ConstraintSecurityHandler(); - server.setHandler(security); - - Constraint constraint = new Constraint(); - constraint.setName("auth"); - constraint.setAuthenticate( true ); - constraint.setRoles(new String[]{"user", "admin"}); - - ConstraintMapping mapping = new ConstraintMapping(); - mapping.setPathSpec( "/*" ); - mapping.setConstraint( constraint ); - - Set knownRoles = new HashSet(); - knownRoles.add("user"); - knownRoles.add("admin"); - - security.setConstraintMappings(Collections.singletonList(mapping), knownRoles); - security.setAuthenticator(new BasicAuthenticator()); - security.setLoginService(loginService); - security.setStrict(false); - - 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}); - security.setHandler(handlers); - } -} diff --git a/jetty-client-old/src/test/java/org/eclipse/jetty/client/SslSecurityListenerTest.java b/jetty-client-old/src/test/java/org/eclipse/jetty/client/SslSecurityListenerTest.java deleted file mode 100644 index c6a991890a0..00000000000 --- a/jetty-client-old/src/test/java/org/eclipse/jetty/client/SslSecurityListenerTest.java +++ /dev/null @@ -1,268 +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.io.InputStream; -import java.io.OutputStream; -import java.util.Arrays; -import java.util.Collections; -import java.util.HashSet; -import java.util.Set; -import java.util.concurrent.CyclicBarrier; -import java.util.concurrent.TimeUnit; - -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -import org.eclipse.jetty.client.security.HashRealmResolver; -import org.eclipse.jetty.client.security.Realm; -import org.eclipse.jetty.http.HttpMethod; -import org.eclipse.jetty.io.EofException; -import org.eclipse.jetty.security.ConstraintMapping; -import org.eclipse.jetty.security.ConstraintSecurityHandler; -import org.eclipse.jetty.security.HashLoginService; -import org.eclipse.jetty.security.LoginService; -import org.eclipse.jetty.security.authentication.BasicAuthenticator; -import org.eclipse.jetty.server.Connector; -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.ssl.SslSocketConnector; -import org.eclipse.jetty.toolchain.test.MavenTestingUtils; -import org.eclipse.jetty.util.log.Log; -import org.eclipse.jetty.util.log.Logger; -import org.eclipse.jetty.util.security.Constraint; -import org.eclipse.jetty.util.ssl.SslContextFactory; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; - -/* ------------------------------------------------------------ */ -/** - * Functional testing. - */ -public class SslSecurityListenerTest -{ - private static final Logger LOG = Log.getLogger(SslSecurityListenerTest.class); - - protected Server _server; - protected int _port; - protected HttpClient _httpClient; - protected Realm _jettyRealm; - protected int _type = HttpClient.CONNECTOR_SOCKET; - private static final String APP_CONTEXT = "localhost /"; - - /* ------------------------------------------------------------ */ - @Before - public void setUp() throws Exception - { - startServer(); - _httpClient = new HttpClient(); - _httpClient.setConnectorType(_type); - _httpClient.setMaxConnectionsPerAddress(2); - _httpClient.start(); - - _jettyRealm = new Realm() - { - /* ------------------------------------------------------------ */ - public String getId() - { - return "MyRealm"; - } - - /* ------------------------------------------------------------ */ - public String getPrincipal() - { - return "jetty"; - } - - /* ------------------------------------------------------------ */ - public String getCredentials() - { - return "jetty"; - } - }; - - HashRealmResolver resolver = new HashRealmResolver(); - resolver.addSecurityRealm(_jettyRealm); - _httpClient.setRealmResolver(resolver); - } - - /* ------------------------------------------------------------ */ - @After - public void tearDown() throws Exception - { - Thread.sleep(1000); - _httpClient.stop(); - Thread.sleep(1000); - stopServer(); - } - - /* ------------------------------------------------------------ */ - @Test - public void testSslGet() throws Exception - { - // TODO Resolve problems on IBM JVM https://bugs.eclipse.org/bugs/show_bug.cgi?id=304532 - if (System.getProperty("java.vendor").toLowerCase().indexOf("ibm")>=0) - { - LOG.warn("Skipped SSL testSslGet on IBM JVM"); - return; - } - - - final CyclicBarrier barrier = new CyclicBarrier(2); - - ContentExchange httpExchange = new ContentExchange(true) - { - /* ------------------------------------------------------------ */ - @Override - protected void onResponseComplete() throws IOException - { - super.onResponseComplete(); - try{barrier.await();}catch(Exception e){} - } - }; - - httpExchange.setURL("https://127.0.0.1:" + _port + "/"); - httpExchange.setMethod(HttpMethod.GET); - - _httpClient.send(httpExchange); - - barrier.await(10000,TimeUnit.SECONDS); - - assertEquals(HttpServletResponse.SC_OK,httpExchange.getResponseStatus()); - - assertTrue(httpExchange.getResponseContent().length()>400); - - } - - /* ------------------------------------------------------------ */ - protected void startServer() throws Exception - { - _server = new Server(); - //SslSelectChannelConnector connector = new SslSelectChannelConnector(); - SslSocketConnector connector = new SslSocketConnector(); - - String keystore = MavenTestingUtils.getTestResourceFile("keystore").getAbsolutePath(); - - connector.setPort(0); - SslContextFactory cf = connector.getSslContextFactory(); - cf.setKeyStorePath(keystore); - cf.setKeyStorePassword("storepwd"); - cf.setKeyManagerPassword("keypwd"); - - _server.setConnectors(new Connector[] - { connector }); - - Constraint constraint = new Constraint(); - constraint.setName("Need User or Admin"); - constraint.setRoles(new String[] - { "user", "admin" }); - constraint.setAuthenticate(true); - - ConstraintMapping cm = new ConstraintMapping(); - cm.setConstraint(constraint); - cm.setPathSpec("/*"); - - File realmPropFile = MavenTestingUtils.getTestResourceFile("realm.properties"); - LoginService loginService = new HashLoginService("MyRealm",realmPropFile.getAbsolutePath()); - _server.addBean(loginService); - - BasicAuthenticator authenticator = new BasicAuthenticator(); - - ConstraintSecurityHandler sh = new ConstraintSecurityHandler(); - sh.setAuthenticator(authenticator); - - Set roles = new HashSet(Arrays.asList(new String[]{"user", "admin"})); - sh.setConstraintMappings(Collections.singletonList(cm), roles); - _server.setHandler(sh); - - Handler testHandler = new AbstractHandler() - { - /* ------------------------------------------------------------ */ - public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException - { - // System.err.println("passed authentication!\n"+((Request)request).getConnection().getRequestFields()); - - baseRequest.setHandled(true); - response.setStatus(200); - response.setContentType("text/plain"); - if (request.getServerName().equals("jetty.eclipse.org")) - { - response.getOutputStream().println("Proxy request: " + request.getRequestURL()); - } - else if (request.getMethod().equalsIgnoreCase("GET")) - { - response.getOutputStream().println(""); - for (int i = 0; i < 100; i++) - { - response.getOutputStream().println(" " + i + ""); - if (i % 20 == 0) - response.getOutputStream().flush(); - } - response.getOutputStream().println(""); - } - else - { - copyStream(request.getInputStream(),response.getOutputStream()); - } - } - }; - - sh.setHandler(testHandler); - - _server.start(); - _port = connector.getLocalPort(); - } - - /* ------------------------------------------------------------ */ - 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(); - } - } - - /* ------------------------------------------------------------ */ - private void stopServer() throws Exception - { - _server.stop(); - } -} diff --git a/jetty-client-old/src/test/java/org/eclipse/jetty/client/SslValidationTestBase.java b/jetty-client-old/src/test/java/org/eclipse/jetty/client/SslValidationTestBase.java deleted file mode 100644 index a0725cde59b..00000000000 --- a/jetty-client-old/src/test/java/org/eclipse/jetty/client/SslValidationTestBase.java +++ /dev/null @@ -1,103 +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.server.Server; -import org.eclipse.jetty.server.ssl.SslConnector; -import org.eclipse.jetty.toolchain.test.MavenTestingUtils; - -public abstract class SslValidationTestBase //extends ContentExchangeTest -{ - protected static Class __klass; - protected static int __konnector; - - // certificate is valid until Jan 1, 2050 - private String _keypath = MavenTestingUtils.getTargetFile("test-policy/validation/jetty-valid.keystore").getAbsolutePath(); - private String _trustpath = MavenTestingUtils.getTargetFile("test-policy/validation/jetty-trust.keystore").getAbsolutePath(); - private String _clientpath = MavenTestingUtils.getTargetFile("test-policy/validation/jetty-client.keystore").getAbsolutePath(); - private String _crlpath = MavenTestingUtils.getTargetFile("test-policy/validation/crlfile.pem").getAbsolutePath(); - private String _password = "OBF:1wnl1sw01ta01z0f1tae1svy1wml"; - - - protected void configureServer(Server server) - throws Exception - { -// setProtocol("https"); -// -// SslContextFactory srvFactory = new SslContextFactory() { -// @Override -// protected KeyStore getKeyStore(InputStream storeStream, String storePath, String storeType, String storeProvider, String storePassword) throws Exception -// { -// return CertificateUtils.getKeyStore(storeStream, storePath, storeType, storeProvider, storePassword); -// } -// -// @Override -// protected Collection loadCRL(String crlPath) throws Exception -// { -// return CertificateUtils.loadCRL(crlPath); -// } -// }; -// srvFactory.setValidateCerts(true); -// srvFactory.setCrlPath(_crlpath); -// srvFactory.setNeedClientAuth(true); -// -// srvFactory.setKeyStorePath(_keypath); -// srvFactory.setKeyStorePassword(_password); -// srvFactory.setKeyManagerPassword(_password); -// -// srvFactory.setTrustStore(_trustpath); -// srvFactory.setTrustStorePassword(_password); -// -// Constructor constructor = __klass.getConstructor(SslContextFactory.class); -// SslConnector connector = constructor.newInstance(srvFactory); -// connector.setIdleTimeout(5000); -// server.addConnector(connector); -// -// Handler handler = new TestHandler(getBasePath()); -// -// ServletContextHandler root = new ServletContextHandler(); -// root.setContextPath("/"); -// root.setResourceBase(getBasePath()); -// 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 ); -// } -// -// @Override -// protected void configureClient(HttpClient client) -// throws Exception -// { -// client.setConnectorType(__konnector); -// -// SslContextFactory cf = client.getSslContextFactory(); -// cf.setValidateCerts(true); -// cf.setCrlPath(_crlpath); -// -// cf.setKeyStorePath(_clientpath); -// cf.setKeyStorePassword(_password); -// cf.setKeyManagerPassword(_password); -// -// cf.setTrustStore(_trustpath); -// cf.setTrustStorePassword(_password); - } -} diff --git a/jetty-client-old/src/test/java/org/eclipse/jetty/client/TimeoutExchangeTest.java b/jetty-client-old/src/test/java/org/eclipse/jetty/client/TimeoutExchangeTest.java deleted file mode 100644 index 991495919e2..00000000000 --- a/jetty-client-old/src/test/java/org/eclipse/jetty/client/TimeoutExchangeTest.java +++ /dev/null @@ -1,379 +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.TimeUnit; - -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -import junit.framework.Assert; - -import org.eclipse.jetty.http.HttpMethod; -import org.eclipse.jetty.http.HttpStatus; -import org.eclipse.jetty.io.ByteArrayBuffer; -import org.eclipse.jetty.server.Connector; -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.nio.SelectChannelConnector; -import org.junit.After; -import org.junit.AfterClass; -import org.junit.BeforeClass; -import org.junit.Test; - -public class TimeoutExchangeTest -{ - private static HttpClient _httpClient; - private static Server _server; - private static int _port; - - @BeforeClass - public static void startServer() throws Exception - { - _server = new Server(); - _server.setGracefulShutdown(500); - Connector _connector = new SelectChannelConnector(); - _server.addConnector(_connector); - Handler handler = new AbstractHandler() - { - public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, - ServletException - { - try - { - Long sleep = Long.parseLong(request.getParameter("sleep")); - Thread.sleep(sleep); - response.setContentType("text/html"); - response.setStatus(HttpServletResponse.SC_OK); - response.getWriter().println("

Hello

"); - baseRequest.setHandled(true); - } - catch (InterruptedException x) - { - Thread.currentThread().interrupt(); - throw new ServletException(x); - } - } - }; - _server.setHandler(handler); - _server.start(); - _port = _connector.getLocalPort(); - } - - @AfterClass - public static void stopServer() throws Exception - { - _server.stop(); - _server.join(); - _server = null; - } - - @After - public void stopClient() throws Exception - { - if (_httpClient != null) - { - _httpClient.stop(); - _httpClient = null; - } - } - - private void startClient(long clientTimeout) throws Exception - { - startClient(clientTimeout, 20000); - } - - private void startClient(long clientTimeout, long maxIdleTimeout) throws Exception - { - _httpClient = new HttpClient(); - _httpClient.setConnectorType(HttpClient.CONNECTOR_SELECT_CHANNEL); - _httpClient.setMaxConnectionsPerAddress(2); - _httpClient.setTimeout(clientTimeout); - _httpClient.setIdleTimeout(maxIdleTimeout); - _httpClient.start(); - } - - @Test - public void testDefaultTimeoutNotExpiring() throws Exception - { - startClient(300); - long serverSleep = 100; - - CustomContentExchange httpExchange = new CustomContentExchange(); - httpExchange.setURL("http://localhost:" + _port + "/?sleep=" + serverSleep); - httpExchange.setMethod(HttpMethod.POST); - httpExchange.setRequestContent(new ByteArrayBuffer("

??

")); - _httpClient.send(httpExchange); - - Assert.assertTrue(httpExchange.getDoneLatch().await(4 * serverSleep, TimeUnit.MILLISECONDS)); - Assert.assertFalse(httpExchange.isTimeoutOccurred()); - Assert.assertTrue(httpExchange.isResponseReceived()); - Assert.assertFalse(httpExchange.isErrorOccurred()); - } - - @Test - public void testDefaultTimeoutExpiring() throws Exception - { - startClient(100); - long serverSleep = 200; - - CustomContentExchange httpExchange = new CustomContentExchange(); - httpExchange.setURL("http://localhost:" + _port + "/?sleep=" + serverSleep); - httpExchange.setMethod(HttpMethod.POST); - httpExchange.setRequestContent(new ByteArrayBuffer("

??

")); - _httpClient.send(httpExchange); - - Assert.assertTrue(httpExchange.getDoneLatch().await(2 * serverSleep, TimeUnit.MILLISECONDS)); - Assert.assertTrue(httpExchange.isTimeoutOccurred()); - Assert.assertFalse(httpExchange.isResponseReceived()); - Assert.assertFalse(httpExchange.isErrorOccurred()); - } - - @Test - public void testExchangeTimeoutNotExpiring() throws Exception - { - startClient(100); - long serverSleep = 200; - long exchangeTimeout = 300; - - CustomContentExchange httpExchange = new CustomContentExchange(); - httpExchange.setURL("http://localhost:" + _port + "/?sleep=" + serverSleep); - httpExchange.setMethod(HttpMethod.POST); - httpExchange.setRequestContent(new ByteArrayBuffer("

??

")); - httpExchange.setTimeout(exchangeTimeout); - _httpClient.send(httpExchange); - - Assert.assertTrue(httpExchange.getDoneLatch().await(2 * exchangeTimeout, TimeUnit.MILLISECONDS)); - Assert.assertFalse(httpExchange.isTimeoutOccurred()); - Assert.assertTrue(httpExchange.isResponseReceived()); - Assert.assertFalse(httpExchange.isErrorOccurred()); - } - - @Test - public void testExchangeTimeoutExpiring() throws Exception - { - startClient(500); - - long serverSleep = 300; - long exchangeTimeout = 100; - - CustomContentExchange httpExchange = new CustomContentExchange(); - httpExchange.setURL("http://localhost:" + _port + "/?sleep=" + serverSleep); - httpExchange.setMethod(HttpMethod.POST); - httpExchange.setRequestContent(new ByteArrayBuffer("

??

")); - httpExchange.setTimeout(exchangeTimeout); - _httpClient.send(httpExchange); - - Assert.assertTrue(httpExchange.getDoneLatch().await(2 * serverSleep, TimeUnit.MILLISECONDS)); - Assert.assertTrue(httpExchange.isTimeoutOccurred()); - Assert.assertFalse(httpExchange.isResponseReceived()); - Assert.assertFalse(httpExchange.isErrorOccurred()); - } - - @Test - public void testDefaultTimeoutWithSmallerIdleTimeoutNotExpiring() throws Exception - { - startClient(500,150); - long serverSleep = 300; - - // The idle timeout is shorter than the default timeout, but will be - // temporarily increased on the endpoint in order for the exchange to complete. - - CustomContentExchange httpExchange = new CustomContentExchange(); - httpExchange.setURL("http://localhost:" + _port + "/?sleep=" + serverSleep); - httpExchange.setMethod(HttpMethod.POST); - httpExchange.setRequestContent(new ByteArrayBuffer("

??

")); - _httpClient.send(httpExchange); - - Assert.assertTrue(httpExchange.getDoneLatch().await(2 * serverSleep, TimeUnit.MILLISECONDS)); - Assert.assertFalse(httpExchange.isTimeoutOccurred()); - Assert.assertTrue(httpExchange.isResponseReceived()); - Assert.assertFalse(httpExchange.isErrorOccurred()); - } - - @Test - public void testExchangeTimeoutWithSmallerIdleTimeoutNotExpiring() throws Exception - { - startClient(500,150); - long serverSleep = 150; - long exchangeTimeout = 300; - - // The idle timeout is shorter than the default timeout, but will be - // temporarily increased on the endpoint in order for the exchange to complete. - - CustomContentExchange httpExchange = new CustomContentExchange(); - httpExchange.setURL("http://localhost:" + _port + "/?sleep=" + serverSleep); - httpExchange.setMethod(HttpMethod.POST); - httpExchange.setRequestContent(new ByteArrayBuffer("

??

")); - httpExchange.setTimeout(exchangeTimeout); - _httpClient.send(httpExchange); - - Assert.assertTrue(httpExchange.getDoneLatch().await(2 * serverSleep, TimeUnit.MILLISECONDS)); - Assert.assertFalse(httpExchange.isTimeoutOccurred()); - Assert.assertTrue(httpExchange.isResponseReceived()); - Assert.assertFalse(httpExchange.isErrorOccurred()); - } - - private class CustomContentExchange extends ContentExchange - { - private final CountDownLatch _doneLatch = new CountDownLatch(1); - private boolean _errorOccurred = false; - private boolean _timeoutOccurred = false; - private boolean _responseReceived = false; - - public boolean isErrorOccurred() - { - return _errorOccurred; - } - - public boolean isTimeoutOccurred() - { - return _timeoutOccurred; - } - - public boolean isResponseReceived() - { - return _responseReceived; - } - - public CustomContentExchange() - { - super(true); - } - - @Override - protected void onResponseComplete() throws IOException - { - try - { - super.onResponseComplete(); - } - finally - { - doTaskCompleted(); - } - } - - @Override - protected void onExpire() - { - try - { - super.onExpire(); - } - finally - { - doTaskCompleted(); - } - } - - @Override - protected void onException(Throwable ex) - { - try - { - super.onException(ex); - } - finally - { - doTaskCompleted(ex); - } - } - - @Override - protected void onConnectionFailed(Throwable ex) - { - try - { - super.onConnectionFailed(ex); - } - finally - { - doTaskCompleted(ex); - } - } - - protected void doTaskCompleted() - { - int exchangeState = getStatus(); - - try - { - if (exchangeState == HttpExchange.STATUS_COMPLETED) - { - // process the response as the state is ok - try - { - int responseCode = getResponseStatus(); - - if (responseCode >= HttpStatus.CONTINUE_100 && responseCode < HttpStatus.MULTIPLE_CHOICES_300) - { - _responseReceived = true; - } - else - { - _errorOccurred = true; - } - } - catch (Exception e) - { - _errorOccurred = true; - e.printStackTrace(); - } - } - else if (exchangeState == HttpExchange.STATUS_EXPIRED) - { - _timeoutOccurred = true; - } - else - { - _errorOccurred = true; - } - } - finally - { - // make sure to lower the latch - getDoneLatch().countDown(); - } - } - - protected void doTaskCompleted(Throwable ex) - { - try - { - _errorOccurred = true; - } - finally - { - // make sure to lower the latch - getDoneLatch().countDown(); - } - } - - public CountDownLatch getDoneLatch() - { - return _doneLatch; - } - } -} diff --git a/jetty-client-old/src/test/java/org/eclipse/jetty/client/TimeoutTest.java b/jetty-client-old/src/test/java/org/eclipse/jetty/client/TimeoutTest.java deleted file mode 100644 index 2048a55e48c..00000000000 --- a/jetty-client-old/src/test/java/org/eclipse/jetty/client/TimeoutTest.java +++ /dev/null @@ -1,438 +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.hamcrest.Matchers.*; - -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.OutputStream; -import java.net.Socket; -import java.net.SocketException; -import java.nio.channels.SocketChannel; -import java.util.Arrays; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.atomic.AtomicReference; - -import javax.servlet.ServletException; -import javax.servlet.ServletInputStream; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -import org.eclipse.jetty.http.HttpParser; -import org.eclipse.jetty.io.AsyncEndPoint; -import org.eclipse.jetty.io.Buffers; -import org.eclipse.jetty.io.EndPoint; -import org.eclipse.jetty.io.nio.AsyncConnection; -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.toolchain.test.IO; -import org.eclipse.jetty.util.log.Log; -import org.eclipse.jetty.util.log.Logger; -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Ignore; -import org.junit.Test; - -public class TimeoutTest -{ - private static final Logger logger = Log.getLogger(TimeoutTest.class); - private final AtomicInteger httpParses = new AtomicInteger(); - private final AtomicInteger httpRequests = new AtomicInteger(); - private ExecutorService threadPool; - private Server server; - private int serverPort; - private final AtomicReference serverEndPoint = new AtomicReference(); - - @Before - public void init() throws Exception - { - threadPool = Executors.newCachedThreadPool(); - server = new Server(); - - SelectChannelConnector connector = new SelectChannelConnector() - { - @Override - protected AsyncConnection newConnection(SocketChannel channel, final AsyncEndPoint endPoint) - { - serverEndPoint.set(endPoint); - return new org.eclipse.jetty.server.AsyncHttpConnection(this,endPoint,getServer()) - { - @Override - protected HttpParser newHttpParser(Buffers requestBuffers, EndPoint endPoint, HttpParser.EventHandler requestHandler) - { - return new HttpParser(requestBuffers,endPoint,requestHandler) - { - @Override - public int parseNext() throws IOException - { - httpParses.incrementAndGet(); - return super.parseNext(); - } - }; - } - }; - } - }; - connector.setMaxIdleTime(2000); - - // connector.setPort(5870); - connector.setPort(0); - - server.addConnector(connector); - server.setHandler(new AbstractHandler() - { - public void handle(String target, Request request, HttpServletRequest httpRequest, HttpServletResponse httpResponse) throws IOException, - ServletException - { - httpRequests.incrementAndGet(); - request.setHandled(true); - String contentLength = request.getHeader("Content-Length"); - if (contentLength != null) - { - int length = Integer.parseInt(contentLength); - ServletInputStream input = request.getInputStream(); - for (int i = 0; i < length; ++i) - input.read(); - } - } - }); - server.start(); - serverPort = connector.getLocalPort(); - - httpRequests.set(0); - logger.debug(" => :{}",serverPort); - } - - @After - public void destroy() throws Exception - { - if (server != null) - server.stop(); - if (threadPool != null) - threadPool.shutdownNow(); - } - - private Socket newClient() throws IOException, InterruptedException - { - Socket client = new Socket("localhost",serverPort); - return client; - } - - /** - * Test that performs a normal http POST request, with connection:close. - * Check that shutdownOutput is sufficient to close the server connection. - */ - @Test - public void testServerCloseClientDoesClose() throws Exception - { - // Log.getLogger("").setDebugEnabled(true); - final Socket client = newClient(); - final OutputStream clientOutput = client.getOutputStream(); - - byte[] data = new byte[3 * 1024]; - Arrays.fill(data,(byte)'Y'); - String content = new String(data,"UTF-8"); - - // The request section - StringBuilder req = new StringBuilder(); - req.append("POST / HTTP/1.1\r\n"); - req.append("Host: localhost\r\n"); - req.append("Content-Type: text/plain\r\n"); - req.append("Content-Length: ").append(content.length()).append("\r\n"); - req.append("Connection: close\r\n"); - req.append("\r\n"); - // and now, the POST content section. - req.append(content); - - // Send request to server - clientOutput.write(req.toString().getBytes("UTF-8")); - clientOutput.flush(); - - InputStream in = null; - InputStreamReader isr = null; - BufferedReader reader = null; - try - { - in = client.getInputStream(); - isr = new InputStreamReader(in); - reader = new BufferedReader(isr); - - // Read the response header - String line = reader.readLine(); - Assert.assertNotNull(line); - Assert.assertThat(line,startsWith("HTTP/1.1 200 ")); - while ((line = reader.readLine()) != null) - { - if (line.trim().length() == 0) - { - break; - } - } - Assert.assertEquals("one request handled",1,httpRequests.get()); - - Assert.assertEquals("EOF received",-1,client.getInputStream().read()); - - // shutdown the output - client.shutdownOutput(); - - // Check that we did not spin - int httpParseCount = httpParses.get(); - Assert.assertThat(httpParseCount,lessThan(50)); - - // Try to write another request (to prove that stream is closed) - try - { - clientOutput.write(req.toString().getBytes("UTF-8")); - clientOutput.flush(); - - Assert.fail("Should not have been able to send a second POST request (connection: close)"); - } - catch(SocketException e) - { - } - - Assert.assertEquals("one request handled",1,httpRequests.get()); - } - finally - { - IO.close(reader); - IO.close(isr); - IO.close(in); - closeClient(client); - } - } - - /** - * Test that performs a seemingly normal http POST request, but with - * a client that issues "connection: close", and then attempts to - * write a second POST request. - *

- * The connection should be closed by the server - */ - @Test - public void testServerCloseClientMoreDataSent() throws Exception - { - // Log.getLogger("").setDebugEnabled(true); - final Socket client = newClient(); - final OutputStream clientOutput = client.getOutputStream(); - - byte[] data = new byte[3 * 1024]; - Arrays.fill(data,(byte)'Y'); - String content = new String(data,"UTF-8"); - - // The request section - StringBuilder req = new StringBuilder(); - req.append("POST / HTTP/1.1\r\n"); - req.append("Host: localhost\r\n"); - req.append("Content-Type: text/plain\r\n"); - req.append("Content-Length: ").append(content.length()).append("\r\n"); - req.append("Connection: close\r\n"); - req.append("\r\n"); - // and now, the POST content section. - req.append(content); - - // Send request to server - clientOutput.write(req.toString().getBytes("UTF-8")); - clientOutput.flush(); - - InputStream in = null; - InputStreamReader isr = null; - BufferedReader reader = null; - try - { - in = client.getInputStream(); - isr = new InputStreamReader(in); - reader = new BufferedReader(isr); - - // Read the response header - String line = reader.readLine(); - Assert.assertNotNull(line); - Assert.assertThat(line,startsWith("HTTP/1.1 200 ")); - while ((line = reader.readLine()) != null) - { - if (line.trim().length() == 0) - { - break; - } - } - - Assert.assertEquals("EOF received",-1,client.getInputStream().read()); - Assert.assertEquals("one request handled",1,httpRequests.get()); - - // Don't shutdown the output - // client.shutdownOutput(); - - // server side seeking EOF - Assert.assertTrue("is open",serverEndPoint.get().isOpen()); - Assert.assertTrue("close sent",serverEndPoint.get().isOutputShutdown()); - Assert.assertFalse("close not received",serverEndPoint.get().isInputShutdown()); - - - // Check that we did not spin - TimeUnit.SECONDS.sleep(1); - int httpParseCount = httpParses.get(); - Assert.assertThat(httpParseCount,lessThan(50)); - - - // Write another request (which is ignored as the stream is closing), which causes real close. - clientOutput.write(req.toString().getBytes("UTF-8")); - clientOutput.flush(); - - // Check that we did not spin - TimeUnit.SECONDS.sleep(1); - httpParseCount = httpParses.get(); - Assert.assertThat(httpParseCount,lessThan(50)); - - - // server side is closed - Assert.assertFalse("is open",serverEndPoint.get().isOpen()); - Assert.assertTrue("close sent",serverEndPoint.get().isOutputShutdown()); - Assert.assertTrue("close not received",serverEndPoint.get().isInputShutdown()); - - Assert.assertEquals("one request handled",1,httpRequests.get()); - - } - finally - { - IO.close(reader); - IO.close(isr); - IO.close(in); - closeClient(client); - } - } - - - /** - * Test that performs a seemingly normal http POST request, but with - * a client that issues "connection: close", and then does not close - * the connection after reading the response. - *

- * The connection should be closed by the server after a timeout. - */ - @Test - public void testServerCloseClientDoesNotClose() throws Exception - { - // Log.getLogger("").setDebugEnabled(true); - final Socket client = newClient(); - final OutputStream clientOutput = client.getOutputStream(); - - byte[] data = new byte[3 * 1024]; - Arrays.fill(data,(byte)'Y'); - String content = new String(data,"UTF-8"); - - // The request section - StringBuilder req = new StringBuilder(); - req.append("POST / HTTP/1.1\r\n"); - req.append("Host: localhost\r\n"); - req.append("Content-Type: text/plain\r\n"); - req.append("Content-Length: ").append(content.length()).append("\r\n"); - req.append("Connection: close\r\n"); - req.append("\r\n"); - // and now, the POST content section. - req.append(content); - - // Send request to server - clientOutput.write(req.toString().getBytes("UTF-8")); - clientOutput.flush(); - - InputStream in = null; - InputStreamReader isr = null; - BufferedReader reader = null; - try - { - in = client.getInputStream(); - isr = new InputStreamReader(in); - reader = new BufferedReader(isr); - - // Read the response header - String line = reader.readLine(); - Assert.assertNotNull(line); - Assert.assertThat(line,startsWith("HTTP/1.1 200 ")); - while ((line = reader.readLine()) != null) - { - if (line.trim().length() == 0) - { - break; - } - } - - Assert.assertEquals("EOF received",-1,client.getInputStream().read()); - Assert.assertEquals("one request handled",1,httpRequests.get()); - - // Don't shutdown the output - // client.shutdownOutput(); - - // server side seeking EOF - Assert.assertTrue("is open",serverEndPoint.get().isOpen()); - Assert.assertTrue("close sent",serverEndPoint.get().isOutputShutdown()); - Assert.assertFalse("close not received",serverEndPoint.get().isInputShutdown()); - - - // Wait for the server idle timeout - TimeUnit.SECONDS.sleep(3); - int httpParseCount = httpParses.get(); - Assert.assertThat(httpParseCount,lessThan(50)); - - // server side is closed - Assert.assertFalse("is open",serverEndPoint.get().isOpen()); - Assert.assertTrue("close sent",serverEndPoint.get().isOutputShutdown()); - Assert.assertTrue("close not received",serverEndPoint.get().isInputShutdown()); - - Assert.assertEquals("one request handled",1,httpRequests.get()); - - - // client will eventually get broken pipe if it keeps writing - try - { - for (int i=0;i<1000;i++) - { - clientOutput.write(req.toString().getBytes("UTF-8")); - clientOutput.flush(); - } - Assert.fail("Client should have seen a broken pipe"); - } - catch(IOException e) - { - // expected broken pipe - } - - } - finally - { - IO.close(reader); - IO.close(isr); - IO.close(in); - closeClient(client); - } - } - - private void closeClient(Socket client) throws IOException - { - client.close(); - } -} diff --git a/jetty-client-old/src/test/java/org/eclipse/jetty/client/UnexpectedDataTest.java b/jetty-client-old/src/test/java/org/eclipse/jetty/client/UnexpectedDataTest.java deleted file mode 100644 index 0b28002f5b1..00000000000 --- a/jetty-client-old/src/test/java/org/eclipse/jetty/client/UnexpectedDataTest.java +++ /dev/null @@ -1,181 +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.IOException; -import java.io.OutputStream; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicInteger; - -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -import org.eclipse.jetty.http.HttpMethod; -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.IO; -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; - -/** - * Functional testing for HttpExchange. - * - * @author Matthew Purland - * @author Greg Wilkins - */ -public class UnexpectedDataTest -{ - private Server _server; - private int _port; - private HttpClient _httpClient; - private Connector _connector; - private AtomicInteger _count = new AtomicInteger(); - - @Before - public void setUp() throws Exception - { - startServer(); - _httpClient = new HttpClient(); - _httpClient.setConnectorType(HttpClient.CONNECTOR_SELECT_CHANNEL); - _httpClient.setMaxConnectionsPerAddress(1); - _httpClient.start(); - } - - @After - public void tearDown() throws Exception - { - _httpClient.stop(); - Thread.sleep(500); - stopServer(); - } - - @Test - public void testUnexpectedData() throws Exception - { - for (int i = 0; i < 4; ++i) - { - final CountDownLatch done = new CountDownLatch(1); - ContentExchange httpExchange = new ContentExchange() - { - protected void onResponseComplete() throws IOException - { - super.onResponseComplete(); - done.countDown(); - } - }; - httpExchange.setURL("http://localhost:" + _port + "/?i=" + i); - httpExchange.setMethod(HttpMethod.GET); - _httpClient.send(httpExchange); - - Assert.assertTrue(done.await(1000, TimeUnit.SECONDS)); - - int status = httpExchange.getStatus(); - String result = httpExchange.getResponseContent(); - Assert.assertEquals("i=" + i, 0, result.indexOf("")); - Assert.assertEquals("i=" + i, result.length() - 10, result.indexOf("")); - Assert.assertEquals(HttpExchange.STATUS_COMPLETED, status); - - // Give the client the time to read -1 from server before issuing the next request - // There is currently no simple way to be notified of connection closed. - Thread.sleep(500); - } - } - - protected void newServer() throws Exception - { - _server = new Server(); - _server.setGracefulShutdown(500); - _connector = new SelectChannelConnector(); - _connector.setPort(0); - _server.setConnectors(new Connector[]{_connector}); - } - - protected void startServer() throws Exception - { - newServer(); - _server.setHandler(new AbstractHandler() - { - public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) - throws IOException, ServletException - { - int i = 0; - try - { - baseRequest.setHandled(true); - response.setStatus(200); - _count.incrementAndGet(); - - if (request.getMethod().equalsIgnoreCase("GET")) - { - StringBuilder buffer = new StringBuilder(); - buffer.append("\r\n"); - for (; i < 100; i++) - { - buffer.append(" ").append(i).append("\r\n"); - } - buffer.append("\r\n"); - - byte[] buff = buffer.toString().getBytes(); - response.setContentLength(buff.length); - - buffer.append("extra data"); - buff = buffer.toString().getBytes(); - - OutputStream out = response.getOutputStream(); - out.write(buff, 0, buff.length); - out.flush(); - } - else - { - response.setContentType(request.getContentType()); - int size = request.getContentLength(); - ByteArrayOutputStream bout = new ByteArrayOutputStream(size > 0 ? size : 32768); - IO.copy(request.getInputStream(), bout); - response.getOutputStream().write(bout.toByteArray()); - } - } - catch (IOException e) - { - e.printStackTrace(); - throw e; - } - catch (Throwable e) - { - e.printStackTrace(); - throw new ServletException(e); - } - } - }); - _server.start(); - _port = _connector.getLocalPort(); - } - - private void stopServer() throws Exception - { - _server.stop(); - } -} diff --git a/jetty-client-old/src/test/java/org/eclipse/jetty/client/WebSocketUpgradeTest.java b/jetty-client-old/src/test/java/org/eclipse/jetty/client/WebSocketUpgradeTest.java deleted file mode 100644 index bdc1d341020..00000000000 --- a/jetty-client-old/src/test/java/org/eclipse/jetty/client/WebSocketUpgradeTest.java +++ /dev/null @@ -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 static org.junit.Assert.assertEquals; - -import java.io.IOException; -import java.util.concurrent.ArrayBlockingQueue; -import java.util.concurrent.BlockingQueue; -import java.util.concurrent.ConcurrentLinkedQueue; -import java.util.concurrent.TimeUnit; - -import javax.servlet.http.HttpServletRequest; - -import org.eclipse.jetty.http.HttpMethod; - -import org.eclipse.jetty.io.Connection; -import org.eclipse.jetty.io.EndPoint; -import org.eclipse.jetty.server.Connector; -import org.eclipse.jetty.server.Server; -import org.eclipse.jetty.server.nio.SelectChannelConnector; -import org.eclipse.jetty.websocket.WebSocket; -import org.eclipse.jetty.websocket.WebSocketBuffers; -import org.eclipse.jetty.websocket.WebSocketConnectionD00; -import org.eclipse.jetty.websocket.WebSocketHandler; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; - -/* ------------------------------------------------------------ */ -/** - * Functional testing for HttpExchange. - */ -public class WebSocketUpgradeTest -{ - protected Server _server; - protected int _port; - protected HttpClient _httpClient; - protected Connector _connector; - protected ConcurrentLinkedQueue _webSockets= new ConcurrentLinkedQueue(); - protected WebSocketHandler _handler; - protected TestWebSocket _websocket; - final BlockingQueue _results = new ArrayBlockingQueue(100); - - /* ------------------------------------------------------------ */ - @Before - public void setUp() throws Exception - { - startServer(); - _httpClient=new HttpClient(); - _httpClient.setIdleTimeout(2000); - _httpClient.setTimeout(2500); - _httpClient.setConnectTimeout(1000); - _httpClient.setConnectorType(HttpClient.CONNECTOR_SELECT_CHANNEL); - _httpClient.setMaxConnectionsPerAddress(10); - _httpClient.start(); - } - - /* ------------------------------------------------------------ */ - @After - public void tearDown() throws Exception - { - _httpClient.stop(); - Thread.sleep(500); - stopServer(); - } - - /* ------------------------------------------------------------ */ - @Test - public void testGetWithContentExchange() throws Exception - { - final WebSocket clientWS = new WebSocket.OnTextMessage() - { - Connection _connection; - - /* ------------------------------------------------------------ */ - public void onClose(int closeCode, String message) - { - } - - /* ------------------------------------------------------------ */ - public void onOpen(Connection connection) - { - _connection=connection; - _results.add("clientWS.onConnect"); - _results.add(_connection); - } - - /* ------------------------------------------------------------ */ - public void onMessage(String data) - { - _results.add("clientWS.onMessage"); - _results.add(data); - } - }; - - - HttpExchange httpExchange=new HttpExchange() - { - /* ------------------------------------------------------------ */ - /** - * @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 - { - waitFor(2); - _results.add(new Integer(status)); - super.onResponseStatus(version,status,reason); - } - - /* ------------------------------------------------------------ */ - /** - * @see org.eclipse.jetty.client.HttpExchange#onSwitchProtocol(org.eclipse.jetty.io.EndPoint) - */ - @Override - protected Connection onSwitchProtocol(EndPoint endp) throws IOException - { - waitFor(3); - WebSocketConnectionD00 connection = new WebSocketConnectionD00(clientWS,endp,new WebSocketBuffers(4096),System.currentTimeMillis(),1000,""); - - _results.add("onSwitchProtocol"); - _results.add(connection); - clientWS.onOpen(connection); - return connection; - } - - /* ------------------------------------------------------------ */ - private void waitFor(int results) - { - try - { - int c=10; - while(_results.size()0) - Thread.sleep(10); - } - catch(InterruptedException e) - { - e.printStackTrace(); - } - } - }; - - httpExchange.setURL("http://localhost:"+_port+"/"); - httpExchange.setMethod(HttpMethod.GET); - - httpExchange.addRequestHeader("Upgrade","WebSocket"); - httpExchange.addRequestHeader("Connection","Upgrade"); - - _httpClient.send(httpExchange); - int status = httpExchange.waitForDone(); - assertEquals(HttpExchange.STATUS_COMPLETED, status); - - assertEquals("serverWS.onConnect", _results.poll(1,TimeUnit.SECONDS)); - TestWebSocket serverWS = (TestWebSocket)_results.poll(1,TimeUnit.SECONDS); - - assertEquals(new Integer(101), _results.poll(1,TimeUnit.SECONDS)); - - assertEquals("onSwitchProtocol", _results.poll(1,TimeUnit.SECONDS)); - WebSocketConnectionD00 client_conn=(WebSocketConnectionD00)_results.poll(1,TimeUnit.SECONDS); - - assertEquals("clientWS.onConnect", _results.poll(1,TimeUnit.SECONDS)); - assertEquals(client_conn, _results.poll(1,TimeUnit.SECONDS)); - - client_conn.sendMessage("hello world"); - - assertEquals("serverWS.onMessage", _results.poll(1,TimeUnit.SECONDS)); - assertEquals("hello world", _results.poll(1,TimeUnit.SECONDS)); - - serverWS.sendMessage("buongiorno"); - - assertEquals("clientWS.onMessage", _results.poll(1,TimeUnit.SECONDS)); - assertEquals("buongiorno", _results.poll(1,TimeUnit.SECONDS)); - - } - - /* ------------------------------------------------------------ */ - protected void newServer() throws Exception - { - _server=new Server(); - _server.setGracefulShutdown(500); - _connector=new SelectChannelConnector(); - - _connector.setPort(0); - _server.setConnectors(new Connector[] { _connector }); - } - - /* ------------------------------------------------------------ */ - protected void startServer() throws Exception - { - newServer(); - _handler= new WebSocketHandler() - { - /* ------------------------------------------------------------ */ - public WebSocket doWebSocketConnect(HttpServletRequest request, String protocol) - { - _websocket = new TestWebSocket(); - return _websocket; - } - }; - - _server.setHandler(_handler); - _server.start(); - _port=_connector.getLocalPort(); - } - - /* ------------------------------------------------------------ */ - private void stopServer() throws Exception - { - _server.stop(); - _server.join(); - } - - /* ------------------------------------------------------------ */ - class TestWebSocket implements WebSocket.OnTextMessage - { - Connection _connection; - - /* ------------------------------------------------------------ */ - public void onOpen(Connection connection) - { - _connection=connection; - _webSockets.add(this); - _results.add("serverWS.onConnect"); - _results.add(this); - } - - /* ------------------------------------------------------------ */ - public void onMessage(final String data) - { - _results.add("serverWS.onMessage"); - _results.add(data); - } - - /* ------------------------------------------------------------ */ - public void onClose(int code, String message) - { - _results.add("onClose"); - _webSockets.remove(this); - } - - /* ------------------------------------------------------------ */ - public void sendMessage(String msg) throws IOException - { - _connection.sendMessage(msg); - } - } -} diff --git a/jetty-client-old/src/test/java/org/eclipse/jetty/client/WebdavListenerTest.java b/jetty-client-old/src/test/java/org/eclipse/jetty/client/WebdavListenerTest.java deleted file mode 100644 index 5afa5cf2c89..00000000000 --- a/jetty-client-old/src/test/java/org/eclipse/jetty/client/WebdavListenerTest.java +++ /dev/null @@ -1,144 +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.File; - -import org.eclipse.jetty.client.security.Realm; -import org.eclipse.jetty.client.security.SimpleRealmResolver; -import org.eclipse.jetty.http.HttpMethod; -import org.eclipse.jetty.server.Connector; -import org.eclipse.jetty.server.Server; -import org.eclipse.jetty.toolchain.test.MavenTestingUtils; -import org.eclipse.jetty.toolchain.test.PathAssert; -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Ignore; -import org.junit.Test; - -/** - * Functional testing for HttpExchange. - */ -public class WebdavListenerTest -{ - protected String _scheme = "http://"; - protected Server _server; - protected int _port; - protected HttpClient _httpClient; - protected Connector _connector; - - private String _username = "janb"; - private String _password = "xxxxx"; - - private String _singleFileURL; - private String _dirFileURL; - private String _dirURL; - - @Before - public void setUp() throws Exception - { - _singleFileURL = "https://dav.codehaus.org/user/" + _username + "/foo.txt"; - _dirURL = "https://dav.codehaus.org/user/" + _username + "/ttt/"; - _dirFileURL = _dirURL+"foo.txt"; - _scheme="https://"; - - _httpClient=new HttpClient(); - _httpClient.setConnectorType(HttpClient.CONNECTOR_SELECT_CHANNEL); - //_httpClient.setMaxConnectionsPerAddress(4); - - _httpClient.setRealmResolver( new SimpleRealmResolver ( - new Realm(){ - public String getId() - { - return _username + "'s webspace"; //To change body of implemented methods use File | Settings | File Templates. - } - - public String getPrincipal() - { - return _username; //To change body of implemented methods use File | Settings | File Templates. - } - - public String getCredentials() - { - return _password; //To change body of implemented methods use File | Settings | File Templates. - } - } - )); - - _httpClient.registerListener( "org.eclipse.jetty.client.webdav.WebdavListener"); - _httpClient.start(); - } - - - @After - public void tearDown () throws Exception - { - _httpClient.stop(); - } - - - @Test - @Ignore("Only works with real WebDAV server") - public void testPUTandDELETEwithSSL() throws Exception - { - File file = MavenTestingUtils.getTestResourceFile("foo.txt"); - PathAssert.assertFileExists("WebDAV test file", file); - - //PUT a FILE - ContentExchange singleFileExchange = new ContentExchange(); - singleFileExchange.setURL(_singleFileURL); - singleFileExchange.setMethod( HttpMethod.PUT ); - singleFileExchange.setFileForUpload(file); - singleFileExchange.setRequestHeader( "Content-Type", "application/octet-stream"); - singleFileExchange.setRequestHeader("Content-Length", String.valueOf( file.length() )); - _httpClient.send(singleFileExchange); - singleFileExchange.waitForDone(); - - String result = singleFileExchange.getResponseContent(); - Assert.assertEquals(201, singleFileExchange.getResponseStatus()); - - //PUT a FILE in a directory hierarchy - ContentExchange dirFileExchange = new ContentExchange(); - dirFileExchange.setURL(_dirFileURL); - dirFileExchange.setMethod( HttpMethod.PUT ); - dirFileExchange.setFileForUpload(file); - dirFileExchange.setRequestHeader( "Content-Type", "application/octet-stream"); - dirFileExchange.setRequestHeader("Content-Length", String.valueOf( file.length() )); - _httpClient.send(dirFileExchange); - dirFileExchange.waitForDone(); - result = dirFileExchange.getResponseContent(); - Assert.assertEquals(201, singleFileExchange.getResponseStatus()); - - - //DELETE the single file - HttpExchange del = new HttpExchange(); - del.setURL(_singleFileURL); - del.setMethod(HttpMethod.DELETE); - _httpClient.send(del); - del.waitForDone(); - - //DELETE the whole dir - del.setURL(_dirURL); - del.setMethod(HttpMethod.DELETE); - del.setRequestHeader("Depth", "infinity"); - _httpClient.send(del); - del.waitForDone(); - } -} diff --git a/jetty-client-old/src/test/java/org/eclipse/jetty/client/helperClasses/AbstractSslServerAndClientCreator.java b/jetty-client-old/src/test/java/org/eclipse/jetty/client/helperClasses/AbstractSslServerAndClientCreator.java deleted file mode 100644 index 8a62d378b3a..00000000000 --- a/jetty-client-old/src/test/java/org/eclipse/jetty/client/helperClasses/AbstractSslServerAndClientCreator.java +++ /dev/null @@ -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.helperClasses; - -import org.eclipse.jetty.server.Connector; -import org.eclipse.jetty.server.Server; -import org.eclipse.jetty.server.ssl.SslSocketConnector; -import org.eclipse.jetty.toolchain.test.MavenTestingUtils; -import org.eclipse.jetty.util.log.Log; -import org.eclipse.jetty.util.log.Logger; -import org.eclipse.jetty.util.ssl.SslContextFactory; - - -/* ------------------------------------------------------------ */ -/** - */ -public abstract class AbstractSslServerAndClientCreator implements ServerAndClientCreator -{ - private static final Logger LOG = Log.getLogger(AbstractSslServerAndClientCreator.class); - - /* ------------------------------------------------------------ */ - public Server createServer() throws Exception - { - Server server = new Server(); - // SslSelectChannelConnector connector = new SslSelectChannelConnector(); - SslSocketConnector connector = new SslSocketConnector(); - - String keystore = MavenTestingUtils.getTestResourceFile("keystore").getAbsolutePath(); - - connector.setPort(0); - SslContextFactory cf = connector.getSslContextFactory(); - cf.setKeyStorePath(keystore); - cf.setKeyStorePassword("storepwd"); - cf.setKeyManagerPassword("keypwd"); - - server.setConnectors(new Connector[]{ connector }); - server.setHandler(new GenericServerHandler()); - server.start(); - return server; - } - - -} diff --git a/jetty-client-old/src/test/java/org/eclipse/jetty/client/helperClasses/AsyncSslServerAndClientCreator.java b/jetty-client-old/src/test/java/org/eclipse/jetty/client/helperClasses/AsyncSslServerAndClientCreator.java deleted file mode 100644 index 806a95b8b71..00000000000 --- a/jetty-client-old/src/test/java/org/eclipse/jetty/client/helperClasses/AsyncSslServerAndClientCreator.java +++ /dev/null @@ -1,42 +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.helperClasses; - -import org.eclipse.jetty.client.HttpClient; -import org.eclipse.jetty.toolchain.test.MavenTestingUtils; - -public class AsyncSslServerAndClientCreator extends AbstractSslServerAndClientCreator implements ServerAndClientCreator -{ - - /* ------------------------------------------------------------ */ - public HttpClient createClient(long idleTimeout, long timeout, int connectTimeout) throws Exception - { - HttpClient httpClient = new HttpClient(); - httpClient.setConnectorType(HttpClient.CONNECTOR_SELECT_CHANNEL); - httpClient.setMaxConnectionsPerAddress(2); - - String keystore = MavenTestingUtils.getTestResourceFile("keystore").getAbsolutePath(); - httpClient.getSslContextFactory().setKeyStorePath(keystore); - httpClient.getSslContextFactory().setKeyStorePassword("storepwd"); - httpClient.getSslContextFactory().setKeyManagerPassword("keypwd"); - httpClient.start(); - return httpClient; - } - -} diff --git a/jetty-client-old/src/test/java/org/eclipse/jetty/client/helperClasses/ExternalKeyStoreAsyncSslServerAndClientCreator.java b/jetty-client-old/src/test/java/org/eclipse/jetty/client/helperClasses/ExternalKeyStoreAsyncSslServerAndClientCreator.java deleted file mode 100644 index fa22282e98a..00000000000 --- a/jetty-client-old/src/test/java/org/eclipse/jetty/client/helperClasses/ExternalKeyStoreAsyncSslServerAndClientCreator.java +++ /dev/null @@ -1,45 +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.helperClasses; - -import java.io.FileInputStream; - -import org.eclipse.jetty.client.HttpClient; -import org.eclipse.jetty.toolchain.test.MavenTestingUtils; - -public class ExternalKeyStoreAsyncSslServerAndClientCreator extends AbstractSslServerAndClientCreator implements ServerAndClientCreator -{ - - public HttpClient createClient(long idleTimeout, long timeout, int connectTimeout) throws Exception - { - HttpClient httpClient = new HttpClient(); - httpClient.setConnectorType(HttpClient.CONNECTOR_SELECT_CHANNEL); - httpClient.setMaxConnectionsPerAddress(2); - - String keystore = MavenTestingUtils.getTestResourceFile("keystore").getAbsolutePath(); - - httpClient.setKeyStoreInputStream(new FileInputStream(keystore)); - httpClient.setKeyStorePassword("storepwd"); - httpClient.setKeyManagerPassword("keypwd"); - httpClient.start(); - return httpClient; - } - - -} diff --git a/jetty-client-old/src/test/java/org/eclipse/jetty/client/helperClasses/GenericServerHandler.java b/jetty-client-old/src/test/java/org/eclipse/jetty/client/helperClasses/GenericServerHandler.java deleted file mode 100644 index 6a44a7f8530..00000000000 --- a/jetty-client-old/src/test/java/org/eclipse/jetty/client/helperClasses/GenericServerHandler.java +++ /dev/null @@ -1,109 +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.helperClasses; - -import java.io.ByteArrayOutputStream; -import java.io.IOException; - -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -import org.eclipse.jetty.http.HttpHeader; -import org.eclipse.jetty.io.EofException; -import org.eclipse.jetty.server.Request; -import org.eclipse.jetty.server.handler.AbstractHandler; -import org.eclipse.jetty.util.IO; -import org.eclipse.jetty.util.log.Log; -import org.eclipse.jetty.util.log.Logger; - -/** - * Generic Server Handler used for various client tests. - */ -public class GenericServerHandler extends AbstractHandler -{ - private static final Logger LOG = Log.getLogger(GenericServerHandler.class); - - public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException - { - int i = 0; - try - { - baseRequest.setHandled(true); - response.setStatus(200); - - if (request.getServerName().equals("jetty.eclipse.org")) - { - response.getOutputStream().println("Proxy request: " + request.getRequestURL()); - response.getOutputStream().println(request.getHeader(HttpHeader.PROXY_AUTHORIZATION)); - } - else if (request.getMethod().equalsIgnoreCase("GET")) - { - response.getOutputStream().println(""); - for (; i < 100; i++) - { - response.getOutputStream().println(" " + i + ""); - } - else if (request.getMethod().equalsIgnoreCase("OPTIONS")) - { - if ("*".equals(target)) - { - response.setContentLength(0); - response.setHeader("Allow","GET,HEAD,POST,PUT,DELETE,MOVE,OPTIONS,TRACE"); - } - } - else if (request.getMethod().equalsIgnoreCase("SLEEP")) - { - Thread.sleep(10000); - } - else - { - response.setContentType(request.getContentType()); - int size = request.getContentLength(); - ByteArrayOutputStream bout = new ByteArrayOutputStream(size > 0?size:32768); - IO.copy(request.getInputStream(),bout); - response.getOutputStream().write(bout.toByteArray()); - } - } - catch (InterruptedException e) - { - LOG.debug(e); - } - catch (EofException e) - { - LOG.info(e.toString()); - LOG.debug(e); - throw e; - } - catch (IOException e) - { - LOG.warn(e); - throw e; - } - catch (Throwable e) - { - LOG.warn(e); - throw new ServletException(e); - } - } -} diff --git a/jetty-client-old/src/test/java/org/eclipse/jetty/client/helperClasses/HttpServerAndClientCreator.java b/jetty-client-old/src/test/java/org/eclipse/jetty/client/helperClasses/HttpServerAndClientCreator.java deleted file mode 100644 index 453ddb690a3..00000000000 --- a/jetty-client-old/src/test/java/org/eclipse/jetty/client/helperClasses/HttpServerAndClientCreator.java +++ /dev/null @@ -1,54 +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.helperClasses; - -import org.eclipse.jetty.client.HttpClient; -import org.eclipse.jetty.server.Connector; -import org.eclipse.jetty.server.Server; -import org.eclipse.jetty.server.nio.SelectChannelConnector; - -public class HttpServerAndClientCreator implements ServerAndClientCreator -{ - public HttpClient createClient(long idleTimeout, long timeout, int connectTimeout) throws Exception - { - HttpClient httpClient = new HttpClient(); - httpClient.setIdleTimeout(idleTimeout); - httpClient.setTimeout(timeout); - httpClient.setConnectTimeout(connectTimeout); - httpClient.setConnectorType(HttpClient.CONNECTOR_SELECT_CHANNEL); - httpClient.setMaxConnectionsPerAddress(2); - httpClient.start(); - return httpClient; - } - - public Server createServer() throws Exception - { - Server _server = new Server(); - _server.setGracefulShutdown(500); - Connector _connector = new SelectChannelConnector(); - - _connector.setMaxIdleTime(3000000); - - _connector.setPort(0); - _server.setConnectors(new Connector[]{ _connector }); - _server.setHandler(new GenericServerHandler()); - _server.start(); - return _server; - } -} diff --git a/jetty-client-old/src/test/java/org/eclipse/jetty/client/helperClasses/ServerAndClientCreator.java b/jetty-client-old/src/test/java/org/eclipse/jetty/client/helperClasses/ServerAndClientCreator.java deleted file mode 100644 index b95ef7d86a2..00000000000 --- a/jetty-client-old/src/test/java/org/eclipse/jetty/client/helperClasses/ServerAndClientCreator.java +++ /dev/null @@ -1,29 +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.helperClasses; - -import org.eclipse.jetty.client.HttpClient; -import org.eclipse.jetty.server.Server; - -public interface ServerAndClientCreator -{ - Server createServer() throws Exception; - - HttpClient createClient(long idleTimeout, long timeout, int connectTimeout) throws Exception; -} diff --git a/jetty-client-old/src/test/java/org/eclipse/jetty/client/helperClasses/SslServerAndClientCreator.java b/jetty-client-old/src/test/java/org/eclipse/jetty/client/helperClasses/SslServerAndClientCreator.java deleted file mode 100644 index 93bda3b780a..00000000000 --- a/jetty-client-old/src/test/java/org/eclipse/jetty/client/helperClasses/SslServerAndClientCreator.java +++ /dev/null @@ -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.helperClasses; - -import org.eclipse.jetty.client.HttpClient; - -public class SslServerAndClientCreator extends AbstractSslServerAndClientCreator implements ServerAndClientCreator -{ - - public HttpClient createClient(long idleTimeout, long timeout, int connectTimeout) throws Exception - { - HttpClient httpClient = new HttpClient(); - httpClient.setIdleTimeout(idleTimeout); - httpClient.setTimeout(timeout); - httpClient.setConnectTimeout(connectTimeout); - httpClient.setConnectorType(HttpClient.CONNECTOR_SOCKET); - httpClient.setMaxConnectionsPerAddress(2); - httpClient.start(); - return httpClient; - } -} diff --git a/jetty-client-old/src/test/java/org/eclipse/jetty/client/security/SecurityResolverTest.java b/jetty-client-old/src/test/java/org/eclipse/jetty/client/security/SecurityResolverTest.java deleted file mode 100644 index 70ad0bd37f7..00000000000 --- a/jetty-client-old/src/test/java/org/eclipse/jetty/client/security/SecurityResolverTest.java +++ /dev/null @@ -1,51 +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 org.junit.Test; - -public class SecurityResolverTest -{ - @Test - public void testNothing() - { - } - - /* TODO - - public void testCredentialParsing() throws Exception - { - SecurityListener resolver = new SecurityListener(); - Buffer value = new ByteArrayBuffer("basic a=b".getBytes()); - - assertEquals( "basic", resolver.scrapeAuthenticationType( value.toString() ) ); - assertEquals( 1, resolver.scrapeAuthenticationDetails( value.toString() ).size() ); - - value = new ByteArrayBuffer("digest a=boo, c=\"doo\" , egg=foo".getBytes()); - - assertEquals( "digest", resolver.scrapeAuthenticationType( value.toString() ) ); - Map testMap = resolver.scrapeAuthenticationDetails( value.toString() ); - assertEquals( 3, testMap.size() ); - assertEquals( "boo", testMap.get("a") ); - assertEquals( "doo", testMap.get("c") ); - assertEquals( "foo", testMap.get("egg") ); - } - - */ -} diff --git a/jetty-client-old/src/test/resources/foo.txt b/jetty-client-old/src/test/resources/foo.txt deleted file mode 100644 index 58b78820701..00000000000 --- a/jetty-client-old/src/test/resources/foo.txt +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/jetty-client-old/src/test/resources/keystore b/jetty-client-old/src/test/resources/keystore deleted file mode 100644 index b727bd0fb77..00000000000 Binary files a/jetty-client-old/src/test/resources/keystore and /dev/null differ diff --git a/jetty-client-old/src/test/resources/realm.properties b/jetty-client-old/src/test/resources/realm.properties deleted file mode 100644 index 6cd8ffa4012..00000000000 --- a/jetty-client-old/src/test/resources/realm.properties +++ /dev/null @@ -1,22 +0,0 @@ -# -# This file defines users passwords and roles for a HashUserRealm -# -# The format is -# : [, ...] -# -# Passwords may be clear text, obfuscated or checksummed. The class -# org.eclipse.util.Password should be used to generate obfuscated -# passwords or password checksums -# -# If DIGEST Authentication is used, the password must be in a recoverable -# format, either plain text or OBF:. -# -# if using digest authentication, do not MD5-hash the password -jetty: jetty,user -admin: CRYPT:ad1ks..kc.1Ug,server-administrator,content-administrator,admin,user -other: OBF:1xmk1w261u9r1w1c1xmq,user -plain: plain,user -user: password,user - -# This entry is for digest auth. The credential is a MD5 hash of username:realmname:password -digest: MD5:6e120743ad67abfbc385bc2bb754e297,user diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/AuthenticationProtocolHandler.java b/jetty-client/src/main/java/org/eclipse/jetty/client/AuthenticationProtocolHandler.java index 5cc8e057836..c1e2dd722fa 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/AuthenticationProtocolHandler.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/AuthenticationProtocolHandler.java @@ -58,7 +58,7 @@ public class AuthenticationProtocolHandler implements ProtocolHandler @Override public boolean accept(Request request, Response response) { - return response.status() == 401; + return response.getStatus() == 401; } @Override @@ -79,14 +79,14 @@ public class AuthenticationProtocolHandler implements ProtocolHandler public void onComplete(Result result) { Request request = result.getRequest(); - HttpConversation conversation = client.getConversation(request.conversation()); - Response.Listener listener = conversation.exchanges().peekFirst().listener(); + HttpConversation conversation = client.getConversation(request.getConversationID(), false); + List listeners = conversation.getExchanges().peekFirst().getResponseListeners(); ContentResponse response = new HttpContentResponse(result.getResponse(), getContent(), getEncoding()); if (result.isFailed()) { Throwable failure = result.getFailure(); LOG.debug("Authentication challenge failed {}", failure); - notifier.forwardFailureComplete(listener, request, result.getRequestFailure(), response, result.getResponseFailure()); + notifier.forwardFailureComplete(listeners, request, result.getRequestFailure(), response, result.getResponseFailure()); return; } @@ -94,11 +94,11 @@ public class AuthenticationProtocolHandler implements ProtocolHandler if (wwwAuthenticates.isEmpty()) { LOG.debug("Authentication challenge without WWW-Authenticate header"); - notifier.forwardFailureComplete(listener, request, null, response, new HttpResponseException("HTTP protocol violation: 401 without WWW-Authenticate header", response)); + notifier.forwardFailureComplete(listeners, request, null, response, new HttpResponseException("HTTP protocol violation: 401 without WWW-Authenticate header", response)); return; } - final String uri = request.uri(); + final String uri = request.getURI(); Authentication authentication = null; WWWAuthenticate wwwAuthenticate = null; for (WWWAuthenticate wwwAuthn : wwwAuthenticates) @@ -113,7 +113,7 @@ public class AuthenticationProtocolHandler implements ProtocolHandler if (authentication == null) { LOG.debug("No authentication available for {}", request); - notifier.forwardSuccessComplete(listener, request, response); + notifier.forwardSuccessComplete(listeners, request, response); return; } @@ -121,26 +121,27 @@ public class AuthenticationProtocolHandler implements ProtocolHandler LOG.debug("Authentication result {}", authnResult); if (authnResult == null) { - notifier.forwardSuccessComplete(listener, request, response); + notifier.forwardSuccessComplete(listeners, request, response); return; } - authnResult.apply(request); - request.send(new Response.Listener.Empty() + Request newRequest = client.copyRequest(request, request.getURI()); + authnResult.apply(newRequest); + newRequest.onResponseSuccess(new Response.SuccessListener() { @Override public void onSuccess(Response response) { client.getAuthenticationStore().addAuthenticationResult(authnResult); } - }); + }).send(null); } private List parseWWWAuthenticate(Response response) { // TODO: these should be ordered by strength List result = new ArrayList<>(); - List values = Collections.list(response.headers().getValues(HttpHeader.WWW_AUTHENTICATE.asString())); + List values = Collections.list(response.getHeaders().getValues(HttpHeader.WWW_AUTHENTICATE.asString())); for (String value : values) { Matcher matcher = WWW_AUTHENTICATE_PATTERN.matcher(value); diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/ContinueProtocolHandler.java b/jetty-client/src/main/java/org/eclipse/jetty/client/ContinueProtocolHandler.java index 2d12c704374..8588914571a 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/ContinueProtocolHandler.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/ContinueProtocolHandler.java @@ -18,8 +18,11 @@ package org.eclipse.jetty.client; +import java.util.List; + import org.eclipse.jetty.client.api.Request; import org.eclipse.jetty.client.api.Response; +import org.eclipse.jetty.client.api.Result; import org.eclipse.jetty.client.util.BufferingResponseListener; import org.eclipse.jetty.http.HttpHeader; import org.eclipse.jetty.http.HttpHeaderValue; @@ -40,8 +43,9 @@ public class ContinueProtocolHandler implements ProtocolHandler @Override public boolean accept(Request request, Response response) { - boolean expect100 = request.headers().contains(HttpHeader.EXPECT, HttpHeaderValue.CONTINUE.asString()); - boolean handled100 = client.getConversation(request.conversation()).getAttribute(ATTRIBUTE) != null; + boolean expect100 = request.getHeaders().contains(HttpHeader.EXPECT, HttpHeaderValue.CONTINUE.asString()); + HttpConversation conversation = client.getConversation(request.getConversationID(), false); + boolean handled100 = conversation != null && conversation.getAttribute(ATTRIBUTE) != null; return expect100 && !handled100; } @@ -60,20 +64,20 @@ public class ContinueProtocolHandler implements ProtocolHandler // Handling of success must be done here and not from onComplete(), // since the onComplete() is not invoked because the request is not completed yet. - HttpConversation conversation = client.getConversation(response.conversation()); + HttpConversation conversation = client.getConversation(response.getConversationID(), false); // Mark the 100 Continue response as handled conversation.setAttribute(ATTRIBUTE, Boolean.TRUE); - HttpExchange exchange = conversation.exchanges().peekLast(); - assert exchange.response() == response; - Response.Listener listener = exchange.listener(); - switch (response.status()) + HttpExchange exchange = conversation.getExchanges().peekLast(); + assert exchange.getResponse() == response; + List listeners = exchange.getResponseListeners(); + switch (response.getStatus()) { case 100: { // All good, continue exchange.resetResponse(true); - conversation.listener(listener); + conversation.setResponseListeners(listeners); exchange.proceed(true); break; } @@ -81,8 +85,8 @@ public class ContinueProtocolHandler implements ProtocolHandler { // Server either does not support 100 Continue, or it does and wants to refuse the request content HttpContentResponse contentResponse = new HttpContentResponse(response, getContent(), getEncoding()); - notifier.forwardSuccess(listener, contentResponse); - conversation.listener(listener); + notifier.forwardSuccess(listeners, contentResponse); + conversation.setResponseListeners(listeners); exchange.proceed(false); break; } @@ -92,15 +96,20 @@ public class ContinueProtocolHandler implements ProtocolHandler @Override public void onFailure(Response response, Throwable failure) { - HttpConversation conversation = client.getConversation(response.conversation()); + HttpConversation conversation = client.getConversation(response.getConversationID(), false); // Mark the 100 Continue response as handled conversation.setAttribute(ATTRIBUTE, Boolean.TRUE); - HttpExchange exchange = conversation.exchanges().peekLast(); - assert exchange.response() == response; - Response.Listener listener = exchange.listener(); + HttpExchange exchange = conversation.getExchanges().peekLast(); + assert exchange.getResponse() == response; + List listeners = exchange.getResponseListeners(); HttpContentResponse contentResponse = new HttpContentResponse(response, getContent(), getEncoding()); - notifier.forwardFailureComplete(listener, exchange.request(), exchange.requestFailure(), contentResponse, failure); + notifier.forwardFailureComplete(listeners, exchange.getRequest(), exchange.getRequestFailure(), contentResponse, failure); + } + + @Override + public void onComplete(Result result) + { } } } diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/GZIPContentDecoder.java b/jetty-client/src/main/java/org/eclipse/jetty/client/GZIPContentDecoder.java index ce01bfbf715..c6e29016762 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/GZIPContentDecoder.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/GZIPContentDecoder.java @@ -324,7 +324,7 @@ public class GZIPContentDecoder implements ContentDecoder flags = 0; } - protected boolean finished() + protected boolean isFinished() { return state == State.INITIAL; } diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpClient.java b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpClient.java index 4230c7f0a11..ab074d21b01 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpClient.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpClient.java @@ -30,6 +30,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; +import java.util.Locale; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; @@ -45,6 +46,8 @@ import org.eclipse.jetty.client.api.CookieStore; import org.eclipse.jetty.client.api.Destination; import org.eclipse.jetty.client.api.Request; import org.eclipse.jetty.client.api.Response; +import org.eclipse.jetty.http.HttpFields; +import org.eclipse.jetty.http.HttpHeader; import org.eclipse.jetty.http.HttpMethod; import org.eclipse.jetty.io.ByteBufferPool; import org.eclipse.jetty.io.EndPoint; @@ -86,7 +89,7 @@ import org.eclipse.jetty.util.thread.TimerScheduler; * * // Asynchronously * HttpClient client = new HttpClient(); - * client.newRequest("http://localhost:8080").send(new Response.Listener.Adapter() + * client.newRequest("http://localhost:8080").send(new Response.Listener.Empty() * { * @Override * public void onSuccess(Response response) @@ -120,6 +123,7 @@ public class HttpClient extends ContainerLifeCycle private volatile int responseBufferSize = 4096; private volatile int maxRedirects = 8; private volatile SocketAddress bindAddress; + private volatile long connectTimeout = 15000; private volatile long idleTimeout; private volatile boolean tcpNoDelay = true; private volatile boolean dispatchIO = true; @@ -168,6 +172,7 @@ public class HttpClient extends ContainerLifeCycle addBean(scheduler); selectorManager = newSelectorManager(); + selectorManager.setConnectTimeout(getConnectTimeout()); addBean(selectorManager); handlers.add(new ContinueProtocolHandler(this)); @@ -263,9 +268,21 @@ public class HttpClient extends ContainerLifeCycle return new HttpRequest(this, uri); } - protected Request newRequest(long id, String uri) + protected Request copyRequest(Request oldRequest, String newURI) { - return new HttpRequest(this, id, URI.create(uri)); + Request newRequest = new HttpRequest(this, oldRequest.getConversationID(), URI.create(newURI)); + newRequest.method(oldRequest.getMethod()) + .version(oldRequest.getVersion()) + .content(oldRequest.getContent()); + for (HttpFields.Field header : oldRequest.getHeaders()) + { + // We have a new URI, so skip the host header if present + if (HttpHeader.HOST == header.getHeader()) + continue; + + newRequest.header(header.getName(), header.getValue()); + } + return newRequest; } private String address(String scheme, String host, int port) @@ -278,7 +295,7 @@ public class HttpClient extends ContainerLifeCycle return provideDestination(scheme, host, port); } - private HttpDestination provideDestination(String scheme, String host, int port) + protected HttpDestination provideDestination(String scheme, String host, int port) { String address = address(scheme, host, port); HttpDestination destination = destinations.get(address); @@ -305,17 +322,22 @@ public class HttpClient extends ContainerLifeCycle return new ArrayList(destinations.values()); } - protected void send(Request request, Response.Listener listener) + protected void send(final Request request, List listeners) { - String scheme = request.scheme().toLowerCase(); + String scheme = request.getScheme().toLowerCase(Locale.ENGLISH); if (!Arrays.asList("http", "https").contains(scheme)) throw new IllegalArgumentException("Invalid protocol " + scheme); - int port = request.port(); + int port = request.getPort(); if (port < 0) port = "https".equals(scheme) ? 443 : 80; - provideDestination(scheme, request.host(), port).send(request, listener); + for (Response.ResponseListener listener : listeners) + if (listener instanceof Schedulable) + ((Schedulable)listener).schedule(scheduler); + + HttpDestination destination = provideDestination(scheme, request.getHost(), port); + destination.send(request, listeners); } protected void newConnection(HttpDestination destination, Callback callback) @@ -329,7 +351,7 @@ public class HttpClient extends ContainerLifeCycle channel.bind(bindAddress); configure(channel); channel.configureBlocking(false); - channel.connect(new InetSocketAddress(destination.host(), destination.port())); + channel.connect(new InetSocketAddress(destination.getHost(), destination.getPort())); Future result = new ConnectionCallback(destination, callback); selectorManager.connect(channel, result); @@ -359,10 +381,10 @@ public class HttpClient extends ContainerLifeCycle } } - protected HttpConversation getConversation(long id) + protected HttpConversation getConversation(long id, boolean create) { HttpConversation conversation = conversations.get(id); - if (conversation == null) + if (conversation == null && create) { conversation = new HttpConversation(this, id); HttpConversation existing = conversations.putIfAbsent(id, conversation); @@ -389,7 +411,7 @@ public class HttpClient extends ContainerLifeCycle { for (ProtocolHandler handler : getProtocolHandlers()) { - if (handler.accept(request, response)) + if (handler.accept(request, response)) return handler; } return null; @@ -405,6 +427,16 @@ public class HttpClient extends ContainerLifeCycle this.byteBufferPool = byteBufferPool; } + public long getConnectTimeout() + { + return connectTimeout; + } + + public void setConnectTimeout(long connectTimeout) + { + this.connectTimeout = connectTimeout; + } + public long getIdleTimeout() { return idleTimeout; @@ -596,11 +628,11 @@ public class HttpClient extends ContainerLifeCycle HttpDestination destination = callback.destination; SslContextFactory sslContextFactory = getSslContextFactory(); - if ("https".equals(destination.scheme())) + if ("https".equals(destination.getScheme())) { if (sslContextFactory == null) { - IOException failure = new ConnectException("Missing " + SslContextFactory.class.getSimpleName() + " for " + destination.scheme() + " requests"); + IOException failure = new ConnectException("Missing " + SslContextFactory.class.getSimpleName() + " for " + destination.getScheme() + " requests"); callback.failed(null, failure); throw failure; } diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpConnection.java b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpConnection.java index bbfad72d9e0..aae92bcac98 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpConnection.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpConnection.java @@ -21,6 +21,7 @@ package org.eclipse.jetty.client; import java.io.UnsupportedEncodingException; import java.net.URLEncoder; import java.nio.charset.UnsupportedCharsetException; +import java.util.Collections; import java.util.Enumeration; import java.util.Iterator; import java.util.List; @@ -102,52 +103,60 @@ public class HttpConnection extends AbstractConnection implements Connection } @Override - public void send(Request request, Response.Listener listener) + public void send(Request request, Response.CompleteListener listener) + { + send(request, Collections.singletonList(listener)); + } + + public void send(Request request, List listeners) { normalizeRequest(request); // Save the old idle timeout to restore it EndPoint endPoint = getEndPoint(); idleTimeout = endPoint.getIdleTimeout(); - endPoint.setIdleTimeout(request.idleTimeout()); + endPoint.setIdleTimeout(request.getIdleTimeout()); - HttpConversation conversation = client.getConversation(request.conversation()); - HttpExchange exchange = new HttpExchange(conversation, this, request, listener); + HttpConversation conversation = client.getConversation(request.getConversationID(), true); + HttpExchange exchange = new HttpExchange(conversation, this, request, listeners); setExchange(exchange); - conversation.exchanges().offer(exchange); - conversation.listener(listener); + conversation.getExchanges().offer(exchange); + + for (Response.ResponseListener listener : listeners) + if (listener instanceof Schedulable) + ((Schedulable)listener).schedule(client.getScheduler()); sender.send(exchange); } private void normalizeRequest(Request request) { - if (request.method() == null) + if (request.getMethod() == null) request.method(HttpMethod.GET); - if (request.version() == null) + if (request.getVersion() == null) request.version(HttpVersion.HTTP_1_1); - if (request.agent() == null) + if (request.getAgent() == null) request.agent(client.getUserAgent()); - if (request.idleTimeout() <= 0) + if (request.getIdleTimeout() <= 0) request.idleTimeout(client.getIdleTimeout()); - HttpMethod method = request.method(); - HttpVersion version = request.version(); - HttpFields headers = request.headers(); - ContentProvider content = request.content(); + HttpMethod method = request.getMethod(); + HttpVersion version = request.getVersion(); + HttpFields headers = request.getHeaders(); + ContentProvider content = request.getContent(); // Make sure the path is there - String path = request.path(); + String path = request.getPath(); if (path.matches("\\s*")) { path = "/"; request.path(path); } - Fields fields = request.params(); + Fields fields = request.getParams(); if (!fields.isEmpty()) { StringBuilder params = new StringBuilder(); @@ -167,7 +176,7 @@ public class HttpConnection extends AbstractConnection implements Connection } // Behave as a GET, adding the params to the path, if it's a POST with some content - if (method == HttpMethod.POST && request.content() != null) + if (method == HttpMethod.POST && request.getContent() != null) method = HttpMethod.GET; switch (method) @@ -193,8 +202,8 @@ public class HttpConnection extends AbstractConnection implements Connection { if (!headers.containsKey(HttpHeader.HOST.asString())) { - String value = request.host(); - int port = request.port(); + String value = request.getHost(); + int port = request.getPort(); if (port > 0) value += ":" + port; headers.put(HttpHeader.HOST, value); @@ -204,7 +213,7 @@ public class HttpConnection extends AbstractConnection implements Connection // Add content headers if (content != null) { - long contentLength = content.length(); + long contentLength = content.getLength(); if (contentLength >= 0) { if (!headers.containsKey(HttpHeader.CONTENT_LENGTH.asString())) @@ -218,7 +227,7 @@ public class HttpConnection extends AbstractConnection implements Connection } // Cookies - List cookies = client.getCookieStore().findCookies(getDestination(), request.path()); + List cookies = client.getCookieStore().findCookies(getDestination(), request.getPath()); StringBuilder cookieString = null; for (int i = 0; i < cookies.size(); ++i) { @@ -233,7 +242,7 @@ public class HttpConnection extends AbstractConnection implements Connection request.header(HttpHeader.COOKIE.asString(), cookieString.toString()); // Authorization - Authentication.Result authnResult = client.getAuthenticationStore().findAuthenticationResult(request.uri()); + Authentication.Result authnResult = client.getAuthenticationStore().findAuthenticationResult(request.getURI()); if (authnResult != null) authnResult.apply(request); @@ -307,13 +316,15 @@ public class HttpConnection extends AbstractConnection implements Connection HttpExchange existing = this.exchange.getAndSet(null); if (existing == exchange) { + exchange.awaitTermination(); + // Restore idle timeout getEndPoint().setIdleTimeout(idleTimeout); LOG.debug("{} disassociated from {}", exchange, this); if (success) { - HttpFields responseHeaders = exchange.response().headers(); + HttpFields responseHeaders = exchange.getResponse().getHeaders(); Enumeration values = responseHeaders.getValues(HttpHeader.CONNECTION.asString(), ","); if (values != null) { @@ -348,9 +359,13 @@ public class HttpConnection extends AbstractConnection implements Connection } } - public void abort(HttpResponse response) + public boolean abort(HttpExchange exchange, String reason) { - receiver.fail(new HttpResponseException("Response aborted", response)); + // We want the return value to be that of the response + // because if the response has already successfully + // arrived then we failed to abort the exchange + sender.abort(exchange, reason); + return receiver.abort(exchange, reason); } public void proceed(boolean proceed) diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpContentResponse.java b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpContentResponse.java index ea76d9d32d2..aa9dd777eab 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpContentResponse.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpContentResponse.java @@ -20,6 +20,7 @@ package org.eclipse.jetty.client; import java.io.UnsupportedEncodingException; import java.nio.charset.UnsupportedCharsetException; +import java.util.List; import org.eclipse.jetty.client.api.ContentResponse; import org.eclipse.jetty.client.api.Response; @@ -40,60 +41,60 @@ public class HttpContentResponse implements ContentResponse } @Override - public long conversation() + public long getConversationID() { - return response.conversation(); + return response.getConversationID(); } @Override - public Listener listener() + public List getListeners(Class listenerClass) { - return response.listener(); + return response.getListeners(listenerClass); } @Override - public HttpVersion version() + public HttpVersion getVersion() { - return response.version(); + return response.getVersion(); } @Override - public int status() + public int getStatus() { - return response.status(); + return response.getStatus(); } @Override - public String reason() + public String getReason() { - return response.reason(); + return response.getReason(); } @Override - public HttpFields headers() + public HttpFields getHeaders() { - return response.headers(); + return response.getHeaders(); } @Override - public void abort() + public boolean abort(String reason) { - response.abort(); + return response.abort(reason); } @Override - public byte[] content() + public byte[] getContent() { return content; } @Override - public String contentAsString() + public String getContentAsString() { String encoding = this.encoding; try { - return new String(content(), encoding == null ? "UTF-8" : encoding); + return new String(getContent(), encoding == null ? "UTF-8" : encoding); } catch (UnsupportedEncodingException e) { @@ -106,9 +107,9 @@ public class HttpContentResponse implements ContentResponse { return String.format("%s[%s %d %s - %d bytes]", HttpContentResponse.class.getSimpleName(), - version(), - status(), - reason(), - content().length); + getVersion(), + getStatus(), + getReason(), + getContent().length); } } diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpConversation.java b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpConversation.java index 1b4f7a4818e..bacb391e20e 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpConversation.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpConversation.java @@ -21,6 +21,7 @@ package org.eclipse.jetty.client; import java.util.Collections; import java.util.Deque; import java.util.Enumeration; +import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentLinkedDeque; @@ -34,8 +35,7 @@ public class HttpConversation implements Attributes private final Deque exchanges = new ConcurrentLinkedDeque<>(); private final HttpClient client; private final long id; - private volatile Response.Listener listener; - private volatile HttpExchange last; + private volatile List listeners; public HttpConversation(HttpClient client, long id) { @@ -48,40 +48,19 @@ public class HttpConversation implements Attributes return id; } - public Deque exchanges() + public Deque getExchanges() { return exchanges; } - public Response.Listener listener() + public List getResponseListeners() { - return listener; + return listeners; } - public void listener(Response.Listener listener) + public void setResponseListeners(List listeners) { - this.listener = listener; - } - - /** - * @return the exchange that has been identified as the last of this conversation - * @see #last(HttpExchange) - */ - public HttpExchange last() - { - return last; - } - - /** - * Remembers the given {@code exchange} as the last of this conversation. - * - * @param exchange the exchange that is the last of this conversation - * @see #last() - */ - public void last(HttpExchange exchange) - { - if (last == null) - last = exchange; + this.listeners = listeners; } public void complete() @@ -119,6 +98,12 @@ public class HttpConversation implements Attributes attributes.clear(); } + public boolean abort(String reason) + { + HttpExchange exchange = exchanges.peekLast(); + return exchange != null && exchange.abort(reason); + } + @Override public String toString() { diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpCookieParser.java b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpCookieParser.java index 8a7fbca3772..0651fe2636c 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpCookieParser.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpCookieParser.java @@ -44,7 +44,7 @@ public class HttpCookieParser public static List parseCookies(String headerValue) { - if (headerValue.toLowerCase().contains("expires=")) + if (headerValue.toLowerCase(Locale.ENGLISH).contains("expires=")) { HttpCookie cookie = parseCookie(headerValue, 0); if (cookie != null) @@ -111,7 +111,7 @@ public class HttpCookieParser try { String[] attributeParts = cookieParts[i].split("=", 2); - String attributeName = attributeParts[0].trim().toLowerCase(); + String attributeName = attributeParts[0].trim().toLowerCase(Locale.ENGLISH); String attributeValue = attributeParts.length < 2 ? "" : attributeParts[1].trim(); switch (attributeName) { diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpCookieStore.java b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpCookieStore.java index 043447b3578..c30ec560fb0 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpCookieStore.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpCookieStore.java @@ -39,8 +39,8 @@ public class HttpCookieStore implements CookieStore { List result = new ArrayList<>(); - String host = destination.host(); - int port = destination.port(); + String host = destination.getHost(); + int port = destination.getPort(); String key = host + ":" + port + path; // First lookup: direct hit @@ -83,7 +83,7 @@ public class HttpCookieStore implements CookieStore } else { - if (!"https".equalsIgnoreCase(destination.scheme()) && cookie.isSecure()) + if (!"https".equalsIgnoreCase(destination.getScheme()) && cookie.isSecure()) continue; result.add(cookie); } @@ -93,7 +93,7 @@ public class HttpCookieStore implements CookieStore @Override public boolean addCookie(Destination destination, HttpCookie cookie) { - String destinationDomain = destination.host() + ":" + destination.port(); + String destinationDomain = destination.getHost() + ":" + destination.getPort(); // Check whether it is the same domain String domain = cookie.getDomain(); @@ -101,7 +101,7 @@ public class HttpCookieStore implements CookieStore domain = destinationDomain; if (domain.indexOf(':') < 0) - domain += ":" + ("https".equalsIgnoreCase(destination.scheme()) ? 443 : 80); + domain += ":" + ("https".equalsIgnoreCase(destination.getScheme()) ? 443 : 80); // Cookie domains may start with a ".", like ".domain.com" // This also avoids that a request to sub.domain.com sets a cookie for domain.com @@ -113,7 +113,7 @@ public class HttpCookieStore implements CookieStore if (path == null || path.length() == 0) path = "/"; - String key = destination.host() + ":" + destination.port() + path; + String key = destination.getHost() + ":" + destination.getPort() + path; Queue cookies = allCookies.get(key); if (cookies == null) { diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpDestination.java b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpDestination.java index 380d4e1890a..489826a477b 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpDestination.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpDestination.java @@ -50,7 +50,7 @@ public class HttpDestination implements Destination, AutoCloseable, Dumpable private final String scheme; private final String host; private final int port; - private final Queue requests; + private final Queue requests; private final BlockingQueue idleConnections; private final BlockingQueue activeConnections; private final RequestNotifier requestNotifier; @@ -80,39 +80,39 @@ public class HttpDestination implements Destination, AutoCloseable, Dumpable } @Override - public String scheme() + public String getScheme() { return scheme; } @Override - public String host() + public String getHost() { return host; } @Override - public int port() + public int getPort() { return port; } - public void send(Request request, Response.Listener listener) + public void send(Request request, List listeners) { - if (!scheme.equals(request.scheme())) - throw new IllegalArgumentException("Invalid request scheme " + request.scheme() + " for destination " + this); - if (!host.equals(request.host())) - throw new IllegalArgumentException("Invalid request host " + request.host() + " for destination " + this); - int port = request.port(); + if (!scheme.equals(request.getScheme())) + throw new IllegalArgumentException("Invalid request scheme " + request.getScheme() + " for destination " + this); + if (!host.equals(request.getHost())) + throw new IllegalArgumentException("Invalid request host " + request.getHost() + " for destination " + this); + int port = request.getPort(); if (port >= 0 && this.port != port) throw new IllegalArgumentException("Invalid request port " + port + " for destination " + this); - RequestPair requestPair = new RequestPair(request, listener); + RequestContext requestContext = new RequestContext(request, listeners); if (client.isRunning()) { - if (requests.offer(requestPair)) + if (requests.offer(requestContext)) { - if (!client.isRunning() && requests.remove(requestPair)) + if (!client.isRunning() && requests.remove(requestContext)) { throw new RejectedExecutionException(client + " is stopping"); } @@ -189,12 +189,7 @@ public class HttpDestination implements Destination, AutoCloseable, Dumpable @Override public void run() { - RequestPair pair = requests.poll(); - if (pair != null) - { - requestNotifier.notifyFailure(pair.request, x); - responseNotifier.notifyComplete(pair.listener, new Result(pair.request, x, null)); - } + drain(x); } }); } @@ -205,6 +200,20 @@ public class HttpDestination implements Destination, AutoCloseable, Dumpable } } + private void drain(Throwable x) + { + RequestContext requestContext; + while ((requestContext = requests.poll()) != null) + { + Request request = requestContext.request; + requestNotifier.notifyFailure(request, x); + List listeners = requestContext.listeners; + HttpResponse response = new HttpResponse(request, listeners); + responseNotifier.notifyFailure(listeners, response, x); + responseNotifier.notifyComplete(listeners, new Result(request, x, response, x)); + } + } + /** *

Processes a new connection making it idle or active depending on whether requests are waiting to be sent.

*

A new connection is created when a request needs to be executed; it is possible that the request that @@ -214,45 +223,58 @@ public class HttpDestination implements Destination, AutoCloseable, Dumpable * * @param connection the new connection */ - protected void process(final Connection connection, boolean dispatch) + protected void process(Connection connection, boolean dispatch) { - final RequestPair requestPair = requests.poll(); - if (requestPair == null) + // Ugly cast, but lack of generic reification forces it + final HttpConnection httpConnection = (HttpConnection)connection; + + RequestContext requestContext = requests.poll(); + if (requestContext == null) { - LOG.debug("{} idle", connection); - if (!idleConnections.offer(connection)) + LOG.debug("{} idle", httpConnection); + if (!idleConnections.offer(httpConnection)) { LOG.debug("{} idle overflow"); - connection.close(); + httpConnection.close(); } if (!client.isRunning()) { LOG.debug("{} is stopping", client); - remove(connection); - connection.close(); + remove(httpConnection); + httpConnection.close(); } } else { - LOG.debug("{} active", connection); - if (!activeConnections.offer(connection)) + final Request request = requestContext.request; + final List listeners = requestContext.listeners; + if (request.isAborted()) { - LOG.warn("{} active overflow"); - } - if (dispatch) - { - client.getExecutor().execute(new Runnable() - { - @Override - public void run() - { - connection.send(requestPair.request, requestPair.listener); - } - }); + abort(request, listeners, "Aborted"); + LOG.debug("Aborted {} before processing", request); } else { - connection.send(requestPair.request, requestPair.listener); + LOG.debug("{} active", httpConnection); + if (!activeConnections.offer(httpConnection)) + { + LOG.warn("{} active overflow"); + } + if (dispatch) + { + client.getExecutor().execute(new Runnable() + { + @Override + public void run() + { + httpConnection.send(request, listeners); + } + }); + } + else + { + httpConnection.send(request, listeners); + } } } } @@ -283,7 +305,7 @@ public class HttpDestination implements Destination, AutoCloseable, Dumpable activeConnections.remove(connection); idleConnections.remove(connection); - // We need to executed queued requests even if this connection failed. + // We need to execute queued requests even if this connection failed. // We may create a connection that is not needed, but it will eventually // idle timeout, so no worries if (!requests.isEmpty()) @@ -305,19 +327,40 @@ public class HttpDestination implements Destination, AutoCloseable, Dumpable connection.close(); activeConnections.clear(); - AsynchronousCloseException failure = new AsynchronousCloseException(); - RequestPair pair; - while ((pair = requests.poll()) != null) - { - requestNotifier.notifyFailure(pair.request, failure); - responseNotifier.notifyComplete(pair.listener, new Result(pair.request, failure, null)); - } + drain(new AsynchronousCloseException()); connectionCount.set(0); LOG.debug("Closed {}", this); } + public boolean abort(Request request, String reason) + { + for (RequestContext requestContext : requests) + { + if (requestContext.request == request) + { + if (requests.remove(requestContext)) + { + // We were able to remove the pair, so it won't be processed + abort(request, requestContext.listeners, reason); + LOG.debug("Aborted {} while queued", request); + return true; + } + } + } + return false; + } + + private void abort(Request request, List listeners, String reason) + { + HttpResponse response = new HttpResponse(request, listeners); + HttpResponseException responseFailure = new HttpResponseException(reason, response); + responseNotifier.notifyFailure(listeners, response, responseFailure); + HttpRequestException requestFailure = new HttpRequestException(reason, request); + responseNotifier.notifyComplete(listeners, new Result(request, requestFailure, response, responseFailure)); + } + @Override public String dump() { @@ -339,18 +382,18 @@ public class HttpDestination implements Destination, AutoCloseable, Dumpable @Override public String toString() { - return String.format("%s(%s://%s:%d)", HttpDestination.class.getSimpleName(), scheme(), host(), port()); + return String.format("%s(%s://%s:%d)", HttpDestination.class.getSimpleName(), getScheme(), getHost(), getPort()); } - private static class RequestPair + private static class RequestContext { private final Request request; - private final Response.Listener listener; + private final List listeners; - public RequestPair(Request request, Response.Listener listener) + private RequestContext(Request request, List listeners) { this.request = request; - this.listener = listener; + this.listeners = listeners; } } } diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpExchange.java b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpExchange.java index 2905af672e7..8abcd3d2201 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpExchange.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpExchange.java @@ -18,7 +18,10 @@ package org.eclipse.jetty.client; +import java.util.List; +import java.util.concurrent.CountDownLatch; import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicMarkableReference; import org.eclipse.jetty.client.api.Request; import org.eclipse.jetty.client.api.Response; @@ -31,79 +34,95 @@ public class HttpExchange private static final Logger LOG = Log.getLogger(HttpExchange.class); private final AtomicInteger complete = new AtomicInteger(); + private final CountDownLatch terminate = new CountDownLatch(2); private final HttpConversation conversation; private final HttpConnection connection; private final Request request; - private final Response.Listener listener; + private final List listeners; private final HttpResponse response; + private volatile boolean last; private volatile Throwable requestFailure; private volatile Throwable responseFailure; - public HttpExchange(HttpConversation conversation, HttpConnection connection, Request request, Response.Listener listener) + public HttpExchange(HttpConversation conversation, HttpConnection connection, Request request, List listeners) { this.conversation = conversation; this.connection = connection; this.request = request; - this.listener = listener; - this.response = new HttpResponse(this, listener); + this.listeners = listeners; + this.response = new HttpResponse(request, listeners); } - public HttpConversation conversation() + public HttpConversation getConversation() { return conversation; } - public Request request() + public Request getRequest() { return request; } - public Throwable requestFailure() + public Throwable getRequestFailure() { return requestFailure; } - public Response.Listener listener() + public List getResponseListeners() { - return listener; + return listeners; } - public HttpResponse response() + public HttpResponse getResponse() { return response; } - public Throwable responseFailure() + public Throwable getResponseFailure() { return responseFailure; } + /** + * @return whether this exchange is the last in the conversation + */ + public boolean isLast() + { + return last; + } + + /** + * @param last whether this exchange is the last in the conversation + */ + public void setLast(boolean last) + { + this.last = last; + } + public void receive() { connection.receive(); } - public Result requestComplete(Throwable failure) + public AtomicMarkableReference requestComplete(Throwable failure) { - this.requestFailure = failure; int requestSuccess = 0b0011; int requestFailure = 0b0001; - return complete(failure == null ? requestSuccess : requestFailure); + return complete(failure == null ? requestSuccess : requestFailure, failure); } - public Result responseComplete(Throwable failure) + public AtomicMarkableReference responseComplete(Throwable failure) { - this.responseFailure = failure; if (failure == null) { int responseSuccess = 0b1100; - return complete(responseSuccess); + return complete(responseSuccess, failure); } else { proceed(false); int responseFailure = 0b0100; - return complete(responseFailure); + return complete(responseFailure, failure); } } @@ -121,29 +140,65 @@ public class HttpExchange * whether the exchange is completed and whether is successful. * * @param code the bits representing the status code for either the request or the response - * @return the result if the exchange completed, or null if the exchange did not complete + * @param failure the failure - if any - associated with the status code for either the request or the response + * @return an AtomicMarkableReference holding whether the operation modified the + * completion status and the {@link Result} - if any - associated with the status */ - private Result complete(int code) + private AtomicMarkableReference complete(int code, Throwable failure) { - int status = complete.addAndGet(code); - int completed = 0b0101; - if ((status & completed) == completed) + Result result = null; + boolean modified = false; + + int current; + while (true) { - boolean success = status == 0b1111; - LOG.debug("{} complete success={}", this, success); - // Request and response completed - if (this == conversation.last()) - conversation.complete(); - connection.complete(this, success); - return new Result(request(), requestFailure(), response(), responseFailure()); + current = complete.get(); + boolean updateable = (current & code) == 0; + if (updateable) + { + int candidate = current | code; + if (!complete.compareAndSet(current, candidate)) + continue; + current = candidate; + modified = true; + if ((code & 0b01) == 0b01) + requestFailure = failure; + else + responseFailure = failure; + LOG.debug("{} updated", this); + } + break; } - return null; + + int completed = 0b0101; + if ((current & completed) == completed) + { + if (modified) + { + // Request and response completed + LOG.debug("{} complete", this); + if (isLast()) + { + HttpExchange first = conversation.getExchanges().peekFirst(); + List listeners = first.getResponseListeners(); + for (Response.ResponseListener listener : listeners) + if (listener instanceof Schedulable) + ((Schedulable)listener).cancel(); + conversation.complete(); + } + } + result = new Result(getRequest(), getRequestFailure(), getResponse(), getResponseFailure()); + } + + return new AtomicMarkableReference<>(result, modified); } - public void abort() + public boolean abort(String reason) { - LOG.debug("Aborting {}", response); - connection.abort(response); + LOG.debug("Aborting {} reason {}", this, reason); + boolean aborted = connection.abort(this, reason); + LOG.debug("Aborted {}: {}", this, aborted); + return aborted; } public void resetResponse(boolean success) @@ -159,6 +214,28 @@ public class HttpExchange connection.proceed(proceed); } + public void terminateRequest() + { + terminate.countDown(); + } + + public void terminateResponse() + { + terminate.countDown(); + } + + public void awaitTermination() + { + try + { + terminate.await(); + } + catch (InterruptedException x) + { + LOG.ignore(x); + } + } + @Override public String toString() { diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpReceiver.java b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpReceiver.java index 724c376dd23..e8cdec6d1db 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpReceiver.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpReceiver.java @@ -20,9 +20,14 @@ package org.eclipse.jetty.client; import java.io.EOFException; import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.Collections; import java.util.Enumeration; import java.util.List; +import java.util.Locale; import java.util.concurrent.TimeoutException; +import java.util.concurrent.atomic.AtomicMarkableReference; +import java.util.concurrent.atomic.AtomicReference; import org.eclipse.jetty.client.api.CookieStore; import org.eclipse.jetty.client.api.Response; @@ -41,16 +46,16 @@ public class HttpReceiver implements HttpParser.ResponseHandler { private static final Logger LOG = Log.getLogger(HttpReceiver.class); + private final AtomicReference state = new AtomicReference<>(State.IDLE); private final HttpParser parser = new HttpParser(this); private final HttpConnection connection; - private final ResponseNotifier notifier; + private final ResponseNotifier responseNotifier; private ContentDecoder decoder; - private State state = State.IDLE; public HttpReceiver(HttpConnection connection) { this.connection = connection; - this.notifier = new ResponseNotifier(connection.getHttpClient()); + this.responseNotifier = new ResponseNotifier(connection.getHttpClient()); } public void receive() @@ -67,20 +72,16 @@ public class HttpReceiver implements HttpParser.ResponseHandler LOG.debug("Read {} bytes from {}", read, connection); if (read > 0) { - while (buffer.hasRemaining()) - parser.parseNext(buffer); + parse(buffer); } else if (read == 0) { - connection.fillInterested(); + fillInterested(); break; } else { - // Shutting down the parser may invoke messageComplete() or fail() - parser.shutdownInput(); - if (state == State.IDLE || state == State.RECEIVE) - fail(new EOFException()); + shutdown(); break; } } @@ -88,12 +89,12 @@ public class HttpReceiver implements HttpParser.ResponseHandler catch (EofException x) { LOG.ignore(x); - fail(x); + failAndClose(x); } catch (Exception x) { LOG.debug(x); - fail(x); + failAndClose(x); } finally { @@ -101,151 +102,221 @@ public class HttpReceiver implements HttpParser.ResponseHandler } } + private void parse(ByteBuffer buffer) + { + while (buffer.hasRemaining()) + parser.parseNext(buffer); + } + + private void fillInterested() + { + State state = this.state.get(); + if (state == State.IDLE || state == State.RECEIVE) + connection.fillInterested(); + } + + private void shutdown() + { + // Shutting down the parser may invoke messageComplete() or fail() + parser.shutdownInput(); + State state = this.state.get(); + if (state == State.IDLE || state == State.RECEIVE) + { + if (!fail(new EOFException())) + connection.close(); + } + } + @Override public boolean startResponse(HttpVersion version, int status, String reason) { - state = State.RECEIVE; - - HttpExchange exchange = connection.getExchange(); - HttpConversation conversation = exchange.conversation(); - HttpResponse response = exchange.response(); - - response.version(version).status(status).reason(reason); - - // Probe the protocol handlers - Response.Listener currentListener = exchange.listener(); - Response.Listener initialListener = conversation.exchanges().peekFirst().listener(); - HttpClient client = connection.getHttpClient(); - ProtocolHandler protocolHandler = client.findProtocolHandler(exchange.request(), response); - Response.Listener handlerListener = protocolHandler == null ? null : protocolHandler.getResponseListener(); - if (handlerListener == null) + if (updateState(State.IDLE, State.RECEIVE)) { - conversation.last(exchange); - if (currentListener == initialListener) - conversation.listener(initialListener); - else - conversation.listener(new DoubleResponseListener(currentListener, initialListener)); - } - else - { - LOG.debug("Found protocol handler {}", protocolHandler); - if (currentListener == initialListener) - conversation.listener(handlerListener); - else - conversation.listener(new DoubleResponseListener(currentListener, handlerListener)); - } + HttpExchange exchange = connection.getExchange(); + // The exchange may be null if it failed concurrently + if (exchange != null) + { + HttpConversation conversation = exchange.getConversation(); + HttpResponse response = exchange.getResponse(); - LOG.debug("Receiving {}", response); + response.version(version).status(status).reason(reason); - notifier.notifyBegin(conversation.listener(), response); + // Probe the protocol handlers + HttpExchange initialExchange = conversation.getExchanges().peekFirst(); + HttpClient client = connection.getHttpClient(); + ProtocolHandler protocolHandler = client.findProtocolHandler(exchange.getRequest(), response); + Response.Listener handlerListener = protocolHandler == null ? null : protocolHandler.getResponseListener(); + if (handlerListener == null) + { + exchange.setLast(true); + if (initialExchange == exchange) + { + conversation.setResponseListeners(exchange.getResponseListeners()); + } + else + { + List listeners = new ArrayList<>(exchange.getResponseListeners()); + listeners.addAll(initialExchange.getResponseListeners()); + conversation.setResponseListeners(listeners); + } + } + else + { + LOG.debug("Found protocol handler {}", protocolHandler); + if (initialExchange == exchange) + { + conversation.setResponseListeners(Collections.singletonList(handlerListener)); + } + else + { + List listeners = new ArrayList<>(exchange.getResponseListeners()); + listeners.add(handlerListener); + conversation.setResponseListeners(listeners); + } + } + + LOG.debug("Receiving {}", response); + responseNotifier.notifyBegin(conversation.getResponseListeners(), response); + } + } return false; } @Override public boolean parsedHeader(HttpHeader header, String name, String value) { - HttpExchange exchange = connection.getExchange(); - exchange.response().headers().add(name, value); - - switch (name.toLowerCase()) + if (updateState(State.RECEIVE, State.RECEIVE)) { - case "set-cookie": - case "set-cookie2": + HttpExchange exchange = connection.getExchange(); + // The exchange may be null if it failed concurrently + if (exchange != null) { - CookieStore cookieStore = connection.getHttpClient().getCookieStore(); - HttpDestination destination = connection.getDestination(); - List cookies = HttpCookieParser.parseCookies(value); - for (HttpCookie cookie : cookies) - cookieStore.addCookie(destination, cookie); - break; - } - default: - { - break; + exchange.getResponse().getHeaders().add(name, value); + switch (name.toLowerCase(Locale.ENGLISH)) + { + case "set-cookie": + case "set-cookie2": + { + CookieStore cookieStore = connection.getHttpClient().getCookieStore(); + HttpDestination destination = connection.getDestination(); + List cookies = HttpCookieParser.parseCookies(value); + for (HttpCookie cookie : cookies) + cookieStore.addCookie(destination, cookie); + break; + } + default: + { + break; + } + } } } - return false; } @Override public boolean headerComplete() { - HttpExchange exchange = connection.getExchange(); - HttpConversation conversation = exchange.conversation(); - HttpResponse response = exchange.response(); - LOG.debug("Headers {}", response); - notifier.notifyHeaders(conversation.listener(), response); - - Enumeration contentEncodings = response.headers().getValues(HttpHeader.CONTENT_ENCODING.asString(), ","); - if (contentEncodings != null) + if (updateState(State.RECEIVE, State.RECEIVE)) { - for (ContentDecoder.Factory factory : connection.getHttpClient().getContentDecoderFactories()) + HttpExchange exchange = connection.getExchange(); + // The exchange may be null if it failed concurrently + if (exchange != null) { - while (contentEncodings.hasMoreElements()) + HttpConversation conversation = exchange.getConversation(); + HttpResponse response = exchange.getResponse(); + LOG.debug("Headers {}", response); + responseNotifier.notifyHeaders(conversation.getResponseListeners(), response); + + Enumeration contentEncodings = response.getHeaders().getValues(HttpHeader.CONTENT_ENCODING.asString(), ","); + if (contentEncodings != null) { - if (factory.getEncoding().equalsIgnoreCase(contentEncodings.nextElement())) + for (ContentDecoder.Factory factory : connection.getHttpClient().getContentDecoderFactories()) { - this.decoder = factory.newContentDecoder(); - break; + while (contentEncodings.hasMoreElements()) + { + if (factory.getEncoding().equalsIgnoreCase(contentEncodings.nextElement())) + { + this.decoder = factory.newContentDecoder(); + break; + } + } } } } } - return false; } @Override public boolean content(ByteBuffer buffer) { - HttpExchange exchange = connection.getExchange(); - HttpConversation conversation = exchange.conversation(); - HttpResponse response = exchange.response(); - LOG.debug("Content {}: {} bytes", response, buffer.remaining()); - - ContentDecoder decoder = this.decoder; - if (decoder != null) + if (updateState(State.RECEIVE, State.RECEIVE)) { - buffer = decoder.decode(buffer); - LOG.debug("{} {}: {} bytes", decoder, response, buffer.remaining()); - } + HttpExchange exchange = connection.getExchange(); + // The exchange may be null if it failed concurrently + if (exchange != null) + { + HttpConversation conversation = exchange.getConversation(); + HttpResponse response = exchange.getResponse(); + LOG.debug("Content {}: {} bytes", response, buffer.remaining()); - notifier.notifyContent(conversation.listener(), response, buffer); + ContentDecoder decoder = this.decoder; + if (decoder != null) + { + buffer = decoder.decode(buffer); + LOG.debug("{} {}: {} bytes", decoder, response, buffer.remaining()); + } + + responseNotifier.notifyContent(conversation.getResponseListeners(), response, buffer); + } + } return false; } @Override - public boolean messageComplete(long contentLength) + public boolean messageComplete() { - HttpExchange exchange = connection.getExchange(); - // The exchange may be null if it was failed before - if (exchange != null && state == State.RECEIVE) + if (updateState(State.RECEIVE, State.RECEIVE)) success(); return true; } - protected void success() + protected boolean success() { - parser.reset(); - state = State.SUCCESS; - HttpExchange exchange = connection.getExchange(); - HttpResponse response = exchange.response(); + if (exchange == null) + return false; + + AtomicMarkableReference completion = exchange.responseComplete(null); + if (!completion.isMarked()) + return false; + + parser.reset(); + decoder = null; + + if (!updateState(State.RECEIVE, State.IDLE)) + throw new IllegalStateException(); + + exchange.terminateResponse(); + + HttpResponse response = exchange.getResponse(); + List listeners = exchange.getConversation().getResponseListeners(); + responseNotifier.notifySuccess(listeners, response); LOG.debug("Received {}", response); - Result result = exchange.responseComplete(null); - - HttpConversation conversation = exchange.conversation(); - notifier.notifySuccess(conversation.listener(), response); + Result result = completion.getReference(); if (result != null) { - notifier.notifyComplete(conversation.listener(), result); - reset(); + connection.complete(exchange, !result.isFailed()); + + responseNotifier.notifyComplete(listeners, result); } + + return true; } - protected void fail(Throwable failure) + protected boolean fail(Throwable failure) { HttpExchange exchange = connection.getExchange(); // In case of a response error, the failure has already been notified @@ -253,108 +324,84 @@ public class HttpReceiver implements HttpParser.ResponseHandler // loop throws an exception that reenters here but without exchange; // or, the server could just have timed out the connection. if (exchange == null) - return; + return false; + + AtomicMarkableReference completion = exchange.responseComplete(failure); + if (!completion.isMarked()) + return false; parser.close(); - state = State.FAILURE; + decoder = null; - HttpResponse response = exchange.response(); + while (true) + { + State current = state.get(); + if (updateState(current, State.FAILURE)) + break; + } + + exchange.terminateResponse(); + + HttpResponse response = exchange.getResponse(); + HttpConversation conversation = exchange.getConversation(); + responseNotifier.notifyFailure(conversation.getResponseListeners(), response, failure); LOG.debug("Failed {} {}", response, failure); - Result result = exchange.responseComplete(failure); - - HttpConversation conversation = exchange.conversation(); - notifier.notifyFailure(conversation.listener(), response, failure); + Result result = completion.getReference(); if (result != null) { - notifier.notifyComplete(conversation.listener(), result); - reset(); + connection.complete(exchange, false); + + responseNotifier.notifyComplete(conversation.getResponseListeners(), result); } + + return true; } @Override public boolean earlyEOF() { - fail(new EOFException()); + failAndClose(new EOFException()); return false; } + private void failAndClose(Throwable failure) + { + fail(failure); + connection.close(); + } + @Override public void badMessage(int status, String reason) { HttpExchange exchange = connection.getExchange(); - HttpResponse response = exchange.response(); + HttpResponse response = exchange.getResponse(); response.status(status).reason(reason); - fail(new HttpResponseException("HTTP protocol violation: bad response", response)); + failAndClose(new HttpResponseException("HTTP protocol violation: bad response", response)); } public void idleTimeout() { + // If we cannot fail, it means a response arrived + // just when we were timeout idling, so we don't close fail(new TimeoutException()); } - private void reset() + public boolean abort(HttpExchange exchange, String reason) { - decoder = null; - state = State.IDLE; + return fail(new HttpResponseException(reason == null ? "Response aborted" : reason, exchange.getResponse())); } - private class DoubleResponseListener implements Response.Listener + private boolean updateState(State from, State to) { - private final Response.Listener listener1; - private final Response.Listener listener2; - - private DoubleResponseListener(Response.Listener listener1, Response.Listener listener2) - { - this.listener1 = listener1; - this.listener2 = listener2; - } - - @Override - public void onBegin(Response response) - { - notifier.notifyBegin(listener1, response); - notifier.notifyBegin(listener2, response); - } - - @Override - public void onHeaders(Response response) - { - notifier.notifyHeaders(listener1, response); - notifier.notifyHeaders(listener2, response); - } - - @Override - public void onContent(Response response, ByteBuffer content) - { - notifier.notifyContent(listener1, response, content); - notifier.notifyContent(listener2, response, content); - } - - @Override - public void onSuccess(Response response) - { - notifier.notifySuccess(listener1, response); - notifier.notifySuccess(listener2, response); - } - - @Override - public void onFailure(Response response, Throwable failure) - { - notifier.notifyFailure(listener1, response, failure); - notifier.notifyFailure(listener2, response, failure); - } - - @Override - public void onComplete(Result result) - { - notifier.notifyComplete(listener1, result); - notifier.notifyComplete(listener2, result); - } + boolean updated = state.compareAndSet(from, to); + if (!updated) + LOG.debug("State update failed: {} -> {}: {}", from, to, state.get()); + return updated; } private enum State { - IDLE, RECEIVE, SUCCESS, FAILURE + IDLE, RECEIVE, FAILURE } } diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpRequest.java b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpRequest.java index 9837442296e..537c69966b3 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpRequest.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpRequest.java @@ -24,7 +24,9 @@ import java.net.URI; import java.net.URLDecoder; import java.nio.charset.UnsupportedCharsetException; import java.nio.file.Path; +import java.util.ArrayList; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.concurrent.Future; import java.util.concurrent.atomic.AtomicLong; @@ -48,8 +50,10 @@ public class HttpRequest implements Request private final HttpFields headers = new HttpFields(); private final Fields params = new Fields(); private final Map attributes = new HashMap<>(); + private final List requestListeners = new ArrayList<>(); + private final List responseListeners = new ArrayList<>(); private final HttpClient client; - private final long id; + private final long conversation; private final String host; private final int port; private String scheme; @@ -57,7 +61,6 @@ public class HttpRequest implements Request private HttpMethod method; private HttpVersion version; private long idleTimeout; - private Listener listener; private ContentProvider content; private boolean followRedirects; private volatile boolean aborted; @@ -67,10 +70,10 @@ public class HttpRequest implements Request this(client, ids.incrementAndGet(), uri); } - protected HttpRequest(HttpClient client, long id, URI uri) + protected HttpRequest(HttpClient client, long conversation, URI uri) { this.client = client; - this.id = id; + this.conversation = conversation; scheme(uri.getScheme()); host = uri.getHost(); port = uri.getPort(); @@ -101,13 +104,13 @@ public class HttpRequest implements Request } @Override - public long conversation() + public long getConversationID() { - return id; + return conversation; } @Override - public String scheme() + public String getScheme() { return scheme; } @@ -120,19 +123,19 @@ public class HttpRequest implements Request } @Override - public String host() + public String getHost() { return host; } @Override - public int port() + public int getPort() { return port; } @Override - public HttpMethod method() + public HttpMethod getMethod() { return method; } @@ -145,7 +148,7 @@ public class HttpRequest implements Request } @Override - public String path() + public String getPath() { return path; } @@ -158,19 +161,19 @@ public class HttpRequest implements Request } @Override - public String uri() + public String getURI() { - String scheme = scheme(); - String result = scheme + "://" + host(); - int port = port(); + String scheme = getScheme(); + String result = scheme + "://" + getHost(); + int port = getPort(); result += "http".equals(scheme) && port != 80 ? ":" + port : ""; result += "https".equals(scheme) && port != 443 ? ":" + port : ""; - result += path(); + result += getPath(); return result; } @Override - public HttpVersion version() + public HttpVersion getVersion() { return version; } @@ -190,13 +193,13 @@ public class HttpRequest implements Request } @Override - public Fields params() + public Fields getParams() { return params; } @Override - public String agent() + public String getAgent() { return headers.get(HttpHeader.USER_AGENT); } @@ -226,32 +229,106 @@ public class HttpRequest implements Request } @Override - public Map attributes() + public Map getAttributes() { return attributes; } @Override - public HttpFields headers() + public HttpFields getHeaders() { return headers; } @Override - public Listener listener() + public List getRequestListeners(Class type) { - return listener; + ArrayList result = new ArrayList<>(); + for (RequestListener listener : requestListeners) + if (type == null || type.isInstance(listener)) + result.add((T)listener); + return result; } @Override public Request listener(Request.Listener listener) { - this.listener = listener; + this.requestListeners.add(listener); return this; } @Override - public ContentProvider content() + public Request onRequestQueued(QueuedListener listener) + { + this.requestListeners.add(listener); + return this; + } + + @Override + public Request onRequestBegin(BeginListener listener) + { + this.requestListeners.add(listener); + return this; + } + + @Override + public Request onRequestHeaders(HeadersListener listener) + { + this.requestListeners.add(listener); + return this; + } + + @Override + public Request onRequestSuccess(SuccessListener listener) + { + this.requestListeners.add(listener); + return this; + } + + @Override + public Request onRequestFailure(FailureListener listener) + { + this.requestListeners.add(listener); + return this; + } + + @Override + public Request onResponseBegin(Response.BeginListener listener) + { + this.responseListeners.add(listener); + return this; + } + + @Override + public Request onResponseHeaders(Response.HeadersListener listener) + { + this.responseListeners.add(listener); + return this; + } + + @Override + public Request onResponseContent(Response.ContentListener listener) + { + this.responseListeners.add(listener); + return this; + } + + @Override + public Request onResponseSuccess(Response.SuccessListener listener) + { + this.responseListeners.add(listener); + return this; + } + + @Override + public Request onResponseFailure(Response.FailureListener listener) + { + this.responseListeners.add(listener); + return this; + } + + @Override + public ContentProvider getContent() { return content; } @@ -284,7 +361,7 @@ public class HttpRequest implements Request // } @Override - public boolean followRedirects() + public boolean isFollowRedirects() { return followRedirects; } @@ -297,7 +374,7 @@ public class HttpRequest implements Request } @Override - public long idleTimeout() + public long getIdleTimeout() { return idleTimeout; } @@ -312,25 +389,31 @@ public class HttpRequest implements Request @Override public Future send() { - BlockingResponseListener listener = new BlockingResponseListener(); + BlockingResponseListener listener = new BlockingResponseListener(this); send(listener); return listener; } @Override - public void send(final Response.Listener listener) + public void send(Response.CompleteListener listener) { - client.send(this, listener); + if (listener != null) + responseListeners.add(listener); + client.send(this, responseListeners); } @Override - public void abort() + public boolean abort(String reason) { aborted = true; + if (client.provideDestination(getScheme(), getHost(), getPort()).abort(this, reason)) + return true; + HttpConversation conversation = client.getConversation(getConversationID(), false); + return conversation != null && conversation.abort(reason); } @Override - public boolean aborted() + public boolean isAborted() { return aborted; } @@ -338,6 +421,6 @@ public class HttpRequest implements Request @Override public String toString() { - return String.format("%s[%s %s %s]@%x", HttpRequest.class.getSimpleName(), method(), path(), version(), hashCode()); + return String.format("%s[%s %s %s]@%x", HttpRequest.class.getSimpleName(), getMethod(), getPath(), getVersion(), hashCode()); } } diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpResponse.java b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpResponse.java index 0c4c3215d31..0b49f3be92e 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpResponse.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpResponse.java @@ -18,6 +18,10 @@ package org.eclipse.jetty.client; +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.jetty.client.api.Request; import org.eclipse.jetty.client.api.Response; import org.eclipse.jetty.http.HttpFields; import org.eclipse.jetty.http.HttpVersion; @@ -25,19 +29,19 @@ import org.eclipse.jetty.http.HttpVersion; public class HttpResponse implements Response { private final HttpFields headers = new HttpFields(); - private final HttpExchange exchange; - private final Listener listener; + private final Request request; + private final List listeners; private HttpVersion version; private int status; private String reason; - public HttpResponse(HttpExchange exchange, Listener listener) + public HttpResponse(Request request, List listeners) { - this.exchange = exchange; - this.listener = listener; + this.request = request; + this.listeners = listeners; } - public HttpVersion version() + public HttpVersion getVersion() { return version; } @@ -49,7 +53,7 @@ public class HttpResponse implements Response } @Override - public int status() + public int getStatus() { return status; } @@ -60,7 +64,7 @@ public class HttpResponse implements Response return this; } - public String reason() + public String getReason() { return reason; } @@ -72,32 +76,36 @@ public class HttpResponse implements Response } @Override - public HttpFields headers() + public HttpFields getHeaders() { return headers; } @Override - public long conversation() + public long getConversationID() { - return exchange.request().conversation(); + return request.getConversationID(); } @Override - public Listener listener() + public List getListeners(Class type) { - return listener; + ArrayList result = new ArrayList<>(); + for (ResponseListener listener : listeners) + if (type == null || type.isInstance(listener)) + result.add((T)listener); + return result; } @Override - public void abort() + public boolean abort(String reason) { - exchange.abort(); + return request.abort(reason); } @Override public String toString() { - return String.format("%s[%s %d %s]", HttpResponse.class.getSimpleName(), version(), status(), reason()); + return String.format("%s[%s %d %s]", HttpResponse.class.getSimpleName(), getVersion(), getStatus(), getReason()); } } diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpSender.java b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpSender.java index 5de75ff5c02..dabd10cbc12 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpSender.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpSender.java @@ -19,14 +19,18 @@ package org.eclipse.jetty.client; import java.nio.ByteBuffer; +import java.util.ArrayList; import java.util.Collections; import java.util.Iterator; +import java.util.List; import java.util.concurrent.CountDownLatch; import java.util.concurrent.Executor; +import java.util.concurrent.atomic.AtomicMarkableReference; import java.util.concurrent.atomic.AtomicReference; import org.eclipse.jetty.client.api.ContentProvider; import org.eclipse.jetty.client.api.Request; +import org.eclipse.jetty.client.api.Response; import org.eclipse.jetty.client.api.Result; import org.eclipse.jetty.http.HttpGenerator; import org.eclipse.jetty.http.HttpHeader; @@ -43,14 +47,13 @@ public class HttpSender private static final Logger LOG = Log.getLogger(HttpSender.class); private static final String EXPECT_100_ATTRIBUTE = HttpSender.class.getName() + ".expect100"; + private final AtomicReference state = new AtomicReference<>(State.IDLE); private final HttpGenerator generator = new HttpGenerator(); private final HttpConnection connection; private final RequestNotifier requestNotifier; private final ResponseNotifier responseNotifier; private Iterator contentIterator; private ContentInfo expectedContent; - private boolean committed; - private boolean failed; public HttpSender(HttpConnection connection) { @@ -61,16 +64,33 @@ public class HttpSender public void send(HttpExchange exchange) { - Request request = exchange.request(); - if (request.aborted()) + if (!updateState(State.IDLE, State.SEND)) + throw new IllegalStateException(); + + // Arrange the listeners, so that if there is a request failure the proper listeners are notified + HttpConversation conversation = exchange.getConversation(); + HttpExchange initialExchange = conversation.getExchanges().peekFirst(); + if (initialExchange == exchange) { - fail(new HttpRequestException("Request aborted", request)); + conversation.setResponseListeners(exchange.getResponseListeners()); + } + else + { + List listeners = new ArrayList<>(exchange.getResponseListeners()); + listeners.addAll(initialExchange.getResponseListeners()); + conversation.setResponseListeners(listeners); + } + + Request request = exchange.getRequest(); + if (request.isAborted()) + { + exchange.abort(null); } else { LOG.debug("Sending {}", request); requestNotifier.notifyBegin(request); - ContentProvider content = request.content(); + ContentProvider content = request.getContent(); this.contentIterator = content == null ? Collections.emptyIterator() : content.iterator(); send(); } @@ -81,11 +101,18 @@ public class HttpSender ContentInfo contentInfo = expectedContent; if (contentInfo != null) { - contentInfo.await(); if (proceed) + { + LOG.debug("Proceeding {}", connection.getExchange()); + contentInfo.await(); send(); + } else - fail(new HttpRequestException("Expectation failed", connection.getExchange().request())); + { + HttpExchange exchange = connection.getExchange(); + if (exchange != null) + fail(new HttpRequestException("Expectation failed", exchange.getRequest())); + } } } @@ -97,23 +124,26 @@ public class HttpSender ByteBuffer chunk = null; try { - EndPoint endPoint = connection.getEndPoint(); HttpExchange exchange = connection.getExchange(); - final Request request = exchange.request(); - HttpConversation conversation = client.getConversation(request.conversation()); + // The exchange may be null if it failed concurrently + if (exchange == null) + return; + + final Request request = exchange.getRequest(); + HttpConversation conversation = exchange.getConversation(); HttpGenerator.RequestInfo requestInfo = null; - boolean expect100 = request.headers().contains(HttpHeader.EXPECT, HttpHeaderValue.CONTINUE.asString()); + boolean expect100 = request.getHeaders().contains(HttpHeader.EXPECT, HttpHeaderValue.CONTINUE.asString()); expect100 &= conversation.getAttribute(EXPECT_100_ATTRIBUTE) == null; if (expect100) conversation.setAttribute(EXPECT_100_ATTRIBUTE, Boolean.TRUE); ContentInfo contentInfo = this.expectedContent; + this.expectedContent = null; if (contentInfo == null) contentInfo = new ContentInfo(contentIterator); else expect100 = false; - this.expectedContent = null; while (true) { @@ -122,9 +152,9 @@ public class HttpSender { case NEED_INFO: { - ContentProvider content = request.content(); - long contentLength = content == null ? -1 : content.length(); - requestInfo = new HttpGenerator.RequestInfo(request.version(), request.headers(), contentLength, request.method().asString(), request.path()); + ContentProvider content = request.getContent(); + long contentLength = content == null ? -1 : content.getLength(); + requestInfo = new HttpGenerator.RequestInfo(request.getVersion(), request.getHeaders(), contentLength, request.getMethod().asString(), request.getPath()); break; } case NEED_HEADER: @@ -139,76 +169,79 @@ public class HttpSender } case FLUSH: { - if (request.aborted()) + switch (state.get()) { - fail(new HttpRequestException("Request aborted", request)); - } - else - { - StatefulExecutorCallback callback = new StatefulExecutorCallback(client.getExecutor()) - { - @Override - protected void pendingCompleted() - { - LOG.debug("Write completed for {}", request); - - if (!committed) - committed(request); - - if (expectedContent == null) - { - send(); - } - else - { - LOG.debug("Expecting 100 Continue for {}", request); - expectedContent.ready(); - } - } - - @Override - protected void failed(Throwable x) - { - fail(x); - } - }; - - if (expect100) - { - // Save the expected content waiting for the 100 Continue response - expectedContent = contentInfo; - } - - write(callback, header, chunk, expect100 ? null : contentInfo.content); - - if (callback.pending()) - { - LOG.debug("Write pending for {}", request); + case SEND: + case COMMIT: + break; + default: return; - } + } - if (callback.completed()) + StatefulExecutorCallback callback = new StatefulExecutorCallback(client.getExecutor()) + { + @Override + protected void pendingCompleted() { - if (!committed) - committed(request); + LOG.debug("Write completed for {}", request); - if (expect100) - { - LOG.debug("Expecting 100 Continue for {}", request); - expectedContent.ready(); + if (!commit(request)) return; + + if (expectedContent == null) + { + send(); } else { - // Send further content - contentInfo = new ContentInfo(contentIterator); + LOG.debug("Expecting 100 Continue for {}", request); + expectedContent.ready(); } } + + @Override + protected void failed(Throwable x) + { + fail(x); + } + }; + + if (expect100) + { + // Save the expected content waiting for the 100 Continue response + expectedContent = contentInfo; + } + + write(callback, header, chunk, expect100 ? null : contentInfo.content); + + if (callback.pending()) + { + LOG.debug("Write pending for {}", request); + return; + } + + if (callback.completed()) + { + if (!commit(request)) + return; + + if (expect100) + { + LOG.debug("Expecting 100 Continue for {}", request); + expectedContent.ready(); + return; + } + else + { + // Send further content + contentInfo = new ContentInfo(contentIterator); + } } break; } case SHUTDOWN_OUT: { + EndPoint endPoint = connection.getEndPoint(); endPoint.shutdownOutput(); break; } @@ -218,7 +251,7 @@ public class HttpSender } case DONE: { - if (generator.isEnd() && !failed) + if (generator.isEnd()) success(); return; } @@ -282,63 +315,115 @@ public class HttpSender } } - protected void committed(Request request) + protected boolean commit(Request request) { - LOG.debug("Committed {}", request); - committed = true; - requestNotifier.notifyHeaders(request); + while (true) + { + State current = state.get(); + switch (current) + { + case SEND: + if (!updateState(current, State.COMMIT)) + continue; + LOG.debug("Committed {}", request); + requestNotifier.notifyHeaders(request); + return true; + case COMMIT: + return updateState(current, State.COMMIT); + default: + return false; + } + } } - protected void success() + protected boolean success() { - // Cleanup first - generator.reset(); - committed = false; - - // Notify after HttpExchange exchange = connection.getExchange(); - Request request = exchange.request(); + if (exchange == null) + return false; + + AtomicMarkableReference completion = exchange.requestComplete(null); + if (!completion.isMarked()) + return false; + + generator.reset(); + + if (!updateState(State.COMMIT, State.IDLE)) + throw new IllegalStateException(); + + exchange.terminateRequest(); + + // It is important to notify completion *after* we reset because + // the notification may trigger another request/response + + Request request = exchange.getRequest(); + requestNotifier.notifySuccess(request); LOG.debug("Sent {}", request); - Result result = exchange.requestComplete(null); - - // It is important to notify *after* we reset because - // the notification may trigger another request/response - requestNotifier.notifySuccess(request); + Result result = completion.getReference(); if (result != null) { - HttpConversation conversation = exchange.conversation(); - responseNotifier.notifyComplete(conversation.listener(), result); + connection.complete(exchange, !result.isFailed()); + + HttpConversation conversation = exchange.getConversation(); + responseNotifier.notifyComplete(conversation.getResponseListeners(), result); } + + return true; } - protected void fail(Throwable failure) + protected boolean fail(Throwable failure) { - // Cleanup first - generator.abort(); - failed = true; - - // Notify after HttpExchange exchange = connection.getExchange(); - Request request = exchange.request(); + if (exchange == null) + return false; + + AtomicMarkableReference completion = exchange.requestComplete(failure); + if (!completion.isMarked()) + return false; + + generator.abort(); + + State current; + while (true) + { + current = state.get(); + if (updateState(current, State.FAILURE)) + break; + } + + exchange.terminateRequest(); + + Request request = exchange.getRequest(); + requestNotifier.notifyFailure(request, failure); LOG.debug("Failed {} {}", request, failure); - Result result = exchange.requestComplete(failure); - if (result == null && !committed) - result = exchange.responseComplete(null); + Result result = completion.getReference(); + boolean notCommitted = current == State.IDLE || current == State.SEND; + if (result == null && notCommitted && !request.isAborted()) + { + result = exchange.responseComplete(failure).getReference(); + exchange.terminateResponse(); + LOG.debug("Failed on behalf {}", exchange); + } - // If the exchange is not completed, we need to shutdown the output - // to signal to the server that we're done (otherwise it may be - // waiting for more data that will not arrive) - if (result == null) - connection.getEndPoint().shutdownOutput(); - - requestNotifier.notifyFailure(request, failure); if (result != null) { - HttpConversation conversation = exchange.conversation(); - responseNotifier.notifyComplete(conversation.listener(), result); + connection.complete(exchange, false); + + HttpConversation conversation = exchange.getConversation(); + responseNotifier.notifyComplete(conversation.getResponseListeners(), result); } + + return true; + } + + public boolean abort(HttpExchange exchange, String reason) + { + State current = state.get(); + boolean abortable = current == State.IDLE || current == State.SEND || + current == State.COMMIT && contentIterator.hasNext(); + return abortable && fail(new HttpRequestException(reason == null ? "Request aborted" : reason, exchange.getRequest())); } private void releaseBuffers(ByteBufferPool bufferPool, ByteBuffer header, ByteBuffer chunk) @@ -349,6 +434,19 @@ public class HttpSender bufferPool.release(chunk); } + private boolean updateState(State from, State to) + { + boolean updated = state.compareAndSet(from, to); + if (!updated) + LOG.debug("State update failed: {} -> {}: {}", from, to, state.get()); + return updated; + } + + private enum State + { + IDLE, SEND, COMMIT, FAILURE + } + private static abstract class StatefulExecutorCallback implements Callback, Runnable { private final AtomicReference state = new AtomicReference<>(State.INCOMPLETE); @@ -456,7 +554,7 @@ public class HttpSender } catch (InterruptedException x) { - throw new IllegalStateException(x); + LOG.ignore(x); } } } diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/RedirectProtocolHandler.java b/jetty-client/src/main/java/org/eclipse/jetty/client/RedirectProtocolHandler.java index c600f802c89..c53b29e4be8 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/RedirectProtocolHandler.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/RedirectProtocolHandler.java @@ -18,15 +18,16 @@ package org.eclipse.jetty.client; +import java.util.List; + import org.eclipse.jetty.client.api.Request; import org.eclipse.jetty.client.api.Response; import org.eclipse.jetty.client.api.Result; -import org.eclipse.jetty.http.HttpFields; import org.eclipse.jetty.http.HttpMethod; public class RedirectProtocolHandler extends Response.Listener.Empty implements ProtocolHandler { - private static final String ATTRIBUTE = RedirectProtocolHandler.class.getName() + ".redirect"; + private static final String ATTRIBUTE = RedirectProtocolHandler.class.getName() + ".redirects"; private final HttpClient client; private final ResponseNotifier notifier; @@ -40,13 +41,13 @@ public class RedirectProtocolHandler extends Response.Listener.Empty implements @Override public boolean accept(Request request, Response response) { - switch (response.status()) + switch (response.getStatus()) { case 301: case 302: case 303: case 307: - return request.followRedirects(); + return request.isFollowRedirects(); } return false; } @@ -64,14 +65,14 @@ public class RedirectProtocolHandler extends Response.Listener.Empty implements { Request request = result.getRequest(); Response response = result.getResponse(); - String location = response.headers().get("location"); - int status = response.status(); + String location = response.getHeaders().get("location"); + int status = response.getStatus(); switch (status) { case 301: { - if (request.method() == HttpMethod.GET || request.method() == HttpMethod.HEAD) - redirect(result, request.method(), location); + if (request.getMethod() == HttpMethod.GET || request.getMethod() == HttpMethod.HEAD) + redirect(result, request.getMethod(), location); else fail(result, new HttpResponseException("HTTP protocol violation: received 301 for non GET or HEAD request", response)); break; @@ -86,7 +87,7 @@ public class RedirectProtocolHandler extends Response.Listener.Empty implements case 307: { // Keep same method - redirect(result, request.method(), location); + redirect(result, request.getMethod(), location); break; } default: @@ -104,8 +105,8 @@ public class RedirectProtocolHandler extends Response.Listener.Empty implements private void redirect(Result result, HttpMethod method, String location) { - Request request = result.getRequest(); - HttpConversation conversation = client.getConversation(request.conversation()); + final Request request = result.getRequest(); + HttpConversation conversation = client.getConversation(request.getConversationID(), false); Integer redirects = (Integer)conversation.getAttribute(ATTRIBUTE); if (redirects == null) redirects = 0; @@ -115,21 +116,22 @@ public class RedirectProtocolHandler extends Response.Listener.Empty implements ++redirects; conversation.setAttribute(ATTRIBUTE, redirects); - Request redirect = client.newRequest(request.conversation(), location); + Request redirect = client.copyRequest(request, location); // Use given method redirect.method(method); - redirect.version(request.version()); + redirect.onRequestBegin(new Request.BeginListener() + { + @Override + public void onBegin(Request redirect) + { + if (request.isAborted()) + redirect.abort(null); + } + }); - // Copy headers - for (HttpFields.Field header : request.headers()) - redirect.header(header.getName(), header.getValue()); - - // Copy content - redirect.content(request.content()); - - redirect.send(new Response.Listener.Empty()); + redirect.send(null); } else { @@ -141,10 +143,10 @@ public class RedirectProtocolHandler extends Response.Listener.Empty implements { Request request = result.getRequest(); Response response = result.getResponse(); - HttpConversation conversation = client.getConversation(request.conversation()); - Response.Listener listener = conversation.exchanges().peekFirst().listener(); - // TODO: should we reply all event, or just the failure ? - notifier.notifyFailure(listener, response, failure); - notifier.notifyComplete(listener, new Result(request, response, failure)); + HttpConversation conversation = client.getConversation(request.getConversationID(), false); + List listeners = conversation.getExchanges().peekFirst().getResponseListeners(); + // TODO: should we replay all events, or just the failure ? + notifier.notifyFailure(listeners, response, failure); + notifier.notifyComplete(listeners, new Result(request, response, failure)); } } diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/RequestNotifier.java b/jetty-client/src/main/java/org/eclipse/jetty/client/RequestNotifier.java index 0148b8dfd07..b04949b4852 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/RequestNotifier.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/RequestNotifier.java @@ -35,12 +35,13 @@ public class RequestNotifier public void notifyQueued(Request request) { - notifyQueued(request.listener(), request); + for (Request.QueuedListener listener : request.getRequestListeners(Request.QueuedListener.class)) + notifyQueued(listener, request); for (Request.Listener listener : client.getRequestListeners()) notifyQueued(listener, request); } - private void notifyQueued(Request.Listener listener, Request request) + private void notifyQueued(Request.QueuedListener listener, Request request) { try { @@ -55,12 +56,13 @@ public class RequestNotifier public void notifyBegin(Request request) { - notifyBegin(request.listener(), request); + for (Request.BeginListener listener : request.getRequestListeners(Request.BeginListener.class)) + notifyBegin(listener, request); for (Request.Listener listener : client.getRequestListeners()) notifyBegin(listener, request); } - private void notifyBegin(Request.Listener listener, Request request) + private void notifyBegin(Request.BeginListener listener, Request request) { try { @@ -75,12 +77,13 @@ public class RequestNotifier public void notifyHeaders(Request request) { - notifyHeaders(request.listener(), request); + for (Request.HeadersListener listener : request.getRequestListeners(Request.HeadersListener.class)) + notifyHeaders(listener, request); for (Request.Listener listener : client.getRequestListeners()) notifyHeaders(listener, request); } - private void notifyHeaders(Request.Listener listener, Request request) + private void notifyHeaders(Request.HeadersListener listener, Request request) { try { @@ -95,12 +98,13 @@ public class RequestNotifier public void notifySuccess(Request request) { - notifySuccess(request.listener(), request); + for (Request.SuccessListener listener : request.getRequestListeners(Request.SuccessListener.class)) + notifySuccess(listener, request); for (Request.Listener listener : client.getRequestListeners()) notifySuccess(listener, request); } - private void notifySuccess(Request.Listener listener, Request request) + private void notifySuccess(Request.SuccessListener listener, Request request) { try { @@ -115,12 +119,13 @@ public class RequestNotifier public void notifyFailure(Request request, Throwable failure) { - notifyFailure(request.listener(), request, failure); + for (Request.FailureListener listener : request.getRequestListeners(Request.FailureListener.class)) + notifyFailure(listener, request, failure); for (Request.Listener listener : client.getRequestListeners()) notifyFailure(listener, request, failure); } - private void notifyFailure(Request.Listener listener, Request request, Throwable failure) + private void notifyFailure(Request.FailureListener listener, Request request, Throwable failure) { try { diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/ResponseNotifier.java b/jetty-client/src/main/java/org/eclipse/jetty/client/ResponseNotifier.java index e1ac25dabfd..a1b64c6d2ee 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/ResponseNotifier.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/ResponseNotifier.java @@ -19,6 +19,7 @@ package org.eclipse.jetty.client; import java.nio.ByteBuffer; +import java.util.List; import org.eclipse.jetty.client.api.ContentResponse; import org.eclipse.jetty.client.api.Request; @@ -37,12 +38,18 @@ public class ResponseNotifier this.client = client; } - public void notifyBegin(Response.Listener listener, Response response) + public void notifyBegin(List listeners, Response response) + { + for (Response.ResponseListener listener : listeners) + if (listener instanceof Response.BeginListener) + notifyBegin((Response.BeginListener)listener, response); + } + + private void notifyBegin(Response.BeginListener listener, Response response) { try { - if (listener != null) - listener.onBegin(response); + listener.onBegin(response); } catch (Exception x) { @@ -50,12 +57,18 @@ public class ResponseNotifier } } - public void notifyHeaders(Response.Listener listener, Response response) + public void notifyHeaders(List listeners, Response response) + { + for (Response.ResponseListener listener : listeners) + if (listener instanceof Response.HeadersListener) + notifyHeaders((Response.HeadersListener)listener, response); + } + + private void notifyHeaders(Response.HeadersListener listener, Response response) { try { - if (listener != null) - listener.onHeaders(response); + listener.onHeaders(response); } catch (Exception x) { @@ -63,12 +76,19 @@ public class ResponseNotifier } } - public void notifyContent(Response.Listener listener, Response response, ByteBuffer buffer) + public void notifyContent(List listeners, Response response, ByteBuffer buffer) + { + for (Response.ResponseListener listener : listeners) + if (listener instanceof Response.ContentListener) + notifyContent((Response.ContentListener)listener, response, buffer); + + } + + private void notifyContent(Response.ContentListener listener, Response response, ByteBuffer buffer) { try { - if (listener != null) - listener.onContent(response, buffer); + listener.onContent(response, buffer); } catch (Exception x) { @@ -76,12 +96,18 @@ public class ResponseNotifier } } - public void notifySuccess(Response.Listener listener, Response response) + public void notifySuccess(List listeners, Response response) + { + for (Response.ResponseListener listener : listeners) + if (listener instanceof Response.SuccessListener) + notifySuccess((Response.SuccessListener)listener, response); + } + + private void notifySuccess(Response.SuccessListener listener, Response response) { try { - if (listener != null) - listener.onSuccess(response); + listener.onSuccess(response); } catch (Exception x) { @@ -89,12 +115,18 @@ public class ResponseNotifier } } - public void notifyFailure(Response.Listener listener, Response response, Throwable failure) + public void notifyFailure(List listeners, Response response, Throwable failure) + { + for (Response.ResponseListener listener : listeners) + if (listener instanceof Response.FailureListener) + notifyFailure((Response.FailureListener)listener, response, failure); + } + + private void notifyFailure(Response.FailureListener listener, Response response, Throwable failure) { try { - if (listener != null) - listener.onFailure(response, failure); + listener.onFailure(response, failure); } catch (Exception x) { @@ -102,12 +134,18 @@ public class ResponseNotifier } } - public void notifyComplete(Response.Listener listener, Result result) + public void notifyComplete(List listeners, Result result) + { + for (Response.ResponseListener listener : listeners) + if (listener instanceof Response.CompleteListener) + notifyComplete((Response.CompleteListener)listener, result); + } + + private void notifyComplete(Response.CompleteListener listener, Result result) { try { - if (listener != null) - listener.onComplete(result); + listener.onComplete(result); } catch (Exception x) { @@ -115,37 +153,37 @@ public class ResponseNotifier } } - public void forwardSuccess(Response.Listener listener, Response response) + public void forwardSuccess(List listeners, Response response) { - notifyBegin(listener, response); - notifyHeaders(listener, response); + notifyBegin(listeners, response); + notifyHeaders(listeners, response); if (response instanceof ContentResponse) - notifyContent(listener, response, ByteBuffer.wrap(((ContentResponse)response).content())); - notifySuccess(listener, response); + notifyContent(listeners, response, ByteBuffer.wrap(((ContentResponse)response).getContent())); + notifySuccess(listeners, response); } - public void forwardSuccessComplete(Response.Listener listener, Request request, Response response) + public void forwardSuccessComplete(List listeners, Request request, Response response) { - HttpConversation conversation = client.getConversation(request.conversation()); - forwardSuccess(listener, response); + HttpConversation conversation = client.getConversation(request.getConversationID(), false); + forwardSuccess(listeners, response); conversation.complete(); - notifyComplete(listener, new Result(request, response)); + notifyComplete(listeners, new Result(request, response)); } - public void forwardFailure(Response.Listener listener, Response response, Throwable failure) + public void forwardFailure(List listeners, Response response, Throwable failure) { - notifyBegin(listener, response); - notifyHeaders(listener, response); + notifyBegin(listeners, response); + notifyHeaders(listeners, response); if (response instanceof ContentResponse) - notifyContent(listener, response, ByteBuffer.wrap(((ContentResponse)response).content())); - notifyFailure(listener, response, failure); + notifyContent(listeners, response, ByteBuffer.wrap(((ContentResponse)response).getContent())); + notifyFailure(listeners, response, failure); } - public void forwardFailureComplete(Response.Listener listener, Request request, Throwable requestFailure, Response response, Throwable responseFailure) + public void forwardFailureComplete(List listeners, Request request, Throwable requestFailure, Response response, Throwable responseFailure) { - HttpConversation conversation = client.getConversation(request.conversation()); - forwardFailure(listener, response, responseFailure); + HttpConversation conversation = client.getConversation(request.getConversationID(), false); + forwardFailure(listeners, response, responseFailure); conversation.complete(); - notifyComplete(listener, new Result(request, requestFailure, response, responseFailure)); + notifyComplete(listeners, new Result(request, requestFailure, response, responseFailure)); } } diff --git a/jetty-client-old/src/main/java/org/eclipse/jetty/client/security/Realm.java b/jetty-client/src/main/java/org/eclipse/jetty/client/Schedulable.java similarity index 79% rename from jetty-client-old/src/main/java/org/eclipse/jetty/client/security/Realm.java rename to jetty-client/src/main/java/org/eclipse/jetty/client/Schedulable.java index 9414f6ddae9..cc97c4aa2fd 100644 --- a/jetty-client-old/src/main/java/org/eclipse/jetty/client/security/Realm.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/Schedulable.java @@ -16,17 +16,13 @@ // ======================================================================== // -package org.eclipse.jetty.client.security; +package org.eclipse.jetty.client; -/** - * Simple security realm interface. - */ -public interface Realm +import org.eclipse.jetty.util.thread.Scheduler; + +public interface Schedulable { - public String getId(); - - public String getPrincipal(); - - public String getCredentials(); + public boolean schedule(Scheduler scheduler); + public boolean cancel(); } diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/api/Connection.java b/jetty-client/src/main/java/org/eclipse/jetty/client/api/Connection.java index 23d963ca5c8..64b719447e2 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/api/Connection.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/api/Connection.java @@ -37,7 +37,7 @@ public interface Connection extends AutoCloseable * @param request the request to send * @param listener the response listener */ - void send(Request request, Response.Listener listener); + void send(Request request, Response.CompleteListener listener); @Override void close(); diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/api/ContentProvider.java b/jetty-client/src/main/java/org/eclipse/jetty/client/api/ContentProvider.java index 68d626e0056..39a1b141fe5 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/api/ContentProvider.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/api/ContentProvider.java @@ -36,5 +36,5 @@ public interface ContentProvider extends Iterable /** * @return the content length, if known, or -1 if the content length is unknown */ - long length(); + long getLength(); } diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/api/ContentResponse.java b/jetty-client/src/main/java/org/eclipse/jetty/client/api/ContentResponse.java index 98f99be288b..5e12cbfb11b 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/api/ContentResponse.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/api/ContentResponse.java @@ -26,11 +26,11 @@ public interface ContentResponse extends Response /** * @return the response content */ - byte[] content(); + byte[] getContent(); /** * @return the response content as a string, decoding the bytes using the charset * provided by the {@code Content-Type} header, if any, or UTF-8. */ - String contentAsString(); + String getContentAsString(); } diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/api/Destination.java b/jetty-client/src/main/java/org/eclipse/jetty/client/api/Destination.java index 3ed6524699c..daa808f71c4 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/api/Destination.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/api/Destination.java @@ -23,8 +23,8 @@ import java.util.concurrent.Future; import org.eclipse.jetty.client.HttpClient; /** - * {@link Destination} represents the triple made of the {@link #scheme()}, the {@link #host()} - * and the {@link #port()}. + * {@link Destination} represents the triple made of the {@link #getScheme}, the {@link #getHost} + * and the {@link #getPort}. *

* {@link Destination} holds a pool of {@link Connection}s, but allows to create unpooled * connections if the application wants full control over connection management via {@link #newConnection()}. @@ -36,17 +36,17 @@ public interface Destination /** * @return the scheme of this destination, such as "http" or "https" */ - String scheme(); + String getScheme(); /** * @return the host of this destination, such as "127.0.0.1" or "google.com" */ - String host(); + String getHost(); /** * @return the port of this destination such as 80 or 443 */ - int port(); + int getPort(); /** * @return a future to a new, unpooled, {@link Connection} diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/api/Request.java b/jetty-client/src/main/java/org/eclipse/jetty/client/api/Request.java index 72a4ab769c6..1d36b9e8894 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/api/Request.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/api/Request.java @@ -20,11 +20,12 @@ package org.eclipse.jetty.client.api; import java.io.IOException; import java.nio.file.Path; +import java.util.EventListener; +import java.util.List; import java.util.Map; import java.util.concurrent.Future; import org.eclipse.jetty.client.HttpClient; -import org.eclipse.jetty.client.util.InputStreamResponseListener; import org.eclipse.jetty.http.HttpFields; import org.eclipse.jetty.http.HttpMethod; import org.eclipse.jetty.http.HttpVersion; @@ -44,12 +45,12 @@ public interface Request /** * @return the conversation id */ - long conversation(); + long getConversationID(); /** * @return the scheme of this request, such as "http" or "https" */ - String scheme(); + String getScheme(); /** * @param scheme the scheme of this request, such as "http" or "https" @@ -60,17 +61,17 @@ public interface Request /** * @return the host of this request, such as "127.0.0.1" or "google.com" */ - String host(); + String getHost(); /** * @return the port of this request such as 80 or 443 */ - int port(); + int getPort(); /** * @return the method of this request, such as GET or POST */ - HttpMethod method(); + HttpMethod getMethod(); /** * @param method the method of this request, such as GET or POST @@ -81,7 +82,7 @@ public interface Request /** * @return the path of this request, such as "/" */ - String path(); + String getPath(); /** * @param path the path of this request, such as "/" @@ -92,12 +93,12 @@ public interface Request /** * @return the full URI of this request such as "http://host:port/path" */ - String uri(); + String getURI(); /** * @return the HTTP version of this request, such as "HTTP/1.1" */ - HttpVersion version(); + HttpVersion getVersion(); /** * @param version the HTTP version of this request, such as "HTTP/1.1" @@ -108,7 +109,7 @@ public interface Request /** * @return the query parameters of this request */ - Fields params(); + Fields getParams(); /** * @param name the name of the query parameter @@ -120,7 +121,7 @@ public interface Request /** * @return the headers of this request */ - HttpFields headers(); + HttpFields getHeaders(); /** * @param name the name of the header @@ -139,12 +140,12 @@ public interface Request /** * @return the attributes of this request */ - Map attributes(); + Map getAttributes(); /** * @return the content provider of this request */ - ContentProvider content(); + ContentProvider getContent(); /** * @param content the content provider of this request @@ -175,7 +176,7 @@ public interface Request /** * @return the user agent for this request */ - String agent(); + String getAgent(); /** * @param agent the user agent for this request @@ -186,7 +187,7 @@ public interface Request /** * @return the idle timeout for this request */ - long idleTimeout(); + long getIdleTimeout(); /** * @param timeout the idle timeout for this request @@ -197,7 +198,7 @@ public interface Request /** * @return whether this request follows redirects */ - boolean followRedirects(); + boolean isFollowRedirects(); /** * @param follow whether this request follows redirects @@ -206,16 +207,77 @@ public interface Request Request followRedirects(boolean follow); /** - * @return the listener for request events + * @param listenerClass the class of the listener, or null for all listeners classes + * @return the listeners for request events of the given class */ - Listener listener(); + List getRequestListeners(Class listenerClass); /** - * @param listener the listener for request events + * @param listener a listener for request events * @return this request object */ Request listener(Listener listener); + /** + * @param listener a listener for request queued event + * @return this request object + */ + Request onRequestQueued(QueuedListener listener); + + /** + * @param listener a listener for request begin event + * @return this request object + */ + Request onRequestBegin(BeginListener listener); + + /** + * @param listener a listener for request headers event + * @return this request object + */ + Request onRequestHeaders(HeadersListener listener); + + /** + * @param listener a listener for request success event + * @return this request object + */ + Request onRequestSuccess(SuccessListener listener); + + /** + * @param listener a listener for request failure event + * @return this request object + */ + Request onRequestFailure(FailureListener listener); + + /** + * @param listener a listener for response begin event + * @return this request object + */ + Request onResponseBegin(Response.BeginListener listener); + + /** + * @param listener a listener for response headers event + * @return this request object + */ + Request onResponseHeaders(Response.HeadersListener listener); + + /** + * @param listener a listener for response content events + * @return this request object + */ + Request onResponseContent(Response.ContentListener listener); + + /** + * @param listener a listener for response success event + * @return this request object + */ + Request onResponseSuccess(Response.SuccessListener listener); + + /** + * @param listener a listener for response failure event + * @return this request object + */ + Request onResponseFailure(Response.FailureListener listener); + /** * Sends this request and returns a {@link Future} that can be used to wait for the * request and the response to be completed (either with a success or a failure). @@ -241,24 +303,26 @@ public interface Request * * @param listener the listener that receives response events */ - void send(Response.Listener listener); + void send(Response.CompleteListener listener); /** * Attempts to abort the send of this request. * - * @see #aborted() + * @param reason the abort reason + * @return whether the abort succeeded */ - void abort(); + boolean abort(String reason); /** - * @return whether {@link #abort()} was called + * @return whether {@link #abort(String)} was called */ - boolean aborted(); + boolean isAborted(); - /** - * Listener for request events - */ - public interface Listener + public interface RequestListener extends EventListener + { + } + + public interface QueuedListener extends RequestListener { /** * Callback method invoked when the request is queued, waiting to be sent @@ -266,7 +330,10 @@ public interface Request * @param request the request being queued */ public void onQueued(Request request); + } + public interface BeginListener extends RequestListener + { /** * Callback method invoked when the request begins being processed in order to be sent. * This is the last opportunity to modify the request. @@ -274,7 +341,10 @@ public interface Request * @param request the request that begins being processed */ public void onBegin(Request request); + } + public interface HeadersListener extends RequestListener + { /** * Callback method invoked when the request headers (and perhaps small content) have been sent. * The request is now committed, and in transit to the server, and further modifications to the @@ -282,21 +352,33 @@ public interface Request * @param request the request that has been committed */ public void onHeaders(Request request); + } + public interface SuccessListener extends RequestListener + { /** * Callback method invoked when the request has been successfully sent. * * @param request the request sent */ public void onSuccess(Request request); + } + public interface FailureListener extends RequestListener + { /** * Callback method invoked when the request has failed to be sent * @param request the request that failed * @param failure the failure */ public void onFailure(Request request, Throwable failure); + } + /** + * Listener for all request events + */ + public interface Listener extends QueuedListener, BeginListener, HeadersListener, SuccessListener, FailureListener + { /** * An empty implementation of {@link Listener} */ diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/api/Response.java b/jetty-client/src/main/java/org/eclipse/jetty/client/api/Response.java index 8dd362cabd5..951d4853f66 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/api/Response.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/api/Response.java @@ -19,6 +19,8 @@ package org.eclipse.jetty.client.api; import java.nio.ByteBuffer; +import java.util.EventListener; +import java.util.List; import org.eclipse.jetty.client.util.BufferingResponseListener; import org.eclipse.jetty.http.HttpFields; @@ -39,42 +41,46 @@ public interface Response /** * @return the conversation id */ - long conversation(); + long getConversationID(); /** - * @return the response listener passed to {@link Request#send(Listener)} + * @return the response listener passed to {@link Request#send(CompleteListener)} */ - Listener listener(); + List getListeners(Class listenerClass); /** * @return the HTTP version of this response, such as "HTTP/1.1" */ - HttpVersion version(); + HttpVersion getVersion(); /** * @return the HTTP status code of this response, such as 200 or 404 */ - int status(); + int getStatus(); /** - * @return the HTTP reason associated to the {@link #status()} + * @return the HTTP reason associated to the {@link #getStatus} */ - String reason(); + String getReason(); /** * @return the headers of this response */ - HttpFields headers(); + HttpFields getHeaders(); /** - * Attempts to abort the send of this request. + * Attempts to abort the receive of this response. + * + * @param reason the abort reason + * @return whether the abort succeeded */ - void abort(); + boolean abort(String reason); - /** - * Listener for response events - */ - public interface Listener + public interface ResponseListener extends EventListener + { + } + + public interface BeginListener extends ResponseListener { /** * Callback method invoked when the response line containing HTTP version, @@ -85,14 +91,20 @@ public interface Response * @param response the response containing the response line data */ public void onBegin(Response response); + } + public interface HeadersListener extends ResponseListener + { /** * Callback method invoked when the response headers have been received and parsed. * * @param response the response containing the response line data and the headers */ public void onHeaders(Response response); + } + public interface ContentListener extends ResponseListener + { /** * Callback method invoked when the response content has been received. * This method may be invoked multiple times, and the {@code content} buffer must be consumed @@ -102,14 +114,20 @@ public interface Response * @param content the content bytes received */ public void onContent(Response response, ByteBuffer content); + } + public interface SuccessListener extends ResponseListener + { /** * Callback method invoked when the whole response has been successfully received. * * @param response the response containing the response line data and the headers */ public void onSuccess(Response response); + } + public interface FailureListener extends ResponseListener + { /** * Callback method invoked when the response has failed in the process of being received * @@ -117,7 +135,10 @@ public interface Response * @param failure the failure happened */ public void onFailure(Response response, Throwable failure); + } + public interface CompleteListener extends ResponseListener + { /** * Callback method invoked when the request and the response have been processed, * either successfully or not. @@ -126,13 +147,20 @@ public interface Response *

* Requests may complete after response, for example in case of big uploads that are * discarded or read asynchronously by the server. - * This method is always invoked after {@link #onSuccess(Response)} or - * {@link #onFailure(Response, Throwable)}, and only when request indicates that it is completed. + * This method is always invoked after {@link SuccessListener#onSuccess(Response)} or + * {@link FailureListener#onFailure(Response, Throwable)}, and only when request indicates that + * it is completed. * * @param result the result of the request / response exchange */ public void onComplete(Result result); + } + /** + * Listener for response events + */ + public interface Listener extends BeginListener, HeadersListener, ContentListener, SuccessListener, FailureListener, CompleteListener + { /** * An empty implementation of {@link Listener} */ diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/package-info.java b/jetty-client/src/main/java/org/eclipse/jetty/client/package-info.java index 3e4c1890950..a69688c435b 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/package-info.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/package-info.java @@ -36,7 +36,7 @@ *

* When a request is sent, its exchange is associated to a connection, either taken from an idle queue or created * anew, and when both the request and response are completed, the exchange is disassociated from the connection. - * Conversation may span multiple connections on different destinations, and therefore are maintained at the + * A conversation may span multiple connections on different destinations, and therefore are maintained at the * {@link HttpClient} level. *

* Applications may decide to send the request and wait for the response in a blocking way, using diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/util/BasicAuthentication.java b/jetty-client/src/main/java/org/eclipse/jetty/client/util/BasicAuthentication.java index 640b98f1c04..1df75c3953e 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/util/BasicAuthentication.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/util/BasicAuthentication.java @@ -63,7 +63,7 @@ public class BasicAuthentication implements Authentication try { String value = "Basic " + B64Code.encode(user + ":" + password, encoding); - return new BasicResult(request.uri(), value); + return new BasicResult(request.getURI(), value); } catch (UnsupportedEncodingException x) { @@ -91,7 +91,7 @@ public class BasicAuthentication implements Authentication @Override public void apply(Request request) { - if (request.uri().startsWith(uri)) + if (request.getURI().startsWith(uri)) request.header(HttpHeader.AUTHORIZATION.asString(), value); } diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/util/BlockingResponseListener.java b/jetty-client/src/main/java/org/eclipse/jetty/client/util/BlockingResponseListener.java index 6111320815b..bef0fbf305e 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/util/BlockingResponseListener.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/util/BlockingResponseListener.java @@ -18,7 +18,6 @@ package org.eclipse.jetty.client.util; -import java.nio.ByteBuffer; import java.util.concurrent.CancellationException; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutionException; @@ -28,44 +27,25 @@ import java.util.concurrent.TimeoutException; import org.eclipse.jetty.client.HttpContentResponse; import org.eclipse.jetty.client.api.ContentResponse; -import org.eclipse.jetty.client.api.Response; +import org.eclipse.jetty.client.api.Request; import org.eclipse.jetty.client.api.Result; public class BlockingResponseListener extends BufferingResponseListener implements Future { private final CountDownLatch latch = new CountDownLatch(1); + private final Request request; private ContentResponse response; private Throwable failure; private volatile boolean cancelled; - @Override - public void onBegin(Response response) + public BlockingResponseListener(Request request) { - super.onBegin(response); - if (cancelled) - response.abort(); - } - - @Override - public void onHeaders(Response response) - { - super.onHeaders(response); - if (cancelled) - response.abort(); - } - - @Override - public void onContent(Response response, ByteBuffer content) - { - super.onContent(response, content); - if (cancelled) - response.abort(); + this.request = request; } @Override public void onComplete(Result result) { - super.onComplete(result); response = new HttpContentResponse(result.getResponse(), getContent(), getEncoding()); failure = result.getFailure(); latch.countDown(); @@ -75,7 +55,7 @@ public class BlockingResponseListener extends BufferingResponseListener implemen public boolean cancel(boolean mayInterruptIfRunning) { cancelled = true; - return latch.getCount() == 0; + return request.abort("Cancelled"); } @Override @@ -94,7 +74,7 @@ public class BlockingResponseListener extends BufferingResponseListener implemen public ContentResponse get() throws InterruptedException, ExecutionException { latch.await(); - return result(); + return getResult(); } @Override @@ -102,11 +82,14 @@ public class BlockingResponseListener extends BufferingResponseListener implemen { boolean expired = !latch.await(timeout, unit); if (expired) + { + request.abort("Total timeout elapsed"); throw new TimeoutException(); - return result(); + } + return getResult(); } - private ContentResponse result() throws ExecutionException + private ContentResponse getResult() throws ExecutionException { if (isCancelled()) throw (CancellationException)new CancellationException().initCause(failure); diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/util/BufferingResponseListener.java b/jetty-client/src/main/java/org/eclipse/jetty/client/util/BufferingResponseListener.java index 6a3a2e39657..cecd461cfea 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/util/BufferingResponseListener.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/util/BufferingResponseListener.java @@ -21,6 +21,7 @@ package org.eclipse.jetty.client.util; import java.io.UnsupportedEncodingException; import java.nio.ByteBuffer; import java.nio.charset.UnsupportedCharsetException; +import java.util.Locale; import org.eclipse.jetty.client.api.Response; import org.eclipse.jetty.client.api.Result; @@ -33,7 +34,7 @@ import org.eclipse.jetty.http.HttpHeader; *

The content may be retrieved from {@link #onSuccess(Response)} or {@link #onComplete(Result)} * via {@link #getContent()} or {@link #getContentAsString()}.

*/ -public class BufferingResponseListener extends Response.Listener.Empty +public abstract class BufferingResponseListener extends Response.Listener.Empty { private final int maxLength; private volatile byte[] buffer = new byte[0]; @@ -60,16 +61,16 @@ public class BufferingResponseListener extends Response.Listener.Empty @Override public void onHeaders(Response response) { - HttpFields headers = response.headers(); + HttpFields headers = response.getHeaders(); long length = headers.getLongField(HttpHeader.CONTENT_LENGTH.asString()); if (length > maxLength) - response.abort(); + response.abort("Buffering capacity exceeded"); String contentType = headers.get(HttpHeader.CONTENT_TYPE); if (contentType != null) { String charset = "charset="; - int index = contentType.toLowerCase().indexOf(charset); + int index = contentType.toLowerCase(Locale.ENGLISH).indexOf(charset); if (index > 0) { String encoding = contentType.substring(index + charset.length()); @@ -95,6 +96,9 @@ public class BufferingResponseListener extends Response.Listener.Empty buffer = newBuffer; } + @Override + public abstract void onComplete(Result result); + public String getEncoding() { return encoding; diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/util/ByteBufferContentProvider.java b/jetty-client/src/main/java/org/eclipse/jetty/client/util/ByteBufferContentProvider.java index c5c6ae3f816..987530234a2 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/util/ByteBufferContentProvider.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/util/ByteBufferContentProvider.java @@ -39,7 +39,7 @@ public class ByteBufferContentProvider implements ContentProvider } @Override - public long length() + public long getLength() { return length; } diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/util/BytesContentProvider.java b/jetty-client/src/main/java/org/eclipse/jetty/client/util/BytesContentProvider.java index 01ccb3ec5c3..0ef54bd8ea0 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/util/BytesContentProvider.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/util/BytesContentProvider.java @@ -39,7 +39,7 @@ public class BytesContentProvider implements ContentProvider } @Override - public long length() + public long getLength() { return length; } diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/util/DigestAuthentication.java b/jetty-client/src/main/java/org/eclipse/jetty/client/util/DigestAuthentication.java index b21d46213d8..63ccdb74b3a 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/util/DigestAuthentication.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/util/DigestAuthentication.java @@ -25,6 +25,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.List; +import java.util.Locale; import java.util.Map; import java.util.Random; import java.util.concurrent.atomic.AtomicInteger; @@ -96,7 +97,7 @@ public class DigestAuthentication implements Authentication clientQOP = "auth-int"; } - return new DigestResult(request.uri(), response.content(), realm, user, password, algorithm, nonce, clientQOP, opaque); + return new DigestResult(request.getURI(), response.getContent(), realm, user, password, algorithm, nonce, clientQOP, opaque); } private Map parseParams(String wwwAuthenticate) @@ -108,7 +109,7 @@ public class DigestAuthentication implements Authentication Matcher matcher = PARAM_PATTERN.matcher(part); if (matcher.matches()) { - String name = matcher.group(1).trim().toLowerCase(); + String name = matcher.group(1).trim().toLowerCase(Locale.ENGLISH); String value = matcher.group(2).trim(); if (value.startsWith("\"") && value.endsWith("\"")) value = value.substring(1, value.length() - 1); @@ -196,7 +197,7 @@ public class DigestAuthentication implements Authentication @Override public void apply(Request request) { - if (!request.uri().startsWith(uri)) + if (!request.getURI().startsWith(uri)) return; MessageDigest digester = getMessageDigest(algorithm); @@ -207,7 +208,7 @@ public class DigestAuthentication implements Authentication String A1 = user + ":" + realm + ":" + password; String hashA1 = toHexString(digester.digest(A1.getBytes(charset))); - String A2 = request.method().asString() + ":" + request.uri(); + String A2 = request.getMethod().asString() + ":" + request.getURI(); if ("auth-int".equals(qop)) A2 += ":" + toHexString(digester.digest(content)); String hashA2 = toHexString(digester.digest(A2.getBytes(charset))); @@ -236,7 +237,7 @@ public class DigestAuthentication implements Authentication if (opaque != null) value.append(", opaque=\"").append(opaque).append("\""); value.append(", algorithm=\"").append(algorithm).append("\""); - value.append(", uri=\"").append(request.uri()).append("\""); + value.append(", uri=\"").append(request.getURI()).append("\""); if (qop != null) { value.append(", qop=\"").append(qop).append("\""); @@ -251,7 +252,7 @@ public class DigestAuthentication implements Authentication private String nextNonceCount() { String padding = "00000000"; - String next = Integer.toHexString(nonceCount.incrementAndGet()).toLowerCase(); + String next = Integer.toHexString(nonceCount.incrementAndGet()).toLowerCase(Locale.ENGLISH); return padding.substring(0, padding.length() - next.length()) + next; } @@ -265,7 +266,7 @@ public class DigestAuthentication implements Authentication private String toHexString(byte[] bytes) { - return TypeUtil.toHexString(bytes).toLowerCase(); + return TypeUtil.toHexString(bytes).toLowerCase(Locale.ENGLISH); } } } diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/util/InputStreamContentProvider.java b/jetty-client/src/main/java/org/eclipse/jetty/client/util/InputStreamContentProvider.java new file mode 100644 index 00000000000..5fd0ddc39b5 --- /dev/null +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/util/InputStreamContentProvider.java @@ -0,0 +1,101 @@ +// +// ======================================================================== +// 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.util; + +import java.io.IOException; +import java.io.InputStream; +import java.nio.ByteBuffer; +import java.util.Iterator; +import java.util.NoSuchElementException; + +import org.eclipse.jetty.client.api.ContentProvider; +import org.eclipse.jetty.util.BufferUtil; + +public class InputStreamContentProvider implements ContentProvider +{ + private final InputStream stream; + private final int bufferSize; + + public InputStreamContentProvider(InputStream stream) + { + this(stream, 4096); + } + + public InputStreamContentProvider(InputStream stream, int bufferSize) + { + this.stream = stream; + this.bufferSize = bufferSize; + } + + @Override + public long getLength() + { + return -1; + } + + @Override + public Iterator iterator() + { + return new Iterator() + { + private final byte[] buffer = new byte[bufferSize]; + public boolean eof; + + @Override + public boolean hasNext() + { + return !eof; + } + + @Override + public ByteBuffer next() + { + try + { + int read = stream.read(buffer); + if (read > 0) + { + return ByteBuffer.wrap(buffer, 0, read); + } + else if (read < 0) + { + if (eof) + throw new NoSuchElementException(); + eof = true; + return BufferUtil.EMPTY_BUFFER; + } + else + { + return BufferUtil.EMPTY_BUFFER; + } + } + catch (IOException x) + { + throw (NoSuchElementException)new NoSuchElementException().initCause(x); + } + } + + @Override + public void remove() + { + throw new UnsupportedOperationException(); + } + }; + } +} diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/util/PathContentProvider.java b/jetty-client/src/main/java/org/eclipse/jetty/client/util/PathContentProvider.java index 45c120d10c2..fc1f17011ea 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/util/PathContentProvider.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/util/PathContentProvider.java @@ -54,7 +54,7 @@ public class PathContentProvider implements ContentProvider } @Override - public long length() + public long getLength() { return fileSize; } @@ -62,48 +62,46 @@ public class PathContentProvider implements ContentProvider @Override public Iterator iterator() { - return new LazyIterator(); - } - - private class LazyIterator implements Iterator - { - private final ByteBuffer buffer = ByteBuffer.allocateDirect(bufferSize); - private SeekableByteChannel channel; - private long position; - - @Override - public boolean hasNext() + return new Iterator() { - return position < length(); - } + private final ByteBuffer buffer = ByteBuffer.allocateDirect(bufferSize); + private SeekableByteChannel channel; + private long position; - @Override - public ByteBuffer next() - { - try + @Override + public boolean hasNext() { - if (channel == null) - channel = Files.newByteChannel(filePath, StandardOpenOption.READ); - - buffer.clear(); - int read = channel.read(buffer); - if (read < 0) - throw new NoSuchElementException(); - - position += read; - buffer.flip(); - return buffer; + return position < getLength(); } - catch (IOException x) + + @Override + public ByteBuffer next() { - throw (NoSuchElementException)new NoSuchElementException().initCause(x); - } - } + try + { + if (channel == null) + channel = Files.newByteChannel(filePath, StandardOpenOption.READ); - @Override - public void remove() - { - throw new UnsupportedOperationException(); - } + buffer.clear(); + int read = channel.read(buffer); + if (read < 0) + throw new NoSuchElementException(); + + position += read; + buffer.flip(); + return buffer; + } + catch (IOException x) + { + throw (NoSuchElementException)new NoSuchElementException().initCause(x); + } + } + + @Override + public void remove() + { + throw new UnsupportedOperationException(); + } + }; } } diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/util/TimedResponseListener.java b/jetty-client/src/main/java/org/eclipse/jetty/client/util/TimedResponseListener.java new file mode 100644 index 00000000000..6f2cee60697 --- /dev/null +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/util/TimedResponseListener.java @@ -0,0 +1,126 @@ +// +// ======================================================================== +// 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.util; + +import java.nio.ByteBuffer; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicReference; + +import org.eclipse.jetty.client.Schedulable; +import org.eclipse.jetty.client.api.Request; +import org.eclipse.jetty.client.api.Response; +import org.eclipse.jetty.client.api.Result; +import org.eclipse.jetty.util.log.Log; +import org.eclipse.jetty.util.log.Logger; +import org.eclipse.jetty.util.thread.Scheduler; + +public class TimedResponseListener implements Response.Listener, Schedulable, Runnable +{ + private static final Logger LOG = Log.getLogger(TimedResponseListener.class); + + private final AtomicReference task = new AtomicReference<>(); + private final long timeout; + private final TimeUnit unit; + private final Request request; + private final Response.Listener delegate; + + public TimedResponseListener(long timeout, TimeUnit unit, Request request) + { + this(timeout, unit, request, new Empty()); + } + + public TimedResponseListener(long timeout, TimeUnit unit, Request request, Response.Listener delegate) + { + this.timeout = timeout; + this.unit = unit; + this.request = request; + this.delegate = delegate; + } + + @Override + public void onBegin(Response response) + { + delegate.onBegin(response); + } + + @Override + public void onHeaders(Response response) + { + delegate.onHeaders(response); + } + + @Override + public void onContent(Response response, ByteBuffer content) + { + delegate.onContent(response, content); + } + + @Override + public void onSuccess(Response response) + { + delegate.onSuccess(response); + } + + @Override + public void onFailure(Response response, Throwable failure) + { + delegate.onFailure(response, failure); + } + + @Override + public void onComplete(Result result) + { + delegate.onComplete(result); + } + + public boolean schedule(Scheduler scheduler) + { + Scheduler.Task task = this.task.get(); + if (task != null) + return false; + + task = scheduler.schedule(this, timeout, unit); + if (this.task.compareAndSet(null, task)) + { + LOG.debug("Scheduled timeout task {} in {} ms", task, unit.toMillis(timeout)); + return true; + } + else + { + task.cancel(); + return false; + } + } + + @Override + public void run() + { + request.abort("Total timeout elapsed"); + } + + public boolean cancel() + { + Scheduler.Task task = this.task.get(); + if (task == null) + return false; + boolean result = task.cancel(); + LOG.debug("Cancelled timeout task {}", task); + return result; + } +} diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/ExternalSiteTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/ExternalSiteTest.java new file mode 100644 index 00000000000..e21b73f5f13 --- /dev/null +++ b/jetty-client/src/test/java/org/eclipse/jetty/client/ExternalSiteTest.java @@ -0,0 +1,85 @@ +// +// ======================================================================== +// 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.Socket; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +import org.eclipse.jetty.client.api.Response; +import org.eclipse.jetty.client.api.Result; +import org.eclipse.jetty.toolchain.test.TestTracker; +import org.junit.After; +import org.junit.Assert; +import org.junit.Assume; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; + +public class ExternalSiteTest +{ + @Rule + public final TestTracker tracker = new TestTracker(); + + private HttpClient client; + + @Before + public void prepare() throws Exception + { + client = new HttpClient(); + client.start(); + } + + @After + public void dispose() throws Exception + { + client.stop(); + } + + @Test + public void testExternalSite() throws Exception + { + String host = "wikipedia.org"; + int port = 80; + + // Verify that we have connectivity + try + { + new Socket(host, port); + } + catch (IOException x) + { + Assume.assumeNoException(x); + } + + final CountDownLatch latch = new CountDownLatch(1); + client.newRequest(host, port).send(new Response.CompleteListener() + { + @Override + public void onComplete(Result result) + { + if (!result.isFailed() && result.getResponse().getStatus() == 200) + latch.countDown(); + } + }); + + Assert.assertTrue(latch.await(10, TimeUnit.SECONDS)); + } +} diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/GZIPContentDecoderTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/GZIPContentDecoderTest.java index 8b710845116..ca90aee585e 100644 --- a/jetty-client/src/test/java/org/eclipse/jetty/client/GZIPContentDecoderTest.java +++ b/jetty-client/src/test/java/org/eclipse/jetty/client/GZIPContentDecoderTest.java @@ -25,6 +25,8 @@ import java.nio.charset.Charset; import java.util.zip.GZIPInputStream; import java.util.zip.GZIPOutputStream; +import org.eclipse.jetty.toolchain.test.TestTracker; +import org.junit.Rule; import org.junit.Test; import static org.junit.Assert.assertEquals; @@ -33,6 +35,9 @@ import static org.junit.Assert.assertTrue; public class GZIPContentDecoderTest { + @Rule + public final TestTracker tracker = new TestTracker(); + @Test public void testStreamNoBlocks() throws Exception { @@ -139,10 +144,10 @@ public class GZIPContentDecoderTest GZIPContentDecoder decoder = new GZIPContentDecoder(); ByteBuffer decoded = decoder.decode(ByteBuffer.wrap(bytes1)); assertEquals(data, Charset.forName("UTF-8").decode(decoded).toString()); - assertFalse(decoder.finished()); + assertFalse(decoder.isFinished()); decoded = decoder.decode(ByteBuffer.wrap(bytes2)); assertEquals(0, decoded.remaining()); - assertTrue(decoder.finished()); + assertTrue(decoder.isFinished()); } @Test @@ -194,11 +199,11 @@ public class GZIPContentDecoderTest ByteBuffer buffer = ByteBuffer.wrap(bytes); ByteBuffer decoded = decoder.decode(buffer); assertEquals(data1, Charset.forName("UTF-8").decode(decoded).toString()); - assertTrue(decoder.finished()); + assertTrue(decoder.isFinished()); assertTrue(buffer.hasRemaining()); decoded = decoder.decode(buffer); assertEquals(data2, Charset.forName("UTF-8").decode(decoded).toString()); - assertTrue(decoder.finished()); + assertTrue(decoder.isFinished()); assertFalse(buffer.hasRemaining()); } @@ -247,7 +252,7 @@ public class GZIPContentDecoderTest result += Charset.forName("UTF-8").decode(decoded).toString(); } assertEquals(data, result); - assertTrue(decoder.finished()); + assertTrue(decoder.isFinished()); } @Test @@ -277,7 +282,7 @@ public class GZIPContentDecoderTest ByteBuffer decoded = decoder.decode(buffer); if (decoded.hasRemaining()) result += Charset.forName("UTF-8").decode(decoded).toString(); - if (decoder.finished()) + if (decoder.isFinished()) break; } assertEquals(data1, result); diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientAuthenticationTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientAuthenticationTest.java index 21a1932da46..ac4eac505ac 100644 --- a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientAuthenticationTest.java +++ b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientAuthenticationTest.java @@ -20,8 +20,10 @@ package org.eclipse.jetty.client; import java.io.File; import java.io.IOException; +import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicReference; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @@ -97,27 +99,29 @@ public class HttpClientAuthenticationTest extends AbstractHttpClientServerTest public void test_BasicAuthentication() throws Exception { startBasic(new EmptyServerHandler()); - test_Authentication(new BasicAuthentication(scheme + "://localhost:" + connector.getLocalPort(), realm, "basic", "basic")); + String uri = scheme + "://localhost:" + connector.getLocalPort(); + test_Authentication(new BasicAuthentication(uri, realm, "basic", "basic")); } @Test public void test_DigestAuthentication() throws Exception { startDigest(new EmptyServerHandler()); - test_Authentication(new DigestAuthentication(scheme + "://localhost:" + connector.getLocalPort(), realm, "digest", "digest")); + String uri = scheme + "://localhost:" + connector.getLocalPort(); + test_Authentication(new DigestAuthentication(uri, realm, "digest", "digest")); } private void test_Authentication(Authentication authentication) throws Exception { AuthenticationStore authenticationStore = client.getAuthenticationStore(); - final AtomicInteger requests = new AtomicInteger(); + final AtomicReference requests = new AtomicReference<>(new CountDownLatch(1)); Request.Listener.Empty requestListener = new Request.Listener.Empty() { @Override public void onSuccess(Request request) { - requests.incrementAndGet(); + requests.get().countDown(); } }; client.getRequestListeners().add(requestListener); @@ -126,19 +130,19 @@ public class HttpClientAuthenticationTest extends AbstractHttpClientServerTest Request request = client.newRequest("localhost", connector.getLocalPort()).scheme(scheme).path("/secure"); ContentResponse response = request.send().get(5, TimeUnit.SECONDS); Assert.assertNotNull(response); - Assert.assertEquals(401, response.status()); - Assert.assertEquals(1, requests.get()); + Assert.assertEquals(401, response.getStatus()); + Assert.assertTrue(requests.get().await(5, TimeUnit.SECONDS)); client.getRequestListeners().remove(requestListener); - requests.set(0); authenticationStore.addAuthentication(authentication); + requests.set(new CountDownLatch(2)); requestListener = new Request.Listener.Empty() { @Override public void onSuccess(Request request) { - requests.incrementAndGet(); + requests.get().countDown(); } }; client.getRequestListeners().add(requestListener); @@ -146,17 +150,17 @@ public class HttpClientAuthenticationTest extends AbstractHttpClientServerTest // Request with authentication causes a 401 (no previous successful authentication) + 200 response = request.send().get(5, TimeUnit.SECONDS); Assert.assertNotNull(response); - Assert.assertEquals(200, response.status()); - Assert.assertEquals(2, requests.get()); + Assert.assertEquals(200, response.getStatus()); + Assert.assertTrue(requests.get().await(5, TimeUnit.SECONDS)); client.getRequestListeners().remove(requestListener); - requests.set(0); + requests.set(new CountDownLatch(1)); requestListener = new Request.Listener.Empty() { @Override public void onSuccess(Request request) { - requests.incrementAndGet(); + requests.get().countDown(); } }; client.getRequestListeners().add(requestListener); @@ -166,10 +170,9 @@ public class HttpClientAuthenticationTest extends AbstractHttpClientServerTest request.header(HttpHeader.AUTHORIZATION.asString(), null); response = request.send().get(5, TimeUnit.SECONDS); Assert.assertNotNull(response); - Assert.assertEquals(200, response.status()); - Assert.assertEquals(1, requests.get()); + Assert.assertEquals(200, response.getStatus()); + Assert.assertTrue(requests.get().await(5, TimeUnit.SECONDS)); client.getRequestListeners().remove(requestListener); - requests.set(0); } @Test @@ -188,15 +191,16 @@ public class HttpClientAuthenticationTest extends AbstractHttpClientServerTest } }); - client.getAuthenticationStore().addAuthentication(new BasicAuthentication(scheme + "://localhost:" + connector.getLocalPort(), realm, "basic", "basic")); + String uri = scheme + "://localhost:" + connector.getLocalPort(); + client.getAuthenticationStore().addAuthentication(new BasicAuthentication(uri, realm, "basic", "basic")); - final AtomicInteger requests = new AtomicInteger(); + final CountDownLatch requests = new CountDownLatch(3); Request.Listener.Empty requestListener = new Request.Listener.Empty() { @Override public void onSuccess(Request request) { - requests.incrementAndGet(); + requests.countDown(); } }; client.getRequestListeners().add(requestListener); @@ -207,8 +211,8 @@ public class HttpClientAuthenticationTest extends AbstractHttpClientServerTest .send() .get(5, TimeUnit.SECONDS); Assert.assertNotNull(response); - Assert.assertEquals(200, response.status()); - Assert.assertEquals(3, requests.get()); + Assert.assertEquals(200, response.getStatus()); + Assert.assertTrue(requests.await(5, TimeUnit.SECONDS)); client.getRequestListeners().remove(requestListener); } @@ -226,15 +230,16 @@ public class HttpClientAuthenticationTest extends AbstractHttpClientServerTest } }); - client.getAuthenticationStore().addAuthentication(new BasicAuthentication(scheme + "://localhost:" + connector.getLocalPort(), realm, "basic", "basic")); + String uri = scheme + "://localhost:" + connector.getLocalPort(); + client.getAuthenticationStore().addAuthentication(new BasicAuthentication(uri, realm, "basic", "basic")); - final AtomicInteger requests = new AtomicInteger(); + final CountDownLatch requests = new CountDownLatch(3); Request.Listener.Empty requestListener = new Request.Listener.Empty() { @Override public void onSuccess(Request request) { - requests.incrementAndGet(); + requests.countDown(); } }; client.getRequestListeners().add(requestListener); @@ -245,8 +250,8 @@ public class HttpClientAuthenticationTest extends AbstractHttpClientServerTest .send() .get(5, TimeUnit.SECONDS); Assert.assertNotNull(response); - Assert.assertEquals(200, response.status()); - Assert.assertEquals(3, requests.get()); + Assert.assertEquals(200, response.getStatus()); + Assert.assertTrue(requests.await(5, TimeUnit.SECONDS)); client.getRequestListeners().remove(requestListener); } @@ -255,46 +260,46 @@ public class HttpClientAuthenticationTest extends AbstractHttpClientServerTest { startBasic(new EmptyServerHandler()); - final AtomicInteger requests = new AtomicInteger(); + final AtomicReference requests = new AtomicReference<>(new CountDownLatch(2)); Request.Listener.Empty requestListener = new Request.Listener.Empty() { @Override public void onSuccess(Request request) { - requests.incrementAndGet(); + requests.get().countDown(); } }; client.getRequestListeners().add(requestListener); AuthenticationStore authenticationStore = client.getAuthenticationStore(); - BasicAuthentication authentication = new BasicAuthentication(scheme + "://localhost:" + connector.getLocalPort(), realm, "basic", "basic"); + String uri = scheme + "://localhost:" + connector.getLocalPort(); + BasicAuthentication authentication = new BasicAuthentication(uri, realm, "basic", "basic"); authenticationStore.addAuthentication(authentication); Request request = client.newRequest("localhost", connector.getLocalPort()).scheme(scheme).path("/secure"); ContentResponse response = request.send().get(5, TimeUnit.SECONDS); Assert.assertNotNull(response); - Assert.assertEquals(200, response.status()); - Assert.assertEquals(2, requests.get()); - requests.set(0); + Assert.assertEquals(200, response.getStatus()); + Assert.assertTrue(requests.get().await(5, TimeUnit.SECONDS)); authenticationStore.removeAuthentication(authentication); + requests.set(new CountDownLatch(1)); request = client.newRequest("localhost", connector.getLocalPort()).scheme(scheme).path("/secure"); response = request.send().get(5, TimeUnit.SECONDS); Assert.assertNotNull(response); - Assert.assertEquals(200, response.status()); - Assert.assertEquals(1, requests.get()); - requests.set(0); + Assert.assertEquals(200, response.getStatus()); + Assert.assertTrue(requests.get().await(5, TimeUnit.SECONDS)); - Authentication.Result result = authenticationStore.findAuthenticationResult(request.uri()); + Authentication.Result result = authenticationStore.findAuthenticationResult(request.getURI()); Assert.assertNotNull(result); authenticationStore.removeAuthenticationResult(result); + requests.set(new CountDownLatch(1)); request = client.newRequest("localhost", connector.getLocalPort()).scheme(scheme).path("/secure"); response = request.send().get(5, TimeUnit.SECONDS); Assert.assertNotNull(response); - Assert.assertEquals(401, response.status()); - Assert.assertEquals(1, requests.get()); - requests.set(0); + Assert.assertEquals(401, response.getStatus()); + Assert.assertTrue(requests.get().await(5, TimeUnit.SECONDS)); } } diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientContinueTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientContinueTest.java index 8aa84edfe76..bf787a94c77 100644 --- a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientContinueTest.java +++ b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientContinueTest.java @@ -35,10 +35,13 @@ import org.eclipse.jetty.client.util.BytesContentProvider; import org.eclipse.jetty.http.HttpHeader; import org.eclipse.jetty.http.HttpHeaderValue; import org.eclipse.jetty.http.HttpMethod; +import org.eclipse.jetty.server.HttpChannel; import org.eclipse.jetty.server.Request; import org.eclipse.jetty.server.handler.AbstractHandler; import org.eclipse.jetty.toolchain.test.annotation.Slow; import org.eclipse.jetty.util.IO; +import org.eclipse.jetty.util.log.Log; +import org.eclipse.jetty.util.log.StdErrLog; import org.eclipse.jetty.util.ssl.SslContextFactory; import org.junit.Assert; import org.junit.Test; @@ -83,10 +86,10 @@ public class HttpClientContinueTest extends AbstractHttpClientServerTest .get(5, TimeUnit.SECONDS); Assert.assertNotNull(response); - Assert.assertEquals(200, response.status()); + Assert.assertEquals(200, response.getStatus()); int index = 0; - byte[] responseContent = response.content(); + byte[] responseContent = response.getContent(); for (byte[] content : contents) { for (byte b : content) @@ -121,7 +124,7 @@ public class HttpClientContinueTest extends AbstractHttpClientServerTest .content(new BytesContentProvider(content1, content2) { @Override - public long length() + public long getLength() { return -1; } @@ -130,10 +133,10 @@ public class HttpClientContinueTest extends AbstractHttpClientServerTest .get(5, TimeUnit.SECONDS); Assert.assertNotNull(response); - Assert.assertEquals(200, response.status()); + Assert.assertEquals(200, response.getStatus()); int index = 0; - byte[] responseContent = response.content(); + byte[] responseContent = response.getContent(); for (byte b : content1) Assert.assertEquals(b, responseContent[index++]); for (byte b : content2) @@ -182,7 +185,7 @@ public class HttpClientContinueTest extends AbstractHttpClientServerTest byte[] content = getContent(); Assert.assertNotNull(content); Assert.assertTrue(content.length > 0); - Assert.assertEquals(error, result.getResponse().status()); + Assert.assertEquals(error, result.getResponse().getStatus()); latch.countDown(); } }); @@ -228,7 +231,7 @@ public class HttpClientContinueTest extends AbstractHttpClientServerTest public void onComplete(Result result) { Assert.assertFalse(result.isFailed()); - Assert.assertEquals(200, result.getResponse().status()); + Assert.assertEquals(200, result.getResponse().getStatus()); Assert.assertEquals(data, getContentAsString()); latch.countDown(); } @@ -279,7 +282,7 @@ public class HttpClientContinueTest extends AbstractHttpClientServerTest Assert.assertTrue(result.isFailed()); Assert.assertNotNull(result.getRequestFailure()); Assert.assertNull(result.getResponseFailure()); - Assert.assertEquals(302, result.getResponse().status()); + Assert.assertEquals(302, result.getResponse().getStatus()); latch.countDown(); } }); @@ -405,7 +408,7 @@ public class HttpClientContinueTest extends AbstractHttpClientServerTest @Override public void onBegin(Response response) { - response.abort(); + response.abort(null); } @Override @@ -417,24 +420,34 @@ public class HttpClientContinueTest extends AbstractHttpClientServerTest } }); - byte[] content = new byte[1024]; - final CountDownLatch latch = new CountDownLatch(1); - client.newRequest("localhost", connector.getLocalPort()) - .scheme(scheme) - .header(HttpHeader.EXPECT.asString(), HttpHeaderValue.CONTINUE.asString()) - .content(new BytesContentProvider(content)) - .send(new BufferingResponseListener() - { - @Override - public void onComplete(Result result) - { - Assert.assertTrue(result.isFailed()); - Assert.assertNotNull(result.getRequestFailure()); - Assert.assertNotNull(result.getResponseFailure()); - latch.countDown(); - } - }); + try + { + Log.getLogger(HttpChannel.class).info("Expecting Close warning..."); + ((StdErrLog)Log.getLogger(HttpChannel.class)).setHideStacks(true); - Assert.assertTrue(latch.await(5, TimeUnit.SECONDS)); + byte[] content = new byte[1024]; + final CountDownLatch latch = new CountDownLatch(1); + client.newRequest("localhost", connector.getLocalPort()) + .scheme(scheme) + .header(HttpHeader.EXPECT.asString(), HttpHeaderValue.CONTINUE.asString()) + .content(new BytesContentProvider(content)) + .send(new BufferingResponseListener() + { + @Override + public void onComplete(Result result) + { + Assert.assertTrue(result.isFailed()); + Assert.assertNotNull(result.getRequestFailure()); + Assert.assertNotNull(result.getResponseFailure()); + latch.countDown(); + } + }); + + Assert.assertTrue(latch.await(5, TimeUnit.SECONDS)); + } + finally + { + ((StdErrLog)Log.getLogger(HttpChannel.class)).setHideStacks(false); + } } } diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientExplicitConnectionTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientExplicitConnectionTest.java index cd315986b0d..81cd2c750f0 100644 --- a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientExplicitConnectionTest.java +++ b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientExplicitConnectionTest.java @@ -45,13 +45,13 @@ public class HttpClientExplicitConnectionTest extends AbstractHttpClientServerTe Destination destination = client.getDestination(scheme, "localhost", connector.getLocalPort()); try (Connection connection = destination.newConnection().get(5, TimeUnit.SECONDS)) { - Request request = client.newRequest(destination.host(), destination.port()).scheme(scheme); - BlockingResponseListener listener = new BlockingResponseListener(); + Request request = client.newRequest(destination.getHost(), destination.getPort()).scheme(scheme); + BlockingResponseListener listener = new BlockingResponseListener(request); connection.send(request, listener); ContentResponse response = listener.get(5, TimeUnit.SECONDS); Assert.assertNotNull(response); - Assert.assertEquals(200, response.status()); + Assert.assertEquals(200, response.getStatus()); HttpDestination httpDestination = (HttpDestination)destination; Assert.assertTrue(httpDestination.getActiveConnections().isEmpty()); @@ -67,12 +67,12 @@ public class HttpClientExplicitConnectionTest extends AbstractHttpClientServerTe Destination destination = client.getDestination(scheme, "localhost", connector.getLocalPort()); Connection connection = destination.newConnection().get(5, TimeUnit.SECONDS); - Request request = client.newRequest(destination.host(), destination.port()).scheme(scheme); - BlockingResponseListener listener = new BlockingResponseListener(); + Request request = client.newRequest(destination.getHost(), destination.getPort()).scheme(scheme); + BlockingResponseListener listener = new BlockingResponseListener(request); connection.send(request, listener); ContentResponse response = listener.get(5, TimeUnit.SECONDS); - Assert.assertEquals(200, response.status()); + Assert.assertEquals(200, response.getStatus()); connector.stop(); diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientLoadTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientLoadTest.java index 3056dcc5ae3..25c4be15340 100644 --- a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientLoadTest.java +++ b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientLoadTest.java @@ -23,6 +23,7 @@ import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.Locale; import java.util.Random; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; @@ -68,7 +69,7 @@ public class HttpClientLoadTest extends AbstractHttpClientServerTest client.setDispatchIO(false); Random random = new Random(); - int iterations = 200; + int iterations = 500; CountDownLatch latch = new CountDownLatch(iterations); List failures = new ArrayList<>(); @@ -106,6 +107,9 @@ public class HttpClientLoadTest extends AbstractHttpClientServerTest long elapsed = TimeUnit.NANOSECONDS.toMillis(end - begin); logger.info("{} requests in {} ms, {} req/s", iterations, elapsed, elapsed > 0 ? iterations * 1000 / elapsed : -1); + for (String failure : failures) + System.err.println("FAILED: "+failure); + Assert.assertTrue(failures.toString(), failures.isEmpty()); } @@ -129,15 +133,15 @@ public class HttpClientLoadTest extends AbstractHttpClientServerTest else if (!ssl && random.nextBoolean()) request.header("X-Close", "true"); + int contentLength = random.nextInt(maxContentLength) + 1; switch (method) { case GET: // Randomly ask the server to download data upon this GET request if (random.nextBoolean()) - request.header("X-Download", String.valueOf(random.nextInt(maxContentLength) + 1)); + request.header("X-Download", String.valueOf(contentLength)); break; case POST: - int contentLength = random.nextInt(maxContentLength) + 1; request.header("X-Upload", String.valueOf(contentLength)); request.content(new BytesContentProvider(new byte[contentLength])); break; @@ -150,7 +154,7 @@ public class HttpClientLoadTest extends AbstractHttpClientServerTest @Override public void onHeaders(Response response) { - String content = response.headers().get("X-Content"); + String content = response.getHeaders().get("X-Content"); if (content != null) contentLength.set(Integer.parseInt(content)); } @@ -165,7 +169,10 @@ public class HttpClientLoadTest extends AbstractHttpClientServerTest public void onComplete(Result result) { if (result.isFailed()) + { + result.getFailure().printStackTrace(); failures.add("Result failed " + result); + } if (contentLength.get() != 0) failures.add("Content length mismatch " + contentLength); latch.countDown(); @@ -178,7 +185,7 @@ public class HttpClientLoadTest extends AbstractHttpClientServerTest @Override public void handle(String target, org.eclipse.jetty.server.Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { - String method = request.getMethod().toUpperCase(); + String method = request.getMethod().toUpperCase(Locale.ENGLISH); switch (method) { case "GET": diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientRedirectTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientRedirectTest.java index 51027227c8e..c9679a75437 100644 --- a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientRedirectTest.java +++ b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientRedirectTest.java @@ -62,8 +62,8 @@ public class HttpClientRedirectTest extends AbstractHttpClientServerTest .path("/303/localhost/done") .send().get(5, TimeUnit.SECONDS); Assert.assertNotNull(response); - Assert.assertEquals(200, response.status()); - Assert.assertFalse(response.headers().containsKey(HttpHeader.LOCATION.asString())); + Assert.assertEquals(200, response.getStatus()); + Assert.assertFalse(response.getHeaders().containsKey(HttpHeader.LOCATION.asString())); } @Test @@ -74,8 +74,8 @@ public class HttpClientRedirectTest extends AbstractHttpClientServerTest .path("/303/localhost/302/localhost/done") .send().get(5, TimeUnit.SECONDS); Assert.assertNotNull(response); - Assert.assertEquals(200, response.status()); - Assert.assertFalse(response.headers().containsKey(HttpHeader.LOCATION.asString())); + Assert.assertEquals(200, response.getStatus()); + Assert.assertFalse(response.getHeaders().containsKey(HttpHeader.LOCATION.asString())); } @Test @@ -86,8 +86,8 @@ public class HttpClientRedirectTest extends AbstractHttpClientServerTest .path("/303/127.0.0.1/302/localhost/done") .send().get(5, TimeUnit.SECONDS); Assert.assertNotNull(response); - Assert.assertEquals(200, response.status()); - Assert.assertFalse(response.headers().containsKey(HttpHeader.LOCATION.asString())); + Assert.assertEquals(200, response.getStatus()); + Assert.assertFalse(response.getHeaders().containsKey(HttpHeader.LOCATION.asString())); } @Test @@ -99,8 +99,8 @@ public class HttpClientRedirectTest extends AbstractHttpClientServerTest .path("/301/localhost/done") .send().get(5, TimeUnit.SECONDS); Assert.assertNotNull(response); - Assert.assertEquals(200, response.status()); - Assert.assertFalse(response.headers().containsKey(HttpHeader.LOCATION.asString())); + Assert.assertEquals(200, response.getStatus()); + Assert.assertFalse(response.getHeaders().containsKey(HttpHeader.LOCATION.asString())); } @Test @@ -120,8 +120,8 @@ public class HttpClientRedirectTest extends AbstractHttpClientServerTest HttpResponseException xx = (HttpResponseException)x.getCause(); Response response = xx.getResponse(); Assert.assertNotNull(response); - Assert.assertEquals(301, response.status()); - Assert.assertTrue(response.headers().containsKey(HttpHeader.LOCATION.asString())); + Assert.assertEquals(301, response.getStatus()); + Assert.assertTrue(response.getHeaders().containsKey(HttpHeader.LOCATION.asString())); } } @@ -136,9 +136,9 @@ public class HttpClientRedirectTest extends AbstractHttpClientServerTest .content(new ByteBufferContentProvider(ByteBuffer.wrap(data))) .send().get(5, TimeUnit.SECONDS); Assert.assertNotNull(response); - Assert.assertEquals(200, response.status()); - Assert.assertFalse(response.headers().containsKey(HttpHeader.LOCATION.asString())); - Assert.assertArrayEquals(data, response.content()); + Assert.assertEquals(200, response.getStatus()); + Assert.assertFalse(response.getHeaders().containsKey(HttpHeader.LOCATION.asString())); + Assert.assertArrayEquals(data, response.getContent()); } @Test @@ -159,8 +159,8 @@ public class HttpClientRedirectTest extends AbstractHttpClientServerTest HttpResponseException xx = (HttpResponseException)x.getCause(); Response response = xx.getResponse(); Assert.assertNotNull(response); - Assert.assertEquals(302, response.status()); - Assert.assertTrue(response.headers().containsKey(HttpHeader.LOCATION.asString())); + Assert.assertEquals(302, response.getStatus()); + Assert.assertTrue(response.getHeaders().containsKey(HttpHeader.LOCATION.asString())); } } @@ -172,8 +172,8 @@ public class HttpClientRedirectTest extends AbstractHttpClientServerTest .path("/303/localhost/done?close=true") .send().get(5, TimeUnit.SECONDS); Assert.assertNotNull(response); - Assert.assertEquals(200, response.status()); - Assert.assertFalse(response.headers().containsKey(HttpHeader.LOCATION.asString())); + Assert.assertEquals(200, response.getStatus()); + Assert.assertFalse(response.getHeaders().containsKey(HttpHeader.LOCATION.asString())); } @Test @@ -185,8 +185,8 @@ public class HttpClientRedirectTest extends AbstractHttpClientServerTest .path("/303/localhost/done?close=true") .send().get(5, TimeUnit.SECONDS); Assert.assertNotNull(response); - Assert.assertEquals(303, response.status()); - Assert.assertTrue(response.headers().containsKey(HttpHeader.LOCATION.asString())); + Assert.assertEquals(303, response.getStatus()); + Assert.assertTrue(response.getHeaders().containsKey(HttpHeader.LOCATION.asString())); } private class RedirectHandler extends AbstractHandler diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientStreamTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientStreamTest.java index 5a977d2b6d3..7f744cc22f6 100644 --- a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientStreamTest.java +++ b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientStreamTest.java @@ -72,7 +72,7 @@ public class HttpClientStreamTest extends AbstractHttpClientServerTest ContentResponse response = client.newRequest("localhost", connector.getLocalPort()) .scheme(scheme) .file(upload) - .listener(new Request.Listener.Empty() + .onRequestSuccess(new Request.SuccessListener() { @Override public void onSuccess(Request request) @@ -84,7 +84,7 @@ public class HttpClientStreamTest extends AbstractHttpClientServerTest .get(10, TimeUnit.SECONDS); long responseTime = System.nanoTime(); - Assert.assertEquals(200, response.status()); + Assert.assertEquals(200, response.getStatus()); Assert.assertTrue(requestTime.get() <= responseTime); // Give some time to the server to consume the request content @@ -114,7 +114,7 @@ public class HttpClientStreamTest extends AbstractHttpClientServerTest .send(listener); Response response = listener.get(5, TimeUnit.SECONDS); Assert.assertNotNull(response); - Assert.assertEquals(200, response.status()); + Assert.assertEquals(200, response.getStatus()); InputStream input = listener.getInputStream(); Assert.assertNotNull(input); @@ -162,7 +162,7 @@ public class HttpClientStreamTest extends AbstractHttpClientServerTest .send(listener); Response response = listener.get(5, TimeUnit.SECONDS); Assert.assertNotNull(response); - Assert.assertEquals(200, response.status()); + Assert.assertEquals(200, response.getStatus()); InputStream input = listener.getInputStream(); Assert.assertNotNull(input); diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientSynchronizationTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientSynchronizationTest.java new file mode 100644 index 00000000000..2011c162597 --- /dev/null +++ b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientSynchronizationTest.java @@ -0,0 +1,108 @@ +// +// ======================================================================== +// 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.ConnectException; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +import org.eclipse.jetty.client.api.Request; +import org.eclipse.jetty.client.api.Response; +import org.eclipse.jetty.client.api.Result; +import org.eclipse.jetty.util.ssl.SslContextFactory; +import org.hamcrest.Matchers; +import org.junit.Assert; +import org.junit.Test; + +/** + * Verifies that synchronization performed from outside HttpClient does not cause deadlocks + */ +public class HttpClientSynchronizationTest extends AbstractHttpClientServerTest +{ + public HttpClientSynchronizationTest(SslContextFactory sslContextFactory) + { + super(sslContextFactory); + } + + @Test + public void testSynchronizationOnException() throws Exception + { + start(new EmptyServerHandler()); + int port = connector.getLocalPort(); + server.stop(); + + int count = 10; + final CountDownLatch latch = new CountDownLatch(count); + for (int i = 0; i < count; ++i) + { + Request request = client.newRequest("localhost", port) + .scheme(scheme); + + synchronized (this) + { + request.send(new Response.Listener.Empty() + { + @Override + public void onFailure(Response response, Throwable failure) + { + synchronized (HttpClientSynchronizationTest.this) + { + Assert.assertThat(failure, Matchers.instanceOf(ConnectException.class)); + latch.countDown(); + } + } + }); + } + } + + Assert.assertTrue(latch.await(5, TimeUnit.SECONDS)); + } + + @Test + public void testSynchronizationOnComplete() throws Exception + { + start(new EmptyServerHandler()); + + int count = 10; + final CountDownLatch latch = new CountDownLatch(count); + for (int i = 0; i < count; ++i) + { + Request request = client.newRequest("localhost", connector.getLocalPort()) + .scheme(scheme); + + synchronized (this) + { + request.send(new Response.Listener.Empty() + { + @Override + public void onComplete(Result result) + { + synchronized (HttpClientSynchronizationTest.this) + { + Assert.assertFalse(result.isFailed()); + latch.countDown(); + } + } + }); + } + } + + Assert.assertTrue(latch.await(5, TimeUnit.SECONDS)); + } +} diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientTest.java index a4a2eb474a8..5ffc74a0679 100644 --- a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientTest.java +++ b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientTest.java @@ -73,7 +73,7 @@ public class HttpClientTest extends AbstractHttpClientServerTest int port = connector.getLocalPort(); String path = "/"; Response response = client.GET(scheme + "://" + host + ":" + port + path).get(5, TimeUnit.SECONDS); - Assert.assertEquals(200, response.status()); + Assert.assertEquals(200, response.getStatus()); HttpDestination destination = (HttpDestination)client.getDestination(scheme, host, port); @@ -111,9 +111,9 @@ public class HttpClientTest extends AbstractHttpClientServerTest Assert.assertEquals(1, destinations.size()); Destination destination = destinations.get(0); Assert.assertNotNull(destination); - Assert.assertEquals(scheme, destination.scheme()); - Assert.assertEquals(host, destination.host()); - Assert.assertEquals(port, destination.port()); + Assert.assertEquals(scheme, destination.getScheme()); + Assert.assertEquals(host, destination.getHost()); + Assert.assertEquals(port, destination.getPort()); } @Test @@ -124,7 +124,7 @@ public class HttpClientTest extends AbstractHttpClientServerTest Response response = client.GET(scheme + "://localhost:" + connector.getLocalPort()).get(5, TimeUnit.SECONDS); Assert.assertNotNull(response); - Assert.assertEquals(200, response.status()); + Assert.assertEquals(200, response.getStatus()); } @Test @@ -144,8 +144,8 @@ public class HttpClientTest extends AbstractHttpClientServerTest ContentResponse response = client.GET(scheme + "://localhost:" + connector.getLocalPort()).get(5, TimeUnit.SECONDS); Assert.assertNotNull(response); - Assert.assertEquals(200, response.status()); - byte[] content = response.content(); + Assert.assertEquals(200, response.getStatus()); + byte[] content = response.getContent(); Assert.assertArrayEquals(data, content); } @@ -176,8 +176,8 @@ public class HttpClientTest extends AbstractHttpClientServerTest ContentResponse response = client.GET(scheme + "://localhost:" + connector.getLocalPort() + "/?" + query).get(5, TimeUnit.SECONDS); Assert.assertNotNull(response); - Assert.assertEquals(200, response.status()); - String content = new String(response.content(), "UTF-8"); + Assert.assertEquals(200, response.getStatus()); + String content = new String(response.getContent(), "UTF-8"); Assert.assertEquals(value1 + "empty", content); } @@ -212,8 +212,8 @@ public class HttpClientTest extends AbstractHttpClientServerTest ContentResponse response = client.GET(scheme + "://localhost:" + connector.getLocalPort() + "/?" + query).get(5, TimeUnit.SECONDS); Assert.assertNotNull(response); - Assert.assertEquals(200, response.status()); - String content = new String(response.content(), "UTF-8"); + Assert.assertEquals(200, response.getStatus()); + String content = new String(response.getContent(), "UTF-8"); Assert.assertEquals(value11 + value12 + value2, content); } @@ -242,8 +242,8 @@ public class HttpClientTest extends AbstractHttpClientServerTest .param(paramName, paramValue).send().get(5, TimeUnit.SECONDS); Assert.assertNotNull(response); - Assert.assertEquals(200, response.status()); - Assert.assertEquals(paramValue, new String(response.content(), "UTF-8")); + Assert.assertEquals(200, response.getStatus()); + Assert.assertEquals(paramValue, new String(response.getContent(), "UTF-8")); } @Test @@ -274,8 +274,8 @@ public class HttpClientTest extends AbstractHttpClientServerTest .send().get(5, TimeUnit.SECONDS); Assert.assertNotNull(response); - Assert.assertEquals(200, response.status()); - Assert.assertArrayEquals(content, response.content()); + Assert.assertEquals(200, response.getStatus()); + Assert.assertArrayEquals(content, response.getContent()); } @Test @@ -289,7 +289,7 @@ public class HttpClientTest extends AbstractHttpClientServerTest final CountDownLatch successLatch = new CountDownLatch(2); client.newRequest("localhost", connector.getLocalPort()) .scheme(scheme) - .listener(new Request.Listener.Empty() + .onRequestBegin(new Request.BeginListener() { @Override public void onBegin(Request request) @@ -309,14 +309,14 @@ public class HttpClientTest extends AbstractHttpClientServerTest @Override public void onSuccess(Response response) { - Assert.assertEquals(200, response.status()); + Assert.assertEquals(200, response.getStatus()); successLatch.countDown(); } }); client.newRequest("localhost", connector.getLocalPort()) .scheme(scheme) - .listener(new Request.Listener.Empty() + .onRequestQueued(new Request.QueuedListener() { @Override public void onQueued(Request request) @@ -329,7 +329,7 @@ public class HttpClientTest extends AbstractHttpClientServerTest @Override public void onSuccess(Response response) { - Assert.assertEquals(200, response.status()); + Assert.assertEquals(200, response.getStatus()); successLatch.countDown(); } }); @@ -371,26 +371,28 @@ public class HttpClientTest extends AbstractHttpClientServerTest latch.countDown(); } }) - .send(new Response.Listener.Empty() + .onResponseFailure(new Response.FailureListener() { @Override public void onFailure(Response response, Throwable failure) { latch.countDown(); } - }); + }) + .send(null); client.newRequest("localhost", connector.getLocalPort()) .scheme(scheme) - .send(new Response.Listener.Empty() + .onResponseSuccess(new Response.SuccessListener() { @Override public void onSuccess(Response response) { - Assert.assertEquals(200, response.status()); + Assert.assertEquals(200, response.getStatus()); latch.countDown(); } - }); + }) + .send(null); Assert.assertTrue(latch.await(5 * idleTimeout, TimeUnit.MILLISECONDS)); } @@ -419,7 +421,7 @@ public class HttpClientTest extends AbstractHttpClientServerTest client.newRequest("localhost", connector.getLocalPort()) .scheme(scheme) .file(file) - .listener(new Request.Listener.Empty() + .onRequestSuccess(new Request.SuccessListener() { @Override public void onSuccess(Request request) @@ -477,7 +479,7 @@ public class HttpClientTest extends AbstractHttpClientServerTest .content(new ContentProvider() { @Override - public long length() + public long getLength() { return -1; } @@ -529,7 +531,7 @@ public class HttpClientTest extends AbstractHttpClientServerTest final int port = connector.getLocalPort(); client.newRequest(host, port) .scheme(scheme) - .listener(new Request.Listener.Empty() + .onRequestBegin(new Request.BeginListener() { @Override public void onBegin(Request request) @@ -572,8 +574,8 @@ public class HttpClientTest extends AbstractHttpClientServerTest .send() .get(5, TimeUnit.SECONDS); - Assert.assertEquals(200, response.status()); - Assert.assertArrayEquals(data, response.content()); + Assert.assertEquals(200, response.getStatus()); + Assert.assertArrayEquals(data, response.getContent()); } @Slow @@ -619,6 +621,6 @@ public class HttpClientTest extends AbstractHttpClientServerTest .send().get(3 * idleTimeout, TimeUnit.MILLISECONDS); Assert.assertNotNull(response); - Assert.assertEquals(200, response.status()); + Assert.assertEquals(200, response.getStatus()); } } diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientTimeoutTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientTimeoutTest.java new file mode 100644 index 00000000000..ba3f6488557 --- /dev/null +++ b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientTimeoutTest.java @@ -0,0 +1,239 @@ +// +// ======================================================================== +// 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.ByteArrayInputStream; +import java.io.IOException; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.eclipse.jetty.client.api.Connection; +import org.eclipse.jetty.client.api.Destination; +import org.eclipse.jetty.client.api.Request; +import org.eclipse.jetty.client.api.Response; +import org.eclipse.jetty.client.api.Result; +import org.eclipse.jetty.client.util.BufferingResponseListener; +import org.eclipse.jetty.client.util.InputStreamContentProvider; +import org.eclipse.jetty.client.util.TimedResponseListener; +import org.eclipse.jetty.server.handler.AbstractHandler; +import org.eclipse.jetty.toolchain.test.annotation.Slow; +import org.eclipse.jetty.util.IO; +import org.eclipse.jetty.util.ssl.SslContextFactory; +import org.junit.Assert; +import org.junit.Test; + +public class HttpClientTimeoutTest extends AbstractHttpClientServerTest +{ + public HttpClientTimeoutTest(SslContextFactory sslContextFactory) + { + super(sslContextFactory); + } + + @Slow + @Test(expected = TimeoutException.class) + public void testTimeoutOnFuture() throws Exception + { + long timeout = 1000; + start(new TimeoutHandler(2 * timeout)); + + client.newRequest("localhost", connector.getLocalPort()) + .scheme(scheme) + .send().get(timeout, TimeUnit.MILLISECONDS); + } + + @Slow + @Test + public void testTimeoutOnListener() throws Exception + { + long timeout = 1000; + start(new TimeoutHandler(2 * timeout)); + + final CountDownLatch latch = new CountDownLatch(1); + Request request = client.newRequest("localhost", connector.getLocalPort()).scheme(scheme); + request.send(new TimedResponseListener(timeout, TimeUnit.MILLISECONDS, request) + { + @Override + public void onComplete(Result result) + { + Assert.assertTrue(result.isFailed()); + latch.countDown(); + } + }); + Assert.assertTrue(latch.await(3 * timeout, TimeUnit.MILLISECONDS)); + } + + @Slow + @Test + public void testTimeoutOnQueuedRequest() throws Exception + { + long timeout = 1000; + start(new TimeoutHandler(3 * timeout)); + + // Only one connection so requests get queued + client.setMaxConnectionsPerAddress(1); + + // The first request has a long timeout + final CountDownLatch firstLatch = new CountDownLatch(1); + Request request = client.newRequest("localhost", connector.getLocalPort()).scheme(scheme); + request.send(new TimedResponseListener(4 * timeout, TimeUnit.MILLISECONDS, request) + { + @Override + public void onComplete(Result result) + { + Assert.assertFalse(result.isFailed()); + firstLatch.countDown(); + } + }); + + // Second request has a short timeout and should fail in the queue + final CountDownLatch secondLatch = new CountDownLatch(1); + request = client.newRequest("localhost", connector.getLocalPort()).scheme(scheme); + request.send(new TimedResponseListener(timeout, TimeUnit.MILLISECONDS, request) + { + @Override + public void onComplete(Result result) + { + Assert.assertTrue(result.isFailed()); + secondLatch.countDown(); + } + }); + + Assert.assertTrue(secondLatch.await(2 * timeout, TimeUnit.MILLISECONDS)); + // The second request must fail before the first request has completed + Assert.assertTrue(firstLatch.getCount() > 0); + Assert.assertTrue(firstLatch.await(5 * timeout, TimeUnit.MILLISECONDS)); + } + + @Slow + @Test + public void testTimeoutIsCancelledOnSuccess() throws Exception + { + long timeout = 1000; + start(new TimeoutHandler(timeout)); + + final CountDownLatch latch = new CountDownLatch(1); + final byte[] content = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; + Request request = client.newRequest("localhost", connector.getLocalPort()) + .scheme(scheme) + .content(new InputStreamContentProvider(new ByteArrayInputStream(content))); + request.send(new TimedResponseListener(2 * timeout, TimeUnit.MILLISECONDS, request, new BufferingResponseListener() + { + @Override + public void onComplete(Result result) + { + Assert.assertFalse(result.isFailed()); + Assert.assertArrayEquals(content, getContent()); + latch.countDown(); + } + })); + + Assert.assertTrue(latch.await(3 * timeout, TimeUnit.MILLISECONDS)); + + TimeUnit.MILLISECONDS.sleep(2 * timeout); + + Assert.assertFalse(request.isAborted()); + } + + @Slow + @Test + public void testTimeoutOnListenerWithExplicitConnection() throws Exception + { + long timeout = 1000; + start(new TimeoutHandler(2 * timeout)); + + final CountDownLatch latch = new CountDownLatch(1); + Destination destination = client.getDestination(scheme, "localhost", connector.getLocalPort()); + try (Connection connection = destination.newConnection().get(5, TimeUnit.SECONDS)) + { + Request request = client.newRequest("localhost", connector.getLocalPort()).scheme(scheme); + connection.send(request, new TimedResponseListener(timeout, TimeUnit.MILLISECONDS, request) + { + @Override + public void onComplete(Result result) + { + Assert.assertTrue(result.isFailed()); + latch.countDown(); + } + }); + + Assert.assertTrue(latch.await(3 * timeout, TimeUnit.MILLISECONDS)); + } + } + + @Slow + @Test + public void testTimeoutIsCancelledOnSuccessWithExplicitConnection() throws Exception + { + long timeout = 1000; + start(new TimeoutHandler(timeout)); + + final CountDownLatch latch = new CountDownLatch(1); + Destination destination = client.getDestination(scheme, "localhost", connector.getLocalPort()); + try (Connection connection = destination.newConnection().get(5, TimeUnit.SECONDS)) + { + Request request = client.newRequest(destination.getHost(), destination.getPort()).scheme(scheme); + connection.send(request, new TimedResponseListener(2 * timeout, TimeUnit.MILLISECONDS, request) + { + @Override + public void onComplete(Result result) + { + Response response = result.getResponse(); + Assert.assertEquals(200, response.getStatus()); + Assert.assertFalse(result.isFailed()); + latch.countDown(); + } + }); + + Assert.assertTrue(latch.await(3 * timeout, TimeUnit.MILLISECONDS)); + + TimeUnit.MILLISECONDS.sleep(2 * timeout); + + Assert.assertFalse(request.isAborted()); + } + } + + private class TimeoutHandler extends AbstractHandler + { + private final long timeout; + + public TimeoutHandler(long timeout) + { + this.timeout = timeout; + } + + @Override + public void handle(String target, org.eclipse.jetty.server.Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException + { + baseRequest.setHandled(true); + try + { + TimeUnit.MILLISECONDS.sleep(timeout); + IO.copy(request.getInputStream(), response.getOutputStream()); + } + catch (InterruptedException x) + { + throw new ServletException(x); + } + } + } +} diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpConnectionLifecycleTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpConnectionLifecycleTest.java index e8bc8bdcd76..b0aa3b6135e 100644 --- a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpConnectionLifecycleTest.java +++ b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpConnectionLifecycleTest.java @@ -36,6 +36,7 @@ import org.eclipse.jetty.client.util.ByteBufferContentProvider; import org.eclipse.jetty.http.HttpHeader; import org.eclipse.jetty.server.handler.AbstractHandler; import org.eclipse.jetty.toolchain.test.annotation.Slow; +import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.StdErrLog; import org.eclipse.jetty.util.ssl.SslContextFactory; import org.junit.Assert; @@ -67,7 +68,7 @@ public class HttpConnectionLifecycleTest extends AbstractHttpClientServerTest final CountDownLatch successLatch = new CountDownLatch(3); client.newRequest(host, port) .scheme(scheme) - .listener(new Request.Listener.Empty() + .onRequestSuccess(new Request.SuccessListener() { @Override public void onSuccess(Request request) @@ -75,7 +76,7 @@ public class HttpConnectionLifecycleTest extends AbstractHttpClientServerTest successLatch.countDown(); } }) - .send(new Response.Listener.Empty() + .onResponseHeaders(new Response.HeadersListener() { @Override public void onHeaders(Response response) @@ -84,7 +85,9 @@ public class HttpConnectionLifecycleTest extends AbstractHttpClientServerTest Assert.assertEquals(1, activeConnections.size()); headersLatch.countDown(); } - + }) + .send(new Response.Listener.Empty() + { @Override public void onSuccess(Response response) { @@ -194,7 +197,7 @@ public class HttpConnectionLifecycleTest extends AbstractHttpClientServerTest @Override public void onSuccess(Response response) { - Assert.assertEquals(400, response.status()); + Assert.assertEquals(400, response.getStatus()); // 400 response also come with a Connection: close, // so the connection is closed and removed successLatch.countDown(); @@ -267,7 +270,7 @@ public class HttpConnectionLifecycleTest extends AbstractHttpClientServerTest @Override public void onSuccess(Response response) { - Assert.assertEquals(400, response.status()); + Assert.assertEquals(400, response.getStatus()); // 400 response also come with a Connection: close, // so the connection is closed and removed successLatch.countDown(); @@ -307,7 +310,7 @@ public class HttpConnectionLifecycleTest extends AbstractHttpClientServerTest final CountDownLatch failureLatch = new CountDownLatch(2); client.newRequest(host, port) .scheme(scheme) - .listener(new Request.Listener.Empty() + .onRequestFailure(new Request.FailureListener() { @Override public void onFailure(Request request, Throwable failure) @@ -403,6 +406,8 @@ public class HttpConnectionLifecycleTest extends AbstractHttpClientServerTest final BlockingQueue activeConnections = destination.getActiveConnections(); Assert.assertEquals(0, activeConnections.size()); + Log.getLogger(HttpConnection.class).info("Expecting java.lang.IllegalStateException: HttpParser{s=CLOSED,..."); + final CountDownLatch latch = new CountDownLatch(1); client.newRequest(host, port) .scheme(scheme) @@ -450,7 +455,7 @@ public class HttpConnectionLifecycleTest extends AbstractHttpClientServerTest .send() .get(5, TimeUnit.SECONDS); - Assert.assertEquals(200, response.status()); + Assert.assertEquals(200, response.getStatus()); connector.stop(); diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpCookieParserTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpCookieParserTest.java index 0b4c57cb020..744fd437451 100644 --- a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpCookieParserTest.java +++ b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpCookieParserTest.java @@ -21,11 +21,16 @@ package org.eclipse.jetty.client; import java.util.List; import org.eclipse.jetty.http.HttpCookie; +import org.eclipse.jetty.toolchain.test.TestTracker; import org.junit.Assert; +import org.junit.Rule; import org.junit.Test; public class HttpCookieParserTest { + @Rule + public final TestTracker tracker = new TestTracker(); + @Test public void testParseCookie1() throws Exception { diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpCookieStoreTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpCookieStoreTest.java index b616dd18449..804a7656bda 100644 --- a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpCookieStoreTest.java +++ b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpCookieStoreTest.java @@ -23,11 +23,16 @@ import java.util.List; import org.eclipse.jetty.client.api.CookieStore; import org.eclipse.jetty.client.api.Destination; import org.eclipse.jetty.http.HttpCookie; +import org.eclipse.jetty.toolchain.test.TestTracker; import org.junit.Assert; +import org.junit.Rule; import org.junit.Test; public class HttpCookieStoreTest { + @Rule + public final TestTracker tracker = new TestTracker(); + private HttpClient client = new HttpClient(); @Test diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpCookieTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpCookieTest.java index 68b434b7990..568197c85a8 100644 --- a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpCookieTest.java +++ b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpCookieTest.java @@ -61,7 +61,7 @@ public class HttpCookieTest extends AbstractHttpClientServerTest int port = connector.getLocalPort(); String path = "/path"; Response response = client.GET(scheme + "://" + host + ":" + port + path).get(5, TimeUnit.SECONDS); - Assert.assertEquals(200, response.status()); + Assert.assertEquals(200, response.getStatus()); Destination destination = client.getDestination(scheme, host, port); List cookies = client.getCookieStore().findCookies(destination, path); @@ -98,6 +98,6 @@ public class HttpCookieTest extends AbstractHttpClientServerTest client.getCookieStore().addCookie(destination, new HttpCookie(name, value, null, path)); Response response = client.GET(scheme + "://" + host + ":" + port + path).get(5, TimeUnit.SECONDS); - Assert.assertEquals(200, response.status()); + Assert.assertEquals(200, response.getStatus()); } } diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpReceiverTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpReceiverTest.java index e075ac53d3d..aa7948e925c 100644 --- a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpReceiverTest.java +++ b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpReceiverTest.java @@ -22,11 +22,10 @@ import java.io.ByteArrayOutputStream; import java.io.EOFException; import java.net.URI; import java.nio.ByteBuffer; -import java.util.concurrent.CountDownLatch; +import java.util.Collections; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; -import java.util.concurrent.atomic.AtomicReference; import java.util.zip.GZIPOutputStream; import org.eclipse.jetty.client.api.ContentResponse; @@ -36,13 +35,18 @@ import org.eclipse.jetty.http.HttpFields; import org.eclipse.jetty.http.HttpHeader; import org.eclipse.jetty.http.HttpVersion; import org.eclipse.jetty.io.ByteArrayEndPoint; +import org.eclipse.jetty.toolchain.test.TestTracker; import org.junit.After; import org.junit.Assert; import org.junit.Before; +import org.junit.Rule; import org.junit.Test; public class HttpReceiverTest { + @Rule + public final TestTracker tracker = new TestTracker(); + private HttpClient client; private HttpDestination destination; private ByteArrayEndPoint endPoint; @@ -66,13 +70,15 @@ public class HttpReceiverTest client.stop(); } - protected HttpExchange newExchange(Response.Listener listener) + protected HttpExchange newExchange() { HttpRequest request = new HttpRequest(client, URI.create("http://localhost")); - HttpExchange exchange = new HttpExchange(conversation, connection, request, listener); - conversation.exchanges().offer(exchange); + BlockingResponseListener listener = new BlockingResponseListener(request); + HttpExchange exchange = new HttpExchange(conversation, connection, request, Collections.singletonList(listener)); + conversation.getExchanges().offer(exchange); connection.setExchange(exchange); exchange.requestComplete(null); + exchange.terminateRequest(); return exchange; } @@ -83,26 +89,16 @@ public class HttpReceiverTest "HTTP/1.1 200 OK\r\n" + "Content-length: 0\r\n" + "\r\n"); - final AtomicReference responseRef = new AtomicReference<>(); - final CountDownLatch latch = new CountDownLatch(1); - HttpExchange exchange = newExchange(new Response.Listener.Empty() - { - @Override - public void onSuccess(Response response) - { - responseRef.set(response); - latch.countDown(); - } - }); + HttpExchange exchange = newExchange(); + BlockingResponseListener listener = (BlockingResponseListener)exchange.getResponseListeners().get(0); exchange.receive(); - Assert.assertTrue(latch.await(5, TimeUnit.SECONDS)); - Response response = responseRef.get(); + Response response = listener.get(5, TimeUnit.SECONDS); Assert.assertNotNull(response); - Assert.assertEquals(200, response.status()); - Assert.assertEquals("OK", response.reason()); - Assert.assertSame(HttpVersion.HTTP_1_1, response.version()); - HttpFields headers = response.headers(); + Assert.assertEquals(200, response.getStatus()); + Assert.assertEquals("OK", response.getReason()); + Assert.assertSame(HttpVersion.HTTP_1_1, response.getVersion()); + HttpFields headers = response.getHeaders(); Assert.assertNotNull(headers); Assert.assertEquals(1, headers.size()); Assert.assertEquals("0", headers.get(HttpHeader.CONTENT_LENGTH)); @@ -117,16 +113,16 @@ public class HttpReceiverTest "Content-length: " + content.length() + "\r\n" + "\r\n" + content); - BlockingResponseListener listener = new BlockingResponseListener(); - HttpExchange exchange = newExchange(listener); + HttpExchange exchange = newExchange(); + BlockingResponseListener listener = (BlockingResponseListener)exchange.getResponseListeners().get(0); exchange.receive(); Response response = listener.get(5, TimeUnit.SECONDS); Assert.assertNotNull(response); - Assert.assertEquals(200, response.status()); - Assert.assertEquals("OK", response.reason()); - Assert.assertSame(HttpVersion.HTTP_1_1, response.version()); - HttpFields headers = response.headers(); + Assert.assertEquals(200, response.getStatus()); + Assert.assertEquals("OK", response.getReason()); + Assert.assertSame(HttpVersion.HTTP_1_1, response.getVersion()); + HttpFields headers = response.getHeaders(); Assert.assertNotNull(headers); Assert.assertEquals(1, headers.size()); Assert.assertEquals(String.valueOf(content.length()), headers.get(HttpHeader.CONTENT_LENGTH)); @@ -144,8 +140,8 @@ public class HttpReceiverTest "Content-length: " + (content1.length() + content2.length()) + "\r\n" + "\r\n" + content1); - BlockingResponseListener listener = new BlockingResponseListener(); - HttpExchange exchange = newExchange(listener); + HttpExchange exchange = newExchange(); + BlockingResponseListener listener = (BlockingResponseListener)exchange.getResponseListeners().get(0); exchange.receive(); endPoint.setInputEOF(); exchange.receive(); @@ -168,8 +164,8 @@ public class HttpReceiverTest "HTTP/1.1 200 OK\r\n" + "Content-length: 1\r\n" + "\r\n"); - BlockingResponseListener listener = new BlockingResponseListener(); - HttpExchange exchange = newExchange(listener); + HttpExchange exchange = newExchange(); + BlockingResponseListener listener = (BlockingResponseListener)exchange.getResponseListeners().get(0); exchange.receive(); // Simulate an idle timeout connection.idleTimeout(); @@ -192,8 +188,8 @@ public class HttpReceiverTest "HTTP/1.1 200 OK\r\n" + "Content-length: A\r\n" + "\r\n"); - BlockingResponseListener listener = new BlockingResponseListener(); - HttpExchange exchange = newExchange(listener); + HttpExchange exchange = newExchange(); + BlockingResponseListener listener = (BlockingResponseListener)exchange.getResponseListeners().get(0); exchange.receive(); try @@ -223,8 +219,8 @@ public class HttpReceiverTest "Content-Length: " + gzip.length + "\r\n" + "Content-Encoding: gzip\r\n" + "\r\n"); - BlockingResponseListener listener = new BlockingResponseListener(); - HttpExchange exchange = newExchange(listener); + HttpExchange exchange = newExchange(); + BlockingResponseListener listener = (BlockingResponseListener)exchange.getResponseListeners().get(0); exchange.receive(); endPoint.reset(); @@ -242,7 +238,7 @@ public class HttpReceiverTest ContentResponse response = listener.get(5, TimeUnit.SECONDS); Assert.assertNotNull(response); - Assert.assertEquals(200, response.status()); - Assert.assertArrayEquals(data, response.content()); + Assert.assertEquals(200, response.getStatus()); + Assert.assertArrayEquals(data, response.getContent()); } } diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpRequestAbortTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpRequestAbortTest.java index e4178b58966..337db292b2f 100644 --- a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpRequestAbortTest.java +++ b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpRequestAbortTest.java @@ -21,7 +21,9 @@ package org.eclipse.jetty.client; import java.io.EOFException; import java.io.IOException; import java.nio.ByteBuffer; +import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutionException; +import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicReference; @@ -31,16 +33,19 @@ import javax.servlet.http.HttpServletResponse; import org.eclipse.jetty.client.api.ContentResponse; import org.eclipse.jetty.client.api.Request; +import org.eclipse.jetty.client.api.Response; +import org.eclipse.jetty.client.api.Result; import org.eclipse.jetty.client.util.ByteBufferContentProvider; +import org.eclipse.jetty.server.HttpChannel; import org.eclipse.jetty.server.handler.AbstractHandler; +import org.eclipse.jetty.toolchain.test.annotation.Slow; import org.eclipse.jetty.util.IO; +import org.eclipse.jetty.util.log.StdErrLog; import org.eclipse.jetty.util.ssl.SslContextFactory; +import org.hamcrest.Matchers; import org.junit.Assert; import org.junit.Test; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.fail; - public class HttpRequestAbortTest extends AbstractHttpClientServerTest { public HttpRequestAbortTest(SslContextFactory sslContextFactory) @@ -63,7 +68,7 @@ public class HttpRequestAbortTest extends AbstractHttpClientServerTest @Override public void onQueued(Request request) { - request.abort(); + request.abort(null); } @Override @@ -73,23 +78,23 @@ public class HttpRequestAbortTest extends AbstractHttpClientServerTest } }) .send().get(5, TimeUnit.SECONDS); - fail(); + Assert.fail(); } catch (ExecutionException x) { - HttpRequestException xx = (HttpRequestException)x.getCause(); - Request request = xx.getRequest(); - Assert.assertNotNull(request); + Assert.assertThat(x.getCause(), Matchers.instanceOf(HttpResponseException.class)); Assert.assertFalse(begin.get()); } } + @Slow @Test public void testAbortOnBegin() throws Exception { start(new EmptyServerHandler()); - final AtomicBoolean headers = new AtomicBoolean(); + final CountDownLatch aborted = new CountDownLatch(1); + final CountDownLatch headers = new CountDownLatch(1); try { client.newRequest("localhost", connector.getLocalPort()) @@ -99,24 +104,24 @@ public class HttpRequestAbortTest extends AbstractHttpClientServerTest @Override public void onBegin(Request request) { - request.abort(); + if (request.abort(null)) + aborted.countDown(); } @Override public void onHeaders(Request request) { - headers.set(true); + headers.countDown(); } }) .send().get(5, TimeUnit.SECONDS); - fail(); + Assert.fail(); } catch (ExecutionException x) { - HttpRequestException xx = (HttpRequestException)x.getCause(); - Request request = xx.getRequest(); - Assert.assertNotNull(request); - Assert.assertFalse(headers.get()); + Assert.assertThat(x.getCause(), Matchers.instanceOf(HttpResponseException.class)); + Assert.assertTrue(aborted.await(5, TimeUnit.SECONDS)); + Assert.assertFalse(headers.await(1, TimeUnit.SECONDS)); } } @@ -125,19 +130,33 @@ public class HttpRequestAbortTest extends AbstractHttpClientServerTest { start(new EmptyServerHandler()); - ContentResponse response = client.newRequest("localhost", connector.getLocalPort()) - .scheme(scheme) - .listener(new Request.Listener.Empty() - { - @Override - public void onHeaders(Request request) + // Test can behave in 2 ways: + // A) the request is failed before the response arrived, then we get an ExecutionException + // B) the request is failed after the response arrived, we get the 200 OK + + final CountDownLatch aborted = new CountDownLatch(1); + try + { + ContentResponse response = client.newRequest("localhost", connector.getLocalPort()) + .scheme(scheme) + .onRequestHeaders(new Request.HeadersListener() { - // Too late to abort - request.abort(); - } - }) - .send().get(5, TimeUnit.SECONDS); - assertEquals(200, response.status()); + @Override + public void onHeaders(Request request) + { + if (request.abort(null)) + aborted.countDown(); + } + }) + .send().get(5, TimeUnit.SECONDS); + Assert.assertEquals(200, response.getStatus()); + Assert.assertFalse(aborted.await(1, TimeUnit.SECONDS)); + } + catch (ExecutionException x) + { + Assert.assertThat(x.getCause(), Matchers.instanceOf(HttpResponseException.class)); + Assert.assertTrue(aborted.await(5, TimeUnit.SECONDS)); + } } @Test @@ -164,32 +183,32 @@ public class HttpRequestAbortTest extends AbstractHttpClientServerTest // Test can behave in 3 ways: // A) non-SSL, if the request is failed before the response arrived, then we get an ExecutionException - // B) non-SSL, if the request is failed after the response arrived, then we get a 500 + // B) non-SSL, if the request is failed after the response arrived, then we get the 500 // C) SSL, the server tries to write the 500, but the connection is already closed, the client // reads -1 with a pending exchange and fails the response with an EOFException + StdErrLog.getLogger(HttpChannel.class).setHideStacks(true); try { - ContentResponse response = client.newRequest("localhost", connector.getLocalPort()) + client.newRequest("localhost", connector.getLocalPort()) .scheme(scheme) - .listener(new Request.Listener.Empty() + .onRequestHeaders(new Request.HeadersListener() { @Override public void onHeaders(Request request) { - request.abort(); + request.abort(null); } }) .content(new ByteBufferContentProvider(ByteBuffer.wrap(new byte[]{0}), ByteBuffer.wrap(new byte[]{1})) { @Override - public long length() + public long getLength() { return -1; } }) .send().get(5, TimeUnit.SECONDS); - Assert.assertNotNull(failure.get()); - assertEquals(500, response.status()); + Assert.fail(); } catch (ExecutionException x) { @@ -200,15 +219,108 @@ public class HttpRequestAbortTest extends AbstractHttpClientServerTest } else if (cause instanceof HttpRequestException) { - // Request failed, behavior A + // Request failed, behavior B HttpRequestException xx = (HttpRequestException)cause; Request request = xx.getRequest(); Assert.assertNotNull(request); } + else if (cause instanceof HttpResponseException) + { + // Response failed, behavior A + HttpResponseException xx = (HttpResponseException)cause; + Response response = xx.getResponse(); + Assert.assertNotNull(response); + } else { throw x; } } + finally + { + StdErrLog.getLogger(HttpChannel.class).setHideStacks(false); + } + } + + @Slow + @Test + public void testAbortLongPoll() throws Exception + { + final long delay = 1000; + start(new AbstractHandler() + { + @Override + public void handle(String target, org.eclipse.jetty.server.Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException + { + try + { + baseRequest.setHandled(true); + TimeUnit.MILLISECONDS.sleep(2 * delay); + } + catch (InterruptedException x) + { + throw new ServletException(x); + } + } + }); + + Request request = client.newRequest("localhost", connector.getLocalPort()) + .scheme(scheme); + Future future = request.send(); + + TimeUnit.MILLISECONDS.sleep(delay); + + request.abort(null); + + try + { + future.get(5, TimeUnit.SECONDS); + } + catch (ExecutionException x) + { + Assert.assertThat(x.getCause(), Matchers.instanceOf(HttpResponseException.class)); + } + } + + @Test + public void testAbortConversation() throws Exception + { + start(new AbstractHandler() + { + @Override + public void handle(String target, org.eclipse.jetty.server.Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException + { + baseRequest.setHandled(true); + if (!"/done".equals(request.getRequestURI())) + response.sendRedirect("/done"); + } + }); + + client.getProtocolHandlers().clear(); + client.getProtocolHandlers().add(new RedirectProtocolHandler(client) + { + @Override + public void onComplete(Result result) + { + // Abort the request after the 3xx response but before issuing the next request + if (!result.isFailed()) + result.getRequest().abort(null); + super.onComplete(result); + } + }); + + try + { + client.newRequest("localhost", connector.getLocalPort()) + .scheme(scheme) + .path("/redirect") + .send() + .get(5, TimeUnit.SECONDS); + Assert.fail(); + } + catch (ExecutionException x) + { + Assert.assertThat(x.getCause(), Matchers.instanceOf(HttpResponseException.class)); + } } } diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpResponseAbortTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpResponseAbortTest.java index 4677785300d..74efb0cd14c 100644 --- a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpResponseAbortTest.java +++ b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpResponseAbortTest.java @@ -55,14 +55,16 @@ public class HttpResponseAbortTest extends AbstractHttpClientServerTest final CountDownLatch latch = new CountDownLatch(1); client.newRequest("localhost", connector.getLocalPort()) .scheme(scheme) - .send(new Response.Listener.Empty() + .onResponseBegin(new Response.BeginListener() { @Override public void onBegin(Response response) { - response.abort(); + response.abort(null); } - + }) + .send(new Response.CompleteListener() + { @Override public void onComplete(Result result) { @@ -81,13 +83,16 @@ public class HttpResponseAbortTest extends AbstractHttpClientServerTest final CountDownLatch latch = new CountDownLatch(1); client.newRequest("localhost", connector.getLocalPort()) .scheme(scheme) - .send(new Response.Listener.Empty() + .onResponseHeaders(new Response.HeadersListener() { @Override public void onHeaders(Response response) { - response.abort(); + response.abort(null); } + }) + .send(new Response.CompleteListener() + { @Override public void onComplete(Result result) @@ -126,14 +131,16 @@ public class HttpResponseAbortTest extends AbstractHttpClientServerTest final CountDownLatch latch = new CountDownLatch(1); client.newRequest("localhost", connector.getLocalPort()) .scheme(scheme) - .send(new Response.Listener.Empty() + .onResponseContent(new Response.ContentListener() { @Override public void onContent(Response response, ByteBuffer content) { - response.abort(); + response.abort(null); } - + }) + .send(new Response.CompleteListener() + { @Override public void onComplete(Result result) { diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpSenderTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpSenderTest.java index 9a5c0ec891c..9f46eccdb76 100644 --- a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpSenderTest.java +++ b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpSenderTest.java @@ -20,6 +20,7 @@ package org.eclipse.jetty.client; import java.net.URI; import java.nio.ByteBuffer; +import java.util.Locale; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; @@ -28,14 +29,19 @@ import org.eclipse.jetty.client.api.Response; import org.eclipse.jetty.client.api.Result; import org.eclipse.jetty.client.util.ByteBufferContentProvider; import org.eclipse.jetty.io.ByteArrayEndPoint; +import org.eclipse.jetty.toolchain.test.TestTracker; import org.eclipse.jetty.toolchain.test.annotation.Slow; import org.junit.After; import org.junit.Assert; import org.junit.Before; +import org.junit.Rule; import org.junit.Test; public class HttpSenderTest { + @Rule + public final TestTracker tracker = new TestTracker(); + private HttpClient client; @Before @@ -74,7 +80,7 @@ public class HttpSenderTest successLatch.countDown(); } }); - connection.send(request, null); + connection.send(request, (Response.CompleteListener)null); String requestString = endPoint.takeOutputString(); Assert.assertTrue(requestString.startsWith("GET ")); @@ -91,7 +97,7 @@ public class HttpSenderTest HttpDestination destination = new HttpDestination(client, "http", "localhost", 8080); HttpConnection connection = new HttpConnection(client, endPoint, destination); Request request = client.newRequest(URI.create("http://localhost/")); - connection.send(request, null); + connection.send(request, (Response.CompleteListener)null); // This take will free space in the buffer and allow for the write to complete StringBuilder builder = new StringBuilder(endPoint.takeOutputString()); @@ -202,7 +208,7 @@ public class HttpSenderTest successLatch.countDown(); } }); - connection.send(request, null); + connection.send(request, (Response.CompleteListener)null); String requestString = endPoint.takeOutputString(); Assert.assertTrue(requestString.startsWith("GET ")); @@ -237,7 +243,7 @@ public class HttpSenderTest successLatch.countDown(); } }); - connection.send(request, null); + connection.send(request, (Response.CompleteListener)null); String requestString = endPoint.takeOutputString(); Assert.assertTrue(requestString.startsWith("GET ")); @@ -258,7 +264,7 @@ public class HttpSenderTest request.content(new ByteBufferContentProvider(ByteBuffer.wrap(content1.getBytes("UTF-8")), ByteBuffer.wrap(content2.getBytes("UTF-8"))) { @Override - public long length() + public long getLength() { return -1; } @@ -279,12 +285,12 @@ public class HttpSenderTest successLatch.countDown(); } }); - connection.send(request, null); + connection.send(request, (Response.CompleteListener)null); String requestString = endPoint.takeOutputString(); Assert.assertTrue(requestString.startsWith("GET ")); - String content = Integer.toHexString(content1.length()).toUpperCase() + "\r\n" + content1 + "\r\n"; - content += Integer.toHexString(content2.length()).toUpperCase() + "\r\n" + content2 + "\r\n"; + String content = Integer.toHexString(content1.length()).toUpperCase(Locale.ENGLISH) + "\r\n" + content1 + "\r\n"; + content += Integer.toHexString(content2.length()).toUpperCase(Locale.ENGLISH) + "\r\n" + content2 + "\r\n"; content += "0\r\n\r\n"; Assert.assertTrue(requestString.endsWith("\r\n\r\n" + content)); Assert.assertTrue(headersLatch.await(5, TimeUnit.SECONDS)); diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/api/Usage.java b/jetty-client/src/test/java/org/eclipse/jetty/client/api/Usage.java index 62910a68f35..b53d51bf6c5 100644 --- a/jetty-client/src/test/java/org/eclipse/jetty/client/api/Usage.java +++ b/jetty-client/src/test/java/org/eclipse/jetty/client/api/Usage.java @@ -45,13 +45,13 @@ public class Usage HttpClient client = new HttpClient(); Future responseFuture = client.GET("http://localhost:8080/foo"); Response response = responseFuture.get(); - Assert.assertEquals(200, response.status()); + Assert.assertEquals(200, response.getStatus()); // Headers abstraction needed for: // 1. case insensitivity // 2. multi values // 3. value conversion // Reuse SPDY's ? - response.headers().get("Content-Length"); + response.getHeaders().get("Content-Length"); } @Test @@ -72,7 +72,7 @@ public class Usage .idleTimeout(5000L); Future responseFuture = request.send(); Response response = responseFuture.get(); - Assert.assertEquals(200, response.status()); + Assert.assertEquals(200, response.getStatus()); } @Test @@ -93,7 +93,7 @@ public class Usage Assert.assertTrue(latch.await(5, TimeUnit.SECONDS)); Response response = responseRef.get(); Assert.assertNotNull(response); - Assert.assertEquals(200, response.status()); + Assert.assertEquals(200, response.getStatus()); } @Test @@ -115,7 +115,7 @@ public class Usage { } }).send().get(5, TimeUnit.SECONDS); - Assert.assertEquals(200, response.status()); + Assert.assertEquals(200, response.getStatus()); } @Test @@ -125,11 +125,11 @@ public class Usage try (Connection connection = client.getDestination("http", "localhost", 8080).newConnection().get(5, TimeUnit.SECONDS)) { Request request = client.newRequest("localhost", 8080); - BlockingResponseListener listener = new BlockingResponseListener(); + BlockingResponseListener listener = new BlockingResponseListener(request); connection.send(request, listener); Response response = listener.get(5, TimeUnit.SECONDS); Assert.assertNotNull(response); - Assert.assertEquals(200, response.status()); + Assert.assertEquals(200, response.getStatus()); } } @@ -139,7 +139,7 @@ public class Usage HttpClient client = new HttpClient(); Response response = client.newRequest("localhost", 8080) .content(new PathContentProvider(Paths.get(""))).send().get(); - Assert.assertEquals(200, response.status()); + Assert.assertEquals(200, response.getStatus()); } @Test @@ -148,7 +148,7 @@ public class Usage HttpClient client = new HttpClient(); client.getCookieStore().addCookie(client.getDestination("http", "host", 8080), new HttpCookie("name", "value")); Response response = client.newRequest("host", 8080).send().get(); - Assert.assertEquals(200, response.status()); + Assert.assertEquals(200, response.getStatus()); } // @Test @@ -163,7 +163,7 @@ public class Usage { HttpClient client = new HttpClient(); client.setFollowRedirects(false); - client.newRequest("localhost", 8080).followRedirects(true).send().get().status(); // 200 + client.newRequest("localhost", 8080).followRedirects(true).send().get().getStatus(); // 200 } @Test @@ -174,7 +174,7 @@ public class Usage client.newRequest("localhost", 8080).send(listener); // Call to get() blocks until the headers arrived Response response = listener.get(5, TimeUnit.SECONDS); - if (response.status() == 200) + if (response.getStatus() == 200) { // Solution 1: use input stream byte[] buffer = new byte[256]; @@ -191,7 +191,7 @@ public class Usage } else { - response.abort(); + response.abort(null); } } diff --git a/jetty-continuation/src/main/java/org/eclipse/jetty/continuation/FauxContinuation.java b/jetty-continuation/src/main/java/org/eclipse/jetty/continuation/FauxContinuation.java index bc191215ecd..b6d2b30aaec 100644 --- a/jetty-continuation/src/main/java/org/eclipse/jetty/continuation/FauxContinuation.java +++ b/jetty-continuation/src/main/java/org/eclipse/jetty/continuation/FauxContinuation.java @@ -55,7 +55,7 @@ class FauxContinuation implements FilteredContinuation private boolean _resumed=false; private boolean _timeout=false; private boolean _responseWrapped=false; - private long _timeoutMs=30000; // TODO configure + private long _timeoutMs=30000; private ArrayList _listeners; @@ -84,12 +84,14 @@ class FauxContinuation implements FilteredContinuation /** * @see org.eclipse.jetty.continuation.Continuation#isResponseWrapped() */ + @Override public boolean isResponseWrapped() { return _responseWrapped; } /* ------------------------------------------------------------ */ + @Override public boolean isInitial() { synchronized(this) @@ -99,6 +101,7 @@ class FauxContinuation implements FilteredContinuation } /* ------------------------------------------------------------ */ + @Override public boolean isResumed() { synchronized(this) @@ -108,6 +111,7 @@ class FauxContinuation implements FilteredContinuation } /* ------------------------------------------------------------ */ + @Override public boolean isSuspended() { synchronized(this) @@ -129,6 +133,7 @@ class FauxContinuation implements FilteredContinuation } /* ------------------------------------------------------------ */ + @Override public boolean isExpired() { synchronized(this) @@ -138,12 +143,14 @@ class FauxContinuation implements FilteredContinuation } /* ------------------------------------------------------------ */ + @Override public void setTimeout(long timeoutMs) { _timeoutMs = timeoutMs; } /* ------------------------------------------------------------ */ + @Override public void suspend(ServletResponse response) { _response=response; @@ -152,6 +159,7 @@ class FauxContinuation implements FilteredContinuation } /* ------------------------------------------------------------ */ + @Override public void suspend() { synchronized (this) @@ -185,6 +193,7 @@ class FauxContinuation implements FilteredContinuation /* (non-Javadoc) * @see org.mortbay.jetty.Suspendor#resume() */ + @Override public void resume() { synchronized (this) @@ -223,6 +232,7 @@ class FauxContinuation implements FilteredContinuation /* ------------------------------------------------------------ */ + @Override public void complete() { // just like resume, except don't set _resumed=true; @@ -261,6 +271,7 @@ class FauxContinuation implements FilteredContinuation /** * @see org.eclipse.jetty.continuation.Continuation#getServletResponse() */ + @Override public boolean enter(ServletResponse response) { _response=response; @@ -271,6 +282,7 @@ class FauxContinuation implements FilteredContinuation /** * @see org.eclipse.jetty.continuation.Continuation#getServletResponse() */ + @Override public ServletResponse getServletResponse() { return _response; @@ -297,6 +309,9 @@ class FauxContinuation implements FilteredContinuation case __SUSPENDED: fauxResume(); + _state=__HANDLING; + return; + case __UNSUSPENDING: _state=__HANDLING; return; @@ -312,6 +327,7 @@ class FauxContinuation implements FilteredContinuation /** * @return true if handling is complete */ + @Override public boolean exit() { synchronized (this) @@ -454,6 +470,7 @@ class FauxContinuation implements FilteredContinuation } + @Override public void addContinuationListener(ContinuationListener listener) { if (_listeners==null) @@ -466,6 +483,7 @@ class FauxContinuation implements FilteredContinuation /** * @see org.eclipse.jetty.continuation.Continuation#getAttribute(java.lang.String) */ + @Override public Object getAttribute(String name) { return _request.getAttribute(name); @@ -475,6 +493,7 @@ class FauxContinuation implements FilteredContinuation /** * @see org.eclipse.jetty.continuation.Continuation#removeAttribute(java.lang.String) */ + @Override public void removeAttribute(String name) { _request.removeAttribute(name); @@ -484,6 +503,7 @@ class FauxContinuation implements FilteredContinuation /** * @see org.eclipse.jetty.continuation.Continuation#setAttribute(java.lang.String, java.lang.Object) */ + @Override public void setAttribute(String name, Object attribute) { _request.setAttribute(name,attribute); @@ -493,6 +513,7 @@ class FauxContinuation implements FilteredContinuation /** * @see org.eclipse.jetty.continuation.Continuation#undispatch() */ + @Override public void undispatch() { if (isSuspended()) diff --git a/jetty-continuation/src/main/java/org/eclipse/jetty/continuation/Servlet3Continuation.java b/jetty-continuation/src/main/java/org/eclipse/jetty/continuation/Servlet3Continuation.java index f30eb24bd70..f6758ace35e 100644 --- a/jetty-continuation/src/main/java/org/eclipse/jetty/continuation/Servlet3Continuation.java +++ b/jetty-continuation/src/main/java/org/eclipse/jetty/continuation/Servlet3Continuation.java @@ -45,7 +45,7 @@ public class Servlet3Continuation implements Continuation private final ServletRequest _request; private ServletResponse _response; private AsyncContext _context; - private List _listeners=new ArrayList(); + private final List _listeners=new ArrayList(); private volatile boolean _initial=true; private volatile boolean _resumed=false; private volatile boolean _expired=false; @@ -60,19 +60,23 @@ public class Servlet3Continuation implements Continuation _listeners.add(new AsyncListener() { + @Override public void onComplete(AsyncEvent event) throws IOException { } + @Override public void onError(AsyncEvent event) throws IOException { } + @Override public void onStartAsync(AsyncEvent event) throws IOException { event.getAsyncContext().addListener(this); } + @Override public void onTimeout(AsyncEvent event) throws IOException { _initial=false; @@ -82,25 +86,30 @@ public class Servlet3Continuation implements Continuation } /* ------------------------------------------------------------ */ + @Override public void addContinuationListener(final ContinuationListener listener) { AsyncListener wrapped = new AsyncListener() { + @Override public void onComplete(final AsyncEvent event) throws IOException { listener.onComplete(Servlet3Continuation.this); } + @Override public void onError(AsyncEvent event) throws IOException { listener.onComplete(Servlet3Continuation.this); } + @Override public void onStartAsync(AsyncEvent event) throws IOException { event.getAsyncContext().addListener(this); } + @Override public void onTimeout(AsyncEvent event) throws IOException { _expired=true; @@ -115,6 +124,7 @@ public class Servlet3Continuation implements Continuation } /* ------------------------------------------------------------ */ + @Override public void complete() { AsyncContext context=_context; @@ -124,31 +134,35 @@ public class Servlet3Continuation implements Continuation } /* ------------------------------------------------------------ */ + @Override public ServletResponse getServletResponse() { return _response; } /* ------------------------------------------------------------ */ + @Override public boolean isExpired() { return _expired; } /* ------------------------------------------------------------ */ + @Override public boolean isInitial() { - // TODO - this is not perfect if non continuation API is used directly return _initial&&_request.getDispatcherType()!=DispatcherType.ASYNC; } /* ------------------------------------------------------------ */ + @Override public boolean isResumed() { return _resumed; } /* ------------------------------------------------------------ */ + @Override public boolean isSuspended() { return _request.isAsyncStarted(); @@ -161,6 +175,7 @@ public class Servlet3Continuation implements Continuation } /* ------------------------------------------------------------ */ + @Override public void resume() { AsyncContext context=_context; @@ -171,6 +186,7 @@ public class Servlet3Continuation implements Continuation } /* ------------------------------------------------------------ */ + @Override public void setTimeout(long timeoutMs) { _timeoutMs=timeoutMs; @@ -179,6 +195,7 @@ public class Servlet3Continuation implements Continuation } /* ------------------------------------------------------------ */ + @Override public void suspend(ServletResponse response) { _response=response; @@ -194,6 +211,7 @@ public class Servlet3Continuation implements Continuation } /* ------------------------------------------------------------ */ + @Override public void suspend() { _resumed=false; @@ -207,6 +225,7 @@ public class Servlet3Continuation implements Continuation } /* ------------------------------------------------------------ */ + @Override public boolean isResponseWrapped() { return _responseWrapped; @@ -216,6 +235,7 @@ public class Servlet3Continuation implements Continuation /** * @see org.eclipse.jetty.continuation.Continuation#getAttribute(java.lang.String) */ + @Override public Object getAttribute(String name) { return _request.getAttribute(name); @@ -225,6 +245,7 @@ public class Servlet3Continuation implements Continuation /** * @see org.eclipse.jetty.continuation.Continuation#removeAttribute(java.lang.String) */ + @Override public void removeAttribute(String name) { _request.removeAttribute(name); @@ -234,6 +255,7 @@ public class Servlet3Continuation implements Continuation /** * @see org.eclipse.jetty.continuation.Continuation#setAttribute(java.lang.String, java.lang.Object) */ + @Override public void setAttribute(String name, Object attribute) { _request.setAttribute(name,attribute); @@ -243,6 +265,7 @@ public class Servlet3Continuation implements Continuation /** * @see org.eclipse.jetty.continuation.Continuation#undispatch() */ + @Override public void undispatch() { if (isSuspended()) diff --git a/jetty-deploy/src/main/config/etc/jetty-deploy.xml b/jetty-deploy/src/main/config/etc/jetty-deploy.xml index 5316b500ddf..9b42604d6d3 100644 --- a/jetty-deploy/src/main/config/etc/jetty-deploy.xml +++ b/jetty-deploy/src/main/config/etc/jetty-deploy.xml @@ -43,6 +43,16 @@ /etc/webdefault.xml 1 true + + + + + + diff --git a/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/FileConfigurationManager.java b/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/PropertiesConfigurationManager.java similarity index 54% rename from jetty-deploy/src/main/java/org/eclipse/jetty/deploy/FileConfigurationManager.java rename to jetty-deploy/src/main/java/org/eclipse/jetty/deploy/PropertiesConfigurationManager.java index 076dafe93f6..8cb5c344e82 100644 --- a/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/FileConfigurationManager.java +++ b/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/PropertiesConfigurationManager.java @@ -21,10 +21,15 @@ package org.eclipse.jetty.deploy; import java.io.FileNotFoundException; import java.io.IOException; import java.net.MalformedURLException; +import java.util.Collections; import java.util.HashMap; import java.util.Map; import java.util.Properties; +import org.eclipse.jetty.util.annotation.ManagedAttribute; +import org.eclipse.jetty.util.annotation.ManagedObject; +import org.eclipse.jetty.util.annotation.ManagedOperation; +import org.eclipse.jetty.util.annotation.Name; import org.eclipse.jetty.util.resource.Resource; /** @@ -32,42 +37,55 @@ import org.eclipse.jetty.util.resource.Resource; * * Supplies properties defined in a file. */ -public class FileConfigurationManager implements ConfigurationManager +@ManagedObject("Configure deployed webapps via properties") +public class PropertiesConfigurationManager implements ConfigurationManager { - private Resource _file; - private Map _map = new HashMap(); + private String _properties; + private final Map _map = new HashMap(); - public FileConfigurationManager() + public PropertiesConfigurationManager(String properties) + { + } + + public PropertiesConfigurationManager() { } - public void setFile(String filename) throws MalformedURLException, IOException + @ManagedAttribute("A file or URL of properties") + public void setFile(String resource) throws MalformedURLException, IOException { - _file = Resource.newResource(filename); + _properties=resource; + _map.clear(); + loadProperties(_properties); } + public String getFile() + { + return _properties; + } + + @ManagedOperation("Set a property") + public void put(@Name("name")String name, @Name("value")String value) + { + _map.put(name,value); + } + /** * @see org.eclipse.jetty.deploy.ConfigurationManager#getProperties() */ + @Override public Map getProperties() { - try - { - loadProperties(); - return _map; - } - catch (Exception e) - { - throw new RuntimeException(e); - } + return new HashMap<>(_map); } - private void loadProperties() throws FileNotFoundException, IOException - { - if (_map.isEmpty() && _file!=null) + private void loadProperties(String resource) throws FileNotFoundException, IOException + { + Resource file=Resource.newResource(resource); + if (file!=null && file.exists()) { Properties properties = new Properties(); - properties.load(_file.getInputStream()); + properties.load(file.getInputStream()); for (Map.Entry entry : properties.entrySet()) _map.put(entry.getKey().toString(),String.valueOf(entry.getValue())); } diff --git a/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/providers/WebAppProvider.java b/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/providers/WebAppProvider.java index 61aa16509d1..8b301d8035d 100644 --- a/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/providers/WebAppProvider.java +++ b/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/providers/WebAppProvider.java @@ -22,6 +22,7 @@ import java.io.File; import java.io.FilenameFilter; import java.io.IOException; import java.net.MalformedURLException; +import java.util.Locale; import org.eclipse.jetty.deploy.App; import org.eclipse.jetty.deploy.ConfigurationManager; @@ -77,7 +78,7 @@ public class WebAppProvider extends ScanningAppProvider { return false; } - String lowername = name.toLowerCase(); + String lowername = name.toLowerCase(Locale.ENGLISH); File file = new File(dir,name); @@ -299,9 +300,9 @@ public class WebAppProvider extends ScanningAppProvider { context = URIUtil.SLASH; } - else if (context.toLowerCase().startsWith("root-")) + else if (context.toLowerCase(Locale.ENGLISH).startsWith("root-")) { - int dash=context.toLowerCase().indexOf('-'); + int dash=context.toLowerCase(Locale.ENGLISH).indexOf('-'); String virtual = context.substring(dash+1); wah.setVirtualHosts(new String[]{virtual}); context = URIUtil.SLASH; diff --git a/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/util/FileID.java b/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/util/FileID.java index cda1fe21a88..7df726926f0 100644 --- a/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/util/FileID.java +++ b/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/util/FileID.java @@ -19,6 +19,7 @@ package org.eclipse.jetty.deploy.util; import java.io.File; +import java.util.Locale; /** * Simple, yet surprisingly common utility methods for identifying various file types commonly seen and worked with in a @@ -38,7 +39,7 @@ public class FileID { if (path.isFile()) { - String name = path.getName().toLowerCase(); + String name = path.getName().toLowerCase(Locale.ENGLISH); return (name.endsWith(".war") || name.endsWith(".jar")); } @@ -62,7 +63,7 @@ public class FileID return false; } - String name = path.getName().toLowerCase(); + String name = path.getName().toLowerCase(Locale.ENGLISH); return (name.endsWith(".war") || name.endsWith(".jar")); } @@ -73,7 +74,7 @@ public class FileID return false; } - String name = path.getName().toLowerCase(); + String name = path.getName().toLowerCase(Locale.ENGLISH); return name.endsWith(".xml"); } } diff --git a/jetty-deploy/src/test/java/org/eclipse/jetty/deploy/providers/ScanningAppProviderRuntimeUpdatesTest.java b/jetty-deploy/src/test/java/org/eclipse/jetty/deploy/providers/ScanningAppProviderRuntimeUpdatesTest.java index 6008c5aa443..b4544b02e0f 100644 --- a/jetty-deploy/src/test/java/org/eclipse/jetty/deploy/providers/ScanningAppProviderRuntimeUpdatesTest.java +++ b/jetty-deploy/src/test/java/org/eclipse/jetty/deploy/providers/ScanningAppProviderRuntimeUpdatesTest.java @@ -134,12 +134,13 @@ public class ScanningAppProviderRuntimeUpdatesTest jetty.assertWebAppContextsExists("/foo"); + jetty.removeWebapp("foo.war"); jetty.removeWebapp("foo.xml"); waitForDirectoryScan(); waitForDirectoryScan(); - // FIXME: hot undeploy with removal not working! - jetty.assertNoWebAppContexts(); + jetty.assertNoWebAppContexts(); } /** diff --git a/jetty-deploy/src/test/resources/binding-test-contexts-1.xml b/jetty-deploy/src/test/resources/binding-test-contexts-1.xml index 1614056f430..37f5292ff2e 100644 --- a/jetty-deploy/src/test/resources/binding-test-contexts-1.xml +++ b/jetty-deploy/src/test/resources/binding-test-contexts-1.xml @@ -50,7 +50,7 @@ /webapps 1 - + /xml-configured-jetty.properties diff --git a/jetty-deploy/src/test/resources/jetty-deploymgr-contexts.xml b/jetty-deploy/src/test/resources/jetty-deploymgr-contexts.xml index acf69585ff5..ba38daef80d 100644 --- a/jetty-deploy/src/test/resources/jetty-deploymgr-contexts.xml +++ b/jetty-deploy/src/test/resources/jetty-deploymgr-contexts.xml @@ -17,7 +17,7 @@ /webapps 1 - + /xml-configured-jetty.properties diff --git a/jetty-distribution/pom.xml b/jetty-distribution/pom.xml index a3f782f00f0..20f8027a298 100644 --- a/jetty-distribution/pom.xml +++ b/jetty-distribution/pom.xml @@ -364,28 +364,29 @@ ${project.version} + + org.eclipse.jetty + jetty-jaas + ${project.version} + + org.eclipse.jetty jetty-annotations ${project.version} - unpack-spdy process-resources diff --git a/jetty-distribution/src/main/resources/README.txt b/jetty-distribution/src/main/resources/README.txt index 8bafb492252..9656bab431b 100644 --- a/jetty-distribution/src/main/resources/README.txt +++ b/jetty-distribution/src/main/resources/README.txt @@ -1,21 +1,12 @@ JETTY ===== - The Jetty project is a 100% Java HTTP Server, HTTP Client -and Servlet Container. - - -The Jetty @ eclipse project is based on the Jetty project at codehaus - - http://jetty.codehaus.org - -Ongoing development is now at the eclipse foundation +and Servlet Container from the eclipse foundation http://www.eclipse.org/jetty/ - -Jetty @ eclipse is open source and is dual licensed using the apache 2.0 and +Jetty is open source and is dual licensed using the apache 2.0 and eclipse public license 1.0. You may choose either license when distributing jetty. @@ -23,7 +14,6 @@ jetty. BUILDING JETTY ============== - Jetty uses maven 2 as its build system. Maven will fetch the dependancies, build the server and assemble a runnable version: @@ -34,7 +24,6 @@ version: RUNNING JETTY ============= - The run directory is either the top-level of a binary release or jetty-distribution/target/assembly-prep directory when built from source. @@ -48,9 +37,12 @@ provided by the start.ini file: java -jar start.jar --help + +Most start options can be configured in the start.ini file or they can be appended to the start line. + To run with extra configuration file(s) appended, eg SSL - java -jar start.jar etc/jetty-ssl.xml + java -jar start.jar etc/jetty-https.xml To run with properties diff --git a/jetty-distribution/src/main/resources/contexts-available/README.TXT b/jetty-distribution/src/main/resources/contexts-available/README.TXT deleted file mode 100644 index 7fa2ac54dae..00000000000 --- a/jetty-distribution/src/main/resources/contexts-available/README.TXT +++ /dev/null @@ -1,3 +0,0 @@ - -This directory contains example contexts that may be deployed by -moving/copying/linking them to the ../contexts directory. diff --git a/jetty-distribution/src/main/resources/start.ini b/jetty-distribution/src/main/resources/start.ini index 9fcc0d2b0b5..29f88a4b252 100644 --- a/jetty-distribution/src/main/resources/start.ini +++ b/jetty-distribution/src/main/resources/start.ini @@ -8,10 +8,21 @@ # Use the following command to see more options # java -jar start.jar --help # +# Each line in this file is prepended to the command line +# as arguments, which may be either: +# + A property like: name=value +# + A file of properties like: /etc/myjetty.properties +# + A classpath option like: OPTION=jmx +# + An XML configuration file like: etc/jetty-feature.xml +# + A start.jar option like: --dry-run +# +# If --exec or --exec-print are used, then this file may also +# contain lines with: +# + A JVM option like: -Xmx2000m +# + A System Property like: -Dcom.sun.management.jmxremote +# #=========================================================== - - #=========================================================== # The --exec option should be used if any of the JVM options # in this file are uncommented (eg -D* or -X*). Because a @@ -31,9 +42,22 @@ # --exec #=========================================================== +#=========================================================== +# Configure Properties. +# The properties defined here may be used by the +# element in the XML files +# passed to start.jar. +# Alternately a file ending with ".properties" can be +# added that will include multiple properties. +# Properties, unlike SystemProperties, do not need --exec +# to be specified. +#----------------------------------------------------------- +# jetty.port=8080 +#=========================================================== + #=========================================================== -# Some recommended JVM arguments. +# Configure JVM arguments. # Must be used with --exec or --exec-print #----------------------------------------------------------- # -Dorg.apache.jasper.compiler.disablejsr199=true @@ -53,16 +77,6 @@ # -XX:CMSInitiatingOccupancyFraction=80 #=========================================================== - -#=========================================================== -# Server logging. -# The following configuration will redirect stderr and stdout -# to file which is rolled over daily. -#----------------------------------------------------------- -# etc/jetty-logging.xml -#=========================================================== - - #=========================================================== # Default Server Options # Use the core server jars with websocket on the classpath @@ -76,9 +90,17 @@ etc/jetty.xml start.d/ #=========================================================== +#=========================================================== +# Server logging. +# The following configuration will redirect stderr and stdout +# to file which is rolled over daily. +#----------------------------------------------------------- +# etc/jetty-logging.xml +#=========================================================== + #=========================================================== # JMX Management -# To enable remote JMX access uncomment jmxromote and +# To enable remote JMX access uncomment jmxremote and # enable --exec or use --exec-print (see above) #----------------------------------------------------------- OPTIONS=jmx @@ -86,6 +108,13 @@ OPTIONS=jmx etc/jetty-jmx.xml #=========================================================== +#=========================================================== +# Java Server Pages +#----------------------------------------------------------- +OPTIONS=jsp +#=========================================================== + + #=========================================================== # Annotations JNDI JASS processing #----------------------------------------------------------- @@ -104,24 +133,26 @@ etc/jetty-http.xml #=========================================================== # HTTPS Connector #----------------------------------------------------------- -etc/jetty-https.xml +# etc/jetty-https.xml #=========================================================== - #=========================================================== # SPDY Connector # SPDY should not be used with HTTPS as the SPDY connector # also provides HTTPS. # The NPN jar must be separately downloaded from # http://repo1.maven.org/maven2/org/mortbay/jetty/npn/npn-boot/1.1.0.v20120525/ -# Must also enable --exec or use --exec-print (see above) +# Must also enable --exec or use --exec-print (see above) or +# add -Xbootclasspath/p:lib/npn-boot-1.1.0.v20120525.jar to +# the java commandline you use to start jetty. +# Make sure that you either reconfigure ports or comment +# jetty-http.xml/jetty-https.xml to avoid port conflicts. #----------------------------------------------------------- # OPTIONS=spdy # -Xbootclasspath/p:lib/npn-boot-1.1.0.v20120525.jar # etc/jetty-spdy.xml #=========================================================== - #=========================================================== # Webapplication Deployer #----------------------------------------------------------- diff --git a/jetty-distribution/src/main/resources/webapps/README.TXT b/jetty-distribution/src/main/resources/webapps/README.TXT index 610ea9cf582..dc2b38915e3 100644 --- a/jetty-distribution/src/main/resources/webapps/README.TXT +++ b/jetty-distribution/src/main/resources/webapps/README.TXT @@ -1,13 +1,25 @@ -This directory is scanned by the WebAppDeployer provider for -web applications to deploy. It may contain: +This directory is scanned by the WebAppDeployer provider for web +applications to deploy using the following conventions: + ++ A directory called example/ will be deployed as a standard web +application if it contains a WEB-INF/ subdirectory, otherwise it will be +deployed as context of static content. The context path will be /example +(eg http://localhost:8080/example/) unless the base name is root, in +which case the context path is /. If the directory name ends with ".d" +it is ignored (by may be used by explicit configuration). + ++ A file called example.war will be deployed as a standard web application +with the context path /example (eg http://localhost:8080/example/). If he +base name is root, then the context path is /. If example.war and example/ +exist, then only the WAR is deployed (which may use the directory as an +unpack location). + ++ An XML file like example.xml will be deployed as a context whose +configuration is defined by the XML. The context path must be set by +the configuration itself. If example.xml and example.war exist, then +only the XML is deployed (which may use the war in its configuration). - + standard WAR files - + directories that are deployed as static content, except for - directories ending in ".d", which are ignored. - + Context XML files that contain XmlConfiguration which - describe individual contexts to be deployed to the server. - This directory is scanned for additions, removals and updates for hot deployment. diff --git a/jetty-distribution/src/main/resources/webapps/ROOT/index.html b/jetty-distribution/src/main/resources/webapps/ROOT/index.html index bc7e2b8c5a1..92de4ddf2a9 100644 --- a/jetty-distribution/src/main/resources/webapps/ROOT/index.html +++ b/jetty-distribution/src/main/resources/webapps/ROOT/index.html @@ -43,9 +43,9 @@ The project is 100% Open Sour

getting help ...

diff --git a/jetty-distribution/src/main/resources/webapps/available.d/README.TXT b/jetty-distribution/src/main/resources/webapps/available.d/README.TXT new file mode 100644 index 00000000000..10f0eae32f1 --- /dev/null +++ b/jetty-distribution/src/main/resources/webapps/available.d/README.TXT @@ -0,0 +1,3 @@ + +This directory contains example context XML that may be deployed by +moving/copying/linking them to the ../../webapps directory. diff --git a/test-jetty-webapp/src/main/config/contexts-available/move-context.xml b/jetty-distribution/src/main/resources/webapps/available.d/move-context.xml similarity index 100% rename from test-jetty-webapp/src/main/config/contexts-available/move-context.xml rename to jetty-distribution/src/main/resources/webapps/available.d/move-context.xml diff --git a/jetty-distribution/src/main/resources/contexts-available/resources.xml b/jetty-distribution/src/main/resources/webapps/available.d/resources.xml similarity index 100% rename from jetty-distribution/src/main/resources/contexts-available/resources.xml rename to jetty-distribution/src/main/resources/webapps/available.d/resources.xml diff --git a/jetty-distribution/src/main/resources/webapps/javadoc.xml b/jetty-distribution/src/main/resources/webapps/javadoc.xml index 3fec5c07feb..71567efd934 100644 --- a/jetty-distribution/src/main/resources/webapps/javadoc.xml +++ b/jetty-distribution/src/main/resources/webapps/javadoc.xml @@ -1,13 +1,7 @@ - - + /javadoc /javadoc/ @@ -21,6 +15,5 @@ to serve static html files and images. max-age=3600,public
- diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpContent.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpContent.java index 16ac07bd367..fa7861ea9ac 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpContent.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpContent.java @@ -21,6 +21,7 @@ package org.eclipse.jetty.http; import java.io.IOException; import java.io.InputStream; import java.nio.ByteBuffer; +import java.nio.channels.ReadableByteChannel; import org.eclipse.jetty.util.resource.Resource; @@ -38,6 +39,7 @@ public interface HttpContent Resource getResource(); long getContentLength(); InputStream getInputStream() throws IOException; + ReadableByteChannel getReadableByteChannel() throws IOException; void release(); /* ------------------------------------------------------------ */ @@ -130,6 +132,13 @@ public interface HttpContent { return _resource.getInputStream(); } + + /* ------------------------------------------------------------ */ + @Override + public ReadableByteChannel getReadableByteChannel() throws IOException + { + return _resource.getReadableByteChannel(); + } /* ------------------------------------------------------------ */ @Override diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpFields.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpFields.java index d221c1d3dea..94551ed56cd 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpFields.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpFields.java @@ -46,9 +46,7 @@ import org.eclipse.jetty.util.StringUtil; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; -// TODO: Make this class inherit from oej.util.Fields -// TODO move this class to jetty-http? - +// TODO Make this class inherit from oej.util.Fields /** * HTTP Fields. A collection of HTTP header and or Trailer fields. @@ -812,7 +810,7 @@ public class HttpFields implements Iterable { hasDomain = true; buf.append(";Domain="); - QuotedStringTokenizer.quoteIfNeeded(buf,domain.toLowerCase(),delim); + QuotedStringTokenizer.quoteIfNeeded(buf,domain.toLowerCase(Locale.ENGLISH),delim); } if (maxAge >= 0) diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpGenerator.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpGenerator.java index dc0eb628253..2aa291d4d86 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpGenerator.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpGenerator.java @@ -255,7 +255,7 @@ public class HttpGenerator return len>0?Result.FLUSH:Result.CONTINUE; } - return len>0?Result.FLUSH:Result.DONE; + return Result.FLUSH; } case COMPLETING: diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpParser.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpParser.java index af2091f98c3..960ab49102e 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpParser.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpParser.java @@ -405,7 +405,7 @@ public class HttpParser setState(State.END); BufferUtil.clear(buffer); return_from_parse|=_handler.headerComplete(); - return_from_parse|=_handler.messageComplete(_contentPosition); + return_from_parse|=_handler.messageComplete(); } else _utf8.append(ch); @@ -455,7 +455,7 @@ public class HttpParser setState(State.END); BufferUtil.clear(buffer); return_from_parse|=_handler.headerComplete(); - return_from_parse|=_handler.messageComplete(_contentPosition); + return_from_parse|=_handler.messageComplete(); } } break; @@ -685,7 +685,7 @@ public class HttpParser case NO_CONTENT: return_from_parse|=_handler.headerComplete(); setState(State.END); - return_from_parse|=_handler.messageComplete(_contentPosition); + return_from_parse|=_handler.messageComplete(); break; default: @@ -920,7 +920,7 @@ public class HttpParser if (_contentPosition==_contentLength) { setState(State.END); - if(_handler.messageComplete(_contentPosition)) + if(_handler.messageComplete()) return true; } break; @@ -958,7 +958,7 @@ public class HttpParser if (_responseStatus>0 && _headResponse) { setState(State.END); - if (_handler.messageComplete(_contentLength)) + if (_handler.messageComplete()) return true; } @@ -990,7 +990,7 @@ public class HttpParser if (remaining == 0) { setState(State.END); - if (_handler.messageComplete(_contentPosition)) + if (_handler.messageComplete()) return true; } else @@ -1014,7 +1014,7 @@ public class HttpParser if(_contentPosition == _contentLength) { setState(State.END); - if (_handler.messageComplete(_contentPosition)) + if (_handler.messageComplete()) return true; } } @@ -1049,7 +1049,7 @@ public class HttpParser if (_eol==HttpTokens.CARRIAGE_RETURN && buffer.hasRemaining() && buffer.get(buffer.position())==HttpTokens.LINE_FEED) _eol=buffer.get(); setState(State.END); - if (_handler.messageComplete(_contentPosition)) + if (_handler.messageComplete()) return true; } else @@ -1079,7 +1079,7 @@ public class HttpParser if (_eol==HttpTokens.CARRIAGE_RETURN && buffer.hasRemaining() && buffer.get(buffer.position())==HttpTokens.LINE_FEED) _eol=buffer.get(); setState(State.END); - if (_handler.messageComplete(_contentPosition)) + if (_handler.messageComplete()) return true; } else @@ -1149,12 +1149,12 @@ public class HttpParser /** * Notifies this parser that I/O code read a -1 and therefore no more data will arrive to be parsed. - * Calling this method may result in an invocation to {@link HttpHandler#messageComplete(long)}, for + * Calling this method may result in an invocation to {@link HttpHandler#messageComplete()}, for * example when the content is delimited by the close of the connection. * If the parser is already in a state that does not need data (for example, it is idle waiting for * a request/response to be parsed), then calling this method is a no-operation. * - * @return the result of the invocation to {@link HttpHandler#messageComplete(long)} if there has been + * @return the result of the invocation to {@link HttpHandler#messageComplete()} if there has been * one, or false otherwise. */ public boolean shutdownInput() @@ -1170,7 +1170,7 @@ public class HttpParser case EOF_CONTENT: setState(State.END); - return _handler.messageComplete(_contentPosition); + return _handler.messageComplete(); case CLOSED: break; @@ -1179,7 +1179,7 @@ public class HttpParser setState(State.END); if (!_headResponse) _handler.earlyEOF(); - return _handler.messageComplete(_contentPosition); + return _handler.messageComplete(); } return false; @@ -1250,7 +1250,7 @@ public class HttpParser public boolean headerComplete(); - public boolean messageComplete(long contentLength); + public boolean messageComplete(); /** * This is the method called by parser when a HTTP Header name and value is found diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpTester.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpTester.java index c557ef456d7..908ba46e752 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpTester.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpTester.java @@ -126,7 +126,7 @@ public class HttpTester } @Override - public boolean messageComplete(long contentLength) + public boolean messageComplete() { return true; } diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/MimeTypes.java b/jetty-http/src/main/java/org/eclipse/jetty/http/MimeTypes.java index b252ca99025..17b6056a54d 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/MimeTypes.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/MimeTypes.java @@ -22,6 +22,7 @@ import java.nio.ByteBuffer; import java.nio.charset.Charset; import java.util.Enumeration; import java.util.HashMap; +import java.util.Locale; import java.util.Map; import java.util.MissingResourceException; import java.util.ResourceBundle; @@ -70,7 +71,7 @@ public class MimeTypes _string=s; _buffer=BufferUtil.toBuffer(s); - int i=s.toLowerCase().indexOf("charset="); + int i=s.toLowerCase(Locale.ENGLISH).indexOf("charset="); _charset=(i>0)?Charset.forName(s.substring(i+8)):null; } diff --git a/jetty-http/src/main/resources/org/eclipse/jetty/http/mime.properties b/jetty-http/src/main/resources/org/eclipse/jetty/http/mime.properties index 1d4c73da6ef..74601e30851 100644 --- a/jetty-http/src/main/resources/org/eclipse/jetty/http/mime.properties +++ b/jetty-http/src/main/resources/org/eclipse/jetty/http/mime.properties @@ -171,6 +171,7 @@ xhtml=application/xhtml+xml xls=application/vnd.ms-excel xml=application/xml xpm=image/x-xpixmap +xsd=application/xml xsl=application/xml xslt=application/xslt+xml xul=application/vnd.mozilla.xul+xml diff --git a/jetty-http/src/test/java/org/eclipse/jetty/http/HttpFieldsTest.java b/jetty-http/src/test/java/org/eclipse/jetty/http/HttpFieldsTest.java index 3eba7713e9f..ea1198a786f 100644 --- a/jetty-http/src/test/java/org/eclipse/jetty/http/HttpFieldsTest.java +++ b/jetty-http/src/test/java/org/eclipse/jetty/http/HttpFieldsTest.java @@ -21,6 +21,7 @@ package org.eclipse.jetty.http; import java.nio.ByteBuffer; import java.util.Enumeration; import java.util.HashSet; +import java.util.Locale; import java.util.Set; import org.eclipse.jetty.util.BufferUtil; @@ -385,7 +386,7 @@ public class HttpFieldsTest { Set s=new HashSet(); while(e.hasMoreElements()) - s.add(e.nextElement().toLowerCase()); + s.add(e.nextElement().toLowerCase(Locale.ENGLISH)); return s; } diff --git a/jetty-http/src/test/java/org/eclipse/jetty/http/HttpGeneratorServerTest.java b/jetty-http/src/test/java/org/eclipse/jetty/http/HttpGeneratorServerTest.java index 38df347c30b..967ccf0bb81 100644 --- a/jetty-http/src/test/java/org/eclipse/jetty/http/HttpGeneratorServerTest.java +++ b/jetty-http/src/test/java/org/eclipse/jetty/http/HttpGeneratorServerTest.java @@ -64,7 +64,7 @@ public class HttpGeneratorServerTest } @Override - public boolean messageComplete(long contentLength) + public boolean messageComplete() { return true; } diff --git a/jetty-http/src/test/java/org/eclipse/jetty/http/HttpParserTest.java b/jetty-http/src/test/java/org/eclipse/jetty/http/HttpParserTest.java index 98d13e8f598..c0861fa3f41 100644 --- a/jetty-http/src/test/java/org/eclipse/jetty/http/HttpParserTest.java +++ b/jetty-http/src/test/java/org/eclipse/jetty/http/HttpParserTest.java @@ -36,15 +36,14 @@ import static org.junit.Assert.assertTrue; */ public class HttpParserTest { - /* ------------------------------------------------------------------------------- */ /** * Parse until {@link #END END} state. * If the parser is already in the END state, then it is {@link #reset reset} and re-parsed. - * @param parser TODO + * @param parser The parser to test * @throws IllegalStateException If the buffers have already been partially parsed. */ - public static void parseAll(HttpParser parser, ByteBuffer buffer) throws EofException + public static void parseAll(HttpParser parser, ByteBuffer buffer) { if (parser.isState(State.END)) parser.reset(); @@ -764,7 +763,7 @@ public class HttpParserTest } @Override - public boolean messageComplete(long contentLength) + public boolean messageComplete() { //System.err.println("messageComplete"); _messageCompleted = true; diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/AbstractConnection.java b/jetty-io/src/main/java/org/eclipse/jetty/io/AbstractConnection.java index 2d6a42b54bd..3b3b785a646 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/AbstractConnection.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/AbstractConnection.java @@ -257,27 +257,25 @@ public abstract class AbstractConnection implements Connection @Override public int getMessagesIn() { - return 0; + return -1; } @Override public int getMessagesOut() { - return 0; + return -1; } @Override public long getBytesIn() { - // TODO Auto-generated method stub - return 0; + return -1; } @Override public long getBytesOut() { - // TODO Auto-generated method stub - return 0; + return -1; } @Override diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/AbstractEndPoint.java b/jetty-io/src/main/java/org/eclipse/jetty/io/AbstractEndPoint.java index 0eb655dd91e..df3f3538457 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/AbstractEndPoint.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/AbstractEndPoint.java @@ -222,7 +222,7 @@ public abstract class AbstractEndPoint implements EndPoint @Override public String toString() { - return String.format("%s@%x{%s%s,o=%b,is=%b,os=%b,fi=%s,wf=%s}{%s}", + return String.format("%s@%x{%s%s,o=%b,is=%b,os=%b,fi=%s,wf=%s,to=%d}{%s}", getClass().getSimpleName(), hashCode(), getRemoteAddress(), @@ -232,6 +232,7 @@ public abstract class AbstractEndPoint implements EndPoint isOutputShutdown(), _fillInterest, _writeFlusher, + _idleTimeout, getConnection()); } } diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/ChannelEndPoint.java b/jetty-io/src/main/java/org/eclipse/jetty/io/ChannelEndPoint.java index 39ac51dcc0d..b0ac7a8e792 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/ChannelEndPoint.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/ChannelEndPoint.java @@ -120,6 +120,11 @@ public class ChannelEndPoint extends AbstractEndPoint implements SocketBased { LOG.debug(e); } + finally + { + _ishut=true; + _oshut=true; + } } @Override @@ -179,7 +184,7 @@ public class ChannelEndPoint extends AbstractEndPoint implements SocketBased } LOG.debug("flushed {} {}", flushed, this); } - catch (ClosedChannelException | EOFException | SocketException e) + catch (IOException e) { throw new EofException(e); } diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/FilterConnection.java b/jetty-io/src/main/java/org/eclipse/jetty/io/FilterConnection.java index fa0928642d3..402f72488ed 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/FilterConnection.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/FilterConnection.java @@ -372,6 +372,14 @@ public class FilterConnection extends AbstractConnection public FilteredEndPoint() { super(null,getEndPoint().getLocalAddress(), getEndPoint().getRemoteAddress()); + setIdleTimeout(getEndPoint().getIdleTimeout()); + } + + @Override + public void setIdleTimeout(long idleTimeout) + { + super.setIdleTimeout(idleTimeout); + getEndPoint().setIdleTimeout(idleTimeout); } @Override diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/SelectChannelEndPoint.java b/jetty-io/src/main/java/org/eclipse/jetty/io/SelectChannelEndPoint.java index 494dbb2ea87..4e7925bff1f 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/SelectChannelEndPoint.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/SelectChannelEndPoint.java @@ -144,7 +144,7 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements SelectorMa } else { - LOG.debug("Local interests update conflict: now {}, was {}, attempted {}", _interestOps.get(), oldInterestOps, newInterestOps); + LOG.debug("Local interests update conflict: now {}, was {}, attempted {} for {}", _interestOps.get(), oldInterestOps, newInterestOps, this); continue; } } diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/SelectorManager.java b/jetty-io/src/main/java/org/eclipse/jetty/io/SelectorManager.java index 1aab8ba7698..b1a22cf04dd 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/SelectorManager.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/SelectorManager.java @@ -40,7 +40,6 @@ import java.util.concurrent.Executor; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; -import org.eclipse.jetty.util.ForkInvoker; import org.eclipse.jetty.util.TypeUtil; import org.eclipse.jetty.util.component.AbstractLifeCycle; import org.eclipse.jetty.util.component.ContainerLifeCycle; @@ -303,12 +302,12 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa */ public class ManagedSelector extends AbstractLifeCycle implements Runnable, Dumpable { - private final ForkInvoker invoker = new ManagedSelectorInvoker(); private final Queue _changes = new ConcurrentLinkedQueue<>(); private final int _id; private Selector _selector; - private Thread _thread; + private volatile Thread _thread; private boolean _needsWakeup = true; + private boolean _runningChanges = false; public ManagedSelector(int id) { @@ -335,23 +334,55 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa /** *

Submits a change to be executed in the selector thread.

- *

Changes may be submitted from any thread, and if they are submitted from a thread different - * from the selector thread, they are queued for execution, and the selector thread woken up + *

Changes may be submitted from any thread, and the selector thread woken up * (if necessary) to execute the change.

* * @param change the change to submit - * @return true if the change has been executed, false if it has been queued for later execution */ - public boolean submit(Runnable change) + public void submit(Runnable change) { - return !invoker.invoke(change); + // if we have been called by the selector thread we can directly run the change + if (_thread==Thread.currentThread()) + { + // If we are already iterating over the changes, just add this change to the list. + // No race here because it is this thread that is iterating over the changes. + if (_runningChanges) + _changes.offer(change); + else + { + // Otherwise we run the queued changes + runChanges(); + // and then directly run the passed change + runChange(change); + } + } + else + { + // otherwise we have to queue the change and wakeup the selector + _changes.offer(change); + LOG.debug("Queued change {}", change); + boolean wakeup = _needsWakeup; + if (wakeup) + wakeup(); + } } private void runChanges() { - Runnable change; - while ((change = _changes.poll()) != null) - runChange(change); + try + { + if (_runningChanges) + throw new IllegalStateException(); + _runningChanges=true; + + Runnable change; + while ((change = _changes.poll()) != null) + runChange(change); + } + finally + { + _runningChanges=false; + } } protected void runChange(Runnable change) @@ -534,8 +565,6 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa public void destroyEndPoint(EndPoint endPoint) { - // TODO - LOG.debug("Destroyed {}", endPoint); Connection connection = endPoint.getConnection(); if (connection != null) @@ -606,38 +635,6 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa selector != null && selector.isOpen() ? selector.selectedKeys().size() : -1); } - private class ManagedSelectorInvoker extends ForkInvoker - { - private ManagedSelectorInvoker() - { - super(4); - } - - @Override - protected boolean condition() - { - return Thread.currentThread() != _thread; - } - - @Override - public void fork(Runnable change) - { - _changes.offer(change); - LOG.debug("Queued change {}", change); - boolean wakeup = _needsWakeup; - if (wakeup) - wakeup(); - } - - @Override - public void call(Runnable change) - { - LOG.debug("Submitted change {}", change); - runChanges(); - runChange(change); - } - } - private class DumpKeys implements Runnable { private final CountDownLatch latch = new CountDownLatch(1); diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/ssl/SslConnection.java b/jetty-io/src/main/java/org/eclipse/jetty/io/ssl/SslConnection.java index f9db9e3f1a3..5e9c8ca8363 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/ssl/SslConnection.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/ssl/SslConnection.java @@ -24,6 +24,7 @@ import java.nio.ByteBuffer; import java.nio.channels.ClosedChannelException; import java.util.Arrays; import java.util.concurrent.Executor; + import javax.net.ssl.SSLEngine; import javax.net.ssl.SSLEngineResult; import javax.net.ssl.SSLEngineResult.HandshakeStatus; @@ -99,22 +100,14 @@ public class SslConnection extends AbstractConnection _decryptedEndPoint.getWriteFlusher().completeWrite(); } }; - private final Runnable _runWriteEmpty = new Runnable() - { - @Override - public void run() - { - _decryptedEndPoint.write(null, new Callback.Empty<>(), BufferUtil.EMPTY_BUFFER); - } - }; - + public SslConnection(ByteBufferPool byteBufferPool, Executor executor, EndPoint endPoint, SSLEngine sslEngine) { super(endPoint, executor); this._bufferPool = byteBufferPool; this._sslEngine = sslEngine; this._decryptedEndPoint = newDecryptedEndPoint(); - + if (endPoint instanceof SocketBased) { try @@ -316,18 +309,16 @@ public class SslConnection extends AbstractConnection } getWriteFlusher().onFail(x); - - // TODO release all buffers??? or may in onClose } } }; public DecryptedEndPoint() { - // TODO does this need idle timeouts super(null,getEndPoint().getLocalAddress(), getEndPoint().getRemoteAddress()); + setIdleTimeout(getEndPoint().getIdleTimeout()); } - + @Override protected FillInterest getFillInterest() { @@ -490,11 +481,13 @@ public class SslConnection extends AbstractConnection LOG.debug("{} filled {} encrypted bytes", SslConnection.this, net_filled); if (net_filled > 0) _underFlown = false; - + // Let's try the SSL thang even if we have no net data because in that // case we want to fall through to the handshake handling int pos = BufferUtil.flipToFill(app_in); + SSLEngineResult unwrapResult = _sslEngine.unwrap(_encryptedInput, app_in); + BufferUtil.flipToFlush(app_in, pos); if (DEBUG) LOG.debug("{} unwrap {}", SslConnection.this, unwrapResult); @@ -612,9 +605,9 @@ public class SslConnection extends AbstractConnection finally { // If we are handshaking, then wake up any waiting write as well as it may have been blocked on the read - if (_decryptedEndPoint._flushRequiresFillToProgress) + if (_flushRequiresFillToProgress) { - _decryptedEndPoint._flushRequiresFillToProgress = false; + _flushRequiresFillToProgress = false; getExecutor().execute(_runCompletWrite); } @@ -657,7 +650,7 @@ public class SslConnection extends AbstractConnection // We will need a network buffer if (_encryptedOutput == null) - _encryptedOutput = _bufferPool.acquire(_sslEngine.getSession().getPacketBufferSize() * 2, _encryptedDirectBuffers); + _encryptedOutput = _bufferPool.acquire(_sslEngine.getSession().getPacketBufferSize(), _encryptedDirectBuffers); while (true) { @@ -671,7 +664,7 @@ public class SslConnection extends AbstractConnection BufferUtil.flipToFlush(_encryptedOutput, pos); if (wrapResult.bytesConsumed()>0) consumed+=wrapResult.bytesConsumed(); - + boolean all_consumed=true; // clear empty buffers to prevent position creeping up the buffer for (ByteBuffer b : appOuts) @@ -736,6 +729,9 @@ public class SslConnection extends AbstractConnection // Tell the onFillable method that there might be a write to complete _flushRequiresFillToProgress = true; fill(__FLUSH_CALLED_FILL); + // Check if after the fill() we need to wrap again + if (_sslEngine.getHandshakeStatus() == HandshakeStatus.NEED_WRAP) + continue; } return all_consumed&&BufferUtil.isEmpty(_encryptedOutput); @@ -761,6 +757,8 @@ public class SslConnection extends AbstractConnection private void releaseEncryptedOutputBuffer() { + if (!Thread.holdsLock(DecryptedEndPoint.this)) + throw new IllegalStateException(); if (_encryptedOutput != null && !_encryptedOutput.hasRemaining()) { _bufferPool.release(_encryptedOutput); diff --git a/jetty-nested/pom.xml b/jetty-jaas/pom.xml similarity index 53% rename from jetty-nested/pom.xml rename to jetty-jaas/pom.xml index 811c4613862..9128322745f 100644 --- a/jetty-nested/pom.xml +++ b/jetty-jaas/pom.xml @@ -1,20 +1,21 @@ - - 4.0.0 org.eclipse.jetty jetty-project 9.0.0-SNAPSHOT - jetty-nested - Jetty :: Nested - jar - Local Servlet Connector for jetty. + 4.0.0 + jetty-jaas + Jetty :: JAAS + Jetty JAAS support - ${project.groupId}.nested + ${project.groupId}.jaas + org.apache.felix maven-bundle-plugin @@ -26,16 +27,16 @@ - javax.servlet.*;version="2.6.0",* + <_versionpolicy> + javax.sql.*,javax.security.*,javax.naming.*, + javax.servlet.*;version="2.6.0", + * - + - org.apache.maven.plugins maven-jar-plugin @@ -44,11 +45,34 @@ + + org.apache.maven.plugins + maven-assembly-plugin + + + package + + single + + + + config + + + + + + + + org.apache.maven.plugins + maven-source-plugin + org.codehaus.mojo findbugs-maven-plugin - org.eclipse.jetty.nested.* + org.eclipse.jetty.jaas.* @@ -56,7 +80,7 @@ org.eclipse.jetty - jetty-server + jetty-security ${project.version} diff --git a/jetty-jaas/src/main/config/etc/jetty-jaas.xml b/jetty-jaas/src/main/config/etc/jetty-jaas.xml new file mode 100644 index 00000000000..0d9613dfbeb --- /dev/null +++ b/jetty-jaas/src/main/config/etc/jetty-jaas.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + + + java.security.auth.login.config + /etc/login.conf + + + diff --git a/jetty-plus/src/main/java/org/eclipse/jetty/plus/jaas/JAASGroup.java b/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/JAASGroup.java similarity index 98% rename from jetty-plus/src/main/java/org/eclipse/jetty/plus/jaas/JAASGroup.java rename to jetty-jaas/src/main/java/org/eclipse/jetty/jaas/JAASGroup.java index 51fc5379db0..042aa78da0f 100644 --- a/jetty-plus/src/main/java/org/eclipse/jetty/plus/jaas/JAASGroup.java +++ b/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/JAASGroup.java @@ -16,7 +16,7 @@ // ======================================================================== // -package org.eclipse.jetty.plus.jaas; +package org.eclipse.jetty.jaas; import java.security.Principal; import java.security.acl.Group; diff --git a/jetty-plus/src/main/java/org/eclipse/jetty/plus/jaas/JAASLoginService.java b/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/JAASLoginService.java similarity index 98% rename from jetty-plus/src/main/java/org/eclipse/jetty/plus/jaas/JAASLoginService.java rename to jetty-jaas/src/main/java/org/eclipse/jetty/jaas/JAASLoginService.java index b9d66da7a51..d7f1f48a1ed 100644 --- a/jetty-plus/src/main/java/org/eclipse/jetty/plus/jaas/JAASLoginService.java +++ b/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/JAASLoginService.java @@ -16,7 +16,7 @@ // ======================================================================== // -package org.eclipse.jetty.plus.jaas; +package org.eclipse.jetty.jaas; import java.io.IOException; import java.security.Principal; @@ -34,8 +34,8 @@ import javax.security.auth.callback.UnsupportedCallbackException; import javax.security.auth.login.LoginContext; import javax.security.auth.login.LoginException; -import org.eclipse.jetty.plus.jaas.callback.ObjectCallback; -import org.eclipse.jetty.plus.jaas.callback.RequestParameterCallback; +import org.eclipse.jetty.jaas.callback.ObjectCallback; +import org.eclipse.jetty.jaas.callback.RequestParameterCallback; import org.eclipse.jetty.security.DefaultIdentityService; import org.eclipse.jetty.security.IdentityService; import org.eclipse.jetty.security.LoginService; @@ -56,7 +56,7 @@ public class JAASLoginService extends AbstractLifeCycle implements LoginService { private static final Logger LOG = Log.getLogger(JAASLoginService.class); - public static String DEFAULT_ROLE_CLASS_NAME = "org.eclipse.jetty.plus.jaas.JAASRole"; + public static String DEFAULT_ROLE_CLASS_NAME = "org.eclipse.jetty.jaas.JAASRole"; public static String[] DEFAULT_ROLE_CLASS_NAMES = {DEFAULT_ROLE_CLASS_NAME}; protected String[] _roleClassNames = DEFAULT_ROLE_CLASS_NAMES; diff --git a/jetty-plus/src/main/java/org/eclipse/jetty/plus/jaas/JAASPrincipal.java b/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/JAASPrincipal.java similarity index 98% rename from jetty-plus/src/main/java/org/eclipse/jetty/plus/jaas/JAASPrincipal.java rename to jetty-jaas/src/main/java/org/eclipse/jetty/jaas/JAASPrincipal.java index b66f60033b1..fd050c63d1a 100644 --- a/jetty-plus/src/main/java/org/eclipse/jetty/plus/jaas/JAASPrincipal.java +++ b/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/JAASPrincipal.java @@ -16,7 +16,7 @@ // ======================================================================== // -package org.eclipse.jetty.plus.jaas; +package org.eclipse.jetty.jaas; import java.io.Serializable; import java.security.Principal; diff --git a/jetty-plus/src/main/java/org/eclipse/jetty/plus/jaas/JAASRole.java b/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/JAASRole.java similarity index 96% rename from jetty-plus/src/main/java/org/eclipse/jetty/plus/jaas/JAASRole.java rename to jetty-jaas/src/main/java/org/eclipse/jetty/jaas/JAASRole.java index b6375ca9351..1f50ca737ea 100644 --- a/jetty-plus/src/main/java/org/eclipse/jetty/plus/jaas/JAASRole.java +++ b/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/JAASRole.java @@ -16,7 +16,7 @@ // ======================================================================== // -package org.eclipse.jetty.plus.jaas; +package org.eclipse.jetty.jaas; public class JAASRole extends JAASPrincipal diff --git a/jetty-plus/src/main/java/org/eclipse/jetty/plus/jaas/JAASUserPrincipal.java b/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/JAASUserPrincipal.java similarity index 98% rename from jetty-plus/src/main/java/org/eclipse/jetty/plus/jaas/JAASUserPrincipal.java rename to jetty-jaas/src/main/java/org/eclipse/jetty/jaas/JAASUserPrincipal.java index e8415d0dad3..43676450443 100644 --- a/jetty-plus/src/main/java/org/eclipse/jetty/plus/jaas/JAASUserPrincipal.java +++ b/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/JAASUserPrincipal.java @@ -16,7 +16,7 @@ // ======================================================================== // -package org.eclipse.jetty.plus.jaas; +package org.eclipse.jetty.jaas; import java.security.Principal; import javax.security.auth.Subject; diff --git a/jetty-plus/src/main/java/org/eclipse/jetty/plus/jaas/RoleCheckPolicy.java b/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/RoleCheckPolicy.java similarity index 97% rename from jetty-plus/src/main/java/org/eclipse/jetty/plus/jaas/RoleCheckPolicy.java rename to jetty-jaas/src/main/java/org/eclipse/jetty/jaas/RoleCheckPolicy.java index 105efb9a6df..671cbf0e00d 100644 --- a/jetty-plus/src/main/java/org/eclipse/jetty/plus/jaas/RoleCheckPolicy.java +++ b/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/RoleCheckPolicy.java @@ -16,7 +16,7 @@ // ======================================================================== // -package org.eclipse.jetty.plus.jaas; +package org.eclipse.jetty.jaas; import java.security.Principal; import java.security.acl.Group; diff --git a/jetty-plus/src/main/java/org/eclipse/jetty/plus/jaas/StrictRoleCheckPolicy.java b/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/StrictRoleCheckPolicy.java similarity index 98% rename from jetty-plus/src/main/java/org/eclipse/jetty/plus/jaas/StrictRoleCheckPolicy.java rename to jetty-jaas/src/main/java/org/eclipse/jetty/jaas/StrictRoleCheckPolicy.java index e279fd713ea..edbbf162a57 100644 --- a/jetty-plus/src/main/java/org/eclipse/jetty/plus/jaas/StrictRoleCheckPolicy.java +++ b/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/StrictRoleCheckPolicy.java @@ -16,7 +16,7 @@ // ======================================================================== // -package org.eclipse.jetty.plus.jaas; +package org.eclipse.jetty.jaas; import java.security.Principal; import java.security.acl.Group; diff --git a/jetty-plus/src/main/java/org/eclipse/jetty/plus/jaas/callback/AbstractCallbackHandler.java b/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/callback/AbstractCallbackHandler.java similarity index 97% rename from jetty-plus/src/main/java/org/eclipse/jetty/plus/jaas/callback/AbstractCallbackHandler.java rename to jetty-jaas/src/main/java/org/eclipse/jetty/jaas/callback/AbstractCallbackHandler.java index 89c74cca250..fd8842662ae 100644 --- a/jetty-plus/src/main/java/org/eclipse/jetty/plus/jaas/callback/AbstractCallbackHandler.java +++ b/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/callback/AbstractCallbackHandler.java @@ -16,7 +16,7 @@ // ======================================================================== // -package org.eclipse.jetty.plus.jaas.callback; +package org.eclipse.jetty.jaas.callback; import java.io.IOException; import javax.security.auth.callback.Callback; diff --git a/jetty-plus/src/main/java/org/eclipse/jetty/plus/jaas/callback/DefaultCallbackHandler.java b/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/callback/DefaultCallbackHandler.java similarity index 98% rename from jetty-plus/src/main/java/org/eclipse/jetty/plus/jaas/callback/DefaultCallbackHandler.java rename to jetty-jaas/src/main/java/org/eclipse/jetty/jaas/callback/DefaultCallbackHandler.java index c523efc2255..076ab56e312 100644 --- a/jetty-plus/src/main/java/org/eclipse/jetty/plus/jaas/callback/DefaultCallbackHandler.java +++ b/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/callback/DefaultCallbackHandler.java @@ -16,7 +16,7 @@ // ======================================================================== // -package org.eclipse.jetty.plus.jaas.callback; +package org.eclipse.jetty.jaas.callback; import java.io.IOException; import java.util.Arrays; diff --git a/jetty-plus/src/main/java/org/eclipse/jetty/plus/jaas/callback/ObjectCallback.java b/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/callback/ObjectCallback.java similarity index 97% rename from jetty-plus/src/main/java/org/eclipse/jetty/plus/jaas/callback/ObjectCallback.java rename to jetty-jaas/src/main/java/org/eclipse/jetty/jaas/callback/ObjectCallback.java index 41bf4eafc79..927e941abf7 100644 --- a/jetty-plus/src/main/java/org/eclipse/jetty/plus/jaas/callback/ObjectCallback.java +++ b/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/callback/ObjectCallback.java @@ -16,7 +16,7 @@ // ======================================================================== // -package org.eclipse.jetty.plus.jaas.callback; +package org.eclipse.jetty.jaas.callback; import javax.security.auth.callback.Callback; diff --git a/jetty-plus/src/main/java/org/eclipse/jetty/plus/jaas/callback/RequestParameterCallback.java b/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/callback/RequestParameterCallback.java similarity index 97% rename from jetty-plus/src/main/java/org/eclipse/jetty/plus/jaas/callback/RequestParameterCallback.java rename to jetty-jaas/src/main/java/org/eclipse/jetty/jaas/callback/RequestParameterCallback.java index c56b09af341..a23eaeecd00 100644 --- a/jetty-plus/src/main/java/org/eclipse/jetty/plus/jaas/callback/RequestParameterCallback.java +++ b/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/callback/RequestParameterCallback.java @@ -16,7 +16,7 @@ // ======================================================================== // -package org.eclipse.jetty.plus.jaas.callback; +package org.eclipse.jetty.jaas.callback; import java.util.List; import javax.security.auth.callback.Callback; diff --git a/jetty-plus/src/main/java/org/eclipse/jetty/plus/jaas/spi/AbstractDatabaseLoginModule.java b/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/spi/AbstractDatabaseLoginModule.java similarity index 99% rename from jetty-plus/src/main/java/org/eclipse/jetty/plus/jaas/spi/AbstractDatabaseLoginModule.java rename to jetty-jaas/src/main/java/org/eclipse/jetty/jaas/spi/AbstractDatabaseLoginModule.java index 7535dd23d5c..a4ca5dda3f0 100644 --- a/jetty-plus/src/main/java/org/eclipse/jetty/plus/jaas/spi/AbstractDatabaseLoginModule.java +++ b/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/spi/AbstractDatabaseLoginModule.java @@ -16,7 +16,7 @@ // ======================================================================== // -package org.eclipse.jetty.plus.jaas.spi; +package org.eclipse.jetty.jaas.spi; import java.sql.Connection; import java.sql.PreparedStatement; diff --git a/jetty-plus/src/main/java/org/eclipse/jetty/plus/jaas/spi/AbstractLoginModule.java b/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/spi/AbstractLoginModule.java similarity index 97% rename from jetty-plus/src/main/java/org/eclipse/jetty/plus/jaas/spi/AbstractLoginModule.java rename to jetty-jaas/src/main/java/org/eclipse/jetty/jaas/spi/AbstractLoginModule.java index dd9448162b9..d5934979b56 100644 --- a/jetty-plus/src/main/java/org/eclipse/jetty/plus/jaas/spi/AbstractLoginModule.java +++ b/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/spi/AbstractLoginModule.java @@ -16,7 +16,7 @@ // ======================================================================== // -package org.eclipse.jetty.plus.jaas.spi; +package org.eclipse.jetty.jaas.spi; import java.io.IOException; import java.security.Principal; @@ -33,9 +33,9 @@ import javax.security.auth.callback.UnsupportedCallbackException; import javax.security.auth.login.LoginException; import javax.security.auth.spi.LoginModule; -import org.eclipse.jetty.plus.jaas.JAASPrincipal; -import org.eclipse.jetty.plus.jaas.JAASRole; -import org.eclipse.jetty.plus.jaas.callback.ObjectCallback; +import org.eclipse.jetty.jaas.JAASPrincipal; +import org.eclipse.jetty.jaas.JAASRole; +import org.eclipse.jetty.jaas.callback.ObjectCallback; /** * AbstractLoginModule diff --git a/jetty-plus/src/main/java/org/eclipse/jetty/plus/jaas/spi/DataSourceLoginModule.java b/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/spi/DataSourceLoginModule.java similarity index 98% rename from jetty-plus/src/main/java/org/eclipse/jetty/plus/jaas/spi/DataSourceLoginModule.java rename to jetty-jaas/src/main/java/org/eclipse/jetty/jaas/spi/DataSourceLoginModule.java index 4771399dd09..77517a9711d 100644 --- a/jetty-plus/src/main/java/org/eclipse/jetty/plus/jaas/spi/DataSourceLoginModule.java +++ b/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/spi/DataSourceLoginModule.java @@ -16,7 +16,7 @@ // ======================================================================== // -package org.eclipse.jetty.plus.jaas.spi; +package org.eclipse.jetty.jaas.spi; import java.sql.Connection; import java.util.Map; diff --git a/jetty-plus/src/main/java/org/eclipse/jetty/plus/jaas/spi/JDBCLoginModule.java b/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/spi/JDBCLoginModule.java similarity index 98% rename from jetty-plus/src/main/java/org/eclipse/jetty/plus/jaas/spi/JDBCLoginModule.java rename to jetty-jaas/src/main/java/org/eclipse/jetty/jaas/spi/JDBCLoginModule.java index 0e6ac5e8a10..f4f82dad853 100644 --- a/jetty-plus/src/main/java/org/eclipse/jetty/plus/jaas/spi/JDBCLoginModule.java +++ b/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/spi/JDBCLoginModule.java @@ -16,7 +16,7 @@ // ======================================================================== // -package org.eclipse.jetty.plus.jaas.spi; +package org.eclipse.jetty.jaas.spi; import java.sql.Connection; import java.sql.DriverManager; diff --git a/jetty-plus/src/main/java/org/eclipse/jetty/plus/jaas/spi/LdapLoginModule.java b/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/spi/LdapLoginModule.java similarity index 97% rename from jetty-plus/src/main/java/org/eclipse/jetty/plus/jaas/spi/LdapLoginModule.java rename to jetty-jaas/src/main/java/org/eclipse/jetty/jaas/spi/LdapLoginModule.java index 676233f008c..649b31bbc7b 100644 --- a/jetty-plus/src/main/java/org/eclipse/jetty/plus/jaas/spi/LdapLoginModule.java +++ b/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/spi/LdapLoginModule.java @@ -16,12 +16,13 @@ // ======================================================================== // -package org.eclipse.jetty.plus.jaas.spi; +package org.eclipse.jetty.jaas.spi; import java.io.IOException; import java.util.ArrayList; import java.util.Hashtable; import java.util.List; +import java.util.Locale; import java.util.Map; import java.util.Properties; import javax.naming.Context; @@ -40,7 +41,7 @@ import javax.security.auth.callback.NameCallback; import javax.security.auth.callback.UnsupportedCallbackException; import javax.security.auth.login.LoginException; -import org.eclipse.jetty.plus.jaas.callback.ObjectCallback; +import org.eclipse.jetty.jaas.callback.ObjectCallback; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; import org.eclipse.jetty.util.security.Credential; @@ -652,12 +653,12 @@ public class LdapLoginModule extends AbstractLoginModule public static String convertCredentialJettyToLdap(String encryptedPassword) { - if ("MD5:".startsWith(encryptedPassword.toUpperCase())) + if ("MD5:".startsWith(encryptedPassword.toUpperCase(Locale.ENGLISH))) { return "{MD5}" + encryptedPassword.substring("MD5:".length(), encryptedPassword.length()); } - if ("CRYPT:".startsWith(encryptedPassword.toUpperCase())) + if ("CRYPT:".startsWith(encryptedPassword.toUpperCase(Locale.ENGLISH))) { return "{CRYPT}" + encryptedPassword.substring("CRYPT:".length(), encryptedPassword.length()); } @@ -672,12 +673,12 @@ public class LdapLoginModule extends AbstractLoginModule return encryptedPassword; } - if ("{MD5}".startsWith(encryptedPassword.toUpperCase())) + if ("{MD5}".startsWith(encryptedPassword.toUpperCase(Locale.ENGLISH))) { return "MD5:" + encryptedPassword.substring("{MD5}".length(), encryptedPassword.length()); } - if ("{CRYPT}".startsWith(encryptedPassword.toUpperCase())) + if ("{CRYPT}".startsWith(encryptedPassword.toUpperCase(Locale.ENGLISH))) { return "CRYPT:" + encryptedPassword.substring("{CRYPT}".length(), encryptedPassword.length()); } diff --git a/jetty-plus/src/main/java/org/eclipse/jetty/plus/jaas/spi/PropertyFileLoginModule.java b/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/spi/PropertyFileLoginModule.java similarity index 99% rename from jetty-plus/src/main/java/org/eclipse/jetty/plus/jaas/spi/PropertyFileLoginModule.java rename to jetty-jaas/src/main/java/org/eclipse/jetty/jaas/spi/PropertyFileLoginModule.java index bd4f8cbbe46..fbf2f98f7ea 100644 --- a/jetty-plus/src/main/java/org/eclipse/jetty/plus/jaas/spi/PropertyFileLoginModule.java +++ b/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/spi/PropertyFileLoginModule.java @@ -16,7 +16,7 @@ // ======================================================================== // -package org.eclipse.jetty.plus.jaas.spi; +package org.eclipse.jetty.jaas.spi; import java.security.Principal; import java.util.ArrayList; diff --git a/jetty-plus/src/main/java/org/eclipse/jetty/plus/jaas/spi/UserInfo.java b/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/spi/UserInfo.java similarity index 97% rename from jetty-plus/src/main/java/org/eclipse/jetty/plus/jaas/spi/UserInfo.java rename to jetty-jaas/src/main/java/org/eclipse/jetty/jaas/spi/UserInfo.java index c40010046a2..a03a09a266b 100644 --- a/jetty-plus/src/main/java/org/eclipse/jetty/plus/jaas/spi/UserInfo.java +++ b/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/spi/UserInfo.java @@ -16,7 +16,7 @@ // ======================================================================== // -package org.eclipse.jetty.plus.jaas.spi; +package org.eclipse.jetty.jaas.spi; import java.util.ArrayList; import java.util.List; diff --git a/jetty-jmx/src/main/java/org/eclipse/jetty/jmx/MBeanContainer.java b/jetty-jmx/src/main/java/org/eclipse/jetty/jmx/MBeanContainer.java index 8c81f8654b2..2b1e346844e 100644 --- a/jetty-jmx/src/main/java/org/eclipse/jetty/jmx/MBeanContainer.java +++ b/jetty-jmx/src/main/java/org/eclipse/jetty/jmx/MBeanContainer.java @@ -20,6 +20,7 @@ package org.eclipse.jetty.jmx; import java.io.IOException; import java.util.HashMap; +import java.util.Locale; import java.util.Map; import java.util.WeakHashMap; @@ -164,7 +165,7 @@ public class MBeanContainer implements Container.InheritedListener, Dumpable domain = obj.getClass().getPackage().getName(); - String type = obj.getClass().getName().toLowerCase(); + String type = obj.getClass().getName().toLowerCase(Locale.ENGLISH); int dot = type.lastIndexOf('.'); if (dot >= 0) type = type.substring(dot + 1); diff --git a/jetty-jmx/src/main/java/org/eclipse/jetty/jmx/ObjectMBean.java b/jetty-jmx/src/main/java/org/eclipse/jetty/jmx/ObjectMBean.java index db02cd3eb4b..2dcc9289570 100644 --- a/jetty-jmx/src/main/java/org/eclipse/jetty/jmx/ObjectMBean.java +++ b/jetty-jmx/src/main/java/org/eclipse/jetty/jmx/ObjectMBean.java @@ -30,6 +30,7 @@ import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; +import java.util.Locale; import java.util.Map; import java.util.Set; import javax.management.Attribute; @@ -622,7 +623,7 @@ public class ObjectMBean implements DynamicMBean convert = true; } - String uName = name.substring(0, 1).toUpperCase() + name.substring(1); + String uName = name.substring(0, 1).toUpperCase(Locale.ENGLISH) + name.substring(1); Class oClass = onMBean ? this.getClass() : _managed.getClass(); LOG.debug("defineAttribute {} {}:{}:{}:{}",name,onMBean,readonly,oClass,description); @@ -862,7 +863,7 @@ public class ObjectMBean implements DynamicMBean variableName = variableName.substring(2); } - variableName = variableName.substring(0,1).toLowerCase() + variableName.substring(1); + variableName = variableName.substring(0,1).toLowerCase(Locale.ENGLISH) + variableName.substring(1); return variableName; } diff --git a/jetty-jspc-maven-plugin/pom.xml b/jetty-jspc-maven-plugin/pom.xml index 710ae74caa3..002c58adace 100644 --- a/jetty-jspc-maven-plugin/pom.xml +++ b/jetty-jspc-maven-plugin/pom.xml @@ -62,9 +62,9 @@ 2.0.3 - org.apache.maven + org.apache.maven.plugin-tools maven-plugin-tools-api - 2.0.3 + 3.1 junit diff --git a/jetty-maven-plugin/pom.xml b/jetty-maven-plugin/pom.xml index d7f5ca1cffc..0d230134243 100644 --- a/jetty-maven-plugin/pom.xml +++ b/jetty-maven-plugin/pom.xml @@ -10,7 +10,7 @@ Jetty :: Jetty Maven Plugin 3.0.3 - 2.9 + 3.1 diff --git a/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/AbstractJettyMojo.java b/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/AbstractJettyMojo.java index a891f10caac..ac426630987 100644 --- a/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/AbstractJettyMojo.java +++ b/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/AbstractJettyMojo.java @@ -483,7 +483,7 @@ public abstract class AbstractJettyMojo extends AbstractMojo if (connectors == null || connectors.length == 0) { //if a SystemProperty -Djetty.port= has been supplied, use that as the default port - this.connectors = new Connector[] { this.server.createDefaultConnector(server, System.getProperty(PORT_SYSPROPERTY, null)) }; + this.connectors = new Connector[] { this.server.createDefaultConnector(System.getProperty(PORT_SYSPROPERTY, null)) }; this.server.setConnectors(this.connectors); } } diff --git a/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/ConsoleScanner.java b/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/ConsoleScanner.java index cdd769fa5d8..8b3528678f4 100644 --- a/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/ConsoleScanner.java +++ b/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/ConsoleScanner.java @@ -16,58 +16,55 @@ // ======================================================================== // -/** - * - */ package org.eclipse.jetty.maven.plugin; import java.io.IOException; -public class ConsoleScanner extends Thread +public class ConsoleScanner extends Thread { - + private final AbstractJettyMojo mojo; - - public ConsoleScanner(AbstractJettyMojo mojo) + + public ConsoleScanner(AbstractJettyMojo mojo) { this.mojo = mojo; setName("Console scanner"); setDaemon(true); } - - public void run() - { - try + + public void run() + { + try { - while (true) + while (true) { checkSystemInput(); getSomeSleep(); } - } - catch (IOException e) + } + catch (IOException e) { mojo.getLog().warn(e); } } - - private void getSomeSleep() + + private void getSomeSleep() { - try + try { Thread.sleep(500); - } - catch (InterruptedException e) + } + catch (InterruptedException e) { mojo.getLog().debug(e); } } - - private void checkSystemInput() throws IOException - { + + private void checkSystemInput() throws IOException + { while (System.in.available() > 0) { int inputByte = System.in.read(); - if (inputByte >= 0) + if (inputByte >= 0) { char c = (char)inputByte; if (c == '\n') { @@ -76,12 +73,12 @@ public class ConsoleScanner extends Thread } } } - - + + /** * Skip buffered bytes of system console. */ - private void clearInputBuffer() + private void clearInputBuffer() { try { @@ -101,9 +98,9 @@ public class ConsoleScanner extends Thread catch (IOException e) { mojo.getLog().warn("Error discarding console input buffer", e); - } + } } - + private void restartWebApp() { try diff --git a/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/JettyDeployWar.java b/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/JettyDeployWar.java index 8810e6f484e..9010ccff434 100644 --- a/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/JettyDeployWar.java +++ b/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/JettyDeployWar.java @@ -1,46 +1,45 @@ -// -// ======================================================================== -// 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.maven.plugin; - - -/** - *

- * This goal is used to run Jetty with a pre-assembled war. - *

- *

- * It accepts exactly the same options as the run-war goal. - * However, it doesn't assume that the current artifact is a - * webapp and doesn't try to assemble it into a war before its execution. - * So using it makes sense only when used in conjunction with the - * webApp configuration parameter pointing to a pre-built WAR. - *

- *

- * This goal is useful e.g. for launching a web app in Jetty as a target for unit-tested - * HTTP client components. - *

- * - * @goal deploy-war - * @requiresDependencyResolution runtime - * @execute phase="validate" - * @description Deploy a pre-assembled war - * - */ -public class JettyDeployWar extends JettyRunWarMojo -{ -} +// +// ======================================================================== +// 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.maven.plugin; + +/** + *

+ * This goal is used to run Jetty with a pre-assembled war. + *

+ *

+ * It accepts exactly the same options as the run-war goal. + * However, it doesn't assume that the current artifact is a + * webapp and doesn't try to assemble it into a war before its execution. + * So using it makes sense only when used in conjunction with the + * webApp configuration parameter pointing to a pre-built WAR. + *

+ *

+ * This goal is useful e.g. for launching a web app in Jetty as a target for unit-tested + * HTTP client components. + *

+ * + * @goal deploy-war + * @requiresDependencyResolution runtime + * @execute phase="validate" + * @description Deploy a pre-assembled war + * + */ +public class JettyDeployWar extends JettyRunWarMojo +{ +} diff --git a/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/JettyRunForkedMojo.java b/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/JettyRunForkedMojo.java index 0472850a1af..a38272e09a0 100644 --- a/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/JettyRunForkedMojo.java +++ b/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/JettyRunForkedMojo.java @@ -18,23 +18,33 @@ package org.eclipse.jetty.maven.plugin; +import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.BufferedReader; +import java.io.BufferedWriter; import java.io.File; import java.io.FileOutputStream; +import java.io.FileWriter; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.LineNumberReader; import java.net.MalformedURLException; +import java.net.URL; import java.util.ArrayList; import java.util.Arrays; import java.util.HashSet; import java.util.Iterator; import java.util.List; +import java.util.Locale; +import java.util.Map; import java.util.Properties; import java.util.Random; import java.util.Set; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import org.apache.maven.artifact.Artifact; import org.apache.maven.plugin.AbstractMojo; @@ -42,7 +52,10 @@ import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.plugin.MojoFailureException; import org.apache.maven.plugin.descriptor.PluginDescriptor; import org.apache.maven.project.MavenProject; +import org.codehaus.plexus.component.repository.ComponentDependency; +import org.eclipse.jetty.server.RequestLog; import org.eclipse.jetty.util.IO; +import org.eclipse.jetty.util.resource.Resource; /** @@ -64,7 +77,7 @@ import org.eclipse.jetty.util.IO; * There is a reference guide to the configuration parameters for this plugin, and more detailed information * with examples in the Configuration Guide. *

- * + * * @goal run-forked * @requiresDependencyResolution compile+runtime * @execute phase="test-compile" @@ -72,17 +85,17 @@ import org.eclipse.jetty.util.IO; * */ public class JettyRunForkedMojo extends AbstractMojo -{ +{ public String PORT_SYSPROPERTY = "jetty.port"; - + /** * Whether or not to include dependencies on the plugin's classpath with <scope>provided</scope> * Use WITH CAUTION as you may wind up with duplicate jars/classes. * @parameter default-value="false" */ protected boolean useProvidedScope; - - + + /** * The maven project. * @@ -91,9 +104,9 @@ public class JettyRunForkedMojo extends AbstractMojo * @readonly */ private MavenProject project; + - - + /** * If true, the <testOutputDirectory> * and the dependencies of <scope>test<scope> @@ -101,27 +114,27 @@ public class JettyRunForkedMojo extends AbstractMojo * @parameter alias="useTestClasspath" default-value="false" */ private boolean useTestScope; - - + + /** * The default location of the web.xml file. Will be used * if <webAppConfig><descriptor> is not set. - * + * * @parameter expression="${basedir}/src/main/webapp/WEB-INF/web.xml" * @readonly */ private String webXml; - + /** * The target directory - * + * * @parameter expression="${project.build.directory}" * @required * @readonly */ protected File target; - - + + /** * The temporary directory to use for the webapp. * Defaults to target/tmp @@ -132,26 +145,26 @@ public class JettyRunForkedMojo extends AbstractMojo */ protected File tmpDirectory; - + /** * The directory containing generated classes. * * @parameter expression="${project.build.outputDirectory}" * @required - * + * */ private File classesDirectory; - - - + + + /** * The directory containing generated test classes. - * + * * @parameter expression="${project.build.testOutputDirectory}" * @required */ private File testClassesDirectory; - + /** * Root directory for all html/jsp etc files * @@ -159,34 +172,34 @@ public class JettyRunForkedMojo extends AbstractMojo * */ private File webAppSourceDirectory; - - + + /** * Directories that contain static resources * for the webapp. Optional. - * + * * @parameter */ private File[] resourceBases; - - + + /** - * If true, the webAppSourceDirectory will be first on the list of - * resources that form the resource base for the webapp. If false, + * If true, the webAppSourceDirectory will be first on the list of + * resources that form the resource base for the webapp. If false, * it will be last. - * + * * @parameter default-value="true" */ private boolean baseAppFirst; - + /** - * Location of jetty xml configuration files whose contents + * Location of jetty xml configuration files whose contents * will be applied before any plugin configuration. Optional. * @parameter */ private String jettyXml; - + /** * The context path for the webapp. Defaults to the * name of the webapp's artifact. @@ -205,71 +218,71 @@ public class JettyRunForkedMojo extends AbstractMojo */ private String contextXml; - - /** + + /** * @parameter expression="${jetty.skip}" default-value="false" */ private boolean skip; /** - * Port to listen to stop jetty on executing -DSTOP.PORT=<stopPort> + * Port to listen to stop jetty on executing -DSTOP.PORT=<stopPort> * -DSTOP.KEY=<stopKey> -jar start.jar --stop * @parameter * @required */ protected int stopPort; - + /** - * Key to provide when stopping jetty on executing java -DSTOP.KEY=<stopKey> + * Key to provide when stopping jetty on executing java -DSTOP.KEY=<stopKey> * -DSTOP.PORT=<stopPort> -jar start.jar --stop * @parameter * @required */ protected String stopKey; - + /** * Arbitrary jvm args to pass to the forked process * @parameter */ private String jvmArgs; - - + + /** * @parameter expression="${plugin.artifacts}" * @readonly */ private List pluginArtifacts; - - + + /** * @parameter expression="${plugin}" * @readonly */ private PluginDescriptor plugin; - - - + + + /** * @parameter expression="true" default-value="true" */ private boolean waitForChild; - + private Process forkedProcess; - + private Random random; - - - + + + public class ShutdownThread extends Thread { public ShutdownThread() { super("RunForkedShutdown"); } - + public void run () { if (forkedProcess != null && waitForChild) @@ -278,7 +291,7 @@ public class JettyRunForkedMojo extends AbstractMojo } } } - + /** * @see org.apache.maven.plugin.Mojo#execute() */ @@ -295,20 +308,20 @@ public class JettyRunForkedMojo extends AbstractMojo random = new Random(); startJettyRunner(); } - - + + public List getProvidedJars() throws MojoExecutionException - { + { //if we are configured to include the provided dependencies on the plugin's classpath //(which mimics being on jetty's classpath vs being on the webapp's classpath), we first //try and filter out ones that will clash with jars that are plugin dependencies, then //create a new classloader that we setup in the parent chain. if (useProvidedScope) { - - List provided = new ArrayList(); + + List provided = new ArrayList(); for ( Iterator iter = project.getArtifacts().iterator(); iter.hasNext(); ) - { + { Artifact artifact = iter.next(); if (Artifact.SCOPE_PROVIDED.equals(artifact.getScope()) && !isPluginArtifact(artifact)) { @@ -322,16 +335,16 @@ public class JettyRunForkedMojo extends AbstractMojo else return null; } - + /* ------------------------------------------------------------ */ public File prepareConfiguration() throws MojoExecutionException { try - { + { //work out the configuration based on what is configured in the pom File propsFile = new File (target, "fork.props"); if (propsFile.exists()) - propsFile.delete(); + propsFile.delete(); propsFile.createNewFile(); //propsFile.deleteOnExit(); @@ -358,9 +371,9 @@ public class JettyRunForkedMojo extends AbstractMojo //sort out base dir of webapp if (webAppSourceDirectory != null) props.put("base.dir", webAppSourceDirectory.getAbsolutePath()); - + //sort out the resource base directories of the webapp - StringBuilder builder = new StringBuilder(); + StringBuilder builder = new StringBuilder(); if (baseAppFirst) { add((webAppSourceDirectory==null?null:webAppSourceDirectory.getAbsolutePath()), builder); @@ -371,7 +384,7 @@ public class JettyRunForkedMojo extends AbstractMojo } } else - { + { if (resourceBases != null) { for (File resDir:resourceBases) @@ -380,7 +393,7 @@ public class JettyRunForkedMojo extends AbstractMojo add((webAppSourceDirectory==null?null:webAppSourceDirectory.getAbsolutePath()), builder); } props.put("res.dirs", builder.toString()); - + //web-inf classes List classDirs = getClassesDirs(); @@ -397,7 +410,7 @@ public class JettyRunForkedMojo extends AbstractMojo { props.put("classes.dir", classesDirectory.getAbsolutePath()); } - + if (useTestScope && testClassesDirectory != null) { props.put("testClasses.dir", testClassesDirectory.getAbsolutePath()); @@ -435,7 +448,7 @@ public class JettyRunForkedMojo extends AbstractMojo throw new MojoExecutionException("Prepare webapp configuration", e); } } - + private void add (String string, StringBuilder builder) { if (string == null) @@ -448,62 +461,62 @@ public class JettyRunForkedMojo extends AbstractMojo private List getClassesDirs () { List classesDirs = new ArrayList(); - + //if using the test classes, make sure they are first //on the list if (useTestScope && (testClassesDirectory != null)) classesDirs.add(testClassesDirectory); - + if (classesDirectory != null) classesDirs.add(classesDirectory); - + return classesDirs; } - - - + + + private List getOverlays() throws MalformedURLException, IOException { List overlays = new ArrayList(); for ( Iterator iter = project.getArtifacts().iterator(); iter.hasNext(); ) { - Artifact artifact = (Artifact) iter.next(); - + Artifact artifact = (Artifact) iter.next(); + if (artifact.getType().equals("war")) overlays.add(artifact.getFile()); } return overlays; } - - - + + + private List getDependencyFiles () { List dependencyFiles = new ArrayList(); - + for ( Iterator iter = project.getArtifacts().iterator(); iter.hasNext(); ) { Artifact artifact = (Artifact) iter.next(); - - if (((!Artifact.SCOPE_PROVIDED.equals(artifact.getScope())) && (!Artifact.SCOPE_TEST.equals( artifact.getScope()))) + + if (((!Artifact.SCOPE_PROVIDED.equals(artifact.getScope())) && (!Artifact.SCOPE_TEST.equals( artifact.getScope()))) || (useTestScope && Artifact.SCOPE_TEST.equals( artifact.getScope()))) { dependencyFiles.add(artifact.getFile()); - getLog().debug( "Adding artifact " + artifact.getFile().getName() + " for WEB-INF/lib " ); + getLog().debug( "Adding artifact " + artifact.getFile().getName() + " for WEB-INF/lib " ); } } - - return dependencyFiles; + + return dependencyFiles; } - + public boolean isPluginArtifact(Artifact artifact) { if (pluginArtifacts == null || pluginArtifacts.isEmpty()) return false; - + boolean isPluginArtifact = false; for (Iterator iter = pluginArtifacts.iterator(); iter.hasNext() && !isPluginArtifact; ) { @@ -512,18 +525,18 @@ public class JettyRunForkedMojo extends AbstractMojo if (pluginArtifact.getGroupId().equals(artifact.getGroupId()) && pluginArtifact.getArtifactId().equals(artifact.getArtifactId())) isPluginArtifact = true; } - + return isPluginArtifact; } - - - + + + private Set getExtraJars() throws Exception { Set extraJars = new HashSet(); - - + + List l = pluginArtifacts; Artifact pluginArtifact = null; @@ -531,7 +544,7 @@ public class JettyRunForkedMojo extends AbstractMojo { Iterator itor = l.iterator(); while (itor.hasNext() && pluginArtifact == null) - { + { Artifact a = (Artifact)itor.next(); if (a.getArtifactId().equals(plugin.getArtifactId())) //get the jetty-maven-plugin jar { @@ -543,18 +556,18 @@ public class JettyRunForkedMojo extends AbstractMojo return extraJars; } - + /* ------------------------------------------------------------ */ public void startJettyRunner() throws MojoExecutionException - { + { try { - + File props = prepareConfiguration(); - + List cmd = new ArrayList(); cmd.add(getJavaBin()); - + if (jvmArgs != null) { String[] args = jvmArgs.split(" "); @@ -564,7 +577,7 @@ public class JettyRunForkedMojo extends AbstractMojo cmd.add(args[i].trim()); } } - + String classPath = getClassPath(); if (classPath != null && classPath.length() > 0) { @@ -572,7 +585,7 @@ public class JettyRunForkedMojo extends AbstractMojo cmd.add(classPath); } cmd.add(Starter.class.getCanonicalName()); - + if (stopPort > 0 && stopKey != null) { cmd.add("--stop-port"); @@ -585,26 +598,26 @@ public class JettyRunForkedMojo extends AbstractMojo cmd.add("--jetty-xml"); cmd.add(jettyXml); } - + if (contextXml != null) { cmd.add("--context-xml"); cmd.add(contextXml); } - + cmd.add("--props"); cmd.add(props.getAbsolutePath()); - + String token = createToken(); cmd.add("--token"); cmd.add(token); - + ProcessBuilder builder = new ProcessBuilder(cmd); builder.directory(project.getBasedir()); - + if (PluginLog.getLog().isDebugEnabled()) PluginLog.getLog().debug(Arrays.toString(cmd.toArray())); - + forkedProcess = builder.start(); PluginLog.getLog().info("Forked process starting"); @@ -612,7 +625,7 @@ public class JettyRunForkedMojo extends AbstractMojo { startPump("STDOUT",forkedProcess.getInputStream()); startPump("STDERR",forkedProcess.getErrorStream()); - int exitcode = forkedProcess.waitFor(); + int exitcode = forkedProcess.waitFor(); PluginLog.getLog().info("Forked execution exit: "+exitcode); } else @@ -652,20 +665,20 @@ public class JettyRunForkedMojo extends AbstractMojo { if (forkedProcess != null && waitForChild) forkedProcess.destroy(); - + throw new MojoExecutionException("Failed to start Jetty within time limit"); } catch (Exception ex) { if (forkedProcess != null && waitForChild) forkedProcess.destroy(); - + throw new MojoExecutionException("Failed to create Jetty process", ex); } } - - - + + + public String getClassPath() throws Exception { StringBuilder classPath = new StringBuilder(); @@ -682,16 +695,16 @@ public class JettyRunForkedMojo extends AbstractMojo } } - + //Any jars that we need from the plugin environment (like the ones containing Starter class) Set extraJars = getExtraJars(); for (Artifact a:extraJars) - { + { classPath.append(File.pathSeparator); classPath.append(a.getFile().getAbsolutePath()); } - - + + //Any jars that we need from the project's dependencies because we're useProvided List providedJars = getProvidedJars(); if (providedJars != null && !providedJars.isEmpty()) @@ -703,7 +716,7 @@ public class JettyRunForkedMojo extends AbstractMojo if (getLog().isDebugEnabled()) getLog().debug("Adding provided jar: "+jar); } } - + return classPath.toString(); } @@ -724,7 +737,7 @@ public class JettyRunForkedMojo extends AbstractMojo return "java"; } - + public static String fileSeparators(String path) { StringBuilder ret = new StringBuilder(); @@ -759,13 +772,13 @@ public class JettyRunForkedMojo extends AbstractMojo return ret.toString(); } - + private String createToken () { - return Long.toString(random.nextLong()^System.currentTimeMillis(), 36).toUpperCase(); + return Long.toString(random.nextLong()^System.currentTimeMillis(), 36).toUpperCase(Locale.ENGLISH); } - - + + private void startPump(String mode, InputStream inputStream) { ConsoleStreamer pump = new ConsoleStreamer(mode,inputStream); @@ -774,7 +787,7 @@ public class JettyRunForkedMojo extends AbstractMojo thread.start(); } - + /** diff --git a/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/JettyRunMojo.java b/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/JettyRunMojo.java index acd37629849..f8addd006c6 100644 --- a/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/JettyRunMojo.java +++ b/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/JettyRunMojo.java @@ -63,6 +63,9 @@ import org.eclipse.jetty.webapp.WebAppContext; */ public class JettyRunMojo extends AbstractJettyMojo { + public static final String DEFAULT_WEBAPP_SRC = "src"+File.separator+"main"+File.separator+"webapp"; + + /** * If true, the <testOutputDirectory> * and the dependencies of <scope>test<scope> @@ -134,12 +137,13 @@ public class JettyRunMojo extends AbstractJettyMojo */ private List extraScanTargets; - + + /** * Verify the configuration given in the pom. * - * @see org.eclipse.jetty.maven.plugin.AbstractJettyMojo#checkPomConfiguration() + * @see org.mortbay.jetty.plugin.AbstractJettyMojo#checkPomConfiguration() */ public void checkPomConfiguration () throws MojoExecutionException { @@ -147,9 +151,10 @@ public class JettyRunMojo extends AbstractJettyMojo try { if ((getWebAppSourceDirectory() == null) || !getWebAppSourceDirectory().exists()) - { - webAppSourceDirectory = new File (project.getBasedir(), "src"+File.separator+"main"+File.separator+"webapp"); - getLog().info("webAppSourceDirectory "+getWebAppSourceDirectory() +" does not exist. Defaulting to "+webAppSourceDirectory.getAbsolutePath()); + { + File defaultWebAppSrcDir = new File (project.getBasedir(), DEFAULT_WEBAPP_SRC); + getLog().info("webAppSourceDirectory"+(getWebAppSourceDirectory()==null?" not set.":" does not exist.")+" Defaulting to "+defaultWebAppSrcDir.getAbsolutePath()); + webAppSourceDirectory = defaultWebAppSrcDir; } else getLog().info( "Webapp source directory = " + getWebAppSourceDirectory().getCanonicalPath()); @@ -441,6 +446,7 @@ public class JettyRunMojo extends AbstractJettyMojo for ( Iterator iter = projectArtifacts.iterator(); iter.hasNext(); ) { Artifact artifact = (Artifact) iter.next(); + // Include runtime and compile time libraries, and possibly test libs too if(artifact.getType().equals("war")) { @@ -448,6 +454,7 @@ public class JettyRunMojo extends AbstractJettyMojo { Resource r=Resource.newResource("jar:"+Resource.toURL(artifact.getFile()).toString()+"!/"); overlays.add(r); + getLog().info("Adding overlay for war project artifact "+artifact.getId()); getExtraScanTargets().add(artifact.getFile()); } catch(Exception e) diff --git a/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/JettyRunWarExplodedMojo.java b/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/JettyRunWarExplodedMojo.java index c1e6a855d21..33e344dfa03 100644 --- a/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/JettyRunWarExplodedMojo.java +++ b/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/JettyRunWarExplodedMojo.java @@ -25,19 +25,21 @@ import java.util.List; import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.plugin.MojoFailureException; import org.eclipse.jetty.util.Scanner; +import org.eclipse.jetty.util.resource.Resource; +import org.eclipse.jetty.xml.XmlConfiguration; /** - * + * *

* This goal is used to assemble your webapp into an exploded war and automatically deploy it to Jetty. *

*

- * Once invoked, the plugin can be configured to run continuously, scanning for changes in the pom.xml and - * to WEB-INF/web.xml, WEB-INF/classes or WEB-INF/lib and hot redeploy when a change is detected. + * Once invoked, the plugin can be configured to run continuously, scanning for changes in the pom.xml and + * to WEB-INF/web.xml, WEB-INF/classes or WEB-INF/lib and hot redeploy when a change is detected. *

*

* You may also specify the location of a jetty.xml file whose contents will be applied before any plugin configuration. - * This can be used, for example, to deploy a static webapp that is not part of your maven build. + * This can be used, for example, to deploy a static webapp that is not part of your maven build. *

*

* There is a reference guide to the configuration parameters for this plugin, and more detailed information @@ -51,24 +53,24 @@ import org.eclipse.jetty.util.Scanner; public class JettyRunWarExplodedMojo extends AbstractJettyMojo { - - + + /** * The location of the war file. - * + * * @parameter alias="webApp" expression="${project.build.directory}/${project.build.finalName}" * @required */ private File war; - - - - + + + + /** - * - * @see org.eclipse.jetty.maven.plugin.AbstractJettyMojo#checkPomConfiguration() + * + * @see org.mortbay.jetty.plugin.AbstractJettyMojo#checkPomConfiguration() */ public void checkPomConfiguration() throws MojoExecutionException { @@ -76,7 +78,7 @@ public class JettyRunWarExplodedMojo extends AbstractJettyMojo } /** - * @see org.eclipse.jetty.maven.plugin.AbstractJettyMojo#configureScanner() + * @see org.mortbay.jetty.plugin.AbstractJettyMojo#configureScanner() */ public void configureScanner() throws MojoExecutionException { @@ -93,7 +95,7 @@ public class JettyRunWarExplodedMojo extends AbstractJettyMojo scanList.add(new File(webInfDir, "classes")); scanList.add(new File(webInfDir, "lib")); setScanList(scanList); - + ArrayList listeners = new ArrayList(); listeners.add(new Scanner.BulkListener() { @@ -113,10 +115,10 @@ public class JettyRunWarExplodedMojo extends AbstractJettyMojo setScannerListeners(listeners); } - - - - public void restartWebApp(boolean reconfigureScanner) throws Exception + + + + public void restartWebApp(boolean reconfigureScanner) throws Exception { getLog().info("Restarting webapp"); getLog().debug("Stopping webapp ..."); @@ -152,20 +154,20 @@ public class JettyRunWarExplodedMojo extends AbstractJettyMojo getLog().info("Restart completed."); } - - + + public void configureWebApplication () throws Exception { - super.configureWebApplication(); + super.configureWebApplication(); webApp.setWar(war.getCanonicalPath()); } - + public void execute () throws MojoExecutionException, MojoFailureException { super.execute(); } - - - + + + } diff --git a/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/JettyRunWarMojo.java b/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/JettyRunWarMojo.java index 9c320c968c7..35fc923aebe 100644 --- a/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/JettyRunWarMojo.java +++ b/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/JettyRunWarMojo.java @@ -21,10 +21,14 @@ package org.eclipse.jetty.maven.plugin; import java.io.File; import java.util.ArrayList; import java.util.List; +import java.util.Set; +import org.apache.maven.artifact.Artifact; import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.plugin.MojoFailureException; import org.eclipse.jetty.util.Scanner; +import org.eclipse.jetty.util.resource.Resource; +import org.eclipse.jetty.xml.XmlConfiguration; /** *

@@ -32,18 +36,18 @@ import org.eclipse.jetty.util.Scanner; *

*

* Once invoked, the plugin can be configured to run continuously, scanning for changes in the project and to the - * war file and automatically performing a - * hot redeploy when necessary. + * war file and automatically performing a + * hot redeploy when necessary. *

*

* You may also specify the location of a jetty.xml file whose contents will be applied before any plugin configuration. - * This can be used, for example, to deploy a static webapp that is not part of your maven build. + * This can be used, for example, to deploy a static webapp that is not part of your maven build. *

*

* There is a reference guide to the configuration parameters for this plugin, and more detailed information * with examples in the Configuration Guide. *

- * + * * @goal run-war * @requiresDependencyResolution compile+runtime * @execute phase="package" @@ -61,13 +65,13 @@ public class JettyRunWarMojo extends AbstractJettyMojo private File war; - + /** * @see org.apache.maven.plugin.Mojo#execute() */ public void execute() throws MojoExecutionException, MojoFailureException { - super.execute(); + super.execute(); } @@ -75,18 +79,18 @@ public class JettyRunWarMojo extends AbstractJettyMojo public void configureWebApplication () throws Exception { super.configureWebApplication(); - + webApp.setWar(war.getCanonicalPath()); } - + /** - * @see org.eclipse.jetty.maven.plugin.AbstractJettyMojo#checkPomConfiguration() + * @see org.mortbay.jetty.plugin.AbstractJettyMojo#checkPomConfiguration() */ public void checkPomConfiguration() throws MojoExecutionException { - return; + return; } @@ -100,7 +104,7 @@ public class JettyRunWarMojo extends AbstractJettyMojo scanList.add(getProject().getFile()); scanList.add(war); setScanList(scanList); - + ArrayList listeners = new ArrayList(); listeners.add(new Scanner.BulkListener() { @@ -117,11 +121,11 @@ public class JettyRunWarMojo extends AbstractJettyMojo } } }); - setScannerListeners(listeners); + setScannerListeners(listeners); } - public void restartWebApp(boolean reconfigureScanner) throws Exception + public void restartWebApp(boolean reconfigureScanner) throws Exception { getLog().info("Restarting webapp ..."); getLog().debug("Stopping webapp ..."); diff --git a/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/JettyServer.java b/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/JettyServer.java index 56cbecd035e..b0a38bf4988 100644 --- a/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/JettyServer.java +++ b/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/JettyServer.java @@ -23,7 +23,6 @@ import org.eclipse.jetty.server.Connector; import org.eclipse.jetty.server.Handler; import org.eclipse.jetty.server.RequestLog; import org.eclipse.jetty.server.ServerConnector; -import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.handler.ContextHandlerCollection; import org.eclipse.jetty.server.handler.DefaultHandler; import org.eclipse.jetty.server.handler.HandlerCollection; @@ -33,20 +32,20 @@ import org.eclipse.jetty.webapp.WebAppContext; /** * JettyServer - * + * * Maven jetty plugin version of a wrapper for the Server class. - * + * */ public class JettyServer extends org.eclipse.jetty.server.Server { public static int DEFAULT_PORT = 8080; public static int DEFAULT_MAX_IDLE_TIME = 30000; - + private RequestLog requestLog; private ContextHandlerCollection contexts; - - + + public JettyServer() { super(); @@ -55,7 +54,7 @@ public class JettyServer extends org.eclipse.jetty.server.Server Resource.setDefaultUseCaches(false); } - + public void setRequestLog (RequestLog requestLog) { this.requestLog = requestLog; @@ -69,16 +68,16 @@ public class JettyServer extends org.eclipse.jetty.server.Server super.doStart(); } - + /** * @see org.eclipse.jetty.server.handler.HandlerCollection#addHandler(org.eclipse.jetty.server.Handler) */ public void addWebApplication(WebAppContext webapp) throws Exception - { + { contexts.addHandler (webapp); } - + /** * Set up the handler structure to receive a webapp. * Also put in a DefaultHandler so we get a nice page @@ -86,43 +85,43 @@ public class JettyServer extends org.eclipse.jetty.server.Server * context isn't at root. * @throws Exception */ - public void configureHandlers () throws Exception + public void configureHandlers () throws Exception { DefaultHandler defaultHandler = new DefaultHandler(); RequestLogHandler requestLogHandler = new RequestLogHandler(); if (this.requestLog != null) requestLogHandler.setRequestLog(this.requestLog); - + contexts = (ContextHandlerCollection)super.getChildHandlerByClass(ContextHandlerCollection.class); if (contexts==null) - { + { contexts = new ContextHandlerCollection(); HandlerCollection handlers = (HandlerCollection)super.getChildHandlerByClass(HandlerCollection.class); if (handlers==null) { - handlers = new HandlerCollection(); - super.setHandler(handlers); + handlers = new HandlerCollection(); + super.setHandler(handlers); handlers.setHandlers(new Handler[]{contexts, defaultHandler, requestLogHandler}); } else { handlers.addHandler(contexts); } - } + } } - - - - - public Connector createDefaultConnector(Server server, String portnum) throws Exception + + + + + public Connector createDefaultConnector(String portnum) throws Exception { - ServerConnector connector = new ServerConnector(server); + ServerConnector connector = new ServerConnector(this); int port = ((portnum==null||portnum.equals(""))?DEFAULT_PORT:Integer.parseInt(portnum.trim())); connector.setPort(port); - connector.setIdleTimeout(DEFAULT_MAX_IDLE_TIME); - + // connector.setMaxIdleTime(DEFAULT_MAX_IDLE_TIME); + return connector; } - - + + } diff --git a/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/JettyWebAppContext.java b/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/JettyWebAppContext.java index f6b4e122a5a..4a2dcd7308a 100644 --- a/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/JettyWebAppContext.java +++ b/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/JettyWebAppContext.java @@ -28,7 +28,6 @@ import java.util.Map; import java.util.Set; import java.util.TreeSet; -import org.eclipse.jetty.annotations.AnnotationConfiguration; import org.eclipse.jetty.plus.webapp.EnvConfiguration; import org.eclipse.jetty.util.URIUtil; import org.eclipse.jetty.util.log.Log; @@ -39,8 +38,8 @@ import org.eclipse.jetty.webapp.Configuration; import org.eclipse.jetty.webapp.FragmentConfiguration; import org.eclipse.jetty.webapp.JettyWebXmlConfiguration; import org.eclipse.jetty.webapp.MetaInfConfiguration; -import org.eclipse.jetty.webapp.TagLibConfiguration; import org.eclipse.jetty.webapp.WebAppContext; +import org.eclipse.jetty.webapp.WebInfConfiguration; import org.eclipse.jetty.webapp.WebXmlConfiguration; /** @@ -56,6 +55,7 @@ public class JettyWebAppContext extends WebAppContext { private static final Logger LOG = Log.getLogger(JettyWebAppContext.class); + private static final String DEFAULT_CONTAINER_INCLUDE_JAR_PATTERN = ".*/javax.servlet-[^/]*\\.jar$|.*/servlet-api-[^/]*\\.jar$"; private static final String WEB_INF_CLASSES_PREFIX = "/WEB-INF/classes"; private static final String WEB_INF_LIB_PREFIX = "/WEB-INF/lib"; @@ -73,6 +73,19 @@ public class JettyWebAppContext extends WebAppContext * @deprecated The value of this parameter will be ignored by the plugin. Overlays will always be unpacked. */ private boolean unpackOverlays; + + /** + * Set the "org.eclipse.jetty.server.webapp.ContainerIncludeJarPattern" with a pattern for matching jars on + * container classpath to scan. This is analogous to the WebAppContext.setAttribute() call. + */ + private String containerIncludeJarPattern = null; + + /** + * Set the "org.eclipse.jetty.server.webapp.WebInfIncludeJarPattern" with a pattern for matching jars on + * webapp's classpath to scan. This is analogous to the WebAppContext.setAttribute() call. + */ + private String webInfIncludeJarPattern = null; + /** * @deprecated The value of this parameter will be ignored by the plugin. This option will be always disabled. @@ -91,14 +104,34 @@ public class JettyWebAppContext extends WebAppContext new MetaInfConfiguration(), new FragmentConfiguration(), envConfig = new EnvConfiguration(), - new AnnotationConfiguration(), new org.eclipse.jetty.plus.webapp.PlusConfiguration(), - new JettyWebXmlConfiguration(), - new TagLibConfiguration() + new MavenAnnotationConfiguration(), + new JettyWebXmlConfiguration() }); // Turn off copyWebInf option as it is not applicable for plugin. super.setCopyWebInf(false); } + public void setContainerIncludeJarPattern(String pattern) + { + containerIncludeJarPattern = pattern; + } + + public String getContainerIncludeJarPattern() + { + return containerIncludeJarPattern; + } + + + public String getWebInfIncludeJarPattern() + { + return webInfIncludeJarPattern; + } + public void setWebInfIncludeJarPattern(String pattern) + { + webInfIncludeJarPattern = pattern; + } + + public boolean getUnpackOverlays() { @@ -218,17 +251,21 @@ public class JettyWebAppContext extends WebAppContext { //Set up the pattern that tells us where the jars are that need scanning for //stuff like taglibs so we can tell jasper about it (see TagLibConfiguration) - String tmp = (String)getAttribute("org.eclipse.jetty.server.webapp.ContainerIncludeJarPattern"); - - tmp = addPattern(tmp, ".*/.*jsp-api-[^/]*\\.jar$"); - tmp = addPattern(tmp, ".*/.*jsp-[^/]*\\.jar$"); - tmp = addPattern(tmp, ".*/.*taglibs[^/]*\\.jar$"); - tmp = addPattern(tmp, ".*/.*jstl[^/]*\\.jar$"); - tmp = addPattern(tmp, ".*/.*jsf-impl-[^/]*\\.jar$"); // add in 2 most popular jsf impls - tmp = addPattern(tmp, ".*/.*javax.faces-[^/]*\\.jar$"); - tmp = addPattern(tmp, ".*/.*myfaces-impl-[^/]*\\.jar$"); - setAttribute("org.eclipse.jetty.server.webapp.ContainerIncludeJarPattern", tmp); + //Allow user to set up pattern for names of jars from the container classpath + //that will be scanned - note that by default NO jars are scanned + String tmp = containerIncludeJarPattern; + if (tmp==null || "".equals(tmp)) + tmp = (String)getAttribute(WebInfConfiguration.CONTAINER_JAR_PATTERN); + + tmp = addPattern(tmp, DEFAULT_CONTAINER_INCLUDE_JAR_PATTERN); + setAttribute(WebInfConfiguration.CONTAINER_JAR_PATTERN, tmp); + + //Allow user to set up pattern of jar names from WEB-INF that will be scanned. + //Note that by default ALL jars considered to be in WEB-INF will be scanned - setting + //a pattern restricts scanning + if (webInfIncludeJarPattern != null) + setAttribute(WebInfConfiguration.WEBINF_JAR_PATTERN, webInfIncludeJarPattern); //Set up the classes dirs that comprises the equivalent of WEB-INF/classes if (testClasses != null) @@ -241,7 +278,6 @@ public class JettyWebAppContext extends WebAppContext classpathFiles.addAll(webInfClasses); classpathFiles.addAll(webInfJars); - // Initialize map containing all jars in /WEB-INF/lib webInfJarMap.clear(); for (File file : webInfJars) @@ -255,13 +291,28 @@ public class JettyWebAppContext extends WebAppContext if (this.jettyEnvXml != null) envConfig.setJettyEnvXml(Resource.toURL(new File(this.jettyEnvXml))); - //setShutdown(false); + // CHECK setShutdown(false); super.doStart(); } public void doStop () throws Exception { - //setShutdown(true); + if (classpathFiles != null) + classpathFiles.clear(); + classpathFiles = null; + + classes = null; + testClasses = null; + + if (webInfJarMap != null) + webInfJarMap.clear(); + + webInfClasses.clear(); + webInfJars.clear(); + + + + // CHECK setShutdown(true); //just wait a little while to ensure no requests are still being processed Thread.currentThread().sleep(500L); super.doStop(); @@ -344,37 +395,40 @@ public class JettyWebAppContext extends WebAppContext @Override public Set getResourcePaths(String path) { - // Try to get regular resource paths + // Try to get regular resource paths - this will get appropriate paths from any overlaid wars etc Set paths = super.getResourcePaths(path); - - // If no paths are returned check for virtual paths /WEB-INF/classes and /WEB-INF/lib - if (paths.isEmpty() && path != null) + + if (path != null) { - path = URIUtil.canonicalPath(path); + TreeSet allPaths = new TreeSet(); + allPaths.addAll(paths); + + //add in the dependency jars as a virtual WEB-INF/lib entry if (path.startsWith(WEB_INF_LIB_PREFIX)) { - paths = new TreeSet(); for (String fileName : webInfJarMap.keySet()) { // Return all jar files from class path - paths.add(WEB_INF_LIB_PREFIX + "/" + fileName); + allPaths.add(WEB_INF_LIB_PREFIX + "/" + fileName); } } else if (path.startsWith(WEB_INF_CLASSES_PREFIX)) { int i=0; - while (paths.isEmpty() && (i < webInfClasses.size())) + while (i < webInfClasses.size()) { String newPath = path.replace(WEB_INF_CLASSES_PREFIX, webInfClasses.get(i).getPath()); - paths = super.getResourcePaths(newPath); + allPaths.addAll(super.getResourcePaths(newPath)); i++; } } + return allPaths; } return paths; } + public String addPattern (String s, String pattern) { if (s == null) diff --git a/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/MavenAnnotationConfiguration.java b/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/MavenAnnotationConfiguration.java new file mode 100644 index 00000000000..566b4af53f4 --- /dev/null +++ b/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/MavenAnnotationConfiguration.java @@ -0,0 +1,109 @@ +// +// ======================================================================== +// 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.maven.plugin; + +import java.io.File; + +import org.eclipse.jetty.annotations.AbstractDiscoverableAnnotationHandler; +import org.eclipse.jetty.annotations.AnnotationConfiguration; +import org.eclipse.jetty.annotations.AnnotationParser; +import org.eclipse.jetty.annotations.AnnotationParser.DiscoverableAnnotationHandler; +import org.eclipse.jetty.annotations.ClassNameResolver; +import org.eclipse.jetty.util.log.Log; +import org.eclipse.jetty.util.log.Logger; +import org.eclipse.jetty.util.resource.Resource; +import org.eclipse.jetty.webapp.MetaData; +import org.eclipse.jetty.webapp.WebAppContext; + +public class MavenAnnotationConfiguration extends AnnotationConfiguration +{ + private static final Logger LOG = Log.getLogger(MavenAnnotationConfiguration.class); + + /* ------------------------------------------------------------ */ + @Override + public void parseWebInfClasses(final WebAppContext context, final AnnotationParser parser) throws Exception + { + JettyWebAppContext jwac = (JettyWebAppContext)context; + if (jwac.getClassPathFiles() == null || jwac.getClassPathFiles().size() == 0) + super.parseWebInfClasses (context, parser); + else + { + LOG.debug("Scanning classes "); + //Look for directories on the classpath and process each one of those + + MetaData metaData = context.getMetaData(); + if (metaData == null) + throw new IllegalStateException ("No metadata"); + + parser.clearHandlers(); + for (DiscoverableAnnotationHandler h:_discoverableAnnotationHandlers) + { + if (h instanceof AbstractDiscoverableAnnotationHandler) + ((AbstractDiscoverableAnnotationHandler)h).setResource(null); // + } + parser.registerHandlers(_discoverableAnnotationHandlers); + parser.registerHandler(_classInheritanceHandler); + parser.registerHandlers(_containerInitializerAnnotationHandlers); + + + for (File f:jwac.getClassPathFiles()) + { + //scan the equivalent of the WEB-INF/classes directory that has been synthesised by the plugin + if (f.isDirectory() && f.exists()) + { + doParse(context, parser, Resource.newResource(f.toURL())); + } + } + + //if an actual WEB-INF/classes directory also exists (eg because of overlayed wars) then scan that + //too + if (context.getWebInf() != null && context.getWebInf().exists()) + { + Resource classesDir = context.getWebInf().addPath("classes/"); + if (classesDir.exists()) + { + doParse(context, parser, classesDir); + } + } + } + } + + + public void doParse (final WebAppContext context, final AnnotationParser parser, Resource resource) + throws Exception + { + parser.parse(resource, new ClassNameResolver() + { + public boolean isExcluded (String name) + { + if (context.isSystemClass(name)) return true; + if (context.isServerClass(name)) return false; + return false; + } + + public boolean shouldOverride (String name) + { + //looking at webapp classpath, found already-parsed class of same name - did it come from system or duplicate in webapp? + if (context.isParentLoaderPriority()) + return false; + return true; + } + }); + } +} diff --git a/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/MavenWebInfConfiguration.java b/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/MavenWebInfConfiguration.java index 6048cae1d19..5d439e3e71d 100644 --- a/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/MavenWebInfConfiguration.java +++ b/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/MavenWebInfConfiguration.java @@ -24,8 +24,10 @@ import java.net.URLClassLoader; import java.util.ArrayList; import java.util.Iterator; import java.util.List; +import java.util.Locale; import org.eclipse.jetty.util.IO; +import org.eclipse.jetty.util.LazyList; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; import org.eclipse.jetty.util.resource.Resource; @@ -40,8 +42,8 @@ public class MavenWebInfConfiguration extends WebInfConfiguration protected Resource _originalResourceBase; protected Resource[] _unpackedOverlays; - - + + public void configure(WebAppContext context) throws Exception { JettyWebAppContext jwac = (JettyWebAppContext)context; @@ -54,11 +56,11 @@ public class MavenWebInfConfiguration extends WebInfConfiguration while (itor.hasNext()) ((WebAppClassLoader)context.getClassLoader()).addClassPath(((File)itor.next()).getCanonicalPath()); - if (LOG.isDebugEnabled()) - LOG.debug("Classpath = "+((URLClassLoader)context.getClassLoader()).getURLs()); + //if (LOG.isDebugEnabled()) + //LOG.debug("Classpath = "+LazyList.array2List(((URLClassLoader)context.getClassLoader()).getURLs())); } super.configure(context); - + // knock out environmental maven and plexus classes from webAppContext String[] existingServerClasses = context.getServerClasses(); String[] newServerClasses = new String[2+(existingServerClasses==null?0:existingServerClasses.length)]; @@ -71,7 +73,7 @@ public class MavenWebInfConfiguration extends WebInfConfiguration for (int i=0;i0) + { + try + { + for (int i=0; i<_unpackedOverlays.length; i++) + { + IO.delete(_unpackedOverlays[i].getFile()); + } + } + catch (IOException e) + { + LOG.ignore(e); + } + } + super.deconfigure(context); + //restore whatever the base resource was before we might have included overlaid wars + context.setBaseResource(_originalResourceBase); + + } + + + + + /** + * @see org.eclipse.jetty.webapp.WebInfConfiguration#unpack(org.eclipse.jetty.webapp.WebAppContext) + */ + @Override + public void unpack(WebAppContext context) throws IOException + { + //Unpack and find base resource as normal + super.unpack(context); + + + //Add in any overlays as a resource collection for the base _originalResourceBase = context.getBaseResource(); JettyWebAppContext jwac = (JettyWebAppContext)context; @@ -102,7 +151,7 @@ public class MavenWebInfConfiguration extends WebInfConfiguration origSize = 1; } } - + int overlaySize = jwac.getOverlays().size(); Resource[] newResources = new Resource[origSize + overlaySize]; @@ -112,7 +161,6 @@ public class MavenWebInfConfiguration extends WebInfConfiguration if (jwac.getBaseAppFirst()) { System.arraycopy(origResources,0,newResources,0,origSize); - offset = origSize; } else @@ -120,53 +168,23 @@ public class MavenWebInfConfiguration extends WebInfConfiguration System.arraycopy(origResources,0,newResources,overlaySize,origSize); } } - + // Overlays are always unpacked _unpackedOverlays = new Resource[overlaySize]; List overlays = jwac.getOverlays(); for (int idx=0; idx0) - { - try - { - for (int i=0; i<_unpackedOverlays.length; i++) - { - IO.delete(_unpackedOverlays[i].getFile()); - } - } - catch (IOException e) - { - LOG.ignore(e); - } - } - super.deconfigure(context); - //restore whatever the base resource was before we might have included overlaid wars - context.setBaseResource(_originalResourceBase); - - } - /** * Get the jars to examine from the files from which we have @@ -175,6 +193,7 @@ public class MavenWebInfConfiguration extends WebInfConfiguration * @param context * @return the list of jars found */ + @Override protected List findJars (WebAppContext context) throws Exception { @@ -184,7 +203,7 @@ public class MavenWebInfConfiguration extends WebInfConfiguration { for (File f: jwac.getClassPathFiles()) { - if (f.getName().toLowerCase().endsWith(".jar")) + if (f.getName().toLowerCase(Locale.ENGLISH).endsWith(".jar")) { try { @@ -203,14 +222,16 @@ public class MavenWebInfConfiguration extends WebInfConfiguration list.addAll(superList); return list; } + + protected Resource unpackOverlay (WebAppContext context, Resource overlay) throws IOException { //resolve if not already resolved resolveTempDirectory(context); - - + + //Get the name of the overlayed war and unpack it to a dir of the //same name in the temporary directory String name = overlay.getName(); @@ -225,6 +246,4 @@ public class MavenWebInfConfiguration extends WebInfConfiguration Resource unpackedOverlay = Resource.newResource(dir.getCanonicalPath()); return unpackedOverlay; } - - } diff --git a/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/Monitor.java b/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/Monitor.java index 66e6d1529c1..2ef290ea08a 100644 --- a/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/Monitor.java +++ b/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/Monitor.java @@ -16,12 +16,12 @@ // ======================================================================== // - package org.eclipse.jetty.maven.plugin; import java.io.IOException; import java.io.InputStreamReader; import java.io.LineNumberReader; +import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.ServerSocket; import java.net.Socket; @@ -41,7 +41,7 @@ import org.eclipse.jetty.server.Server; * by stopping the Server instances. The choice of * behaviour is controlled by either passing true * (exit jvm) or false (stop Servers) in the constructor. - * + * */ public class Monitor extends Thread { @@ -51,7 +51,7 @@ public class Monitor extends Thread ServerSocket _serverSocket; boolean _kill; - public Monitor(int port, String key, Server[] servers, boolean kill) + public Monitor(int port, String key, Server[] servers, boolean kill) throws UnknownHostException, IOException { if (port <= 0) @@ -64,7 +64,7 @@ public class Monitor extends Thread _kill = kill; setDaemon(true); setName("StopJettyPluginMonitor"); - InetSocketAddress address = new InetSocketAddress("127.0.0.1", port); + InetSocketAddress address = new InetSocketAddress("127.0.0.1", port); _serverSocket=new ServerSocket(); _serverSocket.setReuseAddress(true); try @@ -77,7 +77,7 @@ public class Monitor extends Thread throw x; } } - + public void run() { while (_serverSocket != null) @@ -88,7 +88,7 @@ public class Monitor extends Thread socket = _serverSocket.accept(); socket.setSoLinger(false, 0); LineNumberReader lin = new LineNumberReader(new InputStreamReader(socket.getInputStream())); - + String key = lin.readLine(); if (!_key.equals(key)) continue; String cmd = lin.readLine(); @@ -97,13 +97,13 @@ public class Monitor extends Thread try{socket.close();}catch (Exception e){e.printStackTrace();} try{socket.close();}catch (Exception e){e.printStackTrace();} try{_serverSocket.close();}catch (Exception e){e.printStackTrace();} - + _serverSocket = null; - + if (_kill) { System.out.println("Killing Jetty"); - System.exit(0); + System.exit(0); } else { @@ -111,7 +111,7 @@ public class Monitor extends Thread { try { - System.out.println("Stopping server "+i); + System.out.println("Stopping server "+i); _servers[i].stop(); } catch (Exception e) diff --git a/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/Starter.java b/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/Starter.java index ef2c1092ecf..93eb1e31721 100644 --- a/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/Starter.java +++ b/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/Starter.java @@ -23,19 +23,23 @@ import java.io.FileInputStream; import java.util.ArrayList; import java.util.List; import java.util.Properties; +import java.util.StringTokenizer; import org.eclipse.jetty.server.Connector; import org.eclipse.jetty.server.Handler; import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.server.handler.ContextHandler; +import org.eclipse.jetty.server.handler.ContextHandlerCollection; import org.eclipse.jetty.server.handler.HandlerCollection; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; import org.eclipse.jetty.util.resource.Resource; import org.eclipse.jetty.util.resource.ResourceCollection; +import org.eclipse.jetty.webapp.WebAppContext; import org.eclipse.jetty.xml.XmlConfiguration; public class Starter -{ +{ public static final String PORT_SYSPROPERTY = "jetty.port"; private static final Logger LOG = Log.getLogger(Starter.class); @@ -45,21 +49,21 @@ public class Starter private JettyServer server; private JettyWebAppContext webApp; private Monitor monitor; - + private int stopPort=0; private String stopKey=null; private Properties props; private String token; - - + + public void configureJetty () throws Exception { LOG.debug("Starting Jetty Server ..."); this.server = new JettyServer(); - //apply any configs from jetty.xml files first + //apply any configs from jetty.xml files first applyJettyXml (); // if the user hasn't configured a connector in the jetty.xml @@ -68,7 +72,7 @@ public class Starter if (connectors == null|| connectors.length == 0) { //if a SystemProperty -Djetty.port= has been supplied, use that as the default port - connectors = new Connector[] { this.server.createDefaultConnector(server, System.getProperty(PORT_SYSPROPERTY, null)) }; + connectors = new Connector[] { this.server.createDefaultConnector(System.getProperty(PORT_SYSPROPERTY, null)) }; this.server.setConnectors(connectors); } @@ -84,15 +88,15 @@ public class Starter this.server.configureHandlers(); webApp = new JettyWebAppContext(); - + //configure webapp from properties file describing unassembled webapp configureWebApp(); - + //set up the webapp from the context xml file provided //NOTE: just like jetty:run mojo this means that the context file can //potentially override settings made in the pom. Ideally, we'd like //the pom to override the context xml file, but as the other mojos all - //configure a WebAppContext in the pom (the element), it is + //configure a WebAppContext in the pom (the element), it is //already configured by the time the context xml file is applied. if (contextXml != null) { @@ -109,30 +113,30 @@ public class Starter monitor = new Monitor(stopPort, stopKey, new Server[]{server}, true); } } - - + + public void configureWebApp () throws Exception { if (props == null) return; - + //apply a properties file that defines the things that we configure in the jetty:run plugin: // - the context path String str = (String)props.get("context.path"); if (str != null) webApp.setContextPath(str); - + // - web.xml str = (String)props.get("web.xml"); if (str != null) webApp.setDescriptor(str); - + // - the tmp directory str = (String)props.getProperty("tmp.dir"); if (str != null) webApp.setTempDirectory(new File(str.trim())); - + // - the base directory str = (String)props.getProperty("base.dir"); if (str != null && !"".equals(str.trim())) @@ -145,7 +149,7 @@ public class Starter ResourceCollection resources = new ResourceCollection(str); webApp.setBaseResource(resources); } - + // - overlays str = (String)props.getProperty("overlay.files"); if (str != null && !"".equals(str.trim())) @@ -163,8 +167,8 @@ public class Starter { webApp.setClasses(new File(str)); } - - str = (String)props.getProperty("testClasses.dir"); + + str = (String)props.getProperty("testClasses.dir"); if (str != null && !"".equals(str.trim())) { webApp.setTestClasses(new File(str)); @@ -181,7 +185,7 @@ public class Starter jars.add(new File(names[j].trim())); webApp.setWebInfLib(jars); } - + } public void getConfiguration (String[] args) @@ -205,7 +209,7 @@ public class Starter for (int j=0; names!= null && j < names.length; j++) { jettyXmls.add(new File(names[j].trim())); - } + } } //--context-xml @@ -221,7 +225,7 @@ public class Starter props = new Properties(); props.load(new FileInputStream(f)); } - + //--token if ("--token".equals(args[i])) { @@ -237,16 +241,16 @@ public class Starter monitor.start(); LOG.info("Started Jetty Server"); - server.start(); + server.start(); } - + public void join () throws Exception { server.join(); } - - + + public void communicateStartupResult (Exception e) { if (token != null) @@ -257,16 +261,16 @@ public class Starter System.out.println(token+"\t"+e.getMessage()); } } - - + + public void applyJettyXml() throws Exception { if (jettyXmls == null) return; - + for ( File xmlFile : jettyXmls ) { - LOG.info( "Configuring Jetty from xml configuration file = " + xmlFile.getCanonicalPath() ); + LOG.info( "Configuring Jetty from xml configuration file = " + xmlFile.getCanonicalPath() ); XmlConfiguration xmlConfiguration = new XmlConfiguration(Resource.toURL(xmlFile)); xmlConfiguration.configure(this.server); } @@ -286,8 +290,8 @@ public class Starter System.arraycopy(existing, 0, children, 1, existing.length); handlers.setHandlers(children); } - - + + public static final void main(String[] args) { if (args == null) diff --git a/jetty-nested/src/main/java/org/eclipse/jetty/nested/NestedConnection.java b/jetty-nested/src/main/java/org/eclipse/jetty/nested/NestedConnection.java deleted file mode 100644 index 9d32f0e643c..00000000000 --- a/jetty-nested/src/main/java/org/eclipse/jetty/nested/NestedConnection.java +++ /dev/null @@ -1,121 +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.nested; - -import java.io.IOException; -import java.util.Enumeration; - -import javax.servlet.DispatcherType; -import javax.servlet.ServletException; -import javax.servlet.ServletInputStream; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -import org.eclipse.jetty.http.HttpFields; -import org.eclipse.jetty.http.HttpURI; -import org.eclipse.jetty.io.Connection; -import org.eclipse.jetty.server.AbstractHttpConnection; - - -public class NestedConnection extends AbstractHttpConnection -{ - protected NestedConnection(final NestedConnector connector, final NestedEndPoint endp, final HttpServletRequest outerRequest, HttpServletResponse outerResponse,String nestedIn) - throws IOException - { - super(connector, - endp, - connector.getServer(), - new NestedParser(), - new NestedGenerator(connector.getResponseBuffers(),endp,outerResponse,nestedIn), - new NestedRequest(outerRequest)); - - ((NestedRequest)_request).setConnection(this); - - // Set the request line - _request.setDispatcherType(DispatcherType.REQUEST); - _request.setScheme(outerRequest.getScheme()); - _request.setMethod(outerRequest.getMethod()); - String uri=outerRequest.getQueryString()==null?outerRequest.getRequestURI():(outerRequest.getRequestURI()+"?"+outerRequest.getQueryString()); - _request.setUri(new HttpURI(uri)); - _request.setPathInfo(outerRequest.getRequestURI()); - _request.setQueryString(outerRequest.getQueryString()); - _request.setProtocol(outerRequest.getProtocol()); - - // Set the headers - HttpFields fields = getRequestFields(); - for (Enumeration e=outerRequest.getHeaderNames();e.hasMoreElements();) - { - String header=e.nextElement(); - String value=outerRequest.getHeader(header); - fields.add(header,value); - } - - // Let outer parse the cookies - _request.setCookies(outerRequest.getCookies()); - - // copy request attributes - for (Enumeration e=outerRequest.getAttributeNames();e.hasMoreElements();) - { - String attr=e.nextElement(); - _request.setAttribute(attr,outerRequest.getAttribute(attr)); - } - - // customize the request - connector.customize(endp,_request); - - // System.err.println(_request.getMethod()+" "+_request.getUri()+" "+_request.getProtocol()); - // System.err.println(fields.toString()); - } - - void service() throws IOException, ServletException - { - setCurrentConnection(this); - try - { - getServer().handle(this); - completeResponse(); - while (!_generator.isComplete() && _endp.isOpen()) - _generator.flushBuffer(); - _endp.flush(); - } - finally - { - setCurrentConnection(null); - } - } - - /* (non-Javadoc) - * @see org.eclipse.jetty.server.HttpConnection#getInputStream() - */ - @Override - public ServletInputStream getInputStream() throws IOException - { - return ((NestedEndPoint)_endp).getServletInputStream(); - } - - /* (non-Javadoc) - * @see org.eclipse.jetty.server.HttpConnection#handle() - */ - @Override - public Connection handle() throws IOException - { - throw new IllegalStateException(); - } - -} diff --git a/jetty-nested/src/main/java/org/eclipse/jetty/nested/NestedConnector.java b/jetty-nested/src/main/java/org/eclipse/jetty/nested/NestedConnector.java deleted file mode 100644 index 1df5988b49b..00000000000 --- a/jetty-nested/src/main/java/org/eclipse/jetty/nested/NestedConnector.java +++ /dev/null @@ -1,90 +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.nested; - -import java.io.IOException; - -import javax.servlet.ServletException; -import javax.servlet.ServletRequest; -import javax.servlet.ServletResponse; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -import org.eclipse.jetty.io.EndPoint; -import org.eclipse.jetty.server.AbstractConnector; -import org.eclipse.jetty.server.Connector; -import org.eclipse.jetty.server.Request; - -/** - * Nested Jetty Connector - *

- * This Jetty {@link Connector} allows a jetty instance to be nested inside another servlet container. - * Requests received by the outer servlet container should be passed to jetty using the {@link #service(ServletRequest, ServletResponse)} method of this connector. - * - */ -public class NestedConnector extends AbstractConnector -{ - String _serverInfo; - - public NestedConnector() - { - setAcceptors(0); - setForwarded(true); - } - - public void open() throws IOException - { - } - - public void close() throws IOException - { - } - - public int getLocalPort() - { - return -1; - } - - public Object getConnection() - { - return null; - } - - @Override - protected void accept(int acceptorID) throws IOException, InterruptedException - { - throw new IllegalStateException(); - } - - /** - * Service a request of the outer servlet container by passing it to the nested instance of Jetty. - * @param outerRequest - * @param outerResponse - * @throws IOException - * @throws ServletException - */ - public void service(ServletRequest outerRequest, ServletResponse outerResponse) throws IOException, ServletException - { - HttpServletRequest outerServletRequest = (HttpServletRequest)outerRequest; - HttpServletResponse outerServletResponse = (HttpServletResponse)outerResponse; - NestedConnection connection=new NestedConnection(this,new NestedEndPoint(outerServletRequest,outerServletResponse),outerServletRequest,outerServletResponse,_serverInfo); - connection.service(); - } - -} diff --git a/jetty-nested/src/main/java/org/eclipse/jetty/nested/NestedEndPoint.java b/jetty-nested/src/main/java/org/eclipse/jetty/nested/NestedEndPoint.java deleted file mode 100644 index ede72016234..00000000000 --- a/jetty-nested/src/main/java/org/eclipse/jetty/nested/NestedEndPoint.java +++ /dev/null @@ -1,77 +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.nested; - -import java.io.IOException; -import javax.servlet.ServletInputStream; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -import org.eclipse.jetty.io.bio.StreamEndPoint; - -public class NestedEndPoint extends StreamEndPoint -{ - private final HttpServletRequest _outerRequest; - - public NestedEndPoint(HttpServletRequest outerRequest, HttpServletResponse outerResponse) - throws IOException - { - super(outerRequest.getInputStream(),outerResponse.getOutputStream()); - _outerRequest=outerRequest; - } - - public ServletInputStream getServletInputStream() - { - return (ServletInputStream)getInputStream(); - } - @Override - public String getLocalAddr() - { - return _outerRequest.getLocalAddr(); - } - - @Override - public String getLocalHost() - { - return _outerRequest.getLocalName(); - } - - @Override - public int getLocalPort() - { - return _outerRequest.getLocalPort(); - } - - @Override - public String getRemoteAddr() - { - return _outerRequest.getRemoteAddr(); - } - - @Override - public String getRemoteHost() - { - return _outerRequest.getRemoteHost(); - } - @Override - public int getRemotePort() - { - return _outerRequest.getRemotePort(); - } -} diff --git a/jetty-nested/src/main/java/org/eclipse/jetty/nested/NestedGenerator.java b/jetty-nested/src/main/java/org/eclipse/jetty/nested/NestedGenerator.java deleted file mode 100644 index 88968373395..00000000000 --- a/jetty-nested/src/main/java/org/eclipse/jetty/nested/NestedGenerator.java +++ /dev/null @@ -1,308 +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.nested; - -import java.io.IOException; - -import javax.servlet.http.HttpServletResponse; - -import org.eclipse.jetty.http.AbstractGenerator; -import org.eclipse.jetty.http.HttpFields; -import org.eclipse.jetty.http.HttpHeaders; -import org.eclipse.jetty.http.HttpVersions; -import org.eclipse.jetty.io.Buffer; -import org.eclipse.jetty.io.Buffers; -import org.eclipse.jetty.io.EndPoint; -import org.eclipse.jetty.server.Server; -import org.eclipse.jetty.util.log.Log; -import org.eclipse.jetty.util.log.Logger; - -public class NestedGenerator extends AbstractGenerator -{ - private static final Logger LOG = Log.getLogger(NestedGenerator.class); - - final HttpServletResponse _response; - final String _nestedIn; - - public NestedGenerator(Buffers buffers, EndPoint io, HttpServletResponse response, String nestedIn) - { - super(buffers,io); - _response=response; - _nestedIn=nestedIn; - } - - public void addContent(Buffer content, boolean last) throws IOException - { - LOG.debug("addContent {} {}",content.length(),last); - if (_noContent) - { - content.clear(); - return; - } - - if (content.isImmutable()) - throw new IllegalArgumentException("immutable"); - - if (_last || _state == STATE_END) - { - LOG.debug("Ignoring extra content {}", content); - content.clear(); - return; - } - _last = last; - - if(!_endp.isOpen()) - { - _state = STATE_END; - return; - } - - // Handle any unfinished business? - if (_content != null && _content.length() > 0) - { - flushBuffer(); - if (_content != null && _content.length() > 0) - throw new IllegalStateException("FULL"); - } - - _content = content; - - _contentWritten += content.length(); - - // Handle the _content - if (_head) - { - content.clear(); - _content = null; - } - else if (!last || _buffer!=null) - { - // Yes - so we better check we have a buffer - initBuffer(); - // Copy _content to buffer; - int len = 0; - len = _buffer.put(_content); - - // make sure there is space for a trailing null (???) - if (len > 0 && _buffer.space() == 0) - { - len--; - _buffer.setPutIndex(_buffer.putIndex() - 1); - } - - LOG.debug("copied {} to buffer",len); - - _content.skip(len); - - if (_content.length() == 0) - _content = null; - } - } - - public boolean addContent(byte b) throws IOException - { - // LOG.debug("addContent 1"); - if (_noContent) - return false; - - if (_last || _state == STATE_END) - throw new IllegalStateException("Closed"); - - - if(!_endp.isOpen()) - { - _state = STATE_END; - return false; - } - - // Handle any unfinished business? - if (_content != null && _content.length() > 0) - { - flushBuffer(); - if (_content != null && _content.length() > 0) - throw new IllegalStateException("FULL"); - } - - _contentWritten++; - - // Handle the _content - if (_head) - return false; - - // we better check we have a buffer - initBuffer(); - - // Copy _content to buffer; - - _buffer.put(b); - - return _buffer.space() <= 1; - } - - /* ------------------------------------------------------------ */ - private void initBuffer() throws IOException - { - if (_buffer == null) - { - // LOG.debug("initContent"); - _buffer = _buffers.getBuffer(); - } - } - - /* ------------------------------------------------------------ */ - @Override - public boolean isRequest() - { - return false; - } - - /* ------------------------------------------------------------ */ - @Override - public boolean isResponse() - { - return true; - } - - /* ------------------------------------------------------------ */ - @Override - public int prepareUncheckedAddContent() throws IOException - { - initBuffer(); - return _buffer.space(); - } - - /* ------------------------------------------------------------ */ - @Override - public void completeHeader(HttpFields fields, boolean allContentAdded) throws IOException - { - if (LOG.isDebugEnabled()) - LOG.debug("completeHeader: {}",fields.toString().trim().replace("\r\n","|")); - if (_state != STATE_HEADER) - return; - - if (_last && !allContentAdded) - throw new IllegalStateException("last?"); - _last = _last | allContentAdded; - - if (_persistent==null) - _persistent=(_version > HttpVersions.HTTP_1_0_ORDINAL); - - - if (_reason == null) - _response.setStatus(_status); - else - _response.setStatus(_status,_reason.toString()); - - if (_status == 100 || _status == 204 || _status == 304) - { - _noContent = true; - _content = null; - } - - - boolean has_server = false; - if (fields != null) - { - // Add headers - int s=fields.size(); - for (int f=0;f 100 && getSendServerVersion()) - _response.setHeader(HttpHeaders.SERVER,"Jetty("+Server.getVersion()+",nested in "+_nestedIn+")"); - - _state = STATE_CONTENT; - } - - /* ------------------------------------------------------------ */ - /** - * Complete the message. - * - * @throws IOException - */ - @Override - public void complete() throws IOException - { - if (_state == STATE_END) - return; - - super.complete(); - - if (_state < STATE_FLUSHING) - _state = STATE_FLUSHING; - - flushBuffer(); - } - - /* ------------------------------------------------------------ */ - @Override - public int flushBuffer() throws IOException - { - if (_state == STATE_HEADER) - throw new IllegalStateException("State==HEADER"); - - int len = 0; - - if (_buffer==null) - { - - if (_content!=null && _content.length()>0) - { - // flush content directly - len = _endp.flush(_content); - if (len>0) - _content.skip(len); - } - } - else - { - if (_buffer.length()==0 && _content!=null && _content.length()>0) - { - // Copy content to buffer - _content.skip(_buffer.put(_content)); - } - - int size=_buffer.length(); - len =_endp.flush(_buffer); - LOG.debug("flushBuffer {} of {}",len,size); - if (len>0) - _buffer.skip(len); - } - - if (_content!=null && _content.length()==0) - _content=null; - if (_buffer!=null && _buffer.length()==0 && _content==null) - { - _buffers.returnBuffer(_buffer); - _buffer=null; - } - - if (_state==STATE_FLUSHING && _buffer==null && _content==null) - _state=STATE_END; - - return len; - } - -} diff --git a/jetty-nosql/src/main/java/org/eclipse/jetty/nosql/NoSqlSession.java b/jetty-nosql/src/main/java/org/eclipse/jetty/nosql/NoSqlSession.java index 397d9859a23..6a1ef0b8f44 100644 --- a/jetty-nosql/src/main/java/org/eclipse/jetty/nosql/NoSqlSession.java +++ b/jetty-nosql/src/main/java/org/eclipse/jetty/nosql/NoSqlSession.java @@ -179,5 +179,19 @@ public class NoSqlSession extends AbstractSession { return _version; } + + @Override + public void setClusterId(String clusterId) + { + super.setClusterId(clusterId); + } + + @Override + public void setNodeId(String nodeId) + { + super.setNodeId(nodeId); + } + + } diff --git a/jetty-nosql/src/main/java/org/eclipse/jetty/nosql/NoSqlSessionManager.java b/jetty-nosql/src/main/java/org/eclipse/jetty/nosql/NoSqlSessionManager.java index 51fed8921c9..dfa77efd63b 100644 --- a/jetty-nosql/src/main/java/org/eclipse/jetty/nosql/NoSqlSessionManager.java +++ b/jetty-nosql/src/main/java/org/eclipse/jetty/nosql/NoSqlSessionManager.java @@ -307,6 +307,34 @@ public abstract class NoSqlSessionManager extends AbstractSessionManager impleme _saveAllAttributes = saveAllAttributes; } + /* ------------------------------------------------------------ */ + @Override + public void renewSessionId(String oldClusterId, String oldNodeId, String newClusterId, String newNodeId) + { + + // Take the old session out of the list of sessions + // Change to the new id + // Put it back into the list of sessions + // Update permanent storage + + synchronized (this) + { + try + { + NoSqlSession session = _sessions.remove(oldClusterId); + update (session, newClusterId, newNodeId); + session.setClusterId(newClusterId); + session.setNodeId(newNodeId); + _sessions.put(newClusterId, session); + } + catch (Exception e) + { + __log.warn(e); + } + } + } + + /* ------------------------------------------------------------ */ abstract protected NoSqlSession loadSession(String clusterId); @@ -318,5 +346,8 @@ public abstract class NoSqlSessionManager extends AbstractSessionManager impleme /* ------------------------------------------------------------ */ abstract protected boolean remove(NoSqlSession session); + + /* ------------------------------------------------------------ */ + abstract protected void update(NoSqlSession session, String newClusterId, String newNodeId) throws Exception; } diff --git a/jetty-nosql/src/main/java/org/eclipse/jetty/nosql/mongodb/MongoSessionIdManager.java b/jetty-nosql/src/main/java/org/eclipse/jetty/nosql/mongodb/MongoSessionIdManager.java index 74621901cff..def72824603 100644 --- a/jetty-nosql/src/main/java/org/eclipse/jetty/nosql/mongodb/MongoSessionIdManager.java +++ b/jetty-nosql/src/main/java/org/eclipse/jetty/nosql/mongodb/MongoSessionIdManager.java @@ -25,6 +25,7 @@ import java.util.Random; import java.util.Set; import java.util.Timer; import java.util.TimerTask; +import java.util.concurrent.TimeUnit; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpSession; @@ -69,6 +70,9 @@ public class MongoSessionIdManager extends AbstractSessionIdManager final static DBObject __valid_false = new BasicDBObject(MongoSessionManager.__VALID,false); final static DBObject __valid_true = new BasicDBObject(MongoSessionManager.__VALID,true); + final static long __defaultScavengeDelay = 10 * 6 * 1000; // wait at least 10 minutes + final static long __defaultScavengePeriod = 30 * 60 * 1000; // every 30 minutes + final DBCollection _sessions; protected Server _server; @@ -79,8 +83,8 @@ public class MongoSessionIdManager extends AbstractSessionIdManager - private long _scavengeDelay = 30 * 60 * 1000; // every 30 minutes - private long _scavengePeriod = 10 * 6 * 1000; // wait at least 10 minutes + private long _scavengeDelay = __defaultScavengeDelay; + private long _scavengePeriod = __defaultScavengePeriod; /** @@ -145,8 +149,8 @@ public class MongoSessionIdManager extends AbstractSessionIdManager */ protected void scavenge() { - __log.debug("SessionIdManager:scavenge:called with delay" + _scavengeDelay); - + long now = System.currentTimeMillis(); + __log.debug("SessionIdManager:scavenge:at " + now); synchronized (_sessionsIds) { /* @@ -158,7 +162,8 @@ public class MongoSessionIdManager extends AbstractSessionIdManager */ BasicDBObject query = new BasicDBObject(); query.put(MongoSessionManager.__ID,new BasicDBObject("$in", _sessionsIds )); - query.put(MongoSessionManager.__ACCESSED, new BasicDBObject("$lt",System.currentTimeMillis() - _scavengeDelay)); + + query.put(MongoSessionManager.__ACCESSED, new BasicDBObject("$lt",now - _scavengePeriod)); DBCursor checkSessions = _sessions.find(query, new BasicDBObject(MongoSessionManager.__ID, 1)); @@ -216,7 +221,7 @@ public class MongoSessionIdManager extends AbstractSessionIdManager BasicDBObject invalidQuery = new BasicDBObject(); invalidQuery.put(MongoSessionManager.__ACCESSED, new BasicDBObject("$lt",System.currentTimeMillis() - _purgeInvalidAge)); - invalidQuery.put(MongoSessionManager.__VALID, __valid_false); + invalidQuery.put(MongoSessionManager.__VALID, false); DBCursor oldSessions = _sessions.find(invalidQuery, new BasicDBObject(MongoSessionManager.__ID, 1)); @@ -234,9 +239,9 @@ public class MongoSessionIdManager extends AbstractSessionIdManager BasicDBObject validQuery = new BasicDBObject(); validQuery.put(MongoSessionManager.__ACCESSED,new BasicDBObject("$lt",System.currentTimeMillis() - _purgeValidAge)); - validQuery.put(MongoSessionManager.__VALID, __valid_false); + validQuery.put(MongoSessionManager.__VALID, true); - oldSessions = _sessions.find(invalidQuery,new BasicDBObject(MongoSessionManager.__ID,1)); + oldSessions = _sessions.find(validQuery,new BasicDBObject(MongoSessionManager.__ID,1)); for (DBObject session : oldSessions) { @@ -301,16 +306,22 @@ public class MongoSessionIdManager extends AbstractSessionIdManager */ public void setScavengeDelay(long scavengeDelay) { - this._scavengeDelay = scavengeDelay; + if (scavengeDelay <= 0) + this._scavengeDelay = __defaultScavengeDelay; + else + this._scavengeDelay = TimeUnit.SECONDS.toMillis(scavengeDelay); } /* ------------------------------------------------------------ */ public void setScavengePeriod(long scavengePeriod) { - this._scavengePeriod = scavengePeriod; + if (scavengePeriod <= 0) + _scavengePeriod = __defaultScavengePeriod; + else + _scavengePeriod = TimeUnit.SECONDS.toMillis(scavengePeriod); } - + /* ------------------------------------------------------------ */ public void setPurgeDelay(long purgeDelay) { @@ -410,7 +421,8 @@ public class MongoSessionIdManager extends AbstractSessionIdManager purge(); } }; - _purgeTimer.schedule(_purgeTask,_purgeDelay); + + _purgeTimer.schedule(_purgeTask,0,_purgeDelay); } } } @@ -539,5 +551,36 @@ public class MongoSessionIdManager extends AbstractSessionIdManager return clusterId; } + + + /* ------------------------------------------------------------ */ + @Override + public void renewSessionId(String oldClusterId, String oldNodeId, HttpServletRequest request) + { + //generate a new id + String newClusterId = newSessionId(request.hashCode()); + + synchronized (_sessionsIds) + { + _sessionsIds.remove(oldClusterId);//remove the old one from the list + _sessionsIds.add(newClusterId); //add in the new session id to the list + + //tell all contexts to update the id + Handler[] contexts = _server.getChildHandlersByClass(ContextHandler.class); + for (int i=0; contexts!=null && i - - https - - 32768 - 8192 - 8192 - - - + + https + + + + 32768 + 8192 + 8192 + + + + + - @@ -44,18 +47,39 @@ - + + + + + - - - .*\.css - .*\.js - .*\.png - .*\.jpg - .*\.gif - - + + + + + + 5000 + 32 diff --git a/jetty-osgi/test-jetty-osgi/src/test/java/org/eclipse/jetty/osgi/test/AbstractTestOSGi.java b/jetty-osgi/test-jetty-osgi/src/test/java/org/eclipse/jetty/osgi/test/AbstractTestOSGi.java index ac154c6ea6f..0d300825b98 100644 --- a/jetty-osgi/test-jetty-osgi/src/test/java/org/eclipse/jetty/osgi/test/AbstractTestOSGi.java +++ b/jetty-osgi/test-jetty-osgi/src/test/java/org/eclipse/jetty/osgi/test/AbstractTestOSGi.java @@ -23,15 +23,13 @@ import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.concurrent.TimeUnit; - import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.eclipse.jetty.client.HttpClient; -import org.eclipse.jetty.client.HttpContentResponse; -import org.eclipse.jetty.client.api.Response; +import org.eclipse.jetty.client.api.ContentResponse; import org.eclipse.jetty.http.HttpStatus; import org.eclipse.jetty.util.ssl.SslContextFactory; import org.junit.Assert; @@ -49,7 +47,7 @@ public class AbstractTestOSGi { private Map _bundles; - + /** * Note: this will run many more tests. * TODO: find a better way to control this and use non-deprecated methods. @@ -58,11 +56,11 @@ public class AbstractTestOSGi protected static void addMoreOSGiContainers(List