View Javadoc

1   package com.bradmcevoy.http.webdav;
2   
3   import com.bradmcevoy.http.*;
4   import com.bradmcevoy.http.Request.Method;
5   import com.bradmcevoy.http.exceptions.BadRequestException;
6   import com.bradmcevoy.http.exceptions.ConflictException;
7   import com.bradmcevoy.http.exceptions.NotAuthorizedException;
8   import org.slf4j.Logger;
9   import org.slf4j.LoggerFactory;
10  
11  import java.net.URI;
12  
13  public class CopyHandler implements ExistingEntityHandler {
14  
15      private Logger log = LoggerFactory.getLogger(CopyHandler.class);
16      private final WebDavResponseHandler responseHandler;
17      private final HandlerHelper handlerHelper;
18      private final ResourceHandlerHelper resourceHandlerHelper;
19      private DeleteHelper deleteHelper;
20      private UserAgentHelper userAgentHelper = new DefaultUserAgentHelper();
21      private boolean deleteExistingBeforeCopy = true;
22  
23      public CopyHandler(WebDavResponseHandler responseHandler, HandlerHelper handlerHelper, ResourceHandlerHelper resourceHandlerHelper) {
24          this.responseHandler = responseHandler;
25          this.handlerHelper = handlerHelper;
26          this.resourceHandlerHelper = resourceHandlerHelper;
27          this.deleteHelper = new DeleteHelperImpl(handlerHelper);
28      }
29  
30      public String[] getMethods() {
31          return new String[]{Method.COPY.code};
32      }
33  
34      @Override
35      public boolean isCompatible(Resource handler) {
36          return (handler instanceof CopyableResource);
37      }
38  
39      public void processResource(HttpManager manager, Request request, Response response, Resource r) throws NotAuthorizedException, ConflictException, BadRequestException {
40          resourceHandlerHelper.processResource(manager, request, response, r, this);
41      }
42  
43      public void process(HttpManager httpManager, Request request, Response response) throws ConflictException, NotAuthorizedException, BadRequestException {
44          resourceHandlerHelper.process(httpManager, request, response, this);
45      }
46  
47      public void processExistingResource(HttpManager manager, Request request, Response response, Resource resource) throws NotAuthorizedException, BadRequestException, ConflictException {
48          CopyableResource r = (CopyableResource) resource;
49          String sDest = request.getDestinationHeader();
50          sDest = HttpManager.decodeUrl(sDest);
51          URI destUri = URI.create(sDest);
52          sDest = destUri.getPath();
53  
54          Dest dest = new Dest(destUri.getHost(), sDest);
55          Resource rDest = manager.getResourceFactory().getResource(dest.host, dest.url);
56          log.debug("process: copying from: " + r.getName() + " -> " + dest.url + "/" + dest.name);
57  
58          if (rDest == null) {
59              log.debug("process: destination parent does not exist: " + sDest);
60              responseHandler.respondConflict(resource, response, request, "Destination does not exist: " + sDest);
61          } else if (!(rDest instanceof CollectionResource)) {
62              log.debug("process: destination exists but is not a collection");
63              responseHandler.respondConflict(resource, response, request, "Destination exists but is not a collection: " + sDest);
64          } else {
65              log.debug("process: copy resource to: " + rDest.getName());
66  
67              Resource fDest = manager.getResourceFactory().getResource(dest.host, dest.url + "/" + dest.name);
68              if (handlerHelper.isLockedOut(request, fDest)) {
69                  responseHandler.respondLocked(request, response, resource);
70                  return;
71              } else {
72                  boolean wasDeleted = false;
73                  CollectionResource colDest = (CollectionResource) rDest;
74                  Resource rExisting = colDest.child(dest.name);
75                  if (rExisting != null) {
76                      if( !canOverwrite( request ) ) {
77                          // Exists, and overwrite = F, disallow - http://www.webdav.org/specs/rfc4918.html#rfc.section.9.8.4
78                          responseHandler.respondPreconditionFailed(request, response, resource);
79                          return;
80                      } else {
81                          // Overwrite is absent or T, so continue
82                          if (deleteHelper.isLockedOut(request, rExisting)) {
83                              log.info("copy destination exists but is locked");
84                              responseHandler.respondPreconditionFailed(request, response, resource);
85                              return;
86                          } else {
87                              if (deleteExistingBeforeCopy) {
88                                  if (rExisting instanceof DeletableResource) {
89                                      log.debug("copy destination exists and is deletable, delete it..");
90                                      DeletableResource dr = (DeletableResource) rExisting;
91                                      deleteHelper.delete(dr);
92                                      wasDeleted = true;
93                                  } else {
94                                      log.warn("copy destination exists and is a collection so must be deleted, but does not implement: " + DeletableResource.class);
95                                      responseHandler.respondConflict(rExisting, response, request, sDest);
96                                      return;
97                                  }
98                              }
99                          }
100                     }
101                 }
102                 r.copyTo(colDest, dest.name);
103 
104                 // See http://www.ettrema.com:8080/browse/MIL-87
105                 if (wasDeleted) {
106                     responseHandler.respondNoContent( resource, response, request );
107                 } else {
108                     responseHandler.respondCreated(resource, response, request);
109                 }
110 
111             }
112         }
113     }
114 
115     public void setDeleteExistingBeforeCopy(boolean deleteExistingBeforeCopy) {
116         this.deleteExistingBeforeCopy = deleteExistingBeforeCopy;
117     }
118 
119     public boolean isDeleteExistingBeforeCopy() {
120         return deleteExistingBeforeCopy;
121     }
122 
123     private boolean canOverwrite( Request request ) {
124         Boolean ow = request.getOverwriteHeader();
125         boolean bHasOverwriteHeader = ( ow != null && request.getOverwriteHeader().booleanValue() );
126         if( bHasOverwriteHeader) {
127             return true;
128         } else {
129             String us = request.getUserAgentHeader();
130             if( userAgentHelper.isMacFinder( us)) {
131                 log.debug( "no overwrite header, but user agent is Finder so permit overwrite");
132                 return true;
133             } else {
134                 return false;
135             }
136         }
137     }
138 
139     public UserAgentHelper getUserAgentHelper() {
140         return userAgentHelper;
141     }
142 
143     public void setUserAgentHelper( UserAgentHelper userAgentHelper ) {
144         this.userAgentHelper = userAgentHelper;
145     }
146 
147 }