forked from I2P_Developers/i2p.i2p
First cut at migrating to Jetty 6 and prep for using an external
Jetty 6 package. - Add several jars from the Jetty 6 distribution - Update jetty.xml - Add context XML files - Update WorkingDir to migrate the content XML files - Update RouterConsoleRunner and LocaleWebAppHandler - Remove all old Jetty 5.1.15 local mods; this will break Seedless using a custom Server() constructor - Update I2PRequestLog to be a mod of NCSARequestLog from 6.1.26 - Put I2PRequestLog in its own jar - Copy MultiPartRequest and other required classes from Jetty 5.1.15 and add it to susimail, as the replacement MultiPartFilter in Jetty 6 is difficult to migrate to, and does not support content-type - Update i2psnark for Jetty 6 - Disable i2psnark RunStandalone, unused and instantiated Jetty 5 - Fix up all webapp build.xml to reference new jars Not yet working: Plugin/webapp run detection and stopping, eepsite CGI Not well tested: Plugins, classpaths, webapps
This commit is contained in:
@@ -1,10 +1,11 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project basedir="." default="all" name="jetty">
|
||||
|
||||
<property name="jetty.base" value="jetty-5.1.15" />
|
||||
<property name="jetty.sha1" value="3a7a3de50f86f0cdb23c33aec632ea7f44132c5e" />
|
||||
<property name="jetty.filename" value="${jetty.base}.tgz" />
|
||||
<property name="jetty.url" value="http://dist.codehaus.org/jetty/jetty-5.1.x/${jetty.filename}" />
|
||||
<property name="jetty.ver" value="6.1.26" />
|
||||
<property name="jetty.base" value="jetty-${jetty.ver}" />
|
||||
<property name="jetty.sha1" value="9485913f1a1945a849a90f1a34853d22350bc524" />
|
||||
<property name="jetty.filename" value="${jetty.base}.zip" />
|
||||
<property name="jetty.url" value="http://dist.codehaus.org/jetty/${jetty.base}/${jetty.filename}" />
|
||||
<property name="verified.filename" value="verified.txt" />
|
||||
<property name="javac.compilerargs" value="" />
|
||||
|
||||
@@ -64,26 +65,46 @@
|
||||
</target>
|
||||
|
||||
<target name="extractJettylib" unless="jetty.zip.extracted" >
|
||||
<!-- for .tgz -->
|
||||
<!--
|
||||
<gunzip src="${jetty.filename}" dest="jetty.tar" />
|
||||
<untar src="jetty.tar" dest="." />
|
||||
-->
|
||||
<!-- for .zip -->
|
||||
<unzip src="${jetty.filename}" dest="." />
|
||||
<mkdir dir="jettylib" />
|
||||
<copy todir="jettylib" preservelastmodified="true" >
|
||||
<fileset dir="${jetty.base}/lib">
|
||||
<include name="*.jar" />
|
||||
</fileset>
|
||||
<fileset dir="${jetty.base}/ext">
|
||||
<include name="ant.jar" />
|
||||
<include name="commons-el.jar" />
|
||||
<include name="commons-logging.jar" />
|
||||
<include name="jasper-compiler.jar" />
|
||||
<include name="jasper-runtime.jar" />
|
||||
</fileset>
|
||||
</copy>
|
||||
<!-- We copy everything to names without the version numbers so we
|
||||
can update them later. Where there was something similar in Jetty 5,
|
||||
we use the same names.
|
||||
Reasons for inclusion:
|
||||
start.jar: Needed for clients.config startup of eepsites
|
||||
jetty-util-xxx.jar: LifeCycle (base class for stuff), URIUtil (used in i2psnark)
|
||||
jetty-sslengine-xxx.jar: SSL NIO Connector for console
|
||||
jetty-java5-threadpool-xxx.jar: Concurrent thread pool for eepsite
|
||||
commons-logging.jar: JspC compiler
|
||||
TODO which of these are available in the Ubuntu packages?
|
||||
-->
|
||||
<copy preservelastmodified="true" file="${jetty.base}/lib/${jetty.base}.jar" tofile="jettylib/org.mortbay.jetty.jar" />
|
||||
<copy preservelastmodified="true" file="${jetty.base}/lib/jetty-util-${jetty.ver}.jar" tofile="jettylib/jetty-util.jar" />
|
||||
<copy preservelastmodified="true" file="${jetty.base}/lib/servlet-api-2.5-20081211.jar" tofile="jettylib/javax.servlet.jar" />
|
||||
<copy preservelastmodified="true" file="${jetty.base}/lib/ext/jetty-sslengine-${jetty.ver}.jar" tofile="jettylib/jetty-sslengine.jar" />
|
||||
<copy preservelastmodified="true" file="${jetty.base}/lib/ext/jetty-java5-threadpool-${jetty.ver}.jar" tofile="jettylib/jetty-threadpool.jar" />
|
||||
<copy preservelastmodified="true" file="${jetty.base}/lib/jsp-2.0/ant-1.6.5.jar" tofile="jettylib/ant.jar" />
|
||||
<copy preservelastmodified="true" file="${jetty.base}/lib/jsp-2.0/commons-el-1.0.jar" tofile="jettylib/commons-el.jar" />
|
||||
<copy preservelastmodified="true" file="${jetty.base}/lib/jsp-2.0/jasper-compiler-5.5.15.jar" tofile="jettylib/jasper-compiler.jar" />
|
||||
<copy preservelastmodified="true" file="${jetty.base}/lib/jsp-2.0/jasper-runtime-5.5.15.jar" tofile="jettylib/jasper-runtime.jar" />
|
||||
<copy preservelastmodified="true" file="${jetty.base}/lib/jsp-2.0/jsp-api-2.0.jar" tofile="jettylib/jsp-api.jar" />
|
||||
<copy preservelastmodified="true" file="${jetty.base}/start.jar" tofile="jettylib/jetty-start.jar" />
|
||||
<delete file="jetty.tar" />
|
||||
<delete dir="${jetty.base}" />
|
||||
<!-- commons-logging.jar not in Jetty 6 but we have it in launch4j so copy it over, we need it
|
||||
for org.apache.jasper.JspC compiler
|
||||
-->
|
||||
<copy preservelastmodified="true" file="../../installer/lib/launch4j/lib/commons-logging.jar" todir="jettylib/" />
|
||||
</target>
|
||||
|
||||
<target name="build" depends="jar" />
|
||||
|
||||
<target name="builddep" />
|
||||
<target name="compile" depends="builddep, ensureJettylib" >
|
||||
<mkdir dir="./build" />
|
||||
@@ -93,7 +114,7 @@
|
||||
debug="true" source="1.5" target="1.5"
|
||||
destdir="./build/obj"
|
||||
includeAntRuntime="false"
|
||||
classpath="./jettylib/commons-logging.jar:./jettylib/javax.servlet.jar:./jettylib/org.mortbay.jetty.jar" >
|
||||
classpath="./jettylib/commons-logging.jar:./jettylib/javax.servlet.jar:./jettylib/org.mortbay.jetty.jar:./jettylib/jetty-util.jar" >
|
||||
<compilerarg line="${javac.compilerargs}" />
|
||||
</javac>
|
||||
</target>
|
||||
@@ -112,10 +133,13 @@
|
||||
</exec>
|
||||
</target>
|
||||
|
||||
<!-- With Jetty 5 we replaced classes in the jar, but with Jetty 6 we
|
||||
put our stuff in its own jar so we can work with standard Jetty 6 packages
|
||||
-->
|
||||
<target name="jar" depends="compile, jarUpToDate, listChangedFiles" unless="jar.uptodate" >
|
||||
<!-- set if unset -->
|
||||
<property name="workspace.changes.tr" value="" />
|
||||
<jar destfile="./jettylib/org.mortbay.jetty.jar" basedir="./build/obj" includes="**/*.class" update="true" >
|
||||
<jar destfile="./jettylib/jetty-i2p.jar" basedir="./build/obj" includes="**/*.class" >
|
||||
<manifest>
|
||||
<attribute name="Build-Date" value="${build.timestamp}" />
|
||||
<attribute name="Base-Revision" value="${workspace.version}" />
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -1,505 +0,0 @@
|
||||
// ========================================================================
|
||||
// $Id: NCSARequestLog.java,v 1.35 2005/08/13 00:01:24 gregwilkins Exp $
|
||||
// Copyright 2000-2004 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// ========================================================================
|
||||
|
||||
package org.mortbay.http;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.io.Writer;
|
||||
import java.util.Locale;
|
||||
import java.util.TimeZone;
|
||||
|
||||
import javax.servlet.http.Cookie;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.mortbay.log.LogFactory;
|
||||
import org.mortbay.util.DateCache;
|
||||
import org.mortbay.util.LogSupport;
|
||||
import org.mortbay.util.RolloverFileOutputStream;
|
||||
import org.mortbay.util.StringUtil;
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** NCSA HTTP Request Log.
|
||||
* NCSA common or NCSA extended (combined) request log.
|
||||
*
|
||||
* Taken from 5.1.12 source and modded to change some private vars to protected
|
||||
* so we can extend it for I2P.
|
||||
*
|
||||
* @version $Id: NCSARequestLog.java,v 1.35 2005/08/13 00:01:24 gregwilkins Exp $
|
||||
* @author Tony Thompson
|
||||
* @author Greg Wilkins
|
||||
*/
|
||||
public class NCSARequestLog implements RequestLog
|
||||
{
|
||||
protected static Log log = LogFactory.getLog(NCSARequestLog.class);
|
||||
|
||||
private String _filename;
|
||||
private boolean _extended;
|
||||
private boolean _append;
|
||||
private int _retainDays;
|
||||
private boolean _closeOut;
|
||||
private boolean _preferProxiedForAddress;
|
||||
private String _logDateFormat="dd/MMM/yyyy:HH:mm:ss ZZZ";
|
||||
private Locale _logLocale=Locale.getDefault();
|
||||
private String _logTimeZone=TimeZone.getDefault().getID();
|
||||
private String[] _ignorePaths;
|
||||
private boolean _logLatency=false;
|
||||
private boolean _logCookies=false;
|
||||
|
||||
protected transient OutputStream _out;
|
||||
protected transient OutputStream _fileOut;
|
||||
protected transient DateCache _logDateCache;
|
||||
protected transient PathMap _ignorePathMap;
|
||||
protected transient Writer _writer;
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Constructor.
|
||||
*/
|
||||
public NCSARequestLog()
|
||||
{
|
||||
_extended=true;
|
||||
_append=true;
|
||||
_retainDays=31;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Constructor.
|
||||
* @param filename Filename, which can be in
|
||||
* rolloverFileOutputStream format
|
||||
* @see org.mortbay.util.RolloverFileOutputStream
|
||||
* @exception IOException
|
||||
*/
|
||||
public NCSARequestLog(String filename)
|
||||
throws IOException
|
||||
{
|
||||
_extended=true;
|
||||
_append=true;
|
||||
_retainDays=31;
|
||||
setFilename(filename);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Set the log filename.
|
||||
* @see NCSARequestLog#setRetainDays(int)
|
||||
* @param filename The filename to use. If the filename contains the
|
||||
* string "yyyy_mm_dd", then a RolloverFileOutputStream is used and the
|
||||
* log is rolled over nightly and aged according setRetainDays. If no
|
||||
* filename is set or a null filename
|
||||
* passed, then requests are logged to System.err.
|
||||
*/
|
||||
public void setFilename(String filename)
|
||||
{
|
||||
if (filename!=null)
|
||||
{
|
||||
filename=filename.trim();
|
||||
if (filename.length()==0)
|
||||
filename=null;
|
||||
}
|
||||
_filename=filename;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Get the log filename.
|
||||
* @see NCSARequestLog#getDatedFilename()
|
||||
* @return The log filename without any date expansion.
|
||||
*/
|
||||
public String getFilename()
|
||||
{
|
||||
return _filename;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Get the dated log filename.
|
||||
* @see NCSARequestLog#getFilename()
|
||||
* @return The log filename with any date encoding expanded.
|
||||
*/
|
||||
public String getDatedFilename()
|
||||
{
|
||||
if (_fileOut instanceof RolloverFileOutputStream)
|
||||
return ((RolloverFileOutputStream)_fileOut).getDatedFilename();
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @param format The date format to use within the log file.
|
||||
*/
|
||||
public void setLogDateFormat(String format)
|
||||
{
|
||||
_logDateFormat=format;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @return The date format to use within the log file.
|
||||
*/
|
||||
public String getLogDateFormat()
|
||||
{
|
||||
return _logDateFormat;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @param tz The date format timezone to use within the log file.
|
||||
*/
|
||||
public void setLogTimeZone(String tz)
|
||||
{
|
||||
_logTimeZone=tz;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @return The date format timezone to use within the log file.
|
||||
*/
|
||||
public String getLogTimeZone()
|
||||
{
|
||||
return _logTimeZone;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @return The number of days to retain rollovered log files.
|
||||
*/
|
||||
public int getRetainDays()
|
||||
{
|
||||
return _retainDays;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @param retainDays The number of days to retain rollovered log files.
|
||||
*/
|
||||
public void setRetainDays(int retainDays)
|
||||
{
|
||||
_retainDays = retainDays;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @return True if NCSA extended format is to be used.
|
||||
*/
|
||||
public boolean isExtended()
|
||||
{
|
||||
return _extended;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @param e True if NCSA extended format is to be used.
|
||||
*/
|
||||
public void setExtended(boolean e)
|
||||
{
|
||||
_extended=e;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @return True if logs are appended to existing log files.
|
||||
*/
|
||||
public boolean isAppend()
|
||||
{
|
||||
return _append;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @param a True if logs are appended to existing log files.
|
||||
*/
|
||||
public void setAppend(boolean a)
|
||||
{
|
||||
_append=a;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @deprecated ignored
|
||||
*/
|
||||
public void setBuffered(boolean b)
|
||||
{}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Set which paths to ignore.
|
||||
*
|
||||
* @param ignorePaths Array of path specifications to ignore
|
||||
*/
|
||||
public void setIgnorePaths(String[] ignorePaths)
|
||||
{
|
||||
// Contributed by Martin Vilcans (martin@jadestone.se)
|
||||
_ignorePaths = ignorePaths;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public String[] getIgnorePaths()
|
||||
{
|
||||
return _ignorePaths;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @return Returns the logCookies.
|
||||
*/
|
||||
public boolean getLogCookies()
|
||||
{
|
||||
return _logCookies;
|
||||
}
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @param logCookies The logCookies to set.
|
||||
*/
|
||||
public void setLogCookies(boolean logCookies)
|
||||
{
|
||||
_logCookies = logCookies;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @return Returns true if logging latency
|
||||
*/
|
||||
public boolean getLogLatency()
|
||||
{
|
||||
return _logLatency;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @param logLatency If true, latency is logged at the end of the log line
|
||||
*/
|
||||
public void setLogLatency(boolean logLatency)
|
||||
{
|
||||
_logLatency = logLatency;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Prefer to log the proxied-for IP address (if present in
|
||||
* the request header) over the native requester IP address.
|
||||
* Useful in reverse-proxy situations when you'd rather see
|
||||
* the IP address of the host before the most recent proxy
|
||||
* server, as opposed to your own proxy server(s) every time.
|
||||
*
|
||||
* jlrobins@socialserve.com, March 2004.
|
||||
**/
|
||||
public void setPreferProxiedForAddress(boolean value)
|
||||
{
|
||||
_preferProxiedForAddress = value;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public void start()
|
||||
throws Exception
|
||||
{
|
||||
_logDateCache=new DateCache(_logDateFormat,_logLocale);
|
||||
_logDateCache.setTimeZoneID(_logTimeZone);
|
||||
|
||||
if (_filename != null)
|
||||
{
|
||||
_fileOut=new RolloverFileOutputStream(_filename,_append,_retainDays);
|
||||
_closeOut=true;
|
||||
}
|
||||
else
|
||||
_fileOut=System.err;
|
||||
|
||||
_out=_fileOut;
|
||||
|
||||
if (_ignorePaths!=null && _ignorePaths.length>0)
|
||||
{
|
||||
_ignorePathMap=new PathMap();
|
||||
for (int i=0;i<_ignorePaths.length;i++)
|
||||
_ignorePathMap.put(_ignorePaths[i],_ignorePaths[i]);
|
||||
}
|
||||
else
|
||||
_ignorePathMap=null;
|
||||
|
||||
_writer=new OutputStreamWriter(_out);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public boolean isStarted()
|
||||
{
|
||||
return _fileOut!=null;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public void stop()
|
||||
{
|
||||
try{if (_writer!=null)_writer.flush();} catch (IOException e){LogSupport.ignore(log,e);}
|
||||
if (_out!=null && _closeOut)
|
||||
try{_out.close();}catch(IOException e){LogSupport.ignore(log,e);}
|
||||
_out=null;
|
||||
_fileOut=null;
|
||||
_closeOut=false;
|
||||
_logDateCache=null;
|
||||
_writer=null;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Log a request.
|
||||
* @param request The request
|
||||
* @param response The response to this request.
|
||||
* @param responseLength The bytes written to the response.
|
||||
*/
|
||||
public void log(HttpRequest request,
|
||||
HttpResponse response,
|
||||
int responseLength)
|
||||
{
|
||||
try{
|
||||
// ignore ignorables
|
||||
if (_ignorePathMap != null &&
|
||||
_ignorePathMap.getMatch(request.getPath()) != null)
|
||||
return;
|
||||
|
||||
// log the rest
|
||||
if (_fileOut==null)
|
||||
return;
|
||||
|
||||
StringBuffer buf = new StringBuffer(160);
|
||||
|
||||
String addr = null;
|
||||
if(_preferProxiedForAddress)
|
||||
{
|
||||
// If header is not present, addr will remain null ...
|
||||
addr = request.getField(HttpFields.__XForwardedFor);
|
||||
}
|
||||
if(addr == null)
|
||||
addr = request.getRemoteAddr();
|
||||
buf.append(addr);
|
||||
|
||||
buf.append(" - ");
|
||||
String user = request.getAuthUser();
|
||||
buf.append((user==null)?"-":user);
|
||||
buf.append(" [");
|
||||
buf.append(_logDateCache.format(request.getTimeStamp()));
|
||||
buf.append("] \"");
|
||||
buf.append(request.getMethod());
|
||||
buf.append(' ');
|
||||
buf.append(request.getURI());
|
||||
buf.append(' ');
|
||||
buf.append(request.getVersion());
|
||||
buf.append("\" ");
|
||||
int status=response.getStatus();
|
||||
buf.append((char)('0'+((status/100)%10)));
|
||||
buf.append((char)('0'+((status/10)%10)));
|
||||
buf.append((char)('0'+(status%10)));
|
||||
if (responseLength>=0)
|
||||
{
|
||||
buf.append(' ');
|
||||
if (responseLength>99999)
|
||||
buf.append(Integer.toString(responseLength));
|
||||
else
|
||||
{
|
||||
if (responseLength>9999)
|
||||
buf.append((char)('0'+((responseLength/10000)%10)));
|
||||
if (responseLength>999)
|
||||
buf.append((char)('0'+((responseLength/1000)%10)));
|
||||
if (responseLength>99)
|
||||
buf.append((char)('0'+((responseLength/100)%10)));
|
||||
if (responseLength>9)
|
||||
buf.append((char)('0'+((responseLength/10)%10)));
|
||||
buf.append((char)('0'+(responseLength%10)));
|
||||
}
|
||||
buf.append(' ');
|
||||
}
|
||||
else
|
||||
buf.append(" - ");
|
||||
|
||||
String log =buf.toString();
|
||||
synchronized(_writer)
|
||||
{
|
||||
_writer.write(log);
|
||||
if (_extended)
|
||||
{
|
||||
logExtended(request,response,_writer);
|
||||
if (!_logCookies)
|
||||
_writer.write(" -");
|
||||
}
|
||||
|
||||
if (_logCookies)
|
||||
{
|
||||
Cookie[] cookies = request.getCookies();
|
||||
if (cookies==null || cookies.length==0)
|
||||
_writer.write(" -");
|
||||
else
|
||||
{
|
||||
_writer.write(" \"");
|
||||
for (int i=0;i<cookies.length;i++)
|
||||
{
|
||||
if (i!=0)
|
||||
_writer.write(';');
|
||||
_writer.write(cookies[i].getName());
|
||||
_writer.write('=');
|
||||
_writer.write(cookies[i].getValue());
|
||||
}
|
||||
_writer.write("\"");
|
||||
}
|
||||
}
|
||||
|
||||
if (_logLatency)
|
||||
_writer.write(" "+(System.currentTimeMillis()-request.getTimeStamp()));
|
||||
|
||||
_writer.write(StringUtil.__LINE_SEPARATOR);
|
||||
_writer.flush();
|
||||
}
|
||||
}
|
||||
catch(IOException e)
|
||||
{
|
||||
log.warn(LogSupport.EXCEPTION,e);
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Log Extended fields.
|
||||
* This method can be extended by a derived class to add extened fields to
|
||||
* each log entry. It is called by the log method after all standard
|
||||
* fields have been added, but before the line terminator.
|
||||
* Derived implementations should write extra fields to the Writer
|
||||
* provided.
|
||||
* The default implementation writes the referer and user agent.
|
||||
* @param request The request to log.
|
||||
* @param response The response to log.
|
||||
* @param log The writer to write the extra fields to.
|
||||
* @exception IOException Problem writing log
|
||||
*/
|
||||
protected void logExtended(HttpRequest request,
|
||||
HttpResponse response,
|
||||
Writer log)
|
||||
throws IOException
|
||||
{
|
||||
String referer = request.getField(HttpFields.__Referer);
|
||||
if(referer==null)
|
||||
log.write("\"-\" ");
|
||||
else
|
||||
{
|
||||
log.write('"');
|
||||
log.write(referer);
|
||||
log.write("\" ");
|
||||
}
|
||||
|
||||
String agent = request.getField(HttpFields.__UserAgent);
|
||||
if(agent==null)
|
||||
log.write("\"-\"");
|
||||
else
|
||||
{
|
||||
log.write('"');
|
||||
log.write(agent);
|
||||
log.write('"');
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
@@ -1,809 +0,0 @@
|
||||
// ========================================================================
|
||||
// $Id: ResourceHandler.java,v 1.66 2005/08/24 08:18:17 gregwilkins Exp $
|
||||
// Copyright 199-2004 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// ========================================================================
|
||||
|
||||
package org.mortbay.http.handler;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.Enumeration;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.mortbay.log.LogFactory;
|
||||
import org.mortbay.http.HttpException;
|
||||
import org.mortbay.http.HttpFields;
|
||||
import org.mortbay.http.HttpRequest;
|
||||
import org.mortbay.http.HttpResponse;
|
||||
import org.mortbay.http.InclusiveByteRange;
|
||||
import org.mortbay.http.MultiPartResponse;
|
||||
import org.mortbay.http.ResourceCache;
|
||||
import org.mortbay.util.CachedResource;
|
||||
import org.mortbay.util.IO;
|
||||
import org.mortbay.util.LogSupport;
|
||||
import org.mortbay.util.Resource;
|
||||
import org.mortbay.util.StringMap;
|
||||
import org.mortbay.util.TypeUtil;
|
||||
import org.mortbay.util.URI;
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Handler to serve files and resources.
|
||||
* Serves files from a given resource URL base and implements
|
||||
* the GET, HEAD, DELETE, OPTIONS, PUT, MOVE methods and the
|
||||
* IfModifiedSince and IfUnmodifiedSince header fields.
|
||||
* A simple memory cache is also provided to reduce file I/O.
|
||||
* HTTP/1.1 ranges are supported.
|
||||
*
|
||||
* @version $Id: ResourceHandler.java,v 1.66 2005/08/24 08:18:17 gregwilkins Exp $
|
||||
* @author Nuno Pregui?a (sorry, wasn't UTF-8)
|
||||
* @author Greg Wilkins
|
||||
*/
|
||||
public class ResourceHandler extends AbstractHttpHandler
|
||||
{
|
||||
private static Log log = LogFactory.getLog(ResourceHandler.class);
|
||||
|
||||
/* ----------------------------------------------------------------- */
|
||||
private boolean _acceptRanges=true;
|
||||
private boolean _redirectWelcomeFiles ;
|
||||
private String[] _methods=null;
|
||||
private String _allowed;
|
||||
private boolean _dirAllowed=true;
|
||||
private int _minGzipLength =-1;
|
||||
private StringMap _methodMap = new StringMap();
|
||||
{
|
||||
setAllowedMethods(new String[]
|
||||
{
|
||||
HttpRequest.__GET,
|
||||
HttpRequest.__POST,
|
||||
HttpRequest.__HEAD,
|
||||
HttpRequest.__OPTIONS,
|
||||
HttpRequest.__TRACE
|
||||
});
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------- */
|
||||
/** Construct a ResourceHandler.
|
||||
*/
|
||||
public ResourceHandler()
|
||||
{}
|
||||
|
||||
|
||||
/* ----------------------------------------------------------------- */
|
||||
public synchronized void start()
|
||||
throws Exception
|
||||
{
|
||||
super.start();
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------- */
|
||||
public void stop()
|
||||
throws InterruptedException
|
||||
{
|
||||
super.stop();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public String[] getAllowedMethods()
|
||||
{
|
||||
return _methods;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public void setAllowedMethods(String[] methods)
|
||||
{
|
||||
StringBuffer b = new StringBuffer();
|
||||
_methods=methods;
|
||||
_methodMap.clear();
|
||||
for (int i=0;i<methods.length;i++)
|
||||
{
|
||||
_methodMap.put(methods[i],methods[i]);
|
||||
if (i>0)
|
||||
b.append(',');
|
||||
b.append(methods[i]);
|
||||
}
|
||||
_allowed=b.toString();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public boolean isMethodAllowed(String method)
|
||||
{
|
||||
return _methodMap.get(method)!=null;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public String getAllowedString()
|
||||
{
|
||||
return _allowed;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public boolean isDirAllowed()
|
||||
{
|
||||
return _dirAllowed;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public void setDirAllowed(boolean dirAllowed)
|
||||
{
|
||||
_dirAllowed = dirAllowed;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public boolean isAcceptRanges()
|
||||
{
|
||||
return _acceptRanges;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @return True if welcome files are redirected to. False if forward is used.
|
||||
*/
|
||||
public boolean getRedirectWelcome()
|
||||
{
|
||||
return _redirectWelcomeFiles;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @param redirectWelcome True if welcome files are redirected to. False
|
||||
* if forward is used.
|
||||
*/
|
||||
public void setRedirectWelcome(boolean redirectWelcome)
|
||||
{
|
||||
_redirectWelcomeFiles = redirectWelcome;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Set if the handler accepts range requests.
|
||||
* Default is false;
|
||||
* @param ar True if the handler should accept ranges
|
||||
*/
|
||||
public void setAcceptRanges(boolean ar)
|
||||
{
|
||||
_acceptRanges=ar;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Get minimum content length for GZIP encoding.
|
||||
* @return Minimum length of content for gzip encoding or -1 if disabled.
|
||||
*/
|
||||
public int getMinGzipLength()
|
||||
{
|
||||
return _minGzipLength;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Set minimum content length for GZIP encoding.
|
||||
* @param minGzipLength If set to a positive integer, then static content
|
||||
* larger than this will be served as gzip content encoded
|
||||
* if a matching resource is found ending with ".gz"
|
||||
*/
|
||||
public void setMinGzipLength(int minGzipLength)
|
||||
{
|
||||
_minGzipLength = minGzipLength;
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** get Resource to serve.
|
||||
* Map a path to a resource. The default implementation calls
|
||||
* HttpContext.getResource but derived handers may provide
|
||||
* their own mapping.
|
||||
* @param pathInContext The path to find a resource for.
|
||||
* @return The resource to serve.
|
||||
*/
|
||||
protected Resource getResource(String pathInContext)
|
||||
throws IOException
|
||||
{
|
||||
return getHttpContext().getResource(pathInContext);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public void handle(String pathInContext,
|
||||
String pathParams,
|
||||
HttpRequest request,
|
||||
HttpResponse response)
|
||||
throws HttpException, IOException
|
||||
{
|
||||
Resource resource = getResource(pathInContext);
|
||||
if (resource==null)
|
||||
return;
|
||||
|
||||
// Is the method allowed?
|
||||
if (!isMethodAllowed(request.getMethod()))
|
||||
{
|
||||
if(log.isDebugEnabled())log.debug("Method not allowed: "+request.getMethod());
|
||||
if (resource.exists())
|
||||
{
|
||||
setAllowHeader(response);
|
||||
response.sendError(HttpResponse.__405_Method_Not_Allowed);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Handle the request
|
||||
try
|
||||
{
|
||||
if(log.isDebugEnabled())log.debug("PATH="+pathInContext+" RESOURCE="+resource);
|
||||
|
||||
// check filename
|
||||
String method=request.getMethod();
|
||||
if (method.equals(HttpRequest.__GET) ||
|
||||
method.equals(HttpRequest.__POST) ||
|
||||
method.equals(HttpRequest.__HEAD))
|
||||
handleGet(request, response, pathInContext, pathParams, resource);
|
||||
else if (method.equals(HttpRequest.__PUT))
|
||||
handlePut(request, response, pathInContext, resource);
|
||||
else if (method.equals(HttpRequest.__DELETE))
|
||||
handleDelete(request, response, pathInContext, resource);
|
||||
else if (method.equals(HttpRequest.__OPTIONS))
|
||||
handleOptions(response, pathInContext);
|
||||
else if (method.equals(HttpRequest.__MOVE))
|
||||
handleMove(request, response, pathInContext, resource);
|
||||
else if (method.equals(HttpRequest.__TRACE))
|
||||
handleTrace(request, response);
|
||||
else
|
||||
{
|
||||
if(log.isDebugEnabled())log.debug("Unknown action:"+method);
|
||||
// anything else...
|
||||
try{
|
||||
if (resource.exists())
|
||||
response.sendError(HttpResponse.__501_Not_Implemented);
|
||||
}
|
||||
catch(Exception e) {LogSupport.ignore(log,e);}
|
||||
}
|
||||
}
|
||||
catch(IllegalArgumentException e)
|
||||
{
|
||||
LogSupport.ignore(log,e);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (resource!=null && !(resource instanceof CachedResource))
|
||||
resource.release();
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------- */
|
||||
public void handleGet(HttpRequest request,
|
||||
HttpResponse response,
|
||||
String pathInContext,
|
||||
String pathParams,
|
||||
Resource resource)
|
||||
throws IOException
|
||||
{
|
||||
if(log.isDebugEnabled())log.debug("Looking for "+resource);
|
||||
|
||||
if (resource!=null && resource.exists())
|
||||
{
|
||||
// check if directory
|
||||
if (resource.isDirectory())
|
||||
{
|
||||
if (!pathInContext.endsWith("/") && !pathInContext.equals("/"))
|
||||
{
|
||||
log.debug("Redirect to directory/");
|
||||
|
||||
String q=request.getQuery();
|
||||
|
||||
// Properly fix URI
|
||||
URI urifix = new URI(request.getRequestURL().toString());
|
||||
urifix.setPath(urifix.getPath());
|
||||
StringBuffer buf = new StringBuffer(urifix.toString());
|
||||
urifix = null;
|
||||
|
||||
if (q!=null&&q.length()!=0)
|
||||
{
|
||||
buf.append('?');
|
||||
buf.append(q);
|
||||
}
|
||||
response.setField(HttpFields.__Location, URI.addPaths(buf.toString(),"/"));
|
||||
response.setStatus(302);
|
||||
request.setHandled(true);
|
||||
return;
|
||||
}
|
||||
|
||||
// See if index file exists
|
||||
String welcome=getHttpContext().getWelcomeFile(resource);
|
||||
if (welcome!=null)
|
||||
{
|
||||
// Forward to the index
|
||||
String ipath=URI.addPaths(pathInContext,welcome);
|
||||
if (_redirectWelcomeFiles)
|
||||
{
|
||||
// Redirect to the index
|
||||
ipath=URI.addPaths(getHttpContext().getContextPath(),ipath);
|
||||
response.setContentLength(0);
|
||||
response.sendRedirect(ipath);
|
||||
}
|
||||
else
|
||||
{
|
||||
URI uri=request.getURI();
|
||||
uri.setPath(URI.addPaths(uri.getPath(),welcome));
|
||||
getHttpContext().handle(ipath,pathParams,request,response);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Check modified dates
|
||||
if (!passConditionalHeaders(request,response,resource))
|
||||
return;
|
||||
// If we got here, no forward to index took place
|
||||
sendDirectory(request,response,resource,pathInContext.length()>1);
|
||||
}
|
||||
// check if it is a file
|
||||
else if (resource.exists())
|
||||
{
|
||||
// Check modified dates
|
||||
if (!passConditionalHeaders(request,response,resource))
|
||||
return;
|
||||
sendData(request,response,pathInContext,resource,true);
|
||||
}
|
||||
else
|
||||
// don't know what it is
|
||||
log.warn("Unknown file type");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/* Check modification date headers.
|
||||
*/
|
||||
private boolean passConditionalHeaders(HttpRequest request,
|
||||
HttpResponse response,
|
||||
Resource resource)
|
||||
throws IOException
|
||||
{
|
||||
if (!request.getMethod().equals(HttpRequest.__HEAD))
|
||||
{
|
||||
// If we have meta data for the file
|
||||
// Try a direct match for most common requests. Avoids
|
||||
// parsing the date.
|
||||
ResourceCache.ResourceMetaData metaData =
|
||||
(ResourceCache.ResourceMetaData)resource.getAssociate();
|
||||
if (metaData!=null)
|
||||
{
|
||||
String ifms=request.getField(HttpFields.__IfModifiedSince);
|
||||
String mdlm=metaData.getLastModified();
|
||||
if (ifms!=null && mdlm!=null && ifms.equals(mdlm))
|
||||
{
|
||||
response.setStatus(HttpResponse.__304_Not_Modified);
|
||||
request.setHandled(true);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
long date=0;
|
||||
// Parse the if[un]modified dates and compare to resource
|
||||
|
||||
if ((date=request.getDateField(HttpFields.__IfUnmodifiedSince))>0)
|
||||
{
|
||||
if (resource.lastModified()/1000 > date/1000)
|
||||
{
|
||||
response.sendError(HttpResponse.__412_Precondition_Failed);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if ((date=request.getDateField(HttpFields.__IfModifiedSince))>0)
|
||||
{
|
||||
|
||||
if (resource.lastModified()/1000 <= date/1000)
|
||||
{
|
||||
response.setStatus(HttpResponse.__304_Not_Modified);
|
||||
request.setHandled(true);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
void handlePut(HttpRequest request,
|
||||
HttpResponse response,
|
||||
String pathInContext,
|
||||
Resource resource)
|
||||
throws IOException
|
||||
{
|
||||
if(log.isDebugEnabled())log.debug("PUT "+pathInContext+" in "+resource);
|
||||
|
||||
boolean exists=resource!=null && resource.exists();
|
||||
if (exists &&
|
||||
!passConditionalHeaders(request,response,resource))
|
||||
return;
|
||||
|
||||
if (pathInContext.endsWith("/"))
|
||||
{
|
||||
if (!exists)
|
||||
{
|
||||
if (!resource.getFile().mkdirs())
|
||||
response.sendError(HttpResponse.__403_Forbidden, "Directories could not be created");
|
||||
else
|
||||
{
|
||||
request.setHandled(true);
|
||||
response.setStatus(HttpResponse.__201_Created);
|
||||
response.commit();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
request.setHandled(true);
|
||||
response.setStatus(HttpResponse.__200_OK);
|
||||
response.commit();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
int toRead = request.getContentLength();
|
||||
InputStream in = request.getInputStream();
|
||||
OutputStream out = resource.getOutputStream();
|
||||
if (toRead>=0)
|
||||
IO.copy(in,out,toRead);
|
||||
else
|
||||
IO.copy(in,out);
|
||||
out.close();
|
||||
request.setHandled(true);
|
||||
response.setStatus(exists
|
||||
?HttpResponse.__200_OK
|
||||
:HttpResponse.__201_Created);
|
||||
response.commit();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
log.warn(LogSupport.EXCEPTION,ex);
|
||||
response.sendError(HttpResponse.__403_Forbidden,
|
||||
ex.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
void handleDelete(HttpRequest request,
|
||||
HttpResponse response,
|
||||
String pathInContext,
|
||||
Resource resource)
|
||||
throws IOException
|
||||
{
|
||||
if(log.isDebugEnabled())log.debug("DELETE "+pathInContext+" from "+resource);
|
||||
|
||||
if (!resource.exists() ||
|
||||
!passConditionalHeaders(request,response,resource))
|
||||
return;
|
||||
|
||||
try
|
||||
{
|
||||
// delete the file
|
||||
if (resource.delete())
|
||||
response.setStatus(HttpResponse.__204_No_Content);
|
||||
else
|
||||
response.sendError(HttpResponse.__403_Forbidden);
|
||||
|
||||
// Send response
|
||||
request.setHandled(true);
|
||||
}
|
||||
catch (SecurityException sex)
|
||||
{
|
||||
log.warn(LogSupport.EXCEPTION,sex);
|
||||
response.sendError(HttpResponse.__403_Forbidden, sex.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
void handleMove(HttpRequest request,
|
||||
HttpResponse response,
|
||||
String pathInContext,
|
||||
Resource resource)
|
||||
throws IOException
|
||||
{
|
||||
if (!resource.exists() || !passConditionalHeaders(request,response,resource))
|
||||
return;
|
||||
|
||||
|
||||
String newPath = URI.canonicalPath(request.getField("New-uri"));
|
||||
if (newPath==null)
|
||||
{
|
||||
response.sendError(HttpResponse.__405_Method_Not_Allowed,
|
||||
"Bad new uri");
|
||||
return;
|
||||
}
|
||||
|
||||
String contextPath = getHttpContext().getContextPath();
|
||||
if (contextPath!=null && !newPath.startsWith(contextPath))
|
||||
{
|
||||
response.sendError(HttpResponse.__405_Method_Not_Allowed,
|
||||
"Not in context");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// Find path
|
||||
try
|
||||
{
|
||||
// TODO - Check this
|
||||
String newInfo=newPath;
|
||||
if (contextPath!=null)
|
||||
newInfo=newInfo.substring(contextPath.length());
|
||||
Resource newFile = getHttpContext().getBaseResource().addPath(newInfo);
|
||||
|
||||
if(log.isDebugEnabled())log.debug("Moving "+resource+" to "+newFile);
|
||||
resource.renameTo(newFile);
|
||||
|
||||
response.setStatus(HttpResponse.__204_No_Content);
|
||||
request.setHandled(true);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
log.warn(LogSupport.EXCEPTION,ex);
|
||||
setAllowHeader(response);
|
||||
response.sendError(HttpResponse.__405_Method_Not_Allowed,
|
||||
"Error:"+ex);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
void handleOptions(HttpResponse response, String pathInContext)
|
||||
throws IOException
|
||||
{
|
||||
if ("*".equals(pathInContext))
|
||||
return;
|
||||
setAllowHeader(response);
|
||||
response.commit();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
void setAllowHeader(HttpResponse response)
|
||||
{
|
||||
response.setField(HttpFields.__Allow, getAllowedString());
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public void writeHeaders(HttpResponse response,Resource resource, long count)
|
||||
throws IOException
|
||||
{
|
||||
ResourceCache.ResourceMetaData metaData =
|
||||
(ResourceCache.ResourceMetaData)resource.getAssociate();
|
||||
|
||||
response.setContentType(metaData.getMimeType());
|
||||
if (count != -1)
|
||||
{
|
||||
if (count==resource.length())
|
||||
response.setField(HttpFields.__ContentLength,metaData.getLength());
|
||||
else
|
||||
response.setContentLength((int)count);
|
||||
}
|
||||
|
||||
response.setField(HttpFields.__LastModified,metaData.getLastModified());
|
||||
|
||||
if (_acceptRanges && response.getHttpRequest().getDotVersion()>0)
|
||||
response.setField(HttpFields.__AcceptRanges,"bytes");
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public void sendData(HttpRequest request,
|
||||
HttpResponse response,
|
||||
String pathInContext,
|
||||
Resource resource,
|
||||
boolean writeHeaders)
|
||||
throws IOException
|
||||
{
|
||||
long resLength=resource.length();
|
||||
|
||||
// see if there are any range headers
|
||||
Enumeration reqRanges =
|
||||
request.getDotVersion()>0
|
||||
?request.getFieldValues(HttpFields.__Range)
|
||||
:null;
|
||||
|
||||
if (!writeHeaders || reqRanges == null || !reqRanges.hasMoreElements())
|
||||
{
|
||||
// look for a gziped content.
|
||||
Resource data=resource;
|
||||
if (_minGzipLength>0)
|
||||
{
|
||||
String accept=request.getField(HttpFields.__AcceptEncoding);
|
||||
if (accept!=null && resLength>_minGzipLength &&
|
||||
!pathInContext.endsWith(".gz"))
|
||||
{
|
||||
Resource gz = getHttpContext().getResource(pathInContext+".gz");
|
||||
if (gz.exists() && accept.indexOf("gzip")>=0)
|
||||
{
|
||||
if(log.isDebugEnabled())log.debug("gzip="+gz);
|
||||
response.setField(HttpFields.__ContentEncoding,"gzip");
|
||||
data=gz;
|
||||
resLength=data.length();
|
||||
}
|
||||
}
|
||||
}
|
||||
writeHeaders(response,resource,resLength);
|
||||
|
||||
request.setHandled(true);
|
||||
OutputStream out = response.getOutputStream();
|
||||
data.writeTo(out,0,resLength);
|
||||
return;
|
||||
}
|
||||
|
||||
// Parse the satisfiable ranges
|
||||
List ranges =InclusiveByteRange.satisfiableRanges(reqRanges,resLength);
|
||||
if(log.isDebugEnabled())log.debug("ranges: " + reqRanges + " == " + ranges);
|
||||
|
||||
// if there are no satisfiable ranges, send 416 response
|
||||
if (ranges==null || ranges.size()==0)
|
||||
{
|
||||
log.debug("no satisfiable ranges");
|
||||
writeHeaders(response, resource, resLength);
|
||||
response.setStatus(HttpResponse.__416_Requested_Range_Not_Satisfiable);
|
||||
response.setReason((String)HttpResponse.__statusMsg
|
||||
.get(TypeUtil.newInteger(HttpResponse.__416_Requested_Range_Not_Satisfiable)));
|
||||
|
||||
response.setField(HttpFields.__ContentRange,
|
||||
InclusiveByteRange.to416HeaderRangeString(resLength));
|
||||
|
||||
OutputStream out = response.getOutputStream();
|
||||
resource.writeTo(out,0,resLength);
|
||||
request.setHandled(true);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// if there is only a single valid range (must be satisfiable
|
||||
// since were here now), send that range with a 216 response
|
||||
if ( ranges.size()== 1)
|
||||
{
|
||||
InclusiveByteRange singleSatisfiableRange =
|
||||
(InclusiveByteRange)ranges.get(0);
|
||||
if(log.isDebugEnabled())log.debug("single satisfiable range: " + singleSatisfiableRange);
|
||||
long singleLength = singleSatisfiableRange.getSize(resLength);
|
||||
writeHeaders(response,resource,singleLength);
|
||||
response.setStatus(HttpResponse.__206_Partial_Content);
|
||||
response.setReason((String)HttpResponse.__statusMsg
|
||||
.get(TypeUtil.newInteger(HttpResponse.__206_Partial_Content)));
|
||||
response.setField(HttpFields.__ContentRange,
|
||||
singleSatisfiableRange.toHeaderRangeString(resLength));
|
||||
OutputStream out = response.getOutputStream();
|
||||
resource.writeTo(out,
|
||||
singleSatisfiableRange.getFirst(resLength),
|
||||
singleLength);
|
||||
request.setHandled(true);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// multiple non-overlapping valid ranges cause a multipart
|
||||
// 216 response which does not require an overall
|
||||
// content-length header
|
||||
//
|
||||
ResourceCache.ResourceMetaData metaData =
|
||||
(ResourceCache.ResourceMetaData)resource.getAssociate();
|
||||
String encoding = metaData.getMimeType();
|
||||
MultiPartResponse multi = new MultiPartResponse(response);
|
||||
response.setStatus(HttpResponse.__206_Partial_Content);
|
||||
response.setReason((String)HttpResponse.__statusMsg
|
||||
.get(TypeUtil.newInteger(HttpResponse.__206_Partial_Content)));
|
||||
|
||||
// If the request has a "Request-Range" header then we need to
|
||||
// send an old style multipart/x-byteranges Content-Type. This
|
||||
// keeps Netscape and acrobat happy. This is what Apache does.
|
||||
String ctp;
|
||||
if (request.containsField(HttpFields.__RequestRange))
|
||||
ctp = "multipart/x-byteranges; boundary=";
|
||||
else
|
||||
ctp = "multipart/byteranges; boundary=";
|
||||
response.setContentType(ctp+multi.getBoundary());
|
||||
|
||||
InputStream in=(resource instanceof CachedResource)
|
||||
?null:resource.getInputStream();
|
||||
OutputStream out = response.getOutputStream();
|
||||
long pos=0;
|
||||
|
||||
for (int i=0;i<ranges.size();i++)
|
||||
{
|
||||
InclusiveByteRange ibr = (InclusiveByteRange) ranges.get(i);
|
||||
String header=HttpFields.__ContentRange+": "+
|
||||
ibr.toHeaderRangeString(resLength);
|
||||
if(log.isDebugEnabled())log.debug("multi range: "+encoding+" "+header);
|
||||
multi.startPart(encoding,new String[]{header});
|
||||
|
||||
long start=ibr.getFirst(resLength);
|
||||
long size=ibr.getSize(resLength);
|
||||
if (in!=null)
|
||||
{
|
||||
// Handle non cached resource
|
||||
if (start<pos)
|
||||
{
|
||||
in.close();
|
||||
in=resource.getInputStream();
|
||||
pos=0;
|
||||
}
|
||||
if (pos<start)
|
||||
{
|
||||
in.skip(start-pos);
|
||||
pos=start;
|
||||
}
|
||||
IO.copy(in,out,size);
|
||||
pos+=size;
|
||||
}
|
||||
else
|
||||
// Handle cached resource
|
||||
resource.writeTo(out,start,size);
|
||||
|
||||
}
|
||||
if (in!=null)
|
||||
in.close();
|
||||
multi.close();
|
||||
|
||||
request.setHandled(true);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------- */
|
||||
void sendDirectory(HttpRequest request,
|
||||
HttpResponse response,
|
||||
Resource resource,
|
||||
boolean parent)
|
||||
throws IOException
|
||||
{
|
||||
if (!_dirAllowed)
|
||||
{
|
||||
response.sendError(HttpResponse.__403_Forbidden);
|
||||
return;
|
||||
}
|
||||
|
||||
request.setHandled(true);
|
||||
|
||||
if(log.isDebugEnabled())log.debug("sendDirectory: "+resource);
|
||||
byte[] data=null;
|
||||
if (resource instanceof CachedResource)
|
||||
data=((CachedResource)resource).getCachedData();
|
||||
|
||||
if (data==null)
|
||||
{
|
||||
String base = URI.addPaths(request.getPath(),"/");
|
||||
String dir = resource.getListHTML(URI.encodePath(base),parent);
|
||||
if (dir==null)
|
||||
{
|
||||
response.sendError(HttpResponse.__403_Forbidden,
|
||||
"No directory");
|
||||
return;
|
||||
}
|
||||
data=dir.getBytes("UTF8");
|
||||
if (resource instanceof CachedResource)
|
||||
((CachedResource)resource).setCachedData(data);
|
||||
}
|
||||
|
||||
response.setContentType("text/html; charset=UTF8");
|
||||
response.setContentLength(data.length);
|
||||
|
||||
if (request.getMethod().equals(HttpRequest.__HEAD))
|
||||
{
|
||||
response.commit();
|
||||
return;
|
||||
}
|
||||
|
||||
response.getOutputStream().write(data,0,data.length);
|
||||
response.commit();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@@ -1,617 +0,0 @@
|
||||
// ========================================================================
|
||||
// $Id: Server.java,v 1.40 2005/10/21 13:52:11 gregwilkins Exp $
|
||||
// Copyright 2002-2004 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// ========================================================================
|
||||
|
||||
package org.mortbay.jetty;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.mortbay.log.LogFactory;
|
||||
import org.mortbay.http.HttpContext;
|
||||
import org.mortbay.http.HttpServer;
|
||||
import org.mortbay.jetty.servlet.ServletHttpContext;
|
||||
import org.mortbay.jetty.servlet.WebApplicationContext;
|
||||
import org.mortbay.util.LogSupport;
|
||||
import org.mortbay.util.Resource;
|
||||
import org.mortbay.xml.XmlConfiguration;
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** The Jetty HttpServer.
|
||||
*
|
||||
* This specialization of org.mortbay.http.HttpServer adds knowledge
|
||||
* about servlets and their specialized contexts. It also included
|
||||
* support for initialization from xml configuration files
|
||||
* that follow the XmlConfiguration dtd.
|
||||
*
|
||||
* HttpContexts created by Server are of the type
|
||||
* org.mortbay.jetty.servlet.ServletHttpContext unless otherwise
|
||||
* specified.
|
||||
*
|
||||
* This class also provides a main() method which starts a server for
|
||||
* each config file passed on the command line. If the system
|
||||
* property JETTY_NO_SHUTDOWN_HOOK is not set to true, then a shutdown
|
||||
* hook is thread is registered to stop these servers.
|
||||
*
|
||||
* @see org.mortbay.xml.XmlConfiguration
|
||||
* @see org.mortbay.jetty.servlet.ServletHttpContext
|
||||
* @version $Revision: 1.40 $
|
||||
* @author Greg Wilkins (gregw)
|
||||
*/
|
||||
public class Server extends HttpServer
|
||||
{
|
||||
static Log log = LogFactory.getLog(Server.class);
|
||||
private String[] _webAppConfigurationClassNames =
|
||||
new String[]{"org.mortbay.jetty.servlet.XMLConfiguration", "org.mortbay.jetty.servlet.JettyWebConfiguration"};
|
||||
private String _configuration;
|
||||
private String _rootWebApp;
|
||||
private static ShutdownHookThread hookThread = new ShutdownHookThread();
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Constructor.
|
||||
*/
|
||||
public Server()
|
||||
{
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Constructor.
|
||||
* @param configuration The filename or URL of the XML
|
||||
* configuration file.
|
||||
*/
|
||||
public Server(String configuration)
|
||||
throws IOException
|
||||
{
|
||||
this(Resource.newResource(configuration).getURL());
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Constructor.
|
||||
* @param configuration The filename or URL of the XML
|
||||
* configuration file.
|
||||
*/
|
||||
public Server(Resource configuration)
|
||||
throws IOException
|
||||
{
|
||||
this(configuration.getURL());
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Constructor.
|
||||
* @param configuration The filename or URL of the XML
|
||||
* configuration file.
|
||||
*/
|
||||
public Server(URL configuration)
|
||||
throws IOException
|
||||
{
|
||||
_configuration=configuration.toString();
|
||||
Server.hookThread.add(this);
|
||||
try
|
||||
{
|
||||
XmlConfiguration config=new XmlConfiguration(configuration);
|
||||
config.configure(this);
|
||||
}
|
||||
catch(IOException e)
|
||||
{
|
||||
throw e;
|
||||
}
|
||||
catch(InvocationTargetException e)
|
||||
{
|
||||
log.warn(LogSupport.EXCEPTION,e.getTargetException());
|
||||
throw new IOException("Jetty configuration problem: "+e.getTargetException());
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
log.warn(LogSupport.EXCEPTION,e);
|
||||
throw new IOException("Jetty configuration problem: "+e);
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public boolean getStopAtShutdown()
|
||||
{
|
||||
return hookThread.contains(this);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public void setStopAtShutdown(boolean stop)
|
||||
{
|
||||
if (stop)
|
||||
hookThread.add(this);
|
||||
else
|
||||
hookThread.remove(this);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Get the root webapp name.
|
||||
* @return The name of the root webapp (eg. "root" for root.war).
|
||||
*/
|
||||
public String getRootWebApp()
|
||||
{
|
||||
return _rootWebApp;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Set the root webapp name.
|
||||
* @param rootWebApp The name of the root webapp (eg. "root" for root.war).
|
||||
*/
|
||||
public void setRootWebApp(String rootWebApp)
|
||||
{
|
||||
_rootWebApp = rootWebApp;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Configure the server from an XML file.
|
||||
* @param configuration The filename or URL of the XML
|
||||
* configuration file.
|
||||
*/
|
||||
public void configure(String configuration)
|
||||
throws IOException
|
||||
{
|
||||
|
||||
URL url=Resource.newResource(configuration).getURL();
|
||||
if (_configuration!=null && _configuration.equals(url.toString()))
|
||||
return;
|
||||
if (_configuration!=null)
|
||||
throw new IllegalStateException("Already configured with "+_configuration);
|
||||
try
|
||||
{
|
||||
XmlConfiguration config=new XmlConfiguration(url);
|
||||
_configuration=url.toString();
|
||||
config.configure(this);
|
||||
}
|
||||
catch(IOException e)
|
||||
{
|
||||
throw e;
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
log.warn(LogSupport.EXCEPTION,e);
|
||||
throw new IOException("Jetty configuration problem: "+e);
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public String getConfiguration()
|
||||
{
|
||||
return _configuration;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Create a new ServletHttpContext.
|
||||
* Ths method is called by HttpServer to creat new contexts. Thus
|
||||
* calls to addContext or getContext that result in a new Context
|
||||
* being created will return an
|
||||
* org.mortbay.jetty.servlet.ServletHttpContext instance.
|
||||
* @return ServletHttpContext
|
||||
*/
|
||||
protected HttpContext newHttpContext()
|
||||
{
|
||||
return new ServletHttpContext();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Create a new WebApplicationContext.
|
||||
* Ths method is called by Server to creat new contexts for web
|
||||
* applications. Thus calls to addWebApplication that result in
|
||||
* a new Context being created will return an correct class instance.
|
||||
* Derived class can override this method to create instance of its
|
||||
* own class derived from WebApplicationContext in case it needs more
|
||||
* functionality.
|
||||
* @param webApp The Web application directory or WAR file.
|
||||
* @return WebApplicationContext
|
||||
*/
|
||||
protected WebApplicationContext newWebApplicationContext(
|
||||
String webApp
|
||||
)
|
||||
{
|
||||
return new WebApplicationContext(webApp);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Add Web Application.
|
||||
* @param contextPathSpec The context path spec. Which must be of
|
||||
* the form / or /path/*
|
||||
* @param webApp The Web application directory or WAR file.
|
||||
* @return The WebApplicationContext
|
||||
* @exception IOException
|
||||
*/
|
||||
public WebApplicationContext addWebApplication(String contextPathSpec,
|
||||
String webApp)
|
||||
throws IOException
|
||||
{
|
||||
return addWebApplication(null,contextPathSpec,webApp);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Add Web Application.
|
||||
* @param virtualHost Virtual host name or null
|
||||
* @param contextPathSpec The context path spec. Which must be of
|
||||
* the form / or /path/*
|
||||
* @param webApp The Web application directory or WAR file.
|
||||
* @return The WebApplicationContext
|
||||
* @exception IOException
|
||||
*/
|
||||
public WebApplicationContext addWebApplication(String virtualHost,
|
||||
String contextPathSpec,
|
||||
String webApp)
|
||||
throws IOException
|
||||
{
|
||||
WebApplicationContext appContext =
|
||||
newWebApplicationContext(webApp);
|
||||
appContext.setContextPath(contextPathSpec);
|
||||
addContext(virtualHost,appContext);
|
||||
if(log.isDebugEnabled())log.debug("Web Application "+appContext+" added");
|
||||
return appContext;
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Add Web Applications.
|
||||
* Add auto webapplications to the server. The name of the
|
||||
* webapp directory or war is used as the context name. If a
|
||||
* webapp is called "root" it is added at "/".
|
||||
* @param webapps Directory file name or URL to look for auto webapplication.
|
||||
* @exception IOException
|
||||
*/
|
||||
public WebApplicationContext[] addWebApplications(String webapps)
|
||||
throws IOException
|
||||
{
|
||||
return addWebApplications(null,webapps,null,false);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Add Web Applications.
|
||||
* Add auto webapplications to the server. The name of the
|
||||
* webapp directory or war is used as the context name. If the
|
||||
* webapp matches the rootWebApp it is added as the "/" context.
|
||||
* @param host Virtual host name or null
|
||||
* @param webapps Directory file name or URL to look for auto webapplication.
|
||||
* @exception IOException
|
||||
*/
|
||||
public WebApplicationContext[] addWebApplications(String host,
|
||||
String webapps)
|
||||
throws IOException
|
||||
{
|
||||
return addWebApplications(host,webapps,null,false);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Add Web Applications.
|
||||
* Add auto webapplications to the server. The name of the
|
||||
* webapp directory or war is used as the context name. If the
|
||||
* webapp matches the rootWebApp it is added as the "/" context.
|
||||
* @param host Virtual host name or null
|
||||
* @param webapps Directory file name or URL to look for auto
|
||||
* webapplication.
|
||||
* @param extract If true, extract war files
|
||||
* @exception IOException
|
||||
*/
|
||||
public WebApplicationContext[] addWebApplications(String host,
|
||||
String webapps,
|
||||
boolean extract)
|
||||
throws IOException
|
||||
{
|
||||
return addWebApplications(host,webapps,null,extract);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Add Web Applications.
|
||||
* Add auto webapplications to the server. The name of the
|
||||
* webapp directory or war is used as the context name. If the
|
||||
* webapp matches the rootWebApp it is added as the "/" context.
|
||||
* @param host Virtual host name or null
|
||||
* @param webapps Directory file name or URL to look for auto
|
||||
* webapplication.
|
||||
* @param defaults The defaults xml filename or URL which is
|
||||
* loaded before any in the web app. Must respect the web.dtd.
|
||||
* If null the default defaults file is used. If the empty string, then
|
||||
* no defaults file is used.
|
||||
* @param extract If true, extract war files
|
||||
* @exception IOException
|
||||
*/
|
||||
public WebApplicationContext[] addWebApplications(String host,
|
||||
String webapps,
|
||||
String defaults,
|
||||
boolean extract)
|
||||
throws IOException
|
||||
{
|
||||
return addWebApplications(host,webapps,defaults,extract,true,null);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Add Web Applications.
|
||||
* Add auto webapplications to the server. The name of the
|
||||
* webapp directory or war is used as the context name. If the
|
||||
* webapp matches the rootWebApp it is added as the "/" context.
|
||||
* @param host Virtual host name or null
|
||||
* @param webapps Directory file name or URL to look for auto
|
||||
* webapplication.
|
||||
* @param defaults The defaults xml filename or URL which is
|
||||
* loaded before any in the web app. Must respect the web.dtd.
|
||||
* If null the default defaults file is used. If the empty string, then
|
||||
* no defaults file is used.
|
||||
* @param extract If true, extract war files
|
||||
* @param java2CompliantClassLoader True if java2 compliance is applied to all webapplications
|
||||
* @exception IOException
|
||||
*/
|
||||
public WebApplicationContext[] addWebApplications(String host,
|
||||
String webapps,
|
||||
String defaults,
|
||||
boolean extract,
|
||||
boolean java2CompliantClassLoader)
|
||||
throws IOException
|
||||
{
|
||||
return addWebApplications(host,webapps,defaults,extract,java2CompliantClassLoader,null);
|
||||
|
||||
}
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Add Web Applications.
|
||||
* Add auto webapplications to the server. The name of the
|
||||
* webapp directory or war is used as the context name. If the
|
||||
* webapp matches the rootWebApp it is added as the "/" context.
|
||||
* @param host Virtual host name or null
|
||||
* @param webapps Directory file name or URL to look for auto
|
||||
* webapplication.
|
||||
* @param defaults The defaults xml filename or URL which is
|
||||
* loaded before any in the web app. Must respect the web.dtd.
|
||||
* If null the default defaults file is used. If the empty string, then
|
||||
* no defaults file is used.
|
||||
* @param extract If true, extract war files
|
||||
* @param java2CompliantClassLoader True if java2 compliance is applied to all webapplications
|
||||
* @param Attributes[] A set of attributes to pass to setAttribute, format is first item is the key, second item is the value.
|
||||
* @exception IOException
|
||||
*/
|
||||
public WebApplicationContext[] addWebApplications(String host,
|
||||
String webapps,
|
||||
String defaults,
|
||||
boolean extract,
|
||||
boolean java2CompliantClassLoader,
|
||||
String Attributes[])
|
||||
throws IOException
|
||||
{
|
||||
ArrayList wacs = new ArrayList();
|
||||
Resource r=Resource.newResource(webapps);
|
||||
if (!r.exists())
|
||||
throw new IllegalArgumentException("No such webapps resource "+r);
|
||||
|
||||
if (!r.isDirectory())
|
||||
throw new IllegalArgumentException("Not directory webapps resource "+r);
|
||||
if(Attributes != null) {
|
||||
if(((Attributes.length / 2) * 2) != Attributes.length) {
|
||||
throw new IllegalArgumentException("Attributes must be in pairs of key,value.");
|
||||
}
|
||||
}
|
||||
String[] files=r.list();
|
||||
|
||||
for (int f=0;files!=null && f<files.length;f++)
|
||||
{
|
||||
String context=files[f];
|
||||
|
||||
if (context.equalsIgnoreCase("CVS/") ||
|
||||
context.equalsIgnoreCase("CVS") ||
|
||||
context.startsWith("."))
|
||||
continue;
|
||||
|
||||
|
||||
String app = r.addPath(r.encode(files[f])).toString();
|
||||
if (context.toLowerCase().endsWith(".war") ||
|
||||
context.toLowerCase().endsWith(".jar"))
|
||||
{
|
||||
context=context.substring(0,context.length()-4);
|
||||
Resource unpacked=r.addPath(context);
|
||||
if (unpacked!=null && unpacked.exists() && unpacked.isDirectory())
|
||||
continue;
|
||||
}
|
||||
|
||||
if (_rootWebApp!=null && (context.equals(_rootWebApp)||context.equals(_rootWebApp+"/")))
|
||||
context="/";
|
||||
else
|
||||
context="/"+context;
|
||||
|
||||
WebApplicationContext wac= addWebApplication(host,
|
||||
context,
|
||||
app);
|
||||
wac.setExtractWAR(extract);
|
||||
wac.setClassLoaderJava2Compliant(java2CompliantClassLoader);
|
||||
if (defaults!=null)
|
||||
{
|
||||
if (defaults.length()==0)
|
||||
wac.setDefaultsDescriptor(null);
|
||||
else
|
||||
wac.setDefaultsDescriptor(defaults);
|
||||
}
|
||||
if(Attributes != null) {
|
||||
for(int i = 0; i < Attributes.length; i++, i++) {
|
||||
wac.setAttribute(Attributes[i],Attributes[i + 1]);
|
||||
}
|
||||
}
|
||||
wacs.add(wac);
|
||||
}
|
||||
|
||||
return (WebApplicationContext[])wacs.toArray(new WebApplicationContext[wacs.size()]);
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** setWebApplicationConfigurationClasses
|
||||
* Set up the list of classnames of WebApplicationContext.Configuration
|
||||
* implementations that will be applied to configure every webapp.
|
||||
* The list can be overridden by individual WebApplicationContexts.
|
||||
* @param configurationClasses
|
||||
*/
|
||||
public void setWebApplicationConfigurationClassNames (String[] configurationClassNames)
|
||||
{
|
||||
if (configurationClassNames != null)
|
||||
{
|
||||
_webAppConfigurationClassNames = new String[configurationClassNames.length];
|
||||
System.arraycopy(configurationClassNames, 0, _webAppConfigurationClassNames, 0, configurationClassNames.length);
|
||||
}
|
||||
}
|
||||
|
||||
public String[] getWebApplicationConfigurationClassNames ()
|
||||
{
|
||||
return _webAppConfigurationClassNames;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/* ------------------------------------------------------------ */
|
||||
/* ------------------------------------------------------------ */
|
||||
public static void main(String[] arg)
|
||||
{
|
||||
String[] dftConfig={"etc/jetty.xml"};
|
||||
|
||||
if (arg.length==0)
|
||||
{
|
||||
log.info("Using default configuration: etc/jetty.xml");
|
||||
arg=dftConfig;
|
||||
}
|
||||
|
||||
final Server[] servers=new Server[arg.length];
|
||||
|
||||
// create and start the servers.
|
||||
for (int i=0;i<arg.length;i++)
|
||||
{
|
||||
try
|
||||
{
|
||||
servers[i] = new Server(arg[i]);
|
||||
servers[i].setStopAtShutdown(true);
|
||||
servers[i].start();
|
||||
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
log.warn(LogSupport.EXCEPTION,e);
|
||||
}
|
||||
}
|
||||
|
||||
// create and start the servers.
|
||||
for (int i=0;i<arg.length;i++)
|
||||
{
|
||||
try{servers[i].join();}
|
||||
catch (Exception e){LogSupport.ignore(log,e);}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* ShutdownHook thread for stopping all servers.
|
||||
*
|
||||
* Thread is hooked first time list of servers is changed.
|
||||
*/
|
||||
private static class ShutdownHookThread extends Thread {
|
||||
private boolean hooked = false;
|
||||
private ArrayList servers = new ArrayList();
|
||||
|
||||
/**
|
||||
* Hooks this thread for shutdown.
|
||||
* @see java.lang.Runtime#addShutdownHook(java.lang.Thread)
|
||||
*/
|
||||
private void createShutdownHook() {
|
||||
if (!Boolean.getBoolean("JETTY_NO_SHUTDOWN_HOOK") && !hooked) {
|
||||
try {
|
||||
Method shutdownHook = java.lang.Runtime.class.getMethod("addShutdownHook",
|
||||
new Class[] { java.lang.Thread.class });
|
||||
shutdownHook.invoke(Runtime.getRuntime(), new Object[] { this });
|
||||
this.hooked = true;
|
||||
} catch (Exception e) {
|
||||
if (log.isDebugEnabled()) log.debug("No shutdown hook in JVM ", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add Server to servers list.
|
||||
*/
|
||||
public boolean add(Server server) {
|
||||
createShutdownHook();
|
||||
return this.servers.add(server);
|
||||
}
|
||||
|
||||
/**
|
||||
* Contains Server in servers list?
|
||||
*/
|
||||
public boolean contains(Server server) {
|
||||
return this.servers.contains(server);
|
||||
}
|
||||
|
||||
/**
|
||||
* Append all Servers from Collection
|
||||
*/
|
||||
public boolean addAll(Collection c) {
|
||||
createShutdownHook();
|
||||
return this.servers.addAll(c);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear list of Servers.
|
||||
*/
|
||||
public void clear() {
|
||||
createShutdownHook();
|
||||
this.servers.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove Server from list.
|
||||
*/
|
||||
public boolean remove(Server server) {
|
||||
createShutdownHook();
|
||||
return this.servers.remove(server);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove all Servers in Collection from list.
|
||||
*/
|
||||
public boolean removeAll(Collection c) {
|
||||
createShutdownHook();
|
||||
return this.servers.removeAll(c);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop all Servers in list.
|
||||
*/
|
||||
public void run() {
|
||||
setName("Shutdown");
|
||||
log.info("Shutdown hook executing");
|
||||
Iterator it = servers.iterator();
|
||||
while (it.hasNext()) {
|
||||
Server svr = (Server) it.next();
|
||||
if (svr == null) continue;
|
||||
try {
|
||||
svr.stop();
|
||||
} catch (Exception e) {
|
||||
log.warn(LogSupport.EXCEPTION, e);
|
||||
}
|
||||
log.info("Shutdown hook complete");
|
||||
|
||||
// Try to avoid JVM crash
|
||||
try {
|
||||
Thread.sleep(1000);
|
||||
} catch (Exception e) {
|
||||
log.warn(LogSupport.EXCEPTION, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
@@ -1,352 +0,0 @@
|
||||
// ========================================================================
|
||||
// $Id: FileResource.java,v 1.31 2006/01/04 13:55:31 gregwilkins Exp $
|
||||
// Copyright 1996-2004 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// ========================================================================
|
||||
package org.mortbay.util;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
import java.security.Permission;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.mortbay.log.LogFactory;
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** File Resource.
|
||||
*
|
||||
* Handle resources of implied or explicit file type.
|
||||
* This class can check for aliasing in the filesystem (eg case
|
||||
* insensitivity). By default this is turned on if the platform does
|
||||
* not have the "/" path separator, or it can be controlled with the
|
||||
* "org.mortbay.util.FileResource.checkAliases" system parameter.
|
||||
*
|
||||
* If alias checking is turned on, then aliased resources are
|
||||
* treated as if they do not exist, nor can they be created.
|
||||
*
|
||||
* @version $Revision: 1.31 $
|
||||
* @author Greg Wilkins (gregw)
|
||||
*/
|
||||
public class FileResource extends URLResource
|
||||
{
|
||||
private static Log log = LogFactory.getLog(Credential.class);
|
||||
private static boolean __checkAliases;
|
||||
static
|
||||
{
|
||||
__checkAliases=
|
||||
"true".equalsIgnoreCase
|
||||
(System.getProperty("org.mortbay.util.FileResource.checkAliases","true"));
|
||||
|
||||
if (__checkAliases)
|
||||
log.info("Checking Resource aliases");
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
private File _file;
|
||||
private transient URL _alias=null;
|
||||
private transient boolean _aliasChecked=false;
|
||||
|
||||
/* ------------------------------------------------------------------------------- */
|
||||
/** setCheckAliases.
|
||||
* @param checkAliases True of resource aliases are to be checked for (eg case insensitivity or 8.3 short names) and treated as not found.
|
||||
*/
|
||||
public static void setCheckAliases(boolean checkAliases)
|
||||
{
|
||||
__checkAliases=checkAliases;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------------- */
|
||||
/** getCheckAliases.
|
||||
* @return True of resource aliases are to be checked for (eg case insensitivity or 8.3 short names) and treated as not found.
|
||||
*/
|
||||
public static boolean getCheckAliases()
|
||||
{
|
||||
return __checkAliases;
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------- */
|
||||
FileResource(URL url)
|
||||
throws IOException, URISyntaxException
|
||||
{
|
||||
super(url,null);
|
||||
|
||||
try
|
||||
{
|
||||
// Try standard API to convert URL to file.
|
||||
_file =new File(new URI(url.toString()));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LogSupport.ignore(log,e);
|
||||
try
|
||||
{
|
||||
// Assume that File.toURL produced unencoded chars. So try
|
||||
// encoding them.
|
||||
String urls=
|
||||
"file:"+org.mortbay.util.URI.encodePath(url.toString().substring(5));
|
||||
_file =new File(new URI(urls));
|
||||
}
|
||||
catch (Exception e2)
|
||||
{
|
||||
LogSupport.ignore(log,e2);
|
||||
|
||||
// Still can't get the file. Doh! try good old hack!
|
||||
checkConnection();
|
||||
Permission perm = _connection.getPermission();
|
||||
_file = new File(perm==null?url.getFile():perm.getName());
|
||||
}
|
||||
}
|
||||
|
||||
if (_file.isDirectory() && !_urlString.endsWith("/"))
|
||||
_urlString=_urlString+"/";
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------- */
|
||||
FileResource(URL url, URLConnection connection, File file)
|
||||
{
|
||||
super(url,connection);
|
||||
_file=file;
|
||||
if (_file.isDirectory() && !_urlString.endsWith("/"))
|
||||
_urlString=_urlString+"/";
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------- */
|
||||
public Resource addPath(String path)
|
||||
throws IOException,MalformedURLException
|
||||
{
|
||||
FileResource r=null;
|
||||
|
||||
if (!isDirectory())
|
||||
{
|
||||
r=(FileResource)super.addPath(path);
|
||||
}
|
||||
else
|
||||
{
|
||||
path = org.mortbay.util.URI.canonicalPath(path);
|
||||
|
||||
// treat all paths being added as relative
|
||||
String rel=path;
|
||||
if (path.startsWith("/"))
|
||||
rel = path.substring(1);
|
||||
|
||||
File newFile = new File(_file,rel.replace('/', File.separatorChar));
|
||||
r=new FileResource(newFile.toURI().toURL(),null,newFile);
|
||||
}
|
||||
|
||||
String encoded=org.mortbay.util.URI.encodePath(path);
|
||||
int expected=r._urlString.length()-encoded.length();
|
||||
int index = r._urlString.lastIndexOf(encoded, expected);
|
||||
|
||||
if (expected!=index && ((expected-1)!=index || path.endsWith("/") || !r.isDirectory()))
|
||||
{
|
||||
r._alias=r._url;
|
||||
r._aliasChecked=true;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public URL getAlias()
|
||||
{
|
||||
if (__checkAliases) {
|
||||
if (!_aliasChecked)
|
||||
{
|
||||
try
|
||||
{
|
||||
String abs=_file.getAbsolutePath();
|
||||
String can=_file.getCanonicalPath();
|
||||
|
||||
if (abs.length()!=can.length() || !abs.equals(can))
|
||||
_alias=new File(can).toURI().toURL();
|
||||
|
||||
_aliasChecked=true;
|
||||
|
||||
if (_alias!=null && log.isDebugEnabled())
|
||||
{
|
||||
log.debug("ALIAS abs="+abs);
|
||||
log.debug("ALIAS can="+can);
|
||||
}
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
log.warn(LogSupport.EXCEPTION,e);
|
||||
return getURL();
|
||||
}
|
||||
}
|
||||
} else return null;
|
||||
return _alias;
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------- */
|
||||
/**
|
||||
* Returns true if the resource exists.
|
||||
*/
|
||||
public boolean exists()
|
||||
{
|
||||
return _file.exists();
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------- */
|
||||
/**
|
||||
* Returns the last modified time
|
||||
*/
|
||||
public long lastModified()
|
||||
{
|
||||
return _file.lastModified();
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------- */
|
||||
/**
|
||||
* Returns true if the respresenetd resource is a container/directory.
|
||||
*/
|
||||
public boolean isDirectory()
|
||||
{
|
||||
return _file.isDirectory();
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------- */
|
||||
/**
|
||||
* Return the length of the resource
|
||||
*/
|
||||
public long length()
|
||||
{
|
||||
return _file.length();
|
||||
}
|
||||
|
||||
|
||||
/* --------------------------------------------------------- */
|
||||
/**
|
||||
* Returns the name of the resource
|
||||
*/
|
||||
public String getName()
|
||||
{
|
||||
return _file.getAbsolutePath();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Returns an File representing the given resource or NULL if this
|
||||
* is not possible.
|
||||
*/
|
||||
public File getFile()
|
||||
{
|
||||
return _file;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------- */
|
||||
/**
|
||||
* Returns an input stream to the resource
|
||||
*/
|
||||
public InputStream getInputStream() throws IOException
|
||||
{
|
||||
return new FileInputStream(_file);
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------- */
|
||||
/**
|
||||
* Returns an output stream to the resource
|
||||
*/
|
||||
public OutputStream getOutputStream()
|
||||
throws java.io.IOException, SecurityException
|
||||
{
|
||||
return new FileOutputStream(_file);
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------- */
|
||||
/**
|
||||
* Deletes the given resource
|
||||
*/
|
||||
public boolean delete()
|
||||
throws SecurityException
|
||||
{
|
||||
return _file.delete();
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------- */
|
||||
/**
|
||||
* Rename the given resource
|
||||
*/
|
||||
public boolean renameTo( Resource dest)
|
||||
throws SecurityException
|
||||
{
|
||||
if( dest instanceof FileResource)
|
||||
return _file.renameTo( ((FileResource)dest)._file);
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------- */
|
||||
/**
|
||||
* Returns a list of resources contained in the given resource
|
||||
*/
|
||||
public String[] list()
|
||||
{
|
||||
String[] list =_file.list();
|
||||
if (list==null)
|
||||
return null;
|
||||
for (int i=list.length;i-->0;)
|
||||
{
|
||||
if (new File(_file,list[i]).isDirectory() &&
|
||||
!list[i].endsWith("/"))
|
||||
list[i]+="/";
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Encode according to this resource type.
|
||||
* File URIs are encoded.
|
||||
* @param uri URI to encode.
|
||||
* @return The uri unchanged.
|
||||
*/
|
||||
public String encode(String uri)
|
||||
{
|
||||
return uri;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @param o
|
||||
* @return
|
||||
*/
|
||||
public boolean equals( Object o)
|
||||
{
|
||||
if (this == o)
|
||||
return true;
|
||||
|
||||
if (null == o || ! (o instanceof FileResource))
|
||||
return false;
|
||||
|
||||
FileResource f=(FileResource)o;
|
||||
return f._file == _file || (null != _file && _file.equals(f._file));
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @return the hashcode.
|
||||
*/
|
||||
public int hashCode()
|
||||
{
|
||||
return null == _file ? super.hashCode() : _file.hashCode();
|
||||
}
|
||||
}
|
@@ -1,253 +0,0 @@
|
||||
// ========================================================================
|
||||
// $Id: InetAddrPort.java,v 1.7 2004/10/23 09:03:22 gregwilkins Exp $
|
||||
// Copyright 1996-2004 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// ========================================================================
|
||||
|
||||
package org.mortbay.util;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.net.InetAddress;
|
||||
|
||||
/* ======================================================================== */
|
||||
/** InetAddress and Port.
|
||||
*/
|
||||
public class InetAddrPort implements Serializable
|
||||
{
|
||||
/* ------------------------------------------------------------ */
|
||||
public final static String __0_0_0_0 = "0.0.0.0";
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
private InetAddress _addr=null;
|
||||
private boolean _addrIsHost=false;
|
||||
private int _port=0;
|
||||
|
||||
/* ------------------------------------------------------------------- */
|
||||
public InetAddrPort()
|
||||
{}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Constructor for a port on all local host address.
|
||||
* @param port
|
||||
*/
|
||||
public InetAddrPort(int port)
|
||||
{
|
||||
_port=port;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Constructor.
|
||||
* @param addr
|
||||
* @param port
|
||||
*/
|
||||
public InetAddrPort(InetAddress addr, int port)
|
||||
{
|
||||
_addr=addr;
|
||||
_port=port;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Constructor.
|
||||
* @param host
|
||||
* @param port
|
||||
*/
|
||||
public InetAddrPort(String host, int port)
|
||||
throws java.net.UnknownHostException
|
||||
{
|
||||
setHost(host);
|
||||
setPort(port);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Constructor.
|
||||
* Patched to support [::1]:port for I2P
|
||||
*
|
||||
* @param inetAddrPort String of the form "addr:port"
|
||||
*/
|
||||
public InetAddrPort(String inetAddrPort)
|
||||
throws java.net.UnknownHostException
|
||||
{
|
||||
int b = inetAddrPort.indexOf('[');
|
||||
if (b>0)
|
||||
throw new java.net.UnknownHostException("Bad [] syntax");
|
||||
if (b==0) // IPV6
|
||||
{
|
||||
int b2 = inetAddrPort.indexOf(']');
|
||||
if (b2<2)
|
||||
throw new java.net.UnknownHostException("Bad [] syntax");
|
||||
String addr=inetAddrPort.substring(1,b2);
|
||||
if (addr.indexOf('/')>0)
|
||||
addr=addr.substring(addr.indexOf('/')+1);
|
||||
inetAddrPort=inetAddrPort.substring(b2+1);
|
||||
int c = inetAddrPort.indexOf(':');
|
||||
if (c>0)
|
||||
throw new java.net.UnknownHostException("Bad [] syntax");
|
||||
if (c==0)
|
||||
inetAddrPort=inetAddrPort.substring(1);
|
||||
|
||||
if (addr.length()>0 && ! __0_0_0_0.equals(addr))
|
||||
{
|
||||
_addrIsHost=!Character.isDigit((addr.charAt(0)));
|
||||
this._addr=InetAddress.getByName(addr);
|
||||
}
|
||||
} else { // IPV4
|
||||
int c = inetAddrPort.indexOf(':');
|
||||
if (c>=0)
|
||||
{
|
||||
String addr=inetAddrPort.substring(0,c);
|
||||
if (addr.indexOf('/')>0)
|
||||
addr=addr.substring(addr.indexOf('/')+1);
|
||||
inetAddrPort=inetAddrPort.substring(c+1);
|
||||
|
||||
if (addr.length()>0 && ! __0_0_0_0.equals(addr))
|
||||
{
|
||||
_addrIsHost=!Character.isDigit((addr.charAt(0)));
|
||||
this._addr=InetAddress.getByName(addr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_port = Integer.parseInt(inetAddrPort);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Constructor.
|
||||
* @param address InetAddrPort top copy.
|
||||
*/
|
||||
public InetAddrPort(InetAddrPort address)
|
||||
{
|
||||
if (address!=null)
|
||||
{
|
||||
_addr=address._addr;
|
||||
_port=address._port;
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Get the Host.
|
||||
* @return The IP address
|
||||
*/
|
||||
public String getHost()
|
||||
{
|
||||
if (_addr==null)
|
||||
return __0_0_0_0;
|
||||
|
||||
return _addrIsHost?_addr.getHostName():_addr.getHostAddress();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Set the Host.
|
||||
* @param host
|
||||
* @exception java.net.UnknownHostException
|
||||
*/
|
||||
public void setHost(String host)
|
||||
throws java.net.UnknownHostException
|
||||
{
|
||||
_addr=null;
|
||||
if (host!=null)
|
||||
{
|
||||
if (host.indexOf('/')>0)
|
||||
host=host.substring(0,host.indexOf('/'));
|
||||
_addrIsHost=!Character.isDigit((host.charAt(0)));
|
||||
_addr=InetAddress.getByName(host);
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Get the IP address.
|
||||
* @return The IP address
|
||||
*/
|
||||
public InetAddress getInetAddress()
|
||||
{
|
||||
return _addr;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Set the IP address.
|
||||
* @param addr The IP address
|
||||
*/
|
||||
public void setInetAddress(InetAddress addr)
|
||||
{
|
||||
_addrIsHost=false;
|
||||
_addr=addr;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Get the port.
|
||||
* @return The port number
|
||||
*/
|
||||
public int getPort()
|
||||
{
|
||||
return _port;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Set the port.
|
||||
* @param port The port number
|
||||
*/
|
||||
public void setPort(int port)
|
||||
{
|
||||
_port=port;
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------- */
|
||||
public String toString()
|
||||
{
|
||||
return getHost()+':'+_port;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Clone the InetAddrPort.
|
||||
* @return A new instance.
|
||||
*/
|
||||
public Object clone()
|
||||
{
|
||||
return new InetAddrPort(this);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Hash Code.
|
||||
* @return hash Code.
|
||||
*/
|
||||
public int hashCode()
|
||||
{
|
||||
return _port+((_addr==null)?0:_addr.hashCode());
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Equals.
|
||||
* @param o
|
||||
* @return True if is the same address and port.
|
||||
*/
|
||||
public boolean equals(Object o)
|
||||
{
|
||||
if (o==null)
|
||||
return false;
|
||||
if (o==this)
|
||||
return true;
|
||||
if (o instanceof InetAddrPort)
|
||||
{
|
||||
InetAddrPort addr=(InetAddrPort)o;
|
||||
return addr._port==_port &&
|
||||
( addr._addr==_addr ||
|
||||
addr._addr!=null && addr._addr.equals(_addr));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@@ -1,431 +0,0 @@
|
||||
// ========================================================================
|
||||
// $Id: Resource.java,v 1.32 2009/05/16 01:53:36 gregwilkins Exp $
|
||||
// Copyright 1996-2004 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// ========================================================================
|
||||
package org.mortbay.util;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.Serializable;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
import java.text.DateFormat;
|
||||
import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.mortbay.log.LogFactory;
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Abstract resource class.
|
||||
*
|
||||
* @version $Id: Resource.java,v 1.32 2009/05/16 01:53:36 gregwilkins Exp $
|
||||
* @author Nuno Preguica
|
||||
* @author Greg Wilkins (gregw)
|
||||
*/
|
||||
public abstract class Resource implements Serializable
|
||||
{
|
||||
private static Log log = LogFactory.getLog(Resource.class);
|
||||
|
||||
Object _associate;
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Construct a resource from a url.
|
||||
* @param url A URL.
|
||||
* @return A Resource object.
|
||||
*/
|
||||
public static Resource newResource(URL url)
|
||||
throws IOException
|
||||
{
|
||||
if (url==null)
|
||||
return null;
|
||||
|
||||
String urls=url.toExternalForm();
|
||||
if( urls.startsWith( "file:"))
|
||||
{
|
||||
try
|
||||
{
|
||||
FileResource fileResource= new FileResource(url);
|
||||
return fileResource;
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
log.debug(LogSupport.EXCEPTION,e);
|
||||
return new BadResource(url,e.toString());
|
||||
}
|
||||
}
|
||||
else if( urls.startsWith( "jar:file:"))
|
||||
{
|
||||
return new JarFileResource(url);
|
||||
}
|
||||
else if( urls.startsWith( "jar:"))
|
||||
{
|
||||
return new JarResource(url);
|
||||
}
|
||||
|
||||
return new URLResource(url,null);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Construct a resource from a string.
|
||||
* @param resource A URL or filename.
|
||||
* @return A Resource object.
|
||||
*/
|
||||
public static Resource newResource(String resource)
|
||||
throws MalformedURLException, IOException
|
||||
{
|
||||
URL url=null;
|
||||
try
|
||||
{
|
||||
// Try to format as a URL?
|
||||
url = new URL(resource);
|
||||
}
|
||||
catch(MalformedURLException e)
|
||||
{
|
||||
if(!resource.startsWith("ftp:") &&
|
||||
!resource.startsWith("file:") &&
|
||||
!resource.startsWith("jar:"))
|
||||
{
|
||||
try
|
||||
{
|
||||
// It's a file.
|
||||
if (resource.startsWith("./"))
|
||||
resource=resource.substring(2);
|
||||
|
||||
File file=new File(resource).getCanonicalFile();
|
||||
url=file.toURI().toURL();
|
||||
|
||||
URLConnection connection=url.openConnection();
|
||||
FileResource fileResource= new FileResource(url,connection,file);
|
||||
return fileResource;
|
||||
}
|
||||
catch(Exception e2)
|
||||
{
|
||||
log.debug(LogSupport.EXCEPTION,e2);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
log.warn("Bad Resource: "+resource);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
String nurl=url.toString();
|
||||
if (nurl.length()>0 &&
|
||||
nurl.charAt(nurl.length()-1)!=
|
||||
resource.charAt(resource.length()-1))
|
||||
{
|
||||
if ((nurl.charAt(nurl.length()-1)!='/' ||
|
||||
nurl.charAt(nurl.length()-2)!=resource.charAt(resource.length()-1))
|
||||
&&
|
||||
(resource.charAt(resource.length()-1)!='/' ||
|
||||
resource.charAt(resource.length()-2)!=nurl.charAt(nurl.length()-1)
|
||||
))
|
||||
{
|
||||
return new BadResource(url,"Trailing special characters stripped by URL in "+resource);
|
||||
}
|
||||
}
|
||||
return newResource(url);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Construct a system resource from a string.
|
||||
* The resource is tried as classloader resource before being
|
||||
* treated as a normal resource.
|
||||
*/
|
||||
public static Resource newSystemResource(String resource)
|
||||
throws IOException
|
||||
{
|
||||
URL url=null;
|
||||
// Try to format as a URL?
|
||||
ClassLoader
|
||||
loader=Thread.currentThread().getContextClassLoader();
|
||||
if (loader!=null)
|
||||
{
|
||||
url=loader.getResource(resource);
|
||||
if (url==null && resource.startsWith("/"))
|
||||
url=loader.getResource(resource.substring(1));
|
||||
}
|
||||
if (url==null)
|
||||
{
|
||||
loader=Resource.class.getClassLoader();
|
||||
if (loader!=null)
|
||||
{
|
||||
url=loader.getResource(resource);
|
||||
if (url==null && resource.startsWith("/"))
|
||||
url=loader.getResource(resource.substring(1));
|
||||
}
|
||||
}
|
||||
|
||||
if (url==null)
|
||||
{
|
||||
url=ClassLoader.getSystemResource(resource);
|
||||
if (url==null && resource.startsWith("/"))
|
||||
url=loader.getResource(resource.substring(1));
|
||||
}
|
||||
|
||||
if (url==null)
|
||||
return null;
|
||||
|
||||
return newResource(url);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
protected void finalize()
|
||||
{
|
||||
release();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Release any resources held by the resource.
|
||||
*/
|
||||
public abstract void release();
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Returns true if the respresened resource exists.
|
||||
*/
|
||||
public abstract boolean exists();
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Returns true if the respresenetd resource is a container/directory.
|
||||
* If the resource is not a file, resources ending with "/" are
|
||||
* considered directories.
|
||||
*/
|
||||
public abstract boolean isDirectory();
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Returns the last modified time
|
||||
*/
|
||||
public abstract long lastModified();
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Return the length of the resource
|
||||
*/
|
||||
public abstract long length();
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Returns an URL representing the given resource
|
||||
*/
|
||||
public abstract URL getURL();
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Returns an File representing the given resource or NULL if this
|
||||
* is not possible.
|
||||
*/
|
||||
public abstract File getFile()
|
||||
throws IOException;
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Returns the name of the resource
|
||||
*/
|
||||
public abstract String getName();
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Returns an input stream to the resource
|
||||
*/
|
||||
public abstract InputStream getInputStream()
|
||||
throws java.io.IOException;
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Returns an output stream to the resource
|
||||
*/
|
||||
public abstract OutputStream getOutputStream()
|
||||
throws java.io.IOException, SecurityException;
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Deletes the given resource
|
||||
*/
|
||||
public abstract boolean delete()
|
||||
throws SecurityException;
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Rename the given resource
|
||||
*/
|
||||
public abstract boolean renameTo( Resource dest)
|
||||
throws SecurityException;
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Returns a list of resource names contained in the given resource
|
||||
* The resource names are not URL encoded.
|
||||
*/
|
||||
public abstract String[] list();
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Returns the resource contained inside the current resource with the
|
||||
* given name.
|
||||
* @param path The path segment to add, which should be encoded by the
|
||||
* encode method.
|
||||
*/
|
||||
public abstract Resource addPath(String path)
|
||||
throws IOException,MalformedURLException;
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Encode according to this resource type.
|
||||
* The default implementation calls URI.encodePath(uri)
|
||||
* @param uri
|
||||
* @return String encoded for this resource type.
|
||||
*/
|
||||
public String encode(String uri)
|
||||
{
|
||||
return URI.encodePath(uri);
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public Object getAssociate()
|
||||
{
|
||||
return _associate;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public void setAssociate(Object o)
|
||||
{
|
||||
_associate=o;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @return The canonical Alias of this resource or null if none.
|
||||
*/
|
||||
public URL getAlias()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public CachedResource cache()
|
||||
throws IOException
|
||||
{
|
||||
return new CachedResource(this);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Get the resource list as a HTML directory listing.
|
||||
* @param base The base URL
|
||||
* @param parent True if the parent directory should be included
|
||||
* @return String of HTML
|
||||
*/
|
||||
public String getListHTML(String base,
|
||||
boolean parent)
|
||||
throws IOException
|
||||
{
|
||||
if (!isDirectory())
|
||||
return null;
|
||||
|
||||
|
||||
String[] ls = list();
|
||||
if (ls==null)
|
||||
return null;
|
||||
Arrays.sort(ls);
|
||||
|
||||
String title = "Directory: "+URI.decodePath(base);
|
||||
title=StringUtil.replace(StringUtil.replace(title,"<","<"),">",">");
|
||||
StringBuffer buf=new StringBuffer(4096);
|
||||
buf.append("<HTML><HEAD><TITLE>");
|
||||
buf.append(title);
|
||||
buf.append("</TITLE></HEAD><BODY>\n<H1>");
|
||||
buf.append(title);
|
||||
buf.append("</H1><TABLE BORDER=0>");
|
||||
|
||||
if (parent)
|
||||
{
|
||||
buf.append("<TR><TD><A HREF=");
|
||||
buf.append(URI.encodePath(URI.addPaths(base,"../")));
|
||||
buf.append(">Parent Directory</A></TD><TD></TD><TD></TD></TR>\n");
|
||||
}
|
||||
|
||||
DateFormat dfmt=DateFormat.getDateTimeInstance(DateFormat.MEDIUM,
|
||||
DateFormat.MEDIUM);
|
||||
for (int i=0 ; i< ls.length ; i++)
|
||||
{
|
||||
String encoded=URI.encodePath(ls[i]);
|
||||
// bugfix for I2P - Backport from Jetty 6 (zero file lengths and last-modified times)
|
||||
// http://jira.codehaus.org/browse/JETTY-361?page=com.atlassian.jira.plugin.system.issuetabpanels%3Achangehistory-tabpanel#issue-tabs
|
||||
// See resource.diff attachment
|
||||
//Resource item = addPath(encoded);
|
||||
Resource item = addPath(ls[i]);
|
||||
|
||||
buf.append("<TR><TD><A HREF=\"");
|
||||
|
||||
String path=URI.addPaths(base,encoded);
|
||||
|
||||
if (item.isDirectory() && !path.endsWith("/"))
|
||||
path=URI.addPaths(path,"/");
|
||||
buf.append(path);
|
||||
buf.append("\">");
|
||||
buf.append(StringUtil.replace(StringUtil.replace(ls[i],"<","<"),">",">"));
|
||||
buf.append("</A> ");
|
||||
buf.append("</TD><TD ALIGN=right>");
|
||||
buf.append(item.length());
|
||||
buf.append(" bytes </TD><TD>");
|
||||
buf.append(dfmt.format(new Date(item.lastModified())));
|
||||
buf.append("</TD></TR>\n");
|
||||
}
|
||||
buf.append("</TABLE>\n");
|
||||
buf.append("</BODY></HTML>\n");
|
||||
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @param out
|
||||
* @param start First byte to write
|
||||
* @param count Bytes to write or -1 for all of them.
|
||||
*/
|
||||
public void writeTo(OutputStream out,long start,long count)
|
||||
throws IOException
|
||||
{
|
||||
InputStream in = getInputStream();
|
||||
try
|
||||
{
|
||||
in.skip(start);
|
||||
if (count<0)
|
||||
IO.copy(in,out);
|
||||
else
|
||||
IO.copy(in,out,(int)count);
|
||||
}
|
||||
finally
|
||||
{
|
||||
in.close();
|
||||
}
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user