From f3b168d5da4e1f7b668b5f03d3aeae23b6b091b0 Mon Sep 17 00:00:00 2001 From: snyk-bot Date: Tue, 2 Aug 2022 06:20:57 +0000 Subject: [PATCH 1/3] fix: upgrade axios from 0.21.4 to 0.27.2 Snyk has created this PR to upgrade axios from 0.21.4 to 0.27.2. See this package in npm: https://www.npmjs.com/package/axios See this project in Snyk: https://app.snyk.io/org/devx-je4/project/54f1a21e-e017-4514-8c91-9b664831971f?utm_source=github&utm_medium=referral&page=upgrade-pr --- package-lock.json | 57 ++++++++++++++++++++++++++++++++++------------- package.json | 2 +- 2 files changed, 43 insertions(+), 16 deletions(-) diff --git a/package-lock.json b/package-lock.json index 5acb2ac..cf44076 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,7 +10,7 @@ "license": "MIT", "dependencies": { "@apimatic/schema": "^0.6.0", - "axios": "^0.21.4", + "axios": "^0.27.2", "detect-node": "^2.0.4", "form-data": "^3.0.0", "json-bigint": "^1.0.0", @@ -2772,11 +2772,25 @@ } }, "node_modules/axios": { - "version": "0.21.4", - "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz", - "integrity": "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.27.2.tgz", + "integrity": "sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ==", "dependencies": { - "follow-redirects": "^1.14.0" + "follow-redirects": "^1.14.9", + "form-data": "^4.0.0" + } + }, + "node_modules/axios/node_modules/form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" } }, "node_modules/axobject-query": { @@ -5096,9 +5110,9 @@ "dev": true }, "node_modules/follow-redirects": { - "version": "1.14.7", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.7.tgz", - "integrity": "sha512-+hbxoLbFMbRKDwohX8GkTataGqO6Jb7jGwpAlwgy2bIz25XtRm7KEzJM76R1WiNT5SwZkX4Y75SwBolkpmE7iQ==", + "version": "1.15.1", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.1.tgz", + "integrity": "sha512-yLAMQs+k0b2m7cVxpS1VKJVvoz7SS9Td1zss3XRwXj+ZDH00RJgnuLx7E44wx02kQLrdM3aOOy+FpzS7+8OizA==", "funding": [ { "type": "individual", @@ -14571,11 +14585,24 @@ "dev": true }, "axios": { - "version": "0.21.4", - "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz", - "integrity": "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.27.2.tgz", + "integrity": "sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ==", "requires": { - "follow-redirects": "^1.14.0" + "follow-redirects": "^1.14.9", + "form-data": "^4.0.0" + }, + "dependencies": { + "form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + } + } } }, "axobject-query": { @@ -16410,9 +16437,9 @@ "dev": true }, "follow-redirects": { - "version": "1.14.7", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.7.tgz", - "integrity": "sha512-+hbxoLbFMbRKDwohX8GkTataGqO6Jb7jGwpAlwgy2bIz25XtRm7KEzJM76R1WiNT5SwZkX4Y75SwBolkpmE7iQ==" + "version": "1.15.1", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.1.tgz", + "integrity": "sha512-yLAMQs+k0b2m7cVxpS1VKJVvoz7SS9Td1zss3XRwXj+ZDH00RJgnuLx7E44wx02kQLrdM3aOOy+FpzS7+8OizA==" }, "for-in": { "version": "1.0.2", diff --git a/package.json b/package.json index c8bbb50..59fd510 100644 --- a/package.json +++ b/package.json @@ -41,7 +41,7 @@ }, "dependencies": { "@apimatic/schema": "^0.6.0", - "axios": "^0.21.4", + "axios": "^0.27.2", "detect-node": "^2.0.4", "form-data": "^3.0.0", "json-bigint": "^1.0.0", From 1798d48f0d5b58a5744e5703455fbd1b6903bf85 Mon Sep 17 00:00:00 2001 From: Brian Date: Tue, 23 Aug 2022 12:32:54 -0400 Subject: [PATCH 2/3] DX-2754 httpClient and header fixes for the axios upgrade --- .dccache | 1 + src/http/httpClient.ts | 361 ++++++++++++++++++++-------------------- src/http/httpHeaders.ts | 18 +- tests/headers.test.js | 41 +++++ tests/media.test.js | 24 +++ tests/messaging.test.js | 24 +++ 6 files changed, 281 insertions(+), 188 deletions(-) create mode 100644 .dccache create mode 100644 tests/headers.test.js diff --git a/.dccache b/.dccache new file mode 100644 index 0000000..ab5c12a --- /dev/null +++ b/.dccache @@ -0,0 +1 @@ +{"/Users/briangomez/Documents/GitHub/node-messaging/babel.config.js":[204,1659705714943.5713,"fa772f54746a9909165c8671bd41c155a7f0ff2eae656b697edf488552660def"],"/Users/briangomez/Documents/GitHub/node-messaging/jest.config.js":[96,1659705714943.6633,"66a86f6289c8f96665d0fc3052a9af9f979bbffbebd6691cec15778049494c83"],"/Users/briangomez/Documents/GitHub/node-messaging/tsdx.config.js":[369,1660050569567.7708,"6654b5b4c7ab9fb4b0aac79f4cd09f9065071200ce95d6261778bc37509d411f"],"/Users/briangomez/Documents/GitHub/node-messaging/tests/media.test.js":[1503,1659705714951.161,"70763f3333de5f2187b97641097b3d2f0fcd1b446f4dba40ce9bc5a10e87d2c5"],"/Users/briangomez/Documents/GitHub/node-messaging/tests/messaging.test.js":[2533,1661272286248.8257,"000b3c5338f152f7a903cf2c2c9dc96f22110d38cb808b849b7f754f65b92bbf"],"/Users/briangomez/Documents/GitHub/node-messaging/src/apiHelper.ts":[1860,1659705714946.8882,"a94c50f2cd7f8c0a26f7dedfc20cf0ad14e3e34f3128b6e3a858ac9e0fc9e19f"],"/Users/briangomez/Documents/GitHub/node-messaging/src/apiResponse.ts":[568,1659705714946.9812,"07d13e790226f8e3dc01ee3a23ee6221cc5715889467bbfbc337dcb4c8cdd663"],"/Users/briangomez/Documents/GitHub/node-messaging/src/authentication.ts":[854,1659705714947.075,"47c65c8a2589f4d60beb8030356aac5efa90adbd75e3df88d052d7da795ca510"],"/Users/briangomez/Documents/GitHub/node-messaging/src/client.ts":[3493,1659705714947.1873,"7e0eec3e4fbef8b7026ac1b96aa35993c6121bea63f50b3c08ef024475d95bf2"],"/Users/briangomez/Documents/GitHub/node-messaging/src/clientInterface.ts":[505,1659705714947.2742,"fcdf7b92d2797f8a54f71823ec9f463056060e0cbe13692610586334ee6eb685"],"/Users/briangomez/Documents/GitHub/node-messaging/src/configuration.ts":[497,1659705714947.362,"9e74601b6fdb3ce9b8cb4d1f2b92b655d505febd77ea12351e0fb5d9f772d004"],"/Users/briangomez/Documents/GitHub/node-messaging/src/defaultConfiguration.ts":[476,1659705714947.7285,"c7d6e0bafeba27ec1e5548c9f30af004a135d6ebc1fb9f877d6c79d58d0cfa58"],"/Users/briangomez/Documents/GitHub/node-messaging/src/dom.d.ts":[139,1659705714947.8186,"92ab09e8e3f62833cb385a7754a2b205eea5c7dc5669d9ad91aafa1a9979cca7"],"/Users/briangomez/Documents/GitHub/node-messaging/src/fileWrapper.ts":[1491,1659705714948.419,"3492941a1fc50b6258f21fd5b64104a57bbe9e1b8c55fae2d4cfa64f47de61a6"],"/Users/briangomez/Documents/GitHub/node-messaging/src/index.ts":[1106,1660231585143.4548,"43921163aa75eb6b6be35faed68b4e03cea0a83b9d26c38eeecdcd2fcb36c64b"],"/Users/briangomez/Documents/GitHub/node-messaging/src/schema.ts":[145,1659705714950.7805,"508ee3b8f142099c776b4382fddda7fc470a10fe14b00093194cbcbcd25b97bb"],"/Users/briangomez/Documents/GitHub/node-messaging/src/types.d.ts":[143,1659705714951.024,"f0054c4571d45fc4f93a5b7586bb8e4cd23526c9c0229abbf7b48bc5b9471cf1"],"/Users/briangomez/Documents/GitHub/node-messaging/src/controllers/apiController.ts":[10651,1659705714947.546,"ef9312726109b7ba0e82f290a6d0b845637709720299e6d68b6a098c3ebe6e57"],"/Users/briangomez/Documents/GitHub/node-messaging/src/controllers/baseController.ts":[455,1659705714947.6387,"0aae976e3b603fb87539ffd3edd99db500df5b4f5bf6538210a816b991d2d7f4"],"/Users/briangomez/Documents/GitHub/node-messaging/src/errors/abortError.ts":[323,1659705714947.9495,"fe98b215a9af04dd9b8e156a3e8852276d41f150a6d6654d28ed75e4b185eebc"],"/Users/briangomez/Documents/GitHub/node-messaging/src/errors/apiError.ts":[1423,1659705714948.0408,"d607ba8bb5436271cbd42053cf2932521dec8d1193cf02946e31522aa064a4ee"],"/Users/briangomez/Documents/GitHub/node-messaging/src/errors/argumentsValidationError.ts":[1361,1659705714948.1301,"0b6c928ea2689b57242d67d82c608be7897de277ed59d994124ecf74f24d4243"],"/Users/briangomez/Documents/GitHub/node-messaging/src/errors/messagingExceptionError.ts":[356,1659705714948.235,"deb97d9ba1d8ee4b1aebd0105730507a54109cc8cb214d26ffc518848079dcd0"],"/Users/briangomez/Documents/GitHub/node-messaging/src/errors/responseValidationError.ts":[1090,1659705714948.329,"291b67dcdcb93d28ee19caaf51fb2a3ee09022864f3008a39b1b4d43262028fb"],"/Users/briangomez/Documents/GitHub/node-messaging/src/http/httpClient.ts":[5849,1661270964276.2244,"78b250fa48fe88684fd662b805bf215aff3f60467ac7642388ed2ea67728ce0d"],"/Users/briangomez/Documents/GitHub/node-messaging/src/http/httpContext.ts":[368,1659705714948.6567,"1f30c6c96df06092b1696c2fd03c77e6f9e97be208f2dc8dce9af99651ee4fbb"],"/Users/briangomez/Documents/GitHub/node-messaging/src/http/httpHeaders.ts":[4873,1661271023960.034,"6af156e11ed255007bccd56ce2e06b7a03f784588113345476dc9622432c10c4"],"/Users/briangomez/Documents/GitHub/node-messaging/src/http/httpInterceptor.ts":[1849,1659705714948.857,"b8c611846da780b543d534d72f2063f17623e493b6ecc103e1d8fbba75e7a7ea"],"/Users/briangomez/Documents/GitHub/node-messaging/src/http/httpRequest.ts":[1338,1659705714948.9624,"f648efeff4fa1e0a458ce6e4a03768d7990701f3dd5fdfbea71f6c02b584967d"],"/Users/briangomez/Documents/GitHub/node-messaging/src/http/httpResponse.ts":[390,1659705714949.0396,"76ca320c9a26719234f6f05c892006179c225335d717349ba5e876e30ade75f9"],"/Users/briangomez/Documents/GitHub/node-messaging/src/http/pathTemplate.ts":[1859,1659705714949.1394,"14c0d9cc6fafbc87d19cbf5a35d2266cf73ae1d8e5c27c9b29b6403a7815f558"],"/Users/briangomez/Documents/GitHub/node-messaging/src/http/queryString.ts":[3698,1659705714949.2363,"cdd2dbb9399984f94ff0a895c360eaf0c28cc529734201de4775728fb41d9fbc"],"/Users/briangomez/Documents/GitHub/node-messaging/src/http/requestBuilder.ts":[17514,1659705714949.3997,"f9ff9f45cc0db6efa085d361b12dc29370678f3cf9848c47e2d9a8cbd7a0a4f3"],"/Users/briangomez/Documents/GitHub/node-messaging/src/http/validate.ts":[1660,1659705714949.52,"87837a0022000319879da7c2f8d201f6efc59553d079d803c3861c74c76d5b1d"],"/Users/briangomez/Documents/GitHub/node-messaging/src/http/xmlSerialization.ts":[407,1659705714949.6067,"6ab7742312537a0b028057b9bdd4ead6f6cff00376f6ef6fa901c8bf72990adc"],"/Users/briangomez/Documents/GitHub/node-messaging/src/models/bandwidthCallbackMessage.ts":[822,1659705714949.8489,"d298cab844e7fd1c3fc043e46afb6cc15f93775d75c454eeb3a994cfe588599e"],"/Users/briangomez/Documents/GitHub/node-messaging/src/models/bandwidthMessage.ts":[1738,1659705714949.9475,"5bacdeefc7367c052741f9bba60a8d657f063244844fc728d79f72501ff10700"],"/Users/briangomez/Documents/GitHub/node-messaging/src/models/bandwidthMessageItem.ts":[1696,1659705714950.0527,"299d728ea4e215513624b815528569edab07bc374412f27a239f1dafbc8db422"],"/Users/briangomez/Documents/GitHub/node-messaging/src/models/bandwidthMessagesList.ts":[836,1659705714950.154,"96d7c053ade31e38f46ed3a460de667ca305fcefb9472fc8833c0feaf0c8d5d5"],"/Users/briangomez/Documents/GitHub/node-messaging/src/models/deferredResult.ts":[438,1659705714950.2507,"0e6f5701fb2a8686243be64b4c7b313c3ea38e9f58532e8047847d13279b16f0"],"/Users/briangomez/Documents/GitHub/node-messaging/src/models/media.ts":[481,1659705714950.3357,"134add70c3443d3fea28d659560fc28525d58e3e70134f47ceb3adddcab56f6d"],"/Users/briangomez/Documents/GitHub/node-messaging/src/models/messageRequest.ts":[1474,1659705714950.4229,"e4057fe137132d8f321b87d45ffe689e9b935bb4fadc42dd6d55bbaaa9713c5f"],"/Users/briangomez/Documents/GitHub/node-messaging/src/models/pageInfo.ts":[786,1659705714950.5034,"995e19f7a5c486a1c79045100ff3f695939b9693736268f7a8e165a6c396e869"],"/Users/briangomez/Documents/GitHub/node-messaging/src/models/priorityEnum.ts":[380,1659705714950.5986,"d673de222c1996690a7cacf3124fa9135771f8e6d188ae57fddb6f2b811679d7"],"/Users/briangomez/Documents/GitHub/node-messaging/src/models/tag.ts":[361,1659705714950.69,"31ffe47f9df8864bd801c4582df0850bcda6f79557a6d240c2fcd7c0ce4bb910"],"/Users/briangomez/Documents/GitHub/node-messaging/src/shim/index.ts":[154,1659705714950.9307,"8b3efc4285ec5c2e77452e51ac9b8b3a1a7745e56c7aa5b825151834e5d47ba7"]} \ No newline at end of file diff --git a/src/http/httpClient.ts b/src/http/httpClient.ts index b132535..37bc6d6 100644 --- a/src/http/httpClient.ts +++ b/src/http/httpClient.ts @@ -4,182 +4,185 @@ * This file was automatically generated by APIMATIC v2.0 ( https://apimatic.io ). */ -import axios, { AxiosInstance, AxiosRequestConfig, AxiosResponse } from 'axios'; -import isNode from 'detect-node'; -import FormData from 'form-data'; -import { isBlob } from '../apiHelper'; -import { AbortError } from '../errors/abortError'; -import { isFileWrapper } from '../fileWrapper'; -import { - CONTENT_TYPE_HEADER, - FORM_URLENCODED_CONTENT_TYPE, - mergeHeaders, - setHeader, - setHeaderIfNotSet, -} from './httpHeaders'; -import { HttpRequest } from './httpRequest'; -import { HttpResponse } from './httpResponse'; -import { urlEncodeKeyValuePairs } from './queryString'; - -export const DEFAULT_AXIOS_CONFIG_OVERRIDES: AxiosRequestConfig = { - transformResponse: [], -}; - -export const DEFAULT_TIMEOUT = 30 * 1000; - -/** - * HTTP client implementation. - * - * This implementation is a wrapper over the Axios client. - */ -export class HttpClient { - private _axiosInstance: AxiosInstance; - private _timeout: number; - - constructor({ - clientConfigOverrides, - timeout = DEFAULT_TIMEOUT, - }: { clientConfigOverrides?: AxiosRequestConfig; timeout?: number } = {}) { - this._timeout = timeout; - this._axiosInstance = axios.create({ - ...DEFAULT_AXIOS_CONFIG_OVERRIDES, - ...clientConfigOverrides, - }); - } - - /** Converts an HttpRequest object to an Axios request. */ - public convertHttpRequest(req: HttpRequest): AxiosRequestConfig { - const newRequest: AxiosRequestConfig = { - method: req.method, - url: req.url, - responseType: 'text', - headers: { ...req.headers }, - }; - - if (req.auth) { - // Set basic auth credentials if provided - newRequest.auth = { - username: req.auth.username, - password: req.auth.password || '', - }; - } - - const requestBody = req.body; - if (requestBody?.type === 'text') { - newRequest.data = requestBody.content; - } else if ( - requestBody?.type === 'form-data' && - requestBody.content.some(item => isFileWrapper(item.value)) - ) { - // Create multipart request if a file is present - const form = new FormData(); - for (const iter of requestBody.content) { - if (isFileWrapper(iter.value)) { - let fileData = iter.value.file; - - // Make sure Blob has the correct content type if provided - if (isBlob(fileData) && iter.value.options?.contentType) { - fileData = new Blob([fileData], { - type: iter.value.options.contentType, - }); - } - - form.append(iter.key, fileData, iter.value.options); - } else { - form.append(iter.key, iter.value); - } - } - - newRequest.data = form; - mergeHeaders(newRequest.headers, form.getHeaders()); - } else if ( - requestBody?.type === 'form-data' || - requestBody?.type === 'form' - ) { - // Create form-urlencoded request - setHeader( - newRequest.headers, - CONTENT_TYPE_HEADER, - FORM_URLENCODED_CONTENT_TYPE - ); - newRequest.data = urlEncodeKeyValuePairs(requestBody.content); - } else if (requestBody?.type === 'stream') { - let contentType = 'application/octet-stream'; - if (isBlob(requestBody.content.file) && requestBody.content.file.type) { - // Set Blob mime type as the content-type header if present - contentType = requestBody.content.file.type; - } else if (requestBody.content.options?.contentType) { - // Otherwise, use the content type if available. - contentType = requestBody.content.options.contentType; - } - setHeaderIfNotSet(newRequest.headers, CONTENT_TYPE_HEADER, contentType); - newRequest.data = requestBody.content.file; - } else if (requestBody?.type !== undefined) { - throw new Error( - `HTTP client encountered unknown body type '${requestBody?.type}'. Could not execute HTTP request.` - ); - } - - if (req.responseType === 'stream') { - newRequest.responseType = isNode ? 'stream' : 'blob'; - } - - // Prevent superagent from converting any status code to error - newRequest.validateStatus = () => true; - - // Set 30 seconds timeout - newRequest.timeout = this._timeout; - - return newRequest; - } - - /** Converts an Axios response to an HttpResponse object. */ - public convertHttpResponse(resp: AxiosResponse): HttpResponse { - return { - body: resp.data, - headers: resp.headers, - statusCode: resp.status, - }; - } - - /** - * Executes the HttpRequest with the given options and returns the HttpResponse - * or throws an error. - */ - public async executeRequest( - request: HttpRequest, - requestOptions?: { abortSignal?: AbortSignal } - ): Promise { - const axiosRequest = this.convertHttpRequest(request); - - if (requestOptions?.abortSignal) { - // throw if already aborted; do not place HTTP call - if (requestOptions.abortSignal.aborted) { - throw this.abortError(); - } - - const cancelToken = axios.CancelToken.source(); - axiosRequest.cancelToken = cancelToken.token; - - // attach abort event handler - requestOptions.abortSignal.addEventListener('abort', () => { - cancelToken.cancel(); - }); - } - - try { - return this.convertHttpResponse(await this._axiosInstance(axiosRequest)); - } catch (error) { - // abort error should be thrown as the AbortError - if (axios.isCancel(error)) { - throw this.abortError(); - } - - throw error; - } - } - - private abortError() { - return new AbortError('The HTTP call was aborted.'); - } -} + import axios, { AxiosInstance, AxiosRequestConfig, AxiosResponse } from 'axios'; + import isNode from 'detect-node'; + import FormData from 'form-data'; + import { isBlob } from '../apiHelper'; + import { AbortError } from '../errors/abortError'; + import { isFileWrapper } from '../fileWrapper'; + import { + CONTENT_TYPE_HEADER, + FORM_URLENCODED_CONTENT_TYPE, + mergeHeaders, + setHeader, + setHeaderIfNotSet, + } from './httpHeaders'; + import { HttpRequest } from './httpRequest'; + import { HttpResponse } from './httpResponse'; + import { urlEncodeKeyValuePairs } from './queryString'; + + export const DEFAULT_AXIOS_CONFIG_OVERRIDES: AxiosRequestConfig = { + transformResponse: [], + }; + + export const DEFAULT_TIMEOUT = 30 * 1000; + + /** + * HTTP client implementation. + * + * This implementation is a wrapper over the Axios client. + */ + export class HttpClient { + private _axiosInstance: AxiosInstance; + private _timeout: number; + + constructor({ + clientConfigOverrides, + timeout = DEFAULT_TIMEOUT, + }: { clientConfigOverrides?: AxiosRequestConfig; timeout?: number } = {}) { + this._timeout = timeout; + this._axiosInstance = axios.create({ + ...DEFAULT_AXIOS_CONFIG_OVERRIDES, + ...clientConfigOverrides, + }); + } + + /** Converts an HttpRequest object to an Axios request. */ + public convertHttpRequest(req: HttpRequest): AxiosRequestConfig { + const newRequest: AxiosRequestConfig = { + method: req.method, + url: req.url, + responseType: 'text', + headers: { ...req.headers }, + }; + + if (req.auth) { + // Set basic auth credentials if provided + newRequest.auth = { + username: req.auth.username, + password: req.auth.password || '', + }; + } + + const requestBody = req.body; + if (requestBody?.type === 'text') { + newRequest.data = requestBody.content; + } else if ( + requestBody?.type === 'form-data' && + requestBody.content.some(item => isFileWrapper(item.value)) + ) { + // Create multipart request if a file is present + const form = new FormData(); + for (const iter of requestBody.content) { + if (isFileWrapper(iter.value)) { + let fileData = iter.value.file; + + // Make sure Blob has the correct content type if provided + if (isBlob(fileData) && iter.value.options?.contentType) { + fileData = new Blob([fileData], { + type: iter.value.options.contentType, + }); + } + + form.append(iter.key, fileData, iter.value.options); + } else { + form.append(iter.key, iter.value); + } + } + + newRequest.data = form; + mergeHeaders(newRequest.headers || {} , form.getHeaders()); + } else if ( + requestBody?.type === 'form-data' || + requestBody?.type === 'form' + ) { + // Create form-urlencoded request + setHeader( + newRequest.headers || {}, + CONTENT_TYPE_HEADER, + FORM_URLENCODED_CONTENT_TYPE + ); + newRequest.data = urlEncodeKeyValuePairs(requestBody.content); + } else if (requestBody?.type === 'stream') { + let contentType = 'application/octet-stream'; + if (isBlob(requestBody.content.file) && requestBody.content.file.type) { + // Set Blob mime type as the content-type header if present + contentType = requestBody.content.file.type; + } else if (requestBody.content.options?.contentType) { + // Otherwise, use the content type if available. + contentType = requestBody.content.options.contentType; + } + setHeaderIfNotSet(newRequest.headers || {}, CONTENT_TYPE_HEADER, contentType); + newRequest.data = requestBody.content.file; + } + else if (requestBody && typeof(requestBody['type']) !== 'undefined') { + + throw new Error( + `HTTP client encountered unknown body type '${requestBody["type"]}'. Could not execute HTTP request.` + ); + } + + if (req.responseType === 'stream') { + newRequest.responseType = isNode ? 'stream' : 'blob'; + } + + // Prevent superagent from converting any status code to error + newRequest.validateStatus = () => true; + + // Set 30 seconds timeout + newRequest.timeout = this._timeout; + + return newRequest; + } + + /** Converts an Axios response to an HttpResponse object. */ + public convertHttpResponse(resp: AxiosResponse): HttpResponse { + return { + body: resp.data, + headers: resp.headers, + statusCode: resp.status, + }; + } + + /** + * Executes the HttpRequest with the given options and returns the HttpResponse + * or throws an error. + */ + public async executeRequest( + request: HttpRequest, + requestOptions?: { abortSignal?: AbortSignal } + ): Promise { + const axiosRequest = this.convertHttpRequest(request); + + if (requestOptions?.abortSignal) { + // throw if already aborted; do not place HTTP call + if (requestOptions.abortSignal.aborted) { + throw this.abortError(); + } + + const cancelToken = axios.CancelToken.source(); + axiosRequest.cancelToken = cancelToken.token; + + // attach abort event handler + requestOptions.abortSignal.addEventListener('abort', () => { + cancelToken.cancel(); + }); + } + + try { + return this.convertHttpResponse(await this._axiosInstance(axiosRequest)); + } catch (error) { + // abort error should be thrown as the AbortError + if (axios.isCancel(error)) { + throw this.abortError(); + } + + throw error; + } + } + + private abortError() { + return new AbortError('The HTTP call was aborted.'); + } + } + \ No newline at end of file diff --git a/src/http/httpHeaders.ts b/src/http/httpHeaders.ts index 7b01081..663d776 100644 --- a/src/http/httpHeaders.ts +++ b/src/http/httpHeaders.ts @@ -13,20 +13,20 @@ * @param name Header name * @param value Header value */ -export function setHeader( - headers: Record, + export function setHeader( + headers: Record, name: string, - value?: string + value?: string | number | boolean | undefined ): void { const realHeaderName = lookupCaseInsensitive(headers, name); setHeaderInternal(headers, realHeaderName, name, value); } function setHeaderInternal( - headers: Record, + headers: Record, realHeaderName: string | null, name: string, - value: string | undefined + value: string | number | boolean | undefined ): void { if (realHeaderName) { delete headers[realHeaderName]; @@ -46,9 +46,9 @@ function setHeaderInternal( * @param value Header value */ export function setHeaderIfNotSet( - headers: Record, + headers: Record, name: string, - value?: string + value?: string | number | boolean | undefined ): void { const realHeaderName = lookupCaseInsensitive(headers, name); if (!realHeaderName) { @@ -111,8 +111,8 @@ export function lookupCaseInsensitive( * @param headersToMerge Headers to set */ export function mergeHeaders( - headers: Record, - headersToMerge: Record + headers: Record, + headersToMerge: Record ): void { const headerKeys: Record = {}; diff --git a/tests/headers.test.js b/tests/headers.test.js new file mode 100644 index 0000000..803fffb --- /dev/null +++ b/tests/headers.test.js @@ -0,0 +1,41 @@ +import * as headers from '../src/http/httpHeaders' + +describe('headers', () => { + it('skips "undefined" value', () => { + let test_headers = {'test': 1} + headers.setHeader(test_headers, 'somethingundefined', undefined) + + expect(test_headers.somethingundefined).toBeUndefined(); + }); + + it('sets header internally if it does not exist', () => { + let test_headers = {} + headers.setHeader(test_headers, 'test', 2) + + expect(test_headers.test).toEqual(2) + }); + + it('sets header internally overring it if exists', () => { + let test_headers = {'test': 1} + headers.setHeader(test_headers, 'test', '22') + + expect(test_headers.test).toEqual('22') + }); + + //current functionality won;t allow false values! + it('sets header internally for boolean values', () => { + let test_headers = {'test': 1} + headers.setHeader(test_headers, 'test', true) + + expect(test_headers.test).toEqual(true) + }); + + it('sets header if not already set', () => { + let test_headers = {'test': 1} + headers.setHeaderIfNotSet(test_headers, 'test', '22') + expect(test_headers.test).toEqual(1) + + headers.setHeaderIfNotSet(test_headers, 'testnew', '22') + expect(test_headers.testnew).toEqual('22') + }); +}) \ No newline at end of file diff --git a/tests/media.test.js b/tests/media.test.js index 043e50d..d73eeab 100644 --- a/tests/media.test.js +++ b/tests/media.test.js @@ -1,4 +1,6 @@ import { Client, ApiController, FileWrapper } from '../src'; +import { HttpClient } from '../src/http/httpClient'; + let controller; @@ -11,6 +13,28 @@ beforeEach(() => { controller = new ApiController(client); }); +describe('http client', () => { + const httpClient = new HttpClient(); + it('should throw error on unknown body type', async () => { + const httpRequest = { + body: { + type: "somethingmadeup" + } + }; + expect(() => httpClient.convertHttpRequest(httpRequest)).toThrow("HTTP client encountered unknown body type 'somethingmadeup'. Could not execute HTTP request."); + }); + + it('should not throw error on known body type', async () => { + const httpRequest = { + body: { + type: "text" + } + }; + expect(httpClient.convertHttpRequest(httpRequest)).toBeDefined(); + }); +}); + + describe('media', () => { it('should upload and download media', async () => { const content = 'Hello world!'; diff --git a/tests/messaging.test.js b/tests/messaging.test.js index 854d311..72c6f92 100644 --- a/tests/messaging.test.js +++ b/tests/messaging.test.js @@ -1,4 +1,6 @@ import { Client, ApiController, FileWrapperi, MessagingExceptionError, MessageRequest } from '../src'; +import { HttpClient } from '../src/http/httpClient'; + let controller; @@ -11,6 +13,28 @@ beforeEach(() => { controller = new ApiController(client); }); +describe('http client', () => { + const httpClient = new HttpClient(); + it('should throw error on unknown body type', async () => { + const httpRequest = { + body: { + type: "somethingmadeup" + } + }; + expect(() => httpClient.convertHttpRequest(httpRequest)).toThrow("HTTP client encountered unknown body type 'somethingmadeup'. Could not execute HTTP request."); + }); + + it('should not throw error on known body type', async () => { + const httpRequest = { + body: { + type: "text" + } + }; + expect(httpClient.convertHttpRequest(httpRequest)).toBeDefined(); + }); +}); + + describe('messaging', () => { it('should create message with proper values', async () => { From 8acc03cbee24dbebf2eaf710a56027d5f514e51b Mon Sep 17 00:00:00 2001 From: Brian Date: Wed, 24 Aug 2022 11:53:36 -0400 Subject: [PATCH 3/3] Delete .dccache --- .dccache | 1 - 1 file changed, 1 deletion(-) delete mode 100644 .dccache diff --git a/.dccache b/.dccache deleted file mode 100644 index ab5c12a..0000000 --- a/.dccache +++ /dev/null @@ -1 +0,0 @@ -{"/Users/briangomez/Documents/GitHub/node-messaging/babel.config.js":[204,1659705714943.5713,"fa772f54746a9909165c8671bd41c155a7f0ff2eae656b697edf488552660def"],"/Users/briangomez/Documents/GitHub/node-messaging/jest.config.js":[96,1659705714943.6633,"66a86f6289c8f96665d0fc3052a9af9f979bbffbebd6691cec15778049494c83"],"/Users/briangomez/Documents/GitHub/node-messaging/tsdx.config.js":[369,1660050569567.7708,"6654b5b4c7ab9fb4b0aac79f4cd09f9065071200ce95d6261778bc37509d411f"],"/Users/briangomez/Documents/GitHub/node-messaging/tests/media.test.js":[1503,1659705714951.161,"70763f3333de5f2187b97641097b3d2f0fcd1b446f4dba40ce9bc5a10e87d2c5"],"/Users/briangomez/Documents/GitHub/node-messaging/tests/messaging.test.js":[2533,1661272286248.8257,"000b3c5338f152f7a903cf2c2c9dc96f22110d38cb808b849b7f754f65b92bbf"],"/Users/briangomez/Documents/GitHub/node-messaging/src/apiHelper.ts":[1860,1659705714946.8882,"a94c50f2cd7f8c0a26f7dedfc20cf0ad14e3e34f3128b6e3a858ac9e0fc9e19f"],"/Users/briangomez/Documents/GitHub/node-messaging/src/apiResponse.ts":[568,1659705714946.9812,"07d13e790226f8e3dc01ee3a23ee6221cc5715889467bbfbc337dcb4c8cdd663"],"/Users/briangomez/Documents/GitHub/node-messaging/src/authentication.ts":[854,1659705714947.075,"47c65c8a2589f4d60beb8030356aac5efa90adbd75e3df88d052d7da795ca510"],"/Users/briangomez/Documents/GitHub/node-messaging/src/client.ts":[3493,1659705714947.1873,"7e0eec3e4fbef8b7026ac1b96aa35993c6121bea63f50b3c08ef024475d95bf2"],"/Users/briangomez/Documents/GitHub/node-messaging/src/clientInterface.ts":[505,1659705714947.2742,"fcdf7b92d2797f8a54f71823ec9f463056060e0cbe13692610586334ee6eb685"],"/Users/briangomez/Documents/GitHub/node-messaging/src/configuration.ts":[497,1659705714947.362,"9e74601b6fdb3ce9b8cb4d1f2b92b655d505febd77ea12351e0fb5d9f772d004"],"/Users/briangomez/Documents/GitHub/node-messaging/src/defaultConfiguration.ts":[476,1659705714947.7285,"c7d6e0bafeba27ec1e5548c9f30af004a135d6ebc1fb9f877d6c79d58d0cfa58"],"/Users/briangomez/Documents/GitHub/node-messaging/src/dom.d.ts":[139,1659705714947.8186,"92ab09e8e3f62833cb385a7754a2b205eea5c7dc5669d9ad91aafa1a9979cca7"],"/Users/briangomez/Documents/GitHub/node-messaging/src/fileWrapper.ts":[1491,1659705714948.419,"3492941a1fc50b6258f21fd5b64104a57bbe9e1b8c55fae2d4cfa64f47de61a6"],"/Users/briangomez/Documents/GitHub/node-messaging/src/index.ts":[1106,1660231585143.4548,"43921163aa75eb6b6be35faed68b4e03cea0a83b9d26c38eeecdcd2fcb36c64b"],"/Users/briangomez/Documents/GitHub/node-messaging/src/schema.ts":[145,1659705714950.7805,"508ee3b8f142099c776b4382fddda7fc470a10fe14b00093194cbcbcd25b97bb"],"/Users/briangomez/Documents/GitHub/node-messaging/src/types.d.ts":[143,1659705714951.024,"f0054c4571d45fc4f93a5b7586bb8e4cd23526c9c0229abbf7b48bc5b9471cf1"],"/Users/briangomez/Documents/GitHub/node-messaging/src/controllers/apiController.ts":[10651,1659705714947.546,"ef9312726109b7ba0e82f290a6d0b845637709720299e6d68b6a098c3ebe6e57"],"/Users/briangomez/Documents/GitHub/node-messaging/src/controllers/baseController.ts":[455,1659705714947.6387,"0aae976e3b603fb87539ffd3edd99db500df5b4f5bf6538210a816b991d2d7f4"],"/Users/briangomez/Documents/GitHub/node-messaging/src/errors/abortError.ts":[323,1659705714947.9495,"fe98b215a9af04dd9b8e156a3e8852276d41f150a6d6654d28ed75e4b185eebc"],"/Users/briangomez/Documents/GitHub/node-messaging/src/errors/apiError.ts":[1423,1659705714948.0408,"d607ba8bb5436271cbd42053cf2932521dec8d1193cf02946e31522aa064a4ee"],"/Users/briangomez/Documents/GitHub/node-messaging/src/errors/argumentsValidationError.ts":[1361,1659705714948.1301,"0b6c928ea2689b57242d67d82c608be7897de277ed59d994124ecf74f24d4243"],"/Users/briangomez/Documents/GitHub/node-messaging/src/errors/messagingExceptionError.ts":[356,1659705714948.235,"deb97d9ba1d8ee4b1aebd0105730507a54109cc8cb214d26ffc518848079dcd0"],"/Users/briangomez/Documents/GitHub/node-messaging/src/errors/responseValidationError.ts":[1090,1659705714948.329,"291b67dcdcb93d28ee19caaf51fb2a3ee09022864f3008a39b1b4d43262028fb"],"/Users/briangomez/Documents/GitHub/node-messaging/src/http/httpClient.ts":[5849,1661270964276.2244,"78b250fa48fe88684fd662b805bf215aff3f60467ac7642388ed2ea67728ce0d"],"/Users/briangomez/Documents/GitHub/node-messaging/src/http/httpContext.ts":[368,1659705714948.6567,"1f30c6c96df06092b1696c2fd03c77e6f9e97be208f2dc8dce9af99651ee4fbb"],"/Users/briangomez/Documents/GitHub/node-messaging/src/http/httpHeaders.ts":[4873,1661271023960.034,"6af156e11ed255007bccd56ce2e06b7a03f784588113345476dc9622432c10c4"],"/Users/briangomez/Documents/GitHub/node-messaging/src/http/httpInterceptor.ts":[1849,1659705714948.857,"b8c611846da780b543d534d72f2063f17623e493b6ecc103e1d8fbba75e7a7ea"],"/Users/briangomez/Documents/GitHub/node-messaging/src/http/httpRequest.ts":[1338,1659705714948.9624,"f648efeff4fa1e0a458ce6e4a03768d7990701f3dd5fdfbea71f6c02b584967d"],"/Users/briangomez/Documents/GitHub/node-messaging/src/http/httpResponse.ts":[390,1659705714949.0396,"76ca320c9a26719234f6f05c892006179c225335d717349ba5e876e30ade75f9"],"/Users/briangomez/Documents/GitHub/node-messaging/src/http/pathTemplate.ts":[1859,1659705714949.1394,"14c0d9cc6fafbc87d19cbf5a35d2266cf73ae1d8e5c27c9b29b6403a7815f558"],"/Users/briangomez/Documents/GitHub/node-messaging/src/http/queryString.ts":[3698,1659705714949.2363,"cdd2dbb9399984f94ff0a895c360eaf0c28cc529734201de4775728fb41d9fbc"],"/Users/briangomez/Documents/GitHub/node-messaging/src/http/requestBuilder.ts":[17514,1659705714949.3997,"f9ff9f45cc0db6efa085d361b12dc29370678f3cf9848c47e2d9a8cbd7a0a4f3"],"/Users/briangomez/Documents/GitHub/node-messaging/src/http/validate.ts":[1660,1659705714949.52,"87837a0022000319879da7c2f8d201f6efc59553d079d803c3861c74c76d5b1d"],"/Users/briangomez/Documents/GitHub/node-messaging/src/http/xmlSerialization.ts":[407,1659705714949.6067,"6ab7742312537a0b028057b9bdd4ead6f6cff00376f6ef6fa901c8bf72990adc"],"/Users/briangomez/Documents/GitHub/node-messaging/src/models/bandwidthCallbackMessage.ts":[822,1659705714949.8489,"d298cab844e7fd1c3fc043e46afb6cc15f93775d75c454eeb3a994cfe588599e"],"/Users/briangomez/Documents/GitHub/node-messaging/src/models/bandwidthMessage.ts":[1738,1659705714949.9475,"5bacdeefc7367c052741f9bba60a8d657f063244844fc728d79f72501ff10700"],"/Users/briangomez/Documents/GitHub/node-messaging/src/models/bandwidthMessageItem.ts":[1696,1659705714950.0527,"299d728ea4e215513624b815528569edab07bc374412f27a239f1dafbc8db422"],"/Users/briangomez/Documents/GitHub/node-messaging/src/models/bandwidthMessagesList.ts":[836,1659705714950.154,"96d7c053ade31e38f46ed3a460de667ca305fcefb9472fc8833c0feaf0c8d5d5"],"/Users/briangomez/Documents/GitHub/node-messaging/src/models/deferredResult.ts":[438,1659705714950.2507,"0e6f5701fb2a8686243be64b4c7b313c3ea38e9f58532e8047847d13279b16f0"],"/Users/briangomez/Documents/GitHub/node-messaging/src/models/media.ts":[481,1659705714950.3357,"134add70c3443d3fea28d659560fc28525d58e3e70134f47ceb3adddcab56f6d"],"/Users/briangomez/Documents/GitHub/node-messaging/src/models/messageRequest.ts":[1474,1659705714950.4229,"e4057fe137132d8f321b87d45ffe689e9b935bb4fadc42dd6d55bbaaa9713c5f"],"/Users/briangomez/Documents/GitHub/node-messaging/src/models/pageInfo.ts":[786,1659705714950.5034,"995e19f7a5c486a1c79045100ff3f695939b9693736268f7a8e165a6c396e869"],"/Users/briangomez/Documents/GitHub/node-messaging/src/models/priorityEnum.ts":[380,1659705714950.5986,"d673de222c1996690a7cacf3124fa9135771f8e6d188ae57fddb6f2b811679d7"],"/Users/briangomez/Documents/GitHub/node-messaging/src/models/tag.ts":[361,1659705714950.69,"31ffe47f9df8864bd801c4582df0850bcda6f79557a6d240c2fcd7c0ce4bb910"],"/Users/briangomez/Documents/GitHub/node-messaging/src/shim/index.ts":[154,1659705714950.9307,"8b3efc4285ec5c2e77452e51ac9b8b3a1a7745e56c7aa5b825151834e5d47ba7"]} \ No newline at end of file