Software zum Installieren eines Smart-Mirror Frameworks , zum Nutzen von hochschulrelevanten Informationen, auf einem Raspberry-Pi.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

tunnel.js 7.4KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264
  1. 'use strict';
  2. var net = require('net');
  3. var tls = require('tls');
  4. var http = require('http');
  5. var https = require('https');
  6. var events = require('events');
  7. var assert = require('assert');
  8. var util = require('util');
  9. exports.httpOverHttp = httpOverHttp;
  10. exports.httpsOverHttp = httpsOverHttp;
  11. exports.httpOverHttps = httpOverHttps;
  12. exports.httpsOverHttps = httpsOverHttps;
  13. function httpOverHttp(options) {
  14. var agent = new TunnelingAgent(options);
  15. agent.request = http.request;
  16. return agent;
  17. }
  18. function httpsOverHttp(options) {
  19. var agent = new TunnelingAgent(options);
  20. agent.request = http.request;
  21. agent.createSocket = createSecureSocket;
  22. agent.defaultPort = 443;
  23. return agent;
  24. }
  25. function httpOverHttps(options) {
  26. var agent = new TunnelingAgent(options);
  27. agent.request = https.request;
  28. return agent;
  29. }
  30. function httpsOverHttps(options) {
  31. var agent = new TunnelingAgent(options);
  32. agent.request = https.request;
  33. agent.createSocket = createSecureSocket;
  34. agent.defaultPort = 443;
  35. return agent;
  36. }
  37. function TunnelingAgent(options) {
  38. var self = this;
  39. self.options = options || {};
  40. self.proxyOptions = self.options.proxy || {};
  41. self.maxSockets = self.options.maxSockets || http.Agent.defaultMaxSockets;
  42. self.requests = [];
  43. self.sockets = [];
  44. self.on('free', function onFree(socket, host, port, localAddress) {
  45. var options = toOptions(host, port, localAddress);
  46. for (var i = 0, len = self.requests.length; i < len; ++i) {
  47. var pending = self.requests[i];
  48. if (pending.host === options.host && pending.port === options.port) {
  49. // Detect the request to connect same origin server,
  50. // reuse the connection.
  51. self.requests.splice(i, 1);
  52. pending.request.onSocket(socket);
  53. return;
  54. }
  55. }
  56. socket.destroy();
  57. self.removeSocket(socket);
  58. });
  59. }
  60. util.inherits(TunnelingAgent, events.EventEmitter);
  61. TunnelingAgent.prototype.addRequest = function addRequest(req, host, port, localAddress) {
  62. var self = this;
  63. var options = mergeOptions({request: req}, self.options, toOptions(host, port, localAddress));
  64. if (self.sockets.length >= this.maxSockets) {
  65. // We are over limit so we'll add it to the queue.
  66. self.requests.push(options);
  67. return;
  68. }
  69. // If we are under maxSockets create a new one.
  70. self.createSocket(options, function(socket) {
  71. socket.on('free', onFree);
  72. socket.on('close', onCloseOrRemove);
  73. socket.on('agentRemove', onCloseOrRemove);
  74. req.onSocket(socket);
  75. function onFree() {
  76. self.emit('free', socket, options);
  77. }
  78. function onCloseOrRemove(err) {
  79. self.removeSocket(socket);
  80. socket.removeListener('free', onFree);
  81. socket.removeListener('close', onCloseOrRemove);
  82. socket.removeListener('agentRemove', onCloseOrRemove);
  83. }
  84. });
  85. };
  86. TunnelingAgent.prototype.createSocket = function createSocket(options, cb) {
  87. var self = this;
  88. var placeholder = {};
  89. self.sockets.push(placeholder);
  90. var connectOptions = mergeOptions({}, self.proxyOptions, {
  91. method: 'CONNECT',
  92. path: options.host + ':' + options.port,
  93. agent: false,
  94. headers: {
  95. host: options.host + ':' + options.port
  96. }
  97. });
  98. if (options.localAddress) {
  99. connectOptions.localAddress = options.localAddress;
  100. }
  101. if (connectOptions.proxyAuth) {
  102. connectOptions.headers = connectOptions.headers || {};
  103. connectOptions.headers['Proxy-Authorization'] = 'Basic ' +
  104. new Buffer(connectOptions.proxyAuth).toString('base64');
  105. }
  106. debug('making CONNECT request');
  107. var connectReq = self.request(connectOptions);
  108. connectReq.useChunkedEncodingByDefault = false; // for v0.6
  109. connectReq.once('response', onResponse); // for v0.6
  110. connectReq.once('upgrade', onUpgrade); // for v0.6
  111. connectReq.once('connect', onConnect); // for v0.7 or later
  112. connectReq.once('error', onError);
  113. connectReq.end();
  114. function onResponse(res) {
  115. // Very hacky. This is necessary to avoid http-parser leaks.
  116. res.upgrade = true;
  117. }
  118. function onUpgrade(res, socket, head) {
  119. // Hacky.
  120. process.nextTick(function() {
  121. onConnect(res, socket, head);
  122. });
  123. }
  124. function onConnect(res, socket, head) {
  125. connectReq.removeAllListeners();
  126. socket.removeAllListeners();
  127. if (res.statusCode !== 200) {
  128. debug('tunneling socket could not be established, statusCode=%d',
  129. res.statusCode);
  130. socket.destroy();
  131. var error = new Error('tunneling socket could not be established, ' +
  132. 'statusCode=' + res.statusCode);
  133. error.code = 'ECONNRESET';
  134. options.request.emit('error', error);
  135. self.removeSocket(placeholder);
  136. return;
  137. }
  138. if (head.length > 0) {
  139. debug('got illegal response body from proxy');
  140. socket.destroy();
  141. var error = new Error('got illegal response body from proxy');
  142. error.code = 'ECONNRESET';
  143. options.request.emit('error', error);
  144. self.removeSocket(placeholder);
  145. return;
  146. }
  147. debug('tunneling connection has established');
  148. self.sockets[self.sockets.indexOf(placeholder)] = socket;
  149. return cb(socket);
  150. }
  151. function onError(cause) {
  152. connectReq.removeAllListeners();
  153. debug('tunneling socket could not be established, cause=%s\n',
  154. cause.message, cause.stack);
  155. var error = new Error('tunneling socket could not be established, ' +
  156. 'cause=' + cause.message);
  157. error.code = 'ECONNRESET';
  158. options.request.emit('error', error);
  159. self.removeSocket(placeholder);
  160. }
  161. };
  162. TunnelingAgent.prototype.removeSocket = function removeSocket(socket) {
  163. var pos = this.sockets.indexOf(socket)
  164. if (pos === -1) {
  165. return;
  166. }
  167. this.sockets.splice(pos, 1);
  168. var pending = this.requests.shift();
  169. if (pending) {
  170. // If we have pending requests and a socket gets closed a new one
  171. // needs to be created to take over in the pool for the one that closed.
  172. this.createSocket(pending, function(socket) {
  173. pending.request.onSocket(socket);
  174. });
  175. }
  176. };
  177. function createSecureSocket(options, cb) {
  178. var self = this;
  179. TunnelingAgent.prototype.createSocket.call(self, options, function(socket) {
  180. var hostHeader = options.request.getHeader('host');
  181. var tlsOptions = mergeOptions({}, self.options, {
  182. socket: socket,
  183. servername: hostHeader ? hostHeader.replace(/:.*$/, '') : options.host
  184. });
  185. // 0 is dummy port for v0.6
  186. var secureSocket = tls.connect(0, tlsOptions);
  187. self.sockets[self.sockets.indexOf(socket)] = secureSocket;
  188. cb(secureSocket);
  189. });
  190. }
  191. function toOptions(host, port, localAddress) {
  192. if (typeof host === 'string') { // since v0.10
  193. return {
  194. host: host,
  195. port: port,
  196. localAddress: localAddress
  197. };
  198. }
  199. return host; // for v0.11 or later
  200. }
  201. function mergeOptions(target) {
  202. for (var i = 1, len = arguments.length; i < len; ++i) {
  203. var overrides = arguments[i];
  204. if (typeof overrides === 'object') {
  205. var keys = Object.keys(overrides);
  206. for (var j = 0, keyLen = keys.length; j < keyLen; ++j) {
  207. var k = keys[j];
  208. if (overrides[k] !== undefined) {
  209. target[k] = overrides[k];
  210. }
  211. }
  212. }
  213. }
  214. return target;
  215. }
  216. var debug;
  217. if (process.env.NODE_DEBUG && /\btunnel\b/.test(process.env.NODE_DEBUG)) {
  218. debug = function() {
  219. var args = Array.prototype.slice.call(arguments);
  220. if (typeof args[0] === 'string') {
  221. args[0] = 'TUNNEL: ' + args[0];
  222. } else {
  223. args.unshift('TUNNEL:');
  224. }
  225. console.error.apply(console, args);
  226. }
  227. } else {
  228. debug = function() {};
  229. }
  230. exports.debug = debug; // for test