1
18 package org.torweg.pulse.webdav;
19
20 import java.io.IOException;
21 import java.io.InputStream;
22 import java.io.OutputStream;
23 import java.net.URI;
24 import java.net.URISyntaxException;
25
26 import javax.servlet.http.HttpServlet;
27 import javax.servlet.http.HttpServletRequest;
28 import javax.servlet.http.HttpServletResponse;
29
30 import org.apache.log4j.NDC;
31 import org.hibernate.Session;
32 import org.hibernate.Transaction;
33 import org.jdom.Namespace;
34 import org.slf4j.Logger;
35 import org.slf4j.LoggerFactory;
36 import org.torweg.pulse.accesscontrol.User;
37 import org.torweg.pulse.invocation.lifecycle.Lifecycle;
38 import org.torweg.pulse.service.PulseException;
39 import org.torweg.pulse.util.MimeMap;
40 import org.torweg.pulse.util.streamscanner.InacceptableStreamException;
41 import org.torweg.pulse.util.streamscanner.InputStreamScannerChain;
42 import org.torweg.pulse.vfs.IllegalFileNameException;
43 import org.torweg.pulse.vfs.VFSDAVStore;
44 import org.torweg.pulse.vfs.VirtualFile;
45 import org.torweg.pulse.vfs.VirtualFileSystem;
46 import org.torweg.pulse.webdav.request.DAVMethod;
47 import org.torweg.pulse.webdav.request.HttpDAVServletRequest;
48 import org.torweg.pulse.webdav.request.PropFindRequest;
49 import org.torweg.pulse.webdav.request.PropPatchRequest;
50 import org.torweg.pulse.webdav.request.PropPatchRequest.OperationType;
51 import org.torweg.pulse.webdav.request.PropPatchRequest.PropPatchOperation;
52 import org.torweg.pulse.webdav.response.HttpDAVServletResponse;
53 import org.torweg.pulse.webdav.response.MultiStatusResponse;
54 import org.torweg.pulse.webdav.response.PropFindResponse;
55 import org.torweg.pulse.webdav.response.PropNameResponse;
56 import org.torweg.pulse.webdav.response.PropPatchResponse;
57 import org.torweg.pulse.webdav.response.VFSPropFindResponse;
58 import org.torweg.pulse.webdav.response.VFSPropNameResponse;
59 import org.torweg.pulse.webdav.util.BasicAuthentication;
60 import org.torweg.pulse.webdav.util.DeadProperty;
61 import org.torweg.pulse.webdav.util.StatusResponseElement;
62
63
69 public abstract class AbstractDAVServlet extends HttpServlet {
70
71
74 private static final long serialVersionUID = -8155839669380772866L;
75
76
79 private static final Logger LOGGER = LoggerFactory
80 .getLogger(AbstractDAVServlet.class);
81
82
85 public static final Namespace DAV_NAMESPACE = Namespace.getNamespace("d",
86 "DAV:");
87
88
95 private URI getResourceURI(final HttpServletRequest req) {
96 try {
97 String pathInfo = req.getPathInfo();
98 if (pathInfo == null) {
99 pathInfo = "/";
100 }
101 return new URI(pathInfo.replace(' ', '+'));
102 } catch (URISyntaxException e) {
103 LOGGER.warn(e.getLocalizedMessage());
104 return null;
105 }
106 }
107
108
117 private URI getResourceURITranslated(final HttpServletRequest req,
118 final DAVStore store) {
119 String pathInfo = req.getPathInfo();
120 if (pathInfo == null) {
121 pathInfo = "/";
122 }
123 return store.translateDavURI(pathInfo);
124 }
125
126
137 private URI getResourceURITranslated(final String davServletPath,
138 final String requestURI, final DAVStore store) {
139 return store.translateDavURI(requestURI.substring(requestURI
140 .indexOf(davServletPath) + davServletPath.length()));
141 }
142
143
154
159 @Override
160 public final void service(final HttpServletRequest req,
161 final HttpServletResponse res) throws IOException {
162 try {
164 NDC.push(req.getRemoteAddr());
165
166 long start = System.currentTimeMillis();
167
168 res.addHeader("DAV", "1");
169 res.addHeader("MS-Author-Via", "DAV");
170
171 User user;
172 try {
173 user = BasicAuthentication.authenticate(req, res);
174 } catch (Exception e) {
175 res.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE);
176 LOGGER.error("Unexpected failure during authentication", e);
177 return;
178 }
179 if (user == null) {
180 return;
181 }
182
183
184 HttpDAVServletRequest davRequest = new HttpDAVServletRequest(req);
185 HttpDAVServletResponse davResponse = new HttpDAVServletResponse(res);
186
187 switch (davRequest.getDAVMethod()) {
188 case OPTIONS:
189 options(davRequest, davResponse, user);
190 break;
191 case PROPFIND:
192 propFind(davRequest, davResponse, user);
193 break;
194 case PROPPATCH:
195 propPatch(davRequest, davResponse, user);
196 break;
197 case MKCOL:
198 mkcol(davRequest, davResponse, user);
199 break;
200 case GET:
201 get(davRequest, davResponse, user);
202 break;
203 case HEAD:
204 head(davRequest, davResponse, user);
205 break;
206 case POST:
207 post(davRequest, davResponse, user);
208 break;
209 case DELETE:
210 delete(davRequest, davResponse, user);
211 break;
212 case PUT:
213 put(davRequest, davResponse, user);
214 break;
215 case COPY:
216 copy(davRequest, davResponse, user);
217 break;
218 case MOVE:
219 move(davRequest, davResponse, user);
220 break;
221 default:
222 res.sendError(DAVStatus.NOT_IMPLEMENTED.getStatusCode(),
223 DAVStatus.NOT_IMPLEMENTED.getStatusMessage());
224 }
225
226 LOGGER.info(
227 "{} ({}ms): {}",
228 new Object[] { davRequest.getDAVMethod(),
229 (System.currentTimeMillis() - start),
230 davRequest.getRequestURI() });
231
232 } catch (RuntimeException e) {
233 LOGGER.error(e.getLocalizedMessage(), e);
234 throw e;
235 } catch (IOException e) {
236 LOGGER.error(e.getLocalizedMessage(), e);
237 throw e;
238 } catch (Exception e) {
239 LOGGER.error(e.getLocalizedMessage(), e);
240 throw new PulseException(e.getLocalizedMessage(), e);
241 } finally {
242 NDC.pop();
243 NDC.remove();
244 }
245 }
246
247
252 protected abstract DAVConfiguration getConfiguration();
253
254
264 protected final void options(final HttpDAVServletRequest req,
265 final HttpDAVServletResponse res, final User user) {
266 DAVStore store = getConfiguration().getDAVStore();
267 URI resourceURI = getResourceURITranslated(req, store);
268 boolean isCollection = store.isCollection(resourceURI);
269 boolean canWrite = store.canWrite(resourceURI, user);
270
271 StringBuilder allowedMethods = new StringBuilder();
272
273 if (!store.canRead(resourceURI, user)) {
274 for (DAVMethod m : DAVMethod.values()) {
275 if (isValidMethod(m, isCollection, canWrite)) {
276 allowedMethods.append(m.getMethodName()).append(',');
277 }
278 }
279 if (allowedMethods.length() > 2) {
280 allowedMethods = allowedMethods.delete(
281 allowedMethods.length() - 1, allowedMethods.length());
282 }
283 }
284 res.setHeader("Allow", allowedMethods.toString());
285 LOGGER.trace("OPTIONS: Allow {}", allowedMethods);
286 }
287
288
301 private boolean isValidMethod(final DAVMethod m,
302 final boolean isCollection, final boolean canWrite) {
303 if (m == DAVMethod.POST) {
304 return false;
305 }
306
307 if ((!isCollection || !canWrite) && (m == DAVMethod.MKCOL)) {
308 return false;
309 }
310
311
313 if (!canWrite
314 && (m == DAVMethod.PUT || m == DAVMethod.DELETE
315 || m == DAVMethod.PROPPATCH || m == DAVMethod.MOVE)) {
316 return false;
318 }
319 return true;
320 }
321
322
334 protected final void propFind(final HttpDAVServletRequest req,
335 final HttpDAVServletResponse res, final User user)
336 throws IOException {
337 PropFindRequest propFindRequest = new PropFindRequest(
338 req.getInputStream(), getConfiguration().getDAVStore(),
339 req.getDepth(), getDAVServletPath(req));
340
341 URI resourceURI = getResourceURI(req);
342 LOGGER.debug("{} on: {}", propFindRequest, resourceURI);
343
344
345 if (!propFindRequest.isPropNameRequest()) {
346 doPropFind(req, res, user, propFindRequest);
347 } else {
348 doPropName(req, res, user, propFindRequest);
349 }
350 }
351
352
366 private void doPropName(final HttpDAVServletRequest req,
367 final HttpDAVServletResponse res, final User user,
368 final PropFindRequest propFindRequest) throws IOException {
369 DAVStore store = getConfiguration().getDAVStore();
370 URI resourceURI = getResourceURI(req);
371 MultiStatusResponse propNameResponse;
372
373 if (store instanceof VFSDAVStore) {
374 propNameResponse = new VFSPropNameResponse(resourceURI,
375 req.getDepth(), user, (VFSDAVStore) store, propFindRequest,
376 res);
377 } else {
378 propNameResponse = new PropNameResponse(resourceURI,
379 req.getDepth(), user, store, res);
380 }
381 propNameResponse.closeResponse();
382 }
383
384
398 private void doPropFind(final HttpDAVServletRequest req,
399 final HttpDAVServletResponse res, final User user,
400 final PropFindRequest propFindRequest) throws IOException {
401 DAVStore store = getConfiguration().getDAVStore();
402 URI resourceURI = getResourceURI(req);
403 MultiStatusResponse propfindResponse;
404
405 if (store instanceof VFSDAVStore) {
406 String uriString = resourceURI.toString();
407 if (uriString.startsWith("/public")
408 || uriString.startsWith("/private")) {
409
410
411 if (!store.objectExists(getResourceURITranslated(req, store))) {
412 res.setStatus(DAVStatus.NOT_FOUND);
413 return;
414 }
415 propfindResponse = new VFSPropFindResponse(resourceURI,
416 propFindRequest, (VFSDAVStore) store, user, res);
417 } else {
418
422 if (!uriString.equals("/") && !uriString.equals("")) {
423
428 res.setStatus(DAVStatus.NOT_FOUND);
429 return;
430 }
431 propfindResponse = propFindAddVFSRootFolders(req, user,
432 propFindRequest, res);
433 }
434 } else {
435
436 if (!store.objectExists(getResourceURITranslated(req, store))) {
437 res.setStatus(DAVStatus.NOT_FOUND);
438 return;
439 }
440 propfindResponse = new PropFindResponse(resourceURI,
441 propFindRequest, store, user, res);
442 }
443
444 propfindResponse.closeResponse();
445 }
446
447
461 private PropFindResponse propFindAddVFSRootFolders(
462 final HttpDAVServletRequest req, final User user,
463 final PropFindRequest propFindRequest,
464 final HttpDAVServletResponse res) {
465 String base = req.getRequestURI();
466 String name = base.substring(base.lastIndexOf('/') + 1);
467 if (!base.endsWith("/")) {
468 base = new StringBuilder(base).append('/').toString();
469 }
470
471 PropFindResponse propFindResponse;
472 propFindResponse = new PropFindResponse(propFindRequest, user, res);
473
474 try {
477 URI baseURI = new URI(base);
478 propFindResponse.add(PropFindResponse.buildDAVResponse(
479 propFindRequest, name, baseURI));
480 propFindResponse.add(PropFindResponse.buildDAVResponse(
481 propFindRequest, "public", new URI(base + "public")));
482 propFindResponse.add(PropFindResponse.buildDAVResponse(
483 propFindRequest, "private", new URI(base + "private")));
484 } catch (Exception e) {
485 throw new PulseException(e);
486 }
487
489 return propFindResponse;
490 }
491
492
504 protected final void propPatch(final HttpDAVServletRequest req,
505 final HttpDAVServletResponse res, final User user)
506 throws IOException {
507 DAVStore store = getConfiguration().getDAVStore();
508 URI resourceURI = getResourceURITranslated(req, store);
509
510 if (!store.canWrite(resourceURI, user)) {
511 res.setStatus(DAVStatus.FORBIDDEN);
512 return;
513 }
514 PropPatchRequest propPatchRequest = new PropPatchRequest(
515 req.getInputStream(), resourceURI);
516
517
518 if (!(store instanceof VFSDAVStore)) {
519 PropPatchResponse propPatchResponse = new PropPatchResponse(
520 propPatchRequest.getOperations().get(0),
521 "Unsupported operation", propPatchRequest, res);
522 propPatchResponse.closeResponse();
523 return;
524 }
525
526
527
528 Session s = Lifecycle.getHibernateDataSource().createNewSession();
529 Transaction tx = s.beginTransaction();
530 try {
531 VirtualFile file = VirtualFileSystem.getInstance().loadVirtualFile(
532 resourceURI, s);
533 for (PropPatchOperation operation : propPatchRequest
534 .getOperations()) {
535 if (operation.getProperty().getNamespaceURI()
536 .equals(AbstractDAVServlet.DAV_NAMESPACE.getURI())) {
537
538 PropPatchResponse propPatchResponse = new PropPatchResponse(
539 operation, "DAV properties cannot be patched",
540 propPatchRequest, res);
541 propPatchResponse.closeResponse();
542 return;
543 } else if (operation.getProperty() instanceof DeadProperty) {
544
545 if (operation.getType() == OperationType.SET) {
546 file.addDeadProperty((DeadProperty) operation
547 .getProperty());
548 } else if (operation.getType() == OperationType.REMOVE) {
549 file.removeDeadProperty((DeadProperty) operation
550 .getProperty().extractPrototype());
551 }
552 }
553 }
554 tx.commit();
555 } catch (Exception e) {
556 tx.rollback();
557 throw new PulseException("Error: " + e.getLocalizedMessage(), e);
558 } finally {
559 s.close();
560 }
561
562
563 PropPatchResponse propPatchResponse = new PropPatchResponse(
564 propPatchRequest, res);
565 propPatchResponse.closeResponse();
566
567 }
568
569
581 protected final void mkcol(final HttpDAVServletRequest req,
582 final HttpDAVServletResponse res, final User user)
583 throws IOException {
584 DAVStore store = getConfiguration().getDAVStore();
585 URI resourceURI = getResourceURITranslated(req, store);
586
587
588 if (store.objectExists(resourceURI)) {
589 res.setStatus(DAVStatus.METHOD_NOT_ALLOWED);
590 return;
591 }
592
593 URI parentURI = store.getParentURI(resourceURI);
594
595 if (!store.objectExists(parentURI) || !store.isCollection(parentURI)) {
596 res.setStatus(DAVStatus.CONFLICT);
597 return;
598 } else if (!store.canWrite(parentURI, user)) {
599
602 res.setStatus(DAVStatus.FORBIDDEN);
603 return;
604 }
605
606
607 if (store.createResourceCollection(resourceURI, user)) {
608 res.setStatus(DAVStatus.CREATED);
609 } else {
610 res.setStatus(DAVStatus.CONFLICT);
611 }
612 }
613
614
626 protected final void get(final HttpDAVServletRequest req,
627 final HttpDAVServletResponse res, final User user)
628 throws IOException {
629 DAVStore store = getConfiguration().getDAVStore();
630 URI resourceURI = getResourceURITranslated(req, store);
631
632 if (!store.canRead(resourceURI, user)) {
633 res.setStatus(DAVStatus.FORBIDDEN);
634 return;
635 }
636
637
638 if (store.isResource(resourceURI)) {
639 try {
640 InputStream in = store.getContent(resourceURI, user);
641 OutputStream out = res.getOutputStream();
642 addHeadResponseHeaders(res, user, store, resourceURI);
644 try {
645 byte[] buffer = new byte[res.getBufferSize()];
646 int available = in.read(buffer);
647 while (available > 0) {
648 out.write(buffer, 0, available);
649 available = in.read(buffer);
650 }
651 } finally {
652 in.close();
653 out.flush();
654 out.close();
655 }
656 } catch (IOException e) {
657 res.setStatus(DAVStatus.NOT_FOUND);
658 LOGGER.warn(e.getLocalizedMessage());
659 }
660 }
661 }
662
663
675 protected final void head(final HttpDAVServletRequest req,
676 final HttpDAVServletResponse res, final User user)
677 throws IOException {
678 DAVStore store = getConfiguration().getDAVStore();
679 URI resourceURI = getResourceURITranslated(req, store);
680
681 try {
682 if (!store.canRead(resourceURI, user)) {
683 res.setStatus(DAVStatus.FORBIDDEN);
684 return;
685 }
686 } catch (Exception e) {
687 LOGGER.warn(e.getLocalizedMessage(), e);
688 res.setStatus(DAVStatus.NOT_FOUND);
689 return;
690 }
691
692 addHeadResponseHeaders(res, user, store, resourceURI);
693 }
694
695
708 private void addHeadResponseHeaders(final HttpDAVServletResponse res,
709 final User user, final DAVStore store, final URI resourceURI) {
710 if (store.isResource(resourceURI)) {
711 res.setContentLength((int) store
712 .getContentLength(resourceURI, user));
713 } else {
714 res.setContentLength(0);
715 }
716 res.setContentType(store.getContentType(resourceURI, user));
717 }
718
719
731 protected final void post(final HttpDAVServletRequest req,
732 final HttpDAVServletResponse res, final User user)
733 throws IOException {
734 res.setStatus(DAVStatus.NOT_IMPLEMENTED);
735 return;
736 }
737
738
750 protected final void put(final HttpDAVServletRequest req,
751 final HttpDAVServletResponse res, final User user)
752 throws IOException {
753 DAVStore store = getConfiguration().getDAVStore();
754 URI resourceURI = getResourceURITranslated(req, store);
755 URI parentURI = resourceURI.resolve("..");
756
757 if (!isPutAllowed(req, res, user, store, resourceURI, parentURI)) {
758 return;
759 }
760
761
762 String contentType = req.getContentType();
763 if ((contentType == null) || (contentType.length() == 0)) {
764 contentType = MimeMap.getInstance().getMimeType(resourceURI);
765 }
766 InputStreamScannerChain filterChain = new InputStreamScannerChain(
767 req.getInputStream(), contentType, user);
768 try {
769 store.setContent(resourceURI, user, filterChain, contentType,
770 req.getCharacterEncoding(), res);
771 } catch (InacceptableStreamException e) {
772 if (LOGGER.isDebugEnabled()) {
773 LOGGER.error(resourceURI + ": " + e.getLocalizedMessage(), e);
774 } else {
775 LOGGER.error("{}: {}", resourceURI, e.getLocalizedMessage());
776 }
777 res.setStatus(DAVStatus.FORBIDDEN);
778 return;
779 } catch (IllegalFileNameException e) {
780 if (LOGGER.isDebugEnabled()) {
781 LOGGER.error(resourceURI + ": " + e.getLocalizedMessage(), e);
782 } else {
783 LOGGER.error("{}: {}", resourceURI, e.getLocalizedMessage());
784 }
785 res.setStatus(DAVStatus.CONFLICT);
786 return;
787 }
788 if (!res.isCommitted()) {
789 res.setStatus(DAVStatus.CREATED);
790 }
791 }
792
793
812 private boolean isPutAllowed(final HttpDAVServletRequest req,
813 final HttpDAVServletResponse res, final User user,
814 final DAVStore store, final URI resourceURI, final URI parentURI) {
815 if (store.objectExists(resourceURI) && store.isCollection(resourceURI)) {
816
817 LOGGER.debug("PUT > METHOD_NOT_ALLOWED: no PUT on collections {}",
818 resourceURI.toASCIIString());
819 res.setStatus(DAVStatus.METHOD_NOT_ALLOWED);
820 return false;
821 } else if (!store.canWrite(parentURI, user)) {
822
823 LOGGER.debug("PUT > CONFLICT: no write access to {}",
824 resourceURI.toASCIIString());
825 res.setStatus(DAVStatus.CONFLICT);
826 return false;
827 } else if (store.objectExists(resourceURI) && !req.isOverwrite()
828 && !store.canWrite(resourceURI, user)) {
829
833 LOGGER.debug("PUT > CONFLICT: no overwriting requested for {}",
834 resourceURI.toASCIIString());
835 res.setStatus(DAVStatus.CONFLICT);
836 return false;
837 }
838 return true;
839 }
840
841
853 protected final void delete(final HttpDAVServletRequest req,
854 final HttpDAVServletResponse res, final User user)
855 throws IOException {
856 DAVStore store = getConfiguration().getDAVStore();
857 URI resourceURI = getResourceURITranslated(req, store);
858
859 MultiStatusResponse multiStatus = new MultiStatusResponse(res);
860 deleteRecursively(multiStatus, store, user, resourceURI);
861
862
866 if (multiStatus.isEmpty()) {
867 res.setStatus(DAVStatus.NO_CONTENT);
868 } else {
869
870 multiStatus.closeResponse();
871 }
872 }
873
874
886 private void deleteRecursively(final MultiStatusResponse multiStatus,
887 final DAVStore store, final User user, final URI current) {
888 if (store.isCollection(current)) {
889 for (URI next : store.getChildren(current, user)) {
890 deleteRecursively(multiStatus, store, user, next);
891 }
892
896 if (store.getChildren(current, user).isEmpty()) {
897 deleteSingleURI(multiStatus, store, user, current);
898 }
899 } else if (store.isResource(current)) {
900 deleteSingleURI(multiStatus, store, user, current);
901 }
902 return;
903 }
904
905
917 private void deleteSingleURI(final MultiStatusResponse multiStatus,
918 final DAVStore store, final User user, final URI current) {
919 if (store.canWrite(current, user)) {
920 try {
921 store.removeObject(current, user);
922 } catch (IOException e) {
923 StatusResponseElement response = new StatusResponseElement(
924 current, store.isCollection(current),
925 store.isResource(current));
926 response.setStatus(DAVStatus.CONFLICT);
927 multiStatus.add(response);
928 LOGGER.warn("Detected conflict while trying to delete {}: {}",
929 current.toASCIIString(), e.getLocalizedMessage());
930 }
931 } else {
932
933 StatusResponseElement response = new StatusResponseElement(current,
934 store.isCollection(current), store.isResource(current));
935 response.setStatus(DAVStatus.FORBIDDEN);
936 multiStatus.add(response);
937 LOGGER.debug("Not allowed to delete {}", current.toASCIIString());
938 }
939 }
940
941
953 protected final void copy(final HttpDAVServletRequest req,
954 final HttpDAVServletResponse res, final User user)
955 throws IOException {
956 DAVStore store = getConfiguration().getDAVStore();
957 URI sourceURI = getResourceURITranslated(req, store);
958 URI destinationURI = getResourceURITranslated(getDAVServletPath(req),
959 req.getDestinationURI(), store);
960
961
962 if (!preliminaryChecksCopyOrMove(req, res, user, store, sourceURI,
963 destinationURI)) {
964 return;
965 }
966 MultiStatusResponse multiStatus = new MultiStatusResponse(res);
967
968
969 store.copy(sourceURI, destinationURI, user, multiStatus);
970
971 if (!multiStatus.isEmpty()) {
972 multiStatus.closeResponse();
973 } else {
974 res.setStatus(DAVStatus.CREATED);
975 }
976 }
977
978
998 private boolean preliminaryChecksCopyOrMove(
999 final HttpDAVServletRequest req, final HttpDAVServletResponse res,
1000 final User user, final DAVStore store, final URI sourceURI,
1001 final URI destinationURI) throws IOException {
1002
1003 if (!store.objectExists(sourceURI) || !store.canRead(sourceURI, user)) {
1004 res.setStatus(DAVStatus.NOT_FOUND);
1005 return false;
1006 }
1007
1008 if (store.objectExists(destinationURI)) {
1009
1010 if (!req.isOverwrite()) {
1011 res.setStatus(DAVStatus.PRECONDITION_FAILED);
1012 return false;
1013 }
1014
1015 if (store.isCollection(destinationURI) != store
1016 .isCollection(sourceURI)) {
1017 res.setStatus(DAVStatus.PRECONDITION_FAILED);
1018 return false;
1019 }
1020
1021 if (store.isResource(destinationURI) != store.isResource(sourceURI)) {
1022 res.setStatus(DAVStatus.PRECONDITION_FAILED);
1023 return false;
1024 }
1025
1026 if (!store.canWrite(destinationURI, user)) {
1027 res.setStatus(DAVStatus.FORBIDDEN);
1028 return false;
1029 }
1030 }
1031
1032
1033 URI parentURI = store.enforceTailingSlash(destinationURI).resolve("..");
1034 if (!store.objectExists(parentURI)) {
1035
1039 res.setStatus(DAVStatus.CONFLICT);
1040 return false;
1041 }
1042
1043 return true;
1044 }
1045
1046
1058 protected final void move(final HttpDAVServletRequest req,
1059 final HttpDAVServletResponse res, final User user)
1060 throws IOException {
1061 DAVStore store = getConfiguration().getDAVStore();
1062 URI sourceURI = getResourceURITranslated(req, store);
1063 URI destinationURI = getResourceURITranslated(getDAVServletPath(req),
1064 req.getDestinationURI(), store);
1065
1066
1067 if (!preliminaryChecksCopyOrMove(req, res, user, store, sourceURI,
1068 destinationURI)) {
1069 return;
1070 }
1071 MultiStatusResponse multiStatus = new MultiStatusResponse(res);
1072
1073
1074 store.move(sourceURI, destinationURI, user, multiStatus);
1075
1076 if (!multiStatus.isEmpty()) {
1077 multiStatus.closeResponse();
1078 } else {
1079 res.setStatus(DAVStatus.CREATED);
1080 }
1081 }
1082
1083
1090 protected final String getDAVServletPath(final HttpServletRequest req) {
1091 return req.getContextPath() + req.getServletPath();
1092 }
1093
1094 }
1095