]> git.argeo.org Git - lgpl/argeo-commons.git/blob - org.argeo.cms/src/org/argeo/cms/dav/DavHttpHandler.java
Simplify and document new content provider implementation
[lgpl/argeo-commons.git] / org.argeo.cms / src / org / argeo / cms / dav / DavHttpHandler.java
1 package org.argeo.cms.dav;
2
3 import java.io.IOException;
4 import java.io.InputStream;
5 import java.io.OutputStream;
6 import java.util.StringJoiner;
7 import java.util.concurrent.CompletableFuture;
8 import java.util.function.Consumer;
9
10 import javax.xml.namespace.NamespaceContext;
11
12 import org.argeo.api.acr.ContentNotFoundException;
13 import org.argeo.cms.http.HttpHeader;
14 import org.argeo.cms.http.HttpMethod;
15 import org.argeo.cms.http.HttpStatus;
16 import org.argeo.cms.http.server.HttpServerUtils;
17
18 import com.sun.net.httpserver.HttpExchange;
19 import com.sun.net.httpserver.HttpHandler;
20
21 /**
22 * Centralise patterns which are not ACR specific. Not really meant as a
23 * framework for building WebDav servers, but rather to make upper-level of
24 * ACR-specific code more readable and maintainable.
25 */
26 public abstract class DavHttpHandler implements HttpHandler {
27
28 @Override
29 public void handle(HttpExchange exchange) throws IOException {
30 String subPath = HttpServerUtils.subPath(exchange);
31 String method = exchange.getRequestMethod();
32 try {
33 if (HttpMethod.GET.name().equals(method)) {
34 handleGET(exchange, subPath);
35 } else if (HttpMethod.OPTIONS.name().equals(method)) {
36 handleOPTIONS(exchange, subPath);
37 exchange.sendResponseHeaders(HttpStatus.NO_CONTENT.getCode(), -1);
38 } else if (HttpMethod.PROPFIND.name().equals(method)) {
39 DavDepth depth = DavDepth.fromHttpExchange(exchange);
40 if (depth == null) {
41 // default, as per http://www.webdav.org/specs/rfc4918.html#METHOD_PROPFIND
42 depth = DavDepth.DEPTH_INFINITY;
43 }
44 DavPropfind davPropfind;
45 try (InputStream in = exchange.getRequestBody()) {
46 davPropfind = DavPropfind.load(depth, in);
47 }
48 MultiStatusWriter multiStatusWriter = new MultiStatusWriter(exchange.getProtocol());
49 CompletableFuture<Void> published = handlePROPFIND(exchange, subPath, davPropfind, multiStatusWriter);
50 exchange.sendResponseHeaders(HttpStatus.MULTI_STATUS.getCode(), 0l);
51 NamespaceContext namespaceContext = getNamespaceContext(exchange, subPath);
52 try (OutputStream out = exchange.getResponseBody()) {
53 multiStatusWriter.process(namespaceContext, out, published.minimalCompletionStage(),
54 davPropfind.isPropname());
55 }
56 } else {
57 throw new IllegalArgumentException("Unsupported method " + method);
58 }
59 } catch (ContentNotFoundException e) {
60 exchange.sendResponseHeaders(HttpStatus.NOT_FOUND.getCode(), -1);
61 }
62 // TODO return a structured error message
63 catch (UnsupportedOperationException e) {
64 e.printStackTrace();
65 exchange.sendResponseHeaders(HttpStatus.NOT_IMPLEMENTED.getCode(), -1);
66 } catch (Exception e) {
67 exchange.sendResponseHeaders(HttpStatus.INTERNAL_SERVER_ERROR.getCode(), -1);
68 }
69
70 }
71
72 protected abstract NamespaceContext getNamespaceContext(HttpExchange httpExchange, String path);
73
74 protected abstract CompletableFuture<Void> handlePROPFIND(HttpExchange exchange, String path,
75 DavPropfind davPropfind, Consumer<DavResponse> consumer) throws IOException;
76
77 protected abstract void handleGET(HttpExchange exchange, String path) throws IOException;
78
79 protected void handleOPTIONS(HttpExchange exchange, String path) throws IOException {
80 exchange.getResponseHeaders().set(HttpHeader.DAV.getHeaderName(), "1, 3");
81 StringJoiner methods = new StringJoiner(",");
82 methods.add(HttpMethod.OPTIONS.name());
83 methods.add(HttpMethod.HEAD.name());
84 methods.add(HttpMethod.GET.name());
85 methods.add(HttpMethod.POST.name());
86 methods.add(HttpMethod.PUT.name());
87 methods.add(HttpMethod.PROPFIND.name());
88 // TODO :
89 methods.add(HttpMethod.PROPPATCH.name());
90 methods.add(HttpMethod.MKCOL.name());
91 methods.add(HttpMethod.DELETE.name());
92 methods.add(HttpMethod.MOVE.name());
93 methods.add(HttpMethod.COPY.name());
94
95 exchange.getResponseHeaders().add(HttpHeader.ALLOW.getHeaderName(), methods.toString());
96 }
97
98 }