UNPKG

2.29 kBJavaScriptView Raw
1'use strict'
2
3const http = require('http')
4const https = require('https')
5
6function protocol (url) {
7 if (url.startsWith('https')) {
8 return https
9 }
10 return http
11}
12
13function unsecureCookies (headers) {
14 ['Set-Cookie', 'set-cookie'].forEach(name => {
15 if (headers[name]) {
16 headers[name] = headers[name].map(cookie => cookie.replace(/\s*secure;/i, ''))
17 }
18 })
19}
20
21function noop () {}
22
23function validateHook (mapping, hookName) {
24 if (typeof mapping[hookName] === 'string') {
25 mapping[hookName] = require(mapping[hookName])
26 }
27}
28
29module.exports = {
30 schema: {
31 'unsecure-cookies': {
32 type: 'boolean',
33 defaultValue: false
34 },
35 'forward-request': {
36 types: ['function', 'string'],
37 defaultValue: noop
38 },
39 'forward-response': {
40 types: ['function', 'string'],
41 defaultValue: noop
42 }
43 },
44 validate: async mapping => {
45 validateHook(mapping, 'forward-request')
46 validateHook(mapping, 'forward-response')
47 },
48 redirect: async ({ configuration, mapping, match, redirect: url, request, response }) => {
49 let done
50 let fail
51 const promise = new Promise((resolve, reject) => {
52 done = resolve
53 fail = reject
54 })
55 const { method, headers } = request
56 delete headers.host // Some websites rely on the host header
57 const options = {
58 method,
59 url,
60 headers
61 }
62 const context = {}
63 await mapping['forward-request']({ configuration, context, mapping, match, request: options })
64 const redirectedRequest = protocol(options.url).request(options.url, options, async redirectedResponse => {
65 if (mapping['unsecure-cookies']) {
66 unsecureCookies(redirectedResponse.headers)
67 }
68 const { headers: responseHeaders } = redirectedResponse
69 await mapping['forward-response']({ configuration, context, mapping, match, headers: responseHeaders })
70 response.writeHead(redirectedResponse.statusCode, responseHeaders)
71 response.on('finish', done)
72 redirectedResponse
73 .on('error', fail)
74 .pipe(response)
75 })
76 redirectedRequest.on('error', fail)
77 request
78 .on('data', chunk => redirectedRequest.write(chunk))
79 .on('error', fail)
80 .on('end', () => { redirectedRequest.end() })
81 return promise
82 }
83}