All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.milton.http.webdav2.LockHandler Maven / Gradle / Ivy

Go to download

Milton Enterprise: Supports DAV level 2 and above, including Caldav and Carddav. Available on AGPL or commercial licenses

There is a newer version: 4.0.5.2400
Show newest version
/*
 * Copyright 2012 McEvoy Software Ltd.
 */
package io.milton.http.webdav2;

import io.milton.resource.Resource;
import io.milton.resource.LockingCollectionResource;
import io.milton.resource.LockableResource;
import io.milton.common.Path;
import io.milton.http.Request.Method;
import io.milton.http.Response.Status;
import io.milton.http.*;
import io.milton.http.exceptions.*;
import io.milton.http.webdav.WebDavResponseHandler;
import io.milton.webdav.utils.LockUtils;

import java.io.IOException;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xml.sax.SAXException;

/**
 * Note that this is both a new entity handler and an existing entity handler
 *
 * @author brad
 */
public class LockHandler implements ResourceHandler {

    private static final Logger log = LoggerFactory.getLogger(LockHandler.class);

    private final WebDavResponseHandler responseHandler;
    private final HandlerHelper handlerHelper;

    public LockHandler(WebDavResponseHandler responseHandler, HandlerHelper handlerHelper) {
        this.responseHandler = responseHandler;
        this.handlerHelper = handlerHelper;
        LockUtils.init();
    }

    @Override
    public void processResource(HttpManager manager, Request request, Response response, Resource r) throws NotAuthorizedException, ConflictException, BadRequestException {
        throw new UnsupportedOperationException("Not supported yet.");
    }

    @Override
    public String[] getMethods() {
        return new String[]{Method.LOCK.code};
    }

    @Override
    public void process(HttpManager manager, Request request, Response response) throws NotAuthorizedException, BadRequestException {
        if (!handlerHelper.checkExpects(responseHandler, request, response)) {
            return;
        }

        String host = request.getHostHeader();
        String url = HttpManager.decodeUrl(request.getAbsolutePath());

        // Find a resource if it exists
        Resource r = manager.getResourceFactory().getResource(host, url);
        if (r != null) {
            log.debug("locking existing resource: {}", r.getName());
            processExistingResource(manager, request, response, r);
        } else {
            log.debug("lock target doesnt exist, attempting lock null..");
            processNonExistingResource(manager, request, response, host, url);
        }
    }

    protected void processExistingResource(HttpManager manager, Request request, Response response, Resource resource) throws NotAuthorizedException {
        if (handlerHelper.isNotCompatible(resource, request.getMethod()) || !isCompatible(resource)) {
            responseHandler.respondMethodNotImplemented(resource, response, request);
            return;
        }
        if (!handlerHelper.checkAuthorisation(manager, resource, request)) {
            responseHandler.respondUnauthorised(resource, response, request);
            return;
        }

        handlerHelper.checkExpects(responseHandler, request, response);

        LockableResource r = (LockableResource) resource;
        LockTimeout timeout = LockTimeout.parseTimeout(request);
        String ifHeader = request.getIfHeader();
        response.setContentTypeHeader(Response.XML);
        if (ifHeader == null || ifHeader.length() == 0) {
            processNewLock(manager, request, response, r, timeout);
        } else {
            processRefresh(manager, request, response, r, timeout, ifHeader);
        }
    }

    /**
     * (from the spec) 7.4 Write Locks and Null Resources
     * 

* It is possible to assert a write lock on a null resource in order to lock * the name. *

* A write locked null resource, referred to as a lock-null resource, MUST * respond with a 404 (Not Found) or 405 (Method Not Allowed) to any * HTTP/1.1 or DAV methods except for PUT, MKCOL, OPTIONS, PROPFIND, LOCK, * and UNLOCK. A lock-null resource MUST appear as a member of its parent * collection. Additionally the lock-null resource MUST have defined on it * all mandatory DAV properties. Most of these properties, such as all the * get* properties, will have no value as a lock-null resource does not * support the GET method. Lock-Null resources MUST have defined values for * lockdiscovery and supportedlock properties. *

* Until a method such as PUT or MKCOL is successfully executed on the * lock-null resource the resource MUST stay in the lock-null state. * However, once a PUT or MKCOL is successfully executed on a lock-null * resource the resource ceases to be in the lock-null state. *

* If the resource is unlocked, for any reason, without a PUT, MKCOL, or * similar method having been successfully executed upon it then the * resource MUST return to the null state. * * @param manager * @param request * @param response * @param host * @param url */ private void processNonExistingResource(HttpManager manager, Request request, Response response, String host, String url) throws NotAuthorizedException, BadRequestException { String name; Path parentPath = Path.path(url); name = parentPath.getName(); parentPath = parentPath.getParent(); url = parentPath.toString(); Resource r = manager.getResourceFactory().getResource(host, url); if (r != null) { if (!handlerHelper.checkAuthorisation(manager, r, request)) { responseHandler.respondUnauthorised(r, response, request); return; } else { processCreateAndLock(manager, request, response, r, name); } } else { log.debug("couldnt find parent to execute lock-null, returning not found"); //respondNotFound(response,request); response.setStatus(Status.SC_CONFLICT); } } private void processCreateAndLock(HttpManager manager, Request request, Response response, Resource parentResource, String name) throws NotAuthorizedException { if (parentResource instanceof LockingCollectionResource) { log.debug("parent supports lock-null. doing createAndLock"); LockingCollectionResource lockingParent = (LockingCollectionResource) parentResource; LockTimeout timeout = LockTimeout.parseTimeout(request); response.setContentTypeHeader(Response.XML); LockInfo lockInfo; try { lockInfo = LockInfoSaxHandler.parseLockInfo(request); } catch (SAXException | IOException ex) { throw new RuntimeException("Exception reading request body", ex); } // TODO: this should be refactored to return a LockResult as for existing entities log.debug("Creating lock on unmapped resource: " + name); LockToken tok = lockingParent.createAndLock(name, timeout, lockInfo); if (tok == null) { throw new RuntimeException("createAndLock returned null, from resource of type: " + lockingParent.getClass().getCanonicalName()); } response.setStatus(Status.SC_CREATED); response.setLockTokenHeader(""); // spec says to set response header. See 8.10.1 LockUtils.respondLocked(tok, request, response); } else { log.debug("parent does not support lock-null, respondong method not allowed"); responseHandler.respondMethodNotImplemented(parentResource, response, request); } } @Override public boolean isCompatible(Resource handler) { return handler instanceof LockableResource; } protected void processNewLock(HttpManager milton, Request request, Response response, LockableResource r, LockTimeout timeout) throws NotAuthorizedException { LockInfo lockInfo; try { lockInfo = LockInfoSaxHandler.parseLockInfo(request); } catch (SAXException | IOException ex) { throw new RuntimeException("Exception reading request body", ex); } if (handlerHelper.isLockedOut(request, r)) { this.responseHandler.respondLocked(request, response, r); return; } log.debug("locking: {}", r.getName()); LockResult result; try { result = r.lock(timeout, lockInfo); } catch (PreConditionFailedException ex) { responseHandler.respondPreconditionFailed(request, response, r); return; } catch (LockedException ex) { responseHandler.respondLocked(request, response, r); return; } if (result.isSuccessful()) { LockToken tok = result.getLockToken(); log.debug("..locked ok: {}", tok.tokenId); response.setLockTokenHeader(""); // spec says to set response header. See 8.10.1 LockUtils.respondLocked(tok, request, response); } else { LockUtils.respondLockFailure(result, request, response); } } protected void processRefresh(HttpManager milton, Request request, Response response, LockableResource r, LockTimeout timeout, String ifHeader) throws NotAuthorizedException { String token = LockUtils.parse(ifHeader); log.debug("refreshing lock: {}", token); LockResult result; try { result = r.refreshLock(token, timeout); } catch (PreConditionFailedException ex) { responseHandler.respondPreconditionFailed(request, response, r); return; } if (result == null) { throw new NullPointerException("Null lock result returned from: " + r.getClass()); } if (result.isSuccessful()) { LockToken tok = result.getLockToken(); response.setLockTokenHeader(""); // spec says to set response header. See 8.10.1 LockUtils.respondLocked(tok, request, response); } else { LockUtils.respondLockFailure(result, request, response); } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy