source: node_modules/nodemailer/lib/smtp-connection/http-proxy-client.js@ 81bc7da

finki-main main
Last change on this file since 81bc7da was 81bc7da, checked in by Klimentina Efremova <klimentina08642@…>, 3 months ago

Initial commit

  • Property mode set to 100644
File size: 4.2 KB
Line 
1'use strict';
2
3/**
4 * Minimal HTTP/S proxy client
5 */
6
7const net = require('net');
8const tls = require('tls');
9const urllib = require('url');
10
11/**
12 * Establishes proxied connection to destinationPort
13 *
14 * httpProxyClient("http://localhost:3128/", 80, "google.com", function(err, socket){
15 * socket.write("GET / HTTP/1.0\r\n\r\n");
16 * });
17 *
18 * @param {String} proxyUrl proxy configuration, etg "http://proxy.host:3128/"
19 * @param {Number} destinationPort Port to open in destination host
20 * @param {String} destinationHost Destination hostname
21 * @param {Function} callback Callback to run with the rocket object once connection is established
22 */
23function httpProxyClient(proxyUrl, destinationPort, destinationHost, callback) {
24 let proxy = urllib.parse(proxyUrl);
25
26 // create a socket connection to the proxy server
27 let options;
28 let connect;
29 let socket;
30
31 options = {
32 host: proxy.hostname,
33 port: Number(proxy.port) ? Number(proxy.port) : proxy.protocol === 'https:' ? 443 : 80
34 };
35
36 if (proxy.protocol === 'https:') {
37 // we can use untrusted proxies as long as we verify actual SMTP certificates
38 options.rejectUnauthorized = false;
39 connect = tls.connect.bind(tls);
40 } else {
41 connect = net.connect.bind(net);
42 }
43
44 // Error harness for initial connection. Once connection is established, the responsibility
45 // to handle errors is passed to whoever uses this socket
46 let finished = false;
47 let tempSocketErr = err => {
48 if (finished) {
49 return;
50 }
51 finished = true;
52 try {
53 socket.destroy();
54 } catch (E) {
55 // ignore
56 }
57 callback(err);
58 };
59
60 let timeoutErr = () => {
61 let err = new Error('Proxy socket timed out');
62 err.code = 'ETIMEDOUT';
63 tempSocketErr(err);
64 };
65
66 socket = connect(options, () => {
67 if (finished) {
68 return;
69 }
70
71 let reqHeaders = {
72 Host: destinationHost + ':' + destinationPort,
73 Connection: 'close'
74 };
75 if (proxy.auth) {
76 reqHeaders['Proxy-Authorization'] = 'Basic ' + Buffer.from(proxy.auth).toString('base64');
77 }
78
79 socket.write(
80 // HTTP method
81 'CONNECT ' +
82 destinationHost +
83 ':' +
84 destinationPort +
85 ' HTTP/1.1\r\n' +
86 // HTTP request headers
87 Object.keys(reqHeaders)
88 .map(key => key + ': ' + reqHeaders[key])
89 .join('\r\n') +
90 // End request
91 '\r\n\r\n'
92 );
93
94 let headers = '';
95 let onSocketData = chunk => {
96 let match;
97 let remainder;
98
99 if (finished) {
100 return;
101 }
102
103 headers += chunk.toString('binary');
104 if ((match = headers.match(/\r\n\r\n/))) {
105 socket.removeListener('data', onSocketData);
106
107 remainder = headers.substr(match.index + match[0].length);
108 headers = headers.substr(0, match.index);
109 if (remainder) {
110 socket.unshift(Buffer.from(remainder, 'binary'));
111 }
112
113 // proxy connection is now established
114 finished = true;
115
116 // check response code
117 match = headers.match(/^HTTP\/\d+\.\d+ (\d+)/i);
118 if (!match || (match[1] || '').charAt(0) !== '2') {
119 try {
120 socket.destroy();
121 } catch (E) {
122 // ignore
123 }
124 return callback(new Error('Invalid response from proxy' + ((match && ': ' + match[1]) || '')));
125 }
126
127 socket.removeListener('error', tempSocketErr);
128 socket.removeListener('timeout', timeoutErr);
129 socket.setTimeout(0);
130
131 return callback(null, socket);
132 }
133 };
134 socket.on('data', onSocketData);
135 });
136
137 socket.setTimeout(httpProxyClient.timeout || 30 * 1000);
138 socket.on('timeout', timeoutErr);
139
140 socket.once('error', tempSocketErr);
141}
142
143module.exports = httpProxyClient;
Note: See TracBrowser for help on using the repository browser.