|
1 | 1 | import axios from "axios" |
2 | 2 | import { AxiosRequestConfig } from "axios" |
| 3 | +import buildURL from "axios/lib/helpers/buildURL" |
3 | 4 | import { cloneSafe } from "./utils" |
4 | 5 |
|
5 | | -// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURI |
6 | | -// see non-escaped chars |
7 | | -// this handles not encoding [!'()*] |
8 | | -function encodeReservedChars(str: String) { |
9 | | - return str.replace(/[!'()*]/g, function(c) { |
10 | | - return '%' + c.charCodeAt(0).toString(16) |
11 | | - }) |
| 6 | +function cleanObject(o: {string: any}) { |
| 7 | + for (const k in o || {}) { |
| 8 | + if (typeof o[k] === "undefined") { |
| 9 | + delete o[k] |
| 10 | + } |
| 11 | + } |
| 12 | +} |
| 13 | + |
| 14 | +// remove query params from url and put into config.params |
| 15 | +function removeSearchFromUrl(config: AxiosRequestConfig) { |
| 16 | + if (!config.url) return |
| 17 | + const url = new URL(config.url) |
| 18 | + const queryString = url.search.substr(1) |
| 19 | + if (queryString) { |
| 20 | + // https://stackoverflow.com/a/8649003/387413 |
| 21 | + const urlParams = JSON.parse('{"' + queryString.replace(/&/g, '","').replace(/=/g,'":"') + '"}', function(key, value) { |
| 22 | + return key === "" ? value : decodeURIComponent(value) |
| 23 | + }) |
| 24 | + for (const k in urlParams) { |
| 25 | + if (!config.params) config.params = {} |
| 26 | + if (k in config.params) continue // params object > url query params |
| 27 | + config.params[k] = urlParams[k] |
| 28 | + } |
| 29 | + url.search = "" |
| 30 | + config.url = url.toString() // if ends with ? should be okay, but could be cleaner |
| 31 | + } |
12 | 32 | } |
13 | 33 |
|
| 34 | +// XXX warn about mutating config object... or clone? |
14 | 35 | export default async function(step: any, config: AxiosRequestConfig, signConfig?: any) { |
15 | | - // XXX warn about mutating config object... or clone? |
| 36 | + cleanObject(config.headers) |
| 37 | + cleanObject(config.params) |
| 38 | + if (typeof config.data === "object") { |
| 39 | + cleanObject(config.data) |
| 40 | + } |
| 41 | + removeSearchFromUrl(config) |
16 | 42 | // OAuth1 request |
17 | 43 | if (signConfig) { |
18 | 44 | const {oauthSignerUri, token} = signConfig |
19 | | - |
20 | | - if (config.url) { |
21 | | - // this handles encoding query string to make sure we match what we sign |
22 | | - const url = new URL(config.url) |
23 | | - url.search = encodeReservedChars(url.search.substr(1)) |
24 | | - config.url = url.toString() |
| 45 | + const requestData = { |
| 46 | + method: config.method || "get", |
| 47 | + url: buildURL(config.url, config.params), // build url as axios will |
| 48 | + data: config.data, |
25 | 49 | } |
26 | | - |
27 | 50 | const payload = { |
28 | | - requestData: config, |
| 51 | + requestData, |
29 | 52 | token, |
30 | 53 | } |
31 | 54 | const oauthSignature = (await axios.post(oauthSignerUri, payload)).data |
32 | 55 | if (!config.headers) config.headers = {} |
33 | 56 | config.headers.Authorization = oauthSignature |
34 | 57 | } |
35 | | - for (const k in config.headers || {}) { |
36 | | - if (typeof config.headers[k] === "undefined") { |
37 | | - delete config.headers[k] |
38 | | - } |
39 | | - } |
40 | 58 | try { |
41 | 59 | return (await axios(config)).data |
42 | 60 | } catch (err) { |
|
0 commit comments