001/*
002 * (C) Copyright 2015-2016 Nuxeo SA (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 *     Florent Guillaume
018 *     Estelle Giuy <egiuly@nuxeo.com>
019 */
020package org.nuxeo.ecm.core.io.download;
021
022import java.io.IOException;
023import java.io.OutputStream;
024import java.io.Serializable;
025import java.util.List;
026import java.util.Map;
027import java.util.function.Consumer;
028import java.util.function.Supplier;
029
030import javax.servlet.http.HttpServletRequest;
031import javax.servlet.http.HttpServletResponse;
032
033import org.nuxeo.ecm.core.api.Blob;
034import org.nuxeo.ecm.core.api.DocumentModel;
035import org.nuxeo.ecm.core.api.impl.blob.AsyncBlob;
036
037/**
038 * This service allows the download of blobs to a HTTP response.
039 *
040 * @since 7.3
041 */
042public interface DownloadService {
043
044    String EVENT_NAME = "download";
045
046    String NXFILE = "nxfile";
047
048    String NXDOWNLOADINFO = "nxdownloadinfo";
049
050    /**
051     * @since 9.3
052     */
053    String NXBLOBSTATUS = "nxblobstatus";
054
055    String NXBIGBLOB = "nxbigblob";
056
057    /** @deprecated since 9.1, use nxbigblob instead */
058    @Deprecated
059    String NXBIGZIPFILE = "nxbigzipfile";
060
061    /** @deprecated since 7.4, use nxfile instead */
062    @Deprecated
063    String NXBIGFILE = "nxbigfile";
064
065    String BLOBHOLDER_PREFIX = "blobholder:";
066
067    String BLOBHOLDER_0 = "blobholder:0";
068
069    /**
070     * The transient store parameter name for storing an error if any. Stored entry must
071     */
072    String TRANSIENT_STORE_PARAM_ERROR = "error";
073
074    String TRANSIENT_STORE_PARAM_PROGRESS = "progress";
075
076    String TRANSIENT_STORE_STORE_NAME = "download";
077
078    public static class ByteRange {
079
080        private final long start;
081
082        private final long end;
083
084        public ByteRange(long start, long end) {
085            this.start = start;
086            this.end = end;
087        }
088
089        public long getStart() {
090            return start;
091        }
092
093        public long getEnd() {
094            return end;
095        }
096
097        public long getLength() {
098            return end - start + 1;
099        }
100    }
101
102    /**
103     * Stores the blobs for later download.
104     *
105     * @param the list of blobs to store
106     * @return the store key used for retrieving the blobs (@see {@link DownloadService#getDownloadUrl(String)}
107     * @since 9.1
108     */
109    String storeBlobs(List<Blob> blobs);
110
111    /**
112     * Gets the URL to use to download the blob at the given xpath in the given document.
113     * <p>
114     * The URL is relative to the Nuxeo Web Application context.
115     * <p>
116     * Returns something like {@code nxfile/reponame/docuuid/blobholder:0/foo.jpg?changeToken=5-1}
117     *
118     * @param doc the document
119     * @param xpath the blob's xpath or blobholder index, or {@code null} for default
120     * @param filename the blob's filename, or {@code null} for default
121     * @return the download URL with changeToken as query param for optimized http caching
122     */
123    String getDownloadUrl(DocumentModel doc, String xpath, String filename);
124
125
126    /**
127     * Gets the URL to use to download the blob at the given xpath in the given document.
128     * <p>
129     * The URL is relative to the Nuxeo Web Application context.
130     * <p>
131     * Returns something like {@code nxfile/reponame/docuuid/blobholder:0/foo.jpg?changeToken=5-1}
132     *
133     * @param doc the document
134     * @param xpath the blob's xpath or blobholder index, or {@code null} for default
135     * @param filename the blob's filename, or {@code null} for default
136     * @param changeToken the doc changeToken which will be appended as a query parameter for optimized http caching.
137     * @return the download URL
138     * @since 10.3
139     */
140    String getDownloadUrl(String repositoryName, String docId, String xpath, String filename, String changeToken);
141
142    /**
143     * Gets the URL to use to download the blob at the given xpath in the given document.
144     * <p>
145     * The URL is relative to the Nuxeo Web Application context.
146     * <p>
147     * Returns something like {@code nxfile/reponame/docuuid/blobholder:0/foo.jpg}
148     *
149     * @param repositoryName the document repository
150     * @param docId the document id
151     * @param xpath the blob's xpath or blobholder index, or {@code null} for default
152     * @param filename the blob's filename, or {@code null} for default
153     * @return the download URL
154     */
155    String getDownloadUrl(String repositoryName, String docId, String xpath, String filename);
156
157    /**
158     * Gets the URL to use to download the blobs identified by a storage key.
159     * <p>
160     * The URL is relative to the Nuxeo Web Application context.
161     * <p>
162     * Returns something like {@code nxbigblob/key}
163     *
164     * @param key The key of stored blobs to download
165     * @return the download URL
166     * @since 9.1
167     */
168    String getDownloadUrl(String storeKey);
169
170    /**
171     * Finds a document's blob given the download URL returned by {@link #getDownloadUrl}.
172     * <p>
173     * The permissions are check whether the user can download the blob or not.
174     *
175     * @param downloadURL the URL to use to download the blob
176     * @return the blob, or {@code null} if not found or if the user has no permission to download it
177     * @since 9.1
178     */
179    Blob resolveBlobFromDownloadUrl(String downloadURL);
180
181    /**
182     * Handles the download of a document.
183     *
184     * @param req the request
185     * @param resp the response
186     * @param baseUrl the request baseUrl
187     * @param path the request path, without the context
188     * @since 9.1
189     */
190    void handleDownload(HttpServletRequest req, HttpServletResponse resp, String baseUrl, String path)
191            throws IOException;
192
193    /**
194     * Triggers a {@link AsyncBlob} download which gives information about an asynchronous blob.
195     *
196     * @param storeKey the stored blobs key
197     * @param reason the download reason
198     * @since 9.3
199     * @deprecated since 10.3, use the @async operation adapter instead.
200     */
201    @Deprecated
202    void downloadBlobStatus(HttpServletRequest request, HttpServletResponse response, String storeKey, String reason)
203            throws IOException;
204
205    /**
206     * Triggers a blobs download. Once the temporary blobs are transfered from the store, they are automatically
207     * deleted. The returned HTTP Status Code is 200 if the blob is ready or 202 if it is still being processed.
208     *
209     * @param storeKey the stored blobs key
210     * @param reason the download reason
211     * @since 9.1
212     */
213    void downloadBlob(HttpServletRequest request, HttpServletResponse response, String storeKey, String reason) throws IOException;
214
215    /**
216     * Triggers a blob download.
217     *
218     * @param doc the document, if available
219     * @param xpath the blob's xpath or blobholder index, if available
220     * @param blob the blob, if already fetched
221     * @param filename the filename to use
222     * @param reason the download reason
223     */
224    void downloadBlob(HttpServletRequest request, HttpServletResponse response, DocumentModel doc, String xpath,
225            Blob blob, String filename, String reason) throws IOException;
226
227    /**
228     * Triggers a blob download.
229     *
230     * @param doc the document, if available
231     * @param xpath the blob's xpath or blobholder index, if available
232     * @param blob the blob, if already fetched
233     * @param filename the filename to use
234     * @param reason the download reason
235     * @param extendedInfos an optional map of extended informations to log
236     */
237    void downloadBlob(HttpServletRequest request, HttpServletResponse response, DocumentModel doc, String xpath,
238            Blob blob, String filename, String reason, Map<String, Serializable> extendedInfos) throws IOException;
239
240    /**
241     * Triggers a blob download.
242     *
243     * @param doc the document, if available
244     * @param xpath the blob's xpath or blobholder index, if available
245     * @param blob the blob, if already fetched
246     * @param filename the filename to use
247     * @param reason the download reason
248     * @param extendedInfos an optional map of extended informations to log
249     * @param inline if not null, force the inline flag for content-disposition
250     */
251    void downloadBlob(HttpServletRequest request, HttpServletResponse response, DocumentModel doc, String xpath,
252            Blob blob, String filename, String reason, Map<String, Serializable> extendedInfos, Boolean inline)
253            throws IOException;
254
255    /**
256     * Triggers a blob download. The actual byte transfer is done through a {@link DownloadExecutor}.
257     *
258     * @param doc the document, if available
259     * @param xpath the blob's xpath or blobholder index, if available
260     * @param blob the blob, if already fetched
261     * @param filename the filename to use
262     * @param reason the download reason
263     * @param extendedInfos an optional map of extended informations to log
264     * @param inline if not null, force the inline flag for content-disposition
265     * @param blobTransferer the transferer of the actual blob
266     * @since 7.10
267     */
268    void downloadBlob(HttpServletRequest request, HttpServletResponse response, DocumentModel doc, String xpath,
269            Blob blob, String filename, String reason, Map<String, Serializable> extendedInfos, Boolean inline,
270            Consumer<ByteRange> blobTransferer) throws IOException;
271
272    /**
273     * Copies the blob stream at the given byte range into the supplied {@link OutputStream}.
274     *
275     * @param blob the blob
276     * @param byteRange the byte range
277     * @param outputStreamSupplier the {@link OutputStream} supplier
278     * @since 7.10
279     */
280    void transferBlobWithByteRange(Blob blob, ByteRange byteRange, Supplier<OutputStream> outputStreamSupplier);
281
282    /**
283     * Logs a download.
284     *
285     * @param doc the doc for which this download occurs, if available
286     * @param blobXPath the blob's xpath or blobholder index, if available
287     * @param filename the filename
288     * @param reason the download reason
289     * @param extendedInfos an optional map of extended informations to log
290     */
291    void logDownload(DocumentModel doc, String blobXPath, String filename, String reason,
292            Map<String, Serializable> extendedInfos);
293
294    /**
295     * Finds a document's blob given an xpath or blobholder index
296     *
297     * @param doc the document
298     * @param xpath the xpath or blobholder index
299     * @return the blob, or {@code null} if not found
300     */
301    Blob resolveBlob(DocumentModel doc, String xpath);
302
303    /**
304     * Finds a document's blob.
305     *
306     * @param doc the document
307     * @return the blob, or {@code null} if not available
308     * @since 9.3
309     */
310    Blob resolveBlob(DocumentModel doc);
311
312    /**
313     * Checks whether the download of the blob is allowed.
314     *
315     * @param doc the doc for which this download occurs, if available
316     * @param blobXPath the blob's xpath or blobholder index, if available
317     * @param blob the blob
318     * @param reason the download reason
319     * @param extendedInfos an optional map of extended informations to log
320     * @return {@code true} if download is allowed
321     * @since 7.10
322     */
323    boolean checkPermission(DocumentModel doc, String xpath, Blob blob, String reason,
324            Map<String, Serializable> extendedInfos);
325
326}