16439: Fixes WebDAV request URL.
[arvados-workbench2.git] / src / common / webdav.ts
1 // Copyright (C) The Arvados Authors. All rights reserved.
2 //
3 // SPDX-License-Identifier: AGPL-3.0
4
5 export class WebDAV {
6
7     defaults: WebDAVDefaults = {
8         baseURL: '',
9         headers: {},
10     };
11
12     constructor(config?: Partial<WebDAVDefaults>, private createRequest = () => new XMLHttpRequest()) {
13         if (config) {
14             this.defaults = { ...this.defaults, ...config };
15         }
16     }
17
18     propfind = (url: string, config: WebDAVRequestConfig = {}) =>
19         this.request({
20             ...config, url,
21             method: 'PROPFIND'
22         })
23
24     put = (url: string, data?: any, config: WebDAVRequestConfig = {}) =>
25         this.request({
26             ...config, url,
27             method: 'PUT',
28             data
29         })
30
31     upload = (url: string, files: File[], config: WebDAVRequestConfig = {}) => {
32         return Promise.all(
33             files.map(file => this.request({
34                 ...config, url,
35                 method: 'PUT',
36                 data: file
37             }))
38         );
39     }
40
41     copy = (url: string, destination: string, config: WebDAVRequestConfig = {}) =>
42         this.request({
43             ...config, url,
44             method: 'COPY',
45             headers: { ...config.headers, Destination: this.defaults.baseURL + destination }
46         })
47
48     move = (url: string, destination: string, config: WebDAVRequestConfig = {}) =>
49         this.request({
50             ...config, url,
51             method: 'MOVE',
52             headers: { ...config.headers, Destination: this.defaults.baseURL + destination }
53         })
54
55     delete = (url: string, config: WebDAVRequestConfig = {}) =>
56         this.request({
57             ...config, url,
58             method: 'DELETE'
59         })
60
61     private request = (config: RequestConfig) => {
62         return new Promise<XMLHttpRequest>((resolve, reject) => {
63             const r = this.createRequest();
64             this.defaults.baseURL = this.defaults.baseURL.replace(/\/+$/, '');
65             r.open(config.method,
66                 `${this.defaults.baseURL
67                     ? this.defaults.baseURL+'/'
68                     : ''}${config.url}`);
69             const headers = { ...this.defaults.headers, ...config.headers };
70             Object
71                 .keys(headers)
72                 .forEach(key => r.setRequestHeader(key, headers[key]));
73
74             if (config.onUploadProgress) {
75                 r.upload.addEventListener('progress', config.onUploadProgress);
76             }
77
78             r.addEventListener('load', () => {
79                 if (r.status === 404) {
80                     return reject(r);
81                 } else {
82                     return resolve(r);
83                 }
84             });
85
86             r.addEventListener('error', () => {
87                 return reject(r);
88             });
89
90             r.upload.addEventListener('error', () => {
91                 return reject(r);
92             });
93
94             r.send(config.data);
95         });
96     }
97 }
98
99 export interface WebDAVRequestConfig {
100     headers?: {
101         [key: string]: string;
102     };
103     onUploadProgress?: (event: ProgressEvent) => void;
104 }
105
106 interface WebDAVDefaults {
107     baseURL: string;
108     headers: { [key: string]: string };
109 }
110
111 interface RequestConfig {
112     method: string;
113     url: string;
114     headers?: { [key: string]: string };
115     data?: any;
116     onUploadProgress?: (event: ProgressEvent) => void;
117 }