]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blame - shared/server-commands/requests/requests.ts
Specify runner name when unregistering the runner
[github/Chocobozzz/PeerTube.git] / shared / server-commands / requests / requests.ts
CommitLineData
c0e8b12e 1/* eslint-disable @typescript-eslint/no-floating-promises */
a1587156 2
9107d791 3import { decode } from 'querystring'
41fb13c3 4import request from 'supertest'
2d1ad5b9 5import { URL } from 'url'
3545e72c 6import { buildAbsoluteFixturePath, pick } from '@shared/core-utils'
c0e8b12e 7import { HttpStatusCode } from '@shared/models'
09209296 8
c0e8b12e 9export type CommonRequestParams = {
a1587156
C
10 url: string
11 path?: string
a1587156 12 contentType?: string
d102de1b 13 responseType?: string
4c280004 14 range?: string
9107d791 15 redirects?: number
012580d9 16 accept?: string
41d1d075 17 host?: string
c0e8b12e
C
18 token?: string
19 headers?: { [ name: string ]: string }
20 type?: string
21 xForwardedFor?: string
22 expectedStatus?: HttpStatusCode
23}
eec63bbc 24
3545e72c
C
25function makeRawRequest (options: {
26 url: string
27 token?: string
28 expectedStatus?: HttpStatusCode
29 range?: string
30 query?: { [ id: string ]: string }
d102de1b 31 method?: 'GET' | 'POST'
3545e72c
C
32}) {
33 const { host, protocol, pathname } = new URL(options.url)
34
d102de1b 35 const reqOptions = {
3545e72c
C
36 url: `${protocol}//${host}`,
37 path: pathname,
e57a840e 38 contentType: undefined,
eec63bbc 39
3545e72c 40 ...pick(options, [ 'expectedStatus', 'range', 'token', 'query' ])
d102de1b
C
41 }
42
43 if (options.method === 'POST') {
44 return makePostBodyRequest(reqOptions)
45 }
46
47 return makeGetRequest(reqOptions)
eec63bbc
C
48}
49
c0e8b12e
C
50function makeGetRequest (options: CommonRequestParams & {
51 query?: any
fb72d2e1 52 rawQuery?: string
eec63bbc 53}) {
c0e8b12e 54 const req = request(options.url).get(options.path)
fb72d2e1
C
55
56 if (options.query) req.query(options.query)
57 if (options.rawQuery) req.query(options.rawQuery)
eec63bbc 58
c0e8b12e
C
59 return buildRequest(req, { contentType: 'application/json', expectedStatus: HttpStatusCode.BAD_REQUEST_400, ...options })
60}
eec63bbc 61
c0e8b12e
C
62function makeHTMLRequest (url: string, path: string) {
63 return makeGetRequest({
64 url,
65 path,
66 accept: 'text/html',
67 expectedStatus: HttpStatusCode.OK_200
68 })
69}
eec63bbc 70
c0e8b12e
C
71function makeActivityPubGetRequest (url: string, path: string, expectedStatus = HttpStatusCode.OK_200) {
72 return makeGetRequest({
73 url,
74 path,
ba2684ce 75 expectedStatus,
c0e8b12e
C
76 accept: 'application/activity+json,text/html;q=0.9,\\*/\\*;q=0.8'
77 })
0e1dc3e7
C
78}
79
790c2837
C
80function makeDeleteRequest (options: CommonRequestParams & {
81 query?: any
82 rawQuery?: string
83}) {
c0e8b12e
C
84 const req = request(options.url).delete(options.path)
85
790c2837
C
86 if (options.query) req.query(options.query)
87 if (options.rawQuery) req.query(options.rawQuery)
88
c0e8b12e
C
89 return buildRequest(req, { accept: 'application/json', expectedStatus: HttpStatusCode.BAD_REQUEST_400, ...options })
90}
91
92function makeUploadRequest (options: CommonRequestParams & {
a1587156 93 method?: 'POST' | 'PUT'
d23dd9fb 94
a1587156 95 fields: { [ fieldName: string ]: any }
77e9f859 96 attaches?: { [ attachName: string ]: any | any[] }
0e1dc3e7 97}) {
c0e8b12e
C
98 let req = options.method === 'PUT'
99 ? request(options.url).put(options.path)
100 : request(options.url).post(options.path)
0e1dc3e7 101
c0e8b12e 102 req = buildRequest(req, { accept: 'application/json', expectedStatus: HttpStatusCode.BAD_REQUEST_400, ...options })
ac81d1a0 103
c0e8b12e 104 buildFields(req, options.fields)
0e1dc3e7 105
77e9f859 106 Object.keys(options.attaches || {}).forEach(attach => {
0e1dc3e7 107 const value = options.attaches[attach]
5cf027bd 108 if (!value) return
c0e8b12e 109
2769e297
C
110 if (Array.isArray(value)) {
111 req.attach(attach, buildAbsoluteFixturePath(value[0]), value[1])
112 } else {
113 req.attach(attach, buildAbsoluteFixturePath(value))
114 }
0e1dc3e7
C
115 })
116
d23dd9fb 117 return req
0e1dc3e7
C
118}
119
c0e8b12e 120function makePostBodyRequest (options: CommonRequestParams & {
a1587156 121 fields?: { [ fieldName: string ]: any }
0e1dc3e7 122}) {
c0e8b12e
C
123 const req = request(options.url).post(options.path)
124 .send(options.fields)
0e1dc3e7 125
c0e8b12e 126 return buildRequest(req, { accept: 'application/json', expectedStatus: HttpStatusCode.BAD_REQUEST_400, ...options })
0e1dc3e7
C
127}
128
129function makePutBodyRequest (options: {
a1587156
C
130 url: string
131 path: string
132 token?: string
133 fields: { [ fieldName: string ]: any }
c0e8b12e 134 expectedStatus?: HttpStatusCode
4bbfc6c6 135}) {
c0e8b12e
C
136 const req = request(options.url).put(options.path)
137 .send(options.fields)
4bbfc6c6 138
c0e8b12e 139 return buildRequest(req, { accept: 'application/json', expectedStatus: HttpStatusCode.BAD_REQUEST_400, ...options })
4bbfc6c6
C
140}
141
9107d791
C
142function decodeQueryString (path: string) {
143 return decode(path.split('?')[1])
144}
145
d102de1b
C
146// ---------------------------------------------------------------------------
147
c1bc8ee4 148function unwrapBody <T> (test: request.Test): Promise<T> {
e8bd7ce7
C
149 return test.then(res => res.body)
150}
151
c1bc8ee4
C
152function unwrapText (test: request.Test): Promise<string> {
153 return test.then(res => res.text)
154}
155
0305db28
JB
156function unwrapBodyOrDecodeToJSON <T> (test: request.Test): Promise<T> {
157 return test.then(res => {
158 if (res.body instanceof Buffer) {
7dd7ff4c
C
159 try {
160 return JSON.parse(new TextDecoder().decode(res.body))
161 } catch (err) {
3a0c2a77 162 console.error('Cannot decode JSON.', { res, body: res.body instanceof Buffer ? res.body.toString() : res.body })
d102de1b
C
163 throw err
164 }
165 }
166
167 if (res.text) {
168 try {
169 return JSON.parse(res.text)
170 } catch (err) {
3a0c2a77 171 console.error('Cannot decode json', { res, text: res.text })
7dd7ff4c
C
172 throw err
173 }
0305db28
JB
174 }
175
176 return res.body
177 })
178}
179
180function unwrapTextOrDecode (test: request.Test): Promise<string> {
181 return test.then(res => res.text || new TextDecoder().decode(res.body))
182}
183
0e1dc3e7
C
184// ---------------------------------------------------------------------------
185
186export {
e032aec9 187 makeHTMLRequest,
0e1dc3e7 188 makeGetRequest,
9107d791 189 decodeQueryString,
ac81d1a0 190 makeUploadRequest,
0e1dc3e7 191 makePostBodyRequest,
eec63bbc 192 makePutBodyRequest,
4bbfc6c6 193 makeDeleteRequest,
09209296 194 makeRawRequest,
2d1ad5b9 195 makeActivityPubGetRequest,
c1bc8ee4 196 unwrapBody,
0305db28
JB
197 unwrapTextOrDecode,
198 unwrapBodyOrDecodeToJSON,
c0e8b12e
C
199 unwrapText
200}
201
202// ---------------------------------------------------------------------------
203
204function buildRequest (req: request.Test, options: CommonRequestParams) {
205 if (options.contentType) req.set('Accept', options.contentType)
d102de1b 206 if (options.responseType) req.responseType(options.responseType)
c0e8b12e
C
207 if (options.token) req.set('Authorization', 'Bearer ' + options.token)
208 if (options.range) req.set('Range', options.range)
209 if (options.accept) req.set('Accept', options.accept)
210 if (options.host) req.set('Host', options.host)
211 if (options.redirects) req.redirects(options.redirects)
c0e8b12e
C
212 if (options.xForwardedFor) req.set('X-Forwarded-For', options.xForwardedFor)
213 if (options.type) req.type(options.type)
214
215 Object.keys(options.headers || {}).forEach(name => {
216 req.set(name, options.headers[name])
217 })
218
d102de1b 219 return req.expect(res => {
cbdbee80 220 if (options.expectedStatus && res.status !== options.expectedStatus) {
d102de1b 221 const err = new Error(`Expected status ${options.expectedStatus}, got ${res.status}. ` +
b65f5367 222 `\nThe server responded: "${res.body?.error ?? res.text}".\n` +
cbdbee80 223 'You may take a closer look at the logs. To see how to do so, check out this page: ' +
d102de1b
C
224 'https://github.com/Chocobozzz/PeerTube/blob/develop/support/doc/development/tests.md#debug-server-logs');
225
226 (err as any).res = res
227
228 throw err
cbdbee80 229 }
d102de1b 230
cbdbee80
F
231 return res
232 })
c0e8b12e
C
233}
234
235function buildFields (req: request.Test, fields: { [ fieldName: string ]: any }, namespace?: string) {
236 if (!fields) return
237
238 let formKey: string
239
240 for (const key of Object.keys(fields)) {
241 if (namespace) formKey = `${namespace}[${key}]`
242 else formKey = key
243
244 if (fields[key] === undefined) continue
245
246 if (Array.isArray(fields[key]) && fields[key].length === 0) {
63436fc5 247 req.field(key, [])
c0e8b12e
C
248 continue
249 }
250
251 if (fields[key] !== null && typeof fields[key] === 'object') {
252 buildFields(req, fields[key], formKey)
253 } else {
254 req.field(formKey, fields[key])
255 }
256 }
0e1dc3e7 257}