container uuid column up
[arvados.git] / src / common / webdav.ts
1 // Copyright (C) The Arvados Authors. All rights reserved.
2 //
3 // SPDX-License-Identifier: AGPL-3.0
4
5 import { customEncodeURI } from "./url";
6
7 export class WebDAV {
8
9     defaults: WebDAVDefaults = {
10         baseURL: '',
11         headers: {},
12     };
13
14     constructor(config?: Partial<WebDAVDefaults>, private createRequest = () => new XMLHttpRequest()) {
15         if (config) {
16             this.defaults = { ...this.defaults, ...config };
17         }
18     }
19
20     propfind = (url: string, config: WebDAVRequestConfig = {}) =>
21         this.request({
22             ...config, url,
23             method: 'PROPFIND'
24         })
25
26     put = (url: string, data?: any, config: WebDAVRequestConfig = {}) =>
27         this.request({
28             ...config, url,
29             method: 'PUT',
30             data
31         })
32
33     get = (url: string, config: WebDAVRequestConfig = {}) =>
34         this.request({
35             ...config, url,
36             method: 'GET'
37         })
38
39     upload = (url: string, files: File[], config: WebDAVRequestConfig = {}) => {
40         return Promise.all(
41             files.map(file => this.request({
42                 ...config, url,
43                 method: 'PUT',
44                 data: file
45             }))
46         );
47     }
48
49     copy = (url: string, destination: string, config: WebDAVRequestConfig = {}) =>
50         this.request({
51             ...config, url,
52             method: 'COPY',
53             headers: {
54                 ...config.headers,
55                 Destination: this.defaults.baseURL
56                     ? this.defaults.baseURL.replace(/\/+$/, '') + '/' + destination.replace(/^\/+/, '')
57                     : destination
58             }
59         })
60
61     move = (url: string, destination: string, config: WebDAVRequestConfig = {}) =>
62         this.request({
63             ...config, url,
64             method: 'MOVE',
65             headers: {
66                 ...config.headers,
67                 Destination: this.defaults.baseURL
68                     ? this.defaults.baseURL.replace(/\/+$/, '') + '/' + destination.replace(/^\/+/, '')
69                     : destination
70             }
71         })
72
73     delete = (url: string, config: WebDAVRequestConfig = {}) =>
74         this.request({
75             ...config, url,
76             method: 'DELETE'
77         })
78
79     private request = (config: RequestConfig) => {
80         return new Promise<XMLHttpRequest>((resolve, reject) => {
81             const r = this.createRequest();
82             this.defaults.baseURL = this.defaults.baseURL.replace(/\/+$/, '');
83             r.open(config.method,
84                 `${this.defaults.baseURL
85                     ? this.defaults.baseURL+'/'
86                     : ''}${customEncodeURI(config.url)}`);
87
88             const headers = { ...this.defaults.headers, ...config.headers };
89             Object
90                 .keys(headers)
91                 .forEach(key => r.setRequestHeader(key, headers[key]));
92
93             if (!(window as any).cancelTokens) {
94                 Object.assign(window, { cancelTokens: {} });
95             }
96
97             (window as any).cancelTokens[config.url] = () => {
98                 resolve(r);
99                 r.abort();
100             }
101
102             if (config.onUploadProgress) {
103                 r.upload.addEventListener('progress', config.onUploadProgress);
104             }
105
106             // This event gets triggered on *any* server response
107             r.addEventListener('load', () => {
108                 if (r.status >= 400) {
109                     return reject(r);
110                 } else {
111                     return resolve(r);
112                 }
113             });
114
115             // This event gets triggered on network errors
116             r.addEventListener('error', () => {
117                 return reject(r);
118             });
119
120             r.upload.addEventListener('error', () => {
121                 return reject(r);
122             });
123
124             r.send(config.data);
125         });
126     }
127 }
128
129 export interface WebDAVRequestConfig {
130     headers?: {
131         [key: string]: string;
132     };
133     onUploadProgress?: (event: ProgressEvent) => void;
134 }
135
136 interface WebDAVDefaults {
137     baseURL: string;
138     headers: { [key: string]: string };
139 }
140
141 interface RequestConfig {
142     method: string;
143     url: string;
144     headers?: { [key: string]: string };
145     data?: any;
146     onUploadProgress?: (event: ProgressEvent) => void;
147 }