tmanderson / ivona-node

Ivona Cloud (via Amazon services) client library for Node
32 stars 5 forks source link

Proxy settings aren't working #9

Closed pablosbrain closed 8 years ago

pablosbrain commented 8 years ago

Using Node v5.5.0 64bit I am getting the following error.

C:\Users\xxx\Desktop\ivonatts\node_modules\ivona-node\src\proxy.js:14 var req = http.request({ ^

ReferenceError: http is not defined at HttpsProxyAgent.createConnection (C:\Users\xxx\Desktop\ivonatts\node_modules\ivona-node\src\proxy.js:14:19) at HttpsProxyAgent.createSocket (C:\Users\xxx\Desktop\ivonatts\node_modules\ivona-node\src\proxy.js:79:10) at HttpsProxyAgent.addRequest (C:\Users\xxx\Desktop\ivonatts\node_modules\ivona-node\src\proxy.js:52:14) at new ClientRequest (_http_client.js:137:16) at Object.exports.request (http.js:31:10) at Object.exports.request (https.js:181:15) at Object.IvonaRequest.exec (C:\Users\xxx\Desktop\ivonatts\node_modules\ivona-node\src\main.js:147:21) at Object.Ivona.createVoice (C:\Users\xxx\Desktop\ivonatts\node_modules\ivona-node\src\main.js:248:29) at Object. (C:\Users\xxx\Desktop\ivonatts\index.js:20:7) at Module._compile (module.js:413:34)

Here is my config.

var ivona = new Ivona({ accessKey: '' , secretKey: '' , proxy: { host: 'proxy.corp.com' , port: 81 } });

Hopefully it may be an easy fix. The lib works great outside a firewall. Just having issues getting through a corporate proxy.

stsvilik commented 8 years ago

This is the same issue I reported earlier - http is not "required" in. If you want to fix it yourself simple add

var http = require("http");

at the top of the file, otherwise create a PR to fix it.

pablosbrain commented 8 years ago

Will give it a try when i'm back in the office after the weekend. I must have missed your earlier report when looking around. Thank you for the quick response!

pablosbrain commented 8 years ago

Getting "TypeError('Request path contains unescaped characters.');"

In the proxy.js file where it is putting together the connection like so...

path : opts.host + ':' + opts.port,

I am getting this in the output.

"path": "[object Object]:undefined",

tmanderson commented 8 years ago

@pablosbrain, I've just pushed the latest patch release (v0.3.0) which should be available through npm soon. We had a PR sometime ago that (I believe) fixed this issue.

Could you please see if the latest version fixes your issue, and let me know the results?

Thanks!

pablosbrain commented 8 years ago

Thanks for the update. I downloaded the 0.3.0 zip. Modified the start of line 13 section this.createConnection = function (opts, callback) { to have this for logging.

this.createConnection = function (opts, callback) {
// do a CONNECT request
console.log("opts passed in:", JSON.stringify(opts));
console.log("opts.host passed in:", JSON.stringify(opts.host));
console.log("opts.port passed in:", JSON.stringify(opts.port));
var reqopts = {
            host    : options.proxyHost,
            port    : options.proxyPort,
            method  : 'CONNECT',
            path    : opts.host + ':' + opts.port,
            headers : {
                host: opts.host
            }
};
console.log("createConnection reqopts", JSON.stringify(reqopts));
var req = http.request(reqopts);
...

opts.port ends up "undefined" and opts.host isn't a string. I console.logged the opts.host object to get this:

{ "_defaultAgent": { "domain": null, "_events": {}, "_eventsCount": 1, "defaultPort": 443, "protocol": "https:", "options": { "path": null }, "requests": {}, "sockets": {}, "freeSockets": {}, "keepAliveMsecs": 1000, "keepAlive": false, "maxSockets": null, "maxFreeSockets": 256, "maxCachedSessions": 100, "_sessionCache": { "map": {}, "list": [] } }, "path": "/ListVoices", "host": "tts.eu-west-1.ivonacloud.com", "buffer": true, "service": "tts", "method": "POST", "region": "eu-west-1", "proxy": { "host": "proxy.internal.com", "port": 80 }, "headers": { "content-type": "application/json", "Host": "tts.eu-west-1.ivonacloud.com", "Content-Length": 11, "X-Amz-Date": "20160516T150827Z", "Authorization": "AWS4-HMAC-SHA256 Credential=accesskeyhere/20160516/eu-west-1/tts/aws4_request, SignedHeaders=content-length;content-type;host;x-amz-date, Signature=eb0683e1c627f833cfc7ce6e15071f239756cc471a4e17c9740708f64d416fe6" }, "body": "{\"Body\":{}}", "agent": { "domain": null, "_events": {}, "_eventsCount": 1, "defaultPort": 443, "protocol": "https:", "options": { "proxyPort": 80, "proxyHost": "proxy.internal.com", "path": null }, "requests": {}, "sockets": { "[object Object]:undefined": [] }, "freeSockets": {}, "keepAliveMsecs": 1000, "keepAlive": false, "maxSockets": null, "maxFreeSockets": 256, "maxCachedSessions": 100, "_sessionCache": { "map": {}, "list": [] }, "proxyHost": "proxy.internal.com", "proxyPort": 80 }, "port": 443 }

pablosbrain commented 8 years ago

Still getting

_http_client.js:53 throw new TypeError('Request path contains unescaped characters.'); ^

And the request object outputs to that below. Will keep digging. Not sure what may be causing the non escaped character error.

requestParams:   { path: '/ListVoices',
  host: 'tts.us-east-1.ivonacloud.com',
  buffer: true,
  service: 'tts',
  method: 'POST',
  region: 'us-east-1',
  proxy: { host: 'proxy.internal.com', port: 80 },
  headers: 
   { 'content-type': 'application/json',
     Host: 'tts.us-east-1.ivonacloud.com',
     'Content-Length': 11,
     'X-Amz-Date': '20160517T193249Z',
     Authorization: 'AWS4-HMAC-SHA256 Credential=IVONAACCESSKEY/20160517/us-east-1/tts/aws4_request, SignedHeaders=content-length;content-type;host;x-amz-date, Signature=d25467b95934fae2e3e86586a2774a225646869c831d2481408d8268599306bd' },
  body: '{"Body":{}}' }
agentdata:   { proxyHost: 'proxy.internal.com', proxyPort: 80 }
requestParams:   { path: '/ListVoices',
  host: 'tts.us-east-1.ivonacloud.com',
  buffer: true,
  service: 'tts',
  method: 'POST',
  region: 'us-east-1',
  proxy: { host: 'proxy.internal.com', port: 80 },
  headers: 
   { 'content-type': 'application/json',
     Host: 'tts.us-east-1.ivonacloud.com',
     'Content-Length': 11,
     'X-Amz-Date': '20160517T193249Z',
     Authorization: 'AWS4-HMAC-SHA256 Credential=IVONAACCESSKEY/20160517/us-east-1/tts/aws4_request, SignedHeaders=content-length;content-type;host;x-amz-date, Signature=d25467b95934fae2e3e86586a2774a225646869c831d2481408d8268599306bd' },
  body: '{"Body":{}}',
  agent: 
   HttpsProxyAgent {
     domain: null,
     _events: { free: [Function] },
     _eventsCount: 1,
     _maxListeners: undefined,
     defaultPort: 443,
     protocol: 'https:',
     options: { proxyPort: 80, proxyHost: 'proxy.internal.com', path: null },
     requests: {},
     sockets: {},
     freeSockets: {},
     keepAliveMsecs: 1000,
     keepAlive: false,
     maxSockets: Infinity,
     maxFreeSockets: 256,
     maxCachedSessions: 100,
     _sessionCache: { map: {}, list: [] },
     proxyHost: 'proxy.internal.com',
     proxyPort: 80,
     createConnection: [Function] } }
pablosbrain commented 8 years ago

Starting in proxy.js on line 13... v0.3.0

    this.createConnection = function (opts, callback) {
        // do a CONNECT request
        var req = http.request({
            host    : options.proxyHost,
            port    : options.proxyPort,
            method  : 'CONNECT',
            path    : opts.host + ':' + opts.port,
            headers : {
                host: opts.host
            }
        });

I'm getting the following when logging the data out. options.proxyHost: proxy.internal.com options.proxyPort: 80 opts.port: undefined opts.host:

{ _defaultAgent:
   Agent {
     domain: null,
     _events: { free: [Function] },
     _eventsCount: 1,
     _maxListeners: undefined,
     defaultPort: 443,
     protocol: 'https:',
     options: { path: null },
     requests: {},
     sockets: {},
     freeSockets: {},
     keepAliveMsecs: 1000,
     keepAlive: false,
     maxSockets: Infinity,
     maxFreeSockets: 256,
     maxCachedSessions: 100,
     _sessionCache: { map: {}, list: [] } },
  path: '/ListVoices',
  host: 'tts.us-east-1.ivonacloud.com',
  buffer: true,
  service: 'tts',
  method: 'POST',
  region: 'us-east-1',
  proxy: { host: 'proxy.internal.com', port: 80 },
  headers:
   { 'content-type': 'application/json',
     Host: 'tts.us-east-1.ivonacloud.com',
     'Content-Length': 11,
     'X-Amz-Date': '20160517T194127Z',
     Authorization: 'AWS4-HMAC-SHA256 Credential=IVONAACCESSKEY/20160517/us-east-1/tts/aws4_request, SignedHeaders=content-length;content-type;host;x-amz-date, Signature=be771b146c52a3697dc4c12fcafed74728e8d86d90c65c773037eeb1a675de25' },
  body: '{"Body":{}}',
  agent:
   HttpsProxyAgent {
     domain: null,
     _events: { free: [Function] },
     _eventsCount: 1,
     _maxListeners: undefined,
     defaultPort: 443,
     protocol: 'https:',
     options: { proxyPort: 80, proxyHost: 'proxy.internal.com', path: null },
     requests: {},
     sockets: { '[object Object]:undefined': [] },
     freeSockets: {},
     keepAliveMsecs: 1000,
     keepAlive: false,
     maxSockets: Infinity,
     maxFreeSockets: 256,
     maxCachedSessions: 100,
     _sessionCache: { map: {}, list: [] },
     proxyHost: 'proxy.internal.com',
     proxyPort: 80,
     createConnection: [Function] },
  port: 443 }

based on that object output are the following supposed to be this? opts.port: 443 opts.host: 'tts.us-east-1.ivonacloud.com',

If so.. would changing it to be the below be close or am i following the wrong path for that.

path    : opts.host.Agent.host + ':' + opts.port.port,
pablosbrain commented 8 years ago

Now getting:

opts.host.host: tts.us-east-1.ivonacloud.com opts.host.port: 443

With this:

    this.createConnection = function (opts, callback) {
        // do a CONNECT request
        var reqdata = {
            host    : options.proxyHost,
            port    : options.proxyPort,
            method  : 'CONNECT',
            path    : opts.host.host + ':' + opts.host.port,
            headers : {
                host: opts.host
            }
        };
        console.log("opts.host.host:\t", opts.host.host);
        console.log("opts.host.port:\t", opts.host.port);
        console.log("reqdata:\t", reqdata);
        var req = http.request(reqdata);

Now the error is:

_http_agent.js:162
        options.servername = hostHeader.replace(/:.*$/, '');
                                        ^

TypeError: hostHeader.replace is not a function
    at Agent.createSocket (_http_agent.js:162:41)
    at Agent.addRequest (_http_agent.js:141:23)
    at new ClientRequest (_http_client.js:137:16)
    at Object.exports.request (http.js:31:10)
    at HttpsProxyAgent.createConnection (C:\Users\user\Desktop\ivonatts\node_modules\ivona-node\src\proxy.js:31:24)
    at HttpsProxyAgent.createSocket (C:\Users\user\Desktop\ivonatts\node_modules\ivona-node\src\proxy.js:88:10)
    at HttpsProxyAgent.addRequest (C:\Users\user\Desktop\ivonatts\node_modules\ivona-node\src\proxy.js:61:14)
    at new ClientRequest (_http_client.js:137:16)
    at Object.exports.request (http.js:31:10)
    at Object.exports.request (https.js:181:15)
pablosbrain commented 8 years ago

Corrected this:

headers : {
                host: opts.host
            }

to this:

headers : {
                host: opts.host.host
            }

And this...

  req.on('connect', function (res, socket, head) {
            var cts = Tls.connect({
                host: opts.host,
                socket: socket
            }, function () {
                callback(false, cts);
            });
        });

To:

  req.on('connect', function (res, socket, head) {
            var cts = Tls.connect({
                host: opts.host.host,
                socket: socket
            }, function () {
                callback(false, cts);
            });
        });

And tada it finally works. I'll post once more with a working modified proxy.js file.

pablosbrain commented 8 years ago

Here is my corrected proxy.js file

var util    = require('util'),
    http    = require('http'),
    https   = require('https'),
    Tls     = require('tls');

// HttpsProxyAgent for handling proxying
function HttpsProxyAgent(options) {
    https.Agent.call(this, options);

    this.proxyHost = options.proxyHost;
    this.proxyPort = options.proxyPort;

    this.createConnection = function (opts, callback) {
        // do a CONNECT request
        var reqdata = {
            host    : options.proxyHost,
            port    : options.proxyPort,
            method  : 'CONNECT',
            path    : opts.host.host + ':' + opts.host.port,
            headers : {
                host: opts.host.host
            }
        };
        //console.log("opts.host:\t", opts.host);
        //console.log("opts.port:\t", opts.port);
        //console.log("opts.host.host:\t", opts.host.host);
        //console.log("opts.host.port:\t", opts.host.port);
        console.log("reqdata:\t", reqdata);
        var req = http.request(reqdata);

        req.on('connect', function (res, socket, head) {
            var cts = Tls.connect({
                host: opts.host.host,
                socket: socket
            }, function () {
                callback(false, cts);
            });
        });

        req.on('error', function (err) {
            callback(err, null);
        });

        req.end();
    };
}

util.inherits(HttpsProxyAgent, https.Agent);

// Almost verbatim copy of http.Agent.addRequest
HttpsProxyAgent.prototype.addRequest = function (req, host, port, localAddress) {
    var name = host + ':' + port;
    if (localAddress) name += ':' + localAddress;

    if (!this.sockets[name]) this.sockets[name] = [];

    if (this.sockets[name].length < this.maxSockets) {
        // if we are under maxSockets create a new one.
        this.createSocket(name, host, port, localAddress, req, function (socket) {
            req.onSocket(socket);
        });
    } else {
        // we are over limit so we'll add it to the queue.
        if (!this.requests[name])
            this.requests[name] = [];
        this.requests[name].push(req);
    }
};

// Almost verbatim copy of http.Agent.createSocket
HttpsProxyAgent.prototype.createSocket = function (name, host, port, localAddress, req, callback) {
    var self = this;
    var options = util._extend({}, self.options);

    options.port         = port;
    options.host         = host;
    options.localAddress = localAddress;

    options.servername = host;
    if (req) {
        var hostHeader = req.getHeader('host');
        if (hostHeader)
            options.servername = hostHeader.replace(/:.*$/, '');
    }

    self.createConnection(options, function (err, s) {
        if (err) {
            err.message += ' while connecting to HTTP(S) proxy server ' + self.proxyHost + ':' + self.proxyPort;

            if (req)
                req.emit('error', err);
            else
                throw err;

            return;
        }

        if (!self.sockets[name]) self.sockets[name] = [];

        self.sockets[name].push(s);

        var onFree = function () {
            self.emit('free', s, host, port, localAddress);
        };

        var onClose = function (err) {
            // this is the only place where sockets get removed from the Agent.
            // if you want to remove a socket from the pool, just close it.
            // all socket errors end in a close event anyway.
            self.removeSocket(s, name, host, port, localAddress);
        };

        var onRemove = function () {
            // we need this function for cases like HTTP 'upgrade'
            // (defined by WebSockets) where we need to remove a socket from the pool
            // because it'll be locked up indefinitely
            self.removeSocket(s, name, host, port, localAddress);
            s.removeListener('close', onClose);
            s.removeListener('free', onFree);
            s.removeListener('agentRemove', onRemove);
        };

        s.on('free', onFree);
        s.on('close', onClose);
        s.on('agentRemove', onRemove);

        callback(s);
    });
};

module.exports = HttpsProxyAgent;
tmanderson commented 8 years ago

@pablosbrain, if you've gotten it to a place where you think things are working would you mind creating fork and then follow up with PR?

Thanks a lot! Glad you managed to get things working!

pablosbrain commented 8 years ago

Will do! I'm very excited to spend time tomorrow working with this now!

tmanderson commented 8 years ago

@pablosbrain, great to hear!

Thank you!

yogeshtas commented 7 years ago

{ [NetworkingError: connect ECONNREFUSED] message: 'connect ECONNREFUSED', code: 'NetworkingError', errno: 'ECONNREFUSED', syscall: 'connect', region: 'ap-south-1', hostname: 'asset-mmp-example.s3.ap-south-1.amazonaws.com', retryable: true, time: Fri Jun 02 2017 12:56:09 GMT-0700 (Pacific Daylight Time) }