001/*
002 * (C) Copyright 2018 Nuxeo (http://nuxeo.com/) and others.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *     http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 *
016 * Contributors:
017 *     Antoine Taillefer
018 *     Thomas Roger
019 */
020
021package org.nuxeo.wopi;
022
023import static java.nio.charset.StandardCharsets.UTF_8;
024import static org.nuxeo.wopi.Constants.ACCESS_TOKEN_ATTRIBUTE;
025import static org.nuxeo.wopi.Constants.ACCESS_TOKEN_TTL_ATTRIBUTE;
026import static org.nuxeo.wopi.Constants.FILES_ENDPOINT_PATH;
027import static org.nuxeo.wopi.Constants.FORM_URL;
028import static org.nuxeo.wopi.Constants.WOPI_BASE_URL_PROPERTY;
029import static org.nuxeo.wopi.Constants.WOPI_JSP;
030import static org.nuxeo.wopi.Constants.WOPI_SRC;
031
032import java.io.IOException;
033import java.net.URLEncoder;
034import java.util.Arrays;
035
036import javax.servlet.RequestDispatcher;
037import javax.servlet.ServletException;
038import javax.servlet.http.HttpServlet;
039import javax.servlet.http.HttpServletRequest;
040import javax.servlet.http.HttpServletResponse;
041
042import org.nuxeo.ecm.core.api.Blob;
043import org.nuxeo.ecm.core.api.CloseableCoreSession;
044import org.nuxeo.ecm.core.api.CoreInstance;
045import org.nuxeo.ecm.core.api.DocumentModel;
046import org.nuxeo.ecm.core.api.DocumentRef;
047import org.nuxeo.ecm.core.api.IdRef;
048import org.nuxeo.ecm.platform.web.common.vh.VirtualHostHelper;
049import org.nuxeo.runtime.api.Framework;
050
051/**
052 * @since 10.3
053 */
054public class WOPIServlet extends HttpServlet {
055
056    private static final long serialVersionUID = 1L;
057
058    @Override
059    protected void doGet(HttpServletRequest request, HttpServletResponse response)
060            throws ServletException, IOException {
061        String path = request.getPathInfo();
062        if (path == null) {
063            response.sendError(HttpServletResponse.SC_BAD_REQUEST, "Null path");
064            return;
065        }
066        // remove first /
067        path = path.substring(1);
068        String[] parts = path.split("/");
069        int length = parts.length;
070        if (length < 4) {
071            response.sendError(HttpServletResponse.SC_BAD_REQUEST, "Invalid path: " + path);
072            return;
073        }
074
075        WOPIService wopiService = Framework.getService(WOPIService.class);
076        if (!wopiService.isEnabled()) {
077            response.sendError(HttpServletResponse.SC_NOT_FOUND, "WOPI not enabled");
078            return;
079        }
080
081        String action = parts[0];
082        String repository = parts[1];
083        String docId = parts[2];
084        String xpath = String.join("/", Arrays.asList(parts).subList(3, length));
085        try (CloseableCoreSession session = CoreInstance.openCoreSession(repository)) {
086            DocumentRef ref = new IdRef(docId);
087            if (!session.exists(ref)) {
088                response.sendError(HttpServletResponse.SC_NOT_FOUND, "Document not found");
089                return;
090            }
091
092            DocumentModel doc = session.getDocument(ref);
093            Blob blob = Helpers.getEditableBlob(doc, xpath);
094            if (blob == null) {
095                response.sendError(HttpServletResponse.SC_NOT_FOUND, "No editable blob on document");
096                return;
097            }
098
099            String actionURL = wopiService.getActionURL(blob, action);
100            if (actionURL == null) {
101                // TODO http code?
102                response.sendError(HttpServletResponse.SC_NOT_FOUND, "Cannot open file with Office Online");
103                return;
104            }
105
106            String token = Helpers.createJWTToken();
107            request.setAttribute(ACCESS_TOKEN_ATTRIBUTE, token);
108            request.setAttribute(ACCESS_TOKEN_TTL_ATTRIBUTE, Helpers.getJWTTokenExp(token));
109            String baseURL = VirtualHostHelper.getBaseURL(request);
110            String wopiBaseURL = Framework.getProperty(WOPI_BASE_URL_PROPERTY, baseURL);
111            String fileId = FileInfo.computeFileId(doc, xpath);
112            String wopiSrc = URLEncoder.encode(String.format("%s%s%s", wopiBaseURL, FILES_ENDPOINT_PATH, fileId),
113                    UTF_8.name());
114            request.setAttribute(FORM_URL, String.format("%s%s=%s", actionURL, WOPI_SRC, wopiSrc));
115            RequestDispatcher requestDispatcher = request.getRequestDispatcher(WOPI_JSP);
116            requestDispatcher.forward(request, response);
117        }
118    }
119
120}