You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by cr...@locus.apache.org on 2000/08/12 01:40:04 UTC
cvs commit: jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/servlets Constants.java DefaultServlet.java InvokerServlet.java LocalStrings.properties ManagerServlet.java SnoopAllServlet.java WebdavServlet.java package.html
craigmcc 00/08/11 16:40:03
Added: catalina/src/share/org/apache/catalina/servlets
Constants.java DefaultServlet.java
InvokerServlet.java LocalStrings.properties
ManagerServlet.java SnoopAllServlet.java
WebdavServlet.java package.html
Log:
Migrate to Tomcat 4.0.
Revision Changes Path
1.1 jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/servlets/Constants.java
Index: Constants.java
===================================================================
/*
* $Header: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/servlets/Constants.java,v 1.1 2000/08/11 23:39:51 craigmcc Exp $
* $Revision: 1.1 $
* $Date: 2000/08/11 23:39:51 $
*
* ====================================================================
*
* The Apache Software License, Version 1.1
*
* Copyright (c) 1999 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution, if
* any, must include the following acknowlegement:
* "This product includes software developed by the
* Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowlegement may appear in the software itself,
* if and wherever such third-party acknowlegements normally appear.
*
* 4. The names "The Jakarta Project", "Tomcat", and "Apache Software
* Foundation" must not be used to endorse or promote products derived
* from this software without prior written permission. For written
* permission, please contact apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache"
* nor may "Apache" appear in their names without prior written
* permission of the Apache Group.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
* [Additional notices, if required by prior licensing conditions]
*
*/
package org.apache.catalina.servlets;
public class Constants {
public static final String Package = "org.apache.catalina.servlets";
public static final String CATALINA_NAME = "Tomcat Catalina";
public static final String CATALINA_VERSION = "4.0";
}
1.1 jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/servlets/DefaultServlet.java
Index: DefaultServlet.java
===================================================================
/*
* $Header: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/servlets/DefaultServlet.java,v 1.1 2000/08/11 23:39:51 craigmcc Exp $
* $Revision: 1.1 $
* $Date: 2000/08/11 23:39:51 $
*
* ====================================================================
*
* The Apache Software License, Version 1.1
*
* Copyright (c) 1999 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution, if
* any, must include the following acknowlegement:
* "This product includes software developed by the
* Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowlegement may appear in the software itself,
* if and wherever such third-party acknowlegements normally appear.
*
* 4. The names "The Jakarta Project", "Tomcat", and "Apache Software
* Foundation" must not be used to endorse or promote products derived
* from this software without prior written permission. For written
* permission, please contact apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache"
* nor may "Apache" appear in their names without prior written
* permission of the Apache Group.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
* [Additional notices, if required by prior licensing conditions]
*
*/
package org.apache.catalina.servlets;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.MalformedURLException;
import java.net.URL;
import java.sql.Timestamp;
import java.util.Date;
import java.util.Enumeration;
import java.util.Vector;
import java.util.StringTokenizer;
import java.util.Locale;
import java.util.Hashtable;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.ServletContext;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.catalina.Resources;
import org.apache.catalina.core.ApplicationContext;
import org.apache.catalina.resources.ResourceBean;
import org.apache.catalina.resources.DirectoryBean;
import org.apache.catalina.util.MD5Encoder;
import org.apache.catalina.util.StringManager;
import org.apache.catalina.util.xml.SaxContext;
import org.apache.catalina.util.xml.XmlAction;
import org.apache.catalina.util.xml.XmlMapper;
/**
* The default resource-serving servlet for most web applications,
* used to serve static resources such as HTML pages and images.
*
* @author Craig R. McClanahan
* @author Remy Maucherat
* @version $Revision: 1.1 $ $Date: 2000/08/11 23:39:51 $
*/
public class DefaultServlet
extends HttpServlet {
// ----------------------------------------------------- Instance Variables
/**
* The debugging detail level for this servlet.
*/
protected int debug = 0;
/**
* The input buffer size to use when serving resources.
*/
protected int input = 2048;
/**
* Should we generate directory listings when no welcome file is present?
*/
protected boolean listings = true;
/**
* Read only flag. By default, it's set to true.
*/
protected boolean readOnly = true;
/**
* The output buffer size to use when serving resources.
*/
protected int output = 2048;
/**
* The set of welcome files for this web application
*/
protected String welcomes[] = new String[0];
/**
* MD5 message digest provider.
*/
protected static MessageDigest md5Helper;
/**
* The MD5 helper object for this class.
*/
protected static final MD5Encoder md5Encoder = new MD5Encoder();
/**
* The set of SimpleDateFormat formats to use in getDateHeader().
*/
protected static final SimpleDateFormat formats[] = {
new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz", Locale.US),
new SimpleDateFormat("EEEEEE, dd-MMM-yy HH:mm:ss zzz", Locale.US),
new SimpleDateFormat("EEE MMMM d HH:mm:ss yyyy", Locale.US)
};
/**
* MIME multipart separation string
*/
protected static final String mimeSeparation = "CATALINA_MIME_BOUNDARY";
/**
* The string manager for this package.
*/
protected static StringManager sm =
StringManager.getManager(Constants.Package);
// --------------------------------------------------------- Public Methods
/**
* Finalize this servlet.
*/
public void destroy() {
; // No actions necessary
}
/**
* Initialize this servlet.
*/
public void init() throws ServletException {
// Set our properties from the initialization parameters
String value = null;
try {
value = getServletConfig().getInitParameter("debug");
debug = Integer.parseInt(value);
} catch (Throwable t) {
;
}
try {
value = getServletConfig().getInitParameter("input");
input = Integer.parseInt(value);
} catch (Throwable t) {
;
}
try {
value = getServletConfig().getInitParameter("listings");
listings = (new Boolean(value)).booleanValue();
} catch (Throwable t) {
;
}
try {
value = getServletConfig().getInitParameter("readonly");
readOnly = (new Boolean(value)).booleanValue();
} catch (Throwable t) {
;
}
try {
value = getServletConfig().getInitParameter("output");
output = Integer.parseInt(value);
} catch (Throwable t) {
;
}
// Sanity check on the specified buffer sizes
if (input < 256)
input = 256;
if (output < 256)
output = 256;
// Initialize the set of welcome files for this application
welcomes = (String[]) getServletContext().getAttribute
("org.apache.catalina.WELCOME_FILES");
if (welcomes == null)
welcomes = new String[0];
if (debug > 0) {
log("DefaultServlet.init: input buffer size=" + input +
", output buffer size=" + output);
for (int i = 0; i < welcomes.length; i++)
log("DefaultServlet.init: welcome file=" +
welcomes[i]);
}
// Load the MD5 helper used to calculate signatures.
try {
md5Helper = MessageDigest.getInstance("MD5");
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
throw new IllegalStateException();
}
}
// ------------------------------------------------------ Protected Methods
/**
* Return the relative path associated with this servlet.
*
* @param request The servlet request we are processing
*/
protected String getRelativePath(HttpServletRequest request) {
String result = request.getPathInfo();
if (result == null) {
result = request.getServletPath();
}
if ((result == null) || (result.equals(""))) {
result = "/";
}
return result;
}
/**
* Process a GET request for the specified resource.
*
* @param request The servlet request we are processing
* @param response The servlet response we are creating
*
* @exception IOException if an input/output error occurs
* @exception ServletException if a servlet-specified error occurs
*/
protected void doGet(HttpServletRequest request,
HttpServletResponse response)
throws IOException, ServletException {
// Serve the requested resource, including the data content
serveResource(request, response, true);
}
/**
* Process a HEAD request for the specified resource.
*
* @param request The servlet request we are processing
* @param response The servlet response we are creating
*
* @exception IOException if an input/output error occurs
* @exception ServletException if a servlet-specified error occurs
*/
protected void doHead(HttpServletRequest request,
HttpServletResponse response)
throws IOException, ServletException {
// Serve the requested resource, without the data content
serveResource(request, response, false);
}
/**
* Process a POST request for the specified resource.
*
* @param request The servlet request we are processing
* @param response The servlet response we are creating
*
* @exception IOException if an input/output error occurs
* @exception ServletException if a servlet-specified error occurs
*/
protected void doPost(HttpServletRequest request,
HttpServletResponse response)
throws IOException, ServletException {
doPut(request, response);
}
/**
* Process a POST request for the specified resource.
*
* @param request The servlet request we are processing
* @param response The servlet response we are creating
*
* @exception IOException if an input/output error occurs
* @exception ServletException if a servlet-specified error occurs
*/
protected void doPut(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
if (readOnly) {
resp.sendError(HttpServletResponse.SC_FORBIDDEN);
return;
}
String path = getRelativePath(req);
// Looking for a Content-Range header
if (req.getHeader("Content-Range") != null) {
// No content range header is supported
resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED);
}
// Retrieve the Catalina context
ApplicationContext context = (ApplicationContext) getServletContext();
Resources resources = context.getResources();
boolean exists = resources.exists(path);
boolean result = resources.setResource(path, req.getInputStream());
if (result) {
if (exists) {
resp.setStatus(HttpServletResponse.SC_NO_CONTENT);
} else {
resp.setStatus(HttpServletResponse.SC_CREATED);
}
} else {
resp.sendError(HttpServletResponse.SC_CONFLICT);
}
}
/**
* Process a POST request for the specified resource.
*
* @param request The servlet request we are processing
* @param response The servlet response we are creating
*
* @exception IOException if an input/output error occurs
* @exception ServletException if a servlet-specified error occurs
*/
protected void doDelete(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
if (readOnly) {
resp.sendError(HttpServletResponse.SC_FORBIDDEN);
return;
}
String path = getRelativePath(req);
// Retrieve the Catalina context
ApplicationContext context = (ApplicationContext) getServletContext();
Resources resources = context.getResources();
boolean exists = resources.exists(path);
if (exists) {
boolean result = resources.deleteResource(path);
if (result) {
resp.setStatus(HttpServletResponse.SC_NO_CONTENT);
} else {
resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED);
}
} else {
resp.sendError(HttpServletResponse.SC_NOT_FOUND);
}
}
/**
* Check if the conditions specified in the optional If headers are
* satisfied.
*
* @param request The servlet request we are processing
* @param response The servlet response we are creating
* @param resourceInfo File object
* @return boolean true if the resource meets all the specified conditions,
* and false if any of the conditions is not satisfied, in which case
* request processing is stopped
*/
protected boolean checkIfHeaders(HttpServletRequest request,
HttpServletResponse response,
ResourceInfo resourceInfo)
throws IOException {
String eTag = getETag(resourceInfo, true);
long fileLength = resourceInfo.length;
long lastModified = resourceInfo.date;
StringTokenizer commaTokenizer;
String headerValue;
// Checking If-Match
headerValue = request.getHeader("If-Match");
if (headerValue != null) {
if (headerValue.indexOf("*") == -1) {
commaTokenizer = new StringTokenizer(headerValue, ",");
boolean conditionSatisfied = false;
while (!conditionSatisfied && commaTokenizer.hasMoreTokens()) {
String currentToken = commaTokenizer.nextToken();
if (currentToken.trim().equals(eTag))
conditionSatisfied = true;
}
// If none of the given ETags match, 412 Precodition failed is
// sent back
if (!conditionSatisfied) {
response.sendError
(HttpServletResponse.SC_PRECONDITION_FAILED);
return false;
}
}
}
// Checking If-Modified-Since
headerValue = request.getHeader("If-Modified-Since");
if (headerValue != null) {
// If an If-None-Match header has been specified, if modified since
// is ignored.
if (request.getHeader("If-None-Match") == null) {
Date date = null;
// Parsing the HTTP Date
for (int i = 0; (date == null) && (i < formats.length); i++) {
try {
date = formats[i].parse(headerValue);
} catch (ParseException e) {
;
}
}
if ((date != null)
&& (lastModified <= (date.getTime() + 1000)) ) {
// The entity has not been modified since the date
// specified by the client. This is not an error case.
response.sendError
(HttpServletResponse.SC_NOT_MODIFIED);
return false;
}
}
}
// Checking If-None-Match
headerValue = request.getHeader("If-None-Match");
if (headerValue != null) {
if (headerValue.indexOf("*") == -1) {
commaTokenizer = new StringTokenizer(headerValue, ",");
boolean conditionSatisfied = false;
while (!conditionSatisfied && commaTokenizer.hasMoreTokens()) {
String currentToken = commaTokenizer.nextToken();
if (currentToken.trim().equals(eTag))
conditionSatisfied = true;
}
if (conditionSatisfied) {
// For GET and HEAD, we should respond with
// 304 Not Modified.
// For every other method, 412 Precondition Failed is sent
// back.
if ( ("GET".equals(request.getMethod()))
|| ("HEAD".equals(request.getMethod())) ) {
response.sendError
(HttpServletResponse.SC_NOT_MODIFIED);
return false;
} else {
response.sendError
(HttpServletResponse.SC_PRECONDITION_FAILED);
return false;
}
}
} else {
if (resourceInfo.exists()) {
}
}
}
// Checking If-Unmodified-Since
headerValue = request.getHeader("If-Unmodified-Since");
if (headerValue != null) {
Date date = null;
// Parsing the HTTP Date
for (int i = 0; (date == null) && (i < formats.length); i++) {
try {
date = formats[i].parse(headerValue);
} catch (ParseException e) {
;
}
}
if ( (date != null) && (lastModified > date.getTime()) ) {
// The entity has not been modified since the date
// specified by the client. This is not an error case.
response.sendError
(HttpServletResponse.SC_PRECONDITION_FAILED);
return false;
}
}
return true;
}
/**
* Get the ETag value associated with a file.
*
* @param resourceInfo File object
* @param strong True if we want a strong ETag, in which case a checksum
* of the file has to be calculated
*/
protected String getETagValue(ResourceInfo resourceInfo, boolean strong) {
// FIXME : Compute a strong ETag if requested, using an MD5 digest
// of the file contents
return resourceInfo.length + "-" + resourceInfo.date;
}
/**
* Get the ETag associated with a file.
*
* @param resourceInfo File object
* @param strong True if we want a strong ETag, in which case a checksum
* of the file has to be calculated
*/
protected String getETag(ResourceInfo resourceInfo, boolean strong) {
if (strong)
return "\"" + getETagValue(resourceInfo, strong) + "\"";
else
return "W/\"" + getETagValue(resourceInfo, strong) + "\"";
}
// -------------------------------------------------------- Private Methods
/**
* Copy the contents of the specified input stream to the specified
* output stream, and ensure that both streams are closed before returning
* (even in the face of an exception).
*
* @param istream The input stream to read from
* @param ostream The output stream to write to
*
* @exception IOException if an input/output error occurs
*/
private void copy(ResourceInfo resourceInfo, ServletOutputStream ostream)
throws IOException {
IOException exception = null;
// FIXME : i18n ?
InputStream resourceInputStream =
resourceInfo.resources.getResourceAsStream(resourceInfo.path);
InputStream istream = new BufferedInputStream
(resourceInputStream, input);
// Copy the input stream to the output stream
exception = copyRange(istream, ostream);
// Clean up the input and output streams
try {
istream.close();
} catch (Throwable t) {
;
}
try {
ostream.flush();
} catch (Throwable t) {
;
}
try {
ostream.close();
} catch (Throwable t) {
;
}
// Rethrow any exception that has occurred
if (exception != null)
throw exception;
}
/**
* Copy the contents of the specified input stream to the specified
* output stream, and ensure that both streams are closed before returning
* (even in the face of an exception).
*
* @param resourceInfo The ResourceInfo object
* @param ostream The output stream to write to
* @param range Range the client wanted to retrieve
* @exception IOException if an input/output error occurs
*/
private void copy(ResourceInfo resourceInfo, ServletOutputStream ostream,
Range range)
throws IOException {
IOException exception = null;
InputStream resourceInputStream =
resourceInfo.resources.getResourceAsStream(resourceInfo.path);
InputStream istream =
new BufferedInputStream(resourceInputStream, input);
exception = copyRange(istream, ostream, range.start, range.end);
// Clean up the input and output streams
try {
istream.close();
} catch (Throwable t) {
;
}
try {
ostream.flush();
} catch (Throwable t) {
;
}
try {
ostream.close();
} catch (Throwable t) {
;
}
// Rethrow any exception that has occurred
if (exception != null)
throw exception;
}
/**
* Copy the contents of the specified input stream to the specified
* output stream, and ensure that both streams are closed before returning
* (even in the face of an exception).
*
* @param resourceInfo The ResourceInfo object
* @param ostream The output stream to write to
* @param ranges Enumeration of the ranges the client wanted to retrieve
* @param contentType Content type of the resource
* @exception IOException if an input/output error occurs
*/
private void copy(ResourceInfo resourceInfo, ServletOutputStream ostream,
Enumeration ranges, String contentType)
throws IOException {
IOException exception = null;
while ( (exception == null) && (ranges.hasMoreElements()) ) {
InputStream resourceInputStream =
resourceInfo.resources.getResourceAsStream(resourceInfo.path);
InputStream istream = // FIXME: internationalization???????
new BufferedInputStream(resourceInputStream, input);
Range currentRange = (Range) ranges.nextElement();
// Writing MIME header.
ostream.println("--" + mimeSeparation);
if (contentType != null)
ostream.println("Content-Type: " + contentType);
ostream.println("Content-Range: bytes " + currentRange.start
+ "-" + currentRange.end + "/"
+ currentRange.length);
ostream.println();
// Printing content
exception = copyRange(istream, ostream, currentRange.start,
currentRange.end);
try {
istream.close();
} catch (Throwable t) {
;
}
}
ostream.print("--" + mimeSeparation + "--");
// Clean up the output streams
try {
ostream.flush();
} catch (Throwable t) {
;
}
try {
ostream.close();
} catch (Throwable t) {
;
}
// Rethrow any exception that has occurred
if (exception != null)
throw exception;
}
/**
* Copy the contents of the specified input stream to the specified
* output stream, and ensure that both streams are closed before returning
* (even in the face of an exception).
*
* @param istream The input stream to read from
* @param ostream The output stream to write to
* @return Exception which occured during processing
*/
private IOException copyRange(InputStream istream,
ServletOutputStream ostream) {
// Copy the input stream to the output stream
IOException exception = null;
byte buffer[] = new byte[input];
int len = buffer.length;
while (true) {
try {
len = istream.read(buffer);
if (len == -1)
break;
ostream.write(buffer, 0, len);
} catch (IOException e) {
exception = e;
len = -1;
break;
}
}
return exception;
}
/**
* Copy the contents of the specified input stream to the specified
* output stream, and ensure that both streams are closed before returning
* (even in the face of an exception).
*
* @param istream The input stream to read from
* @param ostream The output stream to write to
* @param start Start of the range which will be copied
* @param end End of the range which will be copied
* @return Exception which occured during processing
*/
private IOException copyRange(InputStream istream,
ServletOutputStream ostream,
long start, long end) {
try {
istream.skip(start);
} catch (IOException e) {
return e;
}
IOException exception = null;
long bytesToRead = end - start + 1;
byte buffer[] = new byte[input];
int len = buffer.length;
while ( (bytesToRead > 0) && (len >= buffer.length)) {
try {
len = istream.read(buffer);
if (bytesToRead >= len) {
ostream.write(buffer, 0, len);
bytesToRead -= len;
} else {
ostream.write(buffer, 0, (int) bytesToRead);
bytesToRead = 0;
}
} catch (IOException e) {
exception = e;
len = -1;
}
if (len < buffer.length)
break;
}
return exception;
}
/**
* Display the size of a file.
*/
private void displaySize(StringBuffer buf, int filesize) {
int leftside = filesize / 1024;
int rightside = (filesize % 1024) / 103; // makes 1 digit
// To avoid 0.0 for non-zero file, we bump to 0.1
if (leftside == 0 && rightside == 0 && filesize != 0)
rightside = 1;
buf.append(leftside).append(".").append(rightside);
buf.append(" KB");
}
/**
* Check to see if a default page exists.
*
* @param pathname Pathname of the file to be served
*/
private ResourceInfo checkWelcomeFiles(String pathname,
Resources resources) {
String collectionName = pathname;
if (!pathname.endsWith("/")) {
collectionName += "/";
}
// Serve a welcome resource or file if one exists
// FIXME - update the welcome files list?
for (int i = 0; i < welcomes.length; i++) {
// Does the specified resource exist?
String resourceName = collectionName + welcomes[i];
ResourceInfo resourceInfo =
new ResourceInfo(resourceName, resources);
if (resourceInfo.exists()) {
return resourceInfo;
}
}
return null;
}
/**
* Serve the specified resource, optionally including the data content.
*
* @param request The servlet request we are processing
* @param response The servlet response we are creating
* @param content Should the content be included?
*
* @exception IOException if an input/output error occurs
* @exception ServletException if a servlet-specified error occurs
*/
private void serveResource(HttpServletRequest request,
HttpServletResponse response,
boolean content)
throws IOException, ServletException {
// Identify the requested resource path
String path = getRelativePath(request);
if (debug > 0) {
if (content)
log("DefaultServlet.serveResource: Serving resource '" +
path + "' headers and data");
else
log("DefaultServlet.serveResource: Serving resource '" +
path + "' headers only");
}
// Exclude any resource in the /WEB-INF and /META-INF subdirectories
// (the "toUpperCase()" avoids problems on Windows systems)
if (path.toUpperCase().startsWith("/WEB-INF") ||
path.toUpperCase().startsWith("/META-INF")) {
response.sendError(HttpServletResponse.SC_NOT_FOUND, path);
return;
}
// Retrieve the Catalina context
ApplicationContext context = (ApplicationContext) getServletContext();
// Convert the resource path to a URL
URL resourceURL = null;
try {
resourceURL = context.getResource(path);
} catch (MalformedURLException e) {
;
}
if (resourceURL == null) {
response.sendError(HttpServletResponse.SC_NOT_FOUND, path);
return;
}
if (debug > 0)
log("DefaultServlet.serveResource: Corresponding URL is '" +
resourceURL.toString() + "'");
Resources resources = context.getResources();
ResourceInfo resourceInfo = new ResourceInfo(path, resources);
// If the resource is a collection (aka a directory), we check
// the welcome files list.
if (resourceInfo.collection) {
ResourceInfo welcomeFileInfo = checkWelcomeFiles(path, resources);
if (welcomeFileInfo != null) {
resourceInfo = welcomeFileInfo;
}
if ((welcomeFileInfo != null) &&
(!path.endsWith("/"))) {
response.sendRedirect(request.getRequestURI() + "/");
return;
}
}
if (!resourceInfo.exists()) {
response.sendError(HttpServletResponse.SC_NOT_FOUND,
resourceInfo.path);
return;
}
// Checking If headers
if ( !checkIfHeaders(request, response, resourceInfo) )
return;
// Find content type.
String contentType =
getServletContext().getMimeType(resourceInfo.path);
if (resourceInfo.collection) {
// Skip directory listings if we have been configured to
// suppress them
if (!listings) {
response.sendError(HttpServletResponse.SC_NOT_FOUND,
resourceInfo.path);
return;
}
contentType = "text/html";
}
// Parse range specifier
Vector ranges = null;
if (!resourceInfo.collection) {
parseRange(request, response, resourceInfo);
// Last-Modified header
if (debug > 0)
log("DefaultServlet.serveFile: lastModified='" +
(new Timestamp(resourceInfo.date)).toString() + "'");
response.setDateHeader("Last-Modified", resourceInfo.date);
// ETag header
response.setHeader("ETag", getETag(resourceInfo, true));
}
if ( (ranges == null) && (request.getHeader("Range") == null) ) {
// Set the appropriate output headers
if (contentType != null) {
if (debug > 0)
log("DefaultServlet.serveFile: contentType='" +
contentType + "'");
response.setContentType(contentType);
}
long contentLength = resourceInfo.length;
if ((!resourceInfo.collection) && (contentLength >= 0)) {
if (debug > 0)
log("DefaultServlet.serveFile: contentLength=" +
contentLength);
response.setContentLength((int) contentLength);
}
// Copy the input stream to our output stream (if requested)
if (content) {
response.setBufferSize(output);
copy(resourceInfo, response.getOutputStream());
}
} else {
if (ranges == null)
return;
// Partial content response.
response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);
if (ranges.size() == 1) {
Range range = (Range) ranges.elementAt(0);
response.addHeader("Content-Range", "bytes "
+ range.start
+ "-" + range.end + "/"
+ range.length);
if (contentType != null) {
if (debug > 0)
log("DefaultServlet.serveFile: contentType='" +
contentType + "'");
response.setContentType(contentType);
}
if (content) {
response.setBufferSize(output);
copy(resourceInfo, response.getOutputStream(), range);
}
} else {
response.setContentType("multipart/byteranges; boundary="
+ mimeSeparation);
if (content) {
response.setBufferSize(output);
copy(resourceInfo, response.getOutputStream(),
ranges.elements(), contentType);
}
}
}
}
/**
* Parse the range header.
*
* @param request The servlet request we are processing
* @param response The servlet response we are creating
* @return Vector of ranges
*/
private Vector parseRange(HttpServletRequest request,
HttpServletResponse response,
ResourceInfo resourceInfo)
throws IOException {
// Checking If-Range
String headerValue = request.getHeader("If-Range");
if (headerValue != null) {
String eTag = getETag(resourceInfo, true);
long lastModified = resourceInfo.date;
Date date = null;
// Parsing the HTTP Date
for (int i = 0; (date == null) && (i < formats.length); i++) {
try {
date = formats[i].parse(headerValue);
} catch (ParseException e) {
;
}
}
if (date == null) {
// If the ETag the client gave does not match the entity
// etag, then the entire entity is returned.
if (!eTag.equals(headerValue.trim()))
return null;
} else {
// If the timestamp of the entity the client got is older than
// the last modification date of the entity, the entire entity
// is returned.
if (lastModified > (date.getTime() + 1000))
return null;
}
}
long fileLength = resourceInfo.length;
if (fileLength == 0)
return null;
// Retrieving the range header (if any is specified
String rangeHeader = request.getHeader("Range");
if (rangeHeader == null)
return null;
// bytes is the only range unit supported (and I don't see the point
// of adding new ones).
if (!rangeHeader.startsWith("bytes")) {
response.sendError
(HttpServletResponse.SC_REQUESTED_RANGE_NOT_SATISFIABLE);
return null;
}
rangeHeader = rangeHeader.substring(6);
// Vector which will contain all the ranges which are successfully
// parsed.
Vector result = new Vector();
StringTokenizer commaTokenizer = new StringTokenizer(rangeHeader, ",");
// Parsing the range list
while (commaTokenizer.hasMoreTokens()) {
String rangeDefinition = commaTokenizer.nextToken();
Range currentRange = new Range();
currentRange.length = fileLength;
int dashPos = rangeDefinition.indexOf('-');
if (dashPos == -1) {
response.sendError
(HttpServletResponse.SC_REQUESTED_RANGE_NOT_SATISFIABLE);
return null;
}
if (dashPos == 0) {
try {
long offset = Long.parseLong(rangeDefinition);
currentRange.start = fileLength + offset;
currentRange.end = fileLength - 1;
} catch (NumberFormatException e) {
response.sendError
(HttpServletResponse
.SC_REQUESTED_RANGE_NOT_SATISFIABLE);
return null;
}
} else {
try {
currentRange.start = Long.parseLong
(rangeDefinition.substring(0, dashPos));
if (dashPos < rangeDefinition.length() - 1)
currentRange.end = Long.parseLong
(rangeDefinition.substring
(dashPos + 1, rangeDefinition.length()));
else
currentRange.end = fileLength - 1;
} catch (NumberFormatException e) {
response.sendError
(HttpServletResponse
.SC_REQUESTED_RANGE_NOT_SATISFIABLE);
return null;
}
}
if (!currentRange.validate()) {
response.sendError
(HttpServletResponse.SC_REQUESTED_RANGE_NOT_SATISFIABLE);
return null;
}
result.addElement(currentRange);
}
return result;
}
// ------------------------------------------------------ Range Inner Class
private class Range {
public long start;
public long end;
public long length;
/**
* Validate range.
*/
public boolean validate() {
return ( (start >= 0) && (end >= 0) && (length > 0)
&& (start <= end) && (end < length) );
}
}
// ---------------------------------------------- ResourceInfo Inner Class
protected class ResourceInfo {
/**
* Constructor.
*
* @param pathname Path name of the file
*/
public ResourceInfo(String path, Resources resources) {
this.path = path;
this.resources = resources;
this.exists = resources.exists(path);
if (exists) {
this.creationDate = resources.getResourceCreated(path);
this.date = resources.getResourceModified(path);
this.httpDate = formats[0].format(new Date(date));
this.length = resources.getResourceLength(path);
this.collection = resources.isCollection(path);
}
}
public String path;
public long creationDate;
public String httpDate;
public long date;
public long length;
public boolean collection;
public boolean exists;
public Resources resources;
/**
* Test if the associated resource exists.
*/
public boolean exists() {
return exists;
}
/**
* String representation.
*/
public String toString() {
return path;
}
}
}
1.1 jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/servlets/InvokerServlet.java
Index: InvokerServlet.java
===================================================================
/*
* $Header: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/servlets/InvokerServlet.java,v 1.1 2000/08/11 23:39:52 craigmcc Exp $
* $Revision: 1.1 $
* $Date: 2000/08/11 23:39:52 $
*
* ====================================================================
*
* The Apache Software License, Version 1.1
*
* Copyright (c) 1999 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution, if
* any, must include the following acknowlegement:
* "This product includes software developed by the
* Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowlegement may appear in the software itself,
* if and wherever such third-party acknowlegements normally appear.
*
* 4. The names "The Jakarta Project", "Tomcat", and "Apache Software
* Foundation" must not be used to endorse or promote products derived
* from this software without prior written permission. For written
* permission, please contact apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache"
* nor may "Apache" appear in their names without prior written
* permission of the Apache Group.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
* [Additional notices, if required by prior licensing conditions]
*
*/
package org.apache.catalina.servlets;
import java.io.IOException;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.catalina.Context;
import org.apache.catalina.HttpRequest;
import org.apache.catalina.HttpResponse;
import org.apache.catalina.Wrapper;
/**
* The default servlet-invoking servlet for most web applications,
* used to serve requests to servlets that have not been registered
* in the web application deployment descriptor.
*
* @author Craig R. McClanahan
* @version $Revision: 1.1 $ $Date: 2000/08/11 23:39:52 $
*/
public final class InvokerServlet
extends HttpServlet {
// ----------------------------------------------------- Instance Variables
/**
* The Context container associated with our web application.
*/
private Context context = null;
/**
* The debugging detail level for this servlet.
*/
private int debug = 0;
// --------------------------------------------------------- Public Methods
/**
* Finalize this servlet.
*/
public void destroy() {
; // No actions necessary
}
/**
* Process a GET request for the specified resource.
*
* @param request The servlet request we are processing
* @param response The servlet response we are creating
*
* @exception IOException if an input/output error occurs
* @exception ServletException if a servlet-specified error occurs
*/
public void doGet(HttpServletRequest request,
HttpServletResponse response)
throws IOException, ServletException {
serveRequest(request, response);
}
/**
* Process a HEAD request for the specified resource.
*
* @param request The servlet request we are processing
* @param response The servlet response we are creating
*
* @exception IOException if an input/output error occurs
* @exception ServletException if a servlet-specified error occurs
*/
public void doHead(HttpServletRequest request,
HttpServletResponse response)
throws IOException, ServletException {
serveRequest(request, response);
}
/**
* Process a POST request for the specified resource.
*
* @param request The servlet request we are processing
* @param response The servlet response we are creating
*
* @exception IOException if an input/output error occurs
* @exception ServletException if a servlet-specified error occurs
*/
public void doPost(HttpServletRequest request,
HttpServletResponse response)
throws IOException, ServletException {
serveRequest(request, response);
}
/**
* Initialize this servlet.
*/
public void init() throws ServletException {
// Set our properties from the initialization parameters
String value = null;
try {
value = getServletConfig().getInitParameter("debug");
debug = Integer.parseInt(value);
} catch (Throwable t) {
;
}
// Identify the internal container resources we need
Wrapper wrapper = (Wrapper) getServletConfig();
context = (Context) wrapper.getParent();
if (debug >= 1)
log("init: Associated with Context '" + context.getPath() + "'");
}
// -------------------------------------------------------- Private Methods
/**
* Serve the specified request, creating the corresponding response.
* After the first time a particular servlet class is requested, it will
* be served directly (like any registered servlet) because it will have
* been registered and mapped in our associated Context.
*
* @param request The servlet request we are processing
* @param response The servlet response we are creating
*
* @exception IOException if an input/output error occurs
* @exception ServletException if a servlet-specified error occurs
*/
public void serveRequest(HttpServletRequest request,
HttpServletResponse response)
throws IOException, ServletException {
// Identify the class name of the servlet we want
if (debug >= 1)
log("serveRequest: Serving request " + request.getMethod() +
" " + request.getRequestURI());
String pathInfo = request.getPathInfo();
if (pathInfo == null) {
if (debug >= 1)
log("serveRequest: Invalid pathInfo '" + pathInfo + "'");
response.sendError(HttpServletResponse.SC_BAD_REQUEST,
request.getRequestURI());
return;
}
String servletClass = pathInfo.substring(1);
// Identify the servlet name or class, and related information we will need
int slash = servletClass.indexOf("/");
if (slash >= 0) {
pathInfo = servletClass.substring(slash);
servletClass = servletClass.substring(0, slash);
} else {
pathInfo = "";
}
String name = "org.apache.catalina.INVOKER." + servletClass;
String pattern = request.getServletPath() + "/" + servletClass + "/*";
Wrapper wrapper = null;
// Are we referencing an existing servlet name?
wrapper = (Wrapper) context.findChild(servletClass);
if (wrapper != null) {
if (debug >= 1)
log("serveRequest: Using wrapper for servlet '" +
wrapper.getName() + "' with mapping '" + pattern + "'");
context.addServletMapping(pattern, wrapper.getName());
}
// No, create a new wrapper for the specified servlet class
else {
if (debug >= 1)
log("serveRequest: Creating wrapper for '" + servletClass +
"' with mapping '" + pattern + "'");
try {
wrapper = context.createWrapper();
wrapper.setName(name);
wrapper.setLoadOnStartup(1);
wrapper.setServletClass(servletClass);
context.addChild(wrapper);
context.addServletMapping(pattern, name);
} catch (Throwable t) {
log("serveRequest", t);
response.sendError(HttpServletResponse.SC_NOT_FOUND,
request.getRequestURI());
return;
}
}
// Pass this request on to the identified or newly created wrapper
StringBuffer sb = new StringBuffer(request.getServletPath());
sb.append("/");
sb.append(servletClass);
sb.append(pathInfo);
String dispatcherPath = sb.toString();
if (debug >= 1)
log("serveRequest: Forwarding to '" + dispatcherPath + "'");
RequestDispatcher rd =
getServletContext().getRequestDispatcher(dispatcherPath);
rd.forward(request, response);
}
}
1.1 jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/servlets/LocalStrings.properties
Index: LocalStrings.properties
===================================================================
defaultservlet.directorylistingfor=Directory Listing for:
defaultservlet.upto=Up to:
defaultservlet.subdirectories=Subdirectories:
defaultservlet.files=Files:
managerServlet.alreadyContext=FAIL - Application already exists at path {0}
managerServlet.deployed=OK - Deployed application at context path {0}
managerServlet.exception=FAIL - Encountered exception {0}
managerServlet.listed=OK - Listed applications for virtual host {0}
managerServlet.noCommand=FAIL - No command was specified
managerServlet.noContext=FAIL - No context exists for path {0}
managerServlet.noPath=FAIL - No context path was specified
managerServlet.noRole=FAIL - User does not possess role {0}
managerServlet.reloaded=OK - Reloaded application at context path {0}
managerServlet.undeployed=OK - Undeployed application at context path {0}
webdavservlet.jaxpfailed=JAXP initialization failed
1.1 jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/servlets/ManagerServlet.java
Index: ManagerServlet.java
===================================================================
/*
* $Header: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/servlets/ManagerServlet.java,v 1.1 2000/08/11 23:39:52 craigmcc Exp $
* $Revision: 1.1 $
* $Date: 2000/08/11 23:39:52 $
*
* ====================================================================
*
* The Apache Software License, Version 1.1
*
* Copyright (c) 1999 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution, if
* any, must include the following acknowlegement:
* "This product includes software developed by the
* Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowlegement may appear in the software itself,
* if and wherever such third-party acknowlegements normally appear.
*
* 4. The names "The Jakarta Project", "Tomcat", and "Apache Software
* Foundation" must not be used to endorse or promote products derived
* from this software without prior written permission. For written
* permission, please contact apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache"
* nor may "Apache" appear in their names without prior written
* permission of the Apache Group.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
* [Additional notices, if required by prior licensing conditions]
*
*/
package org.apache.catalina.servlets;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.catalina.Container;
import org.apache.catalina.Context;
import org.apache.catalina.Host;
import org.apache.catalina.HttpRequest;
import org.apache.catalina.HttpResponse;
import org.apache.catalina.Wrapper;
import org.apache.catalina.util.StringManager;
/**
* Servlet that enables remote management of the web applications installed
* within the same virtual host as this web application is. Normally, this
* functionality will be protected by a security constraint in the web
* application deployment descriptor. However, this requirement can be
* relaxed during testing.
* <p>
* This servlet examines the value returned by <code>getPathInfo()</code>
* and related query parameters to determine what action is being requested.
* The following actions and parameters (starting after the servlet path)
* are supported:
* <ul>
* <li><b>/list</b> - Return a list of the context paths of all currently
* running web applications in this virtual host.
* <li><b>/deploy?path=/xxx&war={war-url}</b> - Deploy a new web application
* attached to context path <code>/xxx</code>, based on the contents of
* the web application archive found at the specified URL.
* <li><b>/reload?path=/xxx</b> - Reload the Java classes and resources for
* the application at the specified path, but do not reread the web.xml
* configuration files.
* <li><b>/undeploy?path=/xxx</b> - Remove any web application attached to
* context path <code>/xxx</code> from this virtual host.
* </ul>
* <p>
* <b>NOTE</b> - Attempting to reload or undeploy the application containing
* this servlet itself will not succeed. Therefore, this servlet should
* generally be deployed as a separate web application within the virtual host
* to be managed.
* <p>
* The following servlet initialization parameters are recognized:
* <ul>
* <li><b>debug</b> - The debugging detail level that controls the amount
* of information that is logged by this servlet. Default is zero.
* </ul>
*
* @author Craig R. McClanahan
* @version $Revision: 1.1 $ $Date: 2000/08/11 23:39:52 $
*/
public final class ManagerServlet
extends HttpServlet {
// ----------------------------------------------------- Instance Variables
/**
* The Context container associated with our web application.
*/
private Context context = null;
/**
* The debugging detail level for this servlet.
*/
private int debug = 1;
/**
* The Host container that contains our own web application's Context,
* along with the associated Contexts for web applications that we
* are managing.
*/
private Host host = null;
/**
* The string manager for this package.
*/
private static StringManager sm =
StringManager.getManager(Constants.Package);
// --------------------------------------------------------- Public Methods
/**
* Finalize this servlet.
*/
public void destroy() {
; // No actions necessary
}
/**
* Process a GET request for the specified resource.
*
* @param request The servlet request we are processing
* @param response The servlet response we are creating
*
* @exception IOException if an input/output error occurs
* @exception ServletException if a servlet-specified error occurs
*/
public void doGet(HttpServletRequest request,
HttpServletResponse response)
throws IOException, ServletException {
// Identify the request parameters that we need
String command = request.getPathInfo();
if (command == null)
command = request.getServletPath();
String path = request.getParameter("path");
String war = request.getParameter("war");
// Prepare our output writer to generate the response message
response.setContentType("text/plain");
PrintWriter writer = response.getWriter();
// Process the requested command
if (command == null) {
writer.println(sm.getString("managerServlet.noCommand"));
} else if (command.equals("/deploy")) {
deploy(writer, path, war);
} else if (command.equals("/list")) {
list(writer);
} else if (command.equals("/reload")) {
reload(writer, path);
} else if (command.equals("/undeploy")) {
undeploy(writer, path);
} else {
writer.println(sm.getString("managerServlet.unknownCommand",
command));
}
// Finish up the response
writer.flush();
writer.close();
}
/**
* Initialize this servlet.
*/
public void init() throws ServletException {
// Set our properties from the initialization parameters
String value = null;
try {
value = getServletConfig().getInitParameter("debug");
debug = Integer.parseInt(value);
} catch (Throwable t) {
;
}
// Identify the internal container resources we need
Wrapper wrapper = (Wrapper) getServletConfig();
context = (Context) wrapper.getParent();
host = (Host) context.getParent();
// Log debugging messages as necessary
if (debug >= 1) {
log("init: Associated with Host '" + host.getName() + "'");
}
}
// -------------------------------------------------------- Private Methods
/**
* Deploy an application for the specified path from the specified
* web application archive.
*
* @param writer Writer to render results to
* @param path Context path of the application to be deployed
* @param war URL of the web application archive to be deployed
*/
private void deploy(PrintWriter writer, String path, String war) {
if (debug >= 1)
log("deploy: Deploying web application at '" + path +
"' from '" + war + "'");
try {
Context context = (Context) host.findChild(path);
if (context != null) {
writer.println(sm.getString("managerServlet.alreadyContext",
path));
return;
}
; // FIXME - deploy()
writer.println(sm.getString("managerServlet.deployed", path));
} catch (Throwable t) {
getServletContext().log("ManagerServlet.deploy[" + path + "]", t);
writer.println(sm.getString("managerServlet.exception",
t.toString()));
}
}
/**
* Render a list of the currently active Contexts in our virtual host.
*
* @param writer Writer to render to
*/
private void list(PrintWriter writer) {
if (debug >= 1)
log("list: Listing contexts for virtual host '" +
host.getName() + "'");
writer.println(sm.getString("managerServlet.listed", host.getName()));
Container children[] = host.findChildren();
for (int i = 0; i < children.length; i++)
writer.println(children[i].getName());
}
/**
* Reload the web application at the specified context path.
*
* @param writer Writer to render to
* @param path Context path of the application to be restarted
*/
private void reload(PrintWriter writer, String path) {
if (debug >= 1)
log("restart: Reloading web application at '" + path + "'");
try {
Context context = (Context) host.findChild(path);
if (context == null) {
writer.println(sm.getString("managerServlet.noContext", path));
return;
}
context.reload();
writer.println(sm.getString("managerServlet.reloaded", path));
} catch (Throwable t) {
getServletContext().log("ManagerServlet.reload[" + path + "]", t);
writer.println(sm.getString("managerServlet.exception",
t.toString()));
}
}
/**
* Undeploy the web application at the specified context path.
*
* @param writer Writer to render to
* @param path Context path of the application to be undeployed
*/
private void undeploy(PrintWriter writer, String path) {
if (debug >= 1)
log("undeploy: Undeploying web application at '" + path + "'");
try {
Context context = (Context) host.findChild(path);
if (context == null) {
writer.println(sm.getString("managerServlet.noContext", path));
return;
}
host.removeChild(context);
writer.println(sm.getString("managerServlet.undeployed", path));
} catch (Throwable t) {
getServletContext().log("ManagerServlet.undeploy[" + path + "]",
t);
writer.println(sm.getString("managerServlet.exception",
t.toString()));
}
}
}
1.1 jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/servlets/SnoopAllServlet.java
Index: SnoopAllServlet.java
===================================================================
/*
* $Header: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/servlets/SnoopAllServlet.java,v 1.1 2000/08/11 23:39:52 craigmcc Exp $
* $Revision: 1.1 $
* $Date: 2000/08/11 23:39:52 $
*
* ====================================================================
*
* The Apache Software License, Version 1.1
*
* Copyright (c) 1999 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution, if
* any, must include the following acknowlegement:
* "This product includes software developed by the
* Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowlegement may appear in the software itself,
* if and wherever such third-party acknowlegements normally appear.
*
* 4. The names "The Jakarta Project", "Tomcat", and "Apache Software
* Foundation" must not be used to endorse or promote products derived
* from this software without prior written permission. For written
* permission, please contact apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache"
* nor may "Apache" appear in their names without prior written
* permission of the Apache Group.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
* [Additional notices, if required by prior licensing conditions]
*
*/
package org.apache.catalina.servlets;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Enumeration;
import java.util.Locale;
import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* Servlet to dump everything that is known in the current request object
* into an HTML page.
*
* @author Craig R. McClanahan
* @version $Revision: 1.1 $ $Date: 2000/08/11 23:39:52 $
*/
public final class SnoopAllServlet
extends HttpServlet {
/**
* Process a GET request for the specified resource.
*
* @param request The servlet request we are processing
* @param response The servlet response we are creating
*
* @exception IOException if an input/output error occurs
* @exception ServletException if a servlet-specified error occurs
*/
public void doGet(HttpServletRequest request,
HttpServletResponse response)
throws IOException, ServletException {
response.setContentType("text/html");
PrintWriter writer = response.getWriter();
// Generate HTML page header
writer.println("<head>");
writer.println("<title>SnoopAllServlet Output</title>");
writer.println("</head>");
writer.println("<body bgcolor=\"white\">");
// Document the properties from ServletRequest
writer.println("<h1>ServletRequest Properties</h1>");
writer.println("<ul>");
Enumeration attrs = request.getAttributeNames();
while (attrs.hasMoreElements()) {
String attr = (String) attrs.nextElement();
writer.println("<li><b>attribute</b> " + attr + " = " +
request.getAttribute(attr));
}
writer.println("<li><b>characterEncoding</b> = " +
request.getCharacterEncoding());
writer.println("<li><b>contentLength</b> = " +
request.getContentLength());
writer.println("<li><b>contentType</b> = " +
request.getContentType());
Enumeration locales = request.getLocales();
while (locales.hasMoreElements()) {
Locale locale = (Locale) locales.nextElement();
writer.println("<li><b>locale</b> = " + locale);
}
Enumeration params = request.getParameterNames();
while (params.hasMoreElements()) {
String param = (String) params.nextElement();
String values[] = request.getParameterValues(param);
for (int i = 0; i < values.length; i++)
writer.println("<li><b>parameter</b> " + param + " = " +
values[i]);
}
writer.println("<li><b>protocol</b> = " + request.getProtocol());
writer.println("<li><b>remoteAddr</b> = " + request.getRemoteAddr());
writer.println("<li><b>remoteHost</b> = " + request.getRemoteHost());
writer.println("<li><b>scheme</b> = " + request.getScheme());
writer.println("<li><b>secure</b> = " + request.isSecure());
writer.println("<li><b>serverName</b> = " + request.getServerName());
writer.println("<li><b>serverPort</b> = " + request.getServerPort());
writer.println("</ul>");
writer.println("<hr>");
// Document the properties from HttpServletRequest
writer.println("<h1>HttpServletRequest Properties</h1>");
writer.println("<ul>");
writer.println("<li><b>authType</b> = " + request.getAuthType());
writer.println("<li><b>contextPath</b> = " +
request.getContextPath());
Cookie cookies[] = request.getCookies();
for (int i = 0; i < cookies.length; i++)
writer.println("<li><b>cookie</b> " + cookies[i].getName() +
" = " + cookies[i].getValue());
Enumeration headers = request.getHeaderNames();
while (headers.hasMoreElements()) {
String header = (String) headers.nextElement();
writer.println("<li><b>header</b> " + header + " = " +
request.getHeader(header));
}
writer.println("<li><b>method</b> = " + request.getMethod());
writer.println("<li><b>pathInfo</b> = " + request.getPathInfo());
writer.println("<li><b>pathTranslated</b> = " +
request.getPathTranslated());
writer.println("<li><b>queryString</b> = " +
request.getQueryString());
writer.println("<li><b>remoteUser</b> = " +
request.getRemoteUser());
writer.println("<li><b>requestedSessionId</b> = " +
request.getRequestedSessionId());
writer.println("<li><b>requestedSessionIdFromCookie</b> = " +
request.isRequestedSessionIdFromCookie());
writer.println("<li><b>requestedSessionIdFromURL</b> = " +
request.isRequestedSessionIdFromURL());
writer.println("<li><b>requestedSessionIdValid</b> = " +
request.isRequestedSessionIdValid());
writer.println("<li><b>requestURI</b> = " +
request.getRequestURI());
writer.println("<li><b>servletPath</b> = " +
request.getServletPath());
writer.println("<li><b>userPrincipal</b> = " +
request.getUserPrincipal());
writer.println("</ul>");
writer.println("<hr>");
// Document the servlet context attributes
writer.println("<h1>ServletContext Attributes</h1>");
writer.println("<ul>");
attrs = getServletContext().getAttributeNames();
while (attrs.hasMoreElements()) {
String attr = (String) attrs.nextElement();
writer.println("<li><b>" + attr + "</b> = " +
getServletContext().getAttribute(attr));
}
writer.println("</ul>");
writer.println("<hr>");
// Generate HTML page footer
writer.println("</body>");
writer.println("</html>");
}
/**
* Process a POST request for the specified resource.
*
* @param request The servlet request we are processing
* @param response The servlet response we are creating
*
* @exception IOException if an input/output error occurs
* @exception ServletException if a servlet-specified error occurs
*/
public void doPost(HttpServletRequest request,
HttpServletResponse response)
throws IOException, ServletException {
doGet(request, response);
}
}
1.1 jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/servlets/WebdavServlet.java
Index: WebdavServlet.java
===================================================================
/*
* $Header: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/servlets/WebdavServlet.java,v 1.1 2000/08/11 23:39:52 craigmcc Exp $
* $Revision: 1.1 $
* $Date: 2000/08/11 23:39:52 $
*
* ====================================================================
*
* The Apache Software License, Version 1.1
*
* Copyright (c) 1999 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution, if
* any, must include the following acknowlegement:
* "This product includes software developed by the
* Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowlegement may appear in the software itself,
* if and wherever such third-party acknowlegements normally appear.
*
* 4. The names "The Jakarta Project", "Tomcat", and "Apache Software
* Foundation" must not be used to endorse or promote products derived
* from this software without prior written permission. For written
* permission, please contact apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache"
* nor may "Apache" appear in their names without prior written
* permission of the Apache Group.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
* [Additional notices, if required by prior licensing conditions]
*
*/
package org.apache.catalina.servlets;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.io.Writer;
import java.net.MalformedURLException;
import java.net.URL;
import java.sql.Timestamp;
import java.util.Date;
import java.util.Enumeration;
import java.util.Vector;
import java.util.Stack;
import java.util.StringTokenizer;
import java.util.Locale;
import java.util.Hashtable;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.ServletContext;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.w3c.dom.Element;
import org.w3c.dom.Document;
import org.xml.sax.InputSource;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.apache.catalina.Resources;
import org.apache.catalina.core.ApplicationContext;
import org.apache.catalina.resources.ResourceBean;
import org.apache.catalina.resources.DirectoryBean;
import org.apache.catalina.util.MD5Encoder;
import org.apache.catalina.util.StringManager;
import org.apache.catalina.util.XMLWriter;
import org.apache.catalina.util.DOMWriter;
import org.apache.catalina.util.xml.SaxContext;
import org.apache.catalina.util.xml.XmlAction;
import org.apache.catalina.util.xml.XmlMapper;
/**
* Servlet which adds support for WebDAV level 2. All the basic HTTP requests
* are handled by the DefaultServlet.
*
* @author Remy Maucherat
* @version $Revision: 1.1 $ $Date: 2000/08/11 23:39:52 $
*/
public class WebdavServlet
extends DefaultServlet {
// -------------------------------------------------------------- Constants
private static final String METHOD_HEAD = "HEAD";
private static final String METHOD_PROPFIND = "PROPFIND";
private static final String METHOD_PROPPATCH = "PROPPATCH";
private static final String METHOD_MKCOL = "MKCOL";
private static final String METHOD_COPY = "COPY";
private static final String METHOD_MOVE = "MOVE";
private static final String METHOD_LOCK = "LOCK";
private static final String METHOD_UNLOCK = "UNLOCK";
/**
* Default depth is infite.
*/
private static final int INFINITY = 3; // To limit tree browsing a bit
/**
* PROPFIND - Specify a property mask.
*/
private static final int FIND_BY_PROPERTY = 0;
/**
* PROPFIND - Display all properties.
*/
private static final int FIND_ALL_PROP = 1;
/**
* PROPFIND - Return property names.
*/
private static final int FIND_PROPERTY_NAMES = 2;
/**
* Create a new lock.
*/
private static final int LOCK_CREATION = 0;
/**
* Refresh lock.
*/
private static final int LOCK_REFRESH = 1;
/**
* Default lock timeout value.
*/
private static final int DEFAULT_TIMEOUT = 3600;
/**
* Maximum lock timeout.
*/
private static final int MAX_TIMEOUT = 604800;
// ----------------------------------------------------- Instance Variables
/**
* JAXP Document builder.
*/
private DocumentBuilder documentBuilder;
/**
* Repository of the locks put on single resources.
* <p>
* Key : path <br>
* Value : LockInfo
*/
private Hashtable resourceLocks = new Hashtable();
/**
* Repository of the lock-null resources.
* <p>
* Key : path of the collection containing the lock-null resource<br>
* Value : Vector of lock-null resource which are members of the
* collection. Each element of the Vector is the path associated with
* the lock-null resource.
*/
private Hashtable lockNullResources = new Hashtable();
/**
* Vector of the heritable locks.
* <p>
* Key : path <br>
* Value : LockInfo
*/
private Vector collectionLocks = new Vector();
/**
* Secret information used to generate reasonably secure lock ids.
*/
private String secret = "catalina";
// --------------------------------------------------------- Public Methods
/**
* Initialize this servlet.
*/
public void init()
throws ServletException {
super.init();
String value = null;
try {
value = getServletConfig().getInitParameter("secret");
if (value != null)
secret = value;
} catch (Throwable t) {
;
}
try {
documentBuilder =
DocumentBuilderFactory.newInstance().newDocumentBuilder();
} catch(ParserConfigurationException e) {
throw new ServletException
(sm.getString("webdavservlet.jaxpfailed"));
}
}
// ------------------------------------------------------ Protected Methods
/**
* Handles the special WebDAV methods.
*/
protected void service(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
String method = req.getMethod();
String path = getRelativePath(req);
System.out.println("[" + method + "] " + path);
if (method.equals(METHOD_PROPFIND)) {
doPropfind(req, resp);
} else if (method.equals(METHOD_PROPPATCH)) {
doProppatch(req, resp);
} else if (method.equals(METHOD_MKCOL)) {
doMkcol(req, resp);
} else if (method.equals(METHOD_COPY)) {
doCopy(req, resp);
} else if (method.equals(METHOD_MOVE)) {
doMove(req, resp);
} else if (method.equals(METHOD_LOCK)) {
doLock(req, resp);
} else if (method.equals(METHOD_UNLOCK)) {
doUnlock(req, resp);
} else {
// DefaultServlet processing
super.service(req, resp);
}
}
/**
* Check if the conditions specified in the optional If headers are
* satisfied.
*
* @param request The servlet request we are processing
* @param response The servlet response we are creating
* @param resourceInfo File object
* @return boolean true if the resource meets all the specified conditions,
* and false if any of the conditions is not satisfied, in which case
* request processing is stopped
*/
protected boolean checkIfHeaders(HttpServletRequest request,
HttpServletResponse response,
ResourceInfo resourceInfo)
throws IOException {
if (!super.checkIfHeaders(request, response, resourceInfo))
return false;
// TODO : Checking the WebDAV If header
return true;
}
/**
* OPTIONS Method.
*/
protected void doOptions(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
String path = getRelativePath(req);
resp.addHeader("DAV", "1,2");
String methodsAllowed = null;
// Retrieve the Catalina context
ApplicationContext context = (ApplicationContext) getServletContext();
Resources resources = context.getResources();
if (!resources.exists(path)) {
methodsAllowed = "OPTIONS, MKCOL, PUT, LOCK";
resp.addHeader("Allow", methodsAllowed);
return;
}
methodsAllowed = "OPTIONS, GET, HEAD, POST, DELETE, TRACE, "
+ "PROPFIND, PROPPATCH, COPY, MOVE, LOCK, UNLOCK";
if (!resources.isCollection(path)) {
methodsAllowed += ", PUT";
}
resp.addHeader("Allow", methodsAllowed);
}
/**
* PROPFIND Method.
*/
protected void doPropfind(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
if (!listings) {
resp.sendError(WebdavStatus.SC_METHOD_NOT_ALLOWED);
return;
}
String path = getRelativePath(req);
// Properties which are to be displayed.
Vector properties = null;
// Propfind depth
int depth = INFINITY;
// Propfind type
int type = FIND_ALL_PROP;
String depthStr = req.getHeader("Depth");
if (depthStr == null) {
depth = INFINITY;
} else {
if (depthStr.equals("0")) {
depth = 0;
} else if (depthStr.equals("1")) {
depth = 1;
} else if (depthStr.equals("infinity")) {
depth = INFINITY;
}
}
Node propNode = null;
try {
Document document = documentBuilder.parse
(new InputSource(req.getInputStream()));
// Get the root element of the document
Element rootElement = document.getDocumentElement();
NodeList childList = rootElement.getChildNodes();
for (int i=0; i < childList.getLength(); i++) {
Node currentNode = childList.item(i);
switch (currentNode.getNodeType()) {
case Node.TEXT_NODE:
break;
case Node.ELEMENT_NODE:
if (currentNode.getNodeName().endsWith("prop")) {
type = FIND_BY_PROPERTY;
propNode = currentNode;
}
if (currentNode.getNodeName().endsWith("propname")) {
type = FIND_PROPERTY_NAMES;
}
if (currentNode.getNodeName().endsWith("allprop")) {
type = FIND_ALL_PROP;
}
break;
}
}
} catch(Exception e) {
// Most likely there was no content : we use the defaults.
// TODO : Enhance that !
}
if (type == FIND_BY_PROPERTY) {
properties = new Vector();
NodeList childList = propNode.getChildNodes();
for (int i=0; i < childList.getLength(); i++) {
Node currentNode = childList.item(i);
switch (currentNode.getNodeType()) {
case Node.TEXT_NODE:
break;
case Node.ELEMENT_NODE:
String nodeName = currentNode.getNodeName();
String propertyName = null;
if (nodeName.indexOf(':') != -1) {
propertyName = nodeName.substring
(nodeName.indexOf(':') + 1);
} else {
propertyName = nodeName;
}
// href is a live property which is handled differently
properties.addElement(propertyName);
break;
}
}
}
// Retrieve the Catalina context
ApplicationContext context = (ApplicationContext) getServletContext();
Resources resources = context.getResources();
if (!resources.exists(path)) {
resp.sendError(HttpServletResponse.SC_NOT_FOUND, path);
return;
}
resp.setStatus(WebdavStatus.SC_MULTI_STATUS);
// Create multistatus object
XMLWriter generatedXML = new XMLWriter();
generatedXML.writeElement("d", "DAV", "multistatus",
XMLWriter.OPENING);
if (depth == 0) {
parseProperties(req, resources, generatedXML, path, type,
properties);
} else {
// The stack always contains the object of the current level
Stack stack = new Stack();
stack.push(path);
// Stack of the objects one level below
Stack stackBelow = new Stack();
while ((!stack.isEmpty()) && (depth >= 0)) {
String currentPath = (String) stack.pop();
parseProperties(req, resources, generatedXML, currentPath, type,
properties);
if (resources.isCollection(currentPath)) {
String[] children =
resources.getCollectionMembers(currentPath);
for (int i=0; i<children.length; i++) {
stackBelow.push(children[i]);
}
if (depth > 0) {
// Displaying the lock-null resources present in that
// collection
Vector currentLockNullResources =
(Vector) lockNullResources.get(currentPath);
if (currentLockNullResources != null) {
Enumeration lockNullResourcesList =
currentLockNullResources.elements();
while (lockNullResourcesList.hasMoreElements()) {
String lockNullPath = (String)
lockNullResourcesList.nextElement();
parseLockNullProperties
(req, generatedXML, currentPath, type,
properties);
}
}
}
}
if (stack.isEmpty()) {
depth--;
stack = stackBelow;
stackBelow = new Stack();
}
}
}
generatedXML.writeElement("d", "multistatus",
XMLWriter.CLOSING);
Writer writer = resp.getWriter();
writer.write(generatedXML.toString());
writer.flush();
}
/**
* PROPPATCH Method.
*/
protected void doProppatch(HttpServletRequest req,
HttpServletResponse resp)
throws ServletException, IOException {
if (readOnly) {
resp.sendError(WebdavStatus.SC_FORBIDDEN);
return;
}
if (isLocked(req)) {
resp.sendError(WebdavStatus.SC_LOCKED);
return;
}
}
/**
* MKCOL Method.
*/
protected void doMkcol(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
if (readOnly) {
resp.sendError(WebdavStatus.SC_FORBIDDEN);
return;
}
if (isLocked(req)) {
resp.sendError(WebdavStatus.SC_LOCKED);
return;
}
String path = getRelativePath(req);
// Retrieve the Catalina context
ApplicationContext context = (ApplicationContext) getServletContext();
Resources resources = context.getResources();
// Can't create a collection if a resource already exists at the given
// path
if (resources.exists(path)) {
resp.sendError(WebdavStatus.SC_METHOD_NOT_ALLOWED);
return;
}
boolean result = resources.createCollection(path);
if (!result) {
resp.sendError(WebdavStatus.SC_CONFLICT,
WebdavStatus.getStatusText
(WebdavStatus.SC_CONFLICT));
} else {
resp.setStatus(WebdavStatus.SC_CREATED);
// Removing any lock-null resource which would be present
lockNullResources.remove(path);
}
}
/**
* DELETE Method.
*/
protected void doDelete(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
if (readOnly) {
resp.sendError(WebdavStatus.SC_FORBIDDEN);
return;
}
if (isLocked(req)) {
resp.sendError(WebdavStatus.SC_LOCKED);
return;
}
deleteResource(req, resp);
}
/**
* Process a POST request for the specified resource.
*
* @param request The servlet request we are processing
* @param response The servlet response we are creating
*
* @exception IOException if an input/output error occurs
* @exception ServletException if a servlet-specified error occurs
*/
protected void doPut(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
if (isLocked(req)) {
resp.sendError(WebdavStatus.SC_LOCKED);
return;
}
super.doPut(req, resp);
String path = getRelativePath(req);
// Removing any lock-null resource which would be present
lockNullResources.remove(path);
}
/**
* COPY Method.
*/
protected void doCopy(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
if (readOnly) {
resp.sendError(WebdavStatus.SC_FORBIDDEN);
return;
}
copyResource(req, resp);
}
/**
* MOVE Method.
*/
protected void doMove(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
if (readOnly) {
resp.sendError(WebdavStatus.SC_FORBIDDEN);
return;
}
if (isLocked(req)) {
resp.sendError(WebdavStatus.SC_LOCKED);
return;
}
String path = getRelativePath(req);
if (copyResource(req, resp)) {
deleteResource(path, req, resp);
}
}
/**
* LOCK Method.
*/
protected void doLock(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
if (isLocked(req)) {
resp.sendError(WebdavStatus.SC_LOCKED);
return;
}
LockInfo lock = new LockInfo();
// Parsing lock request
// Parsing depth header
String depthStr = req.getHeader("Depth");
if (depthStr == null) {
lock.depth = INFINITY;
} else {
if (depthStr.equals("0")) {
lock.depth = 0;
} else {
lock.depth = INFINITY;
}
}
// Parsing timeout header
int lockDuration = DEFAULT_TIMEOUT;
String lockDurationStr = req.getHeader("Timeout");
if (lockDurationStr == null) {
lockDuration = DEFAULT_TIMEOUT;
} else {
if (lockDurationStr.startsWith("Second-")) {
lockDuration =
(new Integer(lockDurationStr.substring(7))).intValue();
} else {
if (lockDurationStr.equalsIgnoreCase("infinity")) {
lockDuration = MAX_TIMEOUT;
} else {
try {
lockDuration =
(new Integer(lockDurationStr)).intValue();
} catch (NumberFormatException e) {
lockDuration = MAX_TIMEOUT;
}
}
}
if (lockDuration == 0) {
lockDuration = DEFAULT_TIMEOUT;
}
if (lockDuration > MAX_TIMEOUT) {
lockDuration = MAX_TIMEOUT;
}
}
lock.expiresAt = System.currentTimeMillis() + (lockDuration * 1000);
int lockRequestType = LOCK_CREATION;
Node lockInfoNode = null;
try {
Document document = documentBuilder.parse(new InputSource
(req.getInputStream()));
// Get the root element of the document
Element rootElement = document.getDocumentElement();
lockInfoNode = rootElement;
} catch(Exception e) {
lockRequestType = LOCK_REFRESH;
}
if (lockInfoNode != null) {
// Reading lock information
NodeList childList = lockInfoNode.getChildNodes();
StringWriter strWriter = null;
DOMWriter domWriter = null;
Node lockScopeNode = null;
Node lockTypeNode = null;
Node lockOwnerNode = null;
for (int i=0; i < childList.getLength(); i++) {
Node currentNode = childList.item(i);
switch (currentNode.getNodeType()) {
case Node.TEXT_NODE:
break;
case Node.ELEMENT_NODE:
String nodeName = currentNode.getNodeName();
if (nodeName.endsWith("lockscope")) {
lockScopeNode = currentNode;
}
if (nodeName.endsWith("locktype")) {
lockTypeNode = currentNode;
}
if (nodeName.endsWith("owner")) {
lockOwnerNode = currentNode;
}
break;
}
}
if (lockScopeNode != null) {
childList = lockScopeNode.getChildNodes();
for (int i=0; i < childList.getLength(); i++) {
Node currentNode = childList.item(i);
switch (currentNode.getNodeType()) {
case Node.TEXT_NODE:
break;
case Node.ELEMENT_NODE:
String tempScope = currentNode.getNodeName();
if (tempScope.indexOf(':') != -1) {
lock.scope =
tempScope.substring(tempScope.indexOf(':'));
} else {
lock.scope = tempScope;
}
break;
}
}
if (lock.scope == null) {
// Bad request
resp.setStatus(WebdavStatus.SC_BAD_REQUEST);
}
} else {
// Bad request
resp.setStatus(WebdavStatus.SC_BAD_REQUEST);
}
if (lockTypeNode != null) {
childList = lockTypeNode.getChildNodes();
for (int i=0; i < childList.getLength(); i++) {
Node currentNode = childList.item(i);
switch (currentNode.getNodeType()) {
case Node.TEXT_NODE:
break;
case Node.ELEMENT_NODE:
String tempType = currentNode.getNodeName();
if (tempType.indexOf(':') != -1) {
lock.type =
tempType.substring(tempType.indexOf(':') + 1);
} else {
lock.type = tempType;
}
break;
}
}
if (lock.type == null) {
// Bad request
resp.setStatus(WebdavStatus.SC_BAD_REQUEST);
}
} else {
// Bad request
resp.setStatus(WebdavStatus.SC_BAD_REQUEST);
}
if (lockOwnerNode != null) {
childList = lockOwnerNode.getChildNodes();
for (int i=0; i < childList.getLength(); i++) {
Node currentNode = childList.item(i);
switch (currentNode.getNodeType()) {
case Node.TEXT_NODE:
lock.owner += currentNode.getNodeValue();
break;
case Node.ELEMENT_NODE:
strWriter = new StringWriter();
domWriter = new DOMWriter(strWriter, true);
domWriter.print(currentNode);
lock.owner += strWriter.toString();
break;
}
}
if (lock.owner == null) {
// Bad request
resp.setStatus(WebdavStatus.SC_BAD_REQUEST);
}
} else {
lock.owner = new String();
}
}
String path = getRelativePath(req);
lock.path = path;
// Retrieve the Catalina context
ApplicationContext context = (ApplicationContext) getServletContext();
Resources resources = context.getResources();
Enumeration locksList = null;
if (lockRequestType == LOCK_CREATION) {
// Generating lock id
String lockTokenStr = req.getServletPath() + "-" + lock.type + "-"
+ lock.scope + "-" + req.getUserPrincipal() + "-"
+ lock.depth + "-" + lock.owner + "-" + lock.tokens + "-"
+ lock.expiresAt + "-" + System.currentTimeMillis() + "-"
+ secret;
String lockToken =
md5Encoder.encode(md5Helper.digest(lockTokenStr.getBytes()));
if ( (resources.exists(path)) && (resources.isCollection(path)) &&
(lock.depth == INFINITY) ) {
// Locking a collection (and all its member resources)
// Checking if a child resource of this collection is
// already locked
Vector lockPaths = new Vector();
locksList = collectionLocks.elements();
while (locksList.hasMoreElements()) {
LockInfo currentLock = (LockInfo) locksList.nextElement();
if (currentLock.hasExpired()) {
resourceLocks.remove(currentLock.path);
continue;
}
if ( (currentLock.path.startsWith(lock.path)) &&
((currentLock.isExclusive()) ||
(lock.isExclusive())) ) {
// A child collection of this collection is locked
lockPaths.addElement(currentLock.path);
}
}
locksList = resourceLocks.elements();
while (locksList.hasMoreElements()) {
LockInfo currentLock = (LockInfo) locksList.nextElement();
if (currentLock.hasExpired()) {
resourceLocks.remove(currentLock.path);
continue;
}
if ( (currentLock.path.startsWith(lock.path)) &&
((currentLock.isExclusive()) ||
(lock.isExclusive())) ) {
// A child resource of this collection is locked
lockPaths.addElement(currentLock.path);
}
}
if (!lockPaths.isEmpty()) {
// One of the child paths was locked
// We generate a multistatus error report
Enumeration lockPathsList = lockPaths.elements();
resp.setStatus(WebdavStatus.SC_CONFLICT);
XMLWriter generatedXML = new XMLWriter();
generatedXML.writeXMLHeader();
generatedXML.writeElement("d", "DAV", "multistatus",
XMLWriter.OPENING);
while (lockPathsList.hasMoreElements()) {
generatedXML.writeElement("d", "DAV", "response",
XMLWriter.OPENING);
generatedXML.writeElement("d", "DAV", "href",
XMLWriter.OPENING);
generatedXML
.writeText((String) lockPathsList.nextElement());
generatedXML.writeElement("d", "href",
XMLWriter.CLOSING);
generatedXML.writeElement("d", "DAV", "status",
XMLWriter.OPENING);
generatedXML
.writeText("HTTP/1.1 " + WebdavStatus.SC_LOCKED
+ " " + WebdavStatus
.getStatusText(WebdavStatus.SC_LOCKED));
generatedXML.writeElement("d", "status",
XMLWriter.CLOSING);
generatedXML.writeElement("d", "response",
XMLWriter.CLOSING);
}
generatedXML.writeElement("d", "multistatus",
XMLWriter.CLOSING);
Writer writer = resp.getWriter();
writer.write(generatedXML.toString());
writer.close();
return;
}
boolean addLock = true;
// Checking if there is already a shared lock on this path
locksList = collectionLocks.elements();
while (locksList.hasMoreElements()) {
LockInfo currentLock = (LockInfo) locksList.nextElement();
if (currentLock.path.equals(lock.path)) {
if (currentLock.isExclusive()) {
resp.sendError(WebdavStatus.SC_LOCKED);
return;
} else {
if (lock.isExclusive()) {
resp.sendError(WebdavStatus.SC_LOCKED);
return;
}
}
currentLock.tokens.addElement(lockToken);
lock = currentLock;
addLock = false;
}
}
if (addLock) {
lock.tokens.addElement(lockToken);
collectionLocks.addElement(lock);
}
} else {
// Locking a single resource
// Retrieving an already existing lock on that resource
LockInfo presentLock = (LockInfo) resourceLocks.get(lock.path);
if (presentLock != null) {
if ( (presentLock.isExclusive()) || (lock.isExclusive()) ) {
// If either lock is exclusive, the lock can't be
// granted
resp.sendError(WebdavStatus.SC_PRECONDITION_FAILED);
return;
} else {
presentLock.tokens.addElement(lockToken);
lock = presentLock;
}
} else {
lock.tokens.addElement(lockToken);
resourceLocks.put(lock.path, lock);
// Checking if a resource exists at this path
if (!resources.exists(lock.path)) {
// "Creating" a lock-null resource
int slash = lock.path.lastIndexOf('/');
String parentPath = lock.path.substring(0, slash);
Vector lockNulls =
(Vector) lockNullResources.get(parentPath);
if (lockNulls == null) {
lockNulls = new Vector();
lockNullResources.put(parentPath, lockNulls);
}
lockNulls.addElement(lock.path);
}
}
}
}
if (lockRequestType == LOCK_REFRESH) {
String ifHeader = req.getHeader("If");
if (ifHeader == null)
ifHeader = "";
// Checking resource locks
LockInfo toRenew = (LockInfo) resourceLocks.get(path);
Enumeration tokenList = null;
if (lock != null) {
// At least one of the tokens of the locks must have been given
tokenList = toRenew.tokens.elements();
while (tokenList.hasMoreElements()) {
String token = (String) tokenList.nextElement();
if (ifHeader.indexOf(token) != -1) {
toRenew.expiresAt = lock.expiresAt;
lock = toRenew;
}
}
}
// Checking inheritable collection locks
Enumeration collectionLocksList = collectionLocks.elements();
while (collectionLocksList.hasMoreElements()) {
toRenew = (LockInfo) collectionLocksList.nextElement();
if (path.equals(toRenew.path)) {
tokenList = toRenew.tokens.elements();
while (tokenList.hasMoreElements()) {
String token = (String) tokenList.nextElement();
if (ifHeader.indexOf(token) != -1) {
toRenew.expiresAt = lock.expiresAt;
lock = toRenew;
}
}
}
}
}
// Set the status, then generate the XML response containing
// the lock information
XMLWriter generatedXML = new XMLWriter();
generatedXML.writeXMLHeader();
generatedXML.writeElement("d", "DAV", "prop", XMLWriter.OPENING);
generatedXML.writeElement("d", "DAV", "lockdiscovery",
XMLWriter.OPENING);
lock.toXML(generatedXML, true);
generatedXML.writeElement("d", "DAV", "lockdiscovery",
XMLWriter.CLOSING);
generatedXML.writeElement("d", "DAV", "prop", XMLWriter.CLOSING);
resp.setStatus(WebdavStatus.SC_OK);
Writer writer = resp.getWriter();
writer.write(generatedXML.toString());
writer.close();
}
/**
* UNLOCK Method.
*/
protected void doUnlock(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
if (isLocked(req)) {
resp.sendError(WebdavStatus.SC_LOCKED);
return;
}
String path = getRelativePath(req);
String lockTokenHeader = req.getHeader("Lock-Token");
if (lockTokenHeader == null)
lockTokenHeader = "";
// Checking resource locks
LockInfo lock = (LockInfo) resourceLocks.get(path);
Enumeration tokenList = null;
if (lock != null) {
// At least one of the tokens of the locks must have been given
tokenList = lock.tokens.elements();
while (tokenList.hasMoreElements()) {
String token = (String) tokenList.nextElement();
if (lockTokenHeader.indexOf(token) != -1) {
lock.tokens.removeElement(token);
}
}
if (lock.tokens.isEmpty()) {
resourceLocks.remove(path);
// Removing any lock-null resource which would be present
lockNullResources.remove(path);
}
}
// Checking inheritable collection locks
Enumeration collectionLocksList = collectionLocks.elements();
while (collectionLocksList.hasMoreElements()) {
lock = (LockInfo) collectionLocksList.nextElement();
if (path.equals(lock.path)) {
tokenList = lock.tokens.elements();
while (tokenList.hasMoreElements()) {
String token = (String) tokenList.nextElement();
if (lockTokenHeader.indexOf(token) != -1) {
lock.tokens.removeElement(token);
break;
}
}
if (lock.tokens.isEmpty()) {
collectionLocks.removeElement(lock);
// Removing any lock-null resource which would be present
lockNullResources.remove(path);
}
}
}
resp.setStatus(WebdavStatus.SC_NO_CONTENT);
}
// -------------------------------------------------------- Private Methods
/**
* Check to see if a resource is currently write locked. The method
* will look at the "If" header to make sure the client
* has give the appropriate lock tokens.
*
* @param req Servlet request
* @return boolean true if the resource is locked (and no appropriate
* lock token has been found for at least one of the non-shared locks which
* are present on the resource).
*/
private boolean isLocked(HttpServletRequest req) {
String path = getRelativePath(req);
String ifHeader = req.getHeader("If");
if (ifHeader == null)
ifHeader = "";
String lockTokenHeader = req.getHeader("Lock-Token");
if (lockTokenHeader == null)
lockTokenHeader = "";
return isLocked(path, ifHeader + lockTokenHeader);
}
/**
* Check to see if a resource is currently write locked.
*
* @param path Path of the resource
* @param ifHeader "If" HTTP header which was included in the request
* @return boolean true if the resource is locked (and no appropriate
* lock token has been found for at least one of the non-shared locks which
* are present on the resource).
*/
private boolean isLocked(String path, String ifHeader) {
// Checking resource locks
LockInfo lock = (LockInfo) resourceLocks.get(path);
Enumeration tokenList = null;
if ((lock != null) && (lock.hasExpired())) {
resourceLocks.remove(path);
} else if (lock != null) {
// At least one of the tokens of the locks must have been given
tokenList = lock.tokens.elements();
boolean tokenMatch = false;
while (tokenList.hasMoreElements()) {
String token = (String) tokenList.nextElement();
if (ifHeader.indexOf(token) != -1)
tokenMatch = true;
}
if (!tokenMatch)
return true;
}
// Checking inheritable collection locks
Enumeration collectionLocksList = collectionLocks.elements();
while (collectionLocksList.hasMoreElements()) {
lock = (LockInfo) collectionLocksList.nextElement();
if (lock.hasExpired()) {
collectionLocks.removeElement(lock);
} else if (path.startsWith(lock.path)) {
tokenList = lock.tokens.elements();
boolean tokenMatch = false;
while (tokenList.hasMoreElements()) {
String token = (String) tokenList.nextElement();
if (ifHeader.indexOf(token) != -1)
tokenMatch = true;
}
if (!tokenMatch)
return true;
}
}
return false;
}
/**
* Copy a resource.
*
* @param req Servlet request
* @param resp Servlet response
* @return boolean true if the copy is successful
*/
private boolean copyResource(HttpServletRequest req,
HttpServletResponse resp)
throws ServletException, IOException {
// Parsing destination header
String destinationPath = req.getHeader("Destination");
if (destinationPath.startsWith("http://")) {
destinationPath = destinationPath.substring("http://".length());
}
String hostName = req.getServerName();
if ((hostName != null) && (destinationPath.startsWith(hostName))) {
destinationPath = destinationPath.substring(hostName.length());
}
if (destinationPath.startsWith(":")) {
int firstSeparator = destinationPath.indexOf("/");
if (firstSeparator < 0) {
destinationPath = "/";
} else {
destinationPath = destinationPath.substring(firstSeparator);
}
}
String contextPath = req.getContextPath();
if ((contextPath != null) &&
(destinationPath.startsWith(contextPath))) {
destinationPath = destinationPath.substring(contextPath.length());
}
String pathInfo = req.getPathInfo();
if (pathInfo != null) {
String servletPath = req.getServletPath();
if ((servletPath != null) &&
(destinationPath.startsWith(servletPath))) {
destinationPath = destinationPath
.substring(servletPath.length());
}
}
System.out.println("Dest path :" + destinationPath);
String path = getRelativePath(req);
if (destinationPath.equals(path)) {
resp.sendError(WebdavStatus.SC_FORBIDDEN);
return false;
}
// Parsing overwrite header
boolean overwrite = true;
String overwriteHeader = req.getHeader("Overwrite");
if (overwriteHeader != null) {
if (overwriteHeader.equalsIgnoreCase("T")) {
overwrite = true;
} else {
overwrite = false;
}
}
// Overwriting the destination
// Retrieve the Catalina context
ApplicationContext context = (ApplicationContext) getServletContext();
Resources resources = context.getResources();
if (overwrite) {
// Delete destination resource, if it exists
if (resources.exists(destinationPath)) {
if (!deleteResource(destinationPath, req, resp)) {
return false;
} else {
resp.setStatus(WebdavStatus.SC_NO_CONTENT);
}
} else {
resp.setStatus(WebdavStatus.SC_CREATED);
}
} else {
// If the destination exists, then it's a conflict
if (resources.exists(destinationPath)) {
resp.sendError(WebdavStatus.SC_PRECONDITION_FAILED);
return false;
}
}
// Copying source to destination
Hashtable errorList = new Hashtable();
boolean result = copyResource(resources, errorList,
path, destinationPath);
if ((!result) || (!errorList.isEmpty())) {
sendReport(req, resp, errorList);
return false;
}
// Removing any lock-null resource which would be present at
// the destination path
lockNullResources.remove(destinationPath);
return true;
}
/**
* Copy a collection.
*
* @param resources Resources implementation to be used
* @param errorList Hashtable containing the list of errors which occured
* during the copy operation
* @param source Path of the resource to be copied
* @param dest Destination path
*/
private boolean copyResource(Resources resources, Hashtable errorList,
String source, String dest) {
if (resources.isCollection(source)) {
if (!resources.createCollection(dest)) {
errorList.put
(dest,
new Integer(WebdavStatus.SC_CONFLICT));
return false;
}
String[] members = resources.getCollectionMembers(source);
for (int i=0; i<members.length; i++) {
String childDest = dest +
members[i].substring(source.length());
copyResource(resources, errorList, members[i], childDest);
}
} else {
InputStream is = resources.getResourceAsStream(source);
if (!resources.setResource(dest, is)) {
errorList.put
(source,
new Integer(WebdavStatus.SC_INTERNAL_SERVER_ERROR));
return false;
}
}
return true;
}
/**
* Delete a resource.
*
* @param req Servlet request
* @param resp Servlet response
* @return boolean true if the copy is successful
*/
private boolean deleteResource(HttpServletRequest req,
HttpServletResponse resp)
throws ServletException, IOException {
String path = getRelativePath(req);
return deleteResource(path, req, resp);
}
/**
* Delete a resource.
*
* @param path Path of the resource which is to be deleted
* @param req Servlet request
* @param resp Servlet response
*/
private boolean deleteResource(String path, HttpServletRequest req,
HttpServletResponse resp)
throws ServletException, IOException {
String ifHeader = req.getHeader("If");
if (ifHeader == null)
ifHeader = "";
String lockTokenHeader = req.getHeader("Lock-Token");
if (lockTokenHeader == null)
lockTokenHeader = "";
if (isLocked(path, ifHeader + lockTokenHeader)) {
resp.sendError(WebdavStatus.SC_LOCKED);
return false;
}
// Retrieve the Catalina context
ApplicationContext context = (ApplicationContext) getServletContext();
Resources resources = context.getResources();
if (!resources.exists(path)) {
resp.sendError(WebdavStatus.SC_NOT_FOUND);
return false;
}
boolean collection = resources.isCollection(path);
if (!collection) {
if (!resources.deleteResource(path)) {
resp.sendError(WebdavStatus.SC_INTERNAL_SERVER_ERROR);
return false;
}
} else {
Hashtable errorList = new Hashtable();
deleteCollection(req, resources, path, errorList);
resources.deleteResource(path);
if (!errorList.isEmpty()) {
sendReport(req, resp, errorList);
return false;
}
}
resp.setStatus(WebdavStatus.SC_NO_CONTENT);
return true;
}
/**
* Deletes a collection.
*
* @param resources Resources implementation associated with the context
* @param path Path to the collection to be deleted
* @param errorList Contains the list of the errors which occured
*/
private void deleteCollection(HttpServletRequest req, Resources resources,
String path, Hashtable errorList) {
String ifHeader = req.getHeader("If");
if (ifHeader == null)
ifHeader = "";
String lockTokenHeader = req.getHeader("Lock-Token");
if (lockTokenHeader == null)
lockTokenHeader = "";
String[] members = resources.getCollectionMembers(path);
for (int i=0; i<members.length; i++) {
if (isLocked(members[i], ifHeader + lockTokenHeader)) {
errorList.put(members[i], new Integer(WebdavStatus.SC_LOCKED));
} else {
if (resources.isCollection(members[i])) {
deleteCollection(req, resources, members[i], errorList);
}
boolean result = resources.deleteResource(members[i]);
if (!result) {
if (!resources.isCollection(members[i])) {
// If it's not a collection, then it's an unknown
// error
errorList.put
(members[i], new Integer
(WebdavStatus.SC_INTERNAL_SERVER_ERROR));
}
}
}
}
}
/**
* Send a multistatus element containing a complete error report to the
* client.
*
* @param req Servlet request
* @param resp Servlet response
* @param errorList List of error to be displayed
*/
private void sendReport(HttpServletRequest req, HttpServletResponse resp,
Hashtable errorList)
throws ServletException, IOException {
resp.setStatus(WebdavStatus.SC_MULTI_STATUS);
String absoluteUri = req.getRequestURI();
String relativePath = getRelativePath(req);
XMLWriter generatedXML = new XMLWriter();
generatedXML.writeXMLHeader();
generatedXML.writeElement("d", "DAV", "multistatus",
XMLWriter.OPENING);
Enumeration pathList = errorList.keys();
while (pathList.hasMoreElements()) {
String errorPath = (String) pathList.nextElement();
int errorCode = ((Integer) errorList.get(errorPath)).intValue();
generatedXML.writeElement("d", "DAV", "response",
XMLWriter.OPENING);
generatedXML.writeElement("d", "DAV", "href",
XMLWriter.OPENING);
String toAppend = errorPath.substring(relativePath.length());
if (!toAppend.startsWith("/"))
toAppend = "/" + toAppend;
generatedXML.writeText(absoluteUri + toAppend);
generatedXML.writeElement("d", "href",
XMLWriter.CLOSING);
generatedXML.writeElement("d", "DAV", "status",
XMLWriter.OPENING);
generatedXML
.writeText("HTTP/1.1 " + errorCode + " "
+ WebdavStatus.getStatusText(errorCode));
generatedXML.writeElement("d", "status",
XMLWriter.CLOSING);
generatedXML.writeElement("d", "response",
XMLWriter.CLOSING);
}
generatedXML.writeElement("d", "multistatus",
XMLWriter.CLOSING);
Writer writer = resp.getWriter();
writer.write(generatedXML.toString());
writer.close();
}
/**
* Propfind helper method.
*
* @param resources Resources object associated with this context
* @param generatedXML XML response to the Propfind request
* @param path Path of the current resource
* @param type Propfind type
* @param propertiesVector If the propfind type is find properties by
* name, then this Vector contains those properties
*/
private void parseProperties(HttpServletRequest req,
Resources resources, XMLWriter generatedXML,
String path, int type,
Vector propertiesVector) {
// Exclude any resource in the /WEB-INF and /META-INF subdirectories
// (the "toUpperCase()" avoids problems on Windows systems)
if (path.toUpperCase().startsWith("/WEB-INF") ||
path.toUpperCase().startsWith("/META-INF"))
return;
ResourceInfo resourceInfo = new ResourceInfo(path, resources);
generatedXML.writeElement("d", "response", XMLWriter.OPENING);
String status = new String("HTTP/1.1 " + WebdavStatus.SC_OK + " "
+ WebdavStatus.getStatusText
(WebdavStatus.SC_OK));
// Generating href element
generatedXML.writeElement("d", "href", XMLWriter.OPENING);
String absoluteUri = req.getRequestURI();
String relativePath = getRelativePath(req);
String toAppend = path.substring(relativePath.length());
if (!toAppend.startsWith("/"))
toAppend = "/" + toAppend;
generatedXML.writeText(absoluteUri + toAppend);
generatedXML.writeElement("d", "href", XMLWriter.CLOSING);
switch (type) {
case FIND_ALL_PROP :
generatedXML.writeElement("d", "propstat", XMLWriter.OPENING);
generatedXML.writeElement("d", "prop", XMLWriter.OPENING);
generatedXML.writeProperty("d", "DAV", "creationdate",
formats[0].format(new Date
(resourceInfo.creationDate)));
generatedXML.writeProperty("d", "DAV", "displayname",
resourceInfo.path);
generatedXML.writeProperty("d", "DAV", "getcontentlanguage",
Locale.getDefault().toString());
generatedXML.writeProperty("d", "DAV", "getlastmodified",
resourceInfo.httpDate);
if (!resourceInfo.collection) {
generatedXML.writeProperty
("d", "DAV", "getcontentlength",
String.valueOf(resourceInfo.length));
generatedXML.writeProperty
("d", "DAV", "getcontenttype",
getServletContext().getMimeType(resourceInfo.path));
generatedXML.writeProperty("d", "DAV", "getetag",
getETagValue(resourceInfo, true));
generatedXML.writeElement("d", "DAV", "resourcetype",
XMLWriter.NO_CONTENT);
} else {
generatedXML.writeElement("d", "DAV", "resourcetype",
XMLWriter.OPENING);
generatedXML.writeElement("d", "collection",
XMLWriter.NO_CONTENT);
generatedXML.writeElement("d", "resourcetype",
XMLWriter.CLOSING);
}
generatedXML.writeProperty("d", "DAV", "source", "");
String supportedLocks = "<d:lockentry>"
+ "<d:lockscope><d:exclusive/></d:lockscope>"
+ "<d:locktype><d:write/></d:locktype>"
+ "</d:lockentry>" + "<d:lockentry>"
+ "<d:lockscope><d:shared/></d:lockscope>"
+ "<d:locktype><d:write/></d:locktype>"
+ "</d:lockentry>";
generatedXML.writeProperty("d", "DAV", "supportedlock",
supportedLocks);
generateLockDiscovery(path, generatedXML);
generatedXML.writeElement("d", "prop", XMLWriter.CLOSING);
generatedXML.writeProperty("d", "status", status);
generatedXML.writeElement("d", "propstat", XMLWriter.CLOSING);
break;
case FIND_PROPERTY_NAMES :
generatedXML.writeElement("d", "propstat", XMLWriter.OPENING);
generatedXML.writeElement("d", "prop", XMLWriter.OPENING);
generatedXML.writeElement("d", "DAV", "creationdate",
XMLWriter.NO_CONTENT);
generatedXML.writeElement("d", "DAV", "displayname",
XMLWriter.NO_CONTENT);
if (!resourceInfo.collection) {
generatedXML.writeElement("d", "DAV", "getcontentlanguage",
XMLWriter.NO_CONTENT);
generatedXML.writeElement("d", "DAV", "getcontentlength",
XMLWriter.NO_CONTENT);
generatedXML.writeElement("d", "DAV", "getcontenttype",
XMLWriter.NO_CONTENT);
generatedXML.writeElement("d", "DAV", "getetag",
XMLWriter.NO_CONTENT);
generatedXML.writeElement("d", "DAV", "getlastmodified",
XMLWriter.NO_CONTENT);
}
generatedXML.writeElement("d", "DAV", "resourcetype",
XMLWriter.NO_CONTENT);
generatedXML.writeElement("d", "DAV", "source",
XMLWriter.NO_CONTENT);
generatedXML.writeElement("d", "DAV", "lockdiscovery",
XMLWriter.NO_CONTENT);
generatedXML.writeElement("d", "prop", XMLWriter.CLOSING);
generatedXML.writeProperty("d", "status", status);
generatedXML.writeElement("d", "propstat", XMLWriter.CLOSING);
break;
case FIND_BY_PROPERTY :
Vector propertiesNotFound = new Vector();
// Parse the list of properties
generatedXML.writeElement("d", "propstat", XMLWriter.OPENING);
generatedXML.writeElement("d", "prop", XMLWriter.OPENING);
Enumeration properties = propertiesVector.elements();
while (properties.hasMoreElements()) {
String property = (String) properties.nextElement();
if (property.equals("creationdate")) {
generatedXML.writeProperty
("d", "DAV", "creationdate", formats[0].format
(new Date(resourceInfo.creationDate)));
} else if (property.equals("displayname")) {
generatedXML.writeProperty("d", "DAV", "displayname",
resourceInfo.path);
} else if (property.equals("getcontentlanguage")) {
if (resourceInfo.collection) {
propertiesNotFound.addElement(property);
} else {
generatedXML.writeProperty
("d", "DAV", "getcontentlanguage",
Locale.getDefault().toString());
}
} else if (property.equals("getcontentlength")) {
if (resourceInfo.collection) {
propertiesNotFound.addElement(property);
} else {
generatedXML.writeProperty
("d", "DAV", "getcontentlength",
(String.valueOf(resourceInfo.length)));
}
} else if (property.equals("getcontenttype")) {
if (resourceInfo.collection) {
propertiesNotFound.addElement(property);
} else {
generatedXML.writeProperty
("d", "DAV", "getcontenttype",
getServletContext().getMimeType
(resourceInfo.path));
}
} else if (property.equals("getetag")) {
if (resourceInfo.collection) {
propertiesNotFound.addElement(property);
} else {
generatedXML.writeProperty
("d", "DAV", "getetag",
getETagValue(resourceInfo, true));
}
} else if (property.equals("getlastmodified")) {
if (resourceInfo.collection) {
propertiesNotFound.addElement(property);
} else {
generatedXML.writeProperty("d", "DAV",
"getlastmodified",
resourceInfo.httpDate);
}
} else if (property.equals("resourcetype")) {
if (resourceInfo.collection) {
generatedXML.writeElement("d", "DAV", "resourcetype",
XMLWriter.OPENING);
generatedXML.writeElement("d", "collection",
XMLWriter.NO_CONTENT);
generatedXML.writeElement("d", "resourcetype",
XMLWriter.CLOSING);
} else {
generatedXML.writeElement("d", "DAV", "resourcetype",
XMLWriter.NO_CONTENT);
}
} else if (property.equals("source")) {
generatedXML.writeProperty("d", "DAV", "source", "");
} else if (property.equals("supportedlock")) {
supportedLocks = "<d:lockentry>"
+ "<d:lockscope><d:exclusive/></d:lockscope>"
+ "<d:locktype><d:write/></d:locktype>"
+ "</d:lockentry>" + "<d:lockentry>"
+ "<d:lockscope><d:shared/></d:lockscope>"
+ "<d:locktype><d:write/></d:locktype>"
+ "</d:lockentry>";
generatedXML.writeProperty("d", "DAV", "supportedlock",
supportedLocks);
} else if (property.equals("lockdiscovery")) {
generateLockDiscovery(path, generatedXML);
} else {
propertiesNotFound.addElement(property);
}
}
generatedXML.writeElement("d", "prop", XMLWriter.CLOSING);
generatedXML.writeProperty("d", "status", status);
generatedXML.writeElement("d", "propstat", XMLWriter.CLOSING);
Enumeration propertiesNotFoundList = propertiesNotFound.elements();
if (propertiesNotFoundList.hasMoreElements()) {
status = new String("HTTP/1.1 " + WebdavStatus.SC_NOT_FOUND
+ " " + WebdavStatus.getStatusText
(WebdavStatus.SC_NOT_FOUND));
generatedXML.writeElement("d", "propstat", XMLWriter.OPENING);
generatedXML.writeElement("d", "prop", XMLWriter.OPENING);
while (propertiesNotFoundList.hasMoreElements()) {
generatedXML.writeElement
(null, (String) propertiesNotFoundList.nextElement(),
XMLWriter.NO_CONTENT);
}
generatedXML.writeElement("d", "prop", XMLWriter.CLOSING);
generatedXML.writeProperty("d", "status", status);
generatedXML.writeElement("d", "propstat", XMLWriter.CLOSING);
}
break;
}
generatedXML.writeElement("d", "response", XMLWriter.CLOSING);
}
/**
* Propfind helper method. Dispays the properties of a lock-null resource.
*
* @param resources Resources object associated with this context
* @param generatedXML XML response to the Propfind request
* @param path Path of the current resource
* @param type Propfind type
* @param propertiesVector If the propfind type is find properties by
* name, then this Vector contains those properties
*/
private void parseLockNullProperties(HttpServletRequest req,
XMLWriter generatedXML,
String path, int type,
Vector propertiesVector) {
// Exclude any resource in the /WEB-INF and /META-INF subdirectories
// (the "toUpperCase()" avoids problems on Windows systems)
if (path.toUpperCase().startsWith("/WEB-INF") ||
path.toUpperCase().startsWith("/META-INF"))
return;
// Retrieving the lock associated with the lock-null resource
LockInfo lock = (LockInfo) resourceLocks.get(path);
if (lock == null)
return;
generatedXML.writeElement("d", "response", XMLWriter.OPENING);
String status = new String("HTTP/1.1 " + WebdavStatus.SC_OK + " "
+ WebdavStatus.getStatusText
(WebdavStatus.SC_OK));
// Generating href element
generatedXML.writeElement("d", "href", XMLWriter.OPENING);
String absoluteUri = req.getRequestURI();
String relativePath = getRelativePath(req);
String toAppend = path.substring(relativePath.length());
if (!toAppend.startsWith("/"))
toAppend = "/" + toAppend;
generatedXML.writeText(absoluteUri + toAppend);
generatedXML.writeElement("d", "href", XMLWriter.CLOSING);
switch (type) {
case FIND_ALL_PROP :
generatedXML.writeElement("d", "propstat", XMLWriter.OPENING);
generatedXML.writeElement("d", "prop", XMLWriter.OPENING);
generatedXML.writeProperty("d", "DAV", "creationdate",
formats[0].format(lock.creationDate));
generatedXML.writeProperty("d", "DAV", "displayname", path);
generatedXML.writeProperty("d", "DAV", "getcontentlanguage",
Locale.getDefault().toString());
generatedXML.writeProperty("d", "DAV", "getlastmodified",
formats[0].format(lock.creationDate));
generatedXML.writeProperty
("d", "DAV", "getcontentlength", String.valueOf(0));
generatedXML.writeProperty("d", "DAV", "getcontenttype", "");
generatedXML.writeProperty("d", "DAV", "getetag", "");
generatedXML.writeElement("d", "DAV", "resourcetype",
XMLWriter.OPENING);
generatedXML.writeElement("d", "lock-null", XMLWriter.NO_CONTENT);
generatedXML.writeElement("d", "resourcetype",
XMLWriter.CLOSING);
generatedXML.writeProperty("d", "DAV", "source", "");
String supportedLocks = "<d:lockentry>"
+ "<d:lockscope><d:exclusive/></d:lockscope>"
+ "<d:locktype><d:write/></d:locktype>"
+ "</d:lockentry>" + "<d:lockentry>"
+ "<d:lockscope><d:shared/></d:lockscope>"
+ "<d:locktype><d:write/></d:locktype>"
+ "</d:lockentry>";
generatedXML.writeProperty("d", "DAV", "supportedlock",
supportedLocks);
generateLockDiscovery(path, generatedXML);
generatedXML.writeElement("d", "prop", XMLWriter.CLOSING);
generatedXML.writeProperty("d", "status", status);
generatedXML.writeElement("d", "propstat", XMLWriter.CLOSING);
break;
case FIND_PROPERTY_NAMES :
generatedXML.writeElement("d", "propstat", XMLWriter.OPENING);
generatedXML.writeElement("d", "prop", XMLWriter.OPENING);
generatedXML.writeElement("d", "DAV", "creationdate",
XMLWriter.NO_CONTENT);
generatedXML.writeElement("d", "DAV", "displayname",
XMLWriter.NO_CONTENT);
generatedXML.writeElement("d", "DAV", "getcontentlanguage",
XMLWriter.NO_CONTENT);
generatedXML.writeElement("d", "DAV", "getcontentlength",
XMLWriter.NO_CONTENT);
generatedXML.writeElement("d", "DAV", "getcontenttype",
XMLWriter.NO_CONTENT);
generatedXML.writeElement("d", "DAV", "getetag",
XMLWriter.NO_CONTENT);
generatedXML.writeElement("d", "DAV", "getlastmodified",
XMLWriter.NO_CONTENT);
generatedXML.writeElement("d", "DAV", "resourcetype",
XMLWriter.NO_CONTENT);
generatedXML.writeElement("d", "DAV", "source",
XMLWriter.NO_CONTENT);
generatedXML.writeElement("d", "DAV", "lockdiscovery",
XMLWriter.NO_CONTENT);
generatedXML.writeElement("d", "prop", XMLWriter.CLOSING);
generatedXML.writeProperty("d", "status", status);
generatedXML.writeElement("d", "propstat", XMLWriter.CLOSING);
break;
case FIND_BY_PROPERTY :
Vector propertiesNotFound = new Vector();
// Parse the list of properties
generatedXML.writeElement("d", "propstat", XMLWriter.OPENING);
generatedXML.writeElement("d", "prop", XMLWriter.OPENING);
Enumeration properties = propertiesVector.elements();
while (properties.hasMoreElements()) {
String property = (String) properties.nextElement();
if (property.equals("creationdate")) {
generatedXML.writeProperty
("d", "DAV", "creationdate",
formats[0].format(lock.creationDate));
} else if (property.equals("displayname")) {
generatedXML.writeProperty("d", "DAV", "displayname", path);
} else if (property.equals("getcontentlanguage")) {
generatedXML.writeProperty
("d", "DAV", "getcontentlanguage",
Locale.getDefault().toString());
} else if (property.equals("getcontentlength")) {
generatedXML.writeProperty
("d", "DAV", "getcontentlength", (String.valueOf(0)));
} else if (property.equals("getcontenttype")) {
generatedXML.writeProperty
("d", "DAV", "getcontenttype", "");
} else if (property.equals("getetag")) {
generatedXML.writeProperty("d", "DAV", "getetag", "");
} else if (property.equals("getlastmodified")) {
generatedXML.writeProperty
("d", "DAV", "getlastmodified",
formats[0].format(lock.creationDate));
} else if (property.equals("resourcetype")) {
generatedXML.writeElement("d", "DAV", "resourcetype",
XMLWriter.OPENING);
generatedXML.writeElement("d", "lock-null",
XMLWriter.NO_CONTENT);
generatedXML.writeElement("d", "resourcetype",
XMLWriter.CLOSING);
} else if (property.equals("source")) {
generatedXML.writeProperty("d", "DAV", "source", "");
} else if (property.equals("supportedlock")) {
supportedLocks = "<d:lockentry>"
+ "<d:lockscope><d:exclusive/></d:lockscope>"
+ "<d:locktype><d:write/></d:locktype>"
+ "</d:lockentry>" + "<d:lockentry>"
+ "<d:lockscope><d:shared/></d:lockscope>"
+ "<d:locktype><d:write/></d:locktype>"
+ "</d:lockentry>";
generatedXML.writeProperty("d", "DAV", "supportedlock",
supportedLocks);
} else if (property.equals("lockdiscovery")) {
generateLockDiscovery(path, generatedXML);
} else {
propertiesNotFound.addElement(property);
}
}
generatedXML.writeElement("d", "prop", XMLWriter.CLOSING);
generatedXML.writeProperty("d", "status", status);
generatedXML.writeElement("d", "propstat", XMLWriter.CLOSING);
Enumeration propertiesNotFoundList = propertiesNotFound.elements();
if (propertiesNotFoundList.hasMoreElements()) {
status = new String("HTTP/1.1 " + WebdavStatus.SC_NOT_FOUND
+ " " + WebdavStatus.getStatusText
(WebdavStatus.SC_NOT_FOUND));
generatedXML.writeElement("d", "propstat", XMLWriter.OPENING);
generatedXML.writeElement("d", "prop", XMLWriter.OPENING);
while (propertiesNotFoundList.hasMoreElements()) {
generatedXML.writeElement
(null, (String) propertiesNotFoundList.nextElement(),
XMLWriter.NO_CONTENT);
}
generatedXML.writeElement("d", "prop", XMLWriter.CLOSING);
generatedXML.writeProperty("d", "status", status);
generatedXML.writeElement("d", "propstat", XMLWriter.CLOSING);
}
break;
}
generatedXML.writeElement("d", "response", XMLWriter.CLOSING);
}
/**
* Print the lock discovery information associated with a path.
*
* @param path Path
* @param generatedXML XML data to which the locks info will be appended
*/
private void generateLockDiscovery(String path, XMLWriter generatedXML) {
generatedXML.writeElement("d", "DAV", "lockdiscovery",
XMLWriter.OPENING);
LockInfo resourceLock = (LockInfo) resourceLocks.get(path);
if (resourceLock != null) {
resourceLock.toXML(generatedXML);
}
Enumeration collectionLocksList = collectionLocks.elements();
while (collectionLocksList.hasMoreElements()) {
LockInfo currentLock = (LockInfo) collectionLocksList.nextElement();
if (path.startsWith(currentLock.path)) {
currentLock.toXML(generatedXML);
}
}
generatedXML.writeElement("d", "DAV", "lockdiscovery",
XMLWriter.CLOSING);
}
// -------------------------------------------------- LockInfo Inner Class
/**
* Holds a lock information.
*/
private class LockInfo {
// --------------------------------------------------------- Constructor
/**
* Constructor.
*
* @param pathname Path name of the file
*/
public LockInfo() {
}
// -------------------------------------------------- Instance Variables
String path = "/";
String type = "write";
String scope = "exclusive";
int depth = 0;
String owner = "";
Vector tokens = new Vector();
long expiresAt = 0;
Date creationDate = new Date();
// ------------------------------------------------------ Public Methods
/**
* Get a String representation of this lock token.
*/
public String toString() {
String result = "Type:" + type + "\n";
result += "Scope:" + scope + "\n";
result += "Depth:" + depth + "\n";
result += "Owner:" + owner + "\n";
result += "Expiration:" +
formats[0].format(new Date(expiresAt)) + "\n";
Enumeration tokensList = tokens.elements();
while (tokensList.hasMoreElements()) {
result += "Token:" + tokensList.nextElement() + "\n";
}
return result;
}
/**
* Return true if the lock has expired.
*/
public boolean hasExpired() {
return (System.currentTimeMillis() > expiresAt);
}
/**
* Return true if the lock is exclusive.
*/
public boolean isExclusive() {
return (scope.equals("exclusive"));
}
/**
* Get an XML representation of this lock token. This method will
* append an XML fragment to the given XML writer.
*/
public void toXML(XMLWriter generatedXML) {
toXML(generatedXML, false);
}
/**
* Get an XML representation of this lock token. This method will
* append an XML fragment to the given XML writer.
*/
public void toXML(XMLWriter generatedXML, boolean showToken) {
generatedXML.writeElement("d", "DAV", "activelock",
XMLWriter.OPENING);
generatedXML.writeElement("d", "DAV", "locktype",
XMLWriter.OPENING);
generatedXML.writeElement("d", "DAV", type, XMLWriter.NO_CONTENT);
generatedXML.writeElement("d", "DAV", "locktype",
XMLWriter.CLOSING);
generatedXML.writeElement("d", "DAV", "lockscope",
XMLWriter.OPENING);
generatedXML.writeElement("d", "DAV", scope, XMLWriter.NO_CONTENT);
generatedXML.writeElement("d", "DAV", "lockscope",
XMLWriter.CLOSING);
generatedXML.writeElement("d", "DAV", "depth", XMLWriter.OPENING);
if (depth == INFINITY) {
generatedXML.writeText("Infinity");
} else {
generatedXML.writeText("0");
}
generatedXML.writeElement("d", "DAV", "depth", XMLWriter.CLOSING);
generatedXML.writeElement("d", "DAV", "owner", XMLWriter.OPENING);
generatedXML.writeText(owner);
generatedXML.writeElement("d", "DAV", "owner", XMLWriter.CLOSING);
generatedXML.writeElement("d", "DAV", "timeout", XMLWriter.OPENING);
long timeout = (expiresAt - System.currentTimeMillis()) / 1000;
generatedXML.writeText("Second-" + timeout);
generatedXML.writeElement("d", "DAV", "timeout", XMLWriter.CLOSING);
generatedXML.writeElement("d", "DAV", "locktoken",
XMLWriter.OPENING);
if (showToken) {
Enumeration tokensList = tokens.elements();
while (tokensList.hasMoreElements()) {
generatedXML.writeElement("d", "DAV", "href",
XMLWriter.OPENING);
generatedXML.writeText("opaquelocktoken:"
+ tokensList.nextElement());
generatedXML.writeElement("d", "DAV", "href",
XMLWriter.CLOSING);
}
} else {
generatedXML.writeElement("d", "DAV", "href",
XMLWriter.OPENING);
generatedXML.writeText("opaquelocktoken:dummytoken");
generatedXML.writeElement("d", "DAV", "href",
XMLWriter.CLOSING);
}
generatedXML.writeElement("d", "DAV", "locktoken",
XMLWriter.CLOSING);
generatedXML.writeElement("d", "DAV", "activelock",
XMLWriter.CLOSING);
}
}
// --------------------------------------------------- Property Inner Class
private class Property {
public String name;
public String value;
public String namespace;
public String namespaceAbbrev;
public int status = WebdavStatus.SC_OK;
}
};
// -------------------------------------------------------- WebdavStatus Class
/**
* Wraps the HttpServletResponse class to abstract the
* specific protocol used. To support other protocols
* we would only need to modify this class and the
* WebDavRetCode classes.
*
* @author Marc Eaddy
* @version 1.0, 16 Nov 1997
*/
class WebdavStatus {
// ----------------------------------------------------- Instance Variables
/**
* This Hashtable contains the mapping of HTTP and WebDAV
* status codes to descriptive text. This is a static
* variable.
*/
private static Hashtable mapStatusCodes = new Hashtable();
// ------------------------------------------------------ HTTP Status Codes
/**
* Status code (200) indicating the request succeeded normally.
*/
public static final int SC_OK = HttpServletResponse.SC_OK;
/**
* Status code (201) indicating the request succeeded and created
* a new resource on the server.
*/
public static final int SC_CREATED = HttpServletResponse.SC_CREATED;
/**
* Status code (202) indicating that a request was accepted for
* processing, but was not completed.
*/
public static final int SC_ACCEPTED = HttpServletResponse.SC_ACCEPTED;
/**
* Status code (204) indicating that the request succeeded but that
* there was no new information to return.
*/
public static final int SC_NO_CONTENT = HttpServletResponse.SC_NO_CONTENT;
/**
* Status code (301) indicating that the resource has permanently
* moved to a new location, and that future references should use a
* new URI with their requests.
*/
public static final int SC_MOVED_PERMANENTLY =
HttpServletResponse.SC_MOVED_PERMANENTLY;
/**
* Status code (302) indicating that the resource has temporarily
* moved to another location, but that future references should
* still use the original URI to access the resource.
*/
public static final int SC_MOVED_TEMPORARILY =
HttpServletResponse.SC_MOVED_TEMPORARILY;
/**
* Status code (304) indicating that a conditional GET operation
* found that the resource was available and not modified.
*/
public static final int SC_NOT_MODIFIED =
HttpServletResponse.SC_NOT_MODIFIED;
/**
* Status code (400) indicating the request sent by the client was
* syntactically incorrect.
*/
public static final int SC_BAD_REQUEST =
HttpServletResponse.SC_BAD_REQUEST;
/**
* Status code (401) indicating that the request requires HTTP
* authentication.
*/
public static final int SC_UNAUTHORIZED =
HttpServletResponse.SC_UNAUTHORIZED;
/**
* Status code (403) indicating the server understood the request
* but refused to fulfill it.
*/
public static final int SC_FORBIDDEN = HttpServletResponse.SC_FORBIDDEN;
/**
* Status code (404) indicating that the requested resource is not
* available.
*/
public static final int SC_NOT_FOUND = HttpServletResponse.SC_NOT_FOUND;
/**
* Status code (500) indicating an error inside the HTTP service
* which prevented it from fulfilling the request.
*/
public static final int SC_INTERNAL_SERVER_ERROR =
HttpServletResponse.SC_INTERNAL_SERVER_ERROR;
/**
* Status code (501) indicating the HTTP service does not support
* the functionality needed to fulfill the request.
*/
public static final int SC_NOT_IMPLEMENTED =
HttpServletResponse.SC_NOT_IMPLEMENTED;
/**
* Status code (502) indicating that the HTTP server received an
* invalid response from a server it consulted when acting as a
* proxy or gateway.
*/
public static final int SC_BAD_GATEWAY =
HttpServletResponse.SC_BAD_GATEWAY;
/**
* Status code (503) indicating that the HTTP service is
* temporarily overloaded, and unable to handle the request.
*/
public static final int SC_SERVICE_UNAVAILABLE =
HttpServletResponse.SC_SERVICE_UNAVAILABLE;
/**
* Status code (100) indicating the client may continue with
* its request. This interim response is used to inform the
* client that the initial part of the request has been
* received and has not yet been rejected by the server.
*/
public static final int SC_CONTINUE = 100;
/**
* Status code (405) indicating the method specified is not
* allowed for the resource.
*/
public static final int SC_METHOD_NOT_ALLOWED = 405;
/**
* Status code (409) indicating that the request could not be
* completed due to a conflict with the current state of the
* resource.
*/
public static final int SC_CONFLICT = 409;
/**
* Status code (412) indicating the precondition given in one
* or more of the request-header fields evaluated to false
* when it was tested on the server.
*/
public static final int SC_PRECONDITION_FAILED = 412;
/**
* Status code (413) indicating the server is refusing to
* process a request because the request entity is larger
* than the server is willing or able to process.
*/
public static final int SC_REQUEST_TOO_LONG = 413;
/**
* Status code (415) indicating the server is refusing to service
* the request because the entity of the request is in a format
* not supported by the requested resource for the requested
* method.
*/
public static final int SC_UNSUPPORTED_MEDIA_TYPE = 415;
// -------------------------------------------- Extended WebDav status code
/**
* Status code (207) indicating that the response requires
* providing status for multiple independent operations.
*/
public static final int SC_MULTI_STATUS = 207;
// This one colides with HTTP 1.1
// "207 Parital Update OK"
/**
* Status code (418) indicating the entity body submitted with
* the PATCH method was not understood by the resource.
*/
public static final int SC_UNPROCESSABLE_ENTITY = 418;
// This one colides with HTTP 1.1
// "418 Reauthentication Required"
/**
* Status code (419) indicating that the resource does not have
* sufficient space to record the state of the resource after the
* execution of this method.
*/
public static final int SC_INSUFFICIENT_SPACE_ON_RESOURCE = 419;
// This one colides with HTTP 1.1
// "419 Proxy Reauthentication Required"
/**
* Status code (420) indicating the method was not executed on
* a particular resource within its scope because some part of
* the method's execution failed causing the entire method to be
* aborted.
*/
public static final int SC_METHOD_FAILURE = 420;
/**
* Status code (423) indicating the destination resource of a
* method is locked, and either the request did not contain a
* valid Lock-Info header, or the Lock-Info header identifies
* a lock held by another principal.
*/
public static final int SC_LOCKED = 423;
// ------------------------------------------------------------ Initializer
static {
// HTTP 1.0 tatus Code
addStatusCodeMap(SC_OK, "OK");
addStatusCodeMap(SC_CREATED, "Created");
addStatusCodeMap(SC_ACCEPTED, "Accepted");
addStatusCodeMap(SC_NO_CONTENT, "No Content");
addStatusCodeMap(SC_MOVED_PERMANENTLY, "Moved Permanently");
addStatusCodeMap(SC_MOVED_TEMPORARILY, "Moved Temporarily");
addStatusCodeMap(SC_NOT_MODIFIED, "Not Modified");
addStatusCodeMap(SC_BAD_REQUEST, "Bad Request");
addStatusCodeMap(SC_UNAUTHORIZED, "Unauthorized");
addStatusCodeMap(SC_FORBIDDEN, "Forbidden");
addStatusCodeMap(SC_NOT_FOUND, "Not Found");
addStatusCodeMap(SC_INTERNAL_SERVER_ERROR, "Internal Server Error");
addStatusCodeMap(SC_NOT_IMPLEMENTED, "Not Implemented");
addStatusCodeMap(SC_BAD_GATEWAY, "Bad Gateway");
addStatusCodeMap(SC_SERVICE_UNAVAILABLE, "Service Unavailable");
addStatusCodeMap(SC_CONTINUE, "Continue");
addStatusCodeMap(SC_METHOD_NOT_ALLOWED, "Method Not Allowed");
addStatusCodeMap(SC_CONFLICT, "Conflict");
addStatusCodeMap(SC_PRECONDITION_FAILED, "Precondition Failed");
addStatusCodeMap(SC_REQUEST_TOO_LONG, "Request Too Long");
addStatusCodeMap(SC_UNSUPPORTED_MEDIA_TYPE, "Unsupported Media Type");
// WebDav Status Codes
addStatusCodeMap(SC_MULTI_STATUS, "Multi-Status");
addStatusCodeMap(SC_UNPROCESSABLE_ENTITY, "Unprocessable Entity");
addStatusCodeMap(SC_INSUFFICIENT_SPACE_ON_RESOURCE,
"Insufficient Space On Resource");
addStatusCodeMap(SC_METHOD_FAILURE, "Method Failure");
addStatusCodeMap(SC_LOCKED, "Locked");
}
// --------------------------------------------------------- Public Methods
/**
* Returns the HTTP status text for the HTTP or WebDav status code
* specified by looking it up in the static mapping. This is a
* static function.
*
* @param nHttpStatusCode [IN] HTTP or WebDAV status code
* @return A string with a short descriptive phrase for the
* HTTP status code (e.g., "OK").
*/
public static String getStatusText(int nHttpStatusCode) {
Integer intKey = new Integer(nHttpStatusCode);
if (!mapStatusCodes.containsKey(intKey)) {
return "";
} else {
return (String) mapStatusCodes.get(intKey);
}
}
// -------------------------------------------------------- Private Methods
/**
* Adds a new status code -> status text mapping. This is a static
* method because the mapping is a static variable.
*
* @param nKey [IN] HTTP or WebDAV status code
* @param strVal [IN] HTTP status text
*/
private static void addStatusCodeMap(int nKey, String strVal) {
mapStatusCodes.put(new Integer(nKey), strVal);
}
};
1.1 jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/servlets/package.html
Index: package.html
===================================================================
<body>
<p>This package contains <code>Servlets</code> that implement some of the
standard functionality provided by the Catalina servlet container. Because
these servlets are in the <code>org.apache.catalina</code> package hierarchy,
they are in the privileged position of being able to reference internal server
data structures, which application level servlets are prevented from
accessing (by the application class loader implementation).</p>
<p>To the extent that these servlets depend upon internal Catalina data
structures, they are obviously not portable to other servlet container
environments. However, they can be used as models for creating application
level servlets that provide similar capabilities -- most obviously the
<a href="DefaultServlet.html">DefaultServlet</a> implementation, which
serves static resources when Catalina runs stand-alone.</p>
</body>