Setting request headers in Node.js - node.js

I have been working with node.js to set up a proxy server that will handle incoming client request and will verify that they have the proper certificates to get connected to the server.
What I want to do is to be able to add the client's certificate to their header to craft a user name, that I will pass on to the server.
function (req, res) {
//Here is the client certificate in a variable
var clientCertificate = req.socket.getPeerCertificate();
// Proxy a web request
return this.handle_proxy('web', req, res);
};
What I want to be able to do is this : req.setHeader('foo','foo')
I know that the proxy.on('proxyReq) exist, but the way the code is set up, I need to be able to use the req parameter.
Is there a way to do this?
Please let me know if I need to clarify my question.

You can craft your own http request with the headers provided in the original request plus any extra headers that you'd like by using http.request. Just receive the original request, copy the headers into the new request headers, add the new headers and send the new request.
var data = [];
var options = {
hostname: 'www.google.com',
port: 80,
path: '/upload',
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Content-Length': postData.length
}
};
var req = http.request(options, function(res) {
res.setEncoding('utf8');
res.on('data', function (chunk) {
data.push(chunk);
});
res.on('end', function() {
console.log(data.join(""));
//send the response to your original request
});
});
req.on('error', function(e) {
console.log('problem with request: ' + e.message);
});
// Set headers here i.e. req.setHeader('Content-Type', originalReq.getHeader('Content-Type'));
// write data to request body
req.write(/*original request data goes here*/);
req.end();

Related

Send new request response with Node HTTP server

Stack Overflow community, greetings. I'm trying to pass the response of a new request on the request object using the Node HTTP Module for a basic autocomplete search app for my website (i.e using Node as a proxy that will transform and redirect the requests within the server).
The flow basically is:
Client Browser - Node - ElasticSearch - Node - Client Browser
I've started with:
Listen to requests with http.createServer (function (req,res)
Get the body from the req object and use it in a new request with http.request(options, function (newReqResponse)
Get the body from that newReqResponse object and send it back to the client on the res object
The problem is that the content of newReqResponse is always outdated (trails behind the last typed character). i.e.:
If I type "te", the content of newReqResponse corresponds to that if I had typed only "t".
If I type "test", it corresponds to that if I had typed "tes".
And so on.
I've tried to solve it using Node.js streams and using the file system module to write and read files sync and async, but the result is the same. Here's a sample of the whole -code- picture:
var http = require('http');
var fs = require('fs');
http.createServer(function (req, res) {
var reqBody = '';
var newReqResponseBody = "";
req.on('data', function (chunk) {
reqBody += chunk;
fs.writeFile('reqbody.json', reqBody, function(err) {
if (err) {
throw err;
}
});
var options = {
hostname: '127.0.0.1',
port: 9500,
method: 'GET',
path: '/_search',
headers: { host: 'es',
'content-length': Buffer.byteLength(reqBody),
'content-type': 'application/json',
accept: 'application/json' },
};
var newReq = http.request(options, function (newReqResponse) {
newReqResponse.setEncoding("UTF-8");
newReqResponse.on('data', function (ch) {
newReqResponseBody += ch;
});
newReqResponse.on("end", function() {
fs.writeFile("newReqResponseBody.json", newReqResponseBody, function(err) {
if (err) {
throw err;
}
});
});
});
newReq.on("error", function(err) {
console.log(`problem with request: ${err.message}`);
});
newReq.write(reqBody);
newReq.end();
});
req.on('end', function() {
var responseBody = fs.readFileSync('newReqResponseBody.json', 'utf8');
console.log(responseBody);
res.end(responseBody);
});
}).listen(3000, '127.0.0.1');
Is there a workaround to work with requests and responses within the http server? If there isn't, I'll be very grateful if you give me any directions on how to solve this.
Since the planned use for Node is rather basic, I prefer to stick with core modules rather than having to get new ones from npm, unless that it's necessary.
Thanks in advance.
EDIT:
All I had to do was to call res.end(responseBody) within the newReqResponse.on("end") callback, which is totally counterintuitive for me, but... it works.
Glad you solved your own problem. However, I see room for improvement (not sure if you're new), especially if you're transferring data. Which you can do with streams.
You can see that I didn't calculate the content length, you're asked not to and should get ignore (for this specific case) according to HTTP specification as streams pass data in chunks with 'Transfer-Encoding': 'chunked' header.
const fs = require('fs');
const http = require('http');
const options = {
hostname: '127.0.0.1',
port: 9500,
method: 'GET',
path: '/_search',
headers: {
'Content-Type': 'application/json'
}
};
http.createServer((req, res) => {
req.pipe(fs.createWriteStream('reqBody.json'));
let request = http.request(options, (newRes) => {
newRes.pipe(res);
});
fs.createReadStream('reqBody.json').pipe(request);
res.setHeader('Content-Type', 'application/json');
}).listen(3000, '127.0.0.1');
You can shorten this snippet more if you don't want your data saved in the future and only want to pipe the req stream to request.

IIS authentication for http request with Nodejs

I have one problem with HTTP GET/POST request.
When I use the DHC/Postman, send the parameters to the URL + endpoint, works perfectly. 200 is returned.
But with code, like my example, show one 401 error.
I have searched about that and the problem is with the auth, not sure, see... Maybe is the same.
With this explanation, need to set the Authorization, I think. But the problem is when I access the site, the auth is automatic, see:
My code:
var jsonObject = JSON.stringify({ "UserName": login});
// prepare the header
var postheaders = {
'Content-Type' : 'application/json',
'Content-Length' : Buffer.byteLength(jsonObject, 'utf8')
};
// the post options
var optionspost = {
host: "xxxxxxxxxx.com",
// path: '/Home/endpoint', //send the data for the endpoit with Postma works fine
method: 'POST',
headers : postheaders
};
console.info('Options prepared:');
console.info(optionspost);
console.info('Do the POST call');
// do the POST call
var reqPost = http.request(optionspost, function(res) {
console.log("statusCode: ", res.statusCode);
// uncomment it for header details
// console.log("headers: ", res.headers);
res.on('data', function(d) {
console.info('POST result:\n');
process.stdout.write(d);
console.info('\n\nPOST completed');
});
});
// write the json data
reqPost.write(jsonObject);
reqPost.end();
reqPost.on('error', function(e) {
console.error(e);
});
Obs.: This website it's from my Company (.NET) and is Integrated with IIS (Active Directory login users for authenticate), when I access, automatically is logged... I really don't know how to solve this.
Obs II.: I Try to use one anonymous new tab and use DHC online, and my post doesn't work. This application just works inside network company and with Client side (Using postman with my computer).
Obs III.: The request is from Server and the login from my server have all permissions to access this site, and when I request, is like I'm anonymous, but if I did the same with REST Client/Postman, works perfectly. I need that it works with http request from my Server.
You can use a module like ntlm-webapi which will allow you to use NTLM auth. That way the request will go through. Just make sure the user you use is authorized for that server.
var Request = require('ntlm-webapi');
var request = new Request({
url: "http://some.restful.api.org/you/want/to/call",
username: 'username',
password: 'password',
domain: 'company_domain'
});
request.get(function(err, result){
if (err) console.log (err);
console.log (result);
});
It seems that you forgot to add the Authorization header in your code
// prepare the header
var postheaders = {
'Authorization' : 'Negotiate '+ yourAccessKey,
'Content-Type' : 'application/json',
'Content-Length' : Buffer.byteLength(jsonObject, 'utf8')
};

How to access response Body after simulating a POST request in Node.js?

I have been trying this out for a long time now.
I want to scrap contents from a subreddit that has adult contents.
But, the problem is that, you have to answer a simple question before you are given access to that page i.e. if you are 18+ or not.
I did some research on the source code and found that the solution is a simple POST request. where you need to send the parameters "over18=yes".
But my problem is that, I am not able to access the response body after the post.
Here's the code using http request in node. I have even tried it out with the node "request" module, but no help from that either.
Hoping to find someone who can help me out here.
var http = require("http");
var options = {
host: 'www.reddit.com',
port: 80,
path: '/over18?dest=http%3A%2F%2Fwww.reddit.com%2Fr%2Fnsfw&over18=yes',
method: 'POST'
};
var req = http.request(options, function(res) {
console.log('STATUS: ' + res.statusCode);
console.log('HEADERS: ' + JSON.stringify(res.headers));
res.setEncoding('utf8');
res.on('data', function (chunk) {
console.log('BODY: ' + chunk);
});
});
req.on('error', function(e) {
console.log('problem with request: ' + e.message);
});
// write data to request body
req.write('data\n');
req.write('data\n');
req.end();
And here is the code using the Node Request module
var request = require("request");
request.post({url:'http://www.reddit.com/over18?dest=http%3A%2F%2Fwww.reddit.com%2Fr%2Fnsfw', form: {over18:'yes'}}, function(err,httpResponse,body){
console.log(body);
});
the URL i am trying to access is http://www.reddit.com/r/nsfw
In short, when you click YES button, the form sends over18=yes parameter to url http://www.reddit.com/over18?dest=http%3A%2F%2Fwww.reddit.com%2Fr%2Fnsfw using POST method. Then, server responds with an 302 Redirection header, cookie with value over18=1 and finally redirects to url http://www.reddit.com/r/nsfw using GET request. THen, server just checks if youa have a cookie with needed valuse.
All what you need is to do request directly to the final url with cookies using GET method.
var request = require("request");
var target = "http://www.reddit.com/r/nsfw";
var jar = request.jar();
var cookie = request.cookie("over18=1");
cookie.domain = "reddit.com";
cookie.path = "/";
jar.setCookie(cookie, target, function(error, cookie) {
console.log(error);
console.log(cookie);
});
request({
uri: target,
method: "GET",
jar: jar
}, function(error, response, body) {
console.log(response.statusCode);
console.log(body);
});
I too ran into this while ahem doing some research.. Here's my version:
var url = 'http://www.reddit.com/r/nsfw/';
var request = require('request');
request = request.defaults({jar: true });
request.post({
followAllRedirects: true,
url: 'http://www.reddit.com/over18?dest=' + encodeURIComponent(url),
form: {uh: '', over18: 'yes', }
}, function(err, httpResponse, html) {
…
});
Also worth a try are Reddit's Node.js APIs, of which I personally liked Snoocore.

Sending data through POST request from a node.js server to a node.js server

I'm trying to send data through a POST request from a node.js server to another node.js server. What I do in the "client" node.js is the following:
var options = {
host: 'my.url',
port: 80,
path: '/login',
method: 'POST'
};
var req = http.request(options, function(res){
console.log('status: ' + res.statusCode);
console.log('headers: ' + JSON.stringify(res.headers));
res.setEncoding('utf8');
res.on('data', function(chunk){
console.log("body: " + chunk);
});
});
req.on('error', function(e) {
console.log('problem with request: ' + e.message);
});
// write data to request body
req.write('data\n');
req.write('data\n');
req.end();
This chunk is taken more or less from the node.js website so it should be correct. The only thing I don't see is how to include username and password in the options variable to actually login. This is how I deal with the data in the server node.js (I use express):
app.post('/login', function(req, res){
var user = {};
user.username = req.body.username;
user.password = req.body.password;
...
});
How can I add those username and password fields to the options variable to have it logged in?
Thanks
Posting data is a matter of sending a query string (just like the way you would send it with an URL after the ?) as the request body.
This requires Content-Type and Content-Length headers, so the receiving server knows how to interpret the incoming data. (*)
var querystring = require('querystring');
var http = require('http');
var data = querystring.stringify({
username: yourUsernameValue,
password: yourPasswordValue
});
var options = {
host: 'my.url',
port: 80,
path: '/login',
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Content-Length': Buffer.byteLength(data)
}
};
var req = http.request(options, function(res) {
res.setEncoding('utf8');
res.on('data', function (chunk) {
console.log("body: " + chunk);
});
});
req.write(data);
req.end();
(*) Sending data requires the Content-Type header to be set correctly, i.e. application/x-www-form-urlencoded for the traditional format that a standard HTML form would use.
It's easy to send JSON (application/json) in exactly the same manner; just JSON.stringify() the data beforehand.
URL-encoded data supports one level of structure (i.e. key and value). JSON is useful when it comes to exchanging data that has a nested structure.
The bottom line is: The server must be able to interpret the content type in question. It could be text/plain or anything else; there is no need to convert data if the receiving server understands it as it is.
Add a charset parameter (e.g. application/json; charset=Windows-1252) if your data is in an unusual character set, i.e. not UTF-8. This can be necessary if you read it from a file, for example.
You can also use Requestify, a really cool and very simple HTTP client I wrote for nodeJS + it supports caching.
Just do the following for executing a POST request:
var requestify = require('requestify');
requestify.post('http://example.com', {
hello: 'world'
})
.then(function(response) {
// Get the response body (JSON parsed or jQuery object for XMLs)
response.getBody();
});

Using http.request in Node.JS while passing an API key

I am currently fiddling around with Node.JS to try to create a package for PostageApp to be able to send emails through our API.
To start, I am using the following code to test out how Node.JS can best interface with our API, but it doesn't seem to want to pass along the API key that I have attached as part of the headers.
var http = require('http');
function onRequest(request, response) {
response.end();
}
http.createServer(onRequest).listen(8888);
console.log("Server has started.");
var options = {
host: 'api.postageapp.com',
path: '/v.1.0/get_account_info.json',
method: 'POST',
headers: { "api_key" : "MY API KEY HERE" }
};
var req = http.request(options, function(res) {
console.log('STATUS: ' + res.statusCode);
res.setEncoding('utf8');
res.on('data', function (chunk) {
console.log('BODY: ' + chunk);
});
});
req.end();
console.log("Request sent!");
I pulled this together using various examples and what not - it's not pretty, I know. However, using HTTPS, I finally got it to hit our API and get a response:
{"response":{"status":"unauthorized","message":"Invalid or inactive API key used","uid":null}}
The only conclusion I can come up with is that the API key is not getting passed along, and I would appreciate any help as to how to make that happen.
Thanks!
Here's an example of code I have used to call web APIs with a key in the header:
var api = http.createClient(80, 'api.example.org');
var request = api.request('GET', '/api/foo',
{
'host': 'api.example.org',
'accept': 'application/json',
'api-key': 'apikeygoeshere'
});
request.on('response', function (response) {});
request.end();

Resources