Merge branch 'master' into release
This commit is contained in:
commit
5115f6097c
|
@ -1,14 +1,36 @@
|
|||
target/
|
||||
# eclipse
|
||||
.classpath
|
||||
.project
|
||||
.settings
|
||||
|
||||
# maven
|
||||
target/
|
||||
*/src/main/java/META-INF/
|
||||
.pmd
|
||||
|
||||
# common junk
|
||||
*.log
|
||||
*.swp
|
||||
*.diff
|
||||
*.patch
|
||||
|
||||
# intellij
|
||||
*.iml
|
||||
*.ipr
|
||||
*.iws
|
||||
.idea/
|
||||
|
||||
# Mac filesystem dust
|
||||
.DS_Store
|
||||
|
||||
# pmd
|
||||
.pmdruleset
|
||||
.pmd
|
||||
|
||||
# netbeans
|
||||
/nbproject
|
||||
|
||||
# vim
|
||||
.*.sw[a-p]
|
||||
|
||||
# merge tooling
|
||||
*.orig
|
||||
|
|
156
VERSION.txt
156
VERSION.txt
|
@ -1,4 +1,152 @@
|
|||
jetty-7.5.0.v20110901 01 September 2011
|
||||
jetty-7.6.0-SNAPSHOT
|
||||
|
||||
jetty-7.6.0.RC2 - 22 December 2011
|
||||
+ 364638 HttpParser closes if data received while seeking EOF. Tests fixed to
|
||||
cope
|
||||
+ 364921 Made test less time sensitive for ssl
|
||||
+ 364936 use Resource for opening URL streams
|
||||
+ 365267 NullPointerException in bad Address
|
||||
+ 365375 ResourceHandler should be a HandlerWrapper
|
||||
+ 365750 Support WebSocket over SSL, aka wss://
|
||||
+ 365932 Produce jetty-websocket aggregate jar for android use
|
||||
+ 365947 Set headers for Auth failure and retry in http-spi
|
||||
+ 366316 Superfluous printStackTrace on 404
|
||||
+ 366342 Dont persist DosFilter trackers in http session
|
||||
+ 366730 pass the time idle to onIdleExpire
|
||||
+ 367048 test harness for guard on suspended requests
|
||||
+ 367175 SSL 100% CPU spin in case of blocked write and RST.
|
||||
+ 367219 WebSocketClient.open() fails when URI uses default ports.
|
||||
+ JETTY-1460 suppress PrintWriter exceptions
|
||||
+ JETTY-1463 websocket D0 parser should return progress even if no fill done
|
||||
+ JETTY-1465 NPE in ContextHandler.toString
|
||||
|
||||
jetty-7.6.0.RC1 - 04 December 2011
|
||||
+ 352565 cookie httponly flag ignored
|
||||
+ 353285 ServletSecurity annotation ignored
|
||||
+ 357163 jetty 8 ought to proxy jetty8 javadocs
|
||||
+ 357209 JSP tag listeners not called
|
||||
+ 360051 SocketConnectionTest.testServerClosedConnection is excluded.
|
||||
+ 361135 Allow session cookies to NEVER be marked as secure, even on HTTPS
|
||||
requests.
|
||||
+ 362249 update shell scripts to jetty8
|
||||
+ 363878 Add ecj compiler to jetty-8 for jsp
|
||||
+ 364283 can't parse the servlet multipart-config for the web.xml
|
||||
+ 364430 Support web.xml enabled state for servlets
|
||||
+ 365370 ServletHandler can fall through to nested handler
|
||||
|
||||
jetty-7.6.0.RC0 - 29 November 2011
|
||||
+ Refactored NIO layer for better half close handling
|
||||
+ 349110 fixed bypass chunk handling
|
||||
+ 360546 handle set count exceeding max integer
|
||||
+ 362111 StdErrLog.isDebugEnabled() returns true too often
|
||||
+ 362113 Improve Test Coverage of org.eclipse.jetty.util.log classes
|
||||
+ 362407 setTrustStore(Resource) -> setTrustStoreResource(R)
|
||||
+ 362447 add setMaxNonceAge() to DigestAuthenticator
|
||||
+ 362468 NPE at line org.eclipse.jetty.io.BufferUtil.putHexInt
|
||||
+ 362614 NPE in accepting connection
|
||||
+ 362626 IllegalStateException thrown when SslContextFactory preconfigured
|
||||
with SSLContext
|
||||
+ 362696 expand virtual host configuration options to ContextHandler and add
|
||||
associated test case for new behavior
|
||||
+ 362742 improved UTF8 exception reason
|
||||
+ 363124 improved websocket close handling
|
||||
+ 363381 Throw IllegalStateException if Request uri is null on getServerName
|
||||
+ 363408 GzipFilter should not attempt to compress HTTP status 204
|
||||
+ 363488 ShutdownHandler use stopper thread
|
||||
+ 363718 Setting java.rmi.server.hostname in jetty-jmx.xml
|
||||
+ 363757 partial fix
|
||||
+ 363785 StdErrLog must use system-dependent EOL.
|
||||
+ 363943 ignore null attribute values
|
||||
+ 363993 EOFException parsing HEAD response in HttpTester
|
||||
+ 364638 SCEP does idle timestamp checking. New setCheckForIdle method
|
||||
controls onIdleExpired callback. 364921 a second onIdleExpired callback will
|
||||
result in close rather than a shutdown output.
|
||||
+ 364657 Support HTTP only cookies from standard API
|
||||
+ JETTY-1442 add _hostHeader setter for ProxyRule
|
||||
|
||||
jetty-7.5.4.v20111024 - 24 October 2011
|
||||
+ 358263 JDBCSessionIdManager add setDatasource(DataSource) method
|
||||
+ 358649 Replace existing StdErrLog system properties for DEBUG/IGNORED with
|
||||
LEVEL instead.
|
||||
+ 360836 Accept parameters with bad UTF-8. Use replacement character
|
||||
+ 360912 CrossOriginFilter does not send Access-Control-Allow-Origin on
|
||||
responses. 355103 Make allowCredentials default to true in
|
||||
CrossOriginFilter.
|
||||
+ 360938 Connections closed after a while.
|
||||
+ 361319 Log initialization does not catch correct exceptions on all jvms
|
||||
+ 361325 359292 Allow KeyStore to be set
|
||||
+ 361456 release timer task on connection failed
|
||||
+ 361655 ExecutorThreadPool.isLowOnThreads() returns wrong value.
|
||||
+ JETTY-1444 start threadpool before selector manager
|
||||
|
||||
jetty-7.5.3.v20111011 - 11 October 2011
|
||||
+ 348978 migrate jetty-http-spi
|
||||
+ 358649 StdErrLog system properties for package/class logging LEVEL.
|
||||
|
||||
jetty-7.5.2.v20111006 - 06 October 2011
|
||||
+ 336443 check nonce count is increasing
|
||||
+ 342161 ScannerTest fails intermittently on Mac OS X
|
||||
+ 346419 testing HttpClient FDs
|
||||
+ 353267 Request._parameters initialization bug
|
||||
+ 353509 jetty-client unit tests are running too long
|
||||
+ 353627 Basic Auth checks that Basic method has been send
|
||||
+ 356144 Allow SelectorManager thread priority to be set
|
||||
+ 356274 Start SSL socket factory in call to open()
|
||||
+ 357178 websockets draft 14 support
|
||||
+ 357188 Send content buffer directly
|
||||
+ 357216 Logging via Log4J does not expand braces in format strings
|
||||
+ 357240 more half close refinements
|
||||
+ 357338 remove debug
|
||||
+ 357672 resolve issue with serializing pojos with mongodb session manager,
|
||||
thanks to john simone for the discovery and fix
|
||||
+ 357959 Include javadoc in distribution
|
||||
+ 358027 NullPointerException in ResourceHandler with jetty-stylesheet.css
|
||||
+ 358035 idle time only active if > 0
|
||||
+ 358147 Add catch for UnknownHostException to fix leaky file descriptor in
|
||||
client
|
||||
+ 358164 Dispatch from servlet to handler
|
||||
+ 358263 add method for osgi users to register a driver as Class.forName does
|
||||
not work for them
|
||||
+ 358649 StdErrLog system properties for package/class logging LEVEL.
|
||||
+ 358674 Still allows sslv3 for now
|
||||
+ 358687 Updated jsp does not scan for system tlds Fixed pattern.
|
||||
+ 358784 JSP broken on Java 1.5
|
||||
+ 358925 bit more javadoc on usage
|
||||
+ 358959 File descriptor leak with UnresolvedAddressException
|
||||
+ 359309 adjust previous test for servletPath to include pathInfo
|
||||
+ 359673 updated websocket version handling
|
||||
+ 359675 Principal != String, fix for issue in property file login manager
|
||||
+ 360051 SocketConnectionTest.testServerClosedConnection is excluded.
|
||||
+ 360066 jsps referenced in web.xml <jsp-file> elements do not compile
|
||||
+ JETTY-1130 Access Sessions from HashSessionIdManager
|
||||
+ JETTY-1277 Fixed sendRedirect encoding of relative locations
|
||||
+ JETTY-1322 idle sweeper checks for closed endp
|
||||
+ JETTY-1377 extra logging for busy selector
|
||||
+ JETTY-1378 new sys property for the latest jsp-impl to force the use of the
|
||||
JDTCompiler when running in OSGi.
|
||||
+ JETTY-1414 applied to PropertyUserStore
|
||||
+ JETTY-1415 Start/Stop Server and Client only once in test, code format
|
||||
+ JETTY-1420 Set Host header for new request in RedirectListener
|
||||
+ JETTY-1421 Implement RedirectListener.onException,onConnectionFailed
|
||||
+ JETTY-1423 force connection to be closed returned
|
||||
+ JETTY-1430 local JNDI contexts don't carry environment
|
||||
+ JETTY-1434 Add a jsp that exercises jstl.
|
||||
+ JETTY-1439 space in directory installation path causes classloader problem
|
||||
|
||||
jetty-7.5.1.v20110908 - 08 September 2011
|
||||
+ 350634 Added Resource.newResource(File)
|
||||
+ 356190 fix monodb tests for changed test api
|
||||
+ 356428 removed timed waits from test
|
||||
+ 356693 reduce visibility to webapp of websocket implementations
|
||||
+ 356695 jetty server jars are provided for websockets
|
||||
+ 356726 Instead of the sessionDestroyed called sessionCreated after
|
||||
invalidate session
|
||||
+ 356751 Add null protection to ServletContextHandler.doStop
|
||||
+ 356823 correctly decode close codes. Send not utf-8 close code.
|
||||
+ 357058 Acceptor thread blocking
|
||||
|
||||
jetty-7.5.0.v20110901 - 01 September 2011
|
||||
+ 356421 Upgraded websocket to draft 13 support
|
||||
+ 353073 better warnings
|
||||
|
||||
jetty-7.5.0.RC2 - 30 August 2011
|
||||
|
@ -57,6 +205,12 @@ jetty-7.5.0.RC0 - 15 August 2011
|
|||
+ 354397 RewriteRegexRule handles special characters in regex group
|
||||
+ 354466 Typo in example config of jetty-plus.xml
|
||||
|
||||
jetty-7.4.5.v20110725 - 25 July 2011
|
||||
+ 347484 / - > ${/} in some paths in grant codebases
|
||||
+ 352133 resolve some 1.5isms
|
||||
+ 352421 HttpURI paths beginning with '.'
|
||||
+ 352786 GzipFilter fails to pass parameters to GzipResponseWrapper
|
||||
|
||||
jetty-7.4.4.v20110707 - 07 July 2011
|
||||
+ 308851 Converted all jetty-client module tests to JUnit 4
|
||||
+ 345268 JDBCSessionManager does not work with maxInactiveInterval = -1
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-project</artifactId>
|
||||
<version>7.5.0-SNAPSHOT</version>
|
||||
<version>7.6.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>example-jetty-embedded</artifactId>
|
||||
|
@ -28,6 +28,11 @@
|
|||
<artifactId>jetty-servlets</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-rewrite</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-deploy</artifactId>
|
||||
|
@ -42,6 +47,11 @@
|
|||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-ajp</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty.toolchain</groupId>
|
||||
<artifactId>jetty-test-helper</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
|
|
|
@ -15,11 +15,9 @@ package org.eclipse.jetty.embedded;
|
|||
|
||||
import java.lang.management.ManagementFactory;
|
||||
|
||||
import org.eclipse.jetty.ajp.Ajp13SocketConnector;
|
||||
import org.eclipse.jetty.deploy.DeploymentManager;
|
||||
import org.eclipse.jetty.deploy.providers.ContextProvider;
|
||||
import org.eclipse.jetty.deploy.providers.WebAppProvider;
|
||||
import org.eclipse.jetty.http.ssl.SslContextFactory;
|
||||
import org.eclipse.jetty.jmx.MBeanContainer;
|
||||
import org.eclipse.jetty.security.HashLoginService;
|
||||
import org.eclipse.jetty.server.Connector;
|
||||
|
@ -31,9 +29,12 @@ import org.eclipse.jetty.server.handler.DefaultHandler;
|
|||
import org.eclipse.jetty.server.handler.HandlerCollection;
|
||||
import org.eclipse.jetty.server.handler.RequestLogHandler;
|
||||
import org.eclipse.jetty.server.handler.StatisticsHandler;
|
||||
import org.eclipse.jetty.server.nio.BlockingChannelConnector;
|
||||
import org.eclipse.jetty.server.nio.SelectChannelConnector;
|
||||
import org.eclipse.jetty.server.ssl.SslSelectChannelConnector;
|
||||
import org.eclipse.jetty.server.ssl.SslSocketConnector;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.ssl.SslContextFactory;
|
||||
import org.eclipse.jetty.util.thread.QueuedThreadPool;
|
||||
|
||||
public class LikeJettyXml
|
||||
|
@ -51,12 +52,12 @@ public class LikeJettyXml
|
|||
MBeanContainer mbContainer=new MBeanContainer(ManagementFactory.getPlatformMBeanServer());
|
||||
server.getContainer().addEventListener(mbContainer);
|
||||
server.addBean(mbContainer);
|
||||
mbContainer.addBean(Log.getLog());
|
||||
mbContainer.addBean(Log.getRootLogger());
|
||||
|
||||
|
||||
// Setup Threadpool
|
||||
QueuedThreadPool threadPool = new QueuedThreadPool();
|
||||
threadPool.setMaxThreads(100);
|
||||
threadPool.setMaxThreads(500);
|
||||
server.setThreadPool(threadPool);
|
||||
|
||||
// Setup Connectors
|
||||
|
@ -64,15 +65,22 @@ public class LikeJettyXml
|
|||
connector.setPort(8080);
|
||||
connector.setMaxIdleTime(30000);
|
||||
connector.setConfidentialPort(8443);
|
||||
connector.setStatsOn(true);
|
||||
connector.setStatsOn(false);
|
||||
|
||||
server.setConnectors(new Connector[]
|
||||
{ connector });
|
||||
|
||||
BlockingChannelConnector bConnector = new BlockingChannelConnector();
|
||||
bConnector.setPort(8888);
|
||||
bConnector.setMaxIdleTime(30000);
|
||||
bConnector.setConfidentialPort(8443);
|
||||
bConnector.setAcceptors(1);
|
||||
server.addConnector(bConnector);
|
||||
|
||||
SslSelectChannelConnector ssl_connector = new SslSelectChannelConnector();
|
||||
ssl_connector.setPort(8443);
|
||||
SslContextFactory cf = ssl_connector.getSslContextFactory();
|
||||
cf.setKeyStore(jetty_home + "/etc/keystore");
|
||||
cf.setKeyStorePath(jetty_home + "/etc/keystore");
|
||||
cf.setKeyStorePassword("OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4");
|
||||
cf.setKeyManagerPassword("OBF:1u2u1wml1z7s1z7a1wnl1u2g");
|
||||
cf.setTrustStore(jetty_home + "/etc/keystore");
|
||||
|
@ -87,13 +95,25 @@ public class LikeJettyXml
|
|||
"SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA",
|
||||
"SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA"
|
||||
});
|
||||
ssl_connector.setStatsOn(true);
|
||||
ssl_connector.setStatsOn(false);
|
||||
server.addConnector(ssl_connector);
|
||||
ssl_connector.open();
|
||||
|
||||
SslSocketConnector ssl2_connector = new SslSocketConnector(cf);
|
||||
ssl2_connector.setPort(8444);
|
||||
ssl2_connector.setStatsOn(false);
|
||||
server.addConnector(ssl2_connector);
|
||||
ssl2_connector.open();
|
||||
|
||||
|
||||
/*
|
||||
|
||||
Ajp13SocketConnector ajp = new Ajp13SocketConnector();
|
||||
ajp.setPort(8009);
|
||||
server.addConnector(ajp);
|
||||
|
||||
*/
|
||||
|
||||
HandlerCollection handlers = new HandlerCollection();
|
||||
ContextHandlerCollection contexts = new ContextHandlerCollection();
|
||||
RequestLogHandler requestLogHandler = new RequestLogHandler();
|
||||
|
@ -136,10 +156,9 @@ public class LikeJettyXml
|
|||
server.setStopAtShutdown(true);
|
||||
server.setSendServerVersion(true);
|
||||
|
||||
|
||||
|
||||
server.start();
|
||||
|
||||
server.join();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -13,11 +13,11 @@
|
|||
|
||||
package org.eclipse.jetty.embedded;
|
||||
|
||||
import org.eclipse.jetty.http.ssl.SslContextFactory;
|
||||
import org.eclipse.jetty.server.Connector;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.server.nio.SelectChannelConnector;
|
||||
import org.eclipse.jetty.server.ssl.SslSelectChannelConnector;
|
||||
import org.eclipse.jetty.util.ssl.SslContextFactory;
|
||||
import org.eclipse.jetty.util.thread.QueuedThreadPool;
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
@ -47,7 +47,7 @@ public class ManyConnectors
|
|||
System.setProperty("jetty.home",jetty_home);
|
||||
ssl_connector.setPort(8443);
|
||||
SslContextFactory cf = ssl_connector.getSslContextFactory();
|
||||
cf.setKeyStore(jetty_home + "/etc/keystore");
|
||||
cf.setKeyStorePath(jetty_home + "/etc/keystore");
|
||||
cf.setKeyStorePassword("OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4");
|
||||
cf.setKeyManagerPassword("OBF:1u2u1wml1z7s1z7a1wnl1u2g");
|
||||
|
||||
|
|
|
@ -17,19 +17,19 @@ import java.util.Collections;
|
|||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.eclipse.jetty.http.security.Constraint;
|
||||
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.Server;
|
||||
import org.eclipse.jetty.util.security.Constraint;
|
||||
|
||||
public class SecuredHelloHandler
|
||||
{
|
||||
public static void main(String[] args) throws Exception
|
||||
{
|
||||
Server server = new Server(0);
|
||||
Server server = new Server(8080);
|
||||
|
||||
LoginService loginService = new HashLoginService("MyRealm","src/test/resources/realm.properties");
|
||||
server.addBean(loginService);
|
||||
|
|
|
@ -2,10 +2,9 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty.aggregate</groupId>
|
||||
<artifactId>jetty-aggregate-project</artifactId>
|
||||
<version>7.5.0-SNAPSHOT</version>
|
||||
<version>7.6.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>org.eclipse.jetty.aggregate</groupId>
|
||||
<artifactId>jetty-all-server</artifactId>
|
||||
<name>Jetty :: Aggregate :: All Server</name>
|
||||
<properties>
|
||||
|
@ -25,7 +24,7 @@
|
|||
<goal>unpack-dependencies</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<includes>META-INF/**,org/eclipse/**</includes>
|
||||
<includes>META-INF/**,org/eclipse/**,org/apache/jasper/compiler/**</includes>
|
||||
<excludes>**/MANIFEST.MF,javax/**</excludes>
|
||||
<outputDirectory>${project.build.directory}/classes</outputDirectory>
|
||||
<overWriteReleases>false</overWriteReleases>
|
||||
|
@ -146,12 +145,6 @@
|
|||
<version>${project.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-jsp-2.1</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-plus</artifactId>
|
||||
|
|
|
@ -2,13 +2,11 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty.aggregate</groupId>
|
||||
<artifactId>jetty-aggregate-project</artifactId>
|
||||
<version>7.5.0-SNAPSHOT</version>
|
||||
<version>7.6.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>org.eclipse.jetty.aggregate</groupId>
|
||||
<artifactId>jetty-all</artifactId>
|
||||
<name>Jetty :: Aggregate :: All core Jetty</name>
|
||||
|
||||
<build>
|
||||
<sourceDirectory>${project.build.directory}/sources</sourceDirectory>
|
||||
<plugins>
|
||||
|
@ -22,7 +20,7 @@
|
|||
<goal>unpack-dependencies</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<includes>META-INF/**,org/eclipse/**</includes>
|
||||
<includes>META-INF/**,org/eclipse/**,org/apache/jasper/compiler/*</includes>
|
||||
<excludes>**/MANIFEST.MF,javax/**</excludes>
|
||||
<outputDirectory>${project.build.directory}/classes</outputDirectory>
|
||||
<overWriteReleases>false</overWriteReleases>
|
||||
|
@ -75,6 +73,19 @@
|
|||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-javadoc-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>javadoc-jar</id>
|
||||
<phase>compile</phase>
|
||||
<goals>
|
||||
<goal>jar</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
|
@ -118,12 +129,6 @@
|
|||
<version>${project.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-jsp-2.1</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-plus</artifactId>
|
||||
|
|
|
@ -2,10 +2,9 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty.aggregate</groupId>
|
||||
<artifactId>jetty-aggregate-project</artifactId>
|
||||
<version>7.5.0-SNAPSHOT</version>
|
||||
<version>7.6.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>org.eclipse.jetty.aggregate</groupId>
|
||||
<artifactId>jetty-client</artifactId>
|
||||
<name>Jetty :: Aggregate :: HTTP Client</name>
|
||||
|
||||
|
|
|
@ -2,10 +2,9 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty.aggregate</groupId>
|
||||
<artifactId>jetty-aggregate-project</artifactId>
|
||||
<version>7.5.0-SNAPSHOT</version>
|
||||
<version>7.6.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>org.eclipse.jetty.aggregate</groupId>
|
||||
<artifactId>jetty-plus</artifactId>
|
||||
<name>Jetty :: Aggregate :: Plus Server</name>
|
||||
|
||||
|
|
|
@ -2,10 +2,9 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty.aggregate</groupId>
|
||||
<artifactId>jetty-aggregate-project</artifactId>
|
||||
<version>7.5.0-SNAPSHOT</version>
|
||||
<version>7.6.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>org.eclipse.jetty.aggregate</groupId>
|
||||
<artifactId>jetty-server</artifactId>
|
||||
<name>Jetty :: Aggregate :: HTTP Server</name>
|
||||
|
||||
|
|
|
@ -2,10 +2,9 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty.aggregate</groupId>
|
||||
<artifactId>jetty-aggregate-project</artifactId>
|
||||
<version>7.5.0-SNAPSHOT</version>
|
||||
<version>7.6.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>org.eclipse.jetty.aggregate</groupId>
|
||||
<artifactId>jetty-servlet</artifactId>
|
||||
<name>Jetty :: Aggregate :: Servlet Server</name>
|
||||
|
||||
|
|
|
@ -2,10 +2,9 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty.aggregate</groupId>
|
||||
<artifactId>jetty-aggregate-project</artifactId>
|
||||
<version>7.5.0-SNAPSHOT</version>
|
||||
<version>7.6.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>org.eclipse.jetty.aggregate</groupId>
|
||||
<artifactId>jetty-webapp</artifactId>
|
||||
<name>Jetty :: Aggregate :: WebApp Server</name>
|
||||
|
||||
|
@ -22,7 +21,7 @@
|
|||
<goal>unpack-dependencies</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<includes>META-INF/**,org/eclipse/**</includes>
|
||||
<includes>META-INF/**,org/eclipse/**,org/apache/jasper/compiler/**</includes>
|
||||
<excludes>**/MANIFEST.MF,javax/**</excludes>
|
||||
<outputDirectory>${project.build.directory}/classes</outputDirectory>
|
||||
<overWriteReleases>false</overWriteReleases>
|
||||
|
@ -96,11 +95,5 @@
|
|||
<artifactId>servlet-api</artifactId>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-jsp-2.1</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
|
|
|
@ -0,0 +1,88 @@
|
|||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<parent>
|
||||
<groupId>org.eclipse.jetty.aggregate</groupId>
|
||||
<artifactId>jetty-aggregate-project</artifactId>
|
||||
<version>7.6.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>jetty-websocket</artifactId>
|
||||
<name>Jetty :: Aggregate :: Websocket</name>
|
||||
|
||||
<build>
|
||||
<sourceDirectory>${project.build.directory}/sources</sourceDirectory>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-dependency-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>unpack-dependencies</id>
|
||||
<goals>
|
||||
<goal>unpack-dependencies</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<includes>META-INF/**,org/eclipse/**</includes>
|
||||
<excludes>**/MANIFEST.MF,javax/**,about.html</excludes>
|
||||
<outputDirectory>${project.build.directory}/classes</outputDirectory>
|
||||
<overWriteReleases>false</overWriteReleases>
|
||||
<overWriteSnapshots>true</overWriteSnapshots>
|
||||
</configuration>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>unpack-source</id>
|
||||
<phase>generate-sources</phase>
|
||||
<goals>
|
||||
<goal>unpack-dependencies</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<classifier>sources</classifier>
|
||||
<includes>**/*</includes>
|
||||
<excludes>META-INF/**</excludes>
|
||||
<includeGroupIds>org.eclipse.jetty</includeGroupIds>
|
||||
<outputDirectory>${project.build.directory}/sources</outputDirectory>
|
||||
<overWriteReleases>true</overWriteReleases>
|
||||
<overWriteSnapshots>true</overWriteSnapshots>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins
|
||||
</groupId>
|
||||
<artifactId>maven-jar-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>package</id>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>jar</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<archive>
|
||||
<manifest>
|
||||
</manifest>
|
||||
<manifestEntries>
|
||||
<mode>development</mode>
|
||||
<url>http://eclipse.org/jetty</url>
|
||||
<Built-By>${user.name}</Built-By>
|
||||
<package>org.eclipse.jetty</package>
|
||||
<Bundle-License>http://dev.eclipse.org/svnroot/rt/org.eclipse.jetty/jetty/trunk/NOTICE.txt</Bundle-License>
|
||||
<Bundle-Name>Jetty HTTP Server</Bundle-Name>
|
||||
</manifestEntries>
|
||||
</archive>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-websocket</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
|
@ -4,7 +4,7 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-project</artifactId>
|
||||
<version>7.5.0-SNAPSHOT</version>
|
||||
<version>7.6.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<groupId>org.eclipse.jetty.aggregate</groupId>
|
||||
<artifactId>jetty-aggregate-project</artifactId>
|
||||
|
@ -35,6 +35,7 @@
|
|||
<module>jetty-client</module>
|
||||
<module>jetty-servlet</module>
|
||||
<module>jetty-webapp</module>
|
||||
<module>jetty-websocket</module>
|
||||
<module>jetty-plus</module>
|
||||
<module>jetty-all-server</module>
|
||||
<module>jetty-all</module>
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-project</artifactId>
|
||||
<version>7.5.0-SNAPSHOT</version>
|
||||
<version>7.6.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>jetty-ajp</artifactId>
|
||||
|
|
|
@ -216,7 +216,10 @@ public class Ajp13Connection extends BlockingHttpConnection
|
|||
|
||||
public void parsedRequestAttribute(String key, Buffer value) throws IOException
|
||||
{
|
||||
_request.setAttribute(key, value.toString());
|
||||
if (value==null)
|
||||
_request.removeAttribute(key);
|
||||
else
|
||||
_request.setAttribute(key,value.toString());
|
||||
}
|
||||
|
||||
public void parsedRequestAttribute(String key, int value) throws IOException
|
||||
|
|
|
@ -44,38 +44,38 @@ public class Ajp13Generator extends AbstractGenerator
|
|||
static
|
||||
{
|
||||
byte[] xA001 =
|
||||
{ (byte) 0xA0, (byte) 0x01 };
|
||||
{ (byte)0xA0, (byte)0x01 };
|
||||
byte[] xA002 =
|
||||
{ (byte) 0xA0, (byte) 0x02 };
|
||||
{ (byte)0xA0, (byte)0x02 };
|
||||
byte[] xA003 =
|
||||
{ (byte) 0xA0, (byte) 0x03 };
|
||||
{ (byte)0xA0, (byte)0x03 };
|
||||
byte[] xA004 =
|
||||
{ (byte) 0xA0, (byte) 0x04 };
|
||||
{ (byte)0xA0, (byte)0x04 };
|
||||
byte[] xA005 =
|
||||
{ (byte) 0xA0, (byte) 0x05 };
|
||||
{ (byte)0xA0, (byte)0x05 };
|
||||
byte[] xA006 =
|
||||
{ (byte) 0xA0, (byte) 0x06 };
|
||||
{ (byte)0xA0, (byte)0x06 };
|
||||
byte[] xA007 =
|
||||
{ (byte) 0xA0, (byte) 0x07 };
|
||||
{ (byte)0xA0, (byte)0x07 };
|
||||
byte[] xA008 =
|
||||
{ (byte) 0xA0, (byte) 0x08 };
|
||||
{ (byte)0xA0, (byte)0x08 };
|
||||
byte[] xA009 =
|
||||
{ (byte) 0xA0, (byte) 0x09 };
|
||||
{ (byte)0xA0, (byte)0x09 };
|
||||
byte[] xA00A =
|
||||
{ (byte) 0xA0, (byte) 0x0A };
|
||||
{ (byte)0xA0, (byte)0x0A };
|
||||
byte[] xA00B =
|
||||
{ (byte) 0xA0, (byte) 0x0B };
|
||||
__headerHash.put("Content-Type", xA001);
|
||||
__headerHash.put("Content-Language", xA002);
|
||||
__headerHash.put("Content-Length", xA003);
|
||||
__headerHash.put("Date", xA004);
|
||||
__headerHash.put("Last-Modified", xA005);
|
||||
__headerHash.put("Location", xA006);
|
||||
__headerHash.put("Set-Cookie", xA007);
|
||||
__headerHash.put("Set-Cookie2", xA008);
|
||||
__headerHash.put("Servlet-Engine", xA009);
|
||||
__headerHash.put("Status", xA00A);
|
||||
__headerHash.put("WWW-Authenticate", xA00B);
|
||||
{ (byte)0xA0, (byte)0x0B };
|
||||
__headerHash.put("Content-Type",xA001);
|
||||
__headerHash.put("Content-Language",xA002);
|
||||
__headerHash.put("Content-Length",xA003);
|
||||
__headerHash.put("Date",xA004);
|
||||
__headerHash.put("Last-Modified",xA005);
|
||||
__headerHash.put("Location",xA006);
|
||||
__headerHash.put("Set-Cookie",xA007);
|
||||
__headerHash.put("Set-Cookie2",xA008);
|
||||
__headerHash.put("Servlet-Engine",xA009);
|
||||
__headerHash.put("Status",xA00A);
|
||||
__headerHash.put("WWW-Authenticate",xA00B);
|
||||
|
||||
}
|
||||
|
||||
|
@ -83,7 +83,7 @@ public class Ajp13Generator extends AbstractGenerator
|
|||
// 0, 1 ajp int 1 packet length
|
||||
// 9 CPONG response Code
|
||||
private static final byte[] AJP13_CPONG_RESPONSE =
|
||||
{ 'A', 'B', 0, 1, 9};
|
||||
{ 'A', 'B', 0, 1, 9 };
|
||||
|
||||
private static final byte[] AJP13_END_RESPONSE =
|
||||
{ 'A', 'B', 0, 2, 5, 1 };
|
||||
|
@ -114,7 +114,7 @@ public class Ajp13Generator extends AbstractGenerator
|
|||
/* ------------------------------------------------------------ */
|
||||
public Ajp13Generator(Buffers buffers, EndPoint io)
|
||||
{
|
||||
super(buffers, io);
|
||||
super(buffers,io);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
@ -130,19 +130,18 @@ public class Ajp13Generator extends AbstractGenerator
|
|||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
public void reset(boolean returnBuffers)
|
||||
public void reset()
|
||||
{
|
||||
super.reset(returnBuffers);
|
||||
super.reset();
|
||||
|
||||
_needEOC = false;
|
||||
_needMore = false;
|
||||
_expectMore = false;
|
||||
_bufferPrepared = false;
|
||||
_last=false;
|
||||
|
||||
|
||||
_last = false;
|
||||
|
||||
_state = STATE_HEADER;
|
||||
|
||||
|
@ -159,11 +158,9 @@ public class Ajp13Generator extends AbstractGenerator
|
|||
_noContent = false;
|
||||
_persistent = true;
|
||||
|
||||
|
||||
|
||||
_header = null; // Buffer for HTTP header (and maybe small _content)
|
||||
_buffer = null; // Buffer for copy of passed _content
|
||||
_content = null; // Buffer passed to addContent
|
||||
_header = null; // Buffer for HTTP header (and maybe small _content)
|
||||
_buffer = null; // Buffer for copy of passed _content
|
||||
_content = null; // Buffer passed to addContent
|
||||
|
||||
}
|
||||
|
||||
|
@ -175,13 +172,13 @@ public class Ajp13Generator extends AbstractGenerator
|
|||
{
|
||||
initContent();
|
||||
}
|
||||
catch(IOException e)
|
||||
catch (IOException e)
|
||||
{
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
return super.getContentBufferSize()-7;
|
||||
return super.getContentBufferSize() - 7;
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
public void increaseContentBufferSize(int contentBufferSize)
|
||||
|
@ -196,11 +193,9 @@ public class Ajp13Generator extends AbstractGenerator
|
|||
* @param content
|
||||
* @param last
|
||||
* @throws IllegalArgumentException
|
||||
* if <code>content</code> is
|
||||
* {@link Buffer#isImmutable immutable}.
|
||||
* if <code>content</code> is {@link Buffer#isImmutable immutable}.
|
||||
* @throws IllegalStateException
|
||||
* If the request is not expecting any more content, or if the
|
||||
* buffers are full and cannot be flushed.
|
||||
* If the request is not expecting any more content, or if the buffers are full and cannot be flushed.
|
||||
* @throws IOException
|
||||
* if there is a problem flushing the buffers.
|
||||
*/
|
||||
|
@ -217,13 +212,13 @@ public class Ajp13Generator extends AbstractGenerator
|
|||
|
||||
if (_last || _state == STATE_END)
|
||||
{
|
||||
LOG.debug("Ignoring extra content {}", content);
|
||||
LOG.debug("Ignoring extra content {}",content);
|
||||
content.clear();
|
||||
return;
|
||||
}
|
||||
_last = last;
|
||||
|
||||
if(!_endp.isOpen())
|
||||
if (!_endp.isOpen())
|
||||
{
|
||||
_state = STATE_END;
|
||||
return;
|
||||
|
@ -289,8 +284,7 @@ public class Ajp13Generator extends AbstractGenerator
|
|||
if (_last || _state == STATE_END)
|
||||
throw new IllegalStateException("Closed");
|
||||
|
||||
|
||||
if(!_endp.isOpen())
|
||||
if (!_endp.isOpen())
|
||||
{
|
||||
_state = STATE_END;
|
||||
return false;
|
||||
|
@ -322,8 +316,7 @@ public class Ajp13Generator extends AbstractGenerator
|
|||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Prepare buffer for unchecked writes. Prepare the generator buffer to
|
||||
* receive unchecked writes
|
||||
* Prepare buffer for unchecked writes. Prepare the generator buffer to receive unchecked writes
|
||||
*
|
||||
* @return the available space in the buffer.
|
||||
* @throws IOException
|
||||
|
@ -337,8 +330,7 @@ public class Ajp13Generator extends AbstractGenerator
|
|||
if (_last || _state == STATE_END)
|
||||
throw new IllegalStateException("Closed");
|
||||
|
||||
|
||||
if(!_endp.isOpen())
|
||||
if (!_endp.isOpen())
|
||||
{
|
||||
_state = STATE_END;
|
||||
return -1;
|
||||
|
@ -377,8 +369,8 @@ public class Ajp13Generator extends AbstractGenerator
|
|||
_last = _last | allContentAdded;
|
||||
|
||||
boolean has_server = false;
|
||||
if (_persistent==null)
|
||||
_persistent=(_version > HttpVersions.HTTP_1_0_ORDINAL);
|
||||
if (_persistent == null)
|
||||
_persistent = (_version > HttpVersions.HTTP_1_0_ORDINAL);
|
||||
|
||||
// get a header buffer
|
||||
if (_header == null)
|
||||
|
@ -390,13 +382,13 @@ public class Ajp13Generator extends AbstractGenerator
|
|||
try
|
||||
{
|
||||
// start the header
|
||||
_buffer.put((byte) 'A');
|
||||
_buffer.put((byte) 'B');
|
||||
_buffer.put((byte)'A');
|
||||
_buffer.put((byte)'B');
|
||||
addInt(0);
|
||||
_buffer.put((byte) 0x4);
|
||||
_buffer.put((byte)0x4);
|
||||
addInt(_status);
|
||||
if (_reason == null)
|
||||
_reason=HttpGenerator.getReasonBuffer(_status);
|
||||
_reason = HttpGenerator.getReasonBuffer(_status);
|
||||
if (_reason == null)
|
||||
_reason = new ByteArrayBuffer(Integer.toString(_status));
|
||||
addBuffer(_reason);
|
||||
|
@ -407,7 +399,6 @@ public class Ajp13Generator extends AbstractGenerator
|
|||
_content = null;
|
||||
}
|
||||
|
||||
|
||||
// allocate 2 bytes for number of headers
|
||||
int field_index = _buffer.putIndex();
|
||||
addInt(0);
|
||||
|
@ -417,15 +408,15 @@ public class Ajp13Generator extends AbstractGenerator
|
|||
if (fields != null)
|
||||
{
|
||||
// Add headers
|
||||
int s=fields.size();
|
||||
for (int f=0;f<s;f++)
|
||||
int s = fields.size();
|
||||
for (int f = 0; f < s; f++)
|
||||
{
|
||||
HttpFields.Field field = fields.getField(f);
|
||||
if (field==null)
|
||||
if (field == null)
|
||||
continue;
|
||||
num_fields++;
|
||||
|
||||
byte[] codes = (byte[]) __headerHash.get(field.getName());
|
||||
byte[] codes = (byte[])__headerHash.get(field.getName());
|
||||
if (codes != null)
|
||||
{
|
||||
_buffer.put(codes);
|
||||
|
@ -460,14 +451,13 @@ public class Ajp13Generator extends AbstractGenerator
|
|||
// insert the total packet size on 2nd and 3rd byte that
|
||||
// was previously
|
||||
// allocated
|
||||
addInt(2, payloadSize);
|
||||
addInt(2,payloadSize);
|
||||
}
|
||||
finally
|
||||
{
|
||||
_buffer = tmpbuf;
|
||||
}
|
||||
|
||||
|
||||
_state = STATE_CONTENT;
|
||||
|
||||
}
|
||||
|
@ -497,11 +487,11 @@ public class Ajp13Generator extends AbstractGenerator
|
|||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
public long flushBuffer() throws IOException
|
||||
public int flushBuffer() throws IOException
|
||||
{
|
||||
try
|
||||
{
|
||||
if (_state == STATE_HEADER && !_expectMore)
|
||||
if (_state == STATE_HEADER && !_expectMore)
|
||||
throw new IllegalStateException("State==HEADER");
|
||||
prepareBuffers();
|
||||
|
||||
|
@ -528,90 +518,87 @@ public class Ajp13Generator extends AbstractGenerator
|
|||
Flushing: while (true)
|
||||
{
|
||||
int len = -1;
|
||||
int to_flush = ((_header != null && _header.length() > 0) ? 4 : 0) | ((_buffer != null && _buffer.length() > 0) ? 2 : 0);
|
||||
|
||||
int to_flush = ((_header != null && _header.length() > 0)?4:0) | ((_buffer != null && _buffer.length() > 0)?2:0);
|
||||
|
||||
switch (to_flush)
|
||||
{
|
||||
case 7:
|
||||
throw new IllegalStateException(); // should
|
||||
// never
|
||||
// happen!
|
||||
case 6:
|
||||
len = _endp.flush(_header, _buffer, null);
|
||||
case 7:
|
||||
throw new IllegalStateException(); // should
|
||||
// never
|
||||
// happen!
|
||||
case 6:
|
||||
len = _endp.flush(_header,_buffer,null);
|
||||
|
||||
break;
|
||||
case 5:
|
||||
throw new IllegalStateException(); // should
|
||||
// never
|
||||
// happen!
|
||||
case 4:
|
||||
len = _endp.flush(_header);
|
||||
break;
|
||||
case 3:
|
||||
throw new IllegalStateException(); // should
|
||||
// never
|
||||
// happen!
|
||||
case 2:
|
||||
len = _endp.flush(_buffer);
|
||||
break;
|
||||
case 5:
|
||||
throw new IllegalStateException(); // should
|
||||
// never
|
||||
// happen!
|
||||
case 4:
|
||||
len = _endp.flush(_header);
|
||||
break;
|
||||
case 3:
|
||||
throw new IllegalStateException(); // should
|
||||
// never
|
||||
// happen!
|
||||
case 2:
|
||||
len = _endp.flush(_buffer);
|
||||
|
||||
break;
|
||||
case 1:
|
||||
throw new IllegalStateException(); // should
|
||||
// never
|
||||
// happen!
|
||||
case 0:
|
||||
{
|
||||
// Nothing more we can write now.
|
||||
if (_header != null)
|
||||
_header.clear();
|
||||
|
||||
_bufferPrepared = false;
|
||||
|
||||
if (_buffer != null)
|
||||
break;
|
||||
case 1:
|
||||
throw new IllegalStateException(); // should
|
||||
// never
|
||||
// happen!
|
||||
case 0:
|
||||
{
|
||||
_buffer.clear();
|
||||
// Nothing more we can write now.
|
||||
if (_header != null)
|
||||
_header.clear();
|
||||
|
||||
// reserve some space for the
|
||||
// header
|
||||
_buffer.setPutIndex(7);
|
||||
_buffer.setGetIndex(7);
|
||||
_bufferPrepared = false;
|
||||
|
||||
// Special case handling for
|
||||
// small left over buffer from
|
||||
// an addContent that caused a
|
||||
// buffer flush.
|
||||
if (_content != null && _content.length() < _buffer.space() && _state != STATE_FLUSHING)
|
||||
if (_buffer != null)
|
||||
{
|
||||
_buffer.clear();
|
||||
|
||||
// reserve some space for the
|
||||
// header
|
||||
_buffer.setPutIndex(7);
|
||||
_buffer.setGetIndex(7);
|
||||
|
||||
// Special case handling for
|
||||
// small left over buffer from
|
||||
// an addContent that caused a
|
||||
// buffer flush.
|
||||
if (_content != null && _content.length() < _buffer.space() && _state != STATE_FLUSHING)
|
||||
{
|
||||
|
||||
_buffer.put(_content);
|
||||
_content.clear();
|
||||
_content = null;
|
||||
break Flushing;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Are we completely finished for now?
|
||||
if (!_expectMore && !_needEOC && (_content == null || _content.length() == 0))
|
||||
{
|
||||
if (_state == STATE_FLUSHING)
|
||||
_state = STATE_END;
|
||||
|
||||
// if (_state == STATE_END)
|
||||
// {
|
||||
// _endp.close();
|
||||
// }
|
||||
//
|
||||
|
||||
_buffer.put(_content);
|
||||
_content.clear();
|
||||
_content = null;
|
||||
break Flushing;
|
||||
}
|
||||
|
||||
// Try to prepare more to write.
|
||||
prepareBuffers();
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Are we completely finished for now?
|
||||
if (!_expectMore && !_needEOC && (_content == null || _content.length() == 0))
|
||||
{
|
||||
if (_state == STATE_FLUSHING)
|
||||
_state = STATE_END;
|
||||
|
||||
// if (_state == STATE_END)
|
||||
// {
|
||||
// _endp.close();
|
||||
// }
|
||||
//
|
||||
|
||||
break Flushing;
|
||||
}
|
||||
|
||||
// Try to prepare more to write.
|
||||
prepareBuffers();
|
||||
}
|
||||
}
|
||||
|
||||
// If we failed to flush anything twice in a row
|
||||
|
@ -631,7 +618,7 @@ public class Ajp13Generator extends AbstractGenerator
|
|||
catch (IOException e)
|
||||
{
|
||||
LOG.ignore(e);
|
||||
throw (e instanceof EofException) ? e : new EofException(e);
|
||||
throw (e instanceof EofException)?e:new EofException(e);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -680,14 +667,14 @@ public class Ajp13Generator extends AbstractGenerator
|
|||
{
|
||||
_bufferPrepared = true;
|
||||
|
||||
_buffer.put((byte) 0);
|
||||
_buffer.put((byte)0);
|
||||
int put = _buffer.putIndex();
|
||||
_buffer.setGetIndex(0);
|
||||
_buffer.setPutIndex(0);
|
||||
_buffer.put((byte) 'A');
|
||||
_buffer.put((byte) 'B');
|
||||
_buffer.put((byte)'A');
|
||||
_buffer.put((byte)'B');
|
||||
addInt(payloadSize + 4);
|
||||
_buffer.put((byte) 3);
|
||||
_buffer.put((byte)3);
|
||||
addInt(payloadSize);
|
||||
_buffer.setPutIndex(put);
|
||||
}
|
||||
|
@ -759,15 +746,15 @@ public class Ajp13Generator extends AbstractGenerator
|
|||
/* ------------------------------------------------------------ */
|
||||
private void addInt(int i)
|
||||
{
|
||||
_buffer.put((byte) ((i >> 8) & 0xFF));
|
||||
_buffer.put((byte) (i & 0xFF));
|
||||
_buffer.put((byte)((i >> 8) & 0xFF));
|
||||
_buffer.put((byte)(i & 0xFF));
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
private void addInt(int startIndex, int i)
|
||||
{
|
||||
_buffer.poke(startIndex, (byte) ((i >> 8) & 0xFF));
|
||||
_buffer.poke((startIndex + 1), (byte) (i & 0xFF));
|
||||
_buffer.poke(startIndex,(byte)((i >> 8) & 0xFF));
|
||||
_buffer.poke((startIndex + 1),(byte)(i & 0xFF));
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
@ -786,7 +773,7 @@ public class Ajp13Generator extends AbstractGenerator
|
|||
addInt(b.length);
|
||||
|
||||
_buffer.put(b);
|
||||
_buffer.put((byte) 0);
|
||||
_buffer.put((byte)0);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
@ -800,15 +787,14 @@ public class Ajp13Generator extends AbstractGenerator
|
|||
|
||||
addInt(b.length());
|
||||
_buffer.put(b);
|
||||
_buffer.put((byte) 0);
|
||||
_buffer.put((byte)0);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public void getBodyChunk() throws IOException
|
||||
{
|
||||
_needMore = true;
|
||||
_expectMore = true;
|
||||
flushBuffer();
|
||||
ByteArrayBuffer bf = new ByteArrayBuffer(AJP13_MORE_CONTENT);
|
||||
_endp.flush(bf);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
@ -818,7 +804,6 @@ public class Ajp13Generator extends AbstractGenerator
|
|||
_expectMore = false;
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public void sendCPong() throws IOException
|
||||
{
|
||||
|
@ -831,13 +816,11 @@ public class Ajp13Generator extends AbstractGenerator
|
|||
{
|
||||
_endp.flush(buff);
|
||||
}
|
||||
while(buff.length() >0);
|
||||
while (buff.length() > 0);
|
||||
_buffers.returnBuffer(buff);
|
||||
|
||||
reset(true);
|
||||
reset();
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -148,21 +148,16 @@ public class Ajp13Parser implements Parser
|
|||
}
|
||||
|
||||
/* ------------------------------------------------------------------------------- */
|
||||
public int parseAvailable() throws IOException
|
||||
public boolean parseAvailable() throws IOException
|
||||
{
|
||||
int len = parseNext();
|
||||
int total = len > 0 ? len : 0;
|
||||
|
||||
boolean progress=parseNext()>0;
|
||||
|
||||
// continue parsing
|
||||
while (!isComplete() && _buffer != null && _buffer.length() > 0)
|
||||
while (!isComplete() && _buffer!=null && _buffer.length()>0)
|
||||
{
|
||||
len = parseNext();
|
||||
if (len > 0)
|
||||
total += len;
|
||||
else
|
||||
break;
|
||||
progress |= parseNext()>0;
|
||||
}
|
||||
return total;
|
||||
return progress;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------------- */
|
||||
|
@ -876,6 +871,15 @@ public class Ajp13Parser implements Parser
|
|||
|
||||
return _content.length() > 0;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isPersistent()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public void setPersistent(boolean persistent)
|
||||
{
|
||||
LOG.warn("AJP13.setPersistent is not IMPLEMENTED!");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
|
||||
package org.eclipse.jetty.ajp;
|
||||
|
||||
import org.eclipse.jetty.server.HttpConnection;
|
||||
import org.eclipse.jetty.server.AbstractHttpConnection;
|
||||
import org.eclipse.jetty.server.Request;
|
||||
|
||||
public class Ajp13Request extends Request
|
||||
|
@ -24,7 +24,7 @@ public class Ajp13Request extends Request
|
|||
protected boolean _sslSecure;
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public Ajp13Request(HttpConnection connection)
|
||||
public Ajp13Request(AbstractHttpConnection connection)
|
||||
{
|
||||
super(connection);
|
||||
}
|
||||
|
|
|
@ -13,10 +13,10 @@
|
|||
|
||||
package org.eclipse.jetty.ajp;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStream;
|
||||
import java.net.Socket;
|
||||
import java.net.SocketTimeoutException;
|
||||
|
@ -39,8 +39,6 @@ import org.junit.Before;
|
|||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
public class Ajp13ConnectionTest
|
||||
{
|
||||
private static final Logger LOG = Log.getLogger(Ajp13ConnectionTest.class);
|
||||
|
|
|
@ -13,6 +13,9 @@
|
|||
|
||||
package org.eclipse.jetty.ajp;
|
||||
|
||||
import static junit.framework.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.eclipse.jetty.io.Buffer;
|
||||
|
@ -23,9 +26,6 @@ import org.eclipse.jetty.io.SimpleBuffers;
|
|||
import org.eclipse.jetty.util.TypeUtil;
|
||||
import org.junit.Test;
|
||||
|
||||
import static junit.framework.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
public class TestAjpParser
|
||||
{
|
||||
@Test
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-project</artifactId>
|
||||
<version>7.5.0-SNAPSHOT</version>
|
||||
<version>7.6.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>jetty-annotations</artifactId>
|
||||
|
|
|
@ -454,7 +454,10 @@ public class AnnotationParser
|
|||
className = className.replace('.', '/')+".class";
|
||||
URL resource = Loader.getResource(this.getClass(), className, false);
|
||||
if (resource!= null)
|
||||
scanClass(resource.openStream());
|
||||
{
|
||||
Resource r = Resource.newResource(resource);
|
||||
scanClass(r.getInputStream());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -472,7 +475,10 @@ public class AnnotationParser
|
|||
String nameAsResource = cz.getName().replace('.', '/')+".class";
|
||||
URL resource = Loader.getResource(this.getClass(), nameAsResource, false);
|
||||
if (resource!= null)
|
||||
scanClass(resource.openStream());
|
||||
{
|
||||
Resource r = Resource.newResource(resource);
|
||||
scanClass(r.getInputStream());
|
||||
}
|
||||
}
|
||||
}
|
||||
if (visitSuperClasses)
|
||||
|
@ -501,7 +507,10 @@ public class AnnotationParser
|
|||
s = s.replace('.', '/')+".class";
|
||||
URL resource = Loader.getResource(this.getClass(), s, false);
|
||||
if (resource!= null)
|
||||
scanClass(resource.openStream());
|
||||
{
|
||||
Resource r = Resource.newResource(resource);
|
||||
scanClass(r.getInputStream());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -525,7 +534,10 @@ public class AnnotationParser
|
|||
if (name.endsWith(".class"))
|
||||
{
|
||||
if ((resolver == null)|| (!resolver.isExcluded(name) && (!isParsed(name) || resolver.shouldOverride(name))))
|
||||
scanClass(res.getURL().openStream());
|
||||
{
|
||||
Resource r = Resource.newResource(res.getURL());
|
||||
scanClass(r.getInputStream());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-project</artifactId>
|
||||
<version>7.5.0-SNAPSHOT</version>
|
||||
<version>7.6.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// ========================================================================
|
||||
// Copyright (c) 2006-2009 Mort Bay Consulting Pty. Ltd.
|
||||
// Copyright (c) 2006-2011 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
|
||||
|
@ -13,10 +13,8 @@
|
|||
|
||||
package org.eclipse.jetty.client;
|
||||
|
||||
import java.io.EOFException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InterruptedIOException;
|
||||
import java.util.Collections;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
|
@ -31,14 +29,13 @@ import org.eclipse.jetty.http.HttpSchemes;
|
|||
import org.eclipse.jetty.http.HttpStatus;
|
||||
import org.eclipse.jetty.http.HttpVersions;
|
||||
import org.eclipse.jetty.io.AbstractConnection;
|
||||
import org.eclipse.jetty.io.AsyncEndPoint;
|
||||
import org.eclipse.jetty.io.Buffer;
|
||||
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.io.nio.SslSelectChannelEndPoint;
|
||||
import org.eclipse.jetty.util.component.AggregateLifeCycle;
|
||||
import org.eclipse.jetty.util.component.Dumpable;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
|
@ -49,31 +46,29 @@ import org.eclipse.jetty.util.thread.Timeout;
|
|||
*
|
||||
* @version $Revision: 879 $ $Date: 2009-09-11 16:13:28 +0200 (Fri, 11 Sep 2009) $
|
||||
*/
|
||||
public class HttpConnection extends AbstractConnection implements Dumpable
|
||||
public abstract class AbstractHttpConnection extends AbstractConnection implements Dumpable
|
||||
{
|
||||
private static final Logger LOG = Log.getLogger(HttpConnection.class);
|
||||
private static final Logger LOG = Log.getLogger(AbstractHttpConnection.class);
|
||||
|
||||
private HttpDestination _destination;
|
||||
private HttpGenerator _generator;
|
||||
private HttpParser _parser;
|
||||
private boolean _http11 = true;
|
||||
private int _status;
|
||||
private Buffer _connectionHeader;
|
||||
private Buffer _requestContentChunk;
|
||||
private boolean _requestComplete;
|
||||
private boolean _reserved;
|
||||
protected HttpDestination _destination;
|
||||
protected HttpGenerator _generator;
|
||||
protected HttpParser _parser;
|
||||
protected boolean _http11 = true;
|
||||
protected int _status;
|
||||
protected Buffer _connectionHeader;
|
||||
protected boolean _reserved;
|
||||
|
||||
// The current exchange waiting for a response
|
||||
private volatile HttpExchange _exchange;
|
||||
private HttpExchange _pipeline;
|
||||
protected volatile HttpExchange _exchange;
|
||||
protected HttpExchange _pipeline;
|
||||
private final Timeout.Task _idleTimeout = new ConnectionIdleTask();
|
||||
private AtomicBoolean _idle = new AtomicBoolean(false);
|
||||
|
||||
|
||||
HttpConnection(Buffers requestBuffers, Buffers responseBuffers, EndPoint endp)
|
||||
AbstractHttpConnection(Buffers requestBuffers, Buffers responseBuffers, EndPoint endp)
|
||||
{
|
||||
super(endp);
|
||||
|
||||
|
||||
_generator = new HttpGenerator(requestBuffers,endp);
|
||||
_parser = new HttpParser(responseBuffers,endp,new Handler());
|
||||
}
|
||||
|
@ -100,6 +95,7 @@ public class HttpConnection extends AbstractConnection implements Dumpable
|
|||
|
||||
public boolean send(HttpExchange ex) throws IOException
|
||||
{
|
||||
LOG.debug("Send {} on {}",ex,this);
|
||||
synchronized (this)
|
||||
{
|
||||
if (_exchange != null)
|
||||
|
@ -123,16 +119,6 @@ public class HttpConnection extends AbstractConnection implements Dumpable
|
|||
|
||||
_exchange.setStatus(HttpExchange.STATUS_WAITING_FOR_COMMIT);
|
||||
|
||||
if (_endp.isBlocking())
|
||||
{
|
||||
this.notify();
|
||||
}
|
||||
else
|
||||
{
|
||||
AsyncEndPoint scep = (AsyncEndPoint)_endp;
|
||||
scep.scheduleWrite();
|
||||
}
|
||||
|
||||
adjustIdleTimeout();
|
||||
|
||||
return true;
|
||||
|
@ -161,287 +147,8 @@ public class HttpConnection extends AbstractConnection implements Dumpable
|
|||
}
|
||||
}
|
||||
|
||||
public Connection handle() throws IOException
|
||||
{
|
||||
try
|
||||
{
|
||||
int no_progress = 0;
|
||||
public abstract Connection handle() throws IOException;
|
||||
|
||||
boolean failed = false;
|
||||
while (_endp.isBufferingInput() || _endp.isOpen())
|
||||
{
|
||||
synchronized (this)
|
||||
{
|
||||
while (_exchange == null)
|
||||
{
|
||||
if (_endp.isBlocking())
|
||||
{
|
||||
try
|
||||
{
|
||||
this.wait();
|
||||
}
|
||||
catch (InterruptedException e)
|
||||
{
|
||||
throw new InterruptedIOException();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
long filled = _parser.fill();
|
||||
if (filled < 0)
|
||||
{
|
||||
close();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Hopefully just space?
|
||||
_parser.skipCRLF();
|
||||
if (_parser.isMoreInBuffer())
|
||||
{
|
||||
LOG.warn("Unexpected data received but no request sent");
|
||||
close();
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
if (_exchange.getStatus() == HttpExchange.STATUS_WAITING_FOR_COMMIT)
|
||||
{
|
||||
no_progress = 0;
|
||||
commitRequest();
|
||||
}
|
||||
|
||||
long io = 0;
|
||||
_endp.flush();
|
||||
|
||||
if (_generator.isComplete())
|
||||
{
|
||||
if (!_requestComplete)
|
||||
{
|
||||
_requestComplete = true;
|
||||
_exchange.getEventListener().onRequestComplete();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Write as much of the request as possible
|
||||
synchronized (this)
|
||||
{
|
||||
if (_exchange == null)
|
||||
continue;
|
||||
}
|
||||
|
||||
long flushed = _generator.flushBuffer();
|
||||
io += flushed;
|
||||
|
||||
if (!_generator.isComplete())
|
||||
{
|
||||
if (_exchange!=null)
|
||||
{
|
||||
InputStream in = _exchange.getRequestContentSource();
|
||||
if (in != null)
|
||||
{
|
||||
if (_requestContentChunk == null || _requestContentChunk.length() == 0)
|
||||
{
|
||||
_requestContentChunk = _exchange.getRequestContentChunk();
|
||||
|
||||
if (_requestContentChunk != null)
|
||||
_generator.addContent(_requestContentChunk,false);
|
||||
else
|
||||
_generator.complete();
|
||||
|
||||
flushed = _generator.flushBuffer();
|
||||
io += flushed;
|
||||
}
|
||||
}
|
||||
else
|
||||
_generator.complete();
|
||||
}
|
||||
else
|
||||
_generator.complete();
|
||||
}
|
||||
}
|
||||
|
||||
if (_generator.isComplete() && !_requestComplete)
|
||||
{
|
||||
_requestComplete = true;
|
||||
_exchange.getEventListener().onRequestComplete();
|
||||
}
|
||||
|
||||
// If we are not ended then parse available
|
||||
if (!_parser.isComplete() && (_generator.isComplete() || _generator.isCommitted() && !_endp.isBlocking()))
|
||||
{
|
||||
long filled = _parser.parseAvailable();
|
||||
io += filled;
|
||||
}
|
||||
|
||||
if (io > 0)
|
||||
no_progress = 0;
|
||||
else if (no_progress++ >= 1 && !_endp.isBlocking())
|
||||
{
|
||||
// SSL may need an extra flush as it may have made "no progress" while actually doing a handshake.
|
||||
if (_endp instanceof SslSelectChannelEndPoint && !_generator.isComplete() && !_generator.isEmpty())
|
||||
{
|
||||
long flushed = _generator.flushBuffer();
|
||||
if (flushed>0)
|
||||
continue;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
}
|
||||
catch (Throwable e)
|
||||
{
|
||||
LOG.debug("Failure on " + _exchange, e);
|
||||
|
||||
if (e instanceof ThreadDeath)
|
||||
throw (ThreadDeath)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.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
|
||||
{
|
||||
boolean complete = false;
|
||||
boolean close = failed; // always close the connection on error
|
||||
if (!failed)
|
||||
{
|
||||
// are we complete?
|
||||
if (_generator.isComplete())
|
||||
{
|
||||
if (!_requestComplete)
|
||||
{
|
||||
_requestComplete = true;
|
||||
_exchange.getEventListener().onRequestComplete();
|
||||
}
|
||||
|
||||
// we need to return the HttpConnection to a state that
|
||||
// it can be reused or closed out
|
||||
if (_parser.isComplete())
|
||||
{
|
||||
_exchange.cancelTimeout(_destination.getHttpClient());
|
||||
complete = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (_generator.isComplete() && !_parser.isComplete())
|
||||
{
|
||||
if (!_endp.isOpen() || _endp.isInputShutdown())
|
||||
{
|
||||
complete=true;
|
||||
close=true;
|
||||
close();
|
||||
}
|
||||
}
|
||||
|
||||
if (complete || failed)
|
||||
{
|
||||
synchronized (this)
|
||||
{
|
||||
if (!close)
|
||||
close = shouldClose();
|
||||
|
||||
reset(true);
|
||||
|
||||
no_progress = 0;
|
||||
if (_exchange != null)
|
||||
{
|
||||
HttpExchange exchange=_exchange;
|
||||
_exchange = null;
|
||||
|
||||
// Reset the maxIdleTime because it may have been changed
|
||||
if (!close)
|
||||
_endp.setMaxIdleTime((int)_destination.getHttpClient().getIdleTimeout());
|
||||
|
||||
if (_status==HttpStatus.SWITCHING_PROTOCOLS_101)
|
||||
{
|
||||
Connection switched=exchange.onSwitchProtocol(_endp);
|
||||
if (switched!=null)
|
||||
{
|
||||
// switched protocol!
|
||||
exchange = _pipeline;
|
||||
_pipeline = null;
|
||||
if (exchange!=null)
|
||||
_destination.send(exchange);
|
||||
|
||||
return switched;
|
||||
}
|
||||
}
|
||||
|
||||
if (_pipeline == null)
|
||||
{
|
||||
if (!isReserved())
|
||||
_destination.returnConnection(this, close);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (close)
|
||||
{
|
||||
if (!isReserved())
|
||||
_destination.returnConnection(this,close);
|
||||
|
||||
exchange = _pipeline;
|
||||
_pipeline = null;
|
||||
_destination.send(exchange);
|
||||
}
|
||||
else
|
||||
{
|
||||
exchange = _pipeline;
|
||||
_pipeline = null;
|
||||
send(exchange);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
_parser.returnBuffers();
|
||||
|
||||
// Do we have more stuff to write?
|
||||
if (!_generator.isComplete() && _generator.getBytesBuffered()>0 && _endp instanceof AsyncEndPoint)
|
||||
{
|
||||
// Assume we are write blocked!
|
||||
((AsyncEndPoint)_endp).scheduleWrite();
|
||||
}
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public boolean isIdle()
|
||||
{
|
||||
|
@ -456,11 +163,11 @@ public class HttpConnection extends AbstractConnection implements Dumpable
|
|||
return false;
|
||||
}
|
||||
|
||||
public void closed()
|
||||
public void onClose()
|
||||
{
|
||||
}
|
||||
|
||||
private void commitRequest() throws IOException
|
||||
protected void commitRequest() throws IOException
|
||||
{
|
||||
synchronized (this)
|
||||
{
|
||||
|
@ -472,7 +179,7 @@ public class HttpConnection extends AbstractConnection implements Dumpable
|
|||
_generator.setVersion(_exchange.getVersion());
|
||||
|
||||
String method=_exchange.getMethod();
|
||||
String uri = _exchange.getURI();
|
||||
String uri = _exchange.getRequestURI();
|
||||
if (_destination.isProxied() && !HttpMethods.CONNECT.equals(method) && uri.startsWith("/"))
|
||||
{
|
||||
boolean secure = _destination.isSecure();
|
||||
|
@ -536,28 +243,14 @@ public class HttpConnection extends AbstractConnection implements Dumpable
|
|||
}
|
||||
}
|
||||
|
||||
protected void reset(boolean returnBuffers) throws IOException
|
||||
protected void reset() throws IOException
|
||||
{
|
||||
_requestComplete = false;
|
||||
_connectionHeader = null;
|
||||
_parser.reset();
|
||||
if (returnBuffers)
|
||||
_parser.returnBuffers();
|
||||
_generator.reset(returnBuffers);
|
||||
_generator.reset();
|
||||
_http11 = true;
|
||||
}
|
||||
|
||||
private boolean shouldClose()
|
||||
{
|
||||
if (_connectionHeader!=null)
|
||||
{
|
||||
if (HttpHeaderValues.CLOSE_BUFFER.equals(_connectionHeader))
|
||||
return true;
|
||||
if (HttpHeaderValues.KEEP_ALIVE_BUFFER.equals(_connectionHeader))
|
||||
return false;
|
||||
}
|
||||
return !_http11;
|
||||
}
|
||||
|
||||
private class Handler extends HttpParser.EventHandler
|
||||
{
|
||||
|
@ -575,28 +268,33 @@ public class HttpConnection extends AbstractConnection implements Dumpable
|
|||
public void startResponse(Buffer version, int status, Buffer reason) throws IOException
|
||||
{
|
||||
HttpExchange exchange = _exchange;
|
||||
if (exchange!=null)
|
||||
if (exchange==null)
|
||||
{
|
||||
switch(status)
|
||||
{
|
||||
case HttpStatus.CONTINUE_100:
|
||||
case HttpStatus.PROCESSING_102:
|
||||
// TODO check if appropriate expect was sent in the request.
|
||||
exchange.setEventListener(new NonFinalResponseListener(exchange));
|
||||
break;
|
||||
|
||||
case HttpStatus.OK_200:
|
||||
// handle special case for CONNECT 200 responses
|
||||
if (HttpMethods.CONNECT.equalsIgnoreCase(exchange.getMethod()))
|
||||
_parser.setHeadResponse(true);
|
||||
break;
|
||||
}
|
||||
|
||||
_http11 = HttpVersions.HTTP_1_1_BUFFER.equals(version);
|
||||
_status=status;
|
||||
exchange.getEventListener().onResponseStatus(version,status,reason);
|
||||
exchange.setStatus(HttpExchange.STATUS_PARSING_HEADERS);
|
||||
LOG.warn("No exchange for response");
|
||||
_endp.close();
|
||||
return;
|
||||
}
|
||||
|
||||
switch(status)
|
||||
{
|
||||
case HttpStatus.CONTINUE_100:
|
||||
case HttpStatus.PROCESSING_102:
|
||||
// TODO check if appropriate expect was sent in the request.
|
||||
exchange.setEventListener(new NonFinalResponseListener(exchange));
|
||||
break;
|
||||
|
||||
case HttpStatus.OK_200:
|
||||
// handle special case for CONNECT 200 responses
|
||||
if (HttpMethods.CONNECT.equalsIgnoreCase(exchange.getMethod()))
|
||||
_parser.setHeadResponse(true);
|
||||
break;
|
||||
}
|
||||
|
||||
_http11 = HttpVersions.HTTP_1_1_BUFFER.equals(version);
|
||||
_status=status;
|
||||
exchange.getEventListener().onResponseStatus(version,status,reason);
|
||||
exchange.setStatus(HttpExchange.STATUS_PARSING_HEADERS);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -616,8 +314,6 @@ public class HttpConnection extends AbstractConnection implements Dumpable
|
|||
@Override
|
||||
public void headerComplete() throws IOException
|
||||
{
|
||||
if (_endp instanceof AsyncEndPoint)
|
||||
((AsyncEndPoint)_endp).scheduleIdle();
|
||||
HttpExchange exchange = _exchange;
|
||||
if (exchange!=null)
|
||||
exchange.setStatus(HttpExchange.STATUS_PARSING_CONTENT);
|
||||
|
@ -626,8 +322,6 @@ public class HttpConnection extends AbstractConnection implements Dumpable
|
|||
@Override
|
||||
public void content(Buffer ref) throws IOException
|
||||
{
|
||||
if (_endp instanceof AsyncEndPoint)
|
||||
((AsyncEndPoint)_endp).scheduleIdle();
|
||||
HttpExchange exchange = _exchange;
|
||||
if (exchange!=null)
|
||||
exchange.getEventListener().onResponseContent(ref);
|
||||
|
@ -640,12 +334,32 @@ public class HttpConnection extends AbstractConnection implements Dumpable
|
|||
if (exchange!=null)
|
||||
exchange.setStatus(HttpExchange.STATUS_COMPLETED);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void earlyEOF()
|
||||
{
|
||||
HttpExchange exchange = _exchange;
|
||||
if (exchange!=null)
|
||||
{
|
||||
if (!exchange.isDone())
|
||||
{
|
||||
if (exchange.setStatus(HttpExchange.STATUS_EXCEPTED))
|
||||
exchange.getEventListener().onException(new EofException("early EOF"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return "HttpConnection@" + hashCode() + "//" + _destination.getAddress().getHost() + ":" + _destination.getAddress().getPort();
|
||||
return String.format("%s %s g=%s p=%s",
|
||||
super.toString(),
|
||||
_destination == null ? "?.?.?.?:??" : _destination.getAddress(),
|
||||
_generator,
|
||||
_parser);
|
||||
}
|
||||
|
||||
public String toDetailString()
|
||||
|
@ -669,15 +383,22 @@ public class HttpConnection extends AbstractConnection implements Dumpable
|
|||
case HttpExchange.STATUS_EXCEPTED:
|
||||
case HttpExchange.STATUS_EXPIRED:
|
||||
break;
|
||||
case HttpExchange.STATUS_PARSING_CONTENT:
|
||||
if (_endp.isInputShutdown() && _parser.isState(HttpParser.STATE_EOF_CONTENT))
|
||||
break;
|
||||
default:
|
||||
String exch= exchange.toString();
|
||||
String reason = _endp.isOpen()?(_endp.isInputShutdown()?"half closed: ":"local close: "):"closed: ";
|
||||
exchange.setStatus(HttpExchange.STATUS_EXCEPTED);
|
||||
exchange.getEventListener().onException(new EOFException(reason+exch));
|
||||
if (exchange.setStatus(HttpExchange.STATUS_EXCEPTED))
|
||||
exchange.getEventListener().onException(new EofException(reason+exch));
|
||||
}
|
||||
}
|
||||
|
||||
_endp.close();
|
||||
if (_endp.isOpen())
|
||||
{
|
||||
_endp.close();
|
||||
_destination.returnConnection(this, true);
|
||||
}
|
||||
}
|
||||
|
||||
public void setIdleTimeout()
|
||||
|
@ -724,7 +445,7 @@ public class HttpConnection extends AbstractConnection implements Dumpable
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @see org.eclipse.jetty.util.component.Dumpable#dump()
|
||||
|
@ -746,7 +467,7 @@ public class HttpConnection extends AbstractConnection implements Dumpable
|
|||
AggregateLifeCycle.dump(out,indent,Collections.singletonList(_endp));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
private class ConnectionIdleTask extends Timeout.Task
|
||||
{
|
||||
|
@ -757,18 +478,18 @@ public class HttpConnection extends AbstractConnection implements Dumpable
|
|||
// Connection idle, close it
|
||||
if (_idle.compareAndSet(true, false))
|
||||
{
|
||||
_destination.returnIdleConnection(HttpConnection.this);
|
||||
_destination.returnIdleConnection(AbstractHttpConnection.this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
private class NonFinalResponseListener implements HttpEventListener
|
||||
{
|
||||
final HttpExchange _exchange;
|
||||
final HttpEventListener _next;
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public NonFinalResponseListener(HttpExchange exchange)
|
||||
{
|
||||
|
@ -813,7 +534,7 @@ public class HttpConnection extends AbstractConnection implements Dumpable
|
|||
{
|
||||
_exchange.setEventListener(_next);
|
||||
_exchange.setStatus(HttpExchange.STATUS_WAITING_FOR_RESPONSE);
|
||||
_parser.reset();
|
||||
_parser.reset();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
|
@ -43,6 +43,9 @@ public class Address
|
|||
|
||||
public Address(String host, int port)
|
||||
{
|
||||
if (host == null)
|
||||
throw new IllegalArgumentException("Host is null");
|
||||
|
||||
this.host = host.trim();
|
||||
this.port = port;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,260 @@
|
|||
// ========================================================================
|
||||
// Copyright (c) 2006-2011 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.Buffer;
|
||||
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 Buffer _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;
|
||||
Buffer chunk=_requestContentChunk;
|
||||
_requestContentChunk=exchange.getRequestContentChunk(null);
|
||||
_generator.addContent(chunk,_requestContentChunk==null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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)
|
||||
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();
|
||||
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;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,257 @@
|
|||
// ========================================================================
|
||||
// Copyright (c) 2006-2011 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.Buffer;
|
||||
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 Buffer _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");
|
||||
Buffer chunk=_requestContentChunk;
|
||||
_requestContentChunk=exchange.getRequestContentChunk(null);
|
||||
_generator.addContent(chunk,_requestContentChunk==null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
}
|
|
@ -16,6 +16,7 @@ package org.eclipse.jetty.client;
|
|||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.Arrays;
|
||||
import java.util.Enumeration;
|
||||
import java.util.LinkedList;
|
||||
import java.util.Set;
|
||||
|
@ -29,13 +30,13 @@ 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.HttpSchemes;
|
||||
import org.eclipse.jetty.http.ssl.SslContextFactory;
|
||||
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;
|
||||
|
@ -52,11 +53,11 @@ import org.eclipse.jetty.util.thread.Timeout;
|
|||
* 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 HttpConnection},
|
||||
* queued in the {@link HttpConnection} waiting to be transmitted or pipelined on the actual
|
||||
* and they may be queued on the {@link HttpDestination} waiting for a {@link AbstractHttpConnection},
|
||||
* queued in the {@link AbstractHttpConnection} waiting to be transmitted or pipelined on the actual
|
||||
* TCP/IP connection waiting for a response.
|
||||
* <p/>
|
||||
* The {@link HttpDestination} class is an aggregation of {@link HttpConnection}s for the
|
||||
* 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
|
||||
|
@ -164,7 +165,7 @@ public class HttpClient extends HttpBuffers implements Attributes, Dumpable
|
|||
public void dump(Appendable out, String indent) throws IOException
|
||||
{
|
||||
out.append(String.valueOf(this)).append("\n");
|
||||
AggregateLifeCycle.dump(out,indent,_destinations.values());
|
||||
AggregateLifeCycle.dump(out,indent,Arrays.asList(_threadPool,_connector),_destinations.values());
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------------- */
|
||||
|
@ -178,10 +179,19 @@ public class HttpClient extends HttpBuffers implements Attributes, Dumpable
|
|||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @return the threadPool
|
||||
* @return the threadpool
|
||||
*/
|
||||
public ThreadPool getThreadPool()
|
||||
{
|
||||
if (_threadPool==null)
|
||||
{
|
||||
QueuedThreadPool pool = new QueuedThreadPool();
|
||||
pool.setMaxThreads(16);
|
||||
pool.setDaemon(true);
|
||||
pool.setName("HttpClient");
|
||||
_threadPool = pool;
|
||||
}
|
||||
|
||||
return _threadPool;
|
||||
}
|
||||
|
||||
|
@ -420,13 +430,7 @@ public class HttpClient extends HttpBuffers implements Attributes, Dumpable
|
|||
_idleTimeoutQ.setNow();
|
||||
|
||||
if (_threadPool == null)
|
||||
{
|
||||
QueuedThreadPool pool = new QueuedThreadPool();
|
||||
pool.setMaxThreads(16);
|
||||
pool.setDaemon(true);
|
||||
pool.setName("HttpClient");
|
||||
_threadPool = pool;
|
||||
}
|
||||
getThreadPool();
|
||||
|
||||
if (_threadPool instanceof LifeCycle)
|
||||
{
|
||||
|
@ -523,7 +527,7 @@ public class HttpClient extends HttpBuffers implements Attributes, Dumpable
|
|||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @return the period in milliseconds a {@link HttpConnection} can be idle for before it is closed.
|
||||
* @return the period in milliseconds a {@link AbstractHttpConnection} can be idle for before it is closed.
|
||||
*/
|
||||
public long getIdleTimeout()
|
||||
{
|
||||
|
@ -532,7 +536,7 @@ public class HttpClient extends HttpBuffers implements Attributes, Dumpable
|
|||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @param ms the period in milliseconds a {@link HttpConnection} can be idle for before it is closed.
|
||||
* @param ms the period in milliseconds a {@link AbstractHttpConnection} can be idle for before it is closed.
|
||||
*/
|
||||
public void setIdleTimeout(long ms)
|
||||
{
|
||||
|
@ -695,14 +699,14 @@ public class HttpClient extends HttpBuffers implements Attributes, Dumpable
|
|||
@Deprecated
|
||||
public String getKeyStoreLocation()
|
||||
{
|
||||
return _sslContextFactory.getKeyStore();
|
||||
return _sslContextFactory.getKeyStorePath();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Deprecated
|
||||
public void setKeyStoreLocation(String keyStoreLocation)
|
||||
{
|
||||
_sslContextFactory.setKeyStore(keyStoreLocation);
|
||||
_sslContextFactory.setKeyStorePath(keyStoreLocation);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
|
|
|
@ -15,7 +15,7 @@ package org.eclipse.jetty.client;
|
|||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.net.ConnectException;
|
||||
import java.net.ProtocolException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
@ -48,9 +48,9 @@ public class HttpDestination implements Dumpable
|
|||
private static final Logger LOG = Log.getLogger(HttpDestination.class);
|
||||
|
||||
private final List<HttpExchange> _queue = new LinkedList<HttpExchange>();
|
||||
private final List<HttpConnection> _connections = new LinkedList<HttpConnection>();
|
||||
private final List<AbstractHttpConnection> _connections = new LinkedList<AbstractHttpConnection>();
|
||||
private final BlockingQueue<Object> _newQueue = new ArrayBlockingQueue<Object>(10, true);
|
||||
private final List<HttpConnection> _idle = new ArrayList<HttpConnection>();
|
||||
private final List<AbstractHttpConnection> _idle = new ArrayList<AbstractHttpConnection>();
|
||||
private final HttpClient _client;
|
||||
private final Address _address;
|
||||
private final boolean _ssl;
|
||||
|
@ -65,7 +65,7 @@ public class HttpDestination implements Dumpable
|
|||
private List<HttpCookie> _cookies;
|
||||
|
||||
|
||||
|
||||
|
||||
HttpDestination(HttpClient client, Address address, boolean ssl)
|
||||
{
|
||||
_client = client;
|
||||
|
@ -168,9 +168,9 @@ public class HttpDestination implements Dumpable
|
|||
* @return a HttpConnection for this destination
|
||||
* @throws IOException if an I/O error occurs
|
||||
*/
|
||||
private HttpConnection getConnection(long timeout) throws IOException
|
||||
private AbstractHttpConnection getConnection(long timeout) throws IOException
|
||||
{
|
||||
HttpConnection connection = null;
|
||||
AbstractHttpConnection connection = null;
|
||||
|
||||
while ((connection == null) && (connection = getIdleConnection()) == null && timeout > 0)
|
||||
{
|
||||
|
@ -191,9 +191,9 @@ public class HttpDestination implements Dumpable
|
|||
try
|
||||
{
|
||||
Object o = _newQueue.take();
|
||||
if (o instanceof HttpConnection)
|
||||
if (o instanceof AbstractHttpConnection)
|
||||
{
|
||||
connection = (HttpConnection)o;
|
||||
connection = (AbstractHttpConnection)o;
|
||||
}
|
||||
else
|
||||
throw (IOException)o;
|
||||
|
@ -220,17 +220,17 @@ public class HttpDestination implements Dumpable
|
|||
return connection;
|
||||
}
|
||||
|
||||
public HttpConnection reserveConnection(long timeout) throws IOException
|
||||
public AbstractHttpConnection reserveConnection(long timeout) throws IOException
|
||||
{
|
||||
HttpConnection connection = getConnection(timeout);
|
||||
AbstractHttpConnection connection = getConnection(timeout);
|
||||
if (connection != null)
|
||||
connection.setReserved(true);
|
||||
return connection;
|
||||
}
|
||||
|
||||
public HttpConnection getIdleConnection() throws IOException
|
||||
public AbstractHttpConnection getIdleConnection() throws IOException
|
||||
{
|
||||
HttpConnection connection = null;
|
||||
AbstractHttpConnection connection = null;
|
||||
while (true)
|
||||
{
|
||||
synchronized (this)
|
||||
|
@ -246,12 +246,16 @@ public class HttpDestination implements Dumpable
|
|||
}
|
||||
|
||||
if (connection == null)
|
||||
{
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
// Check if the connection was idle,
|
||||
// but it expired just a moment ago
|
||||
if (connection.cancelIdleTimeout())
|
||||
{
|
||||
return connection;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -290,8 +294,8 @@ public class HttpDestination implements Dumpable
|
|||
else if (_queue.size() > 0)
|
||||
{
|
||||
HttpExchange ex = _queue.remove(0);
|
||||
ex.setStatus(HttpExchange.STATUS_EXCEPTED);
|
||||
ex.getEventListener().onConnectionFailed(throwable);
|
||||
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.
|
||||
|
@ -324,13 +328,13 @@ public class HttpDestination implements Dumpable
|
|||
if (_queue.size() > 0)
|
||||
{
|
||||
HttpExchange ex = _queue.remove(0);
|
||||
ex.setStatus(HttpExchange.STATUS_EXCEPTED);
|
||||
ex.getEventListener().onException(throwable);
|
||||
if(ex.setStatus(HttpExchange.STATUS_EXCEPTED))
|
||||
ex.getEventListener().onException(throwable);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void onNewConnection(final HttpConnection connection) throws IOException
|
||||
public void onNewConnection(final AbstractHttpConnection connection) throws IOException
|
||||
{
|
||||
Connection q_connection = null;
|
||||
|
||||
|
@ -352,9 +356,9 @@ public class HttpDestination implements Dumpable
|
|||
else
|
||||
{
|
||||
EndPoint endPoint = connection.getEndPoint();
|
||||
if (isProxied() && endPoint instanceof SelectConnector.ProxySelectChannelEndPoint)
|
||||
if (isProxied() && endPoint instanceof SelectConnector.UpgradableEndPoint)
|
||||
{
|
||||
SelectConnector.ProxySelectChannelEndPoint proxyEndPoint = (SelectConnector.ProxySelectChannelEndPoint)endPoint;
|
||||
SelectConnector.UpgradableEndPoint proxyEndPoint = (SelectConnector.UpgradableEndPoint)endPoint;
|
||||
HttpExchange exchange = _queue.get(0);
|
||||
ConnectExchange connect = new ConnectExchange(getAddress(), proxyEndPoint, exchange);
|
||||
connect.setAddress(getProxy());
|
||||
|
@ -381,7 +385,7 @@ public class HttpDestination implements Dumpable
|
|||
}
|
||||
}
|
||||
|
||||
public void returnConnection(HttpConnection connection, boolean close) throws IOException
|
||||
public void returnConnection(AbstractHttpConnection connection, boolean close) throws IOException
|
||||
{
|
||||
if (connection.isReserved())
|
||||
connection.setReserved(false);
|
||||
|
@ -433,16 +437,11 @@ public class HttpDestination implements Dumpable
|
|||
}
|
||||
}
|
||||
|
||||
public void returnIdleConnection(HttpConnection connection)
|
||||
public void returnIdleConnection(AbstractHttpConnection connection)
|
||||
{
|
||||
try
|
||||
{
|
||||
connection.close();
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
LOG.ignore(e);
|
||||
}
|
||||
// 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)
|
||||
|
@ -524,7 +523,7 @@ public class HttpDestination implements Dumpable
|
|||
// Add any known authorizations
|
||||
if (_authorizations != null)
|
||||
{
|
||||
Authentication auth = (Authentication)_authorizations.match(ex.getURI());
|
||||
Authentication auth = (Authentication)_authorizations.match(ex.getRequestURI());
|
||||
if (auth != null)
|
||||
(auth).setCredentials(ex);
|
||||
}
|
||||
|
@ -533,7 +532,7 @@ public class HttpDestination implements Dumpable
|
|||
// so that we count also the queue time in the timeout
|
||||
ex.scheduleTimeout(this);
|
||||
|
||||
HttpConnection connection = getIdleConnection();
|
||||
AbstractHttpConnection connection = getIdleConnection();
|
||||
if (connection != null)
|
||||
{
|
||||
send(connection, ex);
|
||||
|
@ -566,7 +565,7 @@ public class HttpDestination implements Dumpable
|
|||
}
|
||||
}
|
||||
|
||||
protected void send(HttpConnection connection, HttpExchange exchange) throws IOException
|
||||
protected void send(AbstractHttpConnection connection, HttpExchange exchange) throws IOException
|
||||
{
|
||||
synchronized (this)
|
||||
{
|
||||
|
@ -584,7 +583,7 @@ public class HttpDestination implements Dumpable
|
|||
@Override
|
||||
public synchronized String toString()
|
||||
{
|
||||
return "HttpDestination@" + hashCode() + "//" + _address.getHost() + ":" + _address.getPort() + "(" + _connections.size() + "," + _idle.size() + "," + _queue.size() + ")";
|
||||
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()
|
||||
|
@ -594,7 +593,7 @@ public class HttpDestination implements Dumpable
|
|||
b.append('\n');
|
||||
synchronized (this)
|
||||
{
|
||||
for (HttpConnection connection : _connections)
|
||||
for (AbstractHttpConnection connection : _connections)
|
||||
{
|
||||
b.append(connection.toDetailString());
|
||||
if (_idle.contains(connection))
|
||||
|
@ -637,7 +636,7 @@ public class HttpDestination implements Dumpable
|
|||
{
|
||||
synchronized (this)
|
||||
{
|
||||
for (HttpConnection connection : _connections)
|
||||
for (AbstractHttpConnection connection : _connections)
|
||||
{
|
||||
connection.close();
|
||||
}
|
||||
|
@ -665,13 +664,13 @@ public class HttpDestination implements Dumpable
|
|||
AggregateLifeCycle.dump(out,indent,_connections);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private class ConnectExchange extends ContentExchange
|
||||
{
|
||||
private final SelectConnector.ProxySelectChannelEndPoint proxyEndPoint;
|
||||
private final SelectConnector.UpgradableEndPoint proxyEndPoint;
|
||||
private final HttpExchange exchange;
|
||||
|
||||
public ConnectExchange(Address serverAddress, SelectConnector.ProxySelectChannelEndPoint proxyEndPoint, HttpExchange exchange)
|
||||
public ConnectExchange(Address serverAddress, SelectConnector.UpgradableEndPoint proxyEndPoint, HttpExchange exchange)
|
||||
{
|
||||
this.proxyEndPoint = proxyEndPoint;
|
||||
this.exchange = exchange;
|
||||
|
@ -687,13 +686,18 @@ public class HttpDestination implements Dumpable
|
|||
@Override
|
||||
protected void onResponseComplete() throws IOException
|
||||
{
|
||||
if (getResponseStatus() == HttpStatus.OK_200)
|
||||
int responseStatus = getResponseStatus();
|
||||
if (responseStatus == HttpStatus.OK_200)
|
||||
{
|
||||
proxyEndPoint.upgrade();
|
||||
}
|
||||
else if(responseStatus == HttpStatus.GATEWAY_TIMEOUT_504)
|
||||
{
|
||||
onExpire();
|
||||
}
|
||||
else
|
||||
{
|
||||
onConnectionFailed(new ConnectException(exchange.getAddress().toString()));
|
||||
onException(new ProtocolException("Proxy: " + proxyEndPoint.getRemoteAddr() +":" + proxyEndPoint.getRemotePort() + " didn't return http return code 200, but " + responseStatus + " while trying to request: " + exchange.getAddress().toString()));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -702,5 +706,22 @@ public class HttpDestination implements Dumpable
|
|||
{
|
||||
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();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -35,7 +35,9 @@ import org.eclipse.jetty.util.log.Logger;
|
|||
import org.eclipse.jetty.util.thread.Timeout;
|
||||
|
||||
/**
|
||||
* <p>An HTTP client API that encapsulates an exchange (a request and its response) with a HTTP server.</p>
|
||||
* <p>
|
||||
* An HTTP client API that encapsulates an exchange (a request and its response) with a HTTP server.
|
||||
* </p>
|
||||
*
|
||||
* This object encapsulates:
|
||||
* <ul>
|
||||
|
@ -48,27 +50,29 @@ import org.eclipse.jetty.util.thread.Timeout;
|
|||
* <li>The ability to intercept callbacks (see {@link #setEventListener(HttpEventListener)}
|
||||
* </ul>
|
||||
*
|
||||
* <p>The HttpExchange class is intended to be used by a developer wishing to have close asynchronous
|
||||
* interaction with the the exchange.<br />
|
||||
* Typically a developer will extend the HttpExchange class with a derived
|
||||
* class that overrides some or all of the onXxx callbacks. <br />
|
||||
* 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}.</p>
|
||||
* <p>
|
||||
* The HttpExchange class is intended to be used by a developer wishing to have close asynchronous interaction with the the exchange.<br />
|
||||
* Typically a developer will extend the HttpExchange class with a derived class that overrides some or all of the onXxx callbacks. <br />
|
||||
* 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}.
|
||||
* </p>
|
||||
*
|
||||
* <p>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 HttpConnection} and calls its {@link HttpConnection#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).</p>
|
||||
* <p>
|
||||
* 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).
|
||||
* </p>
|
||||
*
|
||||
* <p>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.</p>
|
||||
* <p>
|
||||
* 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.
|
||||
* </p>
|
||||
*/
|
||||
public class HttpExchange
|
||||
{
|
||||
private static final Logger LOG = Log.getLogger(HttpExchange.class);
|
||||
static final Logger LOG = Log.getLogger(HttpExchange.class);
|
||||
|
||||
public static final int STATUS_START = 0;
|
||||
public static final int STATUS_WAITING_FOR_CONNECTION = 1;
|
||||
|
@ -94,21 +98,21 @@ public class HttpExchange
|
|||
private InputStream _requestContentSource;
|
||||
|
||||
private AtomicInteger _status = new AtomicInteger(STATUS_START);
|
||||
private Buffer _requestContentChunk;
|
||||
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 HttpConnection _connection;
|
||||
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=-1;
|
||||
private long _lastStateChange=System.currentTimeMillis();
|
||||
private long _sent=-1;
|
||||
private int _lastState=-1;
|
||||
private int _lastStatePeriod=-1;
|
||||
|
||||
boolean _onRequestCompleteDone;
|
||||
boolean _onResponseCompleteDone;
|
||||
|
@ -118,9 +122,8 @@ public class HttpExchange
|
|||
{
|
||||
if (getStatus() < HttpExchange.STATUS_COMPLETED)
|
||||
setStatus(HttpExchange.STATUS_EXPIRED);
|
||||
|
||||
destination.exchangeExpired(this);
|
||||
HttpConnection connection = _connection;
|
||||
AbstractHttpConnection connection = _connection;
|
||||
if (connection != null)
|
||||
connection.exchangeExpired(this);
|
||||
}
|
||||
|
@ -131,8 +134,10 @@ public class HttpExchange
|
|||
}
|
||||
|
||||
/**
|
||||
* @param status the status to wait for
|
||||
* @throws InterruptedException if the waiting thread is interrupted
|
||||
* @param status
|
||||
* the status to wait for
|
||||
* @throws InterruptedException
|
||||
* if the waiting thread is interrupted
|
||||
* @deprecated Use {@link #waitForDone()} instead
|
||||
*/
|
||||
@Deprecated
|
||||
|
@ -142,21 +147,17 @@ public class HttpExchange
|
|||
}
|
||||
|
||||
/**
|
||||
* 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:<pre>
|
||||
* done == onConnectionFailed
|
||||
* || onException
|
||||
* || onExpire
|
||||
* || onRequestComplete && onResponseComplete
|
||||
* 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:
|
||||
*
|
||||
* <pre>
|
||||
* done == onConnectionFailed || onException || onExpire || onRequestComplete && onResponseComplete
|
||||
* </pre>
|
||||
*
|
||||
* @return the done status
|
||||
* @throws InterruptedException
|
||||
*/
|
||||
public int waitForDone () throws InterruptedException
|
||||
public int waitForDone() throws InterruptedException
|
||||
{
|
||||
synchronized (this)
|
||||
{
|
||||
|
@ -170,25 +171,34 @@ public class HttpExchange
|
|||
{
|
||||
// TODO - this should do a cancel and wakeup everybody that was waiting.
|
||||
// might need a version number concept
|
||||
synchronized(this)
|
||||
synchronized (this)
|
||||
{
|
||||
_timeoutTask=null;
|
||||
_onRequestCompleteDone=false;
|
||||
_onResponseCompleteDone=false;
|
||||
_onDone=false;
|
||||
_timeoutTask = null;
|
||||
_onRequestCompleteDone = false;
|
||||
_onResponseCompleteDone = false;
|
||||
_onDone = false;
|
||||
setStatus(STATUS_START);
|
||||
}
|
||||
}
|
||||
|
||||
void setStatus(int newStatus)
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @param newStatus
|
||||
* @return True if the status was actually set.
|
||||
*/
|
||||
boolean setStatus(int newStatus)
|
||||
{
|
||||
boolean set = false;
|
||||
try
|
||||
{
|
||||
int oldStatus = _status.get();
|
||||
boolean set = false;
|
||||
if (oldStatus!=newStatus)
|
||||
boolean ignored = false;
|
||||
if (oldStatus != newStatus)
|
||||
{
|
||||
_lastStateChange=System.currentTimeMillis();
|
||||
long now = System.currentTimeMillis();
|
||||
_lastStatePeriod=(int)(now-_lastStateChange);
|
||||
_lastState=oldStatus;
|
||||
_lastStateChange=now;
|
||||
if (newStatus==STATUS_SENDING_REQUEST)
|
||||
_sent=_lastStateChange;
|
||||
}
|
||||
|
@ -204,7 +214,10 @@ public class HttpExchange
|
|||
case STATUS_WAITING_FOR_COMMIT:
|
||||
case STATUS_CANCELLING:
|
||||
case STATUS_EXCEPTED:
|
||||
set=_status.compareAndSet(oldStatus,newStatus);
|
||||
set = _status.compareAndSet(oldStatus,newStatus);
|
||||
break;
|
||||
case STATUS_EXPIRED:
|
||||
set = setStatusExpired(newStatus,oldStatus);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
@ -214,11 +227,10 @@ public class HttpExchange
|
|||
case STATUS_WAITING_FOR_COMMIT:
|
||||
case STATUS_CANCELLING:
|
||||
case STATUS_EXCEPTED:
|
||||
set=_status.compareAndSet(oldStatus,newStatus);
|
||||
set = _status.compareAndSet(oldStatus,newStatus);
|
||||
break;
|
||||
case STATUS_EXPIRED:
|
||||
if (set=_status.compareAndSet(oldStatus,newStatus))
|
||||
getEventListener().onExpire();
|
||||
set = setStatusExpired(newStatus,oldStatus);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
@ -228,11 +240,10 @@ public class HttpExchange
|
|||
case STATUS_SENDING_REQUEST:
|
||||
case STATUS_CANCELLING:
|
||||
case STATUS_EXCEPTED:
|
||||
set=_status.compareAndSet(oldStatus,newStatus);
|
||||
set = _status.compareAndSet(oldStatus,newStatus);
|
||||
break;
|
||||
case STATUS_EXPIRED:
|
||||
if (set=_status.compareAndSet(oldStatus,newStatus))
|
||||
getEventListener().onExpire();
|
||||
set = setStatusExpired(newStatus,oldStatus);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
@ -240,16 +251,15 @@ public class HttpExchange
|
|||
switch (newStatus)
|
||||
{
|
||||
case STATUS_WAITING_FOR_RESPONSE:
|
||||
if (set=_status.compareAndSet(oldStatus,newStatus))
|
||||
if (set = _status.compareAndSet(oldStatus,newStatus))
|
||||
getEventListener().onRequestCommitted();
|
||||
break;
|
||||
case STATUS_CANCELLING:
|
||||
case STATUS_EXCEPTED:
|
||||
set=_status.compareAndSet(oldStatus,newStatus);
|
||||
set = _status.compareAndSet(oldStatus,newStatus);
|
||||
break;
|
||||
case STATUS_EXPIRED:
|
||||
if (set=_status.compareAndSet(oldStatus,newStatus))
|
||||
getEventListener().onExpire();
|
||||
set = setStatusExpired(newStatus,oldStatus);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
@ -259,11 +269,10 @@ public class HttpExchange
|
|||
case STATUS_PARSING_HEADERS:
|
||||
case STATUS_CANCELLING:
|
||||
case STATUS_EXCEPTED:
|
||||
set=_status.compareAndSet(oldStatus,newStatus);
|
||||
set = _status.compareAndSet(oldStatus,newStatus);
|
||||
break;
|
||||
case STATUS_EXPIRED:
|
||||
if (set=_status.compareAndSet(oldStatus,newStatus))
|
||||
getEventListener().onExpire();
|
||||
set = setStatusExpired(newStatus,oldStatus);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
@ -271,16 +280,15 @@ public class HttpExchange
|
|||
switch (newStatus)
|
||||
{
|
||||
case STATUS_PARSING_CONTENT:
|
||||
if (set=_status.compareAndSet(oldStatus,newStatus))
|
||||
if (set = _status.compareAndSet(oldStatus,newStatus))
|
||||
getEventListener().onResponseHeaderComplete();
|
||||
break;
|
||||
case STATUS_CANCELLING:
|
||||
case STATUS_EXCEPTED:
|
||||
set=_status.compareAndSet(oldStatus,newStatus);
|
||||
set = _status.compareAndSet(oldStatus,newStatus);
|
||||
break;
|
||||
case STATUS_EXPIRED:
|
||||
if (set=_status.compareAndSet(oldStatus,newStatus))
|
||||
getEventListener().onExpire();
|
||||
set = setStatusExpired(newStatus,oldStatus);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
@ -288,16 +296,15 @@ public class HttpExchange
|
|||
switch (newStatus)
|
||||
{
|
||||
case STATUS_COMPLETED:
|
||||
if (set=_status.compareAndSet(oldStatus,newStatus))
|
||||
if (set = _status.compareAndSet(oldStatus,newStatus))
|
||||
getEventListener().onResponseComplete();
|
||||
break;
|
||||
case STATUS_CANCELLING:
|
||||
case STATUS_EXCEPTED:
|
||||
set=_status.compareAndSet(oldStatus,newStatus);
|
||||
set = _status.compareAndSet(oldStatus,newStatus);
|
||||
break;
|
||||
case STATUS_EXPIRED:
|
||||
if (set=_status.compareAndSet(oldStatus,newStatus))
|
||||
getEventListener().onExpire();
|
||||
set = setStatusExpired(newStatus,oldStatus);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
@ -307,12 +314,12 @@ public class HttpExchange
|
|||
case STATUS_START:
|
||||
case STATUS_EXCEPTED:
|
||||
case STATUS_WAITING_FOR_RESPONSE:
|
||||
set=_status.compareAndSet(oldStatus,newStatus);
|
||||
set = _status.compareAndSet(oldStatus,newStatus);
|
||||
break;
|
||||
case STATUS_CANCELLING:
|
||||
case STATUS_EXPIRED:
|
||||
// Don't change the status, it's too late
|
||||
set=true;
|
||||
ignored = true;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
@ -321,12 +328,12 @@ public class HttpExchange
|
|||
{
|
||||
case STATUS_EXCEPTED:
|
||||
case STATUS_CANCELLED:
|
||||
if (set=_status.compareAndSet(oldStatus,newStatus))
|
||||
if (set = _status.compareAndSet(oldStatus,newStatus))
|
||||
done();
|
||||
break;
|
||||
default:
|
||||
// Ignore other statuses, we're cancelling
|
||||
set=true;
|
||||
ignored = true;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
@ -336,10 +343,16 @@ public class HttpExchange
|
|||
switch (newStatus)
|
||||
{
|
||||
case STATUS_START:
|
||||
set=_status.compareAndSet(oldStatus,newStatus);
|
||||
set = _status.compareAndSet(oldStatus,newStatus);
|
||||
break;
|
||||
|
||||
case STATUS_COMPLETED:
|
||||
ignored = true;
|
||||
done();
|
||||
break;
|
||||
|
||||
default:
|
||||
set=true;
|
||||
ignored = true;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
@ -348,13 +361,23 @@ public class HttpExchange
|
|||
throw new AssertionError(oldStatus + " => " + newStatus);
|
||||
}
|
||||
|
||||
if (!set)
|
||||
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()
|
||||
|
@ -369,7 +392,7 @@ public class HttpExchange
|
|||
* @deprecated
|
||||
*/
|
||||
@Deprecated
|
||||
public boolean isDone (int status)
|
||||
public boolean isDone(int status)
|
||||
{
|
||||
return isDone();
|
||||
}
|
||||
|
@ -381,10 +404,10 @@ public class HttpExchange
|
|||
|
||||
public void setEventListener(HttpEventListener listener)
|
||||
{
|
||||
_listener=listener;
|
||||
_listener = listener;
|
||||
}
|
||||
|
||||
public void setTimeout( long timeout )
|
||||
public void setTimeout(long timeout)
|
||||
{
|
||||
_timeout = timeout;
|
||||
}
|
||||
|
@ -395,7 +418,8 @@ public class HttpExchange
|
|||
}
|
||||
|
||||
/**
|
||||
* @param url an absolute URL (for example 'http://localhost/foo/bar?a=1')
|
||||
* @param url
|
||||
* an absolute URL (for example 'http://localhost/foo/bar?a=1')
|
||||
*/
|
||||
public void setURL(String url)
|
||||
{
|
||||
|
@ -403,7 +427,8 @@ public class HttpExchange
|
|||
}
|
||||
|
||||
/**
|
||||
* @param address the address of the server
|
||||
* @param address
|
||||
* the address of the server
|
||||
*/
|
||||
public void setAddress(Address address)
|
||||
{
|
||||
|
@ -421,8 +446,7 @@ public class HttpExchange
|
|||
/**
|
||||
* the local address used by the connection
|
||||
*
|
||||
* Note: this method will not be populated unless the exchange
|
||||
* has been executed by the HttpClient
|
||||
* 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.
|
||||
*/
|
||||
|
@ -432,15 +456,17 @@ public class HttpExchange
|
|||
}
|
||||
|
||||
/**
|
||||
* @param scheme the scheme of the URL (for example 'http')
|
||||
* @param scheme
|
||||
* the scheme of the URL (for example 'http')
|
||||
*/
|
||||
public void setScheme(Buffer scheme)
|
||||
{
|
||||
_scheme = scheme;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param scheme the scheme of the URL (for example 'http')
|
||||
* @param scheme
|
||||
* the scheme of the URL (for example 'http')
|
||||
*/
|
||||
public void setScheme(String scheme)
|
||||
{
|
||||
|
@ -464,7 +490,8 @@ public class HttpExchange
|
|||
}
|
||||
|
||||
/**
|
||||
* @param version the HTTP protocol version as integer, 9, 10 or 11 for 0.9, 1.0 or 1.1
|
||||
* @param version
|
||||
* the HTTP protocol version as integer, 9, 10 or 11 for 0.9, 1.0 or 1.1
|
||||
*/
|
||||
public void setVersion(int version)
|
||||
{
|
||||
|
@ -472,7 +499,8 @@ public class HttpExchange
|
|||
}
|
||||
|
||||
/**
|
||||
* @param version the HTTP protocol version as string
|
||||
* @param version
|
||||
* the HTTP protocol version as string
|
||||
*/
|
||||
public void setVersion(String version)
|
||||
{
|
||||
|
@ -493,7 +521,8 @@ public class HttpExchange
|
|||
}
|
||||
|
||||
/**
|
||||
* @param method the HTTP method (for example 'GET')
|
||||
* @param method
|
||||
* the HTTP method (for example 'GET')
|
||||
*/
|
||||
public void setMethod(String method)
|
||||
{
|
||||
|
@ -528,9 +557,10 @@ public class HttpExchange
|
|||
}
|
||||
|
||||
/**
|
||||
* Set the request URI
|
||||
* Set the request URI
|
||||
*
|
||||
* @param uri new request URI
|
||||
* @param uri
|
||||
* new request URI
|
||||
* @see #setRequestURI(String)
|
||||
* @deprecated
|
||||
*/
|
||||
|
@ -541,36 +571,42 @@ public class HttpExchange
|
|||
}
|
||||
|
||||
/**
|
||||
* Set the request URI
|
||||
* Set the request URI
|
||||
*
|
||||
* Per RFC 2616 sec5, Request-URI = "*" | absoluteURI | abs_path | authority<br/>
|
||||
* where:<br/><br/>
|
||||
* "*" - request applies to server itself<br/>
|
||||
* where:<br/>
|
||||
* <br/>
|
||||
* "*" - request applies to server itself<br/>
|
||||
* absoluteURI - required for proxy requests, e.g. http://localhost:8080/context<br/>
|
||||
* (this form is generated automatically by HttpClient)<br/>
|
||||
* abs_path - used for most methods, e.g. /context<br/>
|
||||
* authority - used for CONNECT method only, e.g. localhost:8080<br/>
|
||||
* (this form is generated automatically by HttpClient)<br/>
|
||||
* abs_path - used for most methods, e.g. /context<br/>
|
||||
* authority - used for CONNECT method only, e.g. localhost:8080<br/>
|
||||
* <br/>
|
||||
* For complete definition of URI components, see RFC 2396 sec3.<br/>
|
||||
*
|
||||
* @param uri new request URI
|
||||
*
|
||||
* @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')
|
||||
* @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);
|
||||
|
||||
throw new IllegalArgumentException("!Absolute URI: " + uri);
|
||||
|
||||
if (uri.isOpaque())
|
||||
throw new IllegalArgumentException("Opaque URI: "+uri);
|
||||
throw new IllegalArgumentException("Opaque URI: " + uri);
|
||||
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("URI = {}",uri.toASCIIString());
|
||||
|
||||
String scheme = uri.getScheme();
|
||||
int port = uri.getPort();
|
||||
|
@ -582,13 +618,16 @@ public class HttpExchange
|
|||
|
||||
HttpURI httpUri = new HttpURI(uri);
|
||||
String completePath = httpUri.getCompletePath();
|
||||
setRequestURI(completePath==null ? "/" : completePath);
|
||||
setRequestURI(completePath == null?"/":completePath);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the specified request header
|
||||
* @param name the header name
|
||||
* @param value the header value
|
||||
*
|
||||
* @param name
|
||||
* the header name
|
||||
* @param value
|
||||
* the header value
|
||||
*/
|
||||
public void addRequestHeader(String name, String value)
|
||||
{
|
||||
|
@ -597,8 +636,11 @@ public class HttpExchange
|
|||
|
||||
/**
|
||||
* Adds the specified request header
|
||||
* @param name the header name
|
||||
* @param value the header value
|
||||
*
|
||||
* @param name
|
||||
* the header name
|
||||
* @param value
|
||||
* the header value
|
||||
*/
|
||||
public void addRequestHeader(Buffer name, Buffer value)
|
||||
{
|
||||
|
@ -607,30 +649,37 @@ public class HttpExchange
|
|||
|
||||
/**
|
||||
* Sets the specified request header
|
||||
* @param name the header name
|
||||
* @param value the header value
|
||||
*
|
||||
* @param name
|
||||
* the header name
|
||||
* @param value
|
||||
* the header value
|
||||
*/
|
||||
public void setRequestHeader(String name, String value)
|
||||
{
|
||||
getRequestFields().put(name, value);
|
||||
getRequestFields().put(name,value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the specified request header
|
||||
* @param name the header name
|
||||
* @param value the header value
|
||||
*
|
||||
* @param name
|
||||
* the header name
|
||||
* @param value
|
||||
* the header value
|
||||
*/
|
||||
public void setRequestHeader(Buffer name, Buffer value)
|
||||
{
|
||||
getRequestFields().put(name, value);
|
||||
getRequestFields().put(name,value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param value the content type of the request
|
||||
* @param value
|
||||
* the content type of the request
|
||||
*/
|
||||
public void setRequestContentType(String value)
|
||||
{
|
||||
getRequestFields().put(HttpHeaders.CONTENT_TYPE_BUFFER, value);
|
||||
getRequestFields().put(HttpHeaders.CONTENT_TYPE_BUFFER,value);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -642,7 +691,8 @@ public class HttpExchange
|
|||
}
|
||||
|
||||
/**
|
||||
* @param requestContent the request content
|
||||
* @param requestContent
|
||||
* the request content
|
||||
*/
|
||||
public void setRequestContent(Buffer requestContent)
|
||||
{
|
||||
|
@ -650,7 +700,8 @@ public class HttpExchange
|
|||
}
|
||||
|
||||
/**
|
||||
* @param stream the request content as a stream
|
||||
* @param stream
|
||||
* the request content as a stream
|
||||
*/
|
||||
public void setRequestContentSource(InputStream stream)
|
||||
{
|
||||
|
@ -667,25 +718,22 @@ public class HttpExchange
|
|||
return _requestContentSource;
|
||||
}
|
||||
|
||||
public Buffer getRequestContentChunk() throws IOException
|
||||
public Buffer getRequestContentChunk(Buffer buffer) throws IOException
|
||||
{
|
||||
synchronized (this)
|
||||
{
|
||||
if (_requestContentChunk == null)
|
||||
_requestContentChunk = new ByteArrayBuffer(4096); // TODO configure
|
||||
else
|
||||
if (_requestContentSource!=null)
|
||||
{
|
||||
if (_requestContentChunk.hasContent())
|
||||
throw new IllegalStateException();
|
||||
_requestContentChunk.clear();
|
||||
}
|
||||
if (buffer == null)
|
||||
buffer = new ByteArrayBuffer(8192); // TODO configure
|
||||
|
||||
int read = _requestContentChunk.capacity();
|
||||
int length = _requestContentSource.read(_requestContentChunk.array(),0,read);
|
||||
if (length >= 0)
|
||||
{
|
||||
_requestContentChunk.setPutIndex(length);
|
||||
return _requestContentChunk;
|
||||
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;
|
||||
}
|
||||
|
@ -708,7 +756,8 @@ public class HttpExchange
|
|||
}
|
||||
|
||||
/**
|
||||
* @param retryStatus whether a retry will be attempted or not
|
||||
* @param retryStatus
|
||||
* whether a retry will be attempted or not
|
||||
*/
|
||||
public void setRetryStatus(boolean retryStatus)
|
||||
{
|
||||
|
@ -716,13 +765,10 @@ public class HttpExchange
|
|||
}
|
||||
|
||||
/**
|
||||
* 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()}.
|
||||
* 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()
|
||||
{
|
||||
|
@ -732,17 +778,17 @@ public class HttpExchange
|
|||
|
||||
private void done()
|
||||
{
|
||||
synchronized(this)
|
||||
synchronized (this)
|
||||
{
|
||||
disassociate();
|
||||
_onDone=true;
|
||||
_onDone = true;
|
||||
notifyAll();
|
||||
}
|
||||
}
|
||||
|
||||
private void abort()
|
||||
{
|
||||
HttpConnection httpConnection = _connection;
|
||||
AbstractHttpConnection httpConnection = _connection;
|
||||
if (httpConnection != null)
|
||||
{
|
||||
try
|
||||
|
@ -762,10 +808,10 @@ public class HttpExchange
|
|||
}
|
||||
}
|
||||
|
||||
void associate(HttpConnection connection)
|
||||
void associate(AbstractHttpConnection connection)
|
||||
{
|
||||
if (connection.getEndPoint().getLocalHost() != null)
|
||||
_localAddress = new Address(connection.getEndPoint().getLocalHost(), connection.getEndPoint().getLocalPort());
|
||||
if (connection.getEndPoint().getLocalHost() != null)
|
||||
_localAddress = new Address(connection.getEndPoint().getLocalHost(),connection.getEndPoint().getLocalPort());
|
||||
|
||||
_connection = connection;
|
||||
if (getStatus() == STATUS_CANCELLING)
|
||||
|
@ -777,9 +823,9 @@ public class HttpExchange
|
|||
return this._connection != null;
|
||||
}
|
||||
|
||||
HttpConnection disassociate()
|
||||
AbstractHttpConnection disassociate()
|
||||
{
|
||||
HttpConnection result = _connection;
|
||||
AbstractHttpConnection result = _connection;
|
||||
this._connection = null;
|
||||
if (getStatus() == STATUS_CANCELLING)
|
||||
setStatus(STATUS_CANCELLED);
|
||||
|
@ -789,33 +835,60 @@ public class HttpExchange
|
|||
public static String toState(int s)
|
||||
{
|
||||
String state;
|
||||
switch(s)
|
||||
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";
|
||||
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= String.format("%s@%x=%s//%s%s#%s(%dms)",getClass().getSimpleName(),hashCode(),_method,_address,_uri,state,forMs);
|
||||
if (getStatus()>=STATUS_SENDING_REQUEST)
|
||||
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;
|
||||
}
|
||||
|
@ -828,79 +901,93 @@ public class HttpExchange
|
|||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
* 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
|
||||
* 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
|
||||
* 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(Buffer version, int status, Buffer 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
|
||||
* 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(Buffer name, Buffer 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
|
||||
* 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
|
||||
* 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(Buffer 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
|
||||
* 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).
|
||||
* 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
|
||||
*
|
||||
* @param x
|
||||
* the exception thrown attempting to establish the connection with the server
|
||||
*/
|
||||
protected void onConnectionFailed(Throwable x)
|
||||
{
|
||||
|
@ -908,9 +995,10 @@ public class HttpExchange
|
|||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
* 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)
|
||||
{
|
||||
|
@ -918,8 +1006,7 @@ public class HttpExchange
|
|||
}
|
||||
|
||||
/**
|
||||
* Callback called when no response has been received within the timeout.
|
||||
* This implementation logs a warning.
|
||||
* Callback called when no response has been received within the timeout. This implementation logs a warning.
|
||||
*/
|
||||
protected void onExpire()
|
||||
{
|
||||
|
@ -927,9 +1014,10 @@ public class HttpExchange
|
|||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
* 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
|
||||
{
|
||||
|
@ -948,8 +1036,7 @@ public class HttpExchange
|
|||
}
|
||||
|
||||
/**
|
||||
* @return true if the exchange should have listeners configured for it by the destination,
|
||||
* false if this is being managed elsewhere
|
||||
* @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()
|
||||
|
@ -958,7 +1045,8 @@ public class HttpExchange
|
|||
}
|
||||
|
||||
/**
|
||||
* @param autoConfigure whether the listeners are configured by the destination or elsewhere
|
||||
* @param autoConfigure
|
||||
* whether the listeners are configured by the destination or elsewhere
|
||||
*/
|
||||
public void setConfigureListeners(boolean autoConfigure)
|
||||
{
|
||||
|
@ -981,7 +1069,7 @@ public class HttpExchange
|
|||
HttpClient httpClient = destination.getHttpClient();
|
||||
long timeout = getTimeout();
|
||||
if (timeout > 0)
|
||||
httpClient.schedule(_timeoutTask, timeout);
|
||||
httpClient.schedule(_timeoutTask,timeout);
|
||||
else
|
||||
httpClient.schedule(_timeoutTask);
|
||||
}
|
||||
|
@ -1045,7 +1133,7 @@ public class HttpExchange
|
|||
}
|
||||
finally
|
||||
{
|
||||
synchronized(HttpExchange.this)
|
||||
synchronized (HttpExchange.this)
|
||||
{
|
||||
_onRequestCompleteDone = true;
|
||||
// Member _onDone may already be true, for example
|
||||
|
@ -1066,7 +1154,7 @@ public class HttpExchange
|
|||
}
|
||||
finally
|
||||
{
|
||||
synchronized(HttpExchange.this)
|
||||
synchronized (HttpExchange.this)
|
||||
{
|
||||
_onResponseCompleteDone = true;
|
||||
// Member _onDone may already be true, for example
|
||||
|
@ -1101,7 +1189,7 @@ public class HttpExchange
|
|||
|
||||
public void onRetry()
|
||||
{
|
||||
HttpExchange.this.setRetryStatus( true );
|
||||
HttpExchange.this.setRetryStatus(true);
|
||||
try
|
||||
{
|
||||
HttpExchange.this.onRetry();
|
||||
|
|
|
@ -110,25 +110,49 @@ public class RedirectListener extends HttpEventListenerWrapper
|
|||
if (_location != null)
|
||||
{
|
||||
if (_location.indexOf("://")>0)
|
||||
{
|
||||
_exchange.setURL(_location);
|
||||
}
|
||||
else
|
||||
{
|
||||
_exchange.setRequestURI(_location);
|
||||
}
|
||||
|
||||
// destination may have changed
|
||||
HttpDestination destination=_destination.getHttpClient().getDestination(_exchange.getAddress(),HttpSchemes.HTTPS.equals(String.valueOf(_exchange.getScheme())));
|
||||
|
||||
boolean isHttps = HttpSchemes.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( HttpHeaders.HOST, hostHeader.toString() );
|
||||
|
||||
destination.send(_exchange);
|
||||
}
|
||||
|
||||
|
@ -156,5 +180,28 @@ public class RedirectListener extends HttpEventListenerWrapper
|
|||
|
||||
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 );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,39 +17,37 @@ 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.Arrays;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import javax.net.ssl.SSLContext;
|
||||
import javax.net.ssl.SSLEngine;
|
||||
import javax.net.ssl.SSLSession;
|
||||
|
||||
import org.eclipse.jetty.http.HttpGenerator;
|
||||
import org.eclipse.jetty.http.HttpParser;
|
||||
import org.eclipse.jetty.http.ssl.SslContextFactory;
|
||||
import javax.net.ssl.SSLEngine;
|
||||
|
||||
import org.eclipse.jetty.io.AsyncEndPoint;
|
||||
import org.eclipse.jetty.io.Buffer;
|
||||
import org.eclipse.jetty.io.Buffers;
|
||||
import org.eclipse.jetty.io.Buffers.Type;
|
||||
import org.eclipse.jetty.io.BuffersFactory;
|
||||
import org.eclipse.jetty.io.ConnectedEndPoint;
|
||||
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.SelectChannelEndPoint;
|
||||
import org.eclipse.jetty.io.nio.SelectorManager;
|
||||
import org.eclipse.jetty.io.nio.SslSelectChannelEndPoint;
|
||||
import org.eclipse.jetty.io.nio.SslConnection;
|
||||
import org.eclipse.jetty.util.component.AbstractLifeCycle;
|
||||
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 AbstractLifeCycle implements HttpClient.Connector
|
||||
class SelectConnector extends AbstractLifeCycle implements HttpClient.Connector, Dumpable
|
||||
{
|
||||
private static final Logger LOG = Log.getLogger(SelectConnector.class);
|
||||
|
||||
private final HttpClient _httpClient;
|
||||
private final Manager _selectorManager=new Manager();
|
||||
private final Map<SocketChannel, Timeout.Task> _connectingChannels = new ConcurrentHashMap<SocketChannel, Timeout.Task>();
|
||||
private SSLContext _sslContext;
|
||||
private Buffers _sslBuffers;
|
||||
|
||||
/**
|
||||
* @param httpClient the HttpClient this connector is associated to
|
||||
|
@ -65,16 +63,6 @@ class SelectConnector extends AbstractLifeCycle implements HttpClient.Connector
|
|||
{
|
||||
super.doStart();
|
||||
|
||||
|
||||
final boolean direct=_httpClient.getUseDirectBuffers();
|
||||
|
||||
SSLEngine sslEngine=_selectorManager.newSslEngine(null);
|
||||
final SSLSession ssl_session=sslEngine.getSession();
|
||||
_sslBuffers = BuffersFactory.newBuffers(
|
||||
direct?Type.DIRECT:Type.INDIRECT,ssl_session.getApplicationBufferSize(),
|
||||
direct?Type.DIRECT:Type.INDIRECT,ssl_session.getApplicationBufferSize(),
|
||||
direct?Type.DIRECT:Type.INDIRECT,1024);
|
||||
|
||||
_selectorManager.start();
|
||||
}
|
||||
|
||||
|
@ -85,35 +73,54 @@ class SelectConnector extends AbstractLifeCycle implements HttpClient.Connector
|
|||
_selectorManager.stop();
|
||||
}
|
||||
|
||||
public String dump()
|
||||
{
|
||||
return AggregateLifeCycle.dump(this);
|
||||
}
|
||||
|
||||
public void dump(Appendable out, String indent) throws IOException
|
||||
{
|
||||
out.append(String.valueOf(this)).append("\n");
|
||||
AggregateLifeCycle.dump(out, indent, Arrays.asList(_selectorManager));
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public void startConnection( HttpDestination destination )
|
||||
throws IOException
|
||||
{
|
||||
SocketChannel channel = null;
|
||||
try
|
||||
{
|
||||
SocketChannel channel = SocketChannel.open();
|
||||
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 );
|
||||
channel.socket().connect(address.toSocketAddress(), _httpClient.getConnectTimeout());
|
||||
channel.configureBlocking(false);
|
||||
_selectorManager.register( channel, destination );
|
||||
}
|
||||
else
|
||||
{
|
||||
channel.configureBlocking( false );
|
||||
channel.configureBlocking(false);
|
||||
channel.connect(address.toSocketAddress());
|
||||
_selectorManager.register( channel, destination );
|
||||
ConnectTimeout connectTimeout = new ConnectTimeout(channel, destination);
|
||||
_selectorManager.register(channel,destination);
|
||||
ConnectTimeout connectTimeout = new ConnectTimeout(channel,destination);
|
||||
_httpClient.schedule(connectTimeout,_httpClient.getConnectTimeout());
|
||||
_connectingChannels.put(channel, connectTimeout);
|
||||
_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);
|
||||
}
|
||||
}
|
||||
|
@ -121,6 +128,8 @@ class SelectConnector extends AbstractLifeCycle implements HttpClient.Connector
|
|||
/* ------------------------------------------------------------ */
|
||||
class Manager extends SelectorManager
|
||||
{
|
||||
Logger LOG = SelectConnector.LOG;
|
||||
|
||||
@Override
|
||||
public boolean dispatch(Runnable task)
|
||||
{
|
||||
|
@ -143,12 +152,9 @@ class SelectConnector extends AbstractLifeCycle implements HttpClient.Connector
|
|||
}
|
||||
|
||||
@Override
|
||||
protected Connection newConnection(SocketChannel channel, SelectChannelEndPoint endpoint)
|
||||
public AsyncConnection newConnection(SocketChannel channel, AsyncEndPoint endpoint, Object attachment)
|
||||
{
|
||||
if (endpoint instanceof SslSelectChannelEndPoint)
|
||||
return new HttpConnection(_sslBuffers,_sslBuffers,endpoint);
|
||||
|
||||
return new HttpConnection(_httpClient.getRequestBuffers(),_httpClient.getResponseBuffers(),endpoint);
|
||||
return new AsyncHttpConnection(_httpClient.getRequestBuffers(),_httpClient.getResponseBuffers(),endpoint);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -158,55 +164,48 @@ class SelectConnector extends AbstractLifeCycle implements HttpClient.Connector
|
|||
Timeout.Task connectTimeout = _connectingChannels.remove(channel);
|
||||
if (connectTimeout != null)
|
||||
connectTimeout.cancel();
|
||||
LOG.debug("Channels with connection pending: {}", _connectingChannels.size());
|
||||
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 ep=null;
|
||||
SelectChannelEndPoint scep = new SelectChannelEndPoint(channel, selectSet, key, (int)_httpClient.getIdleTimeout());
|
||||
AsyncEndPoint ep = scep;
|
||||
|
||||
if (dest.isSecure())
|
||||
{
|
||||
if (dest.isProxied())
|
||||
{
|
||||
SSLEngine engine=newSslEngine(channel);
|
||||
ep = new ProxySelectChannelEndPoint(channel, selectSet, key, _sslBuffers, engine, (int)_httpClient.getIdleTimeout());
|
||||
}
|
||||
else
|
||||
{
|
||||
SSLEngine engine=newSslEngine(channel);
|
||||
SslSelectChannelEndPoint sslEp = new SslSelectChannelEndPoint(_sslBuffers, channel, selectSet, key, engine, (int)_httpClient.getIdleTimeout());
|
||||
sslEp.setAllowRenegotiate(_httpClient.getSslContextFactory().isAllowRenegotiate());
|
||||
ep = sslEp;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ep = new SelectChannelEndPoint(channel, selectSet, key, (int)_httpClient.getIdleTimeout());
|
||||
LOG.debug("secure to {}, proxied={}",channel,dest.isProxied());
|
||||
ep = new UpgradableEndPoint(ep,newSslEngine(channel));
|
||||
}
|
||||
|
||||
HttpConnection connection=(HttpConnection)ep.getConnection();
|
||||
connection.setDestination(dest);
|
||||
dest.onNewConnection(connection);
|
||||
return ep;
|
||||
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();
|
||||
if (_sslContext == null)
|
||||
_sslContext = sslContextFactory.getSslContext();
|
||||
|
||||
SSLEngine sslEngine;
|
||||
if (channel != null && sslContextFactory.isSessionCachingEnabled())
|
||||
if (channel != null)
|
||||
{
|
||||
String peerHost = channel.socket().getInetAddress().getHostAddress();
|
||||
int peerPort = channel.socket().getPort();
|
||||
sslEngine = _sslContext.createSSLEngine(peerHost, peerPort);
|
||||
sslEngine = sslContextFactory.newSslEngine(peerHost, peerPort);
|
||||
}
|
||||
else
|
||||
{
|
||||
sslEngine = _sslContext.createSSLEngine();
|
||||
sslEngine = sslContextFactory.newSslEngine();
|
||||
}
|
||||
sslEngine.setUseClientMode(true);
|
||||
sslEngine.beginHandshake();
|
||||
|
@ -221,6 +220,10 @@ class SelectConnector extends AbstractLifeCycle implements HttpClient.Connector
|
|||
@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
|
||||
|
@ -259,203 +262,200 @@ class SelectConnector extends AbstractLifeCycle implements HttpClient.Connector
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An endpoint that is able to "upgrade" from a normal endpoint to a SSL endpoint.
|
||||
* Since {@link HttpParser} and {@link HttpGenerator} only depend on the {@link EndPoint}
|
||||
* interface, this class overrides all methods of {@link EndPoint} to provide the right
|
||||
* behavior depending on the fact that it has been upgraded or not.
|
||||
*/
|
||||
public static class ProxySelectChannelEndPoint extends SslSelectChannelEndPoint
|
||||
public static class UpgradableEndPoint implements AsyncEndPoint
|
||||
{
|
||||
private final SelectChannelEndPoint plainEndPoint;
|
||||
private volatile boolean upgraded = false;
|
||||
AsyncEndPoint _endp;
|
||||
SSLEngine _engine;
|
||||
|
||||
public ProxySelectChannelEndPoint(SocketChannel channel, SelectorManager.SelectSet selectSet, SelectionKey key, Buffers sslBuffers, SSLEngine engine, int maxIdleTimeout) throws IOException
|
||||
public UpgradableEndPoint(AsyncEndPoint endp, SSLEngine engine) throws IOException
|
||||
{
|
||||
super(sslBuffers, channel, selectSet, key, engine, maxIdleTimeout);
|
||||
this.plainEndPoint = new SelectChannelEndPoint(channel, selectSet, key, maxIdleTimeout);
|
||||
_engine=engine;
|
||||
_endp=endp;
|
||||
}
|
||||
|
||||
public void upgrade()
|
||||
{
|
||||
upgraded = true;
|
||||
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
|
||||
{
|
||||
if (upgraded)
|
||||
super.shutdownOutput();
|
||||
else
|
||||
plainEndPoint.shutdownOutput();
|
||||
_endp.shutdownOutput();
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
if (upgraded)
|
||||
super.close();
|
||||
else
|
||||
plainEndPoint.close();
|
||||
_endp.close();
|
||||
}
|
||||
|
||||
public int fill(Buffer buffer) throws IOException
|
||||
{
|
||||
if (upgraded)
|
||||
return super.fill(buffer);
|
||||
else
|
||||
return plainEndPoint.fill(buffer);
|
||||
return _endp.fill(buffer);
|
||||
}
|
||||
|
||||
public boolean isWritable()
|
||||
{
|
||||
return _endp.isWritable();
|
||||
}
|
||||
|
||||
public boolean hasProgressed()
|
||||
{
|
||||
return _endp.hasProgressed();
|
||||
}
|
||||
|
||||
public int flush(Buffer buffer) throws IOException
|
||||
{
|
||||
if (upgraded)
|
||||
return super.flush(buffer);
|
||||
else
|
||||
return plainEndPoint.flush(buffer);
|
||||
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(Buffer header, Buffer buffer, Buffer trailer) throws IOException
|
||||
{
|
||||
if (upgraded)
|
||||
return super.flush(header, buffer, trailer);
|
||||
else
|
||||
return plainEndPoint.flush(header, buffer, trailer);
|
||||
return _endp.flush(header,buffer,trailer);
|
||||
}
|
||||
|
||||
public String getLocalAddr()
|
||||
{
|
||||
if (upgraded)
|
||||
return super.getLocalAddr();
|
||||
else
|
||||
return plainEndPoint.getLocalAddr();
|
||||
return _endp.getLocalAddr();
|
||||
}
|
||||
|
||||
public String getLocalHost()
|
||||
{
|
||||
if (upgraded)
|
||||
return super.getLocalHost();
|
||||
else
|
||||
return plainEndPoint.getLocalHost();
|
||||
return _endp.getLocalHost();
|
||||
}
|
||||
|
||||
public int getLocalPort()
|
||||
{
|
||||
if (upgraded)
|
||||
return super.getLocalPort();
|
||||
else
|
||||
return plainEndPoint.getLocalPort();
|
||||
return _endp.getLocalPort();
|
||||
}
|
||||
|
||||
public String getRemoteAddr()
|
||||
{
|
||||
if (upgraded)
|
||||
return super.getRemoteAddr();
|
||||
else
|
||||
return plainEndPoint.getRemoteAddr();
|
||||
return _endp.getRemoteAddr();
|
||||
}
|
||||
|
||||
public String getRemoteHost()
|
||||
{
|
||||
if (upgraded)
|
||||
return super.getRemoteHost();
|
||||
else
|
||||
return plainEndPoint.getRemoteHost();
|
||||
return _endp.getRemoteHost();
|
||||
}
|
||||
|
||||
public int getRemotePort()
|
||||
{
|
||||
if (upgraded)
|
||||
return super.getRemotePort();
|
||||
else
|
||||
return plainEndPoint.getRemotePort();
|
||||
return _endp.getRemotePort();
|
||||
}
|
||||
|
||||
public boolean isBlocking()
|
||||
{
|
||||
if (upgraded)
|
||||
return super.isBlocking();
|
||||
else
|
||||
return plainEndPoint.isBlocking();
|
||||
}
|
||||
|
||||
public boolean isBufferred()
|
||||
{
|
||||
if (upgraded)
|
||||
return super.isBufferred();
|
||||
else
|
||||
return plainEndPoint.isBufferred();
|
||||
return _endp.isBlocking();
|
||||
}
|
||||
|
||||
public boolean blockReadable(long millisecs) throws IOException
|
||||
{
|
||||
if (upgraded)
|
||||
return super.blockReadable(millisecs);
|
||||
else
|
||||
return plainEndPoint.blockReadable(millisecs);
|
||||
return _endp.blockReadable(millisecs);
|
||||
}
|
||||
|
||||
public boolean blockWritable(long millisecs) throws IOException
|
||||
{
|
||||
if (upgraded)
|
||||
return super.blockWritable(millisecs);
|
||||
else
|
||||
return plainEndPoint.blockWritable(millisecs);
|
||||
return _endp.blockWritable(millisecs);
|
||||
}
|
||||
|
||||
public boolean isOpen()
|
||||
{
|
||||
if (upgraded)
|
||||
return super.isOpen();
|
||||
else
|
||||
return plainEndPoint.isOpen();
|
||||
return _endp.isOpen();
|
||||
}
|
||||
|
||||
public Object getTransport()
|
||||
{
|
||||
if (upgraded)
|
||||
return super.getTransport();
|
||||
else
|
||||
return plainEndPoint.getTransport();
|
||||
}
|
||||
|
||||
public boolean isBufferingInput()
|
||||
{
|
||||
if (upgraded)
|
||||
return super.isBufferingInput();
|
||||
else
|
||||
return plainEndPoint.isBufferingInput();
|
||||
}
|
||||
|
||||
public boolean isBufferingOutput()
|
||||
{
|
||||
if (upgraded)
|
||||
return super.isBufferingOutput();
|
||||
else
|
||||
return plainEndPoint.isBufferingOutput();
|
||||
return _endp.getTransport();
|
||||
}
|
||||
|
||||
public void flush() throws IOException
|
||||
{
|
||||
if (upgraded)
|
||||
super.flush();
|
||||
else
|
||||
plainEndPoint.flush();
|
||||
|
||||
_endp.flush();
|
||||
}
|
||||
|
||||
public int getMaxIdleTime()
|
||||
{
|
||||
if (upgraded)
|
||||
return super.getMaxIdleTime();
|
||||
else
|
||||
return plainEndPoint.getMaxIdleTime();
|
||||
return _endp.getMaxIdleTime();
|
||||
}
|
||||
|
||||
public void setMaxIdleTime(int timeMs) throws IOException
|
||||
{
|
||||
if (upgraded)
|
||||
super.setMaxIdleTime(timeMs);
|
||||
else
|
||||
plainEndPoint.setMaxIdleTime(timeMs);
|
||||
_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();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,7 +17,6 @@ import java.io.InterruptedIOException;
|
|||
import java.net.Socket;
|
||||
|
||||
import javax.net.SocketFactory;
|
||||
import javax.net.ssl.SSLContext;
|
||||
|
||||
import org.eclipse.jetty.io.Connection;
|
||||
import org.eclipse.jetty.io.EndPoint;
|
||||
|
@ -45,18 +44,9 @@ class SocketConnector extends AbstractLifeCycle implements HttpClient.Connector
|
|||
|
||||
public void startConnection(final HttpDestination destination) throws IOException
|
||||
{
|
||||
Socket socket=null;
|
||||
|
||||
if ( destination.isSecure() )
|
||||
{
|
||||
SSLContext sslContext = _httpClient.getSSLContext();
|
||||
socket = sslContext.getSocketFactory().createSocket();
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG.debug("Using Regular Socket");
|
||||
socket = SocketFactory.getDefault().createSocket();
|
||||
}
|
||||
Socket socket= destination.isSecure()
|
||||
?_httpClient.getSslContextFactory().newSslSocket()
|
||||
:SocketFactory.getDefault().createSocket();
|
||||
|
||||
socket.setSoTimeout(0);
|
||||
socket.setTcpNoDelay(true);
|
||||
|
@ -64,9 +54,9 @@ class SocketConnector extends AbstractLifeCycle implements HttpClient.Connector
|
|||
Address address = destination.isProxied() ? destination.getProxy() : destination.getAddress();
|
||||
socket.connect(address.toSocketAddress(), _httpClient.getConnectTimeout());
|
||||
|
||||
EndPoint endpoint=new SocketEndPoint(socket);
|
||||
final EndPoint endpoint=new SocketEndPoint(socket);
|
||||
|
||||
final HttpConnection connection=new HttpConnection(_httpClient.getRequestBuffers(),_httpClient.getResponseBuffers(),endpoint);
|
||||
final AbstractHttpConnection connection=new BlockingHttpConnection(_httpClient.getRequestBuffers(),_httpClient.getResponseBuffers(),endpoint);
|
||||
connection.setDestination(destination);
|
||||
destination.onNewConnection(connection);
|
||||
_httpClient.getThreadPool().dispatch(new Runnable()
|
||||
|
@ -97,6 +87,17 @@ class SocketConnector extends AbstractLifeCycle implements HttpClient.Connector
|
|||
destination.onException(e);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
try
|
||||
{
|
||||
destination.returnConnection(connection,true);
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
LOG.debug(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
@ -17,6 +17,10 @@ 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;
|
||||
|
@ -37,6 +41,14 @@ public abstract class AbstractConnectionTest
|
|||
// 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
|
||||
|
@ -57,6 +69,19 @@ public abstract class AbstractConnectionTest
|
|||
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"));
|
||||
|
@ -80,6 +105,15 @@ public abstract class AbstractConnectionTest
|
|||
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"));
|
||||
|
@ -94,6 +128,112 @@ public abstract class AbstractConnectionTest
|
|||
}
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
|
@ -222,27 +362,33 @@ public abstract class AbstractConnectionTest
|
|||
HttpDestination dest = httpClient.getDestination(new Address("localhost", port),false);
|
||||
|
||||
httpClient.send(exchange);
|
||||
Socket s = serverSocket.accept();
|
||||
Socket server = serverSocket.accept();
|
||||
server.setSoTimeout(5000);
|
||||
byte[] buf = new byte[4096];
|
||||
s.getInputStream().read(buf);
|
||||
|
||||
int len=server.getInputStream().read(buf);
|
||||
assertEquals(1,dest.getConnections());
|
||||
assertEquals(0,dest.getIdleConnections());
|
||||
|
||||
s.getOutputStream().write("HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n".getBytes());
|
||||
|
||||
Thread.sleep(300);
|
||||
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);
|
||||
s.getInputStream().read(buf);
|
||||
assertEquals(1,dest.getConnections());
|
||||
assertEquals(0,dest.getIdleConnections());
|
||||
s.getOutputStream().write("HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n".getBytes());
|
||||
|
||||
|
||||
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);
|
||||
|
||||
|
@ -262,16 +408,16 @@ public abstract class AbstractConnectionTest
|
|||
}
|
||||
}
|
||||
|
||||
private class ConnectionExchange extends HttpExchange
|
||||
protected class ConnectionExchange extends HttpExchange
|
||||
{
|
||||
private final CountDownLatch latch;
|
||||
|
||||
private ConnectionExchange()
|
||||
protected ConnectionExchange()
|
||||
{
|
||||
this.latch = null;
|
||||
}
|
||||
|
||||
private ConnectionExchange(CountDownLatch latch)
|
||||
protected ConnectionExchange(CountDownLatch latch)
|
||||
{
|
||||
this.latch = latch;
|
||||
}
|
||||
|
|
|
@ -14,39 +14,37 @@
|
|||
|
||||
package org.eclipse.jetty.client;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
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.io.Buffer;
|
||||
import org.eclipse.jetty.server.AbstractHttpConnection;
|
||||
import org.eclipse.jetty.server.Connector;
|
||||
import org.eclipse.jetty.server.HttpConnection;
|
||||
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.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;
|
||||
|
||||
/**
|
||||
* @version $Revision$ $Date$
|
||||
*/
|
||||
public abstract class AbstractHttpExchangeCancelTest
|
||||
{
|
||||
private static final Logger LOG = Log.getLogger(AbstractHttpExchangeCancelTest.class);
|
||||
|
||||
private Server server;
|
||||
private Connector connector;
|
||||
|
||||
|
@ -78,13 +76,13 @@ public abstract class AbstractHttpExchangeCancelTest
|
|||
TestHttpExchange exchange = new TestHttpExchange()
|
||||
{
|
||||
@Override
|
||||
void setStatus(int status)
|
||||
boolean setStatus(int status)
|
||||
{
|
||||
// Cancel before setting the new status
|
||||
if (getStatus() == HttpExchange.STATUS_START &&
|
||||
status == STATUS_WAITING_FOR_CONNECTION)
|
||||
cancel();
|
||||
super.setStatus(status);
|
||||
return super.setStatus(status);
|
||||
}
|
||||
};
|
||||
exchange.setAddress(newAddress());
|
||||
|
@ -115,14 +113,15 @@ public abstract class AbstractHttpExchangeCancelTest
|
|||
TestHttpExchange exchange = new TestHttpExchange()
|
||||
{
|
||||
@Override
|
||||
void setStatus(int status)
|
||||
boolean setStatus(int status)
|
||||
{
|
||||
// Cancel after setting the new status
|
||||
int oldStatus = getStatus();
|
||||
super.setStatus(status);
|
||||
boolean set = super.setStatus(status);
|
||||
if (oldStatus == STATUS_START &&
|
||||
getStatus() == HttpExchange.STATUS_WAITING_FOR_CONNECTION)
|
||||
cancel();
|
||||
return set;
|
||||
}
|
||||
};
|
||||
exchange.setAddress(newAddress());
|
||||
|
@ -186,10 +185,10 @@ public abstract class AbstractHttpExchangeCancelTest
|
|||
getHttpClient().send(exchange);
|
||||
|
||||
int status = exchange.waitForDone();
|
||||
assertEquals(HttpExchange.STATUS_CANCELLED, status);
|
||||
assertFalse(exchange.isResponseCompleted());
|
||||
assertFalse(exchange.isFailed());
|
||||
assertFalse(exchange.isAssociated());
|
||||
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));
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
@ -323,7 +322,7 @@ public abstract class AbstractHttpExchangeCancelTest
|
|||
{
|
||||
try
|
||||
{
|
||||
((StdErrLog)Log.getLogger(HttpConnection.class)).setHideStacks(true);
|
||||
((StdErrLog)Log.getLogger(AbstractHttpConnection.class)).setHideStacks(true);
|
||||
TestHttpExchange exchange = new TestHttpExchange();
|
||||
exchange.setAddress(newAddress());
|
||||
exchange.setRequestURI("/?action=throw");
|
||||
|
@ -338,7 +337,7 @@ public abstract class AbstractHttpExchangeCancelTest
|
|||
}
|
||||
finally
|
||||
{
|
||||
((StdErrLog)Log.getLogger(HttpConnection.class)).setHideStacks(false);
|
||||
((StdErrLog)Log.getLogger(AbstractHttpConnection.class)).setHideStacks(false);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -360,7 +359,7 @@ public abstract class AbstractHttpExchangeCancelTest
|
|||
|
||||
int status = exchange.waitForDone();
|
||||
long end = System.currentTimeMillis();
|
||||
|
||||
|
||||
assertTrue(HttpExchange.STATUS_EXPIRED==status||HttpExchange.STATUS_EXCEPTED==status);
|
||||
assertFalse(exchange.isResponseCompleted());
|
||||
assertTrue(end-start<4000);
|
||||
|
@ -369,6 +368,26 @@ public abstract class AbstractHttpExchangeCancelTest
|
|||
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();
|
||||
|
||||
|
@ -447,6 +466,7 @@ public abstract class AbstractHttpExchangeCancelTest
|
|||
@Override
|
||||
protected synchronized void onException(Throwable ex)
|
||||
{
|
||||
LOG.debug(ex);
|
||||
if (ex instanceof SocketTimeoutException ||
|
||||
ex.getCause() instanceof SocketTimeoutException)
|
||||
expired=true;
|
||||
|
|
|
@ -13,6 +13,13 @@
|
|||
|
||||
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()
|
||||
|
@ -22,4 +29,40 @@ public class AsyncSelectConnectionTest extends AbstractConnectionTest
|
|||
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();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -13,19 +13,36 @@
|
|||
|
||||
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
|
||||
{
|
||||
@Override
|
||||
public void setUp() throws Exception
|
||||
private static ServerAndClientCreator serverAndClientCreator = new AsyncSslServerAndClientCreator();
|
||||
|
||||
@Before
|
||||
public void setUpOnce() throws Exception
|
||||
{
|
||||
_scheme="https";
|
||||
startServer();
|
||||
_httpClient=new HttpClient();
|
||||
_httpClient.setIdleTimeout(2000);
|
||||
_httpClient.setTimeout(2500);
|
||||
_httpClient.setConnectTimeout(1000);
|
||||
_httpClient.setConnectorType(HttpClient.CONNECTOR_SELECT_CHANNEL);
|
||||
_httpClient.setMaxConnectionsPerAddress(2);
|
||||
_httpClient.start();
|
||||
_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();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -33,11 +33,26 @@ public class Curl
|
|||
client.start();
|
||||
boolean async=true;
|
||||
boolean dump= false;
|
||||
boolean verbose= false;
|
||||
|
||||
final CountDownLatch latch = new CountDownLatch(args.length);
|
||||
|
||||
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;
|
||||
|
@ -63,6 +78,7 @@ public class Curl
|
|||
}
|
||||
|
||||
final boolean d = dump;
|
||||
final boolean v = verbose;
|
||||
HttpExchange ex = new HttpExchange()
|
||||
{
|
||||
AtomicBoolean counted=new AtomicBoolean(false);
|
||||
|
@ -105,7 +121,8 @@ public class Curl
|
|||
super.onResponseContent(content);
|
||||
if (d)
|
||||
System.out.print(content.toString());
|
||||
System.err.println("got "+content.length());
|
||||
if (v)
|
||||
System.err.println("got "+content.length());
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
@ -116,7 +133,8 @@ public class Curl
|
|||
protected void onResponseHeader(Buffer name, Buffer value) throws IOException
|
||||
{
|
||||
super.onResponseHeader(name,value);
|
||||
System.err.println(name+": "+value);
|
||||
if (v)
|
||||
System.err.println(name+": "+value);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
@ -127,7 +145,8 @@ public class Curl
|
|||
protected void onResponseHeaderComplete() throws IOException
|
||||
{
|
||||
super.onResponseHeaderComplete();
|
||||
System.err.println();
|
||||
if (v)
|
||||
System.err.println();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
@ -138,7 +157,8 @@ public class Curl
|
|||
protected void onResponseStatus(Buffer version, int status, Buffer reason) throws IOException
|
||||
{
|
||||
super.onResponseStatus(version,status,reason);
|
||||
System.err.println(version+" "+status+" "+reason);
|
||||
if (v)
|
||||
System.err.println(version+" "+status+" "+reason);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -13,35 +13,20 @@
|
|||
|
||||
package org.eclipse.jetty.client;
|
||||
|
||||
import java.io.FileInputStream;
|
||||
|
||||
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
|
||||
import org.junit.Test;
|
||||
import org.eclipse.jetty.client.helperClasses.ExternalKeyStoreAsyncSslServerAndClientCreator;
|
||||
import org.eclipse.jetty.client.helperClasses.ServerAndClientCreator;
|
||||
import org.junit.Before;
|
||||
|
||||
public class ExternalKeyStoreAsyncSslHttpExchangeTest extends SslHttpExchangeTest
|
||||
{
|
||||
@Override
|
||||
public void setUp() throws Exception
|
||||
private static ServerAndClientCreator serverAndClientCreator = new ExternalKeyStoreAsyncSslServerAndClientCreator();
|
||||
|
||||
@Before
|
||||
public void setUpOnce() throws Exception
|
||||
{
|
||||
_scheme = "https";
|
||||
startServer();
|
||||
_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();
|
||||
_scheme="https";
|
||||
_server = serverAndClientCreator.createServer();
|
||||
_httpClient = serverAndClientCreator.createClient(3000L,3500L,2000);
|
||||
_port = _server.getConnectors()[0].getLocalPort();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Test
|
||||
public void testBigPostWithContentExchange() throws Exception
|
||||
{
|
||||
super.testBigPostWithContentExchange();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
package org.eclipse.jetty.client;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.jetty.http.HttpFields;
|
||||
import org.junit.Assert;
|
||||
|
||||
public final class HttpAsserts
|
||||
{
|
||||
public static void assertContainsHeaderKey(String expectedKey, HttpFields headers)
|
||||
{
|
||||
if (headers.containsKey(expectedKey))
|
||||
{
|
||||
return;
|
||||
}
|
||||
List<String> names = Collections.list(headers.getFieldNames());
|
||||
StringBuilder err = new StringBuilder();
|
||||
err.append("Missing expected header key [").append(expectedKey);
|
||||
err.append("] (of ").append(names.size()).append(" header fields)");
|
||||
for (int i = 0; i < names.size(); i++)
|
||||
{
|
||||
String value = headers.getStringField(names.get(i));
|
||||
err.append("\n").append(i).append("] ").append(names.get(i));
|
||||
err.append(": ").append(value);
|
||||
}
|
||||
Assert.fail(err.toString());
|
||||
}
|
||||
}
|
|
@ -20,7 +20,6 @@ import static org.junit.Assert.assertThat;
|
|||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.matchers.JUnitMatchers.containsString;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
|
@ -30,13 +29,10 @@ 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;
|
||||
|
||||
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.HttpHeaders;
|
||||
import org.eclipse.jetty.http.HttpMethods;
|
||||
import org.eclipse.jetty.http.HttpStatus;
|
||||
import org.eclipse.jetty.io.Buffer;
|
||||
|
@ -44,15 +40,9 @@ 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.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.toolchain.test.Stress;
|
||||
import org.eclipse.jetty.util.IO;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
import org.eclipse.jetty.util.component.AbstractLifeCycle;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
@ -63,37 +53,44 @@ import org.junit.Test;
|
|||
*/
|
||||
public class HttpExchangeTest
|
||||
{
|
||||
private static final Logger LOG = Log.getLogger(HttpExchangeTest.class);
|
||||
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 int _maxConnectionsPerAddress = 2;
|
||||
protected String _scheme = "http";
|
||||
protected Server _server;
|
||||
protected int _port;
|
||||
protected HttpClient _httpClient;
|
||||
protected Connector _connector;
|
||||
protected AtomicInteger _count = new AtomicInteger();
|
||||
protected static URI getBaseURI()
|
||||
{
|
||||
return URI.create(_scheme + "://localhost:" + _port + "/");
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
// TODO work out why BeforeClass does not work here?
|
||||
@Before
|
||||
public void setUp() throws Exception
|
||||
public void setUpOnce() throws Exception
|
||||
{
|
||||
startServer();
|
||||
_httpClient=new HttpClient();
|
||||
_httpClient.setIdleTimeout(3000);
|
||||
_httpClient.setTimeout(3500);
|
||||
_httpClient.setConnectTimeout(2000);
|
||||
_httpClient.setConnectorType(HttpClient.CONNECTOR_SELECT_CHANNEL);
|
||||
_httpClient.setMaxConnectionsPerAddress(_maxConnectionsPerAddress);
|
||||
_httpClient.start();
|
||||
_scheme = "http";
|
||||
_server = serverAndClientCreator.createServer();
|
||||
_httpClient = serverAndClientCreator.createClient(3000L,3500L,2000);
|
||||
_port = _server.getConnectors()[0].getLocalPort();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@After
|
||||
public void tearDown() throws Exception
|
||||
public void tearDownOnce() throws Exception
|
||||
{
|
||||
_httpClient.stop();
|
||||
Thread.sleep(500);
|
||||
stopServer();
|
||||
long startTime = System.currentTimeMillis();
|
||||
while (!_httpClient.getState().equals(AbstractLifeCycle.STOPPED))
|
||||
{
|
||||
if (System.currentTimeMillis() - startTime > 1000)
|
||||
break;
|
||||
Thread.sleep(5);
|
||||
}
|
||||
_server.stop();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
@ -110,7 +107,9 @@ public class HttpExchangeTest
|
|||
{
|
||||
sender(1,false);
|
||||
sender(1,true);
|
||||
|
||||
sender(10,false);
|
||||
sender(10,true);
|
||||
|
||||
if (Stress.isEnabled())
|
||||
{
|
||||
sender(100,false);
|
||||
|
@ -118,11 +117,6 @@ public class HttpExchangeTest
|
|||
sender(10000,false);
|
||||
sender(10000,true);
|
||||
}
|
||||
else
|
||||
{
|
||||
sender(10,false);
|
||||
sender(10,true);
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
@ -131,54 +125,65 @@ public class HttpExchangeTest
|
|||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
public void sender(final int nb,final boolean close) throws Exception
|
||||
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 CountDownLatch latch=new CountDownLatch(nb);
|
||||
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++)
|
||||
long start = System.currentTimeMillis();
|
||||
for (int i = 0; i < nb; i++)
|
||||
{
|
||||
final int n=i;
|
||||
final int n = i;
|
||||
|
||||
httpExchange[n]=new HttpExchange()
|
||||
httpExchange[n] = new HttpExchange()
|
||||
{
|
||||
String result="pending";
|
||||
int len=0;
|
||||
String result = "pending";
|
||||
int len = 0;
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
protected void onRequestCommitted()
|
||||
{
|
||||
result="committed";
|
||||
if (verbose)
|
||||
System.err.println(n+" [ "+this);
|
||||
result = "committed";
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
protected void onRequestComplete() throws IOException
|
||||
{
|
||||
result="sent";
|
||||
if (verbose)
|
||||
System.err.println(n+" [ ==");
|
||||
result = "sent";
|
||||
}
|
||||
|
||||
@Override
|
||||
/* ------------------------------------------------------------ */
|
||||
protected void onResponseStatus(Buffer version, int status, Buffer reason)
|
||||
{
|
||||
result="status";
|
||||
if (verbose)
|
||||
System.err.println(n+" ] "+version+" "+status+" "+reason);
|
||||
result = "status";
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
protected void onResponseHeader(Buffer name, Buffer value)
|
||||
{
|
||||
if (verbose)
|
||||
System.err.println(n+" ] "+name+": "+value);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
protected void onResponseHeaderComplete() throws IOException
|
||||
{
|
||||
result="content";
|
||||
if (verbose)
|
||||
System.err.println(n+" ] -");
|
||||
result = "content";
|
||||
super.onResponseHeaderComplete();
|
||||
}
|
||||
|
||||
|
@ -186,20 +191,22 @@ public class HttpExchangeTest
|
|||
@Override
|
||||
protected void onResponseContent(Buffer content)
|
||||
{
|
||||
len+=content.length();
|
||||
len += content.length();
|
||||
if (verbose)
|
||||
System.err.println(n+" ] "+content.length()+" -> "+len);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
protected void onResponseComplete()
|
||||
{
|
||||
result="complete";
|
||||
if (len==2009)
|
||||
latch.countDown();
|
||||
if (verbose)
|
||||
System.err.println(n+" ] == "+len+" "+complete.getCount()+"/"+nb);
|
||||
result = "complete";
|
||||
if (len == 2009)
|
||||
allcontent.decrementAndGet();
|
||||
else
|
||||
{
|
||||
System.err.println(n+" ONLY "+len);
|
||||
}
|
||||
System.err.println(n+ " ONLY " + len+ "/2009");
|
||||
complete.countDown();
|
||||
}
|
||||
|
||||
|
@ -207,9 +214,11 @@ public class HttpExchangeTest
|
|||
@Override
|
||||
protected void onConnectionFailed(Throwable ex)
|
||||
{
|
||||
if (verbose)
|
||||
System.err.println(n+" ] "+ex);
|
||||
complete.countDown();
|
||||
result="failed";
|
||||
System.err.println(n+" FAILED "+ex);
|
||||
result = "failed";
|
||||
System.err.println(n+ " FAILED " + ex);
|
||||
super.onConnectionFailed(ex);
|
||||
}
|
||||
|
||||
|
@ -217,9 +226,11 @@ public class HttpExchangeTest
|
|||
@Override
|
||||
protected void onException(Throwable ex)
|
||||
{
|
||||
if (verbose)
|
||||
System.err.println(n+" ] "+ex);
|
||||
complete.countDown();
|
||||
result="excepted";
|
||||
System.err.println(n+" EXCEPTED "+ex);
|
||||
result = "excepted";
|
||||
System.err.println(n+ " EXCEPTED " + ex);
|
||||
super.onException(ex);
|
||||
}
|
||||
|
||||
|
@ -227,9 +238,11 @@ public class HttpExchangeTest
|
|||
@Override
|
||||
protected void onExpire()
|
||||
{
|
||||
if (verbose)
|
||||
System.err.println(n+" ] expired");
|
||||
complete.countDown();
|
||||
result="expired";
|
||||
System.err.println(n+" EXPIRED "+len);
|
||||
result = "expired";
|
||||
System.err.println(n + " EXPIRED " + len);
|
||||
super.onExpire();
|
||||
}
|
||||
|
||||
|
@ -237,11 +250,11 @@ public class HttpExchangeTest
|
|||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return n+" "+result+" "+len;
|
||||
return n+"/"+result+"/"+len+"/"+super.toString();
|
||||
}
|
||||
};
|
||||
|
||||
httpExchange[n].setURL(_scheme+"://localhost:"+_port+"/"+n);
|
||||
httpExchange[n].setURI(getBaseURI().resolve("/" + n));
|
||||
httpExchange[n].addRequestHeader("arbitrary","value");
|
||||
if (close)
|
||||
httpExchange[n].setRequestHeader("Connection","close");
|
||||
|
@ -249,17 +262,12 @@ public class HttpExchangeTest
|
|||
_httpClient.send(httpExchange[n]);
|
||||
}
|
||||
|
||||
assertTrue(complete.await(45,TimeUnit.SECONDS));
|
||||
if (!complete.await(2,TimeUnit.SECONDS))
|
||||
System.err.println(_httpClient.dump());
|
||||
|
||||
long elapsed=System.currentTimeMillis()-start;
|
||||
|
||||
// make windows-friendly ... System.currentTimeMillis() on windows is dope!
|
||||
/*
|
||||
if(elapsed>0)
|
||||
System.err.println(nb+"/"+_count+" c="+close+" rate="+(nb*1000/elapsed));
|
||||
*/
|
||||
|
||||
assertEquals("nb="+nb+" close="+close,0,latch.getCount());
|
||||
assertTrue(complete.await(20,TimeUnit.SECONDS));
|
||||
|
||||
assertEquals("nb="+nb+" close="+close,0,allcontent.get());
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
@ -269,7 +277,7 @@ public class HttpExchangeTest
|
|||
for (int i=0;i<20;i++)
|
||||
{
|
||||
ContentExchange httpExchange=new ContentExchange();
|
||||
httpExchange.setURI(new URI(_scheme, null, "localhost", _port, null, null, null));
|
||||
httpExchange.setURI(getBaseURI());
|
||||
httpExchange.setMethod(HttpMethods.POST);
|
||||
httpExchange.setRequestContent(new ByteArrayBuffer("<hello />"));
|
||||
_httpClient.send(httpExchange);
|
||||
|
@ -288,19 +296,21 @@ public class HttpExchangeTest
|
|||
for (int i=0;i<10;i++)
|
||||
{
|
||||
ContentExchange httpExchange=new ContentExchange();
|
||||
httpExchange.setURI(new URI(_scheme, null, "localhost", _port, "/", "i="+i, null));
|
||||
URI uri = getBaseURI().resolve("?i=" + i);
|
||||
httpExchange.setURI(uri);
|
||||
httpExchange.setMethod(HttpMethods.GET);
|
||||
_httpClient.send(httpExchange);
|
||||
int status = httpExchange.waitForDone();
|
||||
//httpExchange.waitForStatus(HttpExchange.STATUS_COMPLETED);
|
||||
String result=httpExchange.getResponseContent();
|
||||
assertNotNull("Should have received response content", result);
|
||||
assertEquals("i="+i,0,result.indexOf("<hello>"));
|
||||
assertEquals("i="+i,result.length()-10,result.indexOf("</hello>"));
|
||||
assertEquals(HttpExchange.STATUS_COMPLETED, status);
|
||||
Thread.sleep(5);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Test
|
||||
public void testLocalAddressAvailabilityWithContentExchange() throws Exception
|
||||
|
@ -308,30 +318,29 @@ public class HttpExchangeTest
|
|||
for (int i=0;i<10;i++)
|
||||
{
|
||||
ContentExchange httpExchange=new ContentExchange();
|
||||
httpExchange.setURL(_scheme+"://localhost:"+_port+"/?i="+i);
|
||||
URI uri = getBaseURI().resolve("?i=" + i);
|
||||
httpExchange.setURI(uri);
|
||||
httpExchange.setMethod(HttpMethods.GET);
|
||||
_httpClient.send(httpExchange);
|
||||
int status = httpExchange.waitForDone();
|
||||
|
||||
|
||||
assertNotNull(httpExchange.getLocalAddress());
|
||||
|
||||
//System.out.println("Local Address: " + httpExchange.getLocalAddress());
|
||||
|
||||
//httpExchange.waitForStatus(HttpExchange.STATUS_COMPLETED);
|
||||
|
||||
String result=httpExchange.getResponseContent();
|
||||
assertNotNull("Should have received response content", result);
|
||||
assertEquals("i="+i,0,result.indexOf("<hello>"));
|
||||
assertEquals("i="+i,result.length()-10,result.indexOf("</hello>"));
|
||||
assertEquals(HttpExchange.STATUS_COMPLETED, status);
|
||||
Thread.sleep(5);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Test
|
||||
public void testShutdownWithExchange() throws Exception
|
||||
{
|
||||
final AtomicReference<Throwable> throwable=new AtomicReference<Throwable>();
|
||||
|
||||
|
||||
HttpExchange httpExchange=new HttpExchange()
|
||||
{
|
||||
|
||||
|
@ -355,7 +364,7 @@ public class HttpExchangeTest
|
|||
throwable.set(x);
|
||||
}
|
||||
};
|
||||
httpExchange.setURL(_scheme+"://localhost:"+_port+"/");
|
||||
httpExchange.setURI(getBaseURI());
|
||||
httpExchange.setMethod("SLEEP");
|
||||
_httpClient.send(httpExchange);
|
||||
new Thread()
|
||||
|
@ -363,8 +372,8 @@ public class HttpExchangeTest
|
|||
@Override
|
||||
public void run()
|
||||
{
|
||||
try {
|
||||
Thread.sleep(500);
|
||||
try {
|
||||
Thread.sleep(500);
|
||||
_httpClient.stop();
|
||||
} catch(Exception e) {e.printStackTrace();}
|
||||
}
|
||||
|
@ -374,14 +383,62 @@ public class HttpExchangeTest
|
|||
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();
|
||||
ContentExchange httpExchange=new ContentExchange()
|
||||
{
|
||||
int total;
|
||||
|
||||
@Override
|
||||
protected synchronized void onResponseStatus(Buffer version, int status, Buffer reason) throws IOException
|
||||
{
|
||||
if (verbose)
|
||||
System.err.println("] "+version+" "+status+" "+reason);
|
||||
super.onResponseStatus(version,status,reason);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected synchronized void onResponseHeader(Buffer name, Buffer value) throws IOException
|
||||
{
|
||||
if (verbose)
|
||||
System.err.println("] "+name+": "+value);
|
||||
super.onResponseHeader(name,value);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected synchronized void onResponseContent(Buffer 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();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
Buffer babuf = new ByteArrayBuffer(size*36*1024);
|
||||
Buffer niobuf = new DirectNIOBuffer(size*36*1024);
|
||||
|
@ -393,40 +450,67 @@ public class HttpExchangeTest
|
|||
babuf.put(bytes);
|
||||
niobuf.put(bytes);
|
||||
}
|
||||
|
||||
httpExchange.setURL(_scheme+"://localhost:"+_port+"/");
|
||||
|
||||
httpExchange.setURI(getBaseURI());
|
||||
httpExchange.setMethod(HttpMethods.POST);
|
||||
httpExchange.setRequestContentType("application/data");
|
||||
httpExchange.setRequestContent(babuf);
|
||||
|
||||
_httpClient.send(httpExchange);
|
||||
int status = httpExchange.waitForDone();
|
||||
|
||||
long start=System.currentTimeMillis();
|
||||
while(!httpExchange.isDone())
|
||||
{
|
||||
long now=System.currentTimeMillis();
|
||||
if ((now-start)>=10000)
|
||||
{
|
||||
System.err.println("TEST IS TAKING TOOOOO LONG!!!!!!!!!!!!!!!!!!!!");
|
||||
System.err.println("CLIENT:");
|
||||
System.err.println(_httpClient.dump());
|
||||
System.err.println("SERVER:");
|
||||
_server.dumpStdErr();
|
||||
break;
|
||||
}
|
||||
Thread.sleep(100);
|
||||
}
|
||||
int status = httpExchange.waitForDone();
|
||||
assertEquals(HttpExchange.STATUS_COMPLETED,status);
|
||||
String result=httpExchange.getResponseContent();
|
||||
assertEquals(babuf.length(),result.length());
|
||||
|
||||
httpExchange.reset();
|
||||
httpExchange.setURL(_scheme+"://localhost:"+_port+"/");
|
||||
httpExchange.setURI(getBaseURI());
|
||||
httpExchange.setMethod(HttpMethods.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());
|
||||
assertEquals(HttpExchange.STATUS_COMPLETED, status);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Test
|
||||
public void testSlowPost() throws Exception
|
||||
{
|
||||
ContentExchange httpExchange=new ContentExchange()
|
||||
{
|
||||
|
||||
};
|
||||
httpExchange.setURL(_scheme+"://localhost:"+_port);
|
||||
ContentExchange httpExchange=new ContentExchange();
|
||||
httpExchange.setURI(getBaseURI());
|
||||
httpExchange.setMethod(HttpMethods.POST);
|
||||
|
||||
final String data="012345678901234567890123456789012345678901234567890123456789";
|
||||
|
@ -438,16 +522,28 @@ public class HttpExchangeTest
|
|||
@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
|
||||
{
|
||||
if (_index>=data.length())
|
||||
// System.err.printf("reading %d of %d/%d%n",len,_index,data.length());
|
||||
if (_index >= data.length())
|
||||
return -1;
|
||||
|
||||
try
|
||||
|
@ -458,28 +554,27 @@ public class HttpExchangeTest
|
|||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
int l=0;
|
||||
|
||||
while (l<5 && _index<data.length() && l<len)
|
||||
b[off+l++]=(byte)data.charAt(_index++);
|
||||
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);
|
||||
//httpExchange.setRequestContent(new ByteArrayBuffer(data));
|
||||
|
||||
_httpClient.send(httpExchange);
|
||||
|
||||
int status = httpExchange.waitForDone();
|
||||
//httpExchange.waitForStatus(HttpExchange.STATUS_COMPLETED);
|
||||
String result=httpExchange.getResponseContent();
|
||||
assertEquals(HttpExchange.STATUS_COMPLETED, status);
|
||||
String result = httpExchange.getResponseContent();
|
||||
assertEquals(HttpExchange.STATUS_COMPLETED,status);
|
||||
assertEquals(data,result);
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Test
|
||||
public void testProxy() throws Exception
|
||||
|
@ -499,6 +594,7 @@ public class HttpExchangeTest
|
|||
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"));
|
||||
|
@ -515,48 +611,56 @@ public class HttpExchangeTest
|
|||
@Test
|
||||
public void testReserveConnections () throws Exception
|
||||
{
|
||||
final HttpDestination destination = _httpClient.getDestination (new Address("localhost", _port), _scheme.equalsIgnoreCase("https"));
|
||||
final org.eclipse.jetty.client.HttpConnection[] connections = new org.eclipse.jetty.client.HttpConnection[_maxConnectionsPerAddress];
|
||||
for (int i=0; i < _maxConnectionsPerAddress; i++)
|
||||
{
|
||||
connections[i] = destination.reserveConnection(200);
|
||||
assertNotNull(connections[i]);
|
||||
HttpExchange ex = new ContentExchange();
|
||||
ex.setURL(_scheme+"://localhost:"+_port+"/?i="+i);
|
||||
ex.setMethod(HttpMethods.GET);
|
||||
connections[i].send(ex);
|
||||
}
|
||||
_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(HttpMethods.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);
|
||||
// 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);
|
||||
// unreserve first connection
|
||||
destination.returnConnection(connections[0],false);
|
||||
|
||||
//reserving one should now work
|
||||
c = destination.reserveConnection(500);
|
||||
assertNotNull(c);
|
||||
// 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(_scheme+"://localhost:"+_port);
|
||||
httpExchange.setURL(getBaseURI().toASCIIString());
|
||||
httpExchange.setRequestURI("*");
|
||||
httpExchange.setMethod(HttpMethods.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();
|
||||
assertTrue("Response contains Allow header", headers.containsKey("Allow"));
|
||||
|
||||
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" };
|
||||
|
@ -564,9 +668,6 @@ public class HttpExchangeTest
|
|||
{
|
||||
assertThat(allow,containsString(expectedMethod));
|
||||
}
|
||||
|
||||
assertTrue("Response contains Content-Length header", headers.containsKey("Content-Length"));
|
||||
assertEquals("Content-Length header value", 0, headers.getLongField("Content-Length"));
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
@ -574,115 +675,20 @@ public class HttpExchangeTest
|
|||
{
|
||||
try
|
||||
{
|
||||
byte[] buffer=new byte[1024];
|
||||
byte[] buffer = new byte[1024];
|
||||
int len;
|
||||
while ((len=in.read(buffer))>=0)
|
||||
while ((len = in.read(buffer)) >= 0)
|
||||
{
|
||||
out.write(buffer,0,len);
|
||||
}
|
||||
}
|
||||
catch (EofException e)
|
||||
{
|
||||
System.err.println("HttpExchangeTest#copyStream: "+e);
|
||||
System.err.println("HttpExchangeTest#copyStream: " + e);
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
protected void newServer() throws Exception
|
||||
{
|
||||
_server=new Server();
|
||||
_server.setGracefulShutdown(500);
|
||||
_connector=new SelectChannelConnector();
|
||||
|
||||
_connector.setMaxIdleTime(3000000);
|
||||
|
||||
_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.getServerName().equals("jetty.eclipse.org"))
|
||||
{
|
||||
response.getOutputStream().println("Proxy request: "+request.getRequestURL());
|
||||
response.getOutputStream().println(request.getHeader(HttpHeaders.PROXY_AUTHORIZATION));
|
||||
}
|
||||
else if (request.getMethod().equalsIgnoreCase("GET"))
|
||||
{
|
||||
response.getOutputStream().println("<hello>");
|
||||
for (; i<100; i++)
|
||||
{
|
||||
response.getOutputStream().println(" <world>"+i+"</world");
|
||||
if (i%20==0)
|
||||
response.getOutputStream().flush();
|
||||
}
|
||||
response.getOutputStream().println("</hello>");
|
||||
}
|
||||
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(IOException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
throw e;
|
||||
}
|
||||
catch(Throwable e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
throw new ServletException(e);
|
||||
}
|
||||
finally
|
||||
{
|
||||
}
|
||||
}
|
||||
});
|
||||
_server.start();
|
||||
_port=_connector.getLocalPort();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
private void stopServer() throws Exception
|
||||
{
|
||||
_server.stop();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,136 @@
|
|||
// ========================================================================
|
||||
// Copyright (c) 2009-2009 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
|
||||
package org.eclipse.jetty.client;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.ProtocolException;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.eclipse.jetty.http.HttpStatus;
|
||||
import org.eclipse.jetty.server.AbstractHttpConnection;
|
||||
import org.eclipse.jetty.server.Request;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.server.handler.ConnectHandler;
|
||||
import org.eclipse.jetty.server.nio.SelectChannelConnector;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* This UnitTest class executes two tests. Both will send a http request to https://google.com through a misbehaving proxy server.
|
||||
* <p/>
|
||||
* The first test runs against a proxy which simply closes the connection (as nginx does) for a connect request. The second proxy server always responds with a
|
||||
* 500 error.
|
||||
* <p/>
|
||||
* The expected result for both tests is an exception and the HttpExchange should have status HttpExchange.STATUS_EXCEPTED.
|
||||
*/
|
||||
public class HttpsViaBrokenHttpProxyTest
|
||||
{
|
||||
private Server _proxy = new Server();
|
||||
private HttpClient _client = new HttpClient();
|
||||
|
||||
@Before
|
||||
public void init() throws Exception
|
||||
{
|
||||
// setup proxies with different behaviour
|
||||
_proxy.addConnector(new SelectChannelConnector());
|
||||
_proxy.setHandler(new BadBehavingConnectHandler());
|
||||
_proxy.start();
|
||||
int proxyClosingConnectionPort = _proxy.getConnectors()[0].getLocalPort();
|
||||
|
||||
_client.setProxy(new Address("localhost", proxyClosingConnectionPort));
|
||||
_client.start();
|
||||
}
|
||||
|
||||
@After
|
||||
public void destroy() throws Exception
|
||||
{
|
||||
_client.stop();
|
||||
_proxy.stop();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void httpsViaProxyThatClosesConnectionOnConnectRequestTest() throws Exception
|
||||
{
|
||||
sendRequestThroughProxy(new ContentExchange()
|
||||
{
|
||||
|
||||
@Override
|
||||
protected void onException(Throwable x)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
}, "close", 9);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void httpsViaProxyThatReturns500ErrorTest() throws Exception
|
||||
{
|
||||
HttpExchange exchange = new ContentExchange()
|
||||
{
|
||||
@Override
|
||||
protected void onException(Throwable x)
|
||||
{
|
||||
// Suppress logging for expected exception
|
||||
if (!(x instanceof ProtocolException))
|
||||
super.onException(x);
|
||||
}
|
||||
};
|
||||
sendRequestThroughProxy(exchange, "error500", 9);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void httpsViaProxyThatReturns504ErrorTest() throws Exception
|
||||
{
|
||||
sendRequestThroughProxy(new ContentExchange(), "error504", 8);
|
||||
}
|
||||
|
||||
private void sendRequestThroughProxy(HttpExchange exchange, String desiredBehaviour, int exptectedStatus) throws Exception
|
||||
{
|
||||
String url = "https://" + desiredBehaviour + ".com/";
|
||||
exchange.setURL(url);
|
||||
exchange.addRequestHeader("behaviour", desiredBehaviour);
|
||||
_client.send(exchange);
|
||||
assertEquals(HttpExchange.toState(exptectedStatus) + " status awaited", exptectedStatus, exchange.waitForDone());
|
||||
}
|
||||
|
||||
private class BadBehavingConnectHandler extends ConnectHandler
|
||||
{
|
||||
@Override
|
||||
protected void handleConnect(Request baseRequest, HttpServletRequest request, HttpServletResponse response, String serverAddress)
|
||||
throws ServletException, IOException
|
||||
{
|
||||
if (serverAddress.contains("close"))
|
||||
{
|
||||
AbstractHttpConnection.getCurrentConnection().getEndPoint().close();
|
||||
}
|
||||
else if (serverAddress.contains("error500"))
|
||||
{
|
||||
response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR_500);
|
||||
}
|
||||
else if (serverAddress.contains("error504"))
|
||||
{
|
||||
response.setStatus(HttpStatus.GATEWAY_TIMEOUT_504);
|
||||
}
|
||||
baseRequest.setHandled(true);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -51,4 +51,10 @@ public class NonBlockingHttpExchangeCancelTest extends AbstractHttpExchangeCance
|
|||
{
|
||||
return httpClient;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public void testHttpExchangeCancelOnRequestComplete() throws Exception
|
||||
{
|
||||
super.testHttpExchangeCancelOnRequestComplete();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,9 +1,13 @@
|
|||
package org.eclipse.jetty.client;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
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;
|
||||
|
@ -12,7 +16,6 @@ import javax.servlet.http.HttpServletResponse;
|
|||
import org.eclipse.jetty.http.HttpHeaders;
|
||||
import org.eclipse.jetty.http.HttpMethods;
|
||||
import org.eclipse.jetty.http.MimeTypes;
|
||||
import org.eclipse.jetty.http.ssl.SslContextFactory;
|
||||
import org.eclipse.jetty.io.ByteArrayBuffer;
|
||||
import org.eclipse.jetty.server.Connector;
|
||||
import org.eclipse.jetty.server.Handler;
|
||||
|
@ -23,12 +26,10 @@ 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;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
public class ProxyTunnellingTest
|
||||
{
|
||||
private Server server;
|
||||
|
@ -41,13 +42,13 @@ public class ProxyTunnellingTest
|
|||
{
|
||||
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.setKeyStore(keyStorePath);
|
||||
cf.setKeyStorePath(keyStorePath);
|
||||
cf.setKeyStorePassword("storepwd");
|
||||
cf.setKeyManagerPassword("keypwd");
|
||||
startServer(connector, handler);
|
||||
|
@ -217,11 +218,11 @@ public class ProxyTunnellingTest
|
|||
ContentExchange exchange = new ContentExchange(true)
|
||||
{
|
||||
@Override
|
||||
protected void onConnectionFailed(Throwable x)
|
||||
protected void onException(Throwable x)
|
||||
{
|
||||
latch.countDown();
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
exchange.setMethod(HttpMethods.GET);
|
||||
String body = "BODY";
|
||||
|
|
|
@ -19,7 +19,6 @@ import java.util.HashSet;
|
|||
import java.util.Set;
|
||||
|
||||
import org.eclipse.jetty.client.security.Realm;
|
||||
import org.eclipse.jetty.http.security.Constraint;
|
||||
import org.eclipse.jetty.security.ConstraintMapping;
|
||||
import org.eclipse.jetty.security.ConstraintSecurityHandler;
|
||||
import org.eclipse.jetty.security.HashLoginService;
|
||||
|
@ -33,6 +32,7 @@ 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
|
||||
|
|
|
@ -20,7 +20,6 @@ import java.util.Set;
|
|||
|
||||
import org.eclipse.jetty.client.security.Realm;
|
||||
import org.eclipse.jetty.http.HttpStatus;
|
||||
import org.eclipse.jetty.http.security.Constraint;
|
||||
import org.eclipse.jetty.security.ConstraintMapping;
|
||||
import org.eclipse.jetty.security.ConstraintSecurityHandler;
|
||||
import org.eclipse.jetty.security.HashLoginService;
|
||||
|
@ -34,6 +33,7 @@ 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
|
||||
|
|
|
@ -31,7 +31,6 @@ import javax.servlet.http.HttpServletResponse;
|
|||
import org.eclipse.jetty.client.security.Realm;
|
||||
import org.eclipse.jetty.client.security.SimpleRealmResolver;
|
||||
import org.eclipse.jetty.http.HttpMethods;
|
||||
import org.eclipse.jetty.http.security.Constraint;
|
||||
import org.eclipse.jetty.io.Buffer;
|
||||
import org.eclipse.jetty.io.EofException;
|
||||
import org.eclipse.jetty.security.ConstraintMapping;
|
||||
|
@ -46,6 +45,7 @@ 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;
|
||||
|
|
|
@ -0,0 +1,211 @@
|
|||
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.HttpMethods;
|
||||
import org.eclipse.jetty.io.Buffer;
|
||||
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<String> _uris;
|
||||
final int _repeats;
|
||||
int _u;
|
||||
int _r;
|
||||
|
||||
AtomicBoolean counted=new AtomicBoolean(false);
|
||||
|
||||
public ConcurrentExchange(HttpClient client,CountDownLatch latch, List<String> 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(Buffer content) throws IOException
|
||||
{
|
||||
_bytes+=content.length();
|
||||
super.onResponseContent(content);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @see org.eclipse.jetty.client.HttpExchange#onResponseHeader(org.eclipse.jetty.io.Buffer, org.eclipse.jetty.io.Buffer)
|
||||
*/
|
||||
@Override
|
||||
protected void onResponseHeader(Buffer name, Buffer 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.Buffer, int, org.eclipse.jetty.io.Buffer)
|
||||
*/
|
||||
@Override
|
||||
protected void onResponseStatus(Buffer version, int status, Buffer 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(HttpMethods.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<String> uris = new ArrayList<String>();
|
||||
|
||||
for (int i=0; i<args.length; i++)
|
||||
{
|
||||
String arg=args[i];
|
||||
if ("-c".equals(arg))
|
||||
{
|
||||
concurrent=Integer.parseInt(args[++i]);
|
||||
continue;
|
||||
}
|
||||
|
||||
if ("-r".equals(arg))
|
||||
{
|
||||
repeats=Integer.parseInt(args[++i]);
|
||||
continue;
|
||||
}
|
||||
|
||||
uris.add(arg);
|
||||
}
|
||||
|
||||
QueuedThreadPool pool = new QueuedThreadPool();
|
||||
pool.setMaxThreads(500);
|
||||
pool.setDaemon(true);
|
||||
|
||||
HttpClient client = new HttpClient();
|
||||
client.setThreadPool(pool);
|
||||
client.setConnectorType(HttpClient.CONNECTOR_SELECT_CHANNEL);
|
||||
client.setIdleTimeout(30000);
|
||||
client.setConnectTimeout(30000);
|
||||
client.setMaxConnectionsPerAddress(concurrent*2);
|
||||
client.start();
|
||||
|
||||
final CountDownLatch latch = new CountDownLatch(concurrent);
|
||||
|
||||
|
||||
for (int i=0;i<concurrent;i++)
|
||||
{
|
||||
ConcurrentExchange ex = new ConcurrentExchange(client,latch,uris,repeats);
|
||||
if (!ex.next())
|
||||
latch.countDown();
|
||||
}
|
||||
|
||||
latch.await();
|
||||
client.stop();
|
||||
pool.stop();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,246 @@
|
|||
package org.eclipse.jetty.client;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.ServletInputStream;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import junit.framework.Assert;
|
||||
|
||||
import org.eclipse.jetty.http.HttpHeaderValues;
|
||||
import org.eclipse.jetty.http.HttpHeaders;
|
||||
import org.eclipse.jetty.io.Buffer;
|
||||
import org.eclipse.jetty.server.Request;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.server.bio.SocketConnector;
|
||||
import org.eclipse.jetty.server.handler.AbstractHandler;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* A class that attempts to simulate a client communicating with a slow server. It imposes a delay between each handle() call made to the server's handler.
|
||||
*
|
||||
* The client sends a binary blob of data to the server, and this blob is then inspected to verify correct transfer.
|
||||
*/
|
||||
public class SluggishServerTest
|
||||
{
|
||||
|
||||
/** msec to wait between reads in the handler -- may need to adjust based on OS/HW/etc. to reproduce bug */
|
||||
private final static int READ_DELAY = 5;
|
||||
|
||||
private final static String URL = "http://localhost:";
|
||||
|
||||
/** Stream providing a binary message to send */
|
||||
private static class SluggishStream extends InputStream
|
||||
{
|
||||
private final byte[] request;
|
||||
private int pos;
|
||||
|
||||
public SluggishStream(byte[] request)
|
||||
{
|
||||
this.request = request;
|
||||
this.pos = 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read() throws IOException
|
||||
{
|
||||
if (pos < request.length)
|
||||
{
|
||||
int byteVal = request[pos++] & 0xFF;
|
||||
return byteVal;
|
||||
}
|
||||
else
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/** Sends a message containing random binary content to a SluggishHandler */
|
||||
private static class SluggishExchange extends HttpExchange
|
||||
{
|
||||
private byte[] request;
|
||||
|
||||
public SluggishExchange(int port, int count)
|
||||
{
|
||||
request = new byte[count];
|
||||
for (int i=0;i<count;i++)
|
||||
request[i]=(byte)('A'+(i%26));
|
||||
setURL(URL+port);
|
||||
setRequestContentSource(new SluggishStream(request));
|
||||
setRequestContentType("application/octet-stream");
|
||||
setRequestHeader(HttpHeaders.TRANSFER_ENCODING,HttpHeaderValues.CHUNKED);
|
||||
}
|
||||
|
||||
public byte[] getRequestBody()
|
||||
{
|
||||
return request;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onRequestComplete()
|
||||
{
|
||||
//System.err.println("REQUEST COMPLETE " + this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResponseComplete()
|
||||
{
|
||||
//System.err.println("RESPONSE COMPLETE " + this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResponseStatus(Buffer version, int status, Buffer reason) throws IOException
|
||||
{
|
||||
//System.err.printf("<<< %s %d %s%n",version,status,reason);
|
||||
super.onResponseStatus(version,status,reason);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResponseHeader(Buffer name, Buffer value) throws IOException
|
||||
{
|
||||
//System.err.printf("<<< %s: %s%n",name,value);
|
||||
super.onResponseHeader(name,value);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResponseHeaderComplete() throws IOException
|
||||
{
|
||||
//System.err.printf("<<< --%n");
|
||||
super.onResponseHeaderComplete();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/** Receives binary message from a SluggishExchange & stores it for validation */
|
||||
private static class SluggishHandler extends AbstractHandler
|
||||
{
|
||||
|
||||
private final ArrayList<Byte> accumulatedRequest;
|
||||
|
||||
public SluggishHandler(int requestSize)
|
||||
{
|
||||
accumulatedRequest = new ArrayList<Byte>(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();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -13,6 +13,16 @@
|
|||
|
||||
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()
|
||||
|
@ -21,10 +31,66 @@ public class SocketConnectionTest extends AbstractConnectionTest
|
|||
httpClient.setConnectorType(HttpClient.CONNECTOR_SOCKET);
|
||||
return httpClient;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void testServerClosedConnection()
|
||||
public void testServerClosedConnection() throws Exception
|
||||
{
|
||||
// TODO work out why this does not work
|
||||
// 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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,148 @@
|
|||
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.HttpMethods;
|
||||
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 = HttpMethods.GET;
|
||||
exchange.setMethod(method);
|
||||
client.send(exchange);
|
||||
Assert.assertTrue(proxy.awaitClient(5, TimeUnit.SECONDS));
|
||||
|
||||
final SSLSocket server = (SSLSocket)acceptor.accept();
|
||||
server.setUseClientMode(false);
|
||||
|
||||
Future<Object> handshake = threadPool.submit(new Callable<Object>()
|
||||
{
|
||||
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());
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,353 @@
|
|||
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<Integer, SslBytesServerTest.TLSRecord.Type> codes = new HashMap<Integer, SslBytesServerTest.TLSRecord.Type>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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<Object> clientToServer = threadPool.submit(new Callable<Object>()
|
||||
{
|
||||
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<Object> serverToClient = threadPool.submit(new Callable<Object>()
|
||||
{
|
||||
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 resetServer() 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<Object> clientToServer;
|
||||
private final Future<Object> serverToClient;
|
||||
|
||||
public AutomaticFlow(CountDownLatch stopLatch, Future<Object> clientToServer, Future<Object> 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -20,9 +20,6 @@ import java.util.Set;
|
|||
|
||||
import javax.security.auth.Subject;
|
||||
|
||||
import org.eclipse.jetty.http.security.Constraint;
|
||||
import org.eclipse.jetty.http.security.Credential;
|
||||
import org.eclipse.jetty.http.ssl.SslContextFactory;
|
||||
import org.eclipse.jetty.security.ConstraintMapping;
|
||||
import org.eclipse.jetty.security.ConstraintSecurityHandler;
|
||||
import org.eclipse.jetty.security.IdentityService;
|
||||
|
@ -38,6 +35,9 @@ 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
|
||||
{
|
||||
|
@ -58,7 +58,7 @@ public class SslCertSecuredExchangeTest extends ContentExchangeTest
|
|||
cf.setValidateCerts(true);
|
||||
cf.setCrlPath(_crlpath);
|
||||
cf.setNeedClientAuth(true);
|
||||
cf.setKeyStore(_keypath);
|
||||
cf.setKeyStorePath(_keypath);
|
||||
cf.setKeyStorePassword(_password);
|
||||
cf.setKeyManagerPassword(_password);
|
||||
cf.setTrustStore(_trustpath);
|
||||
|
@ -159,7 +159,7 @@ public class SslCertSecuredExchangeTest extends ContentExchangeTest
|
|||
cf.setCrlPath(_crlpath);
|
||||
|
||||
cf.setCertAlias("client");
|
||||
cf.setKeyStore(_clientpath);
|
||||
cf.setKeyStorePath(_clientpath);
|
||||
cf.setKeyStorePassword(_password);
|
||||
cf.setKeyManagerPassword(_password);
|
||||
|
||||
|
|
|
@ -15,7 +15,6 @@ package org.eclipse.jetty.client;
|
|||
|
||||
import java.io.File;
|
||||
|
||||
import org.eclipse.jetty.http.ssl.SslContextFactory;
|
||||
import org.eclipse.jetty.server.Handler;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.server.handler.HandlerCollection;
|
||||
|
@ -24,6 +23,7 @@ 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
|
||||
|
@ -37,7 +37,7 @@ public class SslContentExchangeTest
|
|||
SslSelectChannelConnector connector = new SslSelectChannelConnector();
|
||||
File keystore = MavenTestingUtils.getTestResourceFile("keystore");
|
||||
SslContextFactory cf = connector.getSslContextFactory();
|
||||
cf.setKeyStore(keystore.getAbsolutePath());
|
||||
cf.setKeyStorePath(keystore.getAbsolutePath());
|
||||
cf.setKeyStorePassword("storepwd");
|
||||
cf.setKeyManagerPassword("keypwd");
|
||||
cf.setSessionCachingEnabled(true);
|
||||
|
|
|
@ -16,64 +16,31 @@ package org.eclipse.jetty.client;
|
|||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.hamcrest.Matchers.not;
|
||||
|
||||
import org.eclipse.jetty.http.ssl.SslContextFactory;
|
||||
import org.eclipse.jetty.client.helperClasses.ServerAndClientCreator;
|
||||
import org.eclipse.jetty.client.helperClasses.SslServerAndClientCreator;
|
||||
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.toolchain.test.OS;
|
||||
import org.eclipse.jetty.toolchain.test.Stress;
|
||||
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
|
||||
@Override
|
||||
public void setUp() throws Exception
|
||||
public void setUpOnce() throws Exception
|
||||
{
|
||||
_scheme="https";
|
||||
startServer();
|
||||
_httpClient=new HttpClient();
|
||||
_httpClient.setIdleTimeout(2000);
|
||||
_httpClient.setTimeout(2500);
|
||||
_httpClient.setConnectTimeout(1000);
|
||||
_httpClient.setConnectorType(HttpClient.CONNECTOR_SELECT_CHANNEL);
|
||||
_httpClient.setConnectorType(HttpClient.CONNECTOR_SOCKET);
|
||||
_httpClient.setMaxConnectionsPerAddress(2);
|
||||
_httpClient.start();
|
||||
_server = serverAndClientCreator.createServer();
|
||||
_httpClient = serverAndClientCreator.createClient(3000L,3500L,2000);
|
||||
Connector[] connectors = _server.getConnectors();
|
||||
_port = connectors[0].getLocalPort();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
protected void newServer()
|
||||
{
|
||||
_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.setKeyStore(keystore);
|
||||
cf.setKeyStorePassword("storepwd");
|
||||
cf.setKeyManagerPassword("keypwd");
|
||||
connector.setAllowRenegotiate(true);
|
||||
|
||||
_server.setConnectors(new Connector[]
|
||||
{ connector });
|
||||
_connector=connector;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
private void IgnoreTestOnBuggyIBM()
|
||||
{
|
||||
|
@ -103,9 +70,6 @@ public class SslHttpExchangeTest extends HttpExchangeTest
|
|||
@Override
|
||||
public void testPerf() throws Exception
|
||||
{
|
||||
// TODO needs to be further investigated
|
||||
Assume.assumeTrue(!OS.IS_OSX || Stress.isEnabled());
|
||||
|
||||
// TODO Resolve problems on IBM JVM https://bugs.eclipse.org/bugs/show_bug.cgi?id=304532
|
||||
IgnoreTestOnBuggyIBM();
|
||||
super.testPerf();
|
||||
|
|
|
@ -19,8 +19,6 @@ import java.util.HashSet;
|
|||
import java.util.Set;
|
||||
|
||||
import org.eclipse.jetty.client.security.Realm;
|
||||
import org.eclipse.jetty.http.security.Constraint;
|
||||
import org.eclipse.jetty.http.ssl.SslContextFactory;
|
||||
import org.eclipse.jetty.security.ConstraintMapping;
|
||||
import org.eclipse.jetty.security.ConstraintSecurityHandler;
|
||||
import org.eclipse.jetty.security.HashLoginService;
|
||||
|
@ -34,6 +32,8 @@ 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
|
||||
|
@ -63,7 +63,7 @@ extends ContentExchangeTest
|
|||
SslSelectChannelConnector connector = new SslSelectChannelConnector();
|
||||
File keystore = MavenTestingUtils.getTestResourceFile("keystore");
|
||||
SslContextFactory cf = connector.getSslContextFactory();
|
||||
cf.setKeyStore(keystore.getAbsolutePath());
|
||||
cf.setKeyStorePath(keystore.getAbsolutePath());
|
||||
cf.setKeyStorePassword("storepwd");
|
||||
cf.setKeyManagerPassword("keypwd");
|
||||
server.addConnector(connector);
|
||||
|
|
|
@ -20,7 +20,6 @@ import java.util.Set;
|
|||
|
||||
import org.eclipse.jetty.client.security.Realm;
|
||||
import org.eclipse.jetty.http.HttpStatus;
|
||||
import org.eclipse.jetty.http.security.Constraint;
|
||||
import org.eclipse.jetty.security.ConstraintMapping;
|
||||
import org.eclipse.jetty.security.ConstraintSecurityHandler;
|
||||
import org.eclipse.jetty.security.HashLoginService;
|
||||
|
@ -34,6 +33,7 @@ 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;
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
|
|
@ -34,8 +34,6 @@ import javax.servlet.http.HttpServletResponse;
|
|||
import org.eclipse.jetty.client.security.HashRealmResolver;
|
||||
import org.eclipse.jetty.client.security.Realm;
|
||||
import org.eclipse.jetty.http.HttpMethods;
|
||||
import org.eclipse.jetty.http.security.Constraint;
|
||||
import org.eclipse.jetty.http.ssl.SslContextFactory;
|
||||
import org.eclipse.jetty.io.EofException;
|
||||
import org.eclipse.jetty.security.ConstraintMapping;
|
||||
import org.eclipse.jetty.security.ConstraintSecurityHandler;
|
||||
|
@ -51,6 +49,8 @@ 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;
|
||||
|
@ -165,7 +165,7 @@ public class SslSecurityListenerTest
|
|||
|
||||
connector.setPort(0);
|
||||
SslContextFactory cf = connector.getSslContextFactory();
|
||||
cf.setKeyStore(keystore);
|
||||
cf.setKeyStorePath(keystore);
|
||||
cf.setKeyStorePassword("storepwd");
|
||||
cf.setKeyManagerPassword("keypwd");
|
||||
|
||||
|
|
|
@ -6,7 +6,6 @@ import java.security.KeyStore;
|
|||
import java.security.cert.CRL;
|
||||
import java.util.Collection;
|
||||
|
||||
import org.eclipse.jetty.http.ssl.SslContextFactory;
|
||||
import org.eclipse.jetty.server.Handler;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.server.handler.HandlerCollection;
|
||||
|
@ -16,6 +15,7 @@ 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.CertificateUtils;
|
||||
import org.eclipse.jetty.util.ssl.SslContextFactory;
|
||||
|
||||
public abstract class SslValidationTestBase extends ContentExchangeTest
|
||||
{
|
||||
|
@ -52,7 +52,7 @@ public abstract class SslValidationTestBase extends ContentExchangeTest
|
|||
srvFactory.setCrlPath(_crlpath);
|
||||
srvFactory.setNeedClientAuth(true);
|
||||
|
||||
srvFactory.setKeyStore(_keypath);
|
||||
srvFactory.setKeyStorePath(_keypath);
|
||||
srvFactory.setKeyStorePassword(_password);
|
||||
srvFactory.setKeyManagerPassword(_password);
|
||||
|
||||
|
@ -88,7 +88,7 @@ public abstract class SslValidationTestBase extends ContentExchangeTest
|
|||
cf.setValidateCerts(true);
|
||||
cf.setCrlPath(_crlpath);
|
||||
|
||||
cf.setKeyStore(_clientpath);
|
||||
cf.setKeyStorePath(_clientpath);
|
||||
cf.setKeyStorePassword(_password);
|
||||
cf.setKeyManagerPassword(_password);
|
||||
|
||||
|
|
|
@ -0,0 +1,420 @@
|
|||
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<EndPoint> serverEndPoint = new AtomicReference<EndPoint>();
|
||||
|
||||
@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.
|
||||
* <p>
|
||||
* 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.
|
||||
* <p>
|
||||
* 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();
|
||||
}
|
||||
}
|
|
@ -16,7 +16,6 @@ package org.eclipse.jetty.client;
|
|||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
@ -26,17 +25,17 @@ import javax.servlet.ServletException;
|
|||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.eclipse.jetty.server.Connector;
|
||||
import org.eclipse.jetty.http.HttpMethods;
|
||||
import org.eclipse.jetty.io.EofException;
|
||||
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.
|
||||
|
@ -44,91 +43,71 @@ import org.eclipse.jetty.util.IO;
|
|||
* @author Matthew Purland
|
||||
* @author Greg Wilkins
|
||||
*/
|
||||
public class UnexpectedDataTest extends TestCase
|
||||
public class UnexpectedDataTest
|
||||
{
|
||||
protected int _maxConnectionsPerAddress = 1;
|
||||
protected String _scheme = "http://";
|
||||
protected Server _server;
|
||||
protected int _port;
|
||||
protected HttpClient _httpClient;
|
||||
protected Connector _connector;
|
||||
protected AtomicInteger _count = new AtomicInteger();
|
||||
private Server _server;
|
||||
private int _port;
|
||||
private HttpClient _httpClient;
|
||||
private Connector _connector;
|
||||
private AtomicInteger _count = new AtomicInteger();
|
||||
|
||||
protected void setUp() throws Exception
|
||||
@Before
|
||||
public void setUp() throws Exception
|
||||
{
|
||||
startServer();
|
||||
_httpClient=new HttpClient();
|
||||
_httpClient = new HttpClient();
|
||||
_httpClient.setConnectorType(HttpClient.CONNECTOR_SELECT_CHANNEL);
|
||||
_httpClient.setMaxConnectionsPerAddress(_maxConnectionsPerAddress);
|
||||
_httpClient.setMaxConnectionsPerAddress(1);
|
||||
_httpClient.start();
|
||||
}
|
||||
|
||||
protected void tearDown() throws Exception
|
||||
@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++)
|
||||
for (int i = 0; i < 4; ++i)
|
||||
{
|
||||
final CountDownLatch done=new CountDownLatch(1);
|
||||
ContentExchange httpExchange=new ContentExchange()
|
||||
final CountDownLatch done = new CountDownLatch(1);
|
||||
ContentExchange httpExchange = new ContentExchange()
|
||||
{
|
||||
protected void onResponseComplete() throws IOException
|
||||
{
|
||||
super.onResponseComplete();
|
||||
|
||||
done.countDown();
|
||||
}
|
||||
};
|
||||
httpExchange.setURL(_scheme+"localhost:"+_port+"/?i="+i);
|
||||
httpExchange.setURL("http://localhost:" + _port + "/?i=" + i);
|
||||
httpExchange.setMethod(HttpMethods.GET);
|
||||
_httpClient.send(httpExchange);
|
||||
|
||||
done.await(1,TimeUnit.SECONDS);
|
||||
|
||||
int status = httpExchange.getStatus();
|
||||
String result=httpExchange.getResponseContent();
|
||||
assertEquals("i="+i,0,result.indexOf("<hello>"));
|
||||
assertEquals("i="+i,result.length()-10,result.indexOf("</hello>"));
|
||||
assertEquals(HttpExchange.STATUS_COMPLETED, status);
|
||||
|
||||
Thread.sleep(5);
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
Assert.assertTrue(done.await(1000, TimeUnit.SECONDS));
|
||||
|
||||
int status = httpExchange.getStatus();
|
||||
String result = httpExchange.getResponseContent();
|
||||
Assert.assertEquals("i=" + i, 0, result.indexOf("<hello>"));
|
||||
Assert.assertEquals("i=" + i, result.length() - 10, result.indexOf("</hello>"));
|
||||
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 = new Server();
|
||||
_server.setGracefulShutdown(500);
|
||||
_connector=new SelectChannelConnector();
|
||||
|
||||
_connector = new SelectChannelConnector();
|
||||
_connector.setPort(0);
|
||||
_server.setConnectors(new Connector[] { _connector });
|
||||
_server.setConnectors(new Connector[]{_connector});
|
||||
}
|
||||
|
||||
protected void startServer() throws Exception
|
||||
|
@ -137,28 +116,28 @@ public class UnexpectedDataTest extends TestCase
|
|||
_server.setHandler(new AbstractHandler()
|
||||
{
|
||||
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response)
|
||||
throws IOException, ServletException
|
||||
throws IOException, ServletException
|
||||
{
|
||||
int i=0;
|
||||
int i = 0;
|
||||
try
|
||||
{
|
||||
baseRequest.setHandled(true);
|
||||
response.setStatus(200);
|
||||
_count.incrementAndGet();
|
||||
|
||||
|
||||
if (request.getMethod().equalsIgnoreCase("GET"))
|
||||
{
|
||||
StringBuffer buffer = new StringBuffer();
|
||||
StringBuilder buffer = new StringBuilder();
|
||||
buffer.append("<hello>\r\n");
|
||||
for (; i<100; i++)
|
||||
for (; i < 100; i++)
|
||||
{
|
||||
buffer.append(" <world>"+i+"</world>\r\n");
|
||||
buffer.append(" <world>").append(i).append("</world>\r\n");
|
||||
}
|
||||
buffer.append("</hello>\r\n");
|
||||
|
||||
|
||||
byte[] buff = buffer.toString().getBytes();
|
||||
response.setContentLength(buff.length);
|
||||
|
||||
|
||||
buffer.append("extra data");
|
||||
buff = buffer.toString().getBytes();
|
||||
|
||||
|
@ -169,35 +148,30 @@ public class UnexpectedDataTest extends TestCase
|
|||
else
|
||||
{
|
||||
response.setContentType(request.getContentType());
|
||||
int size=request.getContentLength();
|
||||
ByteArrayOutputStream bout = new ByteArrayOutputStream(size>0?size:32768);
|
||||
IO.copy(request.getInputStream(),bout);
|
||||
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)
|
||||
catch (IOException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
throw e;
|
||||
}
|
||||
catch(Throwable e)
|
||||
catch (Throwable e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
throw new ServletException(e);
|
||||
}
|
||||
finally
|
||||
{
|
||||
// System.err.println("HANDLED "+i);
|
||||
}
|
||||
}
|
||||
});
|
||||
_server.start();
|
||||
_port=_connector.getLocalPort();
|
||||
_port = _connector.getLocalPort();
|
||||
}
|
||||
|
||||
private void stopServer() throws Exception
|
||||
{
|
||||
_server.stop();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -162,8 +162,6 @@ public class WebSocketUpgradeTest
|
|||
int status = httpExchange.waitForDone();
|
||||
assertEquals(HttpExchange.STATUS_COMPLETED, status);
|
||||
|
||||
// System.err.println("results="+_results);
|
||||
|
||||
assertEquals("serverWS.onConnect", _results.poll(1,TimeUnit.SECONDS));
|
||||
TestWebSocket serverWS = (TestWebSocket)_results.poll(1,TimeUnit.SECONDS);
|
||||
|
||||
|
|
|
@ -0,0 +1,55 @@
|
|||
// ========================================================================
|
||||
// Copyright (c) 2009-2009 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;
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
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;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
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;
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,91 @@
|
|||
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.HttpHeaders;
|
||||
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(HttpHeaders.PROXY_AUTHORIZATION));
|
||||
}
|
||||
else if (request.getMethod().equalsIgnoreCase("GET"))
|
||||
{
|
||||
response.getOutputStream().println("<hello>");
|
||||
for (; i < 100; i++)
|
||||
{
|
||||
response.getOutputStream().println(" <world>" + i + "</world");
|
||||
if (i % 20 == 0)
|
||||
response.getOutputStream().flush();
|
||||
}
|
||||
response.getOutputStream().println("</hello>");
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
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;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
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;
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
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;
|
||||
}
|
||||
}
|
|
@ -2,7 +2,7 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-project</artifactId>
|
||||
<version>7.5.0-SNAPSHOT</version>
|
||||
<version>7.6.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>jetty-continuation</artifactId>
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package org.eclipse.jetty.continuation;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.servlet.Filter;
|
||||
import javax.servlet.FilterChain;
|
||||
import javax.servlet.FilterConfig;
|
||||
|
|
|
@ -23,7 +23,7 @@ public class Jetty6Continuation implements ContinuationFilter.FilteredContinuati
|
|||
// Exception reused for all continuations
|
||||
// Turn on debug in ContinuationFilter to see real stack trace.
|
||||
private final static ContinuationThrowable __exception = new ContinuationThrowable();
|
||||
|
||||
|
||||
private final ServletRequest _request;
|
||||
private ServletResponse _response;
|
||||
private final org.mortbay.util.ajax.Continuation _j6Continuation;
|
||||
|
@ -66,7 +66,7 @@ public class Jetty6Continuation implements ContinuationFilter.FilteredContinuati
|
|||
_j6Continuation.resume();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @see org.eclipse.jetty.continuation.Continuation#getAttribute(java.lang.String)
|
||||
|
@ -233,8 +233,6 @@ public class Jetty6Continuation implements ContinuationFilter.FilteredContinuati
|
|||
|
||||
Throwable th=_retry;
|
||||
_retry=null;
|
||||
if (th instanceof ThreadDeath)
|
||||
throw (ThreadDeath)th;
|
||||
if (th instanceof Error)
|
||||
throw (Error)th;
|
||||
if (th instanceof RuntimeException)
|
||||
|
@ -245,7 +243,7 @@ public class Jetty6Continuation implements ContinuationFilter.FilteredContinuati
|
|||
for (ContinuationListener l: _listeners)
|
||||
l.onComplete(this);
|
||||
}
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-project</artifactId>
|
||||
<version>7.5.0-SNAPSHOT</version>
|
||||
<version>7.6.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>jetty-deploy</artifactId>
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
</Set>
|
||||
<Call name="setContextAttribute">
|
||||
<Arg>org.eclipse.jetty.server.webapp.ContainerIncludeJarPattern</Arg>
|
||||
<Arg>.*/jsp-api-[^/]*\.jar$|.*/jsp-[^/]*\.jar$</Arg>
|
||||
<Arg>.*/.*jsp-api-[^/]*\.jar$|.*/.*jsp-[^/]*\.jar$|.*/.*taglibs[^/]*\.jar$</Arg>
|
||||
</Call>
|
||||
|
||||
|
||||
|
|
|
@ -481,7 +481,7 @@ public class DeploymentManager extends AggregateLifeCycle
|
|||
while (it.hasNext())
|
||||
{
|
||||
Node node = it.next();
|
||||
LOG.debug("Executing Node: " + node);
|
||||
LOG.debug("Executing Node {}",node);
|
||||
_lifecycle.runBindings(node,appentry.app,this);
|
||||
appentry.setLifeCycleNode(node);
|
||||
}
|
||||
|
|
|
@ -257,7 +257,7 @@ public class WebAppDeployer extends AbstractLifeCycle
|
|||
|
||||
if (path != null && path.equals(app.getFile().getCanonicalPath()))
|
||||
{
|
||||
LOG.debug("Already deployed:"+path);
|
||||
LOG.debug("Already deployed: {}",path);
|
||||
continue files;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -51,13 +51,14 @@ public class StandardUndeployer implements AppLifeCycle.Binding
|
|||
for (int i = 0, n = children.length; i < n; i++)
|
||||
{
|
||||
Handler child = children[i];
|
||||
LOG.debug("Child handler: " + child);
|
||||
LOG.debug("Child handler {}",child);
|
||||
if (child.equals(context))
|
||||
{
|
||||
LOG.debug("Removing handler: " + child);
|
||||
LOG.debug("Removing handler {}",child);
|
||||
coll.removeHandler(child);
|
||||
child.destroy();
|
||||
LOG.debug(String.format("After removal: %d (originally %d)",coll.getHandlers().length,originalCount));
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("After removal: {} (originally {})",coll.getHandlers().length,originalCount);
|
||||
}
|
||||
else if (child instanceof HandlerCollection)
|
||||
{
|
||||
|
|
|
@ -99,7 +99,8 @@ public abstract class ScanningAppProvider extends AbstractLifeCycle implements A
|
|||
@Override
|
||||
protected void doStart() throws Exception
|
||||
{
|
||||
if (LOG.isDebugEnabled()) LOG.debug(this.getClass().getSimpleName() + ".doStart()");
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug(this.getClass().getSimpleName() + ".doStart()");
|
||||
if (_monitoredDir == null)
|
||||
{
|
||||
throw new IllegalStateException("No configuration dir specified");
|
||||
|
@ -132,7 +133,8 @@ public abstract class ScanningAppProvider extends AbstractLifeCycle implements A
|
|||
/* ------------------------------------------------------------ */
|
||||
protected void fileAdded(String filename) throws Exception
|
||||
{
|
||||
if (LOG.isDebugEnabled()) LOG.debug("added ",filename);
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("added {}",filename);
|
||||
App app = ScanningAppProvider.this.createApp(filename);
|
||||
if (app != null)
|
||||
{
|
||||
|
@ -144,7 +146,8 @@ public abstract class ScanningAppProvider extends AbstractLifeCycle implements A
|
|||
/* ------------------------------------------------------------ */
|
||||
protected void fileChanged(String filename) throws Exception
|
||||
{
|
||||
if (LOG.isDebugEnabled()) LOG.debug("changed ",filename);
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("changed {}",filename);
|
||||
App app = _appMap.remove(filename);
|
||||
if (app != null)
|
||||
{
|
||||
|
@ -161,7 +164,8 @@ public abstract class ScanningAppProvider extends AbstractLifeCycle implements A
|
|||
/* ------------------------------------------------------------ */
|
||||
protected void fileRemoved(String filename) throws Exception
|
||||
{
|
||||
if (LOG.isDebugEnabled()) LOG.debug("removed ",filename);
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("removed {}",filename);
|
||||
App app = _appMap.remove(filename);
|
||||
if (app != null)
|
||||
_deploymentManager.removeApp(app);
|
||||
|
|
|
@ -111,6 +111,7 @@ public class ScanningAppProviderRuntimeUpdatesTest
|
|||
jetty.copyWebapp("foo-webapp-1.war","foo.war");
|
||||
jetty.copyContext("foo.xml","foo.xml");
|
||||
|
||||
waitForDirectoryScan();
|
||||
waitForDirectoryScan();
|
||||
|
||||
jetty.assertWebAppContextsExists("/foo");
|
||||
|
@ -125,12 +126,14 @@ public class ScanningAppProviderRuntimeUpdatesTest
|
|||
jetty.copyWebapp("foo-webapp-1.war","foo.war");
|
||||
jetty.copyContext("foo.xml","foo.xml");
|
||||
|
||||
waitForDirectoryScan();
|
||||
waitForDirectoryScan();
|
||||
|
||||
jetty.assertWebAppContextsExists("/foo");
|
||||
|
||||
jetty.removeContext("foo.xml");
|
||||
|
||||
waitForDirectoryScan();
|
||||
waitForDirectoryScan();
|
||||
|
||||
// FIXME: hot undeploy with removal not working! - jetty.assertNoWebAppContexts();
|
||||
|
@ -151,6 +154,7 @@ public class ScanningAppProviderRuntimeUpdatesTest
|
|||
jetty.copyWebapp("foo-webapp-1.war","foo.war");
|
||||
jetty.copyContext("foo.xml","foo.xml");
|
||||
|
||||
waitForDirectoryScan();
|
||||
waitForDirectoryScan();
|
||||
|
||||
jetty.assertWebAppContextsExists("/foo");
|
||||
|
@ -165,6 +169,7 @@ public class ScanningAppProviderRuntimeUpdatesTest
|
|||
|
||||
// This should result in the existing foo.war being replaced with the new foo.war
|
||||
waitForDirectoryScan();
|
||||
waitForDirectoryScan();
|
||||
jetty.assertWebAppContextsExists("/foo");
|
||||
|
||||
// Test that webapp response contains "-2"
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-project</artifactId>
|
||||
<version>7.5.0-SNAPSHOT</version>
|
||||
<version>7.6.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>jetty-distribution</artifactId>
|
||||
<name>Jetty :: Distribution Assemblies</name>
|
||||
|
@ -20,8 +20,7 @@
|
|||
<orbit-javax-servlet-jsp-version>2.1.0.v201004190952</orbit-javax-servlet-jsp-version>
|
||||
<orbit-javax-servlet-jsp-jstl-version>1.2.0.v201004190952</orbit-javax-servlet-jsp-jstl-version>
|
||||
<orbit-com-sun-el-version>1.0.0.v201004190952</orbit-com-sun-el-version>
|
||||
<!-- orbit-org-apache-jasper-version>2.1.0.v201007080150</orbit-org-apache-jasper-version -->
|
||||
<central-jsp-version>2.1.3-b10</central-jsp-version>
|
||||
<orbit-org-apache-jasper-version>2.1.0.v201110031002</orbit-org-apache-jasper-version>
|
||||
<orbit-org-apache-taglibs-standard-version>1.2.0.v201004190952</orbit-org-apache-taglibs-standard-version>
|
||||
<orbit-org-objectweb-asm-version>3.1.0.v200803061910</orbit-org-objectweb-asm-version>
|
||||
<orbit-javax-transaction-version>1.1.1.v201004190952</orbit-javax-transaction-version>
|
||||
|
@ -77,7 +76,7 @@
|
|||
<url url="${jetty-orbit-url}/javax.servlet.jsp_${orbit-javax-servlet-jsp-version}.jar" />
|
||||
<url url="${jetty-orbit-url}/javax.servlet.jsp.jstl_${orbit-javax-servlet-jsp-jstl-version}.jar" />
|
||||
<url url="${jetty-orbit-url}/com.sun.el_${orbit-com-sun-el-version}.jar" />
|
||||
<!-- url url="${jetty-orbit-url}/org.apache.jasper.glassfish_${orbit-org-apache-jasper-version}.jar" / -->
|
||||
<url url="${jetty-orbit-url}/org.apache.jasper.glassfish_${orbit-org-apache-jasper-version}.jar" />
|
||||
<url url="${jetty-orbit-url}/org.apache.taglibs.standard.glassfish_${orbit-org-apache-taglibs-standard-version}.jar" />
|
||||
<url url="${jetty-orbit-url}/org.objectweb.asm_${orbit-org-objectweb-asm-version}.jar" />
|
||||
<url url="${jetty-orbit-url}/javax.transaction_${orbit-javax-transaction-version}.jar" />
|
||||
|
@ -158,147 +157,6 @@
|
|||
<plugin>
|
||||
<artifactId>maven-dependency-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>unpack</id>
|
||||
<phase>generate-resources</phase>
|
||||
<goals>
|
||||
<goal>unpack</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<artifactItems>
|
||||
<artifactItem>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-rewrite</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<classifier>config</classifier>
|
||||
<type>jar</type>
|
||||
<overWrite>true</overWrite>
|
||||
<includes>**</includes>
|
||||
<outputDirectory>${assembly-directory}</outputDirectory>
|
||||
</artifactItem>
|
||||
<artifactItem>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-ajp</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<classifier>config</classifier>
|
||||
<type>jar</type>
|
||||
<overWrite>true</overWrite>
|
||||
<includes>**</includes>
|
||||
<outputDirectory>${assembly-directory}</outputDirectory>
|
||||
</artifactItem>
|
||||
<artifactItem>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>test-jetty-webapp</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<classifier>config</classifier>
|
||||
<type>jar</type>
|
||||
<overWrite>true</overWrite>
|
||||
<includes>**</includes>
|
||||
<outputDirectory>${assembly-directory}</outputDirectory>
|
||||
</artifactItem>
|
||||
<artifactItem>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-jmx</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<classifier>config</classifier>
|
||||
<type>jar</type>
|
||||
<overWrite>true</overWrite>
|
||||
<includes>**</includes>
|
||||
<outputDirectory>${assembly-directory}</outputDirectory>
|
||||
</artifactItem>
|
||||
<artifactItem>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-util</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<classifier>config</classifier>
|
||||
<type>jar</type>
|
||||
<overWrite>true</overWrite>
|
||||
<includes>**</includes>
|
||||
<outputDirectory>${assembly-directory}</outputDirectory>
|
||||
</artifactItem>
|
||||
<artifactItem>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-webapp</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<classifier>config</classifier>
|
||||
<type>jar</type>
|
||||
<overWrite>true</overWrite>
|
||||
<includes>**</includes>
|
||||
<outputDirectory>${assembly-directory}</outputDirectory>
|
||||
</artifactItem>
|
||||
<artifactItem>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-deploy</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<classifier>config</classifier>
|
||||
<type>jar</type>
|
||||
<overWrite>true</overWrite>
|
||||
<includes>**</includes>
|
||||
<outputDirectory>${assembly-directory}</outputDirectory>
|
||||
</artifactItem>
|
||||
<artifactItem>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-plus</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<classifier>config</classifier>
|
||||
<type>jar</type>
|
||||
<overWrite>true</overWrite>
|
||||
<includes>**</includes>
|
||||
<outputDirectory>${assembly-directory}</outputDirectory>
|
||||
</artifactItem>
|
||||
<artifactItem>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-server</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<classifier>config</classifier>
|
||||
<type>jar</type>
|
||||
<overWrite>true</overWrite>
|
||||
<includes>**</includes>
|
||||
<outputDirectory>${assembly-directory}</outputDirectory>
|
||||
</artifactItem>
|
||||
<artifactItem>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-security</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<classifier>config</classifier>
|
||||
<type>jar</type>
|
||||
<overWrite>true</overWrite>
|
||||
<includes>**</includes>
|
||||
<outputDirectory>${assembly-directory}</outputDirectory>
|
||||
</artifactItem>
|
||||
<artifactItem>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-policy</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<classifier>config</classifier>
|
||||
<type>jar</type>
|
||||
<overWrite>true</overWrite>
|
||||
<includes>**</includes>
|
||||
<outputDirectory>${assembly-directory}</outputDirectory>
|
||||
</artifactItem>
|
||||
<artifactItem>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-monitor</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<classifier>config</classifier>
|
||||
<type>jar</type>
|
||||
<overWrite>true</overWrite>
|
||||
<includes>**</includes>
|
||||
<outputDirectory>${assembly-directory}</outputDirectory>
|
||||
</artifactItem>
|
||||
<artifactItem>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-overlay-deployer</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<classifier>config</classifier>
|
||||
<type>jar</type>
|
||||
<overWrite>true</overWrite>
|
||||
<includes>**</includes>
|
||||
<outputDirectory>${assembly-directory}</outputDirectory>
|
||||
</artifactItem>
|
||||
</artifactItems>
|
||||
</configuration>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>copy</id>
|
||||
<phase>generate-resources</phase>
|
||||
|
@ -317,187 +175,6 @@
|
|||
<outputDirectory>${assembly-directory}/</outputDirectory>
|
||||
<destFileName>VERSION.txt</destFileName>
|
||||
</artifactItem>
|
||||
<artifactItem>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-util</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<type>jar</type>
|
||||
<overWrite>true</overWrite>
|
||||
<includes>**</includes>
|
||||
<outputDirectory>${assembly-directory}/lib</outputDirectory>
|
||||
</artifactItem>
|
||||
<artifactItem>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-io</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<type>jar</type>
|
||||
<overWrite>true</overWrite>
|
||||
<includes>**</includes>
|
||||
<outputDirectory>${assembly-directory}/lib</outputDirectory>
|
||||
</artifactItem>
|
||||
<artifactItem>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-http</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<type>jar</type>
|
||||
<overWrite>true</overWrite>
|
||||
<includes>**</includes>
|
||||
<outputDirectory>${assembly-directory}/lib</outputDirectory>
|
||||
</artifactItem>
|
||||
<artifactItem>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-server</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<type>jar</type>
|
||||
<overWrite>true</overWrite>
|
||||
<includes>**</includes>
|
||||
<outputDirectory>${assembly-directory}/lib</outputDirectory>
|
||||
</artifactItem>
|
||||
<artifactItem>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-security</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<type>jar</type>
|
||||
<overWrite>true</overWrite>
|
||||
<includes>**</includes>
|
||||
<outputDirectory>${assembly-directory}/lib</outputDirectory>
|
||||
</artifactItem>
|
||||
<artifactItem>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-servlet</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<type>jar</type>
|
||||
<overWrite>true</overWrite>
|
||||
<includes>**</includes>
|
||||
<outputDirectory>${assembly-directory}/lib</outputDirectory>
|
||||
</artifactItem>
|
||||
<artifactItem>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-servlets</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<type>jar</type>
|
||||
<overWrite>true</overWrite>
|
||||
<includes>**</includes>
|
||||
<outputDirectory>${assembly-directory}/lib</outputDirectory>
|
||||
</artifactItem>
|
||||
<artifactItem>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-xml</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<type>jar</type>
|
||||
<overWrite>true</overWrite>
|
||||
<includes>**</includes>
|
||||
<outputDirectory>${assembly-directory}/lib</outputDirectory>
|
||||
</artifactItem>
|
||||
<artifactItem>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-webapp</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<type>jar</type>
|
||||
<overWrite>true</overWrite>
|
||||
<includes>**</includes>
|
||||
<outputDirectory>${assembly-directory}/lib</outputDirectory>
|
||||
</artifactItem>
|
||||
<!-- Jetty Deploy -->
|
||||
<artifactItem>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-deploy</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<type>jar</type>
|
||||
<overWrite>true</overWrite>
|
||||
<includes>**</includes>
|
||||
<outputDirectory>${assembly-directory}/lib</outputDirectory>
|
||||
</artifactItem>
|
||||
<artifactItem>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-jmx</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<type>jar</type>
|
||||
<overWrite>true</overWrite>
|
||||
<includes>**</includes>
|
||||
<outputDirectory>${assembly-directory}/lib</outputDirectory>
|
||||
</artifactItem>
|
||||
<artifactItem>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-rewrite</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<type>jar</type>
|
||||
<overWrite>true</overWrite>
|
||||
<includes>**</includes>
|
||||
<outputDirectory>${assembly-directory}/lib</outputDirectory>
|
||||
</artifactItem>
|
||||
<artifactItem>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-ajp</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<type>jar</type>
|
||||
<overWrite>true</overWrite>
|
||||
<includes>**</includes>
|
||||
<outputDirectory>${assembly-directory}/lib</outputDirectory>
|
||||
</artifactItem>
|
||||
<artifactItem>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-annotations</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<type>jar</type>
|
||||
<overWrite>true</overWrite>
|
||||
<includes>**</includes>
|
||||
<outputDirectory>${assembly-directory}/lib</outputDirectory>
|
||||
</artifactItem>
|
||||
<artifactItem>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-client</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<type>jar</type>
|
||||
<overWrite>true</overWrite>
|
||||
<includes>**</includes>
|
||||
<outputDirectory>${assembly-directory}/lib</outputDirectory>
|
||||
</artifactItem>
|
||||
<artifactItem>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-jndi</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<type>jar</type>
|
||||
<overWrite>true</overWrite>
|
||||
<includes>**</includes>
|
||||
<outputDirectory>${assembly-directory}/lib</outputDirectory>
|
||||
</artifactItem>
|
||||
<artifactItem>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-policy</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<type>jar</type>
|
||||
<overWrite>true</overWrite>
|
||||
<includes>**</includes>
|
||||
<outputDirectory>${assembly-directory}/lib</outputDirectory>
|
||||
</artifactItem>
|
||||
<artifactItem>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-monitor</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<type>jar</type>
|
||||
<overWrite>true</overWrite>
|
||||
<includes>**</includes>
|
||||
<outputDirectory>${assembly-directory}/lib/monitor</outputDirectory>
|
||||
</artifactItem>
|
||||
<artifactItem>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-plus</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<type>jar</type>
|
||||
<overWrite>true</overWrite>
|
||||
<includes>**</includes>
|
||||
<outputDirectory>${assembly-directory}/lib</outputDirectory>
|
||||
</artifactItem>
|
||||
<artifactItem>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-continuation</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<type>jar</type>
|
||||
<overWrite>true</overWrite>
|
||||
<includes>**</includes>
|
||||
<outputDirectory>${assembly-directory}/lib</outputDirectory>
|
||||
</artifactItem>
|
||||
<artifactItem>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>test-jetty-webapp</artifactId>
|
||||
|
@ -518,45 +195,64 @@
|
|||
<outputDirectory>${assembly-directory}</outputDirectory>
|
||||
<destFileName>start.jar</destFileName>
|
||||
</artifactItem>
|
||||
<artifactItem>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-websocket</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<type>jar</type>
|
||||
<overWrite>true</overWrite>
|
||||
<includes>**</includes>
|
||||
<outputDirectory>${assembly-directory}/lib</outputDirectory>
|
||||
</artifactItem>
|
||||
<artifactItem>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-overlay-deployer</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<type>jar</type>
|
||||
<overWrite>true</overWrite>
|
||||
<includes>**</includes>
|
||||
<outputDirectory>${assembly-directory}/lib</outputDirectory>
|
||||
</artifactItem>
|
||||
<artifactItem>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-jsp-2.1</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<type>jar</type>
|
||||
<overWrite>true</overWrite>
|
||||
<includes>**</includes>
|
||||
<outputDirectory>${assembly-directory}/lib/jsp</outputDirectory>
|
||||
</artifactItem>
|
||||
<artifactItem>
|
||||
<groupId>org.glassfish.web</groupId>
|
||||
<artifactId>jsp-impl</artifactId>
|
||||
<version>${central-jsp-version}</version>
|
||||
<type>jar</type>
|
||||
<overWrite>true</overWrite>
|
||||
<includes>**</includes>
|
||||
<outputDirectory>${assembly-directory}/lib/jsp</outputDirectory>
|
||||
</artifactItem>
|
||||
</artifactItems>
|
||||
</configuration>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>copy-lib-deps</id>
|
||||
<phase>generate-resources</phase>
|
||||
<goals>
|
||||
<goal>copy-dependencies</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<includeGroupIds>org.eclipse.jetty</includeGroupIds>
|
||||
<excludeArtifactIds>jetty-start,jetty-monitor</excludeArtifactIds>
|
||||
<includeTypes>jar</includeTypes>
|
||||
<outputDirectory>${assembly-directory}/lib</outputDirectory>
|
||||
</configuration>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>copy-lib-monitor-deps</id>
|
||||
<phase>generate-resources</phase>
|
||||
<goals>
|
||||
<goal>copy-dependencies</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<includeGroupIds>org.eclipse.jetty</includeGroupIds>
|
||||
<includeArtifactIds>jetty-monitor</includeArtifactIds>
|
||||
<includeTypes>jar</includeTypes>
|
||||
<excludeTransitive>true</excludeTransitive>
|
||||
<outputDirectory>${assembly-directory}/lib/monitor</outputDirectory>
|
||||
</configuration>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>unpack-config-deps</id>
|
||||
<phase>generate-resources</phase>
|
||||
<goals>
|
||||
<goal>unpack-dependencies</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<includeGroupIds>org.eclipse.jetty</includeGroupIds>
|
||||
<classifier>config</classifier>
|
||||
<failOnMissingClassifierArtifact>false</failOnMissingClassifierArtifact>
|
||||
<outputDirectory>${assembly-directory}</outputDirectory>
|
||||
</configuration>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>unpack-javadoc</id>
|
||||
<phase>generate-resources</phase>
|
||||
<goals>
|
||||
<goal>unpack-dependencies</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<!-- Use already generated javadoc, don't bother regenerating again -->
|
||||
<includeGroupIds>org.eclipse.jetty.aggregate</includeGroupIds>
|
||||
<includeArtifactIds>jetty-all</includeArtifactIds>
|
||||
<includeClassifier>javadoc</includeClassifier>
|
||||
<excludeTransitive>true</excludeTransitive>
|
||||
<outputDirectory>${assembly-directory}/javadoc</outputDirectory>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
|
@ -658,6 +354,16 @@
|
|||
<artifactId>jetty-policy</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-servlets</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-monitor</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-websocket</artifactId>
|
||||
|
@ -669,14 +375,11 @@
|
|||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-jsp-2.1</artifactId>
|
||||
<groupId>org.eclipse.jetty.aggregate</groupId>
|
||||
<artifactId>jetty-all</artifactId>
|
||||
<classifier>javadoc</classifier>
|
||||
<type>jar</type>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.glassfish.web</groupId>
|
||||
<artifactId>jsp-impl</artifactId>
|
||||
<version>${central-jsp-version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
|
|
|
@ -18,9 +18,10 @@
|
|||
# Below are some recommended options for Sun's JRE
|
||||
#-----------------------------------------------------------
|
||||
# --exec
|
||||
# -Dorg.apache.jasper.compiler.disablejsr199=true
|
||||
# -Dcom.sun.management.jmxremote
|
||||
# -Dorg.eclipse.jetty.util.log.IGNORED=true
|
||||
# -Dorg.eclipse.jetty.util.log.stderr.DEBUG=true
|
||||
# -Dorg.eclipse.jetty.LEVEL=DEBUG
|
||||
# -Dorg.eclipse.jetty.util.log.stderr.SOURCE=true
|
||||
# -Xmx2000m
|
||||
# -Xmn512m
|
||||
|
|
|
@ -2,15 +2,33 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-project</artifactId>
|
||||
<version>7.5.0-SNAPSHOT</version>
|
||||
<version>7.6.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>jetty-jsp-2.1</artifactId>
|
||||
<name>Jetty :: Jetty JSP Additions</name>
|
||||
<description>Additions to Jasper implementation from Glassfish</description>
|
||||
<artifactId>jetty-http-spi</artifactId>
|
||||
<name>Jetty :: Http Service Provider Interface</name>
|
||||
<properties>
|
||||
<bundle-symbolic-name>${project.groupId}.jsp-2.1</bundle-symbolic-name>
|
||||
<bundle-symbolic-name>${project.groupId}.http.spi</bundle-symbolic-name>
|
||||
</properties>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.sun.net.httpserver</groupId>
|
||||
<artifactId>http</artifactId>
|
||||
<version>20070405</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-server</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
|
@ -22,30 +40,22 @@
|
|||
<goals>
|
||||
<goal>manifest</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</execution>
|
||||
</executions>
|
||||
<configuration>
|
||||
<instructions>
|
||||
<Import-Package>
|
||||
com.sun.org.apache.commons.logging;version="[2.1,3)";glassfish="split",
|
||||
*
|
||||
</Import-Package>
|
||||
<Export-Package>org.eclipse.jetty*;version="${parsedVersion.osgiVersion}"</Export-Package>
|
||||
<Fragment-Host>org.apache.jasper.glassfish</Fragment-Host>
|
||||
<!-- disable the uses directive: we don't want to fore eeryone that uses us to
|
||||
have to depend on com.sun.org.apache.commons.logging provided by jasper-glassfish. -->
|
||||
<_nouses>true</_nouses>
|
||||
</instructions>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<!--
|
||||
Required for OSGI
|
||||
-->
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-jar-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>artifact-jar</id>
|
||||
<goals>
|
||||
<goal>jar</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
<configuration>
|
||||
<archive>
|
||||
<archive>
|
||||
<manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile>
|
||||
</archive>
|
||||
</configuration>
|
||||
|
@ -54,34 +64,9 @@
|
|||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>findbugs-maven-plugin</artifactId>
|
||||
<configuration>
|
||||
<onlyAnalyze>org.eclipse.jetty.jsp.*</onlyAnalyze>
|
||||
<onlyAnalyze>org.eclipse.jetty.http.spi.*</onlyAnalyze>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-util</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.mortbay.jetty</groupId>
|
||||
<artifactId>jsp-2.1-glassfish</artifactId>
|
||||
<version>${javax-servlet-jsp-version}</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>org.mortbay.jetty</groupId>
|
||||
<artifactId>servlet-api</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.servlet</groupId>
|
||||
<artifactId>servlet-api</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
|
@ -0,0 +1,150 @@
|
|||
package org.eclipse.jetty.http.spi;
|
||||
|
||||
//========================================================================
|
||||
//Copyright (c) 2004-2009 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.
|
||||
//========================================================================
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
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.handler.ContextHandler;
|
||||
|
||||
import com.sun.net.httpserver.Authenticator;
|
||||
import com.sun.net.httpserver.Authenticator.Result;
|
||||
import com.sun.net.httpserver.BasicAuthenticator;
|
||||
import com.sun.net.httpserver.HttpContext;
|
||||
import com.sun.net.httpserver.HttpExchange;
|
||||
import com.sun.net.httpserver.HttpHandler;
|
||||
import com.sun.net.httpserver.HttpPrincipal;
|
||||
|
||||
/**
|
||||
* Jetty handler that bridges requests to {@link HttpHandler}.
|
||||
*/
|
||||
public class HttpSpiContextHandler extends ContextHandler
|
||||
{
|
||||
|
||||
private HttpContext _httpContext;
|
||||
|
||||
private HttpHandler _httpHandler;
|
||||
|
||||
public HttpSpiContextHandler(HttpContext httpContext, HttpHandler httpHandler)
|
||||
{
|
||||
this._httpContext = httpContext;
|
||||
this._httpHandler = httpHandler;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doScope(String target, Request baseRequest, HttpServletRequest req, HttpServletResponse resp) throws IOException, ServletException
|
||||
{
|
||||
if (!target.startsWith(getContextPath()))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
HttpExchange jettyHttpExchange;
|
||||
if (baseRequest.isSecure())
|
||||
{
|
||||
jettyHttpExchange = new JettyHttpsExchange(_httpContext,req,resp);
|
||||
}
|
||||
else
|
||||
{
|
||||
jettyHttpExchange = new JettyHttpExchange(_httpContext,req,resp);
|
||||
}
|
||||
|
||||
// TODO: add filters processing
|
||||
|
||||
try
|
||||
{
|
||||
Authenticator auth = _httpContext.getAuthenticator();
|
||||
if (auth != null)
|
||||
{
|
||||
handleAuthentication(resp,jettyHttpExchange,auth);
|
||||
}
|
||||
else
|
||||
{
|
||||
_httpHandler.handle(jettyHttpExchange);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
PrintWriter writer = new PrintWriter(jettyHttpExchange.getResponseBody());
|
||||
|
||||
resp.setStatus(500);
|
||||
writer.println("<h2>HTTP ERROR: 500</h2>");
|
||||
writer.println("<pre>INTERNAL_SERVER_ERROR</pre>");
|
||||
writer.println("<p>RequestURI=" + req.getRequestURI() + "</p>");
|
||||
|
||||
writer.println("<pre>");
|
||||
ex.printStackTrace(writer);
|
||||
writer.println("</pre>");
|
||||
|
||||
writer.println("<p><i><small><a href=\"http://jetty.mortbay.org\">Powered by jetty://</a></small></i></p>");
|
||||
|
||||
writer.close();
|
||||
}
|
||||
finally
|
||||
{
|
||||
baseRequest.setHandled(true);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void handleAuthentication(HttpServletResponse resp, HttpExchange httpExchange, Authenticator auth) throws IOException
|
||||
{
|
||||
Result result = auth.authenticate(httpExchange);
|
||||
if (result instanceof Authenticator.Failure)
|
||||
{
|
||||
int rc = ((Authenticator.Failure)result).getResponseCode();
|
||||
for (Map.Entry<String,List<String>> header : httpExchange.getResponseHeaders().entrySet())
|
||||
{
|
||||
for (String value : header.getValue())
|
||||
resp.addHeader(header.getKey(),value);
|
||||
}
|
||||
resp.sendError(rc);
|
||||
}
|
||||
else if (result instanceof Authenticator.Retry)
|
||||
{
|
||||
int rc = ((Authenticator.Retry)result).getResponseCode();
|
||||
for (Map.Entry<String,List<String>> header : httpExchange.getResponseHeaders().entrySet())
|
||||
{
|
||||
for (String value : header.getValue())
|
||||
resp.addHeader(header.getKey(),value);
|
||||
}
|
||||
resp.setStatus(rc);
|
||||
resp.flushBuffer();
|
||||
}
|
||||
else if (result instanceof Authenticator.Success)
|
||||
{
|
||||
HttpPrincipal principal = ((Authenticator.Success)result).getPrincipal();
|
||||
((JettyExchange)httpExchange).setPrincipal(principal);
|
||||
_httpHandler.handle(httpExchange);
|
||||
}
|
||||
}
|
||||
|
||||
public HttpHandler getHttpHandler()
|
||||
{
|
||||
return _httpHandler;
|
||||
}
|
||||
|
||||
public void setHttpHandler(HttpHandler handler)
|
||||
{
|
||||
this._httpHandler = handler;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
// ========================================================================
|
||||
// Copyright (c) 2009-2009 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.http.spi;
|
||||
|
||||
import com.sun.net.httpserver.HttpPrincipal;
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
*/
|
||||
public interface JettyExchange
|
||||
{
|
||||
|
||||
HttpPrincipal getPrincipal();
|
||||
|
||||
void setPrincipal(HttpPrincipal principal);
|
||||
|
||||
}
|
|
@ -0,0 +1,106 @@
|
|||
package org.eclipse.jetty.http.spi;
|
||||
|
||||
//========================================================================
|
||||
//Copyright (c) 2004-2009 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.
|
||||
//========================================================================
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.sun.net.httpserver.Authenticator;
|
||||
import com.sun.net.httpserver.Filter;
|
||||
import com.sun.net.httpserver.HttpHandler;
|
||||
import com.sun.net.httpserver.HttpServer;
|
||||
|
||||
/**
|
||||
* Jetty implementation of {@link com.sun.net.httpserver.HttpContext}
|
||||
*/
|
||||
public class JettyHttpContext extends com.sun.net.httpserver.HttpContext
|
||||
{
|
||||
|
||||
private HttpSpiContextHandler _jettyContextHandler;
|
||||
|
||||
private HttpServer _server;
|
||||
|
||||
private Map<String,Object> _attributes = new HashMap<String,Object>();
|
||||
|
||||
private List<Filter> _filters = new ArrayList<Filter>();
|
||||
|
||||
private Authenticator _authenticator;
|
||||
|
||||
|
||||
protected JettyHttpContext(HttpServer server, String path,
|
||||
HttpHandler handler)
|
||||
{
|
||||
this._server = server;
|
||||
_jettyContextHandler = new HttpSpiContextHandler(this, handler);
|
||||
_jettyContextHandler.setContextPath(path);
|
||||
}
|
||||
|
||||
protected HttpSpiContextHandler getJettyContextHandler()
|
||||
{
|
||||
return _jettyContextHandler;
|
||||
}
|
||||
|
||||
@Override
|
||||
public HttpHandler getHandler()
|
||||
{
|
||||
return _jettyContextHandler.getHttpHandler();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setHandler(HttpHandler h)
|
||||
{
|
||||
_jettyContextHandler.setHttpHandler(h);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPath()
|
||||
{
|
||||
return _jettyContextHandler.getContextPath();
|
||||
}
|
||||
|
||||
@Override
|
||||
public HttpServer getServer()
|
||||
{
|
||||
return _server;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> getAttributes()
|
||||
{
|
||||
return _attributes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Filter> getFilters()
|
||||
{
|
||||
return _filters;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Authenticator setAuthenticator(Authenticator auth)
|
||||
{
|
||||
Authenticator previous = _authenticator;
|
||||
_authenticator = auth;
|
||||
return previous;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Authenticator getAuthenticator()
|
||||
{
|
||||
return _authenticator;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,252 @@
|
|||
// ========================================================================
|
||||
// Copyright (c) 2009-2009 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.http.spi;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.URI;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import com.sun.net.httpserver.Headers;
|
||||
import com.sun.net.httpserver.HttpContext;
|
||||
import com.sun.net.httpserver.HttpExchange;
|
||||
import com.sun.net.httpserver.HttpPrincipal;
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
*/
|
||||
public class JettyHttpExchange extends HttpExchange implements JettyExchange
|
||||
{
|
||||
private JettyHttpExchangeDelegate _delegate;
|
||||
|
||||
public JettyHttpExchange(HttpContext jaxWsContext, HttpServletRequest req, HttpServletResponse resp)
|
||||
{
|
||||
super();
|
||||
_delegate = new JettyHttpExchangeDelegate(jaxWsContext,req,resp);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @see org.eclipse.jetty.http.spi.JettyExchange#hashCode()
|
||||
*/
|
||||
@Override
|
||||
public int hashCode()
|
||||
{
|
||||
return _delegate.hashCode();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @see org.eclipse.jetty.http.spi.JettyExchange#getRequestHeaders()
|
||||
*/
|
||||
@Override
|
||||
public Headers getRequestHeaders()
|
||||
{
|
||||
return _delegate.getRequestHeaders();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @see org.eclipse.jetty.http.spi.JettyExchange#getResponseHeaders()
|
||||
*/
|
||||
@Override
|
||||
public Headers getResponseHeaders()
|
||||
{
|
||||
return _delegate.getResponseHeaders();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @see org.eclipse.jetty.http.spi.JettyExchange#getRequestURI()
|
||||
*/
|
||||
@Override
|
||||
public URI getRequestURI()
|
||||
{
|
||||
return _delegate.getRequestURI();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @see org.eclipse.jetty.http.spi.JettyExchange#getRequestMethod()
|
||||
*/
|
||||
@Override
|
||||
public String getRequestMethod()
|
||||
{
|
||||
return _delegate.getRequestMethod();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @see org.eclipse.jetty.http.spi.JettyExchange#getHttpContext()
|
||||
*/
|
||||
@Override
|
||||
public HttpContext getHttpContext()
|
||||
{
|
||||
return _delegate.getHttpContext();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @see org.eclipse.jetty.http.spi.JettyExchange#close()
|
||||
*/
|
||||
@Override
|
||||
public void close()
|
||||
{
|
||||
_delegate.close();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @see org.eclipse.jetty.http.spi.JettyExchange#equals(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object obj)
|
||||
{
|
||||
return _delegate.equals(obj);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @see org.eclipse.jetty.http.spi.JettyExchange#getRequestBody()
|
||||
*/
|
||||
@Override
|
||||
public InputStream getRequestBody()
|
||||
{
|
||||
return _delegate.getRequestBody();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @see org.eclipse.jetty.http.spi.JettyExchange#getResponseBody()
|
||||
*/
|
||||
@Override
|
||||
public OutputStream getResponseBody()
|
||||
{
|
||||
return _delegate.getResponseBody();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @see org.eclipse.jetty.http.spi.JettyExchange#sendResponseHeaders(int, long)
|
||||
*/
|
||||
@Override
|
||||
public void sendResponseHeaders(int rCode, long responseLength) throws IOException
|
||||
{
|
||||
_delegate.sendResponseHeaders(rCode,responseLength);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @see org.eclipse.jetty.http.spi.JettyExchange#getRemoteAddress()
|
||||
*/
|
||||
@Override
|
||||
public InetSocketAddress getRemoteAddress()
|
||||
{
|
||||
return _delegate.getRemoteAddress();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @see org.eclipse.jetty.http.spi.JettyExchange#getResponseCode()
|
||||
*/
|
||||
@Override
|
||||
public int getResponseCode()
|
||||
{
|
||||
return _delegate.getResponseCode();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @see org.eclipse.jetty.http.spi.JettyExchange#getLocalAddress()
|
||||
*/
|
||||
@Override
|
||||
public InetSocketAddress getLocalAddress()
|
||||
{
|
||||
return _delegate.getLocalAddress();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @see org.eclipse.jetty.http.spi.JettyExchange#getProtocol()
|
||||
*/
|
||||
@Override
|
||||
public String getProtocol()
|
||||
{
|
||||
return _delegate.getProtocol();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @see org.eclipse.jetty.http.spi.JettyExchange#getAttribute(java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public Object getAttribute(String name)
|
||||
{
|
||||
return _delegate.getAttribute(name);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @see org.eclipse.jetty.http.spi.JettyExchange#setAttribute(java.lang.String, java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public void setAttribute(String name, Object value)
|
||||
{
|
||||
_delegate.setAttribute(name,value);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @see org.eclipse.jetty.http.spi.JettyExchange#setStreams(java.io.InputStream, java.io.OutputStream)
|
||||
*/
|
||||
@Override
|
||||
public void setStreams(InputStream i, OutputStream o)
|
||||
{
|
||||
_delegate.setStreams(i,o);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @see org.eclipse.jetty.http.spi.JettyExchange#getPrincipal()
|
||||
*/
|
||||
@Override
|
||||
public HttpPrincipal getPrincipal()
|
||||
{
|
||||
return _delegate.getPrincipal();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @see org.eclipse.jetty.http.spi.JettyExchange#setPrincipal(com.sun.net.httpserver.HttpPrincipal)
|
||||
*/
|
||||
public void setPrincipal(HttpPrincipal principal)
|
||||
{
|
||||
_delegate.setPrincipal(principal);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @see org.eclipse.jetty.http.spi.JettyExchange#toString()
|
||||
*/
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return _delegate.toString();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,228 @@
|
|||
package org.eclipse.jetty.http.spi;
|
||||
|
||||
//========================================================================
|
||||
//Copyright (c) 2004-2009 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.
|
||||
//========================================================================
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.Enumeration;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import com.sun.net.httpserver.Headers;
|
||||
import com.sun.net.httpserver.HttpContext;
|
||||
import com.sun.net.httpserver.HttpExchange;
|
||||
import com.sun.net.httpserver.HttpPrincipal;
|
||||
|
||||
/**
|
||||
* Jetty implementation of {@link com.sun.net.httpserver.HttpExchange}
|
||||
*/
|
||||
public class JettyHttpExchangeDelegate extends HttpExchange
|
||||
{
|
||||
|
||||
private HttpContext _httpContext;
|
||||
|
||||
private HttpServletRequest _req;
|
||||
|
||||
private HttpServletResponse _resp;
|
||||
|
||||
private Headers _responseHeaders = new Headers();
|
||||
|
||||
private int _responseCode = 0;
|
||||
|
||||
private InputStream _is;
|
||||
|
||||
private OutputStream _os;
|
||||
|
||||
private HttpPrincipal _httpPrincipal;
|
||||
|
||||
JettyHttpExchangeDelegate(HttpContext jaxWsContext, HttpServletRequest req, HttpServletResponse resp)
|
||||
{
|
||||
this._httpContext = jaxWsContext;
|
||||
this._req = req;
|
||||
this._resp = resp;
|
||||
try
|
||||
{
|
||||
this._is = req.getInputStream();
|
||||
this._os = resp.getOutputStream();
|
||||
}
|
||||
catch (IOException ex)
|
||||
{
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Headers getRequestHeaders()
|
||||
{
|
||||
Headers headers = new Headers();
|
||||
Enumeration<?> en = _req.getHeaderNames();
|
||||
while (en.hasMoreElements())
|
||||
{
|
||||
String name = (String)en.nextElement();
|
||||
Enumeration<?> en2 = _req.getHeaders(name);
|
||||
while (en2.hasMoreElements())
|
||||
{
|
||||
String value = (String)en2.nextElement();
|
||||
headers.add(name,value);
|
||||
}
|
||||
}
|
||||
return headers;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Headers getResponseHeaders()
|
||||
{
|
||||
return _responseHeaders;
|
||||
}
|
||||
|
||||
@Override
|
||||
public URI getRequestURI()
|
||||
{
|
||||
try
|
||||
{
|
||||
String uriAsString = _req.getRequestURI();
|
||||
if (_req.getQueryString() != null)
|
||||
{
|
||||
uriAsString += "?" + _req.getQueryString();
|
||||
}
|
||||
|
||||
return new URI(uriAsString);
|
||||
}
|
||||
catch (URISyntaxException ex)
|
||||
{
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRequestMethod()
|
||||
{
|
||||
return _req.getMethod();
|
||||
}
|
||||
|
||||
@Override
|
||||
public HttpContext getHttpContext()
|
||||
{
|
||||
return _httpContext;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close()
|
||||
{
|
||||
try
|
||||
{
|
||||
_resp.getOutputStream().close();
|
||||
}
|
||||
catch (IOException ex)
|
||||
{
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream getRequestBody()
|
||||
{
|
||||
return _is;
|
||||
}
|
||||
|
||||
@Override
|
||||
public OutputStream getResponseBody()
|
||||
{
|
||||
return _os;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendResponseHeaders(int rCode, long responseLength) throws IOException
|
||||
{
|
||||
this._responseCode = rCode;
|
||||
|
||||
for (Map.Entry<String, List<String>> stringListEntry : _responseHeaders.entrySet())
|
||||
{
|
||||
String name = stringListEntry.getKey();
|
||||
List<String> values = stringListEntry.getValue();
|
||||
|
||||
for (String value : values)
|
||||
{
|
||||
_resp.setHeader(name,value);
|
||||
}
|
||||
}
|
||||
if (responseLength > 0)
|
||||
{
|
||||
_resp.setHeader("content-length","" + responseLength);
|
||||
}
|
||||
_resp.setStatus(rCode);
|
||||
}
|
||||
|
||||
@Override
|
||||
public InetSocketAddress getRemoteAddress()
|
||||
{
|
||||
return new InetSocketAddress(_req.getRemoteAddr(),_req.getRemotePort());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getResponseCode()
|
||||
{
|
||||
return _responseCode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InetSocketAddress getLocalAddress()
|
||||
{
|
||||
return new InetSocketAddress(_req.getLocalAddr(),_req.getLocalPort());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getProtocol()
|
||||
{
|
||||
return _req.getProtocol();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getAttribute(String name)
|
||||
{
|
||||
return _req.getAttribute(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAttribute(String name, Object value)
|
||||
{
|
||||
_req.setAttribute(name,value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setStreams(InputStream i, OutputStream o)
|
||||
{
|
||||
_is = i;
|
||||
_os = o;
|
||||
}
|
||||
|
||||
@Override
|
||||
public HttpPrincipal getPrincipal()
|
||||
{
|
||||
return _httpPrincipal;
|
||||
}
|
||||
|
||||
public void setPrincipal(HttpPrincipal principal)
|
||||
{
|
||||
this._httpPrincipal = principal;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,262 @@
|
|||
package org.eclipse.jetty.http.spi;
|
||||
|
||||
//========================================================================
|
||||
//Copyright (c) 2004-2009 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.
|
||||
//========================================================================
|
||||
|
||||
import com.sun.net.httpserver.HttpContext;
|
||||
import com.sun.net.httpserver.HttpHandler;
|
||||
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.HandlerCollection;
|
||||
import org.eclipse.jetty.server.handler.ContextHandlerCollection;
|
||||
import org.eclipse.jetty.server.nio.SelectChannelConnector;
|
||||
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
|
||||
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
|
||||
/**
|
||||
* Jetty implementation of {@link com.sun.net.httpserver.HttpServer}.
|
||||
*/
|
||||
public class JettyHttpServer extends com.sun.net.httpserver.HttpServer
|
||||
{
|
||||
private static final Logger LOG = Log.getLogger(JettyHttpServer.class);
|
||||
|
||||
|
||||
private Server _server;
|
||||
|
||||
private boolean _serverShared;
|
||||
|
||||
private InetSocketAddress _addr;
|
||||
|
||||
private ThreadPoolExecutor _executor;
|
||||
|
||||
private Map<String, JettyHttpContext> _contexts = new HashMap<String, JettyHttpContext>();
|
||||
|
||||
private Map<String, Connector> _connectors = new HashMap<String, Connector>();
|
||||
|
||||
|
||||
public JettyHttpServer(Server server, boolean shared)
|
||||
{
|
||||
this._server = server;
|
||||
this._serverShared = shared;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bind(InetSocketAddress addr, int backlog) throws IOException
|
||||
{
|
||||
// check if there is already a connector listening
|
||||
Connector[] connectors = _server.getConnectors();
|
||||
if (connectors != null)
|
||||
{
|
||||
for (Connector connector : connectors)
|
||||
{
|
||||
if (connector.getPort() == addr.getPort()) {
|
||||
if (LOG.isDebugEnabled()) LOG.debug("server already bound to port " + addr.getPort() + ", no need to rebind");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (_serverShared)
|
||||
throw new IOException("jetty server is not bound to port " + addr.getPort());
|
||||
|
||||
this._addr = addr;
|
||||
|
||||
if (LOG.isDebugEnabled()) LOG.debug("binding server to port " + addr.getPort());
|
||||
SelectChannelConnector connector = new SelectChannelConnector();
|
||||
connector.setAcceptors(1);
|
||||
connector.setPort(addr.getPort());
|
||||
connector.setHost(addr.getHostName());
|
||||
_server.addConnector(connector);
|
||||
|
||||
_connectors.put(addr.getHostName() + addr.getPort(), connector);
|
||||
}
|
||||
|
||||
@Override
|
||||
public InetSocketAddress getAddress()
|
||||
{
|
||||
return _addr;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start()
|
||||
{
|
||||
if (_serverShared) return;
|
||||
|
||||
try
|
||||
{
|
||||
_server.start();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setExecutor(Executor executor)
|
||||
{
|
||||
if (executor == null)
|
||||
throw new IllegalArgumentException("missing required 'executor' argument");
|
||||
|
||||
if (!(executor instanceof ThreadPoolExecutor))
|
||||
throw new IllegalArgumentException("only java.util.concurrent.ThreadPoolExecutor instances are allowed, got: " + executor.getClass().getName());
|
||||
|
||||
if (LOG.isDebugEnabled()) LOG.debug("using ThreadPoolExecutor for server thread pool");
|
||||
this._executor = (ThreadPoolExecutor) executor;
|
||||
_server.setThreadPool(new ThreadPoolExecutorAdapter(_executor));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Executor getExecutor()
|
||||
{
|
||||
return _executor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop(int delay)
|
||||
{
|
||||
cleanUpContexts();
|
||||
cleanUpConnectors();
|
||||
|
||||
if (_serverShared) return;
|
||||
|
||||
try
|
||||
{
|
||||
_server.stop();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
private void cleanUpContexts()
|
||||
{
|
||||
for (Map.Entry<String, JettyHttpContext> stringJettyHttpContextEntry : _contexts.entrySet())
|
||||
{
|
||||
JettyHttpContext context = stringJettyHttpContextEntry.getValue();
|
||||
_server.removeBean(context.getJettyContextHandler());
|
||||
}
|
||||
_contexts.clear();
|
||||
}
|
||||
|
||||
private void cleanUpConnectors()
|
||||
{
|
||||
for (Map.Entry<String, Connector> stringConnectorEntry : _connectors.entrySet())
|
||||
{
|
||||
Connector connector = stringConnectorEntry.getValue();
|
||||
try
|
||||
{
|
||||
connector.stop();
|
||||
} catch (Exception ex) {
|
||||
LOG.warn(ex);
|
||||
}
|
||||
_server.removeConnector(connector);
|
||||
}
|
||||
_connectors.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public HttpContext createContext(String path, HttpHandler httpHandler)
|
||||
{
|
||||
checkIfContextIsFree(path);
|
||||
|
||||
JettyHttpContext context = new JettyHttpContext(this, path, httpHandler);
|
||||
HttpSpiContextHandler jettyContextHandler = context.getJettyContextHandler();
|
||||
|
||||
ContextHandlerCollection chc = findContextHandlerCollection(_server.getHandlers());
|
||||
if (chc == null)
|
||||
throw new RuntimeException("could not find ContextHandlerCollection, you must configure one");
|
||||
|
||||
chc.addHandler(jettyContextHandler);
|
||||
_contexts.put(path, context);
|
||||
|
||||
return context;
|
||||
}
|
||||
|
||||
private ContextHandlerCollection findContextHandlerCollection(Handler[] handlers)
|
||||
{
|
||||
if (handlers == null)
|
||||
return null;
|
||||
|
||||
for (Handler handler : handlers)
|
||||
{
|
||||
if (handler instanceof ContextHandlerCollection)
|
||||
{
|
||||
return (ContextHandlerCollection) handler;
|
||||
}
|
||||
|
||||
if (handler instanceof HandlerCollection)
|
||||
{
|
||||
HandlerCollection hc = (HandlerCollection) handler;
|
||||
ContextHandlerCollection chc = findContextHandlerCollection(hc.getHandlers());
|
||||
if (chc != null)
|
||||
return chc;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private void checkIfContextIsFree(String path)
|
||||
{
|
||||
Handler serverHandler = _server.getHandler();
|
||||
if (serverHandler instanceof ContextHandler)
|
||||
{
|
||||
ContextHandler ctx = (ContextHandler) serverHandler;
|
||||
if (ctx.getContextPath().equals(path))
|
||||
throw new RuntimeException("another context already bound to path " + path);
|
||||
}
|
||||
|
||||
Handler[] handlers = _server.getHandlers();
|
||||
if (handlers == null) return;
|
||||
|
||||
for (Handler handler : handlers)
|
||||
{
|
||||
if (handler instanceof ContextHandler) {
|
||||
ContextHandler ctx = (ContextHandler) handler;
|
||||
if (ctx.getContextPath().equals(path))
|
||||
throw new RuntimeException("another context already bound to path " + path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public HttpContext createContext(String path)
|
||||
{
|
||||
return createContext(path, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeContext(String path) throws IllegalArgumentException
|
||||
{
|
||||
JettyHttpContext context = _contexts.remove(path);
|
||||
if (context == null) return;
|
||||
_server.removeBean(context.getJettyContextHandler());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeContext(HttpContext context)
|
||||
{
|
||||
removeContext(context.getPath());
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,72 @@
|
|||
package org.eclipse.jetty.http.spi;
|
||||
|
||||
//========================================================================
|
||||
//Copyright (c) 2004-2009 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.
|
||||
//========================================================================
|
||||
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.InetSocketAddress;
|
||||
|
||||
import org.eclipse.jetty.server.Handler;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.server.handler.DefaultHandler;
|
||||
import org.eclipse.jetty.server.handler.HandlerCollection;
|
||||
import org.eclipse.jetty.server.handler.ContextHandlerCollection;
|
||||
|
||||
import com.sun.net.httpserver.HttpServer;
|
||||
import com.sun.net.httpserver.HttpsServer;
|
||||
import com.sun.net.httpserver.spi.HttpServerProvider;
|
||||
|
||||
/**
|
||||
* Jetty implementation of <a href="http://java.sun.com/javase/6/docs/jre/api/net/httpserver/spec/index.html">Java HTTP Server SPI</a>
|
||||
*/
|
||||
public class JettyHttpServerProvider extends HttpServerProvider
|
||||
{
|
||||
|
||||
private static Server _server;
|
||||
|
||||
public static void setServer(Server server)
|
||||
{
|
||||
_server = server;
|
||||
}
|
||||
|
||||
@Override
|
||||
public HttpServer createHttpServer(InetSocketAddress addr, int backlog)
|
||||
throws IOException
|
||||
{
|
||||
Server server = _server;
|
||||
boolean shared = true;
|
||||
|
||||
if (server == null)
|
||||
{
|
||||
server = new Server();
|
||||
|
||||
HandlerCollection handlerCollection = new HandlerCollection();
|
||||
handlerCollection.setHandlers(new Handler[] {new ContextHandlerCollection(), new DefaultHandler()});
|
||||
server.setHandler(handlerCollection);
|
||||
|
||||
shared = false;
|
||||
}
|
||||
|
||||
JettyHttpServer jettyHttpServer = new JettyHttpServer(server, shared);
|
||||
jettyHttpServer.bind(addr, backlog);
|
||||
return jettyHttpServer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public HttpsServer createHttpsServer(InetSocketAddress addr, int backlog) throws IOException
|
||||
{
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,179 @@
|
|||
// ========================================================================
|
||||
// Copyright (c) 2009-2009 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.http.spi;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.URI;
|
||||
|
||||
import javax.net.ssl.SSLSession;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import com.sun.net.httpserver.Headers;
|
||||
import com.sun.net.httpserver.HttpContext;
|
||||
import com.sun.net.httpserver.HttpPrincipal;
|
||||
import com.sun.net.httpserver.HttpsExchange;
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
*/
|
||||
public class JettyHttpsExchange extends HttpsExchange implements JettyExchange
|
||||
{
|
||||
private JettyHttpExchangeDelegate _delegate;
|
||||
|
||||
public JettyHttpsExchange(HttpContext jaxWsContext, HttpServletRequest req, HttpServletResponse resp)
|
||||
{
|
||||
super();
|
||||
_delegate = new JettyHttpExchangeDelegate(jaxWsContext,req,resp);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode()
|
||||
{
|
||||
return _delegate.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Headers getRequestHeaders()
|
||||
{
|
||||
return _delegate.getRequestHeaders();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Headers getResponseHeaders()
|
||||
{
|
||||
return _delegate.getResponseHeaders();
|
||||
}
|
||||
|
||||
@Override
|
||||
public URI getRequestURI()
|
||||
{
|
||||
return _delegate.getRequestURI();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRequestMethod()
|
||||
{
|
||||
return _delegate.getRequestMethod();
|
||||
}
|
||||
|
||||
@Override
|
||||
public HttpContext getHttpContext()
|
||||
{
|
||||
return _delegate.getHttpContext();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close()
|
||||
{
|
||||
_delegate.close();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj)
|
||||
{
|
||||
return _delegate.equals(obj);
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream getRequestBody()
|
||||
{
|
||||
return _delegate.getRequestBody();
|
||||
}
|
||||
|
||||
@Override
|
||||
public OutputStream getResponseBody()
|
||||
{
|
||||
return _delegate.getResponseBody();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendResponseHeaders(int rCode, long responseLength) throws IOException
|
||||
{
|
||||
_delegate.sendResponseHeaders(rCode,responseLength);
|
||||
}
|
||||
|
||||
@Override
|
||||
public InetSocketAddress getRemoteAddress()
|
||||
{
|
||||
return _delegate.getRemoteAddress();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getResponseCode()
|
||||
{
|
||||
return _delegate.getResponseCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public InetSocketAddress getLocalAddress()
|
||||
{
|
||||
return _delegate.getLocalAddress();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getProtocol()
|
||||
{
|
||||
return _delegate.getProtocol();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getAttribute(String name)
|
||||
{
|
||||
return _delegate.getAttribute(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAttribute(String name, Object value)
|
||||
{
|
||||
_delegate.setAttribute(name,value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setStreams(InputStream i, OutputStream o)
|
||||
{
|
||||
_delegate.setStreams(i,o);
|
||||
}
|
||||
|
||||
@Override
|
||||
public HttpPrincipal getPrincipal()
|
||||
{
|
||||
return _delegate.getPrincipal();
|
||||
}
|
||||
|
||||
public void setPrincipal(HttpPrincipal principal)
|
||||
{
|
||||
_delegate.setPrincipal(principal);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return _delegate.toString();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @see com.sun.net.httpserver.HttpsExchange#getSSLSession()
|
||||
*/
|
||||
@Override
|
||||
public SSLSession getSSLSession()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,119 @@
|
|||
package org.eclipse.jetty.http.spi;
|
||||
|
||||
//========================================================================
|
||||
//Copyright (c) 2004-2009 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.
|
||||
//========================================================================
|
||||
|
||||
import java.util.concurrent.RejectedExecutionException;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.eclipse.jetty.util.component.AbstractLifeCycle;
|
||||
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
|
||||
|
||||
import org.eclipse.jetty.util.thread.ThreadPool;
|
||||
|
||||
/**
|
||||
* Jetty {@link ThreadPool} that bridges requests to a {@link ThreadPoolExecutor}.
|
||||
*/
|
||||
public class ThreadPoolExecutorAdapter extends AbstractLifeCycle implements ThreadPool
|
||||
{
|
||||
private static final Logger LOG = Log.getLogger(ThreadPoolExecutorAdapter.class);
|
||||
|
||||
|
||||
private ThreadPoolExecutor executor;
|
||||
|
||||
public ThreadPoolExecutorAdapter(ThreadPoolExecutor executor)
|
||||
{
|
||||
this.executor = executor;
|
||||
}
|
||||
|
||||
public boolean dispatch(Runnable job)
|
||||
{
|
||||
try
|
||||
{
|
||||
executor.execute(job);
|
||||
return true;
|
||||
}
|
||||
catch(RejectedExecutionException e)
|
||||
{
|
||||
LOG.warn(e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public int getIdleThreads()
|
||||
{
|
||||
return executor.getPoolSize()-executor.getActiveCount();
|
||||
}
|
||||
|
||||
public int getThreads()
|
||||
{
|
||||
return executor.getPoolSize();
|
||||
}
|
||||
|
||||
public boolean isLowOnThreads()
|
||||
{
|
||||
return executor.getActiveCount()>=executor.getMaximumPoolSize();
|
||||
}
|
||||
|
||||
public void join() throws InterruptedException
|
||||
{
|
||||
executor.awaitTermination(Long.MAX_VALUE, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
|
||||
|
||||
public boolean isFailed()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isRunning()
|
||||
{
|
||||
return !executor.isTerminated() && !executor.isTerminating();
|
||||
}
|
||||
|
||||
public boolean isStarted()
|
||||
{
|
||||
return !executor.isTerminated() && !executor.isTerminating();
|
||||
}
|
||||
|
||||
public boolean isStarting()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isStopped()
|
||||
{
|
||||
return executor.isTerminated();
|
||||
}
|
||||
|
||||
public boolean isStopping()
|
||||
{
|
||||
return executor.isTerminating();
|
||||
}
|
||||
|
||||
protected void doStart() throws Exception
|
||||
{
|
||||
if (executor.isTerminated() || executor.isTerminating() || executor.isShutdown())
|
||||
throw new IllegalStateException("Cannot restart");
|
||||
}
|
||||
|
||||
protected void doStop() throws Exception
|
||||
{
|
||||
executor.shutdown();
|
||||
if (!executor.awaitTermination(60, TimeUnit.SECONDS))
|
||||
executor.shutdownNow();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
org.eclipse.jetty.http.spi.JettyHttpServerProvider
|
|
@ -0,0 +1,71 @@
|
|||
package org.eclipse.jetty.http.spi;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import com.sun.net.httpserver.BasicAuthenticator;
|
||||
import com.sun.net.httpserver.Headers;
|
||||
import com.sun.net.httpserver.HttpContext;
|
||||
import com.sun.net.httpserver.HttpExchange;
|
||||
import com.sun.net.httpserver.HttpHandler;
|
||||
import com.sun.net.httpserver.HttpServer;
|
||||
|
||||
|
||||
public class TestSPIServer
|
||||
{
|
||||
public static void main(String[] args) throws Exception
|
||||
{
|
||||
String host="localhost";
|
||||
int port = 8080;
|
||||
|
||||
HttpServer server = new JettyHttpServerProvider().createHttpServer(new
|
||||
InetSocketAddress(host, port), 10);
|
||||
server.start();
|
||||
|
||||
final HttpContext httpContext = server.createContext("/",
|
||||
new HttpHandler()
|
||||
{
|
||||
|
||||
@Override
|
||||
public void handle(HttpExchange exchange) throws IOException
|
||||
{
|
||||
Headers responseHeaders = exchange.getResponseHeaders();
|
||||
responseHeaders.set("Content-Type","text/plain");
|
||||
exchange.sendResponseHeaders(200,0);
|
||||
|
||||
OutputStream responseBody = exchange.getResponseBody();
|
||||
Headers requestHeaders = exchange.getRequestHeaders();
|
||||
Set<String> keySet = requestHeaders.keySet();
|
||||
Iterator<String> iter = keySet.iterator();
|
||||
while (iter.hasNext())
|
||||
{
|
||||
String key = iter.next();
|
||||
List values = requestHeaders.get(key);
|
||||
String s = key + " = " + values.toString() + "\n";
|
||||
responseBody.write(s.getBytes());
|
||||
}
|
||||
responseBody.close();
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
httpContext.setAuthenticator(new BasicAuthenticator("Test")
|
||||
{
|
||||
@Override
|
||||
public boolean checkCredentials(String username, String password)
|
||||
{
|
||||
if ("username".equals(username) && password.equals("password"))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
Thread.sleep(10000000);
|
||||
|
||||
}
|
||||
}
|
|
@ -2,7 +2,7 @@
|
|||
<parent>
|
||||
<artifactId>jetty-project</artifactId>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<version>7.5.0-SNAPSHOT</version>
|
||||
<version>7.6.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
|
|
|
@ -4,11 +4,11 @@
|
|||
// 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
|
||||
// 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.
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
|
||||
package org.eclipse.jetty.http;
|
||||
|
@ -27,11 +27,11 @@ import org.eclipse.jetty.util.log.Logger;
|
|||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Abstract Generator. Builds HTTP Messages.
|
||||
*
|
||||
*
|
||||
* Currently this class uses a system parameter "jetty.direct.writers" to control
|
||||
* two optional writer to byte conversions. buffer.writers=true will probably be
|
||||
* two optional writer to byte conversions. buffer.writers=true will probably be
|
||||
* faster, but will consume more memory. This option is just for testing and tuning.
|
||||
*
|
||||
*
|
||||
*/
|
||||
public abstract class AbstractGenerator implements Generator
|
||||
{
|
||||
|
@ -42,16 +42,16 @@ public abstract class AbstractGenerator implements Generator
|
|||
public final static int STATE_CONTENT = 2;
|
||||
public final static int STATE_FLUSHING = 3;
|
||||
public final static int STATE_END = 4;
|
||||
|
||||
|
||||
public static final byte[] NO_BYTES = {};
|
||||
|
||||
// data
|
||||
|
||||
protected final Buffers _buffers; // source of buffers
|
||||
protected final EndPoint _endp;
|
||||
|
||||
|
||||
protected int _state = STATE_HEADER;
|
||||
|
||||
|
||||
protected int _status = 0;
|
||||
protected int _version = HttpVersions.HTTP_1_1_ORDINAL;
|
||||
protected Buffer _reason;
|
||||
|
@ -64,20 +64,20 @@ public abstract class AbstractGenerator implements Generator
|
|||
protected boolean _head = false;
|
||||
protected boolean _noContent = false;
|
||||
protected Boolean _persistent = null;
|
||||
|
||||
|
||||
protected Buffer _header; // Buffer for HTTP header (and maybe small _content)
|
||||
protected Buffer _buffer; // Buffer for copy of passed _content
|
||||
protected Buffer _content; // Buffer passed to addContent
|
||||
|
||||
|
||||
protected Buffer _date;
|
||||
|
||||
|
||||
private boolean _sendServerVersion;
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------- */
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
*
|
||||
* @param buffers buffer pool
|
||||
* @param io the end point
|
||||
*/
|
||||
|
@ -89,18 +89,18 @@ public abstract class AbstractGenerator implements Generator
|
|||
|
||||
/* ------------------------------------------------------------------------------- */
|
||||
public abstract boolean isRequest();
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------- */
|
||||
public abstract boolean isResponse();
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------- */
|
||||
public boolean isOpen()
|
||||
{
|
||||
return _endp.isOpen();
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------- */
|
||||
public void reset(boolean returnBuffers)
|
||||
public void reset()
|
||||
{
|
||||
_state = STATE_HEADER;
|
||||
_status = 0;
|
||||
|
@ -114,27 +114,13 @@ public abstract class AbstractGenerator implements Generator
|
|||
_contentLength = HttpTokens.UNKNOWN_CONTENT;
|
||||
_date = null;
|
||||
|
||||
// always return the body buffer
|
||||
if (_buffer!=null)
|
||||
_buffers.returnBuffer(_buffer);
|
||||
_buffer=null;
|
||||
|
||||
if (returnBuffers)
|
||||
{
|
||||
if (_header!=null)
|
||||
_buffers.returnBuffer(_header);
|
||||
_header=null;
|
||||
}
|
||||
else if (_header != null)
|
||||
_header.clear();
|
||||
|
||||
_content = null;
|
||||
_method=null;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------------- */
|
||||
public void returnBuffers()
|
||||
{
|
||||
{
|
||||
if (_buffer!=null && _buffer.length()==0)
|
||||
{
|
||||
_buffers.returnBuffer(_buffer);
|
||||
|
@ -145,22 +131,22 @@ public abstract class AbstractGenerator implements Generator
|
|||
{
|
||||
_buffers.returnBuffer(_header);
|
||||
_header=null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------- */
|
||||
public void resetBuffer()
|
||||
{
|
||||
{
|
||||
if(_state>=STATE_FLUSHING)
|
||||
throw new IllegalStateException("Flushed");
|
||||
|
||||
|
||||
_last = false;
|
||||
_persistent=null;
|
||||
_contentWritten = 0;
|
||||
_contentLength = HttpTokens.UNKNOWN_CONTENT;
|
||||
_content=null;
|
||||
if (_buffer!=null)
|
||||
_buffer.clear();
|
||||
_buffer.clear();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
@ -190,25 +176,25 @@ public abstract class AbstractGenerator implements Generator
|
|||
_buffer = nb;
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public Buffer getUncheckedBuffer()
|
||||
{
|
||||
return _buffer;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public boolean getSendServerVersion ()
|
||||
{
|
||||
return _sendServerVersion;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public void setSendServerVersion (boolean sendServerVersion)
|
||||
{
|
||||
_sendServerVersion = sendServerVersion;
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public int getState()
|
||||
{
|
||||
|
@ -256,7 +242,7 @@ public abstract class AbstractGenerator implements Generator
|
|||
else
|
||||
_contentLength=value;
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @param head The head to set.
|
||||
|
@ -277,7 +263,7 @@ public abstract class AbstractGenerator implements Generator
|
|||
?_persistent.booleanValue()
|
||||
:(isRequest()?true:_version>HttpVersions.HTTP_1_0_ORDINAL);
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public void setPersistent(boolean persistent)
|
||||
{
|
||||
|
@ -291,7 +277,7 @@ public abstract class AbstractGenerator implements Generator
|
|||
*/
|
||||
public void setVersion(int version)
|
||||
{
|
||||
if (_state != STATE_HEADER)
|
||||
if (_state != STATE_HEADER)
|
||||
throw new IllegalStateException("STATE!=START "+_state);
|
||||
_version = version;
|
||||
if (_version==HttpVersions.HTTP_0_9_ORDINAL && _method!=null)
|
||||
|
@ -303,7 +289,7 @@ public abstract class AbstractGenerator implements Generator
|
|||
{
|
||||
return _version;
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @see org.eclipse.jetty.http.Generator#setDate(org.eclipse.jetty.io.Buffer)
|
||||
|
@ -340,7 +326,7 @@ public abstract class AbstractGenerator implements Generator
|
|||
if (reason!=null)
|
||||
{
|
||||
int len=reason.length();
|
||||
|
||||
|
||||
// TODO don't hard code
|
||||
if (len>1024)
|
||||
len=1024;
|
||||
|
@ -378,14 +364,14 @@ public abstract class AbstractGenerator implements Generator
|
|||
if(_buffer!=null)
|
||||
_buffer.clear();
|
||||
}
|
||||
else
|
||||
else
|
||||
{
|
||||
_contentWritten+=_buffer.length();
|
||||
if (_head)
|
||||
_buffer.clear();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public boolean isBufferFull()
|
||||
{
|
||||
|
@ -404,20 +390,20 @@ public abstract class AbstractGenerator implements Generator
|
|||
{
|
||||
return _contentWritten>0;
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public boolean isAllContentWritten()
|
||||
{
|
||||
return _contentLength>=0 && _contentWritten>=_contentLength;
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public abstract void completeHeader(HttpFields fields, boolean allContentAdded) throws IOException;
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Complete the message.
|
||||
*
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
public void complete() throws IOException
|
||||
|
@ -436,9 +422,9 @@ public abstract class AbstractGenerator implements Generator
|
|||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public abstract long flushBuffer() throws IOException;
|
||||
public abstract int flushBuffer() throws IOException;
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public void flush(long maxIdleTime) throws IOException
|
||||
{
|
||||
|
@ -450,29 +436,20 @@ public abstract class AbstractGenerator implements Generator
|
|||
if (content!=null && content.length()>0 || buffer!=null && buffer.length()>0 || isBufferFull())
|
||||
{
|
||||
flushBuffer();
|
||||
|
||||
|
||||
while (now<end && (content!=null && content.length()>0 ||buffer!=null && buffer.length()>0) && _endp.isOpen()&& !_endp.isOutputShutdown())
|
||||
{
|
||||
blockForOutput(end-now);
|
||||
now=System.currentTimeMillis();
|
||||
}
|
||||
}
|
||||
|
||||
// make sure buffered data is also flushed
|
||||
while (now<end && _endp.isBufferingOutput() && _endp.isOpen() && !_endp.isOutputShutdown())
|
||||
{
|
||||
if (!_endp.isBlocking())
|
||||
_endp.blockWritable(end-now);
|
||||
_endp.flush();
|
||||
now=System.currentTimeMillis();
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Utility method to send an error response. If the builder is not committed, this call is
|
||||
* equivalent to a setResponse, addContent and complete call.
|
||||
*
|
||||
*
|
||||
* @param code The error code
|
||||
* @param reason The error reason
|
||||
* @param content Contents of the error page
|
||||
|
@ -483,10 +460,15 @@ public abstract class AbstractGenerator implements Generator
|
|||
{
|
||||
if (close)
|
||||
_persistent=false;
|
||||
if (!isCommitted())
|
||||
if (isCommitted())
|
||||
{
|
||||
LOG.debug("sendError on committed: {} {}",code,reason);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG.debug("sendError: {} {}",code,reason);
|
||||
setResponse(code, reason);
|
||||
if (content != null)
|
||||
if (content != null)
|
||||
{
|
||||
completeHeader(null, false);
|
||||
addContent(new View(new ByteArrayBuffer(content)), Generator.LAST);
|
||||
|
@ -507,7 +489,7 @@ public abstract class AbstractGenerator implements Generator
|
|||
{
|
||||
return _contentWritten;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
@ -532,9 +514,9 @@ public abstract class AbstractGenerator implements Generator
|
|||
_endp.close();
|
||||
throw new EofException("timeout");
|
||||
}
|
||||
|
||||
|
||||
flushBuffer();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -50,7 +50,7 @@ public interface Generator
|
|||
|
||||
void completeHeader(HttpFields responseFields, boolean last) throws IOException;
|
||||
|
||||
long flushBuffer() throws IOException;
|
||||
int flushBuffer() throws IOException;
|
||||
|
||||
int getContentBufferSize();
|
||||
|
||||
|
@ -70,7 +70,7 @@ public interface Generator
|
|||
|
||||
boolean isPersistent();
|
||||
|
||||
void reset(boolean returnBuffers);
|
||||
void reset();
|
||||
|
||||
void resetBuffer();
|
||||
|
||||
|
|
|
@ -24,7 +24,7 @@ import org.eclipse.jetty.util.component.AbstractLifeCycle;
|
|||
*/
|
||||
public class HttpBuffers extends AbstractLifeCycle
|
||||
{
|
||||
private int _requestBufferSize=12*1024;
|
||||
private int _requestBufferSize=16*1024;
|
||||
private int _requestHeaderSize=6*1024;
|
||||
private int _responseBufferSize=32*1024;
|
||||
private int _responseHeaderSize=6*1024;
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue