1 | 'use strict';
|
2 |
|
3 | const logger = require('./logger').getLogger('http-request');
|
4 | const superagent = require('superagent');
|
5 | const Promise = require('bluebird');
|
6 | const { makeCounters } = require('./httpRequestCounters');
|
7 |
|
8 | const wrapWithMonitoring = makeCounters();
|
9 |
|
10 | const DEFAULT_REQUEST_TIMEOUT = process.env.DEFAULT_REQUEST_TIMEOUT || 30000;
|
11 | const DOWNLOAD_REQUEST_TIMEOUT = 60000;
|
12 |
|
13 | function getCaFile() {
|
14 | return global.caFileContent;
|
15 | }
|
16 |
|
17 | function binaryParser(res, fn) {
|
18 | const data = [];
|
19 |
|
20 | res.on('data', (chunk) => {
|
21 | data.push(chunk);
|
22 | });
|
23 | res.on('end', () => {
|
24 | fn(null, Buffer.concat(data));
|
25 | });
|
26 | }
|
27 |
|
28 | function getProxy() {
|
29 | if (!superagent.Request.prototype.proxy && global.SuperagentProxy) {
|
30 | global.SuperagentProxy(superagent);
|
31 | }
|
32 | return global.proxyUri;
|
33 | }
|
34 |
|
35 | function deleteMethod(url, headers, timeout) {
|
36 | return deleteFullRes(url, headers, timeout)
|
37 | .then(res => {
|
38 | if (res.type === 'text/plain') {
|
39 | return res.text;
|
40 | }
|
41 | return res.body;
|
42 | })
|
43 | .tapCatch((err) => logger.error('failed to delete request', { url, error: { message: err.message, stack: err.stack } }));
|
44 | }
|
45 |
|
46 | function deleteFullRes(url, headers = {}, timeout = DEFAULT_REQUEST_TIMEOUT) {
|
47 | const request = superagent
|
48 | .delete(url)
|
49 | .timeout(timeout)
|
50 | .set(headers);
|
51 |
|
52 | if (getCaFile()) {
|
53 | request.ca(getCaFile());
|
54 | }
|
55 |
|
56 | if (getProxy()) {
|
57 | request.proxy(getProxy());
|
58 | }
|
59 |
|
60 | return Promise.fromCallback((callback) => request.end(callback));
|
61 | }
|
62 |
|
63 | function post({
|
64 | url, body, headers, timeout, retry,
|
65 | }) {
|
66 | return postFullRes(url, body, headers, timeout, retry)
|
67 | .then(res => {
|
68 | if (res.type === 'text/plain') {
|
69 | return res.text;
|
70 | }
|
71 | return res.body;
|
72 | })
|
73 | .tapCatch((err) => logger.error('failed to post request', { url, error: { message: err.message, stack: err.stack } }));
|
74 | }
|
75 |
|
76 | function postFullRes(url, body, headers = {}, timeout = DEFAULT_REQUEST_TIMEOUT, retry) {
|
77 | const request = superagent
|
78 | .post(url)
|
79 | .send(body)
|
80 | .timeout(timeout)
|
81 | .set(headers);
|
82 |
|
83 | if (getCaFile()) {
|
84 | request.ca(getCaFile());
|
85 | }
|
86 |
|
87 | if (getProxy()) {
|
88 | request.proxy(getProxy());
|
89 | }
|
90 |
|
91 | if (retry) {
|
92 | request.retry(retry);
|
93 | }
|
94 |
|
95 | return Promise.fromCallback((callback) => request.end(callback)).catch(e => e, e => {
|
96 | e.url = url;
|
97 | e.originalRequestTimeout = timeout;
|
98 | e.additionalSetHeaders = headers;
|
99 | throw e;
|
100 | });
|
101 | }
|
102 |
|
103 | function postForm(url, fields, files, headers = {}, timeout = DEFAULT_REQUEST_TIMEOUT) {
|
104 | const request = superagent
|
105 | .post(url)
|
106 | .type('form')
|
107 | .timeout(timeout)
|
108 | .set(headers);
|
109 |
|
110 | request.field(fields);
|
111 |
|
112 | Object.keys(files).forEach(file => {
|
113 | request.attach(file, files[file].buffer, files[file].fileName);
|
114 | });
|
115 |
|
116 | if (getCaFile()) {
|
117 | request.ca(getCaFile());
|
118 | }
|
119 |
|
120 | if (getProxy()) {
|
121 | request.proxy(getProxy());
|
122 | }
|
123 |
|
124 | return Promise.fromCallback((callback) => request.end(callback))
|
125 | .then((res) => {
|
126 | if (res.type === 'text/plain') {
|
127 | return res.text;
|
128 | }
|
129 | return res.body;
|
130 | })
|
131 | .tapCatch((err) => logger.error('failed to post request', { url, error: { message: err.message, stack: err.stack } }));
|
132 | }
|
133 |
|
134 | function _get(url, query, headers = {}, timeout = DEFAULT_REQUEST_TIMEOUT, { isBinary = false } = {}) {
|
135 | const request = superagent
|
136 | .get(url)
|
137 | .query(query)
|
138 | .timeout(timeout)
|
139 | .set(headers);
|
140 |
|
141 | if (isBinary) {
|
142 | request.buffer(true);
|
143 | }
|
144 |
|
145 | if (getCaFile()) {
|
146 | request.ca(getCaFile());
|
147 | }
|
148 |
|
149 | if (getProxy()) {
|
150 | request.proxy(getProxy());
|
151 | }
|
152 |
|
153 | return Promise.fromCallback((callback) => request.end(callback));
|
154 | }
|
155 |
|
156 | function getText(url, query, headers) {
|
157 | return _get(url, query, headers)
|
158 | .then((res) => res.text)
|
159 | .tapCatch((err) => logger.error('failed to getText request', { url, query, error: { message: err.message, stack: err.stack } }));
|
160 | }
|
161 |
|
162 | function get(url, query, headers, timeout, options) {
|
163 | return _get(url, query, headers, timeout, options)
|
164 | .then((res) => res.body)
|
165 | .tapCatch((err) => logger.warn('failed to get request', { url, query, error: { message: err.message, stack: err.stack } }));
|
166 | }
|
167 |
|
168 | function getFullRes(url, query, headers, timeout) {
|
169 | return _get(url, query, headers, timeout);
|
170 | }
|
171 |
|
172 | function head(url) {
|
173 | const request = superagent
|
174 | .head(url)
|
175 | .timeout(DEFAULT_REQUEST_TIMEOUT);
|
176 |
|
177 | if (getCaFile()) {
|
178 | request.ca(getCaFile());
|
179 | }
|
180 |
|
181 | if (getProxy()) {
|
182 | request.proxy(getProxy());
|
183 | }
|
184 |
|
185 | return Promise.fromCallback((callback) => request.end(callback))
|
186 | .tapCatch((err) => logger.error('failed to head request', { url, error: { message: err.message, stack: err.stack } }));
|
187 | }
|
188 |
|
189 | function put(url, body, headers = {}, timeout = DEFAULT_REQUEST_TIMEOUT) {
|
190 | const request = superagent
|
191 | .put(url)
|
192 | .send(body)
|
193 | .timeout(timeout)
|
194 | .set(headers);
|
195 |
|
196 | if (getCaFile()) {
|
197 | request.ca(getCaFile());
|
198 | }
|
199 |
|
200 | if (getProxy()) {
|
201 | request.proxy(getProxy());
|
202 | }
|
203 |
|
204 | return Promise.fromCallback((callback) => request.end(callback))
|
205 | .then((res) => res.body)
|
206 | .tapCatch((err) => logger.error('failed to put request', { url, error: { message: err.message, stack: err.stack } }));
|
207 | }
|
208 |
|
209 | function download(url) {
|
210 | logger.info('start to download', { url });
|
211 |
|
212 | const request = superagent
|
213 | .get(url)
|
214 | .timeout(DOWNLOAD_REQUEST_TIMEOUT)
|
215 | .buffer(true)
|
216 | .parse(binaryParser);
|
217 |
|
218 | if (getCaFile()) {
|
219 | request.ca(getCaFile());
|
220 | }
|
221 |
|
222 | if (getProxy()) {
|
223 | request.proxy(getProxy());
|
224 | }
|
225 |
|
226 | return Promise.fromCallback((callback) => request.end(callback))
|
227 | .tap(() => logger.info('finished to download', { url }))
|
228 | .tapCatch((err) => logger.error('failed to download', { error: { message: err.message, stack: err.stack } }));
|
229 | }
|
230 |
|
231 | module.exports = {
|
232 | delete: wrapWithMonitoring(deleteMethod),
|
233 | deleteFullRes: wrapWithMonitoring(deleteFullRes),
|
234 | put: wrapWithMonitoring(put),
|
235 | get: wrapWithMonitoring(get),
|
236 | getText: wrapWithMonitoring(getText),
|
237 | post: wrapWithMonitoring(post),
|
238 | postFullRes: wrapWithMonitoring(postFullRes),
|
239 | getFullRes: wrapWithMonitoring(getFullRes),
|
240 | postForm: wrapWithMonitoring(postForm),
|
241 | head: wrapWithMonitoring(head),
|
242 | download: wrapWithMonitoring(download),
|
243 | isNetworkHealthy: wrapWithMonitoring.isNetworkHealthy,
|
244 | };
|