jenkins-winstone-0.9.10-jenkins-47/0000755000175000017500000000000012202116136017441 5ustar jamespagejamespagejenkins-winstone-0.9.10-jenkins-47/sunCodingConventions.xml0000644000175000017500000003304212200024521024336 0ustar jamespagejamespage 14 false [A-Z][a-zA-Z0-9]+ [A-Z][a-zA-Z0-9]+ [a-z][\w]+ [a-z][\w]+ [a-zA-Z][\w]+ [a-z][\w]+ [a-z][\w]+ [a-zA-Z][\w]+ [a-z][\w]+ [a-z][\w]+ [a-zA-Z][\w]+ [a-z][\w]+ [a-z][\w]+ [a-zA-Z][\w]+ [A-Z][a-zA-Z0-9]+ \w+ [a-z][\w]+ [a-z][\w]+ [a-z][\w]+ [a-z][\w]+ [a-z][\w]+ [a-z][\w]+ [a-z][\w]+ [a-z][\w]+ [a-z][\w]+ [a-z][\w]+ [a-z][\w]+ [a-z][\w]+ [a-z]+(?:\.[a-z]+)* [a-z][\w]+ [a-z][\w]+ [a-z][\w]* false false false false false false false false false false false false false false false false false false false 6 30000 30000 30000 30000 30000 30000 true 1 true false true false false bak 0 1 0 1 1
1
1
1 2 1 1
1 0 1 1 1 1 1 1
0
0
1
false false false false true false true false false false false false false true true true false false true true false @todo false false false - false false Inner Classes Constructors Instance fields Instance initializers Inner Interfaces Methods Static fields/initializers
0 false
disabled 3 java:2|javax:2|org:2|gnu:2|*:0 disabled true true true false true true 1 1 0 1 6 55 -1 4 -1 0 8 -1 1 false false false false true false true false false false true false false static|field|initializer|constructor|method|interface|class false false public|protected|private|abstract|static|final|synchronized|transient|volatile|native|strictfp true true true true false false false false false false true false false true true true true true true false false 1 false false false true false false false false false false false false false false true true 115 false true false false false false false false
jenkins-winstone-0.9.10-jenkins-47/winstone.bat0000644000175000017500000000373712200024521022003 0ustar jamespagejamespage@echo off set JAVA_HOME=c:\java\jdk1.5.0 set WINSTONE_HOME=d:\rick\winstone set CATALINA_HOME=c:\java\tomcat set JAVA_OPTS=-Djava.endorsed.dirs=%JAVA_HOME%\jre\lib\ext set CP=%CP%;%WINSTONE_HOME%\target\winstone-0.9.7-cvs.jar set WINSTONE_OPTS=--prefix=/examples set WINSTONE_OPTS=%WINSTONE_OPTS% --webroot=%CATALINA_HOME%\webapps\jsp-examples set WINSTONE_OPTS=%WINSTONE_OPTS% --debug=8 set WINSTONE_OPTS=%WINSTONE_OPTS% --commonLibFolder=c:\java\commonLibAll set WINSTONE_OPTS=%WINSTONE_OPTS% --javaHome=%JAVA_HOME% set WINSTONE_OPTS=%WINSTONE_OPTS% --argumentsRealm.passwd.rickk=rickk --argumentsRealm.roles.rickk=test,tomcat @rem ******************************************************************** @rem Uncomment for non-1.4 jdks @rem ******************************************************************** @rem set CP=%CP%;%WINSTONE_HOME%\build\lib\gnujaxp.jar set CP=%CP%;%WINSTONE_HOME%\dist\xml-apis.jar set CP=%CP%;%WINSTONE_HOME%\dist\xercesImpl.jar @rem ******************************************************************** @rem Uncomment for jsp support @rem ******************************************************************** @rem set CP=%CP%;%CATALINA_HOME%-5\common\lib\jasper-runtime.jar @rem set CP=%CP%;%CATALINA_HOME%-5\common\lib\jasper-compiler.jar @rem set CP=%CP%;%CATALINA_HOME%\common\lib\commons-logging-api.jar @rem set CP=%CP%;%CATALINA_HOME%-5\common\lib\commons-el.jar @rem set CP=%CP%;%CATALINA_HOME%\common\lib\ant.jar @rem set CP=%CP%;%JAVA_HOME%\lib\tools.jar set WINSTONE_OPTS=%WINSTONE_OPTS% --useJasper @rem ******************************************************************** @rem Uncomment for invoker support (ie Tomcat style) @rem ******************************************************************** set WINSTONE_OPTS=%WINSTONE_OPTS% --useInvoker set CP=%CP%;c:\java\jars\activation.jar set CP=%CP%;c:\java\jars\mail.jar echo Options: %WINSTONE_OPTS% %JAVA_HOME%\bin\java -server -cp %CP% %JAVA_OPTS% winstone.Launcher %WINSTONE_OPTS%jenkins-winstone-0.9.10-jenkins-47/project.properties0000644000175000017500000000124712200024521023223 0ustar jamespagejamespage# repositories for jar file downloads maven.repo.remote=\ file:${basedir}/lib,\ http://repo1.maven.org/maven/ # compile maven.compile.encoding=EUC-JP maven.compile.source=1.2 maven.compile.target=1.1 maven.jar.mainclass=winstone.Launcher # test #maven.test.skip=true maven.junit.format=plain maven.junit.fork=true # project site #maven.docs.locale=ja #maven.docs.inputencoding=UTF-8 #maven.docs.outputencoding=UTF-8 # checkstyle and jalopy maven.checkstyle.properties=checkstyle.xml maven.jalopy.style=sunCodingConventions.xml backup.dir=../backup tck.webapp.dir=/tck/webapps tck.jsp.webapp.dir=/tck/jspwebapps tck.endorsed.dir=/tck/endorsed tck.commonLib.dir=/tck/commonjenkins-winstone-0.9.10-jenkins-47/.gitignore0000644000175000017500000000003112200024521021415 0ustar jamespagejamespage*.iml *.ipr *.iws target jenkins-winstone-0.9.10-jenkins-47/pom.xml0000644000175000017500000001362412200024521020756 0ustar jamespagejamespage 4.0.0 org.jenkins-ci winstone 0.9.10-jenkins-47 jar Winstone http://winstone.sourceforge.net/ Winstone is a servlet container that was written out of a desire to provide servlet functionality without the bloat that full J2EE compliance introduces. GNU Lesser General Public License version 2.1 http://www.gnu.org/licenses/lgpl.html COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0 http://www.sun.com/cddl/cddl.html src/java src/conf true **/*.* src/java **/*.properties src/test src/test **/*.java maven-compiler-plugin 2.4 1.5 1.5 maven-antrun-plugin prepare-testwebapp process-test-classes run maven-surefire-plugin **/*Test.java **/*NaughtyTest.java winstone/testCase/load/LoadTest.java maven-jar-plugin true true winstone.Launcher org.apache.maven.plugins maven-enforcer-plugin 1.1 enforce [1.7,) maven.jenkins-ci.org http://maven.jenkins-ci.org:8081/content/repositories/releases repo.jenkins-ci.org http://repo.jenkins-ci.org/public/ scm:git:git://github.com/jenkinsci/winstone.git scm:git:git@github.com:jenkinsci/winstone.git http://github.com/jenkinsci/winstone junit junit 4.11 test httpunit httpunit 1.6 test jenkins-winstone-0.9.10-jenkins-47/.cvsignore0000644000175000017500000000004512200024521021432 0ustar jamespagejamespagebuild dist build-eclipse logs target jenkins-winstone-0.9.10-jenkins-47/checkstyle.xml0000644000175000017500000002345112200024521022320 0ustar jamespagejamespage jenkins-winstone-0.9.10-jenkins-47/contrib/0000755000175000017500000000000012200024521021073 5ustar jamespagejamespagejenkins-winstone-0.9.10-jenkins-47/contrib/NioSocketServer.java0000644000175000017500000001264412200024521025032 0ustar jamespagejamespagepackage winstone.nio; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.ServerSocket; import java.net.Socket; import java.net.SocketTimeoutException; import java.nio.ByteBuffer; import java.nio.channels.SelectionKey; import java.nio.channels.Selector; import java.nio.channels.ServerSocketChannel; import java.nio.channels.SocketChannel; import java.util.Iterator; import java.util.Set; /** * @author Rick Knowles * @version $Id: NioSocketServer.java,v 1.1 2006/08/27 14:22:32 rickknowles Exp $ */ public class NioSocketServer implements Runnable { private final static int LISTEN_PORT = 6475; private Thread thread; private Selector selector; private ServerSocket serverSocket; public NioSocketServer(boolean useNIO) throws IOException { if (useNIO) { ServerSocketChannel ssc = ServerSocketChannel.open(); ssc.configureBlocking(false); ServerSocket ss = ssc.socket(); ss.bind(new InetSocketAddress(LISTEN_PORT)); this.selector = Selector.open(); ssc.register(this.selector, SelectionKey.OP_ACCEPT); } else { this.serverSocket = new ServerSocket(LISTEN_PORT); this.serverSocket.setSoTimeout(500); } this.thread = new Thread(this); this.thread.setDaemon(true); this.thread.start(); } public void run() { boolean interrupted = false; while (!interrupted) { try { if (this.selector != null) { nioLoop(); } else { jioLoop(); } interrupted = Thread.interrupted(); } catch (IOException err) { err.printStackTrace(); interrupted = true; } } this.thread = null; } private void nioLoop() throws IOException { this.selector.select(500); Set selectedKeys = this.selector.selectedKeys(); Iterator i = selectedKeys.iterator(); while (i.hasNext()) { SelectionKey key = (SelectionKey) i.next(); if (key.isAcceptable()) { ServerSocketChannel ssc = (ServerSocketChannel) key.channel(); SocketChannel sc = ssc.accept(); sc.configureBlocking(false); sc.register(this.selector, SelectionKey.OP_READ); } else if (key.isReadable()) { SocketChannel sc = (SocketChannel) key.channel(); ByteBuffer buffer = ByteBuffer.allocate(10); buffer.clear(); sc.read(buffer); buffer.flip(); sc.write(buffer); sc.close(); } i.remove(); } } private void jioLoop() throws IOException { Socket socket = null; try { socket = this.serverSocket.accept(); } catch (SocketTimeoutException err) { } if (socket != null) { InputStream in = socket.getInputStream(); int pos = 0; int read = 0; byte buffer[] = new byte[10]; while ((pos < buffer.length) && ((read = in.read(buffer, pos, buffer.length - pos)) != -1)){ pos += read; } OutputStream out = socket.getOutputStream(); out.write(buffer, 0, pos); in.close(); out.close(); socket.close(); } } public void stop() { this.thread.interrupt(); } public static void main(String argv[]) throws Exception { String iterArg = argv.length > 1 ? argv[1] : "1000"; int ITERATION_COUNT = Integer.parseInt(iterArg); boolean useNIO = argv.length > 0 && argv[0].equals("nio"); InetAddress LOCATION = InetAddress.getLocalHost(); System.out.println("Address: " + LOCATION); NioSocketServer server = new NioSocketServer(useNIO); Thread.sleep(1000); long startTime = System.currentTimeMillis(); byte TEST_ARRAY[] = "1234567890".getBytes(); for (int n = 0; n < ITERATION_COUNT; n++) { byte buffer[] = new byte[TEST_ARRAY.length]; Socket socket = new Socket(LOCATION, LISTEN_PORT); socket.setSoTimeout(50); OutputStream out = socket.getOutputStream(); out.write(TEST_ARRAY); InputStream in = socket.getInputStream(); int read = 0; int pos = 0; while ((pos < buffer.length) && ((read = in.read(buffer, pos, buffer.length - pos)) != -1)){ pos += read; } in.close(); out.close(); socket.close(); // if (!Arrays.equals(TEST_ARRAY, buffer)) { // throw new RuntimeException("in and out arrays are not equal"); // } if (n % 500 == 0) { System.out.println("Completed " + n + " iterations in " + (System.currentTimeMillis() - startTime) + "ms"); } } System.out.println("Completed " + ITERATION_COUNT + " iterations in " + (System.currentTimeMillis() - startTime) + "ms"); server.stop(); } } jenkins-winstone-0.9.10-jenkins-47/contrib/README_jp.html0000644000175000017500000013771412200024521023424 0ustar jamespagejamespage Winstoneサーブレトコンテーナー (日本語)

Winstoneサーブレトコンテーナー v0.8.1

ダウンロード  ライセンスは更新しました


これはWinstoneサーブレトコンテナーのベタリリースです. プロジェクトのホームページは 'http://winstone.sourceforge.net' です。

作者: Rick Knowles (問い合わせは下記まで)

コンテンツ

About:

始めに:

使い方のヒント:

Winstoneとは ?

大きくないサーブレトコンテナーを欲しかったから、Winstoneを作りました。

全J2EE機能が有るコンテナーを作成するつもりではありませんでした 『JNDI、 JavaMail、EJBの機能は必要ではないので、入てないんです。 そんな機能が欲しかったら、 別なコンテナーを使ったほうがいいです。たとえば ResinやJettyやTomcatはそんな事 ができます』

シンプルコンテナーが要るケースがいろいろ有ります。そんなケースにはWinstoneが便利です。

最初のゴールはこうでした:

  • 1つのウェブ適用に速い安定したコンテナー機能を供給します。
  • 配信したJARファイルのサイズは最小限の物にしています『現在 160KB』
  • 設定ファイルを減らして、using command line options to optionally override sensible compiled in defaults.
  • Eventually compile with GCJ to make a 3-4Meg windows exe for local development/deployment of servlets. This has not happened yet, because of some GCJ class loading problems.
  • Optionally support JSP compilation using Apache's Jasper. (http://jakarta.apache.org)

何で Winstone と言うの ?

The short version (because the long version is way too politically incorrect) is as follows:

Winstone is the name of a rather large Jamaican man a friend of mine met one night, while he was out clubbing in the Roppongi area of Tokyo. He (my friend) was a little liquored up at the time, and when Winstone suggested they head to "this really cool club" he knew, he didn't think anything was wrong. It wasn't until Winstone led him down a dark stairwell and dropped his trousers that my friend clued in and ran like hell.

It was too good a story to let die, so I named this project Winstone so that said friend will continue to be reminded of it. Heheheh ....

ライセンス

The Web-App DTD files (everything in the src/javax/servlet/resources and src/javax/servlet/jsp/resources folders) are covered by the licenses described at the top of each file (usually as licensed by Sun Microsystems).

As of v0.8.1, all other files are dual-licensed, under either the Lesser GNU Public License (LGPL) as described in LICENSE-LGPL.txt, or the Common Development and Distribution License (CDDL) as decribed in LICENSE-CDDL.txt. Until v0.8, the license used was the GNU Public License (GPL).

The goal of dual-licensing is to make Winstone as attractive as possible to distributors of commercial webapps, while ensuring everyone benefits from any improvements. The CDDL allows free distribution with any commercial applications, while distribution with a GPL licensed webapp is also possible under the LGPL. If you are unclear about which license applies to an application you wish to distribute or sell, please contact me.

作者への問い合わせ

You can contact me through the Winstone development list at sourceforge (winstone-devel AT lists DOT sourceforge DOT net). If you have any general comments or questions about Winstone please mail me on that list - I'll try to start a faq soon.

I'm open to help from anyone who's willing to help me meet the above goals for Winstone. Just mail me at the list (winstone-devel AT lists DOT sourceforge DOT net)

最初にする事

If you want to build from source code, you will need to download and install Apache Maven (v1.x). The following instructions assume you have already installed Maven and have the maven shell script in your path (to get Maven, see http://maven.apache.org/).

To build Winstone, unpack the tree:

  tar zxf winstone-src-0.8.1.tar.gz

Then build it:

  cd winstone
  maven clean jar

To run it:

  java -jar target/winstone-0.8.1.jar --webroot=<location of webroot> (+ other options)

- OR -

  java -jar target/winstone-0.8.1.jar --warfile=<location of warfile> (+ other options)

- OR -

  java -jar target/winstone-0.8.1.jar --webappsDir=<location of webapps directory> (+ other options)

- OR -

  java -jar target/winstone-0.8.1.jar --hostsDir=<location of hosts directory> (+ other options)

The winstone.jar file will be in the target directory after the build is complete.

コマンドラインオプション

Syntax:
  java -jar winstone-0.8.1.jar [--option=value] [--option=value] etc

Required options: either --webroot OR --warfile OR --webappsDir OR --hostsDir
   --webroot                = set document root folder.
   --warfile                = set location of warfile to extract from.
   --webappsDir             = set directory for multiple webapps to be deployed from
   --hostsDir               = set directory for name-based virtual hosts to be deployed from

Other options:
   --javaHome               = Override the JAVA_HOME variable
   --toolsJar               = The location of tools.jar (default is JAVA_HOME/lib/tools.jar) 
   --config                 = load configuration properties from here(if supplied).
   --prefix                 = add this prefix to all URLs. (eg http://host/prefix/etc).
   --commonLibFolder        = folder for additional jar files. Default is ./lib
    
   --logfile                = redirect winstone log messages to this file
   --logThrowingLineNo      = show the line no that logged the message (slow). Default is false
   --logThrowingThread      = show the thread that logged the message. Default is false
   --debug                  = set the level of debug msgs (1-9). Default is 5 (INFO level)

   --httpPort               = set the http listening port. -1 to disable, Default is 8080
   --httpListenAddress      = set the http listening address. Default is all interfaces
   --httpDoHostnameLookups  = enable host name lookups on http connections. Default is false
   --httpKeepAliveTimeout   = how long idle HTTP keep-alive connections are kept around (in ms)?
   --httpsPort              = set the https listening port. -1 to disable, Default is disabled
   --httpsListenAddress     = set the https listening address. Default is all interfaces
   --httpsDoHostnameLookups = enable host name lookups on https connections. Default is false
   --httpsKeepAliveTimeout  = how long idle HTTPS keep-alive connections are kept around (in ms)?
   --httpsKeyStore          = the location of the SSL KeyStore file. Default is ./winstone.ks
   --httpsKeyStorePassword  = the password for the SSL KeyStore file. Default is null
   --httpsKeyManagerType    = the SSL KeyManagerFactory type (eg SunX509, IbmX509). Default is SunX509
   --ajp13Port              = set the ajp13 listening port. -1 to disable, Default disabled
   --ajp13ListenAddress     = set the ajp13 listening address. Default is all interfaces
   --controlPort            = set the shutdown/control port. -1 to disable, Default disabled

   --handlerCountStartup    = set the no of worker threads to spawn at startup. Default is 5
   --handlerCountMax        = set the max no of worker threads to allow. Default is 40
   --handlerCountMaxIdle    = set the max no of idle worker threads to allow. Default is 5

   --directoryListings      = enable directory lists (true/false). Default is true
   --useJasper              = enable jasper JSP handling (true/false). Default is false
   --useServletReloading    = enable servlet reloading (true/false). Default is false
   --preferredClassLoader   = override the preferred webapp class loader.
   --useInvoker             = enable the servlet invoker (true/false). Default is true
   --invokerPrefix          = set the invoker prefix. Default is /servlet/
   --simulateModUniqueId    = simulate the apache mod_unique_id function. Default is false
   --usage / --help         = show this message
    
Cluster options:
   --useCluster             = enable cluster support (true/false). Default is false
   --clusterClassName       = Set the cluster class to use. Defaults to SimpleCluster class
   --clusterNodes           = a comma separated list of node addresses (IP:ControlPort,IP:ControlPort,etc)

JNDI options:
   --useJNDI                      = enable JNDI support (true/false). Default is false
   --containerJndiClassName       = Set the container wide JNDI manager class to use. Defaults to ContainerJNDIManager
   --webappJndiClassName          = Set the web-app JNDI manager class to use. Defaults to WebAppJNDIManager
   --jndi.resource.<name>         = set the class to be used for the resource marked <name>
   --jndi.param.<name>.<att>      = set an attribute <att> for the resource marked <name>

Security options:
   --realmClassName               = Set the realm class to use for user authentication. Defaults to ArgumentsRealm class

   --argumentsRealm.passwd.<user> = Password for user <user>. (for ArgumentsRealm)
   --argumentsRealm.roles.<user>  = Roles for user <user> (comma-separated) (for ArgumentsRealm)

   --fileRealm.configFile         = File containing users/passwds/roles. Only valid for the FileRealm realm class

Access logging:
   --accessLoggerClassName        = Set the access logger class to use for user authentication. Defaults to disabled
   --simpleAccessLogger.format    = The log format to use. Supports combined/common/resin/custom (SimpleAccessLogger only)
   --simpleAccessLogger.file      = The location pattern for the log file(SimpleAccessLogger only)

設定ファイル

You don't really need a config file, but sometimes it's handy to be able to use the same settings each time without running through the command history.

Winstone looks for a config file winstone.properties in the current directory (or in the location specified with --config) at startup. It loads the properties in this file, overrides them with any supplied command line properties, and then starts itself.

This is just intended as a handy feature for people who want to cache regular startup options, rather than using batch files.

デプロイーの選択

The simplest way to use winstone is with a single webapp. To do this, just supply the warfile or webroot directory as an argument:

  • java -jar winstone.jar <webroot or warfile>, (this method auto-detects the type) or
  • java -jar winstone.jar --webroot=<webroot>, or
  • java -jar winstone.jar --warfile=<warfile>

If you need to support multiple webapps, use the --webappsDir switch, to which you pass a directory that contains multiple warfiles/webroots.

  • java -jar winstone.jar --webappsDir=<dir containing multiple webroots>

The directory becomes the prefix name for that webapp (so hello becomes /hello, etc). The directory named ROOT becomes the no-prefix webapp.

So, for example, if you had a directory /usr/local/webapps which contained sub-directories ROOT and test, if you executed java -jar winstone.jar --webappsDir=/usr/local/webapps, you would find that the test folder would act as a webroot for requests prefixed with /test, while other requests would go to the webapp in the ROOT folder

From v0.8, if you need multiple hosts (sometimes called name-based virtual hosting), there is a new option --hostsDir. This acts in a similar way to the --webappsDir switch, but it defines an extra level of sub-directories, the top being a per-host directory and the second a per-webapp directory as with --webappsDir.

The directory name becomes the host name: that is, a directory named "www.blah.com" will only serve requests with the host header www.blah.com, unless it is the default host. If a directory named "default" is found, it becomes the default host. If no default directory is found, the first directory in the list (alphabetically) becomes the default host.

  • java -jar winstone.jar --hostsDir=<dir containing multiple host directories>

Winstoneにない機能

As a result of the design goals, there are some things Winstone doesn't do

  • There are now three connectors supplied with Winstone:
    1. An internal HTTP connector - allows plain HTTP/1.1 connections only
    2. An internal HTTPS connector - allows HTTP/1.1 connections over SSL
    3. An AJP13 connector - allows connection to Apache/IIS/iPlanet, etc
    While there is an internal HTTPS/SSL connector included, I recommend using Apache 2.0 with the AJP13 connector (instructions below). It has way more configuration options than Winstone's connector does.
  • HttpSession support is cookie-based only (no URL rewriting). URL rewriting introduces a lot of unnecessary complex request body processing, and given that browser cookie support is common these days (and no-one I know uses URL rewriting), I plan not to implement this.
  • The messages are all in English only. These have been updated to use resource bundles, but no translations yet.

セキュリティ上の注意

If you enable the controlPort, be aware that there is no password protection at all on this port. Anyone who can get access to this port can stop or restart the server. I plan to add some simple authentication to this at some point, but not just yet.

The controlPort is disabled by default. If you choose not to enable it, the only way to shut Winstone down is to kill the process (either by Ctrl-C or kill command).

最近追加した機能

New features in v0.8:

  • Expanded the features of the JDBC connection pool to include keep-alive queries and block-and-retry behaviour when the pool has been exhausted.
  • Added filter match caching (performance improvement)
  • Name-based virtual hosting. Using the --hostsDir switch, you can define a directory that contains directories named by hostname, each of which acts like a --webappsDir. See above for more details.
  • Access logging. Disabled by default, but enabled with the switch --accessLoggerClassName=winstone.accesslog.SimpleAccessLogger. You can provide your own logging implementation, but the simple access logger contains Apache Combined/Common format logging and Resin format logging, so it should suffice for most cases. See below for more details.
  • Better embedding support. You can now embed warfiles and properties file inside the winstone jar itself, for an all-in-one application jar. See below for more details.
  • Tested with WebDAV applications. Winstone has now been tested/debugged with Jakarta Slide and Davenport WebDAV applications, and works correctly (previous versions had some obscure bugs that caused WebDAV to fail)

New features in v0.7:

  • Updated build process to use Apache Maven (see http://maven.apache.org. Build instructions have been updated to match.
  • Source code has been reformatted - a fair bit easier to read now
  • Multiple webapp support has been added. There's no auto-deploy features yet, but that will come soon. Use the --webappsDir=<webapps directory> to declare a folder that will have any directories auto-mounted and any warfiles auto-deployed. (I originally said this was not going to be included, but changed my mind when I realised it could be done with only 10K additional jarfile size).
  • Fixed the bugs in the exception handling and error servlet redirection, as well as in web xml parsing, and more other places that I can possibly list here. If you had some strange bug or incompatibility before, chances are it's been fixed now.
  • Passed the Sun JSR-154 Servlet Test Compatibility Kit (TCK) tests.
  • I also ran the JSR-152 JSP TCK on winstone with Apache Jasper support enabled, and while it didn't pass all tests, the tests it failed were the same ones the Tomcat failed, so I notified the Tomcat/Jasper developers of the test failures. Currently waiting on a response ... in any case I suspect these are actually test errors rather than implementation errors.
  • Better support for open source JVMs. Martin Cordova has been very helpful in testing winstone under a wider range of JVMs, as well as providing some really good feedback on needed features. His tests included JamVM and CacaoVM, as well as IBM's JDK. Jim Huang also reported that winstone works well under Kaffe.
  • User definable webapp class loader: This is likely to be of interest to the Aspect Oriented Programming crowd. It allows you to write your own class loader class (conforming to the same contructor signature as URLClassLoader), and then to use it in place of the normal web app class loader with --preferredClassLoader. This allows AspectWerkz style weaving classloaders to be used on webapps where it wouldn't have been otherwise possible (eg JDKs that don't support the profiler option, such as 1.4 and before), or anything else you can think of doing with a custom classloader.

New features in v0.6:

  • Updated to Servlet 2.4 specification compliance, although I haven't yet run Sun's Test Compatibility Kit on it - I'm still waiting for that. It works with all of the v2.4 webapps I've tried. The only caveat is that you will need Apache Xerces in the system classpath to make it work (see below).
  • Updated to JSP 2.0 specification compliance. This is the main cause for the blowout in size of the larger jar file, but it does result in much simpler set up for Jasper (see below).
  • Added a command-line tool for accessing control port options, such as shutdown and restart. Restart is new to this version, and causes a shutdown and redeploy from scratch.
  • Added a lib folder for additional jars. This defaults to "lib" under the current directory, with any jar or zip files in this folder being added to the webapp classpath.
  • Extensively tested with the Apache Struts and JSTL frameworks. This highlighted a number of bugs related to internationalisation I wouldn't have found otherwise.
  • Many minor features such as range downloads on static resources, a logfile directive for writing log messages to a file, and many MANY performance enhancements and bugfixes. See the TODO.txt file in the source distribution for a full list.
  • Update: June 28, 2004 - Added HTTPS support to version v0.6.4

New features in v0.5:

  • Implemented DIGEST and CERT authentication methods. The CERT type is largely untested (due to lack of A: access to certificates and B: knowledge of browser configuration for client certificates) - if anyone wants to help with testing this, I'd appreciate it.
  • Implemented simple clustering (ie sharing of sessions between multiple Winstone instances). See below for cluster configuration details.
  • Implemented optional JNDI support. This is just a memory-based Context intended for storing lookups on <env-entry> and <resource-ref> references, but it also includes a pooling JDBC DataSource object .... it's funny how you don't realise how important some things are until you go without them ....
  • The control port has been modified to be more useful. See below for usage instructions.
  • The distribution jar is now available in two forms:
    1. Complete version (winstone.jar): This contains the complete winstone feature-set, including AJP13 Apache connectors, Authentication/Realm support and Clustering support.
    2. Lite version (winstone-lite.jar): This is the core winstone feature-set only, ie commonly used servlet features, as fast and reliable as possible, with unnecessary options removed.

New features in v0.4:

  • Implemented the <error-page> directive
  • Added object pools for request/response objects for performance reasons
  • The handler pools are now controllable via startup properties
  • Servlet reloading is now supported (optionally - include --useServletReloading=true at startup)
  • The initial Authentication Model is in place (see below for help). There are two base classes that make it work: AuthenticationRealm and AuthenticationHandler. Currently Argument-based and File-based realms (ie user/password details supplied via command-line args or XML files) and HTTP BASIC and FORM authentication are implemented, but the others (DIGEST and CERT authentication forms) will come soon.

New features in v0.3:

  • The request handler threads now use monitors, which allows them to exist beyond a single request/response cycle. The benefit here is performance - it removes a serious bottleneck.
  • WAR files are now supported via the --warfile attribute. If you specify a warfile in this manner, it will be automatically extracted by the container to a temp directory, overwriting only files that are older than the archive date.
  • Servlet attribute, session, and context listeners (Servlet spec v2.3) are now fully supported. The HttpSessionActivationListener class will be fully supported once the session transfer is implemented.
  • Servlet Filters (Servlet spec v2.3) are now fully supported.
  • There is now an AJP13 connector, which means Winstone will now work behind Apache/IIS/etc using Tomcat's mod_jk. Try it out and see ... there's a section below on using the mod_jk connector.

XMLパーザーでXercesを使ってる (バージョン2.4)

As part of the upgrade in the servlet specification, the v2.4 incarnation of the web.xml file is validated using XML Schema Documents (XSD) as opposed to Document Type Definitions (DTD). While I still have no idea why such a change was necessary - especially given that DTD validation seems to be more than enough in this case - I did implement it. Perhaps the people on the specification committee might want to give a thought to container size next time round, as this one change multiplies the size of the distribution by five.

Anyway, to use Xerces, you'll need to download the latest Xerces-J parser from here, and copy xercesImpl.jar and xml-apis.jar into a folder somewhere (name it "endorsed"). Putting them in the winstone/lib folder will not work, because they must be in the system endorsed classpath to override the JDK internal XML parser.

Then add -Djava.endorsed.dirs=<endorsed dir name> as a JVM arg to your command line for starting winstone, eg:

  java -Djava.endorsed.dirs=/jdk/endorsed -jar winstone.jar --webroot=...

JSP (ApacheのJasperを使ってる)

Winstone supports JSPs using Apache's Jasper JSP compiler. Thanks to a rather clever design by the Jasper team, this was much less work than I expected - well done Jasper guys.

Required steps:

  1. Add --useJasper to your startup command line, since JSPs are disabled by default
  2. Both the v1.1 and v2.0 versions of Jasper are supported. In order to turn on JSP compilation in Winstone, you'll need to place the following jar files into the lib folder under the current directory (or the folder identified by the --commonLibFolder directive).

    • jasper-compiler.jar, jasper-runtime.jar, ant.jar - Not supplied with Winstone. You can get this from the standard Tomcat binary download location. Just download the latest Tomcat, and copy these three files into the lib folder for Winstone. They will be in the tomcat_home/common/lib folder.
    • commons-logging-api.jar, commons-el.jar (Jasper 2 only) - These are required if you are using Jasper 2.0. You can get them from the tomcat binary distribution or separately from the link below.

    All of these are available from the Jakarta download site

  3. You'll also need tools.jar, and this is handled a little differently. The ant javac compile task needs this to turn the generated .java files into .class files at runtime. You should already have this in the <java_home>/lib folder of your jdk.

    There are two new startup arguments for Winstone --javaHome and --toolsJar. You should only need to set --javaHome to make Jasper work properly. Your startup might look like this:

      java -jar winstone.jar --useJasper \
                             --javaHome=c:\java\jdk1.4.2 \
                             --webroot=...

    Additionally, you can specify the exact location of the toolsJar file like this:

      java -jar winstone.jar --useJasper \
                             --javaHome=c:\java\jdk1.4.2 \
                             --toolsJar=c:\tools.jar \
                             --webroot=...

Apacheに繋がってる

These instructions are for beginners: if you know your way around Apache and Tomcat, you'll know what's going on here.

Download and install Apache for your platform (and obviously Winstone too), then follow these steps:

  1. Download mod_jk2.dll/so into the apache modules directory
  2. Add the following to the apache conf file (httpd.conf):
    LoadModule jk2_module modules/mod_jk2.dll
    
    <Location "/<Winstone Prefix>/*">
      JkUriSet worker ajp13:localhost:8009 
    </Location>
    
  3. Create a new file called workers2.properties in the apache conf directory, with the following contents
    # only in the beginning. In production comment out
    [logger.apache2]
    level=DEBUG
    
    # Example socket channel, override port and host.
    [channel.socket:localhost:8009]
    port=8009
    host=127.0.0.1
    
    # define the worker
    [ajp13:localhost:8009]
    channel=channel.socket:localhost:8009
    
  4. Start up Winstone and Apache and try connecting to the your webapp on the apache port, with the winstone prefix. If it doesn't work, try looking at the apache error.log file for hints. If you get hex dumps, mail them to the winstone-devel list, together with any stack traces winstone generated.

Please note this is not an optimal configuration for production uses. This is provided purely for those who need some help to get started. Read the mod_jk documentation with Tomcat for more detailed info.

認証の設定

The process here is almost identical to that of Tomcat (I know this because I used the Tomcat examples webapp to develop against). There are two components - the web.xml component and selecting/configuring an AuthenticationRealm class.

  • The web.xml part is the same for all webapps - you include the <security-constraint> and <login-config> elements as required, eg (from the Tomcat examples web.xml):
    <security-constraint>
      <display-name>Example Security Constraint</display-name>
      <web-resource-collection>
        <web-resource-name>Protected Area</web-resource-name>
        <url-pattern>/jsp/security/protected/*</url-pattern>
        <http-method>DELETE</http-method>
        <http-method>GET</http-method>
        <http-method>POST</http-method>
        <http-method>PUT</http-method>
      </web-resource-collection>
      <auth-constraint>
        <role-name>tomcat</role-name>
        <role-name>role1</role-name>
      </auth-constraint>
    </security-constraint>
    
    <login-config>
      <auth-method>FORM</auth-method>
      <realm-name>Example Form-Based Authentication Area</realm-name>
      <form-login-config>
        <form-login-page>/jsp/security/protected/login.jsp</form-login-page>
        <form-error-page>/jsp/security/protected/error.jsp</form-error-page>
      </form-login-config>
    </login-config>
    
  • The AuthenticationRealm part is Winstone specific. Here you currently have three options:
    1. ArgumentsRealm: Here you simply add additional command line args for each user's password and role list. Passwords are added with --argumentsRealm.passwd.<username>=<password>, and roles are added with --argumentsRealm.roles.<username>=<role1>,<role2>
    2. FileRealm: This is the same as the Tomcat tomcat-users.xml file. Pass in the command line arguments --realmClass=winstone.realm.FileRealm --fileRealm.configFile=<filename>, and it should work exactly the way Tomcat does by default.
    3. Write your own: You just have to extend the winstone.AuthenticationRealm class, and override the appropriate methods (as the File and Arguments Realms do), and specify the class name in --realmClass.

This component is left intentionally fairly simple, and relatively extracted. I'm planning to break the realm and authentication stuff into an optional jar later, since not many webapps I've seen use it.

クラスターの機能

It should be pointed out in the beginning that the Cluster support currently implemented in Winstone is actually just session sharing. If a request comes to a node in the cluster that doesn't recognise the session ID supplied, that node simply asks the others "Do you know this session ?". If one does know it, it transfers the session to the requesting node, and the requesting node carries on as if it had always had the session in the first place.

If a specific node in the cluster goes offline, so do all the sessions that it was holding. There is no active "push" of sessions to other nodes, so as far as resilience to failure goes, this cluster is fairly weak. The clustering provided here is meant to allow a dumb load balancer to redirect requests randomly across a cluster of Winstone instances without requiring it to be "session sticky".

That said, the configuration is fairly simple. The only information you need is the IP address and control port of at least one other active node in the cluster. Once you have that, add the following options to the command line startup:

java -jar winstone.jar ...< other options > ... \
                       --controlPort=<myControlPort> \
                       --useCluster \
                       --clusterNodes=<IP1:controlPort1>

where IP1 is the IP address of the other node in the cluster, and myControlPort and controlPort1 are the port numbers to use for the control ports of this instance and the other node respectively. Note that it is necessary to actively set the controlPort on this instance, since it is disabled by default.

You would likewise set up the other instance with reciprocal options (ie changing the IPs and controlPort values appropriately.

NOTE: There are some additional requirements on your web application for Clustering of sessions to be successful.

  1. You need to include the <distributable/> element in your web.xml file. This tells Winstone that your webapp is programmed correctly to support clustering. If this is missing, clustering will be disabled.
  2. Any objects you add to the session must implement java.io.Serializable. This is required because Winstone serializes the objects in the session over the controlPort to other nodes, and reconstructs the serialized session at the destination. If you try to put a non-serializable object into the session, Winstone will throw an exception reminding you to make all session objects serializable.

コントロールポートの機能とプロトコール

From v0.5, the behaviour of the control port changes slightly. Due to increased usage of the control port by the clustering function, a rudimentary protocol has been added.

The protocol is very simple. The first byte sent to the server is a flag indicating what type of request is being issued. Beyond that the protocol varies for each request type, but the request type flag options are listed below:

  • 0 (ASCII 48) = shutdown
  • 1 (ASCII 49) = request search for a session
  • 2 (ASCII 50) = request list of currently connected cluster nodes
  • 3 (ASCII 51) = cluster node heartbeat
  • 4 (ASCII 52) = request reload of web application context

Obviously, unless you're planning to write your own cluster extensions, the only two you will be interested in are the shutdown and reload options. Luckily there is a wrapper class for accessing these functions, named winstone.tools.WinstoneControl. Try the following to get a usage statement:

  java -cp winstone.jar winstone.tools.WinstoneControl

JNDIの設定

I know that in the introduction I said that Winstone was only going to support the core servlet APIs, but I've since discovered that most people use just a little more than the core servlet API offers. For example, some people use just a JNDI JavaMail session to send administrator error mails, while others want to offer a simple servlet over SSL (and hence need Apache), still others use just a JNDI DataSource to keep a reference to the connection pool.

For this reason I've included a really basic optional JNDI service within Winstone. For the moment, it supports simple operations (such as bind, lookup, rebind, etc) and allows you to store references to environment variables (drawn from the env-entry elements in web.xml and/or command line arguments).

NOTE: JNDI support is disabled by default. It must be enabled using --useJNDI=true

Configuration can be done in two ways:

  • <env-entry> elements - This is the standard way to add simple objects, such as sql strings or configuration integers/strings. For example:
      <env-entry>
        <env-entry-name>test/hello</env-entry-name>
        <env-entry-type>java.lang.Integer</env-entry-type>
        <env-entry-value>45</env-entry-value>
      </env-entry>
    
  • Command line arguments - This is for more complex objects that require attributes to be created (JDBC DataSources for example). The syntax here involves adding a clause of the kind --jndi.resource.<resName>=<className> for each object to create, followed by --jndi.param.<resName>.<attName>=<attValue> for each attribute required. For example:
    java -jar winstone.jar ...< other options > ... \
                            --useJNDI=true \
                            --jndi.resource.test=java.lang.Float \
                            --jndi.param.test.value=45.56
    

Additionally, it includes a JDBC DataSource object which can be used as a wrapper around normal JDBC drivers. This is fairly simple for now, but it meets the requirements I mentioned above. Options are as follows:

  1. url (REQUIRED) - JDBC URL (jdbc:mysql://db.widgets.com/db)
  2. driverClassName (REQUIRED) - JDBC Driver name (eg com.mysql.jdbc.Driver)
  3. username - username for database authentication
  4. password - password for database authentication
  5. maxConnections - Maximum number of connections allowed in the pool. Default is 20
  6. maxIdle - Maximum number of idle connections allowed in the pool. Default is 10
  7. startConnections - The number of connections to open the pool with. Deafault is 2
  8. keepAliveSQL - The sql to execute on keep-alive (or checkBeforeGet) operations. Default is empty
  9. checkBeforeGet - If true, executes the keepAliveSQL before any connection is returned from the pool. Default is true if the keepAliveSQL is defined
  10. keepAlivePeriod - Execute the keepAliveSQL on all unused connection every n minutes. Default is disabled
  11. killInactivePeriod - Kills excess unused connections every n minutes. Default is disabled
  12. retryCount - When the pool is maxed out, block and retry n times. Default is 1 retry
  13. retryPeriod - The period (in ms) over which the retry blocks. Default is 1000ms

For example to create a DataSource object at the JNDI location java:/comp/env/jdbc/connPool, use the following command line (or config file) options:

java -jar winstone.jar ...< other options > ... \
                        --useJNDI=true \
                        --jndi.resource.jdbc/connPool=javax.sql.DataSource \
                        --jndi.param.jdbc/connPool.url=jdbc:mysql://db.widgets.com/db \
                        --jndi.param.jdbc/connPool.driverClassName=com.mysql.jdbc.Driver \
                        --jndi.param.jdbc/connPool.username=foo \
                        --jndi.param.jdbc/connPool.password=bar

HTTPSの設定

Somebody asked me to add HTTPS support, using the JDK 1.4 SSL socket classes, and so I decided to give it a try. It was a lot easier than expected - the API was really nice to use. Unfortunately the hard work seems to be in the configuration, rather than the programming.

I recommend using a shareware tool called KeyStore Explorer, available here. It's much easier than all that messy CLI stuff.

The steps are basically as follows:

  1. Create an empty keystore of type JKS
  2. Generate a key pair (Tools -> Generate Key Pair). I chose RSA 2048 bit, and used "MD5 with RSA" for the algorithm. Set a password and remember it.
  3. Generate a CSR (right click, Generate CSR).
  4. Send the CSR to a Certifying Authority (CA) for processing. I used FreeSSL.com, because it was only US$39 per year.
  5. Once you get the approved certificate back, import it into the key store you were using (Tools -> import CA reply). You should now have only a key pair and a certificate. Save the key store, using the same password you used before.
  6. Start winstone with the following command:
    java -jar winstone.jar --webroot=<webroot>
                           --httpsPort=443 
                           --httpsKeyStore=<keystore file> 
                           --httpsKeyStorePassword=<password>
  7. Set your hosts file (/etc/hosts or c:/Winnt/system32/drivers/etc/hosts) to point the name on your certificate to 127.0.0.1), then try to browse to https://hostname/

Access Logging

From v0.8, there's an option to allow access logging. It's disabled by default, but can be enabled by defining a logging implementation class, with --accessLoggerClassName. The class defined must be an implementation of the interface winstone.AccessLogger, and is defined container wide, but instantiated once per webapp.

The supplied logger is called winstone.accesslog.SimpleAccessLogger. It supports Apache style combined/common format logs, as well as Resin format (which is actually just Apache common style plus a user agent). Configuration options are:

  • --simpleAccessLogger.format: Either "combined", "common", "resin" or a pattern made up of wildcards. For example, the combined format string is:
    ###ip### - ###user### ###time### "###uriLine###" ###status### ###size### "###referer###" "###userAgent###"
    but you can re-arrange this to be any pattern of the above wildcards with the --accessLoggerFormat switch. Defaults to "combined"
  • --simpleAccessLogger.file: A pattern for defining the files to log to. The default value is logs/###host###/###webapp###_access.log, which splits the log files for different webapps and hosts into directories. The wildcards ###host### and ###webapp### can be moved around or even omitted. Omitting the wildcard will mean the access logs will be combined into shared files (since the file name will be the same)

For example, to enable Apache Combined style logging to separate files, use a command line like:

java -jar winstone.jar --hostsDir=<vhostsDir>
                       --accessLoggerClassName=winstone.accesslog.SimpleAccessLogger

Or to log just the date and URI for all hosts/webapps to a single file, use a command line like:

java -jar winstone.jar --hostsDir=<vhostsDir>
                       --accessLoggerClassName=winstone.accesslog.SimpleAccessLogger
                       --simpleAccessLogger.format=###date###\ ###uriLine###
                       --simpleAccessLogger.file=/mylogs/access_log.txt

Embedding Winstone

The design of Winstone has always allowed its easy embedding within another application. It's as simple as:

 // at startup
Map args = new HashMap();
args.put("webroot", "<my webroot dir>"); // or any other command line args, eg port
Launcher.initLogger(args);
Launcher winstone = new Launcher(args); // spawns threads, so your application doesn't block

... (your application code)

// before shutdown
winstone.shutdown(); 

From v0.8 though, there is also the ability to embed in the opposite direction: that is, to embed your warfile into the winstone JAR itself. This allows an all-in-one container plus web-application JAR file to be downloaded, and then unpacked at execution time.

To use this, simply unpack the winstone JAR, and place your WAR file inside the unpacked folder at the top level (with the same parent as the folder named "winstone"). Then rename your WAR file to "embedded.war", and repack the jar as before (make sure to preserve the META-INF and manifest).

Now if you type: "java -jar winstone.jar", your application should automatically deploy as the ROOT web application. Try http://localhost:8080/ to check it out.

If you need to add any default command-line arguments (eg ports or prefixes), you can embed a properties file in exactly the same way, except that the file must be named "embedded.properties".


SourceForge.net Logo    Jars Registered Java.net Linked Project
jenkins-winstone-0.9.10-jenkins-47/contrib/sample_filters.zip0000644000175000017500000002356212200024521024640 0ustar jamespagejamespagePK H3winstone/filters/PK H3winstone/filters/gzip/PKq}3pW$7winstone/filters/gzip/ByteArrayServletOutputStream.javaToHトT]卿Eà嚔感x/k蹼!肖7k@.Rk! vg{3oiS|完JcVdV s,FZi]7Py*h Np幎c&;mJ禿TqDZ85D0*[♂* "iAa BdQG a"邂"勸 ^┯髑fkh)"He版!e*H2A"wo犯taKX準2@涯DXv+0i斬h|/>M 7堅睿f翌m‡6TcuJf=Zd銀j+話捩苻W站驍贅h叱怜Mf1g`y輜0]陸p:衍V摎-35 u! +y(~Teo%dL6ZpX坏 iY,x 6Ι 0/D厨mJB?@恚所?訓Uf#Xk\,yLy建[F柿&)mO*鍼岩]紊yaV$l<;Q=S[GHF膣響q,`dUc絶pR"PU*L[挫fLUT∇ x+h濬X轄V]h溯?闃(スP_?樸饐搆 }9.靜#x滬=苙?^w鎖t領劑蛯?#滂bx竇WW! Sa務{KYdp跪F礑~Znw鍜TT>pTxNA諢+{T{{0CF档嫂G竸文B-&[蓐1g啌%zZ2NI疏>SWO痺0I{wY{`PK|}-3"z^ %winstone/filters/gzip/GzipFilter.javaVmoH)a$Tu)$@@.払j1c髫v醴~~CHR 9}務3S;9>呼%B04_ P.C墅l+!)%盖箜@娉甃^!胛G$V!*Iq+决@_}Jz$6a-X\i'FX4 2,ks3(AB靦彌{後符: 棕F S?Q*."8F名 p uJ1F.4O<$I[栖Q獅aD偃熹鑁瑶畫毳Ih敕%f\|Id^iS事uC聾_桟汨#P:q=A?pm毯CQ*%鯛pJ9w!(SjG*"D*|IJxd_PD46M>DBWa%9C苺J5B7*|HiDC8Qb(力U*6;~h4N苺_p?r啌b耆 ISd域<$)gGGT$!5戻醍OFCsw3du!\^\[#?kWM#OL婦2膃匈J!Yr aAaN゙x2u/,`A 竸,婀4I刃I%旡v<烏|.O59YM;ky1.=4XV;/`鯛Q兆託Yz!SD$\`w5YZ延KF4掏tG夥#荊j鈍杤V[w WPq<虞UK禅k廚4\ 恰LRp3攻米7hcSuXkceem鎌P)FeB%a*飛Z>/X=Co] iVi"渇9siU_M@i.A^`Y六.籏 M許 l7茎!B{X(:Yvj^kp鉞堽MG蝙擧YYY.DT濂mO}潛懣 N纉~`Y!d捏CH veyviPh7HR8n熊|n竃/ RAR8y >PKH}-3U>.winstone/filters/gzip/GzipResponseWrapper.javaXo6?@消(0'ue'i74iA~Kvd00燮b#I搗|Q-Yr#卆wOmno.cZXァVN├Z8b3JZC 懦t^C_KfqvPHn#FLhAZqV!LT Gs2`Czb@Wp)莞黠nHA+j#U #~nB a@輪A):KX26Fr8;P%[(,{;QQY]oxq};醺=u醺顰m)N1$Mh9E >O.hOc鏖7b蟐7: 瑕]檎柬nnn7SDv,K腴>Ow(Z!#格=Qf盤(PLQNS>眇x跼@W>9X夢$qXU緞!8kA/y C4"DGx!:-eO]聯湎洸力-t]迯DbS牟dD3滾omomoIJ[,β捧8詣%堺廩MR;)Y陏蒜]>,n純u寔F殆>L<鯲;w恰E葡3Y]{y}憫=砕羸VΑwA崇=}4"梢悚N$qnow3髑w @V>o3P'QC観u BTH爨bhEcY$]e7J寥;<<}`X 8!Ce0ZH$Kl蹟fF*Qp+3VI`da~) G UZY*_{tv}甥kL 取pN葱縉c&ZS懴iw浙:偸蜷瑪畫瑰鱆瑣)僻 1u@J80V村D蓬\VOr>++TCn,YY臘Blfa坎 deRYl9Z=n艱[x1L梶N蹕\I4X>sM K禽"h`[j]k^9Z5Hhy网諄|I,wS~莪苒耗桍\E.9杙({Cv%l盖 }刊y1W8輌uV%}MX;*ZHr1jlF」9LDd8&E]|gYh鍍急YJM535.zS }^jqkW*MN6RX痙TDD ~O|ro樹1變D0-у\!愁>szF/RfQ蠹x!b^zD5ff^lU}腴L(4z16wvZ國S/L?PK H3winstone/filters/multipart/PKq}3|WJ6winstone/filters/multipart/MultipartRequestFilter.javaWmoH)aI$D%4 4払hc/x笊.~~ccNU4xgyvYS=:<#B}*Gt/_K&UZ,f神>_xTjo2  XP %M|aR 6[WFXlx ZiC散婪=雷mwXNwk亶 5豢FM #?hE堋D|mS*GcrLCa\艨K&KKgS6Gl顛駁I椰Nu|* 邸x^!匣f蓼Y扯b)=bS8LC*p優勳wMi^?~h Z=<B&9c罅鬚9yD那早V 瀏泝MM$慈j沸N墮酵r 齬p&E>sF(-8)xO桂/セKP粭*7?<El行~.l}_Z刈n%p0胱nS?IZU:jd=+W假ei‡9輿.Wii*=!?UU3[}弭煩l蠅TP7z~~C辯鶻s!~ }∇lHY:Is h`s2&tJ^[Qno?&zco{Xq~&}l蹂裏ZzNkxLi°_)BBV9彫gftM.章(J綟!>"e}7pyKgWNS弑%j蕕^J曾e虜eGNP=XtIK.|^dU3=o+J_\)嵌邪源垉r擱f e;)背GIW 3Pp!2Y,[R!N&Ih 1叨%j! gJm-韲D &m^;|zW")s厥3u {古WIU鬣寛1Mw採q2 Wu?H;X W7ErK(iBPpGro2 aXhR乕5麕J65wHG-!m棋R匐znr髟7掻采_{Y8RcnUw(}n6癜c.6.b~縹3 佝#f輒d,ZPKH3領,"=7winstone/filters/multipart/MultipartRequestWrapper.java[}o6@g :rnX朶C,Y5i8+オkl醢_$J"e7!批x卉G,'E*#,I G9]U峨:}hwrG貧iJ>貨ds果kM珮,gl&V4gd$)富4" H,M,4aNYN葬'L~髞ッr5 9+8K9t~a9<"8託|陸j-!_/r\T@仍)SId-9罷*NrH匝H&o72:}GホGw[3xn/I b $Na匁尨xタN'粫9角d|pztN.蕨\6S@y劫dhtb^普l^)[汚8$ジ$Yz-+QxFL *A9D巖/I擲Q8 >%bd,#;笄@畠 z2"d凩湎涙窩糅b$:oIO)e,N@x(/i.閙v*湮0梁WkFgq,,貸M!: s?蹐 ~套xEn!$#Iu-D署1F!ww?耘掛G舖SOK鬟vd<#+QQ *L#^K少91PA,2絵伐mm鉾 j尉'_ i$-癩/K@<頸{箙35uH6 VL含;FV k] *1.kd5yZW$3UfFp -T負k6mjQy!{zA?暾翩Fge%h#s("{_Rsl幗豕t[)Pf@bWovnEIYKZ\訪&p趺矯*) , xl儡JX"+&蔟]Uj,蘢- ;靹o27o[d轅L℃壻姶t_#Vc=簓O梛亀M'媛AVh寺嶐J^C'#vI"SHX+堺QPuYlF)&綯g橇1_f7|才aC iq鱈Vュ+?uXmkw癩_lKw膸疽B俑j恨w ユeC%h拑5'3S Dr*F@SAU?_4klv:jaJS=4\& #'薤yя-JE$+/飄 XQ2jPy0lBcb)ZT<<(xSi:蝓?Z命-}faZXI*6yC潴K_,\]W6+L ?` 蠑Mw?lV賀塗M;H鐸_E$/jTd{XA=9'&l[陟% k*闍)Dzp+ 1|p6nCivPhJC5 4r3gl/k+倡t$Acla1N'OQs(Rd寇r#O蹌W飭l8d6湯 羲頃;g=/&r'晝,wS2EK[|z+ y8湯敘/泥SLE{@硅敢!絢螟*F,b35n*咀'5鉋豚*欹bb+升|^0左\咆\z#H+%ar'+U-勘晩犹P?勤XT6 -g9>熬D.3qksJ\&#恟92ohW蕊=W;庵l兵;#斷]#CD'=XIm揮EriIG_$藉(jq 煌_GEdu鑽o Z帷$hB b%D \X[VT劈"A粮]Q>清4胱w/伐Ktvu@k鷦Xh[P伯Л艷)yV* 罩XW^Vt詁種Ι3W=J戲%M僉 & c1 N蒸*0.<腸萸6(>e ZQ[=猗Id]{=岩t?咏∫G祢洸_鯖蘯{/[穽Zgy~犁e 駸23O= yQ g神jJ?竟PK H3 winstone/PK H3winstone/filters/PK H3/winstone/filters/gzip/PKq}3pW$7 cwinstone/filters/gzip/ByteArrayServletOutputStream.javaPK|}-3"z^ % winstone/filters/gzip/GzipFilter.javaPKH}-3U>. }winstone/filters/gzip/GzipResponseWrapper.javaPK H3winstone/filters/multipart/PKq}3|WJ6 @winstone/filters/multipart/MultipartRequestFilter.javaPKH3領,"=7 winstone/filters/multipart/MultipartRequestWrapper.javaPK H3 U$winstone/PK |$jenkins-winstone-0.9.10-jenkins-47/contrib/JDBCRealm.java0000644000175000017500000001203612200024521023423 0ustar jamespagejamespage/* * Copyright 2006 Rui Damas * Distributed under the terms of either: * - the common development and distribution license (CDDL), v1.0; or * - the GNU Lesser General Public License, v2.1 or later */ package contrib.winstone; import java.sql.*; import java.util.*; import winstone.*; /** * A JDBC authentication realm to be used with Winstone Servelet container. *

* --JDBCRealm.url and --JDBCRealm.user are required. *

* * @author Rui Damas */ public class JDBCRealm implements AuthenticationRealm { // Command line arguments prefix public static String ARGS = "JDBCRealm."; // Command line arguments for connecting public static String ARGS_DRIVER = ARGS + "driver", ARGS_URL = ARGS + "url", ARGS_USER = ARGS + "user", ARGS_PASSWORD = ARGS + "password"; // Command line arguments to SQL identifiers public static String ARGS_USER_REL = ARGS + "userRel", ARGS_USER_NAME_COL = ARGS + "userNameCol", ARGS_USER_CRED_COL = ARGS + "userCredCol", ARGS_USER_ROLE_REL = ARGS + "userRoleRel", ARGS_ROLE_NAME_COL = ARGS + "roleNameCol"; // Defaults for SQL identifiers public static String DEFAULT_USER_REL = "web_users", DEFAULT_USER_NAME_COL = "username", DEFAULT_USER_CRED_COL ="credential", DEFAULT_USER_ROLE_REL = "web_user_roles", DEFAULT_ROLE_NAME_COL = "rolename"; private Connection connection; private final String url, user, password, retriveUserQuery, authenticationQueryPostfix, userRolesQuery; /** Creates a new instance of JDBCAuthenticationRealm.

If a "JDBCRealm.driver" exists in the args map an atempt to load the class will be made and a success message will be printed to System.out, or, if the class fails to load, an error message will be printed to System.err.

*/ public JDBCRealm(Set rolesAllowed, Map args) { // Get connection arguments String driver = args.get(ARGS_DRIVER), url = args.get(ARGS_URL), user = args.get(ARGS_USER), password = args.get(ARGS_PASSWORD); this.url = url; this.user = user; this.password = password; // Get SQL identifier arguments String userRel = args.get(ARGS_USER_REL), userNameCol = args.get(ARGS_USER_NAME_COL), userCredCol = args.get(ARGS_USER_CRED_COL), userRoleRel = args.get(ARGS_USER_ROLE_REL), roleNameCol = args.get(ARGS_ROLE_NAME_COL); // Get defaults if necessary if (userRel == null) userRel = DEFAULT_USER_REL; if (userNameCol == null) userNameCol = DEFAULT_USER_NAME_COL; if (userCredCol == null) userCredCol = DEFAULT_USER_CRED_COL; if (userRoleRel == null) userRoleRel = DEFAULT_USER_ROLE_REL; if (roleNameCol == null) roleNameCol = DEFAULT_ROLE_NAME_COL; retriveUserQuery = "SELECT 1\n" + " FROM \"" + userRel + "\"\n" + " WHERE \"" + userNameCol + "\" = ?"; // Prepare query prefixes authenticationQueryPostfix = "\n AND \"" + userCredCol + "\" = ?"; userRolesQuery = "SELECT \"" + roleNameCol + "\"\n" + " FROM \"" + userRoleRel + "\"\n" + " WHERE \"" + userNameCol + "\" = ?"; // If the driver was specified if (driver != null) try { // Try to load the driver Class.forName(driver); // and notify if loaded System.out.println("JDBCRealm loaded jdbc driver: " + driver);} catch (ClassNotFoundException cnfe) { // Notify if fails System.err.println( "JDBCRealm failed to load jdbc driver: "+ driver);} } public AuthenticationPrincipal getPrincipal (String userName, String password, boolean usePassword) { try { // Get a connection if ((connection == null) || connection.isClosed()) connection = DriverManager.getConnection(url, user, password); // Query for user String query = retriveUserQuery; if (usePassword) query = query + authenticationQueryPostfix; PreparedStatement ps = connection.prepareStatement(query); ps.setString(1, userName); if (usePassword) ps.setString(2, password); ResultSet resultSet = ps.executeQuery(); // If there is a user (row) if (resultSet.next()) { // Query for the user roles query = userRolesQuery; ps = connection.prepareStatement(query); ps.setString(1, userName); resultSet = ps.executeQuery(); // Load list List roles = new Vector(); while (resultSet.next()) roles.add(resultSet.getString(1)); return new AuthenticationPrincipal(userName, password, roles); } } catch (SQLException sqle) {sqle.printStackTrace();} return null; } /** * Authenticate the user - do we know them ? Return a distinct id once we * know them. * @return getPrincipal(userName, password, true); */ public AuthenticationPrincipal authenticateByUsernamePassword (String userName, String password) { return getPrincipal(userName, password, true); } /** * Retrieve an authenticated user * @return getPrincipal(userName, password, false); */ public AuthenticationPrincipal retrieveUser(String userName) { return getPrincipal(userName, null, false); } } jenkins-winstone-0.9.10-jenkins-47/TODO.txt0000644000175000017500000001601712200024521020746 0ustar jamespagejamespageList of other things to do: --------------------------- Long-term - Control port password ? Maybe not, or only if someone asks for it - Add more automated tests as part of release process: - url matching (evaluation of servletPath/pathInfo) - security / authentication - cluster resilience - More complete manual/documentation - Publish apidocs - Eclipse plug-in ? internal launcher plus browser window, and project level config for winstone properties - More accurate profiling of memory usage, object allocation etc - Auto-deployer for webappsDir folder. Redeploy warfiles that have been updated or added - Maven winstone plugin, so we can run maven winstone, and it will war-up and execute v0.9.5 DONE - Add session persistence across reboots (ie serialize to file) DONE - Add v2.5 spec support DONE - Heaps of include/forward and session related fixes (thanks to Martin Cordova and Robert Boyce) v0.8.1 DONE - License change to dual CDDL + LGPL DONE - appfuse bugfix. All listeners need a context class loader set. DONE - update outputstream to do include stacking internally, rather than returning new streams for each level DONE - fixed some nasty web.xml parsing bugs v0.8 DONE - Remove resource bundles as arguments. Declare statically in class DONE - DB connection pool keep-alive support, etc DONE - Cache filter matching calcs for various URLs DONE - Virtual host support DONE - Access log. Apache style if possible, minimal config. DONE - Fix for davenport and jakarta slide webdav applications DONE - Check for warfile, properties file inside classpath, so that we can pack an app in a single jar v0.7 DONE - Fixed load-on-startup optional content bug (thanks to Matthias Wuttke) DONE - Fixed the "error request loses attributes when forwarded" bug DONE - Upgraded to maven build process, ant is deprecated DONE - Reformatted source using eclipse source formatter DONE - Added better resolution of paths in static resource servlet, so that spaces etc in paths are handled properly DONE - Multiple webapp support DONE - Fix for JamVM JNDI properties bug (thanks Martin Cordova) DONE - SSL Key manager factory selector (thanks Martin Cordova) DONE - TCK compliance testing DONE - Added optional gzip and multipart upload filters DONE - Fixed session bugs in SSL (thanks Martin Cordova) v0.6.4 DONE - Added HTTPS listener class DONE - Fixed the path separator bug in the classpath under linux DONE - Changed default hostname lookups to off (more stable). v0.6.3 DONE - Fixed the errorPage directive bug DONE - Fixed bugs related to requestDispatcher and non-existants urls DONE - Fixed querystring parsing error when non-latin1 encoding v0.6.2 DONE - Move all debugging message lookups into logger (performance) DONE - Made invoker servlet on by default v0.6.1 DONE - Fix VariableInfo and BodyContent api errors for jsps DONE - Fix WinstoneDataSource lockup problem v0.6 DONE - Create winstone local jsp 2.0 api classes DONE - Update to v2.4 servlet api classes DONE - Refactor to winstone package, not com.rickknowles.winstone package DONE - Test with Apache Struts framework DONE - Added logfile directive DONE - Fixed request/response locale setting DONE - Fixed jsp include bugs DONE - Fixed http session bugs DONE - Added simple test application DONE - Java wrapper for control operations, such as shutdown or flush DONE - Additional control port options, such as manual webapp forced reload operation DONE - Added 206 Partial Content (ie restartable downloads) to static servlet DONE - Added interface specific binding for ajp13 and http listeners DONE - Add additional listener class calls for request + attributes DONE - Update to make winstone completely compliant with servlet 2.4 spec (non-compliance with 2.4 spec parts completed in v0.6) DONE - 1.6.1 Session Destroyed call timing is not called at correct time DONE - 2.3.2.1 Error handling in servlet.init() - UnavailableException DONE - 2.3.3.2 Error handling in servlet.service() - UnavailableException DONE - 2.3.4 Calling destroy incorrectly - wait for all threads to finish DONE - 3.5 Resource URLs DONE - 4.1.1 Parse conditions for POST parameters DONE - 4.4 Context Path / Servlet Path / Path Info values wrong DONE - 4.5 Path translation methods incorrect DONE - 4.7 Add SSL request attribute (javax.servlet.request.key_size) DONE - 4.9 Request Encoding DONE - 4.10 Implement request listeners DONE - 4.10 Implement request attribute listeners DONE - 5.1 Reset / Buffer management DONE - 5.2 X-Powered-By DONE - 5.3 Redirect URLs must be absolute DONE - 5.4 Locale mapping implementation DONE - 6.2.1 Filter init() error handling DONE - 6.2.4 Build filter chain in reverse order DONE - 6.2.5 Filter config for dispatcher DONE - 7.1.1 Session cookie name DONE - 7.4 Check order of session binding listeners DONE - 7.6 Session accessed time DONE - 7.7.2 Errors in distributed sessions DONE - 8.1 Return null request dispatcher when no url found DONE - 8.1 Request vs Context Dispatchers DONE - 8.1.1 Query string in request dispatchers DONE - 8.3 Request attributes for include dispatches DONE - 8.3.1 getNamedDispatcher DONE - 8.4.2 Forward request attributes DONE - 8.5 Errors in dispatch DONE - 9.5 404 for WEB-INF DONE - 9.6 404 for META-INF DONE - 9.7.1 Shared library classloader (common/lib) IGNR - 9.7.1 Manifest depend libraries DONE - 9.9.1 Error request attributes DONE - 9.9.2 Error page matching DONE - 9.9.3 Error filters DONE - 9.10 Welcome file match DONE - 9.12 Order of startup DONE - 10.3.2 Order of listener invokation DONE - 10.3.4 Session then context listeners DONE - 10.6 Listener exceptions DONE - 10.8 Can determine invalidate or timeout on session DONE - 11.1 Rule order for URL match DONE - 11.2 default mapping of / DONE - 11.2.1 *.jsp mapping is overrideable DONE - 12.2 Security on incoming only DONE - 12.3 Match security-role-ref in IsUserInRole IGNR - 12.7 run-as element in servlet DONE - 12.8.1 * = all roles DONE - 13.1 Locale-mapping element IGNR - 13.2 Canonical paths in web.xml v0.5 DONE - Implement session clustering between multiple Winstone instances DONE - Make the core distribution jar smaller, with optional components detached DONE - Add CLIENT-CERT authentication handler DONE - Add DIGEST authentication handler DONE - Add optional JNDI support for env-refs and jdbc datasource / mail session support v0.4 DONE - Implement errorPage directives in web.xml DONE - Add in request/response object pools to improve execution time DONE - Add command line arguments to control handler thread startup/max-idle/max DONE - Add servlet reloading to the WinstoneClassLoader DONE - Add authentication/security model - pluggable if possible, so Winstone can work in non-security mode DONE - Add xml-file-based realm support DONE - Add FORM based authentication v0.3 DONE - Modify the request handler thread to survive beyond a single request cycle DONE - Add auto WAR extract instead of webroot DONE - Change build process to use external ant DONE - Add listener handlers, etc DONE - Add filter handling code DONE - Refactor HttpConnector links, and build an ajp13 connector jenkins-winstone-0.9.10-jenkins-47/.hgignore0000644000175000017500000000005612200024521021237 0ustar jamespagejamespagetarget winstone.iml winstone.ipr winstone.iws jenkins-winstone-0.9.10-jenkins-47/.settings/0000755000175000017500000000000012200024521021351 5ustar jamespagejamespagejenkins-winstone-0.9.10-jenkins-47/.settings/org.eclipse.core.resources.prefs0000644000175000017500000000015312200024521027563 0ustar jamespagejamespage#Mon Aug 02 09:44:31 JST 2004 eclipse.preferences.version=1 encoding//development/README_jp.html=EUC-JP jenkins-winstone-0.9.10-jenkins-47/.settings/org.eclipse.jdt.core.prefs0000644000175000017500000000115312200024521026333 0ustar jamespagejamespage#Mon Aug 07 01:25:27 JST 2006 eclipse.preferences.version=1 org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.1 org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve org.eclipse.jdt.core.compiler.compliance=1.3 org.eclipse.jdt.core.compiler.debug.lineNumber=generate org.eclipse.jdt.core.compiler.debug.localVariable=generate org.eclipse.jdt.core.compiler.debug.sourceFile=generate org.eclipse.jdt.core.compiler.problem.assertIdentifier=ignore org.eclipse.jdt.core.compiler.problem.enumIdentifier=ignore org.eclipse.jdt.core.compiler.source=1.3 jenkins-winstone-0.9.10-jenkins-47/.project0000644000175000017500000000055712200024521021111 0ustar jamespagejamespage winstone org.eclipse.jdt.core.javabuilder org.eclipse.jdt.core.javanature jenkins-winstone-0.9.10-jenkins-47/LICENSE-CDDL.txt0000644000175000017500000004730212200024521021770 0ustar jamespagejamespage COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0 1. Definitions. 1.1. 'Contributor' means each individual or entity that creates or contributes to the creation of Modifications. 1.2. 'Contributor Version' means the combination of the Original Software, prior Modifications used by a Contributor (if any), and the Modifications made by that particular Contributor. 1.3. 'Covered Software' means (a) the Original Software, or (b) Modifications, or (c) the combination of files containing Original Software with files containing Modifications, in each case including portions thereof. 1.4. 'Executable' means the Covered Software in any form other than Source Code. 1.5. 'Initial Developer' means the individual or entity that first makes Original Software available under this License. 1.6. 'Larger Work' means a work which combines Covered Software or portions thereof with code not governed by the terms of this License. 1.7. 'License' means this document. 1.8. 'Licensable' means having the right to grant, to the maximum extent possible, whether at the time of the initial grant or subsequently acquired, any and all of the rights conveyed herein. 1.9. 'Modifications' means the Source Code and Executable form of any of the following: A. Any file that results from an addition to, deletion from or modification of the contents of a file containing Original Software or previous Modifications; B. Any new file that contains any part of the Original Software or previous Modification; or C. Any new file that is contributed or otherwise made available under the terms of this License. 1.10. 'Original Software' means the Source Code and Executable form of computer software code that is originally released under this License. 1.11. 'Patent Claims' means any patent claim(s), now owned or hereafter acquired, including without limitation, method, process, and apparatus claims, in any patent Licensable by grantor. 1.12. 'Source Code' means (a) the common form of computer software code in which modifications are made and (b) associated documentation included in or with such code. 1.13. 'You' (or 'Your') means an individual or a legal entity exercising rights under, and complying with all of the terms of, this License. For legal entities, 'You' includes any entity which controls, is controlled by, or is under common control with You. For purposes of this definition, 'control' means (a) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (b) ownership of more than fifty percent (50%) of the outstanding shares or beneficial ownership of such entity. 2. License Grants. 2.1. The Initial Developer Grant. Conditioned upon Your compliance with Section 3.1 below and subject to third party intellectual property claims, the Initial Developer hereby grants You a world-wide, royalty-free, non-exclusive license: (a) under intellectual property rights (other than patent or trademark) Licensable by Initial Developer, to use, reproduce, modify, display, perform, sublicense and distribute the Original Software (or portions thereof), with or without Modifications, and/or as part of a Larger Work; and (b) under Patent Claims infringed by the making, using or selling of Original Software, to make, have made, use, practice, sell, and offer for sale, and/or otherwise dispose of the Original Software (or portions thereof). (c) The licenses granted in Sections 2.1(a) and (b) are effective on the date Initial Developer first distributes or otherwise makes the Original Software available to a third party under the terms of this License. (d) Notwithstanding Section 2.1(b) above, no patent license is granted: (1) for code that You delete from the Original Software, or (2) for infringements caused by: (i) the modification of the Original Software, or (ii) the combination of the Original Software with other software or devices. 2.2. Contributor Grant. Conditioned upon Your compliance with Section 3.1 below and subject to third party intellectual property claims, each Contributor hereby grants You a world-wide, royalty-free, non-exclusive license: (a) under intellectual property rights (other than patent or trademark) Licensable by Contributor to use, reproduce, modify, display, perform, sublicense and distribute the Modifications created by such Contributor (or portions thereof), either on an unmodified basis, with other Modifications, as Covered Software and/or as part of a Larger Work; and (b) under Patent Claims infringed by the making, using, or selling of Modifications made by that Contributor either alone and/or in combination with its Contributor Version (or portions of such combination), to make, use, sell, offer for sale, have made, and/or otherwise dispose of: (1) Modifications made by that Contributor (or portions thereof); and (2) the combination of Modifications made by that Contributor with its Contributor Version (or portions of such combination). (c) The licenses granted in Sections 2.2(a) and 2.2(b) are effective on the date Contributor first distributes or otherwise makes the Modifications available to a third party. (d) Notwithstanding Section 2.2(b) above, no patent license is granted: (1) for any code that Contributor has deleted from the Contributor Version; (2) for infringements caused by: (i) third party modifications of Contributor Version, or (ii) the combination of Modifications made by that Contributor with other software (except as part of the Contributor Version) or other devices; or (3) under Patent Claims infringed by Covered Software in the absence of Modifications made by that Contributor. 3. Distribution Obligations. 3.1. Availability of Source Code. Any Covered Software that You distribute or otherwise make available in Executable form must also be made available in Source Code form and that Source Code form must be distributed only under the terms of this License. You must include a copy of this License with every copy of the Source Code form of the Covered Software You distribute or otherwise make available. You must inform recipients of any such Covered Software in Executable form as to how they can obtain such Covered Software in Source Code form in a reasonable manner on or through a medium customarily used for software exchange. 3.2. Modifications. The Modifications that You create or to which You contribute are governed by the terms of this License. You represent that You believe Your Modifications are Your original creation(s) and/or You have sufficient rights to grant the rights conveyed by this License. 3.3. Required Notices. You must include a notice in each of Your Modifications that identifies You as the Contributor of the Modification. You may not remove or alter any copyright, patent or trademark notices contained within the Covered Software, or any notices of licensing or any descriptive text giving attribution to any Contributor or the Initial Developer. 3.4. Application of Additional Terms. You may not offer or impose any terms on any Covered Software in Source Code form that alters or restricts the applicable version of this License or the recipients rights hereunder. You may choose to offer, and to charge a fee for, warranty, support, indemnity or liability obligations to one or more recipients of Covered Software. However, you may do so only on Your own behalf, and not on behalf of the Initial Developer or any Contributor. You must make it absolutely clear that any such warranty, support, indemnity or liability obligation is offered by You alone, and You hereby agree to indemnify the Initial Developer and every Contributor for any liability incurred by the Initial Developer or such Contributor as a result of warranty, support, indemnity or liability terms You offer. 3.5. Distribution of Executable Versions. You may distribute the Executable form of the Covered Software under the terms of this License or under the terms of a license of Your choice, which may contain terms different from this License, provided that You are in compliance with the terms of this License and that the license for the Executable form does not attempt to limit or alter the recipients rights in the Source Code form from the rights set forth in this License. If You distribute the Covered Software in Executable form under a different license, You must make it absolutely clear that any terms which differ from this License are offered by You alone, not by the Initial Developer or Contributor. You hereby agree to indemnify the Initial Developer and every Contributor for any liability incurred by the Initial Developer or such Contributor as a result of any such terms You offer. 3.6. Larger Works. You may create a Larger Work by combining Covered Software with other code not governed by the terms of this License and distribute the Larger Work as a single product. In such a case, You must make sure the requirements of this License are fulfilled for the Covered Software. 4. Versions of the License. 4.1. New Versions. Sun Microsystems, Inc. is the initial license steward and may publish revised and/or new versions of this License from time to time. Each version will be given a distinguishing version number. Except as provided in Section 4.3, no one other than the license steward has the right to modify this License. 4.2. Effect of New Versions. You may always continue to use, distribute or otherwise make the Covered Software available under the terms of the version of the License under which You originally received the Covered Software. If the Initial Developer includes a notice in the Original Software prohibiting it from being distributed or otherwise made available under any subsequent version of the License, You must distribute and make the Covered Software available under the terms of the version of the License under which You originally received the Covered Software. Otherwise, You may also choose to use, distribute or otherwise make the Covered Software available under the terms of any subsequent version of the License published by the license steward. 4.3. Modified Versions. When You are an Initial Developer and You want to create a new license for Your Original Software, You may create and use a modified version of this License if You: (a) rename the license and remove any references to the name of the license steward (except to note that the license differs from this License); and (b) otherwise make it clear that the license contains terms which differ from this License. 5. DISCLAIMER OF WARRANTY. COVERED SOFTWARE IS PROVIDED UNDER THIS LICENSE ON AN 'AS IS' BASIS, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES THAT THE COVERED SOFTWARE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED SOFTWARE IS WITH YOU. SHOULD ANY COVERED SOFTWARE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE. NO USE OF ANY COVERED SOFTWARE IS AUTHORIZED HEREUNDER EXCEPT UNDER THIS DISCLAIMER. 6. TERMINATION. 6.1. This License and the rights granted hereunder will terminate automatically if You fail to comply with terms herein and fail to cure such breach within 30 days of becoming aware of the breach. Provisions which, by their nature, must remain in effect beyond the termination of this License shall survive. 6.2. If You assert a patent infringement claim (excluding declaratory judgment actions) against Initial Developer or a Contributor (the Initial Developer or Contributor against whom You assert such claim is referred to as 'Participant') alleging that the Participant Software (meaning the Contributor Version where the Participant is a Contributor or the Original Software where the Participant is the Initial Developer) directly or indirectly infringes any patent, then any and all rights granted directly or indirectly to You by such Participant, the Initial Developer (if the Initial Developer is not the Participant) and all Contributors under Sections 2.1 and/or 2.2 of this License shall, upon 60 days notice from Participant terminate prospectively and automatically at the expiration of such 60 day notice period, unless if within such 60 day period You withdraw Your claim with respect to the Participant Software against such Participant either unilaterally or pursuant to a written agreement with Participant. 6.3. In the event of termination under Sections 6.1 or 6.2 above, all end user licenses that have been validly granted by You or any distributor hereunder prior to termination (excluding licenses granted to You by any distributor) shall survive termination. 7. LIMITATION OF LIABILITY. UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY, WHETHER TORT (INCLUDING NEGLIGENCE), CONTRACT, OR OTHERWISE, SHALL YOU, THE INITIAL DEVELOPER, ANY OTHER CONTRIBUTOR, OR ANY DISTRIBUTOR OF COVERED SOFTWARE, OR ANY SUPPLIER OF ANY OF SUCH PARTIES, BE LIABLE TO ANY PERSON FOR ANY INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES OF ANY CHARACTER INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOST PROFITS, LOSS OF GOODWILL, WORK STOPPAGE, COMPUTER FAILURE OR MALFUNCTION, OR ANY AND ALL OTHER COMMERCIAL DAMAGES OR LOSSES, EVEN IF SUCH PARTY SHALL HAVE BEEN INFORMED OF THE POSSIBILITY OF SUCH DAMAGES. THIS LIMITATION OF LIABILITY SHALL NOT APPLY TO LIABILITY FOR DEATH OR PERSONAL INJURY RESULTING FROM SUCH PARTYS NEGLIGENCE TO THE EXTENT APPLICABLE LAW PROHIBITS SUCH LIMITATION. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OR LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO THIS EXCLUSION AND LIMITATION MAY NOT APPLY TO YOU. 8. U.S. GOVERNMENT END USERS. The Covered Software is a 'commercial item,' as that term is defined in 48 C.F.R. 2.101 (Oct. 1995), consisting of 'commercial computer software' (as that term is defined at 48 C.F.R. 252.227-7014(a)(1)) and 'commercial computer software documentation' as such terms are used in 48 C.F.R. 12.212 (Sept. 1995). Consistent with 48 C.F.R. 12.212 and 48 C.F.R. 227.7202-1 through 227.7202-4 (June 1995), all U.S. Government End Users acquire Covered Software with only those rights set forth herein. This U.S. Government Rights clause is in lieu of, and supersedes, any other FAR, DFAR, or other clause or provision that addresses Government rights in computer software under this License. 9. MISCELLANEOUS. This License represents the complete agreement concerning subject matter hereof. If any provision of this License is held to be unenforceable, such provision shall be reformed only to the extent necessary to make it enforceable. This License shall be governed by the law of the jurisdiction specified in a notice contained within the Original Software (except to the extent applicable law, if any, provides otherwise), excluding such jurisdictions conflict-of-law provisions. Any litigation relating to this License shall be subject to the jurisdiction of the courts located in the jurisdiction and venue specified in a notice contained within the Original Software, with the losing party responsible for costs, including, without limitation, court costs and reasonable attorneys fees and expenses. The application of the United Nations Convention on Contracts for the International Sale of Goods is expressly excluded. Any law or regulation which provides that the language of a contract shall be construed against the drafter shall not apply to this License. You agree that You alone are responsible for compliance with the United States export administration regulations (and the export control laws and regulation of any other countries) when You use, distribute or otherwise make available any Covered Software. 10. RESPONSIBILITY FOR CLAIMS. As between Initial Developer and the Contributors, each party is responsible for claims and damages arising, directly or indirectly, out of its utilization of rights under this License and You agree to work with Initial Developer and Contributors to distribute such responsibility on an equitable basis. Nothing herein is intended or shall be deemed to constitute any admission of liability. jenkins-winstone-0.9.10-jenkins-47/Makefile0000644000175000017500000002347212200024521021103 0ustar jamespagejamespage ######################################################################################## # Makefile for GCJ compilation of Winstone Servlet Container to native binary # # Currently works under linux only - mingw compilation unsupported # # Author: Rick Knowles # ######################################################################################## CC = gcj CFLAGS = -ffast-math -funroll-loops WINSTONE_JAVA_BASE = ./winstone/src/java WINSTONE_RES_BASE = ./winstone/src/conf CRIMSON_BASE = ./crimson-src WINSTONE_LITE_O = winstone_lite.o winstone_res1.o WINSTONE_AJP_O = winstone_ajp.o winstone_ajp_res1.o WINSTONE_AUTH_O = winstone_auth.o winstone_realm.o winstone_auth_res1.o winstone_realm_res1.o WINSTONE_CLUSTER_O = winstone_cluster.o winstone_cluster_res1.o WINSTONE_CLASSLOADER_O = winstone_classloader.o winstone_classloader_res1.o WINSTONE_JNDI_O = winstone_jndi.o winstone_jndi_res1.o winstone_jndi_res2.o WINSTONE_SSL_O = winstone_ssl.o winstone_ssl_res1.o WINSTONE_INVOKER_O = winstone_invoker.o winstone_invoker_res1.o SERVLET_O = servlet.o servlet_res1.o servlet_res2.o CRIMSON_O = crimson.o crimson_res1.o crimson_res2.o javax_xml.o xml_api.o JSP_API_O = jsp_api.o jsp_api_res1.o jsp_api_res2.o jsp_api_res3.o jsp_api_res4.o jsp_api_res5.o jsp_api_res6.o all: $(WINSTONE_LITE_O) $(WINSTONE_AJP_O) $(WINSTONE_AUTH_O) $(WINSTONE_CLUSTER_O) $(WINSTONE_JNDI_O) $(WINSTONE_CLASSLOADER_O) $(WINSTONE_SSL_O) $(WINSTONE_INVOKER_O) $(SERVLET_O) $(CRIMSON_O) $(JSP_API_O) $(CC) $(CFLAGS) --main=winstone.Launcher -o winstone_lite $(WINSTONE_LITE_O) $(SERVLET_O) $(CRIMSON_O) $(CC) $(CFLAGS) --main=winstone.Launcher -o winstone_full $(WINSTONE_LITE_O) $(SERVLET_O) $(CRIMSON_O) $(WINSTONE_AUTH_O) $(WINSTONE_AJP_O) $(WINSTONE_CLUSTER_O) $(WINSTONE_JNDI_O) $(WINSTONE_CLASSLOADER_O) $(WINSTONE_SSL_O) $(WINSTONE_INVOKER_O) $(JSP_API_O) winstone_lite.o: $(WINSTONE_JAVA_BASE)/winstone/*.java $(CC) $(CFLAGS) -o winstone_lite.o --classpath=$(WINSTONE_JAVA_BASE):$(CRIMSON_BASE) -c $(WINSTONE_JAVA_BASE)/winstone/*.java winstone_res1.o: $(WINSTONE_JAVA_BASE)/winstone/LocalStrings.properties $(CC) $(CFLAGS) -o winstone_res1.o --resource=winstone/LocalStrings.properties -c $(WINSTONE_JAVA_BASE)/winstone/LocalStrings.properties winstone_ajp.o: $(WINSTONE_JAVA_BASE)/winstone/ajp13/*.java $(CC) $(CFLAGS) -o winstone_ajp.o --classpath=$(WINSTONE_JAVA_BASE):$(CRIMSON_BASE) -c $(WINSTONE_JAVA_BASE)/winstone/ajp13/*.java winstone_ajp_res1.o: $(WINSTONE_JAVA_BASE)/winstone/ajp13/LocalStrings.properties $(CC) $(CFLAGS) -o winstone_ajp_res1.o --resource=winstone/ajp13/LocalStrings.properties -c $(WINSTONE_JAVA_BASE)/winstone/ajp13/LocalStrings.properties winstone_auth.o: $(WINSTONE_JAVA_BASE)/winstone/auth/*.java $(CC) $(CFLAGS) -o winstone_auth.o --classpath=$(WINSTONE_JAVA_BASE):$(CRIMSON_BASE) -c $(WINSTONE_JAVA_BASE)/winstone/auth/*.java winstone_auth_res1.o: $(WINSTONE_JAVA_BASE)/winstone/auth/LocalStrings.properties $(CC) $(CFLAGS) -o winstone_auth_res1.o --resource=winstone/auth/LocalStrings.properties -c $(WINSTONE_JAVA_BASE)/winstone/auth/LocalStrings.properties winstone_realm.o: $(WINSTONE_JAVA_BASE)/winstone/realm/*.java $(CC) $(CFLAGS) -o winstone_realm.o --classpath=$(WINSTONE_JAVA_BASE):$(CRIMSON_BASE) -c $(WINSTONE_JAVA_BASE)/winstone/realm/*.java winstone_realm_res1.o: $(WINSTONE_JAVA_BASE)/winstone/realm/LocalStrings.properties $(CC) $(CFLAGS) -o winstone_realm_res1.o --resource=winstone/realm/LocalStrings.properties -c $(WINSTONE_JAVA_BASE)/winstone/realm/LocalStrings.properties winstone_cluster.o: $(WINSTONE_JAVA_BASE)/winstone/cluster/*.java $(CC) $(CFLAGS) -o winstone_cluster.o --classpath=$(WINSTONE_JAVA_BASE):$(CRIMSON_BASE) -c $(WINSTONE_JAVA_BASE)/winstone/cluster/*.java winstone_cluster_res1.o: $(WINSTONE_JAVA_BASE)/winstone/cluster/LocalStrings.properties $(CC) $(CFLAGS) -o winstone_cluster_res1.o --resource=winstone/cluster/LocalStrings.properties -c $(WINSTONE_JAVA_BASE)/winstone/cluster/LocalStrings.properties winstone_classloader.o: $(WINSTONE_JAVA_BASE)/winstone/classLoader/*.java $(CC) $(CFLAGS) -o winstone_classloader.o --classpath=$(WINSTONE_JAVA_BASE):$(CRIMSON_BASE) -c $(WINSTONE_JAVA_BASE)/winstone/classLoader/*.java winstone_classloader_res1.o: $(WINSTONE_JAVA_BASE)/winstone/classLoader/LocalStrings.properties $(CC) $(CFLAGS) -o winstone_classloader_res1.o --resource=winstone/classLoader/LocalStrings.properties -c $(WINSTONE_JAVA_BASE)/winstone/classLoader/LocalStrings.properties winstone_ssl.o: $(WINSTONE_JAVA_BASE)/winstone/ssl/*.java $(CC) $(CFLAGS) -o winstone_ssl.o --classpath=$(WINSTONE_JAVA_BASE):$(CRIMSON_BASE) -c $(WINSTONE_JAVA_BASE)/winstone/ssl/*.java winstone_ssl_res1.o: $(WINSTONE_JAVA_BASE)/winstone/ssl/LocalStrings.properties $(CC) $(CFLAGS) -o winstone_ssl_res1.o --resource=winstone/ssl/LocalStrings.properties -c $(WINSTONE_JAVA_BASE)/winstone/ssl/LocalStrings.properties winstone_invoker.o: $(WINSTONE_JAVA_BASE)/winstone/invoker/*.java $(CC) $(CFLAGS) -o winstone_invoker.o --classpath=$(WINSTONE_JAVA_BASE):$(CRIMSON_BASE) -c $(WINSTONE_JAVA_BASE)/winstone/invoker/*.java winstone_invoker_res1.o: $(WINSTONE_JAVA_BASE)/winstone/invoker/LocalStrings.properties $(CC) $(CFLAGS) -o winstone_invoker_res1.o --resource=winstone/invoker/LocalStrings.properties -c $(WINSTONE_JAVA_BASE)/winstone/invoker/LocalStrings.properties winstone_jndi.o: $(WINSTONE_JAVA_BASE)/winstone/jndi/*.java \ $(WINSTONE_JAVA_BASE)/winstone/jndi/java/*.java \ $(WINSTONE_JAVA_BASE)/winstone/jndi/resourceFactories/*.java $(CC) $(CFLAGS) -o winstone_jndi.o --classpath=$(WINSTONE_JAVA_BASE):$(CRIMSON_BASE) -c \ $(WINSTONE_JAVA_BASE)/winstone/jndi/*.java \ $(WINSTONE_JAVA_BASE)/winstone/jndi/java/*.java \ $(WINSTONE_JAVA_BASE)/winstone/jndi/resourceFactories/*.java winstone_jndi_res1.o: $(WINSTONE_JAVA_BASE)/winstone/jndi/LocalStrings.properties $(CC) $(CFLAGS) -o winstone_jndi_res1.o --resource=winstone/jndi/LocalStrings.properties -c $(WINSTONE_JAVA_BASE)/winstone/jndi/LocalStrings.properties winstone_jndi_res2.o: $(WINSTONE_RES_BASE)/jndi.properties $(CC) $(CFLAGS) -o winstone_jndi_res2.o --resource=jndi.properties -c $(WINSTONE_RES_BASE)/jndi.properties servlet.o: $(WINSTONE_JAVA_BASE)/javax/servlet/*.java $(WINSTONE_JAVA_BASE)/javax/servlet/http/*.java $(CC) $(CFLAGS) -o servlet.o --classpath=$(WINSTONE_JAVA_BASE) -c $(WINSTONE_JAVA_BASE)/javax/servlet/*.java $(WINSTONE_JAVA_BASE)/javax/servlet/http/*.java servlet_res1.o: $(WINSTONE_RES_BASE)/javax/servlet/resources/web-app_2_2.dtd $(CC) $(CFLAGS) -o servlet_res1.o --resource=javax/servlet/resources/web-app_2_2.dtd -c $(WINSTONE_RES_BASE)/javax/servlet/resources/web-app_2_2.dtd servlet_res2.o: $(WINSTONE_RES_BASE)/javax/servlet/resources/web-app_2_3.dtd $(CC) $(CFLAGS) -o servlet_res2.o --resource=javax/servlet/resources/web-app_2_3.dtd -c $(WINSTONE_RES_BASE)/javax/servlet/resources/web-app_2_3.dtd # Add JSP API classes here jsp_api.o: $(WINSTONE_JAVA_BASE)/javax/servlet/jsp/*.java $(WINSTONE_JAVA_BASE)/javax/servlet/jsp/tagext/*.java $(WINSTONE_JAVA_BASE)/javax/servlet/jsp/el/*.java $(CC) $(CFLAGS) -o jsp_api.o --classpath=$(WINSTONE_JAVA_BASE) -c $(WINSTONE_JAVA_BASE)/javax/servlet/jsp/*.java $(WINSTONE_JAVA_BASE)/javax/servlet/jsp/tagext/*.java $(WINSTONE_JAVA_BASE)/javax/servlet/jsp/el/*.java jsp_api_res1.o: $(WINSTONE_RES_BASE)/javax/servlet/jsp/resources/jsp_2_0.xsd $(CC) $(CFLAGS) -o jsp_api_res1.o --resource=javax/servlet/jsp/resources/jsp_2_0.xsd -c $(WINSTONE_RES_BASE)/javax/servlet/jsp/resources/jsp_2_0.xsd jsp_api_res2.o: $(WINSTONE_RES_BASE)/javax/servlet/jsp/resources/jspxml.dtd $(CC) $(CFLAGS) -o jsp_api_res2.o --resource=javax/servlet/jsp/resources/jspxml.dtd -c $(WINSTONE_RES_BASE)/javax/servlet/jsp/resources/jspxml.dtd jsp_api_res3.o: $(WINSTONE_RES_BASE)/javax/servlet/jsp/resources/jspxml.xsd $(CC) $(CFLAGS) -o jsp_api_res3.o --resource=javax/servlet/jsp/resources/jspxml.xsd -c $(WINSTONE_RES_BASE)/javax/servlet/jsp/resources/jspxml.xsd jsp_api_res4.o: $(WINSTONE_RES_BASE)/javax/servlet/jsp/resources/web-jsptaglibrary_1_1.dtd $(CC) $(CFLAGS) -o jsp_api_res4.o --resource=javax/servlet/jsp/resources/web-jsptaglibrary_1_1.dtd -c $(WINSTONE_RES_BASE)/javax/servlet/jsp/resources/web-jsptaglibrary_1_1.dtd jsp_api_res5.o: $(WINSTONE_RES_BASE)/javax/servlet/jsp/resources/web-jsptaglibrary_1_2.dtd $(CC) $(CFLAGS) -o jsp_api_res5.o --resource=javax/servlet/jsp/resources/web-jsptaglibrary_1_2.dtd -c $(WINSTONE_RES_BASE)/javax/servlet/jsp/resources/web-jsptaglibrary_1_2.dtd jsp_api_res6.o: $(WINSTONE_RES_BASE)/javax/servlet/jsp/resources/web-jsptaglibrary_2_0.xsd $(CC) $(CFLAGS) -o jsp_api_res6.o --resource=javax/servlet/jsp/resources/web-jsptaglibrary_2_0.xsd -c $(WINSTONE_RES_BASE)/javax/servlet/jsp/resources/web-jsptaglibrary_2_0.xsd javax_xml.o: $(CRIMSON_BASE)/javax/xml/*/*.java $(CC) $(CFLAGS) -o javax_xml.o -c $(CRIMSON_BASE)/javax/xml/*/*.java xml_api.o: $(CRIMSON_BASE)/org/w3c/dom/*.java $(CRIMSON_BASE)/org/xml/sax/*.java $(CRIMSON_BASE)/org/xml/sax/ext/*.java $(CRIMSON_BASE)/org/xml/sax/helpers/*.java $(CC) $(CFLAGS) -o xml_api.o -c $(CRIMSON_BASE)/org/w3c/dom/*.java $(CRIMSON_BASE)/org/xml/sax/*.java $(CRIMSON_BASE)/org/xml/sax/ext/*.java $(CRIMSON_BASE)/org/xml/sax/helpers/*.java crimson.o: $(CRIMSON_BASE)/org/apache/crimson/*/*.java $(CC) $(CFLAGS) -o crimson.o --classpath=$(CRIMSON_BASE) -c $(CRIMSON_BASE)/org/apache/crimson/*/*.java crimson_res1.o: $(CRIMSON_BASE)/org/apache/crimson/parser/resources/Messages.properties $(CC) $(CFLAGS) -o crimson_res1.o --resource=org/apache/crimson/parser/resources/Messages.properties -c $(CRIMSON_BASE)/org/apache/crimson/parser/resources/Messages.properties crimson_res2.o: $(CRIMSON_BASE)/org/apache/crimson/tree/resources/Messages.properties $(CC) $(CFLAGS) -o crimson_res2.o --resource=org/apache/crimson/tree/resources/Messages.properties -c $(CRIMSON_BASE)/org/apache/crimson/tree/resources/Messages.properties clean: rm -f *.o jenkins-winstone-0.9.10-jenkins-47/maven.xml0000644000175000017500000001013612200024521021264 0ustar jamespagejamespage jenkins-winstone-0.9.10-jenkins-47/project.xml0000644000175000017500000000431512200024521021626 0ustar jamespagejamespage 3 winstone Winstone Servlet Container 0.9.10 2003 winstone Rick Knowles rickk rick@knowleses.org junit 3.8.1 httpunit 1.6 nekohtml 0.9.4 rhino js 1.6R1 xml-apis 1.0.b2 src/java src/test **/*Test.java **/*NaughtyTest.java winstone/testCase/load/LoadTest.java src/conf true **/*.* src/java **/*.properties jenkins-winstone-0.9.10-jenkins-47/src/0000755000175000017500000000000012200024521020222 5ustar jamespagejamespagejenkins-winstone-0.9.10-jenkins-47/src/conf/0000755000175000017500000000000012200024521021147 5ustar jamespagejamespagejenkins-winstone-0.9.10-jenkins-47/src/conf/jndi.properties0000644000175000017500000000015712200024521024214 0ustar jamespagejamespagejava.naming.factory.initial=winstone.jndi.java.javaURLContextFactory java.naming.factory.url.pkgs=winstone.jndijenkins-winstone-0.9.10-jenkins-47/src/testwebapp/0000755000175000017500000000000012200024521022400 5ustar jamespagejamespagejenkins-winstone-0.9.10-jenkins-47/src/testwebapp/WEB-INF/0000755000175000017500000000000012200024521023427 5ustar jamespagejamespagejenkins-winstone-0.9.10-jenkins-47/src/testwebapp/WEB-INF/web.xml0000644000175000017500000000675612200024521024744 0ustar jamespagejamespage WinstoneTestWebApp Designed as an example web application for winstone, and also as a resource for the automated tests ContextParam An example context parameter TimingFilter winstone.testApplication.filters.TimingFilter dumpRequestParameters true WriteAfterServletFilter winstone.testApplication.filters.WriteAfterServletFilter WriteAfterServletFilter /TestWriteAfterServlet winstone.testApplication.listeners.SessionListener CountRequestsServlet winstone.testApplication.servlets.CountRequestsServlet offset 1000 1 UnavailableAtInitServlet winstone.testApplication.servlets.UnavailableServlet errorTime init UnavailableAtGetServlet winstone.testApplication.servlets.UnavailableServlet errorTime get loadOnStartupJSP /loadOnStartup.jsp hiddenJSP /WEB-INF/hidden.jsp CountRequestsServlet /CountRequestsServlet loadOnStartupJSP /loadOnStartup.jsp hiddenJSP /hidden.jsp UnavailableAtInitServlet /UnavailableAtInitServlet UnavailableAtGetServlet /UnavailableAtGetServlet CountRequestsServlet /TestWriteAfterServlet welcome.html index.html jenkins-winstone-0.9.10-jenkins-47/src/java/0000755000175000017500000000000012200024521021143 5ustar jamespagejamespagejenkins-winstone-0.9.10-jenkins-47/src/java/winstone/0000755000175000017500000000000012200024521023011 5ustar jamespagejamespagejenkins-winstone-0.9.10-jenkins-47/src/java/winstone/AuthenticationRealm.java0000644000175000017500000000172412200024521027620 0ustar jamespagejamespage/* * Copyright 2003-2006 Rick Knowles * Distributed under the terms of either: * - the common development and distribution license (CDDL), v1.0; or * - the GNU Lesser General Public License, v2.1 or later */ package winstone; /** * Interface for authentication realms. * * @author Rick Knowles * @version $Id: AuthenticationRealm.java,v 1.3 2006/12/09 03:56:41 rickknowles Exp $ */ public interface AuthenticationRealm { /** * Authenticate the user - do we know them ? Return a distinct id once we * know them. Used by the BASIC and FORM authentication methods. */ public AuthenticationPrincipal authenticateByUsernamePassword( String userName, String password); /** * Retrieve an authenticated user. Used by the DIGEST and CLIENTCERT authentication methods. */ public AuthenticationPrincipal retrieveUser(String userName); } jenkins-winstone-0.9.10-jenkins-47/src/java/winstone/ClientOutputStream.java0000644000175000017500000000236312200024521027473 0ustar jamespagejamespagepackage winstone; import java.io.IOException; import java.io.OutputStream; /** * Wrap an {@link OutputStream} so that we can distinguish errors writing to clients. * *

* Those are normally caused by a browser aborting a connection, and note worthwhile to report to log. * * @author Kohsuke Kawaguchi */ public class ClientOutputStream extends OutputStream { private final OutputStream out; public ClientOutputStream(OutputStream out) { this.out = out; } public void write(int b) throws ClientSocketException { try { out.write(b); } catch (IOException e) { throw new ClientSocketException(e); } } public void write(byte[] b) throws ClientSocketException { try { out.write(b); } catch (IOException e) { throw new ClientSocketException(e); } } public void write(byte[] b, int off, int len) throws ClientSocketException { try { out.write(b, off, len); } catch (IOException e) { throw new ClientSocketException(e); } } public void flush() throws IOException { out.flush(); } public void close() throws IOException { out.close(); } } jenkins-winstone-0.9.10-jenkins-47/src/java/winstone/WebXmlParser.java0000644000175000017500000002417612200024521026241 0ustar jamespagejamespage/* * Copyright 2003-2006 Rick Knowles * Distributed under the terms of either: * - the common development and distribution license (CDDL), v1.0; or * - the GNU Lesser General Public License, v2.1 or later */ package winstone; import java.io.File; import java.io.IOException; import java.net.URL; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import org.w3c.dom.Document; import org.xml.sax.EntityResolver; import org.xml.sax.ErrorHandler; import org.xml.sax.InputSource; import org.xml.sax.SAXException; import org.xml.sax.SAXParseException; /** * The web.xml parsing logic. This is used by more than one launcher, so it's shared from here. * * @author Rick Knowles * @version $Id: WebXmlParser.java,v 1.9 2006/12/08 04:08:44 rickknowles Exp $ */ public class WebXmlParser implements EntityResolver, ErrorHandler { private ClassLoader commonLoader; private boolean rethrowValidationExceptions; public WebXmlParser(ClassLoader commonCL) { this.commonLoader = commonCL; this.rethrowValidationExceptions = true; } private final static String SCHEMA_SOURCE_PROPERTY = "http://java.sun.com/xml/jaxp/properties/schemaSource"; /** * Get a parsed XML DOM from the given inputstream. Used to process the * web.xml application deployment descriptors. Returns null if the parse fails, * so the effect is as if there was no web.xml file available. */ protected Document parseStreamToXML(File webXmlFile) { DocumentBuilderFactory factory = getBaseDBF(); URL localXSD25 = this.commonLoader.getResource(LOCAL_ENTITY_TABLE[3][2]); URL localXSD24 = this.commonLoader.getResource(LOCAL_ENTITY_TABLE[2][2]); // Test for XSD compliance try { factory.setAttribute("http://java.sun.com/xml/jaxp/properties/schemaLanguage", "http://www.w3.org/2001/XMLSchema"); if (localXSD25 != null) { factory.setAttribute(SCHEMA_SOURCE_PROPERTY, localXSD25.toString()); Logger.log(Logger.FULL_DEBUG, Launcher.RESOURCES, "WebXmlParser.Local25XSDEnabled"); } else if (localXSD24 != null) { factory.setAttribute(SCHEMA_SOURCE_PROPERTY, localXSD24.toString()); Logger.log(Logger.FULL_DEBUG, Launcher.RESOURCES, "WebXmlParser.Local24XSDEnabled"); } else { Logger.log(Logger.WARNING, Launcher.RESOURCES, "WebXmlParser.2524XSDNotFound"); } } catch (Throwable err) { // if non-compliant parser, then parse as non-XSD compliant Logger.log(Logger.WARNING, Launcher.RESOURCES, "WebXmlParser.NonXSDParser"); try { this.rethrowValidationExceptions = false; return parseAsV23Webapp(webXmlFile); } catch (Throwable v23Err) { Logger.log(Logger.ERROR, Launcher.RESOURCES, "WebXmlParser.WebXML23ParseError", v23Err); return null; } } // XSD compliant parser available, so parse as 2.5 try { if (localXSD25 != null) { factory.setAttribute(SCHEMA_SOURCE_PROPERTY, localXSD25.toString()); } else { factory.setAttribute(SCHEMA_SOURCE_PROPERTY, null); } DocumentBuilder builder = factory.newDocumentBuilder(); builder.setEntityResolver(this); builder.setErrorHandler(this); this.rethrowValidationExceptions = true; return builder.parse(webXmlFile); } catch (Throwable errV25) { try { // Try as 2.4 if (localXSD24 != null) { factory.setAttribute(SCHEMA_SOURCE_PROPERTY, localXSD24.toString()); } else { factory.setAttribute(SCHEMA_SOURCE_PROPERTY, null); } DocumentBuilder builder = factory.newDocumentBuilder(); builder.setEntityResolver(this); builder.setErrorHandler(this); this.rethrowValidationExceptions = true; return builder.parse(webXmlFile); } catch (Throwable errV24) { // Try parsing as a v2.3 spec webapp, and if another error happens, report 2.3, 2.4, 2.5 try { this.rethrowValidationExceptions = false; return parseAsV23Webapp(webXmlFile); } catch (Throwable errV23) { Logger.log(Logger.ERROR, Launcher.RESOURCES, "WebXmlParser.WebXMLBothErrors"); Logger.log(Logger.ERROR, Launcher.RESOURCES, "WebXmlParser.WebXML25ParseError", errV25); Logger.log(Logger.ERROR, Launcher.RESOURCES, "WebXmlParser.WebXML24ParseError", errV24); Logger.log(Logger.ERROR, Launcher.RESOURCES, "WebXmlParser.WebXML23ParseError", errV23); return null; } } } } private Document parseAsV23Webapp(File webXmlFile) throws ParserConfigurationException, SAXException, IOException { DocumentBuilderFactory factory = getBaseDBF(); DocumentBuilder builder = factory.newDocumentBuilder(); builder.setEntityResolver(this); builder.setErrorHandler(this); return builder.parse(webXmlFile); } private DocumentBuilderFactory getBaseDBF() { // Use JAXP to create a document builder DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); factory.setExpandEntityReferences(false); factory.setValidating(true); factory.setNamespaceAware(true); factory.setIgnoringComments(true); factory.setCoalescing(true); factory.setIgnoringElementContentWhitespace(true); return factory; } /** * Table mapping public doctypes and system ids against local classloader paths. This * is used to resolve local entities where possible. * Column 0 = public doctype * Column 1 = system id * Column 2 = local path */ private static final String LOCAL_ENTITY_TABLE[][] = { {"-//Sun Microsystems, Inc.//DTD Web Application 2.2//EN", null, "javax/servlet/resources/web-app_2_2.dtd"}, {"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN", null, "javax/servlet/resources/web-app_2_3.dtd"}, {null, "http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd", "javax/servlet/resources/web-app_2_4.xsd"}, {null, "http://java.sun.com/xml/ns/j2ee/web-app_2_5.xsd", "javax/servlet/resources/web-app_2_5.xsd"}, {null, "http://www.w3.org/2001/xml.xsd", "javax/servlet/resources/xml.xsd"}, {"-//W3C//DTD XMLSCHEMA 200102//EN", null, "javax/servlet/resources/XMLSchema.dtd"}, {null, "http://www.w3.org/2001/datatypes.dtd", "javax/servlet/resources/datatypes.dtd"}, {null, "http://java.sun.com/xml/ns/j2ee/j2ee_1_4.xsd", "javax/servlet/resources/j2ee_1_4.xsd"}, {null, "http://java.sun.com/xml/ns/j2ee/javaee_5.xsd", "javax/servlet/resources/javaee_5.xsd"}, {null, "http://java.sun.com/xml/ns/j2ee/jsp_2_0.xsd", "javax/servlet/resources/jsp_2_0.xsd"}, {null, "http://java.sun.com/xml/ns/j2ee/jsp_2_1.xsd", "javax/servlet/resources/jsp_2_1.xsd"}, {null, "http://www.ibm.com/webservices/xsd/j2ee_web_services_client_1_1.xsd", "javax/servlet/resources/j2ee_web_services_client_1_1.xsd"}, {null, "http://www.ibm.com/webservices/xsd/j2ee_web_services_client_1_2.xsd", "javax/servlet/resources/javaee_web_services_client_1_2.xsd"} }; /** * Implements the EntityResolver interface. This allows us to redirect any * requests by the parser for webapp DTDs to local copies. It's faster and * it means you can run winstone without being web-connected. */ public InputSource resolveEntity(String publicName, String url) throws SAXException, IOException { Logger.log(Logger.FULL_DEBUG, Launcher.RESOURCES, "WebXmlParser.ResolvingEntity", publicName, url); for (String[] aLOCAL_ENTITY_TABLE : LOCAL_ENTITY_TABLE) { if (((aLOCAL_ENTITY_TABLE[0] != null) && (publicName != null) && publicName.equals(aLOCAL_ENTITY_TABLE[0])) || ((aLOCAL_ENTITY_TABLE[1] != null) && (url != null) && url.equals(aLOCAL_ENTITY_TABLE[1]))) { if (this.commonLoader.getResource(aLOCAL_ENTITY_TABLE[2]) != null) { return getLocalResource(url, aLOCAL_ENTITY_TABLE[2]); } } } if ((url != null) && url.startsWith("jar:")) { return getLocalResource(url, url.substring(url.indexOf("!/") + 2)); } else if ((url != null) && url.startsWith("file:")) { return new InputSource(url); } else { Logger.log(Logger.FULL_DEBUG, Launcher.RESOURCES, "WebXmlParser.NoLocalResource", url); return new InputSource(url); } } private InputSource getLocalResource(String url, String local) { if (this.commonLoader.getResource(local) == null) return new InputSource(url); InputSource is = new InputSource(this.commonLoader.getResourceAsStream(local)); is.setSystemId(url); return is; } public void error(SAXParseException exception) throws SAXException { if (this.rethrowValidationExceptions) { throw exception; } else { Logger.log(Logger.WARNING, Launcher.RESOURCES, "WebXmlParser.XMLParseError", exception.getLineNumber() + "", exception.getMessage()); } } public void fatalError(SAXParseException exception) throws SAXException { error(exception); } public void warning(SAXParseException exception) throws SAXException { Logger.log(Logger.WARNING, Launcher.RESOURCES, "WebXmlParser.XMLParseError", exception.getLineNumber() + "", exception.getMessage()); } } jenkins-winstone-0.9.10-jenkins-47/src/java/winstone/AuthenticationHandler.java0000644000175000017500000000201112200024521030123 0ustar jamespagejamespage/* * Copyright 2003-2006 Rick Knowles * Distributed under the terms of either: * - the common development and distribution license (CDDL), v1.0; or * - the GNU Lesser General Public License, v2.1 or later */ package winstone; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.*; /** * @author Rick Knowles * @version $Id: AuthenticationHandler.java,v 1.2 2006/02/28 07:32:47 rickknowles Exp $ */ public interface AuthenticationHandler { /** * Evaluates any authentication constraints, intercepting if auth is * required. The relevant authentication handler subclass's logic is used to * actually authenticate. * * @return A boolean indicating whether to continue after this request */ public boolean processAuthentication(ServletRequest request, ServletResponse response, String pathRequested) throws IOException, ServletException; } jenkins-winstone-0.9.10-jenkins-47/src/java/winstone/realm/0000755000175000017500000000000012200024521024111 5ustar jamespagejamespagejenkins-winstone-0.9.10-jenkins-47/src/java/winstone/realm/FileRealm.java0000644000175000017500000001467512200024521026631 0ustar jamespagejamespage/* * Copyright 2003-2006 Rick Knowles * Distributed under the terms of either: * - the common development and distribution license (CDDL), v1.0; or * - the GNU Lesser General Public License, v2.1 or later */ package winstone.realm; import java.io.File; import java.io.FileInputStream; import java.io.InputStream; import java.util.ArrayList; import java.util.Arrays; import java.util.Hashtable; import java.util.List; import java.util.Map; import java.util.Set; import java.util.StringTokenizer; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import org.w3c.dom.Document; import org.w3c.dom.Node; import winstone.AuthenticationPrincipal; import winstone.AuthenticationRealm; import winstone.Logger; import winstone.cmdline.Option; import winstone.WinstoneException; import winstone.WinstoneResourceBundle; /** * @author rickk * @version $Id: FileRealm.java,v 1.4 2006/08/30 04:07:52 rickknowles Exp $ */ public class FileRealm implements AuthenticationRealm { private static final WinstoneResourceBundle REALM_RESOURCES = new WinstoneResourceBundle("winstone.realm.LocalStrings"); final String DEFAULT_FILE_NAME = "users.xml"; final String ELEM_USER = "user"; final String ATT_USERNAME = "username"; final String ATT_PASSWORD = "password"; final String ATT_ROLELIST = "roles"; private Map passwords; private Map roles; /** * Constructor - this sets up an authentication realm, using the file * supplied on the command line as a source of userNames/passwords/roles. */ public FileRealm(Set rolesAllowed, Map args) { this.passwords = new Hashtable(); this.roles = new Hashtable(); // Get the filename and parse the xml doc File realmFile = Option.FILEREALM_CONFIGFILE.get(args); if (realmFile==null) realmFile = new File(DEFAULT_FILE_NAME); if (!realmFile.exists()) throw new WinstoneException(REALM_RESOURCES.getString( "FileRealm.FileNotFound", realmFile.getPath())); try { InputStream inFile = new FileInputStream(realmFile); Document doc = this.parseStreamToXML(inFile); inFile.close(); Node rootElm = doc.getDocumentElement(); for (int n = 0; n < rootElm.getChildNodes().getLength(); n++) { Node child = rootElm.getChildNodes().item(n); if ((child.getNodeType() == Node.ELEMENT_NODE) && (child.getNodeName().equals(ELEM_USER))) { String userName = null; String password = null; String roleList = null; // Loop through for attributes for (int j = 0; j < child.getAttributes().getLength(); j++) { Node thisAtt = child.getAttributes().item(j); if (thisAtt.getNodeName().equals(ATT_USERNAME)) userName = thisAtt.getNodeValue(); else if (thisAtt.getNodeName().equals(ATT_PASSWORD)) password = thisAtt.getNodeValue(); else if (thisAtt.getNodeName().equals(ATT_ROLELIST)) roleList = thisAtt.getNodeValue(); } if ((userName == null) || (password == null) || (roleList == null)) Logger.log(Logger.FULL_DEBUG, REALM_RESOURCES, "FileRealm.SkippingUser", userName); else { // Parse the role list into an array and sort it StringTokenizer st = new StringTokenizer(roleList, ","); List rl = new ArrayList(); for (; st.hasMoreTokens();) { String currentRole = st.nextToken(); if (rolesAllowed.contains(currentRole)) rl.add(currentRole); } Object roleArray[] = rl.toArray(); Arrays.sort(roleArray); this.passwords.put(userName, password); this.roles.put(userName, Arrays.asList(roleArray)); } } } Logger.log(Logger.DEBUG, REALM_RESOURCES, "FileRealm.Initialised", "" + this.passwords.size()); } catch (java.io.IOException err) { throw new WinstoneException(REALM_RESOURCES .getString("FileRealm.ErrorLoading"), err); } } /** * Get a parsed XML DOM from the given inputstream. Used to process the * web.xml application deployment descriptors. */ private Document parseStreamToXML(InputStream in) { try { // Use JAXP to create a document builder DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); factory.setExpandEntityReferences(false); factory.setValidating(false); factory.setNamespaceAware(false); factory.setIgnoringComments(true); factory.setCoalescing(true); factory.setIgnoringElementContentWhitespace(true); DocumentBuilder builder = factory.newDocumentBuilder(); return builder.parse(in); } catch (Throwable errParser) { throw new WinstoneException(REALM_RESOURCES .getString("FileRealm.XMLParseError"), errParser); } } /** * Authenticate the user - do we know them ? Return a principal once we know * them */ public AuthenticationPrincipal authenticateByUsernamePassword( String userName, String password) { if ((userName == null) || (password == null)) return null; String realPassword = (String) this.passwords.get(userName); if (realPassword == null) return null; else if (!realPassword.equals(password)) return null; else return new AuthenticationPrincipal(userName, password, (List) this.roles.get(userName)); } /** * Retrieve an authenticated user */ public AuthenticationPrincipal retrieveUser(String userName) { return new AuthenticationPrincipal(userName, (String) this.passwords .get(userName), (List) this.roles.get(userName)); } } jenkins-winstone-0.9.10-jenkins-47/src/java/winstone/realm/LocalStrings.properties0000644000175000017500000000073712200024521030642 0ustar jamespagejamespageArgumentsRealm.Initialised=ArgumentsRealm initialised: users: [#0] ArgumentsRealm.UndeclaredRoles=WARNING: No roles detected in configuration for user [#0] FileRealm.Initialised=FileRealm initialised: users: [#0] FileRealm.FileNotFound=FileRealm could not locate the user file [#0] - disabling security FileRealm.SkippingUser=Skipping user [#0] - details were incomplete FileRealm.ErrorLoading=Error loading FileRealm FileRealm.XMLParseError=Error parsing the users XML documentjenkins-winstone-0.9.10-jenkins-47/src/java/winstone/realm/ArgumentsRealm.java0000644000175000017500000000766412200024521027717 0ustar jamespagejamespage/* * Copyright 2003-2006 Rick Knowles * Distributed under the terms of either: * - the common development and distribution license (CDDL), v1.0; or * - the GNU Lesser General Public License, v2.1 or later */ package winstone.realm; import java.util.ArrayList; import java.util.Arrays; import java.util.Hashtable; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import java.util.StringTokenizer; import winstone.AuthenticationPrincipal; import winstone.AuthenticationRealm; import winstone.Logger; import winstone.cmdline.Option; import winstone.WebAppConfiguration; import winstone.WinstoneResourceBundle; /** * Base class for authentication realms. Subclasses provide the source of * authentication roles, usernames, passwords, etc, and when asked for * validation respond with a role if valid, or null otherwise. * * @author mailto: Rick Knowles * @version $Id: ArgumentsRealm.java,v 1.4 2007/06/01 15:55:41 rickknowles Exp $ */ public class ArgumentsRealm implements AuthenticationRealm { private static final WinstoneResourceBundle REALM_RESOURCES = new WinstoneResourceBundle("winstone.realm.LocalStrings"); private Map passwords; private Map roles; /** * Constructor - this sets up an authentication realm, using the arguments * supplied on the command line as a source of userNames/passwords/roles. */ public ArgumentsRealm(Set rolesAllowed, Map args) { this.passwords = new Hashtable(); this.roles = new Hashtable(); for (Object o : args.keySet()) { String key = (String) o; if (key.startsWith(Option.ARGUMENTS_REALM_PASSWORD.name)) { String userName = key.substring(Option.ARGUMENTS_REALM_PASSWORD.name.length()); String password = (String) args.get(key); String roleList = WebAppConfiguration.stringArg(args, Option.ARGUMENTS_REALM_ROLES.name + userName, ""); if (roleList.equals("")) { Logger.log(Logger.WARNING, REALM_RESOURCES, "ArgumentsRealm.UndeclaredRoles", userName); } else { StringTokenizer st = new StringTokenizer(roleList, ","); List rl = new ArrayList(); for (; st.hasMoreTokens(); ) { String currentRole = st.nextToken(); if (rolesAllowed.contains(currentRole)) rl.add(currentRole); } Object roleArray[] = rl.toArray(); Arrays.sort(roleArray); this.roles.put(userName, Arrays.asList(roleArray)); } this.passwords.put(userName, password); } } Logger.log(Logger.DEBUG, REALM_RESOURCES, "ArgumentsRealm.Initialised", "" + this.passwords.size()); } /** * Authenticate the user - do we know them ? Return a principal once we know * them */ public AuthenticationPrincipal authenticateByUsernamePassword( String userName, String password) { if ((userName == null) || (password == null)) return null; String realPassword = (String) this.passwords.get(userName); if (realPassword == null) return null; else if (!realPassword.equals(password)) return null; else return new AuthenticationPrincipal(userName, password, (List) this.roles.get(userName)); } /** * Retrieve an authenticated user */ public AuthenticationPrincipal retrieveUser(String userName) { if (userName == null) return null; else return new AuthenticationPrincipal(userName, (String) this.passwords.get(userName), (List) this.roles .get(userName)); } }jenkins-winstone-0.9.10-jenkins-47/src/java/winstone/auth/0000755000175000017500000000000012200024521023752 5ustar jamespagejamespagejenkins-winstone-0.9.10-jenkins-47/src/java/winstone/auth/SecurityConstraint.java0000644000175000017500000001454012200024521030475 0ustar jamespagejamespage/* * Copyright 2003-2006 Rick Knowles * Distributed under the terms of either: * - the common development and distribution license (CDDL), v1.0; or * - the GNU Lesser General Public License, v2.1 or later */ package winstone.auth; import java.util.HashSet; import java.util.Set; import javax.servlet.http.HttpServletRequest; import org.w3c.dom.Node; import winstone.Logger; import winstone.Mapping; import winstone.WebAppConfiguration; /** * Models a restriction on a particular set of resources in the webapp. * * @author mailto: Rick Knowles * @version $Id: SecurityConstraint.java,v 1.7 2006/08/10 06:38:30 rickknowles Exp $ */ public class SecurityConstraint { final String ELEM_DISPLAY_NAME = "display-name"; final String ELEM_WEB_RESOURCES = "web-resource-collection"; final String ELEM_WEB_RESOURCE_NAME = "web-resource-name"; final String ELEM_URL_PATTERN = "url-pattern"; final String ELEM_HTTP_METHOD = "http-method"; final String ELEM_AUTH_CONSTRAINT = "auth-constraint"; final String ELEM_ROLE_NAME = "role-name"; final String ELEM_USER_DATA_CONSTRAINT = "user-data-constraint"; final String ELEM_TRANSPORT_GUARANTEE = "transport-guarantee"; final String GUARANTEE_NONE = "NONE"; private String displayName; private String methodSets[]; private Mapping urlPatterns[]; private String rolesAllowed[]; private boolean needsSSL; /** * Constructor */ public SecurityConstraint(Node elm, Set rolesAllowed, int counter) { this.needsSSL = false; Set localUrlPatternList = new HashSet(); Set localMethodSetList = new HashSet(); Set localRolesAllowed = new HashSet(); for (int i = 0; i < elm.getChildNodes().getLength(); i++) { Node child = elm.getChildNodes().item(i); if (child.getNodeType() != Node.ELEMENT_NODE) continue; else if (child.getNodeName().equals(ELEM_DISPLAY_NAME)) this.displayName = WebAppConfiguration.getTextFromNode(child); else if (child.getNodeName().equals(ELEM_WEB_RESOURCES)) { String methodSet = null; // Parse the element and extract for (int k = 0; k < child.getChildNodes().getLength(); k++) { Node resourceChild = child.getChildNodes().item(k); if (resourceChild.getNodeType() != Node.ELEMENT_NODE) continue; String resourceChildNodeName = resourceChild.getNodeName(); if (resourceChildNodeName.equals(ELEM_URL_PATTERN)) { localUrlPatternList.add(Mapping.createFromURL( "Security", WebAppConfiguration.getTextFromNode(resourceChild))); } else if (resourceChildNodeName.equals(ELEM_HTTP_METHOD)) { methodSet = (methodSet == null ? "." : methodSet) + WebAppConfiguration.getTextFromNode(resourceChild) + "."; } } localMethodSetList.add(methodSet == null ? ".ALL." : methodSet); } else if (child.getNodeName().equals(ELEM_AUTH_CONSTRAINT)) { // Parse the element and extract for (int k = 0; k < child.getChildNodes().getLength(); k++) { Node roleChild = child.getChildNodes().item(k); if ((roleChild.getNodeType() != Node.ELEMENT_NODE) || !roleChild.getNodeName().equals(ELEM_ROLE_NAME)) continue; String roleName = WebAppConfiguration.getTextFromNode(roleChild); if (roleName.equals("*")) localRolesAllowed.addAll(rolesAllowed); else localRolesAllowed.add(roleName); } } else if (child.getNodeName().equals(ELEM_USER_DATA_CONSTRAINT)) { // Parse the element and extract for (int k = 0; k < child.getChildNodes().getLength(); k++) { Node roleChild = child.getChildNodes().item(k); if ((roleChild.getNodeType() == Node.ELEMENT_NODE) && roleChild.getNodeName().equals(ELEM_TRANSPORT_GUARANTEE)) this.needsSSL = !WebAppConfiguration.getTextFromNode(roleChild) .equalsIgnoreCase(GUARANTEE_NONE); } } } this.urlPatterns = (Mapping[]) localUrlPatternList.toArray(new Mapping[0]); this.methodSets = (String[]) localMethodSetList.toArray(new String[0]); this.rolesAllowed = (String[]) localRolesAllowed.toArray(new String[0]); if (this.displayName == null) this.displayName = BaseAuthenticationHandler.AUTH_RESOURCES.getString( "SecurityConstraint.DefaultName", "" + counter); } /** * Call this to evaluate the security constraint - is this operation allowed ? */ public boolean isAllowed(HttpServletRequest request) { for (String aRolesAllowed : this.rolesAllowed) { if (request.isUserInRole(aRolesAllowed)) { Logger.log(Logger.FULL_DEBUG, BaseAuthenticationHandler.AUTH_RESOURCES, "SecurityConstraint.Passed", this.displayName, aRolesAllowed); return true; } } Logger.log(Logger.FULL_DEBUG, BaseAuthenticationHandler.AUTH_RESOURCES, "SecurityConstraint.Failed", this.displayName); return false; } /** * Call this to evaluate the security constraint - is this constraint applicable to this url ? */ public boolean isApplicable(String url, String method) { for (int n = 0; n < this.urlPatterns.length; n++) if (this.urlPatterns[n].match(url, null, null) && methodCheck(method, this.methodSets[n])) return true; return false; } private boolean methodCheck(String protocol, String methodSet) { return methodSet.equals(".ALL.") || (methodSet.indexOf("." + protocol.toUpperCase() + ".") != -1); } public boolean needsSSL() { return this.needsSSL; } public String getName() { return this.displayName; } } jenkins-winstone-0.9.10-jenkins-47/src/java/winstone/auth/BasicAuthenticationHandler.java0000644000175000017500000001551612200024521032044 0ustar jamespagejamespage/* * Copyright 2003-2006 Rick Knowles * Distributed under the terms of either: * - the common development and distribution license (CDDL), v1.0; or * - the GNU Lesser General Public License, v2.1 or later */ package winstone.auth; import java.io.IOException; import java.util.List; import java.util.Set; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequestWrapper; import javax.servlet.http.HttpServletResponse; import org.w3c.dom.Node; import winstone.AuthenticationPrincipal; import winstone.AuthenticationRealm; import winstone.Logger; import winstone.WinstoneRequest; /** * Handles HTTP basic authentication. * * @author mailto: Rick Knowles * @version $Id: BasicAuthenticationHandler.java,v 1.5 2007/04/11 13:14:26 rickknowles Exp $ */ public class BasicAuthenticationHandler extends BaseAuthenticationHandler { public BasicAuthenticationHandler(Node loginConfigNode, List constraintNodes, Set rolesAllowed, AuthenticationRealm realm) { super(loginConfigNode, constraintNodes, rolesAllowed, realm); Logger.log(Logger.DEBUG, AUTH_RESOURCES, "BasicAuthenticationHandler.Initialised", realmName); } /** * Call this once we know that we need to authenticate */ protected void requestAuthentication(HttpServletRequest request, HttpServletResponse response, String pathRequested) throws IOException { // Return unauthorized, and set the realm name response.setHeader("WWW-Authenticate", "Basic Realm=\"" + this.realmName + "\""); response.sendError(HttpServletResponse.SC_UNAUTHORIZED, AUTH_RESOURCES .getString("BasicAuthenticationHandler.UnauthorizedMessage")); } /** * Handling the (possible) response */ protected boolean validatePossibleAuthenticationResponse( HttpServletRequest request, HttpServletResponse response, String pathRequested) throws IOException { String authorization = request.getHeader("Authorization"); if ((authorization != null) && authorization.toLowerCase().startsWith("basic")) { char[] inBytes = authorization.substring(5).trim().toCharArray(); byte[] outBytes = new byte[(int) (inBytes.length * 0.75f)]; // always mod 4 = 0 int length = decodeBase64(inBytes, outBytes, 0, inBytes.length, 0); String decoded = new String(outBytes, 0, length); int delimPos = decoded.indexOf(':'); if (delimPos != -1) { AuthenticationPrincipal principal = this.realm .authenticateByUsernamePassword(decoded.substring(0, delimPos).trim(), decoded.substring( delimPos + 1).trim()); if (principal != null) { principal.setAuthType(HttpServletRequest.BASIC_AUTH); if (request instanceof WinstoneRequest) ((WinstoneRequest) request).setRemoteUser(principal); else if (request instanceof HttpServletRequestWrapper) { HttpServletRequestWrapper wrapper = (HttpServletRequestWrapper) request; if (wrapper.getRequest() instanceof WinstoneRequest) ((WinstoneRequest) wrapper.getRequest()) .setRemoteUser(principal); else Logger.log(Logger.WARNING, AUTH_RESOURCES, "BasicAuthenticationHandler.CantSetUser", wrapper.getRequest().getClass().getName()); } else Logger.log(Logger.WARNING, AUTH_RESOURCES, "BasicAuthenticationHandler.CantSetUser", request.getClass().getName()); } } } return true; } /** * Decodes a byte array from base64 */ public static int decodeBase64(char[] input, byte[] output, int inOffset, int inLength, int outOffset) { if (inLength == 0) { return 0; } int outIndex = outOffset; for (int inIndex = inOffset; inIndex < inLength; ) { // Decode four bytes int thisPassInBytes = Math.min(inLength - inIndex, 4); while ((thisPassInBytes > 1) && (input[inIndex + thisPassInBytes - 1] == '=')) { thisPassInBytes--; } if (thisPassInBytes == 2) { int outBuffer = ((B64_DECODE_ARRAY[input[inIndex]] & 0xFF) << 18) | ((B64_DECODE_ARRAY[input[inIndex + 1]] & 0xFF) << 12); output[outIndex] = (byte) ((outBuffer >> 16) & 0xFF); outIndex += 1; } else if (thisPassInBytes == 3) { int outBuffer = ((B64_DECODE_ARRAY[input[inIndex]] & 0xFF) << 18) | ((B64_DECODE_ARRAY[input[inIndex + 1]] & 0xFF) << 12) | ((B64_DECODE_ARRAY[input[inIndex + 2]] & 0xFF) << 6); output[outIndex] = (byte) ((outBuffer >> 16) & 0xFF); output[outIndex + 1] = (byte) ((outBuffer >> 8) & 0xFF); outIndex += 2; } else if (thisPassInBytes == 4) { int outBuffer = ((B64_DECODE_ARRAY[input[inIndex]] & 0xFF) << 18) | ((B64_DECODE_ARRAY[input[inIndex + 1]] & 0xFF) << 12) | ((B64_DECODE_ARRAY[input[inIndex + 2]] & 0xFF) << 6) | (B64_DECODE_ARRAY[input[inIndex + 3]] & 0xFF); output[outIndex] = (byte) ((outBuffer >> 16) & 0xFF); output[outIndex + 1] = (byte) ((outBuffer >> 8) & 0xFF); output[outIndex + 2] = (byte) (outBuffer & 0xFF); outIndex += 3; } inIndex += thisPassInBytes; } return outIndex; } private static byte B64_DECODE_ARRAY[] = new byte[] { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, // Plus sign -1, -1, -1, 63, // Slash 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, // Numbers -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, // Large letters -1, -1, -1, -1, -1, -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, // Small letters -1, -1, -1, -1 }; } jenkins-winstone-0.9.10-jenkins-47/src/java/winstone/auth/FormAuthenticationHandler.java0000644000175000017500000002454612200024521031731 0ustar jamespagejamespage/* * Copyright 2003-2006 Rick Knowles * Distributed under the terms of either: * - the common development and distribution license (CDDL), v1.0; or * - the GNU Lesser General Public License, v2.1 or later */ package winstone.auth; import java.io.IOException; import java.util.List; import java.util.Set; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequestWrapper; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import org.w3c.dom.Node; import winstone.AuthenticationPrincipal; import winstone.AuthenticationRealm; import winstone.Logger; import winstone.WebAppConfiguration; import winstone.WinstoneRequest; /** * Handles FORM based authentication configurations. Fairly simple ... it just * redirects any unauthorized requests to the login page, and any bad logins to * the error page. The auth values are stored in the session in a special slot. * * @author Rick Knowles * @version $Id: FormAuthenticationHandler.java,v 1.7 2006/12/13 14:07:43 rickknowles Exp $ */ public class FormAuthenticationHandler extends BaseAuthenticationHandler { private static final String ELEM_FORM_LOGIN_CONFIG = "form-login-config"; private static final String ELEM_FORM_LOGIN_PAGE = "form-login-page"; private static final String ELEM_FORM_ERROR_PAGE = "form-error-page"; private static final String FORM_ACTION = "j_security_check"; private static final String FORM_USER = "j_username"; private static final String FORM_PASS = "j_password"; private static final String AUTHENTICATED_USER = "winstone.auth.FormAuthenticationHandler.AUTHENTICATED_USER"; private static final String CACHED_REQUEST = "winstone.auth.FormAuthenticationHandler.CACHED_REQUEST"; private String loginPage; private String errorPage; /** * Constructor for the FORM authenticator * * @param realm * The realm against which we are authenticating * @param constraints * The array of security constraints that might apply * @param resources * The list of resource strings for messages * @param realmName * The name of the realm this handler claims */ public FormAuthenticationHandler(Node loginConfigNode, List constraintNodes, Set rolesAllowed, AuthenticationRealm realm) { super(loginConfigNode, constraintNodes, rolesAllowed, realm); for (int n = 0; n < loginConfigNode.getChildNodes().getLength(); n++) { Node loginElm = loginConfigNode.getChildNodes().item(n); if (loginElm.getNodeName().equals(ELEM_FORM_LOGIN_CONFIG)) { for (int k = 0; k < loginElm.getChildNodes().getLength(); k++) { Node formElm = loginElm.getChildNodes().item(k); if (formElm.getNodeType() != Node.ELEMENT_NODE) continue; else if (formElm.getNodeName().equals(ELEM_FORM_LOGIN_PAGE)) loginPage = WebAppConfiguration.getTextFromNode(formElm); else if (formElm.getNodeName().equals(ELEM_FORM_ERROR_PAGE)) errorPage = WebAppConfiguration.getTextFromNode(formElm); } } } Logger.log(Logger.DEBUG, AUTH_RESOURCES, "FormAuthenticationHandler.Initialised", realmName); } /** * Evaluates any authentication constraints, intercepting if auth is * required. The relevant authentication handler subclass's logic is used to * actually authenticate. * * @return A boolean indicating whether to continue after this request */ public boolean processAuthentication(ServletRequest request, ServletResponse response, String pathRequested) throws IOException, ServletException { if (pathRequested.equals(this.loginPage) || pathRequested.equals(this.errorPage)) { return true; } else { return super.processAuthentication(request, response, pathRequested); } } /** * Call this once we know that we need to authenticate */ protected void requestAuthentication(HttpServletRequest request, HttpServletResponse response, String pathRequested) throws ServletException, IOException { // Save the critical details of the request into the session map ServletRequest unwrapped = request; while (unwrapped instanceof HttpServletRequestWrapper) { unwrapped = ((HttpServletRequestWrapper) unwrapped).getRequest(); } HttpSession session = request.getSession(true); session.setAttribute(CACHED_REQUEST, new RetryRequestParams(unwrapped)); // Forward on to the login page Logger.log(Logger.FULL_DEBUG, AUTH_RESOURCES, "FormAuthenticationHandler.GoToLoginPage"); javax.servlet.RequestDispatcher rdLogin = request .getRequestDispatcher(this.loginPage); setNoCache(response); rdLogin.forward(request, response); } /** * Check the response - is it a response to the login page ? * * @return A boolean indicating whether to continue with the request or not */ protected boolean validatePossibleAuthenticationResponse( HttpServletRequest request, HttpServletResponse response, String pathRequested) throws ServletException, IOException { // Check if this is a j_security_check uri if (pathRequested.endsWith(FORM_ACTION)) { String username = request.getParameter(FORM_USER); String password = request.getParameter(FORM_PASS); // Send to error page if invalid AuthenticationPrincipal principal = this.realm .authenticateByUsernamePassword(username, password); if (principal == null) { javax.servlet.RequestDispatcher rdError = request .getRequestDispatcher(this.errorPage); rdError.forward(request, response); } // Send to stashed request else { // Iterate back as far as we can ServletRequest wrapperCheck = request; while (wrapperCheck instanceof HttpServletRequestWrapper) { wrapperCheck = ((HttpServletRequestWrapper) wrapperCheck).getRequest(); } // Get the stashed request WinstoneRequest actualRequest = null; if (wrapperCheck instanceof WinstoneRequest) { actualRequest = (WinstoneRequest) wrapperCheck; actualRequest.setRemoteUser(principal); } else { Logger.log(Logger.WARNING, AUTH_RESOURCES, "FormAuthenticationHandler.CantSetUser", wrapperCheck.getClass().getName()); } HttpSession session = request.getSession(true); String previousLocation = this.loginPage; RetryRequestParams cachedRequest = (RetryRequestParams) session.getAttribute(CACHED_REQUEST); if ((cachedRequest != null) && (actualRequest != null)) { // Repopulate this request from the params we saved request = new RetryRequestWrapper(request, cachedRequest); previousLocation = (request.getServletPath() == null ? "" : request.getServletPath()) + (request.getPathInfo() == null ? "" : request.getPathInfo()); } else { Logger.log(Logger.DEBUG, AUTH_RESOURCES, "FormAuthenticationHandler.NoCachedRequest"); } // do role check, since we don't know that this user has permission if (doRoleCheck(request, response, previousLocation)) { principal.setAuthType(HttpServletRequest.FORM_AUTH); session.setAttribute(AUTHENTICATED_USER, principal); javax.servlet.RequestDispatcher rdPrevious = request .getRequestDispatcher(previousLocation); rdPrevious.forward(request, response); } else { javax.servlet.RequestDispatcher rdError = request .getRequestDispatcher(this.errorPage); rdError.forward(request, response); } } return false; } // If it's not a login, get the session, and look up the auth user variable else { WinstoneRequest actualRequest = null; if (request instanceof WinstoneRequest) { actualRequest = (WinstoneRequest) request; } else if (request instanceof HttpServletRequestWrapper) { HttpServletRequestWrapper wrapper = (HttpServletRequestWrapper) request; if (wrapper.getRequest() instanceof WinstoneRequest) { actualRequest = (WinstoneRequest) wrapper.getRequest(); } else { Logger.log(Logger.WARNING, AUTH_RESOURCES, "FormAuthenticationHandler.CantSetUser", wrapper .getRequest().getClass().getName()); } } else { Logger.log(Logger.WARNING, AUTH_RESOURCES, "FormAuthenticationHandler.CantSetUser", request .getClass().getName()); } HttpSession session = actualRequest.getSession(false); if (session != null) { AuthenticationPrincipal authenticatedUser = (AuthenticationPrincipal) session.getAttribute(AUTHENTICATED_USER); if (authenticatedUser != null) { actualRequest.setRemoteUser(authenticatedUser); Logger.log(Logger.FULL_DEBUG, AUTH_RESOURCES, "FormAuthenticationHandler.GotUserFromSession"); } } return true; } } } jenkins-winstone-0.9.10-jenkins-47/src/java/winstone/auth/DigestAuthenticationHandler.java0000644000175000017500000002043612200024521032237 0ustar jamespagejamespage/* * Copyright 2003-2006 Rick Knowles * Distributed under the terms of either: * - the common development and distribution license (CDDL), v1.0; or * - the GNU Lesser General Public License, v2.1 or later */ package winstone.auth; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.List; import java.util.Random; import java.util.Set; import java.util.StringTokenizer; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequestWrapper; import javax.servlet.http.HttpServletResponse; import org.w3c.dom.Node; import winstone.AuthenticationPrincipal; import winstone.AuthenticationRealm; import winstone.Logger; import winstone.WinstoneRequest; import winstone.WinstoneResourceBundle; /** * Implements the MD5 digest version of authentication * * @author Rick Knowles * @version $Id: DigestAuthenticationHandler.java,v 1.3 2004/05/22 06:53:45 * rickknowles Exp $ */ public class DigestAuthenticationHandler extends BaseAuthenticationHandler { private MessageDigest md5Digester; public DigestAuthenticationHandler(Node loginConfigNode, List constraintNodes, Set rolesAllowed, AuthenticationRealm realm) throws NoSuchAlgorithmException { super(loginConfigNode, constraintNodes, rolesAllowed, realm); this.md5Digester = MessageDigest.getInstance("MD5"); Logger.log(Logger.DEBUG, AUTH_RESOURCES, "DigestAuthenticationHandler.Initialised", realmName); } /** * Call this once we know that we need to authenticate */ protected void requestAuthentication(HttpServletRequest request, HttpServletResponse response, String pathRequested) throws IOException { // Generate the one time token String oneTimeToken = "WinstoneToken:" + (new Random().nextDouble() * System.currentTimeMillis()); // Need to write the www-authenticate header String authHeader = "Digest realm=\"" + this.realmName + "\", qop=\"auth\", " + "nonce=\"" + oneTimeToken + "\", opaque=\"" + md5Encode(oneTimeToken) + "\""; response.setHeader("WWW-Authenticate", authHeader); // Return unauthorized response.sendError(HttpServletResponse.SC_UNAUTHORIZED, AUTH_RESOURCES .getString("DigestAuthenticationHandler.UnauthorizedMessage")); } /** * Handling the (possible) response * * @return True if the request should continue, or false if we have * intercepted it */ protected boolean validatePossibleAuthenticationResponse( HttpServletRequest request, HttpServletResponse response, String pathRequested) throws IOException { String authorization = request.getHeader("Authorization"); if (authorization == null) return true; // Logger.log(Logger.FULL_DEBUG, "Authorization: " + authorization); if (!authorization.startsWith("Digest")) return true; // Extract tokens from auth string String userName = null; String realm = null; String qop = null; String algorithm = null; String uri = null; String nOnce = null; String nc = null; String cnOnce = null; String clientResponseDigest = null; StringTokenizer st = new StringTokenizer(authorization.substring(6) .trim(), ","); while (st.hasMoreTokens()) { String token = st.nextToken().trim(); int equalPos = token.indexOf('='); String paramName = token.substring(0, equalPos); if (paramName.equals("username")) userName = WinstoneResourceBundle.globalReplace(token .substring(equalPos + 1).trim(), "\"", ""); else if (paramName.equals("realm")) realm = WinstoneResourceBundle.globalReplace(token.substring( equalPos + 1).trim(), "\"", ""); else if (paramName.equals("qop")) qop = WinstoneResourceBundle.globalReplace(token.substring( equalPos + 1).trim(), "\"", ""); else if (paramName.equals("algorithm")) algorithm = WinstoneResourceBundle.globalReplace(token .substring(equalPos + 1).trim(), "\"", ""); else if (paramName.equals("uri")) uri = WinstoneResourceBundle.globalReplace(token.substring( equalPos + 1).trim(), "\"", ""); else if (paramName.equals("nonce")) nOnce = WinstoneResourceBundle.globalReplace(token.substring( equalPos + 1).trim(), "\"", ""); else if (paramName.equals("nc")) nc = WinstoneResourceBundle.globalReplace(token.substring( equalPos + 1).trim(), "\"", ""); else if (paramName.equals("cnonce")) cnOnce = WinstoneResourceBundle.globalReplace(token.substring( equalPos + 1).trim(), "\"", ""); else if (paramName.equals("response")) clientResponseDigest = WinstoneResourceBundle.globalReplace( token.substring(equalPos + 1).trim(), "\"", ""); } // Throw out bad attempts if ((userName == null) || (realm == null) || (qop == null) || (uri == null) || (nOnce == null) || (nc == null) || (cnOnce == null) || (clientResponseDigest == null)) return true; else if ((algorithm != null) && !algorithm.equals("MD5")) return true; // Get a user matching the username AuthenticationPrincipal principal = this.realm.retrieveUser(userName); if (principal == null) return true; // Compute the 2 digests and compare String userRealmPasswordDigest = md5Encode(userName + ":" + realm + ":" + principal.getPassword()); String methodURIDigest = md5Encode(request.getMethod() + ":" + uri); String serverResponseDigest = md5Encode(userRealmPasswordDigest + ":" + nOnce + ":" + nc + ":" + cnOnce + ":" + qop + ":" + methodURIDigest); if (serverResponseDigest.equals(clientResponseDigest)) { principal.setAuthType(HttpServletRequest.DIGEST_AUTH); if (request instanceof WinstoneRequest) ((WinstoneRequest) request).setRemoteUser(principal); else if (request instanceof HttpServletRequestWrapper) { HttpServletRequestWrapper wrapper = (HttpServletRequestWrapper) request; if (wrapper.getRequest() instanceof WinstoneRequest) ((WinstoneRequest) wrapper.getRequest()) .setRemoteUser(principal); else Logger.log(Logger.WARNING, AUTH_RESOURCES, "DigestAuthenticationHandler.CantSetUser", wrapper .getRequest().getClass().getName()); } else Logger.log(Logger.WARNING, AUTH_RESOURCES, "DigestAuthenticationHandler.CantSetUser", request .getClass().getName()); } return true; } /** * Returns a hex encoded MD5 digested version of the input string * @param input The string to encode * @return MD5 digested, hex encoded version of the input */ public String md5Encode(String input) throws UnsupportedEncodingException { // Digest byte digestBytes[] = this.md5Digester.digest(input.getBytes("8859_1")); // Write out in hex format char outArray[] = new char[32]; for (int n = 0; n < digestBytes.length; n++) { int hiNibble = (digestBytes[n] & 0xFF) >> 4; int loNibble = (digestBytes[n] & 0xF); outArray[2 * n] = (hiNibble > 9 ? (char) (hiNibble + 87) : (char) (hiNibble + 48)); outArray[2 * n + 1] = (loNibble > 9 ? (char) (loNibble + 87) : (char) (loNibble + 48)); } return new String(outArray); } } jenkins-winstone-0.9.10-jenkins-47/src/java/winstone/auth/RetryRequestParams.java0000644000175000017500000000777312200024521030455 0ustar jamespagejamespage/* * Copyright 2003-2006 Rick Knowles * Distributed under the terms of either: * - the common development and distribution license (CDDL), v1.0; or * - the GNU Lesser General Public License, v2.1 or later */ package winstone.auth; import java.io.IOException; import java.io.InputStream; import java.util.Collections; import java.util.Enumeration; import java.util.HashMap; import java.util.Locale; import java.util.Map; import java.util.Vector; import javax.servlet.ServletRequest; import javax.servlet.http.HttpServletRequest; /** * This is used by the ACL filter to allow a retry by using a key lookup * on old request. It's only used when retrying an old request that was blocked * by the ACL filter. * * @author Rick Knowles * @version $Id: RetryRequestParams.java,v 1.2 2007/06/01 15:59:53 rickknowles Exp $ */ public class RetryRequestParams implements java.io.Serializable { private String method; private String scheme; private String contextPath; private String servletPath; private String pathInfo; private String queryString; private String protocol; private int contentLength; private String contentType; private String encoding; private Map headers; private Vector locales; private Locale locale; private byte[] bodyContent; /** * Constructor - this populates the wrapper from the object in session */ public RetryRequestParams(ServletRequest request) throws IOException { this.protocol = request.getProtocol(); this.locales = new Vector(Collections.list(request.getLocales())); this.locale = request.getLocale(); this.contentLength = request.getContentLength(); this.contentType = request.getContentType(); this.encoding = request.getCharacterEncoding(); this.headers = new HashMap(); if (request instanceof HttpServletRequest) { HttpServletRequest httpRequest = (HttpServletRequest) request; this.method = httpRequest.getMethod(); this.contextPath = httpRequest.getContextPath(); this.servletPath = httpRequest.getServletPath(); this.pathInfo = httpRequest.getPathInfo(); this.queryString = httpRequest.getQueryString(); for (Enumeration names = httpRequest.getHeaderNames(); names.hasMoreElements();) { String name = (String) names.nextElement(); headers.put(name.toLowerCase(), new Vector(Collections.list(httpRequest.getHeaders(name)))); } } if (((this.method == null) || this.method.equalsIgnoreCase("POST")) && (this.contentLength != -1)) { InputStream inData = request.getInputStream(); this.bodyContent = new byte[this.contentLength]; int readCount = 0; int read; while ((read = inData.read(this.bodyContent, readCount, this.contentLength - readCount)) >= 0) { readCount += read; } inData.close(); } } public byte[] getBodyContent() { return bodyContent; } public int getContentLength() { return contentLength; } public String getContentType() { return contentType; } public String getEncoding() { return encoding; } public Map getHeaders() { return headers; } public Locale getLocale() { return locale; } public Vector getLocales() { return locales; } public String getMethod() { return method; } public String getPathInfo() { return pathInfo; } public String getProtocol() { return protocol; } public String getQueryString() { return queryString; } public String getScheme() { return scheme; } public String getServletPath() { return servletPath; } public String getContextPath() { return contextPath; } } jenkins-winstone-0.9.10-jenkins-47/src/java/winstone/auth/BaseAuthenticationHandler.java0000644000175000017500000001451012200024521031666 0ustar jamespagejamespage/* * Copyright 2003-2006 Rick Knowles * Distributed under the terms of either: * - the common development and distribution license (CDDL), v1.0; or * - the GNU Lesser General Public License, v2.1 or later */ package winstone.auth; import java.io.IOException; import java.util.List; import java.util.Set; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.w3c.dom.Node; import winstone.AuthenticationHandler; import winstone.AuthenticationRealm; import winstone.Logger; import winstone.WebAppConfiguration; import winstone.WinstoneResourceBundle; /** * Base class for managers of authentication within Winstone. This class also * acts as a factory, loading the appropriate subclass for the requested auth * type. * * @author mailto: Rick Knowles * @version $Id: BaseAuthenticationHandler.java,v 1.6 2006/02/28 07:32:47 rickknowles Exp $ */ public abstract class BaseAuthenticationHandler implements AuthenticationHandler { static final String ELEM_REALM_NAME = "realm-name"; protected SecurityConstraint constraints[]; protected AuthenticationRealm realm; protected String realmName; public final static WinstoneResourceBundle AUTH_RESOURCES = new WinstoneResourceBundle("winstone.auth.LocalStrings"); /** * Factory method - this parses the web.xml nodes and builds the correct * subclass for handling that auth type. */ protected BaseAuthenticationHandler(Node loginConfigNode, List constraintNodes, Set rolesAllowed, AuthenticationRealm realm) { this.realm = realm; for (int m = 0; m < loginConfigNode.getChildNodes().getLength(); m++) { Node loginElm = loginConfigNode.getChildNodes().item(m); if (loginElm.getNodeType() != Node.ELEMENT_NODE) continue; else if (loginElm.getNodeName().equals(ELEM_REALM_NAME)) realmName = WebAppConfiguration.getTextFromNode(loginElm); } // Build security constraints this.constraints = new SecurityConstraint[constraintNodes.size()]; for (int n = 0; n < constraints.length; n++) this.constraints[n] = new SecurityConstraint((Node) constraintNodes .get(n), rolesAllowed, n); } /** * Evaluates any authentication constraints, intercepting if auth is * required. The relevant authentication handler subclass's logic is used to * actually authenticate. * * @return A boolean indicating whether to continue after this request */ public boolean processAuthentication(ServletRequest inRequest, ServletResponse inResponse, String pathRequested) throws IOException, ServletException { Logger.log(Logger.FULL_DEBUG, AUTH_RESOURCES, "BaseAuthenticationHandler.StartAuthCheck"); HttpServletRequest request = (HttpServletRequest) inRequest; HttpServletResponse response = (HttpServletResponse) inResponse; // Give previous attempts a chance to be validated if (!validatePossibleAuthenticationResponse(request, response, pathRequested)) { return false; } else { return doRoleCheck(request, response, pathRequested); } } protected boolean doRoleCheck(HttpServletRequest request, HttpServletResponse response, String pathRequested) throws IOException, ServletException { // Loop through constraints boolean foundApplicable = false; for (int n = 0; (n < this.constraints.length) && !foundApplicable; n++) { Logger.log(Logger.FULL_DEBUG, AUTH_RESOURCES, "BaseAuthenticationHandler.EvalConstraint", this.constraints[n].getName()); // Find one that applies, then if (this.constraints[n].isApplicable(pathRequested, request.getMethod())) { Logger.log(Logger.FULL_DEBUG, AUTH_RESOURCES, "BaseAuthenticationHandler.ApplicableConstraint", this.constraints[n].getName()); foundApplicable = true; if (this.constraints[n].needsSSL() && !request.isSecure()) { Logger.log(Logger.DEBUG, AUTH_RESOURCES, "BaseAuthenticationHandler.ConstraintNeedsSSL", this.constraints[n].getName()); response.sendError(HttpServletResponse.SC_FORBIDDEN, AUTH_RESOURCES.getString("BaseAuthenticationHandler.ConstraintNeedsSSL", this.constraints[n].getName())); return false; } else if (!this.constraints[n].isAllowed(request)) { // Logger.log(Logger.FULL_DEBUG, "Not allowed - requesting auth"); requestAuthentication(request, response, pathRequested); return false; } else { // Logger.log(Logger.FULL_DEBUG, "Allowed - authorization accepted"); // Ensure that secured resources are not cached setNoCache(response); } } } // If we made it this far without a check being run, there must be none applicable Logger.log(Logger.FULL_DEBUG, AUTH_RESOURCES, "BaseAuthenticationHandler.PassedAuthCheck"); return true; } protected void setNoCache(HttpServletResponse response) { response.setHeader("Pragma", "No-cache"); response.setHeader("Cache-Control", "No-cache"); response.setDateHeader("Expires", 1); } /** * The actual auth request implementation. */ protected abstract void requestAuthentication(HttpServletRequest request, HttpServletResponse response, String pathRequested) throws IOException, ServletException; /** * Handling the (possible) response */ protected abstract boolean validatePossibleAuthenticationResponse( HttpServletRequest request, HttpServletResponse response, String pathRequested) throws ServletException, IOException; } jenkins-winstone-0.9.10-jenkins-47/src/java/winstone/auth/ClientcertAuthenticationHandler.java0000644000175000017500000000766012200024521033120 0ustar jamespagejamespage/* * Copyright 2003-2006 Rick Knowles * Distributed under the terms of either: * - the common development and distribution license (CDDL), v1.0; or * - the GNU Lesser General Public License, v2.1 or later */ package winstone.auth; import java.io.IOException; import java.security.cert.X509Certificate; import java.util.List; import java.util.Set; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequestWrapper; import javax.servlet.http.HttpServletResponse; import org.w3c.dom.Node; import winstone.AuthenticationPrincipal; import winstone.AuthenticationRealm; import winstone.Logger; import winstone.WinstoneRequest; /** * @author Rick Knowles * @version $Id: ClientcertAuthenticationHandler.java,v 1.3 2006/02/28 07:32:47 rickknowles Exp $ */ public class ClientcertAuthenticationHandler extends BaseAuthenticationHandler { public ClientcertAuthenticationHandler(Node loginConfigNode, List constraintNodes, Set rolesAllowed, AuthenticationRealm realm) { super(loginConfigNode, constraintNodes, rolesAllowed, realm); Logger.log(Logger.DEBUG, AUTH_RESOURCES, "ClientcertAuthenticationHandler.Initialised", realmName); } /** * Call this once we know that we need to authenticate */ protected void requestAuthentication(HttpServletRequest request, HttpServletResponse response, String pathRequested) throws IOException { // Return unauthorized, and set the realm name response.sendError(HttpServletResponse.SC_UNAUTHORIZED, AUTH_RESOURCES.getString("ClientcertAuthenticationHandler.UnauthorizedMessage")); } /** * Handling the (possible) response */ protected boolean validatePossibleAuthenticationResponse( HttpServletRequest request, HttpServletResponse response, String pathRequested) throws IOException { // Check for certificates in the request attributes X509Certificate certificateArray[] = (X509Certificate[]) request .getAttribute("javax.servlet.request.X509Certificate"); if ((certificateArray != null) && (certificateArray.length > 0)) { boolean failed = false; for (X509Certificate aCertificateArray : certificateArray) try { aCertificateArray.checkValidity(); } catch (Throwable err) { failed = true; } if (!failed) { AuthenticationPrincipal principal = this.realm .retrieveUser(certificateArray[0].getSubjectDN() .getName()); if (principal != null) { principal.setAuthType(HttpServletRequest.CLIENT_CERT_AUTH); if (request instanceof WinstoneRequest) ((WinstoneRequest) request).setRemoteUser(principal); else if (request instanceof HttpServletRequestWrapper) { HttpServletRequestWrapper wrapper = (HttpServletRequestWrapper) request; if (wrapper.getRequest() instanceof WinstoneRequest) ((WinstoneRequest) wrapper.getRequest()) .setRemoteUser(principal); else Logger.log(Logger.WARNING, AUTH_RESOURCES, "ClientCertAuthenticationHandler.CantSetUser", wrapper.getRequest().getClass().getName()); } else Logger.log(Logger.WARNING, AUTH_RESOURCES, "ClientCertAuthenticationHandler.CantSetUser", request.getClass().getName()); } } } return true; } } jenkins-winstone-0.9.10-jenkins-47/src/java/winstone/auth/RetryRequestWrapper.java0000644000175000017500000003005212200024521030634 0ustar jamespagejamespage/* * Copyright 2003-2006 Rick Knowles * Distributed under the terms of either: * - the common development and distribution license (CDDL), v1.0; or * - the GNU Lesser General Public License, v2.1 or later */ package winstone.auth; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.UnsupportedEncodingException; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.Collections; import java.util.Enumeration; import java.util.HashMap; import java.util.Hashtable; import java.util.Locale; import java.util.Map; import java.util.TimeZone; import java.util.Vector; import javax.servlet.ServletInputStream; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequestWrapper; import javax.servlet.http.HttpUtils; import winstone.Launcher; import winstone.Logger; import winstone.SizeRestrictedHashMap; import winstone.SizeRestrictedHashtable; import winstone.WinstoneException; import winstone.WinstoneInputStream; import winstone.WinstoneRequest; /** * This is used by the ACL filter to allow a retry by using a key lookup * on old request. It's only used when retrying an old request that was blocked * by the ACL filter. * * @author Rick Knowles * @version $Id: RetryRequestWrapper.java,v 1.3 2007/02/26 00:28:05 rickknowles Exp $ */ public class RetryRequestWrapper extends HttpServletRequestWrapper { protected static final DateFormat headerDF = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss z", Locale.US); static { headerDF.setTimeZone(TimeZone.getTimeZone("GMT")); } private final static String METHOD_HEAD = "GET"; private final static String METHOD_GET = "GET"; private final static String METHOD_POST = "POST"; private final static String POST_PARAMETERS = "application/x-www-form-urlencoded"; private RetryRequestParams oldRequest; // PARAMETER/BODY RELATED FUNCTIONS private String encoding; private Map parsedParams; private ServletInputStream inData; /** * Constructor - this populates the wrapper from the object in session */ public RetryRequestWrapper(HttpServletRequest request, RetryRequestParams oldRequest) { super(request); this.oldRequest = oldRequest; this.encoding = this.oldRequest.getEncoding(); } private boolean hasBeenForwarded() { return (super.getAttribute("javax.servlet.forward.request_uri") != null); } public String getScheme() { if (hasBeenForwarded()) { return super.getScheme(); } else { return this.oldRequest.getScheme(); } } public String getMethod() { if (hasBeenForwarded()) { return super.getMethod(); } else { return this.oldRequest.getMethod(); } } public String getContextPath() { if (hasBeenForwarded()) { return super.getContextPath(); } else { return this.oldRequest.getContextPath(); } } public String getServletPath() { if (hasBeenForwarded()) { return super.getServletPath(); } else { return this.oldRequest.getServletPath(); } } public String getPathInfo() { if (hasBeenForwarded()) { return super.getPathInfo(); } else { return this.oldRequest.getPathInfo(); } } public String getQueryString() { if (hasBeenForwarded()) { return super.getQueryString(); } else { return this.oldRequest.getQueryString(); } } public String getRequestURI() { if (hasBeenForwarded()) { return super.getRequestURI(); } else { String contextPath = this.oldRequest.getContextPath(); String servletPath = this.oldRequest.getServletPath(); String pathInfo = this.oldRequest.getPathInfo(); String queryString = this.oldRequest.getQueryString(); return contextPath + servletPath + ((pathInfo == null) ? "" : pathInfo) + ((queryString == null) ? "" : ("?" + queryString)); } } public String getCharacterEncoding() { if (hasBeenForwarded()) { return super.getCharacterEncoding(); } else { return this.oldRequest.getEncoding(); } } public void setCharacterEncoding(String encoding) throws UnsupportedEncodingException { if (hasBeenForwarded()) { super.setCharacterEncoding(encoding); } else { this.encoding = encoding; } } public int getContentLength() { if (hasBeenForwarded()) { return super.getContentLength(); } else { return this.oldRequest.getContentLength(); } } public String getContentType() { if (hasBeenForwarded()) { return super.getContentType(); } else { return this.oldRequest.getContentType(); } } public Locale getLocale() { if (hasBeenForwarded()) { return super.getLocale(); } else { return this.oldRequest.getLocale(); } } public Enumeration getLocales() { if (hasBeenForwarded()) { return super.getLocales(); } else { return this.oldRequest.getLocales().elements(); } } // ------------------------------------------------------------------- // HEADER RELATED FUNCTIONS public long getDateHeader(String name) { if (hasBeenForwarded()) { return super.getDateHeader(name); } else { String dateHeader = getHeader(name); if (dateHeader == null) { return -1; } else { try { synchronized (headerDF) { return headerDF.parse(dateHeader).getTime(); } } catch (java.text.ParseException err) { throw new IllegalArgumentException("Illegal date format: " + dateHeader); } } } } public int getIntHeader(String name) { if (hasBeenForwarded()) { return super.getIntHeader(name); } else { String header = getHeader(name); return header == null ? -1 : Integer.parseInt(header); } } public String getHeader(String name) { if (hasBeenForwarded()) { return super.getHeader(name); } else { Enumeration e = getHeaders(name); return (e != null) && e.hasMoreElements() ? (String) e.nextElement() : null; } } public Enumeration getHeaderNames() { if (hasBeenForwarded()) { return super.getHeaderNames(); } else { return Collections.enumeration(this.oldRequest.getHeaders().keySet()); } } public Enumeration getHeaders(String name) { if (hasBeenForwarded()) { return super.getHeaders(name); } else { Vector result = (Vector) this.oldRequest.getHeaders().get(name.toLowerCase()); return result == null ? null : result.elements(); } } public String getParameter(String name) { if (hasBeenForwarded()) { return super.getParameter(name); } else { parseRequestParameters(); Object param = this.parsedParams.get(name); if (param == null) { return null; } else if (param instanceof String) { return (String) param; } else if (param instanceof String[]) { return ((String[]) param)[0]; } else { return param.toString(); } } } public Enumeration getParameterNames() { if (hasBeenForwarded()) { return super.getParameterNames(); } else { parseRequestParameters(); return Collections.enumeration(this.parsedParams.keySet()); } } public String[] getParameterValues(String name) { if (hasBeenForwarded()) { return super.getParameterValues(name); } else { parseRequestParameters(); Object param = this.parsedParams.get(name); if (param == null) { return null; } else if (param instanceof String) { return new String[] {(String) param}; } else if (param instanceof String[]) { return (String[]) param; } else { throw new WinstoneException(Launcher.RESOURCES.getString( "WinstoneRequest.UnknownParameterType", name + " - " + param.getClass())); } } } public Map getParameterMap() { if (hasBeenForwarded()) { return super.getParameterMap(); } else { Hashtable paramMap = new SizeRestrictedHashtable(HttpUtils.MAX_PARAMETER_COUNT); for (Enumeration names = this.getParameterNames(); names.hasMoreElements();) { String name = (String) names.nextElement(); paramMap.put(name, getParameterValues(name)); } return paramMap; } } public BufferedReader getReader() throws IOException { if (hasBeenForwarded()) { return super.getReader(); } else if (getCharacterEncoding() != null) { return new BufferedReader(new InputStreamReader(getInputStream(), this.encoding)); } else { return new BufferedReader(new InputStreamReader(getInputStream())); } } public ServletInputStream getInputStream() throws IOException { if (hasBeenForwarded()) { return super.getInputStream(); } else if (this.parsedParams != null) { Logger.log(Logger.WARNING, Launcher.RESOURCES, "WinstoneRequest.BothMethods"); } if (this.inData == null) { this.inData = new WinstoneInputStream(this.oldRequest.getBodyContent()); } return this.inData; } // ------------------------------------------------------------------- /** * This takes the parameters in the body of the request and puts them into * the parameters map. */ private void parseRequestParameters() { if (inData != null) { Logger.log(Logger.WARNING, Launcher.RESOURCES, "WinstoneRequest.BothMethods"); } if (this.parsedParams == null) { String contentType = this.oldRequest.getContentType(); String queryString = this.oldRequest.getQueryString(); String method = this.oldRequest.getMethod(); Map workingParameters = new SizeRestrictedHashMap(HttpUtils.MAX_PARAMETER_COUNT); try { // Parse query string from request if ((method.equals(METHOD_GET) || method.equals(METHOD_HEAD) || method.equals(METHOD_POST)) && (queryString != null)) { WinstoneRequest.extractParameters(queryString, this.encoding, workingParameters, false); } if (method.equals(METHOD_POST) && (contentType != null) && (contentType.equals(POST_PARAMETERS) || contentType.startsWith(POST_PARAMETERS + ";"))) { // Parse params String paramLine = (this.encoding == null ? new String(this.oldRequest.getBodyContent()) : new String(this.oldRequest.getBodyContent(), this.encoding)); WinstoneRequest.extractParameters(paramLine.trim(), this.encoding, workingParameters, false); } this.parsedParams = workingParameters; } catch (UnsupportedEncodingException err) { Logger.log(Logger.ERROR, Launcher.RESOURCES, "WinstoneRequest.ErrorBodyParameters", err); this.parsedParams = null; } } } } jenkins-winstone-0.9.10-jenkins-47/src/java/winstone/auth/LocalStrings.properties0000644000175000017500000000370512200024521030501 0ustar jamespagejamespageSecurityConstraint.DefaultName=Security Constraint #[#0] SecurityConstraint.Failed=Failed security constraint: [#0] SecurityConstraint.Passed=Passed security constraint: [#0] role: [#1] BaseAuthenticationHandler.StartAuthCheck=Starting authentication check BaseAuthenticationHandler.PassedAuthCheck=Passed authentication check BaseAuthenticationHandler.EvalConstraint=Evaluating security constraint: [#0] BaseAuthenticationHandler.ApplicableConstraint=Found applicable security constraint: [#0] BaseAuthenticationHandler.ConstraintNeedsSSL=Security constraint requires SSL (failed): [#0] BasicAuthenticationHandler.UnauthorizedMessage=This content can only be viewed by authorized users. BasicAuthenticationHandler.Initialised=BasicAuthenticationHandler initialised for realm: [#0] BasicAuthenticationHandler.CantSetUser=Request type invalid - can't set authenticated user in request class: [#0] FormAuthenticationHandler.NoCachedRequest=No cached request - redirecting to the login page. FormAuthenticationHandler.Initialised=FormAuthenticationHandler initialised for realm: [#0] FormAuthenticationHandler.CantSetUser=Request type invalid - can't set authenticated user in request class: [#0] FormAuthenticationHandler.GoToLoginPage=Forwarding to the login page FormAuthenticationHandler.GotUserFromSession=Got authenticated user from session ClientcertAuthenticationHandler.UnauthorizedMessage=This content can only be viewed by authorized users. ClientcertAuthenticationHandler.Initialised=ClientcertAuthenticationHandler initialised for realm: [#0] ClientcertAuthenticationHandler.CantSetUser=Request type invalid - can't set authenticated user in request class: [#0] DigestAuthenticationHandler.UnauthorizedMessage=This content can only be viewed by authorized users. DigestAuthenticationHandler.Initialised=DigestAuthenticationHandler initialised for realm: [#0] DigestAuthenticationHandler.CantSetUser=Request type invalid - can't set authenticated user in request class: [#0] jenkins-winstone-0.9.10-jenkins-47/src/java/winstone/StaticResourceServlet.java0000644000175000017500000003676512200024521030201 0ustar jamespagejamespage/* * Copyright 2003-2006 Rick Knowles * Distributed under the terms of either: * - the common development and distribution license (CDDL), v1.0; or * - the GNU Lesser General Public License, v2.1 or later */ package winstone; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.StringWriter; import java.io.Writer; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Arrays; import java.util.Date; import java.util.Iterator; import java.util.List; import java.util.StringTokenizer; import javax.servlet.ServletConfig; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; /** * Servlet to handle static resources. Simply finds and sends them, or * dispatches to the error servlet. * * @author Rick Knowles * @version $Id: StaticResourceServlet.java,v 1.17 2004/12/31 07:21:00 * rickknowles Exp $ */ public class StaticResourceServlet extends HttpServlet { // final String JSP_FILE = "org.apache.catalina.jsp_file"; final static String FORWARD_SERVLET_PATH = "javax.servlet.forward.servlet_path"; final static String INCLUDE_SERVLET_PATH = "javax.servlet.include.servlet_path"; final static String CACHED_RESOURCE_DATE_HEADER = "If-Modified-Since"; final static String LAST_MODIFIED_DATE_HEADER = "Last-Modified"; final static String RANGE_HEADER = "Range"; final static String ACCEPT_RANGES_HEADER = "Accept-Ranges"; final static String CONTENT_RANGE_HEADER = "Content-Range"; final static String RESOURCE_FILE = "winstone.LocalStrings"; private DateFormat sdfFileDate = new SimpleDateFormat("dd-MM-yyyy HH:mm"); private File webRoot; private String prefix; private boolean directoryList; public void init(ServletConfig config) throws ServletException { super.init(config); this.webRoot = new File(config.getInitParameter("webRoot")); this.prefix = config.getInitParameter("prefix"); String dirList = config.getInitParameter("directoryList"); this.directoryList = (dirList == null) || dirList.equalsIgnoreCase("true") || dirList.equalsIgnoreCase("yes"); } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { boolean isInclude = (request.getAttribute(INCLUDE_SERVLET_PATH) != null); boolean isForward = (request.getAttribute(FORWARD_SERVLET_PATH) != null); String path; if (isInclude) path = (String) request.getAttribute(INCLUDE_SERVLET_PATH); else { path = request.getServletPath(); } // URL decode path path = WinstoneRequest.decodeURLToken(path); long cachedResDate = request.getDateHeader(CACHED_RESOURCE_DATE_HEADER); Logger.log(Logger.DEBUG, Launcher.RESOURCES, "StaticResourceServlet.PathRequested", getServletConfig().getServletName(), path); // Check for the resource File res = path.equals("") ? this.webRoot : new File( this.webRoot, path); // Send a 404 if not found if (!res.exists()) response.sendError(HttpServletResponse.SC_NOT_FOUND, Launcher.RESOURCES .getString("StaticResourceServlet.PathNotFound", path)); // Check we are below the webroot else if (!isDescendant(this.webRoot, res, this.webRoot)) { Logger.log(Logger.FULL_DEBUG, Launcher.RESOURCES, "StaticResourceServlet.OutsideWebroot", res.getCanonicalPath(), this.webRoot.toString()); response.sendError(HttpServletResponse.SC_FORBIDDEN, Launcher.RESOURCES .getString("StaticResourceServlet.PathInvalid", path)); } // Check we are not below the web-inf else if (!isInclude && !isForward && isDescendant(new File(this.webRoot, "WEB-INF"), res, this.webRoot)) response.sendError(HttpServletResponse.SC_NOT_FOUND, Launcher.RESOURCES .getString("StaticResourceServlet.PathInvalid", path)); // Check we are not below the meta-inf else if (!isInclude && !isForward && isDescendant(new File(this.webRoot, "META-INF"), res, this.webRoot)) response.sendError(HttpServletResponse.SC_NOT_FOUND, Launcher.RESOURCES .getString("StaticResourceServlet.PathInvalid", path)); // check for the directory case else if (res.isDirectory()) { if (path.endsWith("/")) { // Try to match each of the welcome files // String matchedWelcome = matchWelcomeFiles(path, res); // if (matchedWelcome != null) // response.sendRedirect(this.prefix + path + matchedWelcome); // else if (this.directoryList) generateDirectoryList(request, response, path); else response.sendError(HttpServletResponse.SC_FORBIDDEN, Launcher.RESOURCES.getString("StaticResourceServlet.AccessDenied")); } else response.sendRedirect(this.prefix + path + "/"); } // Send a 304 if not modified else if (!isInclude && (cachedResDate != -1) && (cachedResDate < (System.currentTimeMillis() / 1000L * 1000L)) && (cachedResDate >= (res.lastModified() / 1000L * 1000L))) { String mimeType = getServletContext().getMimeType( res.getName().toLowerCase()); if (mimeType != null) response.setContentType(mimeType); response.setStatus(HttpServletResponse.SC_NOT_MODIFIED); response.setContentLength(0); response.flushBuffer(); } // Write out the resource if not range or is included else if ((request.getHeader(RANGE_HEADER) == null) || isInclude) { String mimeType = getServletContext().getMimeType( res.getName().toLowerCase()); if (mimeType != null) response.setContentType(mimeType); InputStream resStream = new FileInputStream(res); response.setStatus(HttpServletResponse.SC_OK); response.setContentLength((int) res.length()); // response.addHeader(ACCEPT_RANGES_HEADER, "bytes"); response.addDateHeader(LAST_MODIFIED_DATE_HEADER, res.lastModified()); OutputStream out = null; Writer outWriter = null; try { out = response.getOutputStream(); } catch (IllegalStateException err) { outWriter = response.getWriter(); } catch (IllegalArgumentException err) { outWriter = response.getWriter(); } byte buffer[] = new byte[4096]; int read = resStream.read(buffer); while (read > 0) { if (out != null) { out.write(buffer, 0, read); } else { outWriter.write(new String(buffer, 0, read, response.getCharacterEncoding())); } read = resStream.read(buffer); } resStream.close(); } else if (request.getHeader(RANGE_HEADER).startsWith("bytes=")) { String mimeType = getServletContext().getMimeType( res.getName().toLowerCase()); if (mimeType != null) response.setContentType(mimeType); InputStream resStream = new FileInputStream(res); List ranges = new ArrayList(); StringTokenizer st = new StringTokenizer(request.getHeader( RANGE_HEADER).substring(6).trim(), ",", false); int totalSent = 0; String rangeText = ""; while (st.hasMoreTokens()) { String rangeBlock = st.nextToken(); int start = 0; int end = (int) res.length(); int delim = rangeBlock.indexOf('-'); if (delim != 0) start = Integer.parseInt(rangeBlock.substring(0, delim) .trim()); if (delim != rangeBlock.length() - 1) end = Integer.parseInt(rangeBlock.substring(delim + 1) .trim()); totalSent += (end - start); rangeText += "," + start + "-" + end; ranges.add(start + "-" + end); } response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT); response.addHeader(CONTENT_RANGE_HEADER, "bytes " + rangeText.substring(1) + "/" + res.length()); response.setContentLength(totalSent); response.addHeader(ACCEPT_RANGES_HEADER, "bytes"); response.addDateHeader(LAST_MODIFIED_DATE_HEADER, res .lastModified()); OutputStream out = response.getOutputStream(); int bytesRead = 0; for (Object range : ranges) { String rangeBlock = (String) range; int delim = rangeBlock.indexOf('-'); int start = Integer.parseInt(rangeBlock.substring(0, delim)); int end = Integer.parseInt(rangeBlock.substring(delim + 1)); int read = 0; while ((read != -1) && (bytesRead <= res.length())) { read = resStream.read(); if ((bytesRead >= start) && (bytesRead < end)) out.write(read); bytesRead++; } } resStream.close(); } else response .sendError(HttpServletResponse.SC_REQUESTED_RANGE_NOT_SATISFIABLE); } /** * Generate a list of the files in this directory */ private void generateDirectoryList(HttpServletRequest request, HttpServletResponse response, String path) throws IOException { // Get the file list File dir = path.equals("") ? this.webRoot : new File( this.webRoot, path); File children[] = dir.listFiles(); Arrays.sort(children); // Build row content StringWriter rowString = new StringWriter(); String oddColour = Launcher.RESOURCES .getString("StaticResourceServlet.DirectoryList.OddColour"); String evenColour = Launcher.RESOURCES .getString("StaticResourceServlet.DirectoryList.EvenColour"); String rowTextColour = Launcher.RESOURCES .getString("StaticResourceServlet.DirectoryList.RowTextColour"); String directoryLabel = Launcher.RESOURCES .getString("StaticResourceServlet.DirectoryList.DirectoryLabel"); String parentDirLabel = Launcher.RESOURCES .getString("StaticResourceServlet.DirectoryList.ParentDirectoryLabel"); String noDateLabel = Launcher.RESOURCES .getString("StaticResourceServlet.DirectoryList.NoDateLabel"); int rowCount = 0; // Write the parent dir row if (!path.equals("") && !path.equals("/")) { rowString.write(Launcher.RESOURCES.getString( "StaticResourceServlet.DirectoryList.Row", new String[] { rowTextColour, evenColour, parentDirLabel, "..", noDateLabel, directoryLabel })); rowCount++; } // Write the rows for each file for (File aChildren : children) { if (!aChildren.getName().equalsIgnoreCase("web-inf") && !aChildren.getName().equalsIgnoreCase("meta-inf")) { File file = aChildren; String date = noDateLabel; String size = directoryLabel; if (!file.isDirectory()) { size = "" + file.length(); synchronized (sdfFileDate) { date = sdfFileDate.format(new Date(file.lastModified())); } } rowString.write(Launcher.RESOURCES.getString( "StaticResourceServlet.DirectoryList.Row", new String[]{ rowTextColour, rowCount % 2 == 0 ? evenColour : oddColour, file.getName() + (file.isDirectory() ? "/" : ""), "./" + file.getName() + (file.isDirectory() ? "/" : ""), date, size})); rowCount++; } } // Build wrapper body String out = Launcher.RESOURCES.getString("StaticResourceServlet.DirectoryList.Body", new String[] { Launcher.RESOURCES.getString("StaticResourceServlet.DirectoryList.HeaderColour"), Launcher.RESOURCES.getString("StaticResourceServlet.DirectoryList.HeaderTextColour"), Launcher.RESOURCES.getString("StaticResourceServlet.DirectoryList.LabelColour"), Launcher.RESOURCES.getString("StaticResourceServlet.DirectoryList.LabelTextColour"), new Date() + "", Launcher.RESOURCES.getString("ServerVersion"), path.equals("") ? "/" : path, rowString.toString() }); response.setContentLength(out.getBytes().length); response.setContentType("text/html"); Writer w = response.getWriter(); w.write(out); w.close(); } public static boolean isDescendant(File parent, File child, File commonBase) throws IOException { if (child.equals(parent)) { return true; } else { // Start by checking canonicals String canonicalParent = parent.getAbsoluteFile().getCanonicalPath(); String canonicalChild = child.getAbsoluteFile().getCanonicalPath(); if (canonicalChild.startsWith(canonicalParent)) { return true; } // If canonicals don't match, we're dealing with symlinked files, so if we can // build a path from the parent to the child, String childOCValue = constructOurCanonicalVersion(child, commonBase); String parentOCValue = constructOurCanonicalVersion(parent, commonBase); return childOCValue.startsWith(parentOCValue); } } public static String constructOurCanonicalVersion(File current, File stopPoint) { int backOnes = 0; StringBuilder ourCanonicalVersion = new StringBuilder(); while ((current != null) && !current.equals(stopPoint)) { if (current.getName().equals("..")) { backOnes++; } else if (current.getName().equals(".")) { // skip - do nothing } else if (backOnes > 0) { backOnes--; } else { ourCanonicalVersion.insert(0, "/" + current.getName()); } current = current.getParentFile(); } return ourCanonicalVersion.toString(); } } jenkins-winstone-0.9.10-jenkins-47/src/java/winstone/WebAppConfiguration.java0000644000175000017500000024627112200024521027576 0ustar jamespagejamespage/* * Copyright 2003-2006 Rick Knowles * Distributed under the terms of either: * - the common development and distribution license (CDDL), v1.0; or * - the GNU Lesser General Public License, v2.1 or later */ package winstone; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.PrintWriter; import java.io.StringWriter; import java.lang.reflect.Constructor; import java.net.MalformedURLException; import java.net.URL; import java.net.URLClassLoader; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.Enumeration; import java.util.HashMap; import java.util.HashSet; import java.util.Hashtable; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Properties; import java.util.Set; import java.util.StringTokenizer; import javax.servlet.ServletContext; import javax.servlet.ServletContextAttributeEvent; import javax.servlet.ServletContextAttributeListener; import javax.servlet.ServletContextEvent; import javax.servlet.ServletContextListener; import javax.servlet.ServletException; import javax.servlet.ServletRequestAttributeListener; import javax.servlet.ServletRequestListener; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSessionActivationListener; import javax.servlet.http.HttpSessionAttributeListener; import javax.servlet.http.HttpSessionListener; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import winstone.classLoader.ReloadingClassLoader; import winstone.cmdline.Option; /** * Models the web.xml file's details ... basically just a bunch of configuration * details, plus the actual instances of mounted servlets. * * @author Rick Knowles * @version $Id: WebAppConfiguration.java,v 1.55 2007/11/13 01:42:47 rickknowles Exp $ */ public class WebAppConfiguration implements ServletContext, Comparator { // private static final String ELEM_DESCRIPTION = "description"; private static final String ELEM_DISPLAY_NAME = "display-name"; private static final String ELEM_SERVLET = "servlet"; private static final String ELEM_SERVLET_MAPPING = "servlet-mapping"; private static final String ELEM_SERVLET_NAME = "servlet-name"; private static final String ELEM_FILTER = "filter"; private static final String ELEM_FILTER_MAPPING = "filter-mapping"; private static final String ELEM_FILTER_NAME = "filter-name"; private static final String ELEM_DISPATCHER = "dispatcher"; private static final String ELEM_URL_PATTERN = "url-pattern"; private static final String ELEM_WELCOME_FILES = "welcome-file-list"; private static final String ELEM_WELCOME_FILE = "welcome-file"; private static final String ELEM_SESSION_CONFIG = "session-config"; private static final String ELEM_SESSION_TIMEOUT = "session-timeout"; private static final String ELEM_MIME_MAPPING = "mime-mapping"; private static final String ELEM_MIME_EXTENSION = "extension"; private static final String ELEM_MIME_TYPE = "mime-type"; private static final String ELEM_CONTEXT_PARAM = "context-param"; private static final String ELEM_PARAM_NAME = "param-name"; private static final String ELEM_PARAM_VALUE = "param-value"; private static final String ELEM_LISTENER = "listener"; private static final String ELEM_LISTENER_CLASS = "listener-class"; private static final String ELEM_DISTRIBUTABLE = "distributable"; private static final String ELEM_ERROR_PAGE = "error-page"; private static final String ELEM_EXCEPTION_TYPE = "exception-type"; private static final String ELEM_ERROR_CODE = "error-code"; private static final String ELEM_ERROR_LOCATION = "location"; private static final String ELEM_SECURITY_CONSTRAINT = "security-constraint"; private static final String ELEM_LOGIN_CONFIG = "login-config"; private static final String ELEM_SECURITY_ROLE = "security-role"; private static final String ELEM_ROLE_NAME = "role-name"; private static final String ELEM_ENV_ENTRY = "env-entry"; private static final String ELEM_LOCALE_ENC_MAP_LIST = "locale-encoding-mapping-list"; private static final String ELEM_LOCALE_ENC_MAPPING = "locale-encoding-mapping"; private static final String ELEM_LOCALE = "locale"; private static final String ELEM_ENCODING = "encoding"; private static final String ELEM_JSP_CONFIG = "jsp-config"; private static final String ELEM_JSP_PROPERTY_GROUP = "jsp-property-group"; private static final String DISPATCHER_REQUEST = "REQUEST"; private static final String DISPATCHER_FORWARD = "FORWARD"; private static final String DISPATCHER_INCLUDE = "INCLUDE"; private static final String DISPATCHER_ERROR = "ERROR"; private static final String JSP_SERVLET_NAME = "JspServlet"; private static final String JSP_SERVLET_MAPPING = "*.jsp"; private static final String JSPX_SERVLET_MAPPING = "*.jspx"; private static final String JSP_SERVLET_LOG_LEVEL = "WARNING"; private static final String INVOKER_SERVLET_NAME = "invoker"; private static final String INVOKER_SERVLET_CLASS = "winstone.invoker.InvokerServlet"; private static final String DEFAULT_SERVLET_NAME = "default"; private static final String DEFAULT_SERVLET_CLASS = "winstone.StaticResourceServlet"; private static final String RELOADING_CL_CLASS = "winstone.classLoader.ReloadingClassLoader"; private static final String WEBAPP_CL_CLASS = "winstone.classLoader.WebappClassLoader"; private static final String ERROR_SERVLET_NAME = "winstoneErrorServlet"; private static final String ERROR_SERVLET_CLASS = "winstone.ErrorServlet"; private static final String WEB_INF = "WEB-INF"; private static final String CLASSES = "classes/"; private static final String LIB = "lib"; static final String JSP_SERVLET_CLASS = "org.apache.jasper.servlet.JspServlet"; private HostConfiguration ownerHostConfig; private Cluster cluster; private String webRoot; private String prefix; private String contextName; private ClassLoader loader; private String displayName; private Map attributes; private Map initParameters; private Map sessions; private Map mimeTypes; private Map servletInstances; private Map filterInstances; private ServletContextAttributeListener contextAttributeListeners[]; private ServletContextListener contextListeners[]; private ServletRequestListener requestListeners[]; private ServletRequestAttributeListener requestAttributeListeners[]; private HttpSessionActivationListener sessionActivationListeners[]; private HttpSessionAttributeListener sessionAttributeListeners[]; private HttpSessionListener sessionListeners[]; private Throwable contextStartupError; private Map exactServletMatchMounts; private Mapping patternMatches[]; private Mapping filterPatternsRequest[]; private Mapping filterPatternsForward[]; private Mapping filterPatternsInclude[]; private Mapping filterPatternsError[]; private AuthenticationHandler authenticationHandler; private AuthenticationRealm authenticationRealm; private String welcomeFiles[]; /** * Session time out in the # of minutes. -1 for default, and 0 for never. */ private Integer sessionTimeout; private Class[] errorPagesByExceptionKeysSorted; private Map errorPagesByException; private Map errorPagesByCode; private Map localeEncodingMap; private String defaultServletName; private String errorServletName; private JNDIManager jndiManager; private AccessLogger accessLogger; private Map filterMatchCache; private boolean useSavedSessions; public static boolean booleanArg(Map args, String name, boolean defaultTrue) { String value = (String) args.get(name); if (defaultTrue) return (value == null) || (value.equalsIgnoreCase("true") || value.equalsIgnoreCase("yes")); else return (value != null) && (value.equalsIgnoreCase("true") || value.equalsIgnoreCase("yes")); } public static String stringArg(Map args, String name, String defaultValue) { return (String) (args.get(name) == null ? defaultValue : args.get(name)); } public static int intArg(Map args, String name, int defaultValue) { return Integer.parseInt(stringArg(args, name, "" + defaultValue)); } public static String getTextFromNode(Node node) { if (node == null) { return null; } Node child = node.getFirstChild(); if (child == null) { return ""; } String textNode = child.getNodeValue(); if (textNode == null) { return ""; } else { return textNode.trim(); } } /** * Constructor. This parses the xml and sets up for basic routing */ public WebAppConfiguration(HostConfiguration ownerHostConfig, Cluster cluster, String webRoot, String prefix, ObjectPool objectPool, Map startupArgs, Node elm, ClassLoader parentClassLoader, File parentClassPaths[], String contextName) { if (!prefix.equals("") && !prefix.startsWith("/")) { Logger.log(Logger.WARNING, Launcher.RESOURCES, "WebAppConfig.AddingLeadingSlash", prefix); prefix = "/" + prefix; } this.ownerHostConfig = ownerHostConfig; this.webRoot = webRoot; this.prefix = prefix; this.contextName = contextName; List localLoaderClassPathFiles = new ArrayList(); this.loader = buildWebAppClassLoader(startupArgs, parentClassLoader, webRoot, localLoaderClassPathFiles); // Build switch values boolean useJasper = Option.USE_JASPER.get(startupArgs,true); boolean useInvoker = Option.USE_INVOKER.get(startupArgs); boolean useJNDI = Option.USE_JNDI.get(startupArgs); this.useSavedSessions = Option.USE_SAVED_SESSIONS.get(startupArgs); this.sessionTimeout = Option.SESSION_TIMEOUT.get(startupArgs); // Check jasper is available - simple tests if (useJasper) { try { Class.forName("javax.servlet.jsp.JspFactory", true, parentClassLoader); Class.forName(JSP_SERVLET_CLASS, true, this.loader); } catch (Throwable err) { if (Option.USE_JASPER.get(startupArgs, false)) { Logger.log(Logger.WARNING, Launcher.RESOURCES, "WebAppConfig.JasperNotFound"); Logger.log(Logger.DEBUG, Launcher.RESOURCES, "WebAppConfig.JasperLoadException", err); } useJasper = false; } } if (useInvoker) { try { Class.forName(INVOKER_SERVLET_CLASS, false, this.loader); } catch (Throwable err) { Logger.log(Logger.WARNING, Launcher.RESOURCES, "WebAppConfig.InvokerNotFound"); useInvoker = false; } } this.attributes = new Hashtable(); this.initParameters = new HashMap(); this.sessions = new Hashtable(); this.servletInstances = new HashMap(); this.filterInstances = new HashMap(); this.filterMatchCache = new HashMap(); List contextAttributeListeners = new ArrayList(); List contextListeners = new ArrayList(); List requestListeners = new ArrayList(); List requestAttributeListeners = new ArrayList(); List sessionActivationListeners = new ArrayList(); List sessionAttributeListeners = new ArrayList(); List sessionListeners = new ArrayList(); this.errorPagesByException = new HashMap(); this.errorPagesByCode = new HashMap(); boolean distributable = false; this.exactServletMatchMounts = new Hashtable(); List localFolderPatterns = new ArrayList(); List localExtensionPatterns = new ArrayList(); List lfpRequest = new ArrayList(); List lfpForward = new ArrayList(); List lfpInclude = new ArrayList(); List lfpError = new ArrayList(); List localWelcomeFiles = new ArrayList(); List startupServlets = new ArrayList(); Set rolesAllowed = new HashSet(); List constraintNodes = new ArrayList(); List envEntryNodes = new ArrayList(); List localErrorPagesByExceptionList = new ArrayList(); Node loginConfigNode = null; // Add the class loader as an implicit context listener if it implements the interface addListenerInstance(this.loader, contextAttributeListeners, contextListeners, requestAttributeListeners, requestListeners, sessionActivationListeners, sessionAttributeListeners, sessionListeners); // init mimeTypes set this.mimeTypes = new Hashtable(); this.mimeTypes.putAll(loadBuiltinMimeTypes()); String[] typeList = new String[] { Option.MIME_TYPES.get(startupArgs) }; for (String allTypes : typeList) { if (allTypes == null) continue; StringTokenizer mappingST = new StringTokenizer(allTypes, ":", false); for (; mappingST.hasMoreTokens(); ) { String mapping = mappingST.nextToken(); int delimPos = mapping.indexOf('='); if (delimPos == -1) continue; String extension = mapping.substring(0, delimPos); String mimeType = mapping.substring(delimPos + 1); this.mimeTypes.put(extension.toLowerCase(), mimeType); } } this.localeEncodingMap = new HashMap(); String encodingMapSet = Launcher.RESOURCES.getString("WebAppConfig.EncodingMap"); StringTokenizer st = new StringTokenizer(encodingMapSet, ";"); for (; st.hasMoreTokens();) { String token = st.nextToken(); int delimPos = token.indexOf("="); if (delimPos == -1) continue; this.localeEncodingMap.put(token.substring(0, delimPos), token .substring(delimPos + 1)); } // init jsp mappings set List jspMappings = new ArrayList(); jspMappings.add(JSP_SERVLET_MAPPING); jspMappings.add(JSPX_SERVLET_MAPPING); // Add required context atttributes File tmpDir = new File(new File(new File(System.getProperty("java.io.tmpdir"), "winstone.tmp"), ownerHostConfig.getHostname()), contextName); tmpDir.mkdirs(); this.attributes.put("javax.servlet.context.tempdir", tmpDir); // Parse the web.xml file if (elm != null) { NodeList children = elm.getChildNodes(); for (int n = 0; n < children.getLength(); n++) { Node child = children.item(n); if (child.getNodeType() != Node.ELEMENT_NODE) continue; String nodeName = child.getNodeName(); if (nodeName.equals(ELEM_DISPLAY_NAME)) this.displayName = getTextFromNode(child); else if (nodeName.equals(ELEM_DISTRIBUTABLE)) distributable = true; else if (nodeName.equals(ELEM_SECURITY_CONSTRAINT)) constraintNodes.add(child); else if (nodeName.equals(ELEM_ENV_ENTRY)) envEntryNodes.add(child); else if (nodeName.equals(ELEM_LOGIN_CONFIG)) loginConfigNode = child; // Session config elements else if (nodeName.equals(ELEM_SESSION_CONFIG)) { for (int m = 0; m < child.getChildNodes().getLength(); m++) { Node timeoutElm = child.getChildNodes().item(m); if ((timeoutElm.getNodeType() == Node.ELEMENT_NODE) && (timeoutElm.getNodeName().equals(ELEM_SESSION_TIMEOUT))) { String timeoutStr = getTextFromNode(timeoutElm); if (!timeoutStr.equals("") && (this.sessionTimeout == -1)) { this.sessionTimeout = Integer.valueOf(timeoutStr); } } } } // Construct the security roles else if (child.getNodeName().equals(ELEM_SECURITY_ROLE)) { for (int m = 0; m < child.getChildNodes().getLength(); m++) { Node roleElm = child.getChildNodes().item(m); if ((roleElm.getNodeType() == Node.ELEMENT_NODE) && (roleElm.getNodeName() .equals(ELEM_ROLE_NAME))) rolesAllowed.add(getTextFromNode(roleElm)); } } // Construct the servlet instances else if (nodeName.equals(ELEM_SERVLET)) { ServletConfiguration instance = new ServletConfiguration( this, child); this.servletInstances.put(instance.getServletName(), instance); if (instance.getLoadOnStartup() >= 0) startupServlets.add(instance); } // Construct the servlet instances else if (nodeName.equals(ELEM_FILTER)) { FilterConfiguration instance = new FilterConfiguration( this, this.loader, child); this.filterInstances.put(instance.getFilterName(), instance); } // Construct the servlet instances else if (nodeName.equals(ELEM_LISTENER)) { String listenerClass = null; for (int m = 0; m < child.getChildNodes().getLength(); m++) { Node listenerElm = child.getChildNodes().item(m); if ((listenerElm.getNodeType() == Node.ELEMENT_NODE) && (listenerElm.getNodeName() .equals(ELEM_LISTENER_CLASS))) listenerClass = getTextFromNode(listenerElm); } if (listenerClass != null) try { Class listener = Class.forName(listenerClass, true, this.loader); Object listenerInstance = listener.newInstance(); addListenerInstance(listenerInstance, contextAttributeListeners, contextListeners, requestAttributeListeners, requestListeners, sessionActivationListeners, sessionAttributeListeners, sessionListeners); Logger.log(Logger.DEBUG, Launcher.RESOURCES, "WebAppConfig.AddListener", listenerClass); } catch (Throwable err) { Logger.log(Logger.WARNING, Launcher.RESOURCES, "WebAppConfig.InvalidListener", listenerClass); } } // Process the servlet mappings else if (nodeName.equals(ELEM_SERVLET_MAPPING)) { String name = null; List mappings = new ArrayList(); // Parse the element and extract NodeList mappingChildren = child.getChildNodes(); for (int k = 0; k < mappingChildren.getLength(); k++) { Node mapChild = mappingChildren.item(k); if (mapChild.getNodeType() != Node.ELEMENT_NODE) continue; String mapNodeName = mapChild.getNodeName(); if (mapNodeName.equals(ELEM_SERVLET_NAME)) { name = getTextFromNode(mapChild); } else if (mapNodeName.equals(ELEM_URL_PATTERN)) { mappings.add(getTextFromNode(mapChild)); } } for (Object mapping : mappings) { processMapping(name, (String) mapping, this.exactServletMatchMounts, localFolderPatterns, localExtensionPatterns); } } // Process the filter mappings else if (nodeName.equals(ELEM_FILTER_MAPPING)) { String filterName = null; List mappings = new ArrayList(); boolean onRequest = false; boolean onForward = false; boolean onInclude = false; boolean onError = false; // Parse the element and extract for (int k = 0; k < child.getChildNodes().getLength(); k++) { Node mapChild = child.getChildNodes().item(k); if (mapChild.getNodeType() != Node.ELEMENT_NODE) continue; String mapNodeName = mapChild.getNodeName(); if (mapNodeName.equals(ELEM_FILTER_NAME)) { filterName = getTextFromNode(mapChild); } else if (mapNodeName.equals(ELEM_SERVLET_NAME)) { mappings.add("srv:" + getTextFromNode(mapChild)); } else if (mapNodeName.equals(ELEM_URL_PATTERN)) { mappings.add("url:" + getTextFromNode(mapChild)); } else if (mapNodeName.equals(ELEM_DISPATCHER)) { String dispatcherValue = getTextFromNode(mapChild); if (dispatcherValue.equals(DISPATCHER_REQUEST)) onRequest = true; else if (dispatcherValue.equals(DISPATCHER_FORWARD)) onForward = true; else if (dispatcherValue.equals(DISPATCHER_INCLUDE)) onInclude = true; else if (dispatcherValue.equals(DISPATCHER_ERROR)) onError = true; } } if (!onRequest && !onInclude && !onForward && !onError) { onRequest = true; } if (mappings.isEmpty()) { throw new WinstoneException(Launcher.RESOURCES.getString( "WebAppConfig.BadFilterMapping", filterName)); } for (Object mapping1 : mappings) { String item = (String) mapping1; Mapping mapping; try { if (item.startsWith("srv:")) { mapping = Mapping.createFromLink(filterName, item.substring(4)); } else { mapping = Mapping.createFromURL(filterName, item.substring(4)); } if (onRequest) lfpRequest.add(mapping); if (onForward) lfpForward.add(mapping); if (onInclude) lfpInclude.add(mapping); if (onError) lfpError.add(mapping); } catch (WinstoneException err) { Logger.log(Logger.WARNING, Launcher.RESOURCES, "WebAppConfig.ErrorMapURL", err.getMessage()); } } } // Process the list of welcome files else if (nodeName.equals(ELEM_WELCOME_FILES)) { for (int m = 0; m < child.getChildNodes().getLength(); m++) { Node welcomeFile = child.getChildNodes().item(m); if ((welcomeFile.getNodeType() == Node.ELEMENT_NODE) && welcomeFile.getNodeName().equals(ELEM_WELCOME_FILE)) { String welcomeStr = getTextFromNode(welcomeFile); if (!welcomeStr.equals("")) { localWelcomeFiles.add(welcomeStr); } } } } // Process the error pages else if (nodeName.equals(ELEM_ERROR_PAGE)) { String code = null; String exception = null; String location = null; // Parse the element and extract for (int k = 0; k < child.getChildNodes().getLength(); k++) { Node errorChild = child.getChildNodes().item(k); if (errorChild.getNodeType() != Node.ELEMENT_NODE) continue; String errorChildName = errorChild.getNodeName(); if (errorChildName.equals(ELEM_ERROR_CODE)) code = getTextFromNode(errorChild); else if (errorChildName.equals(ELEM_EXCEPTION_TYPE)) exception = getTextFromNode(errorChild); else if (errorChildName.equals(ELEM_ERROR_LOCATION)) location = getTextFromNode(errorChild); } if ((code != null) && (location != null)) this.errorPagesByCode.put(code.trim(), location.trim()); if ((exception != null) && (location != null)) try { Class exceptionClass = Class.forName(exception .trim(), false, this.loader); localErrorPagesByExceptionList.add(exceptionClass); this.errorPagesByException.put(exceptionClass, location.trim()); } catch (ClassNotFoundException err) { Logger.log(Logger.ERROR, Launcher.RESOURCES, "WebAppConfig.ExceptionNotFound", exception); } } // Process the list of welcome files else if (nodeName.equals(ELEM_MIME_MAPPING)) { String extension = null; String mimeType = null; for (int m = 0; m < child.getChildNodes().getLength(); m++) { Node mimeTypeNode = child.getChildNodes().item(m); if (mimeTypeNode.getNodeType() != Node.ELEMENT_NODE) continue; else if (mimeTypeNode.getNodeName().equals( ELEM_MIME_EXTENSION)) extension = getTextFromNode(mimeTypeNode); else if (mimeTypeNode.getNodeName().equals( ELEM_MIME_TYPE)) mimeType = getTextFromNode(mimeTypeNode); } if ((extension != null) && (mimeType != null)) this.mimeTypes.put(extension.toLowerCase(), mimeType); else Logger.log(Logger.WARNING, Launcher.RESOURCES, "WebAppConfig.InvalidMimeMapping", extension, mimeType); } // Process the list of welcome files else if (nodeName.equals(ELEM_CONTEXT_PARAM)) { String name = null; String value = null; for (int m = 0; m < child.getChildNodes().getLength(); m++) { Node contextParamNode = child.getChildNodes().item(m); if (contextParamNode.getNodeType() != Node.ELEMENT_NODE) continue; else if (contextParamNode.getNodeName().equals( ELEM_PARAM_NAME)) name = getTextFromNode(contextParamNode); else if (contextParamNode.getNodeName().equals( ELEM_PARAM_VALUE)) value = getTextFromNode(contextParamNode); } if ((name != null) && (value != null)) this.initParameters.put(name, value); else Logger.log(Logger.WARNING, Launcher.RESOURCES, "WebAppConfig.InvalidInitParam", name, value); } // Process locale encoding mapping elements else if (nodeName.equals(ELEM_LOCALE_ENC_MAP_LIST)) { for (int m = 0; m < child.getChildNodes().getLength(); m++) { Node mappingNode = child.getChildNodes().item(m); if (mappingNode.getNodeType() != Node.ELEMENT_NODE) continue; else if (mappingNode.getNodeName().equals(ELEM_LOCALE_ENC_MAPPING)) { String localeName = ""; String encoding = ""; for (int l = 0; l < mappingNode.getChildNodes().getLength(); l++) { Node mappingChildNode = mappingNode.getChildNodes().item(l); if (mappingChildNode.getNodeType() != Node.ELEMENT_NODE) continue; else if (mappingChildNode.getNodeName().equals(ELEM_LOCALE)) localeName = getTextFromNode(mappingChildNode); else if (mappingChildNode.getNodeName().equals(ELEM_ENCODING)) encoding = getTextFromNode(mappingChildNode); } if (!encoding.equals("") && !localeName.equals("")) this.localeEncodingMap.put(localeName, encoding); } } } // Record the url mappings for jsp files if set else if (nodeName.equals(ELEM_JSP_CONFIG)) { for (int m = 0; m < child.getChildNodes().getLength(); m++) { Node propertyGroupNode = child.getChildNodes().item(m); if ((propertyGroupNode.getNodeType() == Node.ELEMENT_NODE) && propertyGroupNode.getNodeName().equals(ELEM_JSP_PROPERTY_GROUP)) { for (int l = 0; l < propertyGroupNode.getChildNodes().getLength(); l++) { Node urlPatternNode = propertyGroupNode.getChildNodes().item(l); if ((urlPatternNode.getNodeType() == Node.ELEMENT_NODE) && urlPatternNode.getNodeName().equals(ELEM_URL_PATTERN)) { String jm = getTextFromNode(urlPatternNode); if (!jm.equals("")) { jspMappings.add(jm); } } } } } } } } // If not distributable, remove the cluster reference if (!distributable && (cluster != null)) { Logger.log(Logger.INFO, Launcher.RESOURCES, "WebAppConfig.ClusterOffNotDistributable", this.contextName); } else { this.cluster = cluster; } // Build the login/security role instance if (!constraintNodes.isEmpty() && (loginConfigNode != null)) { String authMethod = null; for (int n = 0; n < loginConfigNode.getChildNodes().getLength(); n++) { if (loginConfigNode.getChildNodes().item(n).getNodeName().equals("auth-method")) { authMethod = getTextFromNode(loginConfigNode.getChildNodes().item(n)); } } // Load the appropriate auth class if (authMethod == null) { authMethod = "BASIC"; } else { authMethod = WinstoneResourceBundle.globalReplace(authMethod, "-", ""); } String authClassName = "winstone.auth." + authMethod.substring(0, 1).toUpperCase() + authMethod.substring(1).toLowerCase() + "AuthenticationHandler"; try { // Build the realm Class realmClass = Option.REALM_CLASS_NAME.get(startupArgs, AuthenticationRealm.class, parentClassLoader); Constructor realmConstr = realmClass.getConstructor( new Class[] {Set.class, Map.class }); this.authenticationRealm = (AuthenticationRealm) realmConstr.newInstance( rolesAllowed, startupArgs); // Build the authentication handler Class authClass = Class.forName(authClassName); Constructor authConstr = authClass .getConstructor(new Class[] { Node.class, List.class, Set.class, AuthenticationRealm.class }); this.authenticationHandler = (AuthenticationHandler) authConstr .newInstance(loginConfigNode, constraintNodes, rolesAllowed, authenticationRealm); } catch (Throwable err) { Logger.log(Logger.ERROR, Launcher.RESOURCES, "WebAppConfig.AuthError", new String[] { authClassName, "" }, err); } } else if (Option.REALM_CLASS_NAME.isIn(startupArgs)) { Logger.log(Logger.DEBUG, Launcher.RESOURCES, "WebAppConfig.NoWebXMLSecurityDefs"); } // Instantiate the JNDI manager if (useJNDI) { try { // Build the realm Class jndiMgrClass = Option.WEBAPP_JNDI_CLASSNAME.get(startupArgs, JNDIManager.class, parentClassLoader); Constructor jndiMgrConstr = jndiMgrClass.getConstructor(new Class[] { Map.class, List.class, ClassLoader.class }); this.jndiManager = (JNDIManager) jndiMgrConstr.newInstance(null, envEntryNodes, this.loader); if (this.jndiManager != null) this.jndiManager.setup(); } catch (Throwable err) { Logger.log(Logger.ERROR, Launcher.RESOURCES, "WebAppConfig.JNDIError", "", err); } } try { Class loggerClass = Option.ACCESS_LOGGER_CLASSNAME.get(startupArgs,AccessLogger.class,parentClassLoader); if (loggerClass!=null) { // Build the realm Constructor loggerConstr = loggerClass.getConstructor(new Class[] { WebAppConfiguration.class, Map.class }); this.accessLogger = (AccessLogger) loggerConstr.newInstance(this, startupArgs); } else { Logger.log(Logger.DEBUG, Launcher.RESOURCES, "WebAppConfig.LoggerDisabled"); } } catch (Throwable err) { Logger.log(Logger.ERROR, Launcher.RESOURCES, "WebAppConfig.LoggerError", "", err); } // Add the default index.html welcomeFile if none are supplied if (localWelcomeFiles.isEmpty()) { if (useJasper) { localWelcomeFiles.add("index.jsp"); } localWelcomeFiles.add("index.html"); } // Put the name filters after the url filters, then convert to string arrays this.filterPatternsRequest = (Mapping[]) lfpRequest.toArray(new Mapping[0]); this.filterPatternsForward = (Mapping[]) lfpForward.toArray(new Mapping[0]); this.filterPatternsInclude = (Mapping[]) lfpInclude.toArray(new Mapping[0]); this.filterPatternsError = (Mapping[]) lfpError.toArray(new Mapping[0]); if (this.filterPatternsRequest.length > 0) Arrays.sort(this.filterPatternsRequest, this.filterPatternsRequest[0]); if (this.filterPatternsForward.length > 0) Arrays.sort(this.filterPatternsForward, this.filterPatternsForward[0]); if (this.filterPatternsInclude.length > 0) Arrays.sort(this.filterPatternsInclude, this.filterPatternsInclude[0]); if (this.filterPatternsError.length > 0) Arrays.sort(this.filterPatternsError, this.filterPatternsError[0]); this.welcomeFiles = (String[]) localWelcomeFiles.toArray(new String[0]); this.errorPagesByExceptionKeysSorted = (Class[]) localErrorPagesByExceptionList .toArray(new Class[0]); Arrays.sort(this.errorPagesByExceptionKeysSorted, this); // Put the listeners into their arrays this.contextAttributeListeners = (ServletContextAttributeListener[]) contextAttributeListeners .toArray(new ServletContextAttributeListener[0]); this.contextListeners = (ServletContextListener[]) contextListeners .toArray(new ServletContextListener[0]); this.requestListeners = (ServletRequestListener[]) requestListeners .toArray(new ServletRequestListener[0]); this.requestAttributeListeners = (ServletRequestAttributeListener[]) requestAttributeListeners .toArray(new ServletRequestAttributeListener[0]); this.sessionActivationListeners = (HttpSessionActivationListener[]) sessionActivationListeners .toArray(new HttpSessionActivationListener[0]); this.sessionAttributeListeners = (HttpSessionAttributeListener[]) sessionAttributeListeners .toArray(new HttpSessionAttributeListener[0]); this.sessionListeners = (HttpSessionListener[]) sessionListeners .toArray(new HttpSessionListener[0]); // If we haven't explicitly mapped the default servlet, map it here if (this.defaultServletName == null) this.defaultServletName = DEFAULT_SERVLET_NAME; if (this.errorServletName == null) this.errorServletName = ERROR_SERVLET_NAME; // If we don't have an instance of the default servlet, mount the inbuilt one if (this.servletInstances.get(this.defaultServletName) == null) { boolean useDirLists = Option.DIRECTORY_LISTINGS.get(startupArgs); Map staticParams = new Hashtable(); staticParams.put("webRoot", webRoot); staticParams.put("prefix", this.prefix); staticParams.put("directoryList", "" + useDirLists); ServletConfiguration defaultServlet = new ServletConfiguration( this, this.defaultServletName, DEFAULT_SERVLET_CLASS, staticParams, 0); this.servletInstances.put(this.defaultServletName, defaultServlet); startupServlets.add(defaultServlet); } // If we don't have an instance of the default servlet, mount the inbuilt one if (this.servletInstances.get(this.errorServletName) == null) { ServletConfiguration errorServlet = new ServletConfiguration( this, this.errorServletName, ERROR_SERVLET_CLASS, new HashMap(), 0); this.servletInstances.put(this.errorServletName, errorServlet); startupServlets.add(errorServlet); } // Initialise jasper servlet if requested if (useJasper) { setAttribute("org.apache.catalina.classloader", this.loader); try { StringBuilder cp = new StringBuilder(); for (Object localLoaderClassPathFile : localLoaderClassPathFiles) { cp.append(((File) localLoaderClassPathFile).getCanonicalPath()).append( File.pathSeparatorChar); } for (File parentClassPath : parentClassPaths) { cp.append(parentClassPath.getCanonicalPath()).append( File.pathSeparatorChar); } setAttribute("org.apache.catalina.jsp_classpath", (cp.length() > 0 ? cp.substring(0, cp.length() - 1) : "")); } catch (IOException err) { Logger.log(Logger.ERROR, Launcher.RESOURCES, "WebAppConfig.ErrorSettingJSPPaths", err); } Map jspParams = new HashMap(); addJspServletParams(jspParams); ServletConfiguration sc = new ServletConfiguration(this, JSP_SERVLET_NAME, JSP_SERVLET_CLASS, jspParams, 3); this.servletInstances.put(JSP_SERVLET_NAME, sc); startupServlets.add(sc); for (Object jspMapping : jspMappings) { processMapping(JSP_SERVLET_NAME, (String) jspMapping, this.exactServletMatchMounts, localFolderPatterns, localExtensionPatterns); } } // Initialise invoker servlet if requested if (useInvoker) { // Get generic options String invokerPrefix = Option.INVOKER_PREFIX.get(startupArgs); Map invokerParams = new HashMap(); invokerParams.put("prefix", this.prefix); invokerParams.put("invokerPrefix", invokerPrefix); ServletConfiguration sc = new ServletConfiguration(this, INVOKER_SERVLET_NAME, INVOKER_SERVLET_CLASS, invokerParams, 3); this.servletInstances.put(INVOKER_SERVLET_NAME, sc); processMapping(INVOKER_SERVLET_NAME, invokerPrefix + Mapping.STAR, this.exactServletMatchMounts, localFolderPatterns, localExtensionPatterns); } // Sort the folder patterns so the longest paths are first localFolderPatterns.addAll(localExtensionPatterns); this.patternMatches = (Mapping[]) localFolderPatterns.toArray(new Mapping[0]); if (this.patternMatches.length > 0) Arrays.sort(this.patternMatches, this.patternMatches[0]); // Send init notifies try { for (ServletContextListener contextListener : this.contextListeners) { ClassLoader cl = Thread.currentThread().getContextClassLoader(); Thread.currentThread().setContextClassLoader(this.loader); contextListener.contextInitialized(new ServletContextEvent(this)); Thread.currentThread().setContextClassLoader(cl); } } catch (Throwable err) { Logger.log(Logger.ERROR, Launcher.RESOURCES, "WebAppConfig.ContextStartupError", this.contextName, err); this.contextStartupError = err; } if (this.contextStartupError == null) { // Load sessions if enabled if (this.useSavedSessions) { WinstoneSession.loadSessions(this); } // Initialise all the filters for (Object o : this.filterInstances.values()) { FilterConfiguration config = (FilterConfiguration) o; try { config.getFilter(); } catch (ServletException err) { Logger.log(Logger.ERROR, Launcher.RESOURCES, "WebAppConfig.FilterStartupError", config.getFilterName(), err); } } // Initialise load on startup servlets Object autoStarters[] = startupServlets.toArray(); Arrays.sort(autoStarters); for (Object autoStarter : autoStarters) { ((ServletConfiguration) autoStarter).ensureInitialization(); } } } private Properties loadBuiltinMimeTypes() { InputStream in = getClass().getResourceAsStream("mime.properties"); try { Properties props = new Properties(); props.load(in); return props; } catch (IOException e) { throw new Error("Failed to load the built-in MIME types",e); } finally { try { in.close(); } catch (IOException e) { // ignore } } } /** * Build the web-app classloader. This tries to load the preferred classloader first, * but if it fails, falls back to a simple URLClassLoader. */ private ClassLoader buildWebAppClassLoader(Map startupArgs, ClassLoader parentClassLoader, String webRoot, List classPathFileList) { List urlList = new ArrayList(); try { // Web-inf folder File webInfFolder = new File(webRoot, WEB_INF); // Classes folder File classesFolder = new File(webInfFolder, CLASSES); if (classesFolder.exists()) { Logger.log(Logger.DEBUG, Launcher.RESOURCES, "WebAppConfig.WebAppClasses"); String classesFolderURL = classesFolder.getCanonicalFile().toURL().toString(); urlList.add(new URL(classesFolderURL.endsWith("/") ? classesFolderURL : classesFolderURL + "/")); classPathFileList.add(classesFolder); } else { Logger.log(Logger.WARNING, Launcher.RESOURCES, "WebAppConfig.NoWebAppClasses", classesFolder.toString()); } // Lib folder's jar files File libFolder = new File(webInfFolder, LIB); if (libFolder.exists()) { File jars[] = libFolder.listFiles(); for (File jar : jars) { String jarName = jar.getName().toLowerCase(); if (jarName.endsWith(".jar") || jarName.endsWith(".zip")) { Logger.log(Logger.DEBUG, Launcher.RESOURCES, "WebAppConfig.WebAppLib", jar.getName()); urlList.add(jar.toURL()); classPathFileList.add(jar); } } } else { Logger.log(Logger.WARNING, Launcher.RESOURCES, "WebAppConfig.NoWebAppLib", libFolder .toString()); } } catch (MalformedURLException err) { throw new WinstoneException(Launcher.RESOURCES .getString("WebAppConfig.BadURL"), err); } catch (IOException err) { throw new WinstoneException(Launcher.RESOURCES .getString("WebAppConfig.IOException"), err); } URL jarURLs[] = (URL []) urlList.toArray(new URL[urlList.size()]); // Try to set up the preferred class loader, and if we fail, use the normal one ClassLoader outputCL = null; try { Class preferredClassLoader = Option.PREFERRED_CLASS_LOADER.get(startupArgs,ClassLoader.class,parentClassLoader); if (Option.USE_SERVLET_RELOADING.get(startupArgs) && !Option.PREFERRED_CLASS_LOADER.isIn(startupArgs)) { preferredClassLoader = ReloadingClassLoader.class; } Constructor reloadConstr = preferredClassLoader.getConstructor(new Class[] { URL[].class, ClassLoader.class}); outputCL = (ClassLoader) reloadConstr.newInstance(jarURLs, parentClassLoader); } catch (Throwable err) { Logger.log(Logger.ERROR, Launcher.RESOURCES, "WebAppConfig.CLError", err); } if (outputCL == null) { outputCL = new URLClassLoader(jarURLs, parentClassLoader); } Logger.log(Logger.MAX, Launcher.RESOURCES, "WebAppConfig.WebInfClassLoader", outputCL.toString()); return outputCL; } private void addListenerInstance(Object listenerInstance, List contextAttributeListeners, List contextListeners, List requestAttributeListeners, List requestListeners, List sessionActivationListeners, List sessionAttributeListeners, List sessionListeners) { if (listenerInstance instanceof ServletContextAttributeListener) contextAttributeListeners.add(listenerInstance); if (listenerInstance instanceof ServletContextListener) contextListeners.add(listenerInstance); if (listenerInstance instanceof ServletRequestAttributeListener) requestAttributeListeners.add(listenerInstance); if (listenerInstance instanceof ServletRequestListener) requestListeners.add(listenerInstance); if (listenerInstance instanceof HttpSessionActivationListener) sessionActivationListeners.add(listenerInstance); if (listenerInstance instanceof HttpSessionAttributeListener) sessionAttributeListeners.add(listenerInstance); if (listenerInstance instanceof HttpSessionListener) sessionListeners.add(listenerInstance); } public String getContextPath() { return this.prefix; } public String getWebroot() { return this.webRoot; } public ClassLoader getLoader() { return this.loader; } public AccessLogger getAccessLogger() { return this.accessLogger; } public Map getFilters() { return this.filterInstances; } public String getContextName() { return this.contextName; } public Class[] getErrorPageExceptions() { return this.errorPagesByExceptionKeysSorted; } public Map getErrorPagesByException() { return this.errorPagesByException; } public Map getErrorPagesByCode() { return this.errorPagesByCode; } public Map getLocaleEncodingMap() { return this.localeEncodingMap; } public String[] getWelcomeFiles() { return this.welcomeFiles; } public boolean isDistributable() { return (this.cluster != null); } public Map getFilterMatchCache() { return this.filterMatchCache; } public String getOwnerHostname() { return this.ownerHostConfig.getHostname(); } public ServletRequestListener[] getRequestListeners() { return this.requestListeners; } public ServletRequestAttributeListener[] getRequestAttributeListeners() { return this.requestAttributeListeners; } public static void addJspServletParams(Map jspParams) { jspParams.put("logVerbosityLevel", JSP_SERVLET_LOG_LEVEL); jspParams.put("fork", "false"); } public int compare(Object one, Object two) { if (!(one instanceof Class) || !(two instanceof Class)) throw new IllegalArgumentException( "This comparator is only for sorting classes"); Class classOne = (Class) one; Class classTwo = (Class) two; if (classOne.isAssignableFrom(classTwo)) return 1; else if (classTwo.isAssignableFrom(classOne)) return -1; else return 0; } public String getServletURIFromRequestURI(String requestURI) { if (prefix.equals("")) { return requestURI; } else if (requestURI.startsWith(prefix)) { return requestURI.substring(prefix.length()); } else { throw new WinstoneException("This shouldn't happen, " + "since we aborted earlier if we didn't match"); } } /** * Iterates through each of the servlets/filters and calls destroy on them */ public void destroy() { synchronized (this.filterMatchCache) { this.filterMatchCache.clear(); } Collection filterInstances = new ArrayList(this.filterInstances.values()); for (Object filterInstance : filterInstances) { try { ((FilterConfiguration) filterInstance).destroy(); } catch (Throwable err) { Logger.log(Logger.ERROR, Launcher.RESOURCES, "WebAppConfig.ShutdownError", err); } } this.filterInstances.clear(); Collection servletInstances = new ArrayList(this.servletInstances.values()); for (Object servletInstance : servletInstances) { try { ((ServletConfiguration) servletInstance).destroy(); } catch (Throwable err) { Logger.log(Logger.ERROR, Launcher.RESOURCES, "WebAppConfig.ShutdownError", err); } } this.servletInstances.clear(); // Drop all sessions Collection sessions = new ArrayList(this.sessions.values()); for (Object session1 : sessions) { WinstoneSession session = (WinstoneSession) session1; try { if (this.useSavedSessions) { session.saveToTemp(); } else { session.invalidate(); } } catch (Throwable err) { Logger.log(Logger.ERROR, Launcher.RESOURCES, "WebAppConfig.ShutdownError", err); } } this.sessions.clear(); // Send destroy notifies - backwards for (int n = this.contextListeners.length - 1; n >= 0; n--) { try { ClassLoader cl = Thread.currentThread().getContextClassLoader(); Thread.currentThread().setContextClassLoader(this.loader); this.contextListeners[n].contextDestroyed(new ServletContextEvent(this)); this.contextListeners[n] = null; Thread.currentThread().setContextClassLoader(cl); } catch (Throwable err) { Logger.log(Logger.ERROR, Launcher.RESOURCES, "WebAppConfig.ShutdownError", err); } } this.contextListeners = null; // Terminate class loader reloading thread if running if (this.loader != null) { // already shutdown/handled by the servlet context listeners // try { // Method methDestroy = this.loader.getClass().getMethod("destroy", new Class[0]); // methDestroy.invoke(this.loader, new Object[0]); // } catch (Throwable err) { // Logger.log(Logger.ERROR, Launcher.RESOURCES, "WebAppConfig.ShutdownError", err); // } this.loader = null; } // Kill JNDI manager if we have one if (this.jndiManager != null) { this.jndiManager.tearDown(); this.jndiManager = null; } // Kill JNDI manager if we have one if (this.accessLogger != null) { this.accessLogger.destroy(); this.accessLogger = null; } } /** * Triggered by the admin thread on the reloading class loader. This will * cause a full shutdown and reinstantiation of the web app - not real * graceful, but you shouldn't have reloading turned on in high load * environments. */ public void resetClassLoader() throws IOException { this.ownerHostConfig.reloadWebApp(getContextPath()); } /** * Here we process url patterns into the exactMatch and patternMatch lists */ private void processMapping(String name, String pattern, Map exactPatterns, List folderPatterns, List extensionPatterns) { Mapping urlPattern; try { urlPattern = Mapping.createFromURL(name, pattern); } catch (WinstoneException err) { Logger.log(Logger.WARNING, Launcher.RESOURCES, "WebAppConfig.ErrorMapURL", err.getMessage()); return; } // put the pattern in the correct list if (urlPattern.getPatternType() == Mapping.EXACT_PATTERN) { exactPatterns.put(urlPattern.getUrlPattern(), name); } else if (urlPattern.getPatternType() == Mapping.FOLDER_PATTERN) { folderPatterns.add(urlPattern); } else if (urlPattern.getPatternType() == Mapping.EXTENSION_PATTERN) { extensionPatterns.add(urlPattern); } else if (urlPattern.getPatternType() == Mapping.DEFAULT_SERVLET) { this.defaultServletName = name; } else { Logger.log(Logger.WARNING, Launcher.RESOURCES, "WebAppConfig.InvalidMount", name, pattern); } } /** * Execute the pattern match, and try to return a servlet that matches this * URL */ private ServletConfiguration urlMatch(String path, StringBuffer servletPath, StringBuffer pathInfo) { Logger.log(Logger.FULL_DEBUG, Launcher.RESOURCES, "WebAppConfig.URLMatch", path); // Check exact matches first String exact = (String) this.exactServletMatchMounts.get(path); if (exact != null) { if (this.servletInstances.get(exact) != null) { servletPath.append(WinstoneRequest.decodeURLToken(path,false)); // pathInfo.append(""); // a hack - empty becomes null later return (ServletConfiguration) this.servletInstances.get(exact); } } // Inexact mount check for (Mapping urlPattern : this.patternMatches) { if (urlPattern.match(path, servletPath, pathInfo) && (this.servletInstances.get(urlPattern.getMappedTo()) != null)) { return (ServletConfiguration) this.servletInstances .get(urlPattern.getMappedTo()); } } // return default servlet // servletPath.append(""); // unneeded if (this.servletInstances.get(this.defaultServletName) == null) throw new WinstoneException(Launcher.RESOURCES.getString( "WebAppConfig.MatchedNonExistServlet", this.defaultServletName)); // pathInfo.append(path); servletPath.append(WinstoneRequest.decodeURLToken(path,false)); return (ServletConfiguration) this.servletInstances.get(this.defaultServletName); } /** * Constructs a session instance with the given sessionId * * @param sessionId The sessionID for the new session * @return A valid session object */ public WinstoneSession makeNewSession(String sessionId) { WinstoneSession ws = new WinstoneSession(sessionId); ws.setWebAppConfiguration(this); setSessionListeners(ws); if (this.sessionTimeout == -1) { ws.setMaxInactiveInterval(60*60); // 60 mins as the default } else if (this.sessionTimeout > 0) { ws.setMaxInactiveInterval(this.sessionTimeout * 60); } else { ws.setMaxInactiveInterval(-1); } ws.setLastAccessedDate(System.currentTimeMillis()); ws.sendCreatedNotifies(); this.sessions.put(sessionId, ws); return ws; } /** * Retrieves the session by id. If the web app is distributable, it asks the * other members of the cluster if it doesn't have it itself. * * @param sessionId The id of the session we want * @return A valid session instance */ public WinstoneSession getSessionById(String sessionId, boolean localOnly) { if (sessionId == null) { return null; } WinstoneSession session = (WinstoneSession) this.sessions.get(sessionId); if (session != null) { return session; } // If I'm distributable ... check remotely if ((this.cluster != null) && !localOnly) { session = this.cluster.askClusterForSession(sessionId, this); if (session != null) { this.sessions.put(sessionId, session); } return session; } else { return null; } } /** * Add/Remove the session from the collection */ void removeSessionById(String sessionId) { this.sessions.remove(sessionId); } void addSession(String sessionId, WinstoneSession session) { this.sessions.put(sessionId, session); } public void invalidateExpiredSessions() { Object allSessions[] = this.sessions.values().toArray(); int expiredCount = 0; for (Object allSession : allSessions) { WinstoneSession session = (WinstoneSession) allSession; if (/*!session.isNew() &&*/ session.isUnusedByRequests() && session.isExpired()) { session.invalidate(); expiredCount++; } } if (expiredCount > 0) { Logger.log(Logger.DEBUG, Launcher.RESOURCES, "WebAppConfig.InvalidatedSessions", expiredCount + ""); } } public void setSessionListeners(WinstoneSession session) { session.setSessionActivationListeners(this.sessionActivationListeners); session.setSessionAttributeListeners(this.sessionAttributeListeners); session.setSessionListeners(this.sessionListeners); } public void removeServletConfigurationAndMappings(ServletConfiguration config) { this.servletInstances.remove(config.getServletName()); // The urlMatch method will only match to non-null mappings, so we don't need // to remove anything here } /*************************************************************************** * * OK ... from here to the end is the interface implementation methods for * the servletContext interface. * **************************************************************************/ // Application level attributes public Object getAttribute(String name) { return this.attributes.get(name); } public Enumeration getAttributeNames() { return Collections.enumeration(this.attributes.keySet()); } public void removeAttribute(String name) { Object me = this.attributes.get(name); this.attributes.remove(name); if (me != null) for (ServletContextAttributeListener contextAttributeListener : this.contextAttributeListeners) { ClassLoader cl = Thread.currentThread().getContextClassLoader(); Thread.currentThread().setContextClassLoader(getLoader()); contextAttributeListener.attributeRemoved( new ServletContextAttributeEvent(this, name, me)); Thread.currentThread().setContextClassLoader(cl); } } public void setAttribute(String name, Object object) { if (object == null) { removeAttribute(name); } else { Object me = this.attributes.get(name); this.attributes.put(name, object); if (me != null) { for (ServletContextAttributeListener contextAttributeListener : this.contextAttributeListeners) { ClassLoader cl = Thread.currentThread().getContextClassLoader(); Thread.currentThread().setContextClassLoader(getLoader()); contextAttributeListener.attributeReplaced( new ServletContextAttributeEvent(this, name, me)); Thread.currentThread().setContextClassLoader(cl); } } else { for (ServletContextAttributeListener contextAttributeListener : this.contextAttributeListeners) { ClassLoader cl = Thread.currentThread().getContextClassLoader(); Thread.currentThread().setContextClassLoader(getLoader()); contextAttributeListener.attributeAdded( new ServletContextAttributeEvent(this, name, object)); Thread.currentThread().setContextClassLoader(cl); } } } } // Application level init parameters public String getInitParameter(String name) { return (String) this.initParameters.get(name); } public Enumeration getInitParameterNames() { return Collections.enumeration(this.initParameters.keySet()); } // Server info public String getServerInfo() { return Launcher.RESOURCES.getString("ServerVersion"); } public int getMajorVersion() { return 2; } public int getMinorVersion() { return 5; } // Weird mostly deprecated crap to do with getting servlet instances public javax.servlet.ServletContext getContext(String uri) { return this.ownerHostConfig.getWebAppByURI(uri); } public String getServletContextName() { return this.displayName; } /** * Look up the map of mimeType extensions, and return the type that matches */ public String getMimeType(String fileName) { int dotPos = fileName.lastIndexOf('.'); if ((dotPos != -1) && (dotPos != fileName.length() - 1)) { String extension = fileName.substring(dotPos + 1).toLowerCase(); String mimeType = (String) this.mimeTypes.get(extension); return mimeType; } else return null; } // Context level log statements public void log(String message) { Logger.logDirectMessage(Logger.INFO, this.contextName, message, null); } public void log(String message, Throwable throwable) { Logger.logDirectMessage(Logger.ERROR, this.contextName, message, throwable); } /** * Named dispatcher - this basically gets us a simple exact dispatcher (no * url matching, no request attributes and no security) */ public javax.servlet.RequestDispatcher getNamedDispatcher(String name) { ServletConfiguration servlet = (ServletConfiguration) this.servletInstances.get(name); if (servlet != null) { RequestDispatcher rd = new RequestDispatcher(this, servlet); if (rd != null) { rd.setForNamedDispatcher(this.filterPatternsForward, this.filterPatternsInclude); return rd; } } return null; } /** * Gets a dispatcher, which sets the request attributes, etc on a * forward/include. Doesn't execute security though. */ public javax.servlet.RequestDispatcher getRequestDispatcher( String uriInsideWebapp) { if (uriInsideWebapp == null) { return null; } else if (!uriInsideWebapp.startsWith("/")) { return null; } // Parse the url for query string, etc String queryString = ""; int questionPos = uriInsideWebapp.indexOf('?'); if (questionPos != -1) { if (questionPos != uriInsideWebapp.length() - 1) { queryString = uriInsideWebapp.substring(questionPos + 1); } uriInsideWebapp = uriInsideWebapp.substring(0, questionPos); } // Return the dispatcher StringBuffer servletPath = new StringBuffer(); StringBuffer pathInfo = new StringBuffer(); ServletConfiguration servlet = urlMatch(uriInsideWebapp, servletPath, pathInfo); if (servlet != null) { RequestDispatcher rd = new RequestDispatcher(this, servlet); if (rd != null) { rd.setForURLDispatcher(servletPath.toString(), pathInfo.toString() .equals("") ? null : pathInfo.toString(), queryString, uriInsideWebapp, this.filterPatternsForward, this.filterPatternsInclude); return rd; } } return null; } /** * Creates the dispatcher that corresponds to a request level dispatch (ie * the initial entry point). The difference here is that we need to set up * the dispatcher so that on a forward, it executes the security checks and * the request filters, while not setting any of the request attributes for * a forward. Also, we can't return a null dispatcher in error case - instead * we have to return a dispatcher pre-init'd for showing an error page (eg 404). * A null dispatcher is interpreted to mean a successful 302 has occurred. */ public RequestDispatcher getInitialDispatcher(String uriInsideWebapp, WinstoneRequest request, WinstoneResponse response) throws IOException { if (!uriInsideWebapp.equals("") && !uriInsideWebapp.startsWith("/")) { return this.getErrorDispatcherByCode( uriInsideWebapp, HttpServletResponse.SC_BAD_REQUEST, Launcher.RESOURCES.getString("WebAppConfig.InvalidURI", uriInsideWebapp), new IllegalArgumentException("method="+request.getMethod()+"\nprotocol="+request.getProtocol())); } else if (this.contextStartupError != null) { StringWriter sw = new StringWriter(); PrintWriter pw = new PrintWriter(sw, true); this.contextStartupError.printStackTrace(pw); return this.getErrorDispatcherByCode( uriInsideWebapp, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, Launcher.RESOURCES.getString("WebAppConfig.ErrorDuringStartup", sw.toString()), this.contextStartupError); } // Parse the url for query string, etc String queryString = ""; int questionPos = uriInsideWebapp.indexOf('?'); if (questionPos != -1) { if (questionPos != uriInsideWebapp.length() - 1) queryString = uriInsideWebapp.substring(questionPos + 1); uriInsideWebapp = uriInsideWebapp.substring(0, questionPos); } // Return the dispatcher StringBuffer servletPath = new StringBuffer(); StringBuffer pathInfo = new StringBuffer(); ServletConfiguration servlet = urlMatch(uriInsideWebapp, servletPath, pathInfo); if (servlet != null) { // If the default servlet was returned, we should check for welcome files if (servlet.getServletName().equals(this.defaultServletName)) { // Is path a directory ? String directoryPath = servletPath.toString(); if (directoryPath.endsWith("/")) { directoryPath = directoryPath.substring(0, directoryPath.length() - 1); } if (directoryPath.startsWith("/")) { directoryPath = directoryPath.substring(1); } File res = new File(webRoot, directoryPath); if (res.exists() && res.isDirectory() && (request.getMethod().equals("GET") || request.getMethod().equals("HEAD"))) { // Check for the send back with slash case if (!servletPath.toString().endsWith("/")) { Logger.log(Logger.FULL_DEBUG, Launcher.RESOURCES, "WebAppConfig.FoundNonSlashDirectory", servletPath.toString()); response.sendRedirect(this.prefix + servletPath.toString() + pathInfo.toString() + "/" + (queryString.equals("") ? "" : "?" + queryString)); return null; } // Check for welcome files Logger.log(Logger.FULL_DEBUG, Launcher.RESOURCES, "WebAppConfig.CheckWelcomeFile", servletPath.toString() + pathInfo.toString()); String welcomeFile = matchWelcomeFiles(servletPath.toString() + pathInfo.toString(), request, queryString); if (welcomeFile != null) { response.sendRedirect(this.prefix + welcomeFile); // + servletPath.toString() // + pathInfo.toString() // + welcomeFile // + (queryString.equals("") ? "" : "?" + queryString)); return null; } } } RequestDispatcher rd = new RequestDispatcher(this, servlet); rd.setForInitialDispatcher(servletPath.toString(), pathInfo.toString().equals("") ? null : pathInfo.toString(), queryString, uriInsideWebapp, this.filterPatternsRequest, this.authenticationHandler); return rd; } // If we are here, return a 404 return this.getErrorDispatcherByCode(uriInsideWebapp, HttpServletResponse.SC_NOT_FOUND, Launcher.RESOURCES.getString("StaticResourceServlet.PathNotFound", uriInsideWebapp), null); } /** * Gets a dispatcher, set up for error dispatch. */ public RequestDispatcher getErrorDispatcherByClass( Throwable exception) { // Check for exception class match Class exceptionClasses[] = this.errorPagesByExceptionKeysSorted; Throwable errWrapper = new ServletException(exception); while (errWrapper instanceof ServletException) { errWrapper = ((ServletException) errWrapper).getRootCause(); if (errWrapper == null) { break; } for (int n = 0; n < exceptionClasses.length; n++) { Logger.log(Logger.FULL_DEBUG, Launcher.RESOURCES, "WinstoneResponse.TestingException", this.errorPagesByExceptionKeysSorted[n].getName(), errWrapper.getClass().getName()); if (exceptionClasses[n].isInstance(errWrapper)) { String errorURI = (String) this.errorPagesByException.get(exceptionClasses[n]); if (errorURI != null) { RequestDispatcher rd = buildErrorDispatcher(errorURI, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, null, errWrapper); if (rd != null) { return rd; } } else { Logger.log(Logger.WARNING, Launcher.RESOURCES, "WinstoneResponse.SkippingException", exceptionClasses[n].getName(), (String) this.errorPagesByException.get(exceptionClasses[n])); } } else { Logger.log(Logger.WARNING, Launcher.RESOURCES, "WinstoneResponse.ExceptionNotMatched", exceptionClasses[n].getName()); } } } // Otherwise throw a code error Throwable errPassDown = exception; while ((errPassDown instanceof ServletException) && (((ServletException) errPassDown).getRootCause() != null)) { errPassDown = ((ServletException) errPassDown).getRootCause(); } return getErrorDispatcherByCode(null, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, null, errPassDown); } public RequestDispatcher getErrorDispatcherByCode( String requestURI, int statusCode, String summaryMessage, Throwable exception) { // Check for status code match String errorURI = (String) getErrorPagesByCode().get("" + statusCode); if (errorURI != null) { RequestDispatcher rd = buildErrorDispatcher(errorURI, statusCode, summaryMessage, exception); if (rd != null) { return rd; } } // If no dispatcher available, return a dispatcher to the default error formatter ServletConfiguration errorServlet = (ServletConfiguration) this.servletInstances.get(this.errorServletName); if (errorServlet != null) { RequestDispatcher rd = new RequestDispatcher(this, errorServlet); if (rd != null) { rd.setForErrorDispatcher(null, null, null, statusCode, summaryMessage, exception, requestURI, this.filterPatternsError); return rd; } } // Otherwise log and return null Logger.log(Logger.ERROR, Launcher.RESOURCES, "WebAppConfig.NoErrorServlet", "" + statusCode, exception); return null; } /** * Build a dispatcher to the error handler if it's available. If it fails, return null. */ private RequestDispatcher buildErrorDispatcher(String errorURI, int statusCode, String summaryMessage, Throwable exception) { // Parse the url for query string, etc String queryString = ""; int questionPos = errorURI.indexOf('?'); if (questionPos != -1) { if (questionPos != errorURI.length() - 1) { queryString = errorURI.substring(questionPos + 1); } errorURI = errorURI.substring(0, questionPos); } // Get the message by recursing if none supplied ServletException errIterator = new ServletException(exception); while ((summaryMessage == null) && (errIterator != null)) { summaryMessage = errIterator.getMessage(); if (errIterator.getRootCause() instanceof ServletException) { errIterator = (ServletException) errIterator.getRootCause(); } else { if (summaryMessage == null) { summaryMessage = errIterator.getRootCause().getMessage(); } errIterator = null; } } // Return the dispatcher StringBuffer servletPath = new StringBuffer(); StringBuffer pathInfo = new StringBuffer(); ServletConfiguration servlet = urlMatch(errorURI, servletPath, pathInfo); if (servlet != null) { RequestDispatcher rd = new RequestDispatcher(this, servlet); if (rd != null) { rd.setForErrorDispatcher(servletPath.toString(), pathInfo.toString().equals("") ? null : pathInfo.toString(), queryString, statusCode, summaryMessage, exception, errorURI, this.filterPatternsError); return rd; } } return null; } /** * Check if any of the welcome files under this path are available. Returns the * name of the file if found, null otherwise. Returns the full internal webapp uri */ private String matchWelcomeFiles(String path, WinstoneRequest request, String queryString) { if (!path.endsWith("/")) { path = path + "/"; } String qs = (queryString.equals("") ? "" : "?" + queryString); for (String welcomeFile1 : this.welcomeFiles) { String welcomeFile = welcomeFile1; while (welcomeFile.startsWith("/")) { welcomeFile = welcomeFile.substring(1); } welcomeFile = path + welcomeFile; String exact = (String) this.exactServletMatchMounts.get(welcomeFile); if (exact != null) { return welcomeFile + qs; } // Inexact folder mount check - note folder mounts only for (Mapping urlPattern : this.patternMatches) { if ((urlPattern.getPatternType() == Mapping.FOLDER_PATTERN) && urlPattern.match(welcomeFile, null, null)) { return welcomeFile + qs; } } try { if (getResource(welcomeFile) != null) { return welcomeFile + qs; } } catch (MalformedURLException err) { } } return null; } // Getting resources via the classloader public URL getResource(String path) throws MalformedURLException { if (path == null) { return null; } else if (!path.startsWith("/")) { throw new MalformedURLException(Launcher.RESOURCES.getString( "WebAppConfig.BadResourcePath", path)); } else if (!path.equals("/") && path.endsWith("/")) { path = path.substring(0, path.length() - 1); } File res = new File(webRoot, URIUtil.canonicalPath(path)); return res.exists() ? res.toURL() : null; } public InputStream getResourceAsStream(String path) { try { URL res = getResource(path); return res == null ? null : res.openStream(); } catch (IOException err) { throw new WinstoneException(Launcher.RESOURCES .getString("WebAppConfig.ErrorOpeningStream"), err); } } public String getRealPath(String path) { // Trim the prefix if (path == null) return null; else { try { File res = new File(this.webRoot, path); if (res.isDirectory()) return res.getCanonicalPath() + "/"; else return res.getCanonicalPath(); } catch (IOException err) { return null; } } } public Set getResourcePaths(String path) { // Trim the prefix if (path == null) return null; else if (!path.startsWith("/")) throw new WinstoneException(Launcher.RESOURCES.getString( "WebAppConfig.BadResourcePath", path)); else { String workingPath; if (path.equals("/")) workingPath = ""; else { boolean lastCharIsSlash = path.charAt(path.length() - 1) == '/'; workingPath = path.substring(1, path.length() - (lastCharIsSlash ? 1 : 0)); } File inPath = new File(this.webRoot, workingPath.equals("") ? "." : workingPath).getAbsoluteFile(); if (!inPath.exists()) return null; else if (!inPath.isDirectory()) return null; // Find all the files in this folder File children[] = inPath.listFiles(); Set out = new HashSet(); for (File aChildren : children) { // Write the entry as subpath + child element String entry = //this.prefix + "/" + (workingPath.length() != 0 ? workingPath + "/" : "") + aChildren.getName() + (aChildren.isDirectory() ? "/" : ""); out.add(entry); } return out; } } /** * @deprecated */ public javax.servlet.Servlet getServlet(String name) { return null; } /** * @deprecated */ public Enumeration getServletNames() { return Collections.enumeration(new ArrayList()); } /** * @deprecated */ public Enumeration getServlets() { return Collections.enumeration(new ArrayList()); } /** * @deprecated */ public void log(Exception exception, String msg) { this.log(msg, exception); } } jenkins-winstone-0.9.10-jenkins-47/src/java/winstone/ssl/0000755000175000017500000000000012200024521023612 5ustar jamespagejamespagejenkins-winstone-0.9.10-jenkins-47/src/java/winstone/ssl/HttpsListener.java0000644000175000017500000002731712200024521027277 0ustar jamespagejamespage/* * Copyright 2003-2006 Rick Knowles * Distributed under the terms of either: * - the common development and distribution license (CDDL), v1.0; or * - the GNU Lesser General Public License, v2.1 or later */ package winstone.ssl; import java.io.*; import java.math.BigInteger; import java.net.InetAddress; import java.net.ServerSocket; import java.net.Socket; import java.security.*; import java.security.cert.Certificate; import java.security.cert.CertificateFactory; import java.security.cert.X509Certificate; import java.security.spec.RSAPrivateKeySpec; import java.text.MessageFormat; import java.util.Enumeration; import java.util.Map; import javax.net.ssl.KeyManagerFactory; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLServerSocket; import javax.net.ssl.SSLServerSocketFactory; import javax.net.ssl.SSLSession; import javax.net.ssl.SSLSocket; import sun.security.util.DerInputStream; import sun.security.util.DerValue; import sun.security.x509.CertAndKeyGen; import sun.security.x509.X500Name; import winstone.HostGroup; import winstone.HttpListener; import winstone.Logger; import winstone.ObjectPool; import winstone.cmdline.Option; import winstone.WinstoneException; import winstone.WinstoneRequest; import winstone.WinstoneResourceBundle; import winstone.auth.BasicAuthenticationHandler; /** * Implements the main listener daemon thread. This is the class that gets * launched by the command line, and owns the server socket, etc. * * @author Rick Knowles * @version $Id: HttpsListener.java,v 1.10 2007/06/13 15:27:35 rickknowles Exp $ */ public class HttpsListener extends HttpListener { private static final WinstoneResourceBundle SSL_RESOURCES = new WinstoneResourceBundle("winstone.ssl.LocalStrings"); private final KeyStore keystore; private final char[] password; private final String keyManagerType; /** * If true, request the client certificate ala "SSLVerifyClient require" Apache directive. * If false, which is the default, don't do so. * Technically speaking, there's the equivalent of "SSLVerifyClient optional", but IE doesn't * recognize it and it always prompt the certificate chooser dialog box, so in practice * it's useless. *

* See http://hudson.361315.n4.nabble.com/winstone-container-and-ssl-td383501.html for this failure mode in IE. */ private boolean performClientAuth; /** * Constructor */ public HttpsListener(Map args, ObjectPool objectPool, HostGroup hostGroup) throws IOException { super(args, objectPool, hostGroup); if (listenPort<0) { // not running HTTPS listener keystore = null; password = null; keyManagerType = null; } else { try { performClientAuth = Option.HTTPS_VERIFY_CLIENT.get(args); File opensslCert = Option.HTTPS_CERTIFICATE.get(args); File opensslKey = Option.HTTPS_PRIVATE_KEY.get(args); File keyStore = Option.HTTPS_KEY_STORE.get(args); String pwd = Option.HTTPS_KEY_STORE_PASSWORD.get(args); if ((opensslCert!=null ^ opensslKey!=null)) throw new WinstoneException(MessageFormat.format("--{0} and --{1} need to be used together", Option.HTTPS_CERTIFICATE, Option.HTTPS_PRIVATE_KEY)); if (keyStore!=null && opensslKey!=null) throw new WinstoneException(MessageFormat.format("--{0} and --{1} are mutually exclusive", Option.HTTPS_KEY_STORE, Option.HTTPS_PRIVATE_KEY)); if (keyStore!=null) { // load from Java style JKS if (!keyStore.exists() || !keyStore.isFile()) throw new WinstoneException(SSL_RESOURCES.getString( "HttpsListener.KeyStoreNotFound", keyStore.getPath())); this.password = pwd!=null ? pwd.toCharArray() : null; keystore = KeyStore.getInstance("JKS"); keystore.load(new FileInputStream(keyStore), this.password); } else if (opensslCert!=null) { // load from openssl style key files CertificateFactory cf = CertificateFactory.getInstance("X509"); Certificate cert = cf.generateCertificate(new FileInputStream(opensslCert)); PrivateKey key = readPEMRSAPrivateKey(new FileReader(opensslKey)); this.password = "changeit".toCharArray(); keystore = KeyStore.getInstance("JKS"); keystore.load(null); keystore.setKeyEntry("hudson", key, password, new Certificate[]{cert}); } else { // use self-signed certificate this.password = "changeit".toCharArray(); System.out.println("Using one-time self-signed certificate"); CertAndKeyGen ckg = new CertAndKeyGen("RSA", "SHA1WithRSA", null); ckg.generate(1024); PrivateKey privKey = ckg.getPrivateKey(); X500Name xn = new X500Name("Test site", "Unknown", "Unknown", "Unknown"); X509Certificate cert = ckg.getSelfCertificate(xn, 3650L * 24 * 60 * 60); keystore = KeyStore.getInstance("JKS"); keystore.load(null); keystore.setKeyEntry("hudson", privKey, password, new Certificate[]{cert}); } } catch (GeneralSecurityException e) { throw (IOException)new IOException("Failed to handle keys").initCause(e); } this.keyManagerType = Option.HTTPS_KEY_MANAGER_TYPE.get(args); } } private static PrivateKey readPEMRSAPrivateKey(Reader reader) throws IOException, GeneralSecurityException { // TODO: should have more robust format error handling ByteArrayOutputStream baos = new ByteArrayOutputStream(); try { BufferedReader r = new BufferedReader(reader); String line; boolean in = false; while ((line=r.readLine())!=null) { if (line.startsWith("-----")) { in = !in; continue; } if (in) { char[] inBytes = line.toCharArray(); byte[] outBytes = new byte[(inBytes.length*3)/4]; int length = BasicAuthenticationHandler.decodeBase64(inBytes, outBytes, 0, inBytes.length, 0); baos.write(outBytes,0,length); } } } finally { reader.close(); } DerInputStream dis = new DerInputStream(baos.toByteArray()); DerValue[] seq = dis.getSequence(0); // int v = seq[0].getInteger(); BigInteger mod = seq[1].getBigInteger(); // pubExpo BigInteger privExpo = seq[3].getBigInteger(); // p1, p2, exp1, exp2, crtCoef KeyFactory kf = KeyFactory.getInstance("RSA"); return kf.generatePrivate (new RSAPrivateKeySpec(mod,privExpo)); } /** * The default port to use - this is just so that we can override for the * SSL connector. */ protected int getDefaultPort() { return -1; // https disabled by default } /** * The name to use when getting properties - this is just so that we can * override for the SSL connector. */ protected String getConnectorScheme() { return "https"; } /** * Gets a server socket - this gets as SSL socket instead of the standard * socket returned in the base class. */ protected ServerSocket getServerSocket() throws IOException { // Just to make sure it's set before we start SSLContext context = getSSLContext(); SSLServerSocketFactory factory = context.getServerSocketFactory(); SSLServerSocket ss = (SSLServerSocket) (this.listenAddress == null ? factory .createServerSocket(this.listenPort, BACKLOG_COUNT) : factory.createServerSocket(this.listenPort, BACKLOG_COUNT, InetAddress.getByName(this.listenAddress))); ss.setEnableSessionCreation(true); if (performClientAuth) ss.setNeedClientAuth(true); return ss; } /** * Extracts the relevant socket stuff and adds it to the request object. * This method relies on the base class for everything other than SSL * related attributes */ protected void parseSocketInfo(Socket socket, WinstoneRequest req) throws IOException { super.parseSocketInfo(socket, req); if (socket instanceof SSLSocket) { SSLSocket s = (SSLSocket) socket; SSLSession ss = s.getSession(); if (ss != null) { Certificate certChain[] = null; try { certChain = ss.getPeerCertificates(); } catch (Throwable err) {/* do nothing */ } if (certChain != null) { req.setAttribute("javax.servlet.request.X509Certificate", certChain); req.setAttribute("javax.servlet.request.cipher_suite", ss .getCipherSuite()); req.setAttribute("javax.servlet.request.ssl_session", new String(ss.getId())); req.setAttribute("javax.servlet.request.key_size", getKeySize(ss.getCipherSuite())); } } req.setIsSecure(true); } } /** * Just a mapping of key sizes for cipher types. Taken indirectly from the * TLS specs. */ private Integer getKeySize(String cipherSuite) { if (cipherSuite.indexOf("_WITH_NULL_") != -1) return 0; else if (cipherSuite.indexOf("_WITH_IDEA_CBC_") != -1) return 128; else if (cipherSuite.indexOf("_WITH_RC2_CBC_40_") != -1) return 40; else if (cipherSuite.indexOf("_WITH_RC4_40_") != -1) return 40; else if (cipherSuite.indexOf("_WITH_RC4_128_") != -1) return 128; else if (cipherSuite.indexOf("_WITH_DES40_CBC_") != -1) return 40; else if (cipherSuite.indexOf("_WITH_DES_CBC_") != -1) return 56; else if (cipherSuite.indexOf("_WITH_3DES_EDE_CBC_") != -1) return 168; else return null; } /** * Used to get the base ssl context in which to create the server socket. * This is basically just so we can have a custom location for key stores. */ public SSLContext getSSLContext() { try { // Check the key manager factory KeyManagerFactory kmf = KeyManagerFactory.getInstance(this.keyManagerType); kmf.init(keystore, password); Logger.log(Logger.FULL_DEBUG, SSL_RESOURCES, "HttpsListener.KeyCount", keystore.size() + ""); for (Enumeration e = keystore.aliases(); e.hasMoreElements();) { String alias = (String) e.nextElement(); Logger.log(Logger.FULL_DEBUG, SSL_RESOURCES, "HttpsListener.KeyFound", alias, keystore.getCertificate(alias) + ""); } SSLContext context = SSLContext.getInstance("SSL"); context.init(kmf.getKeyManagers(), null, null); return context; } catch (Throwable err) { throw new WinstoneException(SSL_RESOURCES .getString("HttpsListener.ErrorGettingContext"), err); } } } jenkins-winstone-0.9.10-jenkins-47/src/java/winstone/ssl/LocalStrings.properties0000644000175000017500000000070612200024521030337 0ustar jamespagejamespageHttpsListener.ErrorGettingContext=Error getting the SSL context object HttpsListener.KeyCount=Keys/certificates found: [#0] HttpsListener.KeyFound=Key: [#0] - [#1] HttpsListener.KeyStoreNotFound=No SSL key store found at [#0] HttpsListener.KeyManagerFactoryFailed=WARNING: The SSL key manager factory [#0] could not be instantiated. Reverting to default X509 key manager. HttpsListener.UsingKeyManager=Using configured SSL key manager factory class [#0] jenkins-winstone-0.9.10-jenkins-47/src/java/winstone/Launcher.java0000644000175000017500000004626512200024521025432 0ustar jamespagejamespage/* * Copyright 2003-2006 Rick Knowles * Distributed under the terms of either: * - the common development and distribution license (CDDL), v1.0; or * - the GNU Lesser General Public License, v2.1 or later */ package winstone; import winstone.cmdline.CmdLineParser; import winstone.cmdline.Option; import javax.servlet.http.HttpUtils; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.InterruptedIOException; import java.io.ObjectInputStream; import java.io.OutputStream; import java.lang.reflect.Constructor; import java.net.ServerSocket; import java.net.Socket; import java.net.URL; import java.net.URLClassLoader; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Properties; import java.util.logging.Level; /** * Implements the main launcher daemon thread. This is the class that gets * launched by the command line, and owns the server socket, etc. * * @author Rick Knowles * @version $Id: Launcher.java,v 1.29 2007/04/23 02:55:35 rickknowles Exp $ */ public class Launcher implements Runnable { static final String HTTP_LISTENER_CLASS = "winstone.HttpListener"; static final String HTTPS_LISTENER_CLASS = "winstone.ssl.HttpsListener"; static final String AJP_LISTENER_CLASS = "winstone.ajp13.Ajp13Listener"; public static final byte SHUTDOWN_TYPE = (byte) '0'; public static final byte RELOAD_TYPE = (byte) '4'; private int CONTROL_TIMEOUT = 2000; // wait 2s for control connection private Thread controlThread; public final static WinstoneResourceBundle RESOURCES = new WinstoneResourceBundle("winstone.LocalStrings"); private int controlPort; private HostGroup hostGroup; private ObjectPool objectPool; private final List listeners = new ArrayList(); private Map args; private Cluster cluster; private JNDIManager globalJndiManager; /** * Constructor - initialises the web app, object pools, control port and the * available protocol listeners. */ public Launcher(Map args) throws IOException { boolean success=false; try { boolean useJNDI = Option.USE_JNDI.get(args); // Set jndi resource handler if not set (workaround for JamVM bug) if (useJNDI) try { Class ctxFactoryClass = Class.forName("winstone.jndi.java.javaURLContextFactory"); if (System.getProperty("java.naming.factory.initial") == null) { System.setProperty("java.naming.factory.initial", ctxFactoryClass.getName()); } if (System.getProperty("java.naming.factory.url.pkgs") == null) { System.setProperty("java.naming.factory.url.pkgs", "winstone.jndi"); } } catch (ClassNotFoundException err) {} Logger.log(Logger.MAX, RESOURCES, "Launcher.StartupArgs", args + ""); this.args = args; this.controlPort =Option.CONTROL_PORT.get(args); // Check for java home List jars = new ArrayList(); List commonLibCLPaths = new ArrayList(); String defaultJavaHome = System.getProperty("java.home"); File javaHome = Option.JAVA_HOME.get(args,new File(defaultJavaHome)); Logger.log(Logger.DEBUG, RESOURCES, "Launcher.UsingJavaHome", javaHome.getPath()); File toolsJar = Option.TOOLS_JAR.get(args); if (toolsJar == null) { toolsJar = new File(javaHome, "lib/tools.jar"); // first try - if it doesn't exist, try up one dir since we might have // the JRE home by mistake if (!toolsJar.exists()) { File javaHome2 = javaHome.getParentFile(); File toolsJar2 = new File(javaHome2, "lib/tools.jar"); if (toolsJar2.exists()) { javaHome = javaHome2; toolsJar = toolsJar2; } } } // Add tools jar to classloader path if (toolsJar.exists()) { jars.add(toolsJar.toURL()); commonLibCLPaths.add(toolsJar); Logger.log(Logger.DEBUG, RESOURCES, "Launcher.AddedCommonLibJar", toolsJar.getName()); } else if (Option.USE_JASPER.get(args)) Logger.log(Logger.WARNING, RESOURCES, "Launcher.ToolsJarNotFound"); // Set up common lib class loader File libFolder = Option.COMMON_LIB_FOLDER.get(args,new File("lib")); if (libFolder.exists() && libFolder.isDirectory()) { Logger.log(Logger.DEBUG, RESOURCES, "Launcher.UsingCommonLib", libFolder.getCanonicalPath()); File children[] = libFolder.listFiles(); for (File aChildren : children) if (aChildren.getName().endsWith(".jar") || aChildren.getName().endsWith(".zip")) { jars.add(aChildren.toURL()); commonLibCLPaths.add(aChildren); Logger.log(Logger.DEBUG, RESOURCES, "Launcher.AddedCommonLibJar", aChildren.getName()); } } else { Logger.log(Logger.DEBUG, RESOURCES, "Launcher.NoCommonLib"); } ClassLoader commonLibCL = new URLClassLoader((URL[]) jars.toArray(new URL[jars.size()]), getClass().getClassLoader()); Logger.log(Logger.MAX, RESOURCES, "Launcher.CLClassLoader", commonLibCL.toString()); Logger.log(Logger.MAX, RESOURCES, "Launcher.CLClassLoader", commonLibCLPaths.toString()); this.objectPool = new ObjectPool(args); // Optionally set up clustering if enabled and libraries are available if (Option.USE_CLUSTER.get(args)) { if (this.controlPort < 0) { Logger.log(Logger.INFO, RESOURCES, "Launcher.ClusterOffNoControlPort"); } else { try { Class clusterClass = Option.CLUSTER_CLASS_NAME.get(args, Cluster.class); Constructor clusterConstructor = clusterClass .getConstructor(new Class[]{Map.class, Integer.class}); this.cluster = (Cluster) clusterConstructor .newInstance(args, this.controlPort); } catch (Throwable err) { Logger.log(Logger.WARNING, RESOURCES, "Launcher.ClusterStartupError", err); } } } // If jndi is enabled, run the container wide jndi populator if (useJNDI) { try { // Build the realm Class jndiMgrClass = Option.CONTAINER_JNDI_CLASSNAME.get(args,JNDIManager.class,commonLibCL); Constructor jndiMgrConstr = jndiMgrClass.getConstructor(new Class[] { Map.class, List.class, ClassLoader.class }); this.globalJndiManager = (JNDIManager) jndiMgrConstr.newInstance(args, null, commonLibCL); this.globalJndiManager.setup(); } catch (Throwable err) { Logger.log(Logger.ERROR, RESOURCES, "Launcher.JNDIError", "", err); } } // Open the web apps this.hostGroup = new HostGroup(this.cluster, this.objectPool, commonLibCL, (File []) commonLibCLPaths.toArray(new File[0]), args); // Create connectors (http, https and ajp) spawnListener(HTTP_LISTENER_CLASS); spawnListener(AJP_LISTENER_CLASS); try { Class.forName("javax.net.ServerSocketFactory"); spawnListener(HTTPS_LISTENER_CLASS); } catch (ClassNotFoundException err) { Logger.log(Logger.DEBUG, RESOURCES, "Launcher.NeedsJDK14", HTTPS_LISTENER_CLASS); } this.controlThread = new Thread(this, RESOURCES.getString( "Launcher.ThreadName", "" + this.controlPort)); this.controlThread.setDaemon(false); this.controlThread.start(); success = true; } finally { if (!success) shutdown(); } Runtime.getRuntime().addShutdownHook(new ShutdownHook(this)); } /** * Instantiates listeners. Note that an exception thrown in the * constructor is interpreted as the listener being disabled, so * don't do anything too adventurous in the constructor, or if you do, * catch and log any errors locally before rethrowing. */ protected void spawnListener(String listenerClassName) throws IOException { try { Class listenerClass = Class.forName(listenerClassName); Constructor listenerConstructor = listenerClass .getConstructor(new Class[]{Map.class, ObjectPool.class, HostGroup.class}); Listener listener = (Listener) listenerConstructor .newInstance(args, this.objectPool, this.hostGroup); if (listener.start()) { this.listeners.add(listener); } // } catch (ClassNotFoundException err) { // Logger.log(Logger.INFO, RESOURCES, // "Launcher.ListenerNotFound", listenerClassName); } catch (Throwable err) { // Logger.log(Logger.ERROR, RESOURCES, // "Launcher.ListenerStartupError", listenerClassName, err); throw (IOException)new IOException("Failed to start a listener: "+listenerClassName).initCause(err); } } /** * The main run method. This handles the normal thread processing. */ public void run() { boolean interrupted = false; try { ServerSocket controlSocket = null; if (this.controlPort > 0) { controlSocket = new ServerSocket(this.controlPort); controlSocket.setSoTimeout(CONTROL_TIMEOUT); } Logger.log(Logger.INFO, RESOURCES, "Launcher.StartupOK", RESOURCES.getString("ServerVersion"), (this.controlPort > 0 ? "" + this.controlPort : RESOURCES.getString("Launcher.ControlDisabled"))); // Enter the main loop while (!interrupted) { // this.objectPool.removeUnusedRequestHandlers(); // this.hostGroup.invalidateExpiredSessions(); // Check for control request Socket accepted = null; try { if (controlSocket != null) { accepted = controlSocket.accept(); if (accepted != null) { handleControlRequest(accepted); } } else { Thread.sleep(CONTROL_TIMEOUT); } } catch (InterruptedIOException err) { } catch (InterruptedException err) { interrupted = true; } catch (Throwable err) { Logger.log(Logger.ERROR, RESOURCES, "Launcher.ShutdownError", err); } finally { if (accepted != null) { try {accepted.close();} catch (IOException err) {} } if (Thread.interrupted()) { interrupted = true; } } } // Close server socket if (controlSocket != null) { controlSocket.close(); } } catch (Throwable err) { Logger.log(Logger.ERROR, RESOURCES, "Launcher.ShutdownError", err); } Logger.log(Logger.INFO, RESOURCES, "Launcher.ControlThreadShutdownOK"); } protected void handleControlRequest(Socket csAccepted) throws IOException { InputStream inSocket = null; OutputStream outSocket = null; ObjectInputStream inControl = null; try { inSocket = csAccepted.getInputStream(); int reqType = inSocket.read(); if ((byte) reqType == SHUTDOWN_TYPE) { Logger.log(Logger.INFO, RESOURCES, "Launcher.ShutdownRequestReceived"); shutdown(); } else if ((byte) reqType == RELOAD_TYPE) { inControl = new ObjectInputStream(inSocket); String host = inControl.readUTF(); String prefix = inControl.readUTF(); Logger.log(Logger.INFO, RESOURCES, "Launcher.ReloadRequestReceived", host + prefix); HostConfiguration hostConfig = this.hostGroup.getHostByName(host); hostConfig.reloadWebApp(prefix); } else if (this.cluster != null) { outSocket = csAccepted.getOutputStream(); this.cluster.clusterRequest((byte) reqType, inSocket, outSocket, csAccepted, this.hostGroup); } } finally { if (inControl != null) { try {inControl.close();} catch (IOException err) {} } if (inSocket != null) { try {inSocket.close();} catch (IOException err) {} } if (outSocket != null) { try {outSocket.close();} catch (IOException err) {} } } } public void shutdown() { // Release all listeners/pools/webapps for (Object listener : this.listeners) ((Listener) listener).destroy(); this.objectPool.destroy(); if (this.cluster != null) this.cluster.destroy(); if (this.hostGroup!=null) this.hostGroup.destroy(); if (this.globalJndiManager != null) { this.globalJndiManager.tearDown(); } if (this.controlThread != null) { this.controlThread.interrupt(); } Thread.yield(); Logger.log(Logger.INFO, RESOURCES, "Launcher.ShutdownOK"); } public boolean isRunning() { return (this.controlThread != null) && this.controlThread.isAlive(); } /** * Main method. This basically just accepts a few args, then initialises the * listener thread. For now, just shut it down with a control-C. */ public static void main(String argv[]) throws IOException { Map args = getArgsFromCommandLine(argv); if (Option.USAGE.isIn(args) || Option.HELP.isIn(args)) { printUsage(); return; } // Check for embedded war deployEmbeddedWarfile(args); // Check for embedded warfile if (!Option.WEBROOT.isIn(args) && !Option.WARFILE.isIn(args) && !Option.WEBAPPS_DIR.isIn(args) && !Option.HOSTS_DIR.isIn(args)) { printUsage(); return; } int maxParameterCount = Option.MAX_PARAM_COUNT.get(args); if (maxParameterCount>0) { HttpUtils.MAX_PARAMETER_COUNT = maxParameterCount; } // Launch try { new Launcher(args); } catch (Throwable err) { Logger.log(Logger.ERROR, RESOURCES, "Launcher.ContainerStartupError", err); } } public static Map getArgsFromCommandLine(String argv[]) throws IOException { Map args = new CmdLineParser(Option.all(Option.class)).parse(argv,"nonSwitch"); // Small hack to allow re-use of the command line parsing inside the control tool String firstNonSwitchArgument = (String) args.get("nonSwitch"); args.remove("nonSwitch"); // Check if the non-switch arg is a file or folder, and overwrite the config if (firstNonSwitchArgument != null) { File webapp = new File(firstNonSwitchArgument); if (webapp.exists()) { if (webapp.isDirectory()) { args.put(Option.WEBROOT.name, firstNonSwitchArgument); } else if (webapp.isFile()) { args.put(Option.WARFILE.name, firstNonSwitchArgument); } } } return args; } protected static void deployEmbeddedWarfile(Map args) throws IOException { String embeddedWarfileName = RESOURCES.getString("Launcher.EmbeddedWarFile"); InputStream embeddedWarfile = Launcher.class.getResourceAsStream( embeddedWarfileName); if (embeddedWarfile != null) { File tempWarfile = File.createTempFile("embedded", ".war").getAbsoluteFile(); tempWarfile.getParentFile().mkdirs(); tempWarfile.deleteOnExit(); String embeddedWebroot = RESOURCES.getString("Launcher.EmbeddedWebroot"); File tempWebroot = new File(tempWarfile.getParentFile(), embeddedWebroot); tempWebroot.mkdirs(); Logger.log(Logger.DEBUG, RESOURCES, "Launcher.CopyingEmbeddedWarfile", tempWarfile.getAbsolutePath()); OutputStream out = new FileOutputStream(tempWarfile, true); int read; byte buffer[] = new byte[2048]; while ((read = embeddedWarfile.read(buffer)) != -1) { out.write(buffer, 0, read); } out.close(); embeddedWarfile.close(); Option.WARFILE.put(args, tempWarfile.getAbsolutePath()); Option.WARFILE.put(args, tempWebroot.getAbsolutePath()); Option.WEBAPPS_DIR.remove(args); Option.HOSTS_DIR.remove(args); } } public static void initLogger(Map args) throws IOException { // Reset the log level int logLevel = WebAppConfiguration.intArg(args, Option.DEBUG.name, Logger.INFO.intValue()); boolean showThrowingLineNo = Option.LOG_THROWING_LINE_NO.get(args); boolean showThrowingThread = Option.LOG_THROWING_THREAD.get(args); OutputStream logStream; if (args.get("logfile") != null) { logStream = new FileOutputStream((String) args.get("logfile")); } else if (WebAppConfiguration.booleanArg(args, "logToStdErr", false)) { logStream = System.err; } else { logStream = System.out; } // Logger.init(logLevel, logStream, showThrowingLineNo, showThrowingThread); Logger.init(Level.parse(String.valueOf(logLevel)), logStream, showThrowingThread); } protected static void printUsage() { // if the caller overrides the usage, use that instead. String usage = USAGE; if(usage==null) usage = RESOURCES.getString("Launcher.UsageInstructions", RESOURCES.getString("ServerVersion")); System.out.println(usage); } /** * Overridable usage screen */ public static String USAGE; } jenkins-winstone-0.9.10-jenkins-47/src/java/winstone/HostGroup.java0000644000175000017500000001172612200024521025615 0ustar jamespagejamespage/* * Copyright 2003-2006 Rick Knowles * Distributed under the terms of either: * - the common development and distribution license (CDDL), v1.0; or * - the GNU Lesser General Public License, v2.1 or later */ package winstone; import winstone.cmdline.Option; import java.io.File; import java.io.IOException; import java.util.HashSet; import java.util.Hashtable; import java.util.Iterator; import java.util.Map; import java.util.Set; /** * Manages the references to individual hosts within the container. This object handles * the mapping of ip addresses and hostnames to groups of webapps, and init and * shutdown of any hosts it manages. * * @author Rick Knowles * @version $Id: HostGroup.java,v 1.4 2006/03/24 17:24:21 rickknowles Exp $ */ public class HostGroup { private final static String DEFAULT_HOSTNAME = "default"; // private Map args; private Map hostConfigs; private String defaultHostName; public HostGroup(Cluster cluster, ObjectPool objectPool, ClassLoader commonLibCL, File commonLibCLPaths[], Map args) throws IOException { // this.args = args; this.hostConfigs = new Hashtable(); // Is this the single or multiple configuration ? Check args File hostDir = Option.HOSTS_DIR.get(args); File webappsDir = Option.WEBAPPS_DIR.get(args); // If host mode if (hostDir == null) { initHost(webappsDir, DEFAULT_HOSTNAME, cluster, objectPool, commonLibCL, commonLibCLPaths, args); this.defaultHostName = DEFAULT_HOSTNAME; Logger.log(Logger.DEBUG, Launcher.RESOURCES, "HostGroup.InitSingleComplete", this.hostConfigs.size() + "", this.hostConfigs.keySet() + ""); } // Otherwise multi-webapp mode else { initMultiHostDir(hostDir, cluster, objectPool, commonLibCL, commonLibCLPaths, args); Logger.log(Logger.DEBUG, Launcher.RESOURCES, "HostGroup.InitMultiComplete", this.hostConfigs.size() + "", this.hostConfigs.keySet() + ""); } } public HostConfiguration getHostByName(String hostname) { if ((hostname != null) && (this.hostConfigs.size() > 1)) { HostConfiguration host = (HostConfiguration) this.hostConfigs.get(hostname); if (host != null) { return host; } } return (HostConfiguration) this.hostConfigs.get(this.defaultHostName); } public void destroy() { Set hostnames = new HashSet(this.hostConfigs.keySet()); for (Object hostname1 : hostnames) { String hostname = (String) hostname1; HostConfiguration host = (HostConfiguration) this.hostConfigs.get(hostname); host.destroy(); this.hostConfigs.remove(hostname); } this.hostConfigs.clear(); } protected void initHost(File webappsDir, String hostname, Cluster cluster, ObjectPool objectPool, ClassLoader commonLibCL, File commonLibCLPaths[], Map args) throws IOException { Logger.log(Logger.DEBUG, Launcher.RESOURCES, "HostGroup.DeployingHost", hostname); HostConfiguration config = new HostConfiguration(hostname, cluster, objectPool, commonLibCL, commonLibCLPaths, args, webappsDir); this.hostConfigs.put(hostname, config); } protected void initMultiHostDir(File hostsDir, Cluster cluster, ObjectPool objectPool, ClassLoader commonLibCL, File commonLibCLPaths[], Map args) throws IOException { if (hostsDir == null) { hostsDir = new File("hosts"); } if (!hostsDir.exists()) { throw new WinstoneException(Launcher.RESOURCES.getString("HostGroup.HostsDirNotFound", hostsDir.getPath())); } else if (!hostsDir.isDirectory()) { throw new WinstoneException(Launcher.RESOURCES.getString("HostGroup.HostsDirIsNotDirectory", hostsDir.getPath())); } else { File children[] = hostsDir.listFiles(); if ((children == null) || (children.length == 0)) { throw new WinstoneException(Launcher.RESOURCES.getString("HostGroup.HostsDirIsEmpty", hostsDir.getPath())); } for (File aChildren : children) { String childName = aChildren.getName(); // Mount directories as host dirs if (aChildren.isDirectory()) { if (!this.hostConfigs.containsKey(childName)) { initHost(aChildren, childName, cluster, objectPool, commonLibCL, commonLibCLPaths, args); } } if ((defaultHostName == null) || childName.equals(DEFAULT_HOSTNAME)) { this.defaultHostName = childName; } } } } } jenkins-winstone-0.9.10-jenkins-47/src/java/winstone/JNDIManager.java0000644000175000017500000000144512200024521025677 0ustar jamespagejamespage/* * Copyright 2003-2006 Rick Knowles * Distributed under the terms of either: * - the common development and distribution license (CDDL), v1.0; or * - the GNU Lesser General Public License, v2.1 or later */ package winstone; /** * Handles setup and teardown of the JNDI context * * @author Rick Knowles * @version $Id: JNDIManager.java,v 1.2 2006/02/28 07:32:47 rickknowles Exp $ */ public interface JNDIManager { /** * Add the objects passed to the constructor to the JNDI Context addresses * specified */ public void setup(); /** * Remove the objects under administration from the JNDI Context, and then * destroy the objects */ public void tearDown(); } jenkins-winstone-0.9.10-jenkins-47/src/java/winstone/ajp13/0000755000175000017500000000000012200024521023727 5ustar jamespagejamespagejenkins-winstone-0.9.10-jenkins-47/src/java/winstone/ajp13/Ajp13Listener.java0000644000175000017500000004275712200024521027175 0ustar jamespagejamespage/* * Copyright 2003-2006 Rick Knowles * Distributed under the terms of either: * - the common development and distribution license (CDDL), v1.0; or * - the GNU Lesser General Public License, v2.1 or later */ package winstone.ajp13; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import java.io.InterruptedIOException; import java.io.OutputStream; import java.io.UnsupportedEncodingException; import java.io.DataInputStream; import java.net.InetAddress; import java.net.ServerSocket; import java.net.Socket; import java.net.SocketException; import java.security.cert.CertificateException; import java.security.cert.CertificateFactory; import java.security.cert.X509Certificate; import java.util.Arrays; import java.util.Iterator; import java.util.Map; import winstone.HostGroup; import winstone.Launcher; import winstone.Listener; import winstone.Logger; import winstone.ObjectPool; import winstone.cmdline.Option; import winstone.RequestHandlerThread; import winstone.WinstoneException; import winstone.WinstoneInputStream; import winstone.WinstoneOutputStream; import winstone.WinstoneRequest; import winstone.WinstoneResourceBundle; import winstone.WinstoneResponse; /** * Implements the main listener daemon thread. This is the class that gets * launched by the command line, and owns the server socket, etc. * * @author mailto: Rick Knowles * @version $Id: Ajp13Listener.java,v 1.12 2006/03/24 17:24:22 rickknowles Exp $ */ public class Ajp13Listener implements Listener, Runnable { public final static WinstoneResourceBundle AJP_RESOURCES = new WinstoneResourceBundle("winstone.ajp13.LocalStrings"); private final static int LISTENER_TIMEOUT = 5000; // every 5s reset the listener socket private final static int CONNECTION_TIMEOUT = 60000; private final static int BACKLOG_COUNT = 1000; private final static int KEEP_ALIVE_TIMEOUT = -1; // private final static int KEEP_ALIVE_SLEEP = 50; // private final static int KEEP_ALIVE_SLEEP_MAX = 500; private final static String TEMPORARY_URL_STASH = "winstone.ajp13.TemporaryURLAttribute"; private HostGroup hostGroup; private ObjectPool objectPool; private int listenPort; private boolean interrupted; private String listenAddress; private ServerSocket serverSocket; /** * Constructor */ public Ajp13Listener(Map args, ObjectPool objectPool, HostGroup hostGroup) { // Load resources this.hostGroup = hostGroup; this.objectPool = objectPool; this.listenPort = Option.AJP13_PORT.get(args); this.listenAddress = Option.AJP13_LISTEN_ADDRESS.get(args); } public boolean start() throws IOException { if (this.listenPort < 0) { return false; } else { ServerSocket ss; try { ss = this.listenAddress == null ? new ServerSocket( this.listenPort, BACKLOG_COUNT) : new ServerSocket( this.listenPort, BACKLOG_COUNT, InetAddress .getByName(this.listenAddress)); } catch (IOException e) { throw (IOException)new IOException("Failed to listen on port "+listenPort).initCause(e); } ss.setSoTimeout(LISTENER_TIMEOUT); Logger.log(Logger.INFO, AJP_RESOURCES, "Ajp13Listener.StartupOK", this.listenPort + ""); this.serverSocket = ss; this.interrupted = false; Thread thread = new Thread(this, Launcher.RESOURCES.getString( "Listener.ThreadName", new String[] { "ajp13", "" + this.listenPort })); thread.setDaemon(true); thread.start(); return true; } } /** * The main run method. This handles the normal thread processing. */ public void run() { try { // Enter the main loop while (!interrupted) { // Get the listener Socket s; try { s = serverSocket.accept(); } catch (java.io.InterruptedIOException err) { s = null; } // if we actually got a socket, process it. Otherwise go around // again if (s != null) this.objectPool.handleRequest(s, this); } // Close server socket serverSocket.close(); serverSocket = null; Logger.log(Logger.INFO, AJP_RESOURCES, "Ajp13Listener.ShutdownOK"); } catch (Throwable err) { Logger.log(Logger.ERROR, AJP_RESOURCES, "Ajp13Listener.ShutdownError", err); } } /** * Interrupts the listener thread. This will trigger a listener shutdown * once the so timeout has passed. */ public void destroy() { this.interrupted = true; } /** * Called by the request handler thread, because it needs specific setup * code for this connection's protocol (ie construction of request/response * objects, in/out streams, etc). * * This implementation parses incoming AJP13 packets, and builds an * outputstream that is capable of writing back the response in AJP13 * packets. */ public void allocateRequestResponse(Socket socket, InputStream inSocket, OutputStream outSocket, RequestHandlerThread handler, boolean iAmFirst) throws SocketException, IOException { WinstoneRequest req = this.objectPool.getRequestFromPool(); WinstoneResponse rsp = this.objectPool.getResponseFromPool(); rsp.setRequest(req); req.setHostGroup(this.hostGroup); // rsp.updateContentTypeHeader("text/html"); if (iAmFirst || (KEEP_ALIVE_TIMEOUT == -1)) socket.setSoTimeout(CONNECTION_TIMEOUT); else socket.setSoTimeout(KEEP_ALIVE_TIMEOUT); Ajp13IncomingPacket headers = null; try { headers = new Ajp13IncomingPacket(inSocket, handler); } catch (InterruptedIOException err) { // keep alive timeout ? ignore if not first if (iAmFirst) { throw err; } else { deallocateRequestResponse(handler, req, rsp, null, null); return; } } finally { try {socket.setSoTimeout(CONNECTION_TIMEOUT);} catch (Throwable err) {} } if (headers.getPacketLength() > 0) { headers.parsePacket("8859_1"); parseSocketInfo(headers, req); req.parseHeaders(Arrays.asList(headers.getHeaders())); String servletURI = parseURILine(headers, req, rsp); req.setAttribute(TEMPORARY_URL_STASH, servletURI); // If content-length present and non-zero, download the other // packets WinstoneInputStream inData; int contentLength = req.getContentLength(); if (contentLength > 0) { byte bodyContent[] = new byte[contentLength]; int position = 0; while (position < contentLength) { outSocket.write(getBodyRequestPacket(Math.min(contentLength - position, 8184))); position = getBodyResponsePacket(inSocket, bodyContent, position); Logger.log(Logger.FULL_DEBUG, AJP_RESOURCES, "Ajp13Listener.ReadBodyProgress", "" + position, "" + contentLength); } inData = new WinstoneInputStream(bodyContent); inData.setContentLength(contentLength); } else inData = new WinstoneInputStream(new byte[0]); req.setInputStream(inData); // Build input/output streams, plus request/response WinstoneOutputStream outData = new Ajp13OutputStream(socket .getOutputStream(), "8859_1"); outData.setResponse(rsp); rsp.setOutputStream(outData); // Set the handler's member variables so it can execute the servlet handler.setRequest(req); handler.setResponse(rsp); handler.setInStream(inData); handler.setOutStream(outData); } } /** * Called by the request handler thread, because it needs specific shutdown * code for this connection's protocol (ie releasing input/output streams, * etc). */ public void deallocateRequestResponse(RequestHandlerThread handler, WinstoneRequest req, WinstoneResponse rsp, WinstoneInputStream inData, WinstoneOutputStream outData) { handler.setInStream(null); handler.setOutStream(null); handler.setRequest(null); handler.setResponse(null); if (req != null) this.objectPool.releaseRequestToPool(req); if (rsp != null) this.objectPool.releaseResponseToPool(rsp); } /** * This is kind of a hack, since we have already parsed the uri to get the * input stream. Just pass back the request uri */ public String parseURI(RequestHandlerThread handler, WinstoneRequest req, WinstoneResponse rsp, WinstoneInputStream inData, Socket socket, boolean iAmFirst) throws IOException { String uri = (String) req.getAttribute(TEMPORARY_URL_STASH); req.removeAttribute(TEMPORARY_URL_STASH); return uri; } /** * Called by the request handler thread, because it needs specific shutdown * code for this connection's protocol if the keep-alive period expires (ie * closing sockets, etc). * * This implementation simply shuts down the socket and streams. */ public void releaseSocket(Socket socket, InputStream inSocket, OutputStream outSocket) throws IOException { // Logger.log(Logger.FULL_DEBUG, "Releasing socket: " + // Thread.currentThread().getName()); inSocket.close(); outSocket.close(); socket.close(); } /** * Extract the header details relating to socket stuff from the ajp13 header * packet */ private void parseSocketInfo(Ajp13IncomingPacket headers, WinstoneRequest req) { req.setServerPort(headers.getServerPort()); req.setRemoteIP(headers.getRemoteAddress()); req.setServerName(headers.getServerName()); req.setLocalPort(headers.getServerPort()); req.setLocalAddr(headers.getServerName()); req.setRemoteIP(headers.getRemoteAddress()); if ((headers.getRemoteHost() != null) && !headers.getRemoteHost().equals("")) req.setRemoteName(headers.getRemoteHost()); else req.setRemoteName(headers.getRemoteAddress()); req.setScheme(headers.isSSL() ? "https" : "http"); req.setIsSecure(headers.isSSL()); } /** * Extract the header details relating to protocol, uri, etc from the ajp13 * header packet */ private String parseURILine(Ajp13IncomingPacket headers, WinstoneRequest req, WinstoneResponse rsp) throws UnsupportedEncodingException { req.setMethod(headers.getMethod()); req.setProtocol(headers.getProtocol()); rsp.setProtocol(headers.getProtocol()); rsp.extractRequestKeepAliveHeader(req); // req.setServletPath(headers.getURI()); // req.setRequestURI(headers.getURI()); // Get query string if supplied for (Object o : headers.getAttributes().keySet()) { String attName = (String) o; if (attName.equals("query_string")) { String qs = (String) headers.getAttributes().get("query_string"); req.setQueryString(qs); // req.getParameters().putAll(WinstoneRequest.extractParameters(qs, // req.getEncoding(), mainResources)); // req.setRequestURI(headers.getURI() + "?" + qs); } else if (attName.equals("ssl_cert")) { String certValue = (String) headers.getAttributes().get( "ssl_cert"); InputStream certStream = new ByteArrayInputStream(certValue .getBytes("8859_1")); X509Certificate certificateArray[] = new X509Certificate[1]; try { certificateArray[0] = (X509Certificate) CertificateFactory .getInstance("X.509").generateCertificate( certStream); } catch (CertificateException err) { Logger.log(Logger.DEBUG, AJP_RESOURCES, "Ajp13Listener.SkippingCert", certValue); } req.setAttribute("javax.servlet.request.X509Certificate", certificateArray); req.setIsSecure(true); } else if (attName.equals("ssl_cipher")) { String cipher = (String) headers.getAttributes().get( "ssl_cipher"); req.setAttribute("javax.servlet.request.cipher_suite", cipher); req.setAttribute("javax.servlet.request.key_size", getKeySize(cipher)); req.setIsSecure(true); } else if (attName.equals("ssl_session")) { req.setAttribute("javax.servlet.request.ssl_session", headers .getAttributes().get("ssl_session")); req.setIsSecure(true); } else Logger.log(Logger.DEBUG, AJP_RESOURCES, "Ajp13Listener.UnknownAttribute", attName, "" + headers.getAttributes().get(attName)); } return headers.getURI(); } private Integer getKeySize(String cipherSuite) { if (cipherSuite.indexOf("_WITH_NULL_") != -1) return 0; else if (cipherSuite.indexOf("_WITH_IDEA_CBC_") != -1) return 128; else if (cipherSuite.indexOf("_WITH_RC2_CBC_40_") != -1) return 40; else if (cipherSuite.indexOf("_WITH_RC4_40_") != -1) return 40; else if (cipherSuite.indexOf("_WITH_RC4_128_") != -1) return 128; else if (cipherSuite.indexOf("_WITH_DES40_CBC_") != -1) return 40; else if (cipherSuite.indexOf("_WITH_DES_CBC_") != -1) return 56; else if (cipherSuite.indexOf("_WITH_3DES_EDE_CBC_") != -1) return 168; else return null; } /** * Tries to wait for extra requests on the same socket. If any are found * before the timeout expires, it exits with a true, indicating a new * request is waiting. If the timeout expires, return a false, instructing * the handler thread to begin shutting down the socket and relase itself. */ public boolean processKeepAlive(WinstoneRequest request, WinstoneResponse response, InputStream inSocket) { return true; } /** * Build the packet needed for asking for a body chunk */ private byte[] getBodyRequestPacket(int desiredPacketLength) { byte getBodyRequestPacket[] = new byte[] { 0x41, 0x42, 0x00, 0x03, 0x06, 0x00, 0x00 }; Ajp13OutputStream.setIntBlock(desiredPacketLength, getBodyRequestPacket, 5); return getBodyRequestPacket; } /** * Process the server response to a get_body_chunk request. This loads the * packet from the stream, and unpacks it into the buffer at the right * place. */ private int getBodyResponsePacket(InputStream in, byte buffer[], int offset) throws IOException { DataInputStream din = new DataInputStream(in); // Get the incoming packet flag byte headerBuffer[] = new byte[4]; din.readFully(headerBuffer); if ((headerBuffer[0] != 0x12) || (headerBuffer[1] != 0x34)) throw new WinstoneException(AJP_RESOURCES .getString("Ajp13Listener.InvalidHeader")); // Read in the whole packet int packetLength = ((headerBuffer[2] & 0xFF) << 8) + (headerBuffer[3] & 0xFF); if (packetLength == 0) return offset; // Look for packet length byte bodyLengthBuffer[] = new byte[2]; din.readFully(bodyLengthBuffer); int bodyLength = ((bodyLengthBuffer[0] & 0xFF) << 8) + (bodyLengthBuffer[1] & 0xFF); din.readFully(buffer, offset, bodyLength); return bodyLength + offset; } // // /** // * Useful method for dumping out the contents of a packet in hex form // */ // public static void packetDump(byte packetBytes[], int packetLength) { // String dump = ""; // for (int n = 0; n < packetLength; n+=16) { // String line = Integer.toHexString((n >> 4) & 0xF) + "0:"; // for (int j = 0; j < Math.min(packetLength - n, 16); j++) // line = line + " " + ((packetBytes[n + j] & 0xFF) < 16 ? "0" : "") + // Integer.toHexString(packetBytes[n + j] & 0xFF); // // line = line + " "; // for (int j = 0; j < Math.min(packetLength - n, 16); j++) { // byte me = (byte) (packetBytes[n + j] & 0xFF); // line = line + (((me > 32) && (me < 123)) ? (char) me : '.'); // } // dump = dump + line + "\r\n"; // } // System.out.println(dump); // } } jenkins-winstone-0.9.10-jenkins-47/src/java/winstone/ajp13/Ajp13OutputStream.java0000644000175000017500000002000312200024521030040 0ustar jamespagejamespage/* * Copyright 2003-2006 Rick Knowles * Distributed under the terms of either: * - the common development and distribution license (CDDL), v1.0; or * - the GNU Lesser General Public License, v2.1 or later */ package winstone.ajp13; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.OutputStream; import java.io.UnsupportedEncodingException; import java.util.Hashtable; import java.util.Map; import javax.servlet.http.Cookie; import winstone.Logger; import winstone.URIUtil; import winstone.WinstoneException; import winstone.WinstoneOutputStream; /** * Extends the winstone output stream, so that the ajp13 protocol requirements * can be fulfilled. * * @author mailto: Rick Knowles * @version $Id: Ajp13OutputStream.java,v 1.7 2007/05/05 00:52:50 rickknowles Exp $ */ public class Ajp13OutputStream extends WinstoneOutputStream { // Container originated packet types byte CONTAINER_SEND_BODY_CHUNK = 0x03; byte CONTAINER_SEND_HEADERS = 0x04; byte CONTAINER_END_RESPONSE = 0x05; // byte CONTAINER_GET_BODY_CHUNK = 0x06; // byte CONTAINER_CPONG_REPLY = 0x09; static Map headerCodes = null; static { headerCodes = new Hashtable(); headerCodes.put("content-type", new byte[] { (byte) 0xA0, 0x01 }); headerCodes.put("content-language", new byte[] { (byte) 0xA0, 0x02 }); headerCodes.put("content-length", new byte[] { (byte) 0xA0, 0x03 }); headerCodes.put("date", new byte[] { (byte) 0xA0, 0x04 }); headerCodes.put("last-modified", new byte[] { (byte) 0xA0, 0x05 }); headerCodes.put("location", new byte[] { (byte) 0xA0, 0x06 }); headerCodes.put("set-cookie", new byte[] { (byte) 0xA0, 0x07 }); headerCodes.put("set-cookie2", new byte[] { (byte) 0xA0, 0x08 }); headerCodes.put("servlet-engine", new byte[] { (byte) 0xA0, 0x09 }); headerCodes.put("server", new byte[] { (byte) 0xA0, 0x09 }); headerCodes.put("status", new byte[] { (byte) 0xA0, 0x0A }); headerCodes.put("www-authenticate", new byte[] { (byte) 0xA0, 0x0B }); } private String headerEncoding; public Ajp13OutputStream(OutputStream outStream, String headerEncoding) { super(outStream, false); this.headerEncoding = headerEncoding; } public void commit() throws IOException { Logger.log(Logger.FULL_DEBUG, Ajp13Listener.AJP_RESOURCES, "Ajp13OutputStream.CommittedBytes", "" + this.bytesCommitted); this.buffer.flush(); // If we haven't written the headers yet, write them out if (!this.committed) { this.owner.validateHeaders(); this.committed = true; ByteArrayOutputStream headerArrayStream = new ByteArrayOutputStream(); for (String header : this.owner.getHeaders()) { int colonPos = header.indexOf(':'); if (colonPos == -1) throw new WinstoneException(Ajp13Listener.AJP_RESOURCES.getString( "Ajp13OutputStream.NoColonHeader", header)); String headerName = URIUtil.noCRLF(header.substring(0, colonPos).trim()); String headerValue = URIUtil.noCRLF(header.substring(colonPos + 1).trim()); byte headerCode[] = (byte[]) headerCodes.get(headerName .toLowerCase()); if (headerCode == null) { headerArrayStream.write(getStringBlock(headerName)); } else { headerArrayStream.write(headerCode); } headerArrayStream.write(getStringBlock(headerValue)); } for (Object o : this.owner.getCookies()) { Cookie cookie = (Cookie) o; String cookieText = this.owner.writeCookie(cookie); int colonPos = cookieText.indexOf(':'); if (colonPos == -1) throw new WinstoneException(Ajp13Listener.AJP_RESOURCES.getString( "Ajp13OutputStream.NoColonHeader", cookieText)); String headerName = cookieText.substring(0, colonPos).trim(); String headerValue = cookieText.substring(colonPos + 1).trim(); byte headerCode[] = (byte[]) headerCodes.get(headerName.toLowerCase()); if (headerCode == null) { headerArrayStream.write(getStringBlock(headerName)); } else { headerArrayStream.write(headerCode); } headerArrayStream.write(getStringBlock(headerValue)); } // Write packet header + prefix + status code + status msg + header // count byte headerArray[] = headerArrayStream.toByteArray(); byte headerPacket[] = new byte[12]; headerPacket[0] = (byte) 0x41; headerPacket[1] = (byte) 0x42; setIntBlock(headerArray.length + 8, headerPacket, 2); headerPacket[4] = CONTAINER_SEND_HEADERS; setIntBlock(this.owner.getStatus(), headerPacket, 5); setIntBlock(0, headerPacket, 7); // empty msg headerPacket[9] = (byte) 0x00; setIntBlock(this.owner.getHeaders().size() + this.owner.getCookies().size(), headerPacket, 10); // Ajp13Listener.packetDump(headerPacket, headerPacket.length); // Ajp13Listener.packetDump(headerArray, headerArray.length); this.outStream.write(headerPacket); this.outStream.write(headerArray); } // Write out the contents of the buffer in max 8k chunks byte bufferContents[] = this.buffer.toByteArray(); int position = 0; while (position < bufferContents.length) { int packetLength = Math.min(bufferContents.length - position, 8184); byte responsePacket[] = new byte[packetLength + 8]; responsePacket[0] = 0x41; responsePacket[1] = 0x42; setIntBlock(packetLength + 4, responsePacket, 2); responsePacket[4] = CONTAINER_SEND_BODY_CHUNK; setIntBlock(packetLength, responsePacket, 5); System.arraycopy(bufferContents, position, responsePacket, 7, packetLength); responsePacket[packetLength + 7] = 0x00; position += packetLength; // Ajp13Listener.packetDump(responsePacket, responsePacket.length); this.outStream.write(responsePacket); } this.buffer.reset(); this.bufferPosition = 0; } public void finishResponse() throws IOException { // Send end response packet byte endResponse[] = new byte[] { 0x41, 0x42, 0x00, 0x02, CONTAINER_END_RESPONSE, 1 }; // Ajp13Listener.packetDump(endResponse, endResponse.length); this.outStream.write(endResponse); } /** * Useful generic method for getting ajp13 format integers in a packet. */ public byte[] getIntBlock(int integer) { byte hi = (byte) (0xFF & (integer >> 8)); byte lo = (byte) (0xFF & (integer - (hi << 8))); return new byte[] { hi, lo }; } /** * Useful generic method for setting ajp13 format integers in a packet. */ public static void setIntBlock(int integer, byte packet[], int offset) { byte hi = (byte) (0xFF & (integer >> 8)); byte lo = (byte) (0xFF & (integer - (hi << 8))); packet[offset] = hi; packet[offset + 1] = lo; } /** * Useful generic method for getting ajp13 format strings in a packet. */ public byte[] getStringBlock(String text) throws UnsupportedEncodingException { byte textBytes[] = text.getBytes(headerEncoding); byte outArray[] = new byte[textBytes.length + 3]; System.arraycopy(getIntBlock(textBytes.length), 0, outArray, 0, 2); System.arraycopy(textBytes, 0, outArray, 2, textBytes.length); outArray[textBytes.length + 2] = 0x00; return outArray; } } jenkins-winstone-0.9.10-jenkins-47/src/java/winstone/ajp13/Ajp13IncomingPacket.java0000644000175000017500000002730612200024521030274 0ustar jamespagejamespage/* * Copyright 2003-2006 Rick Knowles * Distributed under the terms of either: * - the common development and distribution license (CDDL), v1.0; or * - the GNU Lesser General Public License, v2.1 or later */ package winstone.ajp13; import java.io.ByteArrayInputStream; import java.io.DataInput; import java.io.IOException; import java.io.InputStream; import java.io.DataInputStream; import java.util.Hashtable; import java.util.Map; import winstone.Logger; import winstone.RequestHandlerThread; import winstone.WinstoneException; /** * Models a single incoming ajp13 packet. * * Fixes by Cory Osborn 2007/4/3 - IIS related. Thanks * * @author mailto: Rick Knowles * @version $Id: Ajp13IncomingPacket.java,v 1.6 2007/04/03 01:23:19 rickknowles Exp $ */ public class Ajp13IncomingPacket { // Server originated packet types byte SERVER_FORWARD_REQUEST = 0x02; // public static byte SERVER_SHUTDOWN = 0x07; //not implemented // public static byte SERVER_PING = 0x08; //not implemented // public static byte SERVER_CPING = 0x10; //not implemented private int packetLength; private byte packetBytes[]; private byte packetType; private String method; private String protocol; private String uri; private String remoteAddr; private String remoteHost; private String serverName; private int serverPort; private boolean isSSL; private String headers[]; private Map attributes; /** * Constructor */ public Ajp13IncomingPacket(InputStream in, RequestHandlerThread handler) throws IOException { DataInputStream din = new DataInputStream(in); // Get the incoming packet flag byte headerBuffer[] = new byte[4]; din.readFully(headerBuffer); handler.setRequestStartTime(); if ((headerBuffer[0] != 0x12) || (headerBuffer[1] != 0x34)) throw new WinstoneException(Ajp13Listener.AJP_RESOURCES .getString("Ajp13IncomingPacket.InvalidHeader")); // Read in the whole packet packetLength = ((headerBuffer[2] & 0xFF) << 8) + (headerBuffer[3] & 0xFF); packetBytes = new byte[packetLength]; din.readFully(packetBytes); // Ajp13Listener.packetDump(packetBytes, packetBytesRead); } public byte parsePacket(String encoding) throws IOException { DataInputStream di = new DataInputStream(new ByteArrayInputStream(packetBytes)); this.packetType = di.readByte(); if (this.packetType != SERVER_FORWARD_REQUEST) throw new WinstoneException(Ajp13Listener.AJP_RESOURCES.getString( "Ajp13IncomingPacket.UnknownPacketType", this.packetType + "")); // Check for terminator if (packetBytes[packetLength - 1] != (byte) 255) throw new WinstoneException(Ajp13Listener.AJP_RESOURCES .getString("Ajp13IncomingPacket.InvalidTerminator")); this.method = decodeMethodType(di.readByte()); Logger.log(Logger.FULL_DEBUG, Ajp13Listener.AJP_RESOURCES, "Ajp13IncomingPacket.Method", method); // Protocol this.protocol = readString(di, encoding); Logger.log(Logger.FULL_DEBUG, Ajp13Listener.AJP_RESOURCES, "Ajp13IncomingPacket.Protocol", protocol); // URI this.uri = readString(di, encoding); Logger.log(Logger.FULL_DEBUG, Ajp13Listener.AJP_RESOURCES, "Ajp13IncomingPacket.URI", uri); // Remote addr this.remoteAddr = readString(di, encoding); Logger.log(Logger.FULL_DEBUG, Ajp13Listener.AJP_RESOURCES, "Ajp13IncomingPacket.RemoteAddress", remoteAddr); // Remote host this.remoteHost = readString(di, encoding); Logger.log(Logger.FULL_DEBUG, Ajp13Listener.AJP_RESOURCES, "Ajp13IncomingPacket.RemoteHost", remoteHost); // Server name this.serverName = readString(di, encoding); Logger.log(Logger.FULL_DEBUG, Ajp13Listener.AJP_RESOURCES, "Ajp13IncomingPacket.ServerName", serverName); this.serverPort = di.readShort(); Logger.log(Logger.FULL_DEBUG, Ajp13Listener.AJP_RESOURCES, "Ajp13IncomingPacket.ServerPort", "" + serverPort); this.isSSL = di.readBoolean(); Logger.log(Logger.FULL_DEBUG, Ajp13Listener.AJP_RESOURCES, "Ajp13IncomingPacket.SSL", "" + isSSL); // Read headers int headerCount = di.readShort(); Logger.log(Logger.FULL_DEBUG, Ajp13Listener.AJP_RESOURCES, "Ajp13IncomingPacket.HeaderCount", "" + headerCount); this.headers = new String[headerCount]; for (int n = 0; n < headerCount; n++) { // Header name int headerTypeOrLength = di.readShort(); String headerName; if ((headerTypeOrLength&0xFF00) == 0xA000) headerName = decodeHeaderType(headerTypeOrLength&0xFFFF); else { headerName = readString(di, encoding, headerTypeOrLength); } // Header value this.headers[n] = headerName + ": " + readString(di,encoding); Logger.log(Logger.FULL_DEBUG, Ajp13Listener.AJP_RESOURCES, "Ajp13IncomingPacket.Header", this.headers[n]); } // Attribute parsing this.attributes = new Hashtable(); while (true) { byte type = di.readByte(); if (type==-1) break; // end of attributes String attName = decodeAttributeType(type); if (type==0x0A) { attName = readString(di,encoding); } if (type==0x0B) { int intValue = di.readShort(); // SSL key size is not used. Furthermore, the map // is supposed to contain only Strings anyway. So: // just ignore this. // this.attributes.put(attName, attValue); Logger.log(Logger.FULL_DEBUG, Ajp13Listener.AJP_RESOURCES, "Ajp13IncomingPacket.Attribute", attName, intValue); continue; } String attValue = readString (di,encoding); this.attributes.put(attName, attValue); Logger.log(Logger.FULL_DEBUG, Ajp13Listener.AJP_RESOURCES, "Ajp13IncomingPacket.Attribute", attName, attValue); } Logger.log(Logger.FULL_DEBUG, Ajp13Listener.AJP_RESOURCES, "Ajp13IncomingPacket.SuccessfullyReadRequest", "" + packetLength); return this.packetType; } public int getPacketLength() { return this.packetLength; } public String getMethod() { return this.method; } public String getProtocol() { return this.protocol; } public String getURI() { return this.uri; } public String getRemoteAddress() { return this.remoteAddr; } public String getRemoteHost() { return this.remoteHost; } public String getServerName() { return this.serverName; } public int getServerPort() { return this.serverPort; } public boolean isSSL() { return this.isSSL; } public String[] getHeaders() { return this.headers; } public Map getAttributes() { return this.attributes; } /** * Read a single string from the stream */ private String readString(DataInput di, String encoding) throws IOException { // System.out.println("Reading string length: " + length + // " position=" + position + " packetLength=" + packet.length); return readString(di,encoding,di.readShort()); } private String readString(DataInput di, String encoding, int length) throws IOException { // System.out.println("Reading string length: " + length + // " position=" + position + " packetLength=" + packet.length); if (length == -1) return null; if (length == 0) { di.readByte(); // skip over the null terminator return ""; } byte[] buf = new byte[length]; di.readFully(buf); di.readByte(); // skip over the null terminator return new String(buf,encoding); } /** * Decodes the method types into Winstone HTTP method strings */ private String decodeMethodType(byte methodType) { switch (methodType) { case 1: return "OPTIONS"; case 2: return "GET"; case 3: return "HEAD"; case 4: return "POST"; case 5: return "PUT"; case 6: return "DELETE"; case 7: return "TRACE"; case 8: return "PROPFIND"; case 9: return "PROPPATCH"; case 10: return "MKCOL"; case 11: return "COPY"; case 12: return "MOVE"; case 13: return "LOCK"; case 14: return "UNLOCK"; case 15: return "ACL"; case 16: return "REPORT"; case 17: return "VERSION-CONTROL"; case 18: return "CHECKIN"; case 19: return "CHECKOUT"; case 20: return "UNCHECKOUT"; case 21: return "SEARCH"; case 22: return "MKWORKSPACE"; case 23: return "UPDATE"; case 24: return "LABEL"; case 25: return "MERGE"; case 26: return "BASELINE_CONTROL"; case 27: return "MKACTIVITY"; default: return "UNKNOWN"; } } /** * Decodes the header types into Winstone HTTP header strings */ private String decodeHeaderType(int headerType) { switch (headerType) { case 0xA001: return "Accept"; case 0xA002: return "Accept-Charset"; case 0xA003: return "Accept-Encoding"; case 0xA004: return "Accept-Language"; case 0xA005: return "Authorization"; case 0xA006: return "Connection"; case 0xA007: return "Content-Type"; case 0xA008: return "Content-Length"; case 0xA009: return "Cookie"; case 0xA00A: return "Cookie2"; case 0xA00B: return "Host"; case 0xA00C: return "Pragma"; case 0xA00D: return "Referer"; case 0xA00E: return "User-Agent"; default: return null; } } /** * Decodes the header types into Winstone HTTP header strings */ private String decodeAttributeType(byte attributeType) { switch (attributeType) { case 0x01: return "context"; case 0x02: return "servlet_path"; case 0x03: return "remote_user"; case 0x04: return "auth_type"; case 0x05: return "query_string"; case 0x06: return "jvm_route"; case 0x07: return "ssl_cert"; case 0x08: return "ssl_cipher"; case 0x09: return "ssl_session"; case 0x0A: return "req_attribute"; case 0x0B: return "ssl_key_size"; case 0x0C: return "secret"; case 0x0D: return "stored_method"; default: return null; } } } jenkins-winstone-0.9.10-jenkins-47/src/java/winstone/ajp13/LocalStrings.properties0000644000175000017500000000264412200024521030457 0ustar jamespagejamespageAjp13Listener.ShutdownError=Error during AJP13 listener init or shutdown Ajp13Listener.ShutdownOK=AJP13 Listener shutdown successfully Ajp13Listener.StartupOK=AJP13 Listener started: port=[#0] Ajp13Listener.ReadBodyProgress=Read [#0]/[#1] bytes from request body Ajp13Listener.InvalidHeader=Invalid AJP header Ajp13Listener.ShortPacket=Short AJP packet Ajp13Listener.UnknownAttribute=Unknown request attribute ignored: [#0]=[#1] Ajp13Listener.SkippingCert=Skipping invalid SSL certificate: [#0] Ajp13IncomingPacket.InvalidHeader=Invalid AJP header Ajp13IncomingPacket.ShortPacket=Short AJP packet Ajp13IncomingPacket.SuccessfullyReadRequest=Successfully read AJP13 packet - length=[#0] Ajp13IncomingPacket.UnknownPacketType=Unknown AJP packet type - [#0] Ajp13IncomingPacket.InvalidTerminator=Invalid AJP packet terminator Ajp13IncomingPacket.Method=Method: [#0] Ajp13IncomingPacket.Protocol=Protocol: [#0] Ajp13IncomingPacket.URI=URI: [#0] Ajp13IncomingPacket.RemoteAddress=Remote address: [#0] Ajp13IncomingPacket.RemoteHost=RemoteHost: [#0] Ajp13IncomingPacket.ServerName=Server name: [#0] Ajp13IncomingPacket.ServerPort=Server port: [#0] Ajp13IncomingPacket.SSL=SSL: [#0] Ajp13IncomingPacket.HeaderCount=Header Count: [#0] Ajp13IncomingPacket.Header=Header: [#0] Ajp13IncomingPacket.Attribute=Attribute: [#0]=[#1] Ajp13OutputStream.NoColonHeader=No colon header: [#0] Ajp13OutputStream.CommittedBytes=Written [#0] bytes to response body jenkins-winstone-0.9.10-jenkins-47/src/java/winstone/ErrorServlet.java0000644000175000017500000000402012200024521026306 0ustar jamespagejamespage/* * Copyright 2003-2006 Rick Knowles * Distributed under the terms of either: * - the common development and distribution license (CDDL), v1.0; or * - the GNU Lesser General Public License, v2.1 or later */ package winstone; import java.io.IOException; import java.io.PrintWriter; import java.io.StringWriter; import java.io.Writer; import java.util.Date; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServlet; /** * A simple servlet that writes out the body of the error * * @author Rick Knowles * @version $Id: ErrorServlet.java,v 1.3 2006/02/28 07:32:47 rickknowles Exp $ */ public class ErrorServlet extends HttpServlet { public void service(ServletRequest request, ServletResponse response) throws ServletException, IOException { Integer sc = (Integer) request.getAttribute(RequestDispatcher.ERROR_STATUS_CODE); String msg = (String) request.getAttribute(RequestDispatcher.ERROR_MESSAGE); Throwable err = (Throwable) request.getAttribute(RequestDispatcher.ERROR_EXCEPTION); StringWriter sw = new StringWriter(); PrintWriter pw = new PrintWriter(sw); if (err != null) { err.printStackTrace(pw); } else { pw.println("(none)"); } pw.flush(); // If we are here there was no error servlet, so show the default error page String output = Launcher.RESOURCES.getString("WinstoneResponse.ErrorPage", new String[] { sc + "", URIUtil.htmlEscape(msg == null ? "" : msg), URIUtil.htmlEscape(sw.toString()), Launcher.RESOURCES.getString("ServerVersion"), "" + new Date() }); response.setContentLength(output.getBytes(response.getCharacterEncoding()).length); Writer out = response.getWriter(); out.write(output); out.flush(); } } jenkins-winstone-0.9.10-jenkins-47/src/java/winstone/WinstoneInputStream.java0000644000175000017500000000704012200024521027657 0ustar jamespagejamespage/* * Copyright 2003-2006 Rick Knowles * Distributed under the terms of either: * - the common development and distribution license (CDDL), v1.0; or * - the GNU Lesser General Public License, v2.1 or later */ package winstone; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import java.io.DataInputStream; /** * The request stream management class. * * @author Rick Knowles * @version $Id: WinstoneInputStream.java,v 1.4 2006/02/28 07:32:47 rickknowles Exp $ */ public class WinstoneInputStream extends javax.servlet.ServletInputStream { final int BUFFER_SIZE = 4096; private InputStream inData; private Integer contentLength; private int readSoFar; /** * Constructor */ public WinstoneInputStream(InputStream inData) { super(); this.inData = inData; } public WinstoneInputStream(byte inData[]) { this(new ByteArrayInputStream(inData)); } public InputStream getRawInputStream() { return this.inData; } public void setContentLength(int length) { this.contentLength = length; this.readSoFar = 0; } public int read() throws IOException { if (this.contentLength == null) { int data = this.inData.read(); // System.out.println("Char: " + (char) data); return data; } else if (this.contentLength > this.readSoFar) { this.readSoFar++; int data = this.inData.read(); // System.out.println("Char: " + (char) data); return data; } else return -1; } public int read(byte[] b, int off, int len) throws IOException { if (this.contentLength == null) { return this.inData.read(b,off,len); } else { len = Math.min(len, this.contentLength -this.readSoFar); if (len<=0) return -1; int r = this.inData.read(b,off,len); if (r<0) return r; // EOF this.readSoFar += r; return r; } } /** * Reads like {@link DataInputStream#readFully(byte[], int, int)}, except EOF before * fully reading it won't result in an exception. * * @return number of bytes read. */ public int readAsMuchAsPossible(byte[] buf, int offset, int len) throws IOException { int total = 0; while (total < len) { int count = read(buf, offset + total, len - total); if (count < 0) break; total += count; } return total; } public void finishRequest() { // this.inData = null; // byte content[] = this.dump.toByteArray(); // com.rickknowles.winstone.ajp13.Ajp13Listener.packetDump(content, // content.length); } public int available() throws IOException { return this.inData.available(); } /** * Wrapper for the servletInputStream's readline method */ public byte[] readLine() throws IOException { // System.out.println("ReadLine()"); byte buffer[] = new byte[BUFFER_SIZE]; int charsRead = super.readLine(buffer, 0, BUFFER_SIZE); if (charsRead == -1) { Logger.log(Logger.DEBUG, Launcher.RESOURCES, "WinstoneInputStream.EndOfStream"); return new byte[0]; } byte outBuf[] = new byte[charsRead]; System.arraycopy(buffer, 0, outBuf, 0, charsRead); return outBuf; } } jenkins-winstone-0.9.10-jenkins-47/src/java/winstone/BoundedExecutorService.java0000644000175000017500000000722312200024521030300 0ustar jamespagejamespagepackage winstone; import java.util.LinkedList; import java.util.List; import java.util.concurrent.AbstractExecutorService; import java.util.concurrent.Executor; import java.util.concurrent.ExecutorService; import java.util.concurrent.RejectedExecutionException; import java.util.concurrent.SynchronousQueue; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; /** * Wraps {@link Executor} so that we only ask the wrapped Executor to execute N number of tasks * at any given time. * *

* The intention is to use this with {@link ThreadPoolExecutor} with {@link SynchronousQueue} * with unbounded max capacity (so that for up to N tasks we keep creating more threads for work, * but beyond that we start to push the tasks into the queue of an infinite capacity.) * *

* This is necessary because {@link ThreadPoolExecutor} tries to push work into the queue * first and only create more threads once the queue is full, so for a queue with infinite * capacity it'll never create threads beyond the core pool size. * See http://www.kimchy.org/juc-executorservice-gotcha/ for more discussion of this. * *

* Because there's no call back to tell us when the wrapped {@link ExecutorService} has * finished executing something, this class needs to hand out the next task slightly * before the wrapped {@link ExecutorService} is done with the previous task. The net result * is that the wrapped {@link ExecutorService} will end up running N+1 threads (of which * 1 is almost always idle.) I'm not sure how to fix this. * * @author Kohsuke Kawaguchi */ public class BoundedExecutorService extends AbstractExecutorService { /** * The FIFO queue of tasks waiting to be handed to the wrapped {@link ExecutorService}. */ private final List tasks = new LinkedList(); private final ExecutorService base; private final int max; /** * How many tasks the wrapped {@link ExecutorService} is executing right now? * Touched only in a synchronized block. */ private int current; private boolean isShutdown = false; public BoundedExecutorService(ExecutorService base, int max) { this.base = base; this.max = max; } public synchronized void execute(final Runnable r) { if (isShutdown) throw new RejectedExecutionException("already shut down"); tasks.add(r); if (current < max) scheduleNext(); } private synchronized void scheduleNext() { if (tasks.isEmpty()) { if (isShutdown) base.shutdown(); return; } final Runnable task = tasks.remove(0); base.execute(new Runnable() { public void run() { try { task.run(); } finally { done(); } } }); current++; } private synchronized void done() { current--; scheduleNext(); // we already know that current shutdownNow() { isShutdown = true; List r = base.shutdownNow(); r.addAll(tasks); tasks.clear(); return r; } public boolean isShutdown() { return isShutdown; } public boolean isTerminated() { return base.isTerminated(); } public boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException { return base.awaitTermination(timeout,unit); } }jenkins-winstone-0.9.10-jenkins-47/src/java/winstone/WinstoneOutputStream.java0000644000175000017500000002270212200024521030062 0ustar jamespagejamespage/* * Copyright 2003-2006 Rick Knowles * Distributed under the terms of either: * - the common development and distribution license (CDDL), v1.0; or * - the GNU Lesser General Public License, v2.1 or later */ package winstone; import java.io.BufferedOutputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.OutputStream; import java.util.Stack; import javax.servlet.http.Cookie; /** * Matches the socket output stream to the servlet output. * * @author Rick Knowles * @version $Id: WinstoneOutputStream.java,v 1.19 2007/10/14 14:48:14 rickknowles Exp $ */ public class WinstoneOutputStream extends javax.servlet.ServletOutputStream { private static final int DEFAULT_BUFFER_SIZE = 8192; private static final byte[] CR_LF = "\r\n".getBytes(); protected OutputStream outStream; protected long bufferSize; protected long bufferPosition; protected long bytesCommitted; protected ByteArrayOutputStream buffer; protected boolean committed; protected boolean bodyOnly; protected WinstoneResponse owner; protected boolean disregardMode = false; protected boolean closed = false; protected Stack includeByteStreams; /** * Constructor */ public WinstoneOutputStream(OutputStream out, boolean bodyOnlyForInclude) { this.outStream = new ClientOutputStream(out); this.bodyOnly = bodyOnlyForInclude; this.bufferSize = DEFAULT_BUFFER_SIZE; this.committed = false; // this.headersWritten = false; this.buffer = new ByteArrayOutputStream(); } public void setResponse(WinstoneResponse response) { this.owner = response; } public long getBufferSize() { return this.bufferSize; } public void setBufferSize(int bufferSize) { if (this.owner.isCommitted()) { throw new IllegalStateException(Launcher.RESOURCES.getString( "WinstoneOutputStream.AlreadyCommitted")); } this.bufferSize = bufferSize; } public boolean isCommitted() { return this.committed; } public long getOutputStreamLength() { return this.bytesCommitted + this.bufferPosition; } public long getBytesCommitted() { return this.bytesCommitted; } public void setDisregardMode(boolean disregard) { this.disregardMode = disregard; } public void setClosed(boolean closed) { this.closed = closed; } public void write(int oneChar) throws IOException { if (this.disregardMode || this.closed) { return; } String contentLengthHeader = this.owner.getHeader(WinstoneResponse.CONTENT_LENGTH_HEADER); if ((contentLengthHeader != null) && (this.bytesCommitted >= Long.parseLong(contentLengthHeader))) { return; } // System.out.println("Out: " + this.bufferPosition + " char=" + (char)oneChar); this.buffer.write(oneChar); commit(contentLengthHeader, 1); } public void write(byte[] b, int off, int len) throws IOException { if (this.disregardMode || this.closed) { return; } String contentLengthHeader = this.owner.getHeader(WinstoneResponse.CONTENT_LENGTH_HEADER); if ((contentLengthHeader != null) && (this.bytesCommitted+len > Long.parseLong(contentLengthHeader))) { return; } this.buffer.write(b,off,len); commit(contentLengthHeader,len); } private void commit(String contentLengthHeader, int len) throws IOException { this.bufferPosition+= len; // if (this.headersWritten) if (this.bufferPosition >= this.bufferSize) { commit(); } else if ((contentLengthHeader != null) && ((this.bufferPosition + this.bytesCommitted) >= Long.parseLong(contentLengthHeader))) { commit(); } } public void commit() throws IOException { this.buffer.flush(); // If we haven't written the headers yet, write them out if (!this.committed && !this.bodyOnly) { this.owner.validateHeaders(); this.committed = true; Logger.log(Logger.DEBUG, Launcher.RESOURCES, "WinstoneOutputStream.CommittingOutputStream"); int statusCode = this.owner.getStatus(); String reason = Launcher.RESOURCES.getString("WinstoneOutputStream.reasonPhrase." + statusCode); String statusLine = this.owner.getProtocol() + " " + statusCode + " " + (reason == null ? "No reason" : reason); OutputStream o = new BufferedOutputStream(outStream); o.write(statusLine.getBytes("8859_1")); o.write(CR_LF); Logger.log(Logger.FULL_DEBUG, Launcher.RESOURCES, "WinstoneOutputStream.ResponseStatus", statusLine); // Write headers and cookies for (String header : this.owner.getHeaders()) { o.write(URIUtil.noCRLF(header).getBytes("8859_1")); o.write(CR_LF); Logger.log(Logger.FULL_DEBUG, Launcher.RESOURCES, "WinstoneOutputStream.Header", header); } if (!this.owner.getHeaders().isEmpty()) { for (Object o1 : this.owner.getCookies()) { Cookie cookie = (Cookie) o1; String cookieText = this.owner.writeCookie(cookie); o.write(cookieText.getBytes("8859_1")); o.write(CR_LF); Logger.log(Logger.FULL_DEBUG, Launcher.RESOURCES, "WinstoneOutputStream.Header", cookieText); } } o.write(CR_LF); o.flush(); // Logger.log(Logger.FULL_DEBUG, // Launcher.RESOURCES.getString("HttpProtocol.OutHeaders") + out.toString()); } byte content[] = this.buffer.toByteArray(); this.buffer.reset(); this.bufferPosition = 0; // winstone.ajp13.Ajp13Listener.packetDump(content, content.length); // this.buffer.writeTo(this.outStream); long commitLength = content.length; String contentLengthHeader = this.owner.getHeader(WinstoneResponse.CONTENT_LENGTH_HEADER); if (contentLengthHeader != null) { commitLength = Math.min (Long.parseLong(contentLengthHeader) - this.bytesCommitted, (long)content.length); } if (commitLength > 0) { this.outStream.write(content, 0, (int)commitLength); } this.outStream.flush(); Logger.log(Logger.FULL_DEBUG, Launcher.RESOURCES, "WinstoneOutputStream.CommittedBytes", "" + (this.bytesCommitted + commitLength)); this.bytesCommitted += commitLength; } public void reset() { if (isCommitted()) throw new IllegalStateException(Launcher.RESOURCES .getString("WinstoneOutputStream.AlreadyCommitted")); else { Logger.log(Logger.FULL_DEBUG, Launcher.RESOURCES, "WinstoneOutputStream.ResetBuffer", this.bufferPosition + ""); this.buffer.reset(); this.bufferPosition = 0; this.bytesCommitted = 0; } } public void finishResponse() throws IOException { this.outStream.flush(); this.outStream = null; } public void flush() throws IOException { if (this.disregardMode) { return; } Logger.log(Logger.FULL_DEBUG, Launcher.RESOURCES, "WinstoneOutputStream.Flushing"); this.buffer.flush(); this.commit(); } public void close() throws IOException { if (!isCommitted() && !this.disregardMode && !this.closed && (this.owner.getHeader(WinstoneResponse.CONTENT_LENGTH_HEADER) == null)) { if ((this.owner != null) && !this.bodyOnly) { this.owner.setContentLength((int)getOutputStreamLength()); } } flush(); } // Include related buffering public boolean isIncluding() { return (this.includeByteStreams != null && !this.includeByteStreams.isEmpty()); } public void startIncludeBuffer() { synchronized (this.buffer) { if (this.includeByteStreams == null) { this.includeByteStreams = new Stack(); } } this.includeByteStreams.push(new ByteArrayOutputStream()); } public void finishIncludeBuffer() throws IOException { if (isIncluding()) { ByteArrayOutputStream body = (ByteArrayOutputStream) this.includeByteStreams.pop(); OutputStream topStream = this.outStream; if (!this.includeByteStreams.isEmpty()) { topStream = (OutputStream) this.includeByteStreams.peek(); } byte bodyArr[] = body.toByteArray(); if (bodyArr.length > 0) { topStream.write(bodyArr); } body.close(); } } public void clearIncludeStackForForward() throws IOException { if (isIncluding()) { for (Object includeByteStream : this.includeByteStreams) { ((ByteArrayOutputStream) includeByteStream).close(); } this.includeByteStreams.clear(); } } } jenkins-winstone-0.9.10-jenkins-47/src/java/winstone/Mapping.java0000644000175000017500000002030412200024521025246 0ustar jamespagejamespage/* * Copyright 2003-2006 Rick Knowles * Distributed under the terms of either: * - the common development and distribution license (CDDL), v1.0; or * - the GNU Lesser General Public License, v2.1 or later */ package winstone; /** * Encapsulates the parsing of URL patterns, as well as the mapping of a * url pattern to a servlet instance * * @author Rick Knowles * @version $Id: Mapping.java,v 1.9 2007/04/23 02:55:35 rickknowles Exp $ */ public class Mapping implements java.util.Comparator { public static final int EXACT_PATTERN = 1; public static final int FOLDER_PATTERN = 2; public static final int EXTENSION_PATTERN = 3; public static final int DEFAULT_SERVLET = 4; public static final String STAR = "*"; public static final String SLASH = "/"; private String urlPattern; private String linkName; // used to map filters to a specific servlet by // name private String mappedTo; private int patternType; private boolean isPatternFirst; // ie is this a blah* pattern, not *blah // (extensions only) protected Mapping(String mappedTo) { this.mappedTo = mappedTo; } /** * Factory constructor method - this parses the url pattern into pieces we can use to match * against incoming URLs. */ public static Mapping createFromURL(String mappedTo, String pattern) { if ((pattern == null) || (mappedTo == null)) throw new WinstoneException(Launcher.RESOURCES.getString( "Mapping.InvalidMount", new String[] { mappedTo, pattern })); // Compatibility hacks - add a leading slash if one is not found and not // an extension mapping if (!pattern.equals("") && !pattern.startsWith(STAR) && !pattern.startsWith(SLASH)) { pattern = SLASH + pattern; } else if (pattern.equals(STAR)) { Logger.log(Logger.WARNING, Launcher.RESOURCES, "Mapping.RewritingStarMount"); pattern = SLASH + STAR; } Mapping me = new Mapping(mappedTo); int firstStarPos = pattern.indexOf(STAR); int lastStarPos = pattern.lastIndexOf(STAR); int patternLength = pattern.length(); // check for default servlet, ie mapping = exactly / if (pattern.equals(SLASH)) { me.urlPattern = ""; me.patternType = DEFAULT_SERVLET; } else if (firstStarPos == -1) { me.urlPattern = pattern; me.patternType = EXACT_PATTERN; } // > 1 star = error else if (firstStarPos != lastStarPos) throw new WinstoneException(Launcher.RESOURCES.getString( "Mapping.InvalidMount", new String[] { mappedTo, pattern })); // check for folder style mapping (ends in /*) else if (pattern.indexOf(SLASH + STAR) == (patternLength - (SLASH + STAR).length())) { me.urlPattern = pattern.substring(0, pattern.length() - (SLASH + STAR).length()); me.patternType = FOLDER_PATTERN; } // check for non-extension match else if (pattern.indexOf(SLASH) != -1) throw new WinstoneException(Launcher.RESOURCES.getString( "Mapping.InvalidMount", new String[] { mappedTo, pattern })); // check for extension match at the beginning (eg *blah) else if (firstStarPos == 0) { me.urlPattern = pattern.substring(STAR.length()); me.patternType = EXTENSION_PATTERN; me.isPatternFirst = false; } // check for extension match at the end (eg blah*) else if (firstStarPos == (patternLength - STAR.length())) { me.urlPattern = pattern.substring(0, patternLength - STAR.length()); me.patternType = EXTENSION_PATTERN; me.isPatternFirst = true; } else throw new WinstoneException(Launcher.RESOURCES.getString( "Mapping.InvalidMount", new String[] { mappedTo, pattern })); Logger.log(Logger.FULL_DEBUG, Launcher.RESOURCES, "Mapping.MappedPattern", mappedTo, pattern); return me; } /** * Factory constructor method - this turns a servlet name into a mapping element */ public static Mapping createFromLink(String mappedTo, String linkName) { if ((linkName == null) || (mappedTo == null)) throw new WinstoneException(Launcher.RESOURCES.getString( "Mapping.InvalidLink", new String[] { mappedTo, linkName })); Mapping me = new Mapping(mappedTo); me.linkName = linkName; return me; } public int getPatternType() { return this.patternType; } public String getUrlPattern() { return this.urlPattern; } public String getMappedTo() { return this.mappedTo; } public String getLinkName() { return this.linkName; } /** * Try to match this pattern against the incoming url * * @param inputPattern The URL we want to check for a match * @param servletPath An empty stringbuffer for the servletPath of a successful match * @param pathInfo An empty stringbuffer for the pathInfo of a successful match * @return true if the match is successful */ public boolean match(String inputPattern, StringBuffer servletPath, StringBuffer pathInfo) { switch (this.patternType) { case FOLDER_PATTERN: if (inputPattern.startsWith(this.urlPattern + '/') || inputPattern.equals(this.urlPattern)) { if (servletPath != null) servletPath.append(WinstoneRequest.decodeURLToken(this.urlPattern,false)); if (pathInfo != null) pathInfo.append(WinstoneRequest.decodeURLToken(inputPattern.substring(this.urlPattern.length()))); return true; } else return false; case EXTENSION_PATTERN: // Strip down to the last item in the path int slashPos = inputPattern.lastIndexOf(SLASH); if ((slashPos == -1) || (slashPos == inputPattern.length() - 1)) return false; String fileName = inputPattern.substring(slashPos + 1); if ((this.isPatternFirst && fileName.startsWith(this.urlPattern)) || (!this.isPatternFirst && fileName.endsWith(this.urlPattern))) { if (servletPath != null) servletPath.append(WinstoneRequest.decodeURLToken(inputPattern,false)); return true; } else return false; case EXACT_PATTERN: if (inputPattern.equals(this.urlPattern)) { if (servletPath != null) servletPath.append(WinstoneRequest.decodeURLToken(inputPattern,false)); return true; } else return false; case DEFAULT_SERVLET: if (servletPath != null) servletPath.append(WinstoneRequest.decodeURLToken(inputPattern,false)); return true; default: return false; } } /** * Used to compare two url patterns. Always sorts so that lowest pattern * type then longest path come first. */ public int compare(Object objOne, Object objTwo) { Mapping one = (Mapping) objOne; Mapping two = (Mapping) objTwo; Integer intOne = one.getPatternType(); Integer intTwo = two.getPatternType(); int order = -1 * intOne.compareTo(intTwo); if (order != 0) { return order; } if (one.getLinkName() != null) { // servlet name mapping - just alphabetical sort return one.getLinkName().compareTo(two.getLinkName()); } else { return -1 * one.getUrlPattern().compareTo(two.getUrlPattern()); } } public String toString() { return this.linkName != null ? "Link:" + this.linkName : "URLPattern:type=" + this.patternType + ",pattern=" + this.urlPattern; } } jenkins-winstone-0.9.10-jenkins-47/src/java/winstone/WinstoneRequest.java0000644000175000017500000014362112200024521027042 0ustar jamespagejamespage/* * Copyright 2003-2006 Rick Knowles * Distributed under the terms of either: * - the common development and distribution license (CDDL), v1.0; or * - the GNU Lesser General Public License, v2.1 or later */ package winstone; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.UnsupportedEncodingException; import java.io.ByteArrayOutputStream; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.security.Principal; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Date; import java.util.Enumeration; import java.util.HashMap; import java.util.HashSet; import java.util.Hashtable; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Random; import java.util.Set; import java.util.Stack; import java.util.StringTokenizer; import java.util.TimeZone; import javax.servlet.ServletInputStream; import javax.servlet.ServletRequestAttributeEvent; import javax.servlet.ServletRequestAttributeListener; import javax.servlet.ServletRequestListener; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpSession; import javax.servlet.http.HttpUtils; /** * Implements the request interface required by the servlet spec. * * @author Rick Knowles * @version $Id: WinstoneRequest.java,v 1.38 2007/10/28 16:29:02 rickknowles Exp $ */ public class WinstoneRequest implements HttpServletRequest { protected static DateFormat headerDF = new SimpleDateFormat( "EEE, dd MMM yyyy HH:mm:ss z", Locale.US); protected static Random rnd = null; static { headerDF.setTimeZone(TimeZone.getTimeZone("GMT")); rnd = new Random(System.currentTimeMillis()); } // Request header constants static final String CONTENT_LENGTH_HEADER = "Content-Length"; static final String CONTENT_TYPE_HEADER = "Content-Type"; static final String AUTHORIZATION_HEADER = "Authorization"; static final String LOCALE_HEADER = "Accept-Language"; static final String HOST_HEADER = "Host"; static final String IN_COOKIE_HEADER1 = "Cookie"; static final String IN_COOKIE_HEADER2 = "Cookie2"; static final String METHOD_HEAD = "HEAD"; static final String METHOD_GET = "GET"; static final String METHOD_POST = "POST"; static final String POST_PARAMETERS = "application/x-www-form-urlencoded"; static final String FORWARDED_FOR = "X-Forwarded-For"; protected Map attributes; protected Map parameters; protected Stack attributesStack; protected Stack parametersStack; // protected Map forwardedParameters; protected String headers[]; protected Cookie cookies[]; protected String method; protected String scheme; protected String serverName; protected String requestURI; protected String servletPath; protected String pathInfo; protected String queryString; protected String protocol; protected int contentLength; protected String contentType; protected String encoding; protected int serverPort; protected String remoteIP; protected String remoteName; protected int remotePort; protected String localAddr; protected String localName; protected int localPort; /** * If true, it indicates that the request body was already consumed because of the call to {@link #getParameterMap()} * (or its sibling), which requires implicit form parameter parsing. * * If false, it indicates that the request body shall not be consumed by the said method, because the application * already called {@link #getInputStream()} and showed the intent to parse the request body on its own. * * If null, it indicates that we haven't come to that decision. */ protected Boolean parsedParameters; protected Map requestedSessionIds; protected Map currentSessionIds; protected String deadRequestedSessionId; protected List locales; protected String authorization; protected boolean isSecure; protected WinstoneInputStream inputData; protected BufferedReader inputReader; protected ServletConfiguration servletConfig; protected WebAppConfiguration webappConfig; protected HostGroup hostGroup; protected AuthenticationPrincipal authenticatedUser; protected ServletRequestAttributeListener requestAttributeListeners[]; protected ServletRequestListener requestListeners[]; private MessageDigest md5Digester; private Set usedSessions; /** * InputStream factory method. */ public WinstoneRequest() { this.attributes = new Hashtable(); this.parameters = new SizeRestrictedHashtable(HttpUtils.MAX_PARAMETER_COUNT); this.locales = new ArrayList(); this.attributesStack = new Stack(); this.parametersStack = new Stack(); // this.forwardedParameters = new Hashtable(); this.requestedSessionIds = new Hashtable(); this.currentSessionIds = new Hashtable(); this.usedSessions = new HashSet(); this.contentLength = -1; this.isSecure = false; try { this.md5Digester = MessageDigest.getInstance("MD5"); } catch (NoSuchAlgorithmException err) { throw new WinstoneException( "MD5 digester unavailable - what the ...?"); } } /** * Resets the request to be reused */ public void cleanUp() { this.requestListeners = null; this.requestAttributeListeners = null; this.attributes.clear(); this.parameters.clear(); this.attributesStack.clear(); this.parametersStack.clear(); // this.forwardedParameters.clear(); this.usedSessions.clear(); this.headers = null; this.cookies = null; this.method = null; this.scheme = null; this.serverName = null; this.requestURI = null; this.servletPath = null; this.pathInfo = null; this.queryString = null; this.protocol = null; this.contentLength = -1; this.contentType = null; this.encoding = null; this.inputData = null; this.inputReader = null; this.servletConfig = null; this.webappConfig = null; this.hostGroup = null; this.serverPort = -1; this.remoteIP = null; this.remoteName = null; this.remotePort = -1; this.localAddr = null; this.localName = null; this.localPort = -1; this.parsedParameters = null; this.requestedSessionIds.clear(); this.currentSessionIds.clear(); this.deadRequestedSessionId = null; this.locales.clear(); this.authorization = null; this.isSecure = false; this.authenticatedUser = null; } /** * Steps through the header array, searching for the first header matching */ private String extractFirstHeader(String name) { int len = name.length(); for (String header : this.headers) { if (header.length() > len && header.charAt(len) == ':' && header.regionMatches(true, 0, name, 0, len)) { return header.substring(len + 1).trim(); // 1 for colon } } return null; } private Collection extractHeaderNameList() { Collection headerNames = new HashSet(); for (String name : this.headers) { int colonPos = name.indexOf(':'); headerNames.add(name.substring(0, colonPos)); } return headerNames; } public Map getAttributes() { return this.attributes; } public Map getParameters() { return this.parameters; } // // public Map getForwardedParameters() { // return this.forwardedParameters; // } public Stack getAttributesStack() { return this.attributesStack; } public Stack getParametersStack() { return this.parametersStack; } public Map getCurrentSessionIds() { return this.currentSessionIds; } public Map getRequestedSessionIds() { return this.requestedSessionIds; } public String getDeadRequestedSessionId() { return this.deadRequestedSessionId; } public HostGroup getHostGroup() { return this.hostGroup; } public WebAppConfiguration getWebAppConfig() { return this.webappConfig; } public ServletConfiguration getServletConfig() { return this.servletConfig; } public String getEncoding() { return this.encoding; } public Boolean getParsedParameters() { return this.parsedParameters; } public List getListLocales() { return this.locales; } public void setInputStream(WinstoneInputStream inputData) { this.inputData = inputData; } public void setHostGroup(HostGroup hostGroup) { this.hostGroup = hostGroup; } public void setWebAppConfig(WebAppConfiguration webappConfig) { this.webappConfig = webappConfig; } public void setServletConfig(ServletConfiguration servletConfig) { this.servletConfig = servletConfig; } public void setServerPort(int port) { this.serverPort = port; } public void setRemoteIP(String remoteIP) { this.remoteIP = remoteIP; } public void setRemoteName(String name) { this.remoteName = name; } public void setRemotePort(int port) { this.remotePort = port; } public void setLocalAddr(String ip) { this.localName = ip; } public void setLocalName(String name) { this.localName = name; } public void setLocalPort(int port) { this.localPort = port; } public void setMethod(String method) { this.method = method; } public void setIsSecure(boolean isSecure) { this.isSecure = isSecure; } public void setQueryString(String queryString) { this.queryString = queryString; } public void setServerName(String name) { this.serverName = name; } public void setRequestURI(String requestURI) { this.requestURI = requestURI; } public void setScheme(String scheme) { this.scheme = scheme; } public void setServletPath(String servletPath) { this.servletPath = servletPath; } public void setPathInfo(String pathInfo) { this.pathInfo = pathInfo; } public void setProtocol(String protocolString) { this.protocol = protocolString; } public void setRemoteUser(AuthenticationPrincipal user) { this.authenticatedUser = user; } public void setContentLength(int len) { this.contentLength = len; } public void setContentType(String type) { this.contentType = type; } public void setAuthorization(String auth) { this.authorization = auth; } public void setLocales(List locales) { this.locales = locales; } public void setCurrentSessionIds(Map currentSessionIds) { this.currentSessionIds = currentSessionIds; } public void setRequestedSessionIds(Map requestedSessionIds) { this.requestedSessionIds = requestedSessionIds; } public void setDeadRequestedSessionId(String deadRequestedSessionId) { this.deadRequestedSessionId = deadRequestedSessionId; } public void setEncoding(String encoding) { this.encoding = encoding; } public void setParsedParameters(Boolean parsed) { this.parsedParameters = parsed; } public void setRequestListeners(ServletRequestListener rl[]) { this.requestListeners = rl; } public void setRequestAttributeListeners( ServletRequestAttributeListener ral[]) { this.requestAttributeListeners = ral; } /** * Gets parameters from the url encoded parameter string */ public static void extractParameters(String urlEncodedParams, String encoding, Map outputParams, boolean overwrite) { Logger.log(Logger.DEBUG, Launcher.RESOURCES, "WinstoneRequest.ParsingParameters", urlEncodedParams, encoding); StringTokenizer st = new StringTokenizer(urlEncodedParams, "&", false); Set overwrittenParamNames = null; while (st.hasMoreTokens()) { String token = st.nextToken(); int equalPos = token.indexOf('='); try { String decodedName = decodeURLToken(equalPos == -1 ? token : token.substring(0, equalPos), encoding==null?"UTF-8":encoding ); String decodedValue = (equalPos == -1 ? "" : decodeURLToken(token.substring(equalPos + 1), encoding==null?"UTF-8":encoding)); Object already; if (overwrite) { if (overwrittenParamNames == null) { overwrittenParamNames = new HashSet(); } if (!overwrittenParamNames.contains(decodedName)) { overwrittenParamNames.add(decodedName); outputParams.remove(decodedName); } } already = outputParams.get(decodedName); if (already == null) { outputParams.put(decodedName, decodedValue); } else if (already instanceof String) { String pair[] = new String[2]; pair[0] = (String) already; pair[1] = decodedValue; outputParams.put(decodedName, pair); } else if (already instanceof String[]) { String alreadyArray[] = (String[]) already; String oneMore[] = new String[alreadyArray.length + 1]; System.arraycopy(alreadyArray, 0, oneMore, 0, alreadyArray.length); oneMore[oneMore.length - 1] = decodedValue; outputParams.put(decodedName, oneMore); } else { Logger.log(Logger.WARNING, Launcher.RESOURCES, "WinstoneRequest.UnknownParameterType", decodedName + " = " + decodedValue.getClass()); } } catch (UnsupportedEncodingException err) { Logger.log(Logger.ERROR, Launcher.RESOURCES, "WinstoneRequest.ErrorParameters", err); } } } public static String decodeURLToken(String in) { return decodeURLToken(in,true); } /** * For decoding the URL encoding used on query strings */ public static String decodeURLToken(String in,String encoding) throws UnsupportedEncodingException { return decodeURLToken(in,encoding,true); } public static String decodeURLToken(String in, boolean isQueryString) { try { return decodeURLToken(in,"UTF-8",isQueryString); } catch (UnsupportedEncodingException e) { throw new AssertionError(); // impossible } } /** * @param isQueryString * Decode query string, where '+' is an escape for ' '. Otherwise * decode as path token, where '+' is not an escape character. */ public static String decodeURLToken(String in,String encoding, boolean isQueryString) throws UnsupportedEncodingException { ByteArrayOutputStream baos = new ByteArrayOutputStream(); for (int n = 0; n < in.length(); n++) { char thisChar = in.charAt(n); if (thisChar == '+' && isQueryString) baos.write(' '); else if (thisChar == '%') { String token = in.substring(Math.min(n + 1, in.length()), Math.min(n + 3, in.length())); try { int decoded = Integer.parseInt(token, 16); baos.write(decoded); n += 2; } catch (RuntimeException err) { Logger.log(Logger.WARNING, Launcher.RESOURCES, "WinstoneRequest.InvalidURLTokenChar", token); baos.write(thisChar); } } else baos.write(thisChar); } return new String(baos.toByteArray(),encoding); } public void discardRequestBody() { if (getContentLength() > 0) { try { Logger.log(Logger.DEBUG, Launcher.RESOURCES, "WinstoneResponse.ForceBodyParsing"); // if there's any input that we haven't consumed, throw them away, so that the next request parsing // will start from the right position. byte buffer[] = new byte[2048]; while ((this.inputData.read(buffer))!=-1) ; } catch (IOException err) { Logger.log(Logger.DEBUG, Launcher.RESOURCES, "WinstoneResponse.ErrorForceBodyParsing", err); } } } /** * This takes the parameters in the body of the request and puts them into * the parameters map. */ public void parseRequestParameters() { if ((parsedParameters != null) && !parsedParameters) { Logger.log(Logger.WARNING, Launcher.RESOURCES, "WinstoneRequest.BothMethods"); this.parsedParameters = Boolean.TRUE; } else if (parsedParameters == null) { Map workingParameters = new SizeRestrictedHashMap(HttpUtils.MAX_PARAMETER_COUNT); try { // Parse query string from request if ((method.equals(METHOD_GET) || method.equals(METHOD_HEAD) || method.equals(METHOD_POST)) && (this.queryString != null)) { extractParameters(this.queryString, this.encoding, workingParameters, false); Logger.log(Logger.FULL_DEBUG, Launcher.RESOURCES, "WinstoneRequest.ParamLine", "" + workingParameters); } if (method.equals(METHOD_POST) && (contentType != null) && (contentType.equals(POST_PARAMETERS) || contentType.startsWith(POST_PARAMETERS + ";"))) { Logger.log(Logger.FULL_DEBUG, Launcher.RESOURCES, "WinstoneRequest.ParsingBodyParameters"); // Parse params byte paramBuffer[] = new byte[contentLength]; int readCount = this.inputData.readAsMuchAsPossible(paramBuffer,0,contentLength); if (readCount != contentLength) Logger.log(Logger.WARNING, Launcher.RESOURCES, "WinstoneRequest.IncorrectContentLength", contentLength + "", readCount + ""); String paramLine = (this.encoding == null ? new String( paramBuffer) : new String(paramBuffer, this.encoding)); extractParameters(paramLine.trim(), this.encoding, workingParameters, false); Logger.log(Logger.FULL_DEBUG, Launcher.RESOURCES, "WinstoneRequest.ParamLine", "" + workingParameters); } this.parameters.putAll(workingParameters); this.parsedParameters = Boolean.TRUE; } catch (Throwable err) { Logger.log(Logger.ERROR, Launcher.RESOURCES, "WinstoneRequest.ErrorBodyParameters", err); this.parsedParameters = null; } } } /** * Go through the list of headers, and build the headers/cookies arrays for * the request object. */ public void parseHeaders(List headerList) { // Iterate through headers List outHeaderList = new ArrayList(); List cookieList = new ArrayList(); for (Object aHeaderList : headerList) { String header = (String) aHeaderList; int colonPos = header.indexOf(':'); String name = header.substring(0, colonPos); String value = header.substring(colonPos + 1).trim(); // Add it to out headers if it's not a cookie outHeaderList.add(header); // if (!name.equalsIgnoreCase(IN_COOKIE_HEADER1) // && !name.equalsIgnoreCase(IN_COOKIE_HEADER2)) if (name.equalsIgnoreCase(AUTHORIZATION_HEADER)) this.authorization = value; else if (name.equalsIgnoreCase(LOCALE_HEADER)) this.locales = parseLocales(value); else if (name.equalsIgnoreCase(CONTENT_LENGTH_HEADER)) this.contentLength = Integer.parseInt(value); else if (name.equalsIgnoreCase(HOST_HEADER)) { if (value.indexOf('[') != -1 && value.indexOf(']') != -1) { //IPv6 host as per rfc2732 this.serverName = value.substring(value.indexOf('['), value.indexOf(']')+1); int nextColonPos = value.indexOf("]:"); if ((nextColonPos == -1) || (nextColonPos == value.length() - 1)) { if (this.scheme != null) { if (this.scheme.equals("http")) { this.serverPort = 80; } else if (this.scheme.equals("https")) { this.serverPort = 443; } } } else { this.serverPort = Integer.parseInt(value.substring(nextColonPos + 2)); } } else { //IPv4 host int nextColonPos = value.indexOf(':'); if ((nextColonPos == -1) || (nextColonPos == value.length() - 1)) { this.serverName = value; if (this.scheme != null) { if (this.scheme.equals("http")) { this.serverPort = 80; } else if (this.scheme.equals("https")) { this.serverPort = 443; } } } else { this.serverName = value.substring(0, nextColonPos); this.serverPort = Integer.parseInt(value.substring(nextColonPos + 1)); } } } else if (name.equalsIgnoreCase(CONTENT_TYPE_HEADER)) { this.contentType = value; int semicolon = value.lastIndexOf(';'); if (semicolon != -1) { String encodingClause = value.substring(semicolon + 1).trim(); if (encodingClause.startsWith("charset=")) this.encoding = encodingClause.substring(8); } } else if (name.equalsIgnoreCase(FORWARDED_FOR)) { setRemoteIP(value); } else if (name.equalsIgnoreCase(IN_COOKIE_HEADER1) || name.equalsIgnoreCase(IN_COOKIE_HEADER2)) parseCookieLine(value, cookieList); } this.headers = (String[]) outHeaderList.toArray(new String[0]); if (cookieList.isEmpty()) { this.cookies = null; } else { this.cookies = (Cookie[]) cookieList.toArray(new Cookie[0]); } } private static String nextToken(StringTokenizer st) { if (st.hasMoreTokens()) { return st.nextToken(); } else { return null; } } private void parseCookieLine(String headerValue, List cookieList) { StringTokenizer st = new StringTokenizer(headerValue, ";", false); int version = 0; String cookieLine = nextToken(st); // check cookie version flag if ((cookieLine != null) && cookieLine.startsWith("$Version=")) { int equalPos = cookieLine.indexOf('='); try { version = Integer.parseInt(extractFromQuotes( cookieLine.substring(equalPos + 1).trim())); } catch (NumberFormatException err) { version = 0; } cookieLine = nextToken(st); } // process remainder - parameters while (cookieLine != null) { cookieLine = cookieLine.trim(); int equalPos = cookieLine.indexOf('='); if (equalPos == -1) { // next token cookieLine = nextToken(st); } else { String name = cookieLine.substring(0, equalPos); String value = extractFromQuotes(cookieLine.substring(equalPos + 1)); Cookie thisCookie = new Cookie(name, value); thisCookie.setVersion(version); thisCookie.setSecure(isSecure()); cookieList.add(thisCookie); // check for path / domain / port cookieLine = nextToken(st); while ((cookieLine != null) && cookieLine.trim().startsWith("$")) { cookieLine = cookieLine.trim(); equalPos = cookieLine.indexOf('='); String attrValue = equalPos == -1 ? "" : cookieLine .substring(equalPos + 1).trim(); if (cookieLine.startsWith("$Path")) { thisCookie.setPath(extractFromQuotes(attrValue)); } else if (cookieLine.startsWith("$Domain")) { thisCookie.setDomain(extractFromQuotes(attrValue)); } cookieLine = nextToken(st); } Logger.log(Logger.FULL_DEBUG, Launcher.RESOURCES, "WinstoneRequest.CookieFound", thisCookie.toString()); if (thisCookie.getName().equals(WinstoneSession.SESSION_COOKIE_NAME)) { // Find a context that manages this key HostConfiguration hostConfig = this.hostGroup.getHostByName(this.serverName); WebAppConfiguration ownerContext = hostConfig.getWebAppBySessionKey(thisCookie.getValue()); if (ownerContext != null) { this.requestedSessionIds.put(ownerContext.getContextPath(), thisCookie.getValue()); this.currentSessionIds.put(ownerContext.getContextPath(), thisCookie.getValue()); } // If not found, it was probably dead else { this.deadRequestedSessionId = thisCookie.getValue(); } // this.requestedSessionId = thisCookie.getValue(); // this.currentSessionId = thisCookie.getValue(); Logger.log(Logger.FULL_DEBUG, Launcher.RESOURCES, "WinstoneRequest.SessionCookieFound", thisCookie.getValue(), ownerContext == null ? "" : "prefix:" + ownerContext.getContextPath()); } } } } private static String extractFromQuotes(String input) { if ((input != null) && input.startsWith("\"") && input.endsWith("\"")) { return input.substring(1, input.length() - 1); } else { return input; } } private List parseLocales(String header) { // Strip out the whitespace StringBuilder lb = new StringBuilder(); for (int n = 0; n < header.length(); n++) { char c = header.charAt(n); if (!Character.isWhitespace(c)) lb.append(c); } // Tokenize by commas Map localeEntries = new SizeRestrictedHashMap(HttpUtils.MAX_PARAMETER_COUNT); StringTokenizer commaTK = new StringTokenizer(lb.toString(), ",", false); for (; commaTK.hasMoreTokens();) { String clause = commaTK.nextToken(); // Tokenize by semicolon Float quality = (float) 1; if (clause.indexOf(";q=") != -1) { int pos = clause.indexOf(";q="); try { quality = new Float(clause.substring(pos + 3)); } catch (NumberFormatException err) { quality = (float) 0; } clause = clause.substring(0, pos); } // Build the locale String language; String country = ""; String variant = ""; int dpos = clause.indexOf('-'); if (dpos == -1) language = clause; else { language = clause.substring(0, dpos); String remainder = clause.substring(dpos + 1); int d2pos = remainder.indexOf('-'); if (d2pos == -1) country = remainder; else { country = remainder.substring(0, d2pos); variant = remainder.substring(d2pos + 1); } } Locale loc = new Locale(language, country, variant); // Put into list by quality List localeList = (List) localeEntries.get(quality); if (localeList == null) { localeList = new ArrayList(); localeEntries.put(quality, localeList); } localeList.add(loc); } // Extract and build the list Float orderKeys[] = (Float[]) localeEntries.keySet().toArray(new Float[0]); Arrays.sort(orderKeys); List outputLocaleList = new ArrayList(); for (int n = 0; n < orderKeys.length; n++) { // Skip backwards through the list of maps and add to the output list int reversedIndex = (orderKeys.length - 1) - n; if ((orderKeys[reversedIndex] <= 0) || (orderKeys[reversedIndex] > 1)) continue; List localeList = (List) localeEntries.get(orderKeys[reversedIndex]); for (Object aLocaleList : localeList) outputLocaleList.add(aLocaleList); } return outputLocaleList; } public void addIncludeQueryParameters(String queryString) { Map lastParams = new SizeRestrictedHashtable(HttpUtils.MAX_PARAMETER_COUNT); if (!this.parametersStack.isEmpty()) { lastParams.putAll((Map) this.parametersStack.peek()); } Map newQueryParams = new SizeRestrictedHashMap(HttpUtils.MAX_PARAMETER_COUNT); if (queryString != null) { extractParameters(queryString, this.encoding, newQueryParams, false); } lastParams.putAll(newQueryParams); this.parametersStack.push(lastParams); } public void addIncludeAttributes(String requestURI, String contextPath, String servletPath, String pathInfo, String queryString) { Map includeAttributes = new HashMap(); if (requestURI != null) { includeAttributes.put(RequestDispatcher.INCLUDE_REQUEST_URI, requestURI); } if (contextPath != null) { includeAttributes.put(RequestDispatcher.INCLUDE_CONTEXT_PATH, contextPath); } if (servletPath != null) { includeAttributes.put(RequestDispatcher.INCLUDE_SERVLET_PATH, servletPath); } if (pathInfo != null) { includeAttributes.put(RequestDispatcher.INCLUDE_PATH_INFO, pathInfo); } if (queryString != null) { includeAttributes.put(RequestDispatcher.INCLUDE_QUERY_STRING, queryString); } this.attributesStack.push(includeAttributes); } public void removeIncludeQueryString() { if (!this.parametersStack.isEmpty()) { this.parametersStack.pop(); } } public void clearIncludeStackForForward() { this.parametersStack.clear(); this.attributesStack.clear(); } public void setForwardQueryString(String forwardQueryString) { // this.forwardedParameters.clear(); // Parse query string from include / forward if (forwardQueryString != null) { String oldQueryString = this.queryString == null ? "" : this.queryString; boolean needJoiner = !forwardQueryString.equals("") && !oldQueryString.equals(""); this.queryString = forwardQueryString + (needJoiner ? "&" : "") + oldQueryString; if (this.parsedParameters != null) { Logger.log(Logger.FULL_DEBUG, Launcher.RESOURCES, "WinstoneRequest.ParsingParameters", forwardQueryString, this.encoding); extractParameters(forwardQueryString, this.encoding, this.parameters, true); Logger.log(Logger.FULL_DEBUG, Launcher.RESOURCES, "WinstoneRequest.ParamLine", "" + this.parameters); } } } public void removeIncludeAttributes() { if (!this.attributesStack.isEmpty()) { this.attributesStack.pop(); } } // Implementation methods for the servlet request stuff public Object getAttribute(String name) { if (!this.attributesStack.isEmpty()) { Map includedAttributes = (Map) this.attributesStack.peek(); Object value = includedAttributes.get(name); if (value != null) { return value; } } return this.attributes.get(name); } public Enumeration getAttributeNames() { Map attributes = new HashMap(this.attributes); if (!this.attributesStack.isEmpty()) { Map includedAttributes = (Map) this.attributesStack.peek(); attributes.putAll(includedAttributes); } return Collections.enumeration(attributes.keySet()); } public void removeAttribute(String name) { Object value = attributes.get(name); if (value == null) return; // fire event if (this.requestAttributeListeners != null) { for (ServletRequestAttributeListener requestAttributeListener : this.requestAttributeListeners) { ClassLoader cl = Thread.currentThread().getContextClassLoader(); Thread.currentThread().setContextClassLoader(getWebAppConfig().getLoader()); requestAttributeListener.attributeRemoved( new ServletRequestAttributeEvent(this.webappConfig, this, name, value)); Thread.currentThread().setContextClassLoader(cl); } } this.attributes.remove(name); } public void setAttribute(String name, Object o) { if ((name != null) && (o != null)) { Object oldValue = attributes.get(name); attributes.put(name, o); // make sure it's set at the top level // fire event if (this.requestAttributeListeners != null) { if (oldValue == null) { for (ServletRequestAttributeListener requestAttributeListener : this.requestAttributeListeners) { ClassLoader cl = Thread.currentThread().getContextClassLoader(); Thread.currentThread().setContextClassLoader(getWebAppConfig().getLoader()); requestAttributeListener.attributeAdded( new ServletRequestAttributeEvent(this.webappConfig, this, name, o)); Thread.currentThread().setContextClassLoader(cl); } } else { for (ServletRequestAttributeListener requestAttributeListener : this.requestAttributeListeners) { ClassLoader cl = Thread.currentThread().getContextClassLoader(); Thread.currentThread().setContextClassLoader(getWebAppConfig().getLoader()); requestAttributeListener .attributeReplaced(new ServletRequestAttributeEvent( this.webappConfig, this, name, oldValue)); Thread.currentThread().setContextClassLoader(cl); } } } } else if (name != null) { removeAttribute(name); } } public String getCharacterEncoding() { return this.encoding; } public void setCharacterEncoding(String encoding) throws UnsupportedEncodingException { "blah".getBytes(encoding); // throws an exception if the encoding is unsupported if (this.inputReader == null) { Logger.log(Logger.DEBUG, Launcher.RESOURCES, "WinstoneRequest.SetCharEncoding", this.encoding, encoding); this.encoding = encoding; } } public int getContentLength() { return this.contentLength; } public String getContentType() { return this.contentType; } public Locale getLocale() { return this.locales.isEmpty() ? Locale.getDefault() : (Locale) this.locales.get(0); } public Enumeration getLocales() { List sendLocales = this.locales; if (sendLocales.isEmpty()) sendLocales.add(Locale.getDefault()); return Collections.enumeration(sendLocales); } public String getProtocol() { return this.protocol; } public String getScheme() { return this.scheme; } public boolean isSecure() { return this.isSecure; } public BufferedReader getReader() throws IOException { if (this.inputReader != null) { return this.inputReader; } else { if (this.parsedParameters != null) { if (this.parsedParameters.equals(Boolean.TRUE)) { Logger.log(Logger.WARNING, Launcher.RESOURCES, "WinstoneRequest.BothMethodsReader"); } else { throw new IllegalStateException(Launcher.RESOURCES.getString( "WinstoneRequest.CalledReaderAfterStream")); } } if (this.encoding != null) { this.inputReader = new BufferedReader(new InputStreamReader( this.inputData, this.encoding)); } else { this.inputReader = new BufferedReader(new InputStreamReader( this.inputData)); } this.parsedParameters = Boolean.FALSE; return this.inputReader; } } public ServletInputStream getInputStream() throws IOException { if (this.inputReader != null) { throw new IllegalStateException(Launcher.RESOURCES.getString( "WinstoneRequest.CalledStreamAfterReader")); } if (this.parsedParameters != null) { if (this.parsedParameters.equals(Boolean.TRUE)) { Logger.log(Logger.WARNING, Launcher.RESOURCES, "WinstoneRequest.BothMethods"); } } if (method.equals(METHOD_POST) && POST_PARAMETERS.equals(contentType)) { this.parsedParameters = false; } return this.inputData; } public String getParameter(String name) { parseRequestParameters(); Object param = null; if (!this.parametersStack.isEmpty()) { param = ((Map) this.parametersStack.peek()).get(name); } // if ((param == null) && this.forwardedParameters.get(name) != null) { // param = this.forwardedParameters.get(name); // } if (param == null) { param = this.parameters.get(name); } if (param == null) return null; else if (param instanceof String) return (String) param; else if (param instanceof String[]) return ((String[]) param)[0]; else return param.toString(); } public Enumeration getParameterNames() { parseRequestParameters(); Set parameterKeys = new HashSet(this.parameters.keySet()); // parameterKeys.addAll(this.forwardedParameters.keySet()); if (!this.parametersStack.isEmpty()) { parameterKeys.addAll(((Map) this.parametersStack.peek()).keySet()); } return Collections.enumeration(parameterKeys); } public String[] getParameterValues(String name) { parseRequestParameters(); Object param = null; if (!this.parametersStack.isEmpty()) { param = ((Map) this.parametersStack.peek()).get(name); } // if ((param == null) && this.forwardedParameters.get(name) != null) { // param = this.forwardedParameters.get(name); // } if (param == null) { param = this.parameters.get(name); } if (param == null) return null; else if (param instanceof String) { return new String[] {(String) param}; } else if (param instanceof String[]) return (String[]) param; else throw new WinstoneException(Launcher.RESOURCES.getString( "WinstoneRequest.UnknownParameterType", name + " - " + param.getClass())); } public Map getParameterMap() { Hashtable paramMap = new SizeRestrictedHashtable(HttpUtils.MAX_PARAMETER_COUNT); for (Enumeration names = this.getParameterNames(); names .hasMoreElements();) { String name = (String) names.nextElement(); paramMap.put(name, getParameterValues(name)); } return paramMap; } public String getServerName() { return this.serverName; } public int getServerPort() { return this.serverPort; } public String getRemoteAddr() { return this.remoteIP; } public String getRemoteHost() { return this.remoteName; } public int getRemotePort() { return this.remotePort; } public String getLocalAddr() { return this.localAddr; } public String getLocalName() { return this.localName; } public int getLocalPort() { return this.localPort; } public javax.servlet.RequestDispatcher getRequestDispatcher(String path) { if (path.startsWith("/")) return this.webappConfig.getRequestDispatcher(path); // Take the servlet path + pathInfo, and make an absolute path String fullPath = getServletPath() + (getPathInfo() == null ? "" : getPathInfo()); int lastSlash = fullPath.lastIndexOf('/'); String currentDir = (lastSlash == -1 ? "/" : fullPath.substring(0, lastSlash + 1)); return this.webappConfig.getRequestDispatcher(currentDir + path); } // Now the stuff for HttpServletRequest public String getContextPath() { return this.webappConfig.getContextPath(); } public Cookie[] getCookies() { return this.cookies; } public long getDateHeader(String name) { String dateHeader = getHeader(name); if (dateHeader == null) { return -1; } else try { Date date; synchronized (headerDF) { date = headerDF.parse(dateHeader); } return date.getTime(); } catch (java.text.ParseException err) { throw new IllegalArgumentException(Launcher.RESOURCES.getString( "WinstoneRequest.BadDate", dateHeader)); } } public int getIntHeader(String name) { String header = getHeader(name); return header == null ? -1 : Integer.parseInt(header); } public String getHeader(String name) { return extractFirstHeader(name); } public Enumeration getHeaderNames() { return Collections.enumeration(extractHeaderNameList()); } public Enumeration getHeaders(String name) { int len = name.length(); List headers = new ArrayList(); for (String header : this.headers) if (header.length() > len && header.charAt(len) == ':' && header.regionMatches(true, 0, name, 0, len)) headers .add(header.substring(len + 1) .trim()); // 1 for colon return Collections.enumeration(headers); } public String getMethod() { return this.method; } public String getPathInfo() { return this.pathInfo; } public String getPathTranslated() { return this.webappConfig.getRealPath(this.pathInfo); } public String getQueryString() { return this.queryString; } public String getRequestURI() { return this.requestURI; } public String getServletPath() { return this.servletPath; } public String getRequestedSessionId() { String actualSessionId = (String) this.requestedSessionIds.get(this.webappConfig.getContextPath()); if (actualSessionId != null) { return actualSessionId; } else { return this.deadRequestedSessionId; } } public StringBuffer getRequestURL() { StringBuffer url = new StringBuffer(); url.append(getScheme()).append("://"); url.append(getServerName()); if (!((getServerPort() == 80) && getScheme().equals("http")) && !((getServerPort() == 443) && getScheme().equals("https"))) url.append(':').append(getServerPort()); url.append(getRequestURI()); // need encoded form, so can't use servlet path + path info return url; } public Principal getUserPrincipal() { return this.authenticatedUser; } public boolean isUserInRole(String role) { if (this.authenticatedUser == null) return false; else if (this.servletConfig.getSecurityRoleRefs() == null) return this.authenticatedUser.isUserIsInRole(role); else { String replacedRole = (String) this.servletConfig.getSecurityRoleRefs().get(role); return this.authenticatedUser .isUserIsInRole(replacedRole == null ? role : replacedRole); } } public String getAuthType() { return this.authenticatedUser == null ? null : this.authenticatedUser .getAuthType(); } public String getRemoteUser() { return this.authenticatedUser == null ? null : this.authenticatedUser .getName(); } public boolean isRequestedSessionIdFromCookie() { return (getRequestedSessionId() != null); } public boolean isRequestedSessionIdFromURL() { return false; } public boolean isRequestedSessionIdValid() { String requestedId = getRequestedSessionId(); if (requestedId == null) { return false; } WinstoneSession ws = this.webappConfig.getSessionById(requestedId, false); return (ws != null); // if (ws == null) { // return false; // } else { // return (validationCheck(ws, System.currentTimeMillis(), false) != null); // } } public HttpSession getSession() { return getSession(true); } public HttpSession getSession(boolean create) { String cookieValue = (String) this.currentSessionIds.get(this.webappConfig.getContextPath()); // Handle the null case if (cookieValue == null) { if (!create) { return null; } else { cookieValue = makeNewSession().getId(); } } // Now get the session object WinstoneSession session = this.webappConfig.getSessionById(cookieValue, false); if (session != null) { // long nowDate = System.currentTimeMillis(); // session = validationCheck(session, nowDate, create); // if (session == null) { // this.currentSessionIds.remove(this.webappConfig.getContextPath()); // } } if (create && (session == null)) { session = makeNewSession(); } if (session != null) { this.usedSessions.add(session); session.addUsed(this); } return session; } /** * Make a new session, and return the id */ private WinstoneSession makeNewSession() { String cookieValue = "Winstone_" + this.remoteIP + "_" + this.serverPort + "_" + System.currentTimeMillis() + rnd.nextLong(); byte digestBytes[] = this.md5Digester.digest(cookieValue.getBytes()); // Write out in hex format char outArray[] = new char[32]; for (int n = 0; n < digestBytes.length; n++) { int hiNibble = (digestBytes[n] & 0xFF) >> 4; int loNibble = (digestBytes[n] & 0xF); outArray[2 * n] = (hiNibble > 9 ? (char) (hiNibble + 87) : (char) (hiNibble + 48)); outArray[2 * n + 1] = (loNibble > 9 ? (char) (loNibble + 87) : (char) (loNibble + 48)); } String newSessionId = new String(outArray); this.currentSessionIds.put(this.webappConfig.getContextPath(), newSessionId); return this.webappConfig.makeNewSession(newSessionId); } public void markSessionsAsRequestFinished(long lastAccessedTime, boolean saveSessions) { for (Object usedSession : this.usedSessions) { WinstoneSession session = (WinstoneSession) usedSession; session.setLastAccessedDate(lastAccessedTime); session.removeUsed(this); if (saveSessions) { session.saveToTemp(); } } this.usedSessions.clear(); } /** * @deprecated */ public String getRealPath(String path) { return this.webappConfig.getRealPath(path); } /** * @deprecated */ public boolean isRequestedSessionIdFromUrl() { return isRequestedSessionIdFromURL(); } } jenkins-winstone-0.9.10-jenkins-47/src/java/winstone/WinstoneResourceBundle.java0000644000175000017500000000646612200024521030340 0ustar jamespagejamespage/* * Copyright 2003-2006 Rick Knowles * Distributed under the terms of either: * - the common development and distribution license (CDDL), v1.0; or * - the GNU Lesser General Public License, v2.1 or later */ package winstone; import java.util.Locale; import java.util.ResourceBundle; /** * A ResourceBundle that includes the ability to do string replacement on the * resources it retrieves. * * @author Rick Knowles */ public class WinstoneResourceBundle { private ResourceBundle resources; /** * Constructor */ public WinstoneResourceBundle(String baseName) { this.resources = ResourceBundle.getBundle(baseName); } public WinstoneResourceBundle(String baseName, Locale loc) { this.resources = ResourceBundle.getBundle(baseName, loc); } public WinstoneResourceBundle(String baseName, Locale loc, ClassLoader cl) { this.resources = ResourceBundle.getBundle(baseName, loc, cl); } /** * Default getString method */ public String getString(String key) { return this.resources.getString(key); } /** * Perform a string replace for a single from/to pair. */ public String getString(String key, Object parameter) { return globalReplace(this.resources.getString(key), "[#0]", toString(parameter)); } private String toString(Object s) { return s!=null?s.toString():null; } /** * Perform a string replace for a set of from/to pairs. */ public String getString(String key, Object[] parameters) { String myCopy = this.resources.getString(key); if (parameters != null) { String tokens[][] = new String[parameters.length][2]; for (int n = 0; n < parameters.length; n++) { tokens[n] = new String[] {"[#" + n + "]", toString(parameters[n])}; } myCopy = globalReplace(myCopy, tokens); } return myCopy; } /** * Just does a string swap, replacing occurrences of from with to. */ public static String globalReplace(String input, String fromMarker, String toValue) { StringBuffer out = new StringBuffer(input); globalReplace(out, fromMarker, toValue); return out.toString(); } private static void globalReplace(StringBuffer input, String fromMarker, String toValue) { if (input == null) { return; } else if (fromMarker == null) { return; } int index = 0; int foundAt = input.indexOf(fromMarker, index); while (foundAt != -1) { if (toValue == null) { toValue = "(null)"; } input.replace(foundAt, foundAt + fromMarker.length(), toValue); index = foundAt + toValue.length(); foundAt = input.indexOf(fromMarker, index); } } public static String globalReplace(String input, String parameters[][]) { if (parameters != null) { StringBuffer out = new StringBuffer(input); for (String[] parameter : parameters) { globalReplace(out, parameter[0], parameter[1]); } return out.toString(); } else { return input; } } } jenkins-winstone-0.9.10-jenkins-47/src/java/winstone/HttpListener.java0000644000175000017500000003753512200024521026316 0ustar jamespagejamespage/* * Copyright 2003-2006 Rick Knowles * Distributed under the terms of either: * - the common development and distribution license (CDDL), v1.0; or * - the GNU Lesser General Public License, v2.1 or later */ package winstone; import winstone.cmdline.Option; import java.io.IOException; import java.io.InputStream; import java.io.InterruptedIOException; import java.io.OutputStream; import java.net.Inet6Address; import java.net.InetAddress; import java.net.ServerSocket; import java.net.Socket; import java.net.SocketException; import java.util.ArrayList; import java.util.List; import java.util.Map; /** * Implements the main listener daemon thread. This is the class that gets * launched by the command line, and owns the server socket, etc. Note that this * class is also used as the base class for the HTTPS listener. * * @author Rick Knowles * @version $Id: HttpListener.java,v 1.15 2007/05/01 04:39:49 rickknowles Exp $ */ public class HttpListener implements Listener, Runnable { protected static int LISTENER_TIMEOUT = 5000; // every 5s reset the // listener socket protected static int CONNECTION_TIMEOUT = 60000; protected static int BACKLOG_COUNT = 5000; protected static boolean DEFAULT_HNL = false; protected int keepAliveTimeout; protected static int KEEP_ALIVE_SLEEP = 20; protected static int KEEP_ALIVE_SLEEP_MAX = 500; protected HostGroup hostGroup; protected ObjectPool objectPool; protected boolean doHostnameLookups; protected int listenPort; protected String listenAddress; protected boolean interrupted; private ServerSocket serverSocket; protected HttpListener() { } /** * Constructor */ public HttpListener(Map args, ObjectPool objectPool, HostGroup hostGroup) { // Load resources this.hostGroup = hostGroup; this.objectPool = objectPool; this.listenPort = Integer.parseInt(WebAppConfiguration.stringArg(args, getConnectorName() + Option._PORT, "" + getDefaultPort())); this.listenAddress = WebAppConfiguration.stringArg(args, getConnectorName() + Option._LISTEN_ADDRESS, null); this.doHostnameLookups = WebAppConfiguration.booleanArg(args, getConnectorName() + Option._DO_HOSTNAME_LOOKUPS, DEFAULT_HNL); this.keepAliveTimeout = WebAppConfiguration.intArg(args, getConnectorName() + Option._KEEP_ALIVE_TIMEOUT, Option._KEEP_ALIVE_TIMEOUT.defaultValue); } public boolean start() throws IOException { if (this.listenPort < 0) { return false; } else { this.interrupted = false; ServerSocket ss = getServerSocket(); ss.setSoTimeout(LISTENER_TIMEOUT); Logger.log(Logger.INFO, Launcher.RESOURCES, "HttpListener.StartupOK", getConnectorName().toUpperCase(), this.listenPort + ""); this.serverSocket = ss; Thread thread = new Thread(this, Launcher.RESOURCES.getString( "Listener.ThreadName", new String[] { getConnectorName(), "" + this.listenPort })); thread.setDaemon(true); thread.start(); return true; } } /** * The default port to use - this is just so that we can override for the * SSL connector. */ protected int getDefaultPort() { return 8080; } /** * The name to use when getting properties - this is just so that we can * override for the SSL connector. */ protected String getConnectorName() { return getConnectorScheme(); } protected String getConnectorScheme() { return "http"; } /** * Gets a server socket - this is mostly for the purpose of allowing an * override in the SSL connector. */ protected ServerSocket getServerSocket() throws IOException { try { return this.listenAddress == null ? new ServerSocket( this.listenPort, BACKLOG_COUNT) : new ServerSocket( this.listenPort, BACKLOG_COUNT, InetAddress .getByName(this.listenAddress)); } catch (IOException e) { throw (IOException)new IOException("Failed to listen on port "+listenPort).initCause(e); } } /** * The main run method. This continually listens for incoming connections, * and allocates any that it finds to a request handler thread, before going * back to listen again. */ public void run() { try { // Enter the main loop while (!interrupted) { // Get the listener Socket s; try { s = serverSocket.accept(); } catch (java.io.InterruptedIOException err) { s = null; } // if we actually got a socket, process it. Otherwise go around // again if (s != null) this.objectPool.handleRequest(s, this); } // Close server socket serverSocket.close(); serverSocket = null; Logger.log(Logger.INFO, Launcher.RESOURCES, "HttpListener.ShutdownOK", getConnectorName().toUpperCase()); } catch (Throwable err) { Logger.log(Logger.ERROR, Launcher.RESOURCES, "HttpListener.ShutdownError", getConnectorName().toUpperCase(), err); } } /** * Interrupts the listener thread. This will trigger a listener shutdown * once the so timeout has passed. */ public void destroy() { this.interrupted = true; } /** * Called by the request handler thread, because it needs specific setup * code for this connection's protocol (ie construction of request/response * objects, in/out streams, etc). * * This implementation parses incoming AJP13 packets, and builds an * outputstream that is capable of writing back the response in AJP13 * packets. */ public void allocateRequestResponse(Socket socket, InputStream inSocket, OutputStream outSocket, RequestHandlerThread handler, boolean iAmFirst) throws SocketException, IOException { Logger.log(Logger.FULL_DEBUG, Launcher.RESOURCES, "HttpListener.AllocatingRequest", Thread.currentThread() .getName()); socket.setSoTimeout(CONNECTION_TIMEOUT); // Build input/output streams, plus request/response WinstoneInputStream inData = new WinstoneInputStream(inSocket); WinstoneOutputStream outData = new WinstoneOutputStream(outSocket, false); WinstoneRequest req = this.objectPool.getRequestFromPool(); WinstoneResponse rsp = this.objectPool.getResponseFromPool(); outData.setResponse(rsp); req.setInputStream(inData); rsp.setOutputStream(outData); rsp.setRequest(req); // rsp.updateContentTypeHeader("text/html"); req.setHostGroup(this.hostGroup); // Set the handler's member variables so it can execute the servlet handler.setRequest(req); handler.setResponse(rsp); handler.setInStream(inData); handler.setOutStream(outData); // If using this listener, we must set the server header now, because it // must be the first header. Ajp13 listener can defer to the Apache Server // header rsp.setHeader("Server", Launcher.RESOURCES.getString("ServerVersion")); } /** * Called by the request handler thread, because it needs specific shutdown * code for this connection's protocol (ie releasing input/output streams, * etc). */ public void deallocateRequestResponse(RequestHandlerThread handler, WinstoneRequest req, WinstoneResponse rsp, WinstoneInputStream inData, WinstoneOutputStream outData) { handler.setInStream(null); handler.setOutStream(null); handler.setRequest(null); handler.setResponse(null); if (req != null) this.objectPool.releaseRequestToPool(req); if (rsp != null) this.objectPool.releaseResponseToPool(rsp); } public String parseURI(RequestHandlerThread handler, WinstoneRequest req, WinstoneResponse rsp, WinstoneInputStream inData, Socket socket, boolean iAmFirst) throws IOException { parseSocketInfo(socket, req); // Read the header line (because this is the first line of the request, // apply keep-alive timeouts to it if we are not the first request) socket.setSoTimeout(keepAliveTimeout); byte uriBuffer[] = null; try { Logger.log(Logger.FULL_DEBUG, Launcher.RESOURCES, "HttpListener.WaitingForURILine"); uriBuffer = inData.readLine(); } catch (InterruptedIOException err) { // keep alive timeout ? ignore if not first if (iAmFirst) { throw err; } else { return null; } } finally { try {socket.setSoTimeout(CONNECTION_TIMEOUT);} catch (Throwable err) {} } handler.setRequestStartTime(); // Get header data (eg protocol, method, uri, headers, etc) String uriLine = new String(uriBuffer); if (uriLine.trim().equals("")) throw new SocketException("Empty URI Line"); String servletURI = parseURILine(uriLine, req, rsp); parseHeaders(req, inData); rsp.extractRequestKeepAliveHeader(req); int contentLength = req.getContentLength(); if (contentLength != -1) inData.setContentLength(contentLength); return servletURI; } /** * Called by the request handler thread, because it needs specific shutdown * code for this connection's protocol if the keep-alive period expires (ie * closing sockets, etc). * * This implementation simply shuts down the socket and streams. */ public void releaseSocket(Socket socket, InputStream inSocket, OutputStream outSocket) throws IOException { // Logger.log(Logger.FULL_DEBUG, "Releasing socket: " + // Thread.currentThread().getName()); inSocket.close(); outSocket.close(); socket.close(); } protected void parseSocketInfo(Socket socket, WinstoneRequest req) throws IOException { Logger.log(Logger.FULL_DEBUG, Launcher.RESOURCES, "HttpListener.ParsingSocketInfo"); req.setScheme(getConnectorScheme()); req.setServerPort(socket.getLocalPort()); req.setLocalPort(socket.getLocalPort()); req.setLocalAddr(socket.getLocalAddress().getHostAddress()); req.setRemoteIP(socket.getInetAddress().getHostAddress()); req.setRemotePort(socket.getPort()); if (this.doHostnameLookups) { req.setServerName(getHostName(socket.getLocalAddress())); req.setRemoteName(socket.getInetAddress().getHostName()); req.setLocalName(getHostName(socket.getLocalAddress())); } else { req.setServerName(getHostAddress(socket.getLocalAddress())); req.setRemoteName(socket.getInetAddress().getHostAddress()); req.setLocalName(getHostAddress(socket.getLocalAddress())); } // setRemoteName pairs with getRemoteHost(), and in Jetty // this returns ::1 not [::1]. // but getServerName() and getLocalName() returns [::1] and not ::1. // that's why setRemoteName() is left without the IPv6-aware wrapper method } private String getHostAddress(InetAddress adrs) { if (adrs instanceof Inet6Address) return '['+adrs.getHostAddress()+']'; else return adrs.getHostAddress(); } private String getHostName(InetAddress adrs) { if (adrs instanceof Inet6Address) { String n = adrs.getHostName(); if (n.indexOf(':')>=0) return '['+n+']'; return n; } else return adrs.getHostName(); } /** * Tries to wait for extra requests on the same socket. If any are found * before the timeout expires, it exits with a true, indicating a new * request is waiting. If the protocol does not support keep-alives, or the * request instructed us to close the connection, or the timeout expires, * return a false, instructing the handler thread to begin shutting down the * socket and relase itself. */ public boolean processKeepAlive(WinstoneRequest request, WinstoneResponse response, InputStream inSocket) { // Try keep alive if allowed boolean continueFlag = !response.closeAfterRequest(); return continueFlag; } /** * Processes the uri line into it's component parts, determining protocol, * method and uri */ private String parseURILine(String uriLine, WinstoneRequest req, WinstoneResponse rsp) { Logger.log(Logger.FULL_DEBUG, Launcher.RESOURCES, "HttpListener.UriLine", uriLine.trim()); // Method int spacePos = uriLine.indexOf(' '); if (spacePos == -1) throw new WinstoneException(Launcher.RESOURCES.getString( "HttpListener.ErrorUriLine", uriLine)); String method = uriLine.substring(0, spacePos).toUpperCase(); String fullURI; // URI String remainder = uriLine.substring(spacePos + 1); spacePos = remainder.indexOf(' '); if (spacePos == -1) { fullURI = trimHostName(remainder.trim()); req.setProtocol("HTTP/0.9"); rsp.setProtocol("HTTP/0.9"); } else { fullURI = trimHostName(remainder.substring(0, spacePos).trim()); String protocol = remainder.substring(spacePos + 1).trim().toUpperCase(); if (!protocol.startsWith("HTTP/")) protocol = "HTTP/1.0"; // didn't understand this protocol. this typically means the request line had extra space. assume 1.0 req.setProtocol(protocol); rsp.setProtocol(protocol); } req.setMethod(method); // req.setRequestURI(fullURI); return fullURI; } private String trimHostName(String input) { if (input == null) return null; else if (input.startsWith("/")) return input; int hostStart = input.indexOf("://"); if (hostStart == -1) return input; String hostName = input.substring(hostStart + 3); int pathStart = hostName.indexOf('/'); if (pathStart == -1) return "/"; else return hostName.substring(pathStart); } /** * Parse the incoming stream into a list of headers (stopping at the first * blank line), then call the parseHeaders(req, list) method on that list. */ public void parseHeaders(WinstoneRequest req, WinstoneInputStream inData) throws IOException { List headerList = new ArrayList(); if (!req.getProtocol().startsWith("HTTP/0")) { // Loop to get headers byte headerBuffer[] = inData.readLine(); String headerLine = new String(headerBuffer); while (headerLine.trim().length() > 0) { if (headerLine.indexOf(':') != -1) { headerList.add(headerLine.trim()); Logger.log(Logger.FULL_DEBUG, Launcher.RESOURCES, "HttpListener.Header", headerLine.trim()); } headerBuffer = inData.readLine(); headerLine = new String(headerBuffer); } } // If no headers available, parse an empty list req.parseHeaders(headerList); } } jenkins-winstone-0.9.10-jenkins-47/src/java/winstone/RequestDispatcher.java0000644000175000017500000004707312200024521027326 0ustar jamespagejamespage/* * Copyright 2003-2006 Rick Knowles * Distributed under the terms of either: * - the common development and distribution license (CDDL), v1.0; or * - the GNU Lesser General Public License, v2.1 or later */ package winstone; import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.Map; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletRequestWrapper; import javax.servlet.ServletResponse; import javax.servlet.ServletResponseWrapper; /** * This class implements both the RequestDispatcher and FilterChain components. On * the first call to include() or forward(), it starts the filter chain execution * if one exists. On the final doFilter() or if there is no chain, we call the include() * or forward() again, and the servlet is executed. * * @author Rick Knowles * @version $Id: RequestDispatcher.java,v 1.18 2007/04/23 02:55:35 rickknowles Exp $ */ public class RequestDispatcher implements javax.servlet.RequestDispatcher, javax.servlet.FilterChain { static final String INCLUDE_REQUEST_URI = "javax.servlet.include.request_uri"; static final String INCLUDE_CONTEXT_PATH = "javax.servlet.include.context_path"; static final String INCLUDE_SERVLET_PATH = "javax.servlet.include.servlet_path"; static final String INCLUDE_PATH_INFO = "javax.servlet.include.path_info"; static final String INCLUDE_QUERY_STRING = "javax.servlet.include.query_string"; static final String FORWARD_REQUEST_URI = "javax.servlet.forward.request_uri"; static final String FORWARD_CONTEXT_PATH = "javax.servlet.forward.context_path"; static final String FORWARD_SERVLET_PATH = "javax.servlet.forward.servlet_path"; static final String FORWARD_PATH_INFO = "javax.servlet.forward.path_info"; static final String FORWARD_QUERY_STRING = "javax.servlet.forward.query_string"; static final String ERROR_STATUS_CODE = "javax.servlet.error.status_code"; static final String ERROR_EXCEPTION_TYPE = "javax.servlet.error.exception_type"; static final String ERROR_MESSAGE = "javax.servlet.error.message"; static final String ERROR_EXCEPTION = "javax.servlet.error.exception"; static final String ERROR_REQUEST_URI = "javax.servlet.error.request_uri"; static final String ERROR_SERVLET_NAME = "javax.servlet.error.servlet_name"; private WebAppConfiguration webAppConfig; private ServletConfiguration servletConfig; private String servletPath; private String pathInfo; private String queryString; private String requestURI; private Integer errorStatusCode; private Throwable errorException; private String errorSummaryMessage; private AuthenticationHandler authHandler; private Mapping forwardFilterPatterns[]; private Mapping includeFilterPatterns[]; private FilterConfiguration matchingFilters[]; private int matchingFiltersEvaluated; private Boolean doInclude; private boolean isErrorDispatch; private boolean useRequestAttributes; private WebAppConfiguration includedWebAppConfig; private ServletConfiguration includedServletConfig; /** * Constructor. This initializes the filter chain and sets up the details * needed to handle a servlet excecution, such as security constraints, * filters, etc. */ public RequestDispatcher(WebAppConfiguration webAppConfig, ServletConfiguration servletConfig) { this.servletConfig = servletConfig; this.webAppConfig = webAppConfig; this.matchingFiltersEvaluated = 0; } public void setForNamedDispatcher(Mapping forwardFilterPatterns[], Mapping includeFilterPatterns[]) { this.forwardFilterPatterns = forwardFilterPatterns; this.includeFilterPatterns = includeFilterPatterns; this.matchingFilters = null; // set after the call to forward or include this.useRequestAttributes = false; this.isErrorDispatch = false; } public void setForURLDispatcher(String servletPath, String pathInfo, String queryString, String requestURIInsideWebapp, Mapping forwardFilterPatterns[], Mapping includeFilterPatterns[]) { this.servletPath = servletPath; this.pathInfo = pathInfo; this.queryString = queryString; this.requestURI = requestURIInsideWebapp; this.forwardFilterPatterns = forwardFilterPatterns; this.includeFilterPatterns = includeFilterPatterns; this.matchingFilters = null; // set after the call to forward or include this.useRequestAttributes = true; this.isErrorDispatch = false; } public void setForErrorDispatcher(String servletPath, String pathInfo, String queryString, int statusCode, String summaryMessage, Throwable exception, String errorHandlerURI, Mapping errorFilterPatterns[]) { this.servletPath = servletPath; this.pathInfo = pathInfo; this.queryString = queryString; this.requestURI = errorHandlerURI; this.errorStatusCode = statusCode; this.errorException = exception; this.errorSummaryMessage = summaryMessage; this.matchingFilters = getMatchingFilters(errorFilterPatterns, this.webAppConfig, servletPath + (pathInfo == null ? "" : pathInfo), getName(), "ERROR", (servletPath != null)); this.useRequestAttributes = true; this.isErrorDispatch = true; } public void setForInitialDispatcher(String servletPath, String pathInfo, String queryString, String requestURIInsideWebapp, Mapping requestFilterPatterns[], AuthenticationHandler authHandler) { this.servletPath = servletPath; this.pathInfo = pathInfo; this.queryString = queryString; this.requestURI = requestURIInsideWebapp; this.authHandler = authHandler; this.matchingFilters = getMatchingFilters(requestFilterPatterns, this.webAppConfig, servletPath + (pathInfo == null ? "" : pathInfo), getName(), "REQUEST", (servletPath != null)); this.useRequestAttributes = false; this.isErrorDispatch = false; } public String getName() { return this.servletConfig.getServletName(); } /** * Includes the execution of a servlet into the current request * * Note this method enters itself twice: once with the initial call, and once again * when all the filters have completed. */ public void include(ServletRequest request, ServletResponse response) throws ServletException, IOException { // On the first call, log and initialise the filter chain if (this.doInclude == null) { Logger.log(Logger.DEBUG, Launcher.RESOURCES, "RequestDispatcher.IncludeMessage", getName(), this.requestURI); WinstoneRequest wr = getUnwrappedRequest(request); // Add the query string to the included query string stack wr.addIncludeQueryParameters(this.queryString); // Set request attributes if (useRequestAttributes) { wr.addIncludeAttributes(this.webAppConfig.getContextPath() + this.requestURI, this.webAppConfig.getContextPath(), this.servletPath, this.pathInfo, this.queryString); } // Add another include buffer to the response stack WinstoneResponse wresp = getUnwrappedResponse(response); wresp.startIncludeBuffer(); this.includedServletConfig = wr.getServletConfig(); this.includedWebAppConfig = wr.getWebAppConfig(); wr.setServletConfig(this.servletConfig); wr.setWebAppConfig(this.webAppConfig); wresp.setWebAppConfig(this.webAppConfig); this.doInclude = Boolean.TRUE; } if (this.matchingFilters == null) { this.matchingFilters = getMatchingFilters(this.includeFilterPatterns, this.webAppConfig, this.servletPath + (this.pathInfo == null ? "" : this.pathInfo), getName(), "INCLUDE", (this.servletPath != null)); } try { // Make sure the filter chain is exhausted first if (this.matchingFiltersEvaluated < this.matchingFilters.length) { doFilter(request, response); finishInclude(request, response); } else { try { this.servletConfig.execute(request, response, this.webAppConfig.getContextPath() + this.requestURI); } finally { if (this.matchingFilters.length == 0) { finishInclude(request, response); } } } } catch (Throwable err) { finishInclude(request, response); if (err instanceof ServletException) { throw (ServletException) err; } else if (err instanceof IOException) { throw (IOException) err; } else if (err instanceof Error) { throw (Error) err; } else { throw (RuntimeException) err; } } } private void finishInclude(ServletRequest request, ServletResponse response) throws IOException { WinstoneRequest wr = getUnwrappedRequest(request); wr.removeIncludeQueryString(); // Set request attributes if (useRequestAttributes) { wr.removeIncludeAttributes(); } // Remove the include buffer from the response stack WinstoneResponse wresp = getUnwrappedResponse(response); wresp.finishIncludeBuffer(); if (this.includedServletConfig != null) { wr.setServletConfig(this.includedServletConfig); this.includedServletConfig = null; } if (this.includedWebAppConfig != null) { wr.setWebAppConfig(this.includedWebAppConfig); wresp.setWebAppConfig(this.includedWebAppConfig); this.includedWebAppConfig = null; } } /** * Forwards to another servlet, and when it's finished executing that other * servlet, cut off execution. * * Note this method enters itself twice: once with the initial call, and once again * when all the filters have completed. */ public void forward(ServletRequest request, ServletResponse response) throws ServletException, IOException { // Only on the first call to forward, we should set any forwarding attributes if (this.doInclude == null) { Logger.log(Logger.DEBUG, Launcher.RESOURCES, "RequestDispatcher.ForwardMessage", getName(), this.requestURI); if (response.isCommitted()) { throw new IllegalStateException(Launcher.RESOURCES.getString( "RequestDispatcher.ForwardCommitted")); } WinstoneRequest req = getUnwrappedRequest(request); WinstoneResponse rsp = getUnwrappedResponse(response); // Clear the include stack if one has been accumulated rsp.resetBuffer(); req.clearIncludeStackForForward(); rsp.clearIncludeStackForForward(); // Set request attributes (because it's the first step in the filter chain of a forward or error) if (useRequestAttributes) { req.setAttribute(FORWARD_REQUEST_URI, req.getRequestURI()); req.setAttribute(FORWARD_CONTEXT_PATH, req.getContextPath()); req.setAttribute(FORWARD_SERVLET_PATH, req.getServletPath()); req.setAttribute(FORWARD_PATH_INFO, req.getPathInfo()); req.setAttribute(FORWARD_QUERY_STRING, req.getQueryString()); if (this.isErrorDispatch) { req.setAttribute(ERROR_REQUEST_URI, req.getRequestURI()); req.setAttribute(ERROR_STATUS_CODE, this.errorStatusCode); req.setAttribute(ERROR_MESSAGE, errorSummaryMessage != null ? errorSummaryMessage : ""); if (req.getServletConfig() != null) { req.setAttribute(ERROR_SERVLET_NAME, req.getServletConfig().getServletName()); } if (this.errorException != null) { req.setAttribute(ERROR_EXCEPTION_TYPE, this.errorException.getClass()); req.setAttribute(ERROR_EXCEPTION, this.errorException); } // Revert back to the original request and response rsp.setErrorStatusCode(this.errorStatusCode); request = req; response = rsp; } } req.setServletPath(this.servletPath); req.setPathInfo(this.pathInfo); req.setRequestURI(this.webAppConfig.getContextPath() + this.requestURI); req.setForwardQueryString(this.queryString); req.setWebAppConfig(this.webAppConfig); req.setServletConfig(this.servletConfig); req.setRequestAttributeListeners(this.webAppConfig.getRequestAttributeListeners()); rsp.setWebAppConfig(this.webAppConfig); // Forwards haven't set up the filter pattern set yet if (this.matchingFilters == null) { this.matchingFilters = getMatchingFilters(this.forwardFilterPatterns, this.webAppConfig, this.servletPath + (this.pathInfo == null ? "" : this.pathInfo), getName(), "FORWARD", (this.servletPath != null)); } // Otherwise we are an initial or error dispatcher, so check security if initial - // if we should not continue, return else if (!this.isErrorDispatch && !continueAfterSecurityCheck(request, response)) { return; } this.doInclude = Boolean.FALSE; } // Make sure the filter chain is exhausted first boolean outsideFilter = (this.matchingFiltersEvaluated == 0); if (this.matchingFiltersEvaluated < this.matchingFilters.length) { doFilter(request, response); } else { this.servletConfig.execute(request, response, this.webAppConfig.getContextPath() + this.requestURI); } // Stop any output after the final filter has been executed (e.g. from forwarding servlet) if (outsideFilter) { WinstoneResponse rsp = getUnwrappedResponse(response); rsp.flushBuffer(); rsp.getWinstoneOutputStream().setClosed(true); } } private boolean continueAfterSecurityCheck(ServletRequest request, ServletResponse response) throws IOException, ServletException { // Evaluate security constraints if (this.authHandler != null) { return this.authHandler.processAuthentication(request, response, this.servletPath + (this.pathInfo == null ? "" : this.pathInfo)); } else { return true; } } /** * Handles the processing of the chain of filters, so that we process them * all, then pass on to the main servlet */ public void doFilter(ServletRequest request, ServletResponse response) throws ServletException, IOException { // Loop through the filter mappings until we hit the end while (this.matchingFiltersEvaluated < this.matchingFilters.length) { FilterConfiguration filter = this.matchingFilters[this.matchingFiltersEvaluated++]; Logger.log(Logger.DEBUG, Launcher.RESOURCES, "RequestDispatcher.ExecutingFilter", filter.getFilterName()); filter.execute(request, response, this); return; } // Forward / include as requested in the beginning if (this.doInclude == null) return; // will never happen, because we can't call doFilter before forward/include else if (this.doInclude) include(request, response); else forward(request, response); } /** * Caches the filter matching, so that if the same URL is requested twice, we don't recalculate the * filter matching every time. */ private static FilterConfiguration[] getMatchingFilters(Mapping filterPatterns[], WebAppConfiguration webAppConfig, String fullPath, String servletName, String filterChainType, boolean isURLBasedMatch) { String cacheKey; if (isURLBasedMatch) { cacheKey = filterChainType + ":URI:" + fullPath; } else { cacheKey = filterChainType + ":Servlet:" + servletName; } FilterConfiguration matchingFilters[]; Map cache = webAppConfig.getFilterMatchCache(); synchronized (cache) { matchingFilters = (FilterConfiguration []) cache.get(cacheKey); if (matchingFilters == null) { Logger.log(Logger.FULL_DEBUG, Launcher.RESOURCES, "RequestDispatcher.CalcFilterChain", cacheKey); List outFilters = new ArrayList(); for (Mapping filterPattern : filterPatterns) { // Get the pattern and eval it, bumping up the eval'd count // If the servlet name matches this name, execute it if ((filterPattern.getLinkName() != null) && (filterPattern.getLinkName().equals(servletName) || filterPattern.getLinkName().equals("*"))) { outFilters.add(webAppConfig.getFilters().get(filterPattern.getMappedTo())); } // If the url path matches this filters mappings else if ((filterPattern.getLinkName() == null) && isURLBasedMatch && filterPattern.match(fullPath, null, null)) { outFilters.add(webAppConfig.getFilters().get(filterPattern.getMappedTo())); } } matchingFilters = (FilterConfiguration []) outFilters.toArray(new FilterConfiguration[0]); cache.put(cacheKey, matchingFilters); } else { Logger.log(Logger.FULL_DEBUG, Launcher.RESOURCES, "RequestDispatcher.UseCachedFilterChain", cacheKey); } } return matchingFilters; } /** * Unwrap back to the original container allocated request object */ protected WinstoneRequest getUnwrappedRequest(ServletRequest request) { ServletRequest workingRequest = request; while (workingRequest instanceof ServletRequestWrapper) { workingRequest = ((ServletRequestWrapper) workingRequest).getRequest(); } return (WinstoneRequest) workingRequest; } /** * Unwrap back to the original container allocated response object */ protected WinstoneResponse getUnwrappedResponse(ServletResponse response) { ServletResponse workingResponse = response; while (workingResponse instanceof ServletResponseWrapper) { workingResponse = ((ServletResponseWrapper) workingResponse).getResponse(); } return (WinstoneResponse) workingResponse; } } jenkins-winstone-0.9.10-jenkins-47/src/java/winstone/RequestHandlerThread.java0000644000175000017500000003154012200024521027735 0ustar jamespagejamespage/* * Copyright 2003-2006 Rick Knowles * Distributed under the terms of either: * - the common development and distribution license (CDDL), v1.0; or * - the GNU Lesser General Public License, v2.1 or later */ package winstone; import java.io.IOException; import java.io.InputStream; import java.io.InterruptedIOException; import java.io.OutputStream; import java.net.Socket; import java.net.SocketException; import javax.servlet.ServletRequestEvent; import javax.servlet.ServletRequestListener; /** * The threads to which incoming requests get allocated. * * @author Rick Knowles * @version $Id: RequestHandlerThread.java,v 1.21 2007/04/23 02:55:35 rickknowles Exp $ */ public class RequestHandlerThread implements Runnable { private WinstoneInputStream inData; private WinstoneOutputStream outData; private WinstoneRequest req; private WinstoneResponse rsp; private Listener listener; private Socket socket; private long requestStartTime; private boolean simulateModUniqueId; private boolean saveSessions; // private Object processingMonitor = new Boolean(true); /** * Constructor - this is called by the handler pool, and just sets up for * when a real request comes along. */ public RequestHandlerThread(boolean simulateModUniqueId, boolean saveSessions, Socket socket, Listener listener) { this.simulateModUniqueId = simulateModUniqueId; this.saveSessions = saveSessions; this.socket = socket; this.listener = listener; } /** * The main thread execution code. */ public void run() { // Start request processing InputStream inSocket = null; OutputStream outSocket = null; boolean iAmFirst = true; try { int requestCount = 0; // Get input/output streams inSocket = socket.getInputStream(); outSocket = socket.getOutputStream(); // The keep alive loop - exiting from here means the connection has closed boolean continueFlag = true; while (continueFlag) { try { long requestId = System.currentTimeMillis(); this.listener.allocateRequestResponse(socket, inSocket, outSocket, this, iAmFirst); if (this.req == null) { // Dead request - happens sometimes with ajp13 - discard this.listener.deallocateRequestResponse(this, req, rsp, inData, outData); continue; } String servletURI; String oldName = Thread.currentThread().getName(); Thread.currentThread().setName(String.format("%s : reading request #%d from %s", oldName, requestCount++, socket.getRemoteSocketAddress())); try { servletURI = this.listener.parseURI(this, this.req, this.rsp, this.inData, this.socket, iAmFirst); } finally { Thread.currentThread().setName(oldName); } if (servletURI == null) { Logger.log(Logger.FULL_DEBUG, Launcher.RESOURCES, "RequestHandlerThread.KeepAliveTimedOut", Thread.currentThread().getName()); // Keep alive timed out - deallocate and go into wait state this.listener.deallocateRequestResponse(this, req, rsp, inData, outData); continueFlag = false; continue; } if (this.simulateModUniqueId) { req.setAttribute("UNIQUE_ID", "" + requestId); } long headerParseTime = getRequestProcessTime(); iAmFirst = false; HostConfiguration hostConfig = req.getHostGroup().getHostByName(req.getServerName()); Logger.log(Logger.FULL_DEBUG, Launcher.RESOURCES, "RequestHandlerThread.StartRequest", "" + requestId, hostConfig.getHostname()); // Get the URI from the request, check for prefix, then // match it to a requestDispatcher WebAppConfiguration webAppConfig = hostConfig.getWebAppByURI(servletURI); if (webAppConfig == null) { webAppConfig = hostConfig.getWebAppByURI("/"); } if (webAppConfig == null) { Logger.log(Logger.WARNING, Launcher.RESOURCES, "RequestHandlerThread.UnknownWebapp", servletURI); rsp.sendError(WinstoneResponse.SC_NOT_FOUND, Launcher.RESOURCES.getString("RequestHandlerThread.UnknownWebappPage", servletURI)); rsp.flushBuffer(); req.discardRequestBody(); writeToAccessLog(servletURI, req, rsp, null); // Process keep-alive continueFlag = this.listener.processKeepAlive(req, rsp, inSocket); this.listener.deallocateRequestResponse(this, req, rsp, inData, outData); Logger.log(Logger.FULL_DEBUG, Launcher.RESOURCES, "RequestHandlerThread.FinishRequest", "" + requestId); Logger.log(Logger.SPEED, Launcher.RESOURCES, "RequestHandlerThread.RequestTime", servletURI, "" + headerParseTime, "" + getRequestProcessTime()); continue; } req.setWebAppConfig(webAppConfig); // Now we've verified it's in the right webapp, send // request in scope notify ServletRequestListener reqLsnrs[] = webAppConfig.getRequestListeners(); for (ServletRequestListener reqLsnr1 : reqLsnrs) { ClassLoader cl = Thread.currentThread().getContextClassLoader(); Thread.currentThread().setContextClassLoader(webAppConfig.getLoader()); reqLsnr1.requestInitialized(new ServletRequestEvent(webAppConfig, req)); Thread.currentThread().setContextClassLoader(cl); } // Lookup a dispatcher, then process with it processRequest(webAppConfig, req, rsp, webAppConfig.getServletURIFromRequestURI(servletURI)); writeToAccessLog(servletURI, req, rsp, webAppConfig); this.outData.finishResponse(); this.inData.finishRequest(); Logger.log(Logger.FULL_DEBUG, Launcher.RESOURCES, "RequestHandlerThread.FinishRequest", "" + requestId); // Process keep-alive continueFlag = this.listener.processKeepAlive(req, rsp, inSocket); // Set last accessed time on session as start of this // request req.markSessionsAsRequestFinished(this.requestStartTime, this.saveSessions); // send request listener notifies for (ServletRequestListener reqLsnr : reqLsnrs) { ClassLoader cl = Thread.currentThread().getContextClassLoader(); Thread.currentThread().setContextClassLoader(webAppConfig.getLoader()); reqLsnr.requestDestroyed(new ServletRequestEvent(webAppConfig, req)); Thread.currentThread().setContextClassLoader(cl); } req.setWebAppConfig(null); rsp.setWebAppConfig(null); req.setRequestAttributeListeners(null); this.listener.deallocateRequestResponse(this, req, rsp, inData, outData); Logger.log(Logger.SPEED, Launcher.RESOURCES, "RequestHandlerThread.RequestTime", servletURI, "" + headerParseTime, "" + getRequestProcessTime()); } catch (InterruptedIOException errIO) { continueFlag = false; Logger.log(Logger.FULL_DEBUG, Launcher.RESOURCES, "RequestHandlerThread.SocketTimeout", errIO); } catch (SocketException errIO) { continueFlag = false; } } this.listener.deallocateRequestResponse(this, req, rsp, inData, outData); this.listener.releaseSocket(this.socket, inSocket, outSocket); // shut sockets } catch (Throwable err) { try { this.listener.deallocateRequestResponse(this, req, rsp, inData, outData); } catch (Throwable errClose) { } try { this.listener.releaseSocket(this.socket, inSocket, outSocket); // shut sockets } catch (Throwable errClose) { } if (!(err instanceof ClientSocketException)) { Logger.log(Logger.ERROR, Launcher.RESOURCES, "RequestHandlerThread.RequestError", err); } } } /** * Actually process the request. This takes the request and response, and feeds * them to the desired servlet, which then processes them or throws them off to * another servlet. */ private void processRequest(WebAppConfiguration webAppConfig, WinstoneRequest req, WinstoneResponse rsp, String path) throws IOException { RequestDispatcher rd; javax.servlet.RequestDispatcher rdError = null; try { rd = webAppConfig.getInitialDispatcher(path, req, rsp); // Null RD means an error or we have been redirected to a welcome page if (rd != null) { Logger.log(Logger.FULL_DEBUG, Launcher.RESOURCES, "RequestHandlerThread.HandlingRD", rd.getName()); rd.forward(req, rsp); } // if null returned, assume we were redirected } catch (ClientSocketException err) { // ignore this error. caused by a browser shutting down the connection } catch (Throwable err) { boolean ignore = false; for(Throwable t=err; t!=null; t=t.getCause()) { if (t instanceof ClientSocketException) { ignore = true; break; } } if(!ignore) { Logger.log(Logger.WARNING, Launcher.RESOURCES, "RequestHandlerThread.UntrappedError", err); rdError = webAppConfig.getErrorDispatcherByClass(err); } } // If there was any kind of error, execute the error dispatcher here if (rdError != null) { try { if (rsp.isCommitted()) { rdError.include(req, rsp); } else { rsp.resetBuffer(); rdError.forward(req, rsp); } } catch (Throwable err) { Logger.log(Logger.ERROR, Launcher.RESOURCES, "RequestHandlerThread.ErrorInErrorServlet", err); } // rsp.sendUntrappedError(err, req, rd != null ? rd.getName() : null); } rsp.flushBuffer(); rsp.getWinstoneOutputStream().setClosed(true); req.discardRequestBody(); } public void setRequest(WinstoneRequest request) { this.req = request; } public void setResponse(WinstoneResponse response) { this.rsp = response; } public void setInStream(WinstoneInputStream inStream) { this.inData = inStream; } public void setOutStream(WinstoneOutputStream outStream) { this.outData = outStream; } public void setRequestStartTime() { this.requestStartTime = System.currentTimeMillis(); } public long getRequestProcessTime() { return System.currentTimeMillis() - this.requestStartTime; } protected void writeToAccessLog(String originalURL, WinstoneRequest request, WinstoneResponse response, WebAppConfiguration webAppConfig) { if (webAppConfig != null) { // Log a row containing appropriate data AccessLogger logger = webAppConfig.getAccessLogger(); if (logger != null) { logger.log(originalURL, request, response); } } } } jenkins-winstone-0.9.10-jenkins-47/src/java/winstone/cluster/0000755000175000017500000000000012200024521024472 5ustar jamespagejamespagejenkins-winstone-0.9.10-jenkins-47/src/java/winstone/cluster/ClusterSessionSearch.java0000644000175000017500000000746312200024521031462 0ustar jamespagejamespage/* * Copyright 2003-2006 Rick Knowles * Distributed under the terms of either: * - the common development and distribution license (CDDL), v1.0; or * - the GNU Lesser General Public License, v2.1 or later */ package winstone.cluster; import java.net.*; import java.io.*; import winstone.Logger; import winstone.WinstoneSession; /** * Contains all the logic for reading in sessions * * @author Rick Knowles * @version $Id: ClusterSessionSearch.java,v 1.6 2006/03/24 17:24:18 rickknowles Exp $ */ public class ClusterSessionSearch implements Runnable { final int TIMEOUT = 2000; public static final byte SESSION_CHECK_TYPE = (byte) '1'; public static final String SESSION_NOT_FOUND = "NOTFOUND"; public static final String SESSION_FOUND = "FOUND"; public static final String SESSION_RECEIVED = "OK"; private boolean isFinished; // private boolean interrupted; private WinstoneSession result; private String searchWebAppHostname; private String searchWebAppPrefix; private String searchId; private String searchAddressPort; private int controlPort; /** * Sets up for a threaded search */ public ClusterSessionSearch(String webAppPrefix, String hostName, String sessionId, String ipPort, int controlPort) { this.isFinished = false; this.searchWebAppHostname = hostName; this.searchWebAppPrefix = webAppPrefix; // this.interrupted = false; this.searchId = sessionId; this.searchAddressPort = ipPort; this.result = null; this.controlPort = controlPort; // Start the search thread Thread searchThread = new Thread(this); searchThread.setDaemon(true); searchThread.start(); } /** * Actually implements the search */ public void run() { try { int colonPos = this.searchAddressPort.indexOf(':'); String ipAddress = this.searchAddressPort.substring(0, colonPos); String port = this.searchAddressPort.substring(colonPos + 1); Socket controlConnection = new Socket(ipAddress, Integer.parseInt(port)); controlConnection.setSoTimeout(TIMEOUT); OutputStream out = controlConnection.getOutputStream(); out.write(SESSION_CHECK_TYPE); out.flush(); ObjectOutputStream outControl = new ObjectOutputStream(out); outControl.writeInt(this.controlPort); outControl.writeUTF(this.searchId); outControl.writeUTF(this.searchWebAppHostname); outControl.writeUTF(this.searchWebAppPrefix); outControl.flush(); InputStream in = controlConnection.getInputStream(); ObjectInputStream inSession = new ObjectInputStream(in); String reply = inSession.readUTF(); if ((reply != null) && reply.equals(SESSION_FOUND)) { WinstoneSession session = (WinstoneSession) inSession .readObject(); outControl.writeUTF(SESSION_RECEIVED); this.result = session; } outControl.close(); inSession.close(); out.close(); in.close(); controlConnection.close(); } catch (Throwable err) { Logger.log(Logger.WARNING, SimpleCluster.CLUSTER_RESOURCES, "ClusterSessionSearch.Error", err); } this.isFinished = true; } public boolean isFinished() { return this.isFinished; } public WinstoneSession getResult() { return this.result; } public void destroy() { // this.interrupted = true; } public String getAddressPort() { return this.searchAddressPort; } } jenkins-winstone-0.9.10-jenkins-47/src/java/winstone/cluster/SimpleCluster.java0000644000175000017500000003441112200024521030133 0ustar jamespagejamespage/* * Copyright 2003-2006 Rick Knowles * Distributed under the terms of either: * - the common development and distribution license (CDDL), v1.0; or * - the GNU Lesser General Public License, v2.1 or later */ package winstone.cluster; import java.io.IOException; import java.io.InputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.OutputStream; import java.net.ConnectException; import java.net.Socket; import java.util.ArrayList; import java.util.Collection; import java.util.Date; import java.util.HashSet; import java.util.Hashtable; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import java.util.StringTokenizer; import winstone.Cluster; import winstone.HostConfiguration; import winstone.HostGroup; import winstone.Logger; import winstone.cmdline.Option; import winstone.WebAppConfiguration; import winstone.WinstoneResourceBundle; import winstone.WinstoneSession; /** * Represents a cluster of winstone containers. * * @author Rick Knowles * @version $Id: SimpleCluster.java,v 1.8 2006/08/10 06:38:31 rickknowles Exp $ */ public class SimpleCluster implements Runnable, Cluster { final int SESSION_CHECK_TIMEOUT = 100; final int HEARTBEAT_PERIOD = 5000; final int MAX_NO_OF_MISSING_HEARTBEATS = 3; final byte NODELIST_DOWNLOAD_TYPE = (byte) '2'; final byte NODE_HEARTBEAT_TYPE = (byte) '3'; public static final WinstoneResourceBundle CLUSTER_RESOURCES = new WinstoneResourceBundle("winstone.cluster.LocalStrings"); private int controlPort; private String initialClusterNodes; private Map clusterAddresses; private boolean interrupted; /** * Builds a cluster instance */ public SimpleCluster(Map args, Integer controlPort) { this.interrupted = false; this.clusterAddresses = new Hashtable(); if (controlPort != null) this.controlPort = controlPort; // Start cluster init thread this.initialClusterNodes = Option.CLUSTER_NODES.get(args); Thread thread = new Thread(this, CLUSTER_RESOURCES .getString("SimpleCluster.ThreadName")); thread.setDaemon(true); thread.setPriority(Thread.MIN_PRIORITY); thread.start(); } public void destroy() { this.interrupted = true; } /** * Send a heartbeat every now and then, and remove any nodes that haven't * responded in 3 heartbeats. */ public void run() { // Ask each of the known addresses for their cluster lists, and build a // set if (this.initialClusterNodes != null) { StringTokenizer st = new StringTokenizer(this.initialClusterNodes, ","); while (st.hasMoreTokens() && !interrupted) askClusterNodeForNodeList(st.nextToken()); } Logger.log(Logger.DEBUG, CLUSTER_RESOURCES, "SimpleCluster.InitNodes", "" + this.clusterAddresses.size()); while (!interrupted) { try { Set addresses = new HashSet(this.clusterAddresses.keySet()); Date noHeartbeatDate = new Date(System.currentTimeMillis() - (MAX_NO_OF_MISSING_HEARTBEATS * HEARTBEAT_PERIOD)); for (Object address : addresses) { String ipPort = (String) address; Date lastHeartBeat = (Date) this.clusterAddresses .get(ipPort); if (lastHeartBeat.before(noHeartbeatDate)) { this.clusterAddresses.remove(ipPort); Logger.log(Logger.FULL_DEBUG, CLUSTER_RESOURCES, "SimpleCluster.RemovingNode", ipPort); } // Send heartbeat else sendHeartbeat(ipPort); } Thread.sleep(HEARTBEAT_PERIOD); } catch (Throwable err) { Logger.log(Logger.ERROR, CLUSTER_RESOURCES, "SimpleCluster.ErrorMonitorThread", err); } } Logger.log(Logger.FULL_DEBUG, CLUSTER_RESOURCES, "SimpleCluster.FinishedMonitorThread"); } /** * Check if the other nodes in this cluster have a session for this * sessionId. * * @param sessionId The id of the session to check for * @return A valid session instance */ public WinstoneSession askClusterForSession(String sessionId, WebAppConfiguration webAppConfig) { // Iterate through the cluster members Collection addresses = new ArrayList(clusterAddresses.keySet()); Collection searchThreads = new ArrayList(); for (Object address : addresses) { String ipPort = (String) address; ClusterSessionSearch search = new ClusterSessionSearch( webAppConfig.getContextPath(), webAppConfig.getOwnerHostname(), sessionId, ipPort, this.controlPort); searchThreads.add(search); } // Wait until we get an answer WinstoneSession answer = null; String senderThread = null; boolean finished = false; while (!finished) { // Loop through all search threads. If finished, exit, otherwise // sleep List finishedThreads = new ArrayList(); for (Object searchThread1 : searchThreads) { ClusterSessionSearch searchThread = (ClusterSessionSearch) searchThread1; if (!searchThread.isFinished()) continue; else if (searchThread.getResult() == null) finishedThreads.add(searchThread); else { answer = searchThread.getResult(); senderThread = searchThread.getAddressPort(); } } // Remove finished threads for (Object finishedThread : finishedThreads) searchThreads.remove(finishedThread); if (searchThreads.isEmpty() || (answer != null)) finished = true; else try { Thread.sleep(100); } catch (InterruptedException err) { } } // Once we have an answer, terminate all search threads for (Object searchThread1 : searchThreads) { ClusterSessionSearch searchThread = (ClusterSessionSearch) searchThread1; searchThread.destroy(); } if (answer != null) { answer.activate(webAppConfig); Logger.log(Logger.DEBUG, CLUSTER_RESOURCES, "SimpleCluster.SessionTransferredFrom", senderThread); } return answer; } /** * Given an address, retrieve the list of cluster nodes and initialise dates * * @param address The address to request a node list from */ private void askClusterNodeForNodeList(String address) { try { int colonPos = address.indexOf(':'); String ipAddress = address.substring(0, colonPos); String port = address.substring(colonPos + 1); Socket clusterListSocket = new Socket(ipAddress, Integer.parseInt(port)); this.clusterAddresses.put(clusterListSocket.getInetAddress() .getHostAddress() + ":" + port, new Date()); InputStream in = clusterListSocket.getInputStream(); OutputStream out = clusterListSocket.getOutputStream(); out.write(NODELIST_DOWNLOAD_TYPE); out.flush(); // Write out the control port ObjectOutputStream outControl = new ObjectOutputStream(out); outControl.writeInt(this.controlPort); outControl.flush(); // For each node, add an entry to cluster nodes ObjectInputStream inData = new ObjectInputStream(in); int nodeCount = inData.readInt(); for (int n = 0; n < nodeCount; n++) this.clusterAddresses.put(inData.readUTF(), new Date()); inData.close(); outControl.close(); out.close(); in.close(); clusterListSocket.close(); } catch (ConnectException err) { Logger.log(Logger.DEBUG, CLUSTER_RESOURCES, "SimpleCluster.NoNodeListResponse", address); } catch (Throwable err) { Logger.log(Logger.ERROR, CLUSTER_RESOURCES, "SimpleCluster.ErrorGetNodeList", address, err); } } /** * Given an address, send a heartbeat * * @param address The address to request a node list from */ private void sendHeartbeat(String address) { try { int colonPos = address.indexOf(':'); String ipAddress = address.substring(0, colonPos); String port = address.substring(colonPos + 1); Socket heartbeatSocket = new Socket(ipAddress, Integer.parseInt(port)); OutputStream out = heartbeatSocket.getOutputStream(); out.write(NODE_HEARTBEAT_TYPE); out.flush(); ObjectOutputStream outData = new ObjectOutputStream(out); outData.writeInt(this.controlPort); outData.close(); heartbeatSocket.close(); Logger.log(Logger.FULL_DEBUG, CLUSTER_RESOURCES, "SimpleCluster.HeartbeatSent", address); } catch (ConnectException err) {/* ignore - 3 fails, and we remove */ } catch (Throwable err) { Logger.log(Logger.ERROR, CLUSTER_RESOURCES, "SimpleCluster.HeartbeatError", address, err); } } /** * Accept a control socket request related to the cluster functions and * process the request. * * @param requestType A byte indicating the request type * @param in Socket input stream * @param outSocket output stream * @param webAppConfig Instance of the web app * @throws IOException */ public void clusterRequest(byte requestType, InputStream in, OutputStream out, Socket socket, HostGroup hostGroup) throws IOException { if (requestType == ClusterSessionSearch.SESSION_CHECK_TYPE) handleClusterSessionRequest(socket, in, out, hostGroup); else if (requestType == NODELIST_DOWNLOAD_TYPE) handleNodeListDownloadRequest(socket, in, out); else if (requestType == NODE_HEARTBEAT_TYPE) handleNodeHeartBeatRequest(socket, in); else Logger.log(Logger.ERROR, CLUSTER_RESOURCES, "SimpleCluster.UnknownRequest", "" + (char) requestType); } /** * Handles incoming socket requests for session search */ public void handleClusterSessionRequest(Socket socket, InputStream in, OutputStream out, HostGroup hostGroup) throws IOException { // Read in a string for the sessionId ObjectInputStream inControl = new ObjectInputStream(in); int port = inControl.readInt(); String ipPortSender = socket.getInetAddress().getHostAddress() + ":" + port; String sessionId = inControl.readUTF(); String hostname = inControl.readUTF(); HostConfiguration hostConfig = hostGroup.getHostByName(hostname); String webAppPrefix = inControl.readUTF(); WebAppConfiguration webAppConfig = hostConfig.getWebAppByURI(webAppPrefix); ObjectOutputStream outData = new ObjectOutputStream(out); if (webAppConfig == null) { outData.writeUTF(ClusterSessionSearch.SESSION_NOT_FOUND); } else { WinstoneSession session = webAppConfig.getSessionById(sessionId, true); if (session != null) { outData.writeUTF(ClusterSessionSearch.SESSION_FOUND); outData.writeObject(session); outData.flush(); if (inControl.readUTF().equals( ClusterSessionSearch.SESSION_RECEIVED)) session.passivate(); Logger.log(Logger.DEBUG, CLUSTER_RESOURCES, "SimpleCluster.SessionTransferredTo", ipPortSender); } else { outData.writeUTF(ClusterSessionSearch.SESSION_NOT_FOUND); } } outData.close(); inControl.close(); } /** * Handles incoming socket requests for cluster node lists. */ public void handleNodeListDownloadRequest(Socket socket, InputStream in, OutputStream out) throws IOException { // Get the ip and port of the requester, and make sure we don't send // that ObjectInputStream inControl = new ObjectInputStream(in); int port = inControl.readInt(); String ipPortSender = socket.getInetAddress().getHostAddress() + ":" + port; List allClusterNodes = new ArrayList(this.clusterAddresses.keySet()); List relevantClusterNodes = new ArrayList(); for (Object allClusterNode : allClusterNodes) { String node = (String) allClusterNode; if (!node.equals(ipPortSender)) relevantClusterNodes.add(node); } ObjectOutputStream outData = new ObjectOutputStream(out); outData.writeInt(relevantClusterNodes.size()); outData.flush(); for (Object relevantClusterNode : relevantClusterNodes) { String ipPort = (String) relevantClusterNode; if (!ipPort.equals(ipPortSender)) outData.writeUTF(ipPort); outData.flush(); } outData.close(); inControl.close(); } /** * Handles heartbeats. Just updates the date of this node's last heartbeat */ public void handleNodeHeartBeatRequest(Socket socket, InputStream in) throws IOException { ObjectInputStream inData = new ObjectInputStream(in); int remoteControlPort = inData.readInt(); inData.close(); String ipPort = socket.getInetAddress().getHostAddress() + ":" + remoteControlPort; this.clusterAddresses.put(ipPort, new Date()); Logger.log(Logger.FULL_DEBUG, CLUSTER_RESOURCES, "SimpleCluster.HeartbeatReceived", ipPort); } } jenkins-winstone-0.9.10-jenkins-47/src/java/winstone/cluster/LocalStrings.properties0000644000175000017500000000157312200024521031222 0ustar jamespagejamespageSimpleCluster.ThreadName=Cluster monitor thread SimpleCluster.InitNodes=Cluster initialised with [#0] nodes SimpleCluster.RemovingNode=Removing address from cluster node list: [#0] SimpleCluster.ErrorMonitorThread=Error in cluster monitor thread SimpleCluster.FinishedMonitorThread=Cluster monitor thread finished SimpleCluster.ErrorGetNodeList=Error getting nodelist from: [#0] SimpleCluster.HeartbeatSent=Heartbeat sent to: [#0] SimpleCluster.HeartbeatError=Error sending heartbeat to: [#0] SimpleCluster.UnknownRequest=Unknown cluster request type: [#0] SimpleCluster.SessionTransferredTo=Session transferred to: [#0] SimpleCluster.SessionTransferredFrom=Session transferred from: [#0] SimpleCluster.HeartbeatReceived=Heartbeat received from: [#0] SimpleCluster.NoNodeListResponse=No cluster node detected at [#0] - ignoring ClusterSessionSearch.Error=Error during cluster session searchjenkins-winstone-0.9.10-jenkins-47/src/java/winstone/ClientSocketException.java0000644000175000017500000000050412200024521030121 0ustar jamespagejamespagepackage winstone; import java.io.IOException; /** * Indicates an I/O exception writing to client. * * @author Kohsuke Kawaguchi */ public class ClientSocketException extends IOException { public ClientSocketException(Throwable cause) { super("Failed to write to client"); initCause(cause); } } jenkins-winstone-0.9.10-jenkins-47/src/java/winstone/AccessLogger.java0000644000175000017500000000121112200024521026210 0ustar jamespagejamespage/* * Copyright 2003-2006 Rick Knowles * Distributed under the terms of either: * - the common development and distribution license (CDDL), v1.0; or * - the GNU Lesser General Public License, v2.1 or later */ package winstone; /** * Used for logging accesses, eg in Apache access_log style * * @author Rick Knowles * @version $Id: AccessLogger.java,v 1.2 2006/02/28 07:32:47 rickknowles Exp $ */ public interface AccessLogger { public void log(String originalURL, WinstoneRequest request, WinstoneResponse response); public void destroy(); } jenkins-winstone-0.9.10-jenkins-47/src/java/winstone/WinstoneSession.java0000644000175000017500000004673012200024521027040 0ustar jamespagejamespage/* * Copyright 2003-2006 Rick Knowles * Distributed under the terms of either: * - the common development and distribution license (CDDL), v1.0; or * - the GNU Lesser General Public License, v2.1 or later */ package winstone; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.OutputStream; import java.io.Serializable; import java.util.ArrayList; import java.util.Collections; import java.util.Enumeration; import java.util.HashMap; import java.util.HashSet; import java.util.Hashtable; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import javax.servlet.ServletContext; import javax.servlet.http.HttpSession; import javax.servlet.http.HttpSessionActivationListener; import javax.servlet.http.HttpSessionAttributeListener; import javax.servlet.http.HttpSessionBindingEvent; import javax.servlet.http.HttpSessionBindingListener; import javax.servlet.http.HttpSessionEvent; import javax.servlet.http.HttpSessionListener; /** * Http session implementation for Winstone. * * @author Rick Knowles * @version $Id: WinstoneSession.java,v 1.10 2006/08/27 07:19:47 rickknowles Exp $ */ public class WinstoneSession implements HttpSession, Serializable { public static String SESSION_COOKIE_NAME = "JSESSIONID"; private String sessionId; private WebAppConfiguration webAppConfig; private Map sessionData; private long createTime; private long lastAccessedTime; private int maxInactivePeriod; private boolean isNew; private boolean isInvalidated; private HttpSessionAttributeListener sessionAttributeListeners[]; private HttpSessionListener sessionListeners[]; private HttpSessionActivationListener sessionActivationListeners[]; private boolean distributable; private Object sessionMonitor = true; private Set requestsUsingMe; /** * Constructor */ public WinstoneSession(String sessionId) { this.sessionId = sessionId; this.sessionData = new Hashtable(); this.requestsUsingMe = Collections.synchronizedSet(new HashSet()); this.createTime = System.currentTimeMillis(); this.isNew = true; this.isInvalidated = false; } public void setWebAppConfiguration(WebAppConfiguration webAppConfig) { this.webAppConfig = webAppConfig; this.distributable = webAppConfig.isDistributable(); } public void sendCreatedNotifies() { // Notify session listeners of new session for (HttpSessionListener sessionListener : this.sessionListeners) { ClassLoader cl = Thread.currentThread().getContextClassLoader(); Thread.currentThread().setContextClassLoader(this.webAppConfig.getLoader()); sessionListener.sessionCreated(new HttpSessionEvent(this)); Thread.currentThread().setContextClassLoader(cl); } } public void setSessionActivationListeners( HttpSessionActivationListener listeners[]) { this.sessionActivationListeners = listeners; } public void setSessionAttributeListeners( HttpSessionAttributeListener listeners[]) { this.sessionAttributeListeners = listeners; } public void setSessionListeners(HttpSessionListener listeners[]) { this.sessionListeners = listeners; } public void setLastAccessedDate(long time) { this.lastAccessedTime = time; } public void setIsNew(boolean isNew) { this.isNew = isNew; } public void addUsed(WinstoneRequest request) { this.requestsUsingMe.add(request); } public void removeUsed(WinstoneRequest request) { this.requestsUsingMe.remove(request); } public boolean isUnusedByRequests() { return this.requestsUsingMe.isEmpty(); } public boolean isExpired() { // check if it's expired yet long nowDate = System.currentTimeMillis(); long maxInactive = getMaxInactiveInterval() * 1000; return ((maxInactive > 0) && (nowDate - this.lastAccessedTime > maxInactive )); } // Implementation methods public Object getAttribute(String name) { if (this.isInvalidated) { throw new IllegalStateException(Launcher.RESOURCES.getString("WinstoneSession.InvalidatedSession")); } Object att; synchronized (this.sessionMonitor) { att = this.sessionData.get(name); } return att; } public Enumeration getAttributeNames() { if (this.isInvalidated) { throw new IllegalStateException(Launcher.RESOURCES.getString("WinstoneSession.InvalidatedSession")); } Enumeration names; synchronized (this.sessionMonitor) { names = Collections.enumeration(this.sessionData.keySet()); } return names; } public void setAttribute(String name, Object value) { if (this.isInvalidated) { throw new IllegalStateException(Launcher.RESOURCES.getString("WinstoneSession.InvalidatedSession")); } // Check for serializability if distributable if (this.distributable && (value != null) && !(value instanceof java.io.Serializable)) throw new IllegalArgumentException(Launcher.RESOURCES.getString( "WinstoneSession.AttributeNotSerializable", new String[] { name, value.getClass().getName() })); // valueBound must be before binding if (value instanceof HttpSessionBindingListener) { HttpSessionBindingListener hsbl = (HttpSessionBindingListener) value; ClassLoader cl = Thread.currentThread().getContextClassLoader(); Thread.currentThread().setContextClassLoader(this.webAppConfig.getLoader()); hsbl.valueBound(new HttpSessionBindingEvent(this, name, value)); Thread.currentThread().setContextClassLoader(cl); } Object oldValue; synchronized (this.sessionMonitor) { oldValue = this.sessionData.get(name); if (value == null) { this.sessionData.remove(name); } else { this.sessionData.put(name, value); } } // valueUnbound must be after unbinding if (oldValue instanceof HttpSessionBindingListener) { HttpSessionBindingListener hsbl = (HttpSessionBindingListener) oldValue; ClassLoader cl = Thread.currentThread().getContextClassLoader(); Thread.currentThread().setContextClassLoader(this.webAppConfig.getLoader()); hsbl.valueUnbound(new HttpSessionBindingEvent(this, name, oldValue)); Thread.currentThread().setContextClassLoader(cl); } // Notify other listeners if (oldValue != null) for (HttpSessionAttributeListener sessionAttributeListener1 : this.sessionAttributeListeners) { ClassLoader cl = Thread.currentThread().getContextClassLoader(); Thread.currentThread().setContextClassLoader(this.webAppConfig.getLoader()); sessionAttributeListener1.attributeReplaced( new HttpSessionBindingEvent(this, name, oldValue)); Thread.currentThread().setContextClassLoader(cl); } else for (HttpSessionAttributeListener sessionAttributeListener : this.sessionAttributeListeners) { ClassLoader cl = Thread.currentThread().getContextClassLoader(); Thread.currentThread().setContextClassLoader(this.webAppConfig.getLoader()); sessionAttributeListener.attributeAdded( new HttpSessionBindingEvent(this, name, value)); Thread.currentThread().setContextClassLoader(cl); } } public void removeAttribute(String name) { if (this.isInvalidated) { throw new IllegalStateException(Launcher.RESOURCES.getString("WinstoneSession.InvalidatedSession")); } Object value; synchronized (this.sessionMonitor) { value = this.sessionData.get(name); this.sessionData.remove(name); } // Notify listeners if (value instanceof HttpSessionBindingListener) { HttpSessionBindingListener hsbl = (HttpSessionBindingListener) value; ClassLoader cl = Thread.currentThread().getContextClassLoader(); Thread.currentThread().setContextClassLoader(this.webAppConfig.getLoader()); hsbl.valueUnbound(new HttpSessionBindingEvent(this, name)); Thread.currentThread().setContextClassLoader(cl); } if (value != null) for (HttpSessionAttributeListener sessionAttributeListener : this.sessionAttributeListeners) { ClassLoader cl = Thread.currentThread().getContextClassLoader(); Thread.currentThread().setContextClassLoader(this.webAppConfig.getLoader()); sessionAttributeListener.attributeRemoved( new HttpSessionBindingEvent(this, name, value)); Thread.currentThread().setContextClassLoader(cl); } } public long getCreationTime() { if (this.isInvalidated) { throw new IllegalStateException(Launcher.RESOURCES.getString("WinstoneSession.InvalidatedSession")); } return this.createTime; } public long getLastAccessedTime() { if (this.isInvalidated) { throw new IllegalStateException(Launcher.RESOURCES.getString("WinstoneSession.InvalidatedSession")); } return this.lastAccessedTime; } public String getId() { return this.sessionId; } public int getMaxInactiveInterval() { return this.maxInactivePeriod; } public void setMaxInactiveInterval(int interval) { this.maxInactivePeriod = interval; } public boolean isNew() { if (this.isInvalidated) { throw new IllegalStateException(Launcher.RESOURCES.getString("WinstoneSession.InvalidatedSession")); } return this.isNew; } public ServletContext getServletContext() { return this.webAppConfig; } public void invalidate() { if (this.isInvalidated) { throw new IllegalStateException(Launcher.RESOURCES.getString("WinstoneSession.InvalidatedSession")); } // Notify session listeners of invalidated session -- backwards for (int n = this.sessionListeners.length - 1; n >= 0; n--) { ClassLoader cl = Thread.currentThread().getContextClassLoader(); Thread.currentThread().setContextClassLoader(this.webAppConfig.getLoader()); this.sessionListeners[n].sessionDestroyed(new HttpSessionEvent(this)); Thread.currentThread().setContextClassLoader(cl); } List keys = new ArrayList(this.sessionData.keySet()); for (Object key : keys) removeAttribute((String) key); synchronized (this.sessionMonitor) { this.sessionData.clear(); } this.isInvalidated = true; this.webAppConfig.removeSessionById(this.sessionId); } /** * Called after the session has been serialized to another server. */ public void passivate() { // Notify session listeners of invalidated session for (HttpSessionActivationListener sessionActivationListener : this.sessionActivationListeners) { ClassLoader cl = Thread.currentThread().getContextClassLoader(); Thread.currentThread().setContextClassLoader(this.webAppConfig.getLoader()); sessionActivationListener.sessionWillPassivate( new HttpSessionEvent(this)); Thread.currentThread().setContextClassLoader(cl); } // Question: Is passivation equivalent to invalidation ? Should all // entries be removed ? // List keys = new ArrayList(this.sessionData.keySet()); // for (Iterator i = keys.iterator(); i.hasNext(); ) // removeAttribute((String) i.next()); synchronized (this.sessionMonitor) { this.sessionData.clear(); } this.webAppConfig.removeSessionById(this.sessionId); } /** * Called after the session has been deserialized from another server. */ public void activate(WebAppConfiguration webAppConfig) { this.webAppConfig = webAppConfig; webAppConfig.setSessionListeners(this); // Notify session listeners of invalidated session for (HttpSessionActivationListener sessionActivationListener : this.sessionActivationListeners) { ClassLoader cl = Thread.currentThread().getContextClassLoader(); Thread.currentThread().setContextClassLoader(this.webAppConfig.getLoader()); sessionActivationListener.sessionDidActivate( new HttpSessionEvent(this)); Thread.currentThread().setContextClassLoader(cl); } } /** * Save this session to the temp dir defined for this webapp */ public void saveToTemp() { File toDir = getSessionTempDir(this.webAppConfig); synchronized (this.sessionMonitor) { OutputStream out = null; ObjectOutputStream objOut = null; try { File toFile = new File(toDir, this.sessionId + ".ser"); out = new FileOutputStream(toFile, false); objOut = new ObjectOutputStream(out); objOut.writeObject(this); } catch (IOException err) { Logger.log(Logger.ERROR, Launcher.RESOURCES, "WinstoneSession.ErrorSavingSession", err); } finally { if (objOut != null) { try {objOut.close();} catch (IOException err) {} } if (out != null) { try {out.close();} catch (IOException err) {} } } } } public static File getSessionTempDir(WebAppConfiguration webAppConfig) { File tmpDir = (File) webAppConfig.getAttribute("javax.servlet.context.tempdir"); File sessionsDir = new File(tmpDir, "WEB-INF" + File.separator + "winstoneSessions"); if (!sessionsDir.exists()) { sessionsDir.mkdirs(); } return sessionsDir; } public static void loadSessions(WebAppConfiguration webAppConfig) { int expiredCount = 0; // Iterate through the files in the dir, instantiate and then add to the sessions set File tempDir = getSessionTempDir(webAppConfig); File possibleSessionFiles[] = tempDir.listFiles(); for (File possibleSessionFile : possibleSessionFiles) { if (possibleSessionFile.getName().endsWith(".ser")) { InputStream in = null; ObjectInputStream objIn = null; try { in = new FileInputStream(possibleSessionFile); objIn = new ObjectInputStream(in); WinstoneSession session = (WinstoneSession) objIn.readObject(); session.setWebAppConfiguration(webAppConfig); webAppConfig.setSessionListeners(session); if (session.isExpired()) { session.invalidate(); expiredCount++; } else { webAppConfig.addSession(session.getId(), session); Logger.log(Logger.DEBUG, Launcher.RESOURCES, "WinstoneSession.RestoredSession", session.getId()); } } catch (Throwable err) { Logger.log(Logger.ERROR, Launcher.RESOURCES, "WinstoneSession.ErrorLoadingSession", err); } finally { if (objIn != null) { try { objIn.close(); } catch (IOException err) { } } if (in != null) { try { in.close(); } catch (IOException err) { } } possibleSessionFile.delete(); } } } if (expiredCount > 0) { Logger.log(Logger.DEBUG, Launcher.RESOURCES, "WebAppConfig.InvalidatedSessions", expiredCount + ""); } } /** * Serialization implementation. This makes sure to only serialize the parts * we want to send to another server. * * @param out * The stream to write the contents to * @throws IOException */ private void writeObject(java.io.ObjectOutputStream out) throws IOException { out.writeUTF(sessionId); out.writeLong(createTime); out.writeLong(lastAccessedTime); out.writeInt(maxInactivePeriod); out.writeBoolean(isNew); out.writeBoolean(distributable); // Write the map, but first remove non-serializables Map copy = new HashMap(sessionData); Set keys = new HashSet(copy.keySet()); for (Object key1 : keys) { String key = (String) key1; if (!(copy.get(key) instanceof Serializable)) { Logger.log(Logger.WARNING, Launcher.RESOURCES, "WinstoneSession.SkippingNonSerializable", key, copy.get(key).getClass().getName()); } copy.remove(key); } out.writeInt(copy.size()); for (Object o : copy.keySet()) { String key = (String) o; out.writeUTF(key); out.writeObject(copy.get(key)); } } /** * Deserialization implementation * * @param in * The source of stream data * @throws IOException * @throws ClassNotFoundException */ private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException { this.sessionId = in.readUTF(); this.createTime = in.readLong(); this.lastAccessedTime = in.readLong(); this.maxInactivePeriod = in.readInt(); this.isNew = in.readBoolean(); this.distributable = in.readBoolean(); // Read the map this.sessionData = new Hashtable(); this.requestsUsingMe = Collections.synchronizedSet(new HashSet()); int entryCount = in.readInt(); for (int n = 0; n < entryCount; n++) { String key = in.readUTF(); Object variable = in.readObject(); this.sessionData.put(key, variable); } this.sessionMonitor = true; } /** * @deprecated */ public Object getValue(String name) { return getAttribute(name); } /** * @deprecated */ public void putValue(String name, Object value) { setAttribute(name, value); } /** * @deprecated */ public void removeValue(String name) { removeAttribute(name); } /** * @deprecated */ public String[] getValueNames() { return (String[]) this.sessionData.keySet().toArray(new String[0]); } /** * @deprecated */ public javax.servlet.http.HttpSessionContext getSessionContext() { return null; } // deprecated } jenkins-winstone-0.9.10-jenkins-47/src/java/winstone/tools/0000755000175000017500000000000012200024521024151 5ustar jamespagejamespagejenkins-winstone-0.9.10-jenkins-47/src/java/winstone/tools/WinstoneControlOption.java0000644000175000017500000000025312200024521031354 0ustar jamespagejamespagepackage winstone.tools; import winstone.cmdline.Option; import winstone.cmdline.Option.OInt; /** * @author Kohsuke Kawaguchi */ public class WinstoneControlOption { } jenkins-winstone-0.9.10-jenkins-47/src/java/winstone/tools/WinstoneControl.java0000644000175000017500000001040712200024521030165 0ustar jamespagejamespage/* * Copyright 2003-2006 Rick Knowles * Distributed under the terms of either: * - the common development and distribution license (CDDL), v1.0; or * - the GNU Lesser General Public License, v2.1 or later */ package winstone.tools; import java.io.IOException; import java.io.ObjectOutputStream; import java.io.OutputStream; import java.net.Socket; import java.util.Map; import java.util.logging.Level; import winstone.Launcher; import winstone.Logger; import winstone.WebAppConfiguration; import winstone.WinstoneResourceBundle; import winstone.cmdline.CmdLineParser; import winstone.cmdline.Option; import winstone.cmdline.Option.OInt; import winstone.cmdline.Option.OString; /** * Included so that we can control winstone from the command line a little more * easily. * * @author Rick Knowles * @version $Id: WinstoneControl.java,v 1.6 2006/03/13 15:37:29 rickknowles Exp $ */ public class WinstoneControl { private final static WinstoneResourceBundle TOOLS_RESOURCES = new WinstoneResourceBundle("winstone.tools.LocalStrings"); final static String OPERATION_SHUTDOWN = "shutdown"; final static String OPERATION_RELOAD = "reload:"; static int TIMEOUT = 10000; public static OInt CONTROL_PORT = Option.integer("controlPort"); public static OInt PORT = Option.integer("port"); public static OInt DEBUG = new OInt("debug", 5) { public int get(Map args) { switch(super.get(args)) { // before switching to java.util.Logging, winstone used a (1:9) range for log levels case 1: return Logger.MIN.intValue(); case 2: return Logger.ERROR.intValue(); case 3: return Logger.WARNING.intValue(); case 4: return Logger.INFO.intValue(); case 6: return Logger.SPEED.intValue(); case 7: return Logger.DEBUG.intValue(); case 8: return Logger.FULL_DEBUG.intValue(); case 9: return Logger.MAX.intValue(); case 5: default: return Logger.INFO.intValue(); }}}; public static OString HOST = Option.string("host", "localhost"); /** * Parses command line parameters, and calls the appropriate method for * executing the winstone operation required. */ public static void main(String argv[]) throws Exception { // Load args from the config file Map options = new CmdLineParser(Option.all(WinstoneControl.class)).parse(argv,"operation"); String operation = (String) options.get("operation"); if (operation.equals("")) { printUsage(); return; } Logger.setCurrentDebugLevel(DEBUG.get(options)); String host = HOST.get(options); int port = PORT.get(options, CONTROL_PORT.get(options)); Logger.log(Logger.INFO, TOOLS_RESOURCES, "WinstoneControl.UsingHostPort",host, port); // Check for shutdown if (operation.equalsIgnoreCase(OPERATION_SHUTDOWN)) { Socket socket = new Socket(host, port); socket.setSoTimeout(TIMEOUT); OutputStream out = socket.getOutputStream(); out.write(Launcher.SHUTDOWN_TYPE); out.close(); Logger.log(Logger.INFO, TOOLS_RESOURCES, "WinstoneControl.ShutdownOK",host, port); } // check for reload else if (operation.toLowerCase().startsWith(OPERATION_RELOAD.toLowerCase())) { String webappName = operation.substring(OPERATION_RELOAD.length()); Socket socket = new Socket(host, port); socket.setSoTimeout(TIMEOUT); OutputStream out = socket.getOutputStream(); out.write(Launcher.RELOAD_TYPE); ObjectOutputStream objOut = new ObjectOutputStream(out); objOut.writeUTF(host); objOut.writeUTF(webappName); objOut.close(); out.close(); Logger.log(Logger.INFO, TOOLS_RESOURCES, "WinstoneControl.ReloadOK",host, port); } else { printUsage(); } } /** * Displays the usage message */ private static void printUsage() { System.out.println(TOOLS_RESOURCES.getString("WinstoneControl.Usage")); } } jenkins-winstone-0.9.10-jenkins-47/src/java/winstone/tools/LocalStrings.properties0000644000175000017500000000064312200024521030676 0ustar jamespagejamespageWinstoneControl.Usage=Winstone Command Line Controller\n\ Usage: java winstone.tools.WinstoneControl --host= --port=\n\n\ can be "shutdown" or "reload:" WinstoneControl.UsingHostPort=Connecting to [#0]:[#1] WinstoneControl.ShutdownOK=Successfully sent server shutdown command to [#0]:[#1] WinstoneControl.ReloadOK=Successfully sent webapp reload command to [#0]:[#1] jenkins-winstone-0.9.10-jenkins-47/src/java/winstone/mime.properties0000644000175000017500000006620312200024521026065 0ustar jamespagejamespage123=application/vnd.lotus-1-2-3 3dml=text/vnd.in3d.3dml 3g2=video/3gpp2 3gp=video/3gpp 7z=application/x-7z-compressed aab=application/x-authorware-bin aac=audio/x-aac aam=application/x-authorware-map a=application/octet-stream aas=application/x-authorware-seg abs=audio/x-mpeg abw=application/x-abiword ac=application/pkix-attr-cert acc=application/vnd.americandynamics.acc ace=application/x-ace-compressed acu=application/vnd.acucobol acutc=application/vnd.acucorp adp=audio/adpcm aep=application/vnd.audiograph afm=application/x-font-type1 afp=application/vnd.ibm.modcap ahead=application/vnd.ahead.space ai=application/postscript aif=audio/x-aiff aifc=audio/x-aiff aiff=audio/x-aiff aim=application/x-aim air=application/vnd.adobe.air-application-installer-package+zip ait=application/vnd.dvb.ait ami=application/vnd.amiga.ami anx=application/annodex apk=application/vnd.android.package-archive application=application/x-ms-application apr=application/vnd.lotus-approach art=image/x-jg asc=application/pgp-signature asf=video/x-ms-asf asm=text/x-asm aso=application/vnd.accpac.simply.aso asx=video/x-ms-asf atc=application/vnd.acucorp atom=application/atom+xml atomcat=application/atomcat+xml atomsvc=application/atomsvc+xml atx=application/vnd.antix.game-component au=audio/basic avi=video/x-msvideo avx=video/x-rad-screenplay aw=application/applixware axa=audio/annodex axv=video/annodex azf=application/vnd.airzip.filesecure.azf azs=application/vnd.airzip.filesecure.azs azw=application/vnd.amazon.ebook bat=application/x-msdownload bcpio=application/x-bcpio bdf=application/x-font-bdf bdm=application/vnd.syncml.dm+wbxml bed=application/vnd.realvnc.bed bh2=application/vnd.fujitsu.oasysprs bin=application/octet-stream bmi=application/vnd.bmi bmp=image/bmp body=text/html book=application/vnd.framemaker box=application/vnd.previewsystems.box boz=application/x-bzip2 bpk=application/octet-stream btif=image/prs.btif bz2=application/x-bzip2 bz=application/x-bzip c11amc=application/vnd.cluetrust.cartomobile-config c11amz=application/vnd.cluetrust.cartomobile-config-pkg c4d=application/vnd.clonk.c4group c4f=application/vnd.clonk.c4group c4g=application/vnd.clonk.c4group c4p=application/vnd.clonk.c4group c4u=application/vnd.clonk.c4group cab=application/vnd.ms-cab-compressed cap=application/vnd.tcpdump.pcap car=application/vnd.curl.car cat=application/vnd.ms-pki.seccat cct=application/x-director cc=text/x-c ccxml=application/ccxml+xml cdbcmsg=application/vnd.contact.cmsg cdf=application/x-cdf cdkey=application/vnd.mediastation.cdkey cdmia=application/cdmi-capability cdmic=application/cdmi-container cdmid=application/cdmi-domain cdmio=application/cdmi-object cdmiq=application/cdmi-queue cdx=chemical/x-cdx cdxml=application/vnd.chemdraw+xml cdy=application/vnd.cinderella cer=application/pkix-cert cgm=image/cgm chat=application/x-chat chm=application/vnd.ms-htmlhelp chrt=application/vnd.kde.kchart cif=chemical/x-cif cii=application/vnd.anser-web-certificate-issue-initiation cil=application/vnd.ms-artgalry cla=application/vnd.claymore class=application/java clkk=application/vnd.crick.clicker.keyboard clkp=application/vnd.crick.clicker.palette clkt=application/vnd.crick.clicker.template clkw=application/vnd.crick.clicker.wordbank clkx=application/vnd.crick.clicker clp=application/x-msclip cmc=application/vnd.cosmocaller cmdf=chemical/x-cmdf cml=chemical/x-cml cmp=application/vnd.yellowriver-custom-menu cmx=image/x-cmx cod=application/vnd.rim.cod com=application/x-msdownload conf=text/plain cpio=application/x-cpio cpp=text/x-c cpt=application/mac-compactpro crd=application/x-mscardfile crl=application/pkix-crl crt=application/x-x509-ca-cert cryptonote=application/vnd.rig.cryptonote csh=application/x-csh csml=chemical/x-csml csp=application/vnd.commonspace css=text/css cst=application/x-director csv=text/csv c=text/x-c cu=application/cu-seeme curl=text/vnd.curl cww=application/prs.cww cxt=application/x-director cxx=text/x-c dae=model/vnd.collada+xml daf=application/vnd.mobius.daf dataless=application/vnd.fdsn.seed davmount=application/davmount+xml dcr=application/x-director dcurl=text/vnd.curl.dcurl dd2=application/vnd.oma.dd2+xml ddd=application/vnd.fujixerox.ddd deb=application/x-debian-package def=text/plain deploy=application/octet-stream der=application/x-x509-ca-cert dfac=application/vnd.dreamfactory dib=image/bmp dic=text/x-c diff=text/plain dir=application/x-director dis=application/vnd.mobius.dis dist=application/octet-stream distz=application/octet-stream djv=image/vnd.djvu djvu=image/vnd.djvu dll=application/x-msdownload dmg=application/octet-stream dmp=application/vnd.tcpdump.pcap dms=application/octet-stream dna=application/vnd.dna doc=application/msword docm=application/vnd.ms-word.document.macroenabled.12 docx=application/vnd.openxmlformats-officedocument.wordprocessingml.document dot=application/msword dotm=application/vnd.ms-word.template.macroenabled.12 dotx=application/vnd.openxmlformats-officedocument.wordprocessingml.template dp=application/vnd.osgi.dp dpg=application/vnd.dpgraph dra=audio/vnd.dra dsc=text/prs.lines.tag dssc=application/dssc+der dtb=application/x-dtbook+xml dtd=application/xml-dtd dts=audio/vnd.dts dtshd=audio/vnd.dts.hd dump=application/octet-stream dvb=video/vnd.dvb.file dvi=application/x-dvi dv=video/x-dv dwf=model/vnd.dwf dwg=image/vnd.dwg dxf=image/vnd.dxf dxp=application/vnd.spotfire.dxp dxr=application/x-director ear=application/octet-stream ecelp4800=audio/vnd.nuera.ecelp4800 ecelp7470=audio/vnd.nuera.ecelp7470 ecelp9600=audio/vnd.nuera.ecelp9600 ecma=application/ecmascript edm=application/vnd.novadigm.edm edx=application/vnd.novadigm.edx efif=application/vnd.picsel ei6=application/vnd.pg.osasli elc=application/octet-stream eml=message/rfc822 emma=application/emma+xml eol=audio/vnd.digital-winds eot=application/vnd.ms-fontobject eps=application/postscript epub=application/epub+zip es3=application/vnd.eszigno3+xml esf=application/vnd.epson.esf et3=application/vnd.eszigno3+xml etx=text/x-setext exe=application/x-msdownload exi=application/exi ext=application/vnd.novadigm.ext ez2=application/vnd.ezpix-album ez3=application/vnd.ezpix-package ez=application/andrew-inset f4v=video/x-f4v f77=text/x-fortran f90=text/x-fortran fbs=image/vnd.fastbidsheet fcs=application/vnd.isac.fcs fdf=application/vnd.fdf fe_launch=application/vnd.denovo.fcselayout-link fg5=application/vnd.fujitsu.oasysgp fgd=application/x-director fh4=image/x-freehand fh5=image/x-freehand fh7=image/x-freehand fhc=image/x-freehand fh=image/x-freehand fig=application/x-xfig flac=audio/flac fli=video/x-fli flo=application/vnd.micrografx.flo flv=video/x-flv flw=application/vnd.kde.kivio flx=text/vnd.fmi.flexstor fly=text/vnd.fly fm=application/vnd.framemaker fnc=application/vnd.frogans.fnc for=text/x-fortran fpx=image/vnd.fpx frame=application/vnd.framemaker fsc=application/vnd.fsc.weblaunch fst=image/vnd.fst ftc=application/vnd.fluxtime.clip f=text/x-fortran fti=application/vnd.anser-web-funds-transfer-initiation fvt=video/vnd.fvt fxp=application/vnd.adobe.fxp fxpl=application/vnd.adobe.fxp fzs=application/vnd.fuzzysheet g2w=application/vnd.geoplan g3=image/g3fax g3w=application/vnd.geospace gac=application/vnd.groove-account gbr=application/rpki-ghostbusters gdl=model/vnd.gdl geo=application/vnd.dynageo gex=application/vnd.geometry-explorer ggb=application/vnd.geogebra.file ggt=application/vnd.geogebra.tool ghf=application/vnd.groove-help gif=image/gif gim=application/vnd.groove-identity-message gmx=application/vnd.gmx gnumeric=application/x-gnumeric gph=application/vnd.flographit gqf=application/vnd.grafeq gqs=application/vnd.grafeq gram=application/srgs gre=application/vnd.geometry-explorer grv=application/vnd.groove-injector grxml=application/srgs+xml gsf=application/x-font-ghostscript gtar=application/x-gtar gtm=application/vnd.groove-tool-message gtw=model/vnd.gtw gv=text/vnd.graphviz gxt=application/vnd.geonext gz=application/x-gzip h261=video/h261 h263=video/h263 h264=video/h264 hal=application/vnd.hal+xml hbci=application/vnd.hbci hdf=application/x-hdf hh=text/x-c hlp=application/winhlp hpgl=application/vnd.hp-hpgl hpid=application/vnd.hp-hpid hps=application/vnd.hp-hps hqx=application/mac-binhex40 htc=text/x-component h=text/x-c htke=application/vnd.kenameaapp html=text/html htm=text/html hvd=application/vnd.yamaha.hv-dic hvp=application/vnd.yamaha.hv-voice hvs=application/vnd.yamaha.hv-script i2g=application/vnd.intergeo icc=application/vnd.iccprofile ice=x-conference/x-cooltalk icm=application/vnd.iccprofile ico=image/x-icon ics=text/calendar ief=image/ief ifb=text/calendar ifm=application/vnd.shana.informed.formdata iges=model/iges igl=application/vnd.igloader igm=application/vnd.insors.igm igs=model/iges igx=application/vnd.micrografx.igx iif=application/vnd.shana.informed.interchange imp=application/vnd.accpac.simply.imp ims=application/vnd.ms-ims ink=application/inkml+xml inkml=application/inkml+xml in=text/plain iota=application/vnd.astraea-software.iota ipa=application/octet-stream ipfix=application/ipfix ipk=application/vnd.shana.informed.package irm=application/vnd.ibm.rights-management irp=application/vnd.irepository.package+xml iso=application/octet-stream itp=application/vnd.shana.informed.formtemplate ivp=application/vnd.immervision-ivp ivu=application/vnd.immervision-ivu jad=text/vnd.sun.j2me.app-descriptor jam=application/vnd.jam jar=application/java-archive java=text/x-java-source jisp=application/vnd.jisp jlt=application/vnd.hp-jlyt jnlp=application/x-java-jnlp-file joda=application/vnd.joost.joda-archive jpeg=image/jpeg jpe=image/jpeg jpg=image/jpeg jpgm=video/jpm jpgv=video/jpeg jpm=video/jpm js=application/javascript jsf=text/plain json=application/json jspf=text/plain kar=audio/midi karbon=application/vnd.kde.karbon kfo=application/vnd.kde.kformula kia=application/vnd.kidspiration kil=application/x-killustrator kml=application/vnd.google-earth.kml+xml kmz=application/vnd.google-earth.kmz kne=application/vnd.kinar knp=application/vnd.kinar kon=application/vnd.kde.kontour kpr=application/vnd.kde.kpresenter kpt=application/vnd.kde.kpresenter ksh=text/plain ksp=application/vnd.kde.kspread ktr=application/vnd.kahootz ktx=image/ktx ktz=application/vnd.kahootz kwd=application/vnd.kde.kword kwt=application/vnd.kde.kword lasxml=application/vnd.las.las+xml latex=application/x-latex lbd=application/vnd.llamagraphics.life-balance.desktop lbe=application/vnd.llamagraphics.life-balance.exchange+xml les=application/vnd.hhe.lesson-player lha=application/octet-stream link66=application/vnd.route66.link66+xml list3820=application/vnd.ibm.modcap listafp=application/vnd.ibm.modcap list=text/plain log=text/plain lostxml=application/lost+xml lrf=application/octet-stream lrm=application/vnd.ms-lrm ltf=application/vnd.frogans.ltf lvp=audio/vnd.lucent.voice lwp=application/vnd.lotus-wordpro lzh=application/octet-stream m13=application/x-msmediaview m14=application/x-msmediaview m1v=video/mpeg m21=application/mp21 m2a=audio/mpeg m2v=video/mpeg m3a=audio/mpeg m3u8=application/vnd.apple.mpegurl m3u=audio/x-mpegurl m4a=audio/mp4 m4b=audio/mp4 m4r=audio/mp4 m4u=video/vnd.mpegurl m4v=video/mp4 ma=application/mathematica mac=image/x-macpaint mads=application/mads+xml mag=application/vnd.ecowin.chart maker=application/vnd.framemaker man=text/troff mathml=application/mathml+xml mb=application/mathematica mbk=application/vnd.mobius.mbk mbox=application/mbox mc1=application/vnd.medcalcdata mcd=application/vnd.mcd mcurl=text/vnd.curl.mcurl mdb=application/x-msaccess mdi=image/vnd.ms-modi mesh=model/mesh meta4=application/metalink4+xml me=text/troff mets=application/mets+xml mfm=application/vnd.mfmp mft=application/rpki-manifest mgp=application/vnd.osgeo.mapguide.package mgz=application/vnd.proteus.magazine mht=message/rfc822 mhtml=message/rfc822 mid=audio/midi midi=audio/midi mif=application/vnd.mif mime=message/rfc822 mj2=video/mj2 mjp2=video/mj2 mlp=application/vnd.dolby.mlp mmd=application/vnd.chipnuts.karaoke-mmd mmf=application/vnd.smaf mmr=image/vnd.fujixerox.edmics-mmr mny=application/x-msmoney mobi=application/x-mobipocket-ebook mods=application/mods+xml movie=video/x-sgi-movie mov=video/quicktime mp1=audio/mpeg mp21=application/mp21 mp2a=audio/mpeg mp2=audio/mpeg mp3=audio/mpeg mp4a=audio/mp4 mp4s=application/mp4 mp4=video/mp4 mp4v=video/mp4 mpa=audio/mpeg mpc=application/vnd.mophun.certificate mpega=audio/x-mpeg mpeg=video/mpeg mpe=video/mpeg mpg4=video/mp4 mpga=audio/mpeg mpg=video/mpeg mpkg=application/vnd.apple.installer+xml mpm=application/vnd.blueice.multipass mpn=application/vnd.mophun.application mpp=application/vnd.ms-project mpt=application/vnd.ms-project mpv2=video/mpeg2 mpy=application/vnd.ibm.minipay mqy=application/vnd.mobius.mqy mrc=application/marc mrcx=application/marcxml+xml mscml=application/mediaservercontrol+xml mseed=application/vnd.fdsn.mseed mseq=application/vnd.mseq msf=application/vnd.epson.msf msh=model/mesh msi=application/x-msdownload msl=application/vnd.mobius.msl ms=text/troff msty=application/vnd.muvee.style mts=model/vnd.mts mus=application/vnd.musician musicxml=application/vnd.recordare.musicxml+xml mvb=application/x-msmediaview mwf=application/vnd.mfer mxf=application/mxf mxl=application/vnd.recordare.musicxml mxml=application/xv+xml mxs=application/vnd.triscape.mxs mxu=video/vnd.mpegurl n3=text/n3 nb=application/mathematica nbp=application/vnd.wolfram.player nc=application/x-netcdf ncx=application/x-dtbncx+xml n-gage=application/vnd.nokia.n-gage.symbian.install ngdat=application/vnd.nokia.n-gage.data nlu=application/vnd.neurolanguage.nlu nml=application/vnd.enliven nnd=application/vnd.noblenet-directory nns=application/vnd.noblenet-sealer nnw=application/vnd.noblenet-web npx=image/vnd.net-fpx nsf=application/vnd.lotus-notes nws=message/rfc822 oa2=application/vnd.fujitsu.oasys2 oa3=application/vnd.fujitsu.oasys3 o=application/octet-stream oas=application/vnd.fujitsu.oasys obd=application/x-msbinder obj=application/octet-stream oda=application/oda odb=application/vnd.oasis.opendocument.database odc=application/vnd.oasis.opendocument.chart odf=application/vnd.oasis.opendocument.formula odft=application/vnd.oasis.opendocument.formula-template odg=application/vnd.oasis.opendocument.graphics odi=application/vnd.oasis.opendocument.image odm=application/vnd.oasis.opendocument.text-master odp=application/vnd.oasis.opendocument.presentation ods=application/vnd.oasis.opendocument.spreadsheet odt=application/vnd.oasis.opendocument.text oga=audio/ogg ogg=audio/ogg ogv=video/ogg ogx=application/ogg onepkg=application/onenote onetmp=application/onenote onetoc2=application/onenote onetoc=application/onenote opf=application/oebps-package+xml oprc=application/vnd.palm org=application/vnd.lotus-organizer osf=application/vnd.yamaha.openscoreformat osfpvg=application/vnd.yamaha.openscoreformat.osfpvg+xml otc=application/vnd.oasis.opendocument.chart-template otf=application/x-font-otf otg=application/vnd.oasis.opendocument.graphics-template oth=application/vnd.oasis.opendocument.text-web oti=application/vnd.oasis.opendocument.image-template otm=application/vnd.oasis.opendocument.text-master otp=application/vnd.oasis.opendocument.presentation-template ots=application/vnd.oasis.opendocument.spreadsheet-template ott=application/vnd.oasis.opendocument.text-template oxps=application/oxps oxt=application/vnd.openofficeorg.extension p10=application/pkcs10 p12=application/x-pkcs12 p7b=application/x-pkcs7-certificates p7c=application/pkcs7-mime p7m=application/pkcs7-mime p7r=application/x-pkcs7-certreqresp p7s=application/pkcs7-signature p8=application/pkcs8 pas=text/x-pascal paw=application/vnd.pawaafile pbd=application/vnd.powerbuilder6 pbm=image/x-portable-bitmap pcap=application/vnd.tcpdump.pcap pcf=application/x-font-pcf pcl=application/vnd.hp-pcl pclxl=application/vnd.hp-pclxl pct=image/pict pcurl=application/vnd.curl.pcurl pcx=image/x-pcx pdb=application/vnd.palm pdf=application/pdf pfa=application/x-font-type1 pfb=application/x-font-type1 pfm=application/x-font-type1 pfr=application/font-tdpfr pfx=application/x-pkcs12 pgm=image/x-portable-graymap pgn=application/x-chess-pgn pgp=application/pgp-encrypted pic=image/pict pict=image/pict pkg=application/octet-stream pki=application/pkixcmp pkipath=application/pkix-pkipath plb=application/vnd.3gpp.pic-bw-large plc=application/vnd.mobius.plc plf=application/vnd.pocketlearn plist=text/xml pls=application/pls+xml pl=text/plain pml=application/vnd.ctc-posml png=image/png pnm=image/x-portable-anymap pnt=image/x-macpaint portpkg=application/vnd.macports.portpkg pot=application/vnd.ms-powerpoint potm=application/vnd.ms-powerpoint.template.macroenabled.12 potx=application/vnd.openxmlformats-officedocument.presentationml.template ppa=application/vnd.ms-powerpoint ppam=application/vnd.ms-powerpoint.addin.macroenabled.12 ppd=application/vnd.cups-ppd ppm=image/x-portable-pixmap pps=application/vnd.ms-powerpoint ppsm=application/vnd.ms-powerpoint.slideshow.macroenabled.12 ppsx=application/vnd.openxmlformats-officedocument.presentationml.slideshow ppt=application/vnd.ms-powerpoint pptm=application/vnd.ms-powerpoint.presentation.macroenabled.12 pptx=application/vnd.openxmlformats-officedocument.presentationml.presentation pqa=application/vnd.palm prc=application/x-mobipocket-ebook pre=application/vnd.lotus-freelance prf=application/pics-rules ps=application/postscript psb=application/vnd.3gpp.pic-bw-small psd=image/vnd.adobe.photoshop psf=application/x-font-linux-psf pskcxml=application/pskc+xml p=text/x-pascal ptid=application/vnd.pvi.ptid1 pub=application/x-mspublisher pvb=application/vnd.3gpp.pic-bw-var pwn=application/vnd.3m.post-it-notes pwz=application/vnd.ms-powerpoint pya=audio/vnd.ms-playready.media.pya pyc=application/x-python-code pyo=application/x-python-code py=text/x-python pyv=video/vnd.ms-playready.media.pyv qam=application/vnd.epson.quickanime qbo=application/vnd.intu.qbo qfx=application/vnd.intu.qfx qps=application/vnd.publishare-delta-tree qtif=image/x-quicktime qti=image/x-quicktime qt=video/quicktime qwd=application/vnd.quark.quarkxpress qwt=application/vnd.quark.quarkxpress qxb=application/vnd.quark.quarkxpress qxd=application/vnd.quark.quarkxpress qxl=application/vnd.quark.quarkxpress qxt=application/vnd.quark.quarkxpress ra=audio/x-pn-realaudio ram=audio/x-pn-realaudio rar=application/x-rar-compressed ras=image/x-cmu-raster rcprofile=application/vnd.ipunplugged.rcprofile rdf=application/rdf+xml rdz=application/vnd.data-vision.rdz rep=application/vnd.businessobjects res=application/x-dtbresource+xml rgb=image/x-rgb rif=application/reginfo+xml rip=audio/vnd.rip rl=application/resource-lists+xml rlc=image/vnd.fujixerox.edmics-rlc rld=application/resource-lists-diff+xml rm=application/vnd.rn-realmedia rmi=audio/midi rmp=audio/x-pn-realaudio-plugin rms=application/vnd.jcp.javame.midlet-rms rnc=application/relax-ng-compact-syntax roa=application/rpki-roa roff=text/troff rp9=application/vnd.cloanto.rp9 rpm=application/x-rpm rpss=application/vnd.nokia.radio-presets rpst=application/vnd.nokia.radio-preset rq=application/sparql-query rs=application/rls-services+xml rsd=application/rsd+xml rss=application/rss+xml rtf=application/rtf rtx=text/richtext saf=application/vnd.yamaha.smaf-audio sbml=application/sbml+xml sc=application/vnd.ibm.secure-container scd=application/x-msschedule scm=application/vnd.lotus-screencam scq=application/scvp-cv-request scs=application/scvp-cv-response scurl=text/vnd.curl.scurl sda=application/vnd.stardivision.draw sdc=application/vnd.stardivision.calc sdd=application/vnd.stardivision.impress sdkd=application/vnd.solent.sdkm+xml sdkm=application/vnd.solent.sdkm+xml sdp=application/sdp sdw=application/vnd.stardivision.writer see=application/vnd.seemail seed=application/vnd.fdsn.seed sema=application/vnd.sema semd=application/vnd.semd semf=application/vnd.semf ser=application/java-serialized-object setpay=application/set-payment-initiation setreg=application/set-registration-initiation sfd-hdstx=application/vnd.hydrostatix.sof-data sfs=application/vnd.spotfire.sfs sgl=application/vnd.stardivision.writer-global sgml=text/sgml sgm=text/sgml sh=application/x-sh shar=application/x-shar shf=application/shf+xml sic=application/vnd.wap.sic sig=application/pgp-signature silo=model/mesh sis=application/vnd.symbian.install sisx=application/vnd.symbian.install sit=application/x-stuffit si=text/vnd.wap.si sitx=application/x-stuffitx skd=application/vnd.koan skm=application/vnd.koan skp=application/vnd.koan skt=application/vnd.koan slc=application/vnd.wap.slc sldm=application/vnd.ms-powerpoint.slide.macroenabled.12 sldx=application/vnd.openxmlformats-officedocument.presentationml.slide slt=application/vnd.epson.salt sl=text/vnd.wap.sl sm=application/vnd.stepmania.stepchart smf=application/vnd.stardivision.math smi=application/smil+xml smil=application/smil+xml smzip=application/vnd.stepmania.package snd=audio/basic snf=application/x-font-snf so=application/octet-stream spc=application/x-pkcs7-certificates spf=application/vnd.yamaha.smaf-phrase spl=application/x-futuresplash spot=text/vnd.in3d.spot spp=application/scvp-vp-response spq=application/scvp-vp-request spx=audio/ogg src=application/x-wais-source sru=application/sru+xml srx=application/sparql-results+xml sse=application/vnd.kodak-descriptor ssf=application/vnd.epson.ssf ssml=application/ssml+xml st=application/vnd.sailingtracker.track stc=application/vnd.sun.xml.calc.template std=application/vnd.sun.xml.draw.template s=text/x-asm stf=application/vnd.wt.stf sti=application/vnd.sun.xml.impress.template stk=application/hyperstudio stl=application/vnd.ms-pki.stl str=application/vnd.pg.format stw=application/vnd.sun.xml.writer.template sub=text/vnd.dvb.subtitle sus=application/vnd.sus-calendar susp=application/vnd.sus-calendar sv4cpio=application/x-sv4cpio sv4crc=application/x-sv4crc svc=application/vnd.dvb.service svd=application/vnd.svd svg=image/svg+xml svgz=image/svg+xml swa=application/x-director swf=application/x-shockwave-flash swi=application/vnd.arastra.swi sxc=application/vnd.sun.xml.calc sxd=application/vnd.sun.xml.draw sxg=application/vnd.sun.xml.writer.global sxi=application/vnd.sun.xml.impress sxm=application/vnd.sun.xml.math sxw=application/vnd.sun.xml.writer taglet=application/vnd.mynfc tao=application/vnd.tao.intent-module-archive tar=application/x-tar tcap=application/vnd.3gpp2.tcap tcl=application/x-tcl teacher=application/vnd.smart.teacher tei=application/tei+xml teicorpus=application/tei+xml tex=application/x-tex texi=application/x-texinfo texinfo=application/x-texinfo text=text/plain tfi=application/thraud+xml tfm=application/x-tex-tfm tgz=application/x-gzip thmx=application/vnd.ms-officetheme tiff=image/tiff tif=image/tiff tmo=application/vnd.tmobile-livetv torrent=application/x-bittorrent tpl=application/vnd.groove-tool-template tpt=application/vnd.trid.tpt tra=application/vnd.trueapp trm=application/x-msterminal tr=text/troff tsd=application/timestamped-data tsv=text/tab-separated-values ttc=application/x-font-ttf t=text/troff ttf=application/x-font-ttf ttl=text/turtle twd=application/vnd.simtech-mindmapper twds=application/vnd.simtech-mindmapper txd=application/vnd.genomatix.tuxedo txf=application/vnd.mobius.txf txt=text/plain u32=application/x-authorware-bin udeb=application/x-debian-package ufd=application/vnd.ufdl ufdl=application/vnd.ufdl ulw=audio/basic umj=application/vnd.umajin unityweb=application/vnd.unity uoml=application/vnd.uoml+xml uris=text/uri-list uri=text/uri-list urls=text/uri-list ustar=application/x-ustar utz=application/vnd.uiq.theme uu=text/x-uuencode uva=audio/vnd.dece.audio uvd=application/vnd.dece.data uvf=application/vnd.dece.data uvg=image/vnd.dece.graphic uvh=video/vnd.dece.hd uvi=image/vnd.dece.graphic uvm=video/vnd.dece.mobile uvp=video/vnd.dece.pd uvs=video/vnd.dece.sd uvt=application/vnd.dece.ttml+xml uvu=video/vnd.uvvu.mp4 uvva=audio/vnd.dece.audio uvvd=application/vnd.dece.data uvvf=application/vnd.dece.data uvvg=image/vnd.dece.graphic uvvh=video/vnd.dece.hd uvvi=image/vnd.dece.graphic uvvm=video/vnd.dece.mobile uvvp=video/vnd.dece.pd uvvs=video/vnd.dece.sd uvvt=application/vnd.dece.ttml+xml uvvu=video/vnd.uvvu.mp4 uvv=video/vnd.dece.video uvvv=video/vnd.dece.video uvvx=application/vnd.dece.unspecified uvvz=application/vnd.dece.zip uvx=application/vnd.dece.unspecified uvz=application/vnd.dece.zip vcard=text/vcard vcd=application/x-cdlink vcf=text/x-vcard vcg=application/vnd.groove-vcard vcs=text/x-vcalendar vcx=application/vnd.vcx vis=application/vnd.visionary viv=video/vnd.vivo vor=application/vnd.stardivision.writer vox=application/x-authorware-bin vrml=model/vrml vsd=application/vnd.visio vsf=application/vnd.vsf vss=application/vnd.visio vst=application/vnd.visio vsw=application/vnd.visio vtu=model/vnd.vtu vxml=application/voicexml+xml w3d=application/x-director wad=application/x-doom war=application/octet-stream wav=audio/x-wav wax=audio/x-ms-wax wbmp=image/vnd.wap.wbmp wbs=application/vnd.criticaltools.wbs+xml wbxml=application/vnd.wap.wbxml wcm=application/vnd.ms-works wdb=application/vnd.ms-works weba=audio/webm webm=video/webm webp=image/webp wg=application/vnd.pmi.widget wgt=application/widget wiz=application/msword wks=application/vnd.ms-works wma=audio/x-ms-wma wmd=application/x-ms-wmd wmf=application/x-msmetafile wmlc=application/vnd.wap.wmlc wmlsc=application/vnd.wap.wmlscriptc wmls=text/vnd.wap.wmlscript wml=text/vnd.wap.wml wm=video/x-ms-wm wmv=video/x-ms-wmv wmx=video/x-ms-wmx wmz=application/x-ms-wmz woff=application/x-font-woff wpd=application/vnd.wordperfect wpl=application/vnd.ms-wpl wps=application/vnd.ms-works wqd=application/vnd.wqd wri=application/x-mswrite wrl=model/vrml wsdl=application/wsdl+xml wspolicy=application/wspolicy+xml wtb=application/vnd.webturbo wvx=video/x-ms-wvx x32=application/x-authorware-bin x3d=application/vnd.hzn-3d-crossword xap=application/x-silverlight-app xar=application/vnd.xara xbap=application/x-ms-xbap xbd=application/vnd.fujixerox.docuworks.binder xbm=image/x-xbitmap xdf=application/xcap-diff+xml xdm=application/vnd.syncml.dm+xml xdp=application/vnd.adobe.xdp+xml xdssc=application/dssc+xml xdw=application/vnd.fujixerox.docuworks xenc=application/xenc+xml xer=application/patch-ops-error+xml xfdf=application/vnd.adobe.xfdf xfdl=application/vnd.xfdl xht=application/xhtml+xml xhtml=application/xhtml+xml xhvml=application/xv+xml xif=image/vnd.xiff xla=application/vnd.ms-excel xlam=application/vnd.ms-excel.addin.macroenabled.12 xlb=application/vnd.ms-excel xlc=application/vnd.ms-excel xlm=application/vnd.ms-excel xls=application/vnd.ms-excel xlsb=application/vnd.ms-excel.sheet.binary.macroenabled.12 xlsm=application/vnd.ms-excel.sheet.macroenabled.12 xlsx=application/vnd.openxmlformats-officedocument.spreadsheetml.sheet xlt=application/vnd.ms-excel xltm=application/vnd.ms-excel.template.macroenabled.12 xltx=application/vnd.openxmlformats-officedocument.spreadsheetml.template xlw=application/vnd.ms-excel xml=application/xml xo=application/vnd.olpc-sugar xop=application/xop+xml xpdl=application/xml xpi=application/x-xpinstall xpm=image/x-xpixmap xpr=application/vnd.is-xpr xps=application/vnd.ms-xpsdocument xpw=application/vnd.intercon.formnet xpx=application/vnd.intercon.formnet xsl=application/xml xslt=application/xslt+xml xsm=application/vnd.syncml+xml xspf=application/xspf+xml xul=application/vnd.mozilla.xul+xml xvm=application/xv+xml xvml=application/xv+xml xwd=image/x-xwindowdump xyz=chemical/x-xyz yang=application/yang yin=application/yin+xml z=application/x-compress Z=application/x-compress zaz=application/vnd.zzazz.deck+xml zip=application/zip zir=application/vnd.zul zirz=application/vnd.zul zmm=application/vnd.handheld-entertainment+xml jenkins-winstone-0.9.10-jenkins-47/src/java/winstone/ServletConfiguration.java0000644000175000017500000003241212200024521030032 0ustar jamespagejamespage/* * Copyright 2003-2006 Rick Knowles * Distributed under the terms of either: * - the common development and distribution license (CDDL), v1.0; or * - the GNU Lesser General Public License, v2.1 or later */ package winstone; import java.io.IOException; import java.util.Collections; import java.util.Enumeration; import java.util.Hashtable; import java.util.Map; import javax.servlet.Servlet; import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.UnavailableException; import javax.servlet.http.HttpServletResponse; import org.w3c.dom.Node; /** * This is the one that keeps a specific servlet instance's config, as well as * holding the instance itself. * * @author Rick Knowles * @version $Id: ServletConfiguration.java,v 1.16 2007/04/23 02:55:35 rickknowles Exp $ */ public class ServletConfiguration implements javax.servlet.ServletConfig, Comparable { static final String ELEM_NAME = "servlet-name"; static final String ELEM_DISPLAY_NAME = "display-name"; static final String ELEM_CLASS = "servlet-class"; static final String ELEM_JSP_FILE = "jsp-file"; static final String ELEM_DESCRIPTION = "description"; static final String ELEM_INIT_PARAM = "init-param"; static final String ELEM_INIT_PARAM_NAME = "param-name"; static final String ELEM_INIT_PARAM_VALUE = "param-value"; static final String ELEM_LOAD_ON_STARTUP = "load-on-startup"; static final String ELEM_RUN_AS = "run-as"; static final String ELEM_SECURITY_ROLE_REF = "security-role-ref"; static final String ELEM_ROLE_NAME = "role-name"; static final String ELEM_ROLE_LINK = "role-link"; final String JSP_FILE = "org.apache.catalina.jsp_file"; private String servletName; private String classFile; private Servlet instance; private Map initParameters; private WebAppConfiguration webAppConfig; private int loadOnStartup; private String jspFile; // private String runAsRole; private Map securityRoleRefs; private Object servletSemaphore = true; private boolean isSingleThreadModel = false; private boolean unavailable = false; private Throwable unavailableException = null; protected ServletConfiguration(WebAppConfiguration webAppConfig) { this.webAppConfig = webAppConfig; this.initParameters = new Hashtable(); this.loadOnStartup = -1; this.securityRoleRefs = new Hashtable(); } public ServletConfiguration(WebAppConfiguration webAppConfig, String servletName, String className, Map initParams, int loadOnStartup) { this(webAppConfig); if (initParams != null) this.initParameters.putAll(initParams); this.servletName = servletName; this.classFile = className; this.jspFile = null; this.loadOnStartup = loadOnStartup; } public ServletConfiguration(WebAppConfiguration webAppConfig, Node elm) { this(webAppConfig); // Parse the web.xml file entry for (int n = 0; n < elm.getChildNodes().getLength(); n++) { Node child = elm.getChildNodes().item(n); if (child.getNodeType() != Node.ELEMENT_NODE) continue; String nodeName = child.getNodeName(); // Construct the servlet instances if (nodeName.equals(ELEM_NAME)) this.servletName = WebAppConfiguration.getTextFromNode(child); else if (nodeName.equals(ELEM_CLASS)) this.classFile = WebAppConfiguration.getTextFromNode(child); else if (nodeName.equals(ELEM_JSP_FILE)) this.jspFile = WebAppConfiguration.getTextFromNode(child); else if (nodeName.equals(ELEM_LOAD_ON_STARTUP)) { String index = child.getFirstChild() == null ? "-1" : WebAppConfiguration.getTextFromNode(child); this.loadOnStartup = Integer.parseInt(index); } else if (nodeName.equals(ELEM_INIT_PARAM)) { String paramName = ""; String paramValue = ""; for (int k = 0; k < child.getChildNodes().getLength(); k++) { Node paramNode = child.getChildNodes().item(k); if (paramNode.getNodeType() != Node.ELEMENT_NODE) continue; else if (paramNode.getNodeName().equals(ELEM_INIT_PARAM_NAME)) paramName = WebAppConfiguration.getTextFromNode(paramNode); else if (paramNode.getNodeName().equals(ELEM_INIT_PARAM_VALUE)) paramValue = WebAppConfiguration.getTextFromNode(paramNode); } if (!paramName.equals("")) { this.initParameters.put(paramName, paramValue); } } else if (nodeName.equals(ELEM_RUN_AS)) { for (int m = 0; m < child.getChildNodes().getLength(); m++) { Node roleElm = child.getChildNodes().item(m); if ((roleElm.getNodeType() == Node.ELEMENT_NODE) && (roleElm.getNodeName().equals(ELEM_ROLE_NAME))) { // this.runAsRole = WebAppConfiguration.getTextFromNode(roleElm); // not used } } } else if (nodeName.equals(ELEM_SECURITY_ROLE_REF)) { String name = ""; String link = ""; for (int k = 0; k < child.getChildNodes().getLength(); k++) { Node roleRefNode = child.getChildNodes().item(k); if (roleRefNode.getNodeType() != Node.ELEMENT_NODE) continue; else if (roleRefNode.getNodeName().equals(ELEM_ROLE_NAME)) name = WebAppConfiguration.getTextFromNode(roleRefNode); else if (roleRefNode.getNodeName().equals(ELEM_ROLE_LINK)) link = WebAppConfiguration.getTextFromNode(roleRefNode); } if (!name.equals("") && !link.equals("")) this.initParameters.put(name, link); } } if ((this.jspFile != null) && (this.classFile == null)) { this.classFile = WebAppConfiguration.JSP_SERVLET_CLASS; WebAppConfiguration.addJspServletParams(this.initParameters); } Logger.log(Logger.FULL_DEBUG, Launcher.RESOURCES, "ServletConfiguration.DeployedInstance", this.servletName, this.classFile); } public void ensureInitialization() { if (this.instance != null) { return; // already init'd } synchronized (this.servletSemaphore) { if (this.instance != null) { return; // already init'd } // Check if we were decommissioned while blocking if (this.unavailableException != null) { return; } // If no instance, class load, then call init() ClassLoader cl = Thread.currentThread().getContextClassLoader(); Thread.currentThread().setContextClassLoader(this.webAppConfig.getLoader()); Servlet newInstance = null; Throwable otherError = null; try { Class servletClass = Class.forName(classFile, true, this.webAppConfig.getLoader()); newInstance = (Servlet) servletClass.newInstance(); this.isSingleThreadModel = Class.forName("javax.servlet.SingleThreadModel").isInstance(newInstance); // Initialise with the correct classloader Logger.log(Logger.DEBUG, Launcher.RESOURCES, "ServletConfiguration.init", this.servletName); newInstance.init(this); this.instance = newInstance; } catch (ClassNotFoundException err) { Logger.log(Logger.WARNING, Launcher.RESOURCES, "ServletConfiguration.ClassLoadError", this.classFile, err); setUnavailable(newInstance); this.unavailableException = err; } catch (IllegalAccessException err) { Logger.log(Logger.WARNING, Launcher.RESOURCES, "ServletConfiguration.ClassLoadError", this.classFile, err); setUnavailable(newInstance); this.unavailableException = err; } catch (InstantiationException err) { Logger.log(Logger.WARNING, Launcher.RESOURCES, "ServletConfiguration.ClassLoadError", this.classFile, err); setUnavailable(newInstance); this.unavailableException = err; } catch (ServletException err) { Logger.log(Logger.WARNING, Launcher.RESOURCES, "ServletConfiguration.InitError", this.servletName, err); this.instance = null; // so that we don't call the destroy method setUnavailable(newInstance); this.unavailableException = err; } catch (RuntimeException err) { otherError = err; throw err; } catch (Error err) { otherError = err; throw err; } finally { Thread.currentThread().setContextClassLoader(cl); if ((otherError == null) && (this.unavailableException == null)) { this.instance = newInstance; } } } return; } public void execute(ServletRequest request, ServletResponse response, String requestURI) throws ServletException, IOException { ensureInitialization(); // If init failed, return 500 error if (this.unavailable) { // ((HttpServletResponse) response).sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, // resources.getString("StaticResourceServlet.PathNotFound", requestURI)); RequestDispatcher rd = this.webAppConfig.getErrorDispatcherByClass( this.unavailableException); rd.forward(request, response); return; } if (this.jspFile != null) request.setAttribute(JSP_FILE, this.jspFile); ClassLoader cl = Thread.currentThread().getContextClassLoader(); Thread.currentThread().setContextClassLoader(this.webAppConfig.getLoader()); try { if (this.isSingleThreadModel) { synchronized (this) { this.instance.service(request, response); } } else this.instance.service(request, response); } catch (UnavailableException err) { // catch locally and rethrow as a new ServletException, so // we only invalidate the throwing servlet setUnavailable(this.instance); ((HttpServletResponse) response).sendError(HttpServletResponse.SC_NOT_FOUND, Launcher.RESOURCES.getString("StaticResourceServlet.PathNotFound", requestURI)); // throw new ServletException(resources.getString( // "RequestDispatcher.ForwardError"), err); } finally { Thread.currentThread().setContextClassLoader(cl); } } public int getLoadOnStartup() { return this.loadOnStartup; } public String getInitParameter(String name) { return (String) this.initParameters.get(name); } public Enumeration getInitParameterNames() { return Collections.enumeration(this.initParameters.keySet()); } public ServletContext getServletContext() { return this.webAppConfig; } public String getServletName() { return this.servletName; } public Map getSecurityRoleRefs() { return this.securityRoleRefs; } /** * This was included so that the servlet instances could be sorted on their * loadOnStartup values. Otherwise used. */ public int compareTo(Object objTwo) { Integer one = this.loadOnStartup; Integer two = ((ServletConfiguration) objTwo).loadOnStartup; return one.compareTo(two); } /** * Called when it's time for the container to shut this servlet down. */ public void destroy() { synchronized (this.servletSemaphore) { setUnavailable(this.instance); } } protected void setUnavailable(Servlet unavailableServlet) { this.unavailable = true; if (unavailableServlet != null) { Logger.log(Logger.DEBUG, Launcher.RESOURCES, "ServletConfiguration.destroy", this.servletName); ClassLoader cl = Thread.currentThread().getContextClassLoader(); Thread.currentThread().setContextClassLoader(this.webAppConfig.getLoader()); try { unavailableServlet.destroy(); } finally { Thread.currentThread().setContextClassLoader(cl); this.instance = null; } } // remove from webapp this.webAppConfig.removeServletConfigurationAndMappings(this); } } jenkins-winstone-0.9.10-jenkins-47/src/java/winstone/classLoader/0000755000175000017500000000000012200024521025245 5ustar jamespagejamespagejenkins-winstone-0.9.10-jenkins-47/src/java/winstone/classLoader/WebappClassLoader.java0000644000175000017500000000761412200024521031453 0ustar jamespagejamespage/* * Copyright 2003-2006 Rick Knowles * Distributed under the terms of either: * - the common development and distribution license (CDDL), v1.0; or * - the GNU Lesser General Public License, v2.1 or later */ package winstone.classLoader; import java.io.InputStream; import java.net.URL; import java.net.URLClassLoader; import java.net.URLStreamHandlerFactory; import winstone.Logger; import winstone.WinstoneResourceBundle; /** * Implements the servlet spec model (v2.3 section 9.7.2) for classloading, which * is different to the standard JDK model in that it delegates *after* checking * local repositories. This has the effect of isolating copies of classes that exist * in 2 webapps from each other. * * Thanks to James Berry for the changes to use the system classloader to prevent * loading servlet spec or system classpath classes again. * * @author Rick Knowles * @version $Id: WebappClassLoader.java,v 1.3 2007/12/29 03:32:54 rickknowles Exp $ */ public class WebappClassLoader extends URLClassLoader { private static final WinstoneResourceBundle CL_RESOURCES = new WinstoneResourceBundle("winstone.classLoader.LocalStrings"); protected ClassLoader system = getSystemClassLoader(); public WebappClassLoader(URL[] urls) { super(urls); } public WebappClassLoader(URL[] urls, ClassLoader parent) { super(urls, parent); } public WebappClassLoader(URL[] urls, ClassLoader parent, URLStreamHandlerFactory factory) { super(urls, parent, factory); } protected synchronized Class loadClass(String name, boolean resolve) throws ClassNotFoundException { // First, check if the class has already been loaded Class c = findLoadedClass(name); // Try the system loader first, to ensure that system classes are not // overridden by webapps. Note that this includes any classes in winstone, // including the javax.servlet classes if (c == null) { try { c = system.loadClass(name); if (c != null) { Logger.log(Logger.MAX, CL_RESOURCES, "WebappClassLoader.LoadedBySystemCL", name); } } catch (ClassNotFoundException e) { c = null; } } // If an allowed class, load it locally first if (c == null) { try { // If still not found, then invoke findClass in order to find the class. c = findClass(name); if (c != null) { Logger.log(Logger.MAX, CL_RESOURCES, "WebappClassLoader.LoadedByThisCL", name); } } catch (ClassNotFoundException e) { c = null; } } // otherwise, and only if we have a parent, delegate to our parent // Note that within winstone, the only difference between this and the system // class loader we've already tried is that our parent might include the common/shared lib. if (c == null) { ClassLoader parent = getParent(); if (parent != null) { c = parent.loadClass(name); if (c != null) { Logger.log(Logger.MAX, CL_RESOURCES, "WebappClassLoader.LoadedByParentCL", name); } } else { // We have no other hope for loading the class, so throw the class not found exception throw new ClassNotFoundException(name); } } if (resolve && (c != null)) { resolveClass(c); } return c; } public InputStream getResourceAsStream(String name) { if ((name != null) && name.startsWith("/")) { name = name.substring(1); } return super.getResourceAsStream(name); } } jenkins-winstone-0.9.10-jenkins-47/src/java/winstone/classLoader/ReloadingClassLoader.java0000644000175000017500000002034112200024521032131 0ustar jamespagejamespage/* * Copyright 2003-2006 Rick Knowles * Distributed under the terms of either: * - the common development and distribution license (CDDL), v1.0; or * - the GNU Lesser General Public License, v2.1 or later */ package winstone.classLoader; import java.io.File; import java.io.IOException; import java.net.URL; import java.util.Date; import java.util.Enumeration; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import java.util.jar.JarEntry; import java.util.jar.JarFile; import javax.servlet.ServletContextEvent; import javax.servlet.ServletContextListener; import winstone.Logger; import winstone.WebAppConfiguration; import winstone.WinstoneResourceBundle; /** * This subclass of WinstoneClassLoader is the reloading version. It runs a * monitoring thread in the background that checks for updates to any files in * the class path. * * @author Rick Knowles * @version $Id: ReloadingClassLoader.java,v 1.11 2007/02/17 01:55:12 rickknowles Exp $ */ public class ReloadingClassLoader extends WebappClassLoader implements ServletContextListener, Runnable { private static final int RELOAD_SEARCH_SLEEP = 10; private static final WinstoneResourceBundle CL_RESOURCES = new WinstoneResourceBundle("winstone.classLoader.LocalStrings"); private boolean interrupted; private WebAppConfiguration webAppConfig; private Set loadedClasses; private File classPaths[]; private int classPathsLength; public ReloadingClassLoader(URL urls[], ClassLoader parent) { super(urls, parent); this.loadedClasses = new HashSet(); if (urls != null) { this.classPaths = new File[urls.length]; for (URL url : urls) { this.classPaths[this.classPathsLength++] = new File(url.getFile()); } } } protected void addURL(URL url) { super.addURL(url); synchronized (this.loadedClasses) { if (this.classPaths == null) { this.classPaths = new File[10]; this.classPathsLength = 0; } else if (this.classPathsLength == (this.classPaths.length - 1)) { File temp[] = this.classPaths; this.classPaths = new File[(int) (this.classPathsLength * 1.75)]; System.arraycopy(temp, 0, this.classPaths, 0, this.classPathsLength); } this.classPaths[this.classPathsLength++] = new File(url.getFile()); } } public void contextInitialized(ServletContextEvent sce) { this.webAppConfig = (WebAppConfiguration) sce.getServletContext(); this.interrupted = false; synchronized (this) { this.loadedClasses.clear(); } Thread thread = new Thread(this, CL_RESOURCES .getString("ReloadingClassLoader.ThreadName")); thread.setDaemon(true); thread.setPriority(Thread.MIN_PRIORITY); thread.start(); } public void contextDestroyed(ServletContextEvent sce) { this.interrupted = true; this.webAppConfig = null; synchronized (this) { this.loadedClasses.clear(); } } /** * The maintenance thread. This makes sure that any changes in the files in * the classpath trigger a classLoader self destruct and recreate. */ public void run() { Logger.log(Logger.FULL_DEBUG, CL_RESOURCES, "ReloadingClassLoader.MaintenanceThreadStarted"); Map classDateTable = new HashMap(); Map classLocationTable = new HashMap(); Set lostClasses = new HashSet(); while (!interrupted) { try { String loadedClassesCopy[]; synchronized (this) { loadedClassesCopy = (String []) this.loadedClasses.toArray(new String[0]); } for (int n = 0; (n < loadedClassesCopy.length) && !interrupted; n++) { Thread.sleep(RELOAD_SEARCH_SLEEP); String className = transformToFileFormat(loadedClassesCopy[n]); File location = (File) classLocationTable.get(className); Long classDate = null; if ((location == null) || !location.exists()) { for (int j = 0; (j < this.classPaths.length) && (classDate == null); j++) { File path = this.classPaths[j]; if (!path.exists()) { continue; } else if (path.isDirectory()) { File classLocation = new File(path, className); if (classLocation.exists()) { classDate = classLocation.lastModified(); classLocationTable.put(className, classLocation); } } else if (path.isFile()) { classDate = searchJarPath(className, path); if (classDate != null) classLocationTable.put(className, path); } } } else if (location.exists()) classDate = location.lastModified(); // Has class vanished ? Leave a note and skip over it if (classDate == null) { if (!lostClasses.contains(className)) { lostClasses.add(className); Logger.log(Logger.DEBUG, CL_RESOURCES, "ReloadingClassLoader.ClassLost", className); } continue; } if ((classDate != null) && lostClasses.contains(className)) { lostClasses.remove(className); } // Stash date of loaded files, and compare with last // iteration Long oldClassDate = (Long) classDateTable.get(className); if (oldClassDate == null) { classDateTable.put(className, classDate); } else if (oldClassDate.compareTo(classDate) != 0) { // Trigger reset of webAppConfig Logger.log(Logger.INFO, CL_RESOURCES, "ReloadingClassLoader.ReloadRequired", className, "" + new Date(classDate), "" + new Date(oldClassDate)); this.webAppConfig.resetClassLoader(); } } } catch (Throwable err) { Logger.log(Logger.ERROR, CL_RESOURCES, "ReloadingClassLoader.MaintenanceThreadError", err); } } Logger.log(Logger.FULL_DEBUG, CL_RESOURCES, "ReloadingClassLoader.MaintenanceThreadFinished"); } protected Class findClass(String name) throws ClassNotFoundException { synchronized (this) { this.loadedClasses.add("Class:" + name); } return super.findClass(name); } public URL findResource(String name) { synchronized (this) { this.loadedClasses.add(name); } return super.findResource(name); } /** * Iterates through a jar file searching for a class. If found, it returns that classes date */ private Long searchJarPath(String classResourceName, File path) throws IOException { JarFile jar = new JarFile(path); for (Enumeration e = jar.entries(); e.hasMoreElements() && !interrupted;) { JarEntry entry = (JarEntry) e.nextElement(); if (entry.getName().equals(classResourceName)) return path.lastModified(); } return null; } private static String transformToFileFormat(String name) { if (!name.startsWith("Class:")) return name; else return WinstoneResourceBundle.globalReplace(name.substring(6), ".", "/") + ".class"; } } jenkins-winstone-0.9.10-jenkins-47/src/java/winstone/classLoader/LocalStrings.properties0000644000175000017500000000151112200024521031765 0ustar jamespagejamespageReloadingClassLoader.ThreadName=WinstoneClassLoader Reloading Monitor Thread ReloadingClassLoader.MaintenanceThreadStarted=WinstoneClassLoader reloading monitor thread started ReloadingClassLoader.ClassLost=WARNING: Maintenance thread can't find class [#0] - Lost ? Ignoring ReloadingClassLoader.ReloadRequired=Class [#0] changed at [#1] (old date [#2]) - reloading ReloadingClassLoader.MaintenanceThreadError=Error in WinstoneClassLoader reloading monitor thread ReloadingClassLoader.MaintenanceThreadFinished=WinstoneClassLoader reloading monitor thread finished WebappClassLoader.LoadedByThisCL=Webapp classloader found class locally when loading #0 WebappClassLoader.LoadedByParentCL=Webapp classloader deferred to parent for loading #0 WebappClassLoader.LoadedBySystemCL=Webapp classloader deferred to system classloader for loading #0jenkins-winstone-0.9.10-jenkins-47/src/java/winstone/Cluster.java0000644000175000017500000000330212200024521025273 0ustar jamespagejamespage/* * Copyright 2003-2006 Rick Knowles * Distributed under the terms of either: * - the common development and distribution license (CDDL), v1.0; or * - the GNU Lesser General Public License, v2.1 or later */ package winstone; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.Socket; /** * Represents a cluster implementation, which is basically the communication * mechanism between a group of winstone containers. * * @author Rick Knowles * @version $Id: Cluster.java,v 1.5 2006/02/28 07:32:47 rickknowles Exp $ */ public interface Cluster { /** * Destroy the maintenance thread if there is one. Prepare for shutdown */ public void destroy(); /** * Check if the other nodes in this cluster have a session for this * sessionId. * * @param sessionId The id of the session to check for * @param webAppConfig The web app that owns the session we want * @return A valid session instance */ public WinstoneSession askClusterForSession(String sessionId, WebAppConfiguration webAppConfig); /** * Accept a control socket request related to the cluster functions and * process the request. * * @param requestType A byte indicating the request type * @param in Socket input stream * @param outSocket output stream * @param hostConfig The collection of all local webapps * @throws IOException */ public void clusterRequest(byte requestType, InputStream in, OutputStream out, Socket socket, HostGroup hostGroup) throws IOException; } jenkins-winstone-0.9.10-jenkins-47/src/java/winstone/WinstoneException.java0000644000175000017500000000465612200024521027354 0ustar jamespagejamespage/* * Copyright 2003-2006 Rick Knowles * Distributed under the terms of either: * - the common development and distribution license (CDDL), v1.0; or * - the GNU Lesser General Public License, v2.1 or later */ package winstone; import java.io.PrintStream; import java.io.PrintWriter; /** * Master exception within the servlet container. This is thrown whenever a * non-recoverable error occurs that we want to throw to the top of the * application. * * @author Rick Knowles * @version $Id: WinstoneException.java,v 1.1 2004/03/08 15:27:21 rickknowles * Exp $ */ public class WinstoneException extends RuntimeException { private Throwable nestedError = null; /** * Create an exception with a useful message for the system administrator. * * @param pMsg * Error message for to be used for administrative * troubleshooting */ public WinstoneException(String pMsg) { super(pMsg); } /** * Create an exception with a useful message for the system administrator * and a nested throwable object. * * @param pMsg * Error message for administrative troubleshooting * @param pError * The actual exception that occurred */ public WinstoneException(String pMsg, Throwable pError) { super(pMsg); this.setNestedError(pError); } /** * Get the nested error or exception * * @return The nested error or exception */ public Throwable getNestedError() { return this.nestedError; } /** * Set the nested error or exception * * @param pError * The nested error or exception */ private void setNestedError(Throwable pError) { this.nestedError = pError; } public void printStackTrace(PrintWriter p) { if (this.nestedError != null) this.nestedError.printStackTrace(p); p.write("\n"); super.printStackTrace(p); } public void printStackTrace(PrintStream p) { if (this.nestedError != null) this.nestedError.printStackTrace(p); p.println("\n"); super.printStackTrace(p); } public void printStackTrace() { if (this.nestedError != null) this.nestedError.printStackTrace(); super.printStackTrace(); } } jenkins-winstone-0.9.10-jenkins-47/src/java/winstone/jndi/0000755000175000017500000000000012200024521023735 5ustar jamespagejamespagejenkins-winstone-0.9.10-jenkins-47/src/java/winstone/jndi/WinstoneNameParser.java0000644000175000017500000000222112200024521030361 0ustar jamespagejamespage/* * Copyright 2003-2006 Rick Knowles * Distributed under the terms of either: * - the common development and distribution license (CDDL), v1.0; or * - the GNU Lesser General Public License, v2.1 or later */ package winstone.jndi; import java.util.Properties; import javax.naming.CompoundName; import javax.naming.Name; import javax.naming.NameParser; import javax.naming.NamingException; /** * The name parser for winstone jndi names * * @author Rick Knowles * @version $Id: WinstoneNameParser.java,v 1.2 2006/02/28 07:32:48 rickknowles Exp $ */ public class WinstoneNameParser implements NameParser { private static final Properties syntax = new Properties(); static { syntax.put("jndi.syntax.direction", "left_to_right"); syntax.put("jndi.syntax.separator", "/"); syntax.put("jndi.syntax.ignorecase", "false"); syntax.put("jndi.syntax.escape", "\\"); syntax.put("jndi.syntax.beginquote", "'"); } public Name parse(String name) throws NamingException { return new CompoundName(name, syntax); } } jenkins-winstone-0.9.10-jenkins-47/src/java/winstone/jndi/java/0000755000175000017500000000000012200024521024656 5ustar jamespagejamespagejenkins-winstone-0.9.10-jenkins-47/src/java/winstone/jndi/java/javaURLContextFactory.java0000644000175000017500000000334212200024521031724 0ustar jamespagejamespage/* * Copyright 2003-2006 Rick Knowles * Distributed under the terms of either: * - the common development and distribution license (CDDL), v1.0; or * - the GNU Lesser General Public License, v2.1 or later */ package winstone.jndi.java; import java.util.Hashtable; import javax.naming.Context; import javax.naming.Name; import javax.naming.NamingException; import javax.naming.spi.InitialContextFactory; import javax.naming.spi.ObjectFactory; import winstone.jndi.WinstoneContext; /** * Creates the initial instance of the Winstone JNDI context (corresponds to * java:/ urls) * * @author Rick Knowles * @version $Id: javaURLContextFactory.java,v 1.5 2007/04/23 02:55:35 rickknowles Exp $ */ public class javaURLContextFactory implements InitialContextFactory, ObjectFactory { private static WinstoneContext rootContext; private Object lock = true; public Context getInitialContext(Hashtable env) throws NamingException { synchronized (lock) { if (rootContext == null) { Object lock = true; rootContext = new WinstoneContext(env, null, "java:", lock); WinstoneContext compCtx = new WinstoneContext(env, rootContext, "java:/comp", lock); WinstoneContext envCtx = new WinstoneContext(env, compCtx, "java:/comp/env", lock); rootContext.rebind("java:/comp", compCtx); compCtx.rebind("env", envCtx); } } return (Context) rootContext.lookup("java:/comp/env"); } public Object getObjectInstance(Object object, Name name, Context context, Hashtable env) { return null; } } jenkins-winstone-0.9.10-jenkins-47/src/java/winstone/jndi/ContainerJNDIManager.java0000644000175000017500000002127512200024521030471 0ustar jamespagejamespage/* * Copyright 2003-2006 Rick Knowles * Distributed under the terms of either: * - the common development and distribution license (CDDL), v1.0; or * - the GNU Lesser General Public License, v2.1 or later */ package winstone.jndi; import java.lang.reflect.Constructor; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Properties; import javax.naming.CompositeName; import javax.naming.Context; import javax.naming.InitialContext; import javax.naming.Name; import javax.naming.NamingException; import winstone.JNDIManager; import winstone.Logger; import winstone.cmdline.Option; import winstone.WinstoneResourceBundle; import winstone.jndi.resourceFactories.WinstoneDataSource; /** * Implements a simple web.xml + command line arguments style jndi manager * * @author Rick Knowles * @version $Id: ContainerJNDIManager.java,v 1.3 2006/02/28 07:32:48 rickknowles Exp $ */ public class ContainerJNDIManager implements JNDIManager { public static final WinstoneResourceBundle JNDI_RESOURCES = new WinstoneResourceBundle("winstone.jndi.LocalStrings"); protected Map objectsToCreate; /** * Gets the relevant list of objects from the args, validating against the * web.xml nodes supplied. All node addresses are assumed to be relative to * the java:/comp/env context */ public ContainerJNDIManager(Map args, List webXmlNodes, ClassLoader loader) { // Build all the objects we wanted this.objectsToCreate = new HashMap(); Collection keys = new ArrayList(args != null ? args.keySet() : new ArrayList()); for (Object key1 : keys) { String key = (String) key1; if (key.startsWith(Option.JDNI_RESOURCE.name)) { String resName = key.substring(14); String className = (String) args.get(key); String value = (String) args.get(Option.JNDI_PARAM.name + resName + ".value"); Logger.log(Logger.FULL_DEBUG, JNDI_RESOURCES, "ContainerJNDIManager.CreatingResourceArgs", resName); Object obj = createObject(resName.trim(), className.trim(), value, args, loader); if (obj != null) this.objectsToCreate.put(resName, obj); } } } /** * Add the objects passed to the constructor to the JNDI Context addresses * specified */ public void setup() { try { InitialContext ic = new InitialContext(); for (Object o : this.objectsToCreate.keySet()) { String name = (String) o; try { Name fullName = new CompositeName(name); Context currentContext = ic; while (fullName.size() > 1) { // Make contexts that are not already present try { currentContext = currentContext .createSubcontext(fullName.get(0)); } catch (NamingException err) { currentContext = (Context) currentContext .lookup(fullName.get(0)); } fullName = fullName.getSuffix(1); } ic.bind(name, this.objectsToCreate.get(name)); Logger.log(Logger.FULL_DEBUG, JNDI_RESOURCES, "ContainerJNDIManager.BoundResource", name); } catch (NamingException err) { Logger.log(Logger.ERROR, JNDI_RESOURCES, "ContainerJNDIManager.ErrorBindingResource", name, err); } } Logger.log(Logger.DEBUG, JNDI_RESOURCES, "ContainerJNDIManager.SetupComplete", "" + this.objectsToCreate.size()); } catch (NamingException err) { Logger.log(Logger.ERROR, JNDI_RESOURCES, "ContainerJNDIManager.ErrorGettingInitialContext", err); } } /** * Remove the objects under administration from the JNDI Context, and then * destroy the objects */ public void tearDown() { try { InitialContext ic = new InitialContext(); for (Object o : this.objectsToCreate.keySet()) { String name = (String) o; try { ic.unbind(name); } catch (NamingException err) { Logger.log(Logger.ERROR, JNDI_RESOURCES, "ContainerJNDIManager.ErrorUnbindingResource", name, err); } Object unboundObject = this.objectsToCreate.get(name); if (unboundObject instanceof WinstoneDataSource) ((WinstoneDataSource) unboundObject).destroy(); Logger.log(Logger.FULL_DEBUG, JNDI_RESOURCES, "ContainerJNDIManager.UnboundResource", name); } Logger.log(Logger.DEBUG, JNDI_RESOURCES, "ContainerJNDIManager.TeardownComplete", "" + this.objectsToCreate.size()); } catch (NamingException err) { Logger.log(Logger.ERROR, JNDI_RESOURCES, "ContainerJNDIManager.ErrorGettingInitialContext", err); } } /** * Build an object to insert into the jndi space */ protected Object createObject(String name, String className, String value, Map args, ClassLoader loader) { if ((className == null) || (name == null)) return null; // Set context class loader ClassLoader cl = Thread.currentThread().getContextClassLoader(); Thread.currentThread().setContextClassLoader(loader); try { // If we are working with a datasource if (className.equals("javax.sql.DataSource")) { try { return new WinstoneDataSource(name, extractRelevantArgs(args, name), loader); } catch (Throwable err) { Logger.log(Logger.ERROR, JNDI_RESOURCES, "ContainerJNDIManager.ErrorBuildingDatasource", name, err); } } // If we are working with a mail session else if (className.equals("javax.mail.Session")) { try { Class smtpClass = Class.forName(className, true, loader); Method smtpMethod = smtpClass.getMethod("getInstance", new Class[] { Properties.class, Class.forName("javax.mail.Authenticator") }); return smtpMethod.invoke(null, extractRelevantArgs(args, name), null); //return Session.getInstance(extractRelevantArgs(args, name), null); } catch (Throwable err) { Logger.log(Logger.ERROR, JNDI_RESOURCES, "ContainerJNDIManager.ErrorBuildingMailSession", name, err); } } // If unknown type, try to instantiate with the string constructor else if (value != null) { try { Class objClass = Class.forName(className.trim(), true, loader); Constructor objConstr = objClass .getConstructor(new Class[] { String.class }); return objConstr.newInstance(value); } catch (Throwable err) { Logger.log(Logger.ERROR, JNDI_RESOURCES, "ContainerJNDIManager.ErrorBuildingObject", new String[] { name, className }, err); } } return null; } finally { Thread.currentThread().setContextClassLoader(cl); } } /** * Rips the parameters relevant to a particular resource from the command args */ private Properties extractRelevantArgs(Map input, String name) { Properties relevantArgs = new Properties(); for (Object o : input.keySet()) { String key = (String) o; if (key.startsWith("jndi.param." + name + ".")) relevantArgs.put(key.substring(12 + name.length()), input .get(key)); } return relevantArgs; } } jenkins-winstone-0.9.10-jenkins-47/src/java/winstone/jndi/WinstoneBindingEnumeration.java0000644000175000017500000000637312200024521032121 0ustar jamespagejamespage/* * Copyright 2003-2006 Rick Knowles * Distributed under the terms of either: * - the common development and distribution license (CDDL), v1.0; or * - the GNU Lesser General Public License, v2.1 or later */ package winstone.jndi; import java.util.Arrays; import java.util.Enumeration; import java.util.Hashtable; import java.util.Vector; import javax.naming.Binding; import javax.naming.CompositeName; import javax.naming.Context; import javax.naming.NamingEnumeration; import javax.naming.NamingException; import javax.naming.spi.NamingManager; /** * Enumeration over the set of bindings for this context. * * @author Rick Knowles * @version $Id: WinstoneBindingEnumeration.java,v 1.3 2006/02/28 07:32:48 rickknowles Exp $ */ public class WinstoneBindingEnumeration implements NamingEnumeration { private Enumeration nameEnumeration; private Hashtable bindings; private Hashtable contextEnvironment; private Context context; /** * Constructor - sets up the enumeration ready for retrieving bindings * instead of NameClassPairs. * * @param bindings * The source binding set */ public WinstoneBindingEnumeration(Hashtable bindings, Hashtable environment, Context context) { Object keys[] = bindings.keySet().toArray(); Arrays.sort(keys); Vector nameList = new Vector(Arrays.asList(keys)); this.nameEnumeration = nameList.elements(); this.bindings = (Hashtable) bindings.clone(); this.context = context; this.contextEnvironment = environment; } public Object next() throws NamingException { if (this.nameEnumeration == null) throw new NamingException(ContainerJNDIManager.JNDI_RESOURCES .getString("WinstoneBindingEnumeration.AlreadyClosed")); String name = (String) this.nameEnumeration.nextElement(); Object value = this.bindings.get(name); try { value = NamingManager.getObjectInstance(value, new CompositeName() .add(name), this.context, this.contextEnvironment); } catch (Throwable err) { NamingException errNaming = new NamingException( ContainerJNDIManager.JNDI_RESOURCES .getString("WinstoneBindingEnumeration.FailedToGetInstance")); errNaming.setRootCause(err); throw errNaming; } return new Binding(name, value); } public boolean hasMore() throws NamingException { if (this.nameEnumeration == null) throw new NamingException(ContainerJNDIManager.JNDI_RESOURCES .getString("WinstoneBindingEnumeration.AlreadyClosed")); else return this.nameEnumeration.hasMoreElements(); } public void close() throws NamingException { this.nameEnumeration = null; } public boolean hasMoreElements() { try { return hasMore(); } catch (NamingException err) { return false; } } public Object nextElement() { try { return next(); } catch (NamingException err) { return null; } } } jenkins-winstone-0.9.10-jenkins-47/src/java/winstone/jndi/WinstoneNameEnumeration.java0000644000175000017500000000430012200024521031413 0ustar jamespagejamespage/* * Copyright 2003-2006 Rick Knowles * Distributed under the terms of either: * - the common development and distribution license (CDDL), v1.0; or * - the GNU Lesser General Public License, v2.1 or later */ package winstone.jndi; import java.util.Arrays; import java.util.Enumeration; import java.util.Map; import java.util.Vector; import javax.naming.NameClassPair; import javax.naming.NamingEnumeration; import javax.naming.NamingException; /** * Enumeration across the names/classes of the bindings in a particular context. * Used by the list() method. * * @author Rick Knowles * @version $Id: WinstoneNameEnumeration.java,v 1.3 2006/02/28 07:32:48 rickknowles Exp $ */ public class WinstoneNameEnumeration implements NamingEnumeration { private Enumeration nameEnumeration; /** * Constructor */ public WinstoneNameEnumeration(Map bindings) { Object keys[] = bindings.keySet().toArray(); Arrays.sort(keys); Vector nameClassPairs = new Vector(); for (Object key : keys) nameClassPairs.add(new NameClassPair((String) key, bindings .get(key).getClass().getName())); this.nameEnumeration = nameClassPairs.elements(); } public void close() throws NamingException { this.nameEnumeration = null; } public boolean hasMore() throws NamingException { if (this.nameEnumeration == null) throw new NamingException(ContainerJNDIManager.JNDI_RESOURCES .getString("WinstoneNameEnumeration.AlreadyClosed")); else return this.nameEnumeration.hasMoreElements(); } public Object next() throws NamingException { if (hasMore()) return this.nameEnumeration.nextElement(); else return null; } public boolean hasMoreElements() { try { return hasMore(); } catch (NamingException err) { return false; } } public Object nextElement() { try { return next(); } catch (NamingException err) { return null; } } } jenkins-winstone-0.9.10-jenkins-47/src/java/winstone/jndi/WinstoneContext.java0000644000175000017500000005220712200024521027761 0ustar jamespagejamespage/* * Copyright 2003-2006 Rick Knowles * Distributed under the terms of either: * - the common development and distribution license (CDDL), v1.0; or * - the GNU Lesser General Public License, v2.1 or later */ package winstone.jndi; import java.util.ArrayList; import java.util.Hashtable; import java.util.Iterator; import java.util.List; import java.util.Map; import javax.naming.CompositeName; import javax.naming.Context; import javax.naming.Name; import javax.naming.NameNotFoundException; import javax.naming.NameParser; import javax.naming.NamingEnumeration; import javax.naming.NamingException; import javax.naming.NotContextException; import javax.naming.OperationNotSupportedException; import javax.naming.spi.NamingManager; import winstone.Logger; /** * The main jndi context implementation class. * * @author Rick Knowles * @version $Id: WinstoneContext.java,v 1.3 2006/02/28 07:32:48 rickknowles Exp $ */ public class WinstoneContext implements Context { static final String PREFIX = "java:"; static final String FIRST_CHILD = "comp"; static final String BODGED_PREFIX = "java:comp"; private Hashtable environment; private Hashtable bindings; private final static NameParser nameParser = new WinstoneNameParser(); private WinstoneContext parent; private String myAbsoluteName; private Object contextLock; /** * Constructor - sets up environment */ public WinstoneContext(Map sourceEnvironment, WinstoneContext parent, String absoluteName, Object contextLock) throws NamingException { this.environment = new Hashtable(); List sourceKeys = new ArrayList(sourceEnvironment.keySet()); for (Object sourceKey : sourceKeys) { String key = (String) sourceKey; addToEnvironment(key, sourceEnvironment.get(key)); } this.parent = parent; this.myAbsoluteName = absoluteName; this.contextLock = contextLock; this.bindings = new Hashtable(); Logger.log(Logger.FULL_DEBUG, ContainerJNDIManager.JNDI_RESOURCES, "WinstoneContext.Initialised", this.myAbsoluteName); } /** * Constructor - sets up environment and copies the bindings across */ protected WinstoneContext(Map sourceEnvironment, WinstoneContext parent, String absoluteName, Object contextLock, Hashtable bindings) throws NamingException { this.environment = new Hashtable(); List sourceKeys = new ArrayList(sourceEnvironment.keySet()); for (Object sourceKey : sourceKeys) { String key = (String) sourceKey; addToEnvironment(key, sourceEnvironment.get(key)); } this.parent = parent; this.myAbsoluteName = absoluteName; this.contextLock = contextLock; this.bindings = bindings; Logger.log(Logger.FULL_DEBUG, ContainerJNDIManager.JNDI_RESOURCES, "WinstoneContext.Copied", this.myAbsoluteName); } public void close() throws NamingException { } public Hashtable getEnvironment() throws NamingException { return new Hashtable(this.environment); } public Object removeFromEnvironment(String property) throws NamingException { return this.environment.remove(property); } public Object addToEnvironment(String property, Object value) throws NamingException { return this.environment.put(property, value); } /** * Handles the processing of relative and absolute names. If a relative name * is detected, it is processed by the name parser. If an absolute name is * detected, it determines first if the absolute name refers to this * context. If not, it then determines whether the request can be passed * back to the parent or not, and returns null if it can, and throws an * exception otherwise. */ protected Name validateName(Name name) throws NamingException { // Check for absolute urls and redirect or correct if (name.isEmpty()) return name; else if (name.get(0).equals(BODGED_PREFIX)) { Name newName = name.getSuffix(1).add(0, FIRST_CHILD).add(0, PREFIX); return validateName(newName); } else if (name.get(0).equals(PREFIX)) { String stringName = name.toString(); if (stringName.equals(this.myAbsoluteName)) return nameParser.parse(""); else if (stringName.startsWith(this.myAbsoluteName)) return nameParser.parse(stringName .substring(this.myAbsoluteName.length() + 1)); else if (this.parent != null) return null; else throw new NameNotFoundException(ContainerJNDIManager.JNDI_RESOURCES.getString( "WinstoneContext.NameNotFound", name.toString())); } else if (name instanceof CompositeName) return nameParser.parse(name.toString()); else return name; } /** * Lookup an object in the context. Returns a copy of this context if the * name is empty, or the specified resource (if we have it). If the name is * unknown, throws a NameNotFoundException. */ public Object lookup(Name name) throws NamingException { Name searchName = validateName(name); // If null, it means we don't know how to handle this -> throw to the // parent if (searchName == null) return this.parent.lookup(name); // If empty name, return a copy of this Context else if (searchName.isEmpty()) return new WinstoneContext(this.environment, this.parent, this.myAbsoluteName, this.contextLock, this.bindings); String thisName = searchName.get(0); synchronized (this.contextLock) { Object thisValue = bindings.get(thisName); // If the name points to something in this level, try to find it, // and give // an error if not available if (searchName.size() == 1) { if (thisValue == null) throw new NameNotFoundException(ContainerJNDIManager.JNDI_RESOURCES.getString( "WinstoneContext.NameNotFound", name.toString())); try { return NamingManager.getObjectInstance(thisValue, new CompositeName().add(thisName), this, this.environment); } catch (Exception e) { NamingException ne = new NamingException(ContainerJNDIManager.JNDI_RESOURCES .getString("WinstoneContext.FailedToGetInstance")); ne.setRootCause(e); throw ne; } } else if (thisValue == null) throw new NameNotFoundException(ContainerJNDIManager.JNDI_RESOURCES.getString( "WinstoneContext.NameNotFound", thisName)); // If it's not in this level and what we found is not a context, // complain else if (!(thisValue instanceof Context)) throw new NotContextException(ContainerJNDIManager.JNDI_RESOURCES.getString( "WinstoneContext.NotContext", new String[] { thisName, thisValue.getClass().getName() })); // Open the context, perform a lookup, then close the context we // opened else try { return ((Context) thisValue) .lookup(searchName.getSuffix(1)); } finally { ((Context) thisValue).close(); } } } public Object lookup(String name) throws NamingException { return lookup(new CompositeName(name)); } public Object lookupLink(Name name) throws NamingException { Logger.log(Logger.WARNING, ContainerJNDIManager.JNDI_RESOURCES, "WinstoneContext.LinkRefUnsupported"); return lookup(name); } public Object lookupLink(String name) throws NamingException { return lookupLink(new CompositeName(name)); } /** * Returns a list of objects bound to the context */ public NamingEnumeration list(Name name) throws NamingException { Name searchName = validateName(name); // If null, it means we don't know how to handle this -> throw to the // parent if (searchName == null) return this.parent.list(name); // If empty name, return a copy of this Context else if (searchName.isEmpty()) { NamingEnumeration e; synchronized (this.contextLock) { e = new WinstoneNameEnumeration(this.bindings); } return e; } // Lookup the object - if it's not a context, throw an error else { Object ctx = this.lookup(searchName); if (ctx instanceof Context) try { return ((Context) ctx).list(new CompositeName("")); } finally { ((Context) ctx).close(); } else if (ctx == null) throw new NameNotFoundException(ContainerJNDIManager.JNDI_RESOURCES.getString( "WinstoneContext.NameNotFound", searchName.toString())); else throw new NotContextException(ContainerJNDIManager.JNDI_RESOURCES.getString( "WinstoneContext.NotContext", new String[] { searchName.toString(), ctx.getClass().getName() })); } } public NamingEnumeration list(String name) throws NamingException { return list(new CompositeName(name)); } public NamingEnumeration listBindings(Name name) throws NamingException { Name searchName = validateName(name); // If null, it means we don't know how to handle this -> throw to the // parent if (searchName == null) return this.parent.list(name); // If empty name, return a copy of this Context else if (searchName.isEmpty()) { NamingEnumeration e; synchronized (this.contextLock) { e = new WinstoneBindingEnumeration(this.bindings, this.environment, this); } return e; } // Lookup the object - if it's not a context, throw an error else { Object ctx = this.lookup(searchName); if (ctx instanceof Context) try { return ((Context) ctx).listBindings(new CompositeName("")); } finally { ((Context) ctx).close(); } else if (ctx == null) throw new NameNotFoundException(ContainerJNDIManager.JNDI_RESOURCES.getString( "WinstoneContext.NameNotFound", searchName.toString())); else throw new NotContextException(ContainerJNDIManager.JNDI_RESOURCES.getString( "WinstoneContext.NotContext", new String[] { searchName.toString(), ctx.getClass().getName() })); } } public NamingEnumeration listBindings(String name) throws NamingException { return listBindings(new CompositeName(name)); } public NameParser getNameParser(Name name) throws NamingException { Object obj = lookup(name); if (obj instanceof Context) { ((Context) obj).close(); } return nameParser; } public NameParser getNameParser(String name) throws NamingException { return getNameParser(new CompositeName(name)); } public String getNameInNamespace() throws NamingException { return this.myAbsoluteName; } /*************************************************************************** * Below here is for read-write contexts ... * **************************************************************************/ public void bind(String name, Object value) throws NamingException { bind(new CompositeName(name), value); } public void bind(Name name, Object value) throws NamingException { bind(name, value, false); } protected void bind(Name name, Object value, boolean allowOverwrites) throws NamingException { Name bindName = validateName(name); // If null, it means we don't know how to handle this -> throw to the // parent if (bindName == null) this.parent.bind(name, value, allowOverwrites); // If empty name, complain - we should have a child name here else if (bindName.isEmpty()) throw new NamingException(ContainerJNDIManager.JNDI_RESOURCES.getString( "WinstoneContext.AlreadyExists", name.toString())); else if (bindName.size() > 1) { Object ctx = lookup(bindName.get(0)); if (!(ctx instanceof Context)) throw new NotContextException(ContainerJNDIManager.JNDI_RESOURCES.getString( "WinstoneContext.NotContext", new String[] { bindName.get(0), ctx.getClass().getName() })); else if (ctx == null) throw new NameNotFoundException(ContainerJNDIManager.JNDI_RESOURCES.getString( "WinstoneContext.NameNotFound", bindName.get(0))); else try { if (allowOverwrites) ((Context) ctx).rebind(bindName.getSuffix(1), value); else ((Context) ctx).bind(bindName.getSuffix(1), value); } finally { ((Context) ctx).close(); } } else if ((!allowOverwrites) && this.bindings.get(name.get(0)) != null) throw new NamingException(ContainerJNDIManager.JNDI_RESOURCES.getString( "WinstoneContext.AlreadyExists", name.toString())); else { value = NamingManager.getStateToBind(value, new CompositeName() .add(bindName.get(0)), this, this.environment); synchronized (this.contextLock) { this.bindings.put(bindName.get(0), value); } } } public void rebind(String name, Object value) throws NamingException { rebind(new CompositeName(name), value); } public void rebind(Name name, Object value) throws NamingException { bind(name, value, true); } public void unbind(String name) throws NamingException { unbind(new CompositeName(name)); } public void unbind(Name name) throws NamingException { Name unbindName = validateName(name); // If null, it means we don't know how to handle this -> throw to the // parent if (unbindName == null) this.parent.unbind(name); // If empty name, complain - we should have a child name here else if (unbindName.isEmpty()) throw new NamingException(ContainerJNDIManager.JNDI_RESOURCES .getString("WinstoneContext.CantUnbindEmptyName")); else if (unbindName.size() > 1) { Object ctx = lookup(unbindName.get(0)); if (!(ctx instanceof Context)) throw new NotContextException(ContainerJNDIManager.JNDI_RESOURCES.getString( "WinstoneContext.NotContext", new String[] { unbindName.get(0), ctx.getClass().getName() })); else if (ctx == null) throw new NameNotFoundException(ContainerJNDIManager.JNDI_RESOURCES.getString( "WinstoneContext.NameNotFound", unbindName.get(0))); else try { ((Context) ctx).unbind(unbindName.getSuffix(1)); } finally { ((Context) ctx).close(); } } else if (this.bindings.get(name.get(0)) == null) throw new NamingException(ContainerJNDIManager.JNDI_RESOURCES.getString( "WinstoneContext.NameNotFound", name.toString())); else { synchronized (this.contextLock) { // Object removing = this.bindings.get(unbindName.get(0)); this.bindings.remove(unbindName.get(0)); } } } public void rename(Name oldName, Name newName) throws NamingException { throw new OperationNotSupportedException( "rename not supported in Winstone java:/ context"); } public void rename(String oldName, String newName) throws NamingException { rename(new CompositeName(oldName), new CompositeName(newName)); } public Context createSubcontext(String name) throws NamingException { return createSubcontext(new CompositeName(name)); } public Context createSubcontext(Name name) throws NamingException { Name childName = validateName(name); // If null, it means we don't know how to handle this -> throw to the // parent if (childName == null) return this.parent.createSubcontext(name); // If empty name, complain - we should have a child name here else if (childName.isEmpty()) throw new NamingException(ContainerJNDIManager.JNDI_RESOURCES.getString( "WinstoneContext.AlreadyExists", name.toString())); else if (childName.size() > 1) { Object ctx = lookup(childName.get(0)); if (!(ctx instanceof Context)) throw new NotContextException(ContainerJNDIManager.JNDI_RESOURCES.getString( "WinstoneContext.NotContext", new String[] { childName.get(0), ctx.getClass().getName() })); else if (ctx == null) throw new NameNotFoundException(ContainerJNDIManager.JNDI_RESOURCES.getString( "WinstoneContext.NameNotFound", childName.get(0))); else try { ((Context) ctx).createSubcontext(childName.getSuffix(1)); } finally { ((Context) ctx).close(); } } Context childContext; synchronized (this.contextLock) { if (this.bindings.get(childName.get(0)) != null) throw new NamingException(ContainerJNDIManager.JNDI_RESOURCES.getString( "WinstoneContext.AlreadyExists", childName.get(0))); else { childContext = new WinstoneContext(this.environment, this, this.myAbsoluteName + "/" + childName.get(0), true); this.bindings.put(childName.get(0), childContext); } } return childContext; } public void destroySubcontext(String name) throws NamingException { destroySubcontext(new CompositeName(name)); } public void destroySubcontext(Name name) throws NamingException { Name childName = validateName(name); // If null, it means we don't know how to handle this -> throw to the parent if (childName == null) this.parent.destroySubcontext(name); // If absolutely referring to this context, tell the parent to delete this context else if (childName.isEmpty()) { if (!name.isEmpty()) this.parent.destroySubcontext(name.getSuffix(name.size() - 2)); else throw new NamingException(ContainerJNDIManager.JNDI_RESOURCES .getString("WinstoneContext.CantDestroyEmptyName")); } else if (childName.size() > 1) { Object ctx = lookup(childName.get(0)); if (!(ctx instanceof Context)) throw new NotContextException(ContainerJNDIManager.JNDI_RESOURCES.getString( "WinstoneContext.NotContext", new String[] { childName.get(0), ctx.getClass().getName() })); else if (ctx == null) throw new NameNotFoundException(ContainerJNDIManager.JNDI_RESOURCES.getString( "WinstoneContext.NameNotFound", childName.get(0))); else try { ((Context) ctx).destroySubcontext(childName.getSuffix(1)); } finally { ((Context) ctx).close(); } } else synchronized (this.contextLock) { Context childContext = (Context) lookup(childName.get(0)); childContext.close(); this.bindings.remove(childName.get(0)); } } public String composeName(String name1, String name2) throws NamingException { Name name = composeName(new CompositeName(name1), new CompositeName( name2)); return name == null ? null : name.toString(); } public Name composeName(Name name1, Name name2) throws NamingException { throw new OperationNotSupportedException( "composeName not supported in Winstone java:/ namespace"); } } jenkins-winstone-0.9.10-jenkins-47/src/java/winstone/jndi/WebAppJNDIManager.java0000644000175000017500000000622212200024521027720 0ustar jamespagejamespage/* * Copyright 2003-2006 Rick Knowles * Distributed under the terms of either: * - the common development and distribution license (CDDL), v1.0; or * - the GNU Lesser General Public License, v2.1 or later */ package winstone.jndi; import java.util.Iterator; import java.util.List; import java.util.Map; import org.w3c.dom.Node; import winstone.Logger; import winstone.WebAppConfiguration; /** * Implements a simple web.xml + command line arguments style jndi manager * * @author Rick Knowles * @version $Id: WebAppJNDIManager.java,v 1.9 2006/02/28 07:32:48 rickknowles Exp $ */ public class WebAppJNDIManager extends ContainerJNDIManager { final static String ELEM_ENV_ENTRY = "env-entry"; final static String ELEM_ENV_ENTRY_NAME = "env-entry-name"; final static String ELEM_ENV_ENTRY_TYPE = "env-entry-type"; final static String ELEM_ENV_ENTRY_VALUE = "env-entry-value"; /** * Gets the relevant list of objects from the args, validating against the * web.xml nodes supplied. All node addresses are assumed to be relative to * the java:/comp/env context */ public WebAppJNDIManager(Map args, List webXMLNodes, ClassLoader loader) { super(args, webXMLNodes, loader); // If the webXML nodes are not null, validate that all the entries we // wanted have been created if (webXMLNodes != null) for (Object webXMLNode : webXMLNodes) { Node node = (Node) webXMLNode; // Extract the env-entry nodes and create the objects if (node.getNodeType() != Node.ELEMENT_NODE) continue; else if (node.getNodeName().equals(ELEM_ENV_ENTRY)) { String name = null; String type = null; String value = null; for (int m = 0; m < node.getChildNodes().getLength(); m++) { Node envNode = node.getChildNodes().item(m); if (envNode.getNodeType() != Node.ELEMENT_NODE) continue; else if (envNode.getNodeName().equals(ELEM_ENV_ENTRY_NAME)) name = WebAppConfiguration.getTextFromNode(envNode); else if (envNode.getNodeName().equals(ELEM_ENV_ENTRY_TYPE)) type = WebAppConfiguration.getTextFromNode(envNode); else if (envNode.getNodeName().equals(ELEM_ENV_ENTRY_VALUE)) value = WebAppConfiguration.getTextFromNode(envNode); } if ((name != null) && (type != null) && (value != null)) { Logger.log(Logger.FULL_DEBUG, JNDI_RESOURCES, "WebAppJNDIManager.CreatingResourceWebXML", name); Object obj = createObject(name, type, value, args, loader); if (obj != null) this.objectsToCreate.put(name, obj); } } } } } jenkins-winstone-0.9.10-jenkins-47/src/java/winstone/jndi/resourceFactories/0000755000175000017500000000000012200024521027424 5ustar jamespagejamespagejenkins-winstone-0.9.10-jenkins-47/src/java/winstone/jndi/resourceFactories/WinstoneConnection.java0000644000175000017500000002414012200024521034116 0ustar jamespagejamespage/* * Copyright 2003-2006 Rick Knowles * Distributed under the terms of either: * - the common development and distribution license (CDDL), v1.0; or * - the GNU Lesser General Public License, v2.1 or later */ package winstone.jndi.resourceFactories; import java.sql.Array; import java.sql.Blob; import java.sql.CallableStatement; import java.sql.Clob; import java.sql.Connection; import java.sql.DatabaseMetaData; import java.sql.NClob; import java.sql.PreparedStatement; import java.sql.SQLClientInfoException; import java.sql.SQLException; import java.sql.SQLWarning; import java.sql.SQLXML; import java.sql.Savepoint; import java.sql.Statement; import java.sql.Struct; import java.util.Map; import java.util.Properties; import java.util.concurrent.Executor; import winstone.Logger; /** * JDBC Connection wrapper for use in the pooling datasource. This just suppresses * the close() call, and releases the connection. * * @author Rick Knowles * @version $Id: WinstoneConnection.java,v 1.3 2006/02/28 07:32:48 rickknowles Exp $ */ public class WinstoneConnection implements Connection { private Connection realConnection; private WinstoneDataSource datasource; /** * Constructor - this sets the real connection and the link back to the pool */ public WinstoneConnection(Connection connection, WinstoneDataSource datasource) { this.realConnection = connection; this.datasource = datasource; } public void close() throws SQLException { if ((this.datasource != null) && (this.datasource.getLogWriter() != null)) { this.datasource.getLogWriter().println( WinstoneDataSource.DS_RESOURCES.getString( "WinstoneConnection.ReleaseRollback")); } else { Logger.log(Logger.FULL_DEBUG, WinstoneDataSource.DS_RESOURCES, "WinstoneConnection.ReleaseRollback"); } Connection realConnectionHolder = null; try { if (this.realConnection != null) { realConnectionHolder = this.realConnection; this.realConnection = null; if (!realConnectionHolder.getAutoCommit()) realConnectionHolder.rollback(); } } finally { if ((this.datasource != null) && (realConnectionHolder != null)) { this.datasource.releaseConnection(this, realConnectionHolder); this.datasource = null; } } } public boolean isClosed() throws SQLException { return (this.realConnection == null); } public void commit() throws SQLException { this.realConnection.commit(); } public void rollback() throws SQLException { this.realConnection.rollback(); } public void rollback(Savepoint sp) throws SQLException { this.realConnection.rollback(sp); } public boolean getAutoCommit() throws SQLException { return this.realConnection.getAutoCommit(); } public void setAutoCommit(boolean autoCommit) throws SQLException { this.realConnection.setAutoCommit(autoCommit); } public int getHoldability() throws SQLException { return this.realConnection.getHoldability(); } public void setHoldability(int hold) throws SQLException { this.realConnection.setHoldability(hold); } public int getTransactionIsolation() throws SQLException { return this.realConnection.getTransactionIsolation(); } public void setTransactionIsolation(int level) throws SQLException { this.realConnection.setTransactionIsolation(level); } public void clearWarnings() throws SQLException { this.realConnection.clearWarnings(); } public SQLWarning getWarnings() throws SQLException { return this.realConnection.getWarnings(); } public boolean isReadOnly() throws SQLException { return this.realConnection.isReadOnly(); } public void setReadOnly(boolean ro) throws SQLException { this.realConnection.setReadOnly(ro); } public String getCatalog() throws SQLException { return this.realConnection.getCatalog(); } public void setCatalog(String catalog) throws SQLException { this.realConnection.setCatalog(catalog); } public DatabaseMetaData getMetaData() throws SQLException { return this.realConnection.getMetaData(); } public Savepoint setSavepoint() throws SQLException { return this.realConnection.setSavepoint(); } public Savepoint setSavepoint(String name) throws SQLException { return this.realConnection.setSavepoint(name); } public void releaseSavepoint(Savepoint sp) throws SQLException { this.realConnection.releaseSavepoint(sp); } public Map getTypeMap() throws SQLException { return this.realConnection.getTypeMap(); } public String nativeSQL(String sql) throws SQLException { return this.realConnection.nativeSQL(sql); } public CallableStatement prepareCall(String sql) throws SQLException { return this.realConnection.prepareCall(sql); } public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency) throws SQLException { return this.realConnection.prepareCall(sql, resultSetType, resultSetConcurrency); } public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { return this.realConnection.prepareCall(sql, resultSetType, resultSetConcurrency, resultSetHoldability); } public Statement createStatement() throws SQLException { return this.realConnection.createStatement(); } public Statement createStatement(int resultSetType, int resultSetConcurrency) throws SQLException { return this.realConnection.createStatement(resultSetType, resultSetConcurrency); } public Statement createStatement(int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { return this.realConnection.createStatement(resultSetType, resultSetConcurrency, resultSetHoldability); } public PreparedStatement prepareStatement(String sql) throws SQLException { return this.realConnection.prepareStatement(sql); } public PreparedStatement prepareStatement(String sql, int autogeneratedKeys) throws SQLException { return this.realConnection.prepareStatement(sql, autogeneratedKeys); } public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency) throws SQLException { return this.realConnection.prepareStatement(sql, resultSetType, resultSetConcurrency); } public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { return this.realConnection.prepareStatement(sql, resultSetType, resultSetConcurrency, resultSetHoldability); } public PreparedStatement prepareStatement(String sql, int[] columnIndexes) throws SQLException { return this.realConnection.prepareStatement(sql, columnIndexes); } public PreparedStatement prepareStatement(String sql, String[] columnNames) throws SQLException { return this.realConnection.prepareStatement(sql, columnNames); } public Array createArrayOf(String typeName, Object[] elements) throws SQLException { return this.realConnection.createArrayOf (typeName, elements); } public Clob createClob() throws SQLException { return this.realConnection.createClob (); } public Blob createBlob() throws SQLException { return this.realConnection.createBlob (); } public NClob createNClob() throws SQLException { return this.realConnection.createNClob (); } public SQLXML createSQLXML() throws SQLException { return this.realConnection.createSQLXML (); } public Struct createStruct(String typeName, Object[] attributes) throws SQLException { return this.realConnection.createStruct (typeName, attributes); } public String getClientInfo(String name) throws SQLException { return this.realConnection.getClientInfo (name); } public Properties getClientInfo() throws SQLException { return this.realConnection.getClientInfo (); } public boolean isValid(int timeout) throws SQLException { return this.realConnection.isValid (timeout); } public void setClientInfo(String name, String value) throws SQLClientInfoException { this.realConnection.setClientInfo (name, value); } public void setClientInfo(Properties properties) throws SQLClientInfoException { this.realConnection.setClientInfo (properties); } public T unwrap(Class iface) throws SQLException { return this.realConnection.unwrap(iface); } public boolean isWrapperFor(Class iface) throws SQLException { return this.realConnection.isWrapperFor(iface); } public void setTypeMap(Map> map) throws SQLException { this.realConnection.setTypeMap(map); } public void setSchema(String schema) throws SQLException { this.realConnection.setSchema(schema); } public String getSchema() throws SQLException { return this.realConnection.getSchema(); } public void abort(Executor executor) throws SQLException { this.realConnection.abort(executor); } public void setNetworkTimeout(Executor executor, int milliseconds) throws SQLException { this.realConnection.setNetworkTimeout(executor,milliseconds); } public int getNetworkTimeout() throws SQLException { return this.realConnection.getNetworkTimeout(); } } jenkins-winstone-0.9.10-jenkins-47/src/java/winstone/jndi/resourceFactories/WinstoneDataSource.java0000644000175000017500000004322412200024521034055 0ustar jamespagejamespage/* * Copyright 2003-2006 Rick Knowles * Distributed under the terms of either: * - the common development and distribution license (CDDL), v1.0; or * - the GNU Lesser General Public License, v2.1 or later */ package winstone.jndi.resourceFactories; import java.io.PrintWriter; import java.sql.Connection; import java.sql.Driver; import java.sql.PreparedStatement; import java.sql.SQLException; import java.sql.SQLFeatureNotSupportedException; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Properties; import java.util.logging.Level; import javax.sql.DataSource; import winstone.Logger; import winstone.WebAppConfiguration; import winstone.WinstoneResourceBundle; /** * Implements a JDBC 2.0 pooling datasource. This is meant to act as a wrapper * around a JDBC 1.0 driver, just providing the pool management functions. * * Supports keep alives, and check-connection-before-get options, as well * as normal reclaimable pool management options like maxIdle, maxConnections and * startConnections. Additionally it supports poll-retry on full, which means the * getConnection call will block and retry after a certain period when the pool * is maxed out (good for high load conditions). * * This class was originally drawn from the generator-runtime servlet framework and * modified to make it more JDBC-API only compliant. * * @author Rick Knowles * @version $Id: WinstoneDataSource.java,v 1.8 2006/11/07 01:30:39 rickknowles Exp $ */ public class WinstoneDataSource implements DataSource, Runnable { public static final WinstoneResourceBundle DS_RESOURCES = new WinstoneResourceBundle("winstone.jndi.resourceFactories.LocalStrings"); private String name; private String url; private Driver driver; private Properties connectProps; private int maxIdleCount; private int maxHeldCount; private int retryCount; private int retryPeriod; private String keepAliveSQL; private int keepAlivePeriod; private boolean checkBeforeGet; private int killInactivePeriod; private List usedWrappers; private List unusedRealConnections; // sempahore private List usedRealConnections; private Thread managementThread; private int loginTimeout; private PrintWriter logWriter; /** * Main constructor. Basically just calls the init method */ public WinstoneDataSource(String name, Map args, ClassLoader loader) { this.name = name; this.usedWrappers = new ArrayList(); this.usedRealConnections = new ArrayList(); this.unusedRealConnections = new ArrayList(); this.connectProps = new Properties(); // Extract pool management properties this.keepAliveSQL = WebAppConfiguration.stringArg(args, "keepAliveSQL", ""); this.keepAlivePeriod = WebAppConfiguration.intArg(args, "keepAlivePeriod", -1); this.checkBeforeGet = WebAppConfiguration.booleanArg(args, "checkBeforeGet", !this.keepAliveSQL.equals("")); this.killInactivePeriod = WebAppConfiguration.intArg(args, "killInactivePeriod", -1); this.url = WebAppConfiguration.stringArg(args, "url", null); String driverClassName = WebAppConfiguration.stringArg(args, "driverClassName", ""); if (args.get("username") != null) this.connectProps.put("user", args.get("username")); if (args.get("password") != null) this.connectProps.put("password", args.get("password")); this.maxHeldCount = WebAppConfiguration.intArg(args, "maxConnections", 20); this.maxIdleCount = WebAppConfiguration.intArg(args, "maxIdle", 10); int startCount = WebAppConfiguration.intArg(args, "startConnections", 1); this.retryCount = WebAppConfiguration.intArg(args, "retryCount", 1); this.retryPeriod = WebAppConfiguration.intArg(args, "retryPeriod", 1000); log(Logger.FULL_DEBUG, "WinstoneDataSource.Init", this.url, null); try { synchronized (this.unusedRealConnections) { if (!driverClassName.equals("")) { Class driverClass = Class.forName(driverClassName.trim(), true, loader); this.driver = (Driver) driverClass.newInstance(); for (int n = 0; n < startCount; n++) { makeNewRealConnection(this.unusedRealConnections); } } } } catch (Throwable err) { log(Logger.ERROR, "WinstoneDataSource.ErrorInCreate", this.name, err); } // Start management thread this.managementThread = new Thread(this, "DBConnectionPool management thread"); this.managementThread.start(); } /** * Close this pool - probably because we will want to re-init the pool */ public void destroy() { if (this.managementThread != null) { this.managementThread.interrupt(); this.managementThread = null; } synchronized (this.unusedRealConnections) { killPooledConnections(this.unusedRealConnections, 0); killPooledConnections(this.usedRealConnections, 0); } this.usedRealConnections.clear(); this.unusedRealConnections.clear(); this.usedWrappers.clear(); } /** * Gets a connection with a specific username/password. These are not pooled. */ public Connection getConnection(String username, String password) throws SQLException { Properties newProps = new Properties(); newProps.put("user", username); newProps.put("password", password); Connection conn = this.driver.connect(this.url, newProps); WinstoneConnection wrapper; synchronized (this.unusedRealConnections) { wrapper = new WinstoneConnection(conn, this); this.usedWrappers.add(wrapper); } return wrapper; } public Connection getConnection() throws SQLException { return getConnection(this.retryCount); } /** * Get a read-write connection - preferably from the pool, but fresh if needed */ protected Connection getConnection(int retriesAllowed) throws SQLException { Connection realConnection = null; synchronized (this.unusedRealConnections) { // If we have any spare, get it from the unused pool if (this.unusedRealConnections.size() > 0) { realConnection = (Connection) this.unusedRealConnections.get(0); this.unusedRealConnections.remove(realConnection); this.usedRealConnections.add(realConnection); log(Logger.FULL_DEBUG, "WinstoneDataSource.UsingPooled", new String[] {"" + this.usedRealConnections.size(), "" + this.unusedRealConnections.size()}, null); try { return prepareWrapper(realConnection); } catch (SQLException err) { // Leave the realConnection as non-null, so we know prepareWrapper failed } } // If we are out (and not over our limit), allocate a new one else if (this.usedRealConnections.size() < maxHeldCount) { realConnection = makeNewRealConnection(this.usedRealConnections); log(Logger.FULL_DEBUG, "WinstoneDataSource.UsingNew", new String[] {"" + this.usedRealConnections.size(), "" + this.unusedRealConnections.size()}, null); try { return prepareWrapper(realConnection); } catch (SQLException err) { // Leave the realConnection as non-null, so we know prepareWrapper failed } } } if (realConnection != null) { // prepareWrapper() must have failed, so call this method again realConnection = null; return getConnection(retriesAllowed); } else if (retriesAllowed <= 0) { // otherwise throw fail message - we've blown our limit throw new SQLException(DS_RESOURCES.getString("WinstoneDataSource.Exceeded", "" + maxHeldCount)); } else { log(Logger.FULL_DEBUG, "WinstoneDataSource.Retrying", new String[] { "" + maxHeldCount, "" + retriesAllowed, "" + retryPeriod}, null); // If we are here, it's because we need to retry for a connection try { Thread.sleep(retryPeriod); } catch (InterruptedException err) {} return getConnection(retriesAllowed - 1); } } private Connection prepareWrapper(Connection realConnection) throws SQLException { // Check before get() if (this.checkBeforeGet) { try { executeKeepAlive(realConnection); } catch (SQLException err) { // Dead connection, kill it and try again killConnection(this.usedRealConnections, realConnection); throw err; } } realConnection.setAutoCommit(false); WinstoneConnection wrapper = new WinstoneConnection(realConnection, this); this.usedWrappers.add(wrapper); return wrapper; } /** * Releases connections back to the pool */ void releaseConnection(WinstoneConnection wrapper, Connection realConnection) throws SQLException { synchronized (this.unusedRealConnections) { if (wrapper != null) { this.usedWrappers.remove(wrapper); } if (realConnection != null) { if (this.usedRealConnections.contains(realConnection)) { this.usedRealConnections.remove(realConnection); this.unusedRealConnections.add(realConnection); log(Logger.FULL_DEBUG, "WinstoneDataSource.Releasing", new String[] {"" + this.usedRealConnections.size(), "" + this.unusedRealConnections.size()}, null); } else { log(Logger.WARNING, "WinstoneDataSource.ReleasingUnknown", null); realConnection.close(); } } } } public int getLoginTimeout() { return this.loginTimeout; } public PrintWriter getLogWriter() { return this.logWriter; } public void setLoginTimeout(int timeout) { this.loginTimeout = timeout; } public void setLogWriter(PrintWriter writer) { this.logWriter = writer; } /** * Clean up and keep-alive thread. * Note - this needs a lot more attention to the semaphore use during keepAlive etc */ public void run() { log(Logger.DEBUG, "WinstoneDataSource.MaintenanceStart", null); int keepAliveCounter = -1; int killInactiveCounter = -1; boolean threadRunning = true; while (threadRunning) { try { long startTime = System.currentTimeMillis(); // Keep alive if the time is right if ((this.keepAlivePeriod != -1) && threadRunning) { keepAliveCounter++; if (this.keepAlivePeriod <= keepAliveCounter) { synchronized (this.unusedRealConnections) { executeKeepAliveOnUnused(); } keepAliveCounter = 0; } } if (Thread.interrupted()) { threadRunning = false; } // Kill inactive connections if the time is right if ((this.killInactivePeriod != -1) && threadRunning) { killInactiveCounter++; if (this.killInactivePeriod <= killInactiveCounter) { synchronized (this.unusedRealConnections) { killPooledConnections(this.unusedRealConnections, this.maxIdleCount); } killInactiveCounter = 0; } } if ((killInactiveCounter == 0) || (keepAliveCounter == 0)) { log(Logger.FULL_DEBUG, "WinstoneDataSource.MaintenanceTime", "" + (System.currentTimeMillis() - startTime), null); } if (Thread.interrupted()) { threadRunning = false; } else { Thread.sleep(60000); // sleep 1 minute } if (Thread.interrupted()) { threadRunning = false; } } catch (InterruptedException err) { threadRunning = false; continue; } } log(Logger.DEBUG, "WinstoneDataSource.MaintenanceFinish", null); } /** * Executes keep alive for each of the connections in the supplied pool */ protected void executeKeepAliveOnUnused() { // keep alive all unused roConns now List dead = new ArrayList(); for (Object unusedRealConnection : this.unusedRealConnections) { Connection conn = (Connection) unusedRealConnection; try { executeKeepAlive(conn); } catch (SQLException errSQL) { dead.add(conn); } } for (Object aDead : dead) { killConnection(this.unusedRealConnections, (Connection) aDead); } log(Logger.FULL_DEBUG, "WinstoneDataSource.KeepAliveFinished", "" + this.unusedRealConnections.size(), null); } protected void executeKeepAlive(Connection connection) throws SQLException { if (!this.keepAliveSQL.equals("")) { PreparedStatement qryKeepAlive = null; try { qryKeepAlive = connection.prepareStatement(keepAliveSQL); qryKeepAlive.execute(); } catch (SQLException err) { log(Logger.WARNING, "WinstoneDataSource.KeepAliveFailed", err); throw err; } finally { if (qryKeepAlive != null) { qryKeepAlive.close(); } } } } /** * This makes a new rw connection. It assumes that the synchronization has taken * place in the calling code, so is unsafe for use outside this class. */ protected Connection makeNewRealConnection(List pool) throws SQLException { if (this.url == null) { throw new SQLException("No JDBC URL supplied"); } Connection realConnection = this.driver.connect(this.url, this.connectProps); pool.add(realConnection); log(Logger.FULL_DEBUG, "WinstoneDataSource.AddingNew", new String[] {"" + this.usedRealConnections.size(), "" + this.unusedRealConnections.size()}, null); return realConnection; } /** * Iterates through a list and kills off unused connections until we reach the * minimum idle count for that pool. */ protected void killPooledConnections(List pool, int maxIdleCount) { // kill inactive unused roConns now int killed = 0; while (pool.size() > maxIdleCount) { killed++; Connection conn = (Connection) pool.get(0); killConnection(pool, conn); } if (killed > 0) { log(Logger.FULL_DEBUG, "WinstoneDataSource.Killed", "" + killed, null); } } private static void killConnection(List pool, Connection conn) { pool.remove(conn); try { conn.close(); } catch (SQLException err) { } } private void log(Level level, String msgKey, Throwable err) { if (getLogWriter() != null) { getLogWriter().println(DS_RESOURCES.getString(msgKey)); if (err != null) { err.printStackTrace(getLogWriter()); } } else { Logger.log(level, DS_RESOURCES, msgKey, err); } } private void log(Level level, String msgKey, String arg, Throwable err) { if (getLogWriter() != null) { getLogWriter().println(DS_RESOURCES.getString(msgKey, arg)); if (err != null) { err.printStackTrace(getLogWriter()); } } else { Logger.log(level, DS_RESOURCES, msgKey, arg, err); } } private void log(Level level, String msgKey, String arg[], Throwable err) { if (getLogWriter() != null) { getLogWriter().println(DS_RESOURCES.getString(msgKey, arg)); if (err != null) { err.printStackTrace(getLogWriter()); } } else { Logger.log(level, DS_RESOURCES, msgKey, arg, err); } } public java.util.logging.Logger getParentLogger() throws SQLFeatureNotSupportedException { return java.util.logging.Logger.getLogger(""); } public String toString() { return DS_RESOURCES.getString("WinstoneDataSource.StatusMsg", new String[] { this.name, "" + this.usedRealConnections.size(), "" + this.unusedRealConnections.size()}); } @Override public T unwrap(Class iface) throws SQLException { // TODO Auto-generated method stub return null; } @Override public boolean isWrapperFor(Class iface) throws SQLException { // TODO Auto-generated method stub return false; } } jenkins-winstone-0.9.10-jenkins-47/src/java/winstone/jndi/resourceFactories/LocalStrings.properties0000644000175000017500000000255012200024521034150 0ustar jamespagejamespageWinstoneConnection.ReleaseRollback=Rolling back connection for replacement into the pool WinstoneDataSource.Init=Initialising WinstoneDataSource: url=[#0] WinstoneDataSource.ErrorInCreate=Can't create db connection: [#0] WinstoneDataSource.UsingPooled=Using pooled connection - used: [#0] unused: [#1] WinstoneDataSource.UsingNew=Using new connection - used: [#0] unused: [#1] WinstoneDataSource.Retrying=Connection pool limit ([#0]) exceeded. [#1] retries allowed, waiting [#2]ms WinstoneDataSource.Exceeded=Connection unavailable - pool limit ([#0]) exceeded WinstoneDataSource.Releasing=Releasing connection - used: [#0] unused: [#1] WinstoneDataSource.ReleasingUnknown=Releasing unknown connection. Closing WinstoneDataSource.MaintenanceStart=Connection pool maintenance thread starting WinstoneDataSource.MaintenanceFinish=Connection pool maintenance thread finishing WinstoneDataSource.MaintenanceTime=Connection pool maintenance thread - execution complete in [#0]ms WinstoneDataSource.KeepAliveFailed=Keep alive failed - adding connection to drop list WinstoneDataSource.KeepAliveFinished=Executed keep alive for [#0] connections WinstoneDataSource.AddingNew=Adding new connection - used: [#0] unused: [#1] WinstoneDataSource.Killed=Connection pool killed [#0] connections WinstoneDataSource.StatusMsg=WinstoneDataSource: [#0] JDBC connection status - used: [#0] unused: [#1]jenkins-winstone-0.9.10-jenkins-47/src/java/winstone/jndi/LocalStrings.properties0000644000175000017500000000435412200024521030465 0ustar jamespagejamespageContainerJNDIManager.CreatingResourceArgs=Creating object: [#0] from startup arguments ContainerJNDIManager.CreatingResourceWebXML=Creating object [#0] from web.xml env-entry description ContainerJNDIManager.BoundResource=Bound object [#0] to JNDI Context ContainerJNDIManager.ErrorBindingResource=Error binding object [#0] to JNDI Context ContainerJNDIManager.UnboundResource=Unbound object [#0] from JNDI Context ContainerJNDIManager.ErrorUnbindingResource=Error unbinding object [#0] from JNDI Context ContainerJNDIManager.ErrorGettingInitialContext=Could not get an initial JNDI Context ContainerJNDIManager.ErrorBuildingDatasource=Error building JDBC Datasource object [#0] ContainerJNDIManager.ErrorBuildingMailSession=Error building JavaMail session [#0] ContainerJNDIManager.ErrorBuildingObject=Error building JNDI object [#0] (class: [#1]) ContainerJNDIManager.SetupComplete=JNDI initialization complete - [#0] items pre-bound ContainerJNDIManager.TeardownComplete=JNDI shutdown complete - [#0] items declared at startup unbound ContainerJNDIManager.UsingClassLoader=JNDI initializing with classloader: [#0] WebAppJNDIManager.CreatingResourceWebXML=Creating object [#0] from web.xml env-entry description WinstoneBindingEnumeration.AlreadyClosed=Enumeration has already been closed WinstoneBindingEnumeration.FailedToGetInstance=getObjectInstance failed WinstoneContext.Initialised=WinstoneContext instance [#0] created WinstoneContext.Copied=WinstoneContext instance [#0] copied WinstoneContext.NameNotFound=Name [#0] not found WinstoneContext.FailedToGetInstance=getObjectInstance failed WinstoneContext.NotContext=Name [#0] refers to an object that is not a Context WinstoneContext.AlreadyExists=There is already an object bound to [#0] WinstoneContext.CantUnbindEmptyName=The current context cannot be unbound using an empty name WinstoneContext.CantDestroyEmptyName=The current context cannot be destroyed using an empty name WinstoneContext.LinkRefUnsupported=Link references are not supported - using lookup() instead WinstoneNameEnumeration.AlreadyClosed=Enumeration has already been closed javaURLContextFactory.NewContext=New root context created: ClassLoaderKey=[#0] javaURLContextFactory.TryingForClassLoader=Looking for matching context: ClassLoaderKey=[#0] jenkins-winstone-0.9.10-jenkins-47/src/java/winstone/SizeRestrictedHashtable.java0000644000175000017500000000213212200024521030431 0ustar jamespagejamespagepackage winstone; import java.util.Hashtable; import java.util.Map; /** * {@link Hashtable} that sets the upper bound in the total number of keys. * * This is to protect against the DoS attack based on the hash key collision. * See http://www.ocert.org/advisories/ocert-2011-003.html * * @author Kohsuke Kawaguchi */ public class SizeRestrictedHashtable extends Hashtable { private final int cap; public SizeRestrictedHashtable(int initialCapacity, float loadFactor, int cap) { super(initialCapacity, loadFactor); this.cap = cap; } public SizeRestrictedHashtable(int initialCapacity, int cap) { super(initialCapacity); this.cap = cap; } public SizeRestrictedHashtable(int cap) { this.cap = cap; } public SizeRestrictedHashtable(Map t, int cap) { super(t); this.cap = cap; } @Override public V put(K key, V value) { if (size()>cap) throw new IllegalStateException("Hash table size limit exceeded"); return super.put(key, value); } } jenkins-winstone-0.9.10-jenkins-47/src/java/winstone/AuthenticationPrincipal.java0000644000175000017500000000321212200024521030473 0ustar jamespagejamespage/* * Copyright 2003-2006 Rick Knowles * Distributed under the terms of either: * - the common development and distribution license (CDDL), v1.0; or * - the GNU Lesser General Public License, v2.1 or later */ package winstone; import java.io.Serializable; import java.security.Principal; import java.util.List; /** * Implements the principal method - basically just a way of identifying an * authenticated user. * * @author Rick Knowles * @version $Id: AuthenticationPrincipal.java,v 1.2 2006/02/28 07:32:47 rickknowles Exp $ */ public class AuthenticationPrincipal implements Principal, Serializable { private String userName; private String password; private List roles; private String authenticationType; /** * Constructor */ public AuthenticationPrincipal(String userName, String password, List roles) { this.userName = userName; this.password = password; this.roles = roles; } public String getName() { return this.userName; } public String getPassword() { return this.password; } public String getAuthType() { return this.authenticationType; } public void setAuthType(String authType) { this.authenticationType = authType; } /** * Searches for the requested role in this user's roleset. */ public boolean isUserIsInRole(String role) { if (this.roles == null) return false; else if (role == null) return false; else return this.roles.contains(role); } } jenkins-winstone-0.9.10-jenkins-47/src/java/winstone/ObjectPool.java0000644000175000017500000001566012200024521025724 0ustar jamespagejamespage/* * Copyright 2003-2006 Rick Knowles * Distributed under the terms of either: * - the common development and distribution license (CDDL), v1.0; or * - the GNU Lesser General Public License, v2.1 or later */ package winstone; import winstone.cmdline.Option; import java.io.IOException; import java.net.Socket; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.concurrent.ExecutorService; import java.util.concurrent.RejectedExecutionException; import java.util.concurrent.SynchronousQueue; import java.util.concurrent.ThreadFactory; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; /** * Holds the object pooling code for Winstone. Presently this is only responses * and requests, but may increase. * * @author Rick Knowles * @version $Id: ObjectPool.java,v 1.9 2006/11/18 14:56:59 rickknowles Exp $ */ public class ObjectPool { private static final long FLUSH_PERIOD = 60000L; private final int maxIdleRequestHandlersInPool; private final int maxConcurrentRequests; private long RETRY_PERIOD = 1000; private int START_REQUESTS_IN_POOL = 10; private int MAX_REQUESTS_IN_POOL = 1000; private int START_RESPONSES_IN_POOL = 10; private int MAX_RESPONSES_IN_POOL = 1000; private final ExecutorService requestHandler; private List unusedRequestPool; private List unusedResponsePool; private final Object requestPoolSemaphore = new Object(); private final Object responsePoolSemaphore = new Object(); private boolean simulateModUniqueId; private boolean saveSessions; /** * Constructs an instance of the object pool, including handlers, requests * and responses */ public ObjectPool(Map args) throws IOException { this.simulateModUniqueId = Option.SIMULATE_MOD_UNIQUE_ID.get(args); this.saveSessions = Option.USE_SAVED_SESSIONS.get(args); // this.STARTUP_REQUEST_HANDLERS_IN_POOL = Option.HANDLER_COUNT_STARTUP.get(args); this.maxConcurrentRequests = Option.HANDLER_COUNT_MAX.get(args); this.maxIdleRequestHandlersInPool = Option.HANDLER_COUNT_MAX_IDLE.get(args); ExecutorService es = new ThreadPoolExecutor(maxIdleRequestHandlersInPool, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, // idle thread will only hang around for 60 secs new SynchronousQueue(), new ThreadFactory() { private int threadIndex; public synchronized Thread newThread(Runnable r) { String threadName = Launcher.RESOURCES.getString( "RequestHandlerThread.ThreadName", "" + (++threadIndex)); // allocate a thread to run on this object Thread thread = new Thread(r, threadName); thread.setDaemon(true); return thread; } }); requestHandler = new BoundedExecutorService(es, maxConcurrentRequests); // Build the request/response pools this.unusedRequestPool = new ArrayList(); this.unusedResponsePool = new ArrayList(); // Initialise the request/response pools for (int n = 0; n < START_REQUESTS_IN_POOL; n++) { this.unusedRequestPool.add(new WinstoneRequest()); } for (int n = 0; n < START_RESPONSES_IN_POOL; n++) { this.unusedResponsePool.add(new WinstoneResponse()); } } public void destroy() { requestHandler.shutdown(); } /** * Once the socket request comes in, this method is called. It reserves a * request handler, then delegates the socket to that class. When it * finishes, the handler is released back into the pool. */ public void handleRequest(Socket socket, Listener listener) throws IOException, InterruptedException { try { requestHandler.submit(new RequestHandlerThread(this.simulateModUniqueId,this.saveSessions,socket,listener)); } catch (RejectedExecutionException e) { Logger.log(Logger.WARNING, Launcher.RESOURCES, "ObjectPool.NoRHPoolThreads"); socket.close(); } } /** * An attempt at pooling request objects for reuse. */ public WinstoneRequest getRequestFromPool() throws IOException { WinstoneRequest req; synchronized (this.requestPoolSemaphore) { // If we have any spare, get it from the pool int unused = this.unusedRequestPool.size(); if (unused > 0) { req = this.unusedRequestPool.remove(unused - 1); Logger.log(Logger.FULL_DEBUG, Launcher.RESOURCES, "ObjectPool.UsingRequestFromPool", "" + this.unusedRequestPool.size()); } // If we are out, allocate a new one req = new WinstoneRequest(); Logger.log(Logger.FULL_DEBUG, Launcher.RESOURCES, "ObjectPool.NewRequestForPool"); } return req; } public void releaseRequestToPool(WinstoneRequest req) { req.cleanUp(); synchronized (this.requestPoolSemaphore) { if(this.unusedRequestPool.size() < MAX_REQUESTS_IN_POOL) this.unusedRequestPool.add(req); Logger.log(Logger.FULL_DEBUG, Launcher.RESOURCES, "ObjectPool.RequestReleased", "" + this.unusedRequestPool.size()); } } /** * An attempt at pooling request objects for reuse. */ public WinstoneResponse getResponseFromPool() { WinstoneResponse rsp; synchronized (this.responsePoolSemaphore) { // If we have any spare, get it from the pool int unused = this.unusedResponsePool.size(); if (unused > 0) { rsp = this.unusedResponsePool.remove(unused - 1); Logger.log(Logger.FULL_DEBUG, Launcher.RESOURCES, "ObjectPool.UsingResponseFromPool", "" + this.unusedResponsePool.size()); } // If we are out, allocate a new one rsp = new WinstoneResponse(); Logger.log(Logger.FULL_DEBUG, Launcher.RESOURCES, "ObjectPool.NewResponseForPool"); } return rsp; } public void releaseResponseToPool(WinstoneResponse rsp) { rsp.cleanUp(); synchronized (this.responsePoolSemaphore) { if(this.unusedResponsePool.size() < MAX_RESPONSES_IN_POOL) this.unusedResponsePool.add(rsp); Logger.log(Logger.FULL_DEBUG, Launcher.RESOURCES, "ObjectPool.ResponseReleased", "" + this.unusedResponsePool.size()); } } } jenkins-winstone-0.9.10-jenkins-47/src/java/winstone/HostConfiguration.java0000644000175000017500000003517412200024521027333 0ustar jamespagejamespage/* * Copyright 2003-2006 Rick Knowles * Distributed under the terms of either: * - the common development and distribution license (CDDL), v1.0; or * - the GNU Lesser General Public License, v2.1 or later */ package winstone; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.ArrayList; import java.util.Enumeration; import java.util.HashSet; import java.util.Hashtable; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import java.util.jar.JarEntry; import java.util.jar.JarFile; import org.w3c.dom.Document; import org.w3c.dom.Node; import winstone.cmdline.Option; /** * Manages the references to individual webapps within the container. This object handles * the mapping of url-prefixes to webapps, and init and shutdown of any webapps it manages. * * @author Rick Knowles * @version $Id: HostConfiguration.java,v 1.8 2007/08/02 06:16:00 rickknowles Exp $ */ public class HostConfiguration implements Runnable { private static final long FLUSH_PERIOD = 60000L; private static final String WEB_INF = "WEB-INF"; private static final String WEB_XML = "web.xml"; private String hostname; private Map args; private Map webapps; private Cluster cluster; private ObjectPool objectPool; private ClassLoader commonLibCL; private File commonLibCLPaths[]; private Thread thread; public HostConfiguration(String hostname, Cluster cluster, ObjectPool objectPool, ClassLoader commonLibCL, File commonLibCLPaths[], Map args, File webappsDir) throws IOException { this.hostname = hostname; this.args = args; this.webapps = new Hashtable(); this.cluster = cluster; this.objectPool = objectPool; this.commonLibCL = commonLibCL; this.commonLibCLPaths = commonLibCLPaths; // Is this the single or multiple configuration ? Check args File warfile = Option.WARFILE.get(args); File webroot = Option.WEBROOT.get(args); // If single-webapp mode if ((webappsDir == null) && ((warfile != null) || (webroot != null))) { String prefix = Option.PREFIX.get(args); try { this.webapps.put(prefix, initWebApp(prefix, getWebRoot(webroot, warfile), "webapp")); } catch (IOException err) { Logger.log(Logger.ERROR, Launcher.RESOURCES, "HostConfig.WebappInitError", prefix, err); } } // Otherwise multi-webapp mode else { initMultiWebappDir(webappsDir); } Logger.log(Logger.DEBUG, Launcher.RESOURCES, "HostConfig.InitComplete", this.webapps.size() + "", this.webapps.keySet() + ""); this.thread = new Thread(this, "WinstoneHostConfigurationMgmt:" + this.hostname); this.thread.setDaemon(true); this.thread.start(); } public WebAppConfiguration getWebAppByURI(String uri) { if (uri == null) { return null; } else if (uri.equals("/") || uri.equals("")) { return (WebAppConfiguration) this.webapps.get(""); } else if (uri.startsWith("/")) { String decoded = WinstoneRequest.decodeURLToken(uri); String noLeadingSlash = decoded.substring(1); int slashPos = noLeadingSlash.indexOf("/"); if (slashPos == -1) { return (WebAppConfiguration) this.webapps.get(decoded); } else { return (WebAppConfiguration) this.webapps.get( decoded.substring(0, slashPos + 1)); } } else { return null; } } protected WebAppConfiguration initWebApp(String prefix, File webRoot, String contextName) throws IOException { Node webXMLParentNode = null; File webInfFolder = new File(webRoot, WEB_INF); if (webInfFolder.exists()) { File webXmlFile = new File(webInfFolder, WEB_XML); if (webXmlFile.exists()) { Logger.log(Logger.DEBUG, Launcher.RESOURCES, "HostConfig.ParsingWebXml"); Document webXMLDoc = new WebXmlParser(this.commonLibCL) .parseStreamToXML(webXmlFile); if (webXMLDoc != null) { webXMLParentNode = webXMLDoc.getDocumentElement(); Logger.log(Logger.DEBUG, Launcher.RESOURCES, "HostConfig.WebXmlParseComplete"); } else { Logger.log(Logger.DEBUG, Launcher.RESOURCES, "HostConfig.WebXmlParseFailed"); } } } // Instantiate the webAppConfig return new WebAppConfiguration(this, this.cluster, webRoot .getCanonicalPath(), prefix, this.objectPool, this.args, webXMLParentNode, this.commonLibCL, this.commonLibCLPaths, contextName); } public String getHostname() { return this.hostname; } /** * Destroy this webapp instance. Kills the webapps, plus any servlets, * attributes, etc * * @param prefix The webapp to destroy */ private void destroyWebApp(String prefix) { WebAppConfiguration webAppConfig = (WebAppConfiguration) this.webapps.get(prefix); if (webAppConfig != null) { webAppConfig.destroy(); this.webapps.remove(prefix); } } public void destroy() { Set prefixes = new HashSet(this.webapps.keySet()); for (Object prefixe : prefixes) { destroyWebApp((String) prefixe); } if (this.thread != null) { this.thread.interrupt(); } } public void invalidateExpiredSessions() { Set webapps = new HashSet(this.webapps.values()); for (Object webapp : webapps) { ((WebAppConfiguration) webapp).invalidateExpiredSessions(); } } public void run() { boolean interrupted = false; while (!interrupted) { try { Thread.sleep(FLUSH_PERIOD); invalidateExpiredSessions(); } catch (InterruptedException err) { interrupted = true; } } this.thread = null; } public void reloadWebApp(String prefix) { WebAppConfiguration webAppConfig = (WebAppConfiguration) this.webapps.get(prefix); if (webAppConfig != null) { String webRoot = webAppConfig.getWebroot(); String contextName = webAppConfig.getContextName(); destroyWebApp(prefix); try { this.webapps.put(prefix, initWebApp(prefix, new File(webRoot), contextName)); } catch (Throwable err) { Logger.log(Logger.ERROR, Launcher.RESOURCES, "HostConfig.WebappInitError", prefix, err); } } else { throw new WinstoneException(Launcher.RESOURCES.getString("HostConfig.PrefixUnknown", prefix)); } } /** * Setup the webroot. If a warfile is supplied, extract any files that the * war file is newer than. If none is supplied, use the default temp * directory. */ protected File getWebRoot(File requestedWebroot, File warfile) throws IOException { if (warfile != null) { Logger.log(Logger.INFO, Launcher.RESOURCES, "HostConfig.BeginningWarExtraction"); // open the war file if (!warfile.exists() || !warfile.isFile()) throw new WinstoneException(Launcher.RESOURCES.getString( "HostConfig.WarFileInvalid", warfile)); // Get the webroot folder (or a temp dir if none supplied) File unzippedDir; if (requestedWebroot != null) { unzippedDir = requestedWebroot; } else { File tempFile = File.createTempFile("dummy", "dummy"); String userName = System.getProperty("user.name"); unzippedDir = new File(tempFile.getParent(), (userName != null ? WinstoneResourceBundle.globalReplace(userName, new String[][] {{"/", ""}, {"\\", ""}, {",", ""}}) + "/" : "") + "winstone/" + warfile.getName()); tempFile.delete(); } if (unzippedDir.exists()) { if (!unzippedDir.isDirectory()) { throw new WinstoneException(Launcher.RESOURCES.getString( "HostConfig.WebRootNotDirectory", unzippedDir.getPath())); } else { Logger.log(Logger.DEBUG, Launcher.RESOURCES, "HostConfig.WebRootExists", unzippedDir.getCanonicalPath()); } } // check consistency and if out-of-sync, recreate File timestampFile = new File(unzippedDir,".timestamp"); if(!timestampFile.exists() || Math.abs(timestampFile.lastModified()- warfile.lastModified())>1000) { // contents of the target directory is inconsistent from the war. deleteRecursive(unzippedDir); unzippedDir.mkdirs(); } else { // files are up to date return unzippedDir; } // Iterate through the files byte buffer[] = new byte[8192]; JarFile warArchive = new JarFile(warfile); for (Enumeration e = warArchive.entries(); e.hasMoreElements();) { JarEntry element = (JarEntry) e.nextElement(); if (element.isDirectory()) { continue; } String elemName = element.getName(); // If archive date is newer than unzipped file, overwrite File outFile = new File(unzippedDir, elemName); if (outFile.exists() && (outFile.lastModified() > warfile.lastModified())) { continue; } outFile.getParentFile().mkdirs(); // Copy out the extracted file InputStream inContent = warArchive.getInputStream(element); OutputStream outStream = new FileOutputStream(outFile); int readBytes = inContent.read(buffer); while (readBytes != -1) { outStream.write(buffer, 0, readBytes); readBytes = inContent.read(buffer); } inContent.close(); outStream.close(); } // extraction completed new FileOutputStream(timestampFile).close(); timestampFile.setLastModified(warfile.lastModified()); // Return webroot return unzippedDir; } else { return requestedWebroot; } } private void deleteRecursive(File dir) { File[] children = dir.listFiles(); if(children!=null) { for (File child : children) { deleteRecursive(child); } } dir.delete(); } protected void initMultiWebappDir(File webappsDir) { if (webappsDir == null) { webappsDir = new File("webapps"); } if (!webappsDir.exists()) { throw new WinstoneException(Launcher.RESOURCES.getString("HostConfig.WebAppDirNotFound", webappsDir.getPath())); } else if (!webappsDir.isDirectory()) { throw new WinstoneException(Launcher.RESOURCES.getString("HostConfig.WebAppDirIsNotDirectory", webappsDir.getPath())); } else { File children[] = webappsDir.listFiles(); for (File aChildren : children) { String childName = aChildren.getName(); // Check any directories for warfiles that match, and skip: only deploy the war file if (aChildren.isDirectory()) { File matchingWarFile = new File(webappsDir, aChildren.getName() + ".war"); if (matchingWarFile.exists() && matchingWarFile.isFile()) { Logger.log(Logger.DEBUG, Launcher.RESOURCES, "HostConfig.SkippingWarfileDir", childName); } else { String prefix = childName.equalsIgnoreCase("ROOT") ? "" : "/" + childName; if (!this.webapps.containsKey(prefix)) { try { WebAppConfiguration webAppConfig = initWebApp(prefix, aChildren, childName); this.webapps.put(webAppConfig.getContextPath(), webAppConfig); Logger.log(Logger.INFO, Launcher.RESOURCES, "HostConfig.DeployingWebapp", childName); } catch (Throwable err) { Logger.log(Logger.ERROR, Launcher.RESOURCES, "HostConfig.WebappInitError", prefix, err); } } } } else if (childName.endsWith(".war")) { String outputName = childName.substring(0, childName.lastIndexOf(".war")); String prefix = outputName.equalsIgnoreCase("ROOT") ? "" : "/" + outputName; if (!this.webapps.containsKey(prefix)) { File outputDir = new File(webappsDir, outputName); outputDir.mkdirs(); try { WebAppConfiguration webAppConfig = initWebApp(prefix, getWebRoot(new File(webappsDir, outputName), aChildren), outputName); this.webapps.put(webAppConfig.getContextPath(), webAppConfig); Logger.log(Logger.INFO, Launcher.RESOURCES, "HostConfig.DeployingWebapp", childName); } catch (Throwable err) { Logger.log(Logger.ERROR, Launcher.RESOURCES, "HostConfig.WebappInitError", prefix, err); } } } } } } public WebAppConfiguration getWebAppBySessionKey(String sessionKey) { List allwebapps = new ArrayList(this.webapps.values()); for (Object allwebapp : allwebapps) { WebAppConfiguration webapp = (WebAppConfiguration) allwebapp; WinstoneSession session = webapp.getSessionById(sessionKey, false); if (session != null) { return webapp; } } return null; } } jenkins-winstone-0.9.10-jenkins-47/src/java/winstone/Logger.java0000644000175000017500000001662012200024521025100 0ustar jamespagejamespage/* * Copyright 2003-2006 Rick Knowles * Distributed under the terms of either: * - the common development and distribution license (CDDL), v1.0; or * - the GNU Lesser General Public License, v2.1 or later */ package winstone; import java.io.IOException; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.io.Writer; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.HashMap; import java.util.Map; import java.util.logging.Level; /** * A utility class for logging event and status messages. It maintains a * collection of streams for different types of messages, but any messages with * unknown or unspecified stream go to the default stream. * * @author Rick Knowles * @version $Id: Logger.java,v 1.8 2006/11/09 06:01:43 rickknowles Exp $ */ public class Logger { public final static String DEFAULT_STREAM = "Winstone"; public static Level MIN = Level.OFF; public static Level ERROR = Level.SEVERE; public static Level WARNING = Level.WARNING; public static Level INFO = Level.INFO; public static Level SPEED = Level.FINE; public static Level DEBUG = Level.FINER; public static Level FULL_DEBUG = Level.FINEST; public static Level MAX = Level.ALL; protected static Boolean semaphore = true; protected static boolean initialised = false; protected static Writer defaultStream; protected static Map namedStreams; // protected static Collection nullStreams; protected final static DateFormat sdfLog = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss"); protected static boolean showThrowingThread; /** * Initialises default streams */ public static void init(Level level) { init(level, System.out, false); } public static void init(int level) { init(Level.parse(String.valueOf(level))); } /** * Initialises default streams */ public static void init(Level level, OutputStream defaultStream, boolean showThrowingThreadArg) { synchronized (semaphore) { if (!initialised) { // recheck in case we were blocking on another init initialised = false; LOGGER.setLevel(level); namedStreams = new HashMap(); // nullStreams = new ArrayList(); initialised = true; setStream(DEFAULT_STREAM, defaultStream); showThrowingThread = showThrowingThreadArg; } } } /** * Allocates a stream for redirection to a file etc */ public static void setStream(String name, OutputStream stream) { setStream(name, stream != null ? new OutputStreamWriter(stream) : null); } /** * Allocates a stream for redirection to a file etc */ public static void setStream(String name, Writer stream) { if (name == null) { name = DEFAULT_STREAM; } if (!initialised) { init(INFO); } synchronized (semaphore) { if (name.equals(DEFAULT_STREAM)) { defaultStream = stream; } else if (stream == null) { namedStreams.remove(name); } else { namedStreams.put(name, stream); } } } /** * Forces a flush of the contents to file, display, etc */ public static void flush(String name) { if (!initialised) { init(INFO); } Writer stream = getStreamByName(name); if (stream != null) { try {stream.flush();} catch (IOException err) {} } } private static Writer getStreamByName(String streamName) { if ((streamName != null) && streamName.equals(DEFAULT_STREAM)) { // As long as the stream has not been nulled, assign the default if not found synchronized (semaphore) { Writer stream = (Writer) namedStreams.get(streamName); if ((stream == null) && !namedStreams.containsKey(streamName)) { stream = defaultStream; } return stream; } } else { return defaultStream; } } public static void setCurrentDebugLevel(int level) { if (!initialised) { init(level); } else synchronized (semaphore) { LOGGER.setLevel(Level.parse(String.valueOf(level))); } } /** * Writes a log message to the requested stream, and immediately flushes * the contents of the stream. */ private static void logInternal(Level level, String message, Throwable error) { if (!initialised) { init(INFO); } String msg = ""; if (showThrowingThread) { msg = "["+Thread.currentThread().getName()+"] - "; } msg += message; LOGGER.log(level,msg,error); } public static void log(Level level, WinstoneResourceBundle resources, String messageKey) { if (!LOGGER.isLoggable(level)) { return; } else { logInternal(level, resources.getString(messageKey), null); } } public static void log(Level level, WinstoneResourceBundle resources, String messageKey, Throwable error) { if (!LOGGER.isLoggable(level)) { return; } else { logInternal(level, resources.getString(messageKey), error); } } public static void log(Level level, WinstoneResourceBundle resources, String messageKey, Object param) { if (!LOGGER.isLoggable(level)) { return; } else { logInternal(level, resources.getString(messageKey, param), null); } } public static void log(Level level, WinstoneResourceBundle resources, String messageKey, Object... params) { if (!LOGGER.isLoggable(level)) { return; } else { logInternal(level, resources.getString(messageKey, params), null); } } public static void log(Level level, WinstoneResourceBundle resources, String messageKey, Object param, Throwable error) { if (!LOGGER.isLoggable(level)) { return; } else { logInternal(level, resources.getString(messageKey, param), error); } } public static void log(Level level, WinstoneResourceBundle resources, String messageKey, Object params[], Throwable error) { if (!LOGGER.isLoggable(level)) { return; } else { logInternal(level, resources.getString(messageKey, params), error); } } public static void log(Level level, WinstoneResourceBundle resources, String streamName, String messageKey, Object params[], Throwable error) { if (!LOGGER.isLoggable(level)) { return; } else { logInternal(level, resources.getString(messageKey, params), error); } } public static void logDirectMessage(Level level, String streamName, String message, Throwable error) { if (!LOGGER.isLoggable(level)) { return; } else { logInternal(level, message, error); } } private static final java.util.logging.Logger LOGGER = java.util.logging.Logger.getLogger("winstone"); } jenkins-winstone-0.9.10-jenkins-47/src/java/winstone/invoker/0000755000175000017500000000000012200024521024466 5ustar jamespagejamespagejenkins-winstone-0.9.10-jenkins-47/src/java/winstone/invoker/InvokerServlet.java0000644000175000017500000001237112200024521030317 0ustar jamespagejamespage/* * Copyright 2003-2006 Rick Knowles * Distributed under the terms of either: * - the common development and distribution license (CDDL), v1.0; or * - the GNU Lesser General Public License, v2.1 or later */ package winstone.invoker; import java.io.IOException; import java.util.Hashtable; import java.util.Map; import javax.servlet.ServletConfig; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import winstone.Logger; import winstone.Mapping; import winstone.RequestDispatcher; import winstone.ServletConfiguration; import winstone.WebAppConfiguration; import winstone.WinstoneResourceBundle; /** * If a URI matches a servlet class name, mount an instance of that servlet, and * try to process the request using that servlet. * * @author Rick Knowles * @version $Id: InvokerServlet.java,v 1.6 2006/03/24 17:24:24 rickknowles Exp $ */ public class InvokerServlet extends HttpServlet { // private static final String FORWARD_PATH_INFO = "javax.servlet.forward.path_info"; private static final String INCLUDE_PATH_INFO = "javax.servlet.include.path_info"; private static final WinstoneResourceBundle INVOKER_RESOURCES = new WinstoneResourceBundle("winstone.invoker.LocalStrings"); private Map mountedInstances; // private String prefix; // private String invokerPrefix; /** * Set up a blank map of servlet configuration instances */ public void init(ServletConfig config) throws ServletException { super.init(config); this.mountedInstances = new Hashtable(); // this.prefix = config.getInitParameter("prefix"); // this.invokerPrefix = config.getInitParameter("invokerPrefix"); } /** * Destroy any mounted instances we might be holding, then destroy myself */ public void destroy() { if (this.mountedInstances != null) { synchronized (this.mountedInstances) { for (Object o : this.mountedInstances.values()) ((ServletConfiguration) o).destroy(); this.mountedInstances.clear(); } } this.mountedInstances = null; // this.prefix = null; // this.invokerPrefix = null; } /** * Get an instance of the servlet configuration object */ protected ServletConfiguration getInvokableInstance(String servletName) { ServletConfiguration sc = null; synchronized (this.mountedInstances) { if (this.mountedInstances.containsKey(servletName)) { sc = (ServletConfiguration) this.mountedInstances.get(servletName); } } if (sc == null) { // If found, mount an instance try { // Class servletClass = Class.forName(servletName, true, // Thread.currentThread().getContextClassLoader()); sc = new ServletConfiguration((WebAppConfiguration) this.getServletContext(), getServletConfig().getServletName() + ":" + servletName, servletName, new Hashtable(), -1); this.mountedInstances.put(servletName, sc); Logger.log(Logger.DEBUG, INVOKER_RESOURCES, "InvokerServlet.MountingServlet", servletName, getServletConfig().getServletName()); // just to trigger the servlet.init() sc.ensureInitialization(); } catch (Throwable err) { sc = null; } } return sc; } protected void doGet(HttpServletRequest req, HttpServletResponse rsp) throws ServletException, IOException { boolean isInclude = (req.getAttribute(INCLUDE_PATH_INFO) != null); // boolean isForward = (req.getAttribute(FORWARD_PATH_INFO) != null); String servletName; if (isInclude) servletName = (String) req.getAttribute(INCLUDE_PATH_INFO); // else if (isForward) // servletName = (String) req.getAttribute(FORWARD_PATH_INFO); else if (req.getPathInfo() != null) servletName = req.getPathInfo(); else servletName = ""; if (servletName.startsWith("/")) servletName = servletName.substring(1); ServletConfiguration invokedServlet = getInvokableInstance(servletName); if (invokedServlet == null) { Logger.log(Logger.WARNING, INVOKER_RESOURCES, "InvokerServlet.NoMatchingServletFound", servletName); rsp.sendError(HttpServletResponse.SC_NOT_FOUND, INVOKER_RESOURCES .getString("InvokerServlet.NoMatchingServletFound", servletName)); } else { RequestDispatcher rd = new RequestDispatcher( (WebAppConfiguration) getServletContext(), invokedServlet); rd.setForNamedDispatcher(new Mapping[0], new Mapping[0]); rd.forward(req, rsp); } } protected void doPost(HttpServletRequest req, HttpServletResponse rsp) throws ServletException, IOException { doGet(req, rsp); } } jenkins-winstone-0.9.10-jenkins-47/src/java/winstone/invoker/LocalStrings.properties0000644000175000017500000000024312200024521031207 0ustar jamespagejamespageInvokerServlet.NoMatchingServletFound=There was no invokable servlet found matching the URL: [#0] InvokerServlet.MountingServlet=[#1]: Mounting servlet class [#0] jenkins-winstone-0.9.10-jenkins-47/src/java/winstone/cmdline/0000755000175000017500000000000012200024521024424 5ustar jamespagejamespagejenkins-winstone-0.9.10-jenkins-47/src/java/winstone/cmdline/CmdLineParser.java0000644000175000017500000000745312200024521027770 0ustar jamespagejamespagepackage winstone.cmdline; import winstone.Launcher; import winstone.Logger; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Properties; import static winstone.Launcher.*; /** * Command line argument parser, Winstone style. * * @author Kohsuke Kawaguchi */ public class CmdLineParser { private final List> options; public CmdLineParser(List> options) { this.options = options; } public Map parse(String[] argv, String nonSwitchArgName) throws IOException { Map args = new HashMap(); // Load embedded properties file String embeddedPropertiesFilename = RESOURCES.getString( "Launcher.EmbeddedPropertiesFile"); InputStream embeddedPropsStream = Launcher.class.getResourceAsStream( embeddedPropertiesFilename); if (embeddedPropsStream != null) { loadPropsFromStream(embeddedPropsStream, args); embeddedPropsStream.close(); } // Get command line args String configFilename = RESOURCES.getString("Launcher.DefaultPropertyFile"); for (String option : argv) { if (option.startsWith("--")) { int equalPos = option.indexOf('='); String paramName = option.substring(2, equalPos == -1 ? option.length() : equalPos); Option opt = toOption(paramName); if (opt == null) throw new IllegalArgumentException(RESOURCES.getString("CmdLineParser.UnrecognizedOption", option)); if (equalPos != -1) { args.put(paramName, option.substring(equalPos + 1)); } else { if (opt.type == Boolean.class) args.put(paramName, "true"); else throw new IllegalArgumentException(RESOURCES.getString("CmdLineParser.OperandExpected", option)); } if (paramName.equals(Option.CONFIG.name)) { configFilename = args.get(paramName); } } else { if (args.containsKey(nonSwitchArgName)) throw new IllegalArgumentException(RESOURCES.getString("CmdLineParser.MultipleArgs", option)); args.put(nonSwitchArgName, option); } } // Load default props if available File configFile = new File(configFilename); if (configFile.exists() && configFile.isFile()) { InputStream inConfig = new FileInputStream(configFile); loadPropsFromStream(inConfig, args); inConfig.close(); initLogger(args); Logger.log(Logger.DEBUG, RESOURCES, "Launcher.UsingPropertyFile", configFilename); } else { initLogger(args); } return args; } private static void loadPropsFromStream(InputStream inConfig, Map args) throws IOException { Properties props = new Properties(); props.load(inConfig); for (Object o : props.keySet()) { String key = (String) o; if (!args.containsKey(key.trim())) { args.put(key.trim(), props.getProperty(key).trim()); } } props.clear(); } private Option toOption(String paramName) { for (Option o : options) { if (o.isWildcard() && paramName.startsWith(o.name)) return o; if (!o.isWildcard() && paramName.equals(o.name)) return o; } return null; } } jenkins-winstone-0.9.10-jenkins-47/src/java/winstone/cmdline/Option.java0000644000175000017500000002640112200024521026542 0ustar jamespagejamespagepackage winstone.cmdline; import winstone.Launcher; import winstone.WebAppConfiguration; import winstone.classLoader.WebappClassLoader; import winstone.cluster.SimpleCluster; import winstone.jndi.ContainerJNDIManager; import winstone.jndi.WebAppJNDIManager; import winstone.realm.ArgumentsRealm; import java.io.File; import java.lang.reflect.Field; import java.lang.reflect.Modifier; import java.util.ArrayList; import java.util.List; import java.util.Map; /** * Command line options used in {@link Launcher}. * * @author Kohsuke Kawaguchi */ public class Option { /** * List up all the known options. */ public static List> all(Class clazz) { List> r = new ArrayList>(); for (Field f : clazz.getFields()) { if (Modifier.isStatic(f.getModifiers()) && Option.class.isAssignableFrom(f.getType())) { try { r.add((Option) f.get(null)); } catch (IllegalAccessException e) { throw (Error)new IllegalAccessError().initCause(e); } } } return r; } public static final OFile WEBROOT=file("webroot"); public static final OFile WARFILE=file("warfile"); public static final OFile WEBAPPS_DIR=file("webappsDir"); public static final OFile HOSTS_DIR=file("hostsDir"); public static final OFile JAVA_HOME=file("javaHome"); public static final OFile TOOLS_JAR=file("toolsJar"); public static final OFile CONFIG=file("config"); public static final OString PREFIX=string("prefix",""); public static final OFile COMMON_LIB_FOLDER=file("commonLibFolder"); public static final OFile LOGFILE=file("logfile"); public static final OBoolean LOG_THROWING_LINE_NO=bool("logThrowingLineNo",false); public static final OBoolean LOG_THROWING_THREAD=bool("logThrowingThread",false); public static final OBoolean DEBUG=bool("debug",false); // these are combined with protocol to form options public static final OInt _PORT = integer("Port"); public static final OString _LISTEN_ADDRESS = string("ListenAddress"); public static final OBoolean _DO_HOSTNAME_LOOKUPS = bool("DoHostnameLookups",false); /** * Number of milliseconds for the HTTP keep-alive to hang around until the next request is sent. */ public static final OInt _KEEP_ALIVE_TIMEOUT = integer("KeepAliveTimeout",5000); public static final OInt HTTP_PORT=integer("http"+_PORT); public static final OString HTTP_LISTEN_ADDRESS=string("http"+ _LISTEN_ADDRESS); public static final OBoolean HTTP_DO_HOSTNAME_LOOKUPS=bool("http"+ _DO_HOSTNAME_LOOKUPS,false); public static final OInt HTTP_KEEP_ALIVE_TIMEOUT=integer("http" + _KEEP_ALIVE_TIMEOUT, _KEEP_ALIVE_TIMEOUT.defaultValue); public static final OInt HTTPS_PORT=integer("https"+_PORT); public static final OString HTTPS_LISTEN_ADDRESS=string("https"+_LISTEN_ADDRESS); public static final OBoolean HTTPS_DO_HOSTNAME_LOOKUPS=bool("https"+ _DO_HOSTNAME_LOOKUPS,false); public static final OInt HTTPS_KEEP_ALIVE_TIMEOUT=integer("https" + _KEEP_ALIVE_TIMEOUT, _KEEP_ALIVE_TIMEOUT.defaultValue); public static final OFile HTTPS_KEY_STORE=file("httpsKeyStore"); public static final OString HTTPS_KEY_STORE_PASSWORD=string("httpsKeyStorePassword"); public static final OString HTTPS_KEY_MANAGER_TYPE=string("httpsKeyManagerType","SunX509"); public static final OBoolean HTTPS_VERIFY_CLIENT=bool("httpsVerifyClient",false); public static final OFile HTTPS_CERTIFICATE=file("httpsCertificate"); public static final OFile HTTPS_PRIVATE_KEY=file("httpsPrivateKey"); public static final OInt AJP13_PORT=integer("ajp13"+_PORT,-1); public static final OString AJP13_LISTEN_ADDRESS=string("ajp13"+_LISTEN_ADDRESS); public static final OInt CONTROL_PORT=integer("controlPort",-1); /** * Currently unused. */ public static final OInt HANDLER_COUNT_STARTUP =integer("handlerCountStartup",5); /** * How many requests do we handle concurrently? * * If the system gets really loaded, too many concurrent threads will create vicious cycles * and make everyone slow (or worst case choke every request by OOME), so better to err * on the conservative side (and have inbound connections wait in the queue) */ public static final OInt HANDLER_COUNT_MAX =integer("handlerCountMax",40); /** * Leave this number of request handler threads in the pool even when they are idle. * Other threads are destroyed when they are idle to free up resources. */ public static final OInt HANDLER_COUNT_MAX_IDLE=integer("handlerCountMaxIdle",5); public static final OBoolean DIRECTORY_LISTINGS=bool("directoryListings",true); public static final OBoolean USE_JASPER=bool("useJasper",false); public static final OBoolean USE_SERVLET_RELOADING=bool("useServletReloading",false); public static final OClass PREFERRED_CLASS_LOADER=clazz("preferredClassLoader", WebappClassLoader.class); public static final OBoolean USE_INVOKER=bool("useInvoker",false); public static final OString INVOKER_PREFIX=string("invokerPrefix","/servlet/"); public static final OBoolean SIMULATE_MOD_UNIQUE_ID=bool("simulateModUniqueId",false); public static final OBoolean USE_SAVED_SESSIONS=bool("useSavedSessions",false); public static final OString MIME_TYPES=string("mimeTypes"); public static final OInt MAX_PARAM_COUNT=integer("maxParamCount",-1); public static final OBoolean USAGE=bool("usage",false); public static final OInt SESSION_TIMEOUT=integer("sessionTimeout",-1); public static final OBoolean HELP=bool("help",false); public static final OBoolean USE_CLUSTER=bool("useCluster",false); public static final OClass CLUSTER_CLASS_NAME=clazz("clusterClassName", SimpleCluster.class); public static final OString CLUSTER_NODES=string("clusterNodes"); public static final OBoolean USE_JNDI=bool("useJNDI",false); public static final OClass CONTAINER_JNDI_CLASSNAME=clazz("containerJndiClassName",ContainerJNDIManager.class); public static final OClass WEBAPP_JNDI_CLASSNAME=clazz("webappJndiClassName", WebAppJNDIManager.class); public static final OString JDNI_RESOURCE=string("jndi.resource."); public static final OString JNDI_PARAM=string("jndi.param."); public static final OClass REALM_CLASS_NAME=clazz("realmClassName", ArgumentsRealm.class); public static final OString ARGUMENTS_REALM_PASSWORD=string("argumentsRealm.passwd."); public static final OString ARGUMENTS_REALM_ROLES=string("argumentsRealm.roles."); public static final OFile FILEREALM_CONFIGFILE=file("fileRealm.configFile"); public static final OClass ACCESS_LOGGER_CLASSNAME=clazz("accessLoggerClassName",null); public static final OString SIMPLE_ACCESS_LOGGER_FORMAT=string("simpleAccessLogger.format","combined"); public static final OString SIMPLE_ACCESS_LOGGER_FILE=string("simpleAccessLogger.file","logs/###host###/###webapp###_access.log"); /** * Option name without the "--" prefix. */ public final String name; /** * Expected type. */ public final Class type; public final T defaultValue; public Option(String name, Class type, T defaultValue) { this.name = name; this.type = type; this.defaultValue = defaultValue; } public void remove(Map args) { args.remove(name); } public void put(Map args, String value) { args.put(name, value); } public boolean isIn(Map args) { return args.containsKey(name); } /** * Indicates an option name that takes some argument. */ public boolean isWildcard() { return name.endsWith("."); } @Override public String toString() { return name; } public static OString string(String name) { return new OString(name,null); } public static OString string(String name, String defaultValue) { return new OString(name,defaultValue); } public static OBoolean bool(String name, boolean defaultValue) { return new OBoolean(name,defaultValue); } public static OFile file(String name) { return new OFile(name); } public static OClass clazz(String name, Class defaultValue) { return new OClass(name,defaultValue); } public static OInt integer(String name) { return new OInt(name,-1); } public static OInt integer(String name,int defaultValue) { return new OInt(name,defaultValue); } public static class OBoolean extends Option { public OBoolean(String name, boolean defaultValue) { super(name, Boolean.class, defaultValue); } public boolean get(Map args) { return get(args,defaultValue); } public boolean get(Map args, boolean defaultValue) { return WebAppConfiguration.booleanArg(args, name, defaultValue); } } public static class OInt extends Option { public OInt(String name, int defaultValue) { super(name, Integer.class, defaultValue); } public int get(Map args) { return WebAppConfiguration.intArg(args, name, defaultValue); } public int get(Map args, int defaultValue) { return WebAppConfiguration.intArg(args, name, defaultValue); } } public static class OString extends Option { public OString(String name, String defaultValue) { super(name, String.class, defaultValue); } public String get(Map args) { String v = (String)args.get(name); return v!=null ? v : defaultValue; } } public static class OFile extends Option { public OFile(String name) { super(name, File.class,null); } public File get(Map args, File defaultValue) { String v = (String)args.get(name); return v!=null ? new File(v) : defaultValue; } public File get(Map args) { return get(args,null); } } public static class OClass extends Option { public OClass(String name,Class defaultValue) { super(name, Class.class, defaultValue); } public Class get(Map args, Class expectedType) throws ClassNotFoundException { return get(args,expectedType,getClass().getClassLoader()); } public Class get(Map args, Class expectedType, ClassLoader cl) throws ClassNotFoundException { String v = (String)args.get(name); if (v==null) return defaultValue; v=v.trim(); if (v.length()==0) return defaultValue; Class c = Class.forName(v, true, cl); if (!expectedType.isAssignableFrom(c)) throw new ClassNotFoundException("Expected a subype of "+expectedType+" but got "+c+" instead"); return c.asSubclass(expectedType); } } // static { // String[] protocols = {"http","https","ajp13"}; // for (int i=0; i * Distributed under the terms of either: * - the common development and distribution license (CDDL), v1.0; or * - the GNU Lesser General Public License, v2.1 or later */ package winstone; import java.io.IOException; import java.util.Collections; import java.util.Enumeration; import java.util.Hashtable; import java.util.Map; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.UnavailableException; import org.w3c.dom.Node; /** * Corresponds to a filter object in the web app. Holds one instance only. * * @author Rick Knowles */ public class FilterConfiguration implements javax.servlet.FilterConfig { final String ELEM_NAME = "filter-name"; final String ELEM_DISPLAY_NAME = "display-name"; final String ELEM_CLASS = "filter-class"; final String ELEM_DESCRIPTION = "description"; final String ELEM_INIT_PARAM = "init-param"; final String ELEM_INIT_PARAM_NAME = "param-name"; final String ELEM_INIT_PARAM_VALUE = "param-value"; private String filterName; private String classFile; private Filter instance; private Map initParameters; private ServletContext context; private ClassLoader loader; private boolean unavailableException; private Object filterSemaphore = true; protected FilterConfiguration(ServletContext context, ClassLoader loader) { this.context = context; this.loader = loader; this.initParameters = new Hashtable(); } /** * Constructor */ public FilterConfiguration(ServletContext context, ClassLoader loader, Node elm) { this(context, loader); // Parse the web.xml file entry for (int n = 0; n < elm.getChildNodes().getLength(); n++) { Node child = elm.getChildNodes().item(n); if (child.getNodeType() != Node.ELEMENT_NODE) continue; String nodeName = child.getNodeName(); // Construct the servlet instances if (nodeName.equals(ELEM_NAME)) this.filterName = WebAppConfiguration.getTextFromNode(child); else if (nodeName.equals(ELEM_CLASS)) this.classFile = WebAppConfiguration.getTextFromNode(child); else if (nodeName.equals(ELEM_INIT_PARAM)) { String paramName = null; String paramValue = null; for (int k = 0; k < child.getChildNodes().getLength(); k++) { Node paramNode = child.getChildNodes().item(k); if (paramNode.getNodeType() != Node.ELEMENT_NODE) continue; else if (paramNode.getNodeName().equals( ELEM_INIT_PARAM_NAME)) paramName = WebAppConfiguration.getTextFromNode(paramNode); else if (paramNode.getNodeName().equals( ELEM_INIT_PARAM_VALUE)) paramValue = WebAppConfiguration.getTextFromNode(paramNode); } if ((paramName != null) && (paramValue != null)) this.initParameters.put(paramName, paramValue); } } Logger.log(Logger.FULL_DEBUG, Launcher.RESOURCES, "FilterConfiguration.DeployedInstance", this.filterName, this.classFile); } public String getFilterName() { return this.filterName; } public String getInitParameter(String paramName) { return (String) this.initParameters.get(paramName); } public Enumeration getInitParameterNames() { return Collections.enumeration(this.initParameters.keySet()); } public ServletContext getServletContext() { return this.context; } /** * Implements the first-time-init of an instance, and wraps it in a * dispatcher. */ public Filter getFilter() throws ServletException { synchronized (this.filterSemaphore) { if (isUnavailable()) throw new WinstoneException(Launcher.RESOURCES .getString("FilterConfiguration.FilterUnavailable")); else if (this.instance == null) try { ClassLoader cl = Thread.currentThread() .getContextClassLoader(); Thread.currentThread().setContextClassLoader(this.loader); Class filterClass = Class.forName(classFile, true, this.loader); this.instance = (Filter) filterClass.newInstance(); Logger.log(Logger.DEBUG, Launcher.RESOURCES, "FilterConfiguration.init", this.filterName); // Initialise with the correct classloader this.instance.init(this); Thread.currentThread().setContextClassLoader(cl); } catch (ClassNotFoundException err) { Logger.log(Logger.ERROR, Launcher.RESOURCES, "FilterConfiguration.ClassLoadError", this.classFile, err); } catch (IllegalAccessException err) { Logger.log(Logger.ERROR, Launcher.RESOURCES, "FilterConfiguration.ClassLoadError", this.classFile, err); } catch (InstantiationException err) { Logger.log(Logger.ERROR, Launcher.RESOURCES, "FilterConfiguration.ClassLoadError", this.classFile, err); } catch (ServletException err) { this.instance = null; if (err instanceof UnavailableException) setUnavailable(); throw err; // throw new WinstoneException(resources // .getString("FilterConfiguration.InitError"), err); } } return this.instance; } /** * Called when it's time for the container to shut this servlet down. */ public void destroy() { synchronized (this.filterSemaphore) { setUnavailable(); } } public String toString() { return Launcher.RESOURCES.getString("FilterConfiguration.Description", new String[] { this.filterName, this.classFile }); } public boolean isUnavailable() { return this.unavailableException; } protected void setUnavailable() { this.unavailableException = true; if (this.instance != null) { Logger.log(Logger.DEBUG, Launcher.RESOURCES, "FilterConfiguration.destroy", this.filterName); ClassLoader cl = Thread.currentThread().getContextClassLoader(); Thread.currentThread().setContextClassLoader(this.loader); this.instance.destroy(); Thread.currentThread().setContextClassLoader(cl); this.instance = null; } } public void execute(ServletRequest request, ServletResponse response, FilterChain chain) throws ServletException, IOException { ClassLoader cl = Thread.currentThread().getContextClassLoader(); Thread.currentThread().setContextClassLoader(this.loader); try { getFilter().doFilter(request, response, chain); } catch (UnavailableException err) { setUnavailable(); throw new ServletException(Launcher.RESOURCES .getString("RequestDispatcher.FilterError"), err); } finally { Thread.currentThread().setContextClassLoader(cl); } } } jenkins-winstone-0.9.10-jenkins-47/src/java/winstone/WinstoneResponseWriter.java0000644000175000017500000000556512200024521030411 0ustar jamespagejamespage/* * Copyright 2003-2006 Rick Knowles * Distributed under the terms of either: * - the common development and distribution license (CDDL), v1.0; or * - the GNU Lesser General Public License, v2.1 or later */ package winstone; import java.io.IOException; import java.io.OutputStreamWriter; import java.io.PrintWriter; import java.io.UnsupportedEncodingException; /** * A hacked print writer that allows us to trigger an automatic flush on * println operations that go over the content length or buffer size. * * This is only necessary because the spec authors seem intent of having * the print writer's flushing behaviour be half auto-flush and half not. * Damned if I know why - seems unnecessary and confusing to me. * * @author Rick Knowles * @version $Id: WinstoneResponseWriter.java,v 1.3 2006/02/28 07:32:47 rickknowles Exp $ */ public class WinstoneResponseWriter extends PrintWriter { private WinstoneOutputStream outputStream; private WinstoneResponse response; private int bytesBuffered; public WinstoneResponseWriter(WinstoneOutputStream out, WinstoneResponse response) throws UnsupportedEncodingException { super(new OutputStreamWriter(out, response.getCharacterEncoding()), false); this.outputStream = out; this.response = response; this.bytesBuffered = 0; } public void write(int c) { super.write(c); appendByteCount("" + ((char) c)); } public void write(char[] buf, int off, int len) { super.write(buf, off, len); if (buf != null) { appendByteCount(new String(buf, off, len)); } } public void write(String s, int off, int len) { super.write(s, off, len); if (s != null) { appendByteCount(s.substring(off, len)); } } protected void appendByteCount(String input) { try { this.bytesBuffered += input.getBytes(response.getCharacterEncoding()).length; } catch (IOException err) {/* impossible */} } public void println() { super.println(); simulateAutoFlush(); } public void flush() { super.flush(); this.bytesBuffered = 0; } protected void simulateAutoFlush() { String contentLengthHeader = response.getHeader(WinstoneResponse.CONTENT_LENGTH_HEADER); if ((contentLengthHeader != null) && ((this.outputStream.getOutputStreamLength() + this.bytesBuffered) >= Integer.parseInt(contentLengthHeader))) { Logger.log(Logger.FULL_DEBUG, Launcher.RESOURCES, "WinstoneResponseWriter.AutoFlush", contentLengthHeader, (this.outputStream.getOutputStreamLength() + this.bytesBuffered) + ""); flush(); } } } jenkins-winstone-0.9.10-jenkins-47/src/java/winstone/Listener.java0000644000175000017500000000617112200024521025446 0ustar jamespagejamespage/* * Copyright 2003-2006 Rick Knowles * Distributed under the terms of either: * - the common development and distribution license (CDDL), v1.0; or * - the GNU Lesser General Public License, v2.1 or later */ package winstone; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.Socket; /** * Interface that defines the necessary methods for being a connection listener * within winstone. * * @author Rick Knowles */ public interface Listener { /** * Interrupts the listener thread. This will trigger a listener shutdown * once the so timeout has passed. */ public void destroy(); /** * After the listener is loaded and initialized, this starts the thread */ public boolean start() throws IOException; /** * Called by the request handler thread, because it needs specific setup * code for this connection's protocol (ie construction of request/response * objects, in/out streams, etc). The iAmFirst variable identifies whether or * not this is the initial request on on this socket (ie a keep alive or * a first-time accept) */ public void allocateRequestResponse(Socket socket, InputStream inSocket, OutputStream outSocket, RequestHandlerThread handler, boolean iAmFirst) throws IOException; /** * Called by the request handler thread, because it needs specific shutdown * code for this connection's protocol (ie releasing input/output streams, * etc). */ public void deallocateRequestResponse(RequestHandlerThread handler, WinstoneRequest req, WinstoneResponse rsp, WinstoneInputStream inData, WinstoneOutputStream outData) ; /** * Called by the request handler thread, because it needs specific shutdown * code for this connection's protocol if the keep-alive period expires (ie * closing sockets, etc).The iAmFirst variable identifies whether or * not this is the initial request on on this socket (ie a keep alive or * a first-time accept) */ public String parseURI(RequestHandlerThread handler, WinstoneRequest req, WinstoneResponse rsp, WinstoneInputStream inData, Socket socket, boolean iAmFirst) throws IOException; /** * Called by the request handler thread, because it needs specific shutdown * code for this connection's protocol if the keep-alive period expires (ie * closing sockets, etc). */ public void releaseSocket(Socket socket, InputStream inSocket, OutputStream outSocket) throws IOException; /** * Tries to wait for extra requests on the same socket. If any are found * before the timeout expires, it exits with a true, indicating a new * request is waiting. If the timeout expires, return a false, instructing * the handler thread to begin shutting down the socket and relase itself. */ public boolean processKeepAlive(WinstoneRequest request, WinstoneResponse response, InputStream inSocket) ; } jenkins-winstone-0.9.10-jenkins-47/src/java/winstone/SizeRestrictedHashMap.java0000644000175000017500000000162612200024521030066 0ustar jamespagejamespagepackage winstone; import java.util.Hashtable; import java.util.Map; /** * @see SizeRestrictedHashtable * @author Kohsuke Kawaguchi */ public class SizeRestrictedHashMap extends Hashtable { private final int cap; public SizeRestrictedHashMap(int initialCapacity, float loadFactor, int cap) { super(initialCapacity, loadFactor); this.cap = cap; } public SizeRestrictedHashMap(int initialCapacity, int cap) { super(initialCapacity); this.cap = cap; } public SizeRestrictedHashMap(int cap) { this.cap = cap; } public SizeRestrictedHashMap(Map t, int cap) { super(t); this.cap = cap; } @Override public V put(K key, V value) { if (size()>cap) throw new IllegalStateException("Hash table size limit exceeded"); return super.put(key, value); } } jenkins-winstone-0.9.10-jenkins-47/src/java/winstone/URIUtil.java0000644000175000017500000000461312200024521025155 0ustar jamespagejamespagepackage winstone; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.regex.Pattern; /** * @author Kohsuke Kawaguchi */ public class URIUtil { /** * Eliminates "." and ".." in the path. * So that this method can be used for any string that looks like an URI, * this method preserves the leading and trailing '/'. */ static String canonicalPath(String path) { List r = new ArrayList(Arrays.asList(path.split("[/\\\\]+"))); for (int i=0; i0) { r.remove(i-1); i--; } } else { i++; } } StringBuilder buf = new StringBuilder(); if (path.startsWith("/")) buf.append('/'); boolean first = true; for (Object aR : r) { String token = (String) aR; if (!first) buf.append('/'); else first = false; buf.append(token); } // translation: if (path.endsWith("/") && !buf.endsWith("/")) if (path.endsWith("/") && (buf.length()==0 || buf.charAt(buf.length()-1)!='/')) buf.append('/'); return buf.toString(); } /** * Performs necessary escaping to render arbitrary plain text as plain text without any markup. */ public static String htmlEscape(String text) { StringBuilder buf = new StringBuilder(text.length()+64); for( int i=0; i * Distributed under the terms of either: * - the common development and distribution license (CDDL), v1.0; or * - the GNU Lesser General Public License, v2.1 or later */ package winstone.accesslog; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; import java.io.PrintWriter; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.Date; import java.util.Map; import winstone.AccessLogger; import winstone.Logger; import winstone.cmdline.Option; import winstone.WebAppConfiguration; import winstone.WinstoneRequest; import winstone.WinstoneResourceBundle; import winstone.WinstoneResponse; /** * Simulates an apache "combined" style logger, which logs User-Agent, Referer, etc * * @author Rick Knowles * @version $Id: SimpleAccessLogger.java,v 1.5 2006/03/24 17:24:19 rickknowles Exp $ */ public class SimpleAccessLogger implements AccessLogger { public static final WinstoneResourceBundle ACCESSLOG_RESOURCES = new WinstoneResourceBundle("winstone.accesslog.LocalStrings"); private static final DateFormat DF = new SimpleDateFormat("dd/MMM/yyyy:HH:mm:ss Z"); private static final String COMMON = "###ip### - ###user### ###time### \"###uriLine###\" ###status### ###size###"; private static final String COMBINED = COMMON + " \"###referer###\" \"###userAgent###\""; private static final String RESIN = COMMON + " \"###userAgent###\""; // private WebAppConfiguration webAppConfig; private OutputStream outStream; private PrintWriter outWriter; private String pattern; private String fileName; public SimpleAccessLogger(WebAppConfiguration webAppConfig, Map startupArgs) throws IOException { // this.webAppConfig = webAppConfig; // Get pattern String patternType = Option.SIMPLE_ACCESS_LOGGER_FORMAT.get(startupArgs); if (patternType.equalsIgnoreCase("combined")) { this.pattern = COMBINED; } else if (patternType.equalsIgnoreCase("common")) { this.pattern = COMMON; } else if (patternType.equalsIgnoreCase("resin")) { this.pattern = RESIN; } else { this.pattern = patternType; } // Get filename String filePattern = Option.SIMPLE_ACCESS_LOGGER_FILE.get(startupArgs); this.fileName = WinstoneResourceBundle.globalReplace(filePattern, new String [][] {{"###host###", webAppConfig.getOwnerHostname()}, {"###webapp###", webAppConfig.getContextName()}}); File file = new File(this.fileName); file.getParentFile().mkdirs(); this.outStream = new FileOutputStream(file, true); this.outWriter = new PrintWriter(this.outStream, true); Logger.log(Logger.DEBUG, ACCESSLOG_RESOURCES, "SimpleAccessLogger.Init", this.fileName, patternType); } public void log(String originalURL, WinstoneRequest request, WinstoneResponse response) { String uriLine = request.getMethod() + " " + originalURL + " " + request.getProtocol(); int status = response.getErrorStatusCode() == null ? response.getStatus() : response.getErrorStatusCode(); long size = response.getWinstoneOutputStream().getBytesCommitted(); String date; synchronized (DF) { date = DF.format(new Date()); } String logLine = WinstoneResourceBundle.globalReplace(this.pattern, new String[][] { {"###ip###", request.getRemoteHost()}, {"###user###", nvl(request.getRemoteUser())}, {"###time###", "[" + date + "]"}, {"###uriLine###", uriLine}, {"###status###", "" + status}, {"###size###", "" + size}, {"###referer###", nvl(request.getHeader("Referer"))}, {"###userAgent###", nvl(request.getHeader("User-Agent"))} }); this.outWriter.println(logLine); } private static String nvl(String input) { return input == null ? "-" : input; } public void destroy() { Logger.log(Logger.DEBUG, ACCESSLOG_RESOURCES, "SimpleAccessLogger.Close", this.fileName); if (this.outWriter != null) { this.outWriter.flush(); this.outWriter.close(); this.outWriter = null; } if (this.outStream != null) { try { this.outStream.close(); } catch (IOException err) {} this.outStream = null; } this.fileName = null; // this.webAppConfig = null; } } jenkins-winstone-0.9.10-jenkins-47/src/java/winstone/accesslog/LocalStrings.properties0000644000175000017500000000017012200024521031474 0ustar jamespagejamespageSimpleAccessLogger.Init=Initialized access log at [#0] (format: [#1]) SimpleAccessLogger.Close=Closed access log at [#0]jenkins-winstone-0.9.10-jenkins-47/src/java/winstone/ShutdownHook.java0000644000175000017500000000156512200024521026317 0ustar jamespagejamespage/* * Copyright 2003-2006 Rick Knowles * Distributed under the terms of either: * - the common development and distribution license (CDDL), v1.0; or * - the GNU Lesser General Public License, v2.1 or later */ package winstone; /** * A jvm hook to force the calling of the web-app destroy before the process terminates * * @author Rick Knowles * @version $Id: ShutdownHook.java,v 1.3 2006/02/28 07:32:47 rickknowles Exp $ */ public class ShutdownHook extends Thread { private Launcher launcher; public ShutdownHook(Launcher launcher) { this.launcher = launcher; } public void run() { if (this.launcher != null) { Logger.log(Logger.INFO, Launcher.RESOURCES, "ShutdownHook.Initiating"); this.launcher.shutdown(); } } } jenkins-winstone-0.9.10-jenkins-47/src/java/winstone/WinstoneResponse.java0000644000175000017500000007416412200024521027215 0ustar jamespagejamespage/* * Copyright 2003-2006 Rick Knowles * Distributed under the terms of either: * - the common development and distribution license (CDDL), v1.0; or * - the GNU Lesser General Public License, v2.1 or later */ package winstone; import javax.servlet.ServletOutputStream; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.io.PrintWriter; import java.io.UnsupportedEncodingException; import java.io.Writer; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.*; /** * Response for servlet * * @author Rick Knowles * @version $Id: WinstoneResponse.java,v 1.28 2005/04/19 07:33:41 rickknowles * Exp $ */ public class WinstoneResponse implements HttpServletResponse { private static final DateFormat HTTP_DF = new SimpleDateFormat( "EEE, dd MMM yyyy HH:mm:ss z", Locale.US); private static final DateFormat VERSION0_DF = new SimpleDateFormat( "EEE, dd-MMM-yyyy HH:mm:ss z", Locale.US); static { HTTP_DF.setTimeZone(TimeZone.getTimeZone("GMT")); VERSION0_DF.setTimeZone(TimeZone.getTimeZone("GMT")); } static final String CONTENT_LENGTH_HEADER = "Content-Length"; static final String CONTENT_TYPE_HEADER = "Content-Type"; // Response header constants private static final String CONTENT_LANGUAGE_HEADER = "Content-Language"; private static final String KEEP_ALIVE_HEADER = "Connection"; private static final String KEEP_ALIVE_OPEN = "Keep-Alive"; private static final String KEEP_ALIVE_CLOSE = "Close"; private static final String DATE_HEADER = "Date"; private static final String LOCATION_HEADER = "Location"; private static final String OUT_COOKIE_HEADER1 = "Set-Cookie"; private static final String X_POWERED_BY_HEADER = "X-Powered-By"; private static final String X_POWERED_BY_HEADER_VALUE = Launcher.RESOURCES.getString("PoweredByHeader"); private int statusCode; private WinstoneRequest req; private WebAppConfiguration webAppConfig; private WinstoneOutputStream outputStream; private PrintWriter outputWriter; private List headers; private String explicitEncoding; private String implicitEncoding; private List cookies; /** * Of {@link #cookies}, ones that should be marked as "HttpOnly". * See http://en.wikipedia.org/wiki/HTTP_cookie#HttpOnly_cookie */ private Set httpOnlyCookies; private Locale locale; private String protocol; private String reqKeepAliveHeader; private Integer errorStatusCode; /** * Constructor */ public WinstoneResponse() { this.headers = new ArrayList(); this.cookies = new ArrayList(); this.httpOnlyCookies = new HashSet(); this.statusCode = SC_OK; this.locale = null; //Locale.getDefault(); this.explicitEncoding = null; this.protocol = null; this.reqKeepAliveHeader = null; } /** * Resets the request to be reused */ public void cleanUp() { this.req = null; this.webAppConfig = null; this.outputStream = null; this.outputWriter = null; this.headers.clear(); this.cookies.clear(); this.httpOnlyCookies.clear(); this.protocol = null; this.reqKeepAliveHeader = null; this.statusCode = SC_OK; this.errorStatusCode = null; this.locale = null; //Locale.getDefault(); this.explicitEncoding = null; this.implicitEncoding = null; } private String getEncodingFromLocale(Locale loc) { String localeString = loc.getLanguage() + "_" + loc.getCountry(); Map encMap = this.webAppConfig.getLocaleEncodingMap(); Logger.log(Logger.FULL_DEBUG, Launcher.RESOURCES, "WinstoneResponse.LookForLocaleEncoding", localeString, encMap + ""); String fullMatch = (String) encMap.get(localeString); if (fullMatch != null) { Logger.log(Logger.FULL_DEBUG, Launcher.RESOURCES, "WinstoneResponse.FoundLocaleEncoding", fullMatch); return fullMatch; } else { localeString = loc.getLanguage(); Logger.log(Logger.FULL_DEBUG, Launcher.RESOURCES, "WinstoneResponse.LookForLocaleEncoding", localeString, encMap + ""); String match = (String) encMap.get(localeString); if (match != null) { Logger.log(Logger.FULL_DEBUG, Launcher.RESOURCES, "WinstoneResponse.FoundLocaleEncoding", match); } return match; } } public void setErrorStatusCode(int statusCode) { this.errorStatusCode = statusCode; this.statusCode = statusCode; } public WinstoneOutputStream getWinstoneOutputStream() { return this.outputStream; } public void setOutputStream(WinstoneOutputStream outData) { this.outputStream = outData; } public void setWebAppConfig(WebAppConfiguration webAppConfig) { this.webAppConfig = webAppConfig; } public String getProtocol() { return this.protocol; } public void setProtocol(String protocol) { this.protocol = protocol; } public void extractRequestKeepAliveHeader(WinstoneRequest req) { this.reqKeepAliveHeader = req.getHeader(KEEP_ALIVE_HEADER); } public List getHeaders() { return this.headers; } public List getCookies() { return this.cookies; } public WinstoneRequest getRequest() { return this.req; } public void setRequest(WinstoneRequest req) { this.req = req; } public void startIncludeBuffer() { this.outputStream.startIncludeBuffer(); } public void finishIncludeBuffer() throws IOException { if (isIncluding()) { if (this.outputWriter != null) { this.outputWriter.flush(); } this.outputStream.finishIncludeBuffer(); } } public void clearIncludeStackForForward() throws IOException { this.outputStream.clearIncludeStackForForward(); } protected static String getCharsetFromContentTypeHeader(String type, StringBuffer remainder) { if (type == null) { return null; } // Parse type to set encoding if needed StringTokenizer st = new StringTokenizer(type, ";"); String localEncoding = null; while (st.hasMoreTokens()) { String clause = st.nextToken().trim(); if (clause.startsWith("charset=")) localEncoding = clause.substring(8); else { if (remainder.length() > 0) { remainder.append(";"); } remainder.append(clause); } } if ((localEncoding == null) || !localEncoding.startsWith("\"") || !localEncoding.endsWith("\"")) { return localEncoding; } else { return localEncoding.substring(1, localEncoding.length() - 1); } } /** * This ensures the bare minimum correct http headers are present */ public void validateHeaders() { // Need this block for WebDAV support. "Connection:close" header is ignored String lengthHeader = getHeader(CONTENT_LENGTH_HEADER); if ((lengthHeader == null) && (this.statusCode >= 300)) { long bodyBytes = this.outputStream.getOutputStreamLength(); if (getBufferSize() > bodyBytes) { Logger.log(Logger.FULL_DEBUG, Launcher.RESOURCES, "WinstoneResponse.ForcingContentLength", "" + bodyBytes); forceHeader(CONTENT_LENGTH_HEADER, "" + bodyBytes); lengthHeader = getHeader(CONTENT_LENGTH_HEADER); } } forceHeader(KEEP_ALIVE_HEADER, !closeAfterRequest() ? KEEP_ALIVE_OPEN : KEEP_ALIVE_CLOSE); String contentType = getHeader(CONTENT_TYPE_HEADER); if (this.statusCode != SC_MOVED_TEMPORARILY && this.statusCode != SC_NOT_MODIFIED) { if (contentType == null) { // Bypass normal encoding forceHeader(CONTENT_TYPE_HEADER, "text/html;charset=" + getCharacterEncoding()); } else if (contentType.startsWith("text/")) { // replace charset in content StringBuffer remainder = new StringBuffer(); getCharsetFromContentTypeHeader(contentType, remainder); forceHeader(CONTENT_TYPE_HEADER, remainder.toString() + ";charset=" + getCharacterEncoding()); } } if (getHeader(DATE_HEADER) == null) { forceHeader(DATE_HEADER, formatHeaderDate(new Date())); } if (getHeader(X_POWERED_BY_HEADER) == null) { forceHeader(X_POWERED_BY_HEADER, X_POWERED_BY_HEADER_VALUE); } if (this.locale != null) { String lang = this.locale.getLanguage(); if ((this.locale.getCountry() != null) && !this.locale.getCountry().equals("")) { lang = lang + "-" + this.locale.getCountry(); } forceHeader(CONTENT_LANGUAGE_HEADER, lang); } // If we don't have a webappConfig, exit here, cause we definitely don't // have a session if (req.getWebAppConfig() == null) { return; } // Write out the new session cookie if it's present HostConfiguration hostConfig = req.getHostGroup().getHostByName(req.getServerName()); for (Object o1 : req.getCurrentSessionIds().keySet()) { String prefix = (String) o1; String sessionId = (String) req.getCurrentSessionIds().get(prefix); WebAppConfiguration ownerContext = hostConfig.getWebAppByURI(prefix); if (ownerContext != null) { WinstoneSession session = ownerContext.getSessionById(sessionId, true); if ((session != null) && session.isNew()) { session.setIsNew(false); Cookie cookie = new Cookie(WinstoneSession.SESSION_COOKIE_NAME, session.getId()); cookie.setMaxAge(-1); cookie.setSecure(req.isSecure()); cookie.setVersion(0); //req.isSecure() ? 1 : 0); cookie.setPath(req.getWebAppConfig().getContextPath().equals("") ? "/" : req.getWebAppConfig().getContextPath()); this.cookies.add(cookie); // don't call addCookie because we might be including this.httpOnlyCookies.add(cookie); } } } // Look for expired sessions: ie ones where the requested and current ids are different for (Object o : req.getRequestedSessionIds().keySet()) { String prefix = (String) o; String sessionId = (String) req.getRequestedSessionIds().get(prefix); if (!req.getCurrentSessionIds().containsKey(prefix)) { Cookie cookie = new Cookie(WinstoneSession.SESSION_COOKIE_NAME, sessionId); cookie.setMaxAge(0); // explicitly expire this cookie cookie.setSecure(req.isSecure()); cookie.setVersion(0); //req.isSecure() ? 1 : 0); cookie.setPath(prefix.equals("") ? "/" : prefix); this.cookies.add(cookie); // don't call addCookie because we might be including this.httpOnlyCookies.add(cookie); } } Logger.log(Logger.FULL_DEBUG, Launcher.RESOURCES, "WinstoneResponse.HeadersPreCommit", this.headers + ""); } /** * Writes out the http header for a single cookie */ public String writeCookie(Cookie cookie) { Logger.log(Logger.FULL_DEBUG, Launcher.RESOURCES, "WinstoneResponse.WritingCookie", cookie + ""); StringBuffer out = new StringBuffer(); // Set-Cookie or Set-Cookie2 if (cookie.getVersion() >= 1) out.append(OUT_COOKIE_HEADER1).append(": "); // TCK doesn't like set-cookie2 else out.append(OUT_COOKIE_HEADER1).append(": "); // name/value pair if (cookie.getVersion() == 0) out.append(cookie.getName()).append("=").append(cookie.getValue()); else { out.append(cookie.getName()).append("="); quote(cookie.getValue(), out); } if (cookie.getVersion() >= 1) { out.append("; Version=1"); if (cookie.getDomain() != null) { out.append("; Domain="); quote(cookie.getDomain(), out); } if (cookie.getSecure()) out.append("; Secure"); if (cookie.getMaxAge() >= 0) out.append("; Max-Age=").append(cookie.getMaxAge()); else out.append("; Discard"); if (cookie.getPath() != null) { out.append("; Path="); quote(cookie.getPath(), out); } } else { if (cookie.getDomain() != null) { out.append("; Domain="); out.append(cookie.getDomain()); } if (cookie.getMaxAge() > 0) { long expiryMS = System.currentTimeMillis() + (1000 * (long) cookie.getMaxAge()); String expiryDate; synchronized (VERSION0_DF) { expiryDate = VERSION0_DF.format(new Date(expiryMS)); } out.append("; Expires=").append(expiryDate); } else if (cookie.getMaxAge() == 0) { String expiryDate; synchronized (VERSION0_DF) { expiryDate = VERSION0_DF.format(new Date(5000)); } out.append("; Expires=").append(expiryDate); } if (cookie.getPath() != null) out.append("; Path=").append(cookie.getPath()); if (cookie.getSecure()) out.append("; Secure"); } if (httpOnlyCookies.contains(cookie)) out.append("; HttpOnly"); return out.toString(); } private static String formatHeaderDate(Date dateIn) { String date; synchronized (HTTP_DF) { date = HTTP_DF.format(dateIn); } return date; } /** * Quotes the necessary strings in a cookie header. The quoting is only * applied if the string contains special characters. */ protected static void quote(String value, StringBuffer out) { if (value.startsWith("\"") && value.endsWith("\"")) { out.append(value); } else { boolean containsSpecial = false; for (int n = 0; n < value.length(); n++) { char thisChar = value.charAt(n); if ((thisChar < 32) || (thisChar >= 127) || (specialCharacters.indexOf(thisChar) != -1)) { containsSpecial = true; break; } } if (containsSpecial) out.append('"').append(value).append('"'); else out.append(value); } } private static final String specialCharacters = "()<>@,;:\\\"/[]?={} \t"; /** * Based on request/response headers and the protocol, determine whether or * not this connection should operate in keep-alive mode. */ public boolean closeAfterRequest() { String inKeepAliveHeader = this.reqKeepAliveHeader; String outKeepAliveHeader = getHeader(KEEP_ALIVE_HEADER); boolean hasContentLength = (getHeader(CONTENT_LENGTH_HEADER) != null); if (this.protocol.startsWith("HTTP/0")) return true; else if ((inKeepAliveHeader == null) && (outKeepAliveHeader == null)) return this.protocol.equals("HTTP/1.0") ? true : !hasContentLength; else if (outKeepAliveHeader != null) return outKeepAliveHeader.equalsIgnoreCase(KEEP_ALIVE_CLOSE) || !hasContentLength; else if (inKeepAliveHeader != null) return inKeepAliveHeader.equalsIgnoreCase(KEEP_ALIVE_CLOSE) || !hasContentLength; else return false; } // ServletResponse interface methods public void flushBuffer() throws IOException { if (this.outputWriter != null) { this.outputWriter.flush(); } try { this.outputStream.flush(); } catch (ClientSocketException e) { // ignore this error as it's not interesting enough to log } } public void setBufferSize(int size) { this.outputStream.setBufferSize(size); } public int getBufferSize() { return (int)this.outputStream.getBufferSize(); } public String getCharacterEncoding() { String enc = getCurrentEncoding(); return (enc == null ? "ISO-8859-1" : enc); } public void setCharacterEncoding(String encoding) { if ((this.outputWriter == null) && !isCommitted()) { Logger.log(Logger.FULL_DEBUG, Launcher.RESOURCES, "WinstoneResponse.SettingEncoding", encoding); this.explicitEncoding = encoding; correctContentTypeHeaderEncoding(encoding); } } private void correctContentTypeHeaderEncoding(String encoding) { String contentType = getContentType(); if (contentType != null) { StringBuffer remainderHeader = new StringBuffer(); getCharsetFromContentTypeHeader(contentType, remainderHeader); if (remainderHeader.length() != 0) { forceHeader(CONTENT_TYPE_HEADER, remainderHeader + ";charset=" + encoding); } } } public String getContentType() { return getHeader(CONTENT_TYPE_HEADER); } public void setContentType(String type) { setHeader(CONTENT_TYPE_HEADER, type); } public Locale getLocale() { return this.locale == null ? Locale.getDefault() : this.locale; } private boolean isIncluding() { return this.outputStream.isIncluding(); } public void setLocale(Locale loc) { if (isIncluding()) { return; } else if (isCommitted()) { Logger.log(Logger.WARNING, Launcher.RESOURCES, "WinstoneResponse.SetLocaleTooLate"); } else { if ((this.outputWriter == null) && (this.explicitEncoding == null)) { String localeEncoding = getEncodingFromLocale(loc); if (localeEncoding != null) { this.implicitEncoding = localeEncoding; correctContentTypeHeaderEncoding(localeEncoding); } } this.locale = loc; } } public ServletOutputStream getOutputStream() throws IOException { Logger.log(Logger.FULL_DEBUG, Launcher.RESOURCES, "WinstoneResponse.GetOutputStream"); return this.outputStream; } public PrintWriter getWriter() throws IOException { Logger.log(Logger.FULL_DEBUG, Launcher.RESOURCES, "WinstoneResponse.GetWriter"); if (this.outputWriter != null) return this.outputWriter; else { this.outputWriter = new WinstoneResponseWriter(this.outputStream, this); return this.outputWriter; } } public boolean isCommitted() { return this.outputStream.isCommitted(); } public void reset() { if (!isIncluding()) { resetBuffer(); this.statusCode = SC_OK; this.headers.clear(); this.cookies.clear(); this.httpOnlyCookies.clear(); } } public void resetBuffer() { if (!isIncluding()) { if (isCommitted()) throw new IllegalStateException(Launcher.RESOURCES .getString("WinstoneResponse.ResponseCommitted")); // Disregard any output temporarily while we flush this.outputStream.setDisregardMode(true); if (this.outputWriter != null) { this.outputWriter.flush(); } this.outputStream.setDisregardMode(false); this.outputStream.reset(); } } public void setContentLength(int len) { setIntHeader(CONTENT_LENGTH_HEADER, len); } // HttpServletResponse interface methods public void addCookie(Cookie cookie) { if (!isIncluding()) { this.cookies.add(cookie); } } public boolean containsHeader(String name) { for (String header : this.headers) if (header.startsWith(name)) return true; return false; } public void addDateHeader(String name, long date) { addHeader(name, formatHeaderDate(new Date(date))); } // df.format(new Date(date)));} public void addIntHeader(String name, int value) { addHeader(name, "" + value); } public void addHeader(String name, String value) { if (isIncluding()) { Logger.log(Logger.DEBUG, Launcher.RESOURCES, "WinstoneResponse.HeaderInInclude", name, value); } else if (isCommitted()) { Logger.log(Logger.DEBUG, Launcher.RESOURCES, "WinstoneResponse.HeaderAfterCommitted", name, value); } else if (value != null) { if (name.equals(CONTENT_TYPE_HEADER)) { StringBuffer remainderHeader = new StringBuffer(); String headerEncoding = getCharsetFromContentTypeHeader(value, remainderHeader); if (this.outputWriter != null) { value = remainderHeader + ";charset=" + getCharacterEncoding(); } else if (headerEncoding != null) { this.explicitEncoding = headerEncoding; } } this.headers.add(name + ": " + value); } } public void setDateHeader(String name, long date) { setHeader(name, formatHeaderDate(new Date(date))); } public void setIntHeader(String name, int value) { setHeader(name, "" + value); } public void setHeader(String name, String value) { if (isIncluding()) { Logger.log(Logger.DEBUG, Launcher.RESOURCES, "WinstoneResponse.HeaderInInclude", name, value); } else if (isCommitted()) { Logger.log(Logger.DEBUG, Launcher.RESOURCES, "WinstoneResponse.HeaderAfterCommitted", name, value); } else { boolean found = false; for (int n = 0; (n < this.headers.size()); n++) { String header = this.headers.get(n); if (header.startsWith(name + ": ")) { if (found) { this.headers.remove(n); continue; } if (name.equals(CONTENT_TYPE_HEADER)) { if (value != null) { StringBuffer remainderHeader = new StringBuffer(); String headerEncoding = getCharsetFromContentTypeHeader( value, remainderHeader); if (this.outputWriter != null) { value = remainderHeader + ";charset=" + getCharacterEncoding(); } else if (headerEncoding != null) { this.explicitEncoding = headerEncoding; } } } if (value != null) { this.headers.set(n, name + ": " + value); } else { this.headers.remove(n); } found = true; } } if (!found) { addHeader(name, value); } } } private void forceHeader(String name, String value) { boolean found = false; for (int n = 0; (n < this.headers.size()); n++) { String header = this.headers.get(n); if (header.startsWith(name + ": ")) { found = true; this.headers.set(n, name + ": " + value); } } if (!found) { this.headers.add(name + ": " + value); } } private String getCurrentEncoding() { if (this.explicitEncoding != null) { return this.explicitEncoding; } else if (this.implicitEncoding != null) { return this.implicitEncoding; } else if ((this.req != null) && (this.req.getCharacterEncoding() != null)) { try { "0".getBytes(this.req.getCharacterEncoding()); return this.req.getCharacterEncoding(); } catch (UnsupportedEncodingException err) { return null; } } else { return null; } } public String getHeader(String name) { for (Object header1 : this.headers) { String header = (String) header1; if (header.startsWith(name + ": ")) return header.substring(name.length() + 2); } return null; } public String encodeRedirectURL(String url) { return url; } public String encodeURL(String url) { return url; } public int getStatus() { return this.statusCode; } public Integer getErrorStatusCode() { return this.errorStatusCode; } public void setStatus(int sc) { if (!isIncluding() && (this.errorStatusCode == null)) { // if (!isIncluding()) { this.statusCode = sc; // if (this.errorStatusCode != null) { // this.errorStatusCode = new Integer(sc); // } } } public void sendRedirect(String location) throws IOException { if (isIncluding()) { Logger.log(Logger.ERROR, Launcher.RESOURCES, "IncludeResponse.Redirect", location); return; } else if (isCommitted()) { throw new IllegalStateException(Launcher.RESOURCES.getString("WinstoneOutputStream.AlreadyCommitted")); } resetBuffer(); // Build location StringBuilder fullLocation = new StringBuilder(); if (location.startsWith("http://") || location.startsWith("https://")) { fullLocation.append(location); } else { if (location.trim().equals(".")) { location = ""; } fullLocation.append(this.req.getScheme()).append("://"); fullLocation.append(this.req.getServerName()); if (!((this.req.getServerPort() == 80) && this.req.getScheme().equals("http")) && !((this.req.getServerPort() == 443) && this.req.getScheme().equals("https"))) fullLocation.append(':').append(this.req.getServerPort()); if (location.startsWith("/")) { fullLocation.append(location); } else { fullLocation.append(this.req.getRequestURI()); int questionPos = fullLocation.toString().indexOf("?"); if (questionPos != -1) { fullLocation.delete(questionPos, fullLocation.length()); } fullLocation.delete( fullLocation.toString().lastIndexOf("/") + 1, fullLocation.length()); fullLocation.append(location); } } if (this.req != null) { this.req.discardRequestBody(); } this.statusCode = HttpServletResponse.SC_MOVED_TEMPORARILY; setHeader(LOCATION_HEADER, fullLocation.toString()); setContentLength(0); getWriter().flush(); } public void sendError(int sc) throws IOException { sendError(sc, null); } public void sendError(int sc, String msg) throws IOException { if (isIncluding()) { Logger.log(Logger.ERROR, Launcher.RESOURCES, "IncludeResponse.Error", "" + sc, msg); return; } Logger.log(Logger.DEBUG, Launcher.RESOURCES, "WinstoneResponse.SendingError", "" + sc, msg); if ((this.webAppConfig != null) && (this.req != null)) { RequestDispatcher rd = this.webAppConfig .getErrorDispatcherByCode(req.getRequestURI(), sc, msg, null); if (rd != null) { try { rd.forward(this.req, this); return; } catch (IllegalStateException err) { throw err; } catch (IOException err) { throw err; } catch (Throwable err) { Logger.log(Logger.WARNING, Launcher.RESOURCES, "WinstoneResponse.ErrorInErrorPage", new String[] { rd.getName(), sc + "" }, err); return; } } } // If we are here there was no webapp and/or no request object, so // show the default error page if (this.errorStatusCode == null) { this.statusCode = sc; } String output = Launcher.RESOURCES.getString("WinstoneResponse.ErrorPage", new String[] { sc + "", URIUtil.htmlEscape(msg == null ? "" : msg), "", Launcher.RESOURCES.getString("ServerVersion"), "" + new Date() }); setContentLength(output.getBytes(getCharacterEncoding()).length); Writer out = getWriter(); out.write(output); out.flush(); } /** * @deprecated */ public String encodeRedirectUrl(String url) { return encodeRedirectURL(url); } /** * @deprecated */ public String encodeUrl(String url) { return encodeURL(url); } /** * @deprecated */ public void setStatus(int sc, String sm) { setStatus(sc); } } jenkins-winstone-0.9.10-jenkins-47/src/java/winstone/LocalStrings.properties0000644000175000017500000007501712200024521027545 0ustar jamespagejamespageServerVersion=Winstone Servlet Engine v0.9.10 PoweredByHeader=Servlet/2.5 (Winstone/0.9.10) # WebAppConfig messages WebAppConfig.InvalidMimeMapping=WebAppConfig: Ignoring invalid mime mapping: extension=[#0] mimeType=[#1] WebAppConfig.InvalidInitParam=WebAppConfig: Ignoring invalid init parameter: name=[#0] value=[#1] WebAppConfig.URLMatch=URL Match - path: [#0] WebAppConfig.BadResourcePath=Bad resource path: path=[#0] WebAppConfig.ErrorOpeningStream=Error opening resource stream WebAppConfig.InvalidListener=Error instantiating listener class: [#0] WebAppConfig.AddListener=Adding web application listener: [#0] WebAppConfig.AuthError=Authentication disabled - couldn't load authentication handler: [#0] or realm: [#1] WebAppConfig.AuthDisabled=Authentication disabled - can't load authentication handler for [#0] authentication WebAppConfig.JNDIDisabled=JNDI disabled at webapp level - can't find JNDI Manager class WebAppConfig.JNDIError=JNDI disabled at webapp level - couldn't load JNDI Manager: [#0] WebAppConfig.ExceptionNotFound=Exception [#0] not found in classpath WebAppConfig.NullRD=ERROR: Null request handler for initial dispatch WebAppConfig.CheckWelcomeFile=Beginning welcome file match for path: [#0] WebAppConfig.FoundNonSlashDirectory=Detected directory with no trailing slash (path=[#0]) - redirecting WebAppConfig.ContextStartupError=Error during context startup for webapp [#0] WebAppConfig.ShutdownError=Error during servlet context shutdown WebAppConfig.ErrorDuringStartup=The error below occurred during context initialisation, so no further requests can be \ processed:

[#0]
WebAppConfig.InvalidURI=URI must start with a slash: [#0] WebAppConfig.EncodingMap=en_US=8859_1;en=8859_1;ja=SJIS WebAppConfig.CLError=Erroring setting class loader WebAppConfig.InvalidMount=WebAppConfig: Invalid pattern mount for [#0] pattern [#1] - ignoring WebAppConfig.ErrorMapURL=Error processing URL mapping: [#0] WebAppConfig.MatchedNonExistServlet=Matched URL to a servlet that doesn't exist: [#0] WebAppConfig.JasperNotFound=WARNING: Jasper servlet not found - disabling JSP support. Do you have all \ the jasper libraries in the common lib folder (see --commonLibFolder setting) ? WebAppConfig.JasperLoadException=Error loading Jasper JSP compilation servlet WebAppConfig.InvokerNotFound=WARNING: Invoker servlet not found - disabling invoker support. WebAppConfig.ClusterOffNotDistributable=Clustering disabled for webapp [#0] - the web application must be distributable WebAppConfig.ErrorGettingNamedDispatcher=Error getting a named dispatcher: [#0] WebAppConfig.ErrorGettingDispatcher=Error getting a dispatcher for URI: [#0] WebAppConfig.ServletStartupError=Error during servlet initialization: [#0] WebAppConfig.FilterStartupError=Error during filter initialization: [#0] WebAppConfig.NoErrorServlet=No error servlet available: status code [#0] WebAppConfig.WebInfClassLoader=Using Webapp classloader: [#0] WebAppConfig.ErrorSettingJSPPaths=Error setting the classpaths used by the JSP servlet WebAppConfig.LoggerError=Error instantiating access logger class: [#0] WebAppConfig.LoggerDisabled=Access logging disabled - no logger class defined WebAppConfig.NoWebXMLSecurityDefs=WARNING: Realm configuration ignored, because there are no roles defined in the web.xml WebAppConfig.BadFilterMapping=Error in filter mapping - no pattern and no servlet name for filter [#0] WebAppConfig.InvalidatedSessions=Invalidating [#0] sessions due to excessive inactivity WebAppConfig.AddingLeadingSlash=WARNING: Added missing leading slash to prefix: [#0] Logger.StreamWriteError=Error writing log message: [#0] Mapping.InvalidMount=WebAppConfig: Invalid pattern mount for [#0] pattern [#1] - ignoring Mapping.InvalidLink=WebAppConfig: Invalid link mount for [#0] link [#1] - ignoring Mapping.MappedPattern=Mapped: [#0] to [#1] Mapping.RewritingStarMount=WARNING: Invalid "*" only mount. Interpreting as a "/*" mount HostConfig.PrefixUnknown=Unknown webapp prefix: [#0] HostConfig.WebAppDirNotFound=Webapps dir [#0] not found HostConfig.WebAppDirIsNotDirectory=Webapps dir [#0] is not a directory HostConfig.InitComplete=Initialized [#0] webapps: prefixes - [#1] HostConfig.SkippingWarfileDir=Webapp dir deployment [#0] skipped, since there is a war file of the same name to check for re-extraction HostConfig.DeployingWebapp=Deployed web application found at [#0] HostConfig.ParsingWebXml=Parsing web.xml HostConfig.WebXmlParseComplete=Finished parsing web.xml HostConfig.WebXmlParseFailed=Failure parsing the web.xml file. Ignoring and continuing as if no web.xml was found. HostConfig.WarFileInvalid=The warfile supplied is unavailable or invalid ([#0]) HostConfig.WebRootNotDirectory=The webroot supplied is not a valid directory ([#0]) HostConfig.WebRootExists=The webroot supplied already exists - overwriting where newer ([#0]) HostConfig.BeginningWarExtraction=Beginning extraction from war file HostConfig.WebappInitError=Error initializing web application: prefix [[#0]] HostGroup.InitSingleComplete=Initialized in non-virtual-host mode HostGroup.InitMultiComplete=Initialized in virtual host mode with [#0] hosts: hostnames - [#1] HostGroup.HostsDirNotFound=Hosts dir [#0] not found HostGroup.HostsDirIsNotDirectory=Hosts dir [#0] is not a directory HostGroup.HostsDirIsEmpty=Hosts dir [#0] is empty (no child webapps found) HostGroup.DeployingHost=Deploying host found at [#0] WinstoneRequest.CookieFound=Found cookie: [#0] WinstoneRequest.SessionCookieFound=Found session cookie: [#0] [#1] WinstoneRequest.ParsingParameters=Parsing parameters: [#0] (using encoding [#1]) WinstoneRequest.IgnoringBadParameter=Ignoring bad parameter: [#0] WinstoneRequest.ErrorParameters=Error parsing request parameters WinstoneRequest.UnknownParameterType=Unknown param type: [#0] WinstoneRequest.ParsingBodyParameters=Parsing request body for parameters WinstoneRequest.ErrorBodyParameters=Error parsing body of the request WinstoneRequest.ParamLine=Param line: [#0] WinstoneRequest.IncorrectContentLength=Content-length said [#0], actual length was [#1] WinstoneRequest.BothMethods=Called getInputStream after getParameter ... error WinstoneRequest.BothMethodsReader=Called getReader after getParameter ... error WinstoneRequest.BadDate=Can't convert to date - [#0] WinstoneRequest.SetCharEncoding=Setting the request encoding from [#0] to [#1] WinstoneRequest.InvalidURLTokenChar=Found an invalid character %[#0] in url parameter. Echoing through in escaped form WinstoneRequest.CalledReaderAfterStream=Called getReader() after getInputStream() on request WinstoneRequest.CalledStreamAfterReader=Called getInputStream() after getReader() on request WinstoneSession.AttributeNotSerializable=Web application is marked distributable, but session object [#0] (class [#1]) does not extend java.io.Serializable - this variable will be ignored if the session is tranferred WinstoneSession.SkippingNonSerializable=Web application is marked distributable, but session object [#0] (class [#1]) does not extend java.io.Serializable - this variable is being ignored by session transfer WinstoneSession.InvalidatedSession=Session has been invalidated WinstoneSession.ErrorSavingSession=Error saving the session to temp space. Error: WinstoneSession.ErrorLoadingSession=Error loading session from temp space - skipping. Error: WinstoneSession.RestoredSession=Successfully restored session id [#0] from temp space WinstoneOutputStream.CommittedBytes=Written [#0] bytes to response body WinstoneOutputStream.AlreadyCommitted=OutputStream already committed WinstoneOutputStream.ResetBuffer=Resetting buffer - discarding [#0] bytes WinstoneOutputStream.Header=Header: [#0] WinstoneOutputStream.ResponseStatus=Response: [#0] WinstoneOutputStream.CommittingOutputStream=Committing response body WinstoneOutputStream.Flushing=ServletOutputStream flushed # thanks to RISKO Gergely for the reason phrase patch # borrowed from apache 2.2.6: # % grep 100\ C -A 65 modules/http/http_protocol.c | grep '^[[:space:]]*"' | cut -d\" -f2 | sed 's/^/WinstoneOutputStream.reasonPhrase./;s/ /=/' WinstoneOutputStream.reasonPhrase.100=Continue WinstoneOutputStream.reasonPhrase.101=Switching Protocols WinstoneOutputStream.reasonPhrase.102=Processing WinstoneOutputStream.reasonPhrase.200=OK WinstoneOutputStream.reasonPhrase.201=Created WinstoneOutputStream.reasonPhrase.202=Accepted WinstoneOutputStream.reasonPhrase.203=Non-Authoritative Information WinstoneOutputStream.reasonPhrase.204=No Content WinstoneOutputStream.reasonPhrase.205=Reset Content WinstoneOutputStream.reasonPhrase.206=Partial Content WinstoneOutputStream.reasonPhrase.207=Multi-Status WinstoneOutputStream.reasonPhrase.300=Multiple Choices WinstoneOutputStream.reasonPhrase.301=Moved Permanently WinstoneOutputStream.reasonPhrase.302=Found WinstoneOutputStream.reasonPhrase.303=See Other WinstoneOutputStream.reasonPhrase.304=Not Modified WinstoneOutputStream.reasonPhrase.305=Use Proxy WinstoneOutputStream.reasonPhrase.306=unused WinstoneOutputStream.reasonPhrase.307=Temporary Redirect WinstoneOutputStream.reasonPhrase.400=Bad Request WinstoneOutputStream.reasonPhrase.401=Authorization Required WinstoneOutputStream.reasonPhrase.402=Payment Required WinstoneOutputStream.reasonPhrase.403=Forbidden WinstoneOutputStream.reasonPhrase.404=Not Found WinstoneOutputStream.reasonPhrase.405=Method Not Allowed WinstoneOutputStream.reasonPhrase.406=Not Acceptable WinstoneOutputStream.reasonPhrase.407=Proxy Authentication Required WinstoneOutputStream.reasonPhrase.408=Request Time-out WinstoneOutputStream.reasonPhrase.409=Conflict WinstoneOutputStream.reasonPhrase.410=Gone WinstoneOutputStream.reasonPhrase.411=Length Required WinstoneOutputStream.reasonPhrase.412=Precondition Failed WinstoneOutputStream.reasonPhrase.413=Request Entity Too Large WinstoneOutputStream.reasonPhrase.414=Request-URI Too Large WinstoneOutputStream.reasonPhrase.415=Unsupported Media Type WinstoneOutputStream.reasonPhrase.416=Requested Range Not Satisfiable WinstoneOutputStream.reasonPhrase.417=Expectation Failed WinstoneOutputStream.reasonPhrase.418=unused WinstoneOutputStream.reasonPhrase.419=unused WinstoneOutputStream.reasonPhrase.420=unused WinstoneOutputStream.reasonPhrase.421=unused WinstoneOutputStream.reasonPhrase.422=Unprocessable Entity WinstoneOutputStream.reasonPhrase.423=Locked WinstoneOutputStream.reasonPhrase.424=Failed Dependency WinstoneOutputStream.reasonPhrase.425=No code WinstoneOutputStream.reasonPhrase.426=Upgrade Required WinstoneOutputStream.reasonPhrase.500=Internal Server Error WinstoneOutputStream.reasonPhrase.501=Method Not Implemented WinstoneOutputStream.reasonPhrase.502=Bad Gateway WinstoneOutputStream.reasonPhrase.503=Service Temporarily Unavailable WinstoneOutputStream.reasonPhrase.504=Gateway Time-out WinstoneOutputStream.reasonPhrase.505=HTTP Version Not Supported WinstoneOutputStream.reasonPhrase.506=Variant Also Negotiates WinstoneOutputStream.reasonPhrase.507=Insufficient Storage WinstoneOutputStream.reasonPhrase.508=unused WinstoneOutputStream.reasonPhrase.509=unused WinstoneOutputStream.reasonPhrase.510=Not Extended WinstoneResponse.SetLocaleTooLate=Response.setLocale() ignored, because getWriter already called WinstoneResponse.ShortOutput=Content-length header=[#0] bytes, but only [#1] bytes written to output by the end of this commit WinstoneResponse.WriterError=Error getting printWriter for encoding WinstoneResponse.ErrorPage=Error [#0]\

Status Code: [#0]

Exception: [#1]
Stacktrace:
[#2]


\ Generated by [#3] at [#4] WinstoneResponse.ServletExceptionPage=

Untrapped error in servlet


[#0]
WinstoneResponse.ErrorInErrorPage=Error using error page [#0] for code [#1] WinstoneResponse.SendingError=Sending error message to browser: code [#0], message: [#1] WinstoneResponse.TestingException=Testing error page exception [#0] against thrown exception [#1] WinstoneResponse.ResponseCommitted=Response cannot be reset - it is already committed WinstoneResponse.SkippingException=Error-page [#0] not found for exception [#1] WinstoneResponse.ExceptionNotMatched=Exception [#0] not matched WinstoneResponse.ErrorResettingWriter=Couldn't reset the writer on a resetBuffer() WinstoneResponse.HeadersPreCommit=Headers prepared for writing: [#0] WinstoneResponse.WritingCookie=Writing cookie to output: [#0] WinstoneResponse.LookForLocaleEncoding=Scanning for locale-encoding match: [#0] in [#1] WinstoneResponse.FoundLocaleEncoding=Found locale-encoding match: [#0] WinstoneResponse.SettingEncoding=Setting response character encoding to [#0] WinstoneResponse.GetOutputStream=Called ServletResponse.getOutputStream() WinstoneResponse.GetWriter=Called ServletResponse.getWriter() WinstoneResponse.HeaderInInclude=Header ignored inside include - [#0]: [#1] WinstoneResponse.HeaderAfterCommitted=Header ignored after response committed - [#0]: [#1] WinstoneResponse.ForceBodyParsing=Forcing request body parse WinstoneResponse.ErrorForceBodyParsing=Error forcing body parsing WinstoneResponse.ForcingContentLength=Keep-alive requested but no content length set. Setting to [#0] bytes WinstoneResponseWriter.AutoFlush=Checking for auto-flush of print writer: contentLengthHeader=[#0], responseBytes=[#1] RequestHandlerThread.OpenedPort=New socket opened - remotePort RequestHandlerThread.ClosedPort=Closed socket - remotePort RequestHandlerThread.StartRequest=Starting request on host:[[#1]] with id: [#0] RequestHandlerThread.FinishRequest=Finishing request id: [#0] RequestHandlerThread.RequestTime=Processed complete request: headerParseTime=[#1]ms totalTime=[#2]ms path=[#0] RequestHandlerThread.SocketTimeout=Socket read timed out - exiting request handler thread RequestHandlerThread.RequestError=Error within request handler thread RequestHandlerThread.HandlingRD=Processing with RD: [#0] RequestHandlerThread.UntrappedError=Untrapped Error in Servlet RequestHandlerThread.UnknownWebapp=Request URL [#0] not found - doesn't match any webapp prefix RequestHandlerThread.UnknownWebappPage=Request URL [#0] not found.

RequestHandlerThread.ThreadName=RequestHandlerThread[#[#0]] RequestHandlerThread.EnterWaitState=Thread entering wait state RequestHandlerThread.WakingUp=Thread leaving wait state RequestHandlerThread.ThreadExit=Exiting thread RequestHandlerThread.NullRD=Could not find a request dispatcher for path [#0] RequestHandlerThread.ErrorInErrorServlet=Error in the error servlet RequestHandlerThread.KeepAliveTimedOut=Keep alive timed out in thread: [#0] RequestDispatcher.IncludeMessage=INCLUDE: servlet=[#0], path=[#1] RequestDispatcher.ForwardMessage=FORWARD: servlet=[#0], path=[#1] RequestDispatcher.ForwardCommitted=Called RequestDispatcher.forward() on committed response RequestDispatcher.InvalidMapping=Filter mapping invalid ([#filterPattern]) - ignoring RequestDispatcher.ExecutingFilter=Executing Filter: [#0] RequestDispatcher.BypassingFilter=Skipping Filter: Mapping=[#1], Path=[#2], ServletName=[#0] RequestDispatcher.IncludeError=UnavailableException in servlet include RequestDispatcher.ForwardError=UnavailableException in servlet forward RequestDispatcher.FilterError=Error in filter - marking unavailable RequestDispatcher.CalcFilterChain=No cached filter chain available. Calculating for cacheKey=[#0] RequestDispatcher.UseCachedFilterChain=Cached filter chain available for cacheKey=[#0] IncludeResponse.Error=Error in include: [#0] [#1] IncludeResponse.Redirect=Ignoring redirect in include: [#0] ServletConfiguration.DeployedInstance=Loaded servlet instance [#0] class: [#1] ServletConfiguration.init=[#0]: init ServletConfiguration.destroy=[#0]: destroy ServletConfiguration.ClassLoadError=Failed to load class: [#0] ServletConfiguration.InitError=Failed to initialise servlet ServletConfiguration.ServletUnavailable=This servlet has been marked unavailable because of an earlier error ShutdownHook.Initiating=JVM is terminating. Shutting down Winstone FilterConfiguration.DeployedInstance=Loaded filter instance [#0] class: [#1] FilterConfiguration.init=[#0]: init FilterConfiguration.destroy=[#0]: destroy FilterConfiguration.ClassLoadError=Failed to load class: [#0] FilterConfiguration.InitError=Failed to initialise filter: FilterConfiguration.Description=FilterConfiguration[name=[#0], filterClass=[#1]] FilterConfiguration.FilterUnavailable=This filter has been marked unavailable because of an earlier error WebAppConfig.WebAppClasses=Adding webapp classes folder to classpath WebAppConfig.NoWebAppClasses=No webapp classes folder found - [#0] WebAppConfig.WebAppLib=Adding webapp lib [#0] to classpath WebAppConfig.NoWebAppLib=No webapp lib folder found - [#0] WebAppConfig.BadURL=Bad URL in WinstoneClassLoader WebAppConfig.IOException=IOException in WinstoneClassLoader WinstoneInputStream.EndOfStream=End of stream StaticResourceServlet.PathRequested=[#0]: path=[#1] StaticResourceServlet.PathNotFound=File [#0] not found StaticResourceServlet.PathInvalid=Illegal path error - [#0] StaticResourceServlet.AccessDenied=Access to this resource is denied StaticResourceServlet.OutsideWebroot=Requested path [#0] was outside the webroot [#1] StaticResourceServlet.EvaluatingPathForParentCheck=Checking path for parenthood: candidate=[#1], current=[#0] StaticResourceServlet.DirectoryList.HeaderColour=#ffffff StaticResourceServlet.DirectoryList.HeaderTextColour=#000033 StaticResourceServlet.DirectoryList.LabelColour=#aeaeae StaticResourceServlet.DirectoryList.LabelTextColour=#ffffff StaticResourceServlet.DirectoryList.OddColour=#dddddd StaticResourceServlet.DirectoryList.EvenColour=#cbcbcb StaticResourceServlet.DirectoryList.RowTextColour=#000033 StaticResourceServlet.DirectoryList.ParentDirectoryLabel=(parent directory) StaticResourceServlet.DirectoryList.DirectoryLabel=directory StaticResourceServlet.DirectoryList.NoDateLabel=- StaticResourceServlet.DirectoryList.Row=\ \ [#2]\ [#5]\ [#4] StaticResourceServlet.DirectoryList.Body=\ Winstone directory listing - [#6]\ \ \ \ \ \
\

Directory - [#6]

\
\
\
\ \ \ \ \ \ \ [#7]\
NameSizeDate
\
\
\ Directory list generated by [#5] at [#4]\ HttpListener.ParsingSocketInfo=Parsing socket info HttpListener.WaitingForURILine=Waiting for a URI line HttpListener.UriLine=URI Line: [#0] HttpListener.ErrorUriLine=Error URI Line: [#0] HttpListener.ShutdownError=Error during [#0] listener init or shutdown HttpListener.ShutdownOK=[#0] Listener shutdown successfully HttpListener.StartupOK=[#0] Listener started: port=[#1] HttpListener.AllocatingRequest=Allocating request/response: [#0] HttpListener.Header=Header: [#0] Listener.ThreadName=ConnectorThread:[[#0]-[#1]] ObjectPool.UsingRequestFromPool=ReqPool: Using pooled request - available: [#0] ObjectPool.NewRequestForPool=ReqPool: Spawning new request - available: [#0] ObjectPool.PoolRequestLimitExceeded=ReqPool: Max requests in pool exceeded - denied ObjectPool.RequestReleased=ReqPool: Request released - available: [#0] ObjectPool.UsingResponseFromPool=RspPool: Using pooled response - available: [#0] ObjectPool.NewResponseForPool=RspPool: Spawning new response - available: [#0] ObjectPool.PoolResponseLimitExceeded=RspPool: Max responses in pool exceeded - denied ObjectPool.ResponseReleased=RspPool: Response released - available: [#0] ObjectPool.UsingRHPoolThread=RHPool: Using pooled handler thread - used: [#0] unused: [#1] ObjectPool.NewRHPoolThread=RHPool: Spawning new handler thread - used: [#0] unused: [#1] ObjectPool.NoRHPoolThreads=ERROR: Request ignored because there were no more request handlers available in the pool ObjectPool.NoRHPoolThreadsRetry=WARNING: Request handler pool limit exceeded - waiting for retry ObjectPool.UnknownRHPoolThread=RHPool: Releasing unknown handler. Ignoring ObjectPool.ReleasingRHPoolThread=RHPool: Releasing handler thread - used: [#0] unused: [#1] WebXmlParser.XMLParseError=XML Error (Line [#0]): [#1] WebXmlParser.NoLocalResource=Cannot find local resource for url: [#0] WebXmlParser.ResolvingEntity=Resolving entity - public=[#0], url=[#1] WebXmlParser.WebXMLBothErrors=ERROR: An XSD compliant parser was available, but web.xml parsing failed under both XSD and non-XSD conditions. See below for error reports. WebXmlParser.WebXML23ParseError=Error when parsing web.xml file using the v2.2/2.3 servlet specification: WebXmlParser.WebXML24ParseError=Error when parsing web.xml file using the v2.4 servlet specification: WebXmlParser.WebXML25ParseError=Error when parsing web.xml file using the v2.5 servlet specification: WebXmlParser.NonXSDParser=WARNING: Non-XML-Schema-compliant parser detected. Servlet spec <= 2.3 supported WebXmlParser.2524XSDNotFound=WARNING: The Servlet 2.4/2.5 spec XSD was unavailable inside the winstone classpath. \ Will be retrieved from the web if required (slow) WebXmlParser.Local25XSDEnabled=Found and enabled the local Servlet 2.5 XSD replacement WebXmlParser.Local24XSDEnabled=Found and enabled the local Servlet 2.4 XSD replacement Launcher.ThreadName=LauncherControlThread[ControlPort=[#0]] Launcher.ClusterOffNoControlPort=Clustering disabled - control port must be enabled Launcher.ClusterNotFound=Clustering disabled - cluster implementation class not found Launcher.NoWebRoot=Web root not found - [#0] Launcher.ShutdownError=Error during listener init or shutdown Launcher.ControlThreadShutdownOK=Control thread shutdown successfully Launcher.ShutdownOK=Winstone shutdown successfully Launcher.StartupOK=[#0] running: controlPort=[#1] Launcher.ControlDisabled=disabled Launcher.DefaultPropertyFile=winstone.properties Launcher.NoPropertyFile=Property file not found ([#0]) - ignoring Launcher.UsingPropertyFile=Property file found ([#0]) - loading Launcher.ListenerNotFound=Listener [#0] not found / disabled - ignoring Launcher.ListenerStartupError=Error during listener startup Launcher.UsingCommonLib=Using common lib folder: [#0] Launcher.NoCommonLib=No common lib folder found Launcher.UsingJavaHome=Using JAVA_HOME=[#0] Launcher.ToolsJarNotFound=WARNING: Tools.jar was not found - jsp compilation will cause errors. \ Maybe you should set JAVA_HOME using --javaHome Launcher.AddedCommonLibJar=Adding [#0] to common classpath Launcher.ShutdownRequestReceived=Shutdown request received via the controlPort. Commencing Winstone shutdown Launcher.ReloadRequestReceived=Reload request received via the controlPort. Commencing Winstone reload Launcher.ClusterStartupError=WARNING: Error during startup of cluster implementation - ignoring Launcher.CLClassLoader=Initializing Common Lib classloader: [#0] Launcher.StartupArgs=Winstone startup arguments: [#0] Launcher.JNDIDisabled=JNDI disabled at container level - can't find JNDI Manager class Launcher.JNDIError=JNDI disabled at container level - couldn't load JNDI Manager: [#0] Launcher.EmbeddedPropertiesFile=/embedded.properties Launcher.EmbeddedWarFile=/embedded.war Launcher.EmbeddedWebroot=winstoneEmbeddedWAR Launcher.CopyingEmbeddedWarfile=Extracting embedded warfile to [#0] Launcher.NeedsJDK14=Listener class [#0] needs JDK1.4 support. Disabling Launcher.ContainerStartupError=Container startup failed # Keep synchronized with jenkinsci/extras-executable-war/src/main/java/Main.java Launcher.UsageInstructions=[#0], (c) 2003-2006 Rick Knowles\n\ Usage: java winstone.Launcher [--option=value] [--option=value] [etc]\n\n\ Required options: either --webroot OR --warfile OR --webappsDir OR --hostsDir\n\ \ --webroot = set document root folder.\n\ \ --warfile = set location of warfile to extract from.\n\ \ --webappsDir = set directory for multiple webapps to be deployed from\n\ \ --hostsDir = set directory for name-based virtual hosts to be deployed from\n\n\ Other options:\n\ \ --javaHome = Override the JAVA_HOME variable\n\ \ --toolsJar = The location of tools.jar. Default is JAVA_HOME/lib/tools.jar\n\ \ --config = load configuration properties from here. Default is ./winstone.properties\n\ \ --prefix = add this prefix to all URLs (eg http://localhost:8080/prefix/resource). Default is none\n\ \ --commonLibFolder = folder for additional jar files. Default is ./lib\n\n\ \ --logfile = redirect winstone log messages to this file\n\ \ --logThrowingLineNo = show the line no that logged the message (slow). Default is false\n\ \ --logThrowingThread = show the thread that logged the message. Default is false\n\ \ --debug = set the level of debug msgs (1-9). Default is 5 (INFO level)\n\n\ \ --httpPort = set the http listening port. -1 to disable, Default is 8080\n\ \ --httpListenAddress = set the http listening address. Default is all interfaces\n\ \ --httpDoHostnameLookups = enable host name lookups on incoming http connections (true/false). Default is false\n\ \ --httpKeepAliveTimeout = how long idle HTTP keep-alive connections are kept around (in ms; default 5000)?\n\ \ --httpsPort = set the https listening port. -1 to disable, Default is disabled\n\ \ --httpsListenAddress = set the https listening address. Default is all interfaces\n\ \ --httpsDoHostnameLookups = enable host name lookups on incoming https connections (true/false). Default is false\n\ \ --httpsKeepAliveTimeout = how long idle HTTPS keep-alive connections are kept around (in ms; default 5000)?\n\ \ --httpsKeyStore = the location of the SSL KeyStore file. Default is ./winstone.ks\n\ \ --httpsKeyStorePassword = the password for the SSL KeyStore file. Default is null\n\ \ --httpsKeyManagerType = the SSL KeyManagerFactory type (eg SunX509, IbmX509). Default is SunX509\n\ \ --ajp13Port = set the ajp13 listening port. -1 to disable, Default disabled\n\ \ --ajp13ListenAddress = set the ajp13 listening address. Default is all interfaces\n\ \ --controlPort = set the shutdown/control port. -1 to disable, Default disabled\n\n\ \ --handlerCountStartup = set the no of worker threads to spawn at startup. Default is 5\n\ \ --handlerCountMax = set the max no of worker threads to allow. Default is 40\n\ \ --handlerCountMaxIdle = set the max no of idle worker threads to allow. Default is 5\n\n\ \ --directoryListings = enable directory lists (true/false). Default is true\n\ \ --useJasper = enable jasper JSP handling (true/false). Default is false\n\ \ --useServletReloading = enable servlet reloading (true/false). Default is false\n\ \ --preferredClassLoader = override the preferred webapp class loader.\n\ \ --useInvoker = enable the servlet invoker (true/false). Default is true\n\ \ --invokerPrefix = set the invoker prefix. Default is /servlet/\n\ \ --simulateModUniqueId = simulate the apache mod_unique_id function. Default is false\n\ \ --useSavedSessions = enables session persistence (true/false). Default is false\n\ \ --sessionTimeout = set the http session timeout value in minutes. Default to what webapp specifies, and then to 60 minutes\n\ \ --mimeTypes=ARG = define additional MIME type mappings. ARG would be EXT=MIMETYPE:EXT=MIMETYPE:...\n\ \ (e.g., xls=application/vnd.ms-excel:wmf=application/x-msmetafile)\n\ \ --maxParamCount=N = set the max number of parameters allowed in a form submission to protect\n\ \ against hash DoS attack (oCERT #2011-003). Default is 10000.\n\ \ --usage / --help = show this message\n\n\ Cluster options:\n\ \ --useCluster = enable cluster support (true/false). Default is false\n\ \ --clusterClassName = Set the cluster class to use. Defaults to SimpleCluster class\n\ \ --clusterNodes = a comma separated list of node addresses (IP:ControlPort,IP:ControlPort,etc)\n\n\ JNDI options:\n\ \ --useJNDI = enable JNDI support (true/false). Default is false\n\ \ --containerJndiClassName = Set the container wide JNDI manager class to use. Defaults to ContainerJNDIManager\n\ \ --webappJndiClassName = Set the web-app JNDI manager class to use. Defaults to WebAppJNDIManager\n\ \ --jndi.resource. = set the class to be used for the resource marked \n\ \ --jndi.param.. = set an attribute to be associated with the resource marked \n\n\ Security options:\n\ \ --realmClassName = Set the realm class to use for user authentication. Defaults to ArgumentsRealm class\n\n\ \ --argumentsRealm.passwd. = Password for user . Only valid for the ArgumentsRealm realm class\n\ \ --argumentsRealm.roles. = Roles for user (comma separated). Only valid for the ArgumentsRealm realm class\n\n\ \ --fileRealm.configFile = File containing users/passwds/roles. Only valid for the FileRealm realm class\n\n\ Access logging:\n\ \ --accessLoggerClassName = Set the access logger class to use for user authentication. Defaults to disabled\n\ \ --simpleAccessLogger.format = The log format to use. Supports combined/common/resin/custom (SimpleAccessLogger only)\n\ \ --simpleAccessLogger.file = The location pattern for the log file(SimpleAccessLogger only)\n\n\ This program is free software; you can redistribute it and/or\n\ modify it under the terms of the Common Development and\n\ Distribution License (CDDL) Version 1.0 or under the terms\n\ of the Lesser GNU General Public License Version 2.1 or later as\n\ published by the Free Software Foundation.\n\n\ This program is distributed in the hope that it will be useful,\n\ but WITHOUT ANY WARRANTY; without even the implied warranty of\n\ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n\ Lesser GNU General Public License Version 2.1 for more details.\n\n\ You should have received a copy of the Lesser GNU General Public License\n\ Version 2.1 along with this program; if not, write to the Free Software\n\ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.\n CmdLineParser.MultipleArgs=Multiple command line argument specified: [#0] CmdLineParser.UnrecognizedOption=Unrecognized option: [#0] CmdLineParser.OperandExpected=Expecting --[#0]=VALUE but found no value jenkins-winstone-0.9.10-jenkins-47/src/java/javax/0000755000175000017500000000000012200024521022254 5ustar jamespagejamespagejenkins-winstone-0.9.10-jenkins-47/src/java/javax/servlet/0000755000175000017500000000000012200024521023740 5ustar jamespagejamespagejenkins-winstone-0.9.10-jenkins-47/src/java/javax/servlet/ServletContextEvent.java0000644000175000017500000000131112200024521030572 0ustar jamespagejamespage/* * Copyright 2003-2006 Rick Knowles * Distributed under the terms of either: * - the common development and distribution license (CDDL), v1.0; or * - the GNU Lesser General Public License, v2.1 or later */ package javax.servlet; /** * The event object thrown when a servlet context change occurs. * * @author Rick Knowles */ public class ServletContextEvent extends java.util.EventObject { /** * Constructor */ public ServletContextEvent(ServletContext source) { super(source); } public ServletContext getServletContext() { return (ServletContext) this.source; } } jenkins-winstone-0.9.10-jenkins-47/src/java/javax/servlet/ServletRequestWrapper.java0000644000175000017500000000752612200024521031153 0ustar jamespagejamespage/* * Copyright 2003-2006 Rick Knowles * Distributed under the terms of either: * - the common development and distribution license (CDDL), v1.0; or * - the GNU Lesser General Public License, v2.1 or later */ package javax.servlet; import java.util.Enumeration; import java.util.Locale; import java.util.Map; import java.io.BufferedReader; import java.io.IOException; import java.io.UnsupportedEncodingException; /** * Wraps a servlet request object using the decorator pattern. * * @author Rick Knowles */ public class ServletRequestWrapper implements ServletRequest { private ServletRequest request; public ServletRequestWrapper(ServletRequest request) { setRequest(request); } public ServletRequest getRequest() { return this.request; } public void setRequest(ServletRequest request) { if (request == null) { throw new IllegalArgumentException("Request was null"); } else { this.request = request; } } public Object getAttribute(String name) { return this.request.getAttribute(name); } public Enumeration getAttributeNames() { return this.request.getAttributeNames(); } public void removeAttribute(String name) { this.request.removeAttribute(name); } public void setAttribute(String name, Object o) { this.request.setAttribute(name, o); } public String getCharacterEncoding() { return this.request.getCharacterEncoding(); } public void setCharacterEncoding(String enc) throws UnsupportedEncodingException { this.request.setCharacterEncoding(enc); } public int getContentLength() { return this.request.getContentLength(); } public String getContentType() { return this.request.getContentType(); } public Locale getLocale() { return this.request.getLocale(); } public Enumeration getLocales() { return this.request.getLocales(); } public ServletInputStream getInputStream() throws IOException { return this.request.getInputStream(); } public BufferedReader getReader() throws IOException { return this.request.getReader(); } public String getParameter(String name) { return this.request.getParameter(name); } public Map getParameterMap() { return this.request.getParameterMap(); } public Enumeration getParameterNames() { return this.request.getParameterNames(); } public String[] getParameterValues(String name) { return this.request.getParameterValues(name); } public RequestDispatcher getRequestDispatcher(String path) { return this.request.getRequestDispatcher(path); } public String getProtocol() { return this.request.getProtocol(); } public String getRemoteAddr() { return this.request.getRemoteAddr(); } public String getRemoteHost() { return this.request.getRemoteHost(); } public String getScheme() { return this.request.getScheme(); } public String getServerName() { return this.request.getServerName(); } public int getServerPort() { return this.request.getServerPort(); } public String getLocalAddr() { return this.request.getLocalAddr(); } public String getLocalName() { return this.request.getLocalName(); } public int getLocalPort() { return this.request.getLocalPort(); } public int getRemotePort() { return this.request.getRemotePort(); } public boolean isSecure() { return this.request.isSecure(); } /** * @deprecated */ public String getRealPath(String path) { return this.request.getRealPath(path); } } jenkins-winstone-0.9.10-jenkins-47/src/java/javax/servlet/Servlet.java0000644000175000017500000000134512200024521026232 0ustar jamespagejamespage/* * Copyright 2003-2006 Rick Knowles * Distributed under the terms of either: * - the common development and distribution license (CDDL), v1.0; or * - the GNU Lesser General Public License, v2.1 or later */ package javax.servlet; import java.io.IOException; /** * Basic servlet interface * * @author Rick Knowles */ public interface Servlet { public void destroy(); public ServletConfig getServletConfig(); public String getServletInfo(); public void init(ServletConfig config) throws ServletException; public void service(ServletRequest req, ServletResponse res) throws IOException, ServletException; } jenkins-winstone-0.9.10-jenkins-47/src/java/javax/servlet/ServletContext.java0000644000175000017500000000422012200024521027572 0ustar jamespagejamespage/* * Copyright 2003-2006 Rick Knowles * Distributed under the terms of either: * - the common development and distribution license (CDDL), v1.0; or * - the GNU Lesser General Public License, v2.1 or later */ package javax.servlet; import java.util.Enumeration; import java.net.URL; import java.io.InputStream; import java.util.Set; /** * Models the web application concept as an interface. * * @author Rick Knowles */ public interface ServletContext { public Object getAttribute(String name); public Enumeration getAttributeNames(); public String getInitParameter(String name); public Enumeration getInitParameterNames(); public String getServletContextName(); public ServletContext getContext(String uripath); public String getServerInfo(); public String getMimeType(String file); public int getMajorVersion(); public int getMinorVersion(); public RequestDispatcher getRequestDispatcher(String path); public RequestDispatcher getNamedDispatcher(String name); public String getRealPath(String path); public URL getResource(String path) throws java.net.MalformedURLException; public InputStream getResourceAsStream(String path); public Set getResourcePaths(String path); public String getContextPath(); /** * @deprecated As of Java Servlet API 2.1, with no direct replacement. */ public Servlet getServlet(String name) throws ServletException; /** * @deprecated As of Java Servlet API 2.1, with no replacement. */ public Enumeration getServletNames(); /** * @deprecated As of Java Servlet API 2.0, with no replacement. */ public Enumeration getServlets(); /** * @deprecated As of Java Servlet API 2.1, use log(String message, Throwable * throwable) instead. */ public void log(Exception exception, String msg); public void log(String msg); public void log(String message, Throwable throwable); public void removeAttribute(String name); public void setAttribute(String name, Object object); } jenkins-winstone-0.9.10-jenkins-47/src/java/javax/servlet/ServletRequestAttributeListener.java0000644000175000017500000000147112200024521033175 0ustar jamespagejamespage/* * Copyright 2003-2006 Rick Knowles * Distributed under the terms of either: * - the common development and distribution license (CDDL), v1.0; or * - the GNU Lesser General Public License, v2.1 or later */ package javax.servlet; import java.util.EventListener; /** * Interface defining request attribute listeners * * @author Rick Knowles * @version $Id: ServletRequestAttributeListener.java,v 1.2 2006/02/28 07:32:48 rickknowles Exp $ */ public interface ServletRequestAttributeListener extends EventListener { public void attributeAdded(ServletRequestAttributeEvent srae); public void attributeRemoved(ServletRequestAttributeEvent srae); public void attributeReplaced(ServletRequestAttributeEvent srae); } jenkins-winstone-0.9.10-jenkins-47/src/java/javax/servlet/ServletInputStream.java0000644000175000017500000000234112200024521030423 0ustar jamespagejamespage/* * Copyright 2003-2006 Rick Knowles * Distributed under the terms of either: * - the common development and distribution license (CDDL), v1.0; or * - the GNU Lesser General Public License, v2.1 or later */ package javax.servlet; /** * Provides the base class for servlet request streams. * * @author Rick Knowles */ public abstract class ServletInputStream extends java.io.InputStream { protected ServletInputStream() { super(); } public int readLine(byte[] b, int off, int len) throws java.io.IOException { if (b == null) throw new IllegalArgumentException("null buffer"); else if (len + off > b.length) throw new IllegalArgumentException( "offset + length is greater than buffer length"); int positionCounter = 0; int charRead = read(); while (charRead != -1) { b[off + positionCounter++] = (byte) charRead; if ((charRead == '\n') || (off + positionCounter == len)) { return positionCounter; } else { charRead = read(); } } return -1; } } jenkins-winstone-0.9.10-jenkins-47/src/java/javax/servlet/FilterConfig.java0000644000175000017500000000116012200024521027154 0ustar jamespagejamespage/* * Copyright 2003-2006 Rick Knowles * Distributed under the terms of either: * - the common development and distribution license (CDDL), v1.0; or * - the GNU Lesser General Public License, v2.1 or later */ package javax.servlet; /** * Configuration for filter objects. * * @author Rick Knowles */ public interface FilterConfig { public String getFilterName(); public String getInitParameter(String name); public java.util.Enumeration getInitParameterNames(); public ServletContext getServletContext(); } jenkins-winstone-0.9.10-jenkins-47/src/java/javax/servlet/ServletResponse.java0000644000175000017500000000221012200024521027741 0ustar jamespagejamespage/* * Copyright 2003-2006 Rick Knowles * Distributed under the terms of either: * - the common development and distribution license (CDDL), v1.0; or * - the GNU Lesser General Public License, v2.1 or later */ package javax.servlet; import java.util.Locale; import java.io.IOException; import java.io.PrintWriter; /** * Base response interface definition. * * @author Rick Knowles */ public interface ServletResponse { public void flushBuffer() throws IOException; public int getBufferSize(); public void reset(); public void resetBuffer(); public void setBufferSize(int size); public boolean isCommitted(); public String getCharacterEncoding(); public void setCharacterEncoding(String charset); public String getContentType(); public void setContentType(String type); public void setContentLength(int len); public Locale getLocale(); public void setLocale(Locale loc); public ServletOutputStream getOutputStream() throws IOException; public PrintWriter getWriter() throws IOException; } jenkins-winstone-0.9.10-jenkins-47/src/java/javax/servlet/ServletConfig.java0000644000175000017500000000116512200024521027360 0ustar jamespagejamespage/* * Copyright 2003-2006 Rick Knowles * Distributed under the terms of either: * - the common development and distribution license (CDDL), v1.0; or * - the GNU Lesser General Public License, v2.1 or later */ package javax.servlet; /** * Basic servlet configuation interface * * @author Rick Knowles */ public interface ServletConfig { public String getInitParameter(String name); public java.util.Enumeration getInitParameterNames(); public ServletContext getServletContext(); public String getServletName(); } jenkins-winstone-0.9.10-jenkins-47/src/java/javax/servlet/GenericServlet.java0000644000175000017500000000330512200024521027525 0ustar jamespagejamespage/* * Copyright 2003-2006 Rick Knowles * Distributed under the terms of either: * - the common development and distribution license (CDDL), v1.0; or * - the GNU Lesser General Public License, v2.1 or later */ package javax.servlet; import java.io.IOException; import java.io.Serializable; import java.util.Enumeration; /** * The base class from which all servlets extend. * * @author Rick Knowles */ public abstract class GenericServlet implements Servlet, ServletConfig, Serializable { private ServletConfig config; public GenericServlet() { } public String getInitParameter(String name) { return config.getInitParameter(name); } public Enumeration getInitParameterNames() { return config.getInitParameterNames(); } public ServletConfig getServletConfig() { return this.config; } public void init(ServletConfig config) throws ServletException { this.config = config; init(); } public void init() throws ServletException { } public void destroy() { } public ServletContext getServletContext() { return config.getServletContext(); } public String getServletInfo() { return ""; } public String getServletName() { return config.getServletName(); } public void log(String msg) { config.getServletContext().log(msg); } public void log(String message, Throwable t) { config.getServletContext().log(message, t); } public abstract void service(ServletRequest req, ServletResponse res) throws IOException, ServletException; } jenkins-winstone-0.9.10-jenkins-47/src/java/javax/servlet/ServletRequestEvent.java0000644000175000017500000000173412200024521030607 0ustar jamespagejamespage/* * Copyright 2003-2006 Rick Knowles * Distributed under the terms of either: * - the common development and distribution license (CDDL), v1.0; or * - the GNU Lesser General Public License, v2.1 or later */ package javax.servlet; import java.util.EventObject; /** * Request coming into scope or out of scope event * * @author Rick Knowles * @version $Id: ServletRequestEvent.java,v 1.2 2006/02/28 07:32:47 rickknowles Exp $ */ public class ServletRequestEvent extends EventObject { private ServletRequest request; private ServletContext context; public ServletRequestEvent(ServletContext sc, ServletRequest request) { super(sc); this.request = request; this.context = sc; } public ServletRequest getServletRequest() { return this.request; } public ServletContext getServletContext() { return this.context; } } jenkins-winstone-0.9.10-jenkins-47/src/java/javax/servlet/Filter.java0000644000175000017500000000125612200024521026034 0ustar jamespagejamespage/* * Copyright 2003-2006 Rick Knowles * Distributed under the terms of either: * - the common development and distribution license (CDDL), v1.0; or * - the GNU Lesser General Public License, v2.1 or later */ package javax.servlet; /** * Interface definition for filter objects * * @author Rick Knowles */ public interface Filter { public void destroy(); public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws java.io.IOException, ServletException; public void init(FilterConfig filterConfig) throws ServletException; } jenkins-winstone-0.9.10-jenkins-47/src/java/javax/servlet/ServletResponseWrapper.java0000644000175000017500000000451012200024521031307 0ustar jamespagejamespage/* * Copyright 2003-2006 Rick Knowles * Distributed under the terms of either: * - the common development and distribution license (CDDL), v1.0; or * - the GNU Lesser General Public License, v2.1 or later */ package javax.servlet; import java.util.Locale; import java.io.IOException; /** * Wraps a servlet response object using the decorator pattern * * @author Rick Knowles */ public class ServletResponseWrapper implements ServletResponse { private ServletResponse response; public ServletResponseWrapper(ServletResponse response) { setResponse(response); } public ServletResponse getResponse() { return this.response; } public void setResponse(ServletResponse response) { if (response == null) { throw new IllegalArgumentException("Response was null"); } this.response = response; } public Locale getLocale() { return this.response.getLocale(); } public void setLocale(Locale loc) { this.response.setLocale(loc); } public ServletOutputStream getOutputStream() throws IOException { return this.response.getOutputStream(); } public java.io.PrintWriter getWriter() throws IOException { return this.response.getWriter(); } public boolean isCommitted() { return this.response.isCommitted(); } public int getBufferSize() { return this.response.getBufferSize(); } public void setBufferSize(int size) { this.response.setBufferSize(size); } public void reset() { this.response.reset(); } public void resetBuffer() { this.response.resetBuffer(); } public void flushBuffer() throws IOException { this.response.flushBuffer(); } public void setContentLength(int len) { this.response.setContentLength(len); } public void setContentType(String type) { this.response.setContentType(type); } public String getContentType() { return this.response.getContentType(); } public String getCharacterEncoding() { return this.response.getCharacterEncoding(); } public void setCharacterEncoding(String charset) { this.response.setCharacterEncoding(charset); } } jenkins-winstone-0.9.10-jenkins-47/src/java/javax/servlet/ServletContextListener.java0000644000175000017500000000114412200024521031302 0ustar jamespagejamespage/* * Copyright 2003-2006 Rick Knowles * Distributed under the terms of either: * - the common development and distribution license (CDDL), v1.0; or * - the GNU Lesser General Public License, v2.1 or later */ package javax.servlet; /** * Thrown when a change to the servletContext occurs. * * @author Rick Knowles */ public interface ServletContextListener extends java.util.EventListener { public void contextDestroyed(ServletContextEvent sce); public void contextInitialized(ServletContextEvent sce); } jenkins-winstone-0.9.10-jenkins-47/src/java/javax/servlet/SingleThreadModel.java0000644000175000017500000000077412200024521030145 0ustar jamespagejamespage/* * Copyright 2003-2006 Rick Knowles * Distributed under the terms of either: * - the common development and distribution license (CDDL), v1.0; or * - the GNU Lesser General Public License, v2.1 or later */ package javax.servlet; /** * This is just to ensure that a servlet can flag itself as a non-multithreaded * instance. * * @deprecated * @author Rick Knowles */ public interface SingleThreadModel { } jenkins-winstone-0.9.10-jenkins-47/src/java/javax/servlet/RequestDispatcher.java0000644000175000017500000000134712200024521030247 0ustar jamespagejamespage/* * Copyright 2003-2006 Rick Knowles * Distributed under the terms of either: * - the common development and distribution license (CDDL), v1.0; or * - the GNU Lesser General Public License, v2.1 or later */ package javax.servlet; /** * Interface defining behaviour of servlet container dispatching of requests. * * @author Rick Knowles */ public interface RequestDispatcher { public void forward(ServletRequest request, ServletResponse response) throws ServletException, java.io.IOException; public void include(ServletRequest request, ServletResponse response) throws ServletException, java.io.IOException; } jenkins-winstone-0.9.10-jenkins-47/src/java/javax/servlet/ServletRequest.java0000644000175000017500000000375012200024521027605 0ustar jamespagejamespage/* * Copyright 2003-2006 Rick Knowles * Distributed under the terms of either: * - the common development and distribution license (CDDL), v1.0; or * - the GNU Lesser General Public License, v2.1 or later */ package javax.servlet; import java.io.BufferedReader; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.util.Enumeration; import java.util.Locale; import java.util.Map; /** * Base request object interface definition. * * @author Rick Knowles */ public interface ServletRequest { public Object getAttribute(String name); public Enumeration getAttributeNames(); public String getCharacterEncoding(); public int getContentLength(); public String getContentType(); public ServletInputStream getInputStream() throws IOException; public String getLocalAddr(); public Locale getLocale(); public Enumeration getLocales(); public String getLocalName(); public int getLocalPort(); public String getParameter(String name); public Map getParameterMap(); public Enumeration getParameterNames(); public String[] getParameterValues(String name); public String getProtocol(); public BufferedReader getReader() throws IOException; public String getRemoteAddr(); public String getRemoteHost(); public int getRemotePort(); public RequestDispatcher getRequestDispatcher(String path); public String getScheme(); public String getServerName(); public int getServerPort(); public boolean isSecure(); public void removeAttribute(String name); public void setAttribute(String name, Object o); public void setCharacterEncoding(String enc) throws UnsupportedEncodingException; /** * @deprecated As of Version 2.1 of the Java Servlet API, use * ServletContext.getRealPath(String) instead. */ public String getRealPath(String path); } jenkins-winstone-0.9.10-jenkins-47/src/java/javax/servlet/ServletContextAttributeListener.java0000644000175000017500000000131012200024521033161 0ustar jamespagejamespage/* * Copyright 2003-2006 Rick Knowles * Distributed under the terms of either: * - the common development and distribution license (CDDL), v1.0; or * - the GNU Lesser General Public License, v2.1 or later */ package javax.servlet; /** * Listens for changes to the context attributes. * * @author Rick Knowles */ public interface ServletContextAttributeListener extends java.util.EventListener { public void attributeAdded(ServletContextAttributeEvent scab); public void attributeRemoved(ServletContextAttributeEvent scab); public void attributeReplaced(ServletContextAttributeEvent scab); } jenkins-winstone-0.9.10-jenkins-47/src/java/javax/servlet/ServletRequestListener.java0000644000175000017500000000132112200024521031303 0ustar jamespagejamespage/* * Copyright 2003-2006 Rick Knowles * Distributed under the terms of either: * - the common development and distribution license (CDDL), v1.0; or * - the GNU Lesser General Public License, v2.1 or later */ package javax.servlet; import java.util.EventListener; /** * Listener for requests going in and out of scope * * @author Rick Knowles * @version $Id: ServletRequestListener.java,v 1.2 2006/02/28 07:32:47 rickknowles Exp $ */ public interface ServletRequestListener extends EventListener { public void requestDestroyed(ServletRequestEvent sre); public void requestInitialized(ServletRequestEvent sre); } jenkins-winstone-0.9.10-jenkins-47/src/java/javax/servlet/http/0000755000175000017500000000000012200024521024717 5ustar jamespagejamespagejenkins-winstone-0.9.10-jenkins-47/src/java/javax/servlet/http/HttpSessionBindingEvent.java0000644000175000017500000000166412200024521032351 0ustar jamespagejamespage/* * Copyright 2003-2006 Rick Knowles * Distributed under the terms of either: * - the common development and distribution license (CDDL), v1.0; or * - the GNU Lesser General Public License, v2.1 or later */ package javax.servlet.http; /** * An object addition or removal notification * * @author Rick Knowles */ public class HttpSessionBindingEvent extends HttpSessionEvent { private String name; private Object value; public HttpSessionBindingEvent(HttpSession session, String name) { super(session); this.name = name; } public HttpSessionBindingEvent(HttpSession session, String name, Object value) { this(session, name); this.value = value; } public String getName() { return this.name; } public Object getValue() { return this.value; } } jenkins-winstone-0.9.10-jenkins-47/src/java/javax/servlet/http/HttpSessionListener.java0000644000175000017500000000113412200024521031552 0ustar jamespagejamespage/* * Copyright 2003-2006 Rick Knowles * Distributed under the terms of either: * - the common development and distribution license (CDDL), v1.0; or * - the GNU Lesser General Public License, v2.1 or later */ package javax.servlet.http; /** * Listener events for session creation and destruction * * @author Rick Knowles */ public interface HttpSessionListener extends java.util.EventListener { public void sessionCreated(HttpSessionEvent se); public void sessionDestroyed(HttpSessionEvent se); } jenkins-winstone-0.9.10-jenkins-47/src/java/javax/servlet/http/Cookie.java0000644000175000017500000000664412200024521027005 0ustar jamespagejamespage/* * Copyright 2003-2006 Rick Knowles * Distributed under the terms of either: * - the common development and distribution license (CDDL), v1.0; or * - the GNU Lesser General Public License, v2.1 or later */ package javax.servlet.http; /** * Cookie model value object * * @author Rick Knowles */ public class Cookie implements Cloneable { private String name; private String value; private String comment; private String domain; private String path; private boolean secure; private int maxAge; private int version; public Cookie(String name, String value) { setName(name); setValue(value); setMaxAge(-1); } public Object clone() { Cookie clone = new Cookie(this.name, this.value); clone.setComment(this.comment); clone.setDomain(this.domain); clone.setMaxAge(this.maxAge); clone.setSecure(this.secure); clone.setVersion(this.version); clone.setPath(this.path); return clone; } public String getComment() { return this.comment; } public String getDomain() { return this.domain; } public int getMaxAge() { return this.maxAge; } public String getName() { return this.name; } public String getPath() { return this.path; } public boolean getSecure() { return this.secure; } public String getValue() { return this.value; } public int getVersion() { return this.version; } private void setName(String name) { if (name == null) { throw new IllegalArgumentException("Cookie name was null"); } else if (name.indexOf(";") != -1) { throw new IllegalArgumentException("Cookie name contains a semicolon"); } else if (name.indexOf(",") != -1) { throw new IllegalArgumentException("Cookie name contains a comma"); } else if (name.startsWith("$")) { throw new IllegalArgumentException("Cookie name starts with $"); } else { // Check for white space, comma, semicolon for (int n = 0; n < name.length(); n++) { char c = name.charAt(n); if (c <= 0x20 || c >= 0x7f) { throw new IllegalArgumentException("Cookie name contains whitespace or " + "non-alphanumeric char: " + name.charAt(n) + " in " + name); } } this.name = name; } } public void setComment(String purpose) { this.comment = purpose; } public void setDomain(String pattern) { this.domain = pattern; } public void setMaxAge(int expiry) { this.maxAge = expiry; } public void setPath(String uri) { this.path = uri; } public void setSecure(boolean flag) { this.secure = flag; } public void setValue(String newValue) { this.value = newValue; } public void setVersion(int v) { this.version = v; } public String toString() { return "[Cookie: name=" + this.name + " value=" + this.value + " version=" + this.version + " path=" + this.path + " domain=" + this.domain + " comment=" + this.comment + " maxAge=" + this.maxAge + " secure=" + this.secure + "]"; } } jenkins-winstone-0.9.10-jenkins-47/src/java/javax/servlet/http/HttpServlet.java0000644000175000017500000001567612200024521030065 0ustar jamespagejamespage/* * Copyright 2003-2006 Rick Knowles * Distributed under the terms of either: * - the common development and distribution license (CDDL), v1.0; or * - the GNU Lesser General Public License, v2.1 or later */ package javax.servlet.http; import java.io.IOException; import java.io.OutputStreamWriter; import java.io.PrintWriter; import java.io.Serializable; import java.io.UnsupportedEncodingException; import javax.servlet.ServletException; import javax.servlet.ServletOutputStream; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; /** * Base class for http servlets * * @author Rick Knowles */ public abstract class HttpServlet extends javax.servlet.GenericServlet implements Serializable { static final String METHOD_DELETE = "DELETE"; static final String METHOD_HEAD = "HEAD"; static final String METHOD_GET = "GET"; static final String METHOD_OPTIONS = "OPTIONS"; static final String METHOD_POST = "POST"; static final String METHOD_PUT = "PUT"; static final String METHOD_TRACE = "TRACE"; static final String HEADER_IFMODSINCE = "If-Modified-Since"; static final String HEADER_LASTMOD = "Last-Modified"; public HttpServlet() { super(); } public void service(ServletRequest request, ServletResponse response) throws ServletException, IOException { if ((request instanceof HttpServletRequest) && (response instanceof HttpServletResponse)) service((HttpServletRequest) request, (HttpServletResponse) response); else throw new IllegalArgumentException( "Not an Http servlet request - invalid types"); } private void notAcceptedMethod(HttpServletRequest request, HttpServletResponse response, String method) throws ServletException, IOException { if (request.getProtocol().endsWith("1.1")) response.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, method + " not allowed"); else response.sendError(HttpServletResponse.SC_BAD_REQUEST, method + " not allowed"); } protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { notAcceptedMethod(req, resp, "GET"); } protected long getLastModified(HttpServletRequest req) { return -1; } protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { notAcceptedMethod(req, resp, "POST"); } protected void doPut(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { notAcceptedMethod(req, resp, "PUT"); } protected void doDelete(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { notAcceptedMethod(req, resp, "DELETE"); } protected void doOptions(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { notAcceptedMethod(req, resp, "OPTIONS"); } protected void doTrace(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { notAcceptedMethod(req, resp, "TRACE"); } protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String method = request.getMethod(); if (method.equals(METHOD_GET)) { long lastModified = getLastModified(request); if (lastModified == -1) doGet(request, response); else { long ifModifiedSince = request.getDateHeader(HEADER_IFMODSINCE); if (ifModifiedSince < (lastModified / 1000 * 1000)) { if (!response.containsHeader(HEADER_LASTMOD) && (lastModified >= 0)) response.setDateHeader(HEADER_LASTMOD, lastModified); doGet(request, response); } else response.setStatus(HttpServletResponse.SC_NOT_MODIFIED); } } else if (method.equals(METHOD_HEAD)) { long lastModified = getLastModified(request); if (!response.containsHeader(HEADER_LASTMOD) && (lastModified >= 0)) response.setDateHeader(HEADER_LASTMOD, lastModified); doHead(request, response); } else if (method.equals(METHOD_POST)) doPost(request, response); else if (method.equals(METHOD_PUT)) doPut(request, response); else if (method.equals(METHOD_DELETE)) doDelete(request, response); else if (method.equals(METHOD_OPTIONS)) doOptions(request, response); else if (method.equals(METHOD_TRACE)) doTrace(request, response); else notAcceptedMethod(request, response, method); } protected void doHead(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { NoBodyResponse response = new NoBodyResponse(resp); doGet(req, response); response.setContentLength(); } class NoBodyResponse extends HttpServletResponseWrapper { private NoBodyOutputStream noBody; private PrintWriter writer; private boolean contentLengthSet; NoBodyResponse(HttpServletResponse mainResponse) { super(mainResponse); this.noBody = new NoBodyOutputStream(); } void setContentLength() { if (!contentLengthSet) setContentLength(this.noBody.getContentLength()); } public void setContentLength(int length) { super.setContentLength(length); this.contentLengthSet = true; } public void setContentType(String type) { getResponse().setContentType(type); } public ServletOutputStream getOutputStream() throws IOException { return noBody; } public String getCharacterEncoding() { return getResponse().getCharacterEncoding(); } public PrintWriter getWriter() throws UnsupportedEncodingException { if (writer == null) writer = new PrintWriter(new OutputStreamWriter(noBody, getCharacterEncoding())); return writer; } } class NoBodyOutputStream extends ServletOutputStream { private int contentLength = 0; NoBodyOutputStream() { } int getContentLength() { return contentLength; } public void write(int b) throws IOException { contentLength++; } public void write(byte buf[], int offset, int len) throws IOException { contentLength += len; } } } jenkins-winstone-0.9.10-jenkins-47/src/java/javax/servlet/http/HttpSessionAttributeListener.java0000644000175000017500000000125012200024521033435 0ustar jamespagejamespage/* * Copyright 2003-2006 Rick Knowles * Distributed under the terms of either: * - the common development and distribution license (CDDL), v1.0; or * - the GNU Lesser General Public License, v2.1 or later */ package javax.servlet.http; /** * Interface for session attribute listeners * * @author Rick Knowles */ public interface HttpSessionAttributeListener extends java.util.EventListener { public void attributeAdded(HttpSessionBindingEvent se); public void attributeRemoved(HttpSessionBindingEvent se); public void attributeReplaced(HttpSessionBindingEvent se); } jenkins-winstone-0.9.10-jenkins-47/src/java/javax/servlet/http/HttpUtils.java0000644000175000017500000000774212200024521027534 0ustar jamespagejamespage/* * Copyright 2003-2006 Rick Knowles * Distributed under the terms of either: * - the common development and distribution license (CDDL), v1.0; or * - the GNU Lesser General Public License, v2.1 or later */ package javax.servlet.http; import winstone.SizeRestrictedHashtable; import java.util.Hashtable; import javax.servlet.ServletInputStream; import java.util.StringTokenizer; /** * Generic utility functions for use in the servlet container. * * @author Rick Knowles */ public class HttpUtils { /** * @deprecated Reconstructs the URL the client used to make the request, * using information in the HttpServletRequest object. */ public static StringBuffer getRequestURL(HttpServletRequest req) { return req.getRequestURL(); } /** * @deprecated Parses data from an HTML form that the client sends to the * server using the HTTP POST method and the * application/x-www-form-urlencoded MIME type. */ public static Hashtable parsePostData(int len, ServletInputStream in) { try { byte body[] = new byte[len]; int startPos = 0; int readChars = in.read(body, startPos, len - startPos); while ((readChars != -1) && (len != startPos)) { startPos += readChars; readChars = in.read(body, startPos, len - startPos); } if (len != startPos) throw new java.io.IOException("Stream ended early"); else { String post = new String(body, 0, len, "8859_1"); return parseQueryString(post); } } catch (java.io.IOException err) { throw new IllegalArgumentException("Error parsing request body - " + err.getMessage()); } } /** * @deprecated Parses a query string passed from the client to the server * and builds a HashTable object with key-value pairs. */ public static Hashtable parseQueryString(String urlEncodedParams) { Hashtable params = new SizeRestrictedHashtable(MAX_PARAMETER_COUNT); StringTokenizer st = new StringTokenizer(urlEncodedParams, "&", false); while (st.hasMoreTokens()) { String token = st.nextToken(); int equalPos = token.indexOf('='); if (equalPos == -1) continue; String name = token.substring(0, equalPos); String value = token.substring(equalPos + 1); String decodedName = decodeURLToken(name); String decodedValue = decodeURLToken(value); Object already = params.get(decodedName); if (already == null) params.put(decodedName, new String[] { decodedValue }); else if (already instanceof String[]) { String alreadyArray[] = (String[]) already; String oneMore[] = new String[alreadyArray.length + 1]; System.arraycopy(alreadyArray, 0, oneMore, 0, alreadyArray.length); oneMore[oneMore.length - 1] = decodedValue; params.put(decodedName, oneMore); } } return params; } private static String decodeURLToken(String in) { StringBuilder workspace = new StringBuilder(); for (int n = 0; n < in.length(); n++) { char thisChar = in.charAt(n); if (thisChar == '+') workspace.append(' '); else if (thisChar == '%') { int decoded = Integer.parseInt(in.substring(n + 1, n + 3), 16); workspace.append((char) decoded); n += 2; } else workspace.append(thisChar); } return workspace.toString(); } public static int MAX_PARAMETER_COUNT = Integer.getInteger(HttpUtils.class.getName()+".maxParameterCount",10000); } jenkins-winstone-0.9.10-jenkins-47/src/java/javax/servlet/http/HttpSession.java0000644000175000017500000000370412200024521030051 0ustar jamespagejamespage/* * Copyright 2003-2006 Rick Knowles * Distributed under the terms of either: * - the common development and distribution license (CDDL), v1.0; or * - the GNU Lesser General Public License, v2.1 or later */ package javax.servlet.http; import java.util.Enumeration; import javax.servlet.ServletContext; /** * Interface for http sessions on the server. * * @author Rick Knowles */ public interface HttpSession { public Object getAttribute(String name); public Enumeration getAttributeNames(); public long getCreationTime(); public String getId(); public long getLastAccessedTime(); public int getMaxInactiveInterval(); public ServletContext getServletContext(); public void invalidate(); public boolean isNew(); public void removeAttribute(String name); public void setAttribute(String name, Object value); public void setMaxInactiveInterval(int interval); /** * @deprecated As of Version 2.1, this method is deprecated and has no * replacement. It will be removed in a future version of the * Java Servlet API. */ public HttpSessionContext getSessionContext(); /** * @deprecated As of Version 2.2, this method is replaced by * getAttribute(java.lang.String). */ public Object getValue(String name); /** * @deprecated As of Version 2.2, this method is replaced by * getAttributeNames() */ public String[] getValueNames(); /** * @deprecated As of Version 2.2, this method is replaced by * setAttribute(java.lang.String, java.lang.Object) */ public void putValue(String name, Object value); /** * @deprecated As of Version 2.2, this method is replaced by * removeAttribute(java.lang.String) */ public void removeValue(String name); } jenkins-winstone-0.9.10-jenkins-47/src/java/javax/servlet/http/HttpSessionContext.java0000644000175000017500000000123112200024521031407 0ustar jamespagejamespage/* * Copyright 2003-2006 Rick Knowles * Distributed under the terms of either: * - the common development and distribution license (CDDL), v1.0; or * - the GNU Lesser General Public License, v2.1 or later */ package javax.servlet.http; /** * Shared session context interface - deprecated * * @author Rick Knowles * @deprecated */ public abstract interface HttpSessionContext { /** * @deprecated */ public abstract java.util.Enumeration getIds(); /** * @deprecated */ public abstract HttpSession getSession(String sessionId); } jenkins-winstone-0.9.10-jenkins-47/src/java/javax/servlet/http/HttpServletResponseWrapper.java0000644000175000017500000000575312200024521033140 0ustar jamespagejamespage/* * Copyright 2003-2006 Rick Knowles * Distributed under the terms of either: * - the common development and distribution license (CDDL), v1.0; or * - the GNU Lesser General Public License, v2.1 or later */ package javax.servlet.http; import java.io.IOException; /** * Wraps HttpServletResponse objects in a decorator pattern * * @author Rick Knowles */ public class HttpServletResponseWrapper extends javax.servlet.ServletResponseWrapper implements HttpServletResponse { private HttpServletResponse httpResponse; public HttpServletResponseWrapper(HttpServletResponse response) { super(response); this.httpResponse = response; } public void setResponse(javax.servlet.ServletResponse response) { if (response instanceof HttpServletResponse) { super.setResponse(response); this.httpResponse = (HttpServletResponse) response; } else throw new IllegalArgumentException("Not an HttpServletResponse"); } public void addCookie(Cookie cookie) { this.httpResponse.addCookie(cookie); } public void addDateHeader(String name, long date) { this.httpResponse.addDateHeader(name, date); } public void addHeader(String name, String value) { this.httpResponse.addHeader(name, value); } public void addIntHeader(String name, int value) { this.httpResponse.addIntHeader(name, value); } public boolean containsHeader(String name) { return this.httpResponse.containsHeader(name); } public String encodeRedirectURL(String url) { return this.httpResponse.encodeRedirectURL(url); } public String encodeURL(String url) { return this.httpResponse.encodeURL(url); } public void sendError(int sc) throws IOException { this.httpResponse.sendError(sc); } public void sendError(int sc, String msg) throws IOException { this.httpResponse.sendError(sc, msg); } public void sendRedirect(String location) throws IOException { this.httpResponse.sendRedirect(location); } public void setDateHeader(String name, long date) { this.httpResponse.setDateHeader(name, date); } public void setHeader(String name, String value) { this.httpResponse.setHeader(name, value); } public void setIntHeader(String name, int value) { this.httpResponse.setIntHeader(name, value); } public void setStatus(int sc) { this.httpResponse.setStatus(sc); } /** * @deprecated */ public String encodeRedirectUrl(String url) { return this.httpResponse.encodeRedirectUrl(url); } /** * @deprecated */ public String encodeUrl(String url) { return this.httpResponse.encodeUrl(url); } /** * @deprecated */ public void setStatus(int sc, String sm) { this.httpResponse.setStatus(sc, sm); } } jenkins-winstone-0.9.10-jenkins-47/src/java/javax/servlet/http/HttpSessionActivationListener.java0000644000175000017500000000120312200024521033571 0ustar jamespagejamespage/* * Copyright 2003-2006 Rick Knowles * Distributed under the terms of either: * - the common development and distribution license (CDDL), v1.0; or * - the GNU Lesser General Public License, v2.1 or later */ package javax.servlet.http; /** * Interface for listeners interested in the session activation/deactivation * * @author Rick Knowles */ public interface HttpSessionActivationListener extends java.util.EventListener { public void sessionDidActivate(HttpSessionEvent se); public void sessionWillPassivate(HttpSessionEvent se); } jenkins-winstone-0.9.10-jenkins-47/src/java/javax/servlet/http/HttpServletRequest.java0000644000175000017500000000365412200024521031427 0ustar jamespagejamespage/* * Copyright 2003-2006 Rick Knowles * Distributed under the terms of either: * - the common development and distribution license (CDDL), v1.0; or * - the GNU Lesser General Public License, v2.1 or later */ package javax.servlet.http; import java.util.Enumeration; import java.security.Principal; /** * Interface definition for http requests. * * @author Rick Knowles */ public interface HttpServletRequest extends javax.servlet.ServletRequest { public static final String BASIC_AUTH = "BASIC"; public static final String CLIENT_CERT_AUTH = "CLIENT_CERT"; public static final String DIGEST_AUTH = "DIGEST"; public static final String FORM_AUTH = "FORM"; public String getAuthType(); public String getContextPath(); public Cookie[] getCookies(); public long getDateHeader(String name); public String getHeader(String name); public Enumeration getHeaderNames(); public Enumeration getHeaders(String name); public int getIntHeader(String name); public String getMethod(); public String getPathInfo(); public String getPathTranslated(); public String getQueryString(); public String getRemoteUser(); public String getRequestedSessionId(); public String getRequestURI(); public StringBuffer getRequestURL(); public String getServletPath(); public HttpSession getSession(); public HttpSession getSession(boolean create); public Principal getUserPrincipal(); public boolean isRequestedSessionIdFromCookie(); public boolean isRequestedSessionIdFromURL(); public boolean isRequestedSessionIdValid(); public boolean isUserInRole(String role); /** * @deprecated As of Version 2.1 of the Java Servlet API, use * isRequestedSessionIdFromURL() instead. */ public boolean isRequestedSessionIdFromUrl(); } jenkins-winstone-0.9.10-jenkins-47/src/java/javax/servlet/http/HttpSessionEvent.java0000644000175000017500000000120312200024521031043 0ustar jamespagejamespage/* * Copyright 2003-2006 Rick Knowles * Distributed under the terms of either: * - the common development and distribution license (CDDL), v1.0; or * - the GNU Lesser General Public License, v2.1 or later */ package javax.servlet.http; /** * Base event class for session changed events * * @author Rick Knowles */ public class HttpSessionEvent extends java.util.EventObject { public HttpSessionEvent(HttpSession source) { super(source); } public HttpSession getSession() { return (HttpSession) this.source; } } jenkins-winstone-0.9.10-jenkins-47/src/java/javax/servlet/http/HttpServletRequestWrapper.java0000644000175000017500000000712712200024521032767 0ustar jamespagejamespage/* * Copyright 2003-2006 Rick Knowles * Distributed under the terms of either: * - the common development and distribution license (CDDL), v1.0; or * - the GNU Lesser General Public License, v2.1 or later */ package javax.servlet.http; import java.util.Enumeration; import java.security.Principal; /** * Wraps HttpServletRequest objects in a decorator pattern * * @author Rick Knowles */ public class HttpServletRequestWrapper extends javax.servlet.ServletRequestWrapper implements HttpServletRequest { private HttpServletRequest httpRequest; public HttpServletRequestWrapper(HttpServletRequest request) { super(request); this.httpRequest = request; } public void setRequest(javax.servlet.ServletRequest request) { if (request instanceof HttpServletRequest) { super.setRequest(request); this.httpRequest = (HttpServletRequest) request; } else throw new IllegalArgumentException("Not an HttpServletRequest"); } public String getAuthType() { return this.httpRequest.getAuthType(); } public String getContextPath() { return this.httpRequest.getContextPath(); } public Cookie[] getCookies() { return this.httpRequest.getCookies(); } public long getDateHeader(String name) { return this.httpRequest.getDateHeader(name); } public String getHeader(String name) { return this.httpRequest.getHeader(name); } public Enumeration getHeaderNames() { return this.httpRequest.getHeaderNames(); } public Enumeration getHeaders(String name) { return this.httpRequest.getHeaders(name); } public int getIntHeader(String name) { return this.httpRequest.getIntHeader(name); } public String getMethod() { return this.httpRequest.getMethod(); } public String getPathInfo() { return this.httpRequest.getPathInfo(); } public String getPathTranslated() { return this.httpRequest.getPathTranslated(); } public String getQueryString() { return this.httpRequest.getQueryString(); } public String getRemoteUser() { return this.httpRequest.getRemoteUser(); } public String getRequestedSessionId() { return this.httpRequest.getRequestedSessionId(); } public String getRequestURI() { return this.httpRequest.getRequestURI(); } public String getServletPath() { return this.httpRequest.getServletPath(); } public StringBuffer getRequestURL() { return this.httpRequest.getRequestURL(); } public HttpSession getSession() { return this.httpRequest.getSession(); } public HttpSession getSession(boolean create) { return this.httpRequest.getSession(create); } public Principal getUserPrincipal() { return this.httpRequest.getUserPrincipal(); } public boolean isRequestedSessionIdFromCookie() { return this.httpRequest.isRequestedSessionIdFromCookie(); } public boolean isRequestedSessionIdFromURL() { return this.httpRequest.isRequestedSessionIdFromURL(); } public boolean isRequestedSessionIdValid() { return this.httpRequest.isRequestedSessionIdValid(); } public boolean isUserInRole(String role) { return this.httpRequest.isUserInRole(role); } /** * @deprecated */ public boolean isRequestedSessionIdFromUrl() { return this.httpRequest.isRequestedSessionIdFromUrl(); } } jenkins-winstone-0.9.10-jenkins-47/src/java/javax/servlet/http/HttpSessionBindingListener.java0000644000175000017500000000117112200024521033046 0ustar jamespagejamespage/* * Copyright 2003-2006 Rick Knowles * Distributed under the terms of either: * - the common development and distribution license (CDDL), v1.0; or * - the GNU Lesser General Public License, v2.1 or later */ package javax.servlet.http; /** * Listener interface for listeners to the session binding events * * @author Rick Knowles */ public interface HttpSessionBindingListener extends java.util.EventListener { public void valueBound(HttpSessionBindingEvent event); public void valueUnbound(HttpSessionBindingEvent event); } jenkins-winstone-0.9.10-jenkins-47/src/java/javax/servlet/http/HttpServletResponse.java0000644000175000017500000001003212200024521031561 0ustar jamespagejamespage/* * Copyright 2003-2006 Rick Knowles * Distributed under the terms of either: * - the common development and distribution license (CDDL), v1.0; or * - the GNU Lesser General Public License, v2.1 or later */ package javax.servlet.http; import java.io.IOException; /** * Interface definition for http response objects. * * @author Rick Knowles */ public interface HttpServletResponse extends javax.servlet.ServletResponse { public static final int SC_ACCEPTED = 202; public static final int SC_BAD_GATEWAY = 502; public static final int SC_BAD_REQUEST = 400; public static final int SC_CONFLICT = 409; public static final int SC_CONTINUE = 100; public static final int SC_CREATED = 201; public static final int SC_EXPECTATION_FAILED = 417; public static final int SC_FORBIDDEN = 403; public static final int SC_FOUND = 302; public static final int SC_GATEWAY_TIMEOUT = 504; public static final int SC_GONE = 410; public static final int SC_HTTP_VERSION_NOT_SUPPORTED = 505; public static final int SC_INTERNAL_SERVER_ERROR = 500; public static final int SC_LENGTH_REQUIRED = 411; public static final int SC_METHOD_NOT_ALLOWED = 405; public static final int SC_MOVED_PERMANENTLY = 301; public static final int SC_MOVED_TEMPORARILY = 302; public static final int SC_MULTIPLE_CHOICES = 300; public static final int SC_NO_CONTENT = 204; public static final int SC_NON_AUTHORITATIVE_INFORMATION = 203; public static final int SC_NOT_ACCEPTABLE = 406; public static final int SC_NOT_FOUND = 404; public static final int SC_NOT_IMPLEMENTED = 501; public static final int SC_NOT_MODIFIED = 304; public static final int SC_OK = 200; public static final int SC_PARTIAL_CONTENT = 206; public static final int SC_PAYMENT_REQUIRED = 402; public static final int SC_PRECONDITION_FAILED = 412; public static final int SC_PROXY_AUTHENTICATION_REQUIRED = 407; public static final int SC_REQUEST_ENTITY_TOO_LARGE = 413; public static final int SC_REQUEST_TIMEOUT = 408; public static final int SC_REQUEST_URI_TOO_LONG = 414; public static final int SC_REQUESTED_RANGE_NOT_SATISFIABLE = 416; public static final int SC_RESET_CONTENT = 205; public static final int SC_SEE_OTHER = 303; public static final int SC_SERVICE_UNAVAILABLE = 503; public static final int SC_SWITCHING_PROTOCOLS = 101; public static final int SC_TEMPORARY_REDIRECT = 307; public static final int SC_UNAUTHORIZED = 401; public static final int SC_UNSUPPORTED_MEDIA_TYPE = 415; public static final int SC_USE_PROXY = 305; public void addCookie(Cookie cookie); public void addDateHeader(String name, long date); public void addHeader(String name, String value); public void addIntHeader(String name, int value); public boolean containsHeader(String name); public String encodeRedirectURL(String url); public String encodeURL(String url); public void sendError(int sc) throws IOException; public void sendError(int sc, String msg) throws IOException; public void sendRedirect(String location) throws IOException; public void setDateHeader(String name, long date); public void setHeader(String name, String value); public void setIntHeader(String name, int value); public void setStatus(int sc); /** * @deprecated As of version 2.1, due to ambiguous meaning of the message * parameter. To set a status code use setStatus(int), to send * an error with a description use sendError(int, String). Sets * the status code and message for this response. */ public void setStatus(int sc, String sm); /** * @deprecated As of version 2.1, use encodeRedirectURL(String url) instead */ public String encodeRedirectUrl(String url); /** * @deprecated As of version 2.1, use encodeURL(String url) instead */ public String encodeUrl(String url); } jenkins-winstone-0.9.10-jenkins-47/src/java/javax/servlet/ServletRequestAttributeEvent.java0000644000175000017500000000171612200024521032473 0ustar jamespagejamespage/* * Copyright 2003-2006 Rick Knowles * Distributed under the terms of either: * - the common development and distribution license (CDDL), v1.0; or * - the GNU Lesser General Public License, v2.1 or later */ package javax.servlet; /** * The event thrown to request attribute listeners * * @author Rick Knowles * @version $Id: ServletRequestAttributeEvent.java,v 1.2 2006/02/28 07:32:47 rickknowles Exp $ */ public class ServletRequestAttributeEvent extends ServletRequestEvent { private String name; private Object value; public ServletRequestAttributeEvent(ServletContext sc, ServletRequest request, String name, Object value) { super(sc, request); this.name = name; this.value = value; } public String getName() { return this.name; } public Object getValue() { return this.value; } } jenkins-winstone-0.9.10-jenkins-47/src/java/javax/servlet/FilterChain.java0000644000175000017500000000112312200024521026770 0ustar jamespagejamespage/* * Copyright 2003-2006 Rick Knowles * Distributed under the terms of either: * - the common development and distribution license (CDDL), v1.0; or * - the GNU Lesser General Public License, v2.1 or later */ package javax.servlet; /** * Interface def for chains of filters before invoking the resource. * * @author Rick Knowles */ public interface FilterChain { public void doFilter(ServletRequest request, ServletResponse response) throws java.io.IOException, ServletException; } jenkins-winstone-0.9.10-jenkins-47/src/java/javax/servlet/ServletException.java0000644000175000017500000000171112200024521030106 0ustar jamespagejamespage/* * Copyright 2003-2006 Rick Knowles * Distributed under the terms of either: * - the common development and distribution license (CDDL), v1.0; or * - the GNU Lesser General Public License, v2.1 or later */ package javax.servlet; import java.io.PrintWriter; import java.io.PrintStream; /** * Generic servlet exception * * @author Rick Knowles */ public class ServletException extends java.lang.Exception { private Throwable rootCause; public ServletException() { super(); } public ServletException(String message) { super(message); } public ServletException(String message, Throwable rootCause) { super(message,rootCause); this.rootCause = rootCause; } public ServletException(Throwable rootCause) { super(rootCause); this.rootCause = rootCause; } public Throwable getRootCause() { return this.rootCause; } } jenkins-winstone-0.9.10-jenkins-47/src/java/javax/servlet/ServletContextAttributeEvent.java0000644000175000017500000000143712200024521032467 0ustar jamespagejamespage/* * Copyright 2003-2006 Rick Knowles * Distributed under the terms of either: * - the common development and distribution license (CDDL), v1.0; or * - the GNU Lesser General Public License, v2.1 or later */ package javax.servlet; /** * @author Rick Knowles */ public class ServletContextAttributeEvent extends ServletContextEvent { private String name; private Object value; public ServletContextAttributeEvent(ServletContext source, String name, Object value) { super(source); this.name = name; this.value = value; } public String getName() { return this.name; } public Object getValue() { return this.value; } } jenkins-winstone-0.9.10-jenkins-47/src/java/javax/servlet/UnavailableException.java0000644000175000017500000000443012200024521030706 0ustar jamespagejamespage/* * Copyright 2003-2006 Rick Knowles * Distributed under the terms of either: * - the common development and distribution license (CDDL), v1.0; or * - the GNU Lesser General Public License, v2.1 or later */ package javax.servlet; /** * Thrown if a servlet is permanently or temporarily unavailable * * @author Rick Knowles * @version $Id: UnavailableException.java,v 1.2 2006/02/28 07:32:47 rickknowles Exp $ */ public class UnavailableException extends ServletException { private int seconds; private Servlet servlet; /** * @deprecated As of Java Servlet API 2.2, use UnavailableException(String, * int) instead. */ public UnavailableException(int seconds, Servlet servlet, String msg) { this(servlet, msg); this.seconds = (seconds <= 0 ? 0 : seconds); } /** * @deprecated As of Java Servlet API 2.2, use UnavailableException(String) * instead. */ public UnavailableException(Servlet servlet, String msg) { this(msg); this.servlet = servlet; } /** * Constructs a new exception with a descriptive message indicating that the * servlet is permanently unavailable. */ public UnavailableException(String msg) { super(msg); } /** * Constructs a new exception with a descriptive message indicating that the * servlet is temporarily unavailable and giving an estimate of how long it * will be unavailable. */ public UnavailableException(String msg, int seconds) { this(msg); this.seconds = (seconds <= 0 ? 0 : seconds); } /** * @deprecated As of Java Servlet API 2.2, with no replacement. Returns the * servlet that is reporting its unavailability. */ public Servlet getServlet() { return this.servlet; } /** * Returns the number of seconds the servlet expects to be temporarily * unavailable. */ public int getUnavailableSeconds() { return this.seconds; } /** * Returns a boolean indicating whether the servlet is permanently * unavailable. */ public boolean isPermanent() { return this.seconds <= 0; } } jenkins-winstone-0.9.10-jenkins-47/src/java/javax/servlet/ServletOutputStream.java0000644000175000017500000000345312200024521030631 0ustar jamespagejamespage/* * Copyright 2003-2006 Rick Knowles * Distributed under the terms of either: * - the common development and distribution license (CDDL), v1.0; or * - the GNU Lesser General Public License, v2.1 or later */ package javax.servlet; import java.io.IOException; import java.io.OutputStream; /** * @author Rick Knowles */ public abstract class ServletOutputStream extends OutputStream { final String CR_LF = "\r\n"; protected ServletOutputStream() { super(); } public void print(boolean b) throws IOException { print("" + b); } public void print(char c) throws IOException { print("" + c); } public void print(double d) throws IOException { print("" + d); } public void print(float f) throws IOException { print("" + f); } public void print(int i) throws IOException { print("" + i); } public void print(long l) throws IOException { print("" + l); } public void print(String s) throws IOException { write(s.getBytes()); } public void println() throws IOException { println(""); } public void println(boolean b) throws IOException { println("" + b); } public void println(char c) throws IOException { println("" + c); } public void println(double d) throws IOException { println("" + d); } public void println(float f) throws IOException { println("" + f); } public void println(int i) throws IOException { println("" + i); } public void println(long l) throws IOException { println("" + l); } public void println(String s) throws IOException { print(s + CR_LF); } } jenkins-winstone-0.9.10-jenkins-47/src/test/0000755000175000017500000000000012200024521021201 5ustar jamespagejamespagejenkins-winstone-0.9.10-jenkins-47/src/test/winstone/0000755000175000017500000000000012200024521023047 5ustar jamespagejamespagejenkins-winstone-0.9.10-jenkins-47/src/test/winstone/WinstoneRequestTest.java0000644000175000017500000000236512200024521027737 0ustar jamespagejamespagepackage winstone; import java.util.Arrays; import java.util.Collections; import java.util.Locale; import static org.junit.Assert.*; import org.junit.Test; public class WinstoneRequestTest { @SuppressWarnings("unchecked") @Test public void getHeader() throws Exception { WinstoneRequest r = new WinstoneRequest(); r.parseHeaders(Arrays.asList("Foo: bar", "Baz-Quux: true", "include: stuff", "include: more stuff")); assertEquals("bar", r.getHeader("Foo")); assertEquals("bar", r.getHeader("foo")); assertEquals(null, r.getHeader("Foo:")); assertEquals(null, r.getHeader("Fooz")); assertEquals(null, r.getHeader("Fo")); assertEquals("true", r.getHeader("baz-quux")); Locale l = Locale.getDefault(); Locale.setDefault(Locale.forLanguageTag("tr")); try { assertEquals("stuff", r.getHeader("Include")); assertEquals(Arrays.asList("stuff", "more stuff"), Collections.list(r.getHeaders("Include"))); } finally { Locale.setDefault(l); } assertEquals(Collections.emptyList(), Collections.list(r.getHeaders("includ"))); assertEquals(Collections.emptyList(), Collections.list(r.getHeaders("includes"))); } } jenkins-winstone-0.9.10-jenkins-47/src/test/winstone/URIUtilTest.java0000644000175000017500000000157512200024521026057 0ustar jamespagejamespagepackage winstone; import junit.framework.TestCase; /** * @author Kohsuke Kawaguchi */ public class URIUtilTest extends TestCase { public void test1() { assertIdemPotent("/"); assertIdemPotent(""); assertIdemPotent("/foo"); assertIdemPotent("/bar/"); assertIdemPotent("zot/"); testC12n("","."); testC12n("","foo/.."); testC12n("foo", "foo/bar/./.."); testC12n("/abc","/abc"); testC12n("/abc/","/abc/"); testC12n("/","/abc/../"); testC12n("/","/abc/def/../../"); testC12n("/def","/abc/../def"); testC12n("/xxx","/../../../xxx"); } private void testC12n(String expected, String input) { assertEquals(expected, URIUtil.canonicalPath(input)); } private void assertIdemPotent(String str) { assertEquals(str,URIUtil.canonicalPath(str)); } } jenkins-winstone-0.9.10-jenkins-47/src/test/winstone/WinstoneResponseTest.java0000644000175000017500000000324212200024521030100 0ustar jamespagejamespagepackage winstone; import static org.hamcrest.CoreMatchers.*; import static org.junit.Assert.*; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletResponse; import org.junit.Test; public class WinstoneResponseTest { @SuppressWarnings("unchecked") @Test public void testCookieExpires() throws Exception { WinstoneResponse response = new WinstoneResponse(); Cookie cookie = new Cookie("testcookie", "cookievalue"); cookie.setMaxAge(1000); String cookieAsString = response.writeCookie(cookie); assertTrue("expires date format", cookieAsString.matches(".*Expires=\\w{3}, \\d{1,2}-\\w{3}-\\d{4} \\d{1,2}:\\d{1,2}:\\d{1,2} GMT.*")); } @Test public void testValidateHeadersWhenOk() throws Exception { WinstoneResponse response = setupResponse(HttpServletResponse.SC_OK); response.validateHeaders(); String contentType = response.getHeader(WinstoneResponse.CONTENT_TYPE_HEADER); assertThat(contentType, containsString("text/html")); } @Test public void testValidateHeadersWhenNotModified() throws Exception { WinstoneResponse response = setupResponse(HttpServletResponse.SC_NOT_MODIFIED); response.validateHeaders(); String contentType = response.getHeader(WinstoneResponse.CONTENT_TYPE_HEADER); assertThat(contentType, is(nullValue())); } private WinstoneResponse setupResponse(int statusCode) { WinstoneRequest request = new WinstoneRequest(); WinstoneResponse response = new WinstoneResponse(); response.setOutputStream(new WinstoneOutputStream(null, false)); response.setRequest(request); response.setProtocol("HTTP/1.1"); response.setStatus(statusCode); return response; } } jenkins-winstone-0.9.10-jenkins-47/src/test/winstone/BoundedExecutorServiceDriver.java0000644000175000017500000000355512200024521031516 0ustar jamespagejamespagepackage winstone; import junit.framework.TestCase; import java.util.concurrent.ExecutorService; import java.util.concurrent.SynchronousQueue; import java.util.concurrent.ThreadFactory; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; /** * @author Kohsuke Kawaguchi */ public class BoundedExecutorServiceDriver extends TestCase { public static void main(String[] args) throws Exception { ExecutorService es = new ThreadPoolExecutor(2, Integer.MAX_VALUE, 5L, TimeUnit.SECONDS, // idle thread will only hang around for 60 secs new SynchronousQueue(), new ThreadFactory() { private int threadIndex; public synchronized Thread newThread(Runnable r) { String threadName = Launcher.RESOURCES.getString( "RequestHandlerThread.ThreadName", "" + (++threadIndex)); // allocate a thread to run on this object Thread thread = new Thread(r, threadName); thread.setDaemon(true); return thread; } }); BoundedExecutorService bes = new BoundedExecutorService(es,5); for (int i=0; i<20; i++) { final int n = i; bes.submit(new Runnable() { public void run() { try { System.out.println("#"+n+" started"); Thread.sleep(1000); System.out.println("#"+n+" stopped"); } catch (InterruptedException e) { e.printStackTrace(); } } }); Thread.sleep(100); } Thread.sleep(100000); } } jenkins-winstone-0.9.10-jenkins-47/src/test/winstone/testCase/0000755000175000017500000000000012200024521024622 5ustar jamespagejamespagejenkins-winstone-0.9.10-jenkins-47/src/test/winstone/testCase/HttpConnectorTest.java0000644000175000017500000001162012200024521031117 0ustar jamespagejamespage/* * Copyright 2003-2006 Rick Knowles * Distributed under the terms of either: * - the common development and distribution license (CDDL), v1.0; or * - the GNU Lesser General Public License, v2.1 or later */ package winstone.testCase; import java.io.IOException; import java.io.InputStream; import java.util.HashMap; import java.util.Map; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; import org.xml.sax.SAXException; import winstone.Launcher; import winstone.Logger; import com.meterware.httpunit.GetMethodWebRequest; import com.meterware.httpunit.WebConversation; import com.meterware.httpunit.WebImage; import com.meterware.httpunit.WebRequest; import com.meterware.httpunit.WebResponse; /** * Test case for the Http Connector to Winstone. Simulates a simple connect and * retrieve case, then a keep-alive connection case. * * @author mailto: Rick Knowles * @version $Id: HttpConnectorTest.java,v 1.8 2007/04/23 15:06:22 rickknowles Exp $ */ public class HttpConnectorTest extends TestCase { public static Test suite() { return (new TestSuite(HttpConnectorTest.class)); } /** * Constructor */ public HttpConnectorTest(String name) { super(name); } /** * Test the simple case of connecting, retrieving and disconnecting */ public void testSimpleConnection() throws IOException, SAXException, InterruptedException { // Initialise container Map args = new HashMap(); args.put("webroot", "target/testwebapp"); args.put("prefix", "/examples"); args.put("httpPort", "10003"); args.put("ajp13Port", "-1"); args.put("controlPort", "-1"); args.put("debug", "8"); args.put("logThrowingLineNo", "true"); Logger.init(Logger.FULL_DEBUG, System.out, true); Launcher winstone = new Launcher(args); // Check for a simple connection WebConversation wc = new WebConversation(); WebRequest wreq = new GetMethodWebRequest( "http://localhost:10003/examples/CountRequestsServlet"); WebResponse wresp = wc.getResponse(wreq); InputStream content = wresp.getInputStream(); assertTrue("Loading CountRequestsServlet", content.available() > 0); content.close(); winstone.shutdown(); Thread.sleep(500); } /** * Test the keep alive case */ public void testKeepAliveConnection() throws IOException, InterruptedException, SAXException { // Initialise container Map args = new HashMap(); args.put("webroot", "target/testwebapp"); args.put("prefix", "/examples"); args.put("httpPort", "10004"); args.put("ajp13Port", "-1"); args.put("controlPort", "-1"); args.put("debug", "8"); args.put("logThrowingLineNo", "true"); Logger.init(Logger.FULL_DEBUG, System.out, true); Launcher winstone = new Launcher(args); // Check for a simple connection WebConversation wc = new WebConversation(); WebRequest wreq = new GetMethodWebRequest( "http://localhost:10004/examples/CountRequestsServlet"); WebResponse wresp1 = wc.getResponse(wreq); WebImage img[] = wresp1.getImages(); for (WebImage anImg : img) wc.getResponse(anImg.getRequest()); // Thread.sleep(2000); // WebResponse wresp2 = wc.getResponse(wreq); // Thread.sleep(2000); //WebResponse wresp3 = wc.getResponse(wreq); InputStream content = wresp1.getInputStream(); assertTrue("Loading CountRequestsServlet + child images", content .available() > 0); content.close(); winstone.shutdown(); Thread.sleep(500); } /** * Test the keep alive case */ public void testWriteAfterServlet() throws IOException, InterruptedException, SAXException { // Initialise container Map args = new HashMap(); args.put("webroot", "target/testwebapp"); args.put("prefix", "/examples"); args.put("httpPort", "10005"); args.put("ajp13Port", "-1"); args.put("controlPort", "-1"); args.put("debug", "8"); args.put("logThrowingLineNo", "true"); Logger.init(Logger.FULL_DEBUG, System.out, true); Launcher winstone = new Launcher(args); // Check for a simple connection WebConversation wc = new WebConversation(); WebRequest wreq = new GetMethodWebRequest( "http://localhost:10005/examples/TestWriteAfterServlet"); WebResponse wresp1 = wc.getResponse(wreq); Logger.logDirectMessage(Logger.INFO, "log", "Output: " + wresp1.getText(), null); assertTrue(wresp1.getText().endsWith("Hello")); winstone.shutdown(); Thread.sleep(500); } } jenkins-winstone-0.9.10-jenkins-47/src/test/winstone/testCase/Base64Test.java0000644000175000017500000000452312200024521027355 0ustar jamespagejamespagepackage winstone.testCase; import junit.framework.TestCase; import winstone.auth.BasicAuthenticationHandler; public class Base64Test extends TestCase { public Base64Test(String name) { super(name); } // The letters a-y encoded in base 64 private static String ENCODED_PLUS_ONE = "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eQ=="; private static String ENCODED_PLUS_TWO = "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXo="; public void testDecode() throws Exception { String decoded = decodeBase64(ENCODED_PLUS_TWO); String expected = "abcdefghijklmnopqrstuvwxyz"; assertEquals("Straight decode failed", expected, decoded); decoded = decodeBase64(ENCODED_PLUS_ONE); expected = "abcdefghijklmnopqrstuvwxy"; assertEquals("Decode failed", expected, decoded); } public static void testVersusPostgres() throws Exception { String decoded = decodeBase64("MTIzNDU2Nzg5MA=="); assertEquals("Straight encode failed", "1234567890", decoded); } /** * Expects the classic base64 "abcdefgh=" syntax (equals padded) * and decodes it to original form */ public static String decodeBase64(String input) { char[] inBytes = input.toCharArray(); byte[] outBytes = new byte[(int) (inBytes.length * 0.75f)]; // always mod 4 = 0 int length = BasicAuthenticationHandler.decodeBase64(inBytes, outBytes, 0, inBytes.length, 0); return new String(outBytes, 0, length); } public static String hexEncode(byte input[]) { StringBuilder out = new StringBuilder(); for (byte anInput : input) out.append(Integer.toString((anInput & 0xf0) >> 4, 16)) .append(Integer.toString(anInput & 0x0f, 16)); return out.toString(); } public static byte[] hexDecode(String input) { if (input == null) { return null; } else if (input.length() % 2 != 0) { throw new RuntimeException("Invalid hex for decoding: " + input); } else { byte output[] = new byte[input.length() / 2]; for (int i = 0; i < output.length; i++) { int twoByte = Integer.parseInt(input.substring(i * 2, i * 2 + 2), 16); output[i] = (byte) (twoByte& 0xff); } return output; } } } jenkins-winstone-0.9.10-jenkins-47/src/test/winstone/testCase/StaticResourceServletTest.java0000644000175000017500000000425712200024521032641 0ustar jamespagejamespage/* * Copyright 2003-2006 Rick Knowles * Distributed under the terms of either: * - the common development and distribution license (CDDL), v1.0; or * - the GNU Lesser General Public License, v2.1 or later */ package winstone.testCase; import java.io.File; import java.io.IOException; import junit.framework.TestCase; import winstone.StaticResourceServlet; /** * Automated tests for the url security check inside the static resource servlet * * @author Rick Knowles * @version $Id: StaticResourceServletTest.java,v 1.2 2006/02/28 07:32:49 rickknowles Exp $ */ public class StaticResourceServletTest extends TestCase { /** * Constructor */ public StaticResourceServletTest(String name) { super(name); } public void testIsDescendant() throws IOException { File webroot = new File("src/testwebapp"); File webinf = new File(webroot, "WEB-INF"); assertTrue("Direct subfolder", StaticResourceServlet.isDescendant(webroot, webinf, webroot)); assertTrue("Self is a descendent of itself", StaticResourceServlet.isDescendant(webinf, webinf, webroot)); assertTrue("Direct subfile", StaticResourceServlet.isDescendant(webinf, new File(webinf, "web.xml"), webroot)); assertTrue("Indirect subfile", StaticResourceServlet.isDescendant(webroot, new File(webinf, "web.xml"), webroot)); assertTrue("Backwards iterations", !StaticResourceServlet.isDescendant(webinf, new File(webinf, ".."), webroot)); } public void testCanonicalVersion() throws IOException { File webroot = new File("src/testwebapp"); File webinf = new File(webroot, "WEB-INF"); File webxml = new File(webinf, "web.xml"); assertTrue("Simplest case", StaticResourceServlet.constructOurCanonicalVersion( webxml, webroot).equals("/WEB-INF/web.xml")); assertTrue("One back step", StaticResourceServlet.constructOurCanonicalVersion( new File(webroot, "/test/../WEB-INF/web.xml"), webroot) .equals("/WEB-INF/web.xml")); } } jenkins-winstone-0.9.10-jenkins-47/src/test/winstone/testCase/NamingTest.java0000644000175000017500000001530712200024521027544 0ustar jamespagejamespage/* * Copyright 2003-2006 Rick Knowles * Distributed under the terms of either: * - the common development and distribution license (CDDL), v1.0; or * - the GNU Lesser General Public License, v2.1 or later */ package winstone.testCase; import java.util.Hashtable; import javax.naming.Context; import javax.naming.InitialContext; import javax.naming.NamingEnumeration; import javax.naming.NamingException; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; /** * Automated tests for the JNDI provider component of Winstone * * @author Rick Knowles * @version $Id: NamingTest.java,v 1.2 2006/02/28 07:32:49 rickknowles Exp $ */ public class NamingTest extends TestCase { public static Test suite() { return (new TestSuite(NamingTest.class)); } private InitialContext ic; /** * Constructor for the junit test class for the JNDI service. * * @param name * The name of the test case */ public NamingTest(String name) { super(name); } /** * Begins the setup of the test case */ public void setUp() throws NamingException { Hashtable env = new Hashtable(); env.put(Context.INITIAL_CONTEXT_FACTORY, "winstone.jndi.java.javaURLContextFactory"); env.put(Context.URL_PKG_PREFIXES, "winstone.jndi"); this.ic = new InitialContext(env); } /** * Undoes any setup work for the test case */ public void tearDown() throws NamingException { this.ic.close(); this.ic = null; } /** * Performs an absolute context lookup */ public void testAbsoluteContextLookup() throws NamingException { Object context1 = this.ic.lookup("java:/comp/env"); assertNotNull("Lookup on java:/comp/env must be non-null", context1); assertTrue("Lookup on java:/comp/env must be a Context", context1 instanceof Context); Object context2 = this.ic.lookup("java:/comp/env/"); assertNotNull("Lookup on java:/comp/env/ must be non-null", context2); assertTrue("Lookup on java:/comp/env/ must be a Context", context2 instanceof Context); } /** * Performs an absolute lookup on the context */ public void testAbsoluteLookup() throws NamingException { Object value = this.ic.lookup("java:/comp/env"); assertNotNull("Lookup on java:/comp/env must be non-null", value); } /** * Performs a relative lookup on the context */ public void testRelativeLookup() throws NamingException { Object value = this.ic.lookup(""); assertNotNull("Lookup on \"\" must be non-null", value); } /** * Performs a relative list on the context */ public void testRelativeList() throws NamingException { NamingEnumeration listing = this.ic.list(""); assertNotNull("Listing of current context must be non-null", listing); listing.close(); } /** * Performs an absolute list on the context */ public void testAbsoluteList() throws NamingException { NamingEnumeration listing1 = this.ic.list("java:/comp/env"); assertNotNull("Listing of java:/comp/env must be non-null", listing1); listing1.close(); NamingEnumeration listing2 = this.ic.list("java:/comp/env/"); assertNotNull("Listing of java:/comp/env/ must be non-null", listing2); listing2.close(); } /** * Performs an absolute list on the context */ public void testCreateDestroyContexts() throws NamingException { Context child = this.ic.createSubcontext("TestChildContext"); assertNotNull("Created subcontext TestChildContext must not be null", child); NamingEnumeration listing = child.list(""); assertTrue("Listing on new child context is empty", !listing .hasMoreElements()); listing.close(); this.ic.destroySubcontext("java:/comp/env/TestChildContext"); } /** * Attempts a simple bind */ public void testSimpleBind() throws NamingException { Context child = this.ic.createSubcontext("TestBindContext"); assertNotNull("Created subcontext TestBindContext must not be null", child); child.bind("bindInteger", 80); Object lookupInt = this.ic.lookup("TestBindContext/bindInteger"); assertNotNull( "java:/comp/env/TestBindContext/bindInteger should be non-null", lookupInt); assertEquals("java:/comp/env/TestBindContext/bindInteger", lookupInt, 80); this.ic.destroySubcontext("java:/comp/env/TestBindContext"); } /** * Attempts a rebind */ public void testSimpleRebind() throws NamingException { Context child = this.ic.createSubcontext("TestRebindContext"); assertNotNull("Created subcontext TestRebindContext must not be null", child); Context rebindChild = child.createSubcontext("ChildRebind"); assertNotNull("Created subcontext rebindChild must not be null", rebindChild); rebindChild.rebind( "java:/comp/env/TestRebindContext/ChildRebind/integer", 25); rebindChild.close(); child.close(); Object lookupInt = this.ic .lookup("java:/comp/env/TestRebindContext/ChildRebind/integer"); assertNotNull( "java:/comp/env/TestRebindContext/ChildRebind/integer should be non-null", lookupInt); assertEquals("java:/comp/env/TestRebindContext/ChildRebind/integer", lookupInt, 25); this.ic .rebind("TestRebindContext/ChildRebind/integer", new Integer(40)); Object lookupInt2 = this.ic .lookup("TestRebindContext/ChildRebind/integer"); assertNotNull( "TestRebindContext/ChildRebind/integer should be non-null", lookupInt2); assertEquals("TestRebindContext/ChildRebind/integer", lookupInt2, 40); Object lookupInt3 = this.ic .lookup("java:/comp/env/TestRebindContext/ChildRebind/integer"); assertNotNull( "java:/comp/env/TestRebindContext/ChildRebind/integer should be non-null", lookupInt3); assertEquals("java:/comp/env/TestRebindContext/ChildRebind/integer", lookupInt3, 40); this.ic .destroySubcontext("java:/comp/env/TestRebindContext/ChildRebind"); this.ic.destroySubcontext("java:/comp/env/TestRebindContext"); } } jenkins-winstone-0.9.10-jenkins-47/src/test/winstone/testCase/load/0000755000175000017500000000000012200024521025541 5ustar jamespagejamespagejenkins-winstone-0.9.10-jenkins-47/src/test/winstone/testCase/load/LoadTestThread.java0000644000175000017500000000775412200024521031270 0ustar jamespagejamespage/* * Copyright 2003-2006 Rick Knowles * Distributed under the terms of either: * - the common development and distribution license (CDDL), v1.0; or * - the GNU Lesser General Public License, v2.1 or later */ package winstone.testCase.load; import java.io.IOException; import java.io.InputStream; import org.xml.sax.SAXException; import winstone.Logger; import winstone.WinstoneResourceBundle; import com.meterware.httpunit.GetMethodWebRequest; import com.meterware.httpunit.WebConversation; import com.meterware.httpunit.WebRequest; import com.meterware.httpunit.WebResponse; /** * A single worked thread in the load testing program * * @author Rick Knowles * @version $Id: LoadTestThread.java,v 1.2 2006/02/28 07:32:49 rickknowles Exp $ */ public class LoadTestThread implements Runnable { private WinstoneResourceBundle resources; private String url; private long delayBeforeStarting; private LoadTest loadTest; private WebConversation webConv; private Thread thread; private boolean interrupted; private LoadTestThread next; public LoadTestThread(String url, LoadTest loadTest, WinstoneResourceBundle resources, WebConversation webConv, int delayedThreads) { this.resources = resources; this.url = url; this.loadTest = loadTest; this.webConv = webConv; this.delayBeforeStarting = 1000 * delayedThreads; this.interrupted = false; this.thread = new Thread(this); this.thread.setDaemon(true); this.thread.start(); // Launch the next second's getter if (delayedThreads > 0) this.next = new LoadTestThread(url, loadTest, resources, webConv, delayedThreads - 1); } public void run() { if (this.delayBeforeStarting > 0) try { Thread.sleep(this.delayBeforeStarting); } catch (InterruptedException err) { } long startTime = System.currentTimeMillis(); try { if (this.webConv == null) this.webConv = new WebConversation(); // Access the URL WebRequest wreq = new GetMethodWebRequest(this.url); WebResponse wresp = this.webConv.getResponse(wreq); int responseCode = wresp.getResponseCode(); if (responseCode >= 400) throw new IOException("Failed with status " + responseCode); InputStream inContent = wresp.getInputStream(); int contentLength = wresp.getContentLength(); byte content[] = new byte[contentLength == -1 ? 100 * 1024 : contentLength]; int position = 0; int value = inContent.read(); while ((value != -1) && (((contentLength >= 0) && (position < contentLength)) || (contentLength < 0))) { content[position++] = (byte) value; value = inContent.read(); } inContent.close(); // Confirm the result is the same size the content-length said it // was if ((position == contentLength) || (contentLength == -1)) { if (this.interrupted) return; this.loadTest.incTimeTotal(System.currentTimeMillis() - startTime); this.loadTest.incSuccessCount(); } else throw new IOException("Only downloaded " + position + " of " + contentLength + " bytes"); } catch (IOException err) { Logger.log(Logger.DEBUG, resources, "LoadTestThread.Error", err); } catch (SAXException err) { Logger.log(Logger.DEBUG, resources, "LoadTestThread.Error", err); } } public void destroy() { this.interrupted = true; this.thread.interrupt(); if (this.next != null) this.next.destroy(); } } jenkins-winstone-0.9.10-jenkins-47/src/test/winstone/testCase/load/LoadTest.java0000644000175000017500000001341512200024521030127 0ustar jamespagejamespage/* * Copyright 2003-2006 Rick Knowles * Distributed under the terms of either: * - the common development and distribution license (CDDL), v1.0; or * - the GNU Lesser General Public License, v2.1 or later */ package winstone.testCase.load; import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import winstone.Logger; import winstone.WebAppConfiguration; import winstone.WinstoneResourceBundle; import com.meterware.httpunit.WebConversation; /** * This class is an attempt to benchmark performance under load for winstone. It * works by hitting a supplied URL with parallel threads (with keep-alives or * without) at an escalating rate, and counting the no of failures. * * It uses HttpUnit's WebConversation class for the connection. * * @author Rick Knowles * @version $Id: LoadTest.java,v 1.2 2006/02/28 07:32:49 rickknowles Exp $ */ public class LoadTest { private String url; private boolean useKeepAlives; private int startThreads; private int endThreads; private int stepSize; private long stepPeriod; private long gracePeriod; private long successTimeTotal; private int successCount; private WinstoneResourceBundle resources; private static String LOCAL_RESOURCE_FILE = "winstone.testCase.load.LocalStrings"; public LoadTest(WinstoneResourceBundle resources, String url, boolean useKeepAlives, int startThreads, int endThreads, int stepSize, long stepPeriod, long gracePeriod) { this.resources = resources; this.url = url; this.useKeepAlives = useKeepAlives; this.startThreads = startThreads; this.endThreads = endThreads; this.stepSize = stepSize; this.stepPeriod = stepPeriod; this.gracePeriod = gracePeriod; Logger.log(Logger.INFO, resources, "LoadTest.Config", this.url, this.useKeepAlives + "", this.startThreads + "", this.endThreads + "", this.stepSize + "", this.stepPeriod + "", this.gracePeriod + ""); } public void test() throws InterruptedException { WebConversation wc = null; // Loop through in steps for (int n = this.startThreads; n <= this.endThreads; n += this.stepSize) { if (this.useKeepAlives) wc = new WebConversation(); // Spawn the threads int noOfSeconds = (int) this.stepPeriod / 1000; List threads = new ArrayList(); for (int m = 0; m < n; m++) threads.add(new LoadTestThread(this.url, this, this.resources, wc, noOfSeconds - 1)); // Sleep for step period Thread.sleep(this.stepPeriod + gracePeriod); // int errorCount = (noOfSeconds * n) - this.successCount; Long averageSuccessTime = this.successCount == 0 ? null : this.successTimeTotal / this.successCount; // Write out results Logger.log(Logger.INFO, resources, "LoadTest.LineResult", n + "", this.successCount + "", ((noOfSeconds * n) - this.successCount) + "", averageSuccessTime + ""); // Close threads for (Object thread : threads) ((LoadTestThread) thread).destroy(); this.successTimeTotal = 0; this.successCount = 0; } } public void incTimeTotal(long amount) { this.successTimeTotal += amount; } public void incSuccessCount() { this.successCount++; } public static void main(String args[]) throws Exception { WinstoneResourceBundle resources = new WinstoneResourceBundle( LOCAL_RESOURCE_FILE); // Loop for args Map options = new HashMap(); // String operation = ""; for (String option : args) { if (option.startsWith("--")) { int equalPos = option.indexOf('='); String paramName = option.substring(2, equalPos == -1 ? option .length() : equalPos); String paramValue = (equalPos == -1 ? "true" : option .substring(equalPos + 1)); options.put(paramName, paramValue); } } if (options.size() == 0) { printUsage(resources); return; } Logger.setCurrentDebugLevel(Integer.parseInt(WebAppConfiguration .stringArg(options, "debug", "5"))); String url = WebAppConfiguration.stringArg(options, "url", "http://localhost:8080/"); boolean keepAlive = WebAppConfiguration.booleanArg(options, "keepAlive", true); String startThreads = WebAppConfiguration.stringArg(options, "startThreads", "20"); String endThreads = WebAppConfiguration.stringArg(options, "endThreads", "1000"); String stepSize = WebAppConfiguration.stringArg(options, "stepSize", "20"); String stepPeriod = WebAppConfiguration.stringArg(options, "stepPeriod", "5000"); String gracePeriod = WebAppConfiguration.stringArg(options, "gracePeriod", "5000"); LoadTest lt = new LoadTest(resources, url, keepAlive, Integer .parseInt(startThreads), Integer.parseInt(endThreads), Integer .parseInt(stepSize), Integer.parseInt(stepPeriod), Integer .parseInt(gracePeriod)); lt.test(); } /** * Displays the usage message */ private static void printUsage(WinstoneResourceBundle resources) { System.out.println(resources.getString("LoadTest.Usage")); } } jenkins-winstone-0.9.10-jenkins-47/src/test/winstone/testCase/load/LocalStrings.properties0000644000175000017500000000150712200024521032266 0ustar jamespagejamespageLoadTest.Usage=Winstone Command Line Load Tester\n\ Usage: java winstone.testCase.load.LoadTest --url= \ [--keepAlive=] \ [--startThreads=] \ [--endThreads=] \ [--stepSize=] \ [--stepPeriod=] \ [--gracePeriod=] LoadTest.Config=Load test initialised with properties: URL=[#0], KeepAlives=[#1], \ StartThreads=[#2], EndThreads=[#3], StepSize=[#4], StepPeriod=[#5], GracePeriod=[#6] LoadTest.LineResult=n=[#0], success=[#1], error=[#2], averageTime=[#3]ms LoadTestThread.Error=Error in responsejenkins-winstone-0.9.10-jenkins-47/src/test/winstone/testCase/WinstoneResourceBundleTest.java0000644000175000017500000000416712200024521033005 0ustar jamespagejamespage/* * Copyright 2003-2006 Rick Knowles * Distributed under the terms of either: * - the common development and distribution license (CDDL), v1.0; or * - the GNU Lesser General Public License, v2.1 or later */ package winstone.testCase; import junit.framework.TestCase; import winstone.WinstoneResourceBundle; /** * Simple tests for the string replacer * * @author Rick Knowles * @version $Id: WinstoneResourceBundleTest.java,v 1.1 2006/11/09 05:39:43 rickknowles Exp $ */ public class WinstoneResourceBundleTest extends TestCase { public static void testGlobalReplace() throws Exception { assertEquals("One token", "Foo = bar squared", WinstoneResourceBundle.globalReplace( "Foo = [#0] squared", "[#0]", "bar")); assertEquals("Repeated token", "Foo = bar bar squared", WinstoneResourceBundle.globalReplace( "Foo = [#0] [#0] squared", "[#0]", "bar")); assertEquals("Two tokens", "Foo = blah bar squared", WinstoneResourceBundle.globalReplace( "Foo = [#1] [#0] squared", new String[][] {{"[#0]", "bar"}, {"[#1]", "blah"}})); } // public static void testSpeed() throws Exception { // String tokens[][] = new String[20][2]; // for (int n = 0; n < tokens.length; n++) { // tokens[n] = new String[] {"[#" + n + "]", "token" + n}; // } // Random rnd = new Random(); // String inputs[] = new String[5000]; // for (int n = 0; n < inputs.length; n++) { // inputs[n] = ""; // for (int k = 0; k < tokens.length; k++) { // inputs[n] += "[#" + (rnd.nextInt() % tokens.length) + "] abc"; // } // } // // long startTime = System.currentTimeMillis(); // for (int n = 0; n < inputs.length; n++) { // WinstoneResourceBundle.globalReplace(inputs[n], tokens); // } // System.out.println("Replaced " + tokens.length + " tokens in " + inputs.length + " strings in " + // (System.currentTimeMillis() - startTime) + "ms"); // } } jenkins-winstone-0.9.10-jenkins-47/src/test/winstone/testApplication/0000755000175000017500000000000012200024521026212 5ustar jamespagejamespagejenkins-winstone-0.9.10-jenkins-47/src/test/winstone/testApplication/servlets/0000755000175000017500000000000012200024521030061 5ustar jamespagejamespage././@LongLink0000000000000000000000000000014600000000000011566 Lustar rootrootjenkins-winstone-0.9.10-jenkins-47/src/test/winstone/testApplication/servlets/UnavailableServlet.javajenkins-winstone-0.9.10-jenkins-47/src/test/winstone/testApplication/servlets/UnavailableServlet.jav0000644000175000017500000000321412200024521034353 0ustar jamespagejamespage/* * Copyright 2003-2006 Rick Knowles * Distributed under the terms of either: * - the common development and distribution license (CDDL), v1.0; or * - the GNU Lesser General Public License, v2.1 or later */ package winstone.testApplication.servlets; import java.io.IOException; import java.io.Writer; import javax.servlet.ServletException; import javax.servlet.UnavailableException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; /** * Used to test the unavailable exception processing * * @author Rick Knowles * @version $Id: UnavailableServlet.java,v 1.2 2006/02/28 07:32:49 rickknowles Exp $ */ public class UnavailableServlet extends HttpServlet { protected boolean errorAtInit; public void init() throws ServletException { String errorTime = getServletConfig().getInitParameter("errorTime"); this.errorAtInit = ((errorTime == null) || errorTime.equals("init")); if (this.errorAtInit) throw new UnavailableException( "Error thrown deliberately during init"); } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { if (!this.errorAtInit) throw new UnavailableException( "Error thrown deliberately during get"); Writer out = response.getWriter(); out .write("This should not be shown, because we've thrown unavailable exceptions"); out.close(); } } ././@LongLink0000000000000000000000000000015000000000000011561 Lustar rootrootjenkins-winstone-0.9.10-jenkins-47/src/test/winstone/testApplication/servlets/CountRequestsServlet.javajenkins-winstone-0.9.10-jenkins-47/src/test/winstone/testApplication/servlets/CountRequestsServlet.j0000644000175000017500000000302412200024521034424 0ustar jamespagejamespage/* * Copyright 2003-2006 Rick Knowles * Distributed under the terms of either: * - the common development and distribution license (CDDL), v1.0; or * - the GNU Lesser General Public License, v2.1 or later */ package winstone.testApplication.servlets; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.ServletOutputStream; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; /** * Simple test servlet that counts the number of times it has been requested, * and returns that number in the response. * * @author Rick Knowles * @version $Id: CountRequestsServlet.java,v 1.3 2006/02/28 07:32:49 rickknowles Exp $ */ public class CountRequestsServlet extends HttpServlet { private int numberOfGets; public void init() { String offset = getServletConfig().getInitParameter("offset"); numberOfGets = offset == null ? 0 : Integer.parseInt(offset); } /** * Get implementation - increments and shows the access count */ protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { numberOfGets++; ServletOutputStream out = response.getOutputStream(); out.println("This servlet has been accessed via GET " + numberOfGets + " times"); out.flush(); } } jenkins-winstone-0.9.10-jenkins-47/src/test/winstone/testApplication/filters/0000755000175000017500000000000012200024521027662 5ustar jamespagejamespagejenkins-winstone-0.9.10-jenkins-47/src/test/winstone/testApplication/filters/TimingFilter.java0000644000175000017500000000425512200024521033130 0ustar jamespagejamespage/* * Copyright 2003-2006 Rick Knowles * Distributed under the terms of either: * - the common development and distribution license (CDDL), v1.0; or * - the GNU Lesser General Public License, v2.1 or later */ package winstone.testApplication.filters; import java.io.IOException; import java.util.Enumeration; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; /** * Simple timing and request dumping test filter * * @author Rick Knowles * @version $Id: TimingFilter.java,v 1.2 2006/02/28 07:32:50 rickknowles Exp $ */ public class TimingFilter implements Filter { private boolean dumpRequestParams; private ServletContext context; public void init(FilterConfig config) { String dumpRequestParams = config .getInitParameter("dumpRequestParameters"); this.dumpRequestParams = ((dumpRequestParams != null) && dumpRequestParams .equalsIgnoreCase("true")); this.context = config.getServletContext(); } public void destroy() { this.context = null; } /** * Times the execution of the rest of the filter chain, optionally dumping * the request parameters to the servlet context log */ public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { if (this.dumpRequestParams) for (Enumeration paramNames = request.getParameterNames(); paramNames .hasMoreElements();) { String name = (String) paramNames.nextElement(); this.context.log("Request parameter: " + name + "=" + request.getParameter(name)); } long startTime = System.currentTimeMillis(); chain.doFilter(request, response); this.context.log("Filter chain executed in " + (System.currentTimeMillis() - startTime) + "ms"); } } ././@LongLink0000000000000000000000000000015200000000000011563 Lustar rootrootjenkins-winstone-0.9.10-jenkins-47/src/test/winstone/testApplication/filters/WriteAfterServletFilter.javajenkins-winstone-0.9.10-jenkins-47/src/test/winstone/testApplication/filters/WriteAfterServletFilter0000644000175000017500000000135712200024521034402 0ustar jamespagejamespagepackage winstone.testApplication.filters; import java.io.IOException; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletException; import javax.servlet.ServletOutputStream; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; public class WriteAfterServletFilter implements Filter { public void init(FilterConfig filterConfig) {} public void destroy() {} public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { chain.doFilter(request, response); ServletOutputStream os = response.getOutputStream(); os.print("Hello"); } } jenkins-winstone-0.9.10-jenkins-47/src/test/winstone/testApplication/listeners/0000755000175000017500000000000012200024521030222 5ustar jamespagejamespagejenkins-winstone-0.9.10-jenkins-47/src/test/winstone/testApplication/listeners/SessionListener.java0000644000175000017500000000473212200024521034224 0ustar jamespagejamespage/* * Copyright 2003-2006 Rick Knowles * Distributed under the terms of either: * - the common development and distribution license (CDDL), v1.0; or * - the GNU Lesser General Public License, v2.1 or later */ package winstone.testApplication.listeners; import javax.servlet.http.HttpSessionActivationListener; import javax.servlet.http.HttpSessionAttributeListener; import javax.servlet.http.HttpSessionBindingEvent; import javax.servlet.http.HttpSessionEvent; import javax.servlet.http.HttpSessionListener; /** * Logs messages when any session event is received * * @author Rick Knowles * @version $Id: SessionListener.java,v 1.2 2006/02/28 07:32:46 rickknowles Exp $ */ public class SessionListener implements HttpSessionListener, HttpSessionAttributeListener, HttpSessionActivationListener { public void sessionCreated(HttpSessionEvent se) { se.getSession().getServletContext().log( "Session Created - id=" + se.getSession().getId()); } public void sessionDestroyed(HttpSessionEvent se) { se.getSession().getServletContext().log( "Session Destroyed - id=" + se.getSession().getId()); } public void attributeAdded(HttpSessionBindingEvent se) { se.getSession().getServletContext().log( "Session Attribute added (session id=" + se.getSession().getId() + ") " + se.getName() + "=" + se.getValue()); } public void attributeRemoved(HttpSessionBindingEvent se) { se.getSession().getServletContext().log( "Session Attribute removed (session id=" + se.getSession().getId() + ") " + se.getName() + "=" + se.getValue()); } public void attributeReplaced(HttpSessionBindingEvent se) { se.getSession().getServletContext().log( "Session Attribute replaced (session id=" + se.getSession().getId() + ") " + se.getName() + "=" + se.getValue()); } public void sessionDidActivate(HttpSessionEvent se) { se.getSession().getServletContext().log( "Session activated - id=" + se.getSession().getId()); } public void sessionWillPassivate(HttpSessionEvent se) { se.getSession().getServletContext().log( "Session passivating - id=" + se.getSession().getId()); } } jenkins-winstone-0.9.10-jenkins-47/.classpath0000644000175000017500000000117312200024521021420 0ustar jamespagejamespage jenkins-winstone-0.9.10-jenkins-47/LICENSE-LGPL.txt0000644000175000017500000006347012200024521022024 0ustar jamespagejamespage GNU LESSER GENERAL PUBLIC LICENSE Version 2.1, February 1999 Copyright (C) 1991, 1999 Free Software Foundation, Inc. 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. [This is the first released version of the Lesser GPL. It also counts as the successor of the GNU Library Public License, version 2, hence the version number 2.1.] Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This license, the Lesser General Public License, applies to some specially designated software packages--typically libraries--of the Free Software Foundation and other authors who decide to use it. You can use it too, but we suggest you first think carefully about whether this license or the ordinary General Public License is the better strategy to use in any particular case, based on the explanations below. When we speak of free software, we are referring to freedom of use, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish); that you receive source code or can get it if you want it; that you can change the software and use pieces of it in new free programs; and that you are informed that you can do these things. To protect your rights, we need to make restrictions that forbid distributors to deny you these rights or to ask you to surrender these rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library or if you modify it. For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link other code with the library, you must provide complete object files to the recipients, so that they can relink them with the library after making changes to the library and recompiling it. And you must show them these terms so they know their rights. We protect your rights with a two-step method: (1) we copyright the library, and (2) we offer you this license, which gives you legal permission to copy, distribute and/or modify the library. To protect each distributor, we want to make it very clear that there is no warranty for the free library. Also, if the library is modified by someone else and passed on, the recipients should know that what they have is not the original version, so that the original author's reputation will not be affected by problems that might be introduced by others. Finally, software patents pose a constant threat to the existence of any free program. We wish to make sure that a company cannot effectively restrict the users of a free program by obtaining a restrictive license from a patent holder. Therefore, we insist that any patent license obtained for a version of the library must be consistent with the full freedom of use specified in this license. Most GNU software, including some libraries, is covered by the ordinary GNU General Public License. This license, the GNU Lesser General Public License, applies to certain designated libraries, and is quite different from the ordinary General Public License. We use this license for certain libraries in order to permit linking those libraries into non-free programs. When a program is linked with a library, whether statically or using a shared library, the combination of the two is legally speaking a combined work, a derivative of the original library. The ordinary General Public License therefore permits such linking only if the entire combination fits its criteria of freedom. The Lesser General Public License permits more lax criteria for linking other code with the library. We call this license the "Lesser" General Public License because it does Less to protect the user's freedom than the ordinary General Public License. It also provides other free software developers Less of an advantage over competing non-free programs. These disadvantages are the reason we use the ordinary General Public License for many libraries. However, the Lesser license provides advantages in certain special circumstances. For example, on rare occasions, there may be a special need to encourage the widest possible use of a certain library, so that it becomes a de-facto standard. To achieve this, non-free programs must be allowed to use the library. A more frequent case is that a free library does the same job as widely used non-free libraries. In this case, there is little to gain by limiting the free library to free software only, so we use the Lesser General Public License. In other cases, permission to use a particular library in non-free programs enables a greater number of people to use a large body of free software. For example, permission to use the GNU C Library in non-free programs enables many more people to use the whole GNU operating system, as well as its variant, the GNU/Linux operating system. Although the Lesser General Public License is Less protective of the users' freedom, it does ensure that the user of a program that is linked with the Library has the freedom and the wherewithal to run that program using a modified version of the Library. The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, whereas the latter must be combined with the library in order to run. GNU LESSER GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library or other program which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Lesser General Public License (also called "this License"). Each licensee is addressed as "you". A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) "Source code" for a work means the preferred form of the work for making modifications to it. For a library, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the library. Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. 1. You may copy and distribute verbatim copies of the Library's complete source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and distribute a copy of this License along with the Library. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Library or any portion of it, thus forming a work based on the Library, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) The modified work must itself be a software library. b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. (For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Library, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Library. In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. This option is useful when you wish to copy part of the code of the Library into a program that is not a library. 4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange. If distribution of object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. 5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. 6. As an exception to the Sections above, you may also combine or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) b) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (1) uses at run time a copy of the library already present on the user's computer system, rather than copying library functions into the executable, and (2) will operate properly with a modified version of the library, if the user installs one, as long as the modified version is interface-compatible with the version that the work was made with. c) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. d) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. e) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the materials to be distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. 7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 9. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. 10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties with this License. 11. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Library. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply, and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 13. The Free Software Foundation may publish revised and/or new versions of the Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. 14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Libraries If you develop a new library, and you want it to be of the greatest possible use to the public, we recommend making it free software that everyone can redistribute and change. You can do so by permitting redistribution under these terms (or, alternatively, under the terms of the ordinary General Public License). To apply these terms, attach the following notices to the library. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Also add information on how to contact you by electronic and paper mail. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the library, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the library `Frob' (a library for tweaking knobs) written by James Random Hacker. , 1 April 1990 Ty Coon, President of Vice That's all there is to it! jenkins-winstone-0.9.10-jenkins-47/README.html0000644000175000017500000016133412200024521021266 0ustar jamespagejamespage Winstone Servlet Container

This is a beta release of the Winstone Servlet Container. The homepage for this project is at 'http://winstone.sourceforge.net'

Author: Rick Knowles (contact details below)

What is Winstone ?

Winstone is a servlet container that was written out of a desire to provide servlet functionality without the bloat that full J2EE compliance introduces.

It is not intended to be a completely fully functional J2EE style servlet container (by this I mean supporting extraneous APIs unrelated to Servlets, such as JNDI, JavaMail, EJBs, etc) - this is left to Tomcat, Jetty, Resin, JRun, Weblogic et al.

Sometimes you want just a simple servlet container - without all the other junk - that just goes. This is where Winstone is best suited.

The original goals in writing Winstone were:

  • Supply fast, reliable servlet container functionality for a single webapp per server
  • Keep the size of the core distribution jar as low as possible (currently 166KB)
  • Keep configuration files to an absolute minimum, using command line options to optionally override sensible compiled in defaults.
  • Eventually compile with GCJ to make a 3-4Meg windows exe for local development/deployment of servlets. This has not happened yet, because of some GCJ class loading problems.
  • Optionally support JSP compilation using Apache's Jasper. (http://jakarta.apache.org)

Why is it called Winstone ?

The short version (because the long version is way too politically incorrect) is as follows:

Winstone is the name of a rather large Jamaican man a friend of mine met one night, while he was out clubbing in the Roppongi area of Tokyo. He (my friend) was a little liquored up at the time, and when Winstone suggested they head to "this really cool club" he knew, he didn't think anything was wrong. It wasn't until Winstone led him down a dark stairwell and dropped his trousers that my friend clued in and ran like hell.

It was too good a story to let die, so I named this project Winstone so that said friend will continue to be reminded of it. Heheheh ....

License

The Web-App DTD files (everything in the src/javax/servlet/resources and src/javax/servlet/jsp/resources folders) are covered by the licenses described at the top of each file (usually as licensed by Sun Microsystems).

As of v0.8.1, all other files are dual-licensed, under either the Lesser GNU Public License (LGPL) as described in LICENSE-LGPL.txt, or the Common Development and Distribution License (CDDL) as decribed in LICENSE-CDDL.txt. Until v0.8, the license used was the GNU Public License (GPL).

The goal of dual-licensing is to make Winstone as attractive as possible to distributors of commercial webapps, while ensuring everyone benefits from any improvements. The CDDL allows free distribution with any commercial applications, while distribution with a GPL licensed webapp is also possible under the LGPL. If you are unclear about which license applies to an application you wish to distribute or sell, please contact me.

Contacting the Author

You can contact me through the Winstone development list at sourceforge (winstone-devel AT lists DOT sourceforge DOT net). If you have any general comments or questions about Winstone please mail me on that list - I'll try to start a faq soon.

I'm open to help from anyone who's willing to help me meet the above goals for Winstone. Just mail me at the list (winstone-devel AT lists DOT sourceforge DOT net)

Using Winstone

If you want to build from source code, you will need to download and install Apache Maven (v1.x). The following instructions assume you have already installed Maven and have the maven shell script in your path (to get Maven, see http://maven.apache.org/).

To build Winstone, unpack the tree:

  tar zxf winstone-src-0.9.10.tar.gz

Then build it:

  cd winstone
  maven clean jar

The winstone.jar file will be in the target directory after the build is complete.

To run it:

  java -jar target/winstone-0.9.10.jar --webroot=<location of webroot> (+ other options)

- OR -

  java -jar target/winstone-0.9.10.jar --warfile=<location of warfile> (+ other options)

- OR -

  java -jar target/winstone-0.9.10.jar --webappsDir=<location of webapps directory> (+ other options)

- OR -

  java -jar target/winstone-0.9.10.jar --hostsDir=<location of hosts directory> (+ other options)

Command-line options:

Syntax:
  java -jar winstone-0.9.10.jar [--option=value] [--option=value] etc

Required options: either --webroot OR --warfile OR --webappsDir OR --hostsDir
   --webroot                = set document root folder.
   --warfile                = set location of warfile to extract from.
   --webappsDir             = set directory for multiple webapps to be deployed from
   --hostsDir               = set directory for name-based virtual hosts to be deployed from

Other options:
   --javaHome               = Override the JAVA_HOME variable
   --toolsJar               = The location of tools.jar (default is JAVA_HOME/lib/tools.jar) 
   --config                 = load configuration properties from here(if supplied).
   --prefix                 = add this prefix to all URLs. (eg http://host/prefix/etc).
   --commonLibFolder        = folder for additional jar files. Default is ./lib
    
   --logfile                = redirect winstone log messages to this file
   --logThrowingLineNo      = show the line no that logged the message (slow). Default is false
   --logThrowingThread      = show the thread that logged the message. Default is false
   --debug                  = set the level of debug msgs (1-9). Default is 5 (INFO level)

   --httpPort               = set the http listening port. -1 to disable, Default is 8080
   --httpListenAddress      = set the http listening address. Default is all interfaces
   --httpDoHostnameLookups  = enable host name lookups on http connections. Default is false
   --httpKeepAliveTimeout   = how long idle HTTP keep-alive connections are kept around (in ms; default 5000)?
   --httpsPort              = set the https listening port. -1 to disable, Default is disabled
   --httpsListenAddress     = set the https listening address. Default is all interfaces
   --httpsDoHostnameLookups = enable host name lookups on https connections. Default is false
   --httpsKeepAliveTimeout  = how long idle HTTPS keep-alive connections are kept around (in ms; default 5000)?
   --httpsKeyStore          = the location of the SSL KeyStore file. Default is ./winstone.ks
   --httpsKeyStorePassword  = the password for the SSL KeyStore file. Default is null
   --httpsKeyManagerType    = the SSL KeyManagerFactory type (eg SunX509, IbmX509). Default is SunX509
   --ajp13Port              = set the ajp13 listening port. -1 to disable, Default disabled
   --ajp13ListenAddress     = set the ajp13 listening address. Default is all interfaces
   --controlPort            = set the shutdown/control port. -1 to disable, Default disabled

   --handlerCountStartup    = set the no of worker threads to spawn at startup. Default is 5
   --handlerCountMax        = set the max no of worker threads to allow. Default is 40
   --handlerCountMaxIdle    = set the max no of idle worker threads to allow. Default is 5

   --directoryListings      = enable directory lists (true/false). Default is true
   --useJasper              = enable jasper JSP handling (true/false). Default is false
   --useServletReloading    = enable servlet reloading (true/false). Default is false
   --preferredClassLoader   = override the preferred webapp class loader.
   --useInvoker             = enable the servlet invoker (true/false). Default is true
   --invokerPrefix          = set the invoker prefix. Default is /servlet/
   --simulateModUniqueId    = simulate the apache mod_unique_id function. Default is false
   --useSavedSessions       = enables session persistence (true/false). Default is false
   --usage / --help         = show this message
    
Cluster options:
   --useCluster             = enable cluster support (true/false). Default is false
   --clusterClassName       = Set the cluster class to use. Defaults to SimpleCluster class
   --clusterNodes           = a comma separated list of node addresses (IP:ControlPort,IP:ControlPort,etc)

JNDI options:
   --useJNDI                      = enable JNDI support (true/false). Default is false
   --containerJndiClassName       = Set the container wide JNDI manager class to use. Defaults to ContainerJNDIManager
   --webappJndiClassName          = Set the web-app JNDI manager class to use. Defaults to WebAppJNDIManager
   --jndi.resource.<name>         = set the class to be used for the resource marked <name>
   --jndi.param.<name>.<att>      = set an attribute <att> for the resource marked <name>

Security options:
   --realmClassName               = Set the realm class to use for user authentication. Defaults to ArgumentsRealm class

   --argumentsRealm.passwd.<user> = Password for user <user>. (for ArgumentsRealm)
   --argumentsRealm.roles.<user>  = Roles for user <user> (comma-separated) (for ArgumentsRealm)

   --fileRealm.configFile         = File containing users/passwds/roles. Only valid for the FileRealm realm class

Access logging:
   --accessLoggerClassName        = Set the access logger class to use for user authentication. Defaults to disabled
   --simpleAccessLogger.format    = The log format to use. Supports combined/common/resin/custom (SimpleAccessLogger only)
   --simpleAccessLogger.file      = The location pattern for the log file(SimpleAccessLogger only)

Configuration file

You don't really need a config file, but sometimes it's handy to be able to use the same settings each time without running through the command history.

Winstone looks for a config file winstone.properties in the current directory (or in the location specified with --config) at startup. It loads the properties in this file, overrides them with any supplied command line properties, and then starts itself.

This is just intended as a handy feature for people who want to cache regular startup options, rather than using batch files.

Deployment choices

The simplest way to use winstone is with a single webapp. To do this, just supply the warfile or webroot directory as an argument:

  • java -jar winstone.jar <webroot or warfile>, (this method auto-detects the type) or
  • java -jar winstone.jar --webroot=<webroot>, or
  • java -jar winstone.jar --warfile=<warfile>

If you need to support multiple webapps, use the --webappsDir switch, to which you pass a directory that contains multiple warfiles/webroots.

  • java -jar winstone.jar --webappsDir=<dir containing multiple webroots>

The directory becomes the prefix name for that webapp (so hello becomes /hello, etc). The directory named ROOT becomes the no-prefix webapp.

So, for example, if you had a directory /usr/local/webapps which contained sub-directories ROOT and test, if you executed java -jar winstone.jar --webappsDir=/usr/local/webapps, you would find that the test folder would act as a webroot for requests prefixed with /test, while other requests would go to the webapp in the ROOT folder

From v0.8, if you need multiple hosts (sometimes called name-based virtual hosting), there is a new option --hostsDir. This acts in a similar way to the --webappsDir switch, but it defines an extra level of sub-directories, the top being a per-host directory and the second a per-webapp directory as with --webappsDir.

The directory name becomes the host name: that is, a directory named "www.blah.com" will only serve requests with the host header www.blah.com, unless it is the default host. If a directory named "default" is found, it becomes the default host. If no default directory is found, the first directory in the list (alphabetically) becomes the default host.

  • java -jar winstone.jar --hostsDir=<dir containing multiple host directories>

Caveats

As a result of the design goals, there are some things Winstone doesn't do:

  • There are currently three connectors supplied with Winstone:
    1. An internal HTTP connector - allows plain HTTP/1.1 connections only
    2. An internal HTTPS connector - allows HTTP/1.1 connections over SSL
    3. An AJP13 connector - allows connection to Apache/IIS/iPlanet, etc
    While there is an internal HTTPS/SSL connector included, I recommend using Apache 2.0 with the AJP13 connector (instructions below). It has way more configuration options than Winstone's connector does.
  • HttpSession support is cookie-based only (no URL rewriting). URL rewriting introduces a lot of unnecessary complex request processing, and given that browser cookie support is common these days (and no-one I know actually uses URL rewriting), I plan not to implement this.
  • The messages are all in English only. Resource bundles are used, but no translations yet.

Security Warning

If you enable the controlPort, be aware that there is no password protection at all on this port. Anyone who can get access to this port can stop or restart the server. I plan to add some simple authentication to this at some point, but I'll wait until someone asks for it.

The controlPort is disabled by default. If you choose not to enable it, the only way to shut Winstone down is to kill the process (either by Ctrl-C or kill command).

Recent additions

New features in v0.9:

  • Added Servlet v2.5 spec support. Please note that the annotations support mentioned in the spec is only for J2EE compliant containers, and Winstone is deliberately only JSR154 compliant. The adding of v2.5 support was purely driven by a requirement in the API license, so except for a bit of syntactic sugar in the web.xml and spec clarifications, this isn't really a big deal. Also, while the new spec mandates JDK1.5 or better, winstone should still work with a JDK1.2+ JVM.
  • Added Session persistence across reboots. The best thing about winstone (I find) is it's startup time, but restarts are a pain if you have to rebuild a session in order to get to a page you're working on. By adding --useSavedSessions to the startup args, you'll enable the feature. See below for more.
  • A lot of session and forwarding related fixes - thanks to Martin Cordova and Robert Boyce for pointing these out. These have been bugging me for some time, but having people give you reproducible examples of error cases is often all it takes to fix a long standing problem, and these guys were crucial in providing that.
  • A change is JSP deployment requirements. If you use JSPs, please see below.
  • AJP connector now apparently works with IIS. Many thanks to Cory Osborn for finding these problems and then debugging and fixing them single-handedly.
  • Some classloading changes that should isolate classloading in webapps from each other more thoroughly.

New features in v0.8:

  • Expanded the features of the JDBC connection pool to include keep-alive queries and block-and-retry behaviour when the pool has been exhausted.
  • Added filter match caching (performance improvement)
  • Name-based virtual hosting. Using the --hostsDir switch, you can define a directory that contains directories named by hostname, each of which acts like a --webappsDir. See above for more details.
  • Access logging. Disabled by default, but enabled with the switch --accessLoggerClassName=winstone.accesslog.SimpleAccessLogger. You can provide your own logging implementation, but the simple access logger contains Apache Combined/Common format logging and Resin format logging, so it should suffice for most cases. See below for more details.
  • Better embedding support. You can now embed warfiles and properties file inside the winstone jar itself, for an all-in-one application jar. See below for more details.
  • Tested with WebDAV applications. Winstone has now been tested/debugged with Jakarta Slide and Davenport WebDAV applications, and works correctly (previous versions had some obscure bugs that caused WebDAV to fail)

New features in v0.7:

  • Updated build process to use Apache Maven (see http://maven.apache.org. Build instructions have been updated to match.
  • Source code has been reformatted - a fair bit easier to read now
  • Multiple webapp support has been added. There's no auto-deploy features yet, but that will come soon. Use the --webappsDir=<webapps directory> to declare a folder that will have any directories auto-mounted and any warfiles auto-deployed. (I originally said this was not going to be included, but changed my mind when I realised it could be done with only 10K additional jarfile size).
  • Fixed the bugs in the exception handling and error servlet redirection, as well as in web xml parsing, and more other places that I can possibly list here. If you had some strange bug or incompatibility before, chances are it's been fixed now.
  • Passed the Sun JSR-154 Servlet Test Compatibility Kit (TCK) tests.
  • I also ran the JSR-152 JSP TCK on winstone with Apache Jasper support enabled, and while it didn't pass all tests, the tests it failed were the same ones the Tomcat failed, so I notified the Tomcat/Jasper developers of the test failures. Currently waiting on a response ... in any case I suspect these are actually test errors rather than implementation errors.
  • Better support for open source JVMs. Martin Cordova has been very helpful in testing winstone under a wider range of JVMs, as well as providing some really good feedback on needed features. His tests included JamVM and CacaoVM, as well as IBM's JDK. Jim Huang also reported that winstone works well under Kaffe.
  • User definable webapp class loader: This is likely to be of interest to the Aspect Oriented Programming crowd. It allows you to write your own class loader class (conforming to the same contructor signature as URLClassLoader), and then to use it in place of the normal web app class loader with --preferredClassLoader. This allows AspectWerkz style weaving classloaders to be used on webapps where it wouldn't have been otherwise possible (eg JDKs that don't support the profiler option, such as 1.4 and before), or anything else you can think of doing with a custom classloader.

New features in v0.6:

  • Updated to Servlet 2.4 specification compliance, although I haven't yet run Sun's Test Compatibility Kit on it - I'm still waiting for that. It works with all of the v2.4 webapps I've tried. The only caveat is that you will need Apache Xerces in the system classpath to make it work (see below).
  • Updated to JSP 2.0 specification compliance. This is the main cause for the blowout in size of the larger jar file, but it does result in much simpler set up for Jasper (see below).
  • Added a command-line tool for accessing control port options, such as shutdown and restart. Restart is new to this version, and causes a shutdown and redeploy from scratch.
  • Added a lib folder for additional jars. This defaults to "lib" under the current directory, with any jar or zip files in this folder being added to the webapp classpath.
  • Extensively tested with the Apache Struts and JSTL frameworks. This highlighted a number of bugs related to internationalisation I wouldn't have found otherwise.
  • Many minor features such as range downloads on static resources, a logfile directive for writing log messages to a file, and many MANY performance enhancements and bugfixes. See the TODO.txt file in the source distribution for a full list.
  • Update: June 28, 2004 - Added HTTPS support to version v0.6.4

New features in v0.5:

  • Implemented DIGEST and CERT authentication methods. The CERT type is largely untested (due to lack of A: access to certificates and B: knowledge of browser configuration for client certificates) - if anyone wants to help with testing this, I'd appreciate it.
  • Implemented simple clustering (ie sharing of sessions between multiple Winstone instances). See below for cluster configuration details.
  • Implemented optional JNDI support. This is just a memory-based Context intended for storing lookups on <env-entry> and <resource-ref> references, but it also includes a pooling JDBC DataSource object .... it's funny how you don't realise how important some things are until you go without them ....
  • The control port has been modified to be more useful. See below for usage instructions.
  • The distribution jar is now available in two forms:
    1. Complete version (winstone.jar): This contains the complete winstone feature-set, including AJP13 Apache connectors, Authentication/Realm support and Clustering support.
    2. Lite version (winstone-lite.jar): This is the core winstone feature-set only, ie commonly used servlet features, as fast and reliable as possible, with unnecessary options removed.

New features in v0.4:

  • Implemented the <error-page> directive
  • Added object pools for request/response objects for performance reasons
  • The handler pools are now controllable via startup properties
  • Servlet reloading is now supported (optionally - include --useServletReloading=true at startup)
  • The initial Authentication Model is in place (see below for help). There are two base classes that make it work: AuthenticationRealm and AuthenticationHandler. Currently Argument-based and File-based realms (ie user/password details supplied via command-line args or XML files) and HTTP BASIC and FORM authentication are implemented, but the others (DIGEST and CERT authentication forms) will come soon.

New features in v0.3:

  • The request handler threads now use monitors, which allows them to exist beyond a single request/response cycle. The benefit here is performance - it removes a serious bottleneck.
  • WAR files are now supported via the --warfile attribute. If you specify a warfile in this manner, it will be automatically extracted by the container to a temp directory, overwriting only files that are older than the archive date.
  • Servlet attribute, session, and context listeners (Servlet spec v2.3) are now fully supported. The HttpSessionActivationListener class will be fully supported once the session transfer is implemented.
  • Servlet Filters (Servlet spec v2.3) are now fully supported.
  • There is now an AJP13 connector, which means Winstone will now work behind Apache/IIS/etc using Tomcat's mod_jk. Try it out and see ... there's a section below on using the mod_jk connector.

Using Xerces as an XML parser (required for v2.4 webapps)

As part of the upgrade in the servlet specification, the v2.4 incarnation of the web.xml file is validated using XML Schema Documents (XSD) as opposed to Document Type Definitions (DTD). While I still have no idea why such a change was necessary - especially given that DTD validation seems to be more than enough in this case - I did implement it. Perhaps the people on the specification committee might want to give a thought to container size next time round, as this one change multiplies the size of the distribution by five.

Anyway, to use Xerces, you'll need to download the latest Xerces-J parser from here, and copy xercesImpl.jar and xml-apis.jar into a folder somewhere (name it "endorsed"). Putting them in the winstone/lib folder will not work, because they must be in the system endorsed classpath to override the JDK internal XML parser.

Then add -Djava.endorsed.dirs=<endorsed dir name> as a JVM arg to your command line for starting winstone, eg:

  java -Djava.endorsed.dirs=/jdk/endorsed -jar winstone.jar --webroot=...

JSPs (aka using with Jasper)

Winstone supports JSPs using Apache's Jasper JSP compiler. Thanks to a rather clever design by the Jasper team, this was much less work than I expected - well done Jasper guys.

Required steps:

  1. Add --useJasper to your startup command line, since JSPs are disabled by default
  2. Both the v1.x and v2.x versions of Jasper are supported. In order to turn on JSP compilation in Winstone, you'll need to place the following jar files into the lib folder under the current directory (or the folder identified by the --commonLibFolder directive).

    • jasper-compiler.jar, jasper-runtime.jar, ant.jar, jsp-api.jar - Not supplied with Winstone. You can get this from the standard Tomcat binary download location. Just download the latest Tomcat, and copy these three files into the lib folder for Winstone. They will be in the tomcat_home/common/lib folder.
    • commons-logging-api.jar, commons-el.jar (Jasper 2 only) - These are required if you are using Jasper 2.0. You can get them from the tomcat binary distribution or separately from the link below.

    All of these are available from the Jakarta download site

  3. You'll also need tools.jar, and this is handled a little differently. The ant javac compile task needs this to turn the generated .java files into .class files at runtime. You should already have this in the <java_home>/lib folder of your jdk.

    There are two new startup arguments for Winstone --javaHome and --toolsJar. You should only need to set --javaHome to make Jasper work properly. Your startup might look like this:

      java -jar winstone.jar --useJasper \
                             --javaHome=c:\java\jdk1.4.2 \
                             --webroot=...

    Additionally, you can specify the exact location of the toolsJar file like this:

      java -jar winstone.jar --useJasper \
                             --javaHome=c:\java\jdk1.4.2 \
                             --toolsJar=c:\tools.jar \
                             --webroot=...

Newer versions of Jasper seem to use the Eclipse JDT compiler, and therefore don't require tools.jar. You might want to try deploying the jasper related jars yourself - see if you can get it running with just a JRE configuration. Shouldn't be difficult, just a little debugging of which jar files are necessary.

CHANGED: Until v0.9.5, it wasn't necessary to add the jsp-api.jar, because winstone included it's own copy of the JSP API classes. However, the JSP v2.1 spec mandates the use of JDK1.5 generics in the API classes, so in order to continue supplying the API classes, Winstone would have to require JDK1.5 compilation as a minimum. Since a large percentage of people use Winstone for it's small footprint, and PDAs running on older spec JVMs are affected by this, it seemed more reasonable to just drop the JSP API classes and maintain the backwards compatibility.

I disagree with the Expert Group's penchant for trading away backwards compatibility in exchange for spec features that are unnecessary (such as generics and XSD support). But at the end of the day, they call the shots, so I just do what I can to minimize the downsides in practice.

Connecting to Apache

These instructions are for beginners: if you know your way around Apache and Tomcat, you'll know what's going on here.

Download and install Apache for your platform (and obviously Winstone too), then follow these steps:

  1. Download mod_jk.dll/so into the apache modules directory
  2. Add the following to the apache conf file (httpd.conf):
    LoadModule jk_module modules/mod_jk.dll
    
    <Location "/<Winstone Prefix>/*">
    JkMount /* ajp13
    </Location>
    
  3. Create a new file called workers.properties in the apache conf directory, with the following contents
    worker.list=ajp13
    worker.ajp13.port=8009
    worker.ajp13.host=localhost
    worker.ajp13.type=ajp13
    
  4. Start up Winstone, ensuring that the --ajp13Port=8009 is in the startup args.
  5. Start up Apache and try connecting to your webapp on the apache port, with the Winstone URL prefix. If it doesn't work, try looking at the apache error.log file for hints. If you get hex dumps, mail them to the winstone-devel list, together with any stack traces winstone generated.

Please note this is not an optimal configuration for production uses. This is provided purely for those who need some help to get started. Read the mod_jk documentation with Tomcat for more detailed info. Additionally, Costin Manolache of the Tomcat team suggested I point out that the "jvmRoute" feature (used for managing sticky session behaviour when clustering multiple Winstone's behind a single Apache) is not supported. This may change in the future - we'll see how it goes.

Using Authentication Realms

The process here is almost identical to that of Tomcat (I know this because I used the Tomcat examples webapp to develop against). There are two components - the web.xml component and selecting/configuring an AuthenticationRealm class.

  • The web.xml part is the same for all webapps - you include the <security-constraint> and <login-config> elements as required, eg (from the Tomcat examples web.xml):
    <security-constraint>
      <display-name>Example Security Constraint</display-name>
      <web-resource-collection>
        <web-resource-name>Protected Area</web-resource-name>
        <url-pattern>/jsp/security/protected/*</url-pattern>
        <http-method>DELETE</http-method>
        <http-method>GET</http-method>
        <http-method>POST</http-method>
        <http-method>PUT</http-method>
      </web-resource-collection>
      <auth-constraint>
        <role-name>tomcat</role-name>
        <role-name>role1</role-name>
      </auth-constraint>
    </security-constraint>
    
    <login-config>
      <auth-method>FORM</auth-method>
      <realm-name>Example Form-Based Authentication Area</realm-name>
      <form-login-config>
        <form-login-page>/jsp/security/protected/login.jsp</form-login-page>
        <form-error-page>/jsp/security/protected/error.jsp</form-error-page>
      </form-login-config>
    </login-config>
    
  • The AuthenticationRealm part is Winstone specific. Here you currently have three options:
    1. ArgumentsRealm: Here you simply add additional command line args for each user's password and role list. Passwords are added with --argumentsRealm.passwd.<username>=<password>, and roles are added with --argumentsRealm.roles.<username>=<role1>,<role2>
    2. FileRealm: This is the same as the Tomcat tomcat-users.xml file. Pass in the command line arguments --realmClassName=winstone.realm.FileRealm --fileRealm.configFile=<filename>, and it should work exactly the way Tomcat does by default.
    3. Write your own: You just have to extend the winstone.AuthenticationRealm class, and override the appropriate methods (as the File and Arguments Realms do), and specify the class name in --realmClassName.

This component is left intentionally fairly simple, and relatively extracted. I'm planning to break the realm and authentication stuff into an optional jar later, since not many webapps I've seen use it.

Cluster support

It should be pointed out in the beginning that the Cluster support currently implemented in Winstone is actually just session sharing. If a request comes to a node in the cluster that doesn't recognise the session ID supplied, that node simply asks the others "Do you know this session ?". If one does know it, it transfers the session to the requesting node, and the requesting node carries on as if it had always had the session in the first place.

If a specific node in the cluster goes offline, so do all the sessions that it was holding. There is no active "push" of sessions to other nodes, so as far as resilience to failure goes, this cluster is fairly weak. The clustering provided here is meant to allow a dumb load balancer to redirect requests randomly across a cluster of Winstone instances without requiring it to be "session sticky".

That said, the configuration is fairly simple. The only information you need is the IP address and control port of at least one other active node in the cluster. Once you have that, add the following options to the command line startup:

java -jar winstone.jar ...< other options > ... \
                       --controlPort=<myControlPort> \
                       --useCluster \
                       --clusterNodes=<IP1:controlPort1>

where IP1 is the IP address of the other node in the cluster, and myControlPort and controlPort1 are the port numbers to use for the control ports of this instance and the other node respectively. Note that it is necessary to actively set the controlPort on this instance, since it is disabled by default.

You would likewise set up the other instance with reciprocal options (ie changing the IPs and controlPort values appropriately.

NOTE: There are some additional requirements on your web application for Clustering of sessions to be successful.

  1. You need to include the <distributable/> element in your web.xml file. This tells Winstone that your webapp is programmed correctly to support clustering. If this is missing, clustering will be disabled.
  2. Any objects you add to the session must implement java.io.Serializable. This is required because Winstone serializes the objects in the session over the controlPort to other nodes, and reconstructs the serialized session at the destination. If you try to put a non-serializable object into the session, Winstone will throw an exception reminding you to make all session objects serializable.

Control port functions/protocol

From v0.5, the behaviour of the control port changes slightly. Due to increased usage of the control port by the clustering function, a rudimentary protocol has been added.

The protocol is very simple. The first byte sent to the server is a flag indicating what type of request is being issued. Beyond that the protocol varies for each request type, but the request type flag options are listed below:

  • 0 (ASCII 48) = shutdown
  • 1 (ASCII 49) = request search for a session
  • 2 (ASCII 50) = request list of currently connected cluster nodes
  • 3 (ASCII 51) = cluster node heartbeat
  • 4 (ASCII 52) = request reload of web application context

Obviously, unless you're planning to write your own cluster extensions, the only two you will be interested in are the shutdown and reload options. Luckily there is a wrapper class for accessing these functions, named winstone.tools.WinstoneControl. Try the following to get a usage statement:

  java -cp winstone.jar winstone.tools.WinstoneControl

JNDI support

I know that in the introduction I said that Winstone was only going to support the core servlet APIs, but I've since discovered that most people use just a little more than the core servlet API offers. For example, some people use just a JNDI JavaMail session to send administrator error mails, while others want to offer a simple servlet over SSL (and hence need Apache), still others use just a JNDI DataSource to keep a reference to the connection pool.

For this reason I've included a really basic optional JNDI service within Winstone. For the moment, it supports simple operations (such as bind, lookup, rebind, etc) and allows you to store references to environment variables (drawn from the env-entry elements in web.xml and/or command line arguments).

NOTE: JNDI support is disabled by default. It must be enabled using --useJNDI=true

Configuration can be done in two ways:

  • <env-entry> elements - This is the standard way to add simple objects, such as sql strings or configuration integers/strings. For example:
      <env-entry>
        <env-entry-name>test/hello</env-entry-name>
        <env-entry-type>java.lang.Integer</env-entry-type>
        <env-entry-value>45</env-entry-value>
      </env-entry>
    
  • Command line arguments - This is for more complex objects that require attributes to be created (JDBC DataSources for example). The syntax here involves adding a clause of the kind --jndi.resource.<resName>=<className> for each object to create, followed by --jndi.param.<resName>.<attName>=<attValue> for each attribute required. For example:
    java -jar winstone.jar ...< other options > ... \
                            --useJNDI=true \
                            --jndi.resource.test=java.lang.Float \
                            --jndi.param.test.value=45.56
    

Additionally, it includes a JDBC DataSource object which can be used as a wrapper around normal JDBC drivers. This is fairly simple for now, but it meets the requirements I mentioned above. Options are as follows:

  1. url (REQUIRED) - JDBC URL (jdbc:mysql://db.widgets.com/db)
  2. driverClassName (REQUIRED) - JDBC Driver name (eg com.mysql.jdbc.Driver)
  3. username - username for database authentication
  4. password - password for database authentication
  5. maxConnections - Maximum number of connections allowed in the pool. Default is 20
  6. maxIdle - Maximum number of idle connections allowed in the pool. Default is 10
  7. startConnections - The number of connections to open the pool with. Deafault is 2
  8. keepAliveSQL - The sql to execute on keep-alive (or checkBeforeGet) operations. Default is empty
  9. checkBeforeGet - If true, executes the keepAliveSQL before any connection is returned from the pool. Default is true if the keepAliveSQL is defined
  10. keepAlivePeriod - Execute the keepAliveSQL on all unused connection every n minutes. Default is disabled
  11. killInactivePeriod - Kills excess unused connections every n minutes. Default is disabled
  12. retryCount - When the pool is maxed out, block and retry n times. Default is 1 retry
  13. retryPeriod - The period (in ms) over which the retry blocks. Default is 1000ms

For example to create a DataSource object at the JNDI location java:/comp/env/jdbc/connPool, use the following command line (or config file) options:

java -jar winstone.jar ...< other options > ... \
                        --useJNDI=true \
                        --jndi.resource.jdbc/connPool=javax.sql.DataSource \
                        --jndi.param.jdbc/connPool.url=jdbc:mysql://db.widgets.com/db \
                        --jndi.param.jdbc/connPool.driverClassName=com.mysql.jdbc.Driver \
                        --jndi.param.jdbc/connPool.username=foo \
                        --jndi.param.jdbc/connPool.password=bar

HTTPS support

Somebody asked me to add HTTPS support, using the JDK 1.4 SSL socket classes, and so I decided to give it a try. It was a lot easier than expected - the API was really nice to use. Unfortunately the hard work seems to be in the configuration, rather than the programming.

I recommend using a shareware tool called KeyStore Explorer, available here. It's much easier than all that messy CLI stuff.

The steps are basically as follows:

  1. Create an empty keystore of type JKS
  2. Generate a key pair (Tools -> Generate Key Pair). I chose RSA 2048 bit, and used "MD5 with RSA" for the algorithm. Set a password and remember it.
  3. Generate a CSR (right click, Generate CSR).
  4. Send the CSR to a Certifying Authority (CA) for processing. I used FreeSSL.com, because it was only US$39 per year.
  5. Once you get the approved certificate back, import it into the key store you were using (Tools -> import CA reply). You should now have only a key pair and a certificate. Save the key store, using the same password you used before.
  6. Start winstone with the following command:
    java -jar winstone.jar --webroot=<webroot>
                           --httpsPort=443 
                           --httpsKeyStore=<keystore file> 
                           --httpsKeyStorePassword=<password>
  7. Set your hosts file (/etc/hosts or c:/Winnt/system32/drivers/etc/hosts) to point the name on your certificate to 127.0.0.1, then try to browse to https://(name on certificate)/

Access Logging

From v0.8, there's an option to allow access logging. It's disabled by default, but can be enabled by defining a logging implementation class, with --accessLoggerClassName. The class defined must be an implementation of the interface winstone.AccessLogger, and is defined container wide, but instantiated once per webapp.

The supplied logger is called winstone.accesslog.SimpleAccessLogger. It supports Apache style combined/common format logs, as well as Resin format (which is actually just Apache common style plus a user agent). Configuration options are:

  • --simpleAccessLogger.format: Either "combined", "common", "resin" or a pattern made up of wildcards. For example, the combined format string is:
    ###ip### - ###user### ###time### "###uriLine###" ###status### ###size### "###referer###" "###userAgent###"
    but you can re-arrange this to be any pattern of the above wildcards with the --accessLoggerFormat switch. Defaults to "combined"
  • --simpleAccessLogger.file: A pattern for defining the files to log to. The default value is logs/###host###/###webapp###_access.log, which splits the log files for different webapps and hosts into directories. The wildcards ###host### and ###webapp### can be moved around or even omitted. Omitting the wildcard will mean the access logs will be combined into shared files (since the file name will be the same)

For example, to enable Apache Combined style logging to separate files, use a command line like:

java -jar winstone.jar --hostsDir=<vhostsDir>
                           --accessLoggerClassName=winstone.accesslog.SimpleAccessLogger

Or to log just the date and URI for all hosts/webapps to a single file, use a command line like:

java -jar winstone.jar --hostsDir=<vhostsDir>
                       --accessLoggerClassName=winstone.accesslog.SimpleAccessLogger
                       --simpleAccessLogger.format=###date###\ ###uriLine###
                       --simpleAccessLogger.file=/mylogs/access_log.txt

Embedding Winstone

The design of Winstone has always allowed its easy embedding within another application. It's as simple as:

 // at startup
Map args = new HashMap();
args.put("webroot", "<my webroot dir>"); // or any other command line args, eg port
Launcher.initLogger(args);
Launcher winstone = new Launcher(args); // spawns threads, so your application doesn't block

... (your application code)

// before shutdown
winstone.shutdown(); 

From v0.8 though, there is also the ability to embed in the opposite direction: that is, to embed your warfile into the winstone JAR itself. This allows an all-in-one container plus web-application JAR file to be downloaded, and then unpacked at execution time.

To use this, simply unpack the winstone JAR, and place your WAR file inside the unpacked folder at the top level (with the same parent as the folder named "winstone"). Then rename your WAR file to "embedded.war", and repack the jar as before (make sure to preserve the META-INF and manifest).

Now if you type: "java -jar winstone.jar", your application should automatically deploy as the ROOT web application. Try http://localhost:8080/ to check it out.

If you need to add any default command-line arguments (eg ports or prefixes), you can embed a properties file in exactly the same way, except that the file must be named "embedded.properties".

Session persistence across reboots

From v0.9.5, if you start with --useSavedSessions as an argument, all sessions in the container will be saved to disk after each request, and loaded on container startup. The effect is that sessions will persist across reboots, instead of being lost (which is the default behaviour, or --useSavedSessions=false).

This is useful for development time, if only to prevent you from having to log in to your webapp every time you restart the container. It does however come with a few costs / side effects to think about:

  • Security: The sessions are serialized to disk in the webapp temp directory (see the spec for details) which is, by default, inside the system temp directory. If you are worried about people being able to read these files on a shared machine, set the temp directory manually with -Djava.io.tmpdir=<path>
  • Speed: Each time a request accesses a session, that session is re-saved to disk before the request completes. This introduces a slight hit performance-wise, but it's after the request has released the output stream, so there's good chance you won't notice any slow-down, except maybe under load or heavy keep-alive usage.
  • Serializability: You'll need to make sure anything you put in the session implements java.io.Serializable (for obvious reasons). This follows the same rules about session contents, as the "distributable" webapp / clustering feature, since it shares a large chunk of it's code.

Please give this feature a try if you can, and let me know if you hit any problems. It is still a little green around the edges, so any feedback or corrections will be appreciated.

jenkins-winstone-0.9.10-jenkins-47/site.css0000644000175000017500000000326312200024521021115 0ustar jamespagejamespage#header { width: 770px; margin-left: auto; margin-right: auto; margin-bottom: 20px; text-align:center; font-family:Verdana, Arial, Helvetica, sans-serif; font-size:12px; color:#1D373D; background-color:#bfbfbf; } #header h1 { padding: 20px 0px 0px 0px; font-size:22px; font-weight:bold; } #header ul { width: 245px; padding: 0px; margin: 0px auto 0px auto; list-style:none; } #header ul li { float: left; margin-right: 20px; padding: 0px 0px 10px 0px; } #header ul li.last { float: none; margin-right: 0px; } #footer { width: 770px; margin: 20px auto 0px auto; font-family:Verdana, Arial, Helvetica, sans-serif; font-size:11px; text-align:center; border-top:1px solid #999999; padding: 20px 20px 20px 20px; } #footer ul { width: 410px; padding: 0px; margin: 0px auto 0px auto; list-style:none; } #footer ul li { float: left; margin-right: 20px; padding: 0px 0px 10px 0px; } #footer ul li.last { float: none; margin-right: 0px; } #body { font-family:Verdana, Arial, Helvetica, sans-serif; font-size:12px; width: 770px; margin-left: auto; margin-right: auto; text-align:left; } #body pre, #body code { font-size:12px; padding: 3px; margin: 5px; } #nav { text-align:left; padding: 0px; } #nav ul { list-style:none; margin-top: 0px; } #nav ul li ul { list-style-type:disc; } #nav h2, .section h2 { padding: 5px 0px 0px 0px; margin: 10px 5px 10px 5px; font-size:18px; font-weight:bold; color: #000000; } #nav h3 { font-size:14px; padding: 10px 0px 5px 0px; margin: 0px; } .section { margin-left: auto; margin-right: auto; padding: 0px; } .section p { margin: 5px; padding: 3px; } #header a:visited, #body a:visited, #footer a:visited { color: #0000ff; }