Implementing a simple proxy server using node.js - javascript

I'm trying to create a simple node.js proxy server for experimental purposes and I came up with this simple script:
var url = require("url");
var http = require("http");
var https = require("https");
http.createServer(function (request, response) {
var path = url.parse(request.url).path;
if (!path.indexOf("/resource/")) {
var protocol;
path = path.slice(10);
var location = url.parse(path);
switch (location.protocol) {
case "http:":
protocol = http;
break;
case "https:":
protocol = https;
break;
default:
response.writeHead(400);
response.end();
return;
}
var options = {
host: location.host,
hostname: location.hostname,
port: +location.port,
method: request.method,
path: location.path,
headers: request.headers,
auth: location.auth
};
var clientRequest = protocol.request(options, function (clientResponse) {
response.writeHead(clientResponse.statusCode, clientResponse.headers);
clientResponse.on("data", response.write);
clientResponse.on("end", function () {
response.addTrailers(clientResponse.trailers);
response.end();
});
});
request.on("data", clientRequest.write);
request.on("end", clientRequest.end);
} else {
response.writeHead(404);
response.end();
}
}).listen(8484);
I don't know where I'm going wrong but it gives me the following error when I try to load any page:
http.js:645
this._implicitHeader();
^
TypeError: Object #<IncomingMessage> has no method '_implicitHeader'
at IncomingMessage.<anonymous> (http.js:645:10)
at IncomingMessage.emit (events.js:64:17)
at HTTPParser.onMessageComplete (http.js:137:23)
at Socket.ondata (http.js:1410:22)
at TCP.onread (net.js:374:27)
I wonder what could the problem be. Debugging in node.js is so much more difficult than in Rhino. Any help will be greatly appreciated.

As I mentioned in the comments, your primary problem is that your .write and .end calls are not bound properly to a context, so they will just flip out and throw errors all over.
With that fixed, requests give a 404 because the headers property will pull in the host header of the original request, localhost:8484. Following your example, that will get send to jquery.com's server, and it will 404. You need to remove the host header before proxying.
Add this before calling protocol.request.
delete options.headers.host;

Related

Error: getaddrinfo ENOTFOUND when sending https request Node.js and API

I am developing a dashboard, I need to conect to a API and catch a Auth Token and afther that send info by using a HTTPS protocol. I use a Nodejs, and when I run my code I have the next error on the pm2 monit:
Error: getaddrinfo ENOTFOUND my.url.net/path
at GetAddrInfoReqWrap.onlookup [as oncomplete] (dns.js:67:26) {
errno: -3008,
code: 'ENOTFOUND',
syscall: 'getaddrinfo',
hostname: 'my.url.net/path'
}
Also here is my code where I made the request (Node.js):
const path = require('path');
require('dotenv').config({path: path.join('path','.env')});
const https = require('https');
const database = require('./sql');
const fs = require ('fs');
const user = process.env.USER;
const pwd = PWD;
const host = 'https://my.url.net/extencio';
const host_1 = 'my.url.net/extention';
async function getLoginToken(pForce){
if (login_token.Health && !pForce) { return login_token }
//Creates the POST request
const options = {
protocol: 'https:',
hostname: host_1,
path: '/api/auth/token',
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
}
};
//Body of the POST request, contains the user and password
const post_data = JSON.stringify({username: user, password: pwd});
.
Here is the rest of the code:
return new Promise((resolve, reject) => {
const req = new https.request(options, (response) => {
response.setEncoding('utf8');
response.on('data', function(chunk){
const output = JSON.parse(chunk);
if(output.token){
login_token.Health = true;
login_token.Token = output.token;
resolve(login_token)
}
else{
login_token.Health = false;
login_token.Token = '';
resolve(login_token);
}
});
});
req.write(post_data);
req.end();
req.on('error', function(err) {
console.log(err);
login_token.Health = false;
login_token.Token = '';
resolve(login_token)
});
});
}
Remove protocol, and use domain names only for the host. For instance:
Wrong:
const host = 'https://my.url.net/extencio'
const path = '/api/auth/token'
Correct:
const host = 'my.url.net'
const path = '/extencio/api/auth/token'
See documentation for the http.request options.
It seems that is trying to getaddrinfo of the full url, instead of just the hostname. I would put hostname in option as only "my.url.net" and update path with the rest of the url.
#Eric0607 the error stackoverflow.com/questions/65810720/… you've provided is not showing anymore, I might've been too late to reply.
but in case you got "an invalid local cert SSL error", here is a fix I found that works for it.
disable SSL check in your code, not recommended but it would work temporarily, turn it on after you're done or it can be risky.

How to use a node.js back-end server to interact with the front-end and a mongolab database?

I am building a website with a simple jquery/html/css front-end and a node.js server back-end. If my front-end has a function to request a user's information from the server like so:
function requestUser(email, password) {
xmlhttp = new XMLHttpRequest();
xmlhttp.open("GET", "http://localhost:8888/getUser/" + email + "/" + password, true);
xmlhttp.onreadystatechange = function() {
if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
console.log(xmlhttp.responseText);
}
}
xmlhttp.send();
}
and my node server looks like this:
var http = require("http"),
mongojs = require("mongojs"),
fs = require("fs"),
url = require("url");
express = require("express")
var server = http.createServer(requestHandler);
server.listen(8888);
var uri = "mongodb://<dbuser>:<dbpassword>#ds036698.mongolab.com:36698/alirodatabase";
var db = mongojs(uri, ["Papers", "Users"]);
console.log("node server running back end of app");
function requestHandler(request, response) {
//request for user is .../getUser/<username>/<password>
var path = url.parse(request.url).pathname;
var details = path.split('/');
if(details.indexOf("getUser") != -1) {
console.log("recieved request for user");
var user = db.Users.find({"email": details[details.indexOf("getUser") + 1],
"password": details[details.indexOf("getUser") + 2]});
user = user.toArray[0];
response.writeHead(200, {"Content-Type": "text/json"});
response.write(JSON.stringify(user));
}
else {
fs.readFile("./index.html", function(err, file) {
if(err) {
return
}
response.writeHead(200, {"Content-Type": "text/html"});
response.end(file, "utf-8");
});
}
}
why isn't it working? I get a 'mixed content' and/or 'corss-origin' error from firefox when I try to request from the server. How can I have the node server running in the same domain as the rest of the site to avoid these errors?
is really hard to read your code, I understand what you are trying to do, but let me suggest first a better structure easier to read, understand and implement more routes for your server, please check here:
var express = require('express'),
cors = require('cors'),
app = express();
app.use(cors());
app.get('/getUser/:user/:passwd', function(req, res, next) {
// Perform all mongo operations here using req.params.user and req.params.passwd
// and in the callback send a response like the object below
res.json({
msg: 'This is CORS-enabled for all origins!',
user: req.params.user,
passwd: req.params.passwd
});
});
app.listen(8888, function() {
console.log('CORS-enabled web server listening on port 8888');
});
Also the lack of CORS support (https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS) as you will need this in your use case for if you are planning to host serve static files consuming this service hosted in a different server, so lets use this module: https://www.npmjs.com/package/cors and it will allow express to process a request from anywhere.

Socket.io No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost' is therefore not allowed access

I'm trying to learn nodejs with socket.io and at the moment I'm using this tutorial by GianlucaGuarini. When entering my client.html file I get the following error. I know what it means and that it´s there for preventing Cross browser scripts but I don´t know how to allow my nodejs script to access the client.html file.
XMLHttpRequest cannot load http://localhost:8000/socket.io/?EIO=3&transport=polling&t=1422653081432-10. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost' is therefore not allowed access.
Here is a part of my code with socket.
var app = require('http').createServer(handler),
io = require('socket.io').listen(app),
fs = require('fs'),
mysql = require('mysql'),
connectionsArray = [],
connection = mysql.createConnection({
host: 'localhost',
user: 'root',
password: '',
database: 'database',
port: 3306
}),
POLLING_INTERVAL = 3000,
pollingTimer;
// If there is an error connecting to the database
connection.connect(function(err) {
// connected! (unless `err` is set)
console.log(err);
});
// creating the server ( localhost:8000 )
app.listen(8000);
// on server started we can load our client.html page
function handler(req, res) {
res.writeHead(200, {
/// ...
'Access-Control-Allow-Origin' : '*'
});
fs.readFile(__dirname + '/client.html', function(err, data) {
if (err) {
console.log(err);
res.writeHead(500);
return res.end('Error loading client.html');
}
res.writeHead(200);
res.end(data);
});
}
Does anyone know how I can solve my problem?
Kind regard / H
First of all - stop use writeHead everywhere. Because it rewrite completely response headers.
If tour write like this:
res.writeHead(200,{"coolHeader":"YesIAm"});
res.writeHead(500);
then node.js will sent response just with status 500 and without header "coolHeader";
If you wanna change Status Code, then use
res.statusCode = ###;
If you wanna add new header use
res.setHeader("key", "value");
And if you wanna rewrite all headers then use writeHeader(...)
Second. Add this code
res.statusCode = 200;
//...
res.setHeader("Access-Control-Allow-Origin", "*");
res.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
instead of your
res.writeHead(200, {
/// ...
'Access-Control-Allow-Origin' : '*'
});
and replace all writeHead(###) with res.statusCode = ###;
Try setting the `Access-Control-Allow-Origin' header on your response object in Node.
response.writeHead(200, {
/// ...
'Access-Control-Allow-Origin' : '*'
});
Looks like you are calling .listen for both the app and the socket.io (I believe that is redundant since you are extending your server with socket.io)
I have a little piece that works fine for me using socket.io 1.x
I like to use https since it kills some issues with firewalls and antiviruses, but this example is rewritten to http.
var http = require('http'),
socketio = require('socket.io'),
options={},
port=8080;
//start http
var app = http.createServer(options, handler),
io = socketio(app, {
log: false,
agent: false,
origins: '*:*'
// 'transports': ['websocket', 'htmlfile', 'xhr-polling', 'jsonp-polling']
});
app.listen(port);
console.log('listening on port ' + port);

Node.js error with SSL UNABLE_TO_VERIFY_LEAF_SIGNATURE

System: Windows 7
NodeJS version: 0.10.2
WS module: ws, last version
Error:
events.js:72
throw er; // Unhandled 'error' event
^
Error: UNABLE_TO_VERIFY_LEAF_SIGNATURE
at SecurePair. (tls.js:1283:32)
at SecurePair.EventEmitter.emit (events.js:92:17)
at SecurePair.maybeInitFinished (tls.js:896:10)
at CleartextStream.read [as _read] (tls.js:430:15)
at CleartextStream.Readable.read (_stream_readable.js:294:10)
at EncryptedStream.write [as _write] (tls.js:344:25)
at doWrite (_stream_writable.js:211:10)
at writeOrBuffer (_stream_writable.js:201:5)
at EncryptedStream.Writable.write (_stream_writable.js:172:11)
at write (_stream_readable.js:547:24)
Server:
(function(){
"use strict";
var fs = require('fs');
// you'll probably load configuration from config
var cfg = {
ssl: true,
port: 8080,
ssl_key: 'crt/server1.key',
ssl_cert: 'crt/server1.crt'
};
var httpServ = require('https')
var WebSocketServer = require('ws').Server;
var app = null;
// dummy request processing
var processRequest = function( req, res ) {
res.writeHead(200);
res.end("All glory to WebSockets!\n");
};
if ( cfg.ssl ) {
app = httpServ.createServer({
// providing server with SSL key/cert
key: fs.readFileSync( cfg.ssl_key ),
cert: fs.readFileSync( cfg.ssl_cert ),
//requestCert: true,
//rejectUnauthorized: false
}, processRequest ).listen( cfg.port );
} else {
app = httpServ.createServer( processRequest ).listen( cfg.port );
}
// passing or reference to web server so WS would knew port and SSL capabilities
var wss = new WebSocketServer( { server: app } );
wss.on( 'connection', function ( wsConnect ) {
wsConnect.on( 'message', function ( message ) {
console.log( message );
});
});
}());
Client:
var WebSocket = require('ws');
var ws = new WebSocket('wss://localhost:8080');
ws.on('open', function() {
ws.send('something');
});
The certificate confirmed.
Help> please!
I'm using a package called "superagent" and getting the same error. After trying several potential fixes, I came across this one that works for me 100% of the time:
process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";
There's no need to do any requires or whatever : just add this to your code before your network calls and you're good to go.
The SSL certificate used by the server in your example is probably not fully trusted by the WebSocket client so NodeJS is throwing an error in its network library on the client-side.
You need to set rejectUnauthorized to false (this is an option that most high-level network libraries will allow you to set via an option that gets passed to the lower level NodeJS networking library).
I skimmed the ws module source code and looks like you should try this:
var ws = new WebSocket('wss://localhost:8080', null, {rejectUnauthorized: false});
NOTE: rejectUnauthorized should only be false during testing/development. Production applications should always use rejectUnauthorized: true for full security.
If you do not want to disable your security. Add ca: [cert] option in http /socket client options.
Where cert is Certificate of server you are connecting to or CA of the server you are connecting to.
I've encountered a similar problem before, you may try to use
https.globalAgent.options.secureProtocol = 'SSLv3_method'
to set SSLv3 connection for https.
As per the nginx official website, they clearly mentioned certificate should be the combination of The server certificate and chained certificates.MoreInfo
Below solution is prefect and working fine for me in node js
process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";
Use a library to load the certificates (pem, crt, ...) from a given folder.
https://github.com/fujifish/syswide-cas
You can export the certificates from the browser and try:
const syswidecas = require('syswide-cas');
syswidecas.addCAs('./certs');

Error when trying to acess API with http.get in node.js

I'm a begginer in node.js and now I'm trying to get API's result from http.get. But, when running the code I'm receiving this error:
Error: getaddrinfo ENOTFOUND
Error: getaddrinfo ENOTFOUND
at errnoException (dns.js:37:11)
at Object.onanswer [as oncomplete] (dns.js:124:16)
I'm requiring http correctly (I had it tested to be sure)
Here is my function to illustrate the problem:
function getData(apiUrl, getUrl) {
var options = {
host : apiUrl,
port : 80,
path : getUrl
};
var content = "";
http.get(options, function(res) {
console.log("Got response: " + res.statusCode);
res.on("data", function(chunk) {
content += chunk;
console.log(content);
});
}).on('error', function(e) {
console.log("Error: " + e.message);
console.log( e.stack );
});
}
And calling it this way:
getData('https://api.twitter.com', '/1/statuses/user_timeline.json?&screen_name=twitter&callback=?&count=1');
Hope you can help me, thanks!
You must use the https instead of http module. See http://nodejs.org/api/https.html
In the options object, "host" should just be the hostname, i.e. api.twitter.com.
Specifying port is not necessary, but "80" is wrong in case of https. HTTPS is 443, unless explicitly specified otherwise.
You can generate correct options like this:
parseURL = require('url').parseURL;
parsedURL = parseURL(apiURL);
var options = {
hostname : parsedURL.hostname,
path : getUrl
};
For efficiency, the parseURL function could best be defined outside of the getData function.
If it's important that your getData function supports both http and https urls, you could check parsedURL.protocol. If "https", then use https.get, if "http", then use http.get.

Categories

Resources