Merge branch 'master' into release-9
This commit is contained in:
commit
36a5b50b65
309
VERSION.txt
309
VERSION.txt
|
@ -1,6 +1,6 @@
|
|||
jetty-9.0.0-SNAPSHOT
|
||||
|
||||
jetty-9.0.0.M2 - 05 November 2012
|
||||
jetty-9.0.0.M2 - 06 November 2012
|
||||
+ 371170 MongoSessionManager LastAccessTimeTest fails
|
||||
+ 391877 org.eclipse.jetty.webapp.FragmentDescriptor incorrectly reporting
|
||||
duplicate others for after ordering
|
||||
|
@ -24,9 +24,86 @@ jetty-9.0.0.M2 - 05 November 2012
|
|||
+ 393368 min websocket version
|
||||
+ 393383 delay onClose call until closeOut is done
|
||||
+ 393494 HashSessionManager can't delete unrestorable sessions on Windows
|
||||
+ JETTY-1547 Jetty does not honor web.xml
|
||||
web-app/jsp-config/jsp-property-group/default-content-type
|
||||
+ JETTY-1549 jetty-maven-plugin fails to reload the LoginService properly
|
||||
+ JETTY-1550 virtual WEB-INF not created if project has overlays
|
||||
|
||||
jetty-8.1.8.v20121106 - 06 November 2012
|
||||
+ 371170 MongoSessionManager LastAccessTimeTest fails
|
||||
+ 388675 Non utf8 encoded query strings not decoded to parameter map using
|
||||
queryEncoding
|
||||
+ 388706 Avoid unnecessary indirection through Charset.name
|
||||
+ 389390 AnnotationConfiguration is ignored if the metadata-complete attribute
|
||||
is present in an override descriptor regardless of the value
|
||||
+ 389452 if web-fragment metadata-complete==true still scan its related jar if
|
||||
there there is a ServletContainerInitializer, ensure webapp restarts work
|
||||
+ 389686 Fix reference to org.eclipse.jetty.util.log.stderr.LONG system
|
||||
property in javadoc for StdErrLog
|
||||
+ 389956 Bad __context set in WebAppContext.start sequence with respect to ENC
|
||||
setup
|
||||
+ 389965 OPTIONS should allow spaces in comma separated list
|
||||
+ 390108 Servlet 3.0 API for programmatic login doesn't appear to work
|
||||
+ 390161 Apply DeferredAuthentication fix to jaspi
|
||||
+ 390163 Implement ServletRegistration.Dynamic.setServletSecurity
|
||||
+ 390503 http-method-omission element not being processed
|
||||
+ 390560 The method AnnotationParser.getAnnotationHandlers(String) always
|
||||
returns a empty collection.
|
||||
+ 391080 Multipart temp files can be left on disk from Request.getPart and
|
||||
getParts
|
||||
+ 391082 No exception if multipart input stream incomplete
|
||||
+ 391188 Files written with Request.getPart().write(filename) should not be
|
||||
auto-deleted
|
||||
+ 391483 fix bad javadoc example in shutdown handler
|
||||
+ 391622 Be lenient on RFC6265 restriction on duplicate cookie names in same
|
||||
response
|
||||
+ 391623 Add option to --stop to wait for target jetty to stop
|
||||
+ 391877 org.eclipse.jetty.webapp.FragmentDescriptor incorrectly reporting
|
||||
duplicate others for after ordering
|
||||
+ 392239 Allow no error-code or exception for error-pages
|
||||
+ 392525 Add option to --stop-wait to specify timeout
|
||||
+ 392641 JDBC Sessions not scavenged if expired during downtime
|
||||
+ 392812 MongoSessionIDManager never purges old sessions
|
||||
+ 393014 Mongodb purgevalid using query for purgeinvalid
|
||||
+ 393015 Mongodb purge not rescheduled
|
||||
+ 393075 Jetty WebSocket client cannot connect to Tomcat WebSocket Server
|
||||
+ 393218 add xsd=application/xml mime mapping to defaults
|
||||
+ 393363 Use Locale.ENGLISH for all toUpperCase and toLowerCase calls
|
||||
+ 393368 min websocket version
|
||||
+ 393383 delay onClose call until closeOut is done
|
||||
+ 393494 HashSessionManager can't delete unrestorable sessions on Windows
|
||||
+ JETTY-1547 Jetty does not honor web.xml
|
||||
web-app/jsp-config/jsp-property-group/default-content-type
|
||||
|
||||
jetty-7.6.8.v20121106 - 06 November 2012
|
||||
+ 371170 MongoSessionManager LastAccessTimeTest fails
|
||||
+ 388675 Non utf8 encoded query strings not decoded to parameter map using
|
||||
queryEncoding
|
||||
+ 389686 Fix reference to org.eclipse.jetty.util.log.stderr.LONG system
|
||||
property in javadoc for StdErrLog
|
||||
+ 389956 Bad __context set in WebAppContext.start sequence with respect to ENC
|
||||
setup
|
||||
+ 389965 OPTIONS should allow spaces in comma separated list
|
||||
+ 390161 Apply DeferredAuthentication fix to jaspi
|
||||
+ 390560 The method AnnotationParser.getAnnotationHandlers(String) always
|
||||
returns a empty collection.
|
||||
+ 391483 fix bad javadoc example in shutdown handler
|
||||
+ 391622 Be lenient on RFC6265 restriction on duplicate cookie names in same
|
||||
response
|
||||
+ 391623 Add option to --stop to wait for target jetty to stop
|
||||
+ 392239 Allow no error-code or exception for error-pages
|
||||
+ 392525 Add option to --stop-wait to specify timeout
|
||||
+ 392641 JDBC Sessions not scavenged if expired during downtime
|
||||
+ 392812 MongoSessionIDManager never purges old sessions
|
||||
+ 393014 Mongodb purgevalid using query for purgeinvalid
|
||||
+ 393015 Mongodb purge not rescheduled
|
||||
+ 393075 Jetty WebSocket client cannot connect to Tomcat WebSocket Server
|
||||
+ 393218 add xsd=application/xml mime mapping to defaults
|
||||
+ 393363 Use Locale.ENGLISH for all toUpperCase and toLowerCase calls
|
||||
+ 393368 min websocket version
|
||||
+ 393383 delay onClose call until closeOut is done
|
||||
+ 393494 HashSessionManager can't delete unrestorable sessions on Windows
|
||||
|
||||
jetty-9.0.0.M1 - 15 October 2012
|
||||
+ 369349 directory with spaces --dry-run fix
|
||||
+ 385049 fix issue with pipelined connections when switching protocols
|
||||
|
@ -95,6 +172,10 @@ jetty-8.1.7.v20120910 - 10 September 2012
|
|||
+ 388895 Update dependencies for jetty-jndi
|
||||
+ fix busy logging statement re: sessions
|
||||
|
||||
jetty-7.6.7.v20120910 - 10 September 2012
|
||||
+ 388895 Update dependencies for jetty-jndi
|
||||
+ fix busy logging statement re: sessions
|
||||
|
||||
jetty-8.1.6.v20120903 - 03 September 2012
|
||||
+ 347130 Empty getResourcePaths due to ZipFileClosedException
|
||||
+ 367591 Support Env variables in XmlConfiguration.
|
||||
|
@ -128,6 +209,39 @@ jetty-8.1.6.v20120903 - 03 September 2012
|
|||
+ JETTY-1532 HTTP headers decoded with platform's default encoding
|
||||
+ JETTY-1541 fixed different behaviour for single byte writes
|
||||
|
||||
jetty-7.6.6.v20120903 - 03 September 2012
|
||||
+ 347130 Empty getResourcePaths due to ZipFileClosedException
|
||||
+ 367591 Support Env variables in XmlConfiguration.
|
||||
+ 377055 Prevent webapp classloader leaks
|
||||
+ 379207 backported fixes from jetty-9 to make hierarchy work
|
||||
+ 379423 Jetty URL Decoding fails for certain international characters
|
||||
+ 383304 Reset PrintWriter on response recycle
|
||||
+ 384847 better name
|
||||
+ 385049 fix issue with pipelined connections when switching protocols
|
||||
+ 385651 Message 'Address already in use' not specific enough
|
||||
+ 386010 JspRuntimeContext rewraps System.err
|
||||
+ 386591 add UnixCrypt note to about.html
|
||||
+ 386714 used deferred auth for form login and error pages
|
||||
+ 387896 populate session in SessionAuthentication as a valueBound in addition
|
||||
to activation so it is populate when needed
|
||||
+ 387943 Catch CNFE when no jstl jars are installed
|
||||
+ 387953 jstl does not work with jetty-7 in osgi
|
||||
+ 388072 GZipFilter incorrectly gzips when Accept-Encoding: gzip; q=0
|
||||
+ 388073 null session id from cookie causes NPE fixed
|
||||
+ 388102 Jetty HttpClient memory leaks when sending larger files
|
||||
+ 388393 WebAppProvider doesn't work alongside OSGi deployer
|
||||
+ 388502 handle earlyEOF with 500
|
||||
+ 388652 Do not flush on handle return if request is suspended
|
||||
+ JETTY-1501 Setting custom error response message changes page title
|
||||
+ JETTY-1515 Include cookies on 304 responses from DefaultServlet.
|
||||
+ JETTY-1527 handle requests with URIs like http://host (ie no / )
|
||||
+ JETTY-1529 Ensure new session that has just been authenticated does not get
|
||||
renewed
|
||||
+ JETTY-1532 HTTP headers decoded with platform's default encoding
|
||||
+ JETTY-1541 fixed different behaviour for single byte writes
|
||||
+ 385925: make SslContextFactory.setProtocols and
|
||||
SslContextFactory.setCipherSuites preserve the order of the given parameters
|
||||
|
||||
jetty-8.1.5.v20120716 - 16 June 2012
|
||||
+ 376717 Balancer Servlet with round robin support, contribution, added
|
||||
missing license
|
||||
|
@ -159,6 +273,32 @@ jetty-8.1.5.v20120716 - 16 June 2012
|
|||
+ JETTY-1525 Show handle status in response debug message
|
||||
+ JETTY-1530 refine search control on ldap login module
|
||||
|
||||
jetty-7.6.5.v20120716 - 16 July 2012
|
||||
+ 376717 Balancer Servlet with round robin support, contribution, added
|
||||
missing license
|
||||
+ 379250 Server is added to shutdown hook twice
|
||||
+ 380866 maxIdleTime set to 0 after session migration
|
||||
+ 381399 Unable to stop a jetty instance that has not finished starting
|
||||
+ 381401 Print log warning when stop attempt made with incorrect STOP.KEY
|
||||
+ 381402 Make ContextHandler take set of protected directories
|
||||
+ 381521 set Vary:Accept-Encoding header for content that might be compressed
|
||||
+ 381639 CrossOriginFilter does not support Access-Control-Expose-Headers.
|
||||
+ 381712 Support all declared servlets that implement
|
||||
org.apache.jasper.servlet.JspServlet
|
||||
+ 381825 leave URI params in forwarded requestURI
|
||||
+ 381876 Monitor should wait for child to finish before exiting.
|
||||
+ 382343 Jetty XML support for Map is broken.
|
||||
+ 383251 500 for SocketExceptions
|
||||
+ 383881 WebSocketHandler sets request as handled
|
||||
+ 384254 revert change to writable when not dispatched
|
||||
+ 384847 CrossOriginFilter is not working.
|
||||
+ 384896 JDBCSessionManager fails to load existing sessions on oracle when
|
||||
contextPath is /
|
||||
+ 384980 Jetty client unable to recover from Time outs when connection count
|
||||
per address hits max.
|
||||
+ JETTY-1525 Show handle status in response debug message
|
||||
+ JETTY-1530 refine search control on ldap login module
|
||||
|
||||
jetty-8.1.4.v20120524 - 24 May 2012
|
||||
+ 367608 ignore the aysncrequestreadtest as it is known to fail and is waiting
|
||||
for a fix
|
||||
|
@ -192,6 +332,38 @@ jetty-8.1.4.v20120524 - 24 May 2012
|
|||
+ 380212 Clear buffer if parsing fails due to full buffer
|
||||
+ 380222 JettyPolicyRuntimeTest failure
|
||||
|
||||
jetty-7.6.4.v20120524 - 24 May 2012
|
||||
+ 367608 ignore the aysncrequestreadtest as it is known to fail and is waiting
|
||||
for a fix
|
||||
+ 371853 Support bundleentry: protocol for webapp embedded as directory in
|
||||
osgi bundle
|
||||
+ 373620 Add ch.qos.logback.access.jetty to the Import-Package for
|
||||
jetty-osgi-boot-logback bundle
|
||||
+ 376152 apply context resources recursively
|
||||
+ 376801 Make JAAS login modules useable without jetty infrastructure
|
||||
+ 377391 Manifest updates to jetty-osgi-boot-logback
|
||||
+ 377492 NPE when deploying a Web Application Bundle with unresolved
|
||||
Require-TldBundle
|
||||
+ 377550 set charset when content type is set
|
||||
+ 377587 ConnectHandler write will block on partial write
|
||||
+ 377610 New session not timed out if an old session is invalidated in scope
|
||||
of same request
|
||||
+ 377709 Support for RequestParameterCallback missing
|
||||
+ 378242 Re-extract war on restart if incomplete extraction
|
||||
+ 378273 Remove default Bundle-Localization header
|
||||
+ 378487 Null out contextPath on Request.recycle
|
||||
+ 379015 Use factored jetty xml config files for defaults
|
||||
+ 379046 avoid closing idle connections from selector thread
|
||||
+ 379089 DefaultServlet ignores its resourceBase and uses context's
|
||||
ResourceCollection when listing diretories
|
||||
+ 379194 ProxyServlet enhancement to enable easy creation of alternative
|
||||
HttpClient implementations
|
||||
+ 379909 FormAuthenticator Rembers only the URL of first Request before
|
||||
authentication
|
||||
+ 380034 last modified times taken from JarEntry for JarFile resources
|
||||
+ 380212 Clear buffer if parsing fails due to full buffer
|
||||
+ 380222 JettyPolicyRuntimeTest failure
|
||||
|
||||
jetty-8.1.3.v20120416 - 16 April 2012
|
||||
+ 349110 MultiPartFilter records the content-type in request params
|
||||
+ 367172 Remove detection for slf4j NOPLogger
|
||||
|
@ -234,6 +406,38 @@ jetty-8.1.3.v20120416 - 16 April 2012
|
|||
request.getParameter
|
||||
+ JETTY-1504 HttpServletResponseWrapper ignored when using asyncContext?
|
||||
|
||||
jetty-7.6.3.v20120416 - 16 April 2012
|
||||
+ 367172 Remove detection for slf4j NOPLogger
|
||||
+ 373269 Make ServletHandler.notFound() method impl do nothing - override to
|
||||
send back 404.
|
||||
+ 373421 address potential race condition related to the nonce queue removing
|
||||
the same nonce twice
|
||||
+ 373952 bind called too frequently on refresh
|
||||
+ 374018 correctly handle requestperminuted underflow
|
||||
+ 374252 SslConnection.onClose() does not forward to nested connection.
|
||||
+ 374258 SPDY leaks SSLEngines. Made the test more reliable.
|
||||
+ 374367 NPE in QueuedThreadPool.dump() with early java6 jvms
|
||||
+ 374475 Response.sendRedirect does not encode UTF-8 characters properly
|
||||
+ 374881 Set copyWebInf to false by default
|
||||
+ 374891 enhancement to how ProxyServlet determines the proxy target
|
||||
+ 375009 Filter initialization error will throw MultiException
|
||||
+ 375083 Flow control should take in account window size changes from
|
||||
concurrent SETTINGS
|
||||
+ 375096 If starting a server instance fails in osgi it is cleaned up.
|
||||
+ 375490 NPE with --help on command line
|
||||
+ 375509 Stalled stream stalls other streams or session control frames. Now
|
||||
using a "death pill" instead of a boolean in order to avoid race conditions
|
||||
where DataInfos were read from the queue (but the boolean not updated yet),
|
||||
and viceversa.
|
||||
+ 375594 fixed SSL tests so they are not order dependent
|
||||
+ 375709 Ensure resolveTempDirectory failure does not deadlock; improve error
|
||||
message
|
||||
+ 375970 HttpServletRequest.getRemoteAddr() returns null when HTTP is over
|
||||
SPDY.
|
||||
+ 376201 HalfClosed state not handled properly. Addendum to restore previous
|
||||
behavior, where a closed stream was also half closed.
|
||||
+ JETTY-1504 HttpServletResponseWrapper ignored when using asyncContext?
|
||||
|
||||
jetty-8.1.2.v20120308 - 08 March 2012
|
||||
+ 370387 SafariWebsocketDraft0Test failure during build.
|
||||
+ 371168 Update ClientCrossContextSessionTest
|
||||
|
@ -256,6 +460,27 @@ jetty-8.1.2.v20120308 - 08 March 2012
|
|||
+ JETTY-1489 WebAppProvider attempts to deploy .svn folder
|
||||
+ JETTY-1494 .
|
||||
|
||||
jetty-7.6.2.v20120308 - 08 March 2012
|
||||
+ 370387 SafariWebsocketDraft0Test failure during build.
|
||||
+ 371168 Update ClientCrossContextSessionTest
|
||||
+ 372093 handle quotes in Require-Bundle manifest string
|
||||
+ 372457 Big response + slow clients + pipelined requests cause Jetty spinning
|
||||
and eventually closing connections. Added a TODO for a method renaming that
|
||||
will happen in the next major release (to avoid break implementers).
|
||||
+ 372487 JDBCSessionManager does not work with Oracle
|
||||
+ 372806 Command line should accept relative paths for xml config files
|
||||
+ 373037 jetty.server.Response.setContentLength(int) should not close a Writer
|
||||
when length=0
|
||||
+ 373162 add improved implementation for getParameterMap(), needs a test
|
||||
though and the existing setup doesn't seem like it would easily support the
|
||||
needed test so need to do that still
|
||||
+ 373306 Set default user agent extraction pattern for UserAgentFilter
|
||||
+ 373567 cert validation issue with ocsp and crldp always being enabled when
|
||||
validating turned on fixed
|
||||
+ JETTY-1409 GzipFilter will double-compress application/x-gzip content
|
||||
+ JETTY-1489 WebAppProvider attempts to deploy .svn folder
|
||||
+ JETTY-1494 .
|
||||
|
||||
jetty-8.1.1.v20120215 - 15 February 2012
|
||||
+ 369121 simplified test
|
||||
+ 370120 jvm arguments added via start.ini and --exec are missing spaces
|
||||
|
@ -270,12 +495,32 @@ jetty-8.1.1.v20120215 - 15 February 2012
|
|||
+ JETTY-1484 Add option for HashSessionManager to delete session files if it
|
||||
can't restore them
|
||||
|
||||
jetty-7.6.1.v20120215 - 15 February 2012
|
||||
+ 369121 simplified test
|
||||
+ 370120 jvm arguments added via start.ini and --exec are missing spaces
|
||||
+ 370137 SslContextFactory does not respect order for
|
||||
[included|excluded]Protocols() and [included|excluded]CipherSuites().
|
||||
+ 370368 resolve stack overflow in mongo db session manager
|
||||
+ 370386 Remove META-INF from jetty distro
|
||||
+ 371040 nosqlsession needs to call correct super contructor for new sessions
|
||||
+ 371041 valid was not being set to new mongo db sessions, and the call to
|
||||
mongodb api was wrong in isIdInUse
|
||||
+ 371162 NPE protection for nested security handlers
|
||||
+ JETTY-1484 Add option for HashSessionManager to delete session files if it
|
||||
can't restore them
|
||||
|
||||
jetty-8.1.0.v20120127 - 27 January 2012
|
||||
+ 368773 allow authentication to be set by non securityHandler handlers
|
||||
+ 368992 avoid update key while flushing during a write
|
||||
+ 369216 turned off the shared resource cache
|
||||
+ 369349 replace quotes with a space escape method
|
||||
|
||||
jetty-7.6.0.v20120127 - 27 January 2012
|
||||
+ 368773 allow authentication to be set by non securityHandler handlers
|
||||
+ 368992 avoid update key while flushing during a write
|
||||
+ 369216 turned off the shared resource cache
|
||||
+ 369349 replace quotes with a space escape method
|
||||
|
||||
jetty-8.1.0.RC5 - 20 January 2012
|
||||
+ 359329 Prevent reinvocation of LoginModule.login with jaspi for already
|
||||
authed user
|
||||
|
@ -291,6 +536,22 @@ jetty-8.1.0.RC5 - 20 January 2012
|
|||
+ JETTY-1475 made output state fields volatile to provide memory barrier for
|
||||
non dispatched thread IO
|
||||
|
||||
jetty-7.6.0.RC5 - 20 January 2012
|
||||
+ 359329 Prevent reinvocation of LoginModule.login with jaspi for already
|
||||
authed user
|
||||
+ 368632 Remove superfluous removal of org.apache.catalina.jsp_file
|
||||
+ 368633 fixed configure.dtd resource mappings
|
||||
+ 368635 moved lifecycle state reporting from toString to dump
|
||||
+ 368773 process data constraints without realm
|
||||
+ 368787 always set token view to new header buffers in httpparser
|
||||
+ 368821 improved test harness
|
||||
+ 368920 JettyAwareLogger always formats the arguments.
|
||||
+ 368948 POM for jetty-jndi references unknown version for javax.activation.
|
||||
+ 368992 avoid non-blocking flush when writing to avoid setting !_writable
|
||||
without _writeblocked
|
||||
+ JETTY-1475 made output state fields volatile to provide memory barrier for
|
||||
non dispatched thread IO
|
||||
|
||||
jetty-8.1.0.RC4 - 13 January 2012
|
||||
+ 365048 jetty Http client does not send proxy authentication when requesting
|
||||
a Https-resource through a web-proxy.
|
||||
|
@ -320,6 +581,21 @@ jetty-8.1.0.RC4 - 13 January 2012
|
|||
BeanELResolver.properties
|
||||
+ JETTY-1467 close half closed when idle
|
||||
|
||||
jetty-7.6.0.RC4 - 13 January 2012
|
||||
+ 365048 jetty Http client does not send proxy authentication when requesting
|
||||
a Https-resource through a web-proxy.
|
||||
+ 366774 removed XSS vulnerbility
|
||||
+ 367099 Upgrade jetty-websocket for RFC 6455 - Addendum.
|
||||
+ 367716 simplified maxIdleTime logic
|
||||
+ 368035 WebSocketClientFactory does not invoke super.doStop().
|
||||
+ 368060 do not encode sendRedirect URLs
|
||||
+ 368114 Protect against non-Strings in System properties for Log
|
||||
+ 368189 WebSocketClientFactory should not manage external thread pool.
|
||||
+ 368215 Remove debug from jaspi
|
||||
+ 368240 Improve AggregateLifeCycle handling of shared lifecycles
|
||||
+ 368291 Change warning to info for NoSuchFieldException on
|
||||
BeanELResolver.properties
|
||||
|
||||
jetty-8.1.0.RC2 - 22 December 2011
|
||||
+ 359329 jetty-jaspi must exports its packages. jetty-plus must import
|
||||
javax.security
|
||||
|
@ -344,6 +620,37 @@ jetty-8.1.0.RC2 - 22 December 2011
|
|||
+ JETTY-1463 websocket D0 parser should return progress even if no fill done
|
||||
+ JETTY-1465 NPE in ContextHandler.toString
|
||||
|
||||
jetty-7.6.0.RC3 - 05 January 2012
|
||||
+ 367433 added tests to investigate
|
||||
+ 367435 improved D00 test harness
|
||||
+ 367485 HttpExchange canceled before response do not release connection.
|
||||
+ 367502 WebSocket connections should be closed when application context is
|
||||
stopped.
|
||||
+ 367591 corrected configuration.xml version to 7.6
|
||||
+ 367635 Added support for start.d directory
|
||||
+ 367638 limit number of form parameters to avoid DOS
|
||||
+ JETTY-1467 close half closed when idle
|
||||
|
||||
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-8.1.0.RC1 - 06 December 2011
|
||||
+ 360245 The version of the javax.servlet packages to import is 2.6 instead of
|
||||
3.0
|
||||
|
|
|
@ -0,0 +1,175 @@
|
|||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<parent>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-project</artifactId>
|
||||
<version>9.0.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<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>
|
||||
<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>
|
||||
<excludes>**/MANIFEST.MF,javax/**</excludes>
|
||||
<excludeArtifactIds>javax</excludeArtifactIds>
|
||||
<excludeGroupIds>javax,org.eclipse.jetty.orbit</excludeGroupIds>
|
||||
<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/**,**/Servlet3Continuation*,**/Jetty6Continuation*</excludes>
|
||||
<includeGroupIds>org.eclipse.jetty</includeGroupIds>
|
||||
<excludeArtifactIds>javax</excludeArtifactIds>
|
||||
<excludeGroupIds>javax,org.eclipse.jetty.orbit</excludeGroupIds>
|
||||
<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://git.eclipse.org/c/jetty/org.eclipse.jetty.project.git/tree/NOTICE.txt</Bundle-License>
|
||||
<Bundle-Name>Jetty</Bundle-Name>
|
||||
</manifestEntries>
|
||||
</archive>
|
||||
</configuration>
|
||||
</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>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-client</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-deploy</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty.websocket</groupId>
|
||||
<artifactId>websocket-server</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty.websocket</groupId>
|
||||
<artifactId>websocket-client</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty.orbit</groupId>
|
||||
<artifactId>javax.servlet</artifactId>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-jmx</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-plus</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-annotations</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-util</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-jaspi</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-jndi</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-rewrite</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-servlets</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
|
@ -0,0 +1,102 @@
|
|||
<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">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>org.eclipse.jetty.dist</groupId>
|
||||
<artifactId>dist-parent</artifactId>
|
||||
<version>9.0.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>jetty-deb</artifactId>
|
||||
<name>Jetty :: Unix Distributions :: Debian</name>
|
||||
<packaging>deb</packaging>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.mortbay.jetty.toolchain</groupId>
|
||||
<artifactId>unix-maven-plugin</artifactId>
|
||||
<version>1.0-alpha-6.1</version>
|
||||
<extensions>true</extensions>
|
||||
<configuration>
|
||||
<contact>Jetty Project</contact>
|
||||
<contactEmail>jetty-dev@eclipse.org</contactEmail>
|
||||
<name>Core Jetty ${project.version} Distribution</name>
|
||||
<description>Jetty provides an Web server and javax.servlet
|
||||
container, plus support for Web Sockets, OSGi, JMX, JNDI,
|
||||
JASPI, AJP and many other integrations. These components are
|
||||
open source and available for commercial use and
|
||||
distribution.</description>
|
||||
<deb>
|
||||
<useFakeroot>false</useFakeroot>
|
||||
<priority>optional</priority>
|
||||
<section>java</section>
|
||||
</deb>
|
||||
<packages>
|
||||
<package>
|
||||
<id>jetty-server</id>
|
||||
<assembly>
|
||||
<extractArtifact>
|
||||
<artifact>org.eclipse.jetty:jetty-distribution:zip</artifact>
|
||||
<to>/usr/share/jetty9</to>
|
||||
<pattern>/jetty-distribution-${project.version}(.*)</pattern>
|
||||
<replacement>$1</replacement>
|
||||
<excludes>
|
||||
<exclude>jetty-distribution-*/javadoc</exclude>
|
||||
<exclude>jetty-distribution-*/javadoc/**</exclude>
|
||||
<exclude>jetty-distribution-*/logs/**</exclude>
|
||||
<exclude>jetty-distribution-*/bin/**</exclude>
|
||||
<exclude>jetty-distribution-*/webapps/**</exclude>
|
||||
<exclude>jetty-distribution-*/*.html</exclude>
|
||||
<exclude>jetty-distribution-*/*.txt</exclude>
|
||||
</excludes>
|
||||
</extractArtifact>
|
||||
<extractArtifact>
|
||||
<artifact>org.eclipse.jetty:jetty-distribution:zip</artifact>
|
||||
<to>/usr/share/doc/jetty9</to>
|
||||
<pattern>/jetty-distribution-${project.version}(.*)</pattern>
|
||||
<replacement>$1</replacement>
|
||||
<excludes>
|
||||
<include>jetty-distribution-*/*.html</include>
|
||||
<include>jetty-distribution-*/*.txt</include>
|
||||
<exclude>jetty-distribution-*/**</exclude>
|
||||
</excludes>
|
||||
</extractArtifact>
|
||||
<extractArtifact>
|
||||
<artifact>org.eclipse.jetty:jetty-distribution:zip</artifact>
|
||||
<to>/etc/jetty9</to>
|
||||
<pattern>/jetty-distribution-${project.version}(.*)</pattern>
|
||||
<replacement>$1</replacement>
|
||||
<excludes>
|
||||
<include>jetty-distribution-*/etc/**</include>
|
||||
<exclude>jetty-distribution-*/**</exclude>
|
||||
</excludes>
|
||||
</extractArtifact>
|
||||
</assembly>
|
||||
</package>
|
||||
<package>
|
||||
<id>jetty-test-webapp</id>
|
||||
<classifier>test-webapp</classifier>
|
||||
<assembly>
|
||||
<extractArtifact>
|
||||
<artifact>org.eclipse.jetty:jetty-distribution:zip</artifact>
|
||||
<to>/var/lib/jetty9/webapps</to>
|
||||
<pattern>/jetty-distribution-${project.version}(.*)</pattern>
|
||||
<replacement>$1</replacement>
|
||||
<includes>
|
||||
<include>jetty-distribution-*/webapps/**</include>
|
||||
</includes>
|
||||
</extractArtifact>
|
||||
</assembly>
|
||||
</package>
|
||||
</packages>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-distribution</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<type>zip</type>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
|
@ -0,0 +1,20 @@
|
|||
#!/bin/bash
|
||||
|
||||
LOG_DIR=/var/lib/jetty9/logs
|
||||
WEBAPP_DIR=/var/lib/jetty9/webapps
|
||||
|
||||
# copy the jetty start script into place
|
||||
cp /usr/share/jetty9/bin/jetty.sh /etc/init.d/jetty
|
||||
|
||||
# make it generally executable
|
||||
chmod 755 /etc/init.d/jetty
|
||||
|
||||
# ensure we have a logging directory
|
||||
if [ ! -d "$LOG_DIR" ]; then
|
||||
mkdir $LOG_DIR
|
||||
fi
|
||||
|
||||
# ensure we have a webapps directory
|
||||
if [ ! -d "$WEBAPP_DIR" ]; then
|
||||
mkdir $WEBAPP_DIR
|
||||
fi
|
|
@ -0,0 +1,48 @@
|
|||
#!/bin/bash
|
||||
|
||||
#rm -f /etc/init.d/jetty
|
||||
|
||||
case "$1" in
|
||||
purge)
|
||||
[...]
|
||||
# find first and last SYSTEM_UID numbers
|
||||
for LINE in `grep SYSTEM_UID /etc/adduser.conf | grep -v "^#"`; do
|
||||
case $LINE in
|
||||
FIRST_SYSTEM_UID*)
|
||||
FIST_SYSTEM_UID=`echo $LINE | cut -f2 -d '='`
|
||||
;;
|
||||
LAST_SYSTEM_UID*)
|
||||
LAST_SYSTEM_UID=`echo $LINE | cut -f2 -d '='`
|
||||
;;
|
||||
*)
|
||||
;;
|
||||
esac
|
||||
done
|
||||
# Remove system account if necessary
|
||||
CREATEDUSER="jetty"
|
||||
if [ -n "$FIST_SYSTEM_UID" ] && [ -n "$LAST_SYSTEM_UID" ]; then
|
||||
if USERID=`getent passwd $CREATEDUSER | cut -f 3 -d ':'`; then
|
||||
if [ -n "$USERID" ]; then
|
||||
if [ "$FIST_SYSTEM_UID" -le "$USERID" ] && \
|
||||
[ "$USERID" -le "$LAST_SYSTEM_UID" ]; then
|
||||
echo -n "Removing $CREATEDUSER system user.."
|
||||
deluser --quiet $CREATEDUSER || true
|
||||
echo "..done"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
# Remove system group if necessary
|
||||
CREATEDGROUP="jetty"
|
||||
FIRST_USER_GID=`grep ^USERS_GID /etc/adduser.conf | cut -f2 -d '='`
|
||||
if [ -n "$FIST_USER_GID" ] then
|
||||
if GROUPGID=`getent group $CREATEDGROUP | cut -f 3 -d ':'`; then
|
||||
if [ -n "$GROUPGID" ]; then
|
||||
if [ "$FIST_USER_GID" -gt "$GROUPGID" ]; then
|
||||
echo -n "Removing $CREATEDGROUP group.."
|
||||
delgroup --only-if-empty $CREATEDGROUP || true
|
||||
echo "..done"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
fi
|
|
@ -0,0 +1,60 @@
|
|||
#!/bin/bash
|
||||
|
||||
case "$1" in
|
||||
install|upgrade)
|
||||
|
||||
# If the package has default file it could be sourced, so that
|
||||
# the local admin can overwrite the defaults
|
||||
|
||||
[ -f "/etc/default/jetty9" ] && . /etc/default/jetty9
|
||||
|
||||
# Sane defaults:
|
||||
|
||||
[ -z "$SERVER_HOME" ] && SERVER_HOME=/usr/share/jetty9
|
||||
[ -z "$SERVER_USER" ] && SERVER_USER=jetty
|
||||
[ -z "$SERVER_NAME" ] && SERVER_NAME="Jetty-9 Http and Servlet Engine"
|
||||
[ -z "$SERVER_GROUP" ] && SERVER_GROUP=jetty
|
||||
|
||||
# Groups that the user will be added to, if undefined, then none.
|
||||
ADDGROUP=""
|
||||
|
||||
# create user to avoid running server as root
|
||||
# 1. create group if not existing
|
||||
if ! getent group | grep -q "^$SERVER_GROUP:" ; then
|
||||
echo -n "Adding group $SERVER_GROUP.."
|
||||
addgroup --quiet --system $SERVER_GROUP 2>/dev/null ||true
|
||||
echo "..done"
|
||||
fi
|
||||
# 2. create homedir if not existing
|
||||
test -d $SERVER_HOME || mkdir $SERVER_HOME
|
||||
# 3. create user if not existing
|
||||
if ! getent passwd | grep -q "^$SERVER_USER:"; then
|
||||
echo -n "Adding system user $SERVER_USER.."
|
||||
adduser --quiet \
|
||||
--system \
|
||||
--ingroup $SERVER_GROUP \
|
||||
--no-create-home \
|
||||
--disabled-password \
|
||||
$SERVER_USER 2>/dev/null || true
|
||||
echo "..done"
|
||||
fi
|
||||
# 4. adjust passwd entry
|
||||
usermod -c "$SERVER_NAME" \
|
||||
-d $SERVER_HOME \
|
||||
-g $SERVER_GROUP \
|
||||
$SERVER_USER
|
||||
# 5. adjust file and directory permissions
|
||||
if ! dpkg-statoverride --list $SERVER_HOME >/dev/null
|
||||
then
|
||||
chown -R $SERVER_USER:$SERVER_GROUP $SERVER_HOME
|
||||
chmod u=rwx,g=rxs,o= $SERVER_HOME
|
||||
fi
|
||||
# 6. Add the user to the ADDGROUP group
|
||||
if test -n $ADDGROUP
|
||||
then
|
||||
if ! groups $SERVER_USER | cut -d: -f2 | \
|
||||
grep -qw $ADDGROUP; then
|
||||
adduser $SERVER_USER $ADDGROUP
|
||||
fi
|
||||
fi
|
||||
;;
|
|
@ -0,0 +1,26 @@
|
|||
<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/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>jetty-project</artifactId>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<version>9.0.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>org.eclipse.jetty.dist</groupId>
|
||||
<artifactId>dist-parent</artifactId>
|
||||
<packaging>pom</packaging>
|
||||
<name>Jetty :: Distribution :: Parent</name>
|
||||
<profiles>
|
||||
<profile>
|
||||
<id>linux-packaging</id>
|
||||
<!-- activation>
|
||||
<os>
|
||||
<name>Linux</name>
|
||||
</os>
|
||||
</activation-->
|
||||
<modules>
|
||||
<module>jetty-deb</module>
|
||||
<!--module>jetty-rpm</module-->
|
||||
</modules>
|
||||
</profile>
|
||||
</profiles>
|
||||
</project>
|
|
@ -1,9 +1,9 @@
|
|||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<parent>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-project</artifactId>
|
||||
<artifactId>examples-parent</artifactId>
|
||||
<version>9.0.0-SNAPSHOT</version>
|
||||
<relativePath>../../pom.xml</relativePath>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<parent>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-project</artifactId>
|
||||
<artifactId>examples-parent</artifactId>
|
||||
<version>9.0.0-SNAPSHOT</version>
|
||||
<relativePath>../../pom.xml</relativePath>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>example-jetty-embedded</artifactId>
|
||||
|
|
|
@ -106,7 +106,7 @@ public class LikeJettyXml
|
|||
webapp_provider.setParentLoaderPriority(false);
|
||||
webapp_provider.setExtractWars(true);
|
||||
webapp_provider.setScanInterval(2);
|
||||
webapp_provider.setDefaultsDescriptor(jetty_home + "/etc/webdefault.xml");
|
||||
//webapp_provider.setDefaultsDescriptor(jetty_home + "/etc/webdefault.xml");
|
||||
deployer.addAppProvider(webapp_provider);
|
||||
|
||||
HashLoginService login = new HashLoginService();
|
||||
|
|
|
@ -0,0 +1,47 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
// ========================================================================
|
||||
// Copyright (c) Webtide LLC
|
||||
//
|
||||
// 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.apache.org/licenses/LICENSE-2.0.txt
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
-->
|
||||
<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">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-project</artifactId>
|
||||
<version>9.0.0-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>examples-parent</artifactId>
|
||||
<name>Jetty Examples :: Parent</name>
|
||||
<packaging>pom</packaging>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>findbugs-maven-plugin</artifactId>
|
||||
<configuration>
|
||||
<!-- No Point running Findbugs on example projects -->
|
||||
<skip>true</skip>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
<modules>
|
||||
<module>async-rest</module>
|
||||
<module>embedded</module>
|
||||
</modules>
|
||||
</project>
|
|
@ -1,4 +1,5 @@
|
|||
<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">
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<parent>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-project</artifactId>
|
||||
|
@ -8,7 +9,29 @@
|
|||
<artifactId>jetty-ant</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<name>Jetty :: Ant Plugin</name>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<artifactId>maven-dependency-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>copy-lib-deps</id>
|
||||
<phase>generate-resources</phase>
|
||||
<goals>
|
||||
<goal>copy-dependencies</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<includeGroupIds>org.eclipse.jetty</includeGroupIds>
|
||||
<excludeGroupIds>org.eclipse.jetty.orbit,org.eclipse.jetty.spdy,org.eclipse.jetty.websocket,org.eclipse.jetty.drafts</excludeGroupIds>
|
||||
<excludeArtifactIds>jetty-all,jetty-start,jetty-monitor,jetty-jsp</excludeArtifactIds>
|
||||
<includeTypes>jar</includeTypes>
|
||||
<outputDirectory>${project.build.directory}/test-lib</outputDirectory>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
|
@ -21,6 +44,11 @@
|
|||
<artifactId>ant</artifactId>
|
||||
<version>1.6.5</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ant</groupId>
|
||||
<artifactId>ant-launcher</artifactId>
|
||||
<version>1.6.5</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-security</artifactId>
|
||||
|
@ -35,7 +63,7 @@
|
|||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-webapp</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-annotations</artifactId>
|
||||
|
|
|
@ -35,9 +35,6 @@ import org.eclipse.jetty.webapp.WebXmlConfiguration;
|
|||
* properties into the configured web application. The list of classpath files,
|
||||
* the application base directory and web.xml file could be specified in this
|
||||
* way.
|
||||
*
|
||||
* @author Jakub Pawlowicz
|
||||
* @author Athena Yao
|
||||
*/
|
||||
public class AntWebXmlConfiguration extends WebXmlConfiguration
|
||||
{
|
||||
|
|
|
@ -37,8 +37,6 @@ import org.eclipse.jetty.util.Scanner;
|
|||
|
||||
/**
|
||||
* Ant task for running a Jetty server.
|
||||
*
|
||||
* @author Jakub Pawlowicz
|
||||
*/
|
||||
public class JettyRunTask extends Task
|
||||
{
|
||||
|
|
|
@ -27,7 +27,7 @@ import java.util.Iterator;
|
|||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.eclipse.jetty.ant.types.Connectors.Connector;
|
||||
import org.eclipse.jetty.ant.types.Connector;
|
||||
import org.eclipse.jetty.ant.utils.ServerProxy;
|
||||
import org.eclipse.jetty.ant.utils.TaskLog;
|
||||
import org.eclipse.jetty.ant.utils.WebApplicationProxy;
|
||||
|
@ -47,8 +47,6 @@ import org.xml.sax.SAXException;
|
|||
/**
|
||||
* A proxy class for interaction with Jetty server object. Used to have some
|
||||
* level of abstraction over standard Jetty classes.
|
||||
*
|
||||
* @author Jakub Pawlowicz
|
||||
*/
|
||||
public class ServerProxyImpl implements ServerProxy
|
||||
{
|
||||
|
@ -128,7 +126,10 @@ public class ServerProxyImpl implements ServerProxy
|
|||
jc.setPort(jettyConnector.getPort());
|
||||
jc.setIdleTimeout(jettyConnector.getMaxIdleTime());
|
||||
|
||||
|
||||
server.addConnector(jc);
|
||||
|
||||
|
||||
}
|
||||
|
||||
// Configures login services
|
||||
|
@ -217,6 +218,8 @@ public class ServerProxyImpl implements ServerProxy
|
|||
try
|
||||
{
|
||||
server.start();
|
||||
TaskLog.log("" + server.getConnectors()[0]);
|
||||
|
||||
startScanners();
|
||||
server.join();
|
||||
|
||||
|
|
|
@ -57,7 +57,6 @@ import org.eclipse.jetty.webapp.WebAppContext;
|
|||
/**
|
||||
* An abstraction layer over Jetty WebAppContext.
|
||||
*
|
||||
* @author Jakub Pawlowicz
|
||||
*/
|
||||
public class WebApplicationProxyImpl implements WebApplicationProxy
|
||||
{
|
||||
|
|
|
@ -0,0 +1,57 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2012 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.ant.types;
|
||||
|
||||
public class Connector
|
||||
{
|
||||
private int port;
|
||||
private int maxIdleTime;
|
||||
|
||||
public Connector()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public Connector(int port, int maxIdleTime)
|
||||
{
|
||||
this.port = port;
|
||||
this.maxIdleTime = maxIdleTime;
|
||||
}
|
||||
|
||||
public int getPort()
|
||||
{
|
||||
return port;
|
||||
}
|
||||
|
||||
public void setPort(int port)
|
||||
{
|
||||
this.port = port;
|
||||
}
|
||||
|
||||
public int getMaxIdleTime()
|
||||
{
|
||||
return maxIdleTime;
|
||||
}
|
||||
|
||||
public void setMaxIdleTime(int maxIdleTime)
|
||||
{
|
||||
this.maxIdleTime = maxIdleTime;
|
||||
}
|
||||
|
||||
}
|
|
@ -25,7 +25,6 @@ import java.util.List;
|
|||
/**
|
||||
* Specifies a jetty configuration <connectors/> element for Ant build file.
|
||||
*
|
||||
* @author Jakub Pawlowicz
|
||||
*/
|
||||
public class Connectors
|
||||
{
|
||||
|
@ -81,33 +80,4 @@ public class Connectors
|
|||
return defaultConnectors;
|
||||
}
|
||||
|
||||
public class Connector
|
||||
{
|
||||
private int port;
|
||||
private int maxIdleTime;
|
||||
|
||||
public Connector(int port, int maxIdleTime)
|
||||
{
|
||||
this.port = port;
|
||||
this.maxIdleTime = maxIdleTime;
|
||||
}
|
||||
|
||||
public int getPort() {
|
||||
return port;
|
||||
}
|
||||
|
||||
public void setPort(int port) {
|
||||
this.port = port;
|
||||
}
|
||||
|
||||
public int getMaxIdleTime() {
|
||||
return maxIdleTime;
|
||||
}
|
||||
|
||||
public void setMaxIdleTime(int maxIdleTime) {
|
||||
this.maxIdleTime = maxIdleTime;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -27,7 +27,6 @@ import org.eclipse.jetty.server.handler.ContextHandler;
|
|||
/**
|
||||
* Specifies <contextHandlers/> element in web app configuration.
|
||||
*
|
||||
* @author Jakub Pawlowicz
|
||||
*/
|
||||
public class ContextHandlers
|
||||
{
|
||||
|
|
|
@ -31,7 +31,6 @@ import org.apache.tools.ant.DirectoryScanner;
|
|||
* file. It is used to group application classes, libraries, and scannedTargets
|
||||
* elements.
|
||||
*
|
||||
* @author Jakub Pawlowicz
|
||||
*/
|
||||
public class FileMatchingConfiguration
|
||||
{
|
||||
|
|
|
@ -27,7 +27,6 @@ import org.eclipse.jetty.security.LoginService;
|
|||
/**
|
||||
* Specifies a jetty configuration <loginServices/> element for Ant build file.
|
||||
*
|
||||
* @author Jakub Pawlowicz
|
||||
*/
|
||||
public class LoginServices
|
||||
{
|
||||
|
|
|
@ -28,7 +28,6 @@ import org.eclipse.jetty.ant.utils.TaskLog;
|
|||
/**
|
||||
* Ant <systemProperties/> tag definition.
|
||||
*
|
||||
* @author Jakub Pawlowicz
|
||||
*/
|
||||
public class SystemProperties
|
||||
{
|
||||
|
|
|
@ -31,7 +31,6 @@ import org.apache.tools.ant.types.FileSet;
|
|||
/**
|
||||
* Ant's WebApp object definition.
|
||||
*
|
||||
* @author Jakub Pawlowicz
|
||||
*/
|
||||
public class WebApp
|
||||
{
|
||||
|
|
|
@ -27,7 +27,6 @@ import org.apache.tools.ant.Task;
|
|||
* Provides logging functionality for classes without access to the Ant project
|
||||
* variable.
|
||||
*
|
||||
* @author Jakub Pawlowicz
|
||||
*/
|
||||
public class TaskLog
|
||||
{
|
||||
|
|
|
@ -0,0 +1,297 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2012 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.ant;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.PipedInputStream;
|
||||
import java.io.PipedOutputStream;
|
||||
import java.io.PrintStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.apache.tools.ant.DefaultLogger;
|
||||
import org.apache.tools.ant.Project;
|
||||
import org.apache.tools.ant.ProjectHelper;
|
||||
import org.eclipse.jetty.toolchain.test.IO;
|
||||
|
||||
public class AntBuild
|
||||
{
|
||||
private Thread _process;
|
||||
private String _ant;
|
||||
|
||||
private int _port;
|
||||
private String _host;
|
||||
|
||||
public AntBuild(String ant)
|
||||
{
|
||||
_ant = ant;
|
||||
}
|
||||
|
||||
private class AntBuildProcess implements Runnable
|
||||
{
|
||||
List<String[]> connList;
|
||||
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
File buildFile = new File(_ant);
|
||||
|
||||
Project antProject = new Project();
|
||||
try
|
||||
{
|
||||
antProject.setUserProperty("ant.file",buildFile.getAbsolutePath());
|
||||
DefaultLogger logger = new DefaultLogger();
|
||||
|
||||
ConsoleParser parser = new ConsoleParser();
|
||||
connList = parser.newPattern(".*([0-9]+\\.[0-9]*\\.[0-9]*\\.[0-9]*):([0-9]*)",1);
|
||||
|
||||
PipedOutputStream pos = new PipedOutputStream();
|
||||
PipedInputStream pis = new PipedInputStream(pos);
|
||||
|
||||
PipedOutputStream pose = new PipedOutputStream();
|
||||
PipedInputStream pise = new PipedInputStream(pose);
|
||||
|
||||
startPump("STDOUT",parser,pis);
|
||||
startPump("STDERR",parser,pise);
|
||||
|
||||
logger.setErrorPrintStream(new PrintStream(pos));
|
||||
logger.setOutputPrintStream(new PrintStream(pose));
|
||||
logger.setMessageOutputLevel(Project.MSG_VERBOSE);
|
||||
antProject.addBuildListener(logger);
|
||||
|
||||
antProject.fireBuildStarted();
|
||||
antProject.init();
|
||||
|
||||
ProjectHelper helper = ProjectHelper.getProjectHelper();
|
||||
|
||||
antProject.addReference("ant.projectHelper",helper);
|
||||
|
||||
helper.parse(antProject,buildFile);
|
||||
|
||||
antProject.executeTarget("jetty.run");
|
||||
|
||||
parser.waitForDone(10000,TimeUnit.MILLISECONDS);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
antProject.fireBuildFinished(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void waitForStarted() throws Exception
|
||||
{
|
||||
while (connList == null || connList.isEmpty())
|
||||
{
|
||||
Thread.sleep(10);
|
||||
}
|
||||
}
|
||||
|
||||
public List<String[]> getConnectionList()
|
||||
{
|
||||
return connList;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void start() throws Exception
|
||||
{
|
||||
System.out.println("Starting Ant Build ...");
|
||||
AntBuildProcess abp = new AntBuildProcess();
|
||||
_process = new Thread(abp);
|
||||
|
||||
_process.start();
|
||||
|
||||
abp.waitForStarted();
|
||||
|
||||
// once this has returned we should have the connection info we need
|
||||
_host = abp.getConnectionList().get(0)[0];
|
||||
_port = Integer.parseInt(abp.getConnectionList().get(0)[1]);
|
||||
|
||||
}
|
||||
|
||||
public int getJettyPort()
|
||||
{
|
||||
return _port;
|
||||
}
|
||||
|
||||
public String getJettyHost()
|
||||
{
|
||||
return _host;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Stop the jetty server
|
||||
*/
|
||||
public void stop()
|
||||
{
|
||||
System.out.println("Stopping Ant Build ...");
|
||||
_process.interrupt();
|
||||
}
|
||||
|
||||
private static class ConsoleParser
|
||||
{
|
||||
private List<ConsolePattern> patterns = new ArrayList<ConsolePattern>();
|
||||
private CountDownLatch latch;
|
||||
private int count;
|
||||
|
||||
public List<String[]> newPattern(String exp, int cnt)
|
||||
{
|
||||
ConsolePattern pat = new ConsolePattern(exp,cnt);
|
||||
patterns.add(pat);
|
||||
count += cnt;
|
||||
|
||||
return pat.getMatches();
|
||||
}
|
||||
|
||||
public void parse(String line)
|
||||
{
|
||||
for (ConsolePattern pat : patterns)
|
||||
{
|
||||
Matcher mat = pat.getMatcher(line);
|
||||
if (mat.find())
|
||||
{
|
||||
int num = 0, count = mat.groupCount();
|
||||
String[] match = new String[count];
|
||||
while (num++ < count)
|
||||
{
|
||||
match[num - 1] = mat.group(num);
|
||||
}
|
||||
pat.getMatches().add(match);
|
||||
|
||||
if (pat.getCount() > 0)
|
||||
{
|
||||
getLatch().countDown();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void waitForDone(long timeout, TimeUnit unit) throws InterruptedException
|
||||
{
|
||||
getLatch().await(timeout,unit);
|
||||
}
|
||||
|
||||
private CountDownLatch getLatch()
|
||||
{
|
||||
synchronized (this)
|
||||
{
|
||||
if (latch == null)
|
||||
{
|
||||
latch = new CountDownLatch(count);
|
||||
}
|
||||
}
|
||||
|
||||
return latch;
|
||||
}
|
||||
}
|
||||
|
||||
private static class ConsolePattern
|
||||
{
|
||||
private Pattern pattern;
|
||||
private List<String[]> matches;
|
||||
private int count;
|
||||
|
||||
ConsolePattern(String exp, int cnt)
|
||||
{
|
||||
pattern = Pattern.compile(exp);
|
||||
matches = new ArrayList<String[]>();
|
||||
count = cnt;
|
||||
}
|
||||
|
||||
public Matcher getMatcher(String line)
|
||||
{
|
||||
return pattern.matcher(line);
|
||||
}
|
||||
|
||||
public List<String[]> getMatches()
|
||||
{
|
||||
return matches;
|
||||
}
|
||||
|
||||
public int getCount()
|
||||
{
|
||||
return count;
|
||||
}
|
||||
}
|
||||
|
||||
private void startPump(String mode, ConsoleParser parser, InputStream inputStream)
|
||||
{
|
||||
ConsoleStreamer pump = new ConsoleStreamer(mode,inputStream);
|
||||
pump.setParser(parser);
|
||||
Thread thread = new Thread(pump,"ConsoleStreamer/" + mode);
|
||||
thread.start();
|
||||
}
|
||||
|
||||
/**
|
||||
* Simple streamer for the console output from a Process
|
||||
*/
|
||||
private static class ConsoleStreamer implements Runnable
|
||||
{
|
||||
private String mode;
|
||||
private BufferedReader reader;
|
||||
private ConsoleParser parser;
|
||||
|
||||
public ConsoleStreamer(String mode, InputStream is)
|
||||
{
|
||||
this.mode = mode;
|
||||
this.reader = new BufferedReader(new InputStreamReader(is));
|
||||
}
|
||||
|
||||
public void setParser(ConsoleParser connector)
|
||||
{
|
||||
this.parser = connector;
|
||||
}
|
||||
|
||||
public void run()
|
||||
{
|
||||
String line;
|
||||
//System.out.printf("ConsoleStreamer/%s initiated%n",mode);
|
||||
try
|
||||
{
|
||||
while ((line = reader.readLine()) != (null))
|
||||
{
|
||||
if (parser != null)
|
||||
{
|
||||
parser.parse(line);
|
||||
}
|
||||
System.out.println("[" + mode + "] " + line);
|
||||
}
|
||||
}
|
||||
catch (IOException ignore)
|
||||
{
|
||||
/* ignore */
|
||||
}
|
||||
finally
|
||||
{
|
||||
IO.close(reader);
|
||||
}
|
||||
//System.out.printf("ConsoleStreamer/%s finished%n",mode);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -16,34 +16,36 @@
|
|||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.websocket.core.api;
|
||||
package org.eclipse.jetty.ant;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URI;
|
||||
|
||||
import org.eclipse.jetty.websocket.core.protocol.ExtensionConfig;
|
||||
import junit.framework.Assert;
|
||||
|
||||
public interface UpgradeRequest
|
||||
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
|
||||
import org.junit.Test;
|
||||
|
||||
public class JettyAntTaskTest
|
||||
{
|
||||
public void addExtensions(String... extConfigs);
|
||||
|
||||
public Map<String, String> getCookieMap();
|
||||
|
||||
public List<ExtensionConfig> getExtensions();
|
||||
|
||||
public String getHeader(String name);
|
||||
|
||||
public String getHost();
|
||||
|
||||
public String getHttpEndPointName();
|
||||
|
||||
public String getOrigin();
|
||||
|
||||
public List<String> getSubProtocols();
|
||||
|
||||
public boolean hasSubProtocol(String test);
|
||||
|
||||
public boolean isOrigin(String test);
|
||||
|
||||
public void setSubProtocols(String protocols);
|
||||
|
||||
|
||||
@Test
|
||||
public void testJettyTask() throws Exception
|
||||
{
|
||||
AntBuild build = new AntBuild(MavenTestingUtils.getTestResourceFile("test.xml").getAbsolutePath());
|
||||
|
||||
build.start();
|
||||
|
||||
URI uri = new URI("http://" + build.getJettyHost() + ":" + build.getJettyPort());
|
||||
|
||||
HttpURLConnection connection = (HttpURLConnection)uri.toURL().openConnection();
|
||||
|
||||
connection.connect();
|
||||
|
||||
Assert.assertEquals(404,connection.getResponseCode());
|
||||
|
||||
build.stop();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<project name="Jetty-Ant integration test" basedir=".">
|
||||
<path id="jetty.plugin.classpath">
|
||||
<fileset dir="target/test-lib" includes="*.jar"/>
|
||||
</path>
|
||||
|
||||
<taskdef classpathref="jetty.plugin.classpath" resource="tasks.properties" loaderref="jetty.loader" />
|
||||
|
||||
|
||||
<typedef name="connector" classname="org.eclipse.jetty.ant.types.Connector"
|
||||
classpathref="jetty.plugin.classpath" loaderref="jetty.loader" />
|
||||
|
||||
<target name="jetty.run">
|
||||
<jetty>
|
||||
<connectors>
|
||||
<connector port="0"/>
|
||||
</connectors>
|
||||
</jetty>
|
||||
</target>
|
||||
</project>
|
|
@ -20,7 +20,6 @@ package org.eclipse.jetty.client;
|
|||
|
||||
import java.io.IOException;
|
||||
import java.net.ConnectException;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.SocketAddress;
|
||||
import java.net.SocketException;
|
||||
import java.net.URI;
|
||||
|
@ -44,6 +43,7 @@ import org.eclipse.jetty.client.api.Connection;
|
|||
import org.eclipse.jetty.client.api.ContentResponse;
|
||||
import org.eclipse.jetty.client.api.CookieStore;
|
||||
import org.eclipse.jetty.client.api.Destination;
|
||||
import org.eclipse.jetty.client.api.ProxyConfiguration;
|
||||
import org.eclipse.jetty.client.api.Request;
|
||||
import org.eclipse.jetty.client.api.Response;
|
||||
import org.eclipse.jetty.http.HttpFields;
|
||||
|
@ -127,6 +127,7 @@ public class HttpClient extends ContainerLifeCycle
|
|||
private volatile long idleTimeout;
|
||||
private volatile boolean tcpNoDelay = true;
|
||||
private volatile boolean dispatchIO = true;
|
||||
private volatile ProxyConfiguration proxyConfig;
|
||||
|
||||
public HttpClient()
|
||||
{
|
||||
|
@ -297,6 +298,9 @@ public class HttpClient extends ContainerLifeCycle
|
|||
|
||||
protected HttpDestination provideDestination(String scheme, String host, int port)
|
||||
{
|
||||
if (port <= 0)
|
||||
port = "https".equalsIgnoreCase(scheme) ? 443 : 80;
|
||||
|
||||
String address = address(scheme, host, port);
|
||||
HttpDestination destination = destinations.get(address);
|
||||
if (destination == null)
|
||||
|
@ -328,15 +332,11 @@ public class HttpClient extends ContainerLifeCycle
|
|||
if (!Arrays.asList("http", "https").contains(scheme))
|
||||
throw new IllegalArgumentException("Invalid protocol " + scheme);
|
||||
|
||||
int port = request.getPort();
|
||||
if (port < 0)
|
||||
port = "https".equals(scheme) ? 443 : 80;
|
||||
|
||||
for (Response.ResponseListener listener : listeners)
|
||||
if (listener instanceof Schedulable)
|
||||
((Schedulable)listener).schedule(scheduler);
|
||||
|
||||
HttpDestination destination = provideDestination(scheme, request.getHost(), port);
|
||||
HttpDestination destination = provideDestination(scheme, request.getHost(), request.getPort());
|
||||
destination.send(request, listeners);
|
||||
}
|
||||
|
||||
|
@ -351,7 +351,7 @@ public class HttpClient extends ContainerLifeCycle
|
|||
channel.bind(bindAddress);
|
||||
configure(channel);
|
||||
channel.configureBlocking(false);
|
||||
channel.connect(new InetSocketAddress(destination.getHost(), destination.getPort()));
|
||||
channel.connect(destination.getConnectAddress());
|
||||
|
||||
Future<Connection> result = new ConnectionCallback(destination, callback);
|
||||
selectorManager.connect(channel, result);
|
||||
|
@ -596,6 +596,16 @@ public class HttpClient extends ContainerLifeCycle
|
|||
this.dispatchIO = dispatchIO;
|
||||
}
|
||||
|
||||
public ProxyConfiguration getProxyConfiguration()
|
||||
{
|
||||
return proxyConfig;
|
||||
}
|
||||
|
||||
public void setProxyConfiguration(ProxyConfiguration proxyConfig)
|
||||
{
|
||||
this.proxyConfig = proxyConfig;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dump(Appendable out, String indent) throws IOException
|
||||
{
|
||||
|
|
|
@ -155,6 +155,11 @@ public class HttpConnection extends AbstractConnection implements Connection
|
|||
path = "/";
|
||||
request.path(path);
|
||||
}
|
||||
if (destination.isProxied() && HttpMethod.CONNECT != request.getMethod())
|
||||
{
|
||||
path = request.getURI();
|
||||
request.path(path);
|
||||
}
|
||||
|
||||
Fields fields = request.getParams();
|
||||
if (!fields.isEmpty())
|
||||
|
@ -359,13 +364,13 @@ public class HttpConnection extends AbstractConnection implements Connection
|
|||
}
|
||||
}
|
||||
|
||||
public boolean abort(HttpExchange exchange, String reason)
|
||||
public boolean abort(HttpExchange exchange, Throwable cause)
|
||||
{
|
||||
// We want the return value to be that of the response
|
||||
// because if the response has already successfully
|
||||
// arrived then we failed to abort the exchange
|
||||
sender.abort(exchange, reason);
|
||||
return receiver.abort(exchange, reason);
|
||||
sender.abort(exchange, cause);
|
||||
return receiver.abort(exchange, cause);
|
||||
}
|
||||
|
||||
public void proceed(boolean proceed)
|
||||
|
|
|
@ -77,9 +77,9 @@ public class HttpContentResponse implements ContentResponse
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean abort(String reason)
|
||||
public boolean abort(Throwable cause)
|
||||
{
|
||||
return response.abort(reason);
|
||||
return response.abort(cause);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -98,10 +98,10 @@ public class HttpConversation implements Attributes
|
|||
attributes.clear();
|
||||
}
|
||||
|
||||
public boolean abort(String reason)
|
||||
public boolean abort(Throwable cause)
|
||||
{
|
||||
HttpExchange exchange = exchanges.peekLast();
|
||||
return exchange != null && exchange.abort(reason);
|
||||
return exchange != null && exchange.abort(cause);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -41,23 +41,27 @@ public class HttpCookieStore implements CookieStore
|
|||
|
||||
String host = destination.getHost();
|
||||
int port = destination.getPort();
|
||||
String key = host + ":" + port + path;
|
||||
String key = host + ":" + port;
|
||||
|
||||
// First lookup: direct hit
|
||||
Queue<HttpCookie> cookies = allCookies.get(key);
|
||||
// Root path lookup
|
||||
Queue<HttpCookie> cookies = allCookies.get(key + "/");
|
||||
if (cookies != null)
|
||||
accumulateCookies(destination, cookies, result);
|
||||
|
||||
// Second lookup: root path
|
||||
if (!"/".equals(path))
|
||||
// Path lookup
|
||||
String[] split = path.split("/");
|
||||
for (int i = 1; i < split.length; i++)
|
||||
{
|
||||
key = host + ":" + port + "/";
|
||||
String segment = split[i];
|
||||
key += "/" + segment;
|
||||
cookies = allCookies.get(key);
|
||||
if (cookies != null)
|
||||
accumulateCookies(destination, cookies, result);
|
||||
if (segment.length() > 0)
|
||||
key += "/";
|
||||
}
|
||||
|
||||
// Third lookup: parent domains
|
||||
// Domain lookup
|
||||
int domains = host.split("\\.").length - 1;
|
||||
for (int i = 2; i <= domains; ++i)
|
||||
{
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
package org.eclipse.jetty.client;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.nio.channels.AsynchronousCloseException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
@ -27,13 +28,19 @@ import java.util.concurrent.ArrayBlockingQueue;
|
|||
import java.util.concurrent.BlockingQueue;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.RejectedExecutionException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import org.eclipse.jetty.client.api.Connection;
|
||||
import org.eclipse.jetty.client.api.Destination;
|
||||
import org.eclipse.jetty.client.api.ProxyConfiguration;
|
||||
import org.eclipse.jetty.client.api.Request;
|
||||
import org.eclipse.jetty.client.api.Response;
|
||||
import org.eclipse.jetty.client.api.Result;
|
||||
import org.eclipse.jetty.client.util.TimedResponseListener;
|
||||
import org.eclipse.jetty.http.HttpHeader;
|
||||
import org.eclipse.jetty.http.HttpMethod;
|
||||
import org.eclipse.jetty.http.HttpScheme;
|
||||
import org.eclipse.jetty.util.Callback;
|
||||
import org.eclipse.jetty.util.FutureCallback;
|
||||
import org.eclipse.jetty.util.component.ContainerLifeCycle;
|
||||
|
@ -48,25 +55,28 @@ public class HttpDestination implements Destination, AutoCloseable, Dumpable
|
|||
private final AtomicInteger connectionCount = new AtomicInteger();
|
||||
private final HttpClient client;
|
||||
private final String scheme;
|
||||
private final String host;
|
||||
private final int port;
|
||||
private final InetSocketAddress address;
|
||||
private final Queue<RequestContext> requests;
|
||||
private final BlockingQueue<Connection> idleConnections;
|
||||
private final BlockingQueue<Connection> activeConnections;
|
||||
private final RequestNotifier requestNotifier;
|
||||
private final ResponseNotifier responseNotifier;
|
||||
private final InetSocketAddress proxyAddress;
|
||||
|
||||
public HttpDestination(HttpClient client, String scheme, String host, int port)
|
||||
{
|
||||
this.client = client;
|
||||
this.scheme = scheme;
|
||||
this.host = host;
|
||||
this.port = port;
|
||||
this.address = new InetSocketAddress(host, port);
|
||||
this.requests = new ArrayBlockingQueue<>(client.getMaxQueueSizePerAddress());
|
||||
this.idleConnections = new ArrayBlockingQueue<>(client.getMaxConnectionsPerAddress());
|
||||
this.activeConnections = new ArrayBlockingQueue<>(client.getMaxConnectionsPerAddress());
|
||||
this.requestNotifier = new RequestNotifier(client);
|
||||
this.responseNotifier = new ResponseNotifier(client);
|
||||
|
||||
ProxyConfiguration proxyConfig = client.getProxyConfiguration();
|
||||
proxyAddress = proxyConfig != null && proxyConfig.matches(host, port) ?
|
||||
new InetSocketAddress(proxyConfig.getHost(), proxyConfig.getPort()) : null;
|
||||
}
|
||||
|
||||
protected BlockingQueue<Connection> getIdleConnections()
|
||||
|
@ -88,23 +98,33 @@ public class HttpDestination implements Destination, AutoCloseable, Dumpable
|
|||
@Override
|
||||
public String getHost()
|
||||
{
|
||||
return host;
|
||||
return address.getHostString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPort()
|
||||
{
|
||||
return port;
|
||||
return address.getPort();
|
||||
}
|
||||
|
||||
public InetSocketAddress getConnectAddress()
|
||||
{
|
||||
return isProxied() ? proxyAddress : address;
|
||||
}
|
||||
|
||||
public boolean isProxied()
|
||||
{
|
||||
return proxyAddress != null;
|
||||
}
|
||||
|
||||
public void send(Request request, List<Response.ResponseListener> listeners)
|
||||
{
|
||||
if (!scheme.equals(request.getScheme()))
|
||||
throw new IllegalArgumentException("Invalid request scheme " + request.getScheme() + " for destination " + this);
|
||||
if (!host.equals(request.getHost()))
|
||||
if (!getHost().equals(request.getHost()))
|
||||
throw new IllegalArgumentException("Invalid request host " + request.getHost() + " for destination " + this);
|
||||
int port = request.getPort();
|
||||
if (port >= 0 && this.port != port)
|
||||
if (port >= 0 && getPort() != port)
|
||||
throw new IllegalArgumentException("Invalid request port " + port + " for destination " + this);
|
||||
|
||||
RequestContext requestContext = new RequestContext(request, listeners);
|
||||
|
@ -139,7 +159,7 @@ public class HttpDestination implements Destination, AutoCloseable, Dumpable
|
|||
public Future<Connection> newConnection()
|
||||
{
|
||||
FutureCallback<Connection> result = new FutureCallback<>();
|
||||
newConnection(result);
|
||||
newConnection(new CONNECTCallback(result));
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -170,30 +190,31 @@ public class HttpDestination implements Destination, AutoCloseable, Dumpable
|
|||
if (connectionCount.compareAndSet(current, next))
|
||||
{
|
||||
LOG.debug("Creating connection {}/{} for {}", next, maxConnections, this);
|
||||
newConnection(new Callback<Connection>()
|
||||
|
||||
CONNECTCallback connectCallback = new CONNECTCallback(new Callback<Connection>()
|
||||
{
|
||||
@Override
|
||||
public void completed(Connection connection)
|
||||
{
|
||||
LOG.debug("Created connection {}/{} {} for {}", next, maxConnections, connection, HttpDestination.this);
|
||||
process(connection, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void failed(Connection connection, final Throwable x)
|
||||
public void failed(final Connection connection, final Throwable x)
|
||||
{
|
||||
LOG.debug("Connection failed {} for {}", x, HttpDestination.this);
|
||||
connectionCount.decrementAndGet();
|
||||
client.getExecutor().execute(new Runnable()
|
||||
{
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
drain(x);
|
||||
if (connection != null)
|
||||
connection.close();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
newConnection(new TCPCallback(next, maxConnections, connectCallback));
|
||||
// Try again the idle connections
|
||||
return idleConnections.poll();
|
||||
}
|
||||
|
@ -248,9 +269,10 @@ public class HttpDestination implements Destination, AutoCloseable, Dumpable
|
|||
{
|
||||
final Request request = requestContext.request;
|
||||
final List<Response.ResponseListener> listeners = requestContext.listeners;
|
||||
if (request.isAborted())
|
||||
Throwable cause = request.getAbortCause();
|
||||
if (cause != null)
|
||||
{
|
||||
abort(request, listeners, "Aborted");
|
||||
abort(request, listeners, cause);
|
||||
LOG.debug("Aborted {} before processing", request);
|
||||
}
|
||||
else
|
||||
|
@ -300,10 +322,13 @@ public class HttpDestination implements Destination, AutoCloseable, Dumpable
|
|||
|
||||
public void remove(Connection connection)
|
||||
{
|
||||
LOG.debug("{} removed", connection);
|
||||
connectionCount.decrementAndGet();
|
||||
activeConnections.remove(connection);
|
||||
idleConnections.remove(connection);
|
||||
boolean removed = activeConnections.remove(connection);
|
||||
removed |= idleConnections.remove(connection);
|
||||
if (removed)
|
||||
{
|
||||
LOG.debug("{} removed", connection);
|
||||
connectionCount.decrementAndGet();
|
||||
}
|
||||
|
||||
// We need to execute queued requests even if this connection failed.
|
||||
// We may create a connection that is not needed, but it will eventually
|
||||
|
@ -334,7 +359,7 @@ public class HttpDestination implements Destination, AutoCloseable, Dumpable
|
|||
LOG.debug("Closed {}", this);
|
||||
}
|
||||
|
||||
public boolean abort(Request request, String reason)
|
||||
public boolean abort(Request request, Throwable cause)
|
||||
{
|
||||
for (RequestContext requestContext : requests)
|
||||
{
|
||||
|
@ -343,7 +368,7 @@ public class HttpDestination implements Destination, AutoCloseable, Dumpable
|
|||
if (requests.remove(requestContext))
|
||||
{
|
||||
// We were able to remove the pair, so it won't be processed
|
||||
abort(request, requestContext.listeners, reason);
|
||||
abort(request, requestContext.listeners, cause);
|
||||
LOG.debug("Aborted {} while queued", request);
|
||||
return true;
|
||||
}
|
||||
|
@ -352,13 +377,11 @@ public class HttpDestination implements Destination, AutoCloseable, Dumpable
|
|||
return false;
|
||||
}
|
||||
|
||||
private void abort(Request request, List<Response.ResponseListener> listeners, String reason)
|
||||
private void abort(Request request, List<Response.ResponseListener> listeners, Throwable cause)
|
||||
{
|
||||
HttpResponse response = new HttpResponse(request, listeners);
|
||||
HttpResponseException responseFailure = new HttpResponseException(reason, response);
|
||||
responseNotifier.notifyFailure(listeners, response, responseFailure);
|
||||
HttpRequestException requestFailure = new HttpRequestException(reason, request);
|
||||
responseNotifier.notifyComplete(listeners, new Result(request, requestFailure, response, responseFailure));
|
||||
responseNotifier.notifyFailure(listeners, response, cause);
|
||||
responseNotifier.notifyComplete(listeners, new Result(request, cause, response, cause));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -382,7 +405,12 @@ public class HttpDestination implements Destination, AutoCloseable, Dumpable
|
|||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return String.format("%s(%s://%s:%d)", HttpDestination.class.getSimpleName(), getScheme(), getHost(), getPort());
|
||||
return String.format("%s(%s://%s:%d)%s",
|
||||
HttpDestination.class.getSimpleName(),
|
||||
getScheme(),
|
||||
getHost(),
|
||||
getPort(),
|
||||
proxyAddress == null ? "" : " via " + proxyAddress.getHostString() + ":" + proxyAddress.getPort());
|
||||
}
|
||||
|
||||
private static class RequestContext
|
||||
|
@ -396,4 +424,90 @@ public class HttpDestination implements Destination, AutoCloseable, Dumpable
|
|||
this.listeners = listeners;
|
||||
}
|
||||
}
|
||||
|
||||
private class TCPCallback implements Callback<Connection>
|
||||
{
|
||||
private final int current;
|
||||
private final int max;
|
||||
private final Callback<Connection> delegate;
|
||||
|
||||
private TCPCallback(int current, int max, Callback<Connection> delegate)
|
||||
{
|
||||
this.current = current;
|
||||
this.max = max;
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void completed(Connection connection)
|
||||
{
|
||||
LOG.debug("Created connection {}/{} {} for {}", current, max, connection, HttpDestination.this);
|
||||
delegate.completed(connection);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void failed(Connection connection, Throwable x)
|
||||
{
|
||||
LOG.debug("Connection failed {} for {}", x, HttpDestination.this);
|
||||
connectionCount.decrementAndGet();
|
||||
delegate.failed(connection, x);
|
||||
}
|
||||
}
|
||||
|
||||
private class CONNECTCallback implements Callback<Connection>
|
||||
{
|
||||
private final Callback<Connection> delegate;
|
||||
|
||||
private CONNECTCallback(Callback<Connection> delegate)
|
||||
{
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void completed(Connection connection)
|
||||
{
|
||||
boolean tunnel = isProxied() &&
|
||||
"https".equalsIgnoreCase(getScheme()) &&
|
||||
client.getSslContextFactory() != null;
|
||||
if (tunnel)
|
||||
tunnel(connection);
|
||||
else
|
||||
delegate.completed(connection);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void failed(Connection connection, Throwable x)
|
||||
{
|
||||
delegate.failed(connection, x);
|
||||
}
|
||||
|
||||
private void tunnel(final Connection connection)
|
||||
{
|
||||
String target = address.getHostString() + ":" + address.getPort();
|
||||
Request connect = client.newRequest(proxyAddress.getHostString(), proxyAddress.getPort())
|
||||
.scheme(HttpScheme.HTTP.asString())
|
||||
.method(HttpMethod.CONNECT)
|
||||
.path(target)
|
||||
.header(HttpHeader.HOST.asString(), target);
|
||||
connection.send(connect, new TimedResponseListener(client.getConnectTimeout(), TimeUnit.MILLISECONDS, connect, new Response.CompleteListener()
|
||||
{
|
||||
@Override
|
||||
public void onComplete(Result result)
|
||||
{
|
||||
if (result.isFailed())
|
||||
{
|
||||
failed(connection, result.getFailure());
|
||||
}
|
||||
else
|
||||
{
|
||||
Response response = result.getResponse();
|
||||
if (response.getStatus() == 200)
|
||||
delegate.completed(connection);
|
||||
else
|
||||
failed(connection, new HttpResponseException("Received " + response + " for " + result.getRequest(), response));
|
||||
}
|
||||
}
|
||||
}));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -193,10 +193,10 @@ public class HttpExchange
|
|||
return new AtomicMarkableReference<>(result, modified);
|
||||
}
|
||||
|
||||
public boolean abort(String reason)
|
||||
public boolean abort(Throwable cause)
|
||||
{
|
||||
LOG.debug("Aborting {} reason {}", this, reason);
|
||||
boolean aborted = connection.abort(this, reason);
|
||||
LOG.debug("Aborting {} reason {}", this, cause);
|
||||
boolean aborted = connection.abort(this, cause);
|
||||
LOG.debug("Aborted {}: {}", this, aborted);
|
||||
return aborted;
|
||||
}
|
||||
|
|
|
@ -387,9 +387,9 @@ public class HttpReceiver implements HttpParser.ResponseHandler<ByteBuffer>
|
|||
fail(new TimeoutException());
|
||||
}
|
||||
|
||||
public boolean abort(HttpExchange exchange, String reason)
|
||||
public boolean abort(HttpExchange exchange, Throwable cause)
|
||||
{
|
||||
return fail(new HttpResponseException(reason == null ? "Response aborted" : reason, exchange.getResponse()));
|
||||
return fail(cause);
|
||||
}
|
||||
|
||||
private boolean updateState(State from, State to)
|
||||
|
|
|
@ -28,6 +28,7 @@ import java.util.ArrayList;
|
|||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
|
||||
|
@ -63,7 +64,7 @@ public class HttpRequest implements Request
|
|||
private long idleTimeout;
|
||||
private ContentProvider content;
|
||||
private boolean followRedirects;
|
||||
private volatile boolean aborted;
|
||||
private volatile Throwable aborted;
|
||||
|
||||
public HttpRequest(HttpClient client, URI uri)
|
||||
{
|
||||
|
@ -403,17 +404,17 @@ public class HttpRequest implements Request
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean abort(String reason)
|
||||
public boolean abort(Throwable cause)
|
||||
{
|
||||
aborted = true;
|
||||
if (client.provideDestination(getScheme(), getHost(), getPort()).abort(this, reason))
|
||||
aborted = Objects.requireNonNull(cause);
|
||||
if (client.provideDestination(getScheme(), getHost(), getPort()).abort(this, cause))
|
||||
return true;
|
||||
HttpConversation conversation = client.getConversation(getConversationID(), false);
|
||||
return conversation != null && conversation.abort(reason);
|
||||
return conversation != null && conversation.abort(cause);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAborted()
|
||||
public Throwable getAbortCause()
|
||||
{
|
||||
return aborted;
|
||||
}
|
||||
|
|
|
@ -98,9 +98,9 @@ public class HttpResponse implements Response
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean abort(String reason)
|
||||
public boolean abort(Throwable cause)
|
||||
{
|
||||
return request.abort(reason);
|
||||
return request.abort(cause);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -82,9 +82,10 @@ public class HttpSender
|
|||
}
|
||||
|
||||
Request request = exchange.getRequest();
|
||||
if (request.isAborted())
|
||||
Throwable cause = request.getAbortCause();
|
||||
if (cause != null)
|
||||
{
|
||||
exchange.abort(null);
|
||||
exchange.abort(cause);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -400,7 +401,7 @@ public class HttpSender
|
|||
|
||||
Result result = completion.getReference();
|
||||
boolean notCommitted = current == State.IDLE || current == State.SEND;
|
||||
if (result == null && notCommitted && !request.isAborted())
|
||||
if (result == null && notCommitted && request.getAbortCause() == null)
|
||||
{
|
||||
result = exchange.responseComplete(failure).getReference();
|
||||
exchange.terminateResponse();
|
||||
|
@ -418,12 +419,12 @@ public class HttpSender
|
|||
return true;
|
||||
}
|
||||
|
||||
public boolean abort(HttpExchange exchange, String reason)
|
||||
public boolean abort(HttpExchange exchange, Throwable cause)
|
||||
{
|
||||
State current = state.get();
|
||||
boolean abortable = current == State.IDLE || current == State.SEND ||
|
||||
current == State.COMMIT && contentIterator.hasNext();
|
||||
return abortable && fail(new HttpRequestException(reason == null ? "Request aborted" : reason, exchange.getRequest()));
|
||||
return abortable && fail(cause);
|
||||
}
|
||||
|
||||
private void releaseBuffers(ByteBufferPool bufferPool, ByteBuffer header, ByteBuffer chunk)
|
||||
|
|
|
@ -126,8 +126,9 @@ public class RedirectProtocolHandler extends Response.Listener.Empty implements
|
|||
@Override
|
||||
public void onBegin(Request redirect)
|
||||
{
|
||||
if (request.isAborted())
|
||||
redirect.abort(null);
|
||||
Throwable cause = request.getAbortCause();
|
||||
if (cause != null)
|
||||
redirect.abort(cause);
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
@ -16,36 +16,41 @@
|
|||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.server.handler;
|
||||
package org.eclipse.jetty.client.api;
|
||||
|
||||
import org.eclipse.jetty.server.Handler;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** ProxyHandler.
|
||||
* <p>This class has been renamed to ConnectHandler, as it only implements
|
||||
* the CONNECT method (and a ProxyServlet must be used for full proxy handling).
|
||||
* @deprecated Use {@link ConnectHandler}
|
||||
*/
|
||||
public class ProxyHandler extends ConnectHandler
|
||||
public class ProxyConfiguration
|
||||
{
|
||||
public ProxyHandler()
|
||||
private final Set<String> excluded = new HashSet<>();
|
||||
private final String host;
|
||||
private final int port;
|
||||
|
||||
public ProxyConfiguration(String host, int port)
|
||||
{
|
||||
super();
|
||||
this.host = host;
|
||||
this.port = port;
|
||||
}
|
||||
|
||||
public ProxyHandler(Handler handler, String[] white, String[] black)
|
||||
public String getHost()
|
||||
{
|
||||
super(handler,white,black);
|
||||
return host;
|
||||
}
|
||||
|
||||
public ProxyHandler(Handler handler)
|
||||
public int getPort()
|
||||
{
|
||||
super(handler);
|
||||
return port;
|
||||
}
|
||||
|
||||
public ProxyHandler(String[] white, String[] black)
|
||||
public boolean matches(String host, int port)
|
||||
{
|
||||
super(white,black);
|
||||
String hostPort = host + ":" + port;
|
||||
return !getExcludedHosts().contains(hostPort);
|
||||
}
|
||||
|
||||
public Set<String> getExcludedHosts()
|
||||
{
|
||||
return excluded;
|
||||
}
|
||||
}
|
|
@ -308,15 +308,16 @@ public interface Request
|
|||
/**
|
||||
* Attempts to abort the send of this request.
|
||||
*
|
||||
* @param reason the abort reason
|
||||
* @param cause the abort cause, must not be null
|
||||
* @return whether the abort succeeded
|
||||
*/
|
||||
boolean abort(String reason);
|
||||
boolean abort(Throwable cause);
|
||||
|
||||
/**
|
||||
* @return whether {@link #abort(String)} was called
|
||||
* @return the abort cause passed to {@link #abort(Throwable)},
|
||||
* or null if this request has not been aborted
|
||||
*/
|
||||
boolean isAborted();
|
||||
Throwable getAbortCause();
|
||||
|
||||
public interface RequestListener extends EventListener
|
||||
{
|
||||
|
|
|
@ -71,10 +71,10 @@ public interface Response
|
|||
/**
|
||||
* Attempts to abort the receive of this response.
|
||||
*
|
||||
* @param reason the abort reason
|
||||
* @param cause the abort cause, must not be null
|
||||
* @return whether the abort succeeded
|
||||
*/
|
||||
boolean abort(String reason);
|
||||
boolean abort(Throwable cause);
|
||||
|
||||
public interface ResponseListener extends EventListener
|
||||
{
|
||||
|
|
|
@ -18,9 +18,6 @@
|
|||
|
||||
package org.eclipse.jetty.client.util;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.nio.charset.UnsupportedCharsetException;
|
||||
|
||||
import org.eclipse.jetty.client.api.Authentication;
|
||||
import org.eclipse.jetty.client.api.ContentResponse;
|
||||
import org.eclipse.jetty.client.api.Request;
|
||||
|
@ -60,15 +57,8 @@ public class BasicAuthentication implements Authentication
|
|||
public Result authenticate(Request request, ContentResponse response, String wwwAuthenticate, Attributes context)
|
||||
{
|
||||
String encoding = StringUtil.__ISO_8859_1;
|
||||
try
|
||||
{
|
||||
String value = "Basic " + B64Code.encode(user + ":" + password, encoding);
|
||||
return new BasicResult(request.getURI(), value);
|
||||
}
|
||||
catch (UnsupportedEncodingException x)
|
||||
{
|
||||
throw new UnsupportedCharsetException(encoding);
|
||||
}
|
||||
String value = "Basic " + B64Code.encode(user + ":" + password, encoding);
|
||||
return new BasicResult(request.getURI(), value);
|
||||
}
|
||||
|
||||
private static class BasicResult implements Result
|
||||
|
|
|
@ -55,7 +55,7 @@ public class BlockingResponseListener extends BufferingResponseListener implemen
|
|||
public boolean cancel(boolean mayInterruptIfRunning)
|
||||
{
|
||||
cancelled = true;
|
||||
return request.abort("Cancelled");
|
||||
return request.abort(new CancellationException());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -83,8 +83,9 @@ public class BlockingResponseListener extends BufferingResponseListener implemen
|
|||
boolean expired = !latch.await(timeout, unit);
|
||||
if (expired)
|
||||
{
|
||||
request.abort("Total timeout elapsed");
|
||||
throw new TimeoutException();
|
||||
TimeoutException reason = new TimeoutException();
|
||||
request.abort(reason);
|
||||
throw reason;
|
||||
}
|
||||
return getResult();
|
||||
}
|
||||
|
|
|
@ -64,7 +64,7 @@ public abstract class BufferingResponseListener extends Response.Listener.Empty
|
|||
HttpFields headers = response.getHeaders();
|
||||
long length = headers.getLongField(HttpHeader.CONTENT_LENGTH.asString());
|
||||
if (length > maxLength)
|
||||
response.abort("Buffering capacity exceeded");
|
||||
response.abort(new IllegalArgumentException("Buffering capacity exceeded"));
|
||||
|
||||
String contentType = headers.get(HttpHeader.CONTENT_TYPE);
|
||||
if (contentType != null)
|
||||
|
|
|
@ -18,7 +18,6 @@
|
|||
|
||||
package org.eclipse.jetty.client.util;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.Iterator;
|
||||
|
@ -49,46 +48,64 @@ public class InputStreamContentProvider implements ContentProvider
|
|||
return -1;
|
||||
}
|
||||
|
||||
protected ByteBuffer onRead(byte[] buffer, int offset, int length)
|
||||
{
|
||||
if (length <= 0)
|
||||
return BufferUtil.EMPTY_BUFFER;
|
||||
return ByteBuffer.wrap(buffer, offset, length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<ByteBuffer> iterator()
|
||||
{
|
||||
return new Iterator<ByteBuffer>()
|
||||
{
|
||||
private final byte[] buffer = new byte[bufferSize];
|
||||
public boolean eof;
|
||||
private final byte[] bytes = new byte[bufferSize];
|
||||
private Exception failure;
|
||||
private ByteBuffer buffer;
|
||||
|
||||
@Override
|
||||
public boolean hasNext()
|
||||
{
|
||||
return !eof;
|
||||
try
|
||||
{
|
||||
int read = stream.read(bytes);
|
||||
if (read > 0)
|
||||
{
|
||||
buffer = onRead(bytes, 0, read);
|
||||
return true;
|
||||
}
|
||||
else if (read < 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
buffer = BufferUtil.EMPTY_BUFFER;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
catch (Exception x)
|
||||
{
|
||||
if (failure == null)
|
||||
{
|
||||
failure = x;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer next()
|
||||
{
|
||||
try
|
||||
{
|
||||
int read = stream.read(buffer);
|
||||
if (read > 0)
|
||||
{
|
||||
return ByteBuffer.wrap(buffer, 0, read);
|
||||
}
|
||||
else if (read < 0)
|
||||
{
|
||||
if (eof)
|
||||
throw new NoSuchElementException();
|
||||
eof = true;
|
||||
return BufferUtil.EMPTY_BUFFER;
|
||||
}
|
||||
else
|
||||
{
|
||||
return BufferUtil.EMPTY_BUFFER;
|
||||
}
|
||||
}
|
||||
catch (IOException x)
|
||||
{
|
||||
throw (NoSuchElementException)new NoSuchElementException().initCause(x);
|
||||
}
|
||||
ByteBuffer result = buffer;
|
||||
buffer = null;
|
||||
if (failure != null)
|
||||
throw (NoSuchElementException)new NoSuchElementException().initCause(failure);
|
||||
if (result == null)
|
||||
throw new NoSuchElementException();
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -20,6 +20,7 @@ package org.eclipse.jetty.client.util;
|
|||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import org.eclipse.jetty.client.Schedulable;
|
||||
|
@ -38,14 +39,14 @@ public class TimedResponseListener implements Response.Listener, Schedulable, Ru
|
|||
private final long timeout;
|
||||
private final TimeUnit unit;
|
||||
private final Request request;
|
||||
private final Response.Listener delegate;
|
||||
private final Response.CompleteListener delegate;
|
||||
|
||||
public TimedResponseListener(long timeout, TimeUnit unit, Request request)
|
||||
{
|
||||
this(timeout, unit, request, new Empty());
|
||||
}
|
||||
|
||||
public TimedResponseListener(long timeout, TimeUnit unit, Request request, Response.Listener delegate)
|
||||
public TimedResponseListener(long timeout, TimeUnit unit, Request request, Response.CompleteListener delegate)
|
||||
{
|
||||
this.timeout = timeout;
|
||||
this.unit = unit;
|
||||
|
@ -56,31 +57,36 @@ public class TimedResponseListener implements Response.Listener, Schedulable, Ru
|
|||
@Override
|
||||
public void onBegin(Response response)
|
||||
{
|
||||
delegate.onBegin(response);
|
||||
if (delegate instanceof Response.BeginListener)
|
||||
((Response.BeginListener)delegate).onBegin(response);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onHeaders(Response response)
|
||||
{
|
||||
delegate.onHeaders(response);
|
||||
if (delegate instanceof Response.HeadersListener)
|
||||
((Response.HeadersListener)delegate).onHeaders(response);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onContent(Response response, ByteBuffer content)
|
||||
{
|
||||
delegate.onContent(response, content);
|
||||
if (delegate instanceof Response.ContentListener)
|
||||
((Response.ContentListener)delegate).onContent(response, content);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSuccess(Response response)
|
||||
{
|
||||
delegate.onSuccess(response);
|
||||
if (delegate instanceof Response.SuccessListener)
|
||||
((Response.SuccessListener)delegate).onSuccess(response);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Response response, Throwable failure)
|
||||
{
|
||||
delegate.onFailure(response, failure);
|
||||
if (delegate instanceof Response.FailureListener)
|
||||
((Response.FailureListener)delegate).onFailure(response, failure);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -111,7 +117,7 @@ public class TimedResponseListener implements Response.Listener, Schedulable, Ru
|
|||
@Override
|
||||
public void run()
|
||||
{
|
||||
request.abort("Total timeout elapsed");
|
||||
request.abort(new TimeoutException("Total timeout elapsed"));
|
||||
}
|
||||
|
||||
public boolean cancel()
|
||||
|
|
|
@ -408,7 +408,7 @@ public class HttpClientContinueTest extends AbstractHttpClientServerTest
|
|||
@Override
|
||||
public void onBegin(Response response)
|
||||
{
|
||||
response.abort(null);
|
||||
response.abort(new Exception());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -151,7 +151,7 @@ public class HttpClientTimeoutTest extends AbstractHttpClientServerTest
|
|||
|
||||
TimeUnit.MILLISECONDS.sleep(2 * timeout);
|
||||
|
||||
Assert.assertFalse(request.isAborted());
|
||||
Assert.assertNull(request.getAbortCause());
|
||||
}
|
||||
|
||||
@Slow
|
||||
|
@ -208,7 +208,7 @@ public class HttpClientTimeoutTest extends AbstractHttpClientServerTest
|
|||
|
||||
TimeUnit.MILLISECONDS.sleep(2 * timeout);
|
||||
|
||||
Assert.assertFalse(request.isAborted());
|
||||
Assert.assertNull(request.getAbortCause());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -100,6 +100,21 @@ public class HttpCookieStoreTest
|
|||
Assert.assertEquals("1", cookie.getValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCookieStoredWithPathIsRetrievedWithChildPath() throws Exception
|
||||
{
|
||||
CookieStore cookies = new HttpCookieStore();
|
||||
Destination destination = new HttpDestination(client, "http", "localhost", 80);
|
||||
Assert.assertTrue(cookies.addCookie(destination, new HttpCookie("a", "1", null, "/path")));
|
||||
|
||||
List<HttpCookie> result = cookies.findCookies(destination, "/path/child");
|
||||
Assert.assertNotNull(result);
|
||||
Assert.assertEquals(1, result.size());
|
||||
HttpCookie cookie = result.get(0);
|
||||
Assert.assertEquals("a", cookie.getName());
|
||||
Assert.assertEquals("1", cookie.getValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCookieStoredWithParentDomainIsRetrievedWithChildDomain() throws Exception
|
||||
{
|
||||
|
@ -118,6 +133,19 @@ public class HttpCookieStoreTest
|
|||
Assert.assertEquals(2, result.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCookieStoredWithChildDomainIsNotRetrievedWithParentDomain() throws Exception
|
||||
{
|
||||
CookieStore cookies = new HttpCookieStore();
|
||||
Destination childDestination = new HttpDestination(client, "http", "child.localhost.org", 80);
|
||||
Assert.assertTrue(cookies.addCookie(childDestination, new HttpCookie("b", "2", null, "/")));
|
||||
|
||||
Destination parentDestination = new HttpDestination(client, "http", "localhost.org", 80);
|
||||
List<HttpCookie> result = cookies.findCookies(parentDestination, "/path");
|
||||
Assert.assertNotNull(result);
|
||||
Assert.assertEquals(0, result.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExpiredCookieIsNotRetrieved() throws Exception
|
||||
{
|
||||
|
|
|
@ -33,7 +33,6 @@ import javax.servlet.http.HttpServletResponse;
|
|||
|
||||
import org.eclipse.jetty.client.api.ContentResponse;
|
||||
import org.eclipse.jetty.client.api.Request;
|
||||
import org.eclipse.jetty.client.api.Response;
|
||||
import org.eclipse.jetty.client.api.Result;
|
||||
import org.eclipse.jetty.client.util.ByteBufferContentProvider;
|
||||
import org.eclipse.jetty.server.HttpChannel;
|
||||
|
@ -42,7 +41,6 @@ import org.eclipse.jetty.toolchain.test.annotation.Slow;
|
|||
import org.eclipse.jetty.util.IO;
|
||||
import org.eclipse.jetty.util.log.StdErrLog;
|
||||
import org.eclipse.jetty.util.ssl.SslContextFactory;
|
||||
import org.hamcrest.Matchers;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
|
@ -58,6 +56,7 @@ public class HttpRequestAbortTest extends AbstractHttpClientServerTest
|
|||
{
|
||||
start(new EmptyServerHandler());
|
||||
|
||||
final Throwable cause = new Exception();
|
||||
final AtomicBoolean begin = new AtomicBoolean();
|
||||
try
|
||||
{
|
||||
|
@ -68,7 +67,7 @@ public class HttpRequestAbortTest extends AbstractHttpClientServerTest
|
|||
@Override
|
||||
public void onQueued(Request request)
|
||||
{
|
||||
request.abort(null);
|
||||
request.abort(cause);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -82,7 +81,7 @@ public class HttpRequestAbortTest extends AbstractHttpClientServerTest
|
|||
}
|
||||
catch (ExecutionException x)
|
||||
{
|
||||
Assert.assertThat(x.getCause(), Matchers.instanceOf(HttpResponseException.class));
|
||||
Assert.assertSame(cause, x.getCause());
|
||||
Assert.assertFalse(begin.get());
|
||||
}
|
||||
}
|
||||
|
@ -93,6 +92,7 @@ public class HttpRequestAbortTest extends AbstractHttpClientServerTest
|
|||
{
|
||||
start(new EmptyServerHandler());
|
||||
|
||||
final Throwable cause = new Exception();
|
||||
final CountDownLatch aborted = new CountDownLatch(1);
|
||||
final CountDownLatch headers = new CountDownLatch(1);
|
||||
try
|
||||
|
@ -104,7 +104,7 @@ public class HttpRequestAbortTest extends AbstractHttpClientServerTest
|
|||
@Override
|
||||
public void onBegin(Request request)
|
||||
{
|
||||
if (request.abort(null))
|
||||
if (request.abort(cause))
|
||||
aborted.countDown();
|
||||
}
|
||||
|
||||
|
@ -119,7 +119,7 @@ public class HttpRequestAbortTest extends AbstractHttpClientServerTest
|
|||
}
|
||||
catch (ExecutionException x)
|
||||
{
|
||||
Assert.assertThat(x.getCause(), Matchers.instanceOf(HttpResponseException.class));
|
||||
Assert.assertSame(cause, x.getCause());
|
||||
Assert.assertTrue(aborted.await(5, TimeUnit.SECONDS));
|
||||
Assert.assertFalse(headers.await(1, TimeUnit.SECONDS));
|
||||
}
|
||||
|
@ -134,6 +134,7 @@ public class HttpRequestAbortTest extends AbstractHttpClientServerTest
|
|||
// A) the request is failed before the response arrived, then we get an ExecutionException
|
||||
// B) the request is failed after the response arrived, we get the 200 OK
|
||||
|
||||
final Throwable cause = new Exception();
|
||||
final CountDownLatch aborted = new CountDownLatch(1);
|
||||
try
|
||||
{
|
||||
|
@ -144,7 +145,7 @@ public class HttpRequestAbortTest extends AbstractHttpClientServerTest
|
|||
@Override
|
||||
public void onHeaders(Request request)
|
||||
{
|
||||
if (request.abort(null))
|
||||
if (request.abort(cause))
|
||||
aborted.countDown();
|
||||
}
|
||||
})
|
||||
|
@ -154,7 +155,7 @@ public class HttpRequestAbortTest extends AbstractHttpClientServerTest
|
|||
}
|
||||
catch (ExecutionException x)
|
||||
{
|
||||
Assert.assertThat(x.getCause(), Matchers.instanceOf(HttpResponseException.class));
|
||||
Assert.assertSame(cause, x.getCause());
|
||||
Assert.assertTrue(aborted.await(5, TimeUnit.SECONDS));
|
||||
}
|
||||
}
|
||||
|
@ -181,12 +182,8 @@ public class HttpRequestAbortTest extends AbstractHttpClientServerTest
|
|||
}
|
||||
});
|
||||
|
||||
// Test can behave in 3 ways:
|
||||
// A) non-SSL, if the request is failed before the response arrived, then we get an ExecutionException
|
||||
// B) non-SSL, if the request is failed after the response arrived, then we get the 500
|
||||
// C) SSL, the server tries to write the 500, but the connection is already closed, the client
|
||||
// reads -1 with a pending exchange and fails the response with an EOFException
|
||||
StdErrLog.getLogger(HttpChannel.class).setHideStacks(true);
|
||||
final Throwable cause = new Exception();
|
||||
try
|
||||
{
|
||||
client.newRequest("localhost", connector.getLocalPort())
|
||||
|
@ -196,7 +193,7 @@ public class HttpRequestAbortTest extends AbstractHttpClientServerTest
|
|||
@Override
|
||||
public void onHeaders(Request request)
|
||||
{
|
||||
request.abort(null);
|
||||
request.abort(cause);
|
||||
}
|
||||
})
|
||||
.content(new ByteBufferContentProvider(ByteBuffer.wrap(new byte[]{0}), ByteBuffer.wrap(new byte[]{1}))
|
||||
|
@ -212,24 +209,15 @@ public class HttpRequestAbortTest extends AbstractHttpClientServerTest
|
|||
}
|
||||
catch (ExecutionException x)
|
||||
{
|
||||
Throwable cause = x.getCause();
|
||||
if (cause instanceof EOFException)
|
||||
Throwable abort = x.getCause();
|
||||
if (abort instanceof EOFException)
|
||||
{
|
||||
// Server closed abruptly, behavior C
|
||||
// Server closed abruptly
|
||||
System.err.println("C");
|
||||
}
|
||||
else if (cause instanceof HttpRequestException)
|
||||
else if (abort == cause)
|
||||
{
|
||||
// Request failed, behavior B
|
||||
HttpRequestException xx = (HttpRequestException)cause;
|
||||
Request request = xx.getRequest();
|
||||
Assert.assertNotNull(request);
|
||||
}
|
||||
else if (cause instanceof HttpResponseException)
|
||||
{
|
||||
// Response failed, behavior A
|
||||
HttpResponseException xx = (HttpResponseException)cause;
|
||||
Response response = xx.getResponse();
|
||||
Assert.assertNotNull(response);
|
||||
// Expected
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -270,7 +258,8 @@ public class HttpRequestAbortTest extends AbstractHttpClientServerTest
|
|||
|
||||
TimeUnit.MILLISECONDS.sleep(delay);
|
||||
|
||||
request.abort(null);
|
||||
Throwable cause = new Exception();
|
||||
request.abort(cause);
|
||||
|
||||
try
|
||||
{
|
||||
|
@ -278,7 +267,7 @@ public class HttpRequestAbortTest extends AbstractHttpClientServerTest
|
|||
}
|
||||
catch (ExecutionException x)
|
||||
{
|
||||
Assert.assertThat(x.getCause(), Matchers.instanceOf(HttpResponseException.class));
|
||||
Assert.assertSame(cause, x.getCause());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -296,6 +285,7 @@ public class HttpRequestAbortTest extends AbstractHttpClientServerTest
|
|||
}
|
||||
});
|
||||
|
||||
final Throwable cause = new Exception();
|
||||
client.getProtocolHandlers().clear();
|
||||
client.getProtocolHandlers().add(new RedirectProtocolHandler(client)
|
||||
{
|
||||
|
@ -304,7 +294,7 @@ public class HttpRequestAbortTest extends AbstractHttpClientServerTest
|
|||
{
|
||||
// Abort the request after the 3xx response but before issuing the next request
|
||||
if (!result.isFailed())
|
||||
result.getRequest().abort(null);
|
||||
result.getRequest().abort(cause);
|
||||
super.onComplete(result);
|
||||
}
|
||||
});
|
||||
|
@ -320,7 +310,7 @@ public class HttpRequestAbortTest extends AbstractHttpClientServerTest
|
|||
}
|
||||
catch (ExecutionException x)
|
||||
{
|
||||
Assert.assertThat(x.getCause(), Matchers.instanceOf(HttpResponseException.class));
|
||||
Assert.assertSame(cause, x.getCause());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -60,7 +60,7 @@ public class HttpResponseAbortTest extends AbstractHttpClientServerTest
|
|||
@Override
|
||||
public void onBegin(Response response)
|
||||
{
|
||||
response.abort(null);
|
||||
response.abort(new Exception());
|
||||
}
|
||||
})
|
||||
.send(new Response.CompleteListener()
|
||||
|
@ -88,7 +88,7 @@ public class HttpResponseAbortTest extends AbstractHttpClientServerTest
|
|||
@Override
|
||||
public void onHeaders(Response response)
|
||||
{
|
||||
response.abort(null);
|
||||
response.abort(new Exception());
|
||||
}
|
||||
})
|
||||
.send(new Response.CompleteListener()
|
||||
|
@ -136,7 +136,7 @@ public class HttpResponseAbortTest extends AbstractHttpClientServerTest
|
|||
@Override
|
||||
public void onContent(Response response, ByteBuffer content)
|
||||
{
|
||||
response.abort(null);
|
||||
response.abort(new Exception());
|
||||
}
|
||||
})
|
||||
.send(new Response.CompleteListener()
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
|
||||
package org.eclipse.jetty.client.api;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.InputStream;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
|
@ -26,9 +27,10 @@ import java.util.concurrent.TimeUnit;
|
|||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import org.eclipse.jetty.client.HttpClient;
|
||||
import org.eclipse.jetty.client.util.BasicAuthentication;
|
||||
import org.eclipse.jetty.client.util.BlockingResponseListener;
|
||||
import org.eclipse.jetty.client.util.InputStreamContentProvider;
|
||||
import org.eclipse.jetty.client.util.InputStreamResponseListener;
|
||||
import org.eclipse.jetty.client.util.PathContentProvider;
|
||||
import org.eclipse.jetty.http.HttpCookie;
|
||||
import org.eclipse.jetty.http.HttpMethod;
|
||||
import org.eclipse.jetty.http.HttpVersion;
|
||||
|
@ -43,14 +45,16 @@ public class Usage
|
|||
public void testGETBlocking_ShortAPI() throws Exception
|
||||
{
|
||||
HttpClient client = new HttpClient();
|
||||
client.start();
|
||||
|
||||
Future<ContentResponse> responseFuture = client.GET("http://localhost:8080/foo");
|
||||
// Block to get the response
|
||||
Response response = responseFuture.get();
|
||||
|
||||
// Verify response status code
|
||||
Assert.assertEquals(200, response.getStatus());
|
||||
// Headers abstraction needed for:
|
||||
// 1. case insensitivity
|
||||
// 2. multi values
|
||||
// 3. value conversion
|
||||
// Reuse SPDY's ?
|
||||
|
||||
// Access headers
|
||||
response.getHeaders().get("Content-Length");
|
||||
}
|
||||
|
||||
|
@ -58,6 +62,8 @@ public class Usage
|
|||
public void testGETBlocking() throws Exception
|
||||
{
|
||||
HttpClient client = new HttpClient();
|
||||
client.start();
|
||||
|
||||
// Address must be provided, it's the only thing non defaultable
|
||||
Request request = client.newRequest("localhost", 8080)
|
||||
.scheme("https")
|
||||
|
@ -67,11 +73,12 @@ public class Usage
|
|||
.param("a", "b")
|
||||
.header("X-Header", "Y-value")
|
||||
.agent("Jetty HTTP Client")
|
||||
// .decoder(null)
|
||||
.content(null)
|
||||
.idleTimeout(5000L);
|
||||
|
||||
Future<ContentResponse> responseFuture = request.send();
|
||||
// Block to get the response
|
||||
Response response = responseFuture.get();
|
||||
|
||||
Assert.assertEquals(200, response.getStatus());
|
||||
}
|
||||
|
||||
|
@ -79,17 +86,26 @@ public class Usage
|
|||
public void testGETAsync() throws Exception
|
||||
{
|
||||
HttpClient client = new HttpClient();
|
||||
client.start();
|
||||
|
||||
final AtomicReference<Response> responseRef = new AtomicReference<>();
|
||||
final CountDownLatch latch = new CountDownLatch(1);
|
||||
client.newRequest("localhost", 8080).send(new Response.Listener.Empty()
|
||||
|
||||
client.newRequest("localhost", 8080)
|
||||
// Send asynchronously
|
||||
.send(new Response.CompleteListener()
|
||||
{
|
||||
@Override
|
||||
public void onSuccess(Response response)
|
||||
public void onComplete(Result result)
|
||||
{
|
||||
responseRef.set(response);
|
||||
latch.countDown();
|
||||
if (!result.isFailed())
|
||||
{
|
||||
responseRef.set(result.getResponse());
|
||||
latch.countDown();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Assert.assertTrue(latch.await(5, TimeUnit.SECONDS));
|
||||
Response response = responseRef.get();
|
||||
Assert.assertNotNull(response);
|
||||
|
@ -97,9 +113,12 @@ public class Usage
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testPOSTWithParams() throws Exception
|
||||
public void testPOSTWithParams_ShortAPI() throws Exception
|
||||
{
|
||||
HttpClient client = new HttpClient();
|
||||
client.start();
|
||||
|
||||
// One liner to POST
|
||||
client.POST("http://localhost:8080").param("a", "\u20AC").send();
|
||||
}
|
||||
|
||||
|
@ -107,7 +126,10 @@ public class Usage
|
|||
public void testRequestListener() throws Exception
|
||||
{
|
||||
HttpClient client = new HttpClient();
|
||||
client.start();
|
||||
|
||||
Response response = client.newRequest("localhost", 8080)
|
||||
// Add a request listener
|
||||
.listener(new Request.Listener.Empty()
|
||||
{
|
||||
@Override
|
||||
|
@ -122,12 +144,19 @@ public class Usage
|
|||
public void testRequestWithExplicitConnectionControl() throws Exception
|
||||
{
|
||||
HttpClient client = new HttpClient();
|
||||
client.start();
|
||||
|
||||
// Create an explicit connection, and use try-with-resources to manage it
|
||||
try (Connection connection = client.getDestination("http", "localhost", 8080).newConnection().get(5, TimeUnit.SECONDS))
|
||||
{
|
||||
Request request = client.newRequest("localhost", 8080);
|
||||
|
||||
// Asynchronous send but using BlockingResponseListener
|
||||
BlockingResponseListener listener = new BlockingResponseListener(request);
|
||||
connection.send(request, listener);
|
||||
// Wait for the response on the listener
|
||||
Response response = listener.get(5, TimeUnit.SECONDS);
|
||||
|
||||
Assert.assertNotNull(response);
|
||||
Assert.assertEquals(200, response.getStatus());
|
||||
}
|
||||
|
@ -137,8 +166,11 @@ public class Usage
|
|||
public void testFileUpload() throws Exception
|
||||
{
|
||||
HttpClient client = new HttpClient();
|
||||
Response response = client.newRequest("localhost", 8080)
|
||||
.content(new PathContentProvider(Paths.get(""))).send().get();
|
||||
client.start();
|
||||
|
||||
// One liner to upload files
|
||||
Response response = client.newRequest("localhost", 8080).file(Paths.get("file_to_upload.txt")).send().get();
|
||||
|
||||
Assert.assertEquals(200, response.getStatus());
|
||||
}
|
||||
|
||||
|
@ -146,37 +178,68 @@ public class Usage
|
|||
public void testCookie() throws Exception
|
||||
{
|
||||
HttpClient client = new HttpClient();
|
||||
client.start();
|
||||
|
||||
// Set a cookie to be sent in requests that match the cookie's domain
|
||||
client.getCookieStore().addCookie(client.getDestination("http", "host", 8080), new HttpCookie("name", "value"));
|
||||
|
||||
// Send a request for the cookie's domain
|
||||
Response response = client.newRequest("host", 8080).send().get();
|
||||
|
||||
Assert.assertEquals(200, response.getStatus());
|
||||
}
|
||||
|
||||
// @Test
|
||||
// public void testAuthentication() throws Exception
|
||||
// {
|
||||
// HTTPClient client = new HTTPClient();
|
||||
// client.newRequest("localhost", 8080).authentication(new Authentication.Kerberos()).build().send().get().status(); // 200
|
||||
// }
|
||||
@Test
|
||||
public void testBasicAuthentication() throws Exception
|
||||
{
|
||||
HttpClient client = new HttpClient();
|
||||
client.start();
|
||||
|
||||
String uri = "http://localhost:8080/secure";
|
||||
|
||||
// Setup Basic authentication credentials for TestRealm
|
||||
client.getAuthenticationStore().addAuthentication(new BasicAuthentication(uri, "TestRealm", "username", "password"));
|
||||
|
||||
// One liner to send the request
|
||||
ContentResponse response = client.newRequest(uri).send().get(5, TimeUnit.SECONDS);
|
||||
|
||||
Assert.assertEquals(200, response.getStatus());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFollowRedirects() throws Exception
|
||||
{
|
||||
HttpClient client = new HttpClient();
|
||||
client.start();
|
||||
|
||||
// Do not follow redirects by default
|
||||
client.setFollowRedirects(false);
|
||||
client.newRequest("localhost", 8080).followRedirects(true).send().get().getStatus(); // 200
|
||||
|
||||
ContentResponse response = client.newRequest("localhost", 8080)
|
||||
// Follow redirects for this request only
|
||||
.followRedirects(true)
|
||||
.send()
|
||||
.get(5, TimeUnit.SECONDS);
|
||||
|
||||
Assert.assertEquals(200, response.getStatus());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testResponseInputStream() throws Exception
|
||||
{
|
||||
HttpClient client = new HttpClient();
|
||||
client.start();
|
||||
|
||||
InputStreamResponseListener listener = new InputStreamResponseListener();
|
||||
// Send asynchronously with the InputStreamResponseListener
|
||||
client.newRequest("localhost", 8080).send(listener);
|
||||
// Call to get() blocks until the headers arrived
|
||||
|
||||
// Call to the listener's get() blocks until the headers arrived
|
||||
Response response = listener.get(5, TimeUnit.SECONDS);
|
||||
|
||||
// Now check the response information that arrived to decide whether to read the content
|
||||
if (response.getStatus() == 200)
|
||||
{
|
||||
// Solution 1: use input stream
|
||||
byte[] buffer = new byte[256];
|
||||
try (InputStream input = listener.getInputStream())
|
||||
{
|
||||
|
@ -185,37 +248,30 @@ public class Usage
|
|||
int read = input.read(buffer);
|
||||
if (read < 0)
|
||||
break;
|
||||
// No need for output stream; for example, parse bytes
|
||||
// Do something with the bytes just read
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
response.abort(null);
|
||||
response.abort(new Exception());
|
||||
}
|
||||
}
|
||||
|
||||
// @Test
|
||||
// public void testResponseOutputStream() throws Exception
|
||||
// {
|
||||
// HttpClient client = new HttpClient();
|
||||
//
|
||||
// try (FileOutputStream output = new FileOutputStream(""))
|
||||
// {
|
||||
// OutputStreamResponseListener listener = new OutputStreamResponseListener(output);
|
||||
// client.newRequest("localhost", 8080).send(listener);
|
||||
// // Call to get() blocks until the headers arrived
|
||||
// Response response = listener.get(5, TimeUnit.SECONDS);
|
||||
// if (response.status() == 200)
|
||||
// {
|
||||
// // Solution 2: write to output stream
|
||||
// {
|
||||
// listener.writeTo(output);
|
||||
// }
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// response.abort();
|
||||
// }
|
||||
// }
|
||||
@Test
|
||||
public void testRequestInputStream() throws Exception
|
||||
{
|
||||
HttpClient client = new HttpClient();
|
||||
client.start();
|
||||
|
||||
InputStream input = new ByteArrayInputStream("content".getBytes("UTF-8"));
|
||||
|
||||
ContentResponse response = client.newRequest("localhost", 8080)
|
||||
// Provide the content as InputStream
|
||||
.content(new InputStreamContentProvider(input))
|
||||
.send()
|
||||
.get(5, TimeUnit.SECONDS);
|
||||
|
||||
Assert.assertEquals(200, response.getStatus());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -133,12 +133,24 @@
|
|||
</goals>
|
||||
<configuration>
|
||||
<includeGroupIds>org.eclipse.jetty</includeGroupIds>
|
||||
<excludeGroupIds>org.eclipse.jetty.orbit,org.eclipse.jetty.spdy</excludeGroupIds>
|
||||
<excludeGroupIds>org.eclipse.jetty.orbit,org.eclipse.jetty.spdy,org.eclipse.jetty.websocket,org.eclipse.jetty.drafts</excludeGroupIds>
|
||||
<excludeArtifactIds>jetty-all,jetty-start,jetty-monitor,jetty-jsp</excludeArtifactIds>
|
||||
<includeTypes>jar</includeTypes>
|
||||
<outputDirectory>${assembly-directory}/lib</outputDirectory>
|
||||
</configuration>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>copy-lib-websocket-deps</id>
|
||||
<phase>generate-resources</phase>
|
||||
<goals>
|
||||
<goal>copy-dependencies</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<includeGroupIds>org.eclipse.jetty.websocket,org.eclipse.jetty.drafts</includeGroupIds>
|
||||
<includeTypes>jar</includeTypes>
|
||||
<outputDirectory>${assembly-directory}/lib/websocket</outputDirectory>
|
||||
</configuration>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>copy-orbit-servlet-api-deps</id>
|
||||
<phase>generate-resources</phase>
|
||||
|
@ -346,6 +358,11 @@
|
|||
<artifactId>jetty-servlets</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty.websocket</groupId>
|
||||
<artifactId>websocket-client</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty.websocket</groupId>
|
||||
<artifactId>websocket-server</artifactId>
|
||||
|
|
|
@ -138,18 +138,27 @@ etc/jetty-http.xml
|
|||
|
||||
#===========================================================
|
||||
# SPDY Connector
|
||||
# SPDY should not be used with HTTPS as the SPDY connector
|
||||
# also provides HTTPS.
|
||||
# The NPN jar must be separately downloaded from
|
||||
# http://repo1.maven.org/maven2/org/mortbay/jetty/npn/npn-boot/1.1.0.v20120525/
|
||||
# Must also enable --exec or use --exec-print (see above) or
|
||||
# add -Xbootclasspath/p:lib/npn-boot-1.1.0.v20120525.jar to
|
||||
# the java commandline you use to start jetty.
|
||||
# Make sure that you either reconfigure ports or comment
|
||||
# jetty-http.xml/jetty-https.xml to avoid port conflicts.
|
||||
#
|
||||
# SPDY should not be used with HTTPS. Use HTTPS or SPDY, but
|
||||
# not both, as SPDY also provides HTTPS support.
|
||||
#
|
||||
# SPDY requires the NPN jar iwhich must be separately downloaded:
|
||||
#
|
||||
# http://repo1.maven.org/maven2/org/mortbay/jetty/npn/npn-boot/1.1.1.v20121030/npn-boot-1.1.1.v20121030.jar
|
||||
#
|
||||
# Which should be saved in lib/npn-boot-1.1.1.v20121030.jar
|
||||
#
|
||||
# To include the NPN jar on the boot path, you must either:
|
||||
#
|
||||
# a) enable --exec above and uncomment the -Xbootclass line
|
||||
# below
|
||||
#
|
||||
# b) Add -Xbootclasspath/p:lib/npn-boot-1.1.1.v20121030.jar
|
||||
# to the command line when running jetty.
|
||||
#
|
||||
#-----------------------------------------------------------
|
||||
# OPTIONS=spdy
|
||||
# -Xbootclasspath/p:lib/npn-boot-1.1.0.v20120525.jar
|
||||
# -Xbootclasspath/p:lib/npn-boot-1.1.1.v20121030.jar
|
||||
# etc/jetty-spdy.xml
|
||||
#===========================================================
|
||||
|
||||
|
|
|
@ -36,6 +36,7 @@ public interface HttpContent
|
|||
String getLastModified();
|
||||
ByteBuffer getIndirectBuffer();
|
||||
ByteBuffer getDirectBuffer();
|
||||
String getETag();
|
||||
Resource getResource();
|
||||
long getContentLength();
|
||||
InputStream getInputStream() throws IOException;
|
||||
|
@ -50,19 +51,33 @@ public interface HttpContent
|
|||
final Resource _resource;
|
||||
final String _mimeType;
|
||||
final int _maxBuffer;
|
||||
final String _etag;
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public ResourceAsHttpContent(final Resource resource, final String mimeType)
|
||||
{
|
||||
_resource=resource;
|
||||
_mimeType=mimeType;
|
||||
_maxBuffer=-1;
|
||||
this(resource,mimeType,-1,false);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public ResourceAsHttpContent(final Resource resource, final String mimeType, int maxBuffer)
|
||||
{
|
||||
this(resource,mimeType,maxBuffer,false);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public ResourceAsHttpContent(final Resource resource, final String mimeType, boolean etag)
|
||||
{
|
||||
this(resource,mimeType,-1,etag);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public ResourceAsHttpContent(final Resource resource, final String mimeType, int maxBuffer, boolean etag)
|
||||
{
|
||||
_resource=resource;
|
||||
_mimeType=mimeType;
|
||||
_maxBuffer=maxBuffer;
|
||||
_etag=etag?resource.getWeakETag():null;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
@ -85,6 +100,13 @@ public interface HttpContent
|
|||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
public String getETag()
|
||||
{
|
||||
return _etag;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
|
|
|
@ -562,7 +562,7 @@ public class HttpParser
|
|||
switch (_header)
|
||||
{
|
||||
case CONTENT_LENGTH:
|
||||
if (_endOfContent != EndOfContent.CHUNKED_CONTENT && _responseStatus!=304 && _responseStatus!=204 && (_responseStatus<100 || _responseStatus>=200))
|
||||
if (_endOfContent != EndOfContent.CHUNKED_CONTENT)
|
||||
{
|
||||
try
|
||||
{
|
||||
|
@ -640,7 +640,6 @@ public class HttpParser
|
|||
_header=null;
|
||||
_value=null;
|
||||
|
||||
|
||||
// now handle the ch
|
||||
if (ch == HttpTokens.CARRIAGE_RETURN || ch == HttpTokens.LINE_FEED)
|
||||
{
|
||||
|
@ -657,8 +656,15 @@ public class HttpParser
|
|||
return true;
|
||||
}
|
||||
|
||||
// so work out the _content demarcation
|
||||
if (_endOfContent == EndOfContent.UNKNOWN_CONTENT)
|
||||
// is it a response that cannot have a body?
|
||||
if (_responseHandler !=null && // response
|
||||
(_responseStatus == 304 || // not-modified response
|
||||
_responseStatus == 204 || // no-content response
|
||||
_responseStatus < 200)) // 1xx response
|
||||
_endOfContent=EndOfContent.NO_CONTENT; // ignore any other headers set
|
||||
|
||||
// else if we don't know framing
|
||||
else if (_endOfContent == EndOfContent.UNKNOWN_CONTENT)
|
||||
{
|
||||
if (_responseStatus == 0 // request
|
||||
|| _responseStatus == 304 // not-modified response
|
||||
|
|
|
@ -470,6 +470,25 @@ public class HttpParserTest
|
|||
assertTrue(_messageCompleted);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testResponse101WithTransferEncoding() throws Exception
|
||||
{
|
||||
ByteBuffer buffer= BufferUtil.toBuffer(
|
||||
"HTTP/1.1 101 switching protocols\015\012"
|
||||
+ "Transfer-Encoding: chunked\015\012"
|
||||
+ "\015\012");
|
||||
|
||||
Handler handler = new Handler();
|
||||
HttpParser parser= new HttpParser((HttpParser.ResponseHandler)handler);
|
||||
parser.parseNext(buffer);
|
||||
assertEquals("HTTP/1.1", _methodOrVersion);
|
||||
assertEquals("101", _uriOrStatus);
|
||||
assertEquals("switching protocols", _versionOrReason);
|
||||
assertEquals(null,_content);
|
||||
assertTrue(_headerCompleted);
|
||||
assertTrue(_messageCompleted);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSeekEOF() throws Exception
|
||||
{
|
||||
|
|
|
@ -21,38 +21,19 @@ package org.eclipse.jetty.io;
|
|||
import java.io.IOException;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import org.eclipse.jetty.util.Callback;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
import org.eclipse.jetty.util.thread.Scheduler;
|
||||
|
||||
public abstract class AbstractEndPoint implements EndPoint
|
||||
public abstract class AbstractEndPoint extends IdleTimeout implements EndPoint
|
||||
{
|
||||
private static final Logger LOG = Log.getLogger(AbstractEndPoint.class);
|
||||
private final long _created=System.currentTimeMillis();
|
||||
private final InetSocketAddress _local;
|
||||
private final InetSocketAddress _remote;
|
||||
|
||||
private final Scheduler _scheduler;
|
||||
private final AtomicReference<Scheduler.Task> _timeout = new AtomicReference<>();
|
||||
private final Runnable _idleTask = new Runnable()
|
||||
{
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
long idleLeft=checkIdleTimeout();
|
||||
if (idleLeft>=0)
|
||||
scheduleIdleTimeout(idleLeft > 0 ? idleLeft : getIdleTimeout());
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
private volatile long _idleTimeout;
|
||||
private volatile long _idleTimestamp=System.currentTimeMillis();
|
||||
private volatile Connection _connection;
|
||||
|
||||
private final FillInterest _fillInterest = new FillInterest()
|
||||
|
@ -74,9 +55,9 @@ public abstract class AbstractEndPoint implements EndPoint
|
|||
|
||||
protected AbstractEndPoint(Scheduler scheduler,InetSocketAddress local,InetSocketAddress remote)
|
||||
{
|
||||
super(scheduler);
|
||||
_local=local;
|
||||
_remote=remote;
|
||||
_scheduler=scheduler;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -85,19 +66,6 @@ public abstract class AbstractEndPoint implements EndPoint
|
|||
return _created;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public long getIdleTimeout()
|
||||
{
|
||||
return _idleTimeout;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setIdleTimeout(long idleTimeout)
|
||||
{
|
||||
_idleTimeout = idleTimeout;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InetSocketAddress getLocalAddress()
|
||||
{
|
||||
|
@ -109,17 +77,7 @@ public abstract class AbstractEndPoint implements EndPoint
|
|||
{
|
||||
return _remote;
|
||||
}
|
||||
|
||||
public long getIdleTimestamp()
|
||||
{
|
||||
return _idleTimestamp;
|
||||
}
|
||||
|
||||
protected void notIdle()
|
||||
{
|
||||
_idleTimestamp=System.currentTimeMillis();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Connection getConnection()
|
||||
{
|
||||
|
@ -145,6 +103,12 @@ public abstract class AbstractEndPoint implements EndPoint
|
|||
_writeFlusher.onClose();
|
||||
_fillInterest.onClose();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close()
|
||||
{
|
||||
super.close();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <C> void fillInterested(C context, Callback<C> callback) throws IllegalStateException
|
||||
|
@ -173,56 +137,23 @@ public abstract class AbstractEndPoint implements EndPoint
|
|||
return _writeFlusher;
|
||||
}
|
||||
|
||||
protected void scheduleIdleTimeout(long delay)
|
||||
@Override
|
||||
protected void onIdleExpired(TimeoutException timeout)
|
||||
{
|
||||
Scheduler.Task newTimeout = null;
|
||||
if (isOpen() && delay > 0 && _scheduler!=null)
|
||||
newTimeout = _scheduler.schedule(_idleTask, delay, TimeUnit.MILLISECONDS);
|
||||
Scheduler.Task oldTimeout = _timeout.getAndSet(newTimeout);
|
||||
if (oldTimeout != null)
|
||||
oldTimeout.cancel();
|
||||
}
|
||||
|
||||
protected long checkIdleTimeout()
|
||||
{
|
||||
if (isOpen())
|
||||
if (isOutputShutdown() || _fillInterest.isInterested() || _writeFlusher.isInProgress())
|
||||
{
|
||||
long idleTimestamp = getIdleTimestamp();
|
||||
long idleTimeout = getIdleTimeout();
|
||||
long idleElapsed = System.currentTimeMillis() - idleTimestamp;
|
||||
long idleLeft = idleTimeout - idleElapsed;
|
||||
|
||||
LOG.debug("{} idle timeout check, elapsed: {} ms, remaining: {} ms", this, idleElapsed, idleLeft);
|
||||
|
||||
if (isOutputShutdown() || _fillInterest.isInterested() || _writeFlusher.isInProgress())
|
||||
{
|
||||
if (idleTimestamp != 0 && idleTimeout > 0)
|
||||
{
|
||||
if (idleLeft <= 0)
|
||||
{
|
||||
LOG.debug("{} idle timeout expired", this);
|
||||
|
||||
boolean output_shutdown=isOutputShutdown();
|
||||
TimeoutException timeout = new TimeoutException("Idle timeout expired: " + idleElapsed + "/" + idleTimeout + " ms");
|
||||
_fillInterest.onFail(timeout);
|
||||
_writeFlusher.onFail(timeout);
|
||||
|
||||
if (output_shutdown)
|
||||
close();
|
||||
notIdle();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return idleLeft>=0?idleLeft:0;
|
||||
boolean output_shutdown=isOutputShutdown();
|
||||
_fillInterest.onFail(timeout);
|
||||
_writeFlusher.onFail(timeout);
|
||||
if (output_shutdown)
|
||||
close();
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return String.format("%s@%x{%s<r-l>%s,o=%b,is=%b,os=%b,fi=%s,wf=%s,to=%d}{%s}",
|
||||
return String.format("%s@%x{%s<r-l>%s,o=%b,is=%b,os=%b,fi=%s,wf=%s,it=%d}{%s}",
|
||||
getClass().getSimpleName(),
|
||||
hashCode(),
|
||||
getRemoteAddress(),
|
||||
|
@ -232,7 +163,7 @@ public abstract class AbstractEndPoint implements EndPoint
|
|||
isOutputShutdown(),
|
||||
_fillInterest,
|
||||
_writeFlusher,
|
||||
_idleTimeout,
|
||||
getIdleTimeout(),
|
||||
getConnection());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,153 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2012 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.io;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
import org.eclipse.jetty.util.thread.Scheduler;
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** An Abstract implementation of an Idle Timeout.
|
||||
*
|
||||
* This implementation is optimised that timeout operations are not cancelled on
|
||||
* every operation. Rather timeout are allowed to expire and a check is then made
|
||||
* to see when the last operation took place. If the idle timeout has not expired,
|
||||
* the timeout is rescheduled for the earliest possible time a timeout could occur.
|
||||
*
|
||||
*/
|
||||
public abstract class IdleTimeout
|
||||
{
|
||||
private static final Logger LOG = Log.getLogger(IdleTimeout.class);
|
||||
private final Scheduler _scheduler;
|
||||
private final AtomicReference<Scheduler.Task> _timeout = new AtomicReference<>();
|
||||
private volatile long _idleTimeout;
|
||||
private volatile long _idleTimestamp=System.currentTimeMillis();
|
||||
|
||||
private final Runnable _idleTask = new Runnable()
|
||||
{
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
long idleLeft=checkIdleTimeout();
|
||||
if (idleLeft>=0)
|
||||
scheduleIdleTimeout(idleLeft > 0 ? idleLeft : getIdleTimeout());
|
||||
}
|
||||
};
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @param scheduler A scheduler used to schedule checks for the idle timeout.
|
||||
*/
|
||||
public IdleTimeout(Scheduler scheduler)
|
||||
{
|
||||
_scheduler=scheduler;
|
||||
}
|
||||
|
||||
public long getIdleTimestamp()
|
||||
{
|
||||
return _idleTimestamp;
|
||||
}
|
||||
|
||||
public long getIdleTimeout()
|
||||
{
|
||||
return _idleTimeout;
|
||||
}
|
||||
|
||||
public void setIdleTimeout(long idleTimeout)
|
||||
{
|
||||
_idleTimeout = idleTimeout;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** This method should be called when non-idle activity has taken place.
|
||||
*/
|
||||
public void notIdle()
|
||||
{
|
||||
_idleTimestamp=System.currentTimeMillis();
|
||||
}
|
||||
|
||||
protected void scheduleIdleTimeout(long delay)
|
||||
{
|
||||
Scheduler.Task newTimeout = null;
|
||||
if (isOpen() && delay > 0 && _scheduler!=null)
|
||||
newTimeout = _scheduler.schedule(_idleTask, delay, TimeUnit.MILLISECONDS);
|
||||
Scheduler.Task oldTimeout = _timeout.getAndSet(newTimeout);
|
||||
if (oldTimeout != null)
|
||||
oldTimeout.cancel();
|
||||
}
|
||||
|
||||
protected void close()
|
||||
{
|
||||
Scheduler.Task oldTimeout = _timeout.getAndSet(null);
|
||||
if (oldTimeout != null)
|
||||
oldTimeout.cancel();
|
||||
}
|
||||
|
||||
protected long checkIdleTimeout()
|
||||
{
|
||||
if (isOpen())
|
||||
{
|
||||
long idleTimestamp = getIdleTimestamp();
|
||||
long idleTimeout = getIdleTimeout();
|
||||
long idleElapsed = System.currentTimeMillis() - idleTimestamp;
|
||||
long idleLeft = idleTimeout - idleElapsed;
|
||||
|
||||
LOG.debug("{} idle timeout check, elapsed: {} ms, remaining: {} ms", this, idleElapsed, idleLeft);
|
||||
|
||||
if (idleTimestamp != 0 && idleTimeout > 0)
|
||||
{
|
||||
if (idleLeft <= 0)
|
||||
{
|
||||
LOG.debug("{} idle timeout expired", this);
|
||||
try
|
||||
{
|
||||
onIdleExpired(new TimeoutException("Idle timeout expired: " + idleElapsed + "/" + idleTimeout + " ms"));
|
||||
}
|
||||
finally
|
||||
{
|
||||
notIdle();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return idleLeft>=0?idleLeft:0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** This abstract method is called when the idle timeout has expired.
|
||||
* @param timeout a TimeoutException
|
||||
*/
|
||||
abstract protected void onIdleExpired(TimeoutException timeout);
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** This abstract method should be called to check if idle timeouts
|
||||
* should still be checked.
|
||||
* @return True if the entity monitored should still be checked for idle timeouts
|
||||
*/
|
||||
abstract protected boolean isOpen();
|
||||
}
|
|
@ -19,6 +19,7 @@
|
|||
package org.eclipse.jetty.security.jaspi;
|
||||
|
||||
import java.security.Principal;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
@ -137,7 +138,7 @@ public class JaspiAuthenticatorFactory extends DefaultAuthenticatorFactory
|
|||
{
|
||||
if (_serviceSubject!=null)
|
||||
return _serviceSubject;
|
||||
List subjects = server.getBeans(Subject.class);
|
||||
List<Subject> subjects = (List<Subject>)server.getBeans(Subject.class);
|
||||
if (subjects.size()>0)
|
||||
return (Subject)subjects.get(0);
|
||||
return null;
|
||||
|
|
|
@ -31,7 +31,7 @@ import javax.security.auth.message.MessagePolicy;
|
|||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.eclipse.jetty.http.HttpHeaders;
|
||||
import org.eclipse.jetty.http.HttpHeader;
|
||||
import org.eclipse.jetty.util.security.Constraint;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
|
@ -75,7 +75,7 @@ public class BasicAuthModule extends BaseAuthModule
|
|||
{
|
||||
HttpServletRequest request = (HttpServletRequest) messageInfo.getRequestMessage();
|
||||
HttpServletResponse response = (HttpServletResponse) messageInfo.getResponseMessage();
|
||||
String credentials = request.getHeader(HttpHeaders.AUTHORIZATION);
|
||||
String credentials = request.getHeader(HttpHeader.AUTHORIZATION.asString());
|
||||
|
||||
try
|
||||
{
|
||||
|
@ -87,7 +87,7 @@ public class BasicAuthModule extends BaseAuthModule
|
|||
}
|
||||
|
||||
if (!isMandatory(messageInfo)) { return AuthStatus.SUCCESS; }
|
||||
response.setHeader(HttpHeaders.WWW_AUTHENTICATE, "basic realm=\"" + realmName + '"');
|
||||
response.setHeader(HttpHeader.WWW_AUTHENTICATE.asString(), "basic realm=\"" + realmName + '"');
|
||||
response.sendError(HttpServletResponse.SC_UNAUTHORIZED);
|
||||
return AuthStatus.SEND_CONTINUE;
|
||||
}
|
||||
|
|
|
@ -32,7 +32,7 @@ import javax.security.auth.message.MessagePolicy;
|
|||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.eclipse.jetty.http.HttpHeaders;
|
||||
import org.eclipse.jetty.http.HttpHeader;
|
||||
import org.eclipse.jetty.util.security.Constraint;
|
||||
import org.eclipse.jetty.util.security.Credential;
|
||||
import org.eclipse.jetty.util.B64Code;
|
||||
|
@ -87,7 +87,7 @@ public class DigestAuthModule extends BaseAuthModule
|
|||
{
|
||||
HttpServletRequest request = (HttpServletRequest) messageInfo.getRequestMessage();
|
||||
HttpServletResponse response = (HttpServletResponse) messageInfo.getResponseMessage();
|
||||
String credentials = request.getHeader(HttpHeaders.AUTHORIZATION);
|
||||
String credentials = request.getHeader(HttpHeader.AUTHORIZATION.asString());
|
||||
|
||||
try
|
||||
{
|
||||
|
@ -155,7 +155,7 @@ public class DigestAuthModule extends BaseAuthModule
|
|||
if (!isMandatory(messageInfo)) { return AuthStatus.SUCCESS; }
|
||||
String domain = request.getContextPath();
|
||||
if (domain == null) domain = "/";
|
||||
response.setHeader(HttpHeaders.WWW_AUTHENTICATE, "Digest realm=\"" + realmName
|
||||
response.setHeader(HttpHeader.WWW_AUTHENTICATE.asString(), "Digest realm=\"" + realmName
|
||||
+ "\", domain=\""
|
||||
+ domain
|
||||
+ "\", nonce=\""
|
||||
|
|
|
@ -87,6 +87,11 @@
|
|||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-jaas</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-plus</artifactId>
|
||||
|
|
|
@ -54,11 +54,17 @@ import org.eclipse.jetty.xml.XmlConfiguration;
|
|||
/**
|
||||
* AbstractJettyMojo
|
||||
*
|
||||
*
|
||||
* Common base class for most jetty mojos.
|
||||
*
|
||||
*
|
||||
*/
|
||||
public abstract class AbstractJettyMojo extends AbstractMojo
|
||||
{
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public String PORT_SYSPROPERTY = "jetty.port";
|
||||
|
||||
|
||||
/**
|
||||
* Whether or not to include dependencies on the plugin's classpath with <scope>provided</scope>
|
||||
|
@ -79,7 +85,6 @@ public abstract class AbstractJettyMojo extends AbstractMojo
|
|||
protected String[] excludedGoals;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* List of connectors to use. If none are configured
|
||||
* then the default is a single SelectChannelConnector at port 8080. You can
|
||||
|
@ -114,7 +119,6 @@ public abstract class AbstractJettyMojo extends AbstractMojo
|
|||
protected LoginService[] loginServices;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* A RequestLog implementation to use for the webapp at runtime.
|
||||
* Consider using instead the <jettyXml> element to specify external jetty xml config file.
|
||||
|
@ -126,7 +130,6 @@ public abstract class AbstractJettyMojo extends AbstractMojo
|
|||
protected RequestLog requestLog;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* An instance of org.eclipse.jetty.webapp.WebAppContext that represents the webapp.
|
||||
* Use any of its setters to configure the webapp. This is the preferred and most
|
||||
|
@ -138,32 +141,6 @@ public abstract class AbstractJettyMojo extends AbstractMojo
|
|||
protected JettyWebAppContext webApp;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* The context path for the webapp. Defaults to the
|
||||
* name of the webapp's artifact.
|
||||
*
|
||||
* @deprecated Use <webApp><contextPath> instead.
|
||||
* @parameter expression="/${project.artifactId}"
|
||||
* @required
|
||||
* @readonly
|
||||
*/
|
||||
protected String contextPath;
|
||||
|
||||
|
||||
/**
|
||||
* The temporary directory to use for the webapp.
|
||||
* Defaults to target/tmp.
|
||||
*
|
||||
* @deprecated Use %lt;webApp><tempDirectory> instead.
|
||||
* @parameter expression="${project.build.directory}/tmp"
|
||||
* @required
|
||||
* @readonly
|
||||
*/
|
||||
protected File tmpDirectory;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* The interval in seconds to scan the webapp for changes
|
||||
* and restart the context if necessary. Ignored if reload
|
||||
|
@ -184,6 +161,7 @@ public abstract class AbstractJettyMojo extends AbstractMojo
|
|||
* @parameter expression="${jetty.reload}" default-value="automatic"
|
||||
*/
|
||||
protected String reload;
|
||||
|
||||
|
||||
/**
|
||||
* File containing system properties to be set before execution
|
||||
|
@ -196,6 +174,7 @@ public abstract class AbstractJettyMojo extends AbstractMojo
|
|||
*/
|
||||
protected File systemPropertiesFile;
|
||||
|
||||
|
||||
/**
|
||||
* System properties to set before execution.
|
||||
* Note that these properties will NOT override System properties
|
||||
|
@ -207,7 +186,6 @@ public abstract class AbstractJettyMojo extends AbstractMojo
|
|||
protected SystemProperties systemProperties;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Comma separated list of a jetty xml configuration files whose contents
|
||||
* will be applied before any plugin configuration. Optional.
|
||||
|
@ -226,6 +204,7 @@ public abstract class AbstractJettyMojo extends AbstractMojo
|
|||
*/
|
||||
protected int stopPort;
|
||||
|
||||
|
||||
/**
|
||||
* Key to provide when stopping jetty on executing java -DSTOP.KEY=<stopKey>
|
||||
* -DSTOP.PORT=<stopPort> -jar start.jar --stop
|
||||
|
@ -234,6 +213,7 @@ public abstract class AbstractJettyMojo extends AbstractMojo
|
|||
*/
|
||||
protected String stopKey;
|
||||
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Determines whether or not the server blocks when started. The default
|
||||
|
@ -250,6 +230,7 @@ public abstract class AbstractJettyMojo extends AbstractMojo
|
|||
*/
|
||||
protected boolean daemon;
|
||||
|
||||
|
||||
/**
|
||||
* Skip this mojo execution.
|
||||
*
|
||||
|
@ -290,8 +271,7 @@ public abstract class AbstractJettyMojo extends AbstractMojo
|
|||
* @parameter expression="${mojoExecution}"
|
||||
* @readonly
|
||||
*/
|
||||
private org.apache.maven.plugin.MojoExecution execution;
|
||||
|
||||
protected org.apache.maven.plugin.MojoExecution execution;
|
||||
|
||||
|
||||
/**
|
||||
|
@ -300,8 +280,7 @@ public abstract class AbstractJettyMojo extends AbstractMojo
|
|||
* @parameter expression="${plugin.artifacts}"
|
||||
* @readonly
|
||||
*/
|
||||
private List pluginArtifacts;
|
||||
|
||||
protected List pluginArtifacts;
|
||||
|
||||
|
||||
/**
|
||||
|
@ -309,16 +288,19 @@ public abstract class AbstractJettyMojo extends AbstractMojo
|
|||
*/
|
||||
protected JettyServer server;
|
||||
|
||||
|
||||
/**
|
||||
* A scanner to check for changes to the webapp
|
||||
*/
|
||||
protected Scanner scanner;
|
||||
|
||||
|
||||
/**
|
||||
* List of files and directories to scan
|
||||
*/
|
||||
protected ArrayList<File> scanList;
|
||||
|
||||
|
||||
/**
|
||||
* List of Listeners for the scanner
|
||||
*/
|
||||
|
@ -329,14 +311,17 @@ public abstract class AbstractJettyMojo extends AbstractMojo
|
|||
* A scanner to check ENTER hits on the console
|
||||
*/
|
||||
protected Thread consoleScanner;
|
||||
|
||||
|
||||
public String PORT_SYSPROPERTY = "jetty.port";
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
public abstract void restartWebApp(boolean reconfigureScanner) throws Exception;
|
||||
|
||||
public abstract void checkPomConfiguration() throws MojoExecutionException;
|
||||
|
||||
public abstract void checkPomConfiguration() throws MojoExecutionException;
|
||||
|
||||
|
||||
public abstract void configureScanner () throws MojoExecutionException;
|
||||
|
||||
|
@ -344,9 +329,12 @@ public abstract class AbstractJettyMojo extends AbstractMojo
|
|||
|
||||
|
||||
|
||||
/**
|
||||
* @see org.apache.maven.plugin.Mojo#execute()
|
||||
*/
|
||||
public void execute() throws MojoExecutionException, MojoFailureException
|
||||
{
|
||||
getLog().info("Configuring Jetty for project: " + getProject().getName());
|
||||
getLog().info("Configuring Jetty for project: " + this.project.getName());
|
||||
if (skip)
|
||||
{
|
||||
getLog().info("Skipping Jetty start: jetty.skip==true");
|
||||
|
@ -367,6 +355,11 @@ public abstract class AbstractJettyMojo extends AbstractMojo
|
|||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @throws MojoExecutionException
|
||||
*/
|
||||
public void configurePluginClasspath() throws MojoExecutionException
|
||||
{
|
||||
//if we are configured to include the provided dependencies on the plugin's classpath
|
||||
|
@ -407,6 +400,12 @@ public abstract class AbstractJettyMojo extends AbstractMojo
|
|||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @param artifact
|
||||
* @return
|
||||
*/
|
||||
public boolean isPluginArtifact(Artifact artifact)
|
||||
{
|
||||
if (pluginArtifacts == null || pluginArtifacts.isEmpty())
|
||||
|
@ -424,6 +423,12 @@ public abstract class AbstractJettyMojo extends AbstractMojo
|
|||
return isPluginArtifact;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
public void finishConfigurationBeforeStart() throws Exception
|
||||
{
|
||||
HandlerCollection contexts = (HandlerCollection)server.getChildHandlerByClass(ContextHandlerCollection.class);
|
||||
|
@ -439,6 +444,9 @@ public abstract class AbstractJettyMojo extends AbstractMojo
|
|||
|
||||
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
public void applyJettyXml() throws Exception
|
||||
{
|
||||
if (getJettyXmlFiles() == null)
|
||||
|
@ -454,6 +462,10 @@ public abstract class AbstractJettyMojo extends AbstractMojo
|
|||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @throws MojoExecutionException
|
||||
*/
|
||||
public void startJetty () throws MojoExecutionException
|
||||
{
|
||||
try
|
||||
|
@ -462,13 +474,10 @@ public abstract class AbstractJettyMojo extends AbstractMojo
|
|||
|
||||
printSystemProperties();
|
||||
this.server = new JettyServer();
|
||||
setServer(this.server);
|
||||
|
||||
|
||||
//apply any config from a jetty.xml file first which is able to
|
||||
//be overwritten by config in the pom.xml
|
||||
applyJettyXml ();
|
||||
|
||||
|
||||
applyJettyXml ();
|
||||
|
||||
// if the user hasn't configured their project's pom to use a
|
||||
// different set of connectors,
|
||||
|
@ -488,10 +497,9 @@ public abstract class AbstractJettyMojo extends AbstractMojo
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
//set up a RequestLog if one is provided
|
||||
if (this.requestLog != null)
|
||||
getServer().setRequestLog(this.requestLog);
|
||||
this.server.setRequestLog(this.requestLog);
|
||||
|
||||
//set up the webapp and any context provided
|
||||
this.server.configureHandlers();
|
||||
|
@ -502,7 +510,7 @@ public abstract class AbstractJettyMojo extends AbstractMojo
|
|||
for (int i = 0; (this.loginServices != null) && i < this.loginServices.length; i++)
|
||||
{
|
||||
getLog().debug(this.loginServices[i].getClass().getName() + ": "+ this.loginServices[i].toString());
|
||||
getServer().addBean(this.loginServices[i]);
|
||||
this.server.addBean(this.loginServices[i]);
|
||||
}
|
||||
|
||||
//do any other configuration required by the
|
||||
|
@ -543,12 +551,12 @@ public abstract class AbstractJettyMojo extends AbstractMojo
|
|||
{
|
||||
getLog().info("Jetty server exiting.");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Subclasses should invoke this to setup basic info
|
||||
* on the webapp
|
||||
|
@ -571,22 +579,23 @@ public abstract class AbstractJettyMojo extends AbstractMojo
|
|||
getLog().info("Applying context xml file "+contextXml);
|
||||
xmlConfiguration.configure(webApp);
|
||||
}
|
||||
|
||||
|
||||
//If no contextPath was specified, go with our default
|
||||
//If no contextPath was specified, go with default of project artifactid
|
||||
String cp = webApp.getContextPath();
|
||||
if (cp == null || "".equals(cp))
|
||||
{
|
||||
webApp.setContextPath((contextPath.startsWith("/") ? contextPath : "/"+ contextPath));
|
||||
}
|
||||
cp = "/"+project.getArtifactId();
|
||||
webApp.setContextPath(cp);
|
||||
}
|
||||
|
||||
//If no tmp directory was specified, and we have one, use it
|
||||
if (webApp.getTempDirectory() == null && tmpDirectory != null)
|
||||
if (webApp.getTempDirectory() == null)
|
||||
{
|
||||
if (!tmpDirectory.exists())
|
||||
tmpDirectory.mkdirs();
|
||||
|
||||
webApp.setTempDirectory(tmpDirectory);
|
||||
File target = new File(project.getBuild().getDirectory());
|
||||
File tmp = new File(target,"tmp");
|
||||
if (!tmp.exists())
|
||||
tmp.mkdirs();
|
||||
webApp.setTempDirectory(tmp);
|
||||
}
|
||||
|
||||
getLog().info("Context path = " + webApp.getContextPath());
|
||||
|
@ -595,6 +604,9 @@ public abstract class AbstractJettyMojo extends AbstractMojo
|
|||
getLog().info("Web overrides = "+(webApp.getOverrideDescriptor()==null?" none":webApp.getOverrideDescriptor()));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Run a scanner thread on the given list of files and directories, calling
|
||||
* stop/start on the given list of LifeCycle objects if any of the watched
|
||||
|
@ -604,7 +616,7 @@ public abstract class AbstractJettyMojo extends AbstractMojo
|
|||
private void startScanner() throws Exception
|
||||
{
|
||||
// check if scanning is enabled
|
||||
if (getScanIntervalSeconds() <= 0) return;
|
||||
if (scanIntervalSeconds <= 0) return;
|
||||
|
||||
// check if reload is manual. It disables file scanning
|
||||
if ( "manual".equalsIgnoreCase( reload ) )
|
||||
|
@ -617,17 +629,19 @@ public abstract class AbstractJettyMojo extends AbstractMojo
|
|||
|
||||
scanner = new Scanner();
|
||||
scanner.setReportExistingFilesOnStartup(false);
|
||||
scanner.setScanInterval(getScanIntervalSeconds());
|
||||
scanner.setScanDirs(getScanList());
|
||||
scanner.setScanInterval(scanIntervalSeconds);
|
||||
scanner.setScanDirs(scanList);
|
||||
scanner.setRecursive(true);
|
||||
List listeners = getScannerListeners();
|
||||
Iterator itor = (listeners==null?null:listeners.iterator());
|
||||
Iterator itor = (this.scannerListeners==null?null:this.scannerListeners.iterator());
|
||||
while (itor!=null && itor.hasNext())
|
||||
scanner.addListener((Scanner.Listener)itor.next());
|
||||
getLog().info("Starting scanner at interval of " + getScanIntervalSeconds()+ " seconds.");
|
||||
getLog().info("Starting scanner at interval of " + scanIntervalSeconds + " seconds.");
|
||||
scanner.start();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Run a thread that monitors the console input to detect ENTER hits.
|
||||
*/
|
||||
|
@ -641,6 +655,12 @@ public abstract class AbstractJettyMojo extends AbstractMojo
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private void printSystemProperties ()
|
||||
{
|
||||
// print out which system properties were set up
|
||||
|
@ -658,6 +678,9 @@ public abstract class AbstractJettyMojo extends AbstractMojo
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Try and find a jetty-web.xml file, using some
|
||||
* historical naming conventions if necessary.
|
||||
|
@ -684,61 +707,12 @@ public abstract class AbstractJettyMojo extends AbstractMojo
|
|||
}
|
||||
|
||||
|
||||
public Scanner getScanner ()
|
||||
{
|
||||
return scanner;
|
||||
}
|
||||
|
||||
|
||||
public MavenProject getProject()
|
||||
{
|
||||
return this.project;
|
||||
}
|
||||
|
||||
public void setProject(MavenProject project) {
|
||||
this.project = project;
|
||||
}
|
||||
|
||||
public File getTmpDirectory()
|
||||
{
|
||||
return this.tmpDirectory;
|
||||
}
|
||||
|
||||
public void setTmpDirectory(File tmpDirectory) {
|
||||
this.tmpDirectory = tmpDirectory;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Returns the contextPath.
|
||||
* @param file
|
||||
* @throws Exception
|
||||
*/
|
||||
public String getContextPath()
|
||||
{
|
||||
return this.contextPath;
|
||||
}
|
||||
|
||||
public void setContextPath(String contextPath) {
|
||||
this.contextPath = contextPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Returns the scanIntervalSeconds.
|
||||
*/
|
||||
public int getScanIntervalSeconds()
|
||||
{
|
||||
return this.scanIntervalSeconds;
|
||||
}
|
||||
|
||||
public void setScanIntervalSeconds(int scanIntervalSeconds) {
|
||||
this.scanIntervalSeconds = scanIntervalSeconds;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return returns the path to the systemPropertiesFile
|
||||
*/
|
||||
public File getSystemPropertiesFile()
|
||||
{
|
||||
return this.systemPropertiesFile;
|
||||
}
|
||||
|
||||
public void setSystemPropertiesFile(File file) throws Exception
|
||||
{
|
||||
this.systemPropertiesFile = file;
|
||||
|
@ -760,10 +734,15 @@ public abstract class AbstractJettyMojo extends AbstractMojo
|
|||
|
||||
this.systemProperties.setSystemProperty(prop);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @param systemProperties
|
||||
*/
|
||||
public void setSystemProperties(SystemProperties systemProperties)
|
||||
{
|
||||
if (this.systemProperties == null)
|
||||
|
@ -778,12 +757,16 @@ public abstract class AbstractJettyMojo extends AbstractMojo
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public SystemProperties getSystemProperties ()
|
||||
{
|
||||
return this.systemProperties;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @return
|
||||
*/
|
||||
public List<File> getJettyXmlFiles()
|
||||
{
|
||||
if ( this.jettyXml == null )
|
||||
|
@ -810,170 +793,12 @@ public abstract class AbstractJettyMojo extends AbstractMojo
|
|||
return jettyXmlFiles;
|
||||
}
|
||||
|
||||
|
||||
public JettyServer getServer ()
|
||||
{
|
||||
return this.server;
|
||||
}
|
||||
|
||||
public void setServer (JettyServer server)
|
||||
{
|
||||
this.server = server;
|
||||
}
|
||||
|
||||
|
||||
public void setScanList (ArrayList<File> list)
|
||||
{
|
||||
this.scanList = new ArrayList<File>(list);
|
||||
}
|
||||
|
||||
public ArrayList<File> getScanList ()
|
||||
{
|
||||
return this.scanList;
|
||||
}
|
||||
|
||||
|
||||
public void setScannerListeners (ArrayList<Scanner.BulkListener> listeners)
|
||||
{
|
||||
this.scannerListeners = new ArrayList<Scanner.BulkListener>(listeners);
|
||||
}
|
||||
|
||||
public ArrayList getScannerListeners()
|
||||
{
|
||||
return this.scannerListeners;
|
||||
}
|
||||
|
||||
public JettyWebAppContext getWebAppConfig()
|
||||
{
|
||||
return webApp;
|
||||
}
|
||||
|
||||
public void setWebAppConfig(JettyWebAppContext webAppConfig)
|
||||
{
|
||||
this.webApp = webAppConfig;
|
||||
}
|
||||
|
||||
public RequestLog getRequestLog()
|
||||
{
|
||||
return requestLog;
|
||||
}
|
||||
|
||||
public void setRequestLog(RequestLog requestLog)
|
||||
{
|
||||
this.requestLog = requestLog;
|
||||
}
|
||||
|
||||
public LoginService[] getLoginServices()
|
||||
{
|
||||
return loginServices;
|
||||
}
|
||||
|
||||
public void setLoginServices(LoginService[] loginServices)
|
||||
{
|
||||
this.loginServices = loginServices;
|
||||
}
|
||||
|
||||
public ContextHandler[] getContextHandlers()
|
||||
{
|
||||
return contextHandlers;
|
||||
}
|
||||
|
||||
public void setContextHandlers(ContextHandler[] contextHandlers)
|
||||
{
|
||||
this.contextHandlers = contextHandlers;
|
||||
}
|
||||
|
||||
public Connector[] getConnectors()
|
||||
{
|
||||
return connectors;
|
||||
}
|
||||
|
||||
public void setConnectors(Connector[] connectors)
|
||||
{
|
||||
this.connectors = connectors;
|
||||
}
|
||||
|
||||
public String getReload()
|
||||
{
|
||||
return reload;
|
||||
}
|
||||
|
||||
public void setReload(String reload)
|
||||
{
|
||||
this.reload = reload;
|
||||
}
|
||||
|
||||
public String getJettyConfig()
|
||||
{
|
||||
return jettyXml;
|
||||
}
|
||||
|
||||
public void setJettyConfig(String jettyConfig)
|
||||
{
|
||||
this.jettyXml = jettyConfig;
|
||||
}
|
||||
|
||||
public String getWebAppXml()
|
||||
{
|
||||
return contextXml;
|
||||
}
|
||||
|
||||
public void setWebAppXml(String webAppXml)
|
||||
{
|
||||
this.contextXml = webAppXml;
|
||||
}
|
||||
|
||||
public boolean isSkip()
|
||||
{
|
||||
return skip;
|
||||
}
|
||||
|
||||
public void setSkip(boolean skip)
|
||||
{
|
||||
this.skip = skip;
|
||||
}
|
||||
|
||||
public boolean isDaemon()
|
||||
{
|
||||
return daemon;
|
||||
}
|
||||
|
||||
public void setDaemon(boolean daemon)
|
||||
{
|
||||
this.daemon = daemon;
|
||||
}
|
||||
|
||||
public String getStopKey()
|
||||
{
|
||||
return stopKey;
|
||||
}
|
||||
|
||||
public void setStopKey(String stopKey)
|
||||
{
|
||||
this.stopKey = stopKey;
|
||||
}
|
||||
|
||||
public int getStopPort()
|
||||
{
|
||||
return stopPort;
|
||||
}
|
||||
|
||||
public void setStopPort(int stopPort)
|
||||
{
|
||||
this.stopPort = stopPort;
|
||||
}
|
||||
|
||||
public List getPluginArtifacts()
|
||||
{
|
||||
return pluginArtifacts;
|
||||
}
|
||||
|
||||
public void setPluginArtifacts(List pluginArtifacts)
|
||||
{
|
||||
this.pluginArtifacts = pluginArtifacts;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param goal
|
||||
* @return
|
||||
*/
|
||||
public boolean isExcluded (String goal)
|
||||
{
|
||||
if (excludedGoals == null || goal == null)
|
||||
|
|
|
@ -20,11 +20,26 @@ package org.eclipse.jetty.maven.plugin;
|
|||
|
||||
import java.io.IOException;
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* ConsoleScanner
|
||||
*
|
||||
* Read input from stdin
|
||||
*/
|
||||
public class ConsoleScanner extends Thread
|
||||
{
|
||||
|
||||
private final AbstractJettyMojo mojo;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @param mojo
|
||||
*/
|
||||
public ConsoleScanner(AbstractJettyMojo mojo)
|
||||
{
|
||||
this.mojo = mojo;
|
||||
|
@ -32,6 +47,12 @@ public class ConsoleScanner extends Thread
|
|||
setDaemon(true);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @see java.lang.Thread#run()
|
||||
*/
|
||||
public void run()
|
||||
{
|
||||
try
|
||||
|
@ -48,6 +69,12 @@ public class ConsoleScanner extends Thread
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private void getSomeSleep()
|
||||
{
|
||||
try
|
||||
|
@ -60,6 +87,12 @@ public class ConsoleScanner extends Thread
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @throws IOException
|
||||
*/
|
||||
private void checkSystemInput() throws IOException
|
||||
{
|
||||
while (System.in.available() > 0) {
|
||||
|
@ -75,6 +108,8 @@ public class ConsoleScanner extends Thread
|
|||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Skip buffered bytes of system console.
|
||||
*/
|
||||
|
@ -101,6 +136,12 @@ public class ConsoleScanner extends Thread
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private void restartWebApp()
|
||||
{
|
||||
try
|
||||
|
|
|
@ -18,33 +18,24 @@
|
|||
|
||||
package org.eclipse.jetty.maven.plugin;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.LineNumberReader;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.Random;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.apache.maven.artifact.Artifact;
|
||||
import org.apache.maven.plugin.AbstractMojo;
|
||||
|
@ -52,10 +43,7 @@ import org.apache.maven.plugin.MojoExecutionException;
|
|||
import org.apache.maven.plugin.MojoFailureException;
|
||||
import org.apache.maven.plugin.descriptor.PluginDescriptor;
|
||||
import org.apache.maven.project.MavenProject;
|
||||
import org.codehaus.plexus.component.repository.ComponentDependency;
|
||||
import org.eclipse.jetty.server.RequestLog;
|
||||
import org.eclipse.jetty.util.IO;
|
||||
import org.eclipse.jetty.util.resource.Resource;
|
||||
|
||||
|
||||
/**
|
||||
|
@ -104,7 +92,6 @@ public class JettyRunForkedMojo extends AbstractMojo
|
|||
* @readonly
|
||||
*/
|
||||
private MavenProject project;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
|
@ -125,6 +112,7 @@ public class JettyRunForkedMojo extends AbstractMojo
|
|||
*/
|
||||
private String webXml;
|
||||
|
||||
|
||||
/**
|
||||
* The target directory
|
||||
*
|
||||
|
@ -153,8 +141,7 @@ public class JettyRunForkedMojo extends AbstractMojo
|
|||
* @required
|
||||
*
|
||||
*/
|
||||
private File classesDirectory;
|
||||
|
||||
private File classesDirectory;
|
||||
|
||||
|
||||
/**
|
||||
|
@ -164,6 +151,7 @@ public class JettyRunForkedMojo extends AbstractMojo
|
|||
* @required
|
||||
*/
|
||||
private File testClassesDirectory;
|
||||
|
||||
|
||||
/**
|
||||
* Root directory for all html/jsp etc files
|
||||
|
@ -171,17 +159,8 @@ public class JettyRunForkedMojo extends AbstractMojo
|
|||
* @parameter expression="${basedir}/src/main/webapp"
|
||||
*
|
||||
*/
|
||||
private File webAppSourceDirectory;
|
||||
|
||||
|
||||
/**
|
||||
* Directories that contain static resources
|
||||
* for the webapp. Optional.
|
||||
*
|
||||
* @parameter
|
||||
*/
|
||||
private File[] resourceBases;
|
||||
|
||||
private File webAppSourceDirectory;
|
||||
|
||||
|
||||
/**
|
||||
* If true, the webAppSourceDirectory will be first on the list of
|
||||
|
@ -201,12 +180,9 @@ public class JettyRunForkedMojo extends AbstractMojo
|
|||
private String jettyXml;
|
||||
|
||||
/**
|
||||
* The context path for the webapp. Defaults to the
|
||||
* name of the webapp's artifact.
|
||||
* The context path for the webapp. Defaults to / for jetty-9
|
||||
*
|
||||
* @parameter expression="/${project.artifactId}"
|
||||
* @required
|
||||
* @readonly
|
||||
* @parameter expression="/"
|
||||
*/
|
||||
private String contextPath;
|
||||
|
||||
|
@ -224,6 +200,7 @@ public class JettyRunForkedMojo extends AbstractMojo
|
|||
*/
|
||||
private boolean skip;
|
||||
|
||||
|
||||
/**
|
||||
* Port to listen to stop jetty on executing -DSTOP.PORT=<stopPort>
|
||||
* -DSTOP.KEY=<stopKey> -jar start.jar --stop
|
||||
|
@ -231,6 +208,7 @@ public class JettyRunForkedMojo extends AbstractMojo
|
|||
* @required
|
||||
*/
|
||||
protected int stopPort;
|
||||
|
||||
|
||||
/**
|
||||
* Key to provide when stopping jetty on executing java -DSTOP.KEY=<stopKey>
|
||||
|
@ -246,7 +224,6 @@ public class JettyRunForkedMojo extends AbstractMojo
|
|||
* @parameter
|
||||
*/
|
||||
private String jvmArgs;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
|
@ -263,19 +240,33 @@ public class JettyRunForkedMojo extends AbstractMojo
|
|||
private PluginDescriptor plugin;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @parameter expression="true" default-value="true"
|
||||
*/
|
||||
private boolean waitForChild;
|
||||
|
||||
|
||||
/**
|
||||
* The forked jetty instance
|
||||
*/
|
||||
private Process forkedProcess;
|
||||
|
||||
private Random random;
|
||||
|
||||
/**
|
||||
* Random number generator
|
||||
*/
|
||||
private Random random;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* ShutdownThread
|
||||
*
|
||||
*
|
||||
*/
|
||||
public class ShutdownThread extends Thread
|
||||
{
|
||||
public ShutdownThread()
|
||||
|
@ -292,6 +283,51 @@ public class JettyRunForkedMojo extends AbstractMojo
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* ConsoleStreamer
|
||||
*
|
||||
* Simple streamer for the console output from a Process
|
||||
*/
|
||||
private static class ConsoleStreamer implements Runnable
|
||||
{
|
||||
private String mode;
|
||||
private BufferedReader reader;
|
||||
|
||||
public ConsoleStreamer(String mode, InputStream is)
|
||||
{
|
||||
this.mode = mode;
|
||||
this.reader = new BufferedReader(new InputStreamReader(is));
|
||||
}
|
||||
|
||||
|
||||
public void run()
|
||||
{
|
||||
String line;
|
||||
try
|
||||
{
|
||||
while ((line = reader.readLine()) != (null))
|
||||
{
|
||||
System.out.println("[" + mode + "] " + line);
|
||||
}
|
||||
}
|
||||
catch (IOException ignore)
|
||||
{
|
||||
/* ignore */
|
||||
}
|
||||
finally
|
||||
{
|
||||
IO.close(reader);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @see org.apache.maven.plugin.Mojo#execute()
|
||||
*/
|
||||
|
@ -310,6 +346,12 @@ public class JettyRunForkedMojo extends AbstractMojo
|
|||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @return
|
||||
* @throws MojoExecutionException
|
||||
*/
|
||||
public List<String> getProvidedJars() throws MojoExecutionException
|
||||
{
|
||||
//if we are configured to include the provided dependencies on the plugin's classpath
|
||||
|
@ -336,7 +378,13 @@ public class JettyRunForkedMojo extends AbstractMojo
|
|||
return null;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @return
|
||||
* @throws MojoExecutionException
|
||||
*/
|
||||
public File prepareConfiguration() throws MojoExecutionException
|
||||
{
|
||||
try
|
||||
|
@ -371,29 +419,10 @@ public class JettyRunForkedMojo extends AbstractMojo
|
|||
//sort out base dir of webapp
|
||||
if (webAppSourceDirectory != null)
|
||||
props.put("base.dir", webAppSourceDirectory.getAbsolutePath());
|
||||
|
||||
|
||||
//sort out the resource base directories of the webapp
|
||||
StringBuilder builder = new StringBuilder();
|
||||
if (baseAppFirst)
|
||||
{
|
||||
add((webAppSourceDirectory==null?null:webAppSourceDirectory.getAbsolutePath()), builder);
|
||||
if (resourceBases != null)
|
||||
{
|
||||
for (File resDir:resourceBases)
|
||||
add(resDir.getAbsolutePath(), builder);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (resourceBases != null)
|
||||
{
|
||||
for (File resDir:resourceBases)
|
||||
add(resDir.getAbsolutePath(), builder);
|
||||
}
|
||||
add((webAppSourceDirectory==null?null:webAppSourceDirectory.getAbsolutePath()), builder);
|
||||
}
|
||||
props.put("res.dirs", builder.toString());
|
||||
|
||||
StringBuilder builder = new StringBuilder();
|
||||
props.put("base.first", Boolean.toString(baseAppFirst));
|
||||
|
||||
//web-inf classes
|
||||
List<File> classDirs = getClassesDirs();
|
||||
|
@ -428,18 +457,34 @@ public class JettyRunForkedMojo extends AbstractMojo
|
|||
}
|
||||
props.put("lib.jars", strbuff.toString());
|
||||
|
||||
//any overlays
|
||||
List<File> overlays = getOverlays();
|
||||
strbuff.setLength(0);
|
||||
for (int i=0; i<overlays.size(); i++)
|
||||
//any war files
|
||||
List<Artifact> warArtifacts = getWarArtifacts();
|
||||
for (int i=0; i<warArtifacts.size(); i++)
|
||||
{
|
||||
File f = overlays.get(i);
|
||||
strbuff.append(f.getAbsolutePath());
|
||||
if (i < overlays.size()-1)
|
||||
strbuff.append(",");
|
||||
strbuff.setLength(0);
|
||||
Artifact a = warArtifacts.get(i);
|
||||
strbuff.append(a.getGroupId()+",");
|
||||
strbuff.append(a.getArtifactId()+",");
|
||||
strbuff.append(a.getFile().getAbsolutePath());
|
||||
props.put("maven.war.artifact."+i, strbuff.toString());
|
||||
}
|
||||
props.put("overlay.files", strbuff.toString());
|
||||
|
||||
|
||||
|
||||
//any overlay configuration
|
||||
WarPluginInfo warPlugin = new WarPluginInfo(project);
|
||||
|
||||
//add in the war plugins default includes and excludes
|
||||
props.put("maven.war.includes", toCSV(warPlugin.getDependentMavenWarIncludes()));
|
||||
props.put("maven.war.excludes", toCSV(warPlugin.getDependentMavenWarExcludes()));
|
||||
|
||||
|
||||
List<OverlayConfig> configs = warPlugin.getMavenWarOverlayConfigs();
|
||||
int i=0;
|
||||
for (OverlayConfig c:configs)
|
||||
{
|
||||
props.put("maven.war.overlay."+(i++), c.toString());
|
||||
}
|
||||
|
||||
props.store(new BufferedOutputStream(new FileOutputStream(propsFile)), "properties for forked webapp");
|
||||
return propsFile;
|
||||
}
|
||||
|
@ -449,15 +494,12 @@ public class JettyRunForkedMojo extends AbstractMojo
|
|||
}
|
||||
}
|
||||
|
||||
private void add (String string, StringBuilder builder)
|
||||
{
|
||||
if (string == null)
|
||||
return;
|
||||
if (builder.length() > 0)
|
||||
builder.append(",");
|
||||
builder.append(string);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @return
|
||||
*/
|
||||
private List<File> getClassesDirs ()
|
||||
{
|
||||
List<File> classesDirs = new ArrayList<File>();
|
||||
|
@ -474,24 +516,34 @@ public class JettyRunForkedMojo extends AbstractMojo
|
|||
}
|
||||
|
||||
|
||||
|
||||
|
||||
private List<File> getOverlays()
|
||||
/**
|
||||
* @return
|
||||
* @throws MalformedURLException
|
||||
* @throws IOException
|
||||
*/
|
||||
private List<Artifact> getWarArtifacts()
|
||||
throws MalformedURLException, IOException
|
||||
{
|
||||
List<File> overlays = new ArrayList<File>();
|
||||
List<Artifact> warArtifacts = new ArrayList<Artifact>();
|
||||
for ( Iterator<Artifact> iter = project.getArtifacts().iterator(); iter.hasNext(); )
|
||||
{
|
||||
Artifact artifact = (Artifact) iter.next();
|
||||
|
||||
if (artifact.getType().equals("war"))
|
||||
overlays.add(artifact.getFile());
|
||||
warArtifacts.add(artifact);
|
||||
}
|
||||
|
||||
return overlays;
|
||||
return warArtifacts;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @return
|
||||
*/
|
||||
private List<File> getDependencyFiles ()
|
||||
{
|
||||
List<File> dependencyFiles = new ArrayList<File>();
|
||||
|
@ -512,6 +564,13 @@ public class JettyRunForkedMojo extends AbstractMojo
|
|||
return dependencyFiles;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @param artifact
|
||||
* @return
|
||||
*/
|
||||
public boolean isPluginArtifact(Artifact artifact)
|
||||
{
|
||||
if (pluginArtifacts == null || pluginArtifacts.isEmpty())
|
||||
|
@ -531,7 +590,12 @@ public class JettyRunForkedMojo extends AbstractMojo
|
|||
|
||||
|
||||
|
||||
private Set<Artifact> getExtraJars()
|
||||
|
||||
/**
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
private Set<Artifact> getExtraJars()
|
||||
throws Exception
|
||||
{
|
||||
Set<Artifact> extraJars = new HashSet<Artifact>();
|
||||
|
@ -557,7 +621,11 @@ public class JettyRunForkedMojo extends AbstractMojo
|
|||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
||||
|
||||
/**
|
||||
* @throws MojoExecutionException
|
||||
*/
|
||||
public void startJettyRunner() throws MojoExecutionException
|
||||
{
|
||||
try
|
||||
|
@ -678,7 +746,12 @@ public class JettyRunForkedMojo extends AbstractMojo
|
|||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
public String getClassPath() throws Exception
|
||||
{
|
||||
StringBuilder classPath = new StringBuilder();
|
||||
|
@ -720,6 +793,12 @@ public class JettyRunForkedMojo extends AbstractMojo
|
|||
return classPath.toString();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @return
|
||||
*/
|
||||
private String getJavaBin()
|
||||
{
|
||||
String javaexes[] = new String[]
|
||||
|
@ -738,6 +817,13 @@ public class JettyRunForkedMojo extends AbstractMojo
|
|||
return "java";
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @param path
|
||||
* @return
|
||||
*/
|
||||
public static String fileSeparators(String path)
|
||||
{
|
||||
StringBuilder ret = new StringBuilder();
|
||||
|
@ -755,6 +841,13 @@ public class JettyRunForkedMojo extends AbstractMojo
|
|||
return ret.toString();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @param path
|
||||
* @return
|
||||
*/
|
||||
public static String pathSeparators(String path)
|
||||
{
|
||||
StringBuilder ret = new StringBuilder();
|
||||
|
@ -772,13 +865,24 @@ public class JettyRunForkedMojo extends AbstractMojo
|
|||
return ret.toString();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @return
|
||||
*/
|
||||
private String createToken ()
|
||||
{
|
||||
return Long.toString(random.nextLong()^System.currentTimeMillis(), 36).toUpperCase(Locale.ENGLISH);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @param mode
|
||||
* @param inputStream
|
||||
*/
|
||||
private void startPump(String mode, InputStream inputStream)
|
||||
{
|
||||
ConsoleStreamer pump = new ConsoleStreamer(mode,inputStream);
|
||||
|
@ -787,42 +891,25 @@ public class JettyRunForkedMojo extends AbstractMojo
|
|||
thread.start();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Simple streamer for the console output from a Process
|
||||
* @param strings
|
||||
* @return
|
||||
*/
|
||||
private static class ConsoleStreamer implements Runnable
|
||||
private String toCSV (List<String> strings)
|
||||
{
|
||||
private String mode;
|
||||
private BufferedReader reader;
|
||||
|
||||
public ConsoleStreamer(String mode, InputStream is)
|
||||
if (strings == null)
|
||||
return "";
|
||||
StringBuffer strbuff = new StringBuffer();
|
||||
Iterator<String> itor = strings.iterator();
|
||||
while (itor.hasNext())
|
||||
{
|
||||
this.mode = mode;
|
||||
this.reader = new BufferedReader(new InputStreamReader(is));
|
||||
}
|
||||
|
||||
|
||||
public void run()
|
||||
{
|
||||
String line;
|
||||
try
|
||||
{
|
||||
while ((line = reader.readLine()) != (null))
|
||||
{
|
||||
System.out.println("[" + mode + "] " + line);
|
||||
}
|
||||
}
|
||||
catch (IOException ignore)
|
||||
{
|
||||
/* ignore */
|
||||
}
|
||||
finally
|
||||
{
|
||||
IO.close(reader);
|
||||
}
|
||||
strbuff.append(itor.next());
|
||||
if (itor.hasNext())
|
||||
strbuff.append(",");
|
||||
}
|
||||
return strbuff.toString();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,10 +20,13 @@ package org.eclipse.jetty.maven.plugin;
|
|||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.maven.artifact.Artifact;
|
||||
import org.apache.maven.plugin.MojoExecutionException;
|
||||
|
@ -33,6 +36,7 @@ import org.eclipse.jetty.util.Scanner;
|
|||
import org.eclipse.jetty.util.resource.Resource;
|
||||
import org.eclipse.jetty.webapp.WebAppContext;
|
||||
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* This goal is used in-situ on a Maven project without first requiring that the project
|
||||
|
@ -66,6 +70,7 @@ public class JettyRunMojo extends AbstractJettyMojo
|
|||
public static final String DEFAULT_WEBAPP_SRC = "src"+File.separator+"main"+File.separator+"webapp";
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* If true, the <testOutputDirectory>
|
||||
* and the dependencies of <scope>test<scope>
|
||||
|
@ -73,7 +78,7 @@ public class JettyRunMojo extends AbstractJettyMojo
|
|||
*
|
||||
* @parameter alias="useTestClasspath" default-value="false"
|
||||
*/
|
||||
private boolean useTestScope;
|
||||
protected boolean useTestScope;
|
||||
|
||||
|
||||
/**
|
||||
|
@ -83,7 +88,7 @@ public class JettyRunMojo extends AbstractJettyMojo
|
|||
* @parameter expression="${maven.war.webxml}"
|
||||
* @readonly
|
||||
*/
|
||||
private String webXml;
|
||||
protected String webXml;
|
||||
|
||||
|
||||
/**
|
||||
|
@ -93,8 +98,7 @@ public class JettyRunMojo extends AbstractJettyMojo
|
|||
* @required
|
||||
*
|
||||
*/
|
||||
private File classesDirectory;
|
||||
|
||||
protected File classesDirectory;
|
||||
|
||||
|
||||
/**
|
||||
|
@ -103,7 +107,8 @@ public class JettyRunMojo extends AbstractJettyMojo
|
|||
* @parameter expression="${project.build.testOutputDirectory}"
|
||||
* @required
|
||||
*/
|
||||
private File testClassesDirectory;
|
||||
protected File testClassesDirectory;
|
||||
|
||||
|
||||
/**
|
||||
* Root directory for all html/jsp etc files
|
||||
|
@ -111,14 +116,14 @@ public class JettyRunMojo extends AbstractJettyMojo
|
|||
* @parameter expression="${maven.war.src}"
|
||||
*
|
||||
*/
|
||||
private File webAppSourceDirectory;
|
||||
protected File webAppSourceDirectory;
|
||||
|
||||
|
||||
/**
|
||||
* List of files or directories to additionally periodically scan for changes. Optional.
|
||||
* @parameter
|
||||
*/
|
||||
private File[] scanTargets;
|
||||
protected File[] scanTargets;
|
||||
|
||||
|
||||
/**
|
||||
|
@ -127,15 +132,40 @@ public class JettyRunMojo extends AbstractJettyMojo
|
|||
* or in conjunction with <scanTargets>.Optional.
|
||||
* @parameter
|
||||
*/
|
||||
private ScanTargetPattern[] scanTargetPatterns;
|
||||
protected ScanTargetPattern[] scanTargetPatterns;
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Extra scan targets as a list
|
||||
*/
|
||||
private List<File> extraScanTargets;
|
||||
protected List<File> extraScanTargets;
|
||||
|
||||
|
||||
/**
|
||||
* maven-war-plugin reference
|
||||
*/
|
||||
protected WarPluginInfo warPluginInfo;
|
||||
|
||||
|
||||
/**
|
||||
* List of deps that are wars
|
||||
*/
|
||||
protected List<Artifact> warArtifacts;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @see org.eclipse.jetty.maven.plugin.AbstractJettyMojo#execute()
|
||||
*/
|
||||
@Override
|
||||
public void execute() throws MojoExecutionException, MojoFailureException
|
||||
{
|
||||
warPluginInfo = new WarPluginInfo(project);
|
||||
super.execute();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
@ -150,14 +180,14 @@ public class JettyRunMojo extends AbstractJettyMojo
|
|||
// check the location of the static content/jsps etc
|
||||
try
|
||||
{
|
||||
if ((getWebAppSourceDirectory() == null) || !getWebAppSourceDirectory().exists())
|
||||
if ((webAppSourceDirectory == null) || !webAppSourceDirectory.exists())
|
||||
{
|
||||
File defaultWebAppSrcDir = new File (project.getBasedir(), DEFAULT_WEBAPP_SRC);
|
||||
getLog().info("webAppSourceDirectory"+(getWebAppSourceDirectory()==null?" not set.":" does not exist.")+" Defaulting to "+defaultWebAppSrcDir.getAbsolutePath());
|
||||
getLog().info("webAppSourceDirectory"+(webAppSourceDirectory == null ? " not set." : " does not exist.")+" Defaulting to "+defaultWebAppSrcDir.getAbsolutePath());
|
||||
webAppSourceDirectory = defaultWebAppSrcDir;
|
||||
}
|
||||
else
|
||||
getLog().info( "Webapp source directory = " + getWebAppSourceDirectory().getCanonicalPath());
|
||||
getLog().info( "Webapp source directory = " + webAppSourceDirectory.getCanonicalPath());
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
|
@ -179,12 +209,12 @@ public class JettyRunMojo extends AbstractJettyMojo
|
|||
try
|
||||
{
|
||||
//allow a webapp with no classes in it (just jsps/html)
|
||||
if (getClassesDirectory() != null)
|
||||
if (classesDirectory != null)
|
||||
{
|
||||
if (!getClassesDirectory().exists())
|
||||
getLog().info( "Classes directory "+ getClassesDirectory().getCanonicalPath()+ " does not exist");
|
||||
if (!classesDirectory.exists())
|
||||
getLog().info( "Classes directory "+ classesDirectory.getCanonicalPath()+ " does not exist");
|
||||
else
|
||||
getLog().info("Classes = " + getClassesDirectory().getCanonicalPath());
|
||||
getLog().info("Classes = " + classesDirectory.getCanonicalPath());
|
||||
}
|
||||
else
|
||||
getLog().info("Classes directory not set");
|
||||
|
@ -194,18 +224,16 @@ public class JettyRunMojo extends AbstractJettyMojo
|
|||
throw new MojoExecutionException("Location of classesDirectory does not exist");
|
||||
}
|
||||
|
||||
|
||||
setExtraScanTargets(new ArrayList<File>());
|
||||
extraScanTargets = new ArrayList<File>();
|
||||
if (scanTargets != null)
|
||||
{
|
||||
for (int i=0; i< scanTargets.length; i++)
|
||||
{
|
||||
getLog().info("Added extra scan target:"+ scanTargets[i]);
|
||||
getExtraScanTargets().add(scanTargets[i]);
|
||||
extraScanTargets.add(scanTargets[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (scanTargetPatterns!=null)
|
||||
{
|
||||
for (int i=0;i<scanTargetPatterns.length; i++)
|
||||
|
@ -236,11 +264,11 @@ public class JettyRunMojo extends AbstractJettyMojo
|
|||
itor = files.iterator();
|
||||
while (itor.hasNext())
|
||||
getLog().info("Adding extra scan target from pattern: "+itor.next());
|
||||
List<File> currentTargets = getExtraScanTargets();
|
||||
List<File> currentTargets = extraScanTargets;
|
||||
if(currentTargets!=null && !currentTargets.isEmpty())
|
||||
currentTargets.addAll(files);
|
||||
else
|
||||
setExtraScanTargets(files);
|
||||
extraScanTargets = files;
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
|
@ -253,7 +281,9 @@ public class JettyRunMojo extends AbstractJettyMojo
|
|||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @see org.eclipse.jetty.maven.plugin.AbstractJettyMojo#configureWebApplication()
|
||||
*/
|
||||
public void configureWebApplication() throws Exception
|
||||
{
|
||||
super.configureWebApplication();
|
||||
|
@ -270,13 +300,61 @@ public class JettyRunMojo extends AbstractJettyMojo
|
|||
if (webApp.getBaseResource() == null)
|
||||
webApp.setBaseResource(webAppSourceDirectoryResource);
|
||||
|
||||
if (getClassesDirectory() != null)
|
||||
webApp.setClasses (getClassesDirectory());
|
||||
if (classesDirectory != null)
|
||||
webApp.setClasses (classesDirectory);
|
||||
if (useTestScope && (testClassesDirectory != null))
|
||||
webApp.setTestClasses (testClassesDirectory);
|
||||
|
||||
webApp.setWebInfLib (getDependencyFiles());
|
||||
|
||||
|
||||
//get copy of a list of war artifacts
|
||||
Set<Artifact> matchedWarArtifacts = new HashSet<Artifact>();
|
||||
|
||||
//make sure each of the war artifacts is added to the scanner
|
||||
for (Artifact a:getWarArtifacts())
|
||||
extraScanTargets.add(a.getFile());
|
||||
|
||||
//process any overlays and the war type artifacts
|
||||
List<Overlay> overlays = new ArrayList<Overlay>();
|
||||
for (OverlayConfig config:warPluginInfo.getMavenWarOverlayConfigs())
|
||||
{
|
||||
//overlays can be individually skipped
|
||||
if (config.isSkip())
|
||||
continue;
|
||||
|
||||
//an empty overlay refers to the current project - important for ordering
|
||||
if (config.isCurrentProject())
|
||||
{
|
||||
Overlay overlay = new Overlay(config, null);
|
||||
overlays.add(overlay);
|
||||
continue;
|
||||
}
|
||||
|
||||
//if a war matches an overlay config
|
||||
Artifact a = getArtifactForOverlay(config, getWarArtifacts());
|
||||
if (a != null)
|
||||
{
|
||||
matchedWarArtifacts.add(a);
|
||||
SelectiveJarResource r = new SelectiveJarResource(new URL("jar:"+Resource.toURL(a.getFile()).toString()+"!/"));
|
||||
r.setIncludes(config.getIncludes());
|
||||
r.setExcludes(config.getExcludes());
|
||||
Overlay overlay = new Overlay(config, r);
|
||||
overlays.add(overlay);
|
||||
}
|
||||
}
|
||||
|
||||
//iterate over the left over war artifacts and unpack them (without include/exclude processing) as necessary
|
||||
for (Artifact a: getWarArtifacts())
|
||||
{
|
||||
if (!matchedWarArtifacts.contains(a))
|
||||
{
|
||||
Overlay overlay = new Overlay(null, Resource.newResource(new URL("jar:"+Resource.toURL(a.getFile()).toString()+"!/")));
|
||||
overlays.add(overlay);
|
||||
}
|
||||
}
|
||||
|
||||
webApp.setOverlays(overlays);
|
||||
|
||||
//if we have not already set web.xml location, need to set one up
|
||||
if (webApp.getDescriptor() == null)
|
||||
{
|
||||
|
@ -311,14 +389,20 @@ public class JettyRunMojo extends AbstractJettyMojo
|
|||
}
|
||||
}
|
||||
getLog().info( "web.xml file = "+webApp.getDescriptor());
|
||||
getLog().info("Webapp directory = " + getWebAppSourceDirectory().getCanonicalPath());
|
||||
getLog().info("Webapp directory = " + webAppSourceDirectory.getCanonicalPath());
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @see org.eclipse.jetty.maven.plugin.AbstractJettyMojo#configureScanner()
|
||||
*/
|
||||
public void configureScanner ()
|
||||
throws MojoExecutionException
|
||||
{
|
||||
// start the scanner thread (if necessary) on the main webapp
|
||||
final ArrayList<File> scanList = new ArrayList<File>();
|
||||
scanList = new ArrayList<File>();
|
||||
if (webApp.getDescriptor() != null)
|
||||
{
|
||||
try
|
||||
|
@ -375,25 +459,25 @@ public class JettyRunMojo extends AbstractJettyMojo
|
|||
}
|
||||
|
||||
|
||||
File jettyWebXmlFile = findJettyWebXmlFile(new File(getWebAppSourceDirectory(),"WEB-INF"));
|
||||
File jettyWebXmlFile = findJettyWebXmlFile(new File(webAppSourceDirectory,"WEB-INF"));
|
||||
if (jettyWebXmlFile != null)
|
||||
scanList.add(jettyWebXmlFile);
|
||||
scanList.addAll(getExtraScanTargets());
|
||||
scanList.add(getProject().getFile());
|
||||
scanList.addAll(extraScanTargets);
|
||||
scanList.add(project.getFile());
|
||||
if (webApp.getTestClasses() != null)
|
||||
scanList.add(webApp.getTestClasses());
|
||||
if (webApp.getClasses() != null)
|
||||
scanList.add(webApp.getClasses());
|
||||
scanList.addAll(webApp.getWebInfLib());
|
||||
setScanList(scanList);
|
||||
ArrayList<Scanner.BulkListener> listeners = new ArrayList<Scanner.BulkListener>();
|
||||
listeners.add(new Scanner.BulkListener()
|
||||
|
||||
scannerListeners = new ArrayList<Scanner.BulkListener>();
|
||||
scannerListeners.add(new Scanner.BulkListener()
|
||||
{
|
||||
public void filesChanged (List changes)
|
||||
{
|
||||
try
|
||||
{
|
||||
boolean reconfigure = changes.contains(getProject().getFile().getCanonicalPath());
|
||||
boolean reconfigure = changes.contains(project.getFile().getCanonicalPath());
|
||||
restartWebApp(reconfigure);
|
||||
}
|
||||
catch (Exception e)
|
||||
|
@ -402,9 +486,14 @@ public class JettyRunMojo extends AbstractJettyMojo
|
|||
}
|
||||
}
|
||||
});
|
||||
setScannerListeners(listeners);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @see org.eclipse.jetty.maven.plugin.AbstractJettyMojo#restartWebApp(boolean)
|
||||
*/
|
||||
public void restartWebApp(boolean reconfigureScanner) throws Exception
|
||||
{
|
||||
getLog().info("restarting "+webApp);
|
||||
|
@ -424,14 +513,14 @@ public class JettyRunMojo extends AbstractJettyMojo
|
|||
scanList.add(new File(webApp.getDescriptor()));
|
||||
if (webApp.getJettyEnvXml() != null)
|
||||
scanList.add(new File(webApp.getJettyEnvXml()));
|
||||
scanList.addAll(getExtraScanTargets());
|
||||
scanList.add(getProject().getFile());
|
||||
scanList.addAll(extraScanTargets);
|
||||
scanList.add(project.getFile());
|
||||
if (webApp.getTestClasses() != null)
|
||||
scanList.add(webApp.getTestClasses());
|
||||
if (webApp.getClasses() != null)
|
||||
scanList.add(webApp.getClasses());
|
||||
scanList.addAll(webApp.getWebInfLib());
|
||||
getScanner().setScanDirs(scanList);
|
||||
scanner.setScanDirs(scanList);
|
||||
}
|
||||
|
||||
getLog().debug("Restarting webapp ...");
|
||||
|
@ -439,10 +528,15 @@ public class JettyRunMojo extends AbstractJettyMojo
|
|||
getLog().info("Restart completed at "+new Date().toString());
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @return
|
||||
*/
|
||||
private List<File> getDependencyFiles ()
|
||||
{
|
||||
List<File> dependencyFiles = new ArrayList<File>();
|
||||
List<Resource> overlays = new ArrayList<Resource>();
|
||||
for ( Iterator<Artifact> iter = projectArtifacts.iterator(); iter.hasNext(); )
|
||||
{
|
||||
Artifact artifact = (Artifact) iter.next();
|
||||
|
@ -450,17 +544,6 @@ public class JettyRunMojo extends AbstractJettyMojo
|
|||
// Include runtime and compile time libraries, and possibly test libs too
|
||||
if(artifact.getType().equals("war"))
|
||||
{
|
||||
try
|
||||
{
|
||||
Resource r=Resource.newResource("jar:"+Resource.toURL(artifact.getFile()).toString()+"!/");
|
||||
overlays.add(r);
|
||||
getLog().info("Adding overlay for war project artifact "+artifact.getId());
|
||||
getExtraScanTargets().add(artifact.getFile());
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -473,136 +556,79 @@ public class JettyRunMojo extends AbstractJettyMojo
|
|||
dependencyFiles.add(artifact.getFile());
|
||||
getLog().debug( "Adding artifact " + artifact.getFile().getName() + " with scope "+artifact.getScope()+" for WEB-INF/lib " );
|
||||
}
|
||||
|
||||
webApp.setOverlays(overlays);
|
||||
|
||||
return dependencyFiles;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
private List<File> setUpClassPath(File webInfClasses, File testClasses, List<File> webInfJars)
|
||||
|
||||
|
||||
/**
|
||||
* @return
|
||||
*/
|
||||
private List<Artifact> getWarArtifacts ()
|
||||
{
|
||||
List<File> classPathFiles = new ArrayList<File>();
|
||||
if (webInfClasses != null)
|
||||
classPathFiles.add(webInfClasses);
|
||||
if (testClasses != null)
|
||||
classPathFiles.add(testClasses);
|
||||
classPathFiles.addAll(webInfJars);
|
||||
|
||||
if (getLog().isDebugEnabled())
|
||||
if (warArtifacts != null)
|
||||
return warArtifacts;
|
||||
|
||||
warArtifacts = new ArrayList<Artifact>();
|
||||
for ( Iterator<Artifact> iter = projectArtifacts.iterator(); iter.hasNext(); )
|
||||
{
|
||||
for (int i = 0; i < classPathFiles.size(); i++)
|
||||
Artifact artifact = (Artifact) iter.next();
|
||||
if (artifact.getType().equals("war"))
|
||||
{
|
||||
getLog().debug("classpath element: "+ ((File) classPathFiles.get(i)).getName());
|
||||
try
|
||||
{
|
||||
warArtifacts.add(artifact);
|
||||
getLog().info("Dependent war artifact "+artifact.getId());
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
return classPathFiles;
|
||||
return warArtifacts;
|
||||
}
|
||||
|
||||
private List<File> getClassesDirs ()
|
||||
{
|
||||
List<File> classesDirs = new ArrayList<File>();
|
||||
|
||||
//if using the test classes, make sure they are first
|
||||
//on the list
|
||||
if (useTestScope && (testClassesDirectory != null))
|
||||
classesDirs.add(testClassesDirectory);
|
||||
|
||||
if (getClassesDirectory() != null)
|
||||
classesDirs.add(getClassesDirectory());
|
||||
|
||||
return classesDirs;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
public void execute() throws MojoExecutionException, MojoFailureException
|
||||
{
|
||||
|
||||
super.execute();
|
||||
}
|
||||
|
||||
|
||||
public String getWebXml()
|
||||
{
|
||||
return this.webXml;
|
||||
}
|
||||
|
||||
public void setWebXml(String webXml) {
|
||||
this.webXml = webXml;
|
||||
}
|
||||
|
||||
public File getClassesDirectory()
|
||||
{
|
||||
return this.classesDirectory;
|
||||
}
|
||||
|
||||
public void setClassesDirectory(File classesDirectory) {
|
||||
this.classesDirectory = classesDirectory;
|
||||
}
|
||||
|
||||
public File getWebAppSourceDirectory()
|
||||
{
|
||||
return this.webAppSourceDirectory;
|
||||
}
|
||||
|
||||
public void setWebAppSourceDirectory(File webAppSourceDirectory)
|
||||
{
|
||||
this.webAppSourceDirectory = webAppSourceDirectory;
|
||||
}
|
||||
|
||||
public List<File> getExtraScanTargets()
|
||||
{
|
||||
return this.extraScanTargets;
|
||||
}
|
||||
|
||||
public void setExtraScanTargets(List<File> list)
|
||||
{
|
||||
this.extraScanTargets = list;
|
||||
}
|
||||
|
||||
public boolean isUseTestClasspath()
|
||||
{
|
||||
return useTestScope;
|
||||
}
|
||||
|
||||
public void setUseTestClasspath(boolean useTestClasspath)
|
||||
{
|
||||
this.useTestScope = useTestClasspath;
|
||||
}
|
||||
|
||||
public File getTestClassesDirectory()
|
||||
{
|
||||
return testClassesDirectory;
|
||||
}
|
||||
|
||||
public void setTestClassesDirectory(File testClassesDirectory)
|
||||
{
|
||||
this.testClassesDirectory = testClassesDirectory;
|
||||
}
|
||||
|
||||
public File[] getScanTargets()
|
||||
{
|
||||
return scanTargets;
|
||||
}
|
||||
|
||||
public void setScanTargets(File[] scanTargets)
|
||||
{
|
||||
this.scanTargets = scanTargets;
|
||||
}
|
||||
|
||||
public ScanTargetPattern[] getScanTargetPatterns()
|
||||
{
|
||||
return scanTargetPatterns;
|
||||
}
|
||||
|
||||
public void setScanTargetPatterns(ScanTargetPattern[] scanTargetPatterns)
|
||||
{
|
||||
this.scanTargetPatterns = scanTargetPatterns;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param o
|
||||
* @param warArtifacts
|
||||
* @return
|
||||
*/
|
||||
protected Artifact getArtifactForOverlay (OverlayConfig o, List<Artifact> warArtifacts)
|
||||
{
|
||||
if (o == null || warArtifacts == null || warArtifacts.isEmpty())
|
||||
return null;
|
||||
|
||||
for (Artifact a:warArtifacts)
|
||||
{
|
||||
if (overlayMatchesArtifact (o, a))
|
||||
{
|
||||
return a;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @param o
|
||||
* @param a
|
||||
* @return
|
||||
*/
|
||||
protected boolean overlayMatchesArtifact(OverlayConfig o, Artifact a)
|
||||
{
|
||||
if (((o.getGroupId() == null && a.getGroupId() == null) || (o.getGroupId() != null && o.getGroupId().equals(a.getGroupId())))
|
||||
&& ((o.getArtifactId() == null && a.getArtifactId() == null) || (o.getArtifactId() != null && o.getArtifactId().equals(a.getArtifactId())))
|
||||
&& ((o.getClassifier() == null) || (o.getClassifier().equals(a.getClassifier()))))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -67,7 +67,17 @@ public class JettyRunWarExplodedMojo extends AbstractJettyMojo
|
|||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @see org.eclipse.jetty.maven.plugin.AbstractJettyMojo#execute()
|
||||
*/
|
||||
public void execute () throws MojoExecutionException, MojoFailureException
|
||||
{
|
||||
super.execute();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @see org.mortbay.jetty.plugin.AbstractJettyMojo#checkPomConfiguration()
|
||||
|
@ -77,13 +87,16 @@ public class JettyRunWarExplodedMojo extends AbstractJettyMojo
|
|||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @see org.mortbay.jetty.plugin.AbstractJettyMojo#configureScanner()
|
||||
*/
|
||||
public void configureScanner() throws MojoExecutionException
|
||||
{
|
||||
final ArrayList<File> scanList = new ArrayList<File>();
|
||||
scanList.add(getProject().getFile());
|
||||
scanList = new ArrayList<File>();
|
||||
scanList.add(project.getFile());
|
||||
File webInfDir = new File(war,"WEB-INF");
|
||||
scanList.add(new File(webInfDir, "web.xml"));
|
||||
File jettyWebXmlFile = findJettyWebXmlFile(webInfDir);
|
||||
|
@ -94,16 +107,15 @@ public class JettyRunWarExplodedMojo extends AbstractJettyMojo
|
|||
scanList.add(jettyEnvXmlFile);
|
||||
scanList.add(new File(webInfDir, "classes"));
|
||||
scanList.add(new File(webInfDir, "lib"));
|
||||
setScanList(scanList);
|
||||
|
||||
ArrayList<Scanner.BulkListener> listeners = new ArrayList<Scanner.BulkListener>();
|
||||
listeners.add(new Scanner.BulkListener()
|
||||
|
||||
scannerListeners = new ArrayList<Scanner.BulkListener>();
|
||||
scannerListeners.add(new Scanner.BulkListener()
|
||||
{
|
||||
public void filesChanged(List changes)
|
||||
{
|
||||
try
|
||||
{
|
||||
boolean reconfigure = changes.contains(getProject().getFile().getCanonicalPath());
|
||||
boolean reconfigure = changes.contains(project.getFile().getCanonicalPath());
|
||||
restartWebApp(reconfigure);
|
||||
}
|
||||
catch (Exception e)
|
||||
|
@ -112,12 +124,14 @@ public class JettyRunWarExplodedMojo extends AbstractJettyMojo
|
|||
}
|
||||
}
|
||||
});
|
||||
setScannerListeners(listeners);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @see org.eclipse.jetty.maven.plugin.AbstractJettyMojo#restartWebApp(boolean)
|
||||
*/
|
||||
public void restartWebApp(boolean reconfigureScanner) throws Exception
|
||||
{
|
||||
getLog().info("Restarting webapp");
|
||||
|
@ -132,9 +146,8 @@ public class JettyRunWarExplodedMojo extends AbstractJettyMojo
|
|||
if (reconfigureScanner)
|
||||
{
|
||||
getLog().info("Reconfiguring scanner after change to pom.xml ...");
|
||||
ArrayList<File> scanList = getScanList();
|
||||
scanList.clear();
|
||||
scanList.add(getProject().getFile());
|
||||
scanList.add(project.getFile());
|
||||
File webInfDir = new File(war,"WEB-INF");
|
||||
scanList.add(new File(webInfDir, "web.xml"));
|
||||
File jettyWebXmlFile = findJettyWebXmlFile(webInfDir);
|
||||
|
@ -145,8 +158,7 @@ public class JettyRunWarExplodedMojo extends AbstractJettyMojo
|
|||
scanList.add(jettyEnvXmlFile);
|
||||
scanList.add(new File(webInfDir, "classes"));
|
||||
scanList.add(new File(webInfDir, "lib"));
|
||||
setScanList(scanList);
|
||||
getScanner().setScanDirs(scanList);
|
||||
scanner.setScanDirs(scanList);
|
||||
}
|
||||
|
||||
getLog().debug("Restarting webapp ...");
|
||||
|
@ -155,19 +167,14 @@ public class JettyRunWarExplodedMojo extends AbstractJettyMojo
|
|||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @see org.eclipse.jetty.maven.plugin.AbstractJettyMojo#configureWebApplication()
|
||||
*/
|
||||
public void configureWebApplication () throws Exception
|
||||
{
|
||||
super.configureWebApplication();
|
||||
webApp.setWar(war.getCanonicalPath());
|
||||
}
|
||||
|
||||
public void execute () throws MojoExecutionException, MojoFailureException
|
||||
{
|
||||
super.execute();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -64,7 +64,6 @@ public class JettyRunWarMojo extends AbstractJettyMojo
|
|||
*/
|
||||
private File war;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @see org.apache.maven.plugin.Mojo#execute()
|
||||
|
@ -76,6 +75,7 @@ public class JettyRunWarMojo extends AbstractJettyMojo
|
|||
|
||||
|
||||
|
||||
|
||||
public void configureWebApplication () throws Exception
|
||||
{
|
||||
super.configureWebApplication();
|
||||
|
@ -85,6 +85,7 @@ public class JettyRunWarMojo extends AbstractJettyMojo
|
|||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @see org.mortbay.jetty.plugin.AbstractJettyMojo#checkPomConfiguration()
|
||||
*/
|
||||
|
@ -95,24 +96,24 @@ public class JettyRunWarMojo extends AbstractJettyMojo
|
|||
|
||||
|
||||
|
||||
/* (non-Javadoc)
|
||||
|
||||
/**
|
||||
* @see org.eclipse.jetty.server.plugin.AbstractJettyMojo#configureScanner()
|
||||
*/
|
||||
public void configureScanner() throws MojoExecutionException
|
||||
{
|
||||
final ArrayList scanList = new ArrayList();
|
||||
scanList.add(getProject().getFile());
|
||||
scanList = new ArrayList();
|
||||
scanList.add(project.getFile());
|
||||
scanList.add(war);
|
||||
setScanList(scanList);
|
||||
|
||||
ArrayList listeners = new ArrayList();
|
||||
listeners.add(new Scanner.BulkListener()
|
||||
scannerListeners = new ArrayList();
|
||||
scannerListeners.add(new Scanner.BulkListener()
|
||||
{
|
||||
public void filesChanged(List changes)
|
||||
{
|
||||
try
|
||||
{
|
||||
boolean reconfigure = changes.contains(getProject().getFile().getCanonicalPath());
|
||||
boolean reconfigure = changes.contains(project.getFile().getCanonicalPath());
|
||||
restartWebApp(reconfigure);
|
||||
}
|
||||
catch (Exception e)
|
||||
|
@ -121,10 +122,14 @@ public class JettyRunWarMojo extends AbstractJettyMojo
|
|||
}
|
||||
}
|
||||
});
|
||||
setScannerListeners(listeners);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @see org.eclipse.jetty.maven.plugin.AbstractJettyMojo#restartWebApp(boolean)
|
||||
*/
|
||||
public void restartWebApp(boolean reconfigureScanner) throws Exception
|
||||
{
|
||||
getLog().info("Restarting webapp ...");
|
||||
|
@ -139,12 +144,10 @@ public class JettyRunWarMojo extends AbstractJettyMojo
|
|||
if (reconfigureScanner)
|
||||
{
|
||||
getLog().info("Reconfiguring scanner after change to pom.xml ...");
|
||||
ArrayList scanList = getScanList();
|
||||
scanList.clear();
|
||||
scanList.add(getProject().getFile());
|
||||
scanList.add(project.getFile());
|
||||
scanList.add(war);
|
||||
setScanList(scanList);
|
||||
getScanner().setScanDirs(scanList);
|
||||
scanner.setScanDirs(scanList);
|
||||
}
|
||||
|
||||
getLog().debug("Restarting webapp ...");
|
||||
|
|
|
@ -28,6 +28,7 @@ import java.util.Map;
|
|||
import java.util.Set;
|
||||
import java.util.TreeSet;
|
||||
|
||||
import org.apache.maven.artifact.Artifact;
|
||||
import org.eclipse.jetty.plus.webapp.EnvConfiguration;
|
||||
import org.eclipse.jetty.util.URIUtil;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
|
@ -59,40 +60,40 @@ public class JettyWebAppContext extends WebAppContext
|
|||
private static final String WEB_INF_CLASSES_PREFIX = "/WEB-INF/classes";
|
||||
private static final String WEB_INF_LIB_PREFIX = "/WEB-INF/lib";
|
||||
|
||||
private File classes = null;
|
||||
private File testClasses = null;
|
||||
private final List<File> webInfClasses = new ArrayList<File>();
|
||||
private final List<File> webInfJars = new ArrayList<File>();
|
||||
private final Map<String, File> webInfJarMap = new HashMap<String, File>();
|
||||
private final EnvConfiguration envConfig;
|
||||
private List<File> classpathFiles; //webInfClasses+testClasses+webInfJars
|
||||
private String jettyEnvXml;
|
||||
private List<Resource> overlays;
|
||||
private File _classes = null;
|
||||
private File _testClasses = null;
|
||||
private final List<File> _webInfClasses = new ArrayList<File>();
|
||||
private final List<File> _webInfJars = new ArrayList<File>();
|
||||
private final Map<String, File> _webInfJarMap = new HashMap<String, File>();
|
||||
private final EnvConfiguration _envConfig;
|
||||
private List<File> _classpathFiles; //webInfClasses+testClasses+webInfJars
|
||||
private String _jettyEnvXml;
|
||||
private List<Overlay> _overlays;
|
||||
|
||||
/**
|
||||
* @deprecated The value of this parameter will be ignored by the plugin. Overlays will always be unpacked.
|
||||
*/
|
||||
private boolean unpackOverlays;
|
||||
|
||||
|
||||
/**
|
||||
* Set the "org.eclipse.jetty.server.webapp.ContainerIncludeJarPattern" with a pattern for matching jars on
|
||||
* container classpath to scan. This is analogous to the WebAppContext.setAttribute() call.
|
||||
*/
|
||||
private String containerIncludeJarPattern = null;
|
||||
private String _containerIncludeJarPattern = null;
|
||||
|
||||
/**
|
||||
* Set the "org.eclipse.jetty.server.webapp.WebInfIncludeJarPattern" with a pattern for matching jars on
|
||||
* webapp's classpath to scan. This is analogous to the WebAppContext.setAttribute() call.
|
||||
*/
|
||||
private String webInfIncludeJarPattern = null;
|
||||
private String _webInfIncludeJarPattern = null;
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @deprecated The value of this parameter will be ignored by the plugin. This option will be always disabled.
|
||||
* If there is no maven-war-plugin config for ordering of the current project in the
|
||||
* sequence of overlays, use this to control whether the current project is added
|
||||
* first or last in list of overlaid resources
|
||||
*/
|
||||
private boolean copyWebInf;
|
||||
private boolean _baseAppFirst = true;
|
||||
|
||||
private boolean baseAppFirst = true;
|
||||
|
||||
|
||||
public JettyWebAppContext ()
|
||||
throws Exception
|
||||
|
@ -103,7 +104,7 @@ public class JettyWebAppContext extends WebAppContext
|
|||
new WebXmlConfiguration(),
|
||||
new MetaInfConfiguration(),
|
||||
new FragmentConfiguration(),
|
||||
envConfig = new EnvConfiguration(),
|
||||
_envConfig = new EnvConfiguration(),
|
||||
new org.eclipse.jetty.plus.webapp.PlusConfiguration(),
|
||||
new MavenAnnotationConfiguration(),
|
||||
new JettyWebXmlConfiguration()
|
||||
|
@ -113,114 +114,94 @@ public class JettyWebAppContext extends WebAppContext
|
|||
}
|
||||
public void setContainerIncludeJarPattern(String pattern)
|
||||
{
|
||||
containerIncludeJarPattern = pattern;
|
||||
_containerIncludeJarPattern = pattern;
|
||||
}
|
||||
|
||||
public String getContainerIncludeJarPattern()
|
||||
{
|
||||
return containerIncludeJarPattern;
|
||||
return _containerIncludeJarPattern;
|
||||
}
|
||||
|
||||
|
||||
public String getWebInfIncludeJarPattern()
|
||||
{
|
||||
return webInfIncludeJarPattern;
|
||||
return _webInfIncludeJarPattern;
|
||||
}
|
||||
public void setWebInfIncludeJarPattern(String pattern)
|
||||
{
|
||||
webInfIncludeJarPattern = pattern;
|
||||
_webInfIncludeJarPattern = pattern;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public boolean getUnpackOverlays()
|
||||
{
|
||||
return unpackOverlays;
|
||||
}
|
||||
|
||||
public void setUnpackOverlays(boolean unpackOverlays)
|
||||
{
|
||||
this.unpackOverlays = unpackOverlays;
|
||||
}
|
||||
|
||||
public List<File> getClassPathFiles()
|
||||
{
|
||||
return this.classpathFiles;
|
||||
return this._classpathFiles;
|
||||
}
|
||||
|
||||
public void setOverlays (List<Resource> overlays)
|
||||
{
|
||||
this.overlays = overlays;
|
||||
}
|
||||
|
||||
public List<Resource> getOverlays ()
|
||||
{
|
||||
return this.overlays;
|
||||
}
|
||||
|
||||
public void setJettyEnvXml (String jettyEnvXml)
|
||||
{
|
||||
this.jettyEnvXml = jettyEnvXml;
|
||||
this._jettyEnvXml = jettyEnvXml;
|
||||
}
|
||||
|
||||
public String getJettyEnvXml()
|
||||
{
|
||||
return this.jettyEnvXml;
|
||||
return this._jettyEnvXml;
|
||||
}
|
||||
|
||||
|
||||
public void setClasses(File dir)
|
||||
{
|
||||
classes = dir;
|
||||
_classes = dir;
|
||||
}
|
||||
|
||||
public File getClasses()
|
||||
{
|
||||
return classes;
|
||||
return _classes;
|
||||
}
|
||||
|
||||
public void setWebInfLib (List<File> jars)
|
||||
{
|
||||
webInfJars.addAll(jars);
|
||||
_webInfJars.addAll(jars);
|
||||
}
|
||||
|
||||
|
||||
public void setTestClasses (File dir)
|
||||
{
|
||||
testClasses = dir;
|
||||
_testClasses = dir;
|
||||
}
|
||||
|
||||
|
||||
public File getTestClasses ()
|
||||
{
|
||||
return testClasses;
|
||||
return _testClasses;
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
public void setCopyWebInf(boolean value)
|
||||
/**
|
||||
* Ordered list of wars to overlay on top of the current project. The list
|
||||
* may contain an overlay that represents the current project.
|
||||
* @param overlays
|
||||
*/
|
||||
public void setOverlays (List<Overlay> overlays)
|
||||
{
|
||||
copyWebInf = value;
|
||||
_overlays = overlays;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
public boolean isCopyWebInf()
|
||||
|
||||
public List<Overlay> getOverlays()
|
||||
{
|
||||
return copyWebInf;
|
||||
return _overlays;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public void setBaseAppFirst(boolean value)
|
||||
{
|
||||
baseAppFirst = value;
|
||||
_baseAppFirst = value;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public boolean getBaseAppFirst()
|
||||
{
|
||||
return baseAppFirst;
|
||||
return _baseAppFirst;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
@ -244,7 +225,7 @@ public class JettyWebAppContext extends WebAppContext
|
|||
|
||||
public List<File> getWebInfLib()
|
||||
{
|
||||
return webInfJars;
|
||||
return _webInfJars;
|
||||
}
|
||||
|
||||
public void doStart () throws Exception
|
||||
|
@ -254,7 +235,7 @@ public class JettyWebAppContext extends WebAppContext
|
|||
|
||||
//Allow user to set up pattern for names of jars from the container classpath
|
||||
//that will be scanned - note that by default NO jars are scanned
|
||||
String tmp = containerIncludeJarPattern;
|
||||
String tmp = _containerIncludeJarPattern;
|
||||
if (tmp==null || "".equals(tmp))
|
||||
tmp = (String)getAttribute(WebInfConfiguration.CONTAINER_JAR_PATTERN);
|
||||
|
||||
|
@ -264,32 +245,32 @@ public class JettyWebAppContext extends WebAppContext
|
|||
//Allow user to set up pattern of jar names from WEB-INF that will be scanned.
|
||||
//Note that by default ALL jars considered to be in WEB-INF will be scanned - setting
|
||||
//a pattern restricts scanning
|
||||
if (webInfIncludeJarPattern != null)
|
||||
setAttribute(WebInfConfiguration.WEBINF_JAR_PATTERN, webInfIncludeJarPattern);
|
||||
if (_webInfIncludeJarPattern != null)
|
||||
setAttribute(WebInfConfiguration.WEBINF_JAR_PATTERN, _webInfIncludeJarPattern);
|
||||
|
||||
//Set up the classes dirs that comprises the equivalent of WEB-INF/classes
|
||||
if (testClasses != null)
|
||||
webInfClasses.add(testClasses);
|
||||
if (classes != null)
|
||||
webInfClasses.add(classes);
|
||||
if (_testClasses != null)
|
||||
_webInfClasses.add(_testClasses);
|
||||
if (_classes != null)
|
||||
_webInfClasses.add(_classes);
|
||||
|
||||
// Set up the classpath
|
||||
classpathFiles = new ArrayList<File>();
|
||||
classpathFiles.addAll(webInfClasses);
|
||||
classpathFiles.addAll(webInfJars);
|
||||
_classpathFiles = new ArrayList<File>();
|
||||
_classpathFiles.addAll(_webInfClasses);
|
||||
_classpathFiles.addAll(_webInfJars);
|
||||
|
||||
// Initialize map containing all jars in /WEB-INF/lib
|
||||
webInfJarMap.clear();
|
||||
for (File file : webInfJars)
|
||||
_webInfJarMap.clear();
|
||||
for (File file : _webInfJars)
|
||||
{
|
||||
// Return all jar files from class path
|
||||
String fileName = file.getName();
|
||||
if (fileName.endsWith(".jar"))
|
||||
webInfJarMap.put(fileName, file);
|
||||
_webInfJarMap.put(fileName, file);
|
||||
}
|
||||
|
||||
if (this.jettyEnvXml != null)
|
||||
envConfig.setJettyEnvXml(Resource.toURL(new File(this.jettyEnvXml)));
|
||||
if (this._jettyEnvXml != null)
|
||||
_envConfig.setJettyEnvXml(Resource.toURL(new File(this._jettyEnvXml)));
|
||||
|
||||
// CHECK setShutdown(false);
|
||||
super.doStart();
|
||||
|
@ -297,18 +278,18 @@ public class JettyWebAppContext extends WebAppContext
|
|||
|
||||
public void doStop () throws Exception
|
||||
{
|
||||
if (classpathFiles != null)
|
||||
classpathFiles.clear();
|
||||
classpathFiles = null;
|
||||
if (_classpathFiles != null)
|
||||
_classpathFiles.clear();
|
||||
_classpathFiles = null;
|
||||
|
||||
classes = null;
|
||||
testClasses = null;
|
||||
_classes = null;
|
||||
_testClasses = null;
|
||||
|
||||
if (webInfJarMap != null)
|
||||
webInfJarMap.clear();
|
||||
if (_webInfJarMap != null)
|
||||
_webInfJarMap.clear();
|
||||
|
||||
webInfClasses.clear();
|
||||
webInfJars.clear();
|
||||
_webInfClasses.clear();
|
||||
_webInfJars.clear();
|
||||
|
||||
|
||||
|
||||
|
@ -326,7 +307,7 @@ public class JettyWebAppContext extends WebAppContext
|
|||
resource = super.getResource(uriInContext);
|
||||
|
||||
// If no regular resource exists check for access to /WEB-INF/lib or /WEB-INF/classes
|
||||
if ((resource == null || !resource.exists()) && uriInContext != null && classes != null)
|
||||
if ((resource == null || !resource.exists()) && uriInContext != null && _classes != null)
|
||||
{
|
||||
String uri = URIUtil.canonicalPath(uriInContext);
|
||||
if (uri == null)
|
||||
|
@ -341,19 +322,19 @@ public class JettyWebAppContext extends WebAppContext
|
|||
{
|
||||
//exact match for a WEB-INF/classes, so preferentially return the resource matching the web-inf classes
|
||||
//rather than the test classes
|
||||
if (classes != null)
|
||||
return Resource.newResource(classes);
|
||||
else if (testClasses != null)
|
||||
return Resource.newResource(testClasses);
|
||||
if (_classes != null)
|
||||
return Resource.newResource(_classes);
|
||||
else if (_testClasses != null)
|
||||
return Resource.newResource(_testClasses);
|
||||
}
|
||||
else
|
||||
{
|
||||
//try matching
|
||||
Resource res = null;
|
||||
int i=0;
|
||||
while (res == null && (i < webInfClasses.size()))
|
||||
while (res == null && (i < _webInfClasses.size()))
|
||||
{
|
||||
String newPath = uri.replace(WEB_INF_CLASSES_PREFIX, webInfClasses.get(i).getPath());
|
||||
String newPath = uri.replace(WEB_INF_CLASSES_PREFIX, _webInfClasses.get(i).getPath());
|
||||
res = Resource.newResource(newPath);
|
||||
if (!res.exists())
|
||||
{
|
||||
|
@ -373,7 +354,7 @@ public class JettyWebAppContext extends WebAppContext
|
|||
jarName = jarName.substring(1);
|
||||
if (jarName.length()==0)
|
||||
return null;
|
||||
File jarFile = webInfJarMap.get(jarName);
|
||||
File jarFile = _webInfJarMap.get(jarName);
|
||||
if (jarFile != null)
|
||||
return Resource.newResource(jarFile.getPath());
|
||||
|
||||
|
@ -406,7 +387,7 @@ public class JettyWebAppContext extends WebAppContext
|
|||
//add in the dependency jars as a virtual WEB-INF/lib entry
|
||||
if (path.startsWith(WEB_INF_LIB_PREFIX))
|
||||
{
|
||||
for (String fileName : webInfJarMap.keySet())
|
||||
for (String fileName : _webInfJarMap.keySet())
|
||||
{
|
||||
// Return all jar files from class path
|
||||
allPaths.add(WEB_INF_LIB_PREFIX + "/" + fileName);
|
||||
|
@ -416,9 +397,9 @@ public class JettyWebAppContext extends WebAppContext
|
|||
{
|
||||
int i=0;
|
||||
|
||||
while (i < webInfClasses.size())
|
||||
while (i < _webInfClasses.size())
|
||||
{
|
||||
String newPath = path.replace(WEB_INF_CLASSES_PREFIX, webInfClasses.get(i).getPath());
|
||||
String newPath = path.replace(WEB_INF_CLASSES_PREFIX, _webInfClasses.get(i).getPath());
|
||||
allPaths.addAll(super.getResourcePaths(newPath));
|
||||
i++;
|
||||
}
|
||||
|
|
|
@ -20,14 +20,14 @@ package org.eclipse.jetty.maven.plugin;
|
|||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.URLClassLoader;
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
import org.apache.maven.artifact.Artifact;
|
||||
import org.eclipse.jetty.util.IO;
|
||||
import org.eclipse.jetty.util.LazyList;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
import org.eclipse.jetty.util.resource.Resource;
|
||||
|
@ -36,29 +36,43 @@ import org.eclipse.jetty.webapp.WebAppClassLoader;
|
|||
import org.eclipse.jetty.webapp.WebAppContext;
|
||||
import org.eclipse.jetty.webapp.WebInfConfiguration;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* MavenWebInfConfiguration
|
||||
*
|
||||
* WebInfConfiguration to take account of overlaid wars expressed as project dependencies and
|
||||
* potentiall configured via the maven-war-plugin.
|
||||
*
|
||||
*/
|
||||
public class MavenWebInfConfiguration extends WebInfConfiguration
|
||||
{
|
||||
private static final Logger LOG = Log.getLogger(MavenWebInfConfiguration.class);
|
||||
private static final Logger LOG = Log.getLogger(WebInfConfiguration.class);
|
||||
|
||||
|
||||
protected static int COUNTER = 0;
|
||||
protected Resource _originalResourceBase;
|
||||
protected Resource[] _unpackedOverlays;
|
||||
protected List<Resource> _unpackedOverlayResources;
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @see org.eclipse.jetty.webapp.WebInfConfiguration#configure(org.eclipse.jetty.webapp.WebAppContext)
|
||||
*/
|
||||
public void configure(WebAppContext context) throws Exception
|
||||
{
|
||||
JettyWebAppContext jwac = (JettyWebAppContext)context;
|
||||
|
||||
//put the classes dir and all dependencies into the classpath
|
||||
if (jwac.getClassPathFiles() != null)
|
||||
{
|
||||
if (LOG.isDebugEnabled()) LOG.debug("Setting up classpath ...");
|
||||
|
||||
//put the classes dir and all dependencies into the classpath
|
||||
Iterator itor = jwac.getClassPathFiles().iterator();
|
||||
while (itor.hasNext())
|
||||
((WebAppClassLoader)context.getClassLoader()).addClassPath(((File)itor.next()).getCanonicalPath());
|
||||
|
||||
//if (LOG.isDebugEnabled())
|
||||
//LOG.debug("Classpath = "+LazyList.array2List(((URLClassLoader)context.getClassLoader()).getURLs()));
|
||||
}
|
||||
|
||||
super.configure(context);
|
||||
|
||||
// knock out environmental maven and plexus classes from webAppContext
|
||||
|
@ -76,31 +90,45 @@ public class MavenWebInfConfiguration extends WebInfConfiguration
|
|||
context.setServerClasses( newServerClasses );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @see org.eclipse.jetty.webapp.WebInfConfiguration#preConfigure(org.eclipse.jetty.webapp.WebAppContext)
|
||||
*/
|
||||
public void preConfigure(WebAppContext context) throws Exception
|
||||
{
|
||||
super.preConfigure(context);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @see org.eclipse.jetty.webapp.AbstractConfiguration#postConfigure(org.eclipse.jetty.webapp.WebAppContext)
|
||||
*/
|
||||
public void postConfigure(WebAppContext context) throws Exception
|
||||
{
|
||||
super.postConfigure(context);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @see org.eclipse.jetty.webapp.WebInfConfiguration#deconfigure(org.eclipse.jetty.webapp.WebAppContext)
|
||||
*/
|
||||
public void deconfigure(WebAppContext context) throws Exception
|
||||
{
|
||||
JettyWebAppContext jwac = (JettyWebAppContext)context;
|
||||
|
||||
{
|
||||
//remove the unpacked wars
|
||||
if (_unpackedOverlays != null && _unpackedOverlays.length>0)
|
||||
if (_unpackedOverlayResources != null && !_unpackedOverlayResources.isEmpty())
|
||||
{
|
||||
try
|
||||
{
|
||||
for (int i=0; i<_unpackedOverlays.length; i++)
|
||||
for (Resource r:_unpackedOverlayResources)
|
||||
{
|
||||
IO.delete(_unpackedOverlays[i].getFile());
|
||||
IO.delete(r.getFile());
|
||||
}
|
||||
}
|
||||
catch (IOException e)
|
||||
|
@ -111,12 +139,11 @@ public class MavenWebInfConfiguration extends WebInfConfiguration
|
|||
super.deconfigure(context);
|
||||
//restore whatever the base resource was before we might have included overlaid wars
|
||||
context.setBaseResource(_originalResourceBase);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @see org.eclipse.jetty.webapp.WebInfConfiguration#unpack(org.eclipse.jetty.webapp.WebAppContext)
|
||||
*/
|
||||
|
@ -126,62 +153,49 @@ public class MavenWebInfConfiguration extends WebInfConfiguration
|
|||
//Unpack and find base resource as normal
|
||||
super.unpack(context);
|
||||
|
||||
|
||||
//Add in any overlays as a resource collection for the base
|
||||
//Get the base resource for the "virtual" webapp
|
||||
_originalResourceBase = context.getBaseResource();
|
||||
|
||||
JettyWebAppContext jwac = (JettyWebAppContext)context;
|
||||
|
||||
//Add in any overlaid wars as base resources
|
||||
//determine sequencing of overlays
|
||||
_unpackedOverlayResources = new ArrayList<Resource>();
|
||||
|
||||
|
||||
|
||||
if (jwac.getOverlays() != null && !jwac.getOverlays().isEmpty())
|
||||
{
|
||||
Resource[] origResources = null;
|
||||
int origSize = 0;
|
||||
List<Resource> resourceBaseCollection = new ArrayList<Resource>();
|
||||
|
||||
if (jwac.getBaseResource() != null)
|
||||
for (Overlay o:jwac.getOverlays())
|
||||
{
|
||||
if (jwac.getBaseResource() instanceof ResourceCollection)
|
||||
//can refer to the current project in list of overlays for ordering purposes
|
||||
if (o.getConfig() != null && o.getConfig().isCurrentProject())
|
||||
{
|
||||
origResources = ((ResourceCollection)jwac.getBaseResource()).getResources();
|
||||
origSize = origResources.length;
|
||||
resourceBaseCollection.add(_originalResourceBase);
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
origResources = new Resource[1];
|
||||
origResources[0] = jwac.getBaseResource();
|
||||
origSize = 1;
|
||||
}
|
||||
}
|
||||
|
||||
int overlaySize = jwac.getOverlays().size();
|
||||
Resource[] newResources = new Resource[origSize + overlaySize];
|
||||
|
||||
int offset = 0;
|
||||
if (origSize > 0)
|
||||
Resource unpacked = unpackOverlay(jwac,o);
|
||||
_unpackedOverlayResources.add(unpacked); //remember the unpacked overlays for later so we can delete the tmp files
|
||||
resourceBaseCollection.add(unpacked); //add in the selectively unpacked overlay in the correct order to the webapps resource base
|
||||
}
|
||||
|
||||
if (!resourceBaseCollection.contains(_originalResourceBase))
|
||||
{
|
||||
if (jwac.getBaseAppFirst())
|
||||
{
|
||||
System.arraycopy(origResources,0,newResources,0,origSize);
|
||||
offset = origSize;
|
||||
LOG.info("Adding virtual project first in resource base list");
|
||||
resourceBaseCollection.add(0, _originalResourceBase);
|
||||
}
|
||||
else
|
||||
{
|
||||
System.arraycopy(origResources,0,newResources,overlaySize,origSize);
|
||||
LOG.info("Adding virtual project last in resource base list");
|
||||
resourceBaseCollection.add(_originalResourceBase);
|
||||
}
|
||||
}
|
||||
|
||||
// Overlays are always unpacked
|
||||
_unpackedOverlays = new Resource[overlaySize];
|
||||
List<Resource> overlays = jwac.getOverlays();
|
||||
for (int idx=0; idx<overlaySize; idx++)
|
||||
{
|
||||
LOG.info("Unpacking overlay: " + overlays.get(idx));
|
||||
_unpackedOverlays[idx] = unpackOverlay(context, overlays.get(idx));
|
||||
newResources[idx+offset] = _unpackedOverlays[idx];
|
||||
|
||||
LOG.info("Adding overlay: " + _unpackedOverlays[idx]);
|
||||
}
|
||||
|
||||
jwac.setBaseResource(new ResourceCollection(newResources));
|
||||
jwac.setBaseResource(new ResourceCollection(resourceBaseCollection.toArray(new Resource[resourceBaseCollection.size()])));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -225,25 +239,68 @@ public class MavenWebInfConfiguration extends WebInfConfiguration
|
|||
|
||||
|
||||
|
||||
protected Resource unpackOverlay (WebAppContext context, Resource overlay)
|
||||
protected Resource unpackOverlay (WebAppContext context, Overlay overlay)
|
||||
throws IOException
|
||||
{
|
||||
LOG.info("Unpacking overlay: " + overlay);
|
||||
|
||||
//resolve if not already resolved
|
||||
resolveTempDirectory(context);
|
||||
|
||||
if (overlay.getResource() == null)
|
||||
return null; //nothing to unpack
|
||||
|
||||
//Get the name of the overlayed war and unpack it to a dir of the
|
||||
//same name in the temporary directory
|
||||
String name = overlay.getName();
|
||||
String name = overlay.getResource().getName();
|
||||
if (name.endsWith("!/"))
|
||||
name = name.substring(0,name.length()-2);
|
||||
int i = name.lastIndexOf('/');
|
||||
if (i>0)
|
||||
name = name.substring(i+1,name.length());
|
||||
name = name.replace('.', '_');
|
||||
File dir = new File(context.getTempDirectory(), name);
|
||||
overlay.copyTo(dir);
|
||||
name = name+(++COUNTER); //add some digits to ensure uniqueness
|
||||
File dir = new File(context.getTempDirectory(), name);
|
||||
|
||||
//if specified targetPath, unpack to that subdir instead
|
||||
File unpackDir = dir;
|
||||
if (overlay.getConfig() != null && overlay.getConfig().getTargetPath() != null)
|
||||
unpackDir = new File (dir, overlay.getConfig().getTargetPath());
|
||||
|
||||
overlay.getResource().copyTo(unpackDir);
|
||||
//use top level of unpacked content
|
||||
Resource unpackedOverlay = Resource.newResource(dir.getCanonicalPath());
|
||||
|
||||
LOG.info("Unpacked overlay: "+overlay+" to "+unpackedOverlay);
|
||||
return unpackedOverlay;
|
||||
}
|
||||
|
||||
protected Artifact getArtifactForOverlay (OverlayConfig o, List<Artifact> warArtifacts)
|
||||
{
|
||||
if (o == null || warArtifacts == null || warArtifacts.isEmpty())
|
||||
return null;
|
||||
|
||||
for (Artifact a:warArtifacts)
|
||||
{
|
||||
if (overlayMatchesArtifact (o, a))
|
||||
{
|
||||
return a;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
protected boolean overlayMatchesArtifact(OverlayConfig o, Artifact a)
|
||||
{
|
||||
if ((o.getGroupId() == null && a.getGroupId() == null) || (o.getGroupId() != null && o.getGroupId().equals(a.getGroupId())))
|
||||
{
|
||||
if ((o.getArtifactId() == null && a.getArtifactId() == null) || (o.getArtifactId() != null && o.getArtifactId().equals(a.getArtifactId())))
|
||||
{
|
||||
if ((o.getClassifier() == null) || (o.getClassifier().equals(a.getClassifier())))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,74 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2012 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
|
||||
package org.eclipse.jetty.maven.plugin;
|
||||
|
||||
import org.eclipse.jetty.util.resource.Resource;
|
||||
|
||||
/**
|
||||
* Overlay
|
||||
*
|
||||
*
|
||||
*/
|
||||
public class Overlay
|
||||
{
|
||||
private OverlayConfig _config;
|
||||
private Resource _resource;
|
||||
|
||||
public Overlay (OverlayConfig config, Resource resource)
|
||||
{
|
||||
_config = config;
|
||||
_resource = resource;
|
||||
}
|
||||
|
||||
public Overlay (OverlayConfig config)
|
||||
{
|
||||
_config = config;
|
||||
}
|
||||
|
||||
|
||||
public void setResource (Resource r)
|
||||
{
|
||||
_resource = r;
|
||||
}
|
||||
|
||||
public Resource getResource ()
|
||||
{
|
||||
return _resource;
|
||||
}
|
||||
|
||||
public OverlayConfig getConfig ()
|
||||
{
|
||||
return _config;
|
||||
}
|
||||
|
||||
public String toString()
|
||||
{
|
||||
StringBuffer strbuff = new StringBuffer();
|
||||
if (_resource != null)
|
||||
strbuff.append(_resource);
|
||||
if (_config != null)
|
||||
{
|
||||
strbuff.append(" [");
|
||||
strbuff.append(_config);
|
||||
strbuff.append("]");
|
||||
}
|
||||
return strbuff.toString();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,304 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2012 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
|
||||
package org.eclipse.jetty.maven.plugin;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import org.codehaus.plexus.util.xml.Xpp3Dom;
|
||||
|
||||
import edu.emory.mathcs.backport.java.util.Arrays;
|
||||
|
||||
/**
|
||||
* OverlayConfig
|
||||
*
|
||||
*
|
||||
*/
|
||||
public class OverlayConfig
|
||||
{
|
||||
private String targetPath;
|
||||
private String groupId;
|
||||
private String artifactId;
|
||||
private String classifier;
|
||||
private List<String> includes;
|
||||
private List<String> excludes;
|
||||
private boolean skip;
|
||||
private boolean filtered;
|
||||
|
||||
public OverlayConfig() {}
|
||||
|
||||
public OverlayConfig(String fmt, List<String> defaultIncludes, List<String> defaultExcludes)
|
||||
{
|
||||
if (fmt == null)
|
||||
return;
|
||||
String[] atoms = fmt.split(",");
|
||||
for (int i=0;i<atoms.length;i++)
|
||||
{
|
||||
String s = atoms[i].trim();
|
||||
switch (i)
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
if (!"".equals(s))
|
||||
groupId = s;
|
||||
break;
|
||||
}
|
||||
case 1:
|
||||
{
|
||||
if (!"".equals(s))
|
||||
artifactId = s;
|
||||
break;
|
||||
}
|
||||
case 2:
|
||||
{
|
||||
if (!"".equals(s))
|
||||
classifier = s;
|
||||
break;
|
||||
}
|
||||
case 3:
|
||||
{
|
||||
if (!"".equals(s))
|
||||
targetPath = s;
|
||||
break;
|
||||
}
|
||||
case 4:
|
||||
{
|
||||
if ("".equals(s))
|
||||
skip = false;
|
||||
else
|
||||
skip = Boolean.valueOf(s);
|
||||
break;
|
||||
}
|
||||
case 5:
|
||||
{
|
||||
if ("".equals(s))
|
||||
filtered = false;
|
||||
else
|
||||
filtered = Boolean.valueOf(s);
|
||||
break;
|
||||
}
|
||||
case 6:
|
||||
{
|
||||
if ("".equals(s))
|
||||
break;
|
||||
String[] incs = s.split(";");
|
||||
if (incs.length > 0)
|
||||
includes = Arrays.asList(incs);
|
||||
break;
|
||||
}
|
||||
case 7:
|
||||
{
|
||||
if ("".equals(s))
|
||||
break;
|
||||
String[] exs = s.split(";");
|
||||
if (exs.length > 0)
|
||||
excludes = Arrays.asList(exs);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public OverlayConfig(Xpp3Dom root, List<String> defaultIncludes, List<String> defaultExcludes)
|
||||
{
|
||||
Xpp3Dom node = root.getChild("groupId");
|
||||
setGroupId(node==null?null:node.getValue());
|
||||
|
||||
node = root.getChild("artifactId");
|
||||
setArtifactId(node==null?null:node.getValue());
|
||||
|
||||
node = root.getChild("classifier");
|
||||
setClassifier(node==null?null:node.getValue());
|
||||
|
||||
node = root.getChild("targetPath");
|
||||
setTargetPath(node==null?null:node.getValue());
|
||||
|
||||
node = root.getChild("skip");
|
||||
setSkip(node==null?false:Boolean.valueOf(node.getValue()));
|
||||
|
||||
node = root.getChild("filtered");
|
||||
setFiltered(node==null?false:Boolean.valueOf(node.getValue()));
|
||||
|
||||
node = root.getChild("includes");
|
||||
List<String> includes = null;
|
||||
if (node != null && node.getChildCount() > 0)
|
||||
{
|
||||
Xpp3Dom[] list = node.getChildren("include");
|
||||
for (int j=0; list != null && j < list.length;j++)
|
||||
{
|
||||
if (includes == null)
|
||||
includes = new ArrayList<String>();
|
||||
includes.add(list[j].getValue());
|
||||
}
|
||||
}
|
||||
if (includes == null && defaultIncludes != null)
|
||||
{
|
||||
includes = new ArrayList<String>();
|
||||
includes.addAll(defaultIncludes);
|
||||
}
|
||||
setIncludes(includes);
|
||||
|
||||
|
||||
node = root.getChild("excludes");
|
||||
List<String> excludes = null;
|
||||
if (node != null && node.getChildCount() > 0)
|
||||
{
|
||||
Xpp3Dom[] list = node.getChildren("exclude");
|
||||
for (int j=0; list != null && j < list.length;j++)
|
||||
{
|
||||
if (excludes == null)
|
||||
excludes = new ArrayList<String>();
|
||||
excludes.add(list[j].getValue());
|
||||
}
|
||||
}
|
||||
if (excludes == null && defaultExcludes != null)
|
||||
{
|
||||
excludes = new ArrayList<String>();
|
||||
excludes.addAll(defaultExcludes);
|
||||
}
|
||||
setExcludes(excludes);
|
||||
}
|
||||
|
||||
public String getTargetPath()
|
||||
{
|
||||
return targetPath;
|
||||
}
|
||||
|
||||
public void setTargetPath(String targetPath)
|
||||
{
|
||||
this.targetPath = targetPath;
|
||||
}
|
||||
|
||||
public String getGroupId()
|
||||
{
|
||||
return groupId;
|
||||
}
|
||||
|
||||
public void setGroupId(String groupId)
|
||||
{
|
||||
this.groupId = groupId;
|
||||
}
|
||||
|
||||
public String getArtifactId()
|
||||
{
|
||||
return artifactId;
|
||||
}
|
||||
|
||||
public void setArtifactId(String artifactId)
|
||||
{
|
||||
this.artifactId = artifactId;
|
||||
}
|
||||
|
||||
public String getClassifier()
|
||||
{
|
||||
return classifier;
|
||||
}
|
||||
|
||||
public void setClassifier(String classifier)
|
||||
{
|
||||
this.classifier = classifier;
|
||||
}
|
||||
|
||||
public List<String> getIncludes()
|
||||
{
|
||||
return includes;
|
||||
}
|
||||
|
||||
public void setIncludes(List<String> includes)
|
||||
{
|
||||
this.includes = includes;
|
||||
}
|
||||
|
||||
public List<String> getExcludes()
|
||||
{
|
||||
return excludes;
|
||||
}
|
||||
|
||||
public void setExcludes(List<String> excludes)
|
||||
{
|
||||
this.excludes = excludes;
|
||||
}
|
||||
|
||||
public boolean isSkip()
|
||||
{
|
||||
return skip;
|
||||
}
|
||||
|
||||
public void setSkip(boolean skip)
|
||||
{
|
||||
this.skip = skip;
|
||||
}
|
||||
|
||||
public boolean isFiltered()
|
||||
{
|
||||
return filtered;
|
||||
}
|
||||
|
||||
public void setFiltered(boolean filtered)
|
||||
{
|
||||
this.filtered = filtered;
|
||||
}
|
||||
|
||||
public boolean isCurrentProject()
|
||||
{
|
||||
if (this.groupId == null && this.artifactId == null)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
public String toString()
|
||||
{
|
||||
StringBuffer strbuff = new StringBuffer();
|
||||
strbuff.append((groupId != null ? groupId : "")+",");
|
||||
strbuff.append((artifactId != null ? artifactId : "")+",");
|
||||
strbuff.append((classifier != null ? classifier : "")+",");
|
||||
strbuff.append((targetPath != null ? targetPath : "")+",");
|
||||
strbuff.append(""+skip+",");
|
||||
strbuff.append(""+filtered+",");
|
||||
|
||||
if (includes != null)
|
||||
{
|
||||
Iterator<String> itor = includes.iterator();
|
||||
while (itor.hasNext())
|
||||
{
|
||||
strbuff.append(itor.next());
|
||||
if (itor.hasNext())
|
||||
strbuff.append(";");
|
||||
}
|
||||
}
|
||||
|
||||
strbuff.append(", ");
|
||||
|
||||
if (excludes != null)
|
||||
{
|
||||
Iterator<String> itor = excludes.iterator();
|
||||
while (itor.hasNext())
|
||||
{
|
||||
strbuff.append(itor.next());
|
||||
if (itor.hasNext())
|
||||
strbuff.append(";");
|
||||
}
|
||||
}
|
||||
|
||||
return strbuff.toString();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,236 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2012 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.maven.plugin;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.jar.JarEntry;
|
||||
import java.util.jar.JarInputStream;
|
||||
import java.util.jar.Manifest;
|
||||
|
||||
import org.codehaus.plexus.util.SelectorUtils;
|
||||
import org.eclipse.jetty.util.IO;
|
||||
import org.eclipse.jetty.util.URIUtil;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
import org.eclipse.jetty.util.resource.JarResource;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* SelectiveJarResource
|
||||
*
|
||||
* Selectively copies resources from a jar file based on includes/excludes.
|
||||
*
|
||||
*/
|
||||
public class SelectiveJarResource extends JarResource
|
||||
{
|
||||
private static final Logger LOG = Log.getLogger(SelectiveJarResource.class);
|
||||
public static final List<String> DEFAULT_INCLUDES = Arrays.asList(new String[]{"**"});// No includes supplied, so set it to 'matches all'
|
||||
public static final List<String> DEFAULT_EXCLUDES = Collections.emptyList(); //No includes, set to no exclusions
|
||||
|
||||
|
||||
List<String> _includes = null;
|
||||
List<String> _excludes = null;
|
||||
boolean _caseSensitive = false;
|
||||
|
||||
|
||||
/**
|
||||
* @param url
|
||||
*/
|
||||
public SelectiveJarResource(URL url)
|
||||
{
|
||||
super(url);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param url
|
||||
* @param useCaches
|
||||
*/
|
||||
public SelectiveJarResource(URL url, boolean useCaches)
|
||||
{
|
||||
super(url, useCaches);
|
||||
}
|
||||
|
||||
|
||||
public void setCaseSensitive (boolean caseSensitive)
|
||||
{
|
||||
_caseSensitive = caseSensitive;
|
||||
}
|
||||
|
||||
public void setIncludes (List<String> patterns)
|
||||
{
|
||||
_includes = patterns;
|
||||
}
|
||||
|
||||
|
||||
public void setExcludes (List<String> patterns)
|
||||
{
|
||||
_excludes = patterns;
|
||||
}
|
||||
|
||||
|
||||
protected boolean isIncluded (String name)
|
||||
{
|
||||
for (String include:_includes)
|
||||
{
|
||||
if (SelectorUtils.matchPath(include, name, _caseSensitive))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
protected boolean isExcluded (String name)
|
||||
{
|
||||
for (String exclude:_excludes)
|
||||
{
|
||||
if (SelectorUtils.matchPath (exclude, name, _caseSensitive))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @see org.eclipse.jetty.util.resource.JarResource#copyTo(java.io.File)
|
||||
*/
|
||||
@Override
|
||||
public void copyTo(File directory) throws IOException
|
||||
{
|
||||
if (_includes == null)
|
||||
_includes = DEFAULT_INCLUDES;
|
||||
if (_excludes == null)
|
||||
_excludes = DEFAULT_EXCLUDES;
|
||||
|
||||
//Copy contents of the jar file to the given directory,
|
||||
//using the includes and excludes patterns to control which
|
||||
//parts of the jar file are copied
|
||||
if (!exists())
|
||||
return;
|
||||
|
||||
String urlString = this.getURL().toExternalForm().trim();
|
||||
int endOfJarUrl = urlString.indexOf("!/");
|
||||
int startOfJarUrl = (endOfJarUrl >= 0?4:0);
|
||||
|
||||
if (endOfJarUrl < 0)
|
||||
throw new IOException("Not a valid jar url: "+urlString);
|
||||
|
||||
URL jarFileURL = new URL(urlString.substring(startOfJarUrl, endOfJarUrl));
|
||||
|
||||
InputStream is = jarFileURL.openConnection().getInputStream();
|
||||
JarInputStream jin = new JarInputStream(is);
|
||||
JarEntry entry;
|
||||
|
||||
while((entry=jin.getNextJarEntry())!=null)
|
||||
{
|
||||
String entryName = entry.getName();
|
||||
|
||||
LOG.debug("Looking at "+entryName);
|
||||
String dotCheck = entryName.replace('\\', '/');
|
||||
dotCheck = URIUtil.canonicalPath(dotCheck);
|
||||
if (dotCheck == null)
|
||||
{
|
||||
LOG.info("Invalid entry: "+entryName);
|
||||
continue;
|
||||
}
|
||||
|
||||
File file=new File(directory,entryName);
|
||||
|
||||
if (entry.isDirectory())
|
||||
{
|
||||
if (isIncluded(entryName))
|
||||
{
|
||||
if (!isExcluded(entryName))
|
||||
{
|
||||
// Make directory
|
||||
if (!file.exists())
|
||||
file.mkdirs();
|
||||
}
|
||||
else
|
||||
LOG.debug("{} dir is excluded", entryName);
|
||||
}
|
||||
else
|
||||
LOG.debug("{} dir is NOT included", entryName);
|
||||
}
|
||||
else
|
||||
{
|
||||
//entry is a file, is it included?
|
||||
if (isIncluded(entryName))
|
||||
{
|
||||
if (!isExcluded(entryName))
|
||||
{
|
||||
// make directory (some jars don't list dirs)
|
||||
File dir = new File(file.getParent());
|
||||
if (!dir.exists())
|
||||
dir.mkdirs();
|
||||
|
||||
// Make file
|
||||
FileOutputStream fout = null;
|
||||
try
|
||||
{
|
||||
fout = new FileOutputStream(file);
|
||||
IO.copy(jin,fout);
|
||||
}
|
||||
finally
|
||||
{
|
||||
IO.close(fout);
|
||||
}
|
||||
|
||||
// touch the file.
|
||||
if (entry.getTime()>=0)
|
||||
file.setLastModified(entry.getTime());
|
||||
}
|
||||
else
|
||||
LOG.debug("{} file is excluded", entryName);
|
||||
}
|
||||
else
|
||||
LOG.debug("{} file is NOT included", entryName);
|
||||
}
|
||||
}
|
||||
|
||||
Manifest manifest = jin.getManifest();
|
||||
if (manifest != null)
|
||||
{
|
||||
if (isIncluded("META-INF") && !isExcluded("META-INF"))
|
||||
{
|
||||
File metaInf = new File (directory, "META-INF");
|
||||
metaInf.mkdir();
|
||||
File f = new File(metaInf, "MANIFEST.MF");
|
||||
FileOutputStream fout = new FileOutputStream(f);
|
||||
manifest.write(fout);
|
||||
fout.close();
|
||||
}
|
||||
}
|
||||
IO.close(jin);
|
||||
}
|
||||
|
||||
}
|
|
@ -20,24 +20,33 @@ package org.eclipse.jetty.maven.plugin;
|
|||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
import java.util.StringTokenizer;
|
||||
import java.util.Set;
|
||||
import java.util.TreeMap;
|
||||
|
||||
import org.eclipse.jetty.server.Connector;
|
||||
import org.eclipse.jetty.server.Handler;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.server.handler.ContextHandler;
|
||||
import org.eclipse.jetty.server.handler.ContextHandlerCollection;
|
||||
import org.eclipse.jetty.server.handler.HandlerCollection;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
import org.eclipse.jetty.util.resource.Resource;
|
||||
import org.eclipse.jetty.util.resource.ResourceCollection;
|
||||
import org.eclipse.jetty.webapp.WebAppContext;
|
||||
import org.eclipse.jetty.xml.XmlConfiguration;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Starter
|
||||
*
|
||||
* Class which is exec'ed to create a new jetty process. Used by the JettyRunForked mojo.
|
||||
*
|
||||
*/
|
||||
public class Starter
|
||||
{
|
||||
public static final String PORT_SYSPROPERTY = "jetty.port";
|
||||
|
@ -56,7 +65,57 @@ public class Starter
|
|||
private String token;
|
||||
|
||||
|
||||
/**
|
||||
* Artifact
|
||||
*
|
||||
* A mock maven Artifact class as the maven jars are not put onto the classpath for the
|
||||
* execution of this class.
|
||||
*
|
||||
*/
|
||||
public class Artifact
|
||||
{
|
||||
public String gid;
|
||||
public String aid;
|
||||
public String path;
|
||||
public Resource resource;
|
||||
|
||||
public Artifact (String csv)
|
||||
{
|
||||
if (csv != null && !"".equals(csv))
|
||||
{
|
||||
String[] atoms = csv.split(",");
|
||||
if (atoms.length >= 3)
|
||||
{
|
||||
gid = atoms[0].trim();
|
||||
aid = atoms[1].trim();
|
||||
path = atoms[2].trim();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Artifact (String gid, String aid, String path)
|
||||
{
|
||||
this.gid = gid;
|
||||
this.aid = aid;
|
||||
this.path = path;
|
||||
}
|
||||
|
||||
public boolean equals(Object o)
|
||||
{
|
||||
if (!(o instanceof Artifact))
|
||||
return false;
|
||||
|
||||
Artifact ao = (Artifact)o;
|
||||
return (((gid == null && ao.gid == null) || (gid != null && gid.equals(ao.gid)))
|
||||
&& ((aid == null && ao.aid == null) || (aid != null && aid.equals(ao.aid))));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
public void configureJetty () throws Exception
|
||||
{
|
||||
LOG.debug("Starting Jetty Server ...");
|
||||
|
@ -115,6 +174,9 @@ public class Starter
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
public void configureWebApp ()
|
||||
throws Exception
|
||||
{
|
||||
|
@ -127,39 +189,105 @@ public class Starter
|
|||
if (str != null)
|
||||
webApp.setContextPath(str);
|
||||
|
||||
|
||||
// - web.xml
|
||||
str = (String)props.get("web.xml");
|
||||
if (str != null)
|
||||
webApp.setDescriptor(str);
|
||||
webApp.setDescriptor(str);
|
||||
|
||||
|
||||
// - the tmp directory
|
||||
str = (String)props.getProperty("tmp.dir");
|
||||
if (str != null)
|
||||
webApp.setTempDirectory(new File(str.trim()));
|
||||
|
||||
|
||||
|
||||
// - the base directory
|
||||
str = (String)props.getProperty("base.dir");
|
||||
if (str != null && !"".equals(str.trim()))
|
||||
webApp.setWar(str);
|
||||
|
||||
// - the multiple comma separated resource dirs
|
||||
str = (String)props.getProperty("res.dirs");
|
||||
if (str != null && !"".equals(str.trim()))
|
||||
{
|
||||
ResourceCollection resources = new ResourceCollection(str);
|
||||
webApp.setBaseResource(resources);
|
||||
webApp.setWar(str);
|
||||
webApp.setBaseResource(Resource.newResource(str));
|
||||
}
|
||||
|
||||
// - overlays
|
||||
str = (String)props.getProperty("overlay.files");
|
||||
// - put virtual webapp base resource first on resource path or not
|
||||
str = (String)props.getProperty("base.first");
|
||||
if (str != null && !"".equals(str.trim()))
|
||||
webApp.setBaseAppFirst(Boolean.getBoolean(str));
|
||||
|
||||
|
||||
//For overlays
|
||||
str = (String)props.getProperty("maven.war.includes");
|
||||
List<String> defaultWarIncludes = fromCSV(str);
|
||||
str = (String)props.getProperty("maven.war.excludes");
|
||||
List<String> defaultWarExcludes = fromCSV(str);
|
||||
|
||||
//List of war artifacts
|
||||
List<Artifact> wars = new ArrayList<Artifact>();
|
||||
|
||||
//List of OverlayConfigs
|
||||
TreeMap<String, OverlayConfig> orderedConfigs = new TreeMap<String, OverlayConfig>();
|
||||
Enumeration<String> pnames = (Enumeration<String>)props.propertyNames();
|
||||
while (pnames.hasMoreElements())
|
||||
{
|
||||
List<Resource> overlays = new ArrayList<Resource>();
|
||||
String[] names = str.split(",");
|
||||
for (int j=0; names != null && j < names.length; j++)
|
||||
overlays.add(Resource.newResource("jar:"+Resource.toURL(new File(names[j].trim())).toString()+"!/"));
|
||||
webApp.setOverlays(overlays);
|
||||
String n = pnames.nextElement();
|
||||
if (n.startsWith("maven.war.artifact"))
|
||||
{
|
||||
Artifact a = new Artifact((String)props.get(n));
|
||||
a.resource = Resource.newResource("jar:"+Resource.toURL(new File(a.path)).toString()+"!/");
|
||||
wars.add(a);
|
||||
}
|
||||
else if (n.startsWith("maven.war.overlay"))
|
||||
{
|
||||
OverlayConfig c = new OverlayConfig ((String)props.get(n), defaultWarIncludes, defaultWarExcludes);
|
||||
orderedConfigs.put(n,c);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Set<Artifact> matchedWars = new HashSet<Artifact>();
|
||||
|
||||
//process any overlays and the war type artifacts
|
||||
List<Overlay> overlays = new ArrayList<Overlay>();
|
||||
for (OverlayConfig config:orderedConfigs.values())
|
||||
{
|
||||
//overlays can be individually skipped
|
||||
if (config.isSkip())
|
||||
continue;
|
||||
|
||||
//an empty overlay refers to the current project - important for ordering
|
||||
if (config.isCurrentProject())
|
||||
{
|
||||
Overlay overlay = new Overlay(config, null);
|
||||
overlays.add(overlay);
|
||||
continue;
|
||||
}
|
||||
|
||||
//if a war matches an overlay config
|
||||
Artifact a = getArtifactForOverlayConfig(config, wars);
|
||||
if (a != null)
|
||||
{
|
||||
matchedWars.add(a);
|
||||
SelectiveJarResource r = new SelectiveJarResource(new URL("jar:"+Resource.toURL(new File(a.path)).toString()+"!/"));
|
||||
r.setIncludes(config.getIncludes());
|
||||
r.setExcludes(config.getExcludes());
|
||||
Overlay overlay = new Overlay(config, r);
|
||||
overlays.add(overlay);
|
||||
}
|
||||
}
|
||||
|
||||
//iterate over the left over war artifacts and unpack them (without include/exclude processing) as necessary
|
||||
for (Artifact a: wars)
|
||||
{
|
||||
if (!matchedWars.contains(a))
|
||||
{
|
||||
Overlay overlay = new Overlay(null, a.resource);
|
||||
overlays.add(overlay);
|
||||
}
|
||||
}
|
||||
|
||||
webApp.setOverlays(overlays);
|
||||
|
||||
|
||||
// - the equivalent of web-inf classes
|
||||
str = (String)props.getProperty("classes.dir");
|
||||
|
@ -188,6 +316,10 @@ public class Starter
|
|||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param args
|
||||
* @throws Exception
|
||||
*/
|
||||
public void getConfiguration (String[] args)
|
||||
throws Exception
|
||||
{
|
||||
|
@ -235,6 +367,9 @@ public class Starter
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
public void run() throws Exception
|
||||
{
|
||||
if (monitor != null)
|
||||
|
@ -245,12 +380,18 @@ public class Starter
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
public void join () throws Exception
|
||||
{
|
||||
server.join();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param e
|
||||
*/
|
||||
public void communicateStartupResult (Exception e)
|
||||
{
|
||||
if (token != null)
|
||||
|
@ -263,6 +404,9 @@ public class Starter
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
public void applyJettyXml() throws Exception
|
||||
{
|
||||
if (jettyXmls == null)
|
||||
|
@ -279,6 +423,10 @@ public class Starter
|
|||
|
||||
|
||||
|
||||
/**
|
||||
* @param handler
|
||||
* @param handlers
|
||||
*/
|
||||
protected void prependHandler (Handler handler, HandlerCollection handlers)
|
||||
{
|
||||
if (handler == null || handlers == null)
|
||||
|
@ -292,6 +440,55 @@ public class Starter
|
|||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @param c
|
||||
* @param wars
|
||||
* @return
|
||||
*/
|
||||
protected Artifact getArtifactForOverlayConfig (OverlayConfig c, List<Artifact> wars)
|
||||
{
|
||||
if (wars == null || wars.isEmpty() || c == null)
|
||||
return null;
|
||||
|
||||
Artifact war = null;
|
||||
Iterator<Artifact> itor = wars.iterator();
|
||||
while(itor.hasNext() && war == null)
|
||||
{
|
||||
Artifact a = itor.next();
|
||||
if (((c.getGroupId() == null && a.gid == null) || (c.getGroupId() != null && c.getGroupId().equals(a.gid)))
|
||||
&& ((c.getArtifactId() == null && a.aid == null) || (c.getArtifactId() != null && c.getArtifactId().equals(a.aid)))
|
||||
&& ((c.getClassifier() == null) || (c.getClassifier().equals(a.aid))))
|
||||
{
|
||||
war = a;
|
||||
}
|
||||
}
|
||||
return war;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param csv
|
||||
* @return
|
||||
*/
|
||||
private List<String> fromCSV (String csv)
|
||||
{
|
||||
if (csv == null || "".equals(csv.trim()))
|
||||
return null;
|
||||
String[] atoms = csv.split(",");
|
||||
List<String> list = new ArrayList<String>();
|
||||
for (String a:atoms)
|
||||
{
|
||||
list.add(a.trim());
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @param args
|
||||
*/
|
||||
public static final void main(String[] args)
|
||||
{
|
||||
if (args == null)
|
||||
|
|
|
@ -0,0 +1,203 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2012 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
|
||||
package org.eclipse.jetty.maven.plugin;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.maven.model.Plugin;
|
||||
import org.apache.maven.project.MavenProject;
|
||||
import org.codehaus.plexus.util.xml.Xpp3Dom;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* WarPluginInfo
|
||||
*
|
||||
* Information about the maven-war-plugin contained in the pom
|
||||
*/
|
||||
public class WarPluginInfo
|
||||
{
|
||||
private MavenProject _project;
|
||||
private Plugin _plugin;
|
||||
private List<String> _dependentMavenWarIncludes;
|
||||
private List<String> _dependentMavenWarExcludes;
|
||||
private List<OverlayConfig> _overlayConfigs;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @param project
|
||||
*/
|
||||
public WarPluginInfo (MavenProject project)
|
||||
{
|
||||
_project = project;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Find the maven-war-plugin, if one is configured
|
||||
* @return
|
||||
*/
|
||||
public Plugin getPlugin()
|
||||
{
|
||||
if (_plugin == null)
|
||||
{
|
||||
List plugins = _project.getBuildPlugins();
|
||||
if (plugins == null)
|
||||
return null;
|
||||
|
||||
|
||||
Iterator itor = plugins.iterator();
|
||||
while (itor.hasNext() && _plugin==null)
|
||||
{
|
||||
Plugin plugin = (Plugin)itor.next();
|
||||
if ("maven-war-plugin".equals(plugin.getArtifactId()))
|
||||
_plugin = plugin;
|
||||
}
|
||||
}
|
||||
return _plugin;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Get value of dependentWarIncludes for maven-war-plugin
|
||||
* @return
|
||||
*/
|
||||
public List<String> getDependentMavenWarIncludes()
|
||||
{
|
||||
if (_dependentMavenWarIncludes == null)
|
||||
{
|
||||
getPlugin();
|
||||
|
||||
if (_plugin == null)
|
||||
return null;
|
||||
|
||||
Xpp3Dom node = (Xpp3Dom)_plugin.getConfiguration();
|
||||
if (node == null)
|
||||
return null;
|
||||
|
||||
node = node.getChild("dependentWarIncludes");
|
||||
if (node == null)
|
||||
return null;
|
||||
String val = node.getValue();
|
||||
_dependentMavenWarIncludes = Arrays.asList(val.split(","));
|
||||
}
|
||||
return _dependentMavenWarIncludes;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Get value of dependentWarExcludes for maven-war-plugin
|
||||
* @return
|
||||
*/
|
||||
public List<String> getDependentMavenWarExcludes()
|
||||
{
|
||||
if (_dependentMavenWarExcludes == null)
|
||||
{
|
||||
getPlugin();
|
||||
|
||||
if (_plugin == null)
|
||||
return null;
|
||||
|
||||
Xpp3Dom node = (Xpp3Dom)_plugin.getConfiguration();
|
||||
if (node == null)
|
||||
return null;
|
||||
|
||||
node = node.getChild("dependentWarExcludes");
|
||||
if (node == null)
|
||||
return null;
|
||||
String val = node.getValue();
|
||||
_dependentMavenWarExcludes = Arrays.asList(val.split(","));
|
||||
}
|
||||
return _dependentMavenWarExcludes;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Get config for any overlays that have been declared for the maven-war-plugin.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public List<OverlayConfig> getMavenWarOverlayConfigs ()
|
||||
{
|
||||
if (_overlayConfigs == null)
|
||||
{
|
||||
getPlugin();
|
||||
|
||||
if (_plugin == null)
|
||||
return Collections.emptyList();
|
||||
|
||||
getDependentMavenWarIncludes();
|
||||
getDependentMavenWarExcludes();
|
||||
|
||||
Xpp3Dom node = (Xpp3Dom)_plugin.getConfiguration();
|
||||
if (node == null)
|
||||
return Collections.emptyList();
|
||||
|
||||
node = node.getChild("overlays");
|
||||
if (node == null)
|
||||
return Collections.emptyList();
|
||||
|
||||
Xpp3Dom[] nodes = node.getChildren("overlay");
|
||||
if (nodes == null)
|
||||
return Collections.emptyList();
|
||||
|
||||
_overlayConfigs = new ArrayList<OverlayConfig>();
|
||||
for (int i=0;i<nodes.length;i++)
|
||||
{
|
||||
OverlayConfig overlayConfig = new OverlayConfig(nodes[i], _dependentMavenWarIncludes, _dependentMavenWarExcludes);
|
||||
_overlayConfigs.add(overlayConfig);
|
||||
}
|
||||
}
|
||||
|
||||
return _overlayConfigs;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @return the xml as a string
|
||||
*/
|
||||
public String getMavenWarOverlayConfigAsString ()
|
||||
{
|
||||
getPlugin();
|
||||
|
||||
if (_plugin == null)
|
||||
return "";
|
||||
|
||||
Xpp3Dom node = (Xpp3Dom)_plugin.getConfiguration();
|
||||
if (node == null)
|
||||
return "";
|
||||
return node.toString();
|
||||
}
|
||||
}
|
|
@ -22,11 +22,6 @@
|
|||
<npn-version>1.1.0.v20120525</npn-version>
|
||||
</properties>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit-dep</artifactId>
|
||||
<version>4.10</version>
|
||||
</dependency>
|
||||
<!-- Pax Exam Dependencies -->
|
||||
<!-- OPS4J Swissbox Dependencies -->
|
||||
<dependency>
|
||||
|
@ -233,6 +228,18 @@
|
|||
<version>${project.version}</version>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty.websocket</groupId>
|
||||
<artifactId>websocket-api</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty.websocket</groupId>
|
||||
<artifactId>websocket-common</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty.websocket</groupId>
|
||||
<artifactId>websocket-client</artifactId>
|
||||
|
@ -241,7 +248,7 @@
|
|||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty.websocket</groupId>
|
||||
<artifactId>websocket-core</artifactId>
|
||||
<artifactId>websocket-servlet</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
|
@ -251,6 +258,11 @@
|
|||
<version>${project.version}</version>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty.drafts</groupId>
|
||||
<artifactId>javax.websocket-api</artifactId>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty.spdy</groupId>
|
||||
|
@ -319,6 +331,11 @@
|
|||
<classifier>webbundle</classifier>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty.toolchain</groupId>
|
||||
<artifactId>jetty-test-helper</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<build>
|
||||
<plugins>
|
||||
|
|
|
@ -1,13 +1,11 @@
|
|||
<?xml version="1.0"?>
|
||||
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure.dtd">
|
||||
|
||||
<!DOCTYPE Configure PUBLIC "-" "http://www.eclipse.org/jetty/configure.dtd">
|
||||
<Configure id="Server" class="org.eclipse.jetty.server.Server">
|
||||
|
||||
<!-- =========================================================== -->
|
||||
<!-- Configure Authentication Login Service -->
|
||||
<!-- Realms may be configured for the entire server here, or -->
|
||||
<!-- they can be configured for a specific web app in a context -->
|
||||
<!-- configuration (see $(jetty.home)/contexts/test.xml for an -->
|
||||
<!-- configuration (see $(jetty.home)/webapps/test.xml for an -->
|
||||
<!-- example). -->
|
||||
<!-- =========================================================== -->
|
||||
<Call name="addBean">
|
||||
|
@ -19,5 +17,4 @@
|
|||
</New>
|
||||
</Arg>
|
||||
</Call>
|
||||
|
||||
</Configure>
|
||||
</Configure>
|
|
@ -103,7 +103,10 @@ public class AbstractTestOSGi
|
|||
{
|
||||
diagnoseNonActiveOrNonResolvedBundle(b);
|
||||
}
|
||||
Assert.assertTrue(b.getState() == Bundle.ACTIVE || b.getState() == Bundle.RESOLVED);
|
||||
Assert.assertTrue("Bundle: " + b + " (state should be " +
|
||||
"ACTIVE[" + Bundle.ACTIVE + "] or RESOLVED[" + Bundle.RESOLVED + "]" +
|
||||
", but was [" + b.getState() + "])",
|
||||
(b.getState() == Bundle.ACTIVE) || (b.getState() == Bundle.RESOLVED));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -86,10 +86,12 @@ public class TestJettyOSGiBootCore extends AbstractTestOSGi {
|
|||
res.add(mavenBundle().groupId( "org.eclipse.jetty" ).artifactId( "jetty-security" ).versionAsInProject().noStart());
|
||||
res.add(mavenBundle().groupId( "org.eclipse.jetty" ).artifactId( "jetty-servlets" ).versionAsInProject().noStart());
|
||||
res.add(mavenBundle().groupId( "org.eclipse.jetty" ).artifactId( "jetty-client" ).versionAsInProject().noStart());
|
||||
res.add(mavenBundle().groupId( "org.eclipse.jetty.websocket" ).artifactId( "websocket-core" ).versionAsInProject().noStart());
|
||||
res.add(mavenBundle().groupId( "org.eclipse.jetty.drafts" ).artifactId( "javax.websocket-api" ).versionAsInProject().noStart());
|
||||
res.add(mavenBundle().groupId( "org.eclipse.jetty.websocket" ).artifactId( "websocket-api" ).versionAsInProject().noStart());
|
||||
res.add(mavenBundle().groupId( "org.eclipse.jetty.websocket" ).artifactId( "websocket-common" ).versionAsInProject().noStart());
|
||||
res.add(mavenBundle().groupId( "org.eclipse.jetty.websocket" ).artifactId( "websocket-servlet" ).versionAsInProject().noStart());
|
||||
res.add(mavenBundle().groupId( "org.eclipse.jetty.websocket" ).artifactId( "websocket-server" ).versionAsInProject().noStart());
|
||||
//optional:
|
||||
//res.add(mavenBundle().groupId( "org.eclipse.jetty.websocket" ).artifactId( "websocket-client" ).versionAsInProject().noStart());
|
||||
res.add(mavenBundle().groupId( "org.eclipse.jetty.websocket" ).artifactId( "websocket-client" ).versionAsInProject().noStart());
|
||||
return res;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,88 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<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>
|
||||
<artifactId>jetty-project</artifactId>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<version>9.0.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>jetty-proxy</artifactId>
|
||||
<name>Jetty :: Proxy</name>
|
||||
<description>Jetty Proxy</description>
|
||||
<properties>
|
||||
<bundle-symbolic-name>${project.groupId}.servlets</bundle-symbolic-name>
|
||||
</properties>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.felix</groupId>
|
||||
<artifactId>maven-bundle-plugin</artifactId>
|
||||
<extensions>true</extensions>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>manifest</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<instructions>
|
||||
<Import-Package>javax.servlet.*;version="2.6.0",*</Import-Package>
|
||||
</instructions>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<!--
|
||||
Required for OSGI
|
||||
-->
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-jar-plugin</artifactId>
|
||||
<configuration>
|
||||
<archive>
|
||||
<manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile>
|
||||
</archive>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>findbugs-maven-plugin</artifactId>
|
||||
<configuration>
|
||||
<onlyAnalyze>org.eclipse.jetty.servlets.*</onlyAnalyze>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty.toolchain</groupId>
|
||||
<artifactId>jetty-test-helper</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-continuation</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-webapp</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-client</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-util</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty.orbit</groupId>
|
||||
<artifactId>javax.servlet</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
|
@ -1,62 +0,0 @@
|
|||
<?xml version="1.0"?>
|
||||
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure.dtd">
|
||||
|
||||
<!-- =============================================================== -->
|
||||
<!-- Configure the Jetty Server -->
|
||||
<!-- -->
|
||||
<!-- Documentation of this file format can be found at: -->
|
||||
<!-- http://docs.codehaus.org/display/JETTY/jetty.xml -->
|
||||
<!-- -->
|
||||
<!-- =============================================================== -->
|
||||
|
||||
|
||||
<Configure id="Proxy" class="org.eclipse.jetty.server.Server">
|
||||
|
||||
<!-- =========================================================== -->
|
||||
<!-- Server Thread Pool -->
|
||||
<!-- =========================================================== -->
|
||||
<Set name="ThreadPool">
|
||||
<!-- Default queued blocking threadpool
|
||||
-->
|
||||
<New class="org.eclipse.jetty.util.thread.QueuedThreadPool">
|
||||
<Set name="minThreads">10</Set>
|
||||
<Set name="maxThreads">50</Set>
|
||||
</New>
|
||||
</Set>
|
||||
|
||||
|
||||
<!-- =========================================================== -->
|
||||
<!-- Set connectors -->
|
||||
<!-- =========================================================== -->
|
||||
|
||||
<Call name="addConnector">
|
||||
<Arg>
|
||||
<New class="org.eclipse.jetty.server.ServerConnector">
|
||||
<Set name="host"><Property name="jetty.host" /></Set>
|
||||
<Set name="port"><Property name="jetty.port" default="8888"/></Set>
|
||||
<Set name="idleTimeout">300000</Set>
|
||||
<Set name="Acceptors">2</Set>
|
||||
<Set name="statsOn">false</Set>
|
||||
</New>
|
||||
</Arg>
|
||||
</Call>
|
||||
|
||||
<!-- =========================================================== -->
|
||||
<Set name="handler">
|
||||
<New id="Servlets" class="org.eclipse.jetty.servlet.ServletHandler">
|
||||
<Call name="addServletWithMapping">
|
||||
<Arg>org.eclipse.jetty.servlets.ProxyServlet</Arg>
|
||||
<Arg>/</Arg>
|
||||
</Call>
|
||||
</New>
|
||||
</Set>
|
||||
|
||||
<!-- =========================================================== -->
|
||||
<!-- extra options -->
|
||||
<!-- =========================================================== -->
|
||||
<Set name="stopAtShutdown">true</Set>
|
||||
<Set name="sendServerVersion">true</Set>
|
||||
<Set name="sendDateHeader">true</Set>
|
||||
<Set name="stopTimeout">1000</Set>
|
||||
|
||||
</Configure>
|
|
@ -1,422 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2012 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.proxy;
|
||||
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import javax.servlet.ServletConfig;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.UnavailableException;
|
||||
import javax.servlet.http.Cookie;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.eclipse.jetty.http.HttpURI;
|
||||
import org.eclipse.jetty.server.Request;
|
||||
|
||||
/**
|
||||
* 6
|
||||
*/
|
||||
public class BalancerServlet extends ProxyServlet
|
||||
{
|
||||
|
||||
private static final class BalancerMember
|
||||
{
|
||||
|
||||
private String _name;
|
||||
|
||||
private String _proxyTo;
|
||||
|
||||
private HttpURI _backendURI;
|
||||
|
||||
public BalancerMember(String name, String proxyTo)
|
||||
{
|
||||
super();
|
||||
_name = name;
|
||||
_proxyTo = proxyTo;
|
||||
_backendURI = new HttpURI(_proxyTo);
|
||||
}
|
||||
|
||||
public String getProxyTo()
|
||||
{
|
||||
return _proxyTo;
|
||||
}
|
||||
|
||||
public HttpURI getBackendURI()
|
||||
{
|
||||
return _backendURI;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return "BalancerMember [_name=" + _name + ", _proxyTo=" + _proxyTo + "]";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode()
|
||||
{
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + ((_name == null)?0:_name.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj)
|
||||
{
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null)
|
||||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
BalancerMember other = (BalancerMember)obj;
|
||||
if (_name == null)
|
||||
{
|
||||
if (other._name != null)
|
||||
return false;
|
||||
}
|
||||
else if (!_name.equals(other._name))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static final class RoundRobinIterator implements Iterator<BalancerMember>
|
||||
{
|
||||
|
||||
private BalancerMember[] _balancerMembers;
|
||||
|
||||
private AtomicInteger _index;
|
||||
|
||||
public RoundRobinIterator(Collection<BalancerMember> balancerMembers)
|
||||
{
|
||||
_balancerMembers = (BalancerMember[])balancerMembers.toArray(new BalancerMember[balancerMembers.size()]);
|
||||
_index = new AtomicInteger(-1);
|
||||
}
|
||||
|
||||
public boolean hasNext()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public BalancerMember next()
|
||||
{
|
||||
BalancerMember balancerMember = null;
|
||||
while (balancerMember == null)
|
||||
{
|
||||
int currentIndex = _index.get();
|
||||
int nextIndex = (currentIndex + 1) % _balancerMembers.length;
|
||||
if (_index.compareAndSet(currentIndex,nextIndex))
|
||||
{
|
||||
balancerMember = _balancerMembers[nextIndex];
|
||||
}
|
||||
}
|
||||
return balancerMember;
|
||||
}
|
||||
|
||||
public void remove()
|
||||
{
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static final String BALANCER_MEMBER_PREFIX = "BalancerMember.";
|
||||
|
||||
private static final List<String> FORBIDDEN_CONFIG_PARAMETERS;
|
||||
static
|
||||
{
|
||||
List<String> params = new LinkedList<String>();
|
||||
params.add("HostHeader");
|
||||
params.add("whiteList");
|
||||
params.add("blackList");
|
||||
FORBIDDEN_CONFIG_PARAMETERS = Collections.unmodifiableList(params);
|
||||
}
|
||||
|
||||
private static final List<String> REVERSE_PROXY_HEADERS;
|
||||
static
|
||||
{
|
||||
List<String> params = new LinkedList<String>();
|
||||
params.add("Location");
|
||||
params.add("Content-Location");
|
||||
params.add("URI");
|
||||
REVERSE_PROXY_HEADERS = Collections.unmodifiableList(params);
|
||||
}
|
||||
|
||||
private static final String JSESSIONID = "jsessionid";
|
||||
|
||||
private static final String JSESSIONID_URL_PREFIX = JSESSIONID + "=";
|
||||
|
||||
private boolean _stickySessions;
|
||||
|
||||
private Set<BalancerMember> _balancerMembers = new HashSet<BalancerMember>();
|
||||
|
||||
private boolean _proxyPassReverse;
|
||||
|
||||
private RoundRobinIterator _roundRobinIterator;
|
||||
|
||||
@Override
|
||||
public void init(ServletConfig config) throws ServletException
|
||||
{
|
||||
validateConfig(config);
|
||||
super.init(config);
|
||||
initStickySessions(config);
|
||||
initBalancers(config);
|
||||
initProxyPassReverse(config);
|
||||
postInit();
|
||||
}
|
||||
|
||||
private void validateConfig(ServletConfig config) throws ServletException
|
||||
{
|
||||
@SuppressWarnings("unchecked")
|
||||
List<String> initParameterNames = Collections.list(config.getInitParameterNames());
|
||||
for (String initParameterName : initParameterNames)
|
||||
{
|
||||
if (FORBIDDEN_CONFIG_PARAMETERS.contains(initParameterName))
|
||||
{
|
||||
throw new UnavailableException(initParameterName + " not supported in " + getClass().getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void initStickySessions(ServletConfig config) throws ServletException
|
||||
{
|
||||
_stickySessions = "true".equalsIgnoreCase(config.getInitParameter("StickySessions"));
|
||||
}
|
||||
|
||||
private void initBalancers(ServletConfig config) throws ServletException
|
||||
{
|
||||
Set<String> balancerNames = getBalancerNames(config);
|
||||
for (String balancerName : balancerNames)
|
||||
{
|
||||
String memberProxyToParam = BALANCER_MEMBER_PREFIX + balancerName + ".ProxyTo";
|
||||
String proxyTo = config.getInitParameter(memberProxyToParam);
|
||||
if (proxyTo == null || proxyTo.trim().length() == 0)
|
||||
{
|
||||
throw new UnavailableException(memberProxyToParam + " parameter is empty.");
|
||||
}
|
||||
_balancerMembers.add(new BalancerMember(balancerName,proxyTo));
|
||||
}
|
||||
}
|
||||
|
||||
private void initProxyPassReverse(ServletConfig config)
|
||||
{
|
||||
_proxyPassReverse = "true".equalsIgnoreCase(config.getInitParameter("ProxyPassReverse"));
|
||||
}
|
||||
|
||||
private void postInit()
|
||||
{
|
||||
_roundRobinIterator = new RoundRobinIterator(_balancerMembers);
|
||||
}
|
||||
|
||||
private Set<String> getBalancerNames(ServletConfig config) throws ServletException
|
||||
{
|
||||
Set<String> names = new HashSet<String>();
|
||||
@SuppressWarnings("unchecked")
|
||||
List<String> initParameterNames = Collections.list(config.getInitParameterNames());
|
||||
for (String initParameterName : initParameterNames)
|
||||
{
|
||||
if (!initParameterName.startsWith(BALANCER_MEMBER_PREFIX))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
int endOfNameIndex = initParameterName.lastIndexOf(".");
|
||||
if (endOfNameIndex <= BALANCER_MEMBER_PREFIX.length())
|
||||
{
|
||||
throw new UnavailableException(initParameterName + " parameter does not provide a balancer member name");
|
||||
}
|
||||
names.add(initParameterName.substring(BALANCER_MEMBER_PREFIX.length(),endOfNameIndex));
|
||||
}
|
||||
return names;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected HttpURI proxyHttpURI(HttpServletRequest request, String uri) throws MalformedURLException
|
||||
{
|
||||
BalancerMember balancerMember = selectBalancerMember(request);
|
||||
try
|
||||
{
|
||||
URI dstUri = new URI(balancerMember.getProxyTo() + "/" + uri).normalize();
|
||||
return new HttpURI(dstUri.toString());
|
||||
}
|
||||
catch (URISyntaxException e)
|
||||
{
|
||||
throw new MalformedURLException(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private BalancerMember selectBalancerMember(HttpServletRequest request)
|
||||
{
|
||||
BalancerMember balancerMember = null;
|
||||
if (_stickySessions)
|
||||
{
|
||||
String name = getBalancerMemberNameFromSessionId(request);
|
||||
if (name != null)
|
||||
{
|
||||
balancerMember = findBalancerMemberByName(name);
|
||||
if (balancerMember != null)
|
||||
{
|
||||
return balancerMember;
|
||||
}
|
||||
}
|
||||
}
|
||||
return _roundRobinIterator.next();
|
||||
}
|
||||
|
||||
private BalancerMember findBalancerMemberByName(String name)
|
||||
{
|
||||
BalancerMember example = new BalancerMember(name,"");
|
||||
for (BalancerMember balancerMember : _balancerMembers)
|
||||
{
|
||||
if (balancerMember.equals(example))
|
||||
{
|
||||
return balancerMember;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private String getBalancerMemberNameFromSessionId(HttpServletRequest request)
|
||||
{
|
||||
String name = getBalancerMemberNameFromSessionCookie(request);
|
||||
if (name == null)
|
||||
{
|
||||
name = getBalancerMemberNameFromURL(request);
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
private String getBalancerMemberNameFromSessionCookie(HttpServletRequest request)
|
||||
{
|
||||
Cookie[] cookies = request.getCookies();
|
||||
String name = null;
|
||||
for (Cookie cookie : cookies)
|
||||
{
|
||||
if (JSESSIONID.equalsIgnoreCase(cookie.getName()))
|
||||
{
|
||||
name = extractBalancerMemberNameFromSessionId(cookie.getValue());
|
||||
break;
|
||||
}
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
private String getBalancerMemberNameFromURL(HttpServletRequest request)
|
||||
{
|
||||
String name = null;
|
||||
String requestURI = request.getRequestURI();
|
||||
int idx = requestURI.lastIndexOf(";");
|
||||
if (idx != -1)
|
||||
{
|
||||
String requestURISuffix = requestURI.substring(idx);
|
||||
if (requestURISuffix.startsWith(JSESSIONID_URL_PREFIX))
|
||||
{
|
||||
name = extractBalancerMemberNameFromSessionId(requestURISuffix.substring(JSESSIONID_URL_PREFIX.length()));
|
||||
}
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
private String extractBalancerMemberNameFromSessionId(String sessionId)
|
||||
{
|
||||
String name = null;
|
||||
int idx = sessionId.lastIndexOf(".");
|
||||
if (idx != -1)
|
||||
{
|
||||
String sessionIdSuffix = sessionId.substring(idx + 1);
|
||||
name = (sessionIdSuffix.length() > 0)?sessionIdSuffix:null;
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String filterResponseHeaderValue(String headerName, String headerValue, HttpServletRequest request)
|
||||
{
|
||||
if (_proxyPassReverse && REVERSE_PROXY_HEADERS.contains(headerName))
|
||||
{
|
||||
HttpURI locationURI = new HttpURI(headerValue);
|
||||
if (isAbsoluteLocation(locationURI) && isBackendLocation(locationURI))
|
||||
{
|
||||
Request jettyRequest = (Request)request;
|
||||
URI reverseUri;
|
||||
try
|
||||
{
|
||||
reverseUri = new URI(jettyRequest.getRootURL().append(locationURI.getCompletePath()).toString()).normalize();
|
||||
return reverseUri.toURL().toString();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_log.warn("Not filtering header response",e);
|
||||
return headerValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
return headerValue;
|
||||
}
|
||||
|
||||
private boolean isBackendLocation(HttpURI locationURI)
|
||||
{
|
||||
for (BalancerMember balancerMember : _balancerMembers)
|
||||
{
|
||||
HttpURI backendURI = balancerMember.getBackendURI();
|
||||
if (backendURI.getHost().equals(locationURI.getHost()) && backendURI.getScheme().equals(locationURI.getScheme())
|
||||
&& backendURI.getPort() == locationURI.getPort())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean isAbsoluteLocation(HttpURI locationURI)
|
||||
{
|
||||
return locationURI.getHost() != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getHostHeader()
|
||||
{
|
||||
throw new UnsupportedOperationException("HostHeader not supported in " + getClass().getName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setHostHeader(String hostHeader)
|
||||
{
|
||||
throw new UnsupportedOperationException("HostHeader not supported in " + getClass().getName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean validateDestination(String host, String path)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -1,902 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2012 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.proxy;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.Socket;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.Collections;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
import javax.servlet.Servlet;
|
||||
import javax.servlet.ServletConfig;
|
||||
import javax.servlet.ServletContext;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
import javax.servlet.UnavailableException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.eclipse.jetty.client.HttpClient;
|
||||
import org.eclipse.jetty.client.HttpExchange;
|
||||
import org.eclipse.jetty.continuation.Continuation;
|
||||
import org.eclipse.jetty.continuation.ContinuationSupport;
|
||||
import org.eclipse.jetty.http.HttpHeaderValue;
|
||||
import org.eclipse.jetty.http.HttpHeader;
|
||||
import org.eclipse.jetty.http.HttpScheme;
|
||||
import org.eclipse.jetty.http.HttpURI;
|
||||
import org.eclipse.jetty.http.HttpVersion;
|
||||
import org.eclipse.jetty.http.PathMap;
|
||||
import org.eclipse.jetty.io.EofException;
|
||||
import org.eclipse.jetty.util.HostMap;
|
||||
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.thread.QueuedThreadPool;
|
||||
|
||||
/**
|
||||
* Asynchronous Proxy Servlet.
|
||||
*
|
||||
* Forward requests to another server either as a standard web proxy (as defined by RFC2616) or as a transparent proxy.
|
||||
* <p>
|
||||
* This servlet needs the jetty-util and jetty-client classes to be available to the web application.
|
||||
* <p>
|
||||
* To facilitate JMX monitoring, the "HttpClient" and "ThreadPool" are set as context attributes prefixed with the servlet name.
|
||||
* <p>
|
||||
* The following init parameters may be used to configure the servlet:
|
||||
* <ul>
|
||||
* <li>name - Name of Proxy servlet (default: "ProxyServlet"
|
||||
* <li>maxThreads - maximum threads
|
||||
* <li>maxConnections - maximum connections per destination
|
||||
* <li>timeout - the period in ms the client will wait for a response from the proxied server
|
||||
* <li>idleTimeout - the period in ms a connection to proxied server can be idle for before it is closed
|
||||
* <li>requestHeaderSize - the size of the request header buffer (d. 6,144)
|
||||
* <li>requestBufferSize - the size of the request buffer (d. 12,288)
|
||||
* <li>responseHeaderSize - the size of the response header buffer (d. 6,144)
|
||||
* <li>responseBufferSize - the size of the response buffer (d. 32,768)
|
||||
* <li>HostHeader - Force the host header to a particular value
|
||||
* <li>whiteList - comma-separated list of allowed proxy destinations
|
||||
* <li>blackList - comma-separated list of forbidden proxy destinations
|
||||
* </ul>
|
||||
*
|
||||
* @see org.eclipse.jetty.server.handler.ConnectHandler
|
||||
*/
|
||||
public class ProxyServlet implements Servlet
|
||||
{
|
||||
protected Logger _log;
|
||||
protected HttpClient _client;
|
||||
protected String _hostHeader;
|
||||
|
||||
protected HashSet<String> _DontProxyHeaders = new HashSet<String>();
|
||||
{
|
||||
_DontProxyHeaders.add("proxy-connection");
|
||||
_DontProxyHeaders.add("connection");
|
||||
_DontProxyHeaders.add("keep-alive");
|
||||
_DontProxyHeaders.add("transfer-encoding");
|
||||
_DontProxyHeaders.add("te");
|
||||
_DontProxyHeaders.add("trailer");
|
||||
_DontProxyHeaders.add("proxy-authorization");
|
||||
_DontProxyHeaders.add("proxy-authenticate");
|
||||
_DontProxyHeaders.add("upgrade");
|
||||
}
|
||||
|
||||
protected ServletConfig _config;
|
||||
protected ServletContext _context;
|
||||
protected HostMap<PathMap> _white = new HostMap<PathMap>();
|
||||
protected HostMap<PathMap> _black = new HostMap<PathMap>();
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see javax.servlet.Servlet#init(javax.servlet.ServletConfig)
|
||||
*/
|
||||
public void init(ServletConfig config) throws ServletException
|
||||
{
|
||||
_config = config;
|
||||
_context = config.getServletContext();
|
||||
|
||||
_hostHeader = config.getInitParameter("HostHeader");
|
||||
|
||||
try
|
||||
{
|
||||
_log = createLogger(config);
|
||||
|
||||
_client = createHttpClient(config);
|
||||
|
||||
if (_context != null)
|
||||
{
|
||||
_context.setAttribute(config.getServletName() + ".ThreadPool",_client.getThreadPool());
|
||||
_context.setAttribute(config.getServletName() + ".HttpClient",_client);
|
||||
}
|
||||
|
||||
String white = config.getInitParameter("whiteList");
|
||||
if (white != null)
|
||||
{
|
||||
parseList(white,_white);
|
||||
}
|
||||
String black = config.getInitParameter("blackList");
|
||||
if (black != null)
|
||||
{
|
||||
parseList(black,_black);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new ServletException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public void destroy()
|
||||
{
|
||||
try
|
||||
{
|
||||
_client.stop();
|
||||
}
|
||||
catch (Exception x)
|
||||
{
|
||||
_log.debug(x);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create and return a logger based on the ServletConfig for use in the
|
||||
* proxy servlet
|
||||
*
|
||||
* @param config
|
||||
* @return Logger
|
||||
*/
|
||||
protected Logger createLogger(ServletConfig config)
|
||||
{
|
||||
return Log.getLogger("org.eclipse.jetty.servlets." + config.getServletName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Create and return an HttpClientInstance
|
||||
*
|
||||
* @return HttpClient
|
||||
*/
|
||||
protected HttpClient createHttpClientInstance()
|
||||
{
|
||||
return new HttpClient();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create and return an HttpClient based on ServletConfig
|
||||
*
|
||||
* By default this implementation will create an instance of the
|
||||
* HttpClient for use by this proxy servlet.
|
||||
*
|
||||
* @param config
|
||||
* @return HttpClient
|
||||
* @throws Exception
|
||||
*/
|
||||
protected HttpClient createHttpClient(ServletConfig config) throws Exception
|
||||
{
|
||||
HttpClient client = createHttpClientInstance();
|
||||
client.setConnectorType(HttpClient.CONNECTOR_SELECT_CHANNEL);
|
||||
|
||||
String t = config.getInitParameter("maxThreads");
|
||||
|
||||
if (t != null)
|
||||
{
|
||||
client.setThreadPool(new QueuedThreadPool(Integer.parseInt(t)));
|
||||
}
|
||||
else
|
||||
{
|
||||
client.setThreadPool(new QueuedThreadPool());
|
||||
}
|
||||
|
||||
((QueuedThreadPool)client.getThreadPool()).setName(config.getServletName());
|
||||
|
||||
t = config.getInitParameter("maxConnections");
|
||||
|
||||
if (t != null)
|
||||
{
|
||||
client.setMaxConnectionsPerAddress(Integer.parseInt(t));
|
||||
}
|
||||
|
||||
t = config.getInitParameter("timeout");
|
||||
|
||||
if ( t != null )
|
||||
{
|
||||
client.setTimeout(Long.parseLong(t));
|
||||
}
|
||||
|
||||
t = config.getInitParameter("idleTimeout");
|
||||
|
||||
if ( t != null )
|
||||
{
|
||||
client.setIdleTimeout(Long.parseLong(t));
|
||||
}
|
||||
|
||||
t = config.getInitParameter("requestHeaderSize");
|
||||
|
||||
if ( t != null )
|
||||
{
|
||||
client.setRequestHeaderSize(Integer.parseInt(t));
|
||||
}
|
||||
|
||||
t = config.getInitParameter("requestBufferSize");
|
||||
|
||||
if ( t != null )
|
||||
{
|
||||
client.setRequestBufferSize(Integer.parseInt(t));
|
||||
}
|
||||
|
||||
t = config.getInitParameter("responseHeaderSize");
|
||||
|
||||
if ( t != null )
|
||||
{
|
||||
client.setResponseHeaderSize(Integer.parseInt(t));
|
||||
}
|
||||
|
||||
t = config.getInitParameter("responseBufferSize");
|
||||
|
||||
if ( t != null )
|
||||
{
|
||||
client.setResponseBufferSize(Integer.parseInt(t));
|
||||
}
|
||||
|
||||
client.start();
|
||||
|
||||
return client;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Helper function to process a parameter value containing a list of new entries and initialize the specified host map.
|
||||
*
|
||||
* @param list
|
||||
* comma-separated list of new entries
|
||||
* @param hostMap
|
||||
* target host map
|
||||
*/
|
||||
private void parseList(String list, HostMap<PathMap> hostMap)
|
||||
{
|
||||
if (list != null && list.length() > 0)
|
||||
{
|
||||
int idx;
|
||||
String entry;
|
||||
|
||||
StringTokenizer entries = new StringTokenizer(list,",");
|
||||
while (entries.hasMoreTokens())
|
||||
{
|
||||
entry = entries.nextToken();
|
||||
idx = entry.indexOf('/');
|
||||
|
||||
String host = idx > 0?entry.substring(0,idx):entry;
|
||||
String path = idx > 0?entry.substring(idx):"/*";
|
||||
|
||||
host = host.trim();
|
||||
PathMap pathMap = hostMap.get(host);
|
||||
if (pathMap == null)
|
||||
{
|
||||
pathMap = new PathMap(true);
|
||||
hostMap.put(host,pathMap);
|
||||
}
|
||||
if (path != null)
|
||||
{
|
||||
pathMap.put(path,path);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Check the request hostname and path against white- and blacklist.
|
||||
*
|
||||
* @param host
|
||||
* hostname to check
|
||||
* @param path
|
||||
* path to check
|
||||
* @return true if request is allowed to be proxied
|
||||
*/
|
||||
public boolean validateDestination(String host, String path)
|
||||
{
|
||||
if (_white.size() > 0)
|
||||
{
|
||||
boolean match = false;
|
||||
|
||||
Object whiteObj = _white.getLazyMatches(host);
|
||||
if (whiteObj != null)
|
||||
{
|
||||
List whiteList = (whiteObj instanceof List)?(List)whiteObj:Collections.singletonList(whiteObj);
|
||||
|
||||
for (Object entry : whiteList)
|
||||
{
|
||||
PathMap pathMap = ((Map.Entry<String, PathMap>)entry).getValue();
|
||||
if (match = (pathMap != null && (pathMap.size() == 0 || pathMap.match(path) != null)))
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!match)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (_black.size() > 0)
|
||||
{
|
||||
Object blackObj = _black.getLazyMatches(host);
|
||||
if (blackObj != null)
|
||||
{
|
||||
List blackList = (blackObj instanceof List)?(List)blackObj:Collections.singletonList(blackObj);
|
||||
|
||||
for (Object entry : blackList)
|
||||
{
|
||||
PathMap pathMap = ((Map.Entry<String, PathMap>)entry).getValue();
|
||||
if (pathMap != null && (pathMap.size() == 0 || pathMap.match(path) != null))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see javax.servlet.Servlet#getServletConfig()
|
||||
*/
|
||||
public ServletConfig getServletConfig()
|
||||
{
|
||||
return _config;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Get the hostHeader.
|
||||
*
|
||||
* @return the hostHeader
|
||||
*/
|
||||
public String getHostHeader()
|
||||
{
|
||||
return _hostHeader;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Set the hostHeader.
|
||||
*
|
||||
* @param hostHeader
|
||||
* the hostHeader to set
|
||||
*/
|
||||
public void setHostHeader(String hostHeader)
|
||||
{
|
||||
_hostHeader = hostHeader;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see javax.servlet.Servlet#service(javax.servlet.ServletRequest, javax.servlet.ServletResponse)
|
||||
*/
|
||||
public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException
|
||||
{
|
||||
final int debug = _log.isDebugEnabled()?req.hashCode():0;
|
||||
|
||||
final HttpServletRequest request = (HttpServletRequest)req;
|
||||
final HttpServletResponse response = (HttpServletResponse)res;
|
||||
|
||||
if ("CONNECT".equalsIgnoreCase(request.getMethod()))
|
||||
{
|
||||
handleConnect(request,response);
|
||||
}
|
||||
else
|
||||
{
|
||||
final InputStream in = request.getInputStream();
|
||||
final OutputStream out = response.getOutputStream();
|
||||
|
||||
final Continuation continuation = ContinuationSupport.getContinuation(request);
|
||||
|
||||
if (!continuation.isInitial())
|
||||
response.sendError(HttpServletResponse.SC_GATEWAY_TIMEOUT); // Need better test that isInitial
|
||||
else
|
||||
{
|
||||
|
||||
String uri = request.getRequestURI();
|
||||
if (request.getQueryString() != null)
|
||||
uri += "?" + request.getQueryString();
|
||||
|
||||
HttpURI url = proxyHttpURI(request,uri);
|
||||
|
||||
if (debug != 0)
|
||||
_log.debug(debug + " proxy " + uri + "-->" + url);
|
||||
|
||||
if (url == null)
|
||||
{
|
||||
response.sendError(HttpServletResponse.SC_FORBIDDEN);
|
||||
return;
|
||||
}
|
||||
|
||||
HttpExchange exchange = new HttpExchange()
|
||||
{
|
||||
@Override
|
||||
protected void onRequestCommitted() throws IOException
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onRequestComplete() throws IOException
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResponseComplete() throws IOException
|
||||
{
|
||||
if (debug != 0)
|
||||
_log.debug(debug + " complete");
|
||||
continuation.complete();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResponseContent(Buffer content) throws IOException
|
||||
{
|
||||
if (debug != 0)
|
||||
_log.debug(debug + " content" + content.length());
|
||||
content.writeTo(out);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResponseHeaderComplete() throws IOException
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResponseStatus(Buffer version, int status, Buffer reason) throws IOException
|
||||
{
|
||||
if (debug != 0)
|
||||
_log.debug(debug + " " + version + " " + status + " " + reason);
|
||||
|
||||
if (reason != null && reason.length() > 0)
|
||||
response.setStatus(status,reason.toString());
|
||||
else
|
||||
response.setStatus(status);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResponseHeader(Buffer name, Buffer value) throws IOException
|
||||
{
|
||||
String nameString = name.toString();
|
||||
String s = nameString.toLowerCase(Locale.ENGLISH);
|
||||
if (!_DontProxyHeaders.contains(s) || (HttpHeader.CONNECTION.is(name) && HttpHeaderValue.CLOSE.is(value)))
|
||||
{
|
||||
if (debug != 0)
|
||||
_log.debug(debug + " " + name + ": " + value);
|
||||
|
||||
String filteredHeaderValue = filterResponseHeaderValue(nameString,value.toString(),request);
|
||||
if (filteredHeaderValue != null && filteredHeaderValue.trim().length() > 0)
|
||||
{
|
||||
if (debug != 0)
|
||||
_log.debug(debug + " " + name + ": (filtered): " + filteredHeaderValue);
|
||||
response.addHeader(nameString,filteredHeaderValue);
|
||||
}
|
||||
}
|
||||
else if (debug != 0)
|
||||
_log.debug(debug + " " + name + "! " + value);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onConnectionFailed(Throwable ex)
|
||||
{
|
||||
handleOnConnectionFailed(ex,request,response);
|
||||
|
||||
// it is possible this might trigger before the
|
||||
// continuation.suspend()
|
||||
if (!continuation.isInitial())
|
||||
{
|
||||
continuation.complete();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onException(Throwable ex)
|
||||
{
|
||||
if (ex instanceof EofException)
|
||||
{
|
||||
_log.ignore(ex);
|
||||
return;
|
||||
}
|
||||
handleOnException(ex,request,response);
|
||||
|
||||
// it is possible this might trigger before the
|
||||
// continuation.suspend()
|
||||
if (!continuation.isInitial())
|
||||
{
|
||||
continuation.complete();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onExpire()
|
||||
{
|
||||
handleOnExpire(request,response);
|
||||
continuation.complete();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
exchange.setScheme((HttpScheme.HTTPS.is(request.getScheme())?HttpScheme.HTTPS:HttpScheme.HTTP).asString());
|
||||
exchange.setMethod(request.getMethod());
|
||||
exchange.setURL(url.toString());
|
||||
exchange.setVersion(HttpVersion.CACHE.get(request.getProtocol()));
|
||||
|
||||
|
||||
if (debug != 0)
|
||||
_log.debug(debug + " " + request.getMethod() + " " + url + " " + request.getProtocol());
|
||||
|
||||
// check connection header
|
||||
String connectionHdr = request.getHeader("Connection");
|
||||
if (connectionHdr != null)
|
||||
{
|
||||
connectionHdr = connectionHdr.toLowerCase(Locale.ENGLISH);
|
||||
if (connectionHdr.indexOf("keep-alive") < 0 && connectionHdr.indexOf("close") < 0)
|
||||
connectionHdr = null;
|
||||
}
|
||||
|
||||
// force host
|
||||
if (_hostHeader != null)
|
||||
exchange.setRequestHeader("Host",_hostHeader);
|
||||
|
||||
// copy headers
|
||||
boolean xForwardedFor = false;
|
||||
boolean hasContent = false;
|
||||
long contentLength = -1;
|
||||
Enumeration<?> enm = request.getHeaderNames();
|
||||
while (enm.hasMoreElements())
|
||||
{
|
||||
// TODO could be better than this!
|
||||
String hdr = (String)enm.nextElement();
|
||||
String lhdr = hdr.toLowerCase(Locale.ENGLISH);
|
||||
|
||||
if (_DontProxyHeaders.contains(lhdr))
|
||||
continue;
|
||||
if (connectionHdr != null && connectionHdr.indexOf(lhdr) >= 0)
|
||||
continue;
|
||||
if (_hostHeader != null && "host".equals(lhdr))
|
||||
continue;
|
||||
|
||||
if ("content-type".equals(lhdr))
|
||||
hasContent = true;
|
||||
else if ("content-length".equals(lhdr))
|
||||
{
|
||||
contentLength = request.getContentLength();
|
||||
exchange.setRequestHeader(HttpHeader.CONTENT_LENGTH.asString(),Long.toString(contentLength));
|
||||
if (contentLength > 0)
|
||||
hasContent = true;
|
||||
}
|
||||
else if ("x-forwarded-for".equals(lhdr))
|
||||
xForwardedFor = true;
|
||||
|
||||
Enumeration<?> vals = request.getHeaders(hdr);
|
||||
while (vals.hasMoreElements())
|
||||
{
|
||||
String val = (String)vals.nextElement();
|
||||
if (val != null)
|
||||
{
|
||||
if (debug != 0)
|
||||
_log.debug(debug + " " + hdr + ": " + val);
|
||||
|
||||
exchange.setRequestHeader(hdr,val);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Proxy headers
|
||||
exchange.setRequestHeader("Via","1.1 (jetty)");
|
||||
if (!xForwardedFor)
|
||||
{
|
||||
exchange.addRequestHeader("X-Forwarded-For",request.getRemoteAddr());
|
||||
exchange.addRequestHeader("X-Forwarded-Proto",request.getScheme());
|
||||
exchange.addRequestHeader("X-Forwarded-Host",request.getHeader("Host"));
|
||||
exchange.addRequestHeader("X-Forwarded-Server",request.getLocalName());
|
||||
}
|
||||
|
||||
if (hasContent)
|
||||
{
|
||||
exchange.setRequestContentSource(in);
|
||||
}
|
||||
|
||||
customizeExchange(exchange, request);
|
||||
|
||||
/*
|
||||
* we need to set the timeout on the continuation to take into
|
||||
* account the timeout of the HttpClient and the HttpExchange
|
||||
*/
|
||||
long ctimeout = (_client.getTimeout() > exchange.getTimeout()) ? _client.getTimeout() : exchange.getTimeout();
|
||||
|
||||
// continuation fudge factor of 1000, underlying components
|
||||
// should fail/expire first from exchange
|
||||
if ( ctimeout == 0 )
|
||||
{
|
||||
continuation.setTimeout(0); // ideally never times out
|
||||
}
|
||||
else
|
||||
{
|
||||
continuation.setTimeout(ctimeout + 1000);
|
||||
}
|
||||
|
||||
customizeContinuation(continuation);
|
||||
|
||||
continuation.suspend(response);
|
||||
_client.send(exchange);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public void handleConnect(HttpServletRequest request, HttpServletResponse response) throws IOException
|
||||
{
|
||||
String uri = request.getRequestURI();
|
||||
|
||||
String port = "";
|
||||
String host = "";
|
||||
|
||||
int c = uri.indexOf(':');
|
||||
if (c >= 0)
|
||||
{
|
||||
port = uri.substring(c + 1);
|
||||
host = uri.substring(0,c);
|
||||
if (host.indexOf('/') > 0)
|
||||
host = host.substring(host.indexOf('/') + 1);
|
||||
}
|
||||
|
||||
// TODO - make this async!
|
||||
|
||||
InetSocketAddress inetAddress = new InetSocketAddress(host,Integer.parseInt(port));
|
||||
|
||||
// if (isForbidden(HttpMessage.__SSL_SCHEME,addrPort.getHost(),addrPort.getPort(),false))
|
||||
// {
|
||||
// sendForbid(request,response,uri);
|
||||
// }
|
||||
// else
|
||||
{
|
||||
InputStream in = request.getInputStream();
|
||||
OutputStream out = response.getOutputStream();
|
||||
|
||||
Socket socket = new Socket(inetAddress.getAddress(),inetAddress.getPort());
|
||||
|
||||
response.setStatus(200);
|
||||
response.setHeader("Connection","close");
|
||||
response.flushBuffer();
|
||||
// TODO prevent real close!
|
||||
|
||||
IO.copyThread(socket.getInputStream(),out);
|
||||
IO.copy(in,socket.getOutputStream());
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
protected HttpURI proxyHttpURI(HttpServletRequest request, String uri) throws MalformedURLException
|
||||
{
|
||||
return proxyHttpURI(request.getScheme(), request.getServerName(), request.getServerPort(), uri);
|
||||
}
|
||||
|
||||
protected HttpURI proxyHttpURI(String scheme, String serverName, int serverPort, String uri) throws MalformedURLException
|
||||
{
|
||||
if (!validateDestination(serverName,uri))
|
||||
return null;
|
||||
|
||||
return new HttpURI(scheme + "://" + serverName + ":" + serverPort + uri);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see javax.servlet.Servlet#getServletInfo()
|
||||
*/
|
||||
public String getServletInfo()
|
||||
{
|
||||
return "Proxy Servlet";
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Extension point for subclasses to customize an exchange. Useful for setting timeouts etc. The default implementation does nothing.
|
||||
*
|
||||
* @param exchange
|
||||
* @param request
|
||||
*/
|
||||
protected void customizeExchange(HttpExchange exchange, HttpServletRequest request)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Extension point for subclasses to customize the Continuation after it's initial creation in the service method. Useful for setting timeouts etc. The
|
||||
* default implementation does nothing.
|
||||
*
|
||||
* @param continuation
|
||||
*/
|
||||
protected void customizeContinuation(Continuation continuation)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Extension point for custom handling of an HttpExchange's onConnectionFailed method. The default implementation delegates to
|
||||
* {@link #handleOnException(Throwable, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)}
|
||||
*
|
||||
* @param ex
|
||||
* @param request
|
||||
* @param response
|
||||
*/
|
||||
protected void handleOnConnectionFailed(Throwable ex, HttpServletRequest request, HttpServletResponse response)
|
||||
{
|
||||
handleOnException(ex,request,response);
|
||||
}
|
||||
|
||||
/**
|
||||
* Extension point for custom handling of an HttpExchange's onException method. The default implementation sets the response status to
|
||||
* HttpServletResponse.SC_INTERNAL_SERVER_ERROR (503)
|
||||
*
|
||||
* @param ex
|
||||
* @param request
|
||||
* @param response
|
||||
*/
|
||||
protected void handleOnException(Throwable ex, HttpServletRequest request, HttpServletResponse response)
|
||||
{
|
||||
if (ex instanceof IOException)
|
||||
{
|
||||
_log.warn(ex.toString());
|
||||
_log.debug(ex);
|
||||
}
|
||||
else
|
||||
_log.warn(ex);
|
||||
|
||||
if (!response.isCommitted())
|
||||
{
|
||||
response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Extension point for custom handling of an HttpExchange's onExpire method. The default implementation sets the response status to
|
||||
* HttpServletResponse.SC_GATEWAY_TIMEOUT (504)
|
||||
*
|
||||
* @param request
|
||||
* @param response
|
||||
*/
|
||||
protected void handleOnExpire(HttpServletRequest request, HttpServletResponse response)
|
||||
{
|
||||
if (!response.isCommitted())
|
||||
{
|
||||
response.setStatus(HttpServletResponse.SC_GATEWAY_TIMEOUT);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Extension point for remote server response header filtering. The default implementation returns the header value as is. If null is returned, this header
|
||||
* won't be forwarded back to the client.
|
||||
*
|
||||
* @param headerName
|
||||
* @param headerValue
|
||||
* @param request
|
||||
* @return filteredHeaderValue
|
||||
*/
|
||||
protected String filterResponseHeaderValue(String headerName, String headerValue, HttpServletRequest request)
|
||||
{
|
||||
return headerValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Transparent Proxy.
|
||||
*
|
||||
* This convenience extension to ProxyServlet configures the servlet as a transparent proxy. The servlet is configured with init parameters:
|
||||
* <ul>
|
||||
* <li>ProxyTo - a URI like http://host:80/context to which the request is proxied.
|
||||
* <li>Prefix - a URI prefix that is striped from the start of the forwarded URI.
|
||||
* </ul>
|
||||
* For example, if a request was received at /foo/bar and the ProxyTo was http://host:80/context and the Prefix was /foo, then the request would be proxied
|
||||
* to http://host:80/context/bar
|
||||
*
|
||||
*/
|
||||
public static class Transparent extends ProxyServlet
|
||||
{
|
||||
String _prefix;
|
||||
String _proxyTo;
|
||||
|
||||
public Transparent()
|
||||
{
|
||||
}
|
||||
|
||||
public Transparent(String prefix, String host, int port)
|
||||
{
|
||||
this(prefix,"http",host,port,null);
|
||||
}
|
||||
|
||||
public Transparent(String prefix, String schema, String host, int port, String path)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (prefix != null)
|
||||
{
|
||||
_prefix = new URI(prefix).normalize().toString();
|
||||
}
|
||||
_proxyTo = new URI(schema,null,host,port,path,null,null).normalize().toString();
|
||||
}
|
||||
catch (URISyntaxException ex)
|
||||
{
|
||||
_log.debug("Invalid URI syntax",ex);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(ServletConfig config) throws ServletException
|
||||
{
|
||||
super.init(config);
|
||||
|
||||
String prefix = config.getInitParameter("Prefix");
|
||||
_prefix = prefix == null?_prefix:prefix;
|
||||
|
||||
// Adjust prefix value to account for context path
|
||||
String contextPath = _context.getContextPath();
|
||||
_prefix = _prefix == null?contextPath:(contextPath + _prefix);
|
||||
|
||||
String proxyTo = config.getInitParameter("ProxyTo");
|
||||
_proxyTo = proxyTo == null?_proxyTo:proxyTo;
|
||||
|
||||
if (_proxyTo == null)
|
||||
throw new UnavailableException("ProxyTo parameter is requred.");
|
||||
|
||||
if (!_prefix.startsWith("/"))
|
||||
throw new UnavailableException("Prefix parameter must start with a '/'.");
|
||||
|
||||
_log.info(config.getServletName() + " @ " + _prefix + " to " + _proxyTo);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected HttpURI proxyHttpURI(final String scheme, final String serverName, int serverPort, final String uri) throws MalformedURLException
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!uri.startsWith(_prefix))
|
||||
return null;
|
||||
|
||||
URI dstUri = new URI(_proxyTo + uri.substring(_prefix.length())).normalize();
|
||||
|
||||
if (!validateDestination(dstUri.getHost(),dstUri.getPath()))
|
||||
return null;
|
||||
|
||||
return new HttpURI(dstUri.toString());
|
||||
}
|
||||
catch (URISyntaxException ex)
|
||||
{
|
||||
throw new MalformedURLException(ex.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,164 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2012 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.servlets;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.servlet.http.HttpServlet;
|
||||
|
||||
import org.eclipse.jetty.client.ContentExchange;
|
||||
import org.eclipse.jetty.client.HttpClient;
|
||||
import org.eclipse.jetty.http.HttpCookie;
|
||||
import org.eclipse.jetty.http.HttpMethods;
|
||||
import org.eclipse.jetty.io.Buffer;
|
||||
import org.eclipse.jetty.proxy.BalancerServlet;
|
||||
import org.eclipse.jetty.server.Connector;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.server.SelectChannelConnector;
|
||||
import org.eclipse.jetty.server.session.HashSessionIdManager;
|
||||
import org.eclipse.jetty.servlet.ServletContextHandler;
|
||||
import org.eclipse.jetty.servlet.ServletHolder;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
|
||||
|
||||
public abstract class AbstractBalancerServletTest
|
||||
{
|
||||
|
||||
private boolean _stickySessions;
|
||||
|
||||
private Server _node1;
|
||||
|
||||
private Server _node2;
|
||||
|
||||
private Server _balancerServer;
|
||||
|
||||
private HttpClient _httpClient;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception
|
||||
{
|
||||
_httpClient = new HttpClient();
|
||||
_httpClient.registerListener("org.eclipse.jetty.client.RedirectListener");
|
||||
_httpClient.start();
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() throws Exception
|
||||
{
|
||||
stopServer(_node1);
|
||||
stopServer(_node2);
|
||||
stopServer(_balancerServer);
|
||||
_httpClient.stop();
|
||||
}
|
||||
|
||||
private void stopServer(Server server)
|
||||
{
|
||||
try
|
||||
{
|
||||
server.stop();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
// Do nothing
|
||||
}
|
||||
}
|
||||
|
||||
protected void setStickySessions(boolean stickySessions)
|
||||
{
|
||||
_stickySessions = stickySessions;
|
||||
}
|
||||
|
||||
protected void startBalancer(Class<? extends HttpServlet> httpServletClass) throws Exception
|
||||
{
|
||||
_node1 = createServer(new ServletHolder(httpServletClass.newInstance()),"/pipo","/molo/*");
|
||||
setSessionIdManager(_node1,"node1");
|
||||
_node1.start();
|
||||
|
||||
_node2 = createServer(new ServletHolder(httpServletClass.newInstance()),"/pipo","/molo/*");
|
||||
setSessionIdManager(_node2,"node2");
|
||||
_node2.start();
|
||||
|
||||
BalancerServlet balancerServlet = new BalancerServlet();
|
||||
ServletHolder balancerServletHolder = new ServletHolder(balancerServlet);
|
||||
balancerServletHolder.setInitParameter("StickySessions",String.valueOf(_stickySessions));
|
||||
balancerServletHolder.setInitParameter("ProxyPassReverse","true");
|
||||
balancerServletHolder.setInitParameter("BalancerMember." + "node1" + ".ProxyTo","http://localhost:" + getServerPort(_node1));
|
||||
balancerServletHolder.setInitParameter("BalancerMember." + "node2" + ".ProxyTo","http://localhost:" + getServerPort(_node2));
|
||||
|
||||
_balancerServer = createServer(balancerServletHolder,"/pipo","/molo/*");
|
||||
_balancerServer.start();
|
||||
}
|
||||
|
||||
private Server createServer(ServletHolder servletHolder, String appContext, String servletUrlPattern)
|
||||
{
|
||||
Server server = new Server();
|
||||
SelectChannelConnector httpConnector = new SelectChannelConnector(server);
|
||||
server.addConnector(httpConnector);
|
||||
|
||||
ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS);
|
||||
context.setContextPath(appContext);
|
||||
server.setHandler(context);
|
||||
|
||||
context.addServlet(servletHolder,servletUrlPattern);
|
||||
|
||||
return server;
|
||||
}
|
||||
|
||||
private void setSessionIdManager(Server node, String nodeName)
|
||||
{
|
||||
HashSessionIdManager sessionIdManager = new HashSessionIdManager();
|
||||
sessionIdManager.setWorkerName(nodeName);
|
||||
node.setSessionIdManager(sessionIdManager);
|
||||
}
|
||||
|
||||
private int getServerPort(Server server)
|
||||
{
|
||||
return ((Connector.NetConnector)server.getConnectors()[0]).getLocalPort();
|
||||
}
|
||||
|
||||
protected byte[] sendRequestToBalancer(String requestUri) throws IOException, InterruptedException
|
||||
{
|
||||
ContentExchange exchange = new ContentExchange()
|
||||
{
|
||||
@Override
|
||||
protected void onResponseHeader(Buffer name, Buffer value) throws IOException
|
||||
{
|
||||
// Cookie persistence
|
||||
if (name.toString().equals("Set-Cookie"))
|
||||
{
|
||||
String cookieVal = value.toString();
|
||||
if (cookieVal.startsWith("JSESSIONID="))
|
||||
{
|
||||
String jsessionid = cookieVal.split(";")[0].substring("JSESSIONID=".length());
|
||||
_httpClient.getDestination(getAddress(),false).addCookie(new HttpCookie("JSESSIONID",jsessionid));
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
exchange.setURL("http://localhost:" + getServerPort(_balancerServer) + "/pipo/molo/" + requestUri);
|
||||
exchange.setMethod(HttpMethods.GET);
|
||||
|
||||
_httpClient.send(exchange);
|
||||
exchange.waitForDone();
|
||||
|
||||
return exchange.getResponseContentBytes();
|
||||
}
|
||||
|
||||
}
|
|
@ -1,218 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2012 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.server.handler;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.EOFException;
|
||||
import java.io.IOException;
|
||||
import java.net.Socket;
|
||||
import java.net.SocketTimeoutException;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.eclipse.jetty.proxy.ConnectHandler;
|
||||
import org.eclipse.jetty.server.Connector;
|
||||
import org.eclipse.jetty.server.Handler;
|
||||
import org.eclipse.jetty.server.SelectChannelConnector;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.junit.AfterClass;
|
||||
|
||||
/**
|
||||
* @version $Revision$ $Date$
|
||||
*/
|
||||
public abstract class AbstractConnectHandlerTest
|
||||
{
|
||||
protected static Server server;
|
||||
protected static Connector.NetConnector serverConnector;
|
||||
protected static Server proxy;
|
||||
protected static Connector proxyConnector;
|
||||
|
||||
protected static void startServer(Connector.NetConnector connector, Handler handler) throws Exception
|
||||
{
|
||||
server = new Server();
|
||||
serverConnector = connector;
|
||||
server.addConnector(serverConnector);
|
||||
server.setHandler(handler);
|
||||
server.start();
|
||||
}
|
||||
|
||||
protected static void startProxy() throws Exception
|
||||
{
|
||||
proxy = new Server();
|
||||
proxyConnector = new SelectChannelConnector();
|
||||
proxy.addConnector(proxyConnector);
|
||||
proxy.setHandler(new ConnectHandler());
|
||||
proxy.start();
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void stop() throws Exception
|
||||
{
|
||||
stopProxy();
|
||||
stopServer();
|
||||
}
|
||||
|
||||
protected static void stopServer() throws Exception
|
||||
{
|
||||
server.stop();
|
||||
server.join();
|
||||
}
|
||||
|
||||
protected static void stopProxy() throws Exception
|
||||
{
|
||||
proxy.stop();
|
||||
proxy.join();
|
||||
}
|
||||
|
||||
protected Response readResponse(BufferedReader reader) throws IOException
|
||||
{
|
||||
// Simplified parser for HTTP responses
|
||||
String line = reader.readLine();
|
||||
if (line == null)
|
||||
throw new EOFException();
|
||||
Matcher responseLine = Pattern.compile("HTTP/1\\.1\\s+(\\d+)").matcher(line);
|
||||
assertTrue(responseLine.lookingAt());
|
||||
String code = responseLine.group(1);
|
||||
|
||||
Map<String, String> headers = new LinkedHashMap<String, String>();
|
||||
while ((line = reader.readLine()) != null)
|
||||
{
|
||||
if (line.trim().length() == 0)
|
||||
break;
|
||||
|
||||
Matcher header = Pattern.compile("([^:]+):\\s*(.*)").matcher(line);
|
||||
assertTrue(header.lookingAt());
|
||||
String headerName = header.group(1);
|
||||
String headerValue = header.group(2);
|
||||
headers.put(headerName.toLowerCase(Locale.ENGLISH), headerValue.toLowerCase(Locale.ENGLISH));
|
||||
}
|
||||
|
||||
StringBuilder body;
|
||||
if (headers.containsKey("content-length"))
|
||||
{
|
||||
int readLen = 0;
|
||||
int length = Integer.parseInt(headers.get("content-length"));
|
||||
body=new StringBuilder(length);
|
||||
try
|
||||
{
|
||||
for (int i = 0; i < length; ++i)
|
||||
{
|
||||
char c = (char)reader.read();
|
||||
body.append(c);
|
||||
readLen++;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
catch (SocketTimeoutException e)
|
||||
{
|
||||
System.err.printf("Read %,d bytes (out of an expected %,d bytes)%n",readLen,length);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
else if ("chunked".equals(headers.get("transfer-encoding")))
|
||||
{
|
||||
body = new StringBuilder(64*1024);
|
||||
while ((line = reader.readLine()) != null)
|
||||
{
|
||||
if ("0".equals(line))
|
||||
{
|
||||
line = reader.readLine();
|
||||
assertEquals("", line);
|
||||
break;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
Thread.sleep(5);
|
||||
}
|
||||
catch (InterruptedException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
int length = Integer.parseInt(line, 16);
|
||||
for (int i = 0; i < length; ++i)
|
||||
{
|
||||
char c = (char)reader.read();
|
||||
body.append(c);
|
||||
}
|
||||
line = reader.readLine();
|
||||
assertEquals("", line);
|
||||
}
|
||||
}
|
||||
else throw new IllegalStateException();
|
||||
|
||||
return new Response(code, headers, body.toString().trim());
|
||||
}
|
||||
|
||||
protected Socket newSocket() throws IOException
|
||||
{
|
||||
Socket socket = new Socket("localhost", ((Connector.NetConnector)proxyConnector).getLocalPort());
|
||||
socket.setSoTimeout(10000);
|
||||
return socket;
|
||||
}
|
||||
|
||||
protected class Response
|
||||
{
|
||||
private final String code;
|
||||
private final Map<String, String> headers;
|
||||
private final String body;
|
||||
|
||||
private Response(String code, Map<String, String> headers, String body)
|
||||
{
|
||||
this.code = code;
|
||||
this.headers = headers;
|
||||
this.body = body;
|
||||
}
|
||||
|
||||
public String getCode()
|
||||
{
|
||||
return code;
|
||||
}
|
||||
|
||||
public Map<String, String> getHeaders()
|
||||
{
|
||||
return headers;
|
||||
}
|
||||
|
||||
public String getBody()
|
||||
{
|
||||
return body;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
StringBuilder builder = new StringBuilder();
|
||||
builder.append(code).append("\r\n");
|
||||
for (Map.Entry<String, String> entry : headers.entrySet())
|
||||
builder.append(entry.getKey()).append(": ").append(entry.getValue()).append("\r\n");
|
||||
builder.append("\r\n");
|
||||
builder.append(body);
|
||||
return builder.toString();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,53 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2012 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.proxy;
|
||||
|
||||
import java.util.EnumSet;
|
||||
|
||||
import javax.servlet.DispatcherType;
|
||||
|
||||
import org.eclipse.jetty.server.Connector;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.server.nio.SelectChannelConnector;
|
||||
import org.eclipse.jetty.servlet.ServletHandler;
|
||||
import org.eclipse.jetty.servlet.ServletHolder;
|
||||
|
||||
public class AsyncProxyServer
|
||||
{
|
||||
public static void main(String[] args)
|
||||
throws Exception
|
||||
{
|
||||
Server server = new Server();
|
||||
Connector connector=new SelectChannelConnector();
|
||||
connector.setPort(8888);
|
||||
server.setConnectors(new Connector[]{connector});
|
||||
|
||||
ServletHandler handler=new ServletHandler();
|
||||
server.setHandler(handler);
|
||||
|
||||
//FilterHolder gzip = handler.addFilterWithMapping("org.eclipse.jetty.servlet.GzipFilter","/*",EnumSet.of(DispatcherType.REQUEST,DispatcherType.ASYNC));
|
||||
//gzip.setAsyncSupported(true);
|
||||
//gzip.setInitParameter("minGzipSize","256");
|
||||
ServletHolder proxy = handler.addServletWithMapping("org.eclipse.jetty.servlets.ProxyServlet","/");
|
||||
proxy.setAsyncSupported(true);
|
||||
|
||||
server.start();
|
||||
server.join();
|
||||
}
|
||||
}
|
|
@ -1,135 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2012 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.servlets;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServlet;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public class BalancerServletTest extends AbstractBalancerServletTest
|
||||
{
|
||||
|
||||
@Test
|
||||
public void testRoundRobinBalancer() throws Exception
|
||||
{
|
||||
setStickySessions(false);
|
||||
startBalancer(CounterServlet.class);
|
||||
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
byte[] responseBytes = sendRequestToBalancer("/");
|
||||
String returnedCounter = readFirstLine(responseBytes);
|
||||
// RR : response should increment every other request
|
||||
String expectedCounter = String.valueOf(i / 2);
|
||||
assertEquals(expectedCounter,returnedCounter);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStickySessionsBalancer() throws Exception
|
||||
{
|
||||
setStickySessions(true);
|
||||
startBalancer(CounterServlet.class);
|
||||
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
byte[] responseBytes = sendRequestToBalancer("/");
|
||||
String returnedCounter = readFirstLine(responseBytes);
|
||||
// RR : response should increment on each request
|
||||
String expectedCounter = String.valueOf(i);
|
||||
assertEquals(expectedCounter,returnedCounter);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testProxyPassReverse() throws Exception
|
||||
{
|
||||
setStickySessions(false);
|
||||
startBalancer(RelocationServlet.class);
|
||||
|
||||
byte[] responseBytes = sendRequestToBalancer("index.html");
|
||||
String msg = readFirstLine(responseBytes);
|
||||
assertEquals("success",msg);
|
||||
}
|
||||
|
||||
private String readFirstLine(byte[] responseBytes) throws IOException
|
||||
{
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(new ByteArrayInputStream(responseBytes)));
|
||||
return reader.readLine();
|
||||
}
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
public static final class CounterServlet extends HttpServlet
|
||||
{
|
||||
|
||||
private int counter;
|
||||
|
||||
@Override
|
||||
public void init() throws ServletException
|
||||
{
|
||||
counter = 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
|
||||
{
|
||||
// Force session creation
|
||||
req.getSession();
|
||||
resp.setContentType("text/plain");
|
||||
resp.getWriter().println(counter++);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
public static final class RelocationServlet extends HttpServlet
|
||||
{
|
||||
@Override
|
||||
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
|
||||
{
|
||||
if (req.getRequestURI().endsWith("/index.html"))
|
||||
{
|
||||
resp.sendRedirect("http://localhost:" + req.getLocalPort() + req.getContextPath() + req.getServletPath() + "/other.html?secret=pipo%20molo");
|
||||
return;
|
||||
}
|
||||
resp.setContentType("text/plain");
|
||||
if ("pipo molo".equals(req.getParameter("secret")))
|
||||
{
|
||||
resp.getWriter().println("success");
|
||||
}
|
||||
else
|
||||
{
|
||||
resp.getWriter().println("failure");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,77 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2012 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.proxy;
|
||||
|
||||
import static org.mockito.Mockito.when;
|
||||
import static org.mockito.Matchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.hamcrest.Matchers.*;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.eclipse.jetty.io.EndPoint;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.invocation.InvocationOnMock;
|
||||
import org.mockito.runners.MockitoJUnitRunner;
|
||||
import org.mockito.stubbing.Answer;
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
*/
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class ConnectHandlerUnitTest
|
||||
{
|
||||
@Mock
|
||||
private EndPoint endPoint;
|
||||
|
||||
// TODO update for jetty-9
|
||||
@Test
|
||||
@Ignore
|
||||
public void testPartialWritesWithNonFullBuffer() throws IOException
|
||||
{
|
||||
/*
|
||||
ConnectHandler connectHandler = new ConnectHandler();
|
||||
final byte[] bytes = "foo bar".getBytes();
|
||||
Buffer buffer = new ByteArrayBuffer(bytes.length * 2);
|
||||
buffer.put(bytes);
|
||||
when(endPoint.flush(buffer)).thenAnswer(new Answer<Object>()
|
||||
{
|
||||
public Object answer(InvocationOnMock invocation)
|
||||
{
|
||||
Object[] args = invocation.getArguments();
|
||||
Buffer buffer = (Buffer)args[0];
|
||||
int skip = bytes.length/2;
|
||||
buffer.skip(skip);
|
||||
return skip;
|
||||
}
|
||||
});
|
||||
when(endPoint.blockWritable(anyInt())).thenReturn(true);
|
||||
|
||||
// method to test
|
||||
connectHandler.write(endPoint,buffer,null);
|
||||
|
||||
assertThat(buffer.length(),is(0));
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -1,194 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2012 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.servlets;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.net.MalformedURLException;
|
||||
import java.util.Arrays;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.ServletOutputStream;
|
||||
import javax.servlet.http.HttpServlet;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import junit.framework.Assert;
|
||||
import org.eclipse.jetty.client.ContentExchange;
|
||||
import org.eclipse.jetty.client.HttpClient;
|
||||
import org.eclipse.jetty.client.HttpExchange;
|
||||
import org.eclipse.jetty.http.HttpStatus;
|
||||
import org.eclipse.jetty.http.HttpURI;
|
||||
import org.eclipse.jetty.io.Buffer;
|
||||
import org.eclipse.jetty.proxy.ProxyServlet;
|
||||
import org.eclipse.jetty.server.Connector;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.server.handler.HandlerCollection;
|
||||
import org.eclipse.jetty.server.nio.SelectChannelConnector;
|
||||
import org.eclipse.jetty.servlet.ServletContextHandler;
|
||||
import org.eclipse.jetty.servlet.ServletHolder;
|
||||
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
|
||||
import org.junit.After;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import static org.hamcrest.Matchers.*;
|
||||
|
||||
public class ProxyServletTest
|
||||
{
|
||||
private Server _server;
|
||||
private Connector _connector;
|
||||
private HttpClient _client;
|
||||
|
||||
public void init(HttpServlet servlet) throws Exception
|
||||
{
|
||||
_server = new Server();
|
||||
|
||||
_connector = new SelectChannelConnector();
|
||||
_server.addConnector(_connector);
|
||||
|
||||
HandlerCollection handlers = new HandlerCollection();
|
||||
_server.setHandler(handlers);
|
||||
|
||||
ServletContextHandler proxyCtx = new ServletContextHandler(handlers, "/proxy", ServletContextHandler.NO_SESSIONS);
|
||||
ServletHolder proxyServletHolder = new ServletHolder(new ProxyServlet()
|
||||
{
|
||||
@Override
|
||||
protected HttpURI proxyHttpURI(String scheme, String serverName, int serverPort, String uri) throws MalformedURLException
|
||||
{
|
||||
// Proxies any call to "/proxy" to "/"
|
||||
return new HttpURI(scheme + "://" + serverName + ":" + serverPort + uri.substring("/proxy".length()));
|
||||
}
|
||||
});
|
||||
proxyServletHolder.setInitParameter("timeout", String.valueOf(5 * 60 * 1000L));
|
||||
proxyCtx.addServlet(proxyServletHolder, "/*");
|
||||
|
||||
ServletContextHandler appCtx = new ServletContextHandler(handlers, "/", ServletContextHandler.SESSIONS);
|
||||
ServletHolder appServletHolder = new ServletHolder(servlet);
|
||||
appCtx.addServlet(appServletHolder, "/*");
|
||||
|
||||
handlers.addHandler(proxyCtx);
|
||||
handlers.addHandler(appCtx);
|
||||
|
||||
_server.start();
|
||||
|
||||
_client = new HttpClient();
|
||||
_client.start();
|
||||
}
|
||||
|
||||
@After
|
||||
public void destroy() throws Exception
|
||||
{
|
||||
if (_client != null)
|
||||
_client.stop();
|
||||
|
||||
if (_server != null)
|
||||
{
|
||||
_server.stop();
|
||||
_server.join();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testXForwardedHostHeader() throws Exception
|
||||
{
|
||||
init(new HttpServlet()
|
||||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Override
|
||||
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
|
||||
{
|
||||
PrintWriter writer = resp.getWriter();
|
||||
writer.write(req.getHeader("X-Forwarded-Host"));
|
||||
writer.flush();
|
||||
}
|
||||
});
|
||||
|
||||
String url = "http://localhost:" + _connector.getLocalPort() + "/proxy/test";
|
||||
ContentExchange exchange = new ContentExchange();
|
||||
exchange.setURL(url);
|
||||
_client.send(exchange);
|
||||
exchange.waitForDone();
|
||||
assertThat("Response expected to contain content of X-Forwarded-Host Header from the request",exchange.getResponseContent(),equalTo("localhost:"
|
||||
+ _connector.getLocalPort()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBigDownloadWithSlowReader() throws Exception
|
||||
{
|
||||
// Create a 6 MiB file
|
||||
final File file = File.createTempFile("test_", null, MavenTestingUtils.getTargetTestingDir());
|
||||
file.deleteOnExit();
|
||||
FileOutputStream fos = new FileOutputStream(file);
|
||||
byte[] buffer = new byte[1024];
|
||||
Arrays.fill(buffer, (byte)'X');
|
||||
for (int i = 0; i < 6 * 1024; ++i)
|
||||
fos.write(buffer);
|
||||
fos.close();
|
||||
|
||||
init(new HttpServlet()
|
||||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Override
|
||||
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
|
||||
{
|
||||
FileInputStream fis = new FileInputStream(file);
|
||||
ServletOutputStream output = response.getOutputStream();
|
||||
byte[] buffer = new byte[1024];
|
||||
int read;
|
||||
while ((read = fis.read(buffer)) >= 0)
|
||||
output.write(buffer, 0, read);
|
||||
fis.close();
|
||||
}
|
||||
});
|
||||
|
||||
String url = "http://localhost:" + _connector.getLocalPort() + "/proxy/test";
|
||||
ContentExchange exchange = new ContentExchange(true)
|
||||
{
|
||||
@Override
|
||||
protected void onResponseContent(Buffer content) throws IOException
|
||||
{
|
||||
try
|
||||
{
|
||||
// Slow down the reader
|
||||
TimeUnit.MILLISECONDS.sleep(10);
|
||||
super.onResponseContent(content);
|
||||
}
|
||||
catch (InterruptedException x)
|
||||
{
|
||||
throw (IOException)new IOException().initCause(x);
|
||||
}
|
||||
}
|
||||
};
|
||||
exchange.setURL(url);
|
||||
long start = System.nanoTime();
|
||||
_client.send(exchange);
|
||||
Assert.assertEquals(HttpExchange.STATUS_COMPLETED, exchange.waitForDone());
|
||||
long elapsed = System.nanoTime() - start;
|
||||
Assert.assertEquals(HttpStatus.OK_200, exchange.getResponseStatus());
|
||||
Assert.assertEquals(file.length(), exchange.getResponseContentBytes().length);
|
||||
long millis = TimeUnit.NANOSECONDS.toMillis(elapsed);
|
||||
long rate = file.length() / 1024 * 1000 / millis;
|
||||
System.out.printf("download rate = %d KiB/s%n", rate);
|
||||
}
|
||||
}
|
|
@ -50,7 +50,7 @@ public abstract class AbstractNetworkConnector extends AbstractConnector impleme
|
|||
}
|
||||
|
||||
@Override
|
||||
@ManagedAttribute("Host this connector binds to")
|
||||
@ManagedAttribute("The network interface this connector binds to as an IP address or a hostname. If null or 0.0.0.0, then bind to all interfaces.")
|
||||
public String getHost()
|
||||
{
|
||||
return _host;
|
||||
|
@ -62,7 +62,7 @@ public abstract class AbstractNetworkConnector extends AbstractConnector impleme
|
|||
}
|
||||
|
||||
@Override
|
||||
@ManagedAttribute("Port this connector listens on")
|
||||
@ManagedAttribute("Port this connector listens on. If set the 0 a random port is assigned which may be obtained with getLocalPort()")
|
||||
public int getPort()
|
||||
{
|
||||
return _port;
|
||||
|
|
|
@ -23,10 +23,27 @@ import org.eclipse.jetty.io.Connection;
|
|||
import org.eclipse.jetty.io.EndPoint;
|
||||
|
||||
/**
|
||||
* <p>Factory for {@link Connection}s.</p>
|
||||
* <p>A Factory to create {@link Connection} instances for {@link Connector}s.</p>
|
||||
* <p>A Connection factory is responsible for instantiating and configuring a {@link Connection} instance
|
||||
* to handle an {@link EndPoint} accepted by a {@link Connector}.</p>
|
||||
* <p>
|
||||
* A ConnectionFactory has a protocol name that represents the protocol of the Connections
|
||||
* created. Example of protocol names include:<dl>
|
||||
* <dt>http</dt><dd>Creates a HTTP connection that can handle multiple versions of HTTP from 0.9 to 1.1</dd>
|
||||
* <dt>spdy/2</dt><dd>Creates a HTTP connection that handles a specific version of the SPDY protocol</dd>
|
||||
* <dt>SSL-XYZ</dt><dd>Create an SSL connection chained to a connection obtained from a connection factory
|
||||
* with a protocol "XYZ".</dd>
|
||||
* <dt>SSL-http</dt><dd>Create an SSL connection chained to a HTTP connection (aka https)</dd>
|
||||
* <dt>SSL-npn</dt><dd>Create an SSL connection chained to a NPN connection, that uses a negotiation with
|
||||
* the client to determine the next protocol.</dd>
|
||||
* </dl>
|
||||
*/
|
||||
public interface ConnectionFactory
|
||||
{
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @return A string representing the protocol name.
|
||||
*/
|
||||
public String getProtocol();
|
||||
|
||||
/**
|
||||
|
|
|
@ -75,7 +75,7 @@ public interface Connector extends LifeCycle, Graceful
|
|||
public List<String> getProtocols();
|
||||
|
||||
/**
|
||||
* @return the dle timeout for connections in milliseconds
|
||||
* @return the max idle timeout for connections in milliseconds
|
||||
*/
|
||||
@ManagedAttribute("maximum time a connection can be idle before being closed (in ms)")
|
||||
public long getIdleTimeout();
|
||||
|
|
|
@ -27,6 +27,25 @@ import org.eclipse.jetty.http.HttpHeader;
|
|||
import org.eclipse.jetty.http.HttpScheme;
|
||||
import org.eclipse.jetty.server.HttpConfiguration.Customizer;
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Customize Requests for Proxy Forwarding.
|
||||
* <p>
|
||||
* This customizer looks at at HTTP request for headers that indicate
|
||||
* it has been forwarded by one or more proxies. Specifically handled are:
|
||||
* <ul>
|
||||
* <li>X-Forwarded-Host</li>
|
||||
* <li>X-Forwarded-Server</li>
|
||||
* <li>X-Forwarded-For</li>
|
||||
* <li>X-Forwarded-Proto</li>
|
||||
* </ul>
|
||||
* <p>If these headers are present, then the {@link Request} object is updated
|
||||
* so that the proxy is not seen as the other end point of the connection on which
|
||||
* the request came</p>
|
||||
* <p>Headers can also be defined so that forwarded SSL Session IDs and Cipher
|
||||
* suites may be customised</p>
|
||||
* @see http://en.wikipedia.org/wiki/X-Forwarded-For
|
||||
*/
|
||||
public class ForwardedRequestCustomizer implements Customizer
|
||||
{
|
||||
private String _hostHeader;
|
||||
|
|
|
@ -420,39 +420,42 @@ public class HttpChannel<T> implements HttpParser.RequestHandler<T>, Runnable
|
|||
switch (header)
|
||||
{
|
||||
case EXPECT:
|
||||
HttpHeaderValue expect = HttpHeaderValue.CACHE.get(value);
|
||||
switch (expect == null ? HttpHeaderValue.UNKNOWN : expect)
|
||||
if (_version.getVersion()>=HttpVersion.HTTP_1_1.getVersion())
|
||||
{
|
||||
case CONTINUE:
|
||||
_expect100Continue = true;
|
||||
break;
|
||||
HttpHeaderValue expect = HttpHeaderValue.CACHE.get(value);
|
||||
switch (expect == null ? HttpHeaderValue.UNKNOWN : expect)
|
||||
{
|
||||
case CONTINUE:
|
||||
_expect100Continue = true;
|
||||
break;
|
||||
|
||||
case PROCESSING:
|
||||
_expect102Processing = true;
|
||||
break;
|
||||
case PROCESSING:
|
||||
_expect102Processing = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
String[] values = value.split(",");
|
||||
for (int i = 0; values != null && i < values.length; i++)
|
||||
{
|
||||
expect = HttpHeaderValue.CACHE.get(values[i].trim());
|
||||
if (expect == null)
|
||||
_expect = true;
|
||||
else
|
||||
default:
|
||||
String[] values = value.split(",");
|
||||
for (int i = 0; values != null && i < values.length; i++)
|
||||
{
|
||||
switch (expect)
|
||||
expect = HttpHeaderValue.CACHE.get(values[i].trim());
|
||||
if (expect == null)
|
||||
_expect = true;
|
||||
else
|
||||
{
|
||||
case CONTINUE:
|
||||
_expect100Continue = true;
|
||||
break;
|
||||
case PROCESSING:
|
||||
_expect102Processing = true;
|
||||
break;
|
||||
default:
|
||||
_expect = true;
|
||||
switch (expect)
|
||||
{
|
||||
case CONTINUE:
|
||||
_expect100Continue = true;
|
||||
break;
|
||||
case PROCESSING:
|
||||
_expect102Processing = true;
|
||||
break;
|
||||
default:
|
||||
_expect = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -581,6 +584,7 @@ public class HttpChannel<T> implements HttpParser.RequestHandler<T>, Runnable
|
|||
// TODO is it worthwhile sending if we are at EoF?
|
||||
// "application" info failed to commit, commit with a failsafe 500 info
|
||||
_transport.send(HttpGenerator.RESPONSE_500_INFO,null,true);
|
||||
complete=true;
|
||||
throw e;
|
||||
}
|
||||
catch (Exception e)
|
||||
|
@ -588,8 +592,15 @@ public class HttpChannel<T> implements HttpParser.RequestHandler<T>, Runnable
|
|||
LOG.warn(e);
|
||||
// "application" info failed to commit, commit with a failsafe 500 info
|
||||
_transport.send(HttpGenerator.RESPONSE_500_INFO,null,true);
|
||||
complete=true;
|
||||
throw e;
|
||||
}
|
||||
finally
|
||||
{
|
||||
// TODO this indicates the relationship with HttpOutput is not exactly correct
|
||||
if (complete)
|
||||
_response.getHttpOutput().closed();
|
||||
}
|
||||
}
|
||||
return committed;
|
||||
}
|
||||
|
|
|
@ -25,6 +25,18 @@ import org.eclipse.jetty.http.HttpScheme;
|
|||
import org.eclipse.jetty.util.annotation.ManagedAttribute;
|
||||
import org.eclipse.jetty.util.annotation.ManagedObject;
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** HTTP Configuration.
|
||||
* <p>This class is a holder of HTTP configuration for use by the
|
||||
* {@link HttpChannel} class. Typically a HTTPConfiguration instance
|
||||
* is instantiated and passed to a {@link ConnectionFactory} that can
|
||||
* create HTTP channels (eg HTTP, AJP or SPDY).</p>
|
||||
* <p>The configuration held by this class is not for the wire protocol,
|
||||
* but for the interpretation and handling of HTTP requests that could
|
||||
* be transported by a variety of protocols.
|
||||
* </p>
|
||||
*/
|
||||
@ManagedObject("HTTP Configuration")
|
||||
public class HttpConfiguration
|
||||
{
|
||||
|
@ -49,6 +61,10 @@ public class HttpConfiguration
|
|||
{
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Create a configuration from another.
|
||||
* @param config The configuration to copy.
|
||||
*/
|
||||
public HttpConfiguration(HttpConfiguration config)
|
||||
{
|
||||
_customizers.addAll(config._customizers);
|
||||
|
@ -59,11 +75,20 @@ public class HttpConfiguration
|
|||
_secureScheme=config._secureScheme;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* <p>Add a {@link Customizer} that is invoked for every
|
||||
* request received.</p>
|
||||
* <p>Customiser are often used to interpret optional headers (eg {@link ForwardedRequestCustomizer}) or
|
||||
* optional protocol semantics (eg {@link SecureRequestCustomizer}).
|
||||
* @param customizer A request customizer
|
||||
*/
|
||||
public void addCustomizer(Customizer customizer)
|
||||
{
|
||||
_customizers.add(customizer);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public List<Customizer> getCustomizers()
|
||||
{
|
||||
return _customizers;
|
||||
|
@ -107,32 +132,72 @@ public class HttpConfiguration
|
|||
return _secureScheme;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* <p>Set the {@link Customizer}s that are invoked for every
|
||||
* request received.</p>
|
||||
* <p>Customisers are often used to interpret optional headers (eg {@link ForwardedRequestCustomizer}) or
|
||||
* optional protocol semantics (eg {@link SecureRequestCustomizer}).
|
||||
* @param customizers
|
||||
*/
|
||||
public void setCustomizers(List<Customizer> customizers)
|
||||
{
|
||||
_customizers.clear();
|
||||
_customizers.addAll(customizers);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Set the size of the buffer into which response content is aggregated
|
||||
* before being sent to the client. A larger buffer can improve performance by allowing
|
||||
* a content producer to run without blocking, however larger buffers consume more memory and
|
||||
* may induce some latency before a client starts processing the content.
|
||||
* @param responseBufferSize buffer size in bytes.
|
||||
*/
|
||||
public void setOutputBufferSize(int responseBufferSize)
|
||||
{
|
||||
_outputBufferSize = responseBufferSize;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Set the maximum size of a request header.
|
||||
* <p>Larger headers will allow for more and/or larger cookies plus larger form content encoded
|
||||
* in a URL. However, larger headers consume more memory and can make a server more vulnerable to denial of service
|
||||
* attacks.</p>
|
||||
* @param requestHeaderSize Max header size in bytes
|
||||
*/
|
||||
public void setRequestHeaderSize(int requestHeaderSize)
|
||||
{
|
||||
_requestHeaderSize = requestHeaderSize;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Set the maximum size of a response header.
|
||||
*
|
||||
* <p>Larger headers will allow for more and/or larger cookies and longer HTTP headers (eg for redirection).
|
||||
* However, larger headers will also consume more memory.</p>
|
||||
* @param responseHeaderSize Response header size in bytes.
|
||||
*/
|
||||
public void setResponseHeaderSize(int responseHeaderSize)
|
||||
{
|
||||
_responseHeaderSize = responseHeaderSize;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Set the TCP/IP port used for CONFIDENTIAL and INTEGRAL
|
||||
* redirections.
|
||||
* @param confidentialPort
|
||||
*/
|
||||
public void setSecurePort(int confidentialPort)
|
||||
{
|
||||
_securePort = confidentialPort;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Set the URI scheme used for CONFIDENTIAL and INTEGRAL
|
||||
* redirections.
|
||||
* @param confidentialScheme A string like"https"
|
||||
*/
|
||||
public void setSecureScheme(String confidentialScheme)
|
||||
{
|
||||
_secureScheme = confidentialScheme;
|
||||
|
|
|
@ -25,12 +25,13 @@ import java.util.concurrent.RejectedExecutionException;
|
|||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
import org.eclipse.jetty.http.HttpGenerator;
|
||||
import org.eclipse.jetty.http.HttpGenerator.ResponseInfo;
|
||||
import org.eclipse.jetty.http.HttpHeader;
|
||||
import org.eclipse.jetty.http.HttpHeaderValue;
|
||||
import org.eclipse.jetty.http.HttpMethod;
|
||||
import org.eclipse.jetty.http.HttpParser;
|
||||
import org.eclipse.jetty.http.HttpStatus;
|
||||
import org.eclipse.jetty.http.HttpVersion;
|
||||
import org.eclipse.jetty.http.HttpGenerator.ResponseInfo;
|
||||
import org.eclipse.jetty.io.AbstractConnection;
|
||||
import org.eclipse.jetty.io.ByteBufferPool;
|
||||
import org.eclipse.jetty.io.Connection;
|
||||
|
@ -61,7 +62,7 @@ public class HttpConnection extends AbstractConnection implements Runnable, Http
|
|||
private volatile ByteBuffer _chunk = null;
|
||||
private BlockingCallback _readBlocker = new BlockingCallback();
|
||||
private BlockingCallback _writeBlocker = new BlockingCallback();
|
||||
|
||||
|
||||
// TODO get rid of this
|
||||
private final Runnable _channelRunner = new Runnable()
|
||||
{
|
||||
|
@ -77,7 +78,7 @@ public class HttpConnection extends AbstractConnection implements Runnable, Http
|
|||
{
|
||||
setCurrentConnection(null);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -410,7 +411,7 @@ public class HttpConnection extends AbstractConnection implements Runnable, Http
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public <C> void send(ResponseInfo info, ByteBuffer content, boolean lastContent, C context, Callback<C> callback)
|
||||
{
|
||||
|
@ -514,6 +515,10 @@ public class HttpConnection extends AbstractConnection implements Runnable, Http
|
|||
}
|
||||
}
|
||||
|
||||
public ByteBuffer getRequestBuffer()
|
||||
{
|
||||
return _requestBuffer;
|
||||
}
|
||||
|
||||
private class Input extends ByteBufferHttpInput
|
||||
{
|
||||
|
@ -543,7 +548,7 @@ public class HttpConnection extends AbstractConnection implements Runnable, Http
|
|||
|
||||
// Do we have content ready to parse?
|
||||
if (BufferUtil.isEmpty(_requestBuffer))
|
||||
{
|
||||
{
|
||||
// If no more input
|
||||
if (getEndPoint().isInputShutdown())
|
||||
{
|
||||
|
@ -642,24 +647,32 @@ public class HttpConnection extends AbstractConnection implements Runnable, Http
|
|||
switch (version)
|
||||
{
|
||||
case HTTP_0_9:
|
||||
{
|
||||
persistent = false;
|
||||
break;
|
||||
|
||||
}
|
||||
case HTTP_1_0:
|
||||
{
|
||||
persistent = getRequest().getHttpFields().contains(HttpHeader.CONNECTION, HttpHeaderValue.KEEP_ALIVE.asString());
|
||||
if (!persistent)
|
||||
persistent = HttpMethod.CONNECT.is(getRequest().getMethod());
|
||||
if (persistent)
|
||||
getResponse().getHttpFields().add(HttpHeader.CONNECTION, HttpHeaderValue.KEEP_ALIVE);
|
||||
break;
|
||||
|
||||
}
|
||||
case HTTP_1_1:
|
||||
{
|
||||
persistent = !getRequest().getHttpFields().contains(HttpHeader.CONNECTION, HttpHeaderValue.CLOSE.asString());
|
||||
|
||||
if (!persistent)
|
||||
persistent = HttpMethod.CONNECT.is(getRequest().getMethod());
|
||||
if (!persistent)
|
||||
getResponse().getHttpFields().add(HttpHeader.CONNECTION, HttpHeaderValue.CLOSE);
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
}
|
||||
|
||||
if (!persistent)
|
||||
|
|
|
@ -82,6 +82,19 @@ public class HttpOutput extends ServletOutputStream
|
|||
{
|
||||
_closed = false;
|
||||
}
|
||||
|
||||
/** Called by the HttpChannel if the output was closed
|
||||
* externally (eg by a 500 exception handling).
|
||||
*/
|
||||
void closed()
|
||||
{
|
||||
_closed = true;
|
||||
if (_aggregate != null)
|
||||
{
|
||||
_channel.getConnector().getByteBufferPool().release(_aggregate);
|
||||
_aggregate = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close()
|
||||
|
@ -237,6 +250,10 @@ public class HttpOutput extends ServletOutputStream
|
|||
response.getHttpFields().putDateField(HttpHeader.LAST_MODIFIED, lml);
|
||||
}
|
||||
|
||||
String etag=httpContent.getETag();
|
||||
if (etag!=null)
|
||||
response.getHttpFields().put(HttpHeader.ETAG,etag);
|
||||
|
||||
content = httpContent.getDirectBuffer();
|
||||
if (content == null)
|
||||
content = httpContent.getIndirectBuffer();
|
||||
|
@ -255,7 +272,8 @@ public class HttpOutput extends ServletOutputStream
|
|||
// Process content.
|
||||
if (content instanceof ByteBuffer)
|
||||
{
|
||||
_channel.write((ByteBuffer)content, true); // TODO: we have written all content ?
|
||||
_channel.write((ByteBuffer)content, true);
|
||||
_closed=true;
|
||||
}
|
||||
else if (content instanceof ReadableByteChannel)
|
||||
{
|
||||
|
@ -297,7 +315,6 @@ public class HttpOutput extends ServletOutputStream
|
|||
buffer.limit(len);
|
||||
_channel.write(buffer,false);
|
||||
}
|
||||
_channel.write(BufferUtil.EMPTY_BUFFER,true);
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue