/**
   * Processes the request and returns a response. Calls {@link
   * DavResourceFactory.createResource(DavResourceLocator, DavRequest, DavResponse)} to find the
   * targeted resource. Calls {@link #preconditions(DavRequest, DavResponse, DavResource)} to verify
   * preconditions. Calls {@link #process(DavRequest, DavResponse, DavResource)} to execute the
   * verified request.
   *
   * <p>Invalid preconditions and processing exceptions are handled by sending a response with the
   * appropriate error status and message and an entity describing the error.
   */
  public void handleRequest(HttpServletRequest request, HttpServletResponse response)
      throws ServletException, IOException {

    DavRequest wreq = null;
    DavResponse wres = null;

    try {
      wreq = createDavRequest(request);
      wres = createDavResponse(response);

      DavResource resource = resolveTarget(wreq);
      preconditions(wreq, wres, resource);
      process(wreq, wres, resource);
    } catch (CosmoSecurityException e) {
      // handle security errors
      NeedsPrivilegesException npe = null;
      // Determine required privilege if we can and include
      // in response
      if (e instanceof ItemSecurityException) {
        ItemSecurityException ise = (ItemSecurityException) e;
        DavPrivilege priv =
            ise.getPermission() == Permission.READ ? DavPrivilege.READ : DavPrivilege.WRITE;
        npe = new NeedsPrivilegesException(wreq.getRequestURI(), priv);
      } else {
        // otherwise send generic response
        npe = new NeedsPrivilegesException(e.getMessage());
      }
      wres.sendDavError(npe);
    } catch (Throwable e) {
      DavException de = null;
      if (e instanceof DavException) {
        de = (DavException) e;
      } else {
        de = new DavException(e);
        // stuff the exception into a request attribute so that
        // filters can examine it
        request.setAttribute(ATTR_SERVICE_EXCEPTION, e);
      }

      if (de.getErrorCode() >= 500) log.error("Internal dav error", e);
      else if (de.getErrorCode() >= 400 && de.getMessage() != null)
        log.info("Client error (" + de.getErrorCode() + "): " + de.getMessage());
      wres.sendDavError(de);
    }
  }
  private void ifMatch(DavRequest request, DavResponse response, DavResource resource)
      throws DavException, IOException {
    EntityTag[] requestEtags = request.getIfMatch();
    if (requestEtags.length == 0) return;

    EntityTag resourceEtag = etag(resource);
    if (resourceEtag == null) return;

    if (EntityTag.matchesAny(resourceEtag, requestEtags)) return;

    if (resourceEtag != null) response.setHeader("ETag", resourceEtag.toString());

    throw new PreconditionFailedException("If-Match disallows conditional request");
  }
  private void ifUnmodifiedSince(DavRequest request, DavResponse response, DavResource resource)
      throws DavException, IOException {
    if (resource == null) return;

    long mod = resource.getModificationTime();
    if (mod == -1) return;
    mod = mod / 1000 * 1000;

    long since = request.getDateHeader("If-Unmodified-Since");
    if (since == -1) return;

    if (mod <= since) return;

    throw new PreconditionFailedException("If-Unmodified-Since disallows conditional request");
  }
  private void ifModifiedSince(DavRequest request, DavResponse response, DavResource resource)
      throws DavException, IOException {
    if (resource == null) return;

    long mod = resource.getModificationTime();
    if (mod == -1) return;
    mod = mod / 1000 * 1000;

    long since = request.getDateHeader("If-Modified-Since");
    if (since == -1) return;

    if (mod > since) return;

    throw new NotModifiedException();
  }
  private void ifNoneMatch(DavRequest request, DavResponse response, DavResource resource)
      throws DavException, IOException {
    EntityTag[] requestEtags = request.getIfNoneMatch();
    if (requestEtags.length == 0) return;

    EntityTag resourceEtag = etag(resource);
    if (resourceEtag == null) return;

    if (!EntityTag.matchesAny(resourceEtag, requestEtags)) return;

    if (resourceEtag != null) response.addHeader("ETag", resourceEtag.toString());

    if (deservesNotModified(request)) throw new NotModifiedException();
    else throw new PreconditionFailedException("If-None-Match disallows conditional request");
  }
 private boolean deservesNotModified(DavRequest request) {
   return (request.getMethod().equals("GET") || request.getMethod().equals("HEAD"));
 }
 /**
  * Creates an instance of <code>DavResource</code> representing the resource targeted by the
  * request.
  */
 protected DavResource resolveTarget(DavRequest request) throws DavException {
   return resourceFactory.resolve(request.getResourceLocator(), request);
 }
  /**
   * Hands the request off to a provider method for handling. The provider is created by calling
   * {@link #createProvider(DavResource)}. The specific provider method is chosen by examining the
   * request method.
   */
  protected void process(DavRequest request, DavResponse response, DavResource resource)
      throws IOException, DavException {
    DavProvider provider = createProvider(resource);

    if (request.getMethod().equals("OPTIONS")) options(request, response, resource);
    else if (request.getMethod().equals("GET")) provider.get(request, response, resource);
    else if (request.getMethod().equals("HEAD")) provider.head(request, response, resource);
    else if (request.getMethod().equals("PROPFIND")) provider.propfind(request, response, resource);
    else if (request.getMethod().equals("PROPPATCH"))
      provider.proppatch(request, response, resource);
    else if (request.getMethod().equals("DELETE")) provider.delete(request, response, resource);
    else if (request.getMethod().equals("COPY")) provider.copy(request, response, resource);
    else if (request.getMethod().equals("MOVE")) provider.move(request, response, resource);
    else if (request.getMethod().equals("REPORT")) provider.report(request, response, resource);
    else if (request.getMethod().equals("MKTICKET")) provider.mkticket(request, response, resource);
    else if (request.getMethod().equals("DELTICKET"))
      provider.delticket(request, response, resource);
    else if (request.getMethod().equals("ACL")) provider.acl(request, response, resource);
    else {
      if (resource.isCollection()) {
        if (request.getMethod().equals("MKCOL"))
          provider.mkcol(request, response, (DavCollection) resource);
        else if (request.getMethod().equals("MKCALENDAR"))
          provider.mkcalendar(request, response, (DavCollection) resource);
        else
          throw new MethodNotAllowedException(
              request.getMethod() + " not allowed for a collection");
      } else {
        if (request.getMethod().equals("PUT"))
          provider.put(request, response, (DavContent) resource);
        else
          throw new MethodNotAllowedException(
              request.getMethod() + " not allowed for a non-collection resource");
      }
    }
  }