Blame view

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