Merge from 'master' to 'ws-refactor'

This commit is contained in:
Joakim Erdfelt 2012-11-12 16:22:11 -07:00
commit 42ec683297
212 changed files with 6760 additions and 1138 deletions

View File

@ -1,5 +1,109 @@
jetty-9.0.0-SNAPSHOT
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
+ 392237 Split jaas from jetty-plus into jetty-jaas and port the
test-jaas-webapp from codehaus
+ 392239 Allow no error-code or exception for error-pages
+ 392304 fixed intermittent client SSL failure. Correctly compact in flip2fill
+ 392525 Add option to --stop-wait to specify timeout
+ 392641 JDBC Sessions not scavenged if expired during downtime
+ 392812 MongoSessionIDManager never purges old sessions
+ 392959 Review HttpClient.getConversation(long).
+ 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
+ 393291 Confusing log entry about (non) existing webAppSourceDirectory
+ 393303 use jetty-web.xml to explicitly add the jetty packages that need
visability. This commit also sucked in some changes made to help with the
documentation process (improving deployer configuration management
+ 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-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
@ -68,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.
@ -101,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
@ -132,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
@ -165,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
@ -207,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
@ -229,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
@ -243,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
@ -264,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.
@ -293,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
@ -317,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

78
dists/jetty-deb/pom.xml Normal file
View File

@ -0,0 +1,78 @@
<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>/opt/jetty</to>
<pattern>/jetty-distribution-${project.version}(.*)</pattern>
<replacement>$1</replacement>
<excludes>
<include>jetty-distribution-*/contexts/javadoc.xml</include>
<exclude>jetty-distribution-*/javadoc</exclude>
<exclude>jetty-distribution-*/javadoc/**</exclude>
</excludes>
</extractArtifact>
</assembly>
</package>
<!--package>
<id>jetty-javadoc</id>
<classifier>javadoc</classifier>
<assembly>
<extractArtifact>
<artifact>org.eclipse.jetty:jetty-distribution:zip</artifact>
<to>/opt/jetty</to>
<pattern>/jetty-distribution-${project.version}(.*)</pattern>
<replacement>$1</replacement>
<includes>
<include>jetty-distribution-*/contexts/javadoc.xml</include>
<include>jetty-distribution-*/javadoc/**</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>

View File

@ -0,0 +1,6 @@
#!/bin/bash
cp /opt/jetty/bin/jetty.sh /etc/init.d/jetty
chmod 755 /etc/init.d/jetty
chmod 755 /opt/jetty/bin/*.sh

View File

@ -0,0 +1,3 @@
#!/bin/bash
rm -f /etc/init.d/jetty

26
dists/pom.xml Normal file
View File

@ -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>

View File

@ -3,6 +3,7 @@
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-project</artifactId>
<version>9.0.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>org.eclipse.jetty</groupId>

View File

@ -3,6 +3,7 @@
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-project</artifactId>
<version>9.0.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>example-jetty-embedded</artifactId>

View File

@ -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();

View File

@ -21,13 +21,6 @@ package org.eclipse.jetty.embedded;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.handler.ContextHandler;
/* ------------------------------------------------------------ */
/**
* A {@link ContextHandler} provides a common environment for multiple Handlers,
* such as: URI context path, class loader, static resource base.
*
* Typically a ContextHandler is used only when multiple contexts are likely.
*/
public class OneContext
{
public static void main(String[] args) throws Exception
@ -38,10 +31,10 @@ public class OneContext
context.setContextPath("/");
context.setResourceBase(".");
context.setClassLoader(Thread.currentThread().getContextClassLoader());
server.setHandler(context);
context.setHandler(new HelloHandler());
server.setHandler(context);
server.start();
server.join();
}

View File

@ -26,6 +26,7 @@ import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Locale;
import java.util.jar.JarEntry;
import org.eclipse.jetty.util.Loader;
@ -807,7 +808,7 @@ public class AnnotationParser
try
{
String name = entry.getName();
if (name.toLowerCase().endsWith(".class"))
if (name.toLowerCase(Locale.ENGLISH).endsWith(".class"))
{
String shortName = name.replace('/', '.').substring(0,name.length()-6);
if ((resolver == null)
@ -853,7 +854,7 @@ public class AnnotationParser
try
{
String name = entry.getName();
if (name.toLowerCase().endsWith(".class"))
if (name.toLowerCase(Locale.ENGLISH).endsWith(".class"))
{
String shortName = name.replace('/', '.').substring(0,name.length()-6);

View File

@ -21,6 +21,7 @@ package org.eclipse.jetty.annotations;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Locale;
import javax.annotation.Resource;
import javax.naming.InitialContext;
import javax.naming.NameNotFoundException;
@ -261,7 +262,7 @@ public class ResourceAnnotationHandler extends AbstractIntrospectableAnnotationH
//default name is the javabean property name
String name = method.getName().substring(3);
name = name.substring(0,1).toLowerCase()+name.substring(1);
name = name.substring(0,1).toLowerCase(Locale.ENGLISH)+name.substring(1);
name = clazz.getCanonicalName()+"/"+name;
name = (resource.name()!=null && !resource.name().trim().equals("")? resource.name(): name);

View File

@ -30,6 +30,7 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
@ -323,7 +324,7 @@ public class HttpClient extends ContainerLifeCycle
protected void send(final Request request, List<Response.ResponseListener> listeners)
{
String scheme = request.getScheme().toLowerCase();
String scheme = request.getScheme().toLowerCase(Locale.ENGLISH);
if (!Arrays.asList("http", "https").contains(scheme))
throw new IllegalArgumentException("Invalid protocol " + scheme);

View File

@ -44,7 +44,7 @@ public class HttpCookieParser
public static List<HttpCookie> parseCookies(String headerValue)
{
if (headerValue.toLowerCase().contains("expires="))
if (headerValue.toLowerCase(Locale.ENGLISH).contains("expires="))
{
HttpCookie cookie = parseCookie(headerValue, 0);
if (cookie != null)
@ -111,7 +111,7 @@ public class HttpCookieParser
try
{
String[] attributeParts = cookieParts[i].split("=", 2);
String attributeName = attributeParts[0].trim().toLowerCase();
String attributeName = attributeParts[0].trim().toLowerCase(Locale.ENGLISH);
String attributeValue = attributeParts.length < 2 ? "" : attributeParts[1].trim();
switch (attributeName)
{

View File

@ -24,6 +24,7 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
import java.util.List;
import java.util.Locale;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicMarkableReference;
import java.util.concurrent.atomic.AtomicReference;
@ -191,7 +192,7 @@ public class HttpReceiver implements HttpParser.ResponseHandler<ByteBuffer>
if (exchange != null)
{
exchange.getResponse().getHeaders().add(name, value);
switch (name.toLowerCase())
switch (name.toLowerCase(Locale.ENGLISH))
{
case "set-cookie":
case "set-cookie2":

View File

@ -21,6 +21,7 @@ package org.eclipse.jetty.client.util;
import java.io.UnsupportedEncodingException;
import java.nio.ByteBuffer;
import java.nio.charset.UnsupportedCharsetException;
import java.util.Locale;
import org.eclipse.jetty.client.api.Response;
import org.eclipse.jetty.client.api.Result;
@ -69,7 +70,7 @@ public abstract class BufferingResponseListener extends Response.Listener.Empty
if (contentType != null)
{
String charset = "charset=";
int index = contentType.toLowerCase().indexOf(charset);
int index = contentType.toLowerCase(Locale.ENGLISH).indexOf(charset);
if (index > 0)
{
String encoding = contentType.substring(index + charset.length());

View File

@ -25,6 +25,7 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.atomic.AtomicInteger;
@ -108,7 +109,7 @@ public class DigestAuthentication implements Authentication
Matcher matcher = PARAM_PATTERN.matcher(part);
if (matcher.matches())
{
String name = matcher.group(1).trim().toLowerCase();
String name = matcher.group(1).trim().toLowerCase(Locale.ENGLISH);
String value = matcher.group(2).trim();
if (value.startsWith("\"") && value.endsWith("\""))
value = value.substring(1, value.length() - 1);
@ -251,7 +252,7 @@ public class DigestAuthentication implements Authentication
private String nextNonceCount()
{
String padding = "00000000";
String next = Integer.toHexString(nonceCount.incrementAndGet()).toLowerCase();
String next = Integer.toHexString(nonceCount.incrementAndGet()).toLowerCase(Locale.ENGLISH);
return padding.substring(0, padding.length() - next.length()) + next;
}
@ -265,7 +266,7 @@ public class DigestAuthentication implements Authentication
private String toHexString(byte[] bytes)
{
return TypeUtil.toHexString(bytes).toLowerCase();
return TypeUtil.toHexString(bytes).toLowerCase(Locale.ENGLISH);
}
}
}

View File

@ -23,6 +23,7 @@ import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Locale;
import java.util.Random;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
@ -184,7 +185,7 @@ public class HttpClientLoadTest extends AbstractHttpClientServerTest
@Override
public void handle(String target, org.eclipse.jetty.server.Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
{
String method = request.getMethod().toUpperCase();
String method = request.getMethod().toUpperCase(Locale.ENGLISH);
switch (method)
{
case "GET":

View File

@ -20,6 +20,7 @@ package org.eclipse.jetty.client;
import java.net.URI;
import java.nio.ByteBuffer;
import java.util.Locale;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
@ -288,8 +289,8 @@ public class HttpSenderTest
String requestString = endPoint.takeOutputString();
Assert.assertTrue(requestString.startsWith("GET "));
String content = Integer.toHexString(content1.length()).toUpperCase() + "\r\n" + content1 + "\r\n";
content += Integer.toHexString(content2.length()).toUpperCase() + "\r\n" + content2 + "\r\n";
String content = Integer.toHexString(content1.length()).toUpperCase(Locale.ENGLISH) + "\r\n" + content1 + "\r\n";
content += Integer.toHexString(content2.length()).toUpperCase(Locale.ENGLISH) + "\r\n" + content2 + "\r\n";
content += "0\r\n\r\n";
Assert.assertTrue(requestString.endsWith("\r\n\r\n" + content));
Assert.assertTrue(headersLatch.await(5, TimeUnit.SECONDS));

View File

@ -43,6 +43,16 @@
<Set name="defaultsDescriptor"><Property name="jetty.home" default="." />/etc/webdefault.xml</Set>
<Set name="scanInterval">1</Set>
<Set name="extractWars">true</Set>
<Set name="configurationManager">
<New class="org.eclipse.jetty.deploy.PropertiesConfigurationManager">
<!-- file of context configuration properties
<Set name="file"><SystemProperty name="jetty.home"/>/etc/some.properties</Set>
-->
<!-- set a context configuration property
<Call name="put"><Arg>name</Arg><Arg>value</Arg></Call>
-->
</New>
</Set>
</New>
</Arg>
</Call>

View File

@ -21,10 +21,15 @@ package org.eclipse.jetty.deploy;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.MalformedURLException;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import org.eclipse.jetty.util.annotation.ManagedAttribute;
import org.eclipse.jetty.util.annotation.ManagedObject;
import org.eclipse.jetty.util.annotation.ManagedOperation;
import org.eclipse.jetty.util.annotation.Name;
import org.eclipse.jetty.util.resource.Resource;
/**
@ -32,42 +37,55 @@ import org.eclipse.jetty.util.resource.Resource;
*
* Supplies properties defined in a file.
*/
public class FileConfigurationManager implements ConfigurationManager
@ManagedObject("Configure deployed webapps via properties")
public class PropertiesConfigurationManager implements ConfigurationManager
{
private Resource _file;
private Map<String,String> _map = new HashMap<String,String>();
private String _properties;
private final Map<String,String> _map = new HashMap<String,String>();
public FileConfigurationManager()
public PropertiesConfigurationManager(String properties)
{
}
public PropertiesConfigurationManager()
{
}
public void setFile(String filename) throws MalformedURLException, IOException
@ManagedAttribute("A file or URL of properties")
public void setFile(String resource) throws MalformedURLException, IOException
{
_file = Resource.newResource(filename);
_properties=resource;
_map.clear();
loadProperties(_properties);
}
public String getFile()
{
return _properties;
}
@ManagedOperation("Set a property")
public void put(@Name("name")String name, @Name("value")String value)
{
_map.put(name,value);
}
/**
* @see org.eclipse.jetty.deploy.ConfigurationManager#getProperties()
*/
@Override
public Map<String, String> getProperties()
{
try
{
loadProperties();
return _map;
}
catch (Exception e)
{
throw new RuntimeException(e);
}
return new HashMap<>(_map);
}
private void loadProperties() throws FileNotFoundException, IOException
{
if (_map.isEmpty() && _file!=null)
private void loadProperties(String resource) throws FileNotFoundException, IOException
{
Resource file=Resource.newResource(resource);
if (file!=null && file.exists())
{
Properties properties = new Properties();
properties.load(_file.getInputStream());
properties.load(file.getInputStream());
for (Map.Entry<Object, Object> entry : properties.entrySet())
_map.put(entry.getKey().toString(),String.valueOf(entry.getValue()));
}

View File

@ -22,6 +22,7 @@ import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;
import java.net.MalformedURLException;
import java.util.Locale;
import org.eclipse.jetty.deploy.App;
import org.eclipse.jetty.deploy.ConfigurationManager;
@ -77,7 +78,7 @@ public class WebAppProvider extends ScanningAppProvider
{
return false;
}
String lowername = name.toLowerCase();
String lowername = name.toLowerCase(Locale.ENGLISH);
File file = new File(dir,name);
@ -299,9 +300,9 @@ public class WebAppProvider extends ScanningAppProvider
{
context = URIUtil.SLASH;
}
else if (context.toLowerCase().startsWith("root-"))
else if (context.toLowerCase(Locale.ENGLISH).startsWith("root-"))
{
int dash=context.toLowerCase().indexOf('-');
int dash=context.toLowerCase(Locale.ENGLISH).indexOf('-');
String virtual = context.substring(dash+1);
wah.setVirtualHosts(new String[]{virtual});
context = URIUtil.SLASH;

View File

@ -19,6 +19,7 @@
package org.eclipse.jetty.deploy.util;
import java.io.File;
import java.util.Locale;
/**
* Simple, yet surprisingly common utility methods for identifying various file types commonly seen and worked with in a
@ -38,7 +39,7 @@ public class FileID
{
if (path.isFile())
{
String name = path.getName().toLowerCase();
String name = path.getName().toLowerCase(Locale.ENGLISH);
return (name.endsWith(".war") || name.endsWith(".jar"));
}
@ -62,7 +63,7 @@ public class FileID
return false;
}
String name = path.getName().toLowerCase();
String name = path.getName().toLowerCase(Locale.ENGLISH);
return (name.endsWith(".war") || name.endsWith(".jar"));
}
@ -73,7 +74,7 @@ public class FileID
return false;
}
String name = path.getName().toLowerCase();
String name = path.getName().toLowerCase(Locale.ENGLISH);
return name.endsWith(".xml");
}
}

View File

@ -50,7 +50,7 @@
<Set name="monitoredDirName"><SystemProperty name="jetty.home" />/webapps</Set>
<Set name="scanInterval">1</Set>
<Set name="configurationManager">
<New class="org.eclipse.jetty.deploy.FileConfigurationManager">
<New class="org.eclipse.jetty.deploy.PropertiesConfigurationManager">
<Set name="file">
<SystemProperty name="jetty.home"/>/xml-configured-jetty.properties
</Set>

View File

@ -17,7 +17,7 @@
<Set name="monitoredDirName"><SystemProperty name="jetty.home" />/webapps</Set>
<Set name="scanInterval">1</Set>
<Set name="configurationManager">
<New class="org.eclipse.jetty.deploy.FileConfigurationManager">
<New class="org.eclipse.jetty.deploy.PropertiesConfigurationManager">
<Set name="file">
<SystemProperty name="jetty.home"/>/xml-configured-jetty.properties
</Set>

View File

@ -364,6 +364,12 @@
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-jaas</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-annotations</artifactId>
@ -381,11 +387,6 @@
<artifactId>jetty-jndi</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-plus</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-client</artifactId>

View File

@ -1,13 +1,7 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure.dtd">
<!--
Configure a custom context for the javadoc.
This context contains only a ServletHandler with a default servlet
to serve static html files and images.
-->
<!--Configure a context for the javadoc -->
<Configure class="org.eclipse.jetty.server.handler.ContextHandler">
<Set name="contextPath">/javadoc</Set>
<Set name="resourceBase"><SystemProperty name="jetty.home" default="."/>/javadoc/</Set>
@ -21,6 +15,5 @@ to serve static html files and images.
<Set name="cacheControl">max-age=3600,public</Set>
</New>
</Set>
</Configure>

View File

@ -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

View File

@ -810,7 +810,7 @@ public class HttpFields implements Iterable<HttpFields.Field>
{
hasDomain = true;
buf.append(";Domain=");
QuotedStringTokenizer.quoteIfNeeded(buf,domain.toLowerCase(),delim);
QuotedStringTokenizer.quoteIfNeeded(buf,domain.toLowerCase(Locale.ENGLISH),delim);
}
if (maxAge >= 0)

View File

@ -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

View File

@ -22,6 +22,7 @@ import java.nio.ByteBuffer;
import java.nio.charset.Charset;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.MissingResourceException;
import java.util.ResourceBundle;
@ -70,7 +71,7 @@ public class MimeTypes
_string=s;
_buffer=BufferUtil.toBuffer(s);
int i=s.toLowerCase().indexOf("charset=");
int i=s.toLowerCase(Locale.ENGLISH).indexOf("charset=");
_charset=(i>0)?Charset.forName(s.substring(i+8)):null;
}

View File

@ -171,6 +171,7 @@ xhtml=application/xhtml+xml
xls=application/vnd.ms-excel
xml=application/xml
xpm=image/x-xpixmap
xsd=application/xml
xsl=application/xml
xslt=application/xslt+xml
xul=application/vnd.mozilla.xul+xml

View File

@ -21,6 +21,7 @@ package org.eclipse.jetty.http;
import java.nio.ByteBuffer;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Locale;
import java.util.Set;
import org.eclipse.jetty.util.BufferUtil;
@ -385,7 +386,7 @@ public class HttpFieldsTest
{
Set<String> s=new HashSet<String>();
while(e.hasMoreElements())
s.add(e.nextElement().toLowerCase());
s.add(e.nextElement().toLowerCase(Locale.ENGLISH));
return s;
}

View File

@ -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
{

View File

@ -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());
}
}

View File

@ -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();
}

View File

@ -45,7 +45,6 @@
</archive>
</configuration>
</plugin>
<!--
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
@ -63,7 +62,6 @@
</execution>
</executions>
</plugin>
-->
<!-- always include the sources to be able to prepare the eclipse-jetty-SDK feature
with a snapshot. -->
<plugin>

View File

@ -14,17 +14,4 @@
<Arg><SystemProperty name="jetty.home" default="." />/etc/login.conf</Arg>
</Call>
<!-- ======================================================== -->
<!-- An example JAAS realm setup -->
<!-- ======================================================== -->
<Call name="addBean">
<Arg>
<New class="org.eclipse.jetty.jaas.JAASLoginService">
<Set name="Name">Test JAAS Realm</Set>
<Set name="LoginModuleName">xyz</Set>
</New>
</Arg>
</Call>
</Configure>

View File

@ -22,6 +22,7 @@ import java.io.IOException;
import java.util.ArrayList;
import java.util.Hashtable;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Properties;
import javax.naming.Context;
@ -652,12 +653,12 @@ public class LdapLoginModule extends AbstractLoginModule
public static String convertCredentialJettyToLdap(String encryptedPassword)
{
if ("MD5:".startsWith(encryptedPassword.toUpperCase()))
if ("MD5:".startsWith(encryptedPassword.toUpperCase(Locale.ENGLISH)))
{
return "{MD5}" + encryptedPassword.substring("MD5:".length(), encryptedPassword.length());
}
if ("CRYPT:".startsWith(encryptedPassword.toUpperCase()))
if ("CRYPT:".startsWith(encryptedPassword.toUpperCase(Locale.ENGLISH)))
{
return "{CRYPT}" + encryptedPassword.substring("CRYPT:".length(), encryptedPassword.length());
}
@ -672,12 +673,12 @@ public class LdapLoginModule extends AbstractLoginModule
return encryptedPassword;
}
if ("{MD5}".startsWith(encryptedPassword.toUpperCase()))
if ("{MD5}".startsWith(encryptedPassword.toUpperCase(Locale.ENGLISH)))
{
return "MD5:" + encryptedPassword.substring("{MD5}".length(), encryptedPassword.length());
}
if ("{CRYPT}".startsWith(encryptedPassword.toUpperCase()))
if ("{CRYPT}".startsWith(encryptedPassword.toUpperCase(Locale.ENGLISH)))
{
return "CRYPT:" + encryptedPassword.substring("{CRYPT}".length(), encryptedPassword.length());
}

View File

@ -20,6 +20,7 @@ package org.eclipse.jetty.jmx;
import java.io.IOException;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.WeakHashMap;
@ -164,7 +165,7 @@ public class MBeanContainer implements Container.InheritedListener, Dumpable
domain = obj.getClass().getPackage().getName();
String type = obj.getClass().getName().toLowerCase();
String type = obj.getClass().getName().toLowerCase(Locale.ENGLISH);
int dot = type.lastIndexOf('.');
if (dot >= 0)
type = type.substring(dot + 1);

View File

@ -30,6 +30,7 @@ import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import javax.management.Attribute;
@ -622,7 +623,7 @@ public class ObjectMBean implements DynamicMBean
convert = true;
}
String uName = name.substring(0, 1).toUpperCase() + name.substring(1);
String uName = name.substring(0, 1).toUpperCase(Locale.ENGLISH) + name.substring(1);
Class<?> oClass = onMBean ? this.getClass() : _managed.getClass();
LOG.debug("defineAttribute {} {}:{}:{}:{}",name,onMBean,readonly,oClass,description);
@ -862,7 +863,7 @@ public class ObjectMBean implements DynamicMBean
variableName = variableName.substring(2);
}
variableName = variableName.substring(0,1).toLowerCase() + variableName.substring(1);
variableName = variableName.substring(0,1).toLowerCase(Locale.ENGLISH) + variableName.substring(1);
return variableName;
}

View File

@ -483,7 +483,7 @@ public abstract class AbstractJettyMojo extends AbstractMojo
if (connectors == null || connectors.length == 0)
{
//if a SystemProperty -Djetty.port=<portnum> has been supplied, use that as the default port
this.connectors = new Connector[] { this.server.createDefaultConnector(server, System.getProperty(PORT_SYSPROPERTY, null)) };
this.connectors = new Connector[] { this.server.createDefaultConnector(System.getProperty(PORT_SYSPROPERTY, null)) };
this.server.setConnectors(this.connectors);
}
}

View File

@ -16,58 +16,55 @@
// ========================================================================
//
/**
*
*/
package org.eclipse.jetty.maven.plugin;
import java.io.IOException;
public class ConsoleScanner extends Thread
public class ConsoleScanner extends Thread
{
private final AbstractJettyMojo mojo;
public ConsoleScanner(AbstractJettyMojo mojo)
public ConsoleScanner(AbstractJettyMojo mojo)
{
this.mojo = mojo;
setName("Console scanner");
setDaemon(true);
}
public void run()
{
try
public void run()
{
try
{
while (true)
while (true)
{
checkSystemInput();
getSomeSleep();
}
}
catch (IOException e)
}
catch (IOException e)
{
mojo.getLog().warn(e);
}
}
private void getSomeSleep()
private void getSomeSleep()
{
try
try
{
Thread.sleep(500);
}
catch (InterruptedException e)
}
catch (InterruptedException e)
{
mojo.getLog().debug(e);
}
}
private void checkSystemInput() throws IOException
{
private void checkSystemInput() throws IOException
{
while (System.in.available() > 0) {
int inputByte = System.in.read();
if (inputByte >= 0)
if (inputByte >= 0)
{
char c = (char)inputByte;
if (c == '\n') {
@ -76,12 +73,12 @@ public class ConsoleScanner extends Thread
}
}
}
/**
* Skip buffered bytes of system console.
*/
private void clearInputBuffer()
private void clearInputBuffer()
{
try
{
@ -101,9 +98,9 @@ public class ConsoleScanner extends Thread
catch (IOException e)
{
mojo.getLog().warn("Error discarding console input buffer", e);
}
}
}
private void restartWebApp()
{
try

View File

@ -1,46 +1,45 @@
//
// ========================================================================
// Copyright (c) 1995-2012 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
//
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
//
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
//
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
//
package org.eclipse.jetty.maven.plugin;
/**
* <p>
* This goal is used to run Jetty with a pre-assembled war.
* </p>
* <p>
* It accepts exactly the same options as the <a href="run-war-mojo.html">run-war</a> goal.
* However, it doesn't assume that the current artifact is a
* webapp and doesn't try to assemble it into a war before its execution.
* So using it makes sense only when used in conjunction with the
* <a href="run-war-mojo.html#webApp">webApp</a> configuration parameter pointing to a pre-built WAR.
* </p>
* <p>
* This goal is useful e.g. for launching a web app in Jetty as a target for unit-tested
* HTTP client components.
* </p>
*
* @goal deploy-war
* @requiresDependencyResolution runtime
* @execute phase="validate"
* @description Deploy a pre-assembled war
*
*/
public class JettyDeployWar extends JettyRunWarMojo
{
}
//
// ========================================================================
// Copyright (c) 1995-2012 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
//
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
//
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
//
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
//
package org.eclipse.jetty.maven.plugin;
/**
* <p>
* This goal is used to run Jetty with a pre-assembled war.
* </p>
* <p>
* It accepts exactly the same options as the <a href="run-war-mojo.html">run-war</a> goal.
* However, it doesn't assume that the current artifact is a
* webapp and doesn't try to assemble it into a war before its execution.
* So using it makes sense only when used in conjunction with the
* <a href="run-war-mojo.html#webApp">webApp</a> configuration parameter pointing to a pre-built WAR.
* </p>
* <p>
* This goal is useful e.g. for launching a web app in Jetty as a target for unit-tested
* HTTP client components.
* </p>
*
* @goal deploy-war
* @requiresDependencyResolution runtime
* @execute phase="validate"
* @description Deploy a pre-assembled war
*
*/
public class JettyDeployWar extends JettyRunWarMojo
{
}

View File

@ -18,23 +18,33 @@
package org.eclipse.jetty.maven.plugin;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.LineNumberReader;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Properties;
import java.util.Random;
import java.util.Set;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.maven.artifact.Artifact;
import org.apache.maven.plugin.AbstractMojo;
@ -42,7 +52,10 @@ import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.plugin.descriptor.PluginDescriptor;
import org.apache.maven.project.MavenProject;
import org.codehaus.plexus.component.repository.ComponentDependency;
import org.eclipse.jetty.server.RequestLog;
import org.eclipse.jetty.util.IO;
import org.eclipse.jetty.util.resource.Resource;
/**
@ -64,7 +77,7 @@ import org.eclipse.jetty.util.IO;
* There is a <a href="run-war-mojo.html">reference guide</a> to the configuration parameters for this plugin, and more detailed information
* with examples in the <a href="http://docs.codehaus.org/display/JETTY/Maven+Jetty+Plugin/">Configuration Guide</a>.
* </p>
*
*
* @goal run-forked
* @requiresDependencyResolution compile+runtime
* @execute phase="test-compile"
@ -72,17 +85,17 @@ import org.eclipse.jetty.util.IO;
*
*/
public class JettyRunForkedMojo extends AbstractMojo
{
{
public String PORT_SYSPROPERTY = "jetty.port";
/**
* Whether or not to include dependencies on the plugin's classpath with &lt;scope&gt;provided&lt;/scope&gt;
* Use WITH CAUTION as you may wind up with duplicate jars/classes.
* @parameter default-value="false"
*/
protected boolean useProvidedScope;
/**
* The maven project.
*
@ -91,9 +104,9 @@ public class JettyRunForkedMojo extends AbstractMojo
* @readonly
*/
private MavenProject project;
/**
* If true, the &lt;testOutputDirectory&gt;
* and the dependencies of &lt;scope&gt;test&lt;scope&gt;
@ -101,27 +114,27 @@ public class JettyRunForkedMojo extends AbstractMojo
* @parameter alias="useTestClasspath" default-value="false"
*/
private boolean useTestScope;
/**
* The default location of the web.xml file. Will be used
* if &lt;webAppConfig&gt;&lt;descriptor&gt; is not set.
*
*
* @parameter expression="${basedir}/src/main/webapp/WEB-INF/web.xml"
* @readonly
*/
private String webXml;
/**
* The target directory
*
*
* @parameter expression="${project.build.directory}"
* @required
* @readonly
*/
protected File target;
/**
* The temporary directory to use for the webapp.
* Defaults to target/tmp
@ -132,26 +145,26 @@ public class JettyRunForkedMojo extends AbstractMojo
*/
protected File tmpDirectory;
/**
* The directory containing generated classes.
*
* @parameter expression="${project.build.outputDirectory}"
* @required
*
*
*/
private File classesDirectory;
/**
* The directory containing generated test classes.
*
*
* @parameter expression="${project.build.testOutputDirectory}"
* @required
*/
private File testClassesDirectory;
/**
* Root directory for all html/jsp etc files
*
@ -159,34 +172,34 @@ public class JettyRunForkedMojo extends AbstractMojo
*
*/
private File webAppSourceDirectory;
/**
* Directories that contain static resources
* for the webapp. Optional.
*
*
* @parameter
*/
private File[] resourceBases;
/**
* If true, the webAppSourceDirectory will be first on the list of
* resources that form the resource base for the webapp. If false,
* If true, the webAppSourceDirectory will be first on the list of
* resources that form the resource base for the webapp. If false,
* it will be last.
*
*
* @parameter default-value="true"
*/
private boolean baseAppFirst;
/**
* Location of jetty xml configuration files whose contents
* Location of jetty xml configuration files whose contents
* will be applied before any plugin configuration. Optional.
* @parameter
*/
private String jettyXml;
/**
* The context path for the webapp. Defaults to the
* name of the webapp's artifact.
@ -205,71 +218,71 @@ public class JettyRunForkedMojo extends AbstractMojo
*/
private String contextXml;
/**
/**
* @parameter expression="${jetty.skip}" default-value="false"
*/
private boolean skip;
/**
* Port to listen to stop jetty on executing -DSTOP.PORT=&lt;stopPort&gt;
* Port to listen to stop jetty on executing -DSTOP.PORT=&lt;stopPort&gt;
* -DSTOP.KEY=&lt;stopKey&gt; -jar start.jar --stop
* @parameter
* @required
*/
protected int stopPort;
/**
* Key to provide when stopping jetty on executing java -DSTOP.KEY=&lt;stopKey&gt;
* Key to provide when stopping jetty on executing java -DSTOP.KEY=&lt;stopKey&gt;
* -DSTOP.PORT=&lt;stopPort&gt; -jar start.jar --stop
* @parameter
* @required
*/
protected String stopKey;
/**
* Arbitrary jvm args to pass to the forked process
* @parameter
*/
private String jvmArgs;
/**
* @parameter expression="${plugin.artifacts}"
* @readonly
*/
private List pluginArtifacts;
/**
* @parameter expression="${plugin}"
* @readonly
*/
private PluginDescriptor plugin;
/**
* @parameter expression="true" default-value="true"
*/
private boolean waitForChild;
private Process forkedProcess;
private Random random;
public class ShutdownThread extends Thread
{
public ShutdownThread()
{
super("RunForkedShutdown");
}
public void run ()
{
if (forkedProcess != null && waitForChild)
@ -278,7 +291,7 @@ public class JettyRunForkedMojo extends AbstractMojo
}
}
}
/**
* @see org.apache.maven.plugin.Mojo#execute()
*/
@ -295,20 +308,20 @@ public class JettyRunForkedMojo extends AbstractMojo
random = new Random();
startJettyRunner();
}
public List<String> getProvidedJars() throws MojoExecutionException
{
{
//if we are configured to include the provided dependencies on the plugin's classpath
//(which mimics being on jetty's classpath vs being on the webapp's classpath), we first
//try and filter out ones that will clash with jars that are plugin dependencies, then
//create a new classloader that we setup in the parent chain.
if (useProvidedScope)
{
List<String> provided = new ArrayList<String>();
List<String> provided = new ArrayList<String>();
for ( Iterator<Artifact> iter = project.getArtifacts().iterator(); iter.hasNext(); )
{
{
Artifact artifact = iter.next();
if (Artifact.SCOPE_PROVIDED.equals(artifact.getScope()) && !isPluginArtifact(artifact))
{
@ -322,16 +335,16 @@ public class JettyRunForkedMojo extends AbstractMojo
else
return null;
}
/* ------------------------------------------------------------ */
public File prepareConfiguration() throws MojoExecutionException
{
try
{
{
//work out the configuration based on what is configured in the pom
File propsFile = new File (target, "fork.props");
if (propsFile.exists())
propsFile.delete();
propsFile.delete();
propsFile.createNewFile();
//propsFile.deleteOnExit();
@ -358,9 +371,9 @@ public class JettyRunForkedMojo extends AbstractMojo
//sort out base dir of webapp
if (webAppSourceDirectory != null)
props.put("base.dir", webAppSourceDirectory.getAbsolutePath());
//sort out the resource base directories of the webapp
StringBuilder builder = new StringBuilder();
StringBuilder builder = new StringBuilder();
if (baseAppFirst)
{
add((webAppSourceDirectory==null?null:webAppSourceDirectory.getAbsolutePath()), builder);
@ -371,7 +384,7 @@ public class JettyRunForkedMojo extends AbstractMojo
}
}
else
{
{
if (resourceBases != null)
{
for (File resDir:resourceBases)
@ -380,7 +393,7 @@ public class JettyRunForkedMojo extends AbstractMojo
add((webAppSourceDirectory==null?null:webAppSourceDirectory.getAbsolutePath()), builder);
}
props.put("res.dirs", builder.toString());
//web-inf classes
List<File> classDirs = getClassesDirs();
@ -397,7 +410,7 @@ public class JettyRunForkedMojo extends AbstractMojo
{
props.put("classes.dir", classesDirectory.getAbsolutePath());
}
if (useTestScope && testClassesDirectory != null)
{
props.put("testClasses.dir", testClassesDirectory.getAbsolutePath());
@ -435,7 +448,7 @@ public class JettyRunForkedMojo extends AbstractMojo
throw new MojoExecutionException("Prepare webapp configuration", e);
}
}
private void add (String string, StringBuilder builder)
{
if (string == null)
@ -448,62 +461,62 @@ public class JettyRunForkedMojo extends AbstractMojo
private List<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 (classesDirectory != null)
classesDirs.add(classesDirectory);
return classesDirs;
}
private List<File> getOverlays()
throws MalformedURLException, IOException
{
List<File> overlays = new ArrayList<File>();
for ( Iterator<Artifact> iter = project.getArtifacts().iterator(); iter.hasNext(); )
{
Artifact artifact = (Artifact) iter.next();
Artifact artifact = (Artifact) iter.next();
if (artifact.getType().equals("war"))
overlays.add(artifact.getFile());
}
return overlays;
}
private List<File> getDependencyFiles ()
{
List<File> dependencyFiles = new ArrayList<File>();
for ( Iterator<Artifact> iter = project.getArtifacts().iterator(); iter.hasNext(); )
{
Artifact artifact = (Artifact) iter.next();
if (((!Artifact.SCOPE_PROVIDED.equals(artifact.getScope())) && (!Artifact.SCOPE_TEST.equals( artifact.getScope())))
if (((!Artifact.SCOPE_PROVIDED.equals(artifact.getScope())) && (!Artifact.SCOPE_TEST.equals( artifact.getScope())))
||
(useTestScope && Artifact.SCOPE_TEST.equals( artifact.getScope())))
{
dependencyFiles.add(artifact.getFile());
getLog().debug( "Adding artifact " + artifact.getFile().getName() + " for WEB-INF/lib " );
getLog().debug( "Adding artifact " + artifact.getFile().getName() + " for WEB-INF/lib " );
}
}
return dependencyFiles;
return dependencyFiles;
}
public boolean isPluginArtifact(Artifact artifact)
{
if (pluginArtifacts == null || pluginArtifacts.isEmpty())
return false;
boolean isPluginArtifact = false;
for (Iterator<Artifact> iter = pluginArtifacts.iterator(); iter.hasNext() && !isPluginArtifact; )
{
@ -512,18 +525,18 @@ public class JettyRunForkedMojo extends AbstractMojo
if (pluginArtifact.getGroupId().equals(artifact.getGroupId()) && pluginArtifact.getArtifactId().equals(artifact.getArtifactId()))
isPluginArtifact = true;
}
return isPluginArtifact;
}
private Set<Artifact> getExtraJars()
throws Exception
{
Set<Artifact> extraJars = new HashSet<Artifact>();
List l = pluginArtifacts;
Artifact pluginArtifact = null;
@ -531,7 +544,7 @@ public class JettyRunForkedMojo extends AbstractMojo
{
Iterator itor = l.iterator();
while (itor.hasNext() && pluginArtifact == null)
{
{
Artifact a = (Artifact)itor.next();
if (a.getArtifactId().equals(plugin.getArtifactId())) //get the jetty-maven-plugin jar
{
@ -543,18 +556,18 @@ public class JettyRunForkedMojo extends AbstractMojo
return extraJars;
}
/* ------------------------------------------------------------ */
public void startJettyRunner() throws MojoExecutionException
{
{
try
{
File props = prepareConfiguration();
List<String> cmd = new ArrayList<String>();
cmd.add(getJavaBin());
if (jvmArgs != null)
{
String[] args = jvmArgs.split(" ");
@ -564,7 +577,7 @@ public class JettyRunForkedMojo extends AbstractMojo
cmd.add(args[i].trim());
}
}
String classPath = getClassPath();
if (classPath != null && classPath.length() > 0)
{
@ -572,7 +585,7 @@ public class JettyRunForkedMojo extends AbstractMojo
cmd.add(classPath);
}
cmd.add(Starter.class.getCanonicalName());
if (stopPort > 0 && stopKey != null)
{
cmd.add("--stop-port");
@ -585,26 +598,26 @@ public class JettyRunForkedMojo extends AbstractMojo
cmd.add("--jetty-xml");
cmd.add(jettyXml);
}
if (contextXml != null)
{
cmd.add("--context-xml");
cmd.add(contextXml);
}
cmd.add("--props");
cmd.add(props.getAbsolutePath());
String token = createToken();
cmd.add("--token");
cmd.add(token);
ProcessBuilder builder = new ProcessBuilder(cmd);
builder.directory(project.getBasedir());
if (PluginLog.getLog().isDebugEnabled())
PluginLog.getLog().debug(Arrays.toString(cmd.toArray()));
forkedProcess = builder.start();
PluginLog.getLog().info("Forked process starting");
@ -612,7 +625,7 @@ public class JettyRunForkedMojo extends AbstractMojo
{
startPump("STDOUT",forkedProcess.getInputStream());
startPump("STDERR",forkedProcess.getErrorStream());
int exitcode = forkedProcess.waitFor();
int exitcode = forkedProcess.waitFor();
PluginLog.getLog().info("Forked execution exit: "+exitcode);
}
else
@ -652,20 +665,20 @@ public class JettyRunForkedMojo extends AbstractMojo
{
if (forkedProcess != null && waitForChild)
forkedProcess.destroy();
throw new MojoExecutionException("Failed to start Jetty within time limit");
}
catch (Exception ex)
{
if (forkedProcess != null && waitForChild)
forkedProcess.destroy();
throw new MojoExecutionException("Failed to create Jetty process", ex);
}
}
public String getClassPath() throws Exception
{
StringBuilder classPath = new StringBuilder();
@ -682,16 +695,16 @@ public class JettyRunForkedMojo extends AbstractMojo
}
}
//Any jars that we need from the plugin environment (like the ones containing Starter class)
Set<Artifact> extraJars = getExtraJars();
for (Artifact a:extraJars)
{
{
classPath.append(File.pathSeparator);
classPath.append(a.getFile().getAbsolutePath());
}
//Any jars that we need from the project's dependencies because we're useProvided
List<String> providedJars = getProvidedJars();
if (providedJars != null && !providedJars.isEmpty())
@ -703,7 +716,7 @@ public class JettyRunForkedMojo extends AbstractMojo
if (getLog().isDebugEnabled()) getLog().debug("Adding provided jar: "+jar);
}
}
return classPath.toString();
}
@ -724,7 +737,7 @@ public class JettyRunForkedMojo extends AbstractMojo
return "java";
}
public static String fileSeparators(String path)
{
StringBuilder ret = new StringBuilder();
@ -759,13 +772,13 @@ public class JettyRunForkedMojo extends AbstractMojo
return ret.toString();
}
private String createToken ()
{
return Long.toString(random.nextLong()^System.currentTimeMillis(), 36).toUpperCase();
return Long.toString(random.nextLong()^System.currentTimeMillis(), 36).toUpperCase(Locale.ENGLISH);
}
private void startPump(String mode, InputStream inputStream)
{
ConsoleStreamer pump = new ConsoleStreamer(mode,inputStream);
@ -774,7 +787,7 @@ public class JettyRunForkedMojo extends AbstractMojo
thread.start();
}
/**

View File

@ -63,6 +63,9 @@ import org.eclipse.jetty.webapp.WebAppContext;
*/
public class JettyRunMojo extends AbstractJettyMojo
{
public static final String DEFAULT_WEBAPP_SRC = "src"+File.separator+"main"+File.separator+"webapp";
/**
* If true, the &lt;testOutputDirectory&gt;
* and the dependencies of &lt;scope&gt;test&lt;scope&gt;
@ -134,12 +137,13 @@ public class JettyRunMojo extends AbstractJettyMojo
*/
private List<File> extraScanTargets;
/**
* Verify the configuration given in the pom.
*
* @see org.eclipse.jetty.maven.plugin.AbstractJettyMojo#checkPomConfiguration()
* @see org.mortbay.jetty.plugin.AbstractJettyMojo#checkPomConfiguration()
*/
public void checkPomConfiguration () throws MojoExecutionException
{
@ -147,9 +151,10 @@ public class JettyRunMojo extends AbstractJettyMojo
try
{
if ((getWebAppSourceDirectory() == null) || !getWebAppSourceDirectory().exists())
{
webAppSourceDirectory = new File (project.getBasedir(), "src"+File.separator+"main"+File.separator+"webapp");
getLog().info("webAppSourceDirectory "+getWebAppSourceDirectory() +" does not exist. Defaulting to "+webAppSourceDirectory.getAbsolutePath());
{
File defaultWebAppSrcDir = new File (project.getBasedir(), DEFAULT_WEBAPP_SRC);
getLog().info("webAppSourceDirectory"+(getWebAppSourceDirectory()==null?" not set.":" does not exist.")+" Defaulting to "+defaultWebAppSrcDir.getAbsolutePath());
webAppSourceDirectory = defaultWebAppSrcDir;
}
else
getLog().info( "Webapp source directory = " + getWebAppSourceDirectory().getCanonicalPath());
@ -441,6 +446,7 @@ public class JettyRunMojo extends AbstractJettyMojo
for ( Iterator<Artifact> iter = projectArtifacts.iterator(); iter.hasNext(); )
{
Artifact artifact = (Artifact) iter.next();
// Include runtime and compile time libraries, and possibly test libs too
if(artifact.getType().equals("war"))
{
@ -448,6 +454,7 @@ public class JettyRunMojo extends AbstractJettyMojo
{
Resource r=Resource.newResource("jar:"+Resource.toURL(artifact.getFile()).toString()+"!/");
overlays.add(r);
getLog().info("Adding overlay for war project artifact "+artifact.getId());
getExtraScanTargets().add(artifact.getFile());
}
catch(Exception e)

View File

@ -25,19 +25,21 @@ import java.util.List;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.eclipse.jetty.util.Scanner;
import org.eclipse.jetty.util.resource.Resource;
import org.eclipse.jetty.xml.XmlConfiguration;
/**
*
*
* <p>
* This goal is used to assemble your webapp into an exploded war and automatically deploy it to Jetty.
* </p>
* <p>
* Once invoked, the plugin can be configured to run continuously, scanning for changes in the pom.xml and
* to WEB-INF/web.xml, WEB-INF/classes or WEB-INF/lib and hot redeploy when a change is detected.
* Once invoked, the plugin can be configured to run continuously, scanning for changes in the pom.xml and
* to WEB-INF/web.xml, WEB-INF/classes or WEB-INF/lib and hot redeploy when a change is detected.
* </p>
* <p>
* You may also specify the location of a jetty.xml file whose contents will be applied before any plugin configuration.
* This can be used, for example, to deploy a static webapp that is not part of your maven build.
* This can be used, for example, to deploy a static webapp that is not part of your maven build.
* </p>
* <p>
* There is a <a href="run-exploded-mojo.html">reference guide</a> to the configuration parameters for this plugin, and more detailed information
@ -51,24 +53,24 @@ import org.eclipse.jetty.util.Scanner;
public class JettyRunWarExplodedMojo extends AbstractJettyMojo
{
/**
* The location of the war file.
*
*
* @parameter alias="webApp" expression="${project.build.directory}/${project.build.finalName}"
* @required
*/
private File war;
/**
*
* @see org.eclipse.jetty.maven.plugin.AbstractJettyMojo#checkPomConfiguration()
*
* @see org.mortbay.jetty.plugin.AbstractJettyMojo#checkPomConfiguration()
*/
public void checkPomConfiguration() throws MojoExecutionException
{
@ -76,7 +78,7 @@ public class JettyRunWarExplodedMojo extends AbstractJettyMojo
}
/**
* @see org.eclipse.jetty.maven.plugin.AbstractJettyMojo#configureScanner()
* @see org.mortbay.jetty.plugin.AbstractJettyMojo#configureScanner()
*/
public void configureScanner() throws MojoExecutionException
{
@ -93,7 +95,7 @@ public class JettyRunWarExplodedMojo extends AbstractJettyMojo
scanList.add(new File(webInfDir, "classes"));
scanList.add(new File(webInfDir, "lib"));
setScanList(scanList);
ArrayList<Scanner.BulkListener> listeners = new ArrayList<Scanner.BulkListener>();
listeners.add(new Scanner.BulkListener()
{
@ -113,10 +115,10 @@ public class JettyRunWarExplodedMojo extends AbstractJettyMojo
setScannerListeners(listeners);
}
public void restartWebApp(boolean reconfigureScanner) throws Exception
public void restartWebApp(boolean reconfigureScanner) throws Exception
{
getLog().info("Restarting webapp");
getLog().debug("Stopping webapp ...");
@ -152,20 +154,20 @@ public class JettyRunWarExplodedMojo extends AbstractJettyMojo
getLog().info("Restart completed.");
}
public void configureWebApplication () throws Exception
{
super.configureWebApplication();
super.configureWebApplication();
webApp.setWar(war.getCanonicalPath());
}
public void execute () throws MojoExecutionException, MojoFailureException
{
super.execute();
}
}

View File

@ -21,10 +21,14 @@ package org.eclipse.jetty.maven.plugin;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import org.apache.maven.artifact.Artifact;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.eclipse.jetty.util.Scanner;
import org.eclipse.jetty.util.resource.Resource;
import org.eclipse.jetty.xml.XmlConfiguration;
/**
* <p>
@ -32,18 +36,18 @@ import org.eclipse.jetty.util.Scanner;
* </p>
* <p>
* Once invoked, the plugin can be configured to run continuously, scanning for changes in the project and to the
* war file and automatically performing a
* hot redeploy when necessary.
* war file and automatically performing a
* hot redeploy when necessary.
* </p>
* <p>
* You may also specify the location of a jetty.xml file whose contents will be applied before any plugin configuration.
* This can be used, for example, to deploy a static webapp that is not part of your maven build.
* This can be used, for example, to deploy a static webapp that is not part of your maven build.
* </p>
* <p>
* There is a <a href="run-war-mojo.html">reference guide</a> to the configuration parameters for this plugin, and more detailed information
* with examples in the <a href="http://docs.codehaus.org/display/JETTY/Maven+Jetty+Plugin/">Configuration Guide</a>.
* </p>
*
*
* @goal run-war
* @requiresDependencyResolution compile+runtime
* @execute phase="package"
@ -61,13 +65,13 @@ public class JettyRunWarMojo extends AbstractJettyMojo
private File war;
/**
* @see org.apache.maven.plugin.Mojo#execute()
*/
public void execute() throws MojoExecutionException, MojoFailureException
{
super.execute();
super.execute();
}
@ -75,18 +79,18 @@ public class JettyRunWarMojo extends AbstractJettyMojo
public void configureWebApplication () throws Exception
{
super.configureWebApplication();
webApp.setWar(war.getCanonicalPath());
}
/**
* @see org.eclipse.jetty.maven.plugin.AbstractJettyMojo#checkPomConfiguration()
* @see org.mortbay.jetty.plugin.AbstractJettyMojo#checkPomConfiguration()
*/
public void checkPomConfiguration() throws MojoExecutionException
{
return;
return;
}
@ -100,7 +104,7 @@ public class JettyRunWarMojo extends AbstractJettyMojo
scanList.add(getProject().getFile());
scanList.add(war);
setScanList(scanList);
ArrayList listeners = new ArrayList();
listeners.add(new Scanner.BulkListener()
{
@ -117,11 +121,11 @@ public class JettyRunWarMojo extends AbstractJettyMojo
}
}
});
setScannerListeners(listeners);
setScannerListeners(listeners);
}
public void restartWebApp(boolean reconfigureScanner) throws Exception
public void restartWebApp(boolean reconfigureScanner) throws Exception
{
getLog().info("Restarting webapp ...");
getLog().debug("Stopping webapp ...");

View File

@ -23,7 +23,6 @@ import org.eclipse.jetty.server.Connector;
import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.server.RequestLog;
import org.eclipse.jetty.server.ServerConnector;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.handler.ContextHandlerCollection;
import org.eclipse.jetty.server.handler.DefaultHandler;
import org.eclipse.jetty.server.handler.HandlerCollection;
@ -33,20 +32,20 @@ import org.eclipse.jetty.webapp.WebAppContext;
/**
* JettyServer
*
*
* Maven jetty plugin version of a wrapper for the Server class.
*
*
*/
public class JettyServer extends org.eclipse.jetty.server.Server
{
public static int DEFAULT_PORT = 8080;
public static int DEFAULT_MAX_IDLE_TIME = 30000;
private RequestLog requestLog;
private ContextHandlerCollection contexts;
public JettyServer()
{
super();
@ -55,7 +54,7 @@ public class JettyServer extends org.eclipse.jetty.server.Server
Resource.setDefaultUseCaches(false);
}
public void setRequestLog (RequestLog requestLog)
{
this.requestLog = requestLog;
@ -69,16 +68,16 @@ public class JettyServer extends org.eclipse.jetty.server.Server
super.doStart();
}
/**
* @see org.eclipse.jetty.server.handler.HandlerCollection#addHandler(org.eclipse.jetty.server.Handler)
*/
public void addWebApplication(WebAppContext webapp) throws Exception
{
{
contexts.addHandler (webapp);
}
/**
* Set up the handler structure to receive a webapp.
* Also put in a DefaultHandler so we get a nice page
@ -86,43 +85,43 @@ public class JettyServer extends org.eclipse.jetty.server.Server
* context isn't at root.
* @throws Exception
*/
public void configureHandlers () throws Exception
public void configureHandlers () throws Exception
{
DefaultHandler defaultHandler = new DefaultHandler();
RequestLogHandler requestLogHandler = new RequestLogHandler();
if (this.requestLog != null)
requestLogHandler.setRequestLog(this.requestLog);
contexts = (ContextHandlerCollection)super.getChildHandlerByClass(ContextHandlerCollection.class);
if (contexts==null)
{
{
contexts = new ContextHandlerCollection();
HandlerCollection handlers = (HandlerCollection)super.getChildHandlerByClass(HandlerCollection.class);
if (handlers==null)
{
handlers = new HandlerCollection();
super.setHandler(handlers);
handlers = new HandlerCollection();
super.setHandler(handlers);
handlers.setHandlers(new Handler[]{contexts, defaultHandler, requestLogHandler});
}
else
{
handlers.addHandler(contexts);
}
}
}
}
public Connector createDefaultConnector(Server server, String portnum) throws Exception
public Connector createDefaultConnector(String portnum) throws Exception
{
ServerConnector connector = new ServerConnector(server);
ServerConnector connector = new ServerConnector(this);
int port = ((portnum==null||portnum.equals(""))?DEFAULT_PORT:Integer.parseInt(portnum.trim()));
connector.setPort(port);
connector.setIdleTimeout(DEFAULT_MAX_IDLE_TIME);
// connector.setMaxIdleTime(DEFAULT_MAX_IDLE_TIME);
return connector;
}
}

View File

@ -28,7 +28,6 @@ import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import org.eclipse.jetty.annotations.AnnotationConfiguration;
import org.eclipse.jetty.plus.webapp.EnvConfiguration;
import org.eclipse.jetty.util.URIUtil;
import org.eclipse.jetty.util.log.Log;
@ -39,8 +38,8 @@ import org.eclipse.jetty.webapp.Configuration;
import org.eclipse.jetty.webapp.FragmentConfiguration;
import org.eclipse.jetty.webapp.JettyWebXmlConfiguration;
import org.eclipse.jetty.webapp.MetaInfConfiguration;
import org.eclipse.jetty.webapp.TagLibConfiguration;
import org.eclipse.jetty.webapp.WebAppContext;
import org.eclipse.jetty.webapp.WebInfConfiguration;
import org.eclipse.jetty.webapp.WebXmlConfiguration;
/**
@ -56,6 +55,7 @@ public class JettyWebAppContext extends WebAppContext
{
private static final Logger LOG = Log.getLogger(JettyWebAppContext.class);
private static final String DEFAULT_CONTAINER_INCLUDE_JAR_PATTERN = ".*/javax.servlet-[^/]*\\.jar$|.*/servlet-api-[^/]*\\.jar$";
private static final String WEB_INF_CLASSES_PREFIX = "/WEB-INF/classes";
private static final String WEB_INF_LIB_PREFIX = "/WEB-INF/lib";
@ -73,6 +73,19 @@ public class JettyWebAppContext extends WebAppContext
* @deprecated The value of this parameter will be ignored by the plugin. Overlays will always be unpacked.
*/
private boolean unpackOverlays;
/**
* Set the "org.eclipse.jetty.server.webapp.ContainerIncludeJarPattern" with a pattern for matching jars on
* container classpath to scan. This is analogous to the WebAppContext.setAttribute() call.
*/
private String containerIncludeJarPattern = null;
/**
* Set the "org.eclipse.jetty.server.webapp.WebInfIncludeJarPattern" with a pattern for matching jars on
* webapp's classpath to scan. This is analogous to the WebAppContext.setAttribute() call.
*/
private String webInfIncludeJarPattern = null;
/**
* @deprecated The value of this parameter will be ignored by the plugin. This option will be always disabled.
@ -91,14 +104,34 @@ public class JettyWebAppContext extends WebAppContext
new MetaInfConfiguration(),
new FragmentConfiguration(),
envConfig = new EnvConfiguration(),
new AnnotationConfiguration(),
new org.eclipse.jetty.plus.webapp.PlusConfiguration(),
new JettyWebXmlConfiguration(),
new TagLibConfiguration()
new MavenAnnotationConfiguration(),
new JettyWebXmlConfiguration()
});
// Turn off copyWebInf option as it is not applicable for plugin.
super.setCopyWebInf(false);
}
public void setContainerIncludeJarPattern(String pattern)
{
containerIncludeJarPattern = pattern;
}
public String getContainerIncludeJarPattern()
{
return containerIncludeJarPattern;
}
public String getWebInfIncludeJarPattern()
{
return webInfIncludeJarPattern;
}
public void setWebInfIncludeJarPattern(String pattern)
{
webInfIncludeJarPattern = pattern;
}
public boolean getUnpackOverlays()
{
@ -218,17 +251,21 @@ public class JettyWebAppContext extends WebAppContext
{
//Set up the pattern that tells us where the jars are that need scanning for
//stuff like taglibs so we can tell jasper about it (see TagLibConfiguration)
String tmp = (String)getAttribute("org.eclipse.jetty.server.webapp.ContainerIncludeJarPattern");
tmp = addPattern(tmp, ".*/.*jsp-api-[^/]*\\.jar$");
tmp = addPattern(tmp, ".*/.*jsp-[^/]*\\.jar$");
tmp = addPattern(tmp, ".*/.*taglibs[^/]*\\.jar$");
tmp = addPattern(tmp, ".*/.*jstl[^/]*\\.jar$");
tmp = addPattern(tmp, ".*/.*jsf-impl-[^/]*\\.jar$"); // add in 2 most popular jsf impls
tmp = addPattern(tmp, ".*/.*javax.faces-[^/]*\\.jar$");
tmp = addPattern(tmp, ".*/.*myfaces-impl-[^/]*\\.jar$");
setAttribute("org.eclipse.jetty.server.webapp.ContainerIncludeJarPattern", tmp);
//Allow user to set up pattern for names of jars from the container classpath
//that will be scanned - note that by default NO jars are scanned
String tmp = containerIncludeJarPattern;
if (tmp==null || "".equals(tmp))
tmp = (String)getAttribute(WebInfConfiguration.CONTAINER_JAR_PATTERN);
tmp = addPattern(tmp, DEFAULT_CONTAINER_INCLUDE_JAR_PATTERN);
setAttribute(WebInfConfiguration.CONTAINER_JAR_PATTERN, tmp);
//Allow user to set up pattern of jar names from WEB-INF that will be scanned.
//Note that by default ALL jars considered to be in WEB-INF will be scanned - setting
//a pattern restricts scanning
if (webInfIncludeJarPattern != null)
setAttribute(WebInfConfiguration.WEBINF_JAR_PATTERN, webInfIncludeJarPattern);
//Set up the classes dirs that comprises the equivalent of WEB-INF/classes
if (testClasses != null)
@ -241,7 +278,6 @@ public class JettyWebAppContext extends WebAppContext
classpathFiles.addAll(webInfClasses);
classpathFiles.addAll(webInfJars);
// Initialize map containing all jars in /WEB-INF/lib
webInfJarMap.clear();
for (File file : webInfJars)
@ -255,13 +291,28 @@ public class JettyWebAppContext extends WebAppContext
if (this.jettyEnvXml != null)
envConfig.setJettyEnvXml(Resource.toURL(new File(this.jettyEnvXml)));
//setShutdown(false);
// CHECK setShutdown(false);
super.doStart();
}
public void doStop () throws Exception
{
//setShutdown(true);
if (classpathFiles != null)
classpathFiles.clear();
classpathFiles = null;
classes = null;
testClasses = null;
if (webInfJarMap != null)
webInfJarMap.clear();
webInfClasses.clear();
webInfJars.clear();
// CHECK setShutdown(true);
//just wait a little while to ensure no requests are still being processed
Thread.currentThread().sleep(500L);
super.doStop();
@ -344,37 +395,40 @@ public class JettyWebAppContext extends WebAppContext
@Override
public Set<String> getResourcePaths(String path)
{
// Try to get regular resource paths
// Try to get regular resource paths - this will get appropriate paths from any overlaid wars etc
Set<String> paths = super.getResourcePaths(path);
// If no paths are returned check for virtual paths /WEB-INF/classes and /WEB-INF/lib
if (paths.isEmpty() && path != null)
if (path != null)
{
path = URIUtil.canonicalPath(path);
TreeSet<String> allPaths = new TreeSet<String>();
allPaths.addAll(paths);
//add in the dependency jars as a virtual WEB-INF/lib entry
if (path.startsWith(WEB_INF_LIB_PREFIX))
{
paths = new TreeSet<String>();
for (String fileName : webInfJarMap.keySet())
{
// Return all jar files from class path
paths.add(WEB_INF_LIB_PREFIX + "/" + fileName);
allPaths.add(WEB_INF_LIB_PREFIX + "/" + fileName);
}
}
else if (path.startsWith(WEB_INF_CLASSES_PREFIX))
{
int i=0;
while (paths.isEmpty() && (i < webInfClasses.size()))
while (i < webInfClasses.size())
{
String newPath = path.replace(WEB_INF_CLASSES_PREFIX, webInfClasses.get(i).getPath());
paths = super.getResourcePaths(newPath);
allPaths.addAll(super.getResourcePaths(newPath));
i++;
}
}
return allPaths;
}
return paths;
}
public String addPattern (String s, String pattern)
{
if (s == null)

View File

@ -0,0 +1,109 @@
//
// ========================================================================
// Copyright (c) 1995-2012 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
//
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
//
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
//
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
//
package org.eclipse.jetty.maven.plugin;
import java.io.File;
import org.eclipse.jetty.annotations.AbstractDiscoverableAnnotationHandler;
import org.eclipse.jetty.annotations.AnnotationConfiguration;
import org.eclipse.jetty.annotations.AnnotationParser;
import org.eclipse.jetty.annotations.AnnotationParser.DiscoverableAnnotationHandler;
import org.eclipse.jetty.annotations.ClassNameResolver;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
import org.eclipse.jetty.util.resource.Resource;
import org.eclipse.jetty.webapp.MetaData;
import org.eclipse.jetty.webapp.WebAppContext;
public class MavenAnnotationConfiguration extends AnnotationConfiguration
{
private static final Logger LOG = Log.getLogger(MavenAnnotationConfiguration.class);
/* ------------------------------------------------------------ */
@Override
public void parseWebInfClasses(final WebAppContext context, final AnnotationParser parser) throws Exception
{
JettyWebAppContext jwac = (JettyWebAppContext)context;
if (jwac.getClassPathFiles() == null || jwac.getClassPathFiles().size() == 0)
super.parseWebInfClasses (context, parser);
else
{
LOG.debug("Scanning classes ");
//Look for directories on the classpath and process each one of those
MetaData metaData = context.getMetaData();
if (metaData == null)
throw new IllegalStateException ("No metadata");
parser.clearHandlers();
for (DiscoverableAnnotationHandler h:_discoverableAnnotationHandlers)
{
if (h instanceof AbstractDiscoverableAnnotationHandler)
((AbstractDiscoverableAnnotationHandler)h).setResource(null); //
}
parser.registerHandlers(_discoverableAnnotationHandlers);
parser.registerHandler(_classInheritanceHandler);
parser.registerHandlers(_containerInitializerAnnotationHandlers);
for (File f:jwac.getClassPathFiles())
{
//scan the equivalent of the WEB-INF/classes directory that has been synthesised by the plugin
if (f.isDirectory() && f.exists())
{
doParse(context, parser, Resource.newResource(f.toURL()));
}
}
//if an actual WEB-INF/classes directory also exists (eg because of overlayed wars) then scan that
//too
if (context.getWebInf() != null && context.getWebInf().exists())
{
Resource classesDir = context.getWebInf().addPath("classes/");
if (classesDir.exists())
{
doParse(context, parser, classesDir);
}
}
}
}
public void doParse (final WebAppContext context, final AnnotationParser parser, Resource resource)
throws Exception
{
parser.parse(resource, new ClassNameResolver()
{
public boolean isExcluded (String name)
{
if (context.isSystemClass(name)) return true;
if (context.isServerClass(name)) return false;
return false;
}
public boolean shouldOverride (String name)
{
//looking at webapp classpath, found already-parsed class of same name - did it come from system or duplicate in webapp?
if (context.isParentLoaderPriority())
return false;
return true;
}
});
}
}

View File

@ -24,8 +24,10 @@ import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import org.eclipse.jetty.util.IO;
import org.eclipse.jetty.util.LazyList;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
import org.eclipse.jetty.util.resource.Resource;
@ -40,8 +42,8 @@ public class MavenWebInfConfiguration extends WebInfConfiguration
protected Resource _originalResourceBase;
protected Resource[] _unpackedOverlays;
public void configure(WebAppContext context) throws Exception
{
JettyWebAppContext jwac = (JettyWebAppContext)context;
@ -54,11 +56,11 @@ public class MavenWebInfConfiguration extends WebInfConfiguration
while (itor.hasNext())
((WebAppClassLoader)context.getClassLoader()).addClassPath(((File)itor.next()).getCanonicalPath());
if (LOG.isDebugEnabled())
LOG.debug("Classpath = "+((URLClassLoader)context.getClassLoader()).getURLs());
//if (LOG.isDebugEnabled())
//LOG.debug("Classpath = "+LazyList.array2List(((URLClassLoader)context.getClassLoader()).getURLs()));
}
super.configure(context);
// knock out environmental maven and plexus classes from webAppContext
String[] existingServerClasses = context.getServerClasses();
String[] newServerClasses = new String[2+(existingServerClasses==null?0:existingServerClasses.length)];
@ -71,7 +73,7 @@ public class MavenWebInfConfiguration extends WebInfConfiguration
for (int i=0;i<newServerClasses.length;i++)
LOG.debug(newServerClasses[i]);
}
context.setServerClasses( newServerClasses );
context.setServerClasses( newServerClasses );
}
@ -79,6 +81,53 @@ public class MavenWebInfConfiguration extends WebInfConfiguration
{
super.preConfigure(context);
}
public void postConfigure(WebAppContext context) throws Exception
{
super.postConfigure(context);
}
public void deconfigure(WebAppContext context) throws Exception
{
JettyWebAppContext jwac = (JettyWebAppContext)context;
//remove the unpacked wars
if (_unpackedOverlays != null && _unpackedOverlays.length>0)
{
try
{
for (int i=0; i<_unpackedOverlays.length; i++)
{
IO.delete(_unpackedOverlays[i].getFile());
}
}
catch (IOException e)
{
LOG.ignore(e);
}
}
super.deconfigure(context);
//restore whatever the base resource was before we might have included overlaid wars
context.setBaseResource(_originalResourceBase);
}
/**
* @see org.eclipse.jetty.webapp.WebInfConfiguration#unpack(org.eclipse.jetty.webapp.WebAppContext)
*/
@Override
public void unpack(WebAppContext context) throws IOException
{
//Unpack and find base resource as normal
super.unpack(context);
//Add in any overlays as a resource collection for the base
_originalResourceBase = context.getBaseResource();
JettyWebAppContext jwac = (JettyWebAppContext)context;
@ -102,7 +151,7 @@ public class MavenWebInfConfiguration extends WebInfConfiguration
origSize = 1;
}
}
int overlaySize = jwac.getOverlays().size();
Resource[] newResources = new Resource[origSize + overlaySize];
@ -112,7 +161,6 @@ public class MavenWebInfConfiguration extends WebInfConfiguration
if (jwac.getBaseAppFirst())
{
System.arraycopy(origResources,0,newResources,0,origSize);
offset = origSize;
}
else
@ -120,53 +168,23 @@ public class MavenWebInfConfiguration extends WebInfConfiguration
System.arraycopy(origResources,0,newResources,overlaySize,origSize);
}
}
// Overlays are always unpacked
_unpackedOverlays = new Resource[overlaySize];
List<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));
}
}
public void postConfigure(WebAppContext context) throws Exception
{
super.postConfigure(context);
}
public void deconfigure(WebAppContext context) throws Exception
{
JettyWebAppContext jwac = (JettyWebAppContext)context;
//remove the unpacked wars
if (_unpackedOverlays != null && _unpackedOverlays.length>0)
{
try
{
for (int i=0; i<_unpackedOverlays.length; i++)
{
IO.delete(_unpackedOverlays[i].getFile());
}
}
catch (IOException e)
{
LOG.ignore(e);
}
}
super.deconfigure(context);
//restore whatever the base resource was before we might have included overlaid wars
context.setBaseResource(_originalResourceBase);
}
/**
* Get the jars to examine from the files from which we have
@ -175,6 +193,7 @@ public class MavenWebInfConfiguration extends WebInfConfiguration
* @param context
* @return the list of jars found
*/
@Override
protected List<Resource> findJars (WebAppContext context)
throws Exception
{
@ -184,7 +203,7 @@ public class MavenWebInfConfiguration extends WebInfConfiguration
{
for (File f: jwac.getClassPathFiles())
{
if (f.getName().toLowerCase().endsWith(".jar"))
if (f.getName().toLowerCase(Locale.ENGLISH).endsWith(".jar"))
{
try
{
@ -203,14 +222,16 @@ public class MavenWebInfConfiguration extends WebInfConfiguration
list.addAll(superList);
return list;
}
protected Resource unpackOverlay (WebAppContext context, Resource overlay)
throws IOException
{
//resolve if not already resolved
resolveTempDirectory(context);
//Get the name of the overlayed war and unpack it to a dir of the
//same name in the temporary directory
String name = overlay.getName();
@ -225,6 +246,4 @@ public class MavenWebInfConfiguration extends WebInfConfiguration
Resource unpackedOverlay = Resource.newResource(dir.getCanonicalPath());
return unpackedOverlay;
}
}

View File

@ -16,12 +16,12 @@
// ========================================================================
//
package org.eclipse.jetty.maven.plugin;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.LineNumberReader;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
@ -41,7 +41,7 @@ import org.eclipse.jetty.server.Server;
* by stopping the Server instances. The choice of
* behaviour is controlled by either passing true
* (exit jvm) or false (stop Servers) in the constructor.
*
*
*/
public class Monitor extends Thread
{
@ -51,7 +51,7 @@ public class Monitor extends Thread
ServerSocket _serverSocket;
boolean _kill;
public Monitor(int port, String key, Server[] servers, boolean kill)
public Monitor(int port, String key, Server[] servers, boolean kill)
throws UnknownHostException, IOException
{
if (port <= 0)
@ -64,7 +64,7 @@ public class Monitor extends Thread
_kill = kill;
setDaemon(true);
setName("StopJettyPluginMonitor");
InetSocketAddress address = new InetSocketAddress("127.0.0.1", port);
InetSocketAddress address = new InetSocketAddress("127.0.0.1", port);
_serverSocket=new ServerSocket();
_serverSocket.setReuseAddress(true);
try
@ -77,7 +77,7 @@ public class Monitor extends Thread
throw x;
}
}
public void run()
{
while (_serverSocket != null)
@ -88,7 +88,7 @@ public class Monitor extends Thread
socket = _serverSocket.accept();
socket.setSoLinger(false, 0);
LineNumberReader lin = new LineNumberReader(new InputStreamReader(socket.getInputStream()));
String key = lin.readLine();
if (!_key.equals(key)) continue;
String cmd = lin.readLine();
@ -97,13 +97,13 @@ public class Monitor extends Thread
try{socket.close();}catch (Exception e){e.printStackTrace();}
try{socket.close();}catch (Exception e){e.printStackTrace();}
try{_serverSocket.close();}catch (Exception e){e.printStackTrace();}
_serverSocket = null;
if (_kill)
{
System.out.println("Killing Jetty");
System.exit(0);
System.exit(0);
}
else
{
@ -111,7 +111,7 @@ public class Monitor extends Thread
{
try
{
System.out.println("Stopping server "+i);
System.out.println("Stopping server "+i);
_servers[i].stop();
}
catch (Exception e)

View File

@ -23,19 +23,23 @@ import java.io.FileInputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import java.util.StringTokenizer;
import org.eclipse.jetty.server.Connector;
import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.handler.ContextHandler;
import org.eclipse.jetty.server.handler.ContextHandlerCollection;
import org.eclipse.jetty.server.handler.HandlerCollection;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
import org.eclipse.jetty.util.resource.Resource;
import org.eclipse.jetty.util.resource.ResourceCollection;
import org.eclipse.jetty.webapp.WebAppContext;
import org.eclipse.jetty.xml.XmlConfiguration;
public class Starter
{
{
public static final String PORT_SYSPROPERTY = "jetty.port";
private static final Logger LOG = Log.getLogger(Starter.class);
@ -45,21 +49,21 @@ public class Starter
private JettyServer server;
private JettyWebAppContext webApp;
private Monitor monitor;
private int stopPort=0;
private String stopKey=null;
private Properties props;
private String token;
public void configureJetty () throws Exception
{
LOG.debug("Starting Jetty Server ...");
this.server = new JettyServer();
//apply any configs from jetty.xml files first
//apply any configs from jetty.xml files first
applyJettyXml ();
// if the user hasn't configured a connector in the jetty.xml
@ -68,7 +72,7 @@ public class Starter
if (connectors == null|| connectors.length == 0)
{
//if a SystemProperty -Djetty.port=<portnum> has been supplied, use that as the default port
connectors = new Connector[] { this.server.createDefaultConnector(server, System.getProperty(PORT_SYSPROPERTY, null)) };
connectors = new Connector[] { this.server.createDefaultConnector(System.getProperty(PORT_SYSPROPERTY, null)) };
this.server.setConnectors(connectors);
}
@ -84,15 +88,15 @@ public class Starter
this.server.configureHandlers();
webApp = new JettyWebAppContext();
//configure webapp from properties file describing unassembled webapp
configureWebApp();
//set up the webapp from the context xml file provided
//NOTE: just like jetty:run mojo this means that the context file can
//potentially override settings made in the pom. Ideally, we'd like
//the pom to override the context xml file, but as the other mojos all
//configure a WebAppContext in the pom (the <webApp> element), it is
//configure a WebAppContext in the pom (the <webApp> element), it is
//already configured by the time the context xml file is applied.
if (contextXml != null)
{
@ -109,30 +113,30 @@ public class Starter
monitor = new Monitor(stopPort, stopKey, new Server[]{server}, true);
}
}
public void configureWebApp ()
throws Exception
{
if (props == null)
return;
//apply a properties file that defines the things that we configure in the jetty:run plugin:
// - the context path
String str = (String)props.get("context.path");
if (str != null)
webApp.setContextPath(str);
// - web.xml
str = (String)props.get("web.xml");
if (str != null)
webApp.setDescriptor(str);
// - the tmp directory
str = (String)props.getProperty("tmp.dir");
if (str != null)
webApp.setTempDirectory(new File(str.trim()));
// - the base directory
str = (String)props.getProperty("base.dir");
if (str != null && !"".equals(str.trim()))
@ -145,7 +149,7 @@ public class Starter
ResourceCollection resources = new ResourceCollection(str);
webApp.setBaseResource(resources);
}
// - overlays
str = (String)props.getProperty("overlay.files");
if (str != null && !"".equals(str.trim()))
@ -163,8 +167,8 @@ public class Starter
{
webApp.setClasses(new File(str));
}
str = (String)props.getProperty("testClasses.dir");
str = (String)props.getProperty("testClasses.dir");
if (str != null && !"".equals(str.trim()))
{
webApp.setTestClasses(new File(str));
@ -181,7 +185,7 @@ public class Starter
jars.add(new File(names[j].trim()));
webApp.setWebInfLib(jars);
}
}
public void getConfiguration (String[] args)
@ -205,7 +209,7 @@ public class Starter
for (int j=0; names!= null && j < names.length; j++)
{
jettyXmls.add(new File(names[j].trim()));
}
}
}
//--context-xml
@ -221,7 +225,7 @@ public class Starter
props = new Properties();
props.load(new FileInputStream(f));
}
//--token
if ("--token".equals(args[i]))
{
@ -237,16 +241,16 @@ public class Starter
monitor.start();
LOG.info("Started Jetty Server");
server.start();
server.start();
}
public void join () throws Exception
{
server.join();
}
public void communicateStartupResult (Exception e)
{
if (token != null)
@ -257,16 +261,16 @@ public class Starter
System.out.println(token+"\t"+e.getMessage());
}
}
public void applyJettyXml() throws Exception
{
if (jettyXmls == null)
return;
for ( File xmlFile : jettyXmls )
{
LOG.info( "Configuring Jetty from xml configuration file = " + xmlFile.getCanonicalPath() );
LOG.info( "Configuring Jetty from xml configuration file = " + xmlFile.getCanonicalPath() );
XmlConfiguration xmlConfiguration = new XmlConfiguration(Resource.toURL(xmlFile));
xmlConfiguration.configure(this.server);
}
@ -286,8 +290,8 @@ public class Starter
System.arraycopy(existing, 0, children, 1, existing.length);
handlers.setHandlers(children);
}
public static final void main(String[] args)
{
if (args == null)

View File

@ -23,6 +23,7 @@ import java.io.FilenameFilter;
import java.io.IOException;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Locale;
import java.util.Map.Entry;
import java.util.Set;
@ -116,7 +117,7 @@ public class OSGiAppProvider extends ScanningAppProvider implements AppProvider
*/
private static String getDeployedAppName(String contextFileName)
{
String lowername = contextFileName.toLowerCase();
String lowername = contextFileName.toLowerCase(Locale.ENGLISH);
if (lowername.endsWith(".xml"))
{
String contextName = contextFileName.substring(0, lowername.length() - ".xml".length());

View File

@ -26,6 +26,7 @@ import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
@ -109,7 +110,7 @@ public class LibExtClassLoaderHelper
for (File f : jettyResources.listFiles())
{
jettyResFiles.put(f.getName(), f);
if (f.getName().toLowerCase().startsWith("readme"))
if (f.getName().toLowerCase(Locale.ENGLISH).startsWith("readme"))
{
continue;
}

View File

@ -7,16 +7,19 @@
<!-- HttpChannel Configuration -->
<!-- =========================================================== -->
<New id="httpConfig" class="org.eclipse.jetty.server.HttpConfiguration">
<Set name="secureScheme">https</Set>
<Set name="securePort"><SystemProperty name="jetty.spdy.port" default="8443"/></Set>
<Set name="outputBufferSize">32768</Set>
<Set name="requestHeaderSize">8192</Set>
<Set name="responseHeaderSize">8192</Set>
<Call name="addCustomizer">
<Arg><New class="org.eclipse.jetty.server.ForwardedRequestCustomizer"/></Arg>
</Call>
<Set name="secureScheme">https</Set>
<Set name="securePort">
<SystemProperty name="jetty.spdy.port" default="8443"/>
</Set>
<Set name="outputBufferSize">32768</Set>
<Set name="requestHeaderSize">8192</Set>
<Set name="responseHeaderSize">8192</Set>
<Call name="addCustomizer">
<Arg>
<New class="org.eclipse.jetty.server.ForwardedRequestCustomizer"/>
</Arg>
</Call>
</New>
<!-- =========================================================== -->
@ -44,18 +47,39 @@
</Ref>
<!-- =========================================================== -->
<!-- Create a push strategy -->
<!-- Create a push strategy which can be used by reference by -->
<!-- individual connection factories below. -->
<!-- -->
<!-- Consult the javadoc of o.e.j.spdy.server.http.ReferrerPushStrategy -->
<!-- for all configuration that may be set here. -->
<!-- =========================================================== -->
<New id="pushStrategy" class="org.eclipse.jetty.spdy.server.http.ReferrerPushStrategy">
<Arg type="List">
<Array type="String">
<Item>.*\.css</Item>
<Item>.*\.js</Item>
<Item>.*\.png</Item>
<Item>.*\.jpg</Item>
<Item>.*\.gif</Item>
</Array>
</Arg>
<!-- Uncomment to blacklist browsers for this push strategy. If one of the blacklisted Strings occurs in the
user-agent header sent by the client, push will be disabled for this browser. This is case insensitive" -->
<!--
<Set name="UserAgentBlacklist">
<Array type="String">
<Item>.*(?i)firefox/14.*</Item>
<Item>.*(?i)firefox/15.*</Item>
<Item>.*(?i)firefox/16.*</Item>
</Array>
</Set>
-->
<!-- Uncomment to override default file extensions to push -->
<!--
<Set name="PushRegexps">
<Array type="String">
<Item>.*\.css</Item>
<Item>.*\.js</Item>
<Item>.*\.png</Item>
<Item>.*\.jpg</Item>
<Item>.*\.gif</Item>
</Array>
</Set>
-->
<Set name="referrerPushPeriod">5000</Set>
<Set name="maxAssociatedResources">32</Set>
</New>
<!-- =========================================================== -->

View File

@ -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>

View File

@ -21,6 +21,7 @@ package org.eclipse.jetty.plus.annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Member;
import java.lang.reflect.Method;
import java.util.Locale;
import javax.naming.InitialContext;
import javax.naming.NamingException;
@ -140,7 +141,7 @@ public class Injection
_resourceClass = resourceType;
//first look for a javabeans style setter matching the targetName
String setter = "set"+target.substring(0,1).toUpperCase()+target.substring(1);
String setter = "set"+target.substring(0,1).toUpperCase(Locale.ENGLISH)+target.substring(1);
try
{
LOG.debug("Looking for method for setter: "+setter+" with arg "+_resourceClass);

View File

@ -26,6 +26,7 @@ import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import javax.naming.InitialContext;
import javax.naming.NameNotFoundException;
import javax.naming.NamingException;
@ -413,7 +414,7 @@ public class DataSourceLoginService extends MappedLoginService
DatabaseMetaData metaData = connection.getMetaData();
//check if tables exist
String tableName = (metaData.storesLowerCaseIdentifiers()? _userTableName.toLowerCase(): (metaData.storesUpperCaseIdentifiers()?_userTableName.toUpperCase(): _userTableName));
String tableName = (metaData.storesLowerCaseIdentifiers()? _userTableName.toLowerCase(Locale.ENGLISH): (metaData.storesUpperCaseIdentifiers()?_userTableName.toUpperCase(Locale.ENGLISH): _userTableName));
ResultSet result = metaData.getTables(null, null, tableName, null);
if (!result.next())
{
@ -431,7 +432,7 @@ public class DataSourceLoginService extends MappedLoginService
result.close();
tableName = (metaData.storesLowerCaseIdentifiers()? _roleTableName.toLowerCase(): (metaData.storesUpperCaseIdentifiers()?_roleTableName.toUpperCase(): _roleTableName));
tableName = (metaData.storesLowerCaseIdentifiers()? _roleTableName.toLowerCase(Locale.ENGLISH): (metaData.storesUpperCaseIdentifiers()?_roleTableName.toUpperCase(Locale.ENGLISH): _roleTableName));
result = metaData.getTables(null, null, tableName, null);
if (!result.next())
{
@ -448,7 +449,7 @@ public class DataSourceLoginService extends MappedLoginService
result.close();
tableName = (metaData.storesLowerCaseIdentifiers()? _userRoleTableName.toLowerCase(): (metaData.storesUpperCaseIdentifiers()?_userRoleTableName.toUpperCase(): _userRoleTableName));
tableName = (metaData.storesLowerCaseIdentifiers()? _userRoleTableName.toLowerCase(Locale.ENGLISH): (metaData.storesUpperCaseIdentifiers()?_userRoleTableName.toUpperCase(Locale.ENGLISH): _userRoleTableName));
result = metaData.getTables(null, null, tableName, null);
if (!result.next())
{

View File

@ -30,6 +30,7 @@ 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;
@ -489,7 +490,7 @@ public class ProxyServlet implements Servlet
protected void onResponseHeader(Buffer name, Buffer value) throws IOException
{
String nameString = name.toString();
String s = nameString.toLowerCase();
String s = nameString.toLowerCase(Locale.ENGLISH);
if (!_DontProxyHeaders.contains(s) || (HttpHeader.CONNECTION.is(name) && HttpHeaderValue.CLOSE.is(value)))
{
if (debug != 0)
@ -560,7 +561,7 @@ public class ProxyServlet implements Servlet
String connectionHdr = request.getHeader("Connection");
if (connectionHdr != null)
{
connectionHdr = connectionHdr.toLowerCase();
connectionHdr = connectionHdr.toLowerCase(Locale.ENGLISH);
if (connectionHdr.indexOf("keep-alive") < 0 && connectionHdr.indexOf("close") < 0)
connectionHdr = null;
}
@ -578,7 +579,7 @@ public class ProxyServlet implements Servlet
{
// TODO could be better than this!
String hdr = (String)enm.nextElement();
String lhdr = hdr.toLowerCase();
String lhdr = hdr.toLowerCase(Locale.ENGLISH);
if (_DontProxyHeaders.contains(lhdr))
continue;

View File

@ -27,6 +27,7 @@ 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;
@ -105,7 +106,7 @@ public abstract class AbstractConnectHandlerTest
assertTrue(header.lookingAt());
String headerName = header.group(1);
String headerValue = header.group(2);
headers.put(headerName.toLowerCase(), headerValue.toLowerCase());
headers.put(headerName.toLowerCase(Locale.ENGLISH), headerValue.toLowerCase(Locale.ENGLISH));
}
StringBuilder body;

View File

@ -79,6 +79,20 @@ public class RewriteHandlerTest extends AbstractRuleTestCase
@Test
public void test() throws Exception
{
_response.setStatus(200);
_request.setHandled(false);
_handler.setOriginalPathAttribute("/before");
_handler.setRewriteRequestURI(true);
_handler.setRewritePathInfo(true);
_request.setRequestURI("/xxx/bar");
_request.setPathInfo("/xxx/bar");
_handler.handle("/xxx/bar",_request,_request, _response);
assertEquals(201,_response.getStatus());
assertEquals("/bar/zzz",_request.getAttribute("target"));
assertEquals("/bar/zzz",_request.getAttribute("URI"));
assertEquals("/bar/zzz",_request.getAttribute("info"));
assertEquals(null,_request.getAttribute("before"));
_response.setStatus(200);
_request.setHandled(false);
_handler.setOriginalPathAttribute("/before");

View File

@ -70,10 +70,12 @@ public abstract class SecurityHandler extends HandlerWrapper implements Authenti
private Authenticator.Factory _authenticatorFactory=new DefaultAuthenticatorFactory();
private String _realmName;
private String _authMethod;
private final Map<String,String> _initParameters=new HashMap<>();
private final Map<String,String> _initParameters=new HashMap<String,String>();
private LoginService _loginService;
private IdentityService _identityService;
private boolean _renewSession=true;
private boolean _discoveredIdentityService = false;
private boolean _discoveredLoginService = false;
/* ------------------------------------------------------------ */
protected SecurityHandler()
@ -338,7 +340,10 @@ public abstract class SecurityHandler extends HandlerWrapper implements Authenti
// many different ways these can be constructed and injected.
if (_loginService==null)
{
setLoginService(findLoginService());
_discoveredLoginService = true;
}
if (_identityService==null)
{
@ -350,6 +355,8 @@ public abstract class SecurityHandler extends HandlerWrapper implements Authenti
if (_identityService==null && _realmName!=null)
setIdentityService(new DefaultIdentityService());
_discoveredIdentityService = true;
}
if (_loginService!=null)
@ -375,6 +382,27 @@ public abstract class SecurityHandler extends HandlerWrapper implements Authenti
super.doStart();
}
@Override
/* ------------------------------------------------------------ */
protected void doStop() throws Exception
{
//if we discovered the services (rather than had them explicitly configured), remove them.
if (_discoveredIdentityService)
{
removeBean(_identityService);
_identityService = null;
}
if (_discoveredLoginService)
{
removeBean(_loginService);
_loginService = null;
}
super.doStop();
}
/* ------------------------------------------------------------ */
protected boolean checkSecurity(Request request)
{

View File

@ -21,6 +21,7 @@ package org.eclipse.jetty.security.authentication;
import java.io.IOException;
import java.util.Collections;
import java.util.Enumeration;
import java.util.Locale;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
@ -413,7 +414,7 @@ public class FormAuthenticator extends LoginAuthenticator
@Override
public long getDateHeader(String name)
{
if (name.toLowerCase().startsWith("if-"))
if (name.toLowerCase(Locale.ENGLISH).startsWith("if-"))
return -1;
return super.getDateHeader(name);
}
@ -421,7 +422,7 @@ public class FormAuthenticator extends LoginAuthenticator
@Override
public String getHeader(String name)
{
if (name.toLowerCase().startsWith("if-"))
if (name.toLowerCase(Locale.ENGLISH).startsWith("if-"))
return null;
return super.getHeader(name);
}
@ -435,7 +436,7 @@ public class FormAuthenticator extends LoginAuthenticator
@Override
public Enumeration<String> getHeaders(String name)
{
if (name.toLowerCase().startsWith("if-"))
if (name.toLowerCase(Locale.ENGLISH).startsWith("if-"))
return Collections.<String>enumeration(Collections.<String>emptyList());
return super.getHeaders(name);
}

View File

@ -25,6 +25,7 @@ import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executor;
@ -314,7 +315,7 @@ public abstract class AbstractConnector extends ContainerLifeCycle implements Co
{
synchronized (_factories)
{
return _factories.get(protocol.toLowerCase());
return _factories.get(protocol.toLowerCase(Locale.ENGLISH));
}
}
@ -337,7 +338,7 @@ public abstract class AbstractConnector extends ContainerLifeCycle implements Co
ConnectionFactory old=_factories.remove(factory.getProtocol());
if (old!=null)
removeBean(old);
_factories.put(factory.getProtocol().toLowerCase(), factory);
_factories.put(factory.getProtocol().toLowerCase(Locale.ENGLISH), factory);
addBean(factory);
if (_defaultProtocol==null)
_defaultProtocol=factory.getProtocol();
@ -348,7 +349,7 @@ public abstract class AbstractConnector extends ContainerLifeCycle implements Co
{
synchronized (_factories)
{
ConnectionFactory factory= _factories.remove(protocol.toLowerCase());
ConnectionFactory factory= _factories.remove(protocol.toLowerCase(Locale.ENGLISH));
removeBean(factory);
return factory;
}
@ -403,7 +404,7 @@ public abstract class AbstractConnector extends ContainerLifeCycle implements Co
public void setDefaultProtocol(String defaultProtocol)
{
_defaultProtocol = defaultProtocol.toLowerCase();
_defaultProtocol = defaultProtocol.toLowerCase(Locale.ENGLISH);
if (isRunning())
_defaultConnectionFactory=getConnectionFactory(_defaultProtocol);
}

View File

@ -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;

View File

@ -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();

View File

@ -17,6 +17,8 @@
//
package org.eclipse.jetty.server;
import java.util.Locale;
import javax.servlet.http.Cookie;
import org.eclipse.jetty.util.LazyList;
@ -283,7 +285,7 @@ public class CookieCutter
{
if (name.startsWith("$"))
{
String lowercaseName = name.toLowerCase();
String lowercaseName = name.toLowerCase(Locale.ENGLISH);
if ("$path".equals(lowercaseName))
{
if (cookie!=null)

View File

@ -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;

View File

@ -237,6 +237,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();

View File

@ -56,24 +56,18 @@ public class ResourceCache
private final ResourceFactory _factory;
private final ResourceCache _parent;
private final MimeTypes _mimeTypes;
private final boolean _etagSupported;
private boolean _useFileMappedBuffer=true;
private int _maxCachedFileSize =4*1024*1024;
private int _maxCachedFiles=2048;
private int _maxCacheSize =32*1024*1024;
/* ------------------------------------------------------------ */
public ResourceCache(ResourceCache parent, ResourceFactory factory, MimeTypes mimeTypes,boolean useFileMappedBuffer)
{
this(parent,factory,mimeTypes);
setUseFileMappedBuffer(useFileMappedBuffer);
}
/* ------------------------------------------------------------ */
/** Constructor.
* @param mimeTypes Mimetype to use for meta data
*/
public ResourceCache(ResourceCache parent, ResourceFactory factory, MimeTypes mimeTypes)
public ResourceCache(ResourceCache parent, ResourceFactory factory, MimeTypes mimeTypes,boolean useFileMappedBuffer,boolean etags)
{
_factory = factory;
_cache=new ConcurrentHashMap<String,Content>();
@ -81,6 +75,7 @@ public class ResourceCache
_cachedFiles=new AtomicInteger();
_mimeTypes=mimeTypes;
_parent=parent;
_etagSupported=etags;
}
/* ------------------------------------------------------------ */
@ -247,7 +242,7 @@ public class ResourceCache
return content;
}
return new HttpContent.ResourceAsHttpContent(resource,_mimeTypes.getMimeByExtension(resource.toString()),getMaxCachedFileSize());
return new HttpContent.ResourceAsHttpContent(resource,_mimeTypes.getMimeByExtension(resource.toString()),getMaxCachedFileSize(),_etagSupported);
}
@ -375,6 +370,7 @@ public class ResourceCache
final long _lastModified;
final ByteBuffer _lastModifiedBytes;
final ByteBuffer _contentType;
final String _etag;
volatile long _lastAccessed;
AtomicReference<ByteBuffer> _indirectBuffer=new AtomicReference<ByteBuffer>();
@ -395,6 +391,8 @@ public class ResourceCache
_cachedSize.addAndGet(_length);
_cachedFiles.incrementAndGet();
_lastAccessed=System.currentTimeMillis();
_etag=ResourceCache.this._etagSupported?resource.getWeakETag():null;
}
@ -422,11 +420,18 @@ public class ResourceCache
{
return _resource;
}
/* ------------------------------------------------------------ */
@Override
public String getETag()
{
return _etag;
}
/* ------------------------------------------------------------ */
boolean isValid()
{
if (_lastModified==_resource.lastModified())
if (_lastModified==_resource.lastModified() && _length==_resource.length())
{
_lastAccessed=System.currentTimeMillis();
return true;

View File

@ -50,6 +50,7 @@ import org.eclipse.jetty.util.annotation.ManagedAttribute;
import org.eclipse.jetty.util.annotation.ManagedObject;
import org.eclipse.jetty.util.annotation.Name;
import org.eclipse.jetty.util.component.Graceful;
import org.eclipse.jetty.util.component.LifeCycle;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
import org.eclipse.jetty.util.thread.QueuedThreadPool;
@ -298,6 +299,14 @@ public class Server extends HandlerWrapper implements Attributes
mex.ifExceptionThrow();
}
@Override
protected void start(LifeCycle l) throws Exception
{
// start connectors last
if (!(l instanceof Connector))
super.start(l);
}
/* ------------------------------------------------------------ */
@Override
protected void doStop() throws Exception

View File

@ -83,17 +83,28 @@ public class ServerConnector extends AbstractNetworkConnector
private volatile ServerSocketChannel _acceptChannel;
private volatile boolean _inheritChannel = false;
private volatile int _localPort = -1;
private volatile int _acceptQueueSize = 128;
private volatile int _acceptQueueSize = 0;
private volatile boolean _reuseAddress = true;
private volatile int _lingerTime = -1;
/* ------------------------------------------------------------ */
/** HTTP Server Connection.
* <p>Construct a ServerConnector with a private instance of {@link HttpConnectionFactory} as the only factory.</p>
* @param server The {@link Server} this connector will accept connection for.
*/
public ServerConnector(
@Name("server") Server server)
{
this(server,null,null,null,0,0,new HttpConnectionFactory());
}
/* ------------------------------------------------------------ */
/** Generic Server Connection with default configuration.
* <p>Construct a Server Connector with the passed Connection factories.</p>
* @param server The {@link Server} this connector will accept connection for.
* @param factories Zero or more {@link ConnectionFactory} instances used to create and configure connections.
*/
public ServerConnector(
@Name("server") Server server,
@Name("factories") ConnectionFactory... factories)
@ -101,6 +112,13 @@ public class ServerConnector extends AbstractNetworkConnector
this(server,null,null,null,0,0,factories);
}
/* ------------------------------------------------------------ */
/** HTTP Server Connection.
* <p>Construct a ServerConnector with a private instance of {@link HttpConnectionFactory} as the primary protocol</p>.
* @param server The {@link Server} this connector will accept connection for.
* @param sslContextFactory If non null, then a {@link SslConnectionFactory} is instantiated and prepended to the
* list of HTTP Connection Factory.
*/
public ServerConnector(
@Name("server") Server server,
@Name("sslContextFactory") SslContextFactory sslContextFactory)
@ -108,6 +126,13 @@ public class ServerConnector extends AbstractNetworkConnector
this(server,null,null,null,0,0,AbstractConnectionFactory.getFactories(sslContextFactory,new HttpConnectionFactory()));
}
/* ------------------------------------------------------------ */
/** Generic SSL Server Connection.
* @param server The {@link Server} this connector will accept connection for.
* @param sslContextFactory If non null, then a {@link SslConnectionFactory} is instantiated and prepended to the
* list of ConnectionFactories, with the first factory being the default protocol for the SslConnectionFactory.
* @param factories Zero or more {@link ConnectionFactory} instances used to create and configure connections.
*/
public ServerConnector(
@Name("server") Server server,
@Name("sslContextFactory") SslContextFactory sslContextFactory,
@ -116,24 +141,33 @@ public class ServerConnector extends AbstractNetworkConnector
this(server,null,null,null,0,0,AbstractConnectionFactory.getFactories(sslContextFactory,factories));
}
/**
* @param server The server this connector will be added to. Must not be null.
* @param executor An executor for this connector or null to use the servers executor
* @param scheduler A scheduler for this connector or null to use the servers scheduler
* @param pool A buffer pool for this connector or null to use a default {@link ByteBufferPool}
* @param acceptors the number of acceptor threads to use, or 0 for a default value.
* @param factories Zero or more {@link ConnectionFactory} instances.
/** Generic Server Connection.
* @param server
* The server this connector will be accept connection for.
* @param executor
* An executor used to run tasks for handling requests, acceptors and selectors. I
* If null then use the servers executor
* @param scheduler
* A scheduler used to schedule timeouts. If null then use the servers scheduler
* @param bufferPool
* A ByteBuffer pool used to allocate buffers. If null then create a private pool with default configuration.
* @param acceptors
* the number of acceptor threads to use, or 0 for a default value. Acceptors accept new TCP/IP connections.
* @param selectors
* the number of selector threads, or 0 for a default value. Selectors notice and schedule established connection that can make IO progress.
* @param factories
* Zero or more {@link ConnectionFactory} instances used to create and configure connections.
*/
public ServerConnector(
@Name("server") Server server,
@Name("executor") Executor executor,
@Name("scheduler") Scheduler scheduler,
@Name("bufferPool") ByteBufferPool pool,
@Name("bufferPool") ByteBufferPool bufferPool,
@Name("acceptors") int acceptors,
@Name("selectors") int selectors,
@Name("factories") ConnectionFactory... factories)
{
super(server,executor,scheduler,pool,acceptors,factories);
super(server,executor,scheduler,bufferPool,acceptors,factories);
_manager = new ServerConnectorManager(getExecutor(), getScheduler(), selectors > 0 ? selectors : Runtime.getRuntime().availableProcessors());
addBean(_manager, true);
}
@ -298,8 +332,8 @@ public class ServerConnector extends AbstractNetworkConnector
* @return the linger time
* @see Socket#getSoLinger()
*/
@ManagedAttribute("linger time")
public int getLingerTime()
@ManagedAttribute("TCP/IP solinger time or -1 to disable")
public int getSoLingerTime()
{
return _lingerTime;
}

View File

@ -746,13 +746,13 @@ public class ContextHandler extends ScopedHandler implements Attributes, Gracefu
super.doStart();
// Context listeners
// Call context listeners
if (!_contextListeners.isEmpty())
{
ServletContextEvent event = new ServletContextEvent(_scontext);
for (ServletContextListener listener:_contextListeners)
callContextInitialized(listener, event);
}
}
}
/* ------------------------------------------------------------ */

View File

@ -66,6 +66,7 @@ public class ResourceHandler extends HandlerWrapper
String _cacheControl;
boolean _aliases;
boolean _directory;
boolean _etags;
/* ------------------------------------------------------------ */
public ResourceHandler()
@ -125,6 +126,24 @@ public class ResourceHandler extends HandlerWrapper
_directory = directory;
}
/* ------------------------------------------------------------ */
/**
* @return True if ETag processing is done
*/
public boolean isEtags()
{
return _etags;
}
/* ------------------------------------------------------------ */
/**
* @param etags True if ETag processing is done
*/
public void setEtags(boolean etags)
{
_etags = etags;
}
/* ------------------------------------------------------------ */
@Override
public void doStart()
@ -417,6 +436,21 @@ public class ResourceHandler extends HandlerWrapper
// set some headers
long last_modified=resource.lastModified();
String etag=null;
if (_etags)
{
// simple handling of only a single etag
String ifnm = request.getHeader(HttpHeader.IF_NONE_MATCH.asString());
etag=resource.getWeakETag();
if (ifnm!=null && resource!=null && ifnm.equals(etag))
{
response.setStatus(HttpStatus.NOT_MODIFIED_304);
baseRequest.getResponse().getHttpFields().put(HttpHeader.ETAG,etag);
return;
}
}
if (last_modified>0)
{
long if_modified=request.getDateHeader(HttpHeader.IF_MODIFIED_SINCE.asString());
@ -434,6 +468,9 @@ public class ResourceHandler extends HandlerWrapper
// set the headers
doResponseHeaders(response,resource,mime!=null?mime.toString():null);
response.setDateHeader(HttpHeader.LAST_MODIFIED.asString(),last_modified);
if (_etags)
baseRequest.getResponse().getHttpFields().put(HttpHeader.ETAG,etag);
if(skipContentBody)
return;
// Send the content

View File

@ -513,33 +513,40 @@ public class HashSessionManager extends AbstractSessionManager
protected synchronized HashedSession restoreSession(String idInCuster)
{
File file = new File(_storeDir,idInCuster);
FileInputStream in = null;
Exception error = null;
try
{
if (file.exists())
{
FileInputStream in = new FileInputStream(file);
in = new FileInputStream(file);
HashedSession session = restoreSession(in, null);
in.close();
addSession(session, false);
session.didActivate();
file.delete();
return session;
}
}
catch (Exception e)
{
if (isDeleteUnrestorableSessions())
error = e;
}
finally
{
if (in != null)
try {in.close();} catch (Exception x) {__log.ignore(x);}
if (error != null)
{
if (file.exists())
if (isDeleteUnrestorableSessions() && file.exists())
{
file.delete();
LOG.warn("Deleting file for unrestorable session "+idInCuster, e);
LOG.warn("Deleting file for unrestorable session "+idInCuster, error);
}
else
LOG.warn("Problem restoring session "+idInCuster, error);
}
else
LOG.warn("Problem restoring session "+idInCuster, e);
file.delete(); //delete successfully restored file
}
return null;
}

View File

@ -34,6 +34,7 @@ import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Random;
import java.util.Timer;
import java.util.TimerTask;
@ -124,7 +125,7 @@ public class JDBCSessionIdManager extends AbstractSessionIdManager
public DatabaseAdaptor (DatabaseMetaData dbMeta)
throws SQLException
{
_dbName = dbMeta.getDatabaseProductName().toLowerCase();
_dbName = dbMeta.getDatabaseProductName().toLowerCase(Locale.ENGLISH);
LOG.debug ("Using database {}",_dbName);
_isLower = dbMeta.storesLowerCaseIdentifiers();
_isUpper = dbMeta.storesUpperCaseIdentifiers();
@ -140,9 +141,9 @@ public class JDBCSessionIdManager extends AbstractSessionIdManager
public String convertIdentifier (String identifier)
{
if (_isLower)
return identifier.toLowerCase();
return identifier.toLowerCase(Locale.ENGLISH);
if (_isUpper)
return identifier.toUpperCase();
return identifier.toUpperCase(Locale.ENGLISH);
return identifier;
}

View File

@ -47,9 +47,9 @@ public class ResourceCacheTest
Resource[] r = rc.getResources();
MimeTypes mime = new MimeTypes();
ResourceCache rc3 = new ResourceCache(null,r[2],mime,false);
ResourceCache rc2 = new ResourceCache(rc3,r[1],mime,false);
ResourceCache rc1 = new ResourceCache(rc2,r[0],mime,false);
ResourceCache rc3 = new ResourceCache(null,r[2],mime,false,false);
ResourceCache rc2 = new ResourceCache(rc3,r[1],mime,false,false);
ResourceCache rc1 = new ResourceCache(rc2,r[0],mime,false,false);
assertEquals("1 - one", getContent(rc1, "1.txt"));
assertEquals("2 - two", getContent(rc1, "2.txt"));
@ -77,8 +77,8 @@ public class ResourceCacheTest
Resource[] r = rc.getResources();
MimeTypes mime = new MimeTypes();
ResourceCache rc3 = new ResourceCache(null,r[2],mime,false);
ResourceCache rc2 = new ResourceCache(rc3,r[1],mime,false)
ResourceCache rc3 = new ResourceCache(null,r[2],mime,false,false);
ResourceCache rc2 = new ResourceCache(rc3,r[1],mime,false,false)
{
@Override
public boolean isCacheable(Resource resource)
@ -87,7 +87,7 @@ public class ResourceCacheTest
}
};
ResourceCache rc1 = new ResourceCache(rc2,r[0],mime,false);
ResourceCache rc1 = new ResourceCache(rc2,r[0],mime,false,false);
assertEquals("1 - one", getContent(rc1, "1.txt"));
assertEquals("2 - two", getContent(rc1, "2.txt"));
@ -127,7 +127,7 @@ public class ResourceCacheTest
directory=Resource.newResource(files[0].getParentFile().getAbsolutePath());
cache=new ResourceCache(null,directory,new MimeTypes(),false);
cache=new ResourceCache(null,directory,new MimeTypes(),false,false);
cache.setMaxCacheSize(95);
cache.setMaxCachedFileSize(85);

View File

@ -24,6 +24,7 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.Socket;
import java.util.Locale;
import org.eclipse.jetty.server.session.SessionHandler;
import org.eclipse.jetty.util.IO;
@ -52,7 +53,7 @@ public class SelectChannelTimeoutTest extends ConnectorTimeoutTest
_handler.setSuspendFor(100);
_handler.setResumeAfter(25);
assertTrue(process(null).toUpperCase().contains("RESUMED"));
assertTrue(process(null).toUpperCase(Locale.ENGLISH).contains("RESUMED"));
}
@Test
@ -66,7 +67,7 @@ public class SelectChannelTimeoutTest extends ConnectorTimeoutTest
_server.start();
_handler.setSuspendFor(50);
assertTrue(process(null).toUpperCase().contains("TIMEOUT"));
assertTrue(process(null).toUpperCase(Locale.ENGLISH).contains("TIMEOUT"));
}
@Test
@ -81,7 +82,7 @@ public class SelectChannelTimeoutTest extends ConnectorTimeoutTest
_handler.setSuspendFor(100);
_handler.setCompleteAfter(25);
assertTrue(process(null).toUpperCase().contains("COMPLETED"));
assertTrue(process(null).toUpperCase(Locale.ENGLISH).contains("COMPLETED"));
}
private synchronized String process(String content) throws UnsupportedEncodingException, IOException, InterruptedException

View File

@ -30,6 +30,7 @@ import java.net.Socket;
import java.util.Arrays;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.Locale;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@ -153,7 +154,7 @@ public class IPAccessHandlerTest
assertTrue(header.lookingAt());
String headerName = header.group(1);
String headerValue = header.group(2);
headers.put(headerName.toLowerCase(), headerValue.toLowerCase());
headers.put(headerName.toLowerCase(Locale.ENGLISH), headerValue.toLowerCase(Locale.ENGLISH));
}
StringBuilder body = new StringBuilder();

View File

@ -25,7 +25,6 @@ import java.io.OutputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.Map;
@ -53,6 +52,7 @@ import org.eclipse.jetty.server.handler.ContextHandler;
import org.eclipse.jetty.util.BufferUtil;
import org.eclipse.jetty.util.IO;
import org.eclipse.jetty.util.MultiPartOutputStream;
import org.eclipse.jetty.util.QuotedStringTokenizer;
import org.eclipse.jetty.util.URIUtil;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
@ -111,6 +111,8 @@ import org.eclipse.jetty.util.resource.ResourceFactory;
*
* aliases If True, aliases of resources are allowed (eg. symbolic
* links and caps variations). May bypass security constraints.
*
* etags If True, weak etags will be generated and handled.
*
* maxCacheSize The maximum total size of the cache or 0 for no cache.
* maxCachedFileSize The maximum size of a file to cache
@ -147,6 +149,7 @@ public class DefaultServlet extends HttpServlet implements ResourceFactory
private boolean _redirectWelcome=false;
private boolean _gzip=true;
private boolean _pathInfoOnly=false;
private boolean _etags=false;
private Resource _resourceBase;
private ResourceCache _cache;
@ -255,11 +258,13 @@ public class DefaultServlet extends HttpServlet implements ResourceFactory
LOG.debug("Cache {}={}",resourceCache,_cache);
}
_etags = getInitBoolean("etags",_etags);
try
{
if (_cache==null && max_cached_files>0)
{
_cache= new ResourceCache(null,this,_mimeTypes,_useFileMappedBuffer);
_cache= new ResourceCache(null,this,_mimeTypes,_useFileMappedBuffer,_etags);
if (max_cache_size>0)
_cache.setMaxCacheSize(max_cache_size);
@ -280,6 +285,7 @@ public class DefaultServlet extends HttpServlet implements ResourceFactory
if (h.getServletInstance()==this)
_defaultHolder=h;
if (LOG.isDebugEnabled())
LOG.debug("resource base = "+_resourceBase);
}
@ -492,7 +498,7 @@ public class DefaultServlet extends HttpServlet implements ResourceFactory
{
// ensure we have content
if (content==null)
content=new HttpContent.ResourceAsHttpContent(resource,_mimeTypes.getMimeByExtension(resource.toString()),response.getBufferSize());
content=new HttpContent.ResourceAsHttpContent(resource,_mimeTypes.getMimeByExtension(resource.toString()),response.getBufferSize(),_etags);
if (included.booleanValue() || passConditionalHeaders(request,response, resource,content))
{
@ -563,7 +569,7 @@ public class DefaultServlet extends HttpServlet implements ResourceFactory
}
else
{
content=new HttpContent.ResourceAsHttpContent(resource,_mimeTypes.getMimeByExtension(resource.toString()));
content=new HttpContent.ResourceAsHttpContent(resource,_mimeTypes.getMimeByExtension(resource.toString()),_etags);
if (included.booleanValue() || passConditionalHeaders(request,response, resource,content))
sendDirectory(request,response,resource,pathInContext);
}
@ -665,6 +671,77 @@ public class DefaultServlet extends HttpServlet implements ResourceFactory
{
if (!HttpMethod.HEAD.is(request.getMethod()))
{
if (_etags)
{
String ifm=request.getHeader(HttpHeader.IF_MATCH.asString());
if (ifm!=null)
{
boolean match=false;
if (content!=null && content.getETag()!=null)
{
QuotedStringTokenizer quoted = new QuotedStringTokenizer(ifm,", ",false,true);
while (!match && quoted.hasMoreTokens())
{
String tag = quoted.nextToken();
if (content.getETag().toString().equals(tag))
match=true;
}
}
if (!match)
{
Response r = Response.getResponse(response);
r.reset(true);
r.setStatus(HttpServletResponse.SC_PRECONDITION_FAILED);
return false;
}
}
String ifnm=request.getHeader(HttpHeader.IF_NONE_MATCH.asString());
if (ifnm!=null && content!=null && content.getETag()!=null)
{
// Look for GzipFiltered version of etag
if (content.getETag().toString().equals(request.getAttribute("o.e.j.s.GzipFilter.ETag")))
{
Response r = Response.getResponse(response);
r.reset(true);
r.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
r.getHttpFields().put(HttpHeader.ETAG,ifnm);
return false;
}
// Handle special case of exact match.
if (content.getETag().toString().equals(ifnm))
{
Response r = Response.getResponse(response);
r.reset(true);
r.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
r.getHttpFields().put(HttpHeader.ETAG,content.getETag());
return false;
}
// Handle list of tags
QuotedStringTokenizer quoted = new QuotedStringTokenizer(ifnm,", ",false,true);
while (quoted.hasMoreTokens())
{
String tag = quoted.nextToken();
if (content.getETag().toString().equals(tag))
{
Response r = Response.getResponse(response);
r.reset(true);
r.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
r.getHttpFields().put(HttpHeader.ETAG,content.getETag());
return false;
}
}
// If etag requires content to be served, then do not check if-modified-since
return true;
}
}
// Handle if modified since
String ifms=request.getHeader(HttpHeader.IF_MODIFIED_SINCE.asString());
if (ifms!=null)
{
@ -964,7 +1041,7 @@ public class DefaultServlet extends HttpServlet implements ResourceFactory
/* ------------------------------------------------------------ */
protected void writeHeaders(HttpServletResponse response,HttpContent content,long count)
throws IOException
{
{
if (content.getContentType()!=null && response.getContentType()==null)
response.setContentType(content.getContentType().toString());
@ -986,6 +1063,9 @@ public class DefaultServlet extends HttpServlet implements ResourceFactory
r.setLongContentLength(count);
writeOptionHeaders(fields);
if (_etags)
fields.put(HttpHeader.ETAG,content.getETag());
}
else
{
@ -1002,11 +1082,14 @@ public class DefaultServlet extends HttpServlet implements ResourceFactory
}
writeOptionHeaders(response);
if (_etags)
response.setHeader(HttpHeader.ETAG.asString(),content.getETag().toString());
}
}
/* ------------------------------------------------------------ */
protected void writeOptionHeaders(HttpFields fields) throws IOException
protected void writeOptionHeaders(HttpFields fields)
{
if (_acceptRanges)
fields.put(HttpHeader.ACCEPT_RANGES,"bytes");
@ -1016,7 +1099,7 @@ public class DefaultServlet extends HttpServlet implements ResourceFactory
}
/* ------------------------------------------------------------ */
protected void writeOptionHeaders(HttpServletResponse response) throws IOException
protected void writeOptionHeaders(HttpServletResponse response)
{
if (_acceptRanges)
response.setHeader(HttpHeader.ACCEPT_RANGES.asString(),"bytes");
@ -1024,8 +1107,6 @@ public class DefaultServlet extends HttpServlet implements ResourceFactory
if (_cacheControl!=null)
response.setHeader(HttpHeader.CACHE_CONTROL.asString(),_cacheControl);
}
/* ------------------------------------------------------------ */
/*

View File

@ -21,6 +21,7 @@ package org.eclipse.jetty.servlet;
import java.io.IOException;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
@ -90,7 +91,7 @@ public class Invoker extends HttpServlet
{
String param=(String)e.nextElement();
String value=getInitParameter(param);
String lvalue=value.toLowerCase();
String lvalue=value.toLowerCase(Locale.ENGLISH);
if ("nonContextServlets".equals(param))
{
_nonContextServlets=value.length()>0 && lvalue.startsWith("t");

View File

@ -257,7 +257,7 @@ public class ServletContextHandler extends ContextHandler
@Override
protected void startContext() throws Exception
{
// OK to Initialize servlet handler now
if (_servletHandler != null)
{
for (int i=_decorators.size()-1;i>=0; i--)
@ -270,11 +270,13 @@ public class ServletContextHandler extends ContextHandler
for (ServletHolder holder:_servletHandler.getServlets())
decorator.decorateServletHolder(holder);
}
_servletHandler.initialize();
}
super.startContext();
// OK to Initialize servlet handler now that all relevant object trees have been started
if (_servletHandler != null)
_servletHandler.initialize();
}
/* ------------------------------------------------------------ */

View File

@ -68,6 +68,7 @@ import org.eclipse.jetty.util.TypeUtil;
import org.eclipse.jetty.util.URIUtil;
import org.eclipse.jetty.util.annotation.ManagedAttribute;
import org.eclipse.jetty.util.annotation.ManagedObject;
import org.eclipse.jetty.util.component.LifeCycle;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
@ -160,6 +161,19 @@ public class ServletHandler extends ScopedHandler
super.doStart();
}
/* ----------------------------------------------------------------- */
@Override
protected void start(LifeCycle l) throws Exception
{
//Don't start the whole object tree (ie all the servlet and filter Holders) when
//this handler starts. They have a slightly special lifecycle, and should only be
//started AFTER the handlers have all started (and the ContextHandler has called
//the context listeners).
if (!(l instanceof Holder))
super.start(l);
}
/* ----------------------------------------------------------------- */
@Override
@ -715,8 +729,22 @@ public class ServletHandler extends ScopedHandler
mx.add(e);
}
}
mx.ifExceptionThrow();
}
//start the servlet and filter holders now
for (Holder<?> h: getBeans(Holder.class))
{
try
{
h.start();
}
catch (Exception e)
{
mx.add(e);
}
}
mx.ifExceptionThrow();
}
/* ------------------------------------------------------------ */

View File

@ -23,6 +23,8 @@ import java.io.FileOutputStream;
import java.io.IOException;
import java.util.EnumSet;
import javax.servlet.DispatcherType;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
@ -30,12 +32,14 @@ import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import org.eclipse.jetty.http.HttpFields;
import org.eclipse.jetty.server.LocalConnector;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.toolchain.test.FS;
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
import org.eclipse.jetty.toolchain.test.OS;
import org.eclipse.jetty.toolchain.test.TestingDir;
import org.eclipse.jetty.util.DateCache;
import org.eclipse.jetty.util.IO;
import org.eclipse.jetty.util.StringUtil;
import org.hamcrest.Matchers;
@ -495,6 +499,123 @@ public class DefaultServletTest
assertResponseNotContains("Content-Length: 12", response);
}
@Test
public void testIfModifiedSmall() throws Exception
{
testIfModified("Hello World");
}
@Test
public void testIfModifiedLarge() throws Exception
{
testIfModified("Now is the time for all good men to come to the aid of the party");
}
public void testIfModified(String content) throws Exception
{
testdir.ensureEmpty();
File resBase = testdir.getFile("docroot");
FS.ensureDirExists(resBase);
File file = new File(resBase, "file.txt");
String resBasePath = resBase.getAbsolutePath();
ServletHolder defholder = context.addServlet(DefaultServlet.class, "/");
defholder.setInitParameter("resourceBase", resBasePath);
defholder.setInitParameter("maxCacheSize", "4096");
defholder.setInitParameter("maxCachedFileSize", "25");
defholder.setInitParameter("maxCachedFiles", "100");
String response = connector.getResponses("GET /context/file.txt HTTP/1.0\r\n\r\n");
assertResponseContains("404", response);
createFile(file, content);
response = connector.getResponses("GET /context/file.txt HTTP/1.1\r\nHost:test\r\nConnection:close\r\n\r\n");
assertResponseContains("200", response);
assertResponseContains("Last-Modified", response);
String last_modified = getHeaderValue("Last-Modified",response);
response = connector.getResponses("GET /context/file.txt HTTP/1.1\r\nHost:test\r\nConnection:close\r\nIf-Modified-Since: "+last_modified+"\r\n\r\n");
assertResponseContains("304", response);
response = connector.getResponses("GET /context/file.txt HTTP/1.1\r\nHost:test\r\nConnection:close\r\nIf-Modified-Since: "+HttpFields.formatDate(System.currentTimeMillis()-10000)+"\r\n\r\n");
assertResponseContains("200", response);
response = connector.getResponses("GET /context/file.txt HTTP/1.1\r\nHost:test\r\nConnection:close\r\nIf-Modified-Since: "+HttpFields.formatDate(System.currentTimeMillis()+10000)+"\r\n\r\n");
assertResponseContains("304", response);
response = connector.getResponses("GET /context/file.txt HTTP/1.1\r\nHost:test\r\nConnection:close\r\nIf-Unmodified-Since: "+HttpFields.formatDate(System.currentTimeMillis()+10000)+"\r\n\r\n");
assertResponseContains("200", response);
response = connector.getResponses("GET /context/file.txt HTTP/1.1\r\nHost:test\r\nConnection:close\r\nIf-Unmodified-Since: "+HttpFields.formatDate(System.currentTimeMillis()-10000)+"\r\n\r\n");
assertResponseContains("412", response);
}
@Test
public void testIfETagSmall() throws Exception
{
testIfETag("Hello World");
}
@Test
public void testIfETagLarge() throws Exception
{
testIfETag("Now is the time for all good men to come to the aid of the party");
}
public void testIfETag(String content) throws Exception
{
testdir.ensureEmpty();
File resBase = testdir.getFile("docroot");
FS.ensureDirExists(resBase);
File file = new File(resBase, "file.txt");
String resBasePath = resBase.getAbsolutePath();
ServletHolder defholder = context.addServlet(DefaultServlet.class, "/");
defholder.setInitParameter("resourceBase", resBasePath);
defholder.setInitParameter("maxCacheSize", "4096");
defholder.setInitParameter("maxCachedFileSize", "25");
defholder.setInitParameter("maxCachedFiles", "100");
defholder.setInitParameter("etags", "true");
String response;
createFile(file, content);
response = connector.getResponses("GET /context/file.txt HTTP/1.1\r\nHost:test\r\nConnection:close\r\n\r\n");
assertResponseContains("200", response);
assertResponseContains("ETag", response);
String etag = getHeaderValue("ETag",response);
response = connector.getResponses("GET /context/file.txt HTTP/1.1\r\nHost:test\r\nConnection:close\r\nIf-None-Match: "+etag+"\r\n\r\n");
assertResponseContains("304", response);
response = connector.getResponses("GET /context/file.txt HTTP/1.1\r\nHost:test\r\nConnection:close\r\nIf-None-Match: wibble,"+etag+",wobble\r\n\r\n");
assertResponseContains("304", response);
response = connector.getResponses("GET /context/file.txt HTTP/1.1\r\nHost:test\r\nConnection:close\r\nIf-None-Match: wibble\r\n\r\n");
assertResponseContains("200", response);
response = connector.getResponses("GET /context/file.txt HTTP/1.1\r\nHost:test\r\nConnection:close\r\nIf-None-Match: wibble, wobble\r\n\r\n");
assertResponseContains("200", response);
response = connector.getResponses("GET /context/file.txt HTTP/1.1\r\nHost:test\r\nConnection:close\r\nIf-Match: "+etag+"\r\n\r\n");
assertResponseContains("200", response);
response = connector.getResponses("GET /context/file.txt HTTP/1.1\r\nHost:test\r\nConnection:close\r\nIf-Match: wibble,"+etag+",wobble\r\n\r\n");
assertResponseContains("200", response);
response = connector.getResponses("GET /context/file.txt HTTP/1.1\r\nHost:test\r\nConnection:close\r\nIf-Match: wibble\r\n\r\n");
assertResponseContains("412", response);
response = connector.getResponses("GET /context/file.txt HTTP/1.1\r\nHost:test\r\nConnection:close\r\nIf-Match: wibble, wobble\r\n\r\n");
assertResponseContains("412", response);
}
public static class OutputFilter implements Filter
{
@Override
@ -583,4 +704,13 @@ public class DefaultServletTest
Assert.assertTrue("Deleting: " + file.getName(), file.delete());
}
}
private String getHeaderValue(String header, String response)
{
Pattern pattern=Pattern.compile("[\\r\\n]"+header+"\\s*:\\s*(.*?)\\s*[\\r\\n]");
Matcher matcher = pattern.matcher(response);
if (matcher.find())
return matcher.group(1);
return null;
}
}

View File

@ -24,6 +24,7 @@ import java.io.InputStream;
import java.io.OutputStream;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
@ -138,7 +139,7 @@ public class CGI extends HttpServlet
if (!_env.envMap.containsKey("SystemRoot"))
{
String os = System.getProperty("os.name");
if (os != null && os.toLowerCase().indexOf("windows") != -1)
if (os != null && os.toLowerCase(Locale.ENGLISH).indexOf("windows") != -1)
{
_env.set("SystemRoot","C:\\WINDOWS");
}
@ -255,7 +256,7 @@ public class CGI extends HttpServlet
{
String name = (String)enm.nextElement();
String value = req.getHeader(name);
env.set("HTTP_" + name.toUpperCase().replace('-','_'),value);
env.set("HTTP_" + name.toUpperCase(Locale.ENGLISH).replace('-','_'),value);
}
// these extra ones were from printenv on www.dev.nomura.co.uk

View File

@ -20,6 +20,7 @@ package org.eclipse.jetty.servlets;
import java.io.IOException;
import java.util.HashSet;
import java.util.Locale;
import java.util.Set;
import java.util.StringTokenizer;
import java.util.regex.Pattern;
@ -104,8 +105,10 @@ public class GzipFilter extends UserAgentFilter
{
private static final Logger LOG = Log.getLogger(GzipFilter.class);
public final static String GZIP="gzip";
public final static String ETAG_GZIP="-gzip\"";
public final static String DEFLATE="deflate";
public final static String ETAG_DEFLATE="-deflate\"";
public final static String ETAG="o.e.j.s.GzipFilter.ETag";
protected Set<String> _mimeTypes;
protected int _bufferSize=8192;
@ -233,6 +236,16 @@ public class GzipFilter extends UserAgentFilter
return;
}
// Special handling for etags
String etag = request.getHeader("If-None-Match");
if (etag!=null)
{
if (etag.endsWith(ETAG_GZIP))
request.setAttribute(ETAG,etag.substring(0,etag.length()-ETAG_GZIP.length())+'"');
else if (etag.endsWith(ETAG_DEFLATE))
request.setAttribute(ETAG,etag.substring(0,etag.length()-ETAG_DEFLATE.length())+'"');
}
CompressedResponseWrapper wrappedResponse = createWrappedResponse(request,response,compressionType);
boolean exceptional=true;
@ -277,7 +290,7 @@ public class GzipFilter extends UserAgentFilter
{
for (int i=0; i< encodings.length; i++)
{
if (encodings[i].toLowerCase().contains(GZIP))
if (encodings[i].toLowerCase(Locale.ENGLISH).contains(GZIP))
{
if (isEncodingAcceptable(encodings[i]))
{
@ -286,7 +299,7 @@ public class GzipFilter extends UserAgentFilter
}
}
if (encodings[i].toLowerCase().contains(DEFLATE))
if (encodings[i].toLowerCase(Locale.ENGLISH).contains(DEFLATE))
{
if (isEncodingAcceptable(encodings[i]))
{
@ -360,9 +373,9 @@ public class GzipFilter extends UserAgentFilter
wrappedResponse = new CompressedResponseWrapper(request,response)
{
@Override
protected AbstractCompressedStream newCompressedStream(HttpServletRequest request,HttpServletResponse response,long contentLength,int bufferSize, int minCompressSize) throws IOException
protected AbstractCompressedStream newCompressedStream(HttpServletRequest request,HttpServletResponse response) throws IOException
{
return new AbstractCompressedStream(compressionType,request,response,contentLength,bufferSize,minCompressSize)
return new AbstractCompressedStream(compressionType,request,this)
{
@Override
protected DeflaterOutputStream createStream() throws IOException
@ -378,9 +391,9 @@ public class GzipFilter extends UserAgentFilter
wrappedResponse = new CompressedResponseWrapper(request,response)
{
@Override
protected AbstractCompressedStream newCompressedStream(HttpServletRequest request,HttpServletResponse response,long contentLength,int bufferSize, int minCompressSize) throws IOException
protected AbstractCompressedStream newCompressedStream(HttpServletRequest request,HttpServletResponse response) throws IOException
{
return new AbstractCompressedStream(compressionType,request,response,contentLength,bufferSize,minCompressSize)
return new AbstractCompressedStream(compressionType,request,this)
{
@Override
protected DeflaterOutputStream createStream() throws IOException
@ -415,6 +428,7 @@ public class GzipFilter extends UserAgentFilter
this.wrappedResponse = wrappedResponse;
}
@Override
public void onComplete(Continuation continuation)
{
try
@ -427,6 +441,7 @@ public class GzipFilter extends UserAgentFilter
}
}
@Override
public void onTimeout(Continuation continuation)
{
}

View File

@ -74,9 +74,9 @@ public class IncludableGzipFilter extends GzipFilter
wrappedResponse = new IncludableResponseWrapper(request,response)
{
@Override
protected AbstractCompressedStream newCompressedStream(HttpServletRequest request,HttpServletResponse response,long contentLength,int bufferSize, int minCompressSize) throws IOException
protected AbstractCompressedStream newCompressedStream(HttpServletRequest request,HttpServletResponse response) throws IOException
{
return new AbstractCompressedStream(compressionType,request,response,contentLength,bufferSize,minCompressSize)
return new AbstractCompressedStream(compressionType,request,this)
{
@Override
protected DeflaterOutputStream createStream() throws IOException
@ -101,9 +101,9 @@ public class IncludableGzipFilter extends GzipFilter
wrappedResponse = new IncludableResponseWrapper(request,response)
{
@Override
protected AbstractCompressedStream newCompressedStream(HttpServletRequest request,HttpServletResponse response,long contentLength,int bufferSize, int minCompressSize) throws IOException
protected AbstractCompressedStream newCompressedStream(HttpServletRequest request,HttpServletResponse response) throws IOException
{
return new AbstractCompressedStream(compressionType,request,response,contentLength,bufferSize,minCompressSize)
return new AbstractCompressedStream(compressionType,request,this)
{
@Override
protected DeflaterOutputStream createStream() throws IOException

View File

@ -31,6 +31,7 @@ import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import javax.servlet.Filter;
import javax.servlet.FilterChain;

View File

@ -39,43 +39,26 @@ import org.eclipse.jetty.util.ByteArrayOutputStream2;
public abstract class AbstractCompressedStream extends ServletOutputStream
{
private final String _encoding;
protected HttpServletRequest _request;
protected HttpServletResponse _response;
protected final CompressedResponseWrapper _wrapper;
protected final HttpServletResponse _response;
protected OutputStream _out;
protected ByteArrayOutputStream2 _bOut;
protected DeflaterOutputStream _compressedOutputStream;
protected boolean _closed;
protected int _bufferSize;
protected int _minCompressSize;
protected long _contentLength;
protected boolean _doNotCompress;
/**
* Instantiates a new compressed stream.
*
* @param request
* the request
* @param response
* the response
* @param contentLength
* the content length
* @param bufferSize
* the buffer size
* @param minCompressSize
* the min compress size
* @throws IOException
* Signals that an I/O exception has occurred.
*/
public AbstractCompressedStream(String encoding,HttpServletRequest request, HttpServletResponse response, long contentLength, int bufferSize, int minCompressSize)
public AbstractCompressedStream(String encoding,HttpServletRequest request, CompressedResponseWrapper wrapper)
throws IOException
{
_encoding=encoding;
_request = request;
_response = response;
_contentLength = contentLength;
_bufferSize = bufferSize;
_minCompressSize = minCompressSize;
if (minCompressSize == 0)
_wrapper = wrapper;
_response = (HttpServletResponse)wrapper.getResponse();
if (_wrapper.getMinCompressSize()==0)
doCompress();
}
@ -95,21 +78,19 @@ public abstract class AbstractCompressedStream extends ServletOutputStream
_doNotCompress = false;
}
/**
* Sets the content length.
*
* @param length
* the new content length
*/
public void setContentLength(long length)
/* ------------------------------------------------------------ */
public void setContentLength()
{
_contentLength = length;
if (_doNotCompress && length >= 0)
if (_doNotCompress)
{
if (_contentLength < Integer.MAX_VALUE)
_response.setContentLength((int)_contentLength);
else
_response.setHeader("Content-Length",Long.toString(_contentLength));
long length=_wrapper.getContentLength();
if (length>=0)
{
if (length < Integer.MAX_VALUE)
_response.setContentLength((int)length);
else
_response.setHeader("Content-Length",Long.toString(length));
}
}
}
@ -122,7 +103,8 @@ public abstract class AbstractCompressedStream extends ServletOutputStream
{
if (_out == null || _bOut != null)
{
if (_contentLength > 0 && _contentLength < _minCompressSize)
long length=_wrapper.getContentLength();
if (length > 0 && length < _wrapper.getMinCompressSize())
doNotCompress();
else
doCompress();
@ -141,15 +123,19 @@ public abstract class AbstractCompressedStream extends ServletOutputStream
if (_closed)
return;
if (_request.getAttribute("javax.servlet.include.request_uri") != null)
if (_wrapper.getRequest().getAttribute("javax.servlet.include.request_uri") != null)
flush();
else
{
if (_bOut != null)
{
if (_contentLength < 0)
_contentLength = _bOut.getCount();
if (_contentLength < _minCompressSize)
long length=_wrapper.getContentLength();
if (length < 0)
{
length = _bOut.getCount();
_wrapper.setContentLength(length);
}
if (length < _wrapper.getMinCompressSize())
doNotCompress();
else
doCompress();
@ -179,7 +165,8 @@ public abstract class AbstractCompressedStream extends ServletOutputStream
{
if (_out == null || _bOut != null)
{
if (_contentLength > 0 && _contentLength < _minCompressSize)
long length=_wrapper.getContentLength();
if (length > 0 && length < _wrapper.getMinCompressSize())
doNotCompress();
else
doCompress();
@ -248,6 +235,10 @@ public abstract class AbstractCompressedStream extends ServletOutputStream
_out.write(_bOut.getBuf(),0,_bOut.getCount());
_bOut=null;
}
String etag=_wrapper.getETag();
if (etag!=null)
setHeader("ETag",etag.substring(0,etag.length()-1)+'-'+_encoding+'"');
}
else
doNotCompress();
@ -266,10 +257,13 @@ public abstract class AbstractCompressedStream extends ServletOutputStream
throw new IllegalStateException("Compressed output stream is already assigned.");
if (_out == null || _bOut != null)
{
if (_wrapper.getETag()!=null)
setHeader("ETag",_wrapper.getETag());
_doNotCompress = true;
_out = _response.getOutputStream();
setContentLength(_contentLength);
setContentLength();
if (_bOut != null)
_out.write(_bOut.getBuf(),0,_bOut.getCount());
@ -280,30 +274,32 @@ public abstract class AbstractCompressedStream extends ServletOutputStream
/**
* Check out.
*
* @param length
* @param lengthToWrite
* the length
* @throws IOException
* Signals that an I/O exception has occurred.
*/
private void checkOut(int length) throws IOException
private void checkOut(int lengthToWrite) throws IOException
{
if (_closed)
throw new IOException("CLOSED");
if (_out == null)
{
if (_response.isCommitted() || (_contentLength >= 0 && _contentLength < _minCompressSize))
long length=_wrapper.getContentLength();
if (_response.isCommitted() || (length >= 0 && length < _wrapper.getMinCompressSize()))
doNotCompress();
else if (length > _minCompressSize)
else if (lengthToWrite > _wrapper.getMinCompressSize())
doCompress();
else
_out = _bOut = new ByteArrayOutputStream2(_bufferSize);
_out = _bOut = new ByteArrayOutputStream2(_wrapper.getBufferSize());
}
else if (_bOut != null)
{
if (_response.isCommitted() || (_contentLength >= 0 && _contentLength < _minCompressSize))
long length=_wrapper.getContentLength();
if (_response.isCommitted() || (length >= 0 && length < _wrapper.getMinCompressSize()))
doNotCompress();
else if (length >= (_bOut.getBuf().length - _bOut.getCount()))
else if (lengthToWrite >= (_bOut.getBuf().length - _bOut.getCount()))
doCompress();
}
}

View File

@ -47,15 +47,48 @@ public abstract class CompressedResponseWrapper extends HttpServletResponseWrapp
private PrintWriter _writer;
private AbstractCompressedStream _compressedStream;
private String _etag;
private long _contentLength=-1;
private boolean _noCompression;
/* ------------------------------------------------------------ */
public CompressedResponseWrapper(HttpServletRequest request, HttpServletResponse response)
{
super(response);
_request = request;
}
/* ------------------------------------------------------------ */
public long getContentLength()
{
return _contentLength;
}
/* ------------------------------------------------------------ */
public int getBufferSize()
{
return _bufferSize;
}
/* ------------------------------------------------------------ */
public int getMinCompressSize()
{
return _minCompressSize;
}
/* ------------------------------------------------------------ */
public String getETag()
{
return _etag;
}
/* ------------------------------------------------------------ */
public HttpServletRequest getRequest()
{
return _request;
}
/* ------------------------------------------------------------ */
/**
* @see org.eclipse.jetty.servlets.gzip.CompressedResponseWrapper#setMimeTypes(java.util.Set)
@ -147,7 +180,7 @@ public abstract class CompressedResponseWrapper extends HttpServletResponseWrapp
{
_contentLength=length;
if (_compressedStream!=null)
_compressedStream.setContentLength(length);
_compressedStream.setContentLength();
else if (_noCompression && _contentLength>=0)
{
HttpServletResponse response = (HttpServletResponse)getResponse();
@ -161,7 +194,7 @@ public abstract class CompressedResponseWrapper extends HttpServletResponseWrapp
}
}
}
/* ------------------------------------------------------------ */
/**
* @see org.eclipse.jetty.servlets.gzip.CompressedResponseWrapper#addHeader(java.lang.String, java.lang.String)
@ -173,7 +206,7 @@ public abstract class CompressedResponseWrapper extends HttpServletResponseWrapp
{
_contentLength=Long.parseLong(value);
if (_compressedStream!=null)
_compressedStream.setContentLength(_contentLength);
_compressedStream.setContentLength();
}
else if ("content-type".equalsIgnoreCase(name))
{
@ -187,6 +220,8 @@ public abstract class CompressedResponseWrapper extends HttpServletResponseWrapp
noCompression();
}
}
else if ("etag".equalsIgnoreCase(name))
_etag=value;
else
super.addHeader(name,value);
}
@ -324,10 +359,21 @@ public abstract class CompressedResponseWrapper extends HttpServletResponseWrapp
noCompression();
}
}
else if ("etag".equalsIgnoreCase(name))
_etag=value;
else
super.setHeader(name,value);
}
/* ------------------------------------------------------------ */
@Override
public boolean containsHeader(String name)
{
if ("etag".equalsIgnoreCase(name) && _etag!=null)
return true;
return super.containsHeader(name);
}
/* ------------------------------------------------------------ */
/**
* @see org.eclipse.jetty.servlets.gzip.CompressedResponseWrapper#getOutputStream()
@ -343,7 +389,7 @@ public abstract class CompressedResponseWrapper extends HttpServletResponseWrapp
return getResponse().getOutputStream();
}
_compressedStream=newCompressedStream(_request,(HttpServletResponse)getResponse(),_contentLength,_bufferSize,_minCompressSize);
_compressedStream=newCompressedStream(_request,(HttpServletResponse)getResponse());
}
else if (_writer!=null)
throw new IllegalStateException("getWriter() called");
@ -369,7 +415,7 @@ public abstract class CompressedResponseWrapper extends HttpServletResponseWrapp
return getResponse().getWriter();
}
_compressedStream=newCompressedStream(_request,(HttpServletResponse)getResponse(),_contentLength,_bufferSize,_minCompressSize);
_compressedStream=newCompressedStream(_request,(HttpServletResponse)getResponse());
_writer=newWriter(_compressedStream,getCharacterEncoding());
}
return _writer;
@ -386,7 +432,7 @@ public abstract class CompressedResponseWrapper extends HttpServletResponseWrapp
{
_contentLength=value;
if (_compressedStream!=null)
_compressedStream.setContentLength(_contentLength);
_compressedStream.setContentLength();
}
else
super.setIntHeader(name,value);
@ -410,6 +456,6 @@ public abstract class CompressedResponseWrapper extends HttpServletResponseWrapp
/**
*@return the underlying CompressedStream implementation
*/
protected abstract AbstractCompressedStream newCompressedStream(HttpServletRequest _request, HttpServletResponse response, long _contentLength2, int _bufferSize2, int _minCompressedSize2) throws IOException;
protected abstract AbstractCompressedStream newCompressedStream(HttpServletRequest _request, HttpServletResponse response) throws IOException;
}

View File

@ -293,9 +293,9 @@ public class GzipHandler extends HandlerWrapper
}
@Override
protected AbstractCompressedStream newCompressedStream(HttpServletRequest request,HttpServletResponse response,long contentLength,int bufferSize, int minCompressSize) throws IOException
protected AbstractCompressedStream newCompressedStream(HttpServletRequest request,HttpServletResponse response) throws IOException
{
return new AbstractCompressedStream("gzip",request,response,contentLength,bufferSize,minCompressSize)
return new AbstractCompressedStream("gzip",request,this)
{
@Override
protected DeflaterOutputStream createStream() throws IOException

View File

@ -26,6 +26,7 @@ import java.net.URL;
import java.util.Arrays;
import java.util.EnumSet;
import java.util.HashSet;
import java.util.Locale;
import java.util.Set;
import javax.servlet.DispatcherType;
import javax.servlet.http.HttpServletResponse;
@ -62,7 +63,7 @@ public class PutFilterTest
FilterHolder holder = tester.addFilter(PutFilter.class,"/*",EnumSet.of(DispatcherType.REQUEST));
holder.setInitParameter("delAllowed","true");
// Bloody Windows does not allow file renaming
if (!System.getProperty("os.name").toLowerCase().contains("windows"))
if (!System.getProperty("os.name").toLowerCase(Locale.ENGLISH).contains("windows"))
holder.setInitParameter("putAtomic","true");
tester.start();
}

View File

@ -21,6 +21,7 @@ package org.eclipse.jetty.spdy.generator;
import java.io.ByteArrayOutputStream;
import java.nio.ByteBuffer;
import java.nio.charset.Charset;
import java.util.Locale;
import org.eclipse.jetty.spdy.CompressionDictionary;
import org.eclipse.jetty.spdy.CompressionFactory;
@ -45,7 +46,7 @@ public class HeadersBlockGenerator
writeCount(version, buffer, headers.size());
for (Fields.Field header : headers)
{
String name = header.name().toLowerCase();
String name = header.name().toLowerCase(Locale.ENGLISH);
byte[] nameBytes = name.getBytes(iso1);
writeNameLength(version, buffer, nameBytes.length);
buffer.write(nameBytes, 0, nameBytes.length);

View File

@ -25,7 +25,7 @@
<Set name="TrustStorePath"><Property name="jetty.home" default="." />/etc/keystore</Set>
<Set name="TrustStorePassword">OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4</Set>
</New>
<!-- =========================================================== -->
<!-- Create a TLS specific HttpConfiguration based on the -->
<!-- common HttpConfiguration defined in jetty.xml -->
@ -38,7 +38,7 @@
<Arg><New class="org.eclipse.jetty.server.SecureRequestCustomizer"/></Arg>
</Call>
</New>
<!-- =========================================================== -->
<!-- Create a push strategy which can be used by reference by -->
<!-- individual connection factories below. -->
@ -47,15 +47,30 @@
<!-- for all configuration that may be set here. -->
<!-- =========================================================== -->
<New id="pushStrategy" class="org.eclipse.jetty.spdy.server.http.ReferrerPushStrategy">
<Arg name="pushPatterns" type="List">
<Array type="String">
<Item>.*\.css</Item>
<Item>.*\.js</Item>
<Item>.*\.png</Item>
<Item>.*\.jpg</Item>
<Item>.*\.gif</Item>
</Array>
</Arg>
<!-- Uncomment to blacklist browsers for this push strategy. If one of the blacklisted Strings occurs in the
user-agent header sent by the client, push will be disabled for this browser. This is case insensitive" -->
<!--
<Set name="UserAgentBlacklist">
<Array type="String">
<Item>.*(?i)firefox/14.*</Item>
<Item>.*(?i)firefox/15.*</Item>
<Item>.*(?i)firefox/16.*</Item>
</Array>
</Set>
-->
<!-- Uncomment to override default file extensions to push -->
<!--
<Set name="PushRegexps">
<Array type="String">
<Item>.*\.css</Item>
<Item>.*\.js</Item>
<Item>.*\.png</Item>
<Item>.*\.jpg</Item>
<Item>.*\.gif</Item>
</Array>
</Set>
-->
<Set name="referrerPushPeriod">5000</Set>
<Set name="maxAssociatedResources">32</Set>
</New>
@ -64,7 +79,7 @@
<!-- Add a SPDY/HTTPS Connector. -->
<!-- Configure an o.e.j.server.ServerConnector with connection -->
<!-- factories for TLS (aka SSL), NPN, SPDY and HTTP to provide -->
<!-- a connector that can accept HTTPS or SPDY connections. -->
<!-- a connector that can accept HTTPS or SPDY connections. -->
<!-- -->
<!-- All accepted TLS connections are initially wired to a NPN -->
<!-- connection, which attempts to use a TLS extension to -->
@ -87,7 +102,7 @@
<Arg name="server"><Ref id="Server" /></Arg>
<Arg name="factories">
<Array type="org.eclipse.jetty.server.ConnectionFactory">
<!-- SSL Connection factory with NPN as next protocol -->
<Item>
<New class="org.eclipse.jetty.server.SslConnectionFactory">
@ -113,7 +128,7 @@
<New class="org.eclipse.jetty.spdy.server.http.HTTPSPDYServerConnectionFactory">
<Arg name="version" type="int">3</Arg>
<Arg name="config"><Ref id="tlsHttpConfig" /></Arg>
<Arg name="pushStrategy"><Ref id="pushStrategy"/></Arg>
<Arg name="pushStrategy"><Ref id="pushStrategy"/></Arg>
</New>
</Item>
@ -133,7 +148,7 @@
</Item>
</Array>
</Arg>
<Set name="host"><Property name="jetty.host" /></Set>
<Set name="port"><Property name="jetty.tls.port" default="8443" /></Set>
<Set name="idleTimeout">30000</Set>

View File

@ -23,6 +23,7 @@ import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
@ -32,32 +33,25 @@ import java.util.regex.Pattern;
import org.eclipse.jetty.spdy.api.Stream;
import org.eclipse.jetty.util.Fields;
import org.eclipse.jetty.util.annotation.Name;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
/**
* <p>A SPDY push strategy that auto-populates push metadata based on referrer URLs.</p>
* <p>A typical request for a main resource such as <tt>index.html</tt> is immediately
* followed by a number of requests for associated resources. Associated resource requests
* will have a <tt>Referer</tt> HTTP header that points to <tt>index.html</tt>, which is
* used to link the associated resource to the main resource.</p>
* <p>However, also following a hyperlink generates a HTTP request with a <tt>Referer</tt>
* HTTP header that points to <tt>index.html</tt>; therefore a proper value for {@link #getReferrerPushPeriod()}
* has to be set. If the referrerPushPeriod for a main resource has elapsed, no more
* associated resources will be added for that main resource.</p>
* <p>This class distinguishes associated main resources by their URL path suffix and content
* type.
* CSS stylesheets, images and JavaScript files have recognizable URL path suffixes that
* are classified as associated resources. The suffix regexs can be configured by constructor argument</p>
* <p>When CSS stylesheets refer to images, the CSS image request will have the CSS
* stylesheet as referrer. This implementation will push also the CSS image.</p>
* <p>The push metadata built by this implementation is limited by the number of pages
* of the application itself, and by the
* {@link #getMaxAssociatedResources() max associated resources} parameter.
* This parameter limits the number of associated resources per each main resource, so
* that if a main resource has hundreds of associated resources, only up to the number
* specified by this parameter will be pushed.</p>
* <p>A SPDY push strategy that auto-populates push metadata based on referrer URLs.</p> <p>A typical request for a main
* resource such as <tt>index.html</tt> is immediately followed by a number of requests for associated resources.
* Associated resource requests will have a <tt>Referer</tt> HTTP header that points to <tt>index.html</tt>, which is
* used to link the associated resource to the main resource.</p> <p>However, also following a hyperlink generates a
* HTTP request with a <tt>Referer</tt> HTTP header that points to <tt>index.html</tt>; therefore a proper value for
* {@link #setReferrerPushPeriod(int)} has to be set. If the referrerPushPeriod for a main resource has elapsed,
* no more associated resources will be added for that main resource.</p> <p>This class distinguishes associated main
* resources by their URL path suffix and content type. CSS stylesheets, images and JavaScript files have
* recognizable URL path suffixes that are classified as associated resources. The suffix regexs can be configured by
* constructor argument</p>
* <p>When CSS stylesheets refer to images, the CSS image request will have the CSS stylesheet as referrer. This
* implementation will push also the CSS image.</p> <p>The push metadata built by this implementation is limited by the
* number of pages of the application itself, and by the {@link #setMaxAssociatedResources(int)} max associated resources}
* parameter. This parameter limits the number of associated resources per each main resource, so that if a main
* resource has hundreds of associated resources, only up to the number specified by this parameter will be pushed.</p>
*/
public class ReferrerPushStrategy implements PushStrategy
{
@ -66,42 +60,56 @@ public class ReferrerPushStrategy implements PushStrategy
private final Set<Pattern> pushRegexps = new HashSet<>();
private final Set<String> pushContentTypes = new HashSet<>();
private final Set<Pattern> allowedPushOrigins = new HashSet<>();
private final Set<Pattern> userAgentBlacklist = new HashSet<>();
private volatile int maxAssociatedResources = 32;
private volatile int referrerPushPeriod = 5000;
public ReferrerPushStrategy()
{
this(Arrays.asList(".*\\.css", ".*\\.js", ".*\\.png", ".*\\.jpeg", ".*\\.jpg", ".*\\.gif", ".*\\.ico"));
}
List<String> defaultPushRegexps = Arrays.asList(".*\\.css", ".*\\.js", ".*\\.png", ".*\\.jpeg", ".*\\.jpg",
".*\\.gif", ".*\\.ico");
addPushRegexps(defaultPushRegexps);
public ReferrerPushStrategy(@Name("pushPatterns") List<String> pushRegexps)
{
this(pushRegexps, Arrays.asList(
List<String> defaultPushContentTypes = Arrays.asList(
"text/css",
"text/javascript", "application/javascript", "application/x-javascript",
"image/png", "image/x-png",
"image/jpeg",
"image/gif",
"image/x-icon", "image/vnd.microsoft.icon"));
"image/x-icon", "image/vnd.microsoft.icon");
this.pushContentTypes.addAll(defaultPushContentTypes);
}
public ReferrerPushStrategy(List<String> pushRegexps, List<String> pushContentTypes)
public void setPushRegexps(List<String> pushRegexps)
{
this(pushRegexps, pushContentTypes, Collections.<String>emptyList());
pushRegexps.clear();
addPushRegexps(pushRegexps);
}
public ReferrerPushStrategy(List<String> pushRegexps, List<String> pushContentTypes, List<String> allowedPushOrigins)
private void addPushRegexps(List<String> pushRegexps)
{
for (String pushRegexp : pushRegexps)
this.pushRegexps.add(Pattern.compile(pushRegexp));
this.pushContentTypes.addAll(pushContentTypes);
}
public void setPushContentTypes(List<String> pushContentTypes)
{
pushContentTypes.clear();
pushContentTypes.addAll(pushContentTypes);
}
public void setAllowedPushOrigins(List<String> allowedPushOrigins)
{
allowedPushOrigins.clear();
for (String allowedPushOrigin : allowedPushOrigins)
this.allowedPushOrigins.add(Pattern.compile(allowedPushOrigin.replace(".", "\\.").replace("*", ".*")));
}
public int getMaxAssociatedResources()
public void setUserAgentBlacklist(List<String> userAgentPatterns)
{
return maxAssociatedResources;
userAgentBlacklist.clear();
for (String userAgentPattern : userAgentPatterns)
userAgentBlacklist.add(Pattern.compile(userAgentPattern));
}
public void setMaxAssociatedResources(int maxAssociatedResources)
@ -109,22 +117,48 @@ public class ReferrerPushStrategy implements PushStrategy
this.maxAssociatedResources = maxAssociatedResources;
}
public int getReferrerPushPeriod()
{
return referrerPushPeriod;
}
public void setReferrerPushPeriod(int referrerPushPeriod)
{
this.referrerPushPeriod = referrerPushPeriod;
}
public Set<Pattern> getPushRegexps()
{
return pushRegexps;
}
public Set<String> getPushContentTypes()
{
return pushContentTypes;
}
public Set<Pattern> getAllowedPushOrigins()
{
return allowedPushOrigins;
}
public Set<Pattern> getUserAgentBlacklist()
{
return userAgentBlacklist;
}
public int getMaxAssociatedResources()
{
return maxAssociatedResources;
}
public int getReferrerPushPeriod()
{
return referrerPushPeriod;
}
@Override
public Set<String> apply(Stream stream, Fields requestHeaders, Fields responseHeaders)
{
Set<String> result = Collections.<String>emptySet();
short version = stream.getSession().getVersion();
if (!isIfModifiedSinceHeaderPresent(requestHeaders) && isValidMethod(requestHeaders.get(HTTPSPDYHeader.METHOD.name(version)).value()))
if (!isIfModifiedSinceHeaderPresent(requestHeaders) && isValidMethod(requestHeaders.get(HTTPSPDYHeader.METHOD
.name(version)).value()) && !isUserAgentBlacklisted(requestHeaders))
{
String scheme = requestHeaders.get(HTTPSPDYHeader.SCHEME.name(version)).value();
String host = requestHeaders.get(HTTPSPDYHeader.HOST.name(version)).value();
@ -196,6 +230,16 @@ public class ReferrerPushStrategy implements PushStrategy
return !isPushResource(url, responseHeaders);
}
public boolean isUserAgentBlacklisted(Fields headers)
{
Fields.Field userAgentHeader = headers.get("user-agent");
if (userAgentHeader != null)
for (Pattern userAgentPattern : userAgentBlacklist)
if (userAgentPattern.matcher(userAgentHeader.value()).matches())
return true;
return false;
}
private boolean isPushResource(String url, Fields responseHeaders)
{
for (Pattern pushRegexp : pushRegexps)
@ -206,7 +250,7 @@ public class ReferrerPushStrategy implements PushStrategy
if (header == null)
return true;
String contentType = header.value().toLowerCase();
String contentType = header.value().toLowerCase(Locale.ENGLISH);
for (String pushContentType : pushContentTypes)
if (contentType.startsWith(pushContentType))
return true;
@ -275,10 +319,8 @@ public class ReferrerPushStrategy implements PushStrategy
private boolean isPushOriginAllowed(String origin)
{
for (Pattern allowedPushOrigin : allowedPushOrigins)
{
if (allowedPushOrigin.matcher(origin).matches())
return true;
}
return false;
}
}

View File

@ -20,6 +20,7 @@ package org.eclipse.jetty.spdy.server.proxy;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.Locale;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@ -92,7 +93,7 @@ public class ProxyHTTPSPDYConnection extends HttpConnection implements HttpParse
@Override
public boolean parsedHeader(HttpHeader header, String headerName, String headerValue)
{
switch (headerName.toLowerCase())
switch (headerName.toLowerCase(Locale.ENGLISH))
{
case "host":
headers.put(HTTPSPDYHeader.HOST.name(version), headerValue);

View File

@ -21,6 +21,7 @@ package org.eclipse.jetty.spdy.server.http;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.InetSocketAddress;
import java.util.Arrays;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import javax.servlet.ServletException;
@ -42,12 +43,21 @@ import org.eclipse.jetty.spdy.api.SynInfo;
import org.eclipse.jetty.spdy.server.NPNServerConnectionFactory;
import org.eclipse.jetty.util.Fields;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;
public class ReferrerPushStrategyTest extends AbstractHTTPSPDYTest
{
private final String mainResource = "/index.html";
private final int referrerPushPeriod = 1000;
private final String cssResource = "/style.css";
private InetSocketAddress serverAddress;
private ReferrerPushStrategy pushStrategy;
private ConnectionFactory defaultFactory;
private Fields mainRequestHeaders;
public ReferrerPushStrategyTest(short version)
{
@ -57,82 +67,63 @@ public class ReferrerPushStrategyTest extends AbstractHTTPSPDYTest
@Override
protected HTTPSPDYServerConnector newHTTPSPDYServerConnector(short version)
{
HTTPSPDYServerConnector connector =
new HTTPSPDYServerConnector(server,version,new HttpConfiguration(),new ReferrerPushStrategy());
return connector;
return new HTTPSPDYServerConnector(server, version, new HttpConfiguration(), new ReferrerPushStrategy());
}
@Before
public void setUp() throws Exception
{
serverAddress = createServer();
pushStrategy = new ReferrerPushStrategy();
pushStrategy.setReferrerPushPeriod(referrerPushPeriod);
defaultFactory = new HTTPSPDYServerConnectionFactory(version, new HttpConfiguration(), pushStrategy);
connector.addConnectionFactory(defaultFactory);
if (connector.getConnectionFactory(NPNServerConnectionFactory.class) != null)
connector.getConnectionFactory(NPNServerConnectionFactory.class).setDefaultProtocol(defaultFactory.getProtocol());
else
connector.setDefaultProtocol(defaultFactory.getProtocol());
mainRequestHeaders = createHeadersWithoutReferrer(mainResource);
}
@Test
public void testPushHeadersAreValid() throws Exception
{
InetSocketAddress address = createServer();
sendMainRequestAndCSSRequest();
run2ndClientRequests(true, true);
}
ReferrerPushStrategy pushStrategy = new ReferrerPushStrategy();
int referrerPushPeriod = 1000;
pushStrategy.setReferrerPushPeriod(referrerPushPeriod);
ConnectionFactory defaultFactory = new HTTPSPDYServerConnectionFactory(version,new HttpConfiguration(), pushStrategy);
connector.addConnectionFactory(defaultFactory);
if (connector.getConnectionFactory(NPNServerConnectionFactory.class)!=null)
connector.getConnectionFactory(NPNServerConnectionFactory.class).setDefaultProtocol(defaultFactory.getProtocol());
else
connector.setDefaultProtocol(defaultFactory.getProtocol());
connector.setDefaultProtocol(defaultFactory.getProtocol()); // TODO I don't think this is right
Fields mainRequestHeaders = createHeadersWithoutReferrer(mainResource);
Session session1 = sendMainRequestAndCSSRequest(address, mainRequestHeaders);
// Sleep for pushPeriod This should prevent application.js from being mapped as pushResource
Thread.sleep(referrerPushPeriod + 1);
sendJSRequest(session1);
run2ndClientRequests(address, mainRequestHeaders, true);
@Test
public void testUserAgentBlackList() throws Exception
{
pushStrategy.setUserAgentBlacklist(Arrays.asList(".*(?i)firefox/16.*"));
sendMainRequestAndCSSRequest();
run2ndClientRequests(false, false);
}
@Test
public void testReferrerPushPeriod() throws Exception
{
InetSocketAddress address = createServer();
ReferrerPushStrategy pushStrategy = new ReferrerPushStrategy();
int referrerPushPeriod = 1000;
pushStrategy.setReferrerPushPeriod(referrerPushPeriod);
ConnectionFactory defaultFactory = new HTTPSPDYServerConnectionFactory(version,new HttpConfiguration(), pushStrategy);
connector.addConnectionFactory(defaultFactory);
if (connector.getConnectionFactory(NPNServerConnectionFactory.class)!=null)
connector.getConnectionFactory(NPNServerConnectionFactory.class).setDefaultProtocol(defaultFactory.getProtocol());
else
connector.setDefaultProtocol(defaultFactory.getProtocol());
Fields mainRequestHeaders = createHeadersWithoutReferrer(mainResource);
Session session1 = sendMainRequestAndCSSRequest(address, mainRequestHeaders);
Session session1 = sendMainRequestAndCSSRequest();
// Sleep for pushPeriod This should prevent application.js from being mapped as pushResource
Thread.sleep(referrerPushPeriod+1);
Thread.sleep(referrerPushPeriod + 1);
sendJSRequest(session1);
run2ndClientRequests(address, mainRequestHeaders, false);
run2ndClientRequests(false, true);
}
@Test
public void testMaxAssociatedResources() throws Exception
{
InetSocketAddress address = createServer();
ReferrerPushStrategy pushStrategy = new ReferrerPushStrategy();
pushStrategy.setMaxAssociatedResources(1);
ConnectionFactory defaultFactory = new HTTPSPDYServerConnectionFactory(version,new HttpConfiguration(), pushStrategy);
connector.addConnectionFactory(defaultFactory);
connector.setDefaultProtocol(defaultFactory.getProtocol()); // TODO I don't think this is right
Fields mainRequestHeaders = createHeadersWithoutReferrer(mainResource);
Session session1 = sendMainRequestAndCSSRequest(address, mainRequestHeaders);
Session session1 = sendMainRequestAndCSSRequest();
sendJSRequest(session1);
run2ndClientRequests(address, mainRequestHeaders, false);
run2ndClientRequests(false, true);
}
private InetSocketAddress createServer() throws Exception
@ -155,9 +146,9 @@ public class ReferrerPushStrategyTest extends AbstractHTTPSPDYTest
});
}
private Session sendMainRequestAndCSSRequest(InetSocketAddress address, Fields mainRequestHeaders) throws Exception
private Session sendMainRequestAndCSSRequest() throws Exception
{
Session session1 = startClient(version, address, null);
Session session1 = startClient(version, serverAddress, null);
final CountDownLatch mainResourceLatch = new CountDownLatch(1);
session1.syn(new SynInfo(mainRequestHeaders, true), new StreamFrameListener.Adapter()
@ -207,7 +198,8 @@ public class ReferrerPushStrategyTest extends AbstractHTTPSPDYTest
Assert.assertTrue(associatedResourceLatch2.await(5, TimeUnit.SECONDS));
}
private void run2ndClientRequests(InetSocketAddress address, Fields mainRequestHeaders, final boolean validateHeaders) throws Exception
private void run2ndClientRequests(final boolean validateHeaders,
boolean expectPushResource) throws Exception
{
// Create another client, and perform the same request for the main resource,
// we expect the css being pushed, but not the js
@ -215,16 +207,20 @@ public class ReferrerPushStrategyTest extends AbstractHTTPSPDYTest
final CountDownLatch mainStreamLatch = new CountDownLatch(2);
final CountDownLatch pushDataLatch = new CountDownLatch(1);
final CountDownLatch pushSynHeadersValid = new CountDownLatch(1);
Session session2 = startClient(version, address, new SessionFrameListener.Adapter()
Session session2 = startClient(version, serverAddress, new SessionFrameListener.Adapter()
{
@Override
public StreamFrameListener onSyn(Stream stream, SynInfo synInfo)
{
if(validateHeaders)
if (validateHeaders)
validateHeaders(synInfo.getHeaders(), pushSynHeadersValid);
Assert.assertTrue(stream.isUnidirectional());
Assert.assertTrue(synInfo.getHeaders().get(HTTPSPDYHeader.URI.name(version)).value().endsWith(".css"));
assertThat("Stream is unidirectional",stream.isUnidirectional(),is(true));
assertThat("URI header ends with css", synInfo.getHeaders().get(HTTPSPDYHeader.URI.name(version))
.value().endsWith
("" +
".css"),
is(true));
return new StreamFrameListener.Adapter()
{
@Override
@ -243,7 +239,7 @@ public class ReferrerPushStrategyTest extends AbstractHTTPSPDYTest
@Override
public void onReply(Stream stream, ReplyInfo replyInfo)
{
Assert.assertFalse(replyInfo.isClose());
assertThat("replyInfo.isClose() is false", replyInfo.isClose(), is(false));
mainStreamLatch.countDown();
}
@ -256,10 +252,13 @@ public class ReferrerPushStrategyTest extends AbstractHTTPSPDYTest
}
});
Assert.assertTrue("Main request reply and/or data not received", mainStreamLatch.await(5, TimeUnit.SECONDS));
Assert.assertTrue("Pushed data not received", pushDataLatch.await(5, TimeUnit.SECONDS));
if(validateHeaders)
Assert.assertTrue("Push syn headers not valid", pushSynHeadersValid.await(5, TimeUnit.SECONDS));
assertThat("Main request reply and/or data not received", mainStreamLatch.await(5, TimeUnit.SECONDS), is(true));
if (expectPushResource)
assertThat("Pushed data not received", pushDataLatch.await(5, TimeUnit.SECONDS), is(true));
else
assertThat("No push data is received", pushDataLatch.await(1, TimeUnit.SECONDS), is(false));
if (validateHeaders)
assertThat("Push syn headers not valid", pushSynHeadersValid.await(5, TimeUnit.SECONDS), is(true));
}
@Test
@ -758,7 +757,7 @@ public class ReferrerPushStrategyTest extends AbstractHTTPSPDYTest
});
Assert.assertTrue(mainStreamLatch.await(5, TimeUnit.SECONDS));
Assert.assertFalse("We don't expect data to be pushed as the main request contained an if-modified-since header",pushDataLatch.await(1, TimeUnit.SECONDS));
Assert.assertFalse("We don't expect data to be pushed as the main request contained an if-modified-since header", pushDataLatch.await(1, TimeUnit.SECONDS));
}
private void validateHeaders(Fields headers, CountDownLatch pushSynHeadersValid)
@ -805,12 +804,14 @@ public class ReferrerPushStrategyTest extends AbstractHTTPSPDYTest
private Fields createHeadersWithoutReferrer(String resource)
{
Fields associatedRequestHeaders = new Fields();
associatedRequestHeaders.put(HTTPSPDYHeader.METHOD.name(version), "GET");
associatedRequestHeaders.put(HTTPSPDYHeader.URI.name(version), resource);
associatedRequestHeaders.put(HTTPSPDYHeader.VERSION.name(version), "HTTP/1.1");
associatedRequestHeaders.put(HTTPSPDYHeader.SCHEME.name(version), "http");
associatedRequestHeaders.put(HTTPSPDYHeader.HOST.name(version), "localhost:" + connector.getLocalPort());
return associatedRequestHeaders;
Fields requestHeaders = new Fields();
requestHeaders.put("User-Agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.7; rv:16.0) " +
"Gecko/20100101 Firefox/16.0");
requestHeaders.put(HTTPSPDYHeader.METHOD.name(version), "GET");
requestHeaders.put(HTTPSPDYHeader.URI.name(version), resource);
requestHeaders.put(HTTPSPDYHeader.VERSION.name(version), "HTTP/1.1");
requestHeaders.put(HTTPSPDYHeader.SCHEME.name(version), "http");
requestHeaders.put(HTTPSPDYHeader.HOST.name(version), "localhost:" + connector.getLocalPort());
return requestHeaders;
}
}

View File

@ -18,6 +18,7 @@
package org.eclipse.jetty.spdy.server.http;
import java.util.Arrays;
import java.util.Set;
import org.eclipse.jetty.spdy.api.SPDY;
@ -44,7 +45,7 @@ public class ReferrerPushStrategyUnitTest
public static final String METHOD = "GET";
// class under test
private ReferrerPushStrategy referrerPushStrategy;
private ReferrerPushStrategy referrerPushStrategy = new ReferrerPushStrategy();
@Mock
Stream stream;
@ -55,7 +56,7 @@ public class ReferrerPushStrategyUnitTest
@Before
public void setup()
{
referrerPushStrategy = new ReferrerPushStrategy();
referrerPushStrategy.setUserAgentBlacklist(Arrays.asList(".*(?i)firefox/16.*"));
}
@Test
@ -67,22 +68,45 @@ public class ReferrerPushStrategyUnitTest
setMockExpectations();
String referrerUrl = fillPushStrategyCache(requestHeaders);
Set<String> pushResources;
// sleep to pretend that the user manually clicked on a linked resource instead the browser requesting subresources immediately
// sleep to pretend that the user manually clicked on a linked resource instead the browser requesting sub
// resources immediately
Thread.sleep(referrerCallTimeout + 1);
requestHeaders.put(HTTPSPDYHeader.URI.name(VERSION), "image2.jpg");
requestHeaders.put("referer", referrerUrl);
pushResources = referrerPushStrategy.apply(stream, requestHeaders, new Fields());
Set<String> pushResources = referrerPushStrategy.apply(stream, requestHeaders, new Fields());
assertThat("pushResources is empty", pushResources.size(), is(0));
requestHeaders.put(HTTPSPDYHeader.URI.name(VERSION), MAIN_URI);
pushResources = referrerPushStrategy.apply(stream, requestHeaders, new Fields());
// as the image2.jpg request has been a link and not a subresource, we expect that pushResources.size() is still 2
// as the image2.jpg request has been a link and not a sub resource, we expect that pushResources.size() is
// still 2
assertThat("pushResources contains two elements image.jpg and style.css", pushResources.size(), is(2));
}
@Test
public void testUserAgentFilter() throws InterruptedException
{
Fields requestHeaders = getBaseHeaders(VERSION);
setMockExpectations();
fillPushStrategyCache(requestHeaders);
Set<String> pushResources = referrerPushStrategy.apply(stream, requestHeaders, new Fields());
assertThat("pushResources contains two elements image.jpg and style.css as no user-agent header is present",
pushResources.size(), is(2));
requestHeaders.put("User-Agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_5) AppleWebKit/537.4 (KHTML, like Gecko) Chrome/22.0.1229.94 Safari/537.4");
pushResources = referrerPushStrategy.apply(stream, requestHeaders, new Fields());
assertThat("pushResources contains two elements image.jpg and style.css as chrome is not blacklisted",
pushResources.size(), is(2));
requestHeaders.put("User-Agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.7; rv:16.0) Gecko/20100101 Firefox/16.0");
pushResources = referrerPushStrategy.apply(stream, requestHeaders, new Fields());
assertThat("no resources are returned as we want to filter firefox", pushResources.size(), is(0));
}
private Fields getBaseHeaders(short version)
{
Fields requestHeaders = new Fields();

View File

@ -38,6 +38,7 @@ import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
@ -269,7 +270,7 @@ public class Config
}
else
{
String name = entry.getName().toLowerCase();
String name = entry.getName().toLowerCase(Locale.ENGLISH);
if (name.endsWith(".jar") || name.endsWith(".zip"))
{
String jar = entry.getCanonicalPath();
@ -796,7 +797,7 @@ public class Config
}
// Add XML configuration
if (subject.toLowerCase().endsWith(".xml"))
if (subject.toLowerCase(Locale.ENGLISH).endsWith(".xml"))
{
// Config file
File f = new File(fixPath(file));
@ -807,7 +808,7 @@ public class Config
}
// Set the main class to execute (overrides any previously set)
if (subject.toLowerCase().endsWith(".class"))
if (subject.toLowerCase(Locale.ENGLISH).endsWith(".class"))
{
// Class
String cn = expand(subject.substring(0,subject.length() - 6));
@ -820,7 +821,7 @@ public class Config
}
// Add raw classpath entry
if (subject.toLowerCase().endsWith(".path"))
if (subject.toLowerCase(Locale.ENGLISH).endsWith(".path"))
{
// classpath (jetty.class.path?) to add to runtime classpath
String cn = expand(subject.substring(0,subject.length() - 5));

Some files were not shown because too many files have changed in this diff Show More