0001: // DAVFrame.java
0002: // $Id: DAVFrame.java,v 1.39 2007/02/09 22:45:42 ylafon Exp $
0003: // (c) COPYRIGHT MIT, INRIA and Keio, 2000.
0004: // Please first read the full copyright statement in file COPYRIGHT.html
0005: package org.w3c.jigsaw.webdav;
0006:
0007: import java.io.ByteArrayInputStream;
0008: import java.io.ByteArrayOutputStream;
0009: import java.io.FileInputStream;
0010: import java.io.InputStream;
0011: import java.io.IOException;
0012:
0013: import java.net.MalformedURLException;
0014: import java.net.URL;
0015:
0016: import java.util.Date;
0017: import java.util.Enumeration;
0018: import java.util.Hashtable;
0019: import java.util.ListIterator;
0020: import java.util.LinkedList;
0021: import java.util.Vector;
0022:
0023: import org.xml.sax.SAXException;
0024:
0025: import org.apache.xml.serialize.OutputFormat;
0026: import org.apache.xml.serialize.XMLSerializer;
0027:
0028: import org.w3c.dom.Document;
0029: import org.w3c.dom.DOMException;
0030: import org.w3c.dom.Element;
0031: import org.w3c.dom.Node;
0032:
0033: import org.w3c.jigsaw.auth.AuthFilter;
0034:
0035: import org.w3c.jigsaw.frames.PostableFrame;
0036:
0037: import org.w3c.jigsaw.http.HTTPException;
0038: import org.w3c.jigsaw.http.Reply;
0039: import org.w3c.jigsaw.http.Request;
0040:
0041: import org.w3c.www.http.ContentLengthInputStream;
0042:
0043: import org.w3c.tools.codec.Base64Decoder;
0044: import org.w3c.tools.codec.Base64Encoder;
0045: import org.w3c.tools.codec.Base64FormatException;
0046:
0047: import org.w3c.tools.resources.Attribute;
0048: import org.w3c.tools.resources.AttributeRegistry;
0049: import org.w3c.tools.resources.ContainerResource;
0050: import org.w3c.tools.resources.DateAttribute;
0051: import org.w3c.tools.resources.DirectoryResource;
0052: import org.w3c.tools.resources.FramedResource;
0053: import org.w3c.tools.resources.IntegerAttribute;
0054: import org.w3c.tools.resources.InvalidResourceException;
0055: import org.w3c.tools.resources.LookupResult;
0056: import org.w3c.tools.resources.LookupState;
0057: import org.w3c.tools.resources.ProtocolException;
0058: import org.w3c.tools.resources.PropertiesAttribute;
0059: import org.w3c.tools.resources.RequestInterface;
0060: import org.w3c.tools.resources.ReplyInterface;
0061: import org.w3c.tools.resources.Resource;
0062: import org.w3c.tools.resources.ResourceException;
0063: import org.w3c.tools.resources.ResourceFrame;
0064: import org.w3c.tools.resources.ResourceReference;
0065: import org.w3c.tools.resources.ServerInterface;
0066: import org.w3c.tools.resources.StringAttribute;
0067:
0068: import org.w3c.util.ArrayDictionary;
0069: import org.w3c.util.DateParser;
0070: import org.w3c.util.InvalidDateException;
0071: import org.w3c.util.ObservableProperties;
0072: import org.w3c.util.URLUtils;
0073:
0074: import org.w3c.www.http.HeaderDescription;
0075: import org.w3c.www.http.HeaderValue;
0076: import org.w3c.www.http.HTTP;
0077: import org.w3c.www.http.HttpDate;
0078: import org.w3c.www.http.HttpEntityTag;
0079: import org.w3c.www.http.HttpFactory;
0080: import org.w3c.www.http.HttpInvalidValueException;
0081: import org.w3c.www.http.HttpMimeType;
0082: import org.w3c.www.http.HttpMessage;
0083: import org.w3c.www.http.HttpReplyMessage;
0084: import org.w3c.www.http.HttpRequestMessage;
0085: import org.w3c.www.http.HttpTokenList;
0086:
0087: import org.w3c.www.mime.MimeType;
0088: import org.w3c.www.mime.MimeTypeFormatException;
0089:
0090: import org.w3c.www.webdav.WEBDAV;
0091: import org.w3c.www.webdav.DAVEntityTag;
0092: import org.w3c.www.webdav.DAVIf;
0093: import org.w3c.www.webdav.DAVParser;
0094: import org.w3c.www.webdav.DAVStateToken;
0095:
0096: import org.w3c.www.webdav.xml.DAVBody;
0097: import org.w3c.www.webdav.xml.DAVFactory;
0098: import org.w3c.www.webdav.xml.DAVLockInfo;
0099: import org.w3c.www.webdav.xml.DAVMultiStatus;
0100: import org.w3c.www.webdav.xml.DAVNode;
0101: import org.w3c.www.webdav.xml.DAVPropAction;
0102: import org.w3c.www.webdav.xml.DAVPropertyBehavior;
0103: import org.w3c.www.webdav.xml.DAVPropFind;
0104: import org.w3c.www.webdav.xml.DAVPropStat;
0105: import org.w3c.www.webdav.xml.DAVProperties;
0106: import org.w3c.www.webdav.xml.DAVPropertyUpdate;
0107: import org.w3c.www.webdav.xml.DAVResponse;
0108:
0109: /**
0110: * @version $Revision: 1.39 $
0111: * @author Benoît Mahé (bmahe@w3.org)
0112: */
0113: public class DAVFrame extends PostableFrame {
0114:
0115: public static final boolean debug = false;
0116:
0117: public static final boolean debugxml = false;
0118:
0119: /**
0120: * Condition check return code - Condition existed and succeeded.
0121: * And lock has been checked
0122: */
0123: public static final int COND_OK_LOCK = 3;
0124:
0125: /**
0126: * Cached mime type
0127: */
0128: protected static HttpMimeType xmlcontenttype = null;
0129: protected static HttpMimeType collectioncontenttype = null;
0130:
0131: protected static boolean isReadOnly(String propname) {
0132: return (propname.equals(DAVNode.CREATIONDATE_NODE)
0133: || propname.equals(DAVNode.GETCONTENTLENGTH_NODE)
0134: || propname.equals(DAVNode.GETETAG_NODE) || propname
0135: .equals(DAVNode.GETLASTMODIFIED_NODE));
0136: }
0137:
0138: protected static boolean acceptRedirect(DAVRequest request) {
0139: String method = request.getMethod();
0140: return !(method.equals("PROPPATCH")
0141: || method.equals("PROPFIND") || method.equals("COPY")
0142: || method.equals("MOVE") || method.equals("DELETE")
0143: || method.equals("LOCK") || method.equals("UNLOCK"));
0144: }
0145:
0146: /**
0147: * The DAVManager we use.
0148: */
0149: protected org.w3c.www.protocol.webdav.DAVManager manager = null;
0150:
0151: /**
0152: * Name ot the state to hold the remaining path (used with MKCOL)
0153: */
0154: public final static String REMAINING_PATH = "org.w3c.jigsaw.webdav.rpath";
0155:
0156: public final static String LOCK_USERNAME = "org.w3c.jigsaw.webdav.user";
0157: public final static String LOCK_TOKEN = "org.w3c.jigsaw.webdav.token";
0158: public final static String LOCK_OWNER = "org.w3c.jigsaw.webdav.owner";
0159: public final static String LOCK_EXPIRE = "org.w3c.jigsaw.webdav.expire";
0160: public final static String LOCK_TIMEOUT = "org.w3c.jigsaw.webdav.timeout";
0161:
0162: public final static String LOCKED_REREFENCE = "org.w3c.jigsaw.webdav.reference";
0163:
0164: public final static Long DEFAULT_LOCK_TIMEOUT = new Long(
0165: 24 * 60 * 60 * 1000); // 1 day
0166:
0167: public final static Long MAX_LOCK_TIMEOUT = new Long(7 * 24 * 60
0168: * 60 * 1000); // 1 week
0169:
0170: /**
0171: * Attribute index - The index for the creation date attribute.
0172: */
0173: protected static int ATTR_CREATION_DATE = -1;
0174:
0175: /**
0176: * Attribute index - The index for the dead properties
0177: */
0178: protected static int ATTR_DEAD_PROPERTIES = -1;
0179:
0180: /**
0181: * Attribute index - The index for the lock token
0182: */
0183: protected static int ATTR_LOCK_TOKEN = -1;
0184:
0185: /**
0186: * Attribute index - The index for the lock token
0187: */
0188: protected static int ATTR_LOCK_TIMEOUT = -1;
0189:
0190: /**
0191: * Attribute index - The index for the lock date
0192: */
0193: protected static int ATTR_LOCK_DATE = -1;
0194:
0195: /**
0196: * Attribute index - The index for the lock depth
0197: */
0198: protected static int ATTR_LOCK_DEPTH = -1;
0199:
0200: /**
0201: * Attribute index - The index for the lock owner
0202: */
0203: protected static int ATTR_LOCK_OWNER = -1;
0204:
0205: /**
0206: * Attribute index - The index for the lock username
0207: */
0208: protected static int ATTR_LOCK_USERNAME = -1;
0209:
0210: static {
0211: Class cls = null;
0212: // Get a pointer to our own class:
0213: try {
0214: cls = Class.forName("org.w3c.jigsaw.webdav.DAVFrame");
0215: } catch (Exception ex) {
0216: ex.printStackTrace();
0217: System.exit(1);
0218: }
0219: // Our creation date
0220: Attribute a = new DateAttribute("creation-date", null,
0221: Attribute.COMPUTED);
0222: ATTR_CREATION_DATE = AttributeRegistry
0223: .registerAttribute(cls, a);
0224: // Our creation date
0225: a = new PropertiesAttribute("dead-properties", null,
0226: Attribute.COMPUTED);
0227: ATTR_DEAD_PROPERTIES = AttributeRegistry.registerAttribute(cls,
0228: a);
0229: // Our lock token (if any)
0230: a = new StringAttribute("lock-token", null, Attribute.COMPUTED);
0231: ATTR_LOCK_TOKEN = AttributeRegistry.registerAttribute(cls, a);
0232: // Our timeout token (if any)
0233: a = new DateAttribute("lock-timeout", null, Attribute.COMPUTED);
0234: ATTR_LOCK_TIMEOUT = AttributeRegistry.registerAttribute(cls, a);
0235: // Our lock token date
0236: a = new DateAttribute("lock-date", null, Attribute.COMPUTED);
0237: ATTR_LOCK_DATE = AttributeRegistry.registerAttribute(cls, a);
0238: // Our expire token (if any)
0239: a = new IntegerAttribute("lock-depth", null, Attribute.COMPUTED);
0240: ATTR_LOCK_DEPTH = AttributeRegistry.registerAttribute(cls, a);
0241: // Our lock owner
0242: a = new StringAttribute("lock-owner", null, Attribute.COMPUTED);
0243: ATTR_LOCK_OWNER = AttributeRegistry.registerAttribute(cls, a);
0244: // Our lock owner
0245: a = new StringAttribute("lock-username", null,
0246: Attribute.COMPUTED);
0247: ATTR_LOCK_USERNAME = AttributeRegistry
0248: .registerAttribute(cls, a);
0249:
0250: // xml content type
0251: try {
0252: MimeType type = new MimeType("text/xml");
0253: type.addParameter("charset", WEBDAV.ENCODING);
0254: xmlcontenttype = HttpFactory.makeMimeType(type);
0255: type = new MimeType("httpd/unix-directory");
0256: type.addParameter("charset", WEBDAV.ENCODING);
0257: collectioncontenttype = HttpFactory.makeMimeType(type);
0258: } catch (MimeTypeFormatException ex) {
0259: ex.printStackTrace();
0260: System.exit(1);
0261: }
0262: }
0263:
0264: public boolean isCollection() {
0265: return (dresource != null);
0266: }
0267:
0268: /**
0269: * Get this resource creation date
0270: * @return A long giving the creation date or -1 if undefined.
0271: */
0272: public long getCreationDate() {
0273: return getLong(ATTR_CREATION_DATE, (long) -1);
0274: }
0275:
0276: protected void updateLockDate(DAVRequest request) {
0277: if (checkLockOwner(request)) {
0278: if (debug) {
0279: System.out.println(">>> update lock date");
0280: }
0281: setValue(ATTR_LOCK_DATE, new Long(System
0282: .currentTimeMillis()));
0283: }
0284: }
0285:
0286: /**
0287: * Get the lock token expiration date
0288: * @return A long giving the expiration date or -1 if undefined.
0289: */
0290: protected long getTokenExpirationDate(DAVRequest request) {
0291: long timeout = getLong(ATTR_LOCK_TIMEOUT, (long) -1);
0292: long lockdate = getLong(ATTR_LOCK_DATE, (long) -1);
0293: if ((lockdate != -1) && (timeout != -1)) {
0294: return lockdate + timeout;
0295: } else if (request != null) {
0296: Long expire = (Long) request.getState(LOCK_EXPIRE);
0297: if (expire != null) {
0298: return expire.longValue();
0299: }
0300: }
0301: return -1;
0302: }
0303:
0304: /**
0305: * Get the lock token
0306: * @return A String instance or null
0307: */
0308: protected String getCurrentLockToken(DAVRequest request) {
0309: String token = getString(ATTR_LOCK_TOKEN, null);
0310: if ((token == null) && (request != null)) {
0311: token = (String) request.getState(LOCK_TOKEN);
0312: }
0313: return token;
0314: }
0315:
0316: protected long getCurrentLockTimeout(DAVRequest request) {
0317: long timeout = getLong(ATTR_LOCK_TIMEOUT, (long) -1);
0318: if (timeout == -1) {
0319: Long l = (Long) request.getState(LOCK_TIMEOUT);
0320: if (l != null) {
0321: return l.longValue();
0322: } else {
0323: return DEFAULT_LOCK_TIMEOUT.longValue();
0324: }
0325: } else {
0326: return timeout;
0327: }
0328: }
0329:
0330: protected Node ownerNode = null;
0331:
0332: /**
0333: * Get the lock owner
0334: * @return A String instance or null
0335: */
0336: protected Node getCurrentLockOwner(DAVRequest request) {
0337: if (ownerNode == null) {
0338: String owner = getString(ATTR_LOCK_OWNER, null);
0339: if (owner != null) {
0340: Base64Decoder decoder = new Base64Decoder(owner);
0341: try {
0342: String decoded = decoder.processString();
0343: ByteArrayInputStream in = new ByteArrayInputStream(
0344: decoded.getBytes());
0345: Document doc = DAVBody.getDocument(in, null);
0346: ownerNode = doc.getDocumentElement();
0347: } catch (Exception ex) {
0348: ex.printStackTrace();
0349: }
0350: } else if ((owner == null) && (request != null)) {
0351: return (Node) request.getState(LOCK_OWNER);
0352: }
0353: }
0354: return ownerNode;
0355: }
0356:
0357: /**
0358: * Set the lock Owner
0359: */
0360: protected void setLockOwner(Node owner) {
0361: ownerNode = owner;
0362: saveLockOwner();
0363: }
0364:
0365: private synchronized void saveLockOwner() {
0366: if (ownerNode != null) {
0367: Document doc = DAVBody.createDocument(DAVNode.OWNER_NODE);
0368: DAVNode.exportChildren(doc, doc.getDocumentElement(),
0369: ownerNode, true);
0370: ByteArrayOutputStream out = new ByteArrayOutputStream();
0371: OutputFormat format = new OutputFormat(doc,
0372: WEBDAV.ENCODING, true);
0373: format.setOmitXMLDeclaration(false);
0374: format.setPreserveSpace(true);
0375: XMLSerializer serializer = new XMLSerializer(out, format);
0376: try {
0377: serializer.serialize(doc);
0378: if (debug)
0379: System.out.println("["
0380: + out.toString(WEBDAV.ENCODING) + "]");
0381: Base64Encoder encoder = new Base64Encoder(out
0382: .toString(WEBDAV.ENCODING));
0383: setValue(ATTR_LOCK_OWNER, encoder.processString());
0384: } catch (IOException ex) {
0385: ex.printStackTrace();
0386: }
0387: }
0388: }
0389:
0390: /**
0391: * Get the lock depth
0392: * @return An int (WEBDAV.DEPTH_0 or WEBDAV.DEPTH_INFINITY)
0393: */
0394: protected int getCurrentLockDepth() {
0395: return getInt(ATTR_LOCK_DEPTH, WEBDAV.DEPTH_INFINITY);
0396: }
0397:
0398: /**
0399: * Get the username of the client that lock the resource
0400: */
0401: protected String getCurrentLockUsername(DAVRequest request) {
0402: String username = (String) getValue(ATTR_LOCK_USERNAME, null);
0403: if ((username == null) && (request != null)) {
0404: username = (String) request.getState(LOCK_USERNAME);
0405: }
0406: return username;
0407: }
0408:
0409: private boolean hasLock() {
0410: return definesAttribute(ATTR_LOCK_TOKEN);
0411: }
0412:
0413: /**
0414: * Check if this resource or one of their parent (with depth equals
0415: * to infinity) has been locked
0416: * @param request the incomming request (it null isLocked will returns
0417: * true if and only if the resource has been personally locked, not one
0418: * of its parents)
0419: * @return a boolean
0420: */
0421: protected boolean isLocked(DAVRequest request) {
0422: if (hasLock()) {
0423: if (debug) {
0424: System.out.println(">>> Checking timeout...");
0425: System.out.println(System.currentTimeMillis() + " > ");
0426: System.out.println(getTokenExpirationDate(null));
0427: }
0428: if (System.currentTimeMillis() > getTokenExpirationDate(null)) {
0429: // timeout reached, remove the lock
0430: unlock();
0431: return false;
0432: }
0433: return true;
0434: } else {
0435: return ((request != null) && (request.hasState(LOCK_TOKEN)));
0436: }
0437: }
0438:
0439: protected void setTimeout(String timeouts[]) {
0440: setValue(ATTR_LOCK_DATE, new Long(System.currentTimeMillis()));
0441: setValue(ATTR_LOCK_TIMEOUT, DEFAULT_LOCK_TIMEOUT); // default
0442: if (timeouts != null) {
0443: int len = timeouts.length;
0444: for (int i = 0; i < len; i++) {
0445: if (timeouts[i].startsWith("Second-")) {
0446: String sec = timeouts[i].substring(7);
0447: long timeout = Long.parseLong(sec) * 1000; // in ms
0448: if (timeout > MAX_LOCK_TIMEOUT.longValue()) {
0449: setValue(ATTR_LOCK_TIMEOUT, MAX_LOCK_TIMEOUT);
0450: } else if (timeout > 0) {
0451: setValue(ATTR_LOCK_TIMEOUT, new Long(timeout));
0452: } else {
0453: setValue(ATTR_LOCK_TIMEOUT,
0454: DEFAULT_LOCK_TIMEOUT);
0455: }
0456: break;
0457: }
0458: }
0459: }
0460:
0461: }
0462:
0463: protected synchronized void refreshLock(String timeouts[]) {
0464: setTimeout(timeouts);
0465: }
0466:
0467: /**
0468: * lock this resource
0469: * @param token the lock token
0470: * @param depth the lock depth (0 or -1)
0471: * @param timeout the lock timeout
0472: */
0473: protected synchronized void lock(String token, int depth,
0474: String timeouts[], String username, Node owner)
0475: throws HTTPException {
0476: setValue(ATTR_LOCK_TOKEN, token);
0477: if (username != null) {
0478: setValue(ATTR_LOCK_USERNAME, username);
0479: } else if (debug) {
0480: System.out.println("************************************");
0481: System.out.println("WARNING NULL USER");
0482: System.out.println("************************************");
0483: }
0484: setValue(ATTR_LOCK_DEPTH, new Integer(depth));
0485: setLockOwner(owner);
0486: setTimeout(timeouts);
0487: }
0488:
0489: protected void unlock() {
0490: setValue(ATTR_LOCK_TOKEN, null);
0491: setValue(ATTR_LOCK_DEPTH, null);
0492: setValue(ATTR_LOCK_TIMEOUT, null);
0493: setValue(ATTR_LOCK_DATE, null);
0494: setValue(ATTR_LOCK_OWNER, null);
0495: setValue(ATTR_LOCK_USERNAME, null);
0496: }
0497:
0498: protected void addSupportedLock(DAVProperties prop) {
0499: // <supportedlock>
0500: Element sl = prop.addDAVNode(DAVNode.SUPPORTEDLOCK_NODE, null);
0501: // <lockentry>
0502: Element le = DAVNode.addDAVNode(sl, DAVNode.LOCKENTRY_NODE,
0503: null);
0504: // <lockscope><exclusive></lockscope>
0505: Element ls = DAVNode.addDAVNode(le, DAVNode.LOCKSCOPE_NODE,
0506: null);
0507: DAVNode.addDAVNode(ls, DAVNode.EXCLUSIVE_NODE, null);
0508: // <locktype><write></locktype>
0509: Element lt = DAVNode
0510: .addDAVNode(le, DAVNode.LOCKTYPE_NODE, null);
0511: DAVNode.addDAVNode(lt, DAVNode.WRITE_NODE, null);
0512: }
0513:
0514: protected void addLockDiscovery(DAVRequest request,
0515: DAVProperties prop) {
0516: addLockDiscovery(request, prop.getNode());
0517: }
0518:
0519: protected void addLockDiscovery(DAVRequest request, Node parent) {
0520: if (isLocked(request)) {
0521: Element ld = DAVNode.addDAVNode(parent,
0522: DAVNode.LOCKDISCOVERY_NODE, null);
0523: Element al = DAVNode.addDAVNode(ld,
0524: DAVNode.ACTIVELOCK_NODE, null);
0525: // locktype
0526: Element lt = DAVNode.addDAVNode(al, DAVNode.LOCKTYPE_NODE,
0527: null);
0528: DAVNode.addDAVNode(lt, DAVNode.WRITE_NODE, null);
0529: // lockscope
0530: Element ls = DAVNode.addDAVNode(al, DAVNode.LOCKSCOPE_NODE,
0531: null);
0532: DAVNode.addDAVNode(ls, DAVNode.EXCLUSIVE_NODE, null);
0533: // depth
0534: String depth = request.depthToString(getCurrentLockDepth());
0535: DAVNode.addDAVNode(al, DAVNode.DEPTH_NODE, depth);
0536: // owner
0537: Node owner = getCurrentLockOwner(request);
0538: if (owner != null) {
0539: DAVNode.importNode(parent.getOwnerDocument(), al,
0540: owner, true);
0541: }
0542: // timeout
0543: String timeout = "Second-"
0544: + (getCurrentLockTimeout(request) / 1000);
0545: DAVNode.addDAVNode(al, DAVNode.TIMEOUT_NODE, timeout);
0546: // lock token
0547: Element ltk = DAVNode.addDAVNode(al,
0548: DAVNode.LOCKTOKEN_NODE, null);
0549: DAVNode.addDAVNode(ltk, DAVNode.HREF_NODE,
0550: getCurrentLockToken(request));
0551: }
0552: }
0553:
0554: /**
0555: * Get the dead properties
0556: * @return a ArrayDictionary instance
0557: * @see org.w3c.util.ArrayDictionary
0558: */
0559: public ArrayDictionary getDeadProperties() {
0560: return (ArrayDictionary) getValue(ATTR_DEAD_PROPERTIES, null);
0561: }
0562:
0563: protected Hashtable deadindex = null; // <namespace, document>
0564:
0565: protected boolean deadpropmodified = false;
0566:
0567: protected synchronized Hashtable getDeadPropertiesIndex() {
0568: if (deadindex == null) {
0569: ArrayDictionary dic = getDeadProperties();
0570: if (dic == null) {
0571: return new Hashtable();
0572: }
0573: Enumeration denum = dic.keys();
0574: deadindex = new Hashtable(dic.size());
0575: while (denum.hasMoreElements()) {
0576: String key = (String) denum.nextElement();
0577: Base64Decoder decoder = new Base64Decoder((String) dic
0578: .get(key));
0579: try {
0580: String decoded = decoder.processString();
0581: ByteArrayInputStream in = new ByteArrayInputStream(
0582: decoded.getBytes());
0583: Document doc = DAVBody.getDocument(in, null);
0584: deadindex.put(key, doc);
0585: } catch (Base64FormatException ex) {
0586: ex.printStackTrace();
0587: } catch (IOException ex) {
0588: ex.printStackTrace();
0589: } catch (SAXException ex) {
0590: ex.printStackTrace();
0591: }
0592: }
0593: }
0594: return deadindex;
0595: }
0596:
0597: protected synchronized void setDeadProperty(Element el)
0598: throws DOMException {
0599: if (deadindex == null) {
0600: deadindex = new Hashtable();
0601: }
0602: String ns = el.getNamespaceURI();
0603: if (ns == null) {
0604: throw new DOMException(DOMException.NAMESPACE_ERR,
0605: "Missing namespace.");
0606: }
0607: Document doc = (Document) getDeadPropertiesIndex().get(ns);
0608: if (doc == null) {
0609: doc = DAVBody.createDocumentNS(DAVNode.PROP_NODE, ns, el
0610: .getPrefix());
0611: Element prop = doc.getDocumentElement();
0612: Node imported = doc.importNode(el, true);
0613: prop.appendChild(imported);
0614: deadindex.put(ns, doc);
0615: deadpropmodified = true;
0616: } else {
0617: Element prop = doc.getDocumentElement();
0618: DAVProperties dp = DAVFactory.createProperties(prop);
0619: Element props[] = dp.getProperties();
0620: int len = props.length;
0621: for (int i = 0; i < len; i++) {
0622: Element p = props[i];
0623: if (p.getNamespaceURI().equals(ns)
0624: && p.getLocalName().equals(el.getLocalName())) {
0625: // same, replace
0626: prop.replaceChild(doc.importNode(el, true), p);
0627: deadpropmodified = true;
0628: return;
0629: }
0630: }
0631: prop.appendChild(doc.importNode(el, true));
0632: deadpropmodified = true;
0633: }
0634: }
0635:
0636: protected synchronized void removeDeadProperty(Element el)
0637: throws DOMException {
0638: String name = el.getNodeName();
0639: String ns = el.getNamespaceURI();
0640: if (ns == null) {
0641: throw new DOMException(DOMException.NAMESPACE_ERR,
0642: "Missing namespace");
0643: }
0644: Document doc = (Document) getDeadPropertiesIndex().get(ns);
0645: if (doc != null) {
0646: Element prop = doc.getDocumentElement();
0647: DAVProperties dp = DAVFactory.createProperties(prop);
0648: Element props[] = dp.getProperties();
0649: int len = props.length;
0650: for (int i = 0; i < len; i++) {
0651: Element p = props[i];
0652: if (p.getNamespaceURI().equals(ns)
0653: && p.getLocalName().equals(el.getLocalName())) {
0654: prop.removeChild(p);
0655: deadpropmodified = true;
0656: return;
0657: }
0658: }
0659: }
0660: String msg = el.getLocalName()
0661: + " property cannot be removed, not found";
0662: throw new DOMException(DOMException.NOT_FOUND_ERR, msg);
0663: }
0664:
0665: protected synchronized void reloadDeadProperties() {
0666: // will be reloaded later...
0667: deadindex = null;
0668: deadpropmodified = false;
0669: }
0670:
0671: protected synchronized void saveDeadProperties() {
0672: if (deadpropmodified) {
0673: ArrayDictionary dic = new ArrayDictionary(deadindex.size());
0674: Enumeration denum = deadindex.keys();
0675: while (denum.hasMoreElements()) {
0676: String ns = (String) denum.nextElement();
0677: Document doc = (Document) deadindex.get(ns);
0678: ByteArrayOutputStream out = new ByteArrayOutputStream();
0679: OutputFormat format = new OutputFormat(doc,
0680: WEBDAV.ENCODING, true);
0681: format.setOmitXMLDeclaration(false);
0682: format.setPreserveSpace(true);
0683: XMLSerializer serializer = new XMLSerializer(out,
0684: format);
0685: try {
0686: serializer.serialize(doc);
0687: if (debug)
0688: System.out.println("["
0689: + out.toString(WEBDAV.ENCODING) + "]");
0690: Base64Encoder encoder = new Base64Encoder(out
0691: .toString(WEBDAV.ENCODING));
0692: dic.put(ns, encoder.processString());
0693: } catch (IOException ex) {
0694: ex.printStackTrace();
0695: }
0696: }
0697: setValue(ATTR_DEAD_PROPERTIES, dic);
0698: deadpropmodified = false;
0699: }
0700: }
0701:
0702: /**
0703: * get the Allowed methods for this resource
0704: * @return an HttpTokenList
0705: */
0706: protected HttpTokenList getAllow() {
0707: allowed = super .getAllow();
0708: allowed.addToken("PROPFIND", false);
0709: allowed.addToken("PROPPATCH", false);
0710: allowed.addToken("MKCOL", false);
0711: allowed.addToken("COPY", false);
0712: allowed.addToken("MOVE", false);
0713: allowed.addToken("LOCK", false);
0714: allowed.addToken("UNLOCK", false);
0715: return allowed;
0716: }
0717:
0718: protected DAVBody getBody(DAVRequest request) throws HTTPException {
0719: try {
0720: InputStream in = request.getInputStream();
0721: if ((in instanceof ContentLengthInputStream)
0722: && (request.getContentLength() == 0)) {
0723: return null;
0724: }
0725: if (in != null) {
0726: return new DAVBody(in);
0727: }
0728: return null;
0729: } catch (Exception ex) {
0730: Reply error = request.makeReply(HTTP.BAD_REQUEST);
0731: error.setContent("Invalid request: " + ex.getMessage());
0732: throw new HTTPException(error);
0733: }
0734: }
0735:
0736: /**
0737: * The WEBDAV OPTIONS method replies with the DAV Header
0738: * @param request The request to handle.
0739: * @exception ProtocolException In case of errors.
0740: * @exception ResourceException If the resource got a fatal error.
0741: */
0742: public Reply options(Request request) throws ProtocolException,
0743: ResourceException {
0744: DAVReply reply = (DAVReply) super .options((Request) request);
0745: reply.setDAV(WEBDAV.CLASS_2_COMPLIANT);
0746: return reply;
0747: }
0748:
0749: /**
0750: * Perform the request
0751: * @param req The request to handle.
0752: * @exception ProtocolException If processsing the request failed.
0753: * @exception ResourceException If the resource got a fatal error.
0754: */
0755:
0756: public ReplyInterface perform(RequestInterface req)
0757: throws ProtocolException, ResourceException {
0758: if (req instanceof DAVRequest) {
0759: DAVRequest request = (DAVRequest) req;
0760: int check = checkIf(request);
0761: if (check == COND_FAILED) {
0762: request.skipBody();
0763: Reply reply = request
0764: .makeReply(HTTP.PRECONDITION_FAILED);
0765: reply.setContent("Pre-conditions failed.");
0766: reply.setContentMD5(null);
0767: return reply;
0768: } else if (check == COND_OK || check == 0) {
0769: if (isLockable(request) && isLocked(request)) {
0770: request.skipBody();
0771: Reply reply = request.makeReply(WEBDAV.LOCKED);
0772: reply.setContent("The resource is locked");
0773: return reply;
0774: }
0775: } else if ((check == COND_OK_LOCK)
0776: && (!checkLockOwner(request))) {
0777: Reply reply = request.makeReply(WEBDAV.LOCKED);
0778: reply.setContent("The resource is locked");
0779: return reply;
0780: }
0781: }
0782: return super .perform(req);
0783: }
0784:
0785: /**
0786: * The handler for unknown method replies with a not implemented.
0787: * @param request The request to handle.
0788: * @exception ProtocolException If processsing the request failed.
0789: * @exception ResourceException If the resource got a fatal error.
0790: */
0791: public Reply extended(Request request) throws ProtocolException,
0792: ResourceException {
0793: if (request instanceof DAVRequest) {
0794: DAVRequest davrequest = (DAVRequest) request;
0795: String method = davrequest.getMethod();
0796: Reply reply = null;
0797: if (method.equals("PROPFIND")) {
0798: reply = propfind(davrequest);
0799: } else if (method.equals("PROPPATCH")) {
0800: reply = proppatch(davrequest);
0801: } else if (method.equals("MKCOL")) {
0802: reply = mkcol(davrequest);
0803: } else if (method.equals("COPY")) {
0804: reply = copy(davrequest);
0805: } else if (method.equals("MOVE")) {
0806: reply = move(davrequest);
0807: } else if (method.equals("LOCK")) {
0808: reply = lock(davrequest);
0809: } else if (method.equals("UNLOCK")) {
0810: reply = unlock(davrequest);
0811: } else {
0812: reply = davextended(davrequest);
0813: }
0814: return reply;
0815: }
0816: String method = request.getMethod();
0817: Reply error = request.makeReply(HTTP.NOT_IMPLEMENTED);
0818: error.setContent("Method " + method + " not implemented.");
0819: throw new HTTPException(error);
0820: }
0821:
0822: public Reply davextended(DAVRequest request)
0823: throws ProtocolException, ResourceException {
0824: String method = request.getMethod();
0825: Reply error = request.makeReply(HTTP.NOT_IMPLEMENTED);
0826: error.setContent("Method " + method + " not implemented.");
0827: throw new HTTPException(error);
0828: }
0829:
0830: protected String decodeURL(DAVRequest request, String encoded)
0831: throws HTTPException {
0832: try {
0833: return DAVParser.decodeURL(encoded);
0834: } catch (HttpInvalidValueException ex) {
0835: Reply error = request.makeReply(HTTP.BAD_REQUEST);
0836: error.setContent("Invalid request: " + ex.getMessage());
0837: throw new HTTPException(error);
0838: }
0839: }
0840:
0841: protected boolean isLockable(DAVRequest request) {
0842: String method = request.getMethod();
0843: return (method.equals("PUT") || method.equals("POST")
0844: || method.equals("PROPATCH") || method.equals("LOCK")
0845: || method.equals("MOVE") || method.equals("DELETE") || method
0846: .equals("MKCOL"));
0847: }
0848:
0849: protected boolean checkLockOwner(DAVRequest request) {
0850: String user = (String) request
0851: .getState(AuthFilter.STATE_AUTHUSER);
0852: if (debug) {
0853: System.out.println("REQ USER : [" + user + "]");
0854: System.out.println("LOCK USER : ["
0855: + getCurrentLockUsername(request) + "]");
0856: }
0857: String lockuser = getCurrentLockUsername(request);
0858: if (lockuser == null) {
0859: return true;
0860: }
0861: if (user != null) {
0862: return user.equals(lockuser);
0863: } else {
0864: return false;
0865: }
0866: }
0867:
0868: /**
0869: * Check the <code>If</code> condition of that request.
0870: * @param request The request to check.
0871: * @return An integer, either <code>COND_FAILED</cond> if condition
0872: * was checked, but failed, <code>COND_OK</code> if condition was checked
0873: * and succeeded, or <strong>0</strong> if the condition was not checked
0874: * at all (eg because the resource or the request didn't support it).
0875: */
0876: protected int checkIf(DAVRequest request) throws HTTPException {
0877: URL url = getURL(request);
0878: String surl = url.toExternalForm();
0879: DAVIf ifs[] = request.getIf();
0880: if (ifs != null) {
0881: if (debug) {
0882: System.out.println(">>> Check If Header...");
0883: }
0884: int len = ifs.length;
0885: boolean tagged = request.isTaggedListIfHeader();
0886: boolean lockchecked = false;
0887:
0888: for (int i = 0; i < len; i++) {
0889: DAVIf dif = ifs[i];
0890: boolean parent = false;
0891: // check that if
0892: if (dif.hasResource()) {
0893: URL resURL = null;
0894: try {
0895: resURL = new URL(url, dif.getResource());
0896: } catch (MalformedURLException ex) {
0897: ex.printStackTrace();
0898: continue;
0899: }
0900: if (!resURL.equals(url)) {
0901: if (surl.startsWith(resURL.toExternalForm())) {
0902: // parent lock
0903: parent = true;
0904: } else {
0905: // not us
0906: continue;
0907: }
0908: }
0909: }
0910: ListIterator it = dif.getTokenListIterator();
0911: while (it.hasNext()) { // OR
0912: boolean checked = true;
0913: boolean not = false;
0914: LinkedList list = (LinkedList) it.next();
0915: ListIterator it2 = list.listIterator(0);
0916: while (it2.hasNext()) { // AND
0917: Object tok = it2.next();
0918: if (tok instanceof DAVStateToken) {
0919: DAVStateToken dst = (DAVStateToken) tok;
0920: if (matchLockToken(request, dst
0921: .getStateToken())) {
0922: if (dst.isNot()) {
0923: checked = false;
0924: not = false;
0925: } else {
0926: if (debug)
0927: System.out
0928: .println(">>> Lock checked");
0929: lockchecked = true;
0930: }
0931: } else if (!dst.isNot()) {
0932: checked = false;
0933: }
0934: } else if ((!parent)
0935: && (tok instanceof DAVEntityTag)) {
0936: DAVEntityTag det = (DAVEntityTag) tok;
0937: if (matchETag(det)) {
0938: if (debug)
0939: System.out
0940: .println(">>> ETag checked");
0941: if (det.isNot()) {
0942: checked = false;
0943: not = false;
0944: }
0945: } else if (!det.isNot()) {
0946: checked = false;
0947: }
0948: }
0949: }
0950: if (!parent) {
0951: if (checked && lockchecked) {
0952: return COND_OK_LOCK;
0953: } else if (checked) {
0954: return COND_OK;
0955: }
0956: }
0957: }
0958: }
0959: if (tagged) {
0960: if (lockchecked) {
0961: return COND_OK_LOCK;
0962: } else {
0963: return 0;
0964: }
0965: } else {
0966: return COND_FAILED;
0967: }
0968: }
0969: return 0;
0970: }
0971:
0972: protected boolean matchETag(HttpEntityTag retag) {
0973: HttpEntityTag etag = getETag();
0974: if (etag != null) {
0975: return etag.getTag().equals(retag.getTag());
0976: }
0977: return false;
0978: }
0979:
0980: protected boolean matchLockToken(DAVRequest request,
0981: String locktoken) {
0982: return locktoken.equals(getCurrentLockToken(request));
0983: }
0984:
0985: /**
0986: * The WEBDAV DELETE method, actually the resource (file, directory)
0987: * is moved into the trash directory which is not accessible via HTTP.
0988: * @param request The request to handle.
0989: * @exception ProtocolException If processsing the request failed.
0990: * @exception ResourceException If the resource got a fatal error.
0991: */
0992:
0993: public Reply delete(Request request) throws ProtocolException,
0994: ResourceException {
0995: return super .delete(request);
0996: }
0997:
0998: /**
0999: * Get this resource body.
1000: * If we are allowed to convert GET requests to POST, than we first
1001: * check to see if there is some search string in the request, and continue
1002: * with normal POST request processing.
1003: * <p>If there is no search string, or if we are not allowed to convert
1004: * GETs to POSTs, than we just invoke our <code>super</code> method,
1005: * which will perform the appropriate job.
1006: * @param request The request to handle.
1007: * @exception ProtocolException If request couldn't be processed.
1008: * @exception ResourceException If the resource got a fatal error.
1009: */
1010: public Reply get(Request request) throws ProtocolException,
1011: ResourceException {
1012: return super .get(request);
1013: }
1014:
1015: /**
1016: * The WEBDAV PUT method.
1017: * @param request The request to handle.
1018: * @exception ProtocolException If processsing the request failed.
1019: * @exception ResourceException If the resource got a fatal error.
1020: */
1021:
1022: public Reply put(Request request) throws ProtocolException,
1023: ResourceException {
1024: return super .put(request);
1025: }
1026:
1027: /**
1028: * Perform the post method.
1029: * @param request The request to handle.
1030: * @exception ProtocolException If request couldn't be processed.
1031: * @exception ResourceException If the resource got a fatal error.
1032: */
1033: public Reply post(Request request) throws ProtocolException,
1034: ResourceException {
1035: return super .post(request);
1036: }
1037:
1038: private HTTPException notYetImplemented(DAVRequest request)
1039: throws ProtocolException {
1040: Reply error = request.makeReply(HTTP.NOT_IMPLEMENTED);
1041: error.setContent("Method " + request.getMethod()
1042: + " not implemented.");
1043: throw new HTTPException(error);
1044: }
1045:
1046: protected boolean hasProperty(int idx) {
1047: return (getValue(idx, null) != null);
1048: }
1049:
1050: protected boolean hasStringProperty(int idx) {
1051: String value = (String) getValue(idx, "");
1052: return (value.length() > 0);
1053: }
1054:
1055: protected boolean hasLongProperty(int idx) {
1056: return (getLong(idx, -1) != -1);
1057: }
1058:
1059: protected boolean hasIntProperty(int idx) {
1060: return (getInt(idx, -1) != -1);
1061: }
1062:
1063: protected void addCreationDate(DAVProperties props) {
1064: Date d = new Date(getCreationDate());
1065: String isodate = DateParser.getIsoDateNoMillis(d);
1066: props.addProperty(DAVNode.CREATIONDATE_NODE, isodate);
1067: }
1068:
1069: protected void addDisplayName(DAVProperties props) {
1070: String title = getTitle();
1071: if ((title != null) && (title.length() > 0)) {
1072: props.addProperty(DAVNode.DISPLAYNAME_NODE, title);
1073: }
1074: }
1075:
1076: protected void addContentLanguage(DAVProperties props) {
1077: String lang = getContentLanguage();
1078: if (lang != null) {
1079: props.addProperty(DAVNode.GETCONTENTLANGUAGE_NODE, lang);
1080: }
1081: }
1082:
1083: protected void addContentType(DAVProperties props) {
1084: MimeType mime = getContentType();
1085: if (mime != null) {
1086: props.addProperty(DAVNode.GETCONTENTTYPE_NODE, mime
1087: .toString());
1088: }
1089: }
1090:
1091: private void addCollectionContentType(DAVProperties props) {
1092: props.addProperty(DAVNode.GETCONTENTTYPE_NODE,
1093: collectioncontenttype.toString());
1094: }
1095:
1096: protected void addContentLength(DAVProperties props) {
1097: int length = getContentLength();
1098: if (length >= 0) {
1099: props.addProperty(DAVNode.GETCONTENTLENGTH_NODE, String
1100: .valueOf(length));
1101: }
1102: }
1103:
1104: protected void addETag(DAVProperties props) {
1105: HttpEntityTag tag = getETag();
1106: if (tag != null) {
1107: props.addProperty(DAVNode.GETETAG_NODE, tag.getTag());
1108: }
1109: }
1110:
1111: protected void addLastModified(DAVProperties props) {
1112: HttpDate hdate = HttpFactory.makeDate(getLastModified());
1113: String httpdate = hdate.toString();
1114: props.addProperty(DAVNode.GETLASTMODIFIED_NODE, httpdate);
1115: }
1116:
1117: protected void addResourceType(DAVProperties props) {
1118: if (isCollection()) {
1119: props.setResourceType(DAVNode.COLLECTION_NODE);
1120: } else {
1121: props.setResourceType(null);
1122: }
1123: }
1124:
1125: protected void addIsCollection(DAVProperties props) {
1126: props.addProperty(DAVNode.ISCOLLECTION_NODE,
1127: isCollection() ? "1" : "0");
1128: }
1129:
1130: /**
1131: * Get the properties of our associated resource require in
1132: * the given DAVProperties Object.
1133: * @param doc the response XML Document
1134: * @param dp the DAVProperties node in found the request body
1135: * @return a DAVProperties instance
1136: */
1137: protected DAVProperties getProperties(DAVRequest request,
1138: Document doc, DAVProperties dp) {
1139: DAVProperties props = DAVFactory.createProperties(doc);
1140: Element[] els = dp.getProperties();
1141: int len = els.length;
1142: for (int i = 0; i < len; i++) {
1143: Element el = els[i];
1144: String ns = el.getNamespaceURI();
1145: String propname = el.getLocalName();
1146: if ((ns == null) || (ns.equals(WEBDAV.NAMESPACE_URI))) {
1147: // live property
1148: if (propname.equals(DAVNode.CREATIONDATE_NODE)) {
1149: addCreationDate(props);
1150: } else if (propname.equals(DAVNode.DISPLAYNAME_NODE)) {
1151: addDisplayName(props);
1152: } else if (propname
1153: .equals(DAVNode.GETCONTENTLANGUAGE_NODE)) {
1154: addContentLanguage(props);
1155: } else if (propname.equals(DAVNode.GETCONTENTTYPE_NODE)) {
1156: addContentType(props);
1157: } else if (propname
1158: .equals(DAVNode.GETCONTENTLENGTH_NODE)) {
1159: addContentLength(props);
1160: } else if (propname.equals(DAVNode.GETETAG_NODE)) {
1161: addETag(props);
1162: } else if (propname
1163: .equals(DAVNode.GETLASTMODIFIED_NODE)) {
1164: addLastModified(props);
1165: } else if (propname.equals(DAVNode.LOCKDISCOVERY_NODE)) {
1166: addLockDiscovery(request, props);
1167: } else if (propname.equals(DAVNode.RESOURCETYPE_NODE)) {
1168: addResourceType(props);
1169: } else if (propname.equals(DAVNode.SOURCE_NODE)) {
1170: // FIXME
1171: } else if (propname.equals(DAVNode.SUPPORTEDLOCK_NODE)) {
1172: addSupportedLock(props);
1173: } else { // property not found
1174: // FIXME add with 404 reply
1175: }
1176: } else {
1177: // dead property
1178: Document pdoc = (Document) getDeadPropertiesIndex()
1179: .get(ns);
1180: if (pdoc != null) {
1181: Element prop = pdoc.getDocumentElement();
1182: DAVProperties dpns = DAVFactory
1183: .createProperties(prop);
1184: Node pnode = dpns.getNodeNS(propname, ns);
1185: if (pnode != null) {
1186: props.addNodeNS(doc.importNode(pnode, true));
1187: }
1188: }
1189: }
1190: }
1191: return props;
1192: }
1193:
1194: protected DAVPropStat[] getPropStat(DAVRequest request,
1195: Document doc, DAVProperties dp) {
1196: DAVProperties props = DAVFactory.createProperties(doc);
1197: DAVProperties nfprops = null;
1198: Element[] els = dp.getProperties();
1199: int len = els.length;
1200: for (int i = 0; i < len; i++) {
1201: Element el = els[i];
1202: String ns = el.getNamespaceURI();
1203: String propname = el.getLocalName();
1204: if ((ns == null) || (ns.equals(WEBDAV.NAMESPACE_URI))) {
1205: // live property
1206: if (propname.equals(DAVNode.CREATIONDATE_NODE)) {
1207: addCreationDate(props);
1208: } else if (propname.equals(DAVNode.DISPLAYNAME_NODE)) {
1209: addDisplayName(props);
1210: } else if (propname
1211: .equals(DAVNode.GETCONTENTLANGUAGE_NODE)) {
1212: addContentLanguage(props);
1213: } else if (propname.equals(DAVNode.GETCONTENTTYPE_NODE)) {
1214: addContentType(props);
1215: } else if (propname
1216: .equals(DAVNode.GETCONTENTLENGTH_NODE)) {
1217: addContentLength(props);
1218: } else if (propname.equals(DAVNode.GETETAG_NODE)) {
1219: addETag(props);
1220: } else if (propname
1221: .equals(DAVNode.GETLASTMODIFIED_NODE)) {
1222: addLastModified(props);
1223: } else if (propname.equals(DAVNode.LOCKDISCOVERY_NODE)) {
1224: addLockDiscovery(request, props);
1225: } else if (propname.equals(DAVNode.RESOURCETYPE_NODE)) {
1226: addResourceType(props);
1227: } else if (propname.equals(DAVNode.SOURCE_NODE)) {
1228: // FIXME
1229: } else if (propname.equals(DAVNode.SUPPORTEDLOCK_NODE)) {
1230: addSupportedLock(props);
1231: } else { // property not found
1232: if (nfprops == null) {
1233: nfprops = DAVFactory.createProperties(doc);
1234: }
1235: Element e;
1236: e = doc.createElementNS(
1237: "http://www.w3.org/Jigsaw/Webdav/",
1238: propname);
1239: e.setPrefix("F");
1240: nfprops.addNodeNS(nfprops.getNode(), (Node) e);
1241: }
1242: } else {
1243: // dead property
1244: Document pdoc = (Document) getDeadPropertiesIndex()
1245: .get(ns);
1246: if (pdoc != null) {
1247: Element prop = pdoc.getDocumentElement();
1248: DAVProperties dpns = DAVFactory
1249: .createProperties(prop);
1250: Node pnode = dpns.getNodeNS(propname, ns);
1251: if (pnode != null) {
1252: props.addNodeNS(doc.importNode(pnode, true));
1253: }
1254: }
1255: }
1256: }
1257: DAVPropStat[] dps = null;
1258: if (nfprops != null) {
1259: dps = new DAVPropStat[2];
1260: dps[1] = DAVFactory.createPropStat(
1261: getStatusLine(HTTP.NOT_FOUND), doc);
1262: dps[1].addDAVNode(nfprops);
1263: } else {
1264: dps = new DAVPropStat[1];
1265: }
1266: dps[0] = DAVFactory.createPropStat(getStatusLine(HTTP.OK), doc);
1267: dps[0].addDAVNode(props);
1268: return dps;
1269: }
1270:
1271: /**
1272: * Get all the properties of our associated resource.
1273: * @param doc the response XML Document
1274: * @return a DAVProperties instance
1275: */
1276: protected DAVProperties getProperties(DAVRequest request,
1277: Document doc) {
1278: DAVProperties props = DAVFactory.createProperties(doc);
1279: // creationdate
1280: addCreationDate(props);
1281: // displayname
1282: addDisplayName(props);
1283: // getcontentlanguage
1284: addContentLanguage(props);
1285: // getcontentlength
1286: addContentLength(props);
1287: // getetag
1288: addETag(props);
1289: // getlastmodified
1290: addLastModified(props);
1291: // getcontenttype
1292: if (isCollection()) {
1293: addCollectionContentType(props);
1294: } else {
1295: addContentType(props);
1296: }
1297: // lockdiscovery
1298: addLockDiscovery(request, props);
1299: // resourcetype
1300: addResourceType(props);
1301: // supportedlock
1302: addSupportedLock(props);
1303: // non std stuff
1304: addIsCollection(props);
1305: // Dead properties
1306: Hashtable dp = getDeadPropertiesIndex();
1307: Enumeration e = dp.keys();
1308: while (e.hasMoreElements()) {
1309: String ns = (String) e.nextElement();
1310: Document d = (Document) dp.get(ns);
1311: Element el = d.getDocumentElement(); // prop
1312: try {
1313: DAVNode.exportChildren(doc, props.getNode(), el, true);
1314: } catch (DOMException ex) {
1315: ex.printStackTrace();
1316: }
1317: }
1318: return props;
1319: }
1320:
1321: protected DAVProperties getPropertiesForCopy(Document doc) {
1322: DAVProperties props = DAVFactory.createProperties(doc);
1323: // displayname
1324: addDisplayName(props);
1325: // getcontentlanguage
1326: addContentLanguage(props);
1327: // getcontenttype
1328: addContentType(props);
1329: // source
1330:
1331: // Dead properties
1332: Hashtable dp = getDeadPropertiesIndex();
1333: Enumeration e = dp.keys();
1334: while (e.hasMoreElements()) {
1335: String ns = (String) e.nextElement();
1336: Document d = (Document) dp.get(ns);
1337: Element el = d.getDocumentElement(); // prop
1338: try {
1339: DAVNode.exportChildren(doc, props.getNode(), el, true);
1340: } catch (DOMException ex) {
1341: ex.printStackTrace();
1342: }
1343: }
1344: return props;
1345: }
1346:
1347: /**
1348: * Get all the property names of our associated resource.
1349: * @param doc the response XML Document
1350: * @return a DAVProperties instance
1351: */
1352: protected DAVProperties getPropNames(DAVRequest request,
1353: Document doc) {
1354: DAVProperties props = DAVFactory.createProperties(doc);
1355: // dead property
1356: Hashtable dp = getDeadPropertiesIndex();
1357: Enumeration e = dp.keys();
1358: while (e.hasMoreElements()) {
1359: String ns = (String) e.nextElement();
1360: Document d = (Document) dp.get(ns);
1361: Element el = d.getDocumentElement(); // prop
1362: try {
1363: DAVNode.exportChildren(doc, props.getNode(), el, false);
1364: } catch (DOMException ex) {
1365: ex.printStackTrace();
1366: }
1367: }
1368: // live properties
1369: if (hasStringProperty(ATTR_TITLE)) {
1370: props.addProperty(DAVNode.DISPLAYNAME_NODE);
1371: }
1372: if (hasStringProperty(ATTR_CONTENT_LANGUAGE)) {
1373: props.addProperty(DAVNode.GETCONTENTLANGUAGE_NODE);
1374: }
1375: if (getETag() != null) {
1376: props.addProperty(DAVNode.GETETAG_NODE);
1377: }
1378: if (hasProperty(ATTR_CONTENT_TYPE)) {
1379: props.addProperty(DAVNode.GETCONTENTTYPE_NODE);
1380: }
1381: if (hasIntProperty(ATTR_CONTENT_LENGTH)) {
1382: props.addProperty(DAVNode.GETCONTENTLENGTH_NODE);
1383: }
1384: if (hasLongProperty(ATTR_CREATION_DATE)) {
1385: props.addProperty(DAVNode.CREATIONDATE_NODE);
1386: }
1387: if (getCurrentLockToken(request) != null) {
1388: props.addProperty(DAVNode.LOCKDISCOVERY_NODE);
1389: }
1390: props.addProperty(DAVNode.GETLASTMODIFIED_NODE);
1391: props.addProperty(DAVNode.RESOURCETYPE_NODE);
1392: props.addProperty(DAVNode.SUPPORTEDLOCK_NODE);
1393: return props;
1394: }
1395:
1396: /**
1397: * Get an appropriate DAV Response to the given PROPFIND request
1398: * @param request the DAV Request
1399: * @param dpf the DAVPropFind XML Node (can be null)
1400: * @param document the XML document
1401: * @return a DAVResponse
1402: */
1403: protected DAVResponse getResponse(DAVRequest request,
1404: DAVPropFind dpf, Document document) {
1405: if (fresource != null) {
1406: fresource.checkContent();
1407: }
1408: updateCachedHeaders();
1409:
1410: DAVProperties props = null;
1411: if (dpf != null) {
1412: if (dpf.findPropNames()) {
1413: props = getPropNames(request, document);
1414: } else if (dpf.findAllProps()) {
1415: props = getProperties(request, document);
1416: } else {
1417: DAVProperties dp = dpf.getProperties();
1418: // props = getProperties(request, document, dp);
1419: DAVPropStat[] dps = getPropStat(request, document, dp);
1420: DAVResponse dr = DAVFactory.createResponse(
1421: // getURL(request).toExternalForm(),
1422: getURL(request).getFile(), document);
1423: for (int i = 0; i < dps.length; i++) {
1424: dr.addDAVNode(dps[i]);
1425: }
1426: return dr;
1427: }
1428: } else { // default is all property values
1429: props = getProperties(request, document);
1430: }
1431: return DAVFactory.createPropStatResponse(
1432: // getURL(request).toExternalForm(),
1433: getURL(request).getFile(), getStatusLine(HTTP.OK),
1434: props, document);
1435: }
1436:
1437: /**
1438: * Get an appropriate DAV Response to the given PROPFIND request from
1439: * our children
1440: * @param request the DAV Request
1441: * @param dpf the DAVPropFind XML Node (can be null)
1442: * @param document the XML document
1443: * @param deep do it recursivly if true
1444: * @return a DAVResponse array
1445: */
1446: protected DAVResponse[] getChildResponses(DAVRequest request,
1447: DAVPropFind dpf, Document document, boolean deep) {
1448: if (resource instanceof ContainerResource) {
1449: Vector v = new Vector();
1450: ContainerResource cresource = (ContainerResource) resource;
1451: Enumeration e = cresource.enumerateResourceIdentifiers();
1452: ResourceReference rr = null;
1453: FramedResource fr = null;
1454: while (e.hasMoreElements()) {
1455: String name = (String) e.nextElement();
1456: rr = cresource.lookup(name);
1457: if (rr != null) {
1458: try {
1459: fr = (FramedResource) rr.lock();
1460: if (fr == resource) { // for root
1461: continue;
1462: }
1463: DAVFrame df = (DAVFrame) fr
1464: .getFrame(DAVFrame.class);
1465: if (df != null) {
1466: v.addElement(df.getResponse(request, dpf,
1467: document));
1468: if (deep
1469: && (fr instanceof ContainerResource)) {
1470: DAVResponse responses[] = df
1471: .getChildResponses(request,
1472: dpf, document, deep);
1473: if (responses != null) {
1474: int len = responses.length;
1475: for (int i = 0; i < len; i++) {
1476: v.addElement(responses[i]);
1477: }
1478: }
1479: }
1480: } else {
1481: // what should I do there?
1482: }
1483: } catch (InvalidResourceException ex) {
1484: // build error response?
1485: } finally {
1486: rr.unlock();
1487: }
1488: }
1489: }
1490: DAVResponse responses[] = new DAVResponse[v.size()];
1491: v.copyInto(responses);
1492: return responses;
1493: }
1494: return null;
1495: }
1496:
1497: /**
1498: * Create a DAV reply for a specific DAV request.
1499: * @param request the DAVRequest
1500: * @param status the status of the reply
1501: * @param document the XML content of the reply
1502: * @return a Reply instance
1503: */
1504: protected Reply createDAVReply(DAVRequest request, int status,
1505: Document document) {
1506: Reply reply = request.makeReply(status);
1507: reply.setHeaderValue(Reply.H_CONTENT_TYPE, xmlcontenttype);
1508: reply.setDate((System.currentTimeMillis() / 1000L) * 1000L);
1509:
1510: ByteArrayOutputStream out = new ByteArrayOutputStream();
1511:
1512: OutputFormat format = new OutputFormat(document,
1513: WEBDAV.ENCODING, true);
1514: format.setOmitXMLDeclaration(false);
1515: format.setPreserveSpace(false);
1516: XMLSerializer serializer = new XMLSerializer(out, format);
1517: try {
1518: serializer.serialize(document);
1519: } catch (IOException ex) {
1520: ex.printStackTrace();
1521: }
1522:
1523: if (debugxml) {
1524: serializer = new XMLSerializer(System.out, format);
1525: try {
1526: serializer.serialize(document);
1527: } catch (IOException ex) {
1528: ex.printStackTrace();
1529: }
1530: }
1531:
1532: int len = out.size();
1533: reply.setContentLength(len);
1534:
1535: ByteArrayInputStream in = new ByteArrayInputStream(out
1536: .toByteArray());
1537: reply.setStream(in);
1538: return reply;
1539: }
1540:
1541: protected String getStatusLine(int status) {
1542: return "HTTP/1.1 " + status + " "
1543: + DAVReply.getDAVReason(status);
1544: }
1545:
1546: /**
1547: * Handle the PROPFIND request.
1548: * @param request the WEBDAV request
1549: * @return a Reply instance
1550: * @exception ProtocolException If processsing the request failed.
1551: * @exception ResourceException If the resource got a fatal error.
1552: */
1553: public Reply propfind(DAVRequest request) throws ProtocolException,
1554: ResourceException {
1555: int depth = request.getDepth();
1556: DAVBody body = getBody(request);
1557: Document document = DAVBody
1558: .createDocument(DAVNode.MULTISTATUS_NODE);
1559: DAVMultiStatus dms = DAVFactory.createMultiStatus(document
1560: .getDocumentElement());
1561: DAVPropFind propfind = null;
1562: DAVResponse dr = null;
1563: if (body != null) {
1564: propfind = body.getPropFind();
1565: }
1566: switch (depth) {
1567: case 0:
1568: dr = getResponse(request, propfind, document);
1569: dms.addDAVNode(dr);
1570: break;
1571: case 1:
1572: dr = getResponse(request, propfind, document);
1573: dms.addDAVNode(dr);
1574: dms.addDAVNodes(getChildResponses(request, propfind,
1575: document, false));
1576: break;
1577: default: // infinity
1578: dr = getResponse(request, propfind, document);
1579: dms.addDAVNode(dr);
1580: dms.addDAVNodes(getChildResponses(request, propfind,
1581: document, true));
1582:
1583: }
1584: return createDAVReply(request, WEBDAV.MULTI_STATUS, document);
1585: }
1586:
1587: protected DAVPropStat setDAVProperties(DAVProperties props,
1588: Document document) throws DAVPropertyException {
1589: Element properties[] = props.getProperties();
1590: int len = properties.length;
1591: DAVProperties okdp = DAVFactory.createProperties(document);
1592: try {
1593: for (int i = 0; i < len; i++) {
1594: Element el = properties[i];
1595: String ns = el.getNamespaceURI();
1596: if ((ns == null) || (ns.equals(WEBDAV.NAMESPACE_URI))) {
1597: // live property
1598: setLiveProperty(DAVFactory.createDAVNode(el), okdp,
1599: document);
1600: } else {
1601: // dead property
1602: setDeadProperty(DAVFactory.createDAVNode(el), okdp,
1603: document);
1604: }
1605: }
1606: } catch (DAVPropertyException ex) {
1607: // something failed
1608: DAVPropStat dps = (DAVPropStat) ex.getReason();
1609: String msg = ex.getMessage();
1610: DAVPropStat stats[] = null;
1611: if (okdp.getNode().hasChildNodes()) {
1612: DAVPropStat okdps = DAVFactory.createPropStat(
1613: getStatusLine(HTTP.OK), okdp, document);
1614: stats = new DAVPropStat[2];
1615: stats[0] = okdps;
1616: stats[1] = dps;
1617: } else {
1618: stats = new DAVPropStat[1];
1619: stats[0] = dps;
1620: }
1621: // send ok properties and the one that failed
1622: throw new DAVPropertyException(msg, stats);
1623: }
1624: // everything is ok
1625: if (okdp.getNode().hasChildNodes()) {
1626: return DAVFactory.createPropStat(getStatusLine(HTTP.OK),
1627: okdp, document);
1628: }
1629: return null;
1630: }
1631:
1632: protected void setDeadProperty(DAVNode node, DAVProperties okdp,
1633: Document document) throws DAVPropertyException {
1634: Node n = node.getNode();
1635: String name = n.getLocalName();
1636: try {
1637: if (n.getNodeType() == n.ELEMENT_NODE) {
1638: Element el = (Element) n;
1639: setDeadProperty(el);
1640: okdp.addNodeNS(document.importNode(el, false));
1641: } else {
1642: DAVPropStat dps = DAVFactory.createPropStatNS(
1643: getStatusLine(HTTP.CONFLICT), document
1644: .importNode(n, false), document);
1645: String msg = "Invalid XML : " + name;
1646: throw new DAVPropertyException(msg, dps);
1647: }
1648: } catch (DOMException ex) {
1649: DAVPropStat dps = DAVFactory.createPropStatNS(
1650: getStatusLine(HTTP.CONFLICT), document.importNode(
1651: n, false), document);
1652: throw new DAVPropertyException(ex.getMessage(), dps);
1653: }
1654: }
1655:
1656: protected void setLiveProperty(DAVNode node, DAVProperties okdp,
1657: Document document) throws DAVPropertyException {
1658: String name = node.getNode().getLocalName();
1659: String value = node.getTextValue();
1660: if (name.equals(DAVNode.DISPLAYNAME_NODE)) {
1661: setValue(ATTR_TITLE, value);
1662: okdp.addProperty(name);
1663: } else if (name.equals(DAVNode.GETCONTENTLANGUAGE_NODE)) {
1664: setValue(ATTR_CONTENT_LANGUAGE, value);
1665: okdp.addProperty(name);
1666: } else if (name.equals(DAVNode.SOURCE_NODE)) {
1667: // FIXME
1668: } else if (name.equals(DAVNode.RESOURCETYPE_NODE)) {
1669: // FIXME
1670: } else if (name.equals(DAVNode.GETCONTENTTYPE_NODE)) {
1671: try {
1672: MimeType mime = new MimeType(value);
1673: setValue(ATTR_CONTENT_TYPE, mime);
1674: okdp.addProperty(name);
1675: } catch (MimeTypeFormatException ex) {
1676: DAVPropStat dps = DAVFactory.createPropStat(
1677: getStatusLine(HTTP.CONFLICT), name, document);
1678: // throw exception now
1679: String msg = "Invalid value for " + name + " : "
1680: + value;
1681: throw new DAVPropertyException(msg, dps);
1682: }
1683: } else if (isReadOnly(name)) {
1684: // forbidden
1685: DAVPropStat dps = DAVFactory.createPropStat(
1686: getStatusLine(HTTP.FORBIDDEN), name, document);
1687: throw new DAVPropertyException(
1688: name + " cannot be modified", dps);
1689: } else {
1690: // not found so add it as a dead one
1691: setDeadProperty(node, okdp, document);
1692: }
1693: }
1694:
1695: protected DAVPropStat removeDAVProperties(DAVProperties props,
1696: Document document) throws DAVPropertyException {
1697: Element properties[] = props.getProperties();
1698: int len = properties.length;
1699: DAVProperties okdp = DAVFactory.createProperties(document);
1700: try {
1701: for (int i = 0; i < len; i++) {
1702: Element el = properties[i];
1703: String ns = el.getNamespaceURI();
1704: if ((ns == null) || (ns.equals(WEBDAV.NAMESPACE_URI))) {
1705: // live property
1706: removeLiveProperty(DAVFactory.createDAVNode(el),
1707: okdp, document);
1708: } else {
1709: // dead property
1710: removeDeadProperty(DAVFactory.createDAVNode(el),
1711: okdp, document);
1712: }
1713: }
1714: } catch (DAVPropertyException ex) {
1715: // something failed
1716: DAVPropStat dps = (DAVPropStat) ex.getReason();
1717: String msg = ex.getMessage();
1718: DAVPropStat stats[] = null;
1719: if (okdp.getNode().hasChildNodes()) {
1720: DAVPropStat okdps = DAVFactory.createPropStat(
1721: getStatusLine(HTTP.OK), okdp, document);
1722: stats = new DAVPropStat[2];
1723: stats[0] = okdps;
1724: stats[1] = dps;
1725: } else {
1726: stats = new DAVPropStat[1];
1727: stats[0] = dps;
1728: }
1729: // send ok properties and the one that failed
1730: throw new DAVPropertyException(msg, stats);
1731: }
1732: // everything is ok
1733: if (okdp.getNode().hasChildNodes()) {
1734: return DAVFactory.createPropStat(getStatusLine(HTTP.OK),
1735: okdp, document);
1736: }
1737: return null;
1738: }
1739:
1740: protected void removeLiveProperty(DAVNode node, DAVProperties okdp,
1741: Document document) throws DAVPropertyException {
1742: String name = node.getNode().getLocalName();
1743: String value = node.getTextValue();
1744: if (name.equals(DAVNode.DISPLAYNAME_NODE)) {
1745: setValue(ATTR_TITLE, "");
1746: okdp.addProperty(name);
1747: } else if (name.equals(DAVNode.GETCONTENTLANGUAGE_NODE)) {
1748: setValue(ATTR_CONTENT_LANGUAGE, null);
1749: okdp.addProperty(name);
1750: } else {
1751: // may be it's a dead "DAV:" property
1752: try {
1753: removeDeadProperty(node, okdp, document);
1754: } catch (DAVPropertyException ex) {
1755: DAVPropStat edps = DAVFactory.createPropStat(
1756: getStatusLine(HTTP.CONFLICT), name, document);
1757: throw new DAVPropertyException(name
1758: + " cannot be removed", edps);
1759: }
1760: }
1761: }
1762:
1763: protected void removeDeadProperty(DAVNode node, DAVProperties okdp,
1764: Document document) throws DAVPropertyException {
1765: Node n = node.getNode();
1766: String name = n.getLocalName();
1767: try {
1768: if (n.getNodeType() == n.ELEMENT_NODE) {
1769: Element el = (Element) n;
1770: removeDeadProperty(el);
1771: okdp.addNodeNS(document.importNode(el, false));
1772: } else {
1773: DAVPropStat dps = DAVFactory.createPropStatNS(
1774: getStatusLine(HTTP.CONFLICT), document
1775: .importNode(n, false), document);
1776: String msg = "Invalid XML : " + name;
1777: throw new DAVPropertyException(msg, dps);
1778: }
1779: } catch (DOMException ex) {
1780: DAVPropStat dps = DAVFactory.createPropStatNS(
1781: getStatusLine(HTTP.CONFLICT), document.importNode(
1782: n, false), document);
1783: throw new DAVPropertyException(ex.getMessage(), dps);
1784: }
1785: }
1786:
1787: /**
1788: * Handle the PROPPATCH request.
1789: * @param request the WEBDAV request
1790: * @return a Reply instance
1791: * @exception ProtocolException If processsing the request failed.
1792: * @exception ResourceException If the resource got a fatal error.
1793: */
1794: public Reply proppatch(DAVRequest request)
1795: throws ProtocolException, ResourceException {
1796: // prepare undo
1797: Object oldvalues[] = this .values;
1798: DAVBody body = getBody(request);
1799: Document document = DAVBody
1800: .createDocument(DAVNode.MULTISTATUS_NODE);
1801: DAVResponse dr = DAVFactory.createResponse(getURL(request)
1802: .getFile(),
1803: //toExternalForm(),
1804: document);
1805: // attach the response to the document
1806: document.getDocumentElement().appendChild(dr.getNode());
1807:
1808: if (body != null) {
1809: DAVPropertyUpdate dpu = body.getPropertyUpdate();
1810: if (dpu != null) {
1811: DAVPropAction dpas[] = dpu.getActions();
1812: DAVPropStat dps = null;
1813: int len = dpas.length;
1814: try {
1815: for (int i = 0; i < len; i++) {
1816: DAVPropAction dpa = dpas[i];
1817: switch (dpa.getAction()) {
1818: case DAVPropAction.SET:
1819: dps = setDAVProperties(dpa.getProperties(),
1820: document);
1821: break;
1822: case DAVPropAction.REMOVE:
1823: dps = removeDAVProperties(dpa
1824: .getProperties(), document);
1825: break;
1826: default:
1827: // error
1828: Reply error = request
1829: .makeReply(HTTP.BAD_REQUEST);
1830: error.setContent("Invalid request");
1831: throw new HTTPException(error);
1832: }
1833: if (dps != null) {
1834: dr.addDAVNode(dps);
1835: }
1836: }
1837: saveDeadProperties();
1838: } catch (DAVPropertyException ex) {
1839: // stop all an undo change
1840: reloadDeadProperties();
1841: this .values = oldvalues;
1842: // report error
1843: DAVPropStat dpss[] = (DAVPropStat[]) ex.getReason();
1844: for (int j = 0; j < dpss.length; j++) {
1845: dr.addDAVNode(dpss[j]);
1846: }
1847: dr.setDescription(ex.getMessage());
1848: }
1849: return createDAVReply(request, WEBDAV.MULTI_STATUS,
1850: document);
1851: }
1852: }
1853: Reply error = request.makeReply(HTTP.BAD_REQUEST);
1854: error.setContent("Invalid request");
1855: throw new HTTPException(error);
1856: }
1857:
1858: /**
1859: * Handle the MKCOL request.
1860: * @param request the WEBDAV request
1861: * @return a Reply instance
1862: * @exception ProtocolException If processsing the request failed.
1863: * @exception ResourceException If the resource got a fatal error.
1864: */
1865: public Reply mkcol(DAVRequest request) throws ProtocolException,
1866: ResourceException {
1867: if (dresource != null) {
1868: String newcol = (String) request.getState(REMAINING_PATH);
1869: if (newcol != null) {
1870: if (dresource.getExtensibleFlag() && getPutableFlag()) {
1871: // create a new collection
1872: ResourceReference rr = dresource
1873: .createDirectoryResource(newcol);
1874: if (rr == null) {
1875: Reply error = request
1876: .makeReply(HTTP.UNSUPPORTED_MEDIA_TYPE);
1877: error.setContent("Failed to create collection "
1878: + newcol);
1879: throw new HTTPException(error);
1880: } else {
1881: Reply reply = request.makeReply(HTTP.CREATED);
1882: reply.setContent("<P>Collection " + newcol
1883: + " succesfully created");
1884:
1885: return reply;
1886: }
1887: } else {
1888: Reply error = request.makeReply(HTTP.FORBIDDEN);
1889: error
1890: .setContent("The server doen't allow collection "
1891: + "creation here.");
1892: throw new HTTPException(error);
1893: }
1894: } else {
1895: Reply error = request.makeReply(HTTP.NOT_ALLOWED);
1896: error.setContent(dresource.getIdentifier()
1897: + " already exists!");
1898: throw new HTTPException(error);
1899: }
1900: } else {
1901: Reply error = request.makeReply(HTTP.NOT_ALLOWED);
1902: error.setContent(dresource.getIdentifier()
1903: + " already exists!");
1904: throw new HTTPException(error);
1905: }
1906: }
1907:
1908: protected org.w3c.www.protocol.webdav.DAVRequest createRequest(
1909: DAVRequest req, String mtd, URL url, Hashtable headers,
1910: InputStream in) {
1911: org.w3c.www.protocol.webdav.DAVRequest request = null;
1912: request = manager.createDAVRequest();
1913: request.setURL(url);
1914: request.setMethod(mtd);
1915: if (req.hasAuthorization()) {
1916: request.setAuthorization(req.getAuthorization());
1917: }
1918: if (headers != null) {
1919: Enumeration keys = headers.keys();
1920: while (keys.hasMoreElements()) {
1921: String header = (String) keys.nextElement();
1922: String value = (String) headers.get(header);
1923: request.setValue(header, value);
1924: }
1925: }
1926: if (in != null) {
1927: request.setOutputStream(in);
1928: }
1929: return request;
1930: }
1931:
1932: protected org.w3c.www.protocol.webdav.DAVRequest createRequest(
1933: DAVRequest request, String mtd, URL url, Hashtable headers) {
1934: return createRequest(request, mtd, url, headers,
1935: (InputStream) null);
1936: }
1937:
1938: protected org.w3c.www.protocol.webdav.DAVRequest createRequest(
1939: DAVRequest request, String mtd, URL url, Hashtable headers,
1940: Document document) {
1941: if (document != null) {
1942: ByteArrayOutputStream out = new ByteArrayOutputStream();
1943:
1944: OutputFormat format = new OutputFormat(document,
1945: WEBDAV.ENCODING, true);
1946: format.setOmitXMLDeclaration(false);
1947: format.setPreserveSpace(false);
1948: XMLSerializer serializer = new XMLSerializer(out, format);
1949: try {
1950: serializer.serialize(document);
1951: } catch (IOException ex) {
1952: ex.printStackTrace();
1953: }
1954:
1955: int len = out.size();
1956: if (headers == null) {
1957: headers = new Hashtable();
1958: }
1959: headers.put("Content-Length", String.valueOf(len));
1960: headers.put("Content-Type", xmlcontenttype.toString());
1961: InputStream in = new ByteArrayInputStream(out.toByteArray());
1962: return createRequest(request, mtd, url, headers, in);
1963: } else {
1964: return createRequest(request, mtd, url, headers,
1965: (InputStream) null);
1966: }
1967: }
1968:
1969: protected DAVRequest createInternalRequest(DAVRequest request,
1970: String mtd, URL url, Hashtable headers, Document document) {
1971: if (document != null) {
1972: ByteArrayOutputStream out = new ByteArrayOutputStream();
1973:
1974: OutputFormat format = new OutputFormat(document,
1975: WEBDAV.ENCODING, true);
1976: format.setOmitXMLDeclaration(false);
1977: format.setPreserveSpace(false);
1978: XMLSerializer serializer = new XMLSerializer(out, format);
1979: try {
1980: serializer.serialize(document);
1981: } catch (IOException ex) {
1982: ex.printStackTrace();
1983: }
1984:
1985: int len = out.size();
1986: if (headers == null) {
1987: headers = new Hashtable();
1988: }
1989: headers.put("Content-Length", String.valueOf(len));
1990: headers.put("Content-Type", xmlcontenttype.toString());
1991: InputStream in = new ByteArrayInputStream(out.toByteArray());
1992: return createInternalRequest(request, mtd, url, headers, in);
1993: } else {
1994: return createInternalRequest(request, mtd, url, headers,
1995: (InputStream) null);
1996: }
1997: }
1998:
1999: /**
2000: * Should be called to purge the reply, otherwise the connection won't
2001: * be marked idle and won't be reused.
2002: * @param reply the reply to purge.
2003: */
2004: protected void skipBody(org.w3c.www.protocol.webdav.DAVReply reply) {
2005: try {
2006: if (reply.hasInputStream()) {
2007: InputStream in = reply.getInputStream();
2008: byte buffer[] = new byte[256];
2009: try {
2010: if (debug) {
2011: System.out.println(">>> skipping body <<<<");
2012: int nb = -1;
2013: while ((nb = in.read(buffer)) != -1) {
2014: System.out.print(new String(buffer, 0, nb));
2015: }
2016: System.out.println(">>> end body <<<<\n");
2017: } else {
2018: while (in.read(buffer) != -1)
2019: ;
2020: }
2021: } catch (IOException ioex) {
2022: try {
2023: in.close();
2024: } catch (IOException ioex2) {
2025: }
2026: }
2027: }
2028: } catch (IOException ex) {
2029: //nothing to do
2030: }
2031: }
2032:
2033: protected void closeInternalReply(DAVReply reply) {
2034: if (reply.hasStream()) {
2035: try {
2036: reply.openStream().close();
2037: reply.setStream((InputStream) null);
2038: reply.setContentLength(0);
2039: } catch (IOException ex) {
2040: }
2041: }
2042: }
2043:
2044: protected DAVRequest createInternalRequest(DAVRequest req,
2045: String mtd, URL url, Hashtable headers, InputStream in) {
2046: DAVRequest request;
2047: request = (DAVRequest) req.getClone();
2048: request.setURL(url);
2049: request.setMethod(mtd);
2050: if (req.hasAuthorization()) {
2051: request.setAuthorization(req.getAuthorization());
2052: }
2053: if (headers != null) {
2054: Enumeration keys = headers.keys();
2055: while (keys.hasMoreElements()) {
2056: String header = (String) keys.nextElement();
2057: String value = (String) headers.get(header);
2058: request.setValue(header, value);
2059: }
2060: }
2061: if (in != null) {
2062: request.setStream(in);
2063: }
2064: request.setInternal(true);
2065: return request;
2066: }
2067:
2068: protected DAVRequest createInternalRequest(DAVRequest req,
2069: String mtd, URL url, Hashtable headers) {
2070: return createInternalRequest(req, mtd, url, headers,
2071: (InputStream) null);
2072: }
2073:
2074: private Reply internalCopy(DAVRequest request, URL dst)
2075: throws ProtocolException, ResourceException {
2076: DAVRequest req;
2077: DAVReply rep;
2078: req = createInternalRequest(request, "HEAD", dst, null);
2079: try {
2080: rep = (DAVReply) getServer().perform(req);
2081: closeInternalReply(rep);
2082: } catch (Exception ex) {
2083: Reply error = request.makeReply(HTTP.INTERNAL_SERVER_ERROR);
2084: error.setContent(ex.getMessage());
2085: throw new HTTPException(error);
2086: }
2087: boolean overwrite = false;
2088: if (rep.getStatus() != HTTP.NOT_FOUND) {
2089: overwrite = request.getOverwrite();
2090: if (!overwrite) {
2091: // 412 Precondition failed
2092: String msg = "The state of the destination is non-null";
2093: Reply error = request
2094: .makeReply(HTTP.PRECONDITION_FAILED);
2095: error.setContent(msg);
2096: return error;
2097: } else {
2098: // overwrite but DELETE before
2099: req = createInternalRequest(request, "DELETE", dst,
2100: null);
2101: try {
2102: rep = (DAVReply) getServer().perform(req);
2103: closeInternalReply(rep);
2104: } catch (Exception ex) {
2105: Reply error = request
2106: .makeReply(HTTP.INTERNAL_SERVER_ERROR);
2107: error.setContent(ex.getMessage());
2108: throw new HTTPException(error);
2109: }
2110: // silent error, if delete failed try to overwrite...
2111: }
2112: }
2113: // ok, perform the real copy now
2114: if (isCollection()) {
2115: return internalCopyCollection(dst, request, overwrite);
2116: } else {
2117: return internalCopyResource(dst, request, overwrite);
2118: }
2119: }
2120:
2121: /**
2122: * Handle the COPY request.
2123: * @param request the WEBDAV request
2124: * @return a Reply instance
2125: * @exception ProtocolException If processsing the request failed.
2126: * @exception ResourceException If the resource got a fatal error.
2127: */
2128: public Reply copy(DAVRequest request) throws ProtocolException,
2129: ResourceException {
2130: String dest = request.getDestination();
2131: URL src = getURL(request);
2132: URL dst = null;
2133: try {
2134: dst = new URL(dest);
2135: } catch (MalformedURLException ex) {
2136: Reply error = request.makeReply(HTTP.BAD_REQUEST);
2137: error.setContent("Invalid destination URL");
2138: throw new HTTPException(error);
2139: }
2140: // check that we're not going to copy on ourself
2141: if (dst.equals(src)) {
2142: // 403 Forbidden
2143: Reply error = request.makeReply(HTTP.FORBIDDEN);
2144: String msg = "The source and destination URIs are the same";
2145: error.setContent(msg);
2146: return error;
2147: }
2148: // is this local?
2149: if (URLUtils.equalsProtocolHostPort(src, dst)) {
2150: // yes, use only internal calls
2151: return internalCopy(request, dst);
2152: }
2153: // not local, use remote access procedure
2154:
2155: // check for overwrite
2156: org.w3c.www.protocol.webdav.DAVRequest crequest = null;
2157: org.w3c.www.protocol.webdav.DAVReply creply = null;
2158: crequest = createRequest(request, "HEAD", dst, null);
2159: try {
2160: creply = manager.runDAVRequest(crequest);
2161: skipBody(creply);
2162: } catch (org.w3c.www.protocol.http.HttpException ex) {
2163: Reply error = request.makeReply(HTTP.INTERNAL_SERVER_ERROR);
2164: error.setContent(ex.getMessage());
2165: throw new HTTPException(error);
2166: }
2167: boolean overwrite = false;
2168: if (creply.getStatus() != HTTP.NOT_FOUND) {
2169: overwrite = request.getOverwrite();
2170: if (!overwrite) {
2171: // 412 Precondition failed
2172: String msg = "The state of the destination is non-null";
2173: Reply error = request
2174: .makeReply(HTTP.PRECONDITION_FAILED);
2175: error.setContent(msg);
2176: return error;
2177: } else {
2178: // overwrite but DELETE before
2179: crequest = createRequest(request, "DELETE", dst, null);
2180: try {
2181: creply = manager.runDAVRequest(crequest);
2182: skipBody(creply);
2183: } catch (org.w3c.www.protocol.http.HttpException ex) {
2184: Reply error = request
2185: .makeReply(HTTP.INTERNAL_SERVER_ERROR);
2186: error.setContent(ex.getMessage());
2187: throw new HTTPException(error);
2188: }
2189: // silent error, if delete failed try to overwrite...
2190: }
2191: }
2192: // ok, perform the real copy now
2193: if (isCollection()) {
2194: return copyCollection(dst, request, overwrite);
2195: } else {
2196: return copyResource(dst, request, overwrite);
2197: }
2198: }
2199:
2200: /**
2201: * Kind of proxying the reply but only for headers.
2202: */
2203: protected Reply dupReply(DAVRequest request,
2204: org.w3c.www.protocol.webdav.DAVReply rep, boolean created) {
2205: Reply reply = null;
2206: if (created) {
2207: reply = request.makeReply(HTTP.NO_CONTENT);
2208: return reply;
2209: } else {
2210: reply = request.makeReply(rep.getStatus());
2211: }
2212: reply.setHeaderValue(Reply.H_SERVER, null);
2213: Enumeration e = rep.enumerateHeaderDescriptions();
2214: while (e.hasMoreElements()) {
2215: HeaderDescription d = (HeaderDescription) e.nextElement();
2216: HeaderValue v = rep.getHeaderValue(d);
2217: if (v != null)
2218: reply.setHeaderValue(d, v);
2219: }
2220: reply.setContentLength(0);
2221: reply.setHeaderValue(Reply.H_CONNECTION, null);
2222: reply.setHeaderValue(Reply.H_PROXY_CONNECTION, null);
2223: reply.setHeaderValue(Reply.H_PUBLIC, null);
2224: reply.setHeaderValue(Reply.H_TRANSFER_ENCODING, null);
2225: reply.setHeaderValue(Reply.H_UPGRADE, null);
2226: reply.setHeaderValue(Reply.H_CONTENT_TYPE, null);
2227: reply.removeHeader("keep-alive");
2228: return reply;
2229: }
2230:
2231: /**
2232: * Handle the COPY request for a collection
2233: * @param dst the destination URL
2234: * @param request the WEBDAV request
2235: * @return a Reply instance
2236: * @exception ProtocolException If processsing the request failed.
2237: * @exception ResourceException If the resource got a fatal error.
2238: */
2239: protected Reply copyCollection(URL destination, DAVRequest request,
2240: boolean overwrite) throws ProtocolException,
2241: ResourceException {
2242: DAVBody body = getBody(request);
2243: Document document = DAVBody
2244: .createDocument(DAVNode.MULTISTATUS_NODE);
2245: Reply reply = null;
2246: try {
2247: return copyCollection(destination, request, overwrite,
2248: body, document);
2249: } catch (MultiStatusException ex) {
2250: return createDAVReply(request, WEBDAV.MULTI_STATUS, ex
2251: .getDocument());
2252: }
2253: }
2254:
2255: /**
2256: * Handle the COPY request for a collection
2257: * @param dst the destination URL
2258: * @param request the WEBDAV request
2259: * @return a Reply instance
2260: * @exception ProtocolException If processsing the request failed.
2261: * @exception ResourceException If the resource got a fatal error.
2262: */
2263: private Reply internalCopyCollection(URL destination,
2264: DAVRequest request, boolean overwrite)
2265: throws ProtocolException, ResourceException {
2266: DAVBody body = getBody(request);
2267: Document document = DAVBody
2268: .createDocument(DAVNode.MULTISTATUS_NODE);
2269: Reply reply = null;
2270: try {
2271: return internalCopyCollection(destination, request,
2272: overwrite, body, document);
2273: } catch (MultiStatusException ex) {
2274: return createDAVReply(request, WEBDAV.MULTI_STATUS, ex
2275: .getDocument());
2276: }
2277: }
2278:
2279: protected Reply copyCollection(URL destination, DAVRequest request,
2280: boolean overwrite, DAVBody body, Document document)
2281: throws ProtocolException, ResourceException,
2282: MultiStatusException {
2283: // first copy myself
2284: // MKCOL
2285: org.w3c.www.protocol.webdav.DAVRequest crequest = null;
2286: org.w3c.www.protocol.webdav.DAVReply creply = null;
2287: crequest = createRequest(request, "MKCOL", destination, null);
2288: try {
2289: creply = manager.runDAVRequest(crequest);
2290: skipBody(creply);
2291: } catch (org.w3c.www.protocol.http.HttpException ex) {
2292: Reply error = request.makeReply(HTTP.INTERNAL_SERVER_ERROR);
2293: error.setContent(ex.getMessage());
2294: throw new HTTPException(error);
2295: }
2296: if (creply.getStatus() != HTTP.CREATED) {
2297: return dupReply(request, creply, false);
2298: }
2299: org.w3c.www.protocol.webdav.DAVReply mkcolreply = creply;
2300: // Copy Properties
2301: copyProperties(request, destination, body);
2302: // CHILDREN? (Depth can only be 0 or infinity see RFC 2518 - 8.8.3)
2303: if (request.getDepth() == 0) {
2304: // only me so return
2305: return dupReply(request, creply, overwrite);
2306: } else {
2307: // XML Document
2308: DAVMultiStatus dms = DAVFactory.createMultiStatus(document
2309: .getDocumentElement());
2310: boolean multistatus = false;
2311: // Children resource
2312: Enumeration e = dresource.enumerateResourceIdentifiers();
2313: ResourceReference rr = null;
2314: FramedResource fr = null;
2315: while (e.hasMoreElements()) {
2316: String name = (String) e.nextElement();
2317: rr = dresource.lookup(name);
2318: if (rr != null) {
2319: try {
2320: fr = (FramedResource) rr.lock();
2321: if (fr == resource) { // for root
2322: continue;
2323: }
2324: DAVFrame df = (DAVFrame) fr
2325: .getFrame(DAVFrame.class);
2326: URL dest = null;
2327: if (df != null) {
2328: try {
2329: dest = computeDestURL(destination, df);
2330: } catch (MalformedURLException ex) {
2331: Reply error = request
2332: .makeReply(HTTP.INTERNAL_SERVER_ERROR);
2333: String msg = "Can't build destination URI : "
2334: + ex.getMessage();
2335: error.setContent(msg);
2336: throw new HTTPException(error);
2337: }
2338: if (df.isCollection()) {
2339: try {
2340: // silent success
2341: df.copyCollection(dest, request,
2342: overwrite, body, document);
2343: } catch (MultiStatusException ex) {
2344: multistatus = true;
2345: ex.printStackTrace();
2346: ex.addResponses(document, dms);
2347: }
2348: } else {
2349: try {
2350: // silent success
2351: df.copyDAVResource(request, df
2352: .getURL(request), dest,
2353: body);
2354: } catch (MultiStatusException ex) {
2355: multistatus = true;
2356: ex.printStackTrace();
2357: // add to multistatus node
2358: ex.addResponses(document, dms);
2359: }
2360: }
2361: } else {
2362: // what should I do there?
2363: // nothing I guess
2364: }
2365: } catch (InvalidResourceException ex) {
2366: // build error response?
2367: } finally {
2368: rr.unlock();
2369: }
2370: }
2371: }
2372: if (multistatus) {
2373: throw new MultiStatusException(document);
2374: } else {
2375: return dupReply(request, mkcolreply, overwrite);
2376: }
2377: }
2378: }
2379:
2380: protected Reply internalCopyCollection(URL destination,
2381: DAVRequest request, boolean overwrite, DAVBody body,
2382: Document document) throws ProtocolException,
2383: ResourceException, MultiStatusException {
2384: // first copy myself
2385: // MKCOL
2386: DAVRequest crequest = null;
2387: DAVReply creply = null;
2388: crequest = createInternalRequest(request, "MKCOL", destination,
2389: null);
2390: try {
2391: creply = (DAVReply) getServer().perform(crequest);
2392: closeInternalReply(creply);
2393: } catch (Exception ex) {
2394: Reply error = request.makeReply(HTTP.INTERNAL_SERVER_ERROR);
2395: error.setContent(ex.getMessage());
2396: throw new HTTPException(error);
2397: }
2398: if (creply.getStatus() != HTTP.CREATED) {
2399: return creply;
2400: }
2401: DAVReply mkcolreply = creply;
2402: // Copy Properties
2403: internalCopyProperties(request, destination, body);
2404: // CHILDREN? (Depth can only be 0 or infinity see RFC 2518 - 8.8.3)
2405: if (request.getDepth() == 0) {
2406: // only me so return
2407: if (overwrite) {
2408: creply.setStatus(HTTP.NO_CONTENT);
2409: }
2410: return creply;
2411: } else {
2412: // XML Document
2413: DAVMultiStatus dms = DAVFactory.createMultiStatus(document
2414: .getDocumentElement());
2415: boolean multistatus = false;
2416: // Children resource
2417: Enumeration e = dresource.enumerateResourceIdentifiers();
2418: ResourceReference rr = null;
2419: FramedResource fr = null;
2420: while (e.hasMoreElements()) {
2421: String name = (String) e.nextElement();
2422: rr = dresource.lookup(name);
2423: if (rr != null) {
2424: try {
2425: fr = (FramedResource) rr.lock();
2426: if (fr == resource) { // for root
2427: continue;
2428: }
2429: DAVFrame df = (DAVFrame) fr
2430: .getFrame(DAVFrame.class);
2431: URL dest = null;
2432: if (df != null) {
2433: try {
2434: dest = computeDestURL(destination, df);
2435: } catch (MalformedURLException ex) {
2436: Reply error = request
2437: .makeReply(HTTP.INTERNAL_SERVER_ERROR);
2438: String msg = "Can't build destination URI : "
2439: + ex.getMessage();
2440: error.setContent(msg);
2441: throw new HTTPException(error);
2442: }
2443: if (df.isCollection()) {
2444: try {
2445: // silent success
2446: df.internalCopyCollection(dest,
2447: request, overwrite, body,
2448: document);
2449: } catch (MultiStatusException ex) {
2450: multistatus = true;
2451: ex.printStackTrace();
2452: ex.addResponses(document, dms);
2453: }
2454: } else {
2455: try {
2456: // silent success
2457: df.internalCopyDAVResource(request,
2458: df.getURL(request), dest,
2459: body);
2460: } catch (MultiStatusException ex) {
2461: multistatus = true;
2462: ex.printStackTrace();
2463: // add to multistatus node
2464: ex.addResponses(document, dms);
2465: }
2466: }
2467: } else {
2468: // what should I do there?
2469: // nothing I guess
2470: }
2471: } catch (InvalidResourceException ex) {
2472: // build error response?
2473: } finally {
2474: rr.unlock();
2475: }
2476: }
2477: }
2478: if (multistatus) {
2479: throw new MultiStatusException(document);
2480: } else {
2481: if (overwrite) {
2482: mkcolreply.setStatus(HTTP.NO_CONTENT);
2483: }
2484: return mkcolreply;
2485: }
2486: }
2487: }
2488:
2489: protected URL computeDestURL(URL parent, DAVFrame df)
2490: throws MalformedURLException {
2491: String file = parent.getFile();
2492: StringBuffer buffer = new StringBuffer(file);
2493: if (!file.endsWith("/")) {
2494: buffer.append("/");
2495: }
2496: buffer.append(df.getResource().getIdentifier());
2497: if (df.isCollection()) {
2498: buffer.append("/");
2499: }
2500: return new URL(parent, buffer.toString());
2501: }
2502:
2503: /**
2504: * Handle the COPY request for a simple resource (not a collection)
2505: * @param dst the destination URL
2506: * @param request the WEBDAV request
2507: * @return a Reply instance
2508: * @exception ProtocolException If processsing the request failed.
2509: * @exception ResourceException If the resource got a fatal error.
2510: */
2511: protected Reply copyResource(URL dst, DAVRequest request,
2512: boolean overwrite) throws ProtocolException,
2513: ResourceException {
2514: try {
2515: URL src = getURL(request);
2516: org.w3c.www.protocol.webdav.DAVReply reply = copyDAVResource(
2517: request, src, dst, getBody(request));
2518: if (overwrite) {
2519: reply.setStatus(HTTP.NO_CONTENT);
2520: }
2521: return dupReply(request, reply, overwrite);
2522: } catch (MultiStatusException ex) {
2523: return createDAVReply(request, WEBDAV.MULTI_STATUS, ex
2524: .getDocument());
2525: }
2526: }
2527:
2528: protected org.w3c.www.protocol.webdav.DAVReply copyDAVResource(
2529: DAVRequest req, URL source, URL destination, DAVBody body)
2530: throws MultiStatusException {
2531: DAVResponse dr = null;
2532: org.w3c.www.protocol.webdav.DAVRequest request = null;
2533: org.w3c.www.protocol.webdav.DAVReply reply = null;
2534: // perform the PUT request to send the body.
2535: // headers
2536: Hashtable headers = new Hashtable();
2537: headers.put("Content-Length", String
2538: .valueOf(getContentLength()));
2539: headers.put("Content-Type", getContentType().toString());
2540: // body
2541: InputStream in = null;
2542: try {
2543: in = new FileInputStream(fresource.getFile());
2544: } catch (IOException ex) {
2545: // error that should not occurs
2546: String msg = "Cannot read source file";
2547: throw new MultiStatusException(
2548: destination.toExternalForm(),
2549: getStatusLine(HTTP.INTERNAL_SERVER_ERROR), msg);
2550: }
2551: request = createRequest(req, "PUT", destination, headers, in);
2552: try {
2553: reply = manager.runDAVRequest(request);
2554: skipBody(reply);
2555: } catch (org.w3c.www.protocol.http.HttpException ex) {
2556: throw new MultiStatusException(
2557: destination.toExternalForm(),
2558: getStatusLine(HTTP.INTERNAL_SERVER_ERROR), ex
2559: .getMessage());
2560: }
2561: int putstatus = reply.getStatus();
2562: org.w3c.www.protocol.webdav.DAVReply putreply = reply;
2563: if (putstatus / 100 != 2) {
2564: // error
2565: throw new MultiStatusException(
2566: destination.toExternalForm(),
2567: getStatusLine(putstatus));
2568: }
2569: // now update properties
2570: copyProperties(req, destination, body);
2571: // done
2572: return putreply;
2573: }
2574:
2575: /**
2576: * Handle the COPY request for a simple resource (not a collection)
2577: * @param dst the destination URL
2578: * @param request the WEBDAV request
2579: * @return a Reply instance
2580: * @exception ProtocolException If processsing the request failed.
2581: * @exception ResourceException If the resource got a fatal error.
2582: */
2583: protected Reply internalCopyResource(URL dst, DAVRequest request,
2584: boolean overwrite) throws ProtocolException,
2585: ResourceException {
2586: try {
2587: URL src = getURL(request);
2588: DAVReply reply = internalCopyDAVResource(request, src, dst,
2589: getBody(request));
2590: if (overwrite) {
2591: reply.setStatus(HTTP.NO_CONTENT);
2592: }
2593: return reply;
2594: } catch (MultiStatusException ex) {
2595: return createDAVReply(request, WEBDAV.MULTI_STATUS, ex
2596: .getDocument());
2597: }
2598: }
2599:
2600: protected DAVReply internalCopyDAVResource(DAVRequest req,
2601: URL source, URL destination, DAVBody body)
2602: throws MultiStatusException {
2603: DAVResponse dr = null;
2604: DAVRequest request = null;
2605: DAVReply reply = null;
2606: // perform the PUT request to send the body.
2607: // headers
2608: Hashtable headers = new Hashtable();
2609: headers.put("Content-Length", String
2610: .valueOf(getContentLength()));
2611: headers.put("Content-Type", getContentType().toString());
2612: // body
2613: InputStream in = null;
2614: try {
2615: in = new FileInputStream(fresource.getFile());
2616: } catch (IOException ex) {
2617: // error that should not occurs
2618: String msg = "Cannot read source file";
2619: throw new MultiStatusException(
2620: destination.toExternalForm(),
2621: getStatusLine(HTTP.INTERNAL_SERVER_ERROR), msg);
2622: }
2623: request = createInternalRequest(req, "PUT", destination,
2624: headers, in);
2625: try {
2626: reply = (DAVReply) getServer().perform(request);
2627: closeInternalReply(reply);
2628: } catch (Exception ex) {
2629: throw new MultiStatusException(
2630: destination.toExternalForm(),
2631: getStatusLine(HTTP.INTERNAL_SERVER_ERROR), ex
2632: .getMessage());
2633: }
2634: int putstatus = reply.getStatus();
2635: DAVReply putreply = reply;
2636: if (putstatus / 100 != 2) {
2637: // error
2638: throw new MultiStatusException(
2639: destination.toExternalForm(),
2640: getStatusLine(putstatus));
2641: }
2642: // now update properties
2643: internalCopyProperties(req, destination, body);
2644: // done
2645: return putreply;
2646: }
2647:
2648: protected void copyProperties(DAVRequest req, URL destination,
2649: DAVBody body) throws MultiStatusException {
2650: org.w3c.www.protocol.webdav.DAVRequest request = null;
2651: org.w3c.www.protocol.webdav.DAVReply reply = null;
2652: // first try to copy all properties
2653: Document document = DAVBody
2654: .createDocument(DAVNode.PROPERTYUPDATE_NODE);
2655: DAVPropAction dpa = DAVFactory.createPropAction(
2656: DAVPropAction.SET, getPropertiesForCopy(document),
2657: document);
2658: document.getDocumentElement().appendChild(dpa.getNode());
2659: request = createRequest(req, "PROPPATCH", destination, null,
2660: document);
2661: try {
2662: reply = manager.runDAVRequest(request);
2663: skipBody(reply);
2664: } catch (org.w3c.www.protocol.http.HttpException ex) {
2665: throw new MultiStatusException(
2666: destination.toExternalForm(),
2667: getStatusLine(HTTP.INTERNAL_SERVER_ERROR), ex
2668: .getMessage());
2669: }
2670: // check with keepalive flag
2671: // FIXME
2672: if (body != null) {
2673: DAVPropertyBehavior dpb = body.getPropertyBehavior();
2674: if ((dpb != null) && (!dpb.omit())) {
2675: if (dpb.keepaliveAll()) {
2676:
2677: } else {
2678: String properties[] = dpb.getHrefs();
2679: }
2680: } else {
2681:
2682: }
2683: }
2684: }
2685:
2686: protected void internalCopyProperties(DAVRequest req,
2687: URL destination, DAVBody body) throws MultiStatusException {
2688: DAVRequest request = null;
2689: DAVReply reply = null;
2690: // first try to copy all properties
2691: Document document = DAVBody
2692: .createDocument(DAVNode.PROPERTYUPDATE_NODE);
2693: DAVPropAction dpa = DAVFactory.createPropAction(
2694: DAVPropAction.SET, getPropertiesForCopy(document),
2695: document);
2696: document.getDocumentElement().appendChild(dpa.getNode());
2697: request = createInternalRequest(req, "PROPPATCH", destination,
2698: null, document);
2699: try {
2700:
2701: reply = (DAVReply) getServer().perform(request);
2702: closeInternalReply(reply);
2703: } catch (Exception ex) {
2704: throw new MultiStatusException(
2705: destination.toExternalForm(),
2706: getStatusLine(HTTP.INTERNAL_SERVER_ERROR), ex
2707: .getMessage());
2708: }
2709: // check with keepalive flag
2710: // FIXME
2711: if (body != null) {
2712: DAVPropertyBehavior dpb = body.getPropertyBehavior();
2713: if ((dpb != null) && (!dpb.omit())) {
2714: if (dpb.keepaliveAll()) {
2715:
2716: } else {
2717: String properties[] = dpb.getHrefs();
2718: }
2719: } else {
2720:
2721: }
2722: }
2723: }
2724:
2725: /**
2726: * Handle the MOVE request.
2727: * @param request the WEBDAV request
2728: * @return a Reply instance
2729: * @exception ProtocolException If processsing the request failed.
2730: * @exception ResourceException If the resource got a fatal error.
2731: */
2732: public Reply move(DAVRequest request) throws ProtocolException,
2733: ResourceException {
2734: // check that we can be deleted
2735: if (getAllowDeleteFlag()) {
2736: Reply reply = copy(request);
2737: int status = reply.getStatus();
2738: if (status == HTTP.NO_CONTENT || status == HTTP.CREATED) {
2739: delete(request);
2740: return reply;
2741: } else {
2742: return reply;
2743: }
2744: }
2745: Reply error = request.makeReply(HTTP.NOT_ALLOWED);
2746: error.setContent("Method MOVE not allowed.");
2747: error.setHeaderValue(Reply.H_ALLOW, getAllow());
2748: throw new HTTPException(error);
2749: }
2750:
2751: protected synchronized String getNewLockToken() {
2752: return "opaquelocktoken:"
2753: + (new org.w3c.util.UUID()).toString();
2754: }
2755:
2756: /**
2757: * Handle the LOCK request.
2758: * @param request the WEBDAV request
2759: * @return a Reply instance
2760: * @exception ProtocolException If processsing the request failed.
2761: * @exception ResourceException If the resource got a fatal error.
2762: */
2763: public synchronized Reply lock(DAVRequest request)
2764: throws ProtocolException, ResourceException {
2765: DAVBody body = getBody(request);
2766: if (body == null) { // refresh?
2767: if (debug) {
2768: System.out.println(">>> Refreshing lock...");
2769: }
2770: refreshLock(request.getTimeout());
2771: Document doc = DAVBody.createDocument(DAVNode.PROP_NODE);
2772: addLockDiscovery(request, doc.getDocumentElement());
2773: Reply ok = createDAVReply(request, HTTP.OK, doc);
2774: return ok;
2775: } else { // real new lock
2776: String timeouts[] = request.getTimeout();
2777: DAVLockInfo lockinfo = body.getLockInfo();
2778: if (lockinfo != null) {
2779: Node owner = lockinfo.getOwner();
2780: lock(getNewLockToken(), request.getDepth(), request
2781: .getTimeout(), (String) request
2782: .getState(AuthFilter.STATE_AUTHUSER), owner);
2783: Document doc = DAVBody
2784: .createDocument(DAVNode.PROP_NODE);
2785: addLockDiscovery(request, doc.getDocumentElement());
2786: Reply ok = createDAVReply(request, HTTP.OK, doc);
2787: return ok;
2788: }
2789: // bad request
2790: Reply error = request.makeReply(HTTP.BAD_REQUEST);
2791: error.setContent("Invalid request: missing lockinfo");
2792: throw new HTTPException(error);
2793: }
2794: }
2795:
2796: /**
2797: * Handle the UNLOCK request.
2798: * @param request the WEBDAV request
2799: * @return a Reply instance
2800: * @exception ProtocolException If processsing the request failed.
2801: * @exception ResourceException If the resource got a fatal error.
2802: */
2803: public synchronized Reply unlock(DAVRequest request)
2804: throws ProtocolException, ResourceException {
2805: if (debug) {
2806: System.out.println(">>> UNLOCK");
2807: }
2808: if (!isLocked(request)) {
2809: // stupid client :)
2810: return request.makeReply(HTTP.NO_CONTENT);
2811: }
2812: // check the locktocken header
2813: String token = request.getLockToken();
2814: if (token != null) {
2815: String mytoken = getCurrentLockToken(request);
2816: String rtoken = decodeURL(request, token);
2817: if (debug) {
2818: System.out.println("REQ TOKEN : [" + rtoken + "]");
2819: System.out.println("LOCK TOKEN : [" + mytoken + "]");
2820: }
2821: if (rtoken.equals(mytoken) && checkLockOwner(request)) {
2822: if (definesAttribute(ATTR_LOCK_TOKEN)) {
2823: unlock();
2824: } else {
2825: ResourceReference rr = (ResourceReference) request
2826: .getState(LOCKED_REREFENCE);
2827: if (rr == null) {
2828: Reply error = request
2829: .makeReply(HTTP.INTERNAL_SERVER_ERROR);
2830: error
2831: .setContent("Unable to unlock, no request state");
2832: throw new HTTPException(error);
2833: } else {
2834: try {
2835: DAVFrame fr = (DAVFrame) rr.lock();
2836: fr.unlock();
2837: } catch (Exception ex) {
2838: ex.printStackTrace();
2839: Reply error = request
2840: .makeReply(HTTP.INTERNAL_SERVER_ERROR);
2841: error.setContent(ex.getMessage());
2842: throw new HTTPException(error);
2843: } finally {
2844: rr.unlock();
2845: }
2846: }
2847: }
2848: return request.makeReply(HTTP.NO_CONTENT);
2849: } else {
2850: Reply reply = request.makeReply(WEBDAV.LOCKED);
2851: reply.setContent("The resource is locked");
2852: return reply;
2853: }
2854: }
2855: // sorry
2856: Reply error = request.makeReply(HTTP.FORBIDDEN);
2857: error.setContent("You are not allowed to unlock this resource");
2858: throw new HTTPException(error);
2859: }
2860:
2861: private void updateStates(DAVRequest request) {
2862: if (getCurrentLockDepth() == WEBDAV.DEPTH_INFINITY) {
2863: // propagate the lock
2864: request.setState(LOCKED_REREFENCE, getResourceReference());
2865: request.setState(LOCK_OWNER, getCurrentLockOwner(null));
2866: request.setState(LOCK_TOKEN, getCurrentLockToken(null));
2867: request.setState(LOCK_USERNAME,
2868: getCurrentLockUsername(null));
2869: request.setState(LOCK_EXPIRE, new Long(
2870: getTokenExpirationDate(null)));
2871: request.setState(LOCK_TIMEOUT, getValue(ATTR_LOCK_TIMEOUT,
2872: DEFAULT_LOCK_TIMEOUT));
2873: }
2874: }
2875:
2876: /**
2877: * Lookup the target resource (dispath to more specific lookup methods).
2878: * @param ls The current lookup state
2879: * @param lr The result
2880: * @return true if lookup is done.
2881: * @exception ProtocolException If an error relative to the protocol occurs
2882: * @see #lookupDirectory
2883: * @see #lookupFile
2884: * @see #lookupOther
2885: */
2886: protected boolean lookupResource(LookupState ls, LookupResult lr)
2887: throws ProtocolException {
2888: DAVRequest request = (DAVRequest) ls.getRequest();
2889: if ((request != null) && (isLocked(null))) {
2890: updateLockDate(request);
2891: }
2892: return super .lookupResource(ls, lr);
2893: }
2894:
2895: /**
2896: * Lookup the target resource when associated with a DirectoryResource.
2897: * @param ls The current lookup state
2898: * @param lr The result
2899: * @return true if lookup is done.
2900: * @exception ProtocolException If an error relative to the protocol
2901: * occurs
2902: */
2903: protected boolean lookupDirectory(LookupState ls, LookupResult lr)
2904: throws ProtocolException {
2905: // handle PUT and MKCOL
2906: // refresh the timeout value
2907: DAVRequest request = (DAVRequest) ls.getRequest();
2908: if (request == null) {
2909: return super .lookupDirectory(ls, lr);
2910: }
2911: if (isLocked(null)) {
2912: updateStates(request);
2913: }
2914: if (ls.hasMoreComponents()) {
2915: if (request.getMethod().equals("PUT")) {
2916: String name = ls.peekNextComponent();
2917: ResourceReference rr = dresource.lookup(name);
2918: if ((rr == null) && dresource.getExtensibleFlag()
2919: && getPutableFlag()) {
2920: // the resource doesn't exists
2921: if (ls.countRemainingComponents() == 1) {
2922: rr = dresource.createResource(name, request);
2923: if (rr == null) {
2924: Reply error = request
2925: .makeReply(HTTP.UNSUPPORTED_MEDIA_TYPE);
2926: error
2927: .setContent("Failed to create resource "
2928: + name
2929: + " : "
2930: + "Unable to create the appropriate file:"
2931: + request.getURLPath()
2932: + " this media type is not supported");
2933: throw new HTTPException(error);
2934: }
2935: } else { //FORBIDDEN IN WEBDAV
2936: Reply error = request.makeReply(HTTP.CONFLICT);
2937: error.setContent(name + " does not exists!");
2938: throw new HTTPException(error);
2939: }
2940: } else if (rr == null) {
2941: Reply error = request.makeReply(HTTP.FORBIDDEN);
2942: error
2943: .setContent("You are not allowed to create resource "
2944: + name
2945: + " : "
2946: + dresource.getIdentifier()
2947: + " is not extensible.");
2948: throw new HTTPException(error);
2949: }
2950: } else if (request.getMethod().equals("MKCOL")) {
2951: String name = ls.peekNextComponent();
2952: ResourceReference rr = dresource.lookup(name);
2953: if (rr == null) {
2954: if (ls.countRemainingComponents() == 1) {
2955: request.setState(REMAINING_PATH, name);
2956: return true;
2957: } else {
2958: Reply error = request.makeReply(HTTP.CONFLICT);
2959: error.setContent("Can't create "
2960: + ls.getRemainingPath(true));
2961: throw new HTTPException(error);
2962: }
2963: }
2964: }
2965: }
2966: // normal lookup
2967: if (super .lookupOther(ls, lr)) {
2968: if (!ls.isDirectory() && !ls.isInternal()) {
2969: // The directory lookup URL doesn't end with a slash:
2970: if (request == null) {
2971: lr.setTarget(null);
2972: return true;
2973: } else if (!acceptRedirect(request)) {
2974: return true;
2975: }
2976: URL url = null;
2977: try {
2978: if ((request != null)
2979: && request.hasState(Request.ORIG_URL_STATE)) {
2980: URL oldurl;
2981: oldurl = (URL) request
2982: .getState(Request.ORIG_URL_STATE);
2983: url = new URL(oldurl, oldurl.getFile() + "/");
2984: } else {
2985: url = (ls.hasRequest() ? getURL(request)
2986: : new URL(getServer().getURL(),
2987: resource.getURLPath()));
2988: }
2989: } catch (MalformedURLException ex) {
2990: getServer().errlog(this ,
2991: "unable to build full URL.");
2992: throw new HTTPException("Internal server error");
2993: }
2994: String msg = "Invalid requested URL: the directory resource "
2995: + " you are trying to reach is available only through "
2996: + " its full URL: <a href=\""
2997: + url
2998: + "\">"
2999: + url + "</a>.";
3000: if (getRelocateFlag()) {
3001: // Emit an error (with reloc if allowed)
3002: Reply reloc = request.makeReply(HTTP.FOUND);
3003: reloc.setContent(msg);
3004: reloc.setLocation(url);
3005: lr.setTarget(null);
3006: lr.setReply(reloc);
3007: return true;
3008: } else {
3009: Reply error = request.makeReply(HTTP.NOT_FOUND);
3010: error.setContent(msg);
3011: lr.setTarget(null);
3012: lr.setReply(error);
3013: return true;
3014: }
3015: } else if (!ls.isInternal() && acceptRedirect(request)) {
3016: request.setState(STATE_CONTENT_LOCATION, "true");
3017: // return the index file.
3018: String indexes[] = getIndexes();
3019: if (indexes != null) {
3020: for (int i = 0; i < indexes.length; i++) {
3021: String index = indexes[i];
3022: if (index != null && index.length() > 0) {
3023: DirectoryResource dir = (DirectoryResource) resource;
3024: ResourceReference rr = dir.lookup(index);
3025: if (rr != null) {
3026: try {
3027: FramedResource rindex = (FramedResource) rr
3028: .lock();
3029: return rindex.lookup(ls, lr);
3030: } catch (InvalidResourceException ex) {
3031: } finally {
3032: rr.unlock();
3033: }
3034: }
3035: }
3036: }
3037: }
3038: }
3039: return true;
3040: }
3041: return false;
3042: }
3043:
3044: /**
3045: * companion to initialize, called after the register
3046: */
3047: public void registerResource(FramedResource resource) {
3048: super .registerResource(resource);
3049: ObservableProperties props = getResource().getServer()
3050: .getProperties();
3051: manager = org.w3c.www.protocol.webdav.DAVManager
3052: .getDAVManager(props);
3053: }
3054:
3055: public void initialize(Object values[]) {
3056: super .initialize(values);
3057: if (getCreationDate() == -1) { // first time
3058: setValue(ATTR_CREATION_DATE, new Long(System
3059: .currentTimeMillis()));
3060: }
3061: }
3062:
3063: }
|