Proxy request with Node.js: net::ERR_EMPTY_RESPONSE - javascript

Ultimately I am just trying to POST an image from the browser to a server. Unfortunately running into CORS issues, so for the moment, attempting to use our Node.js server as a proxy server.
I have this:
router.post('/image', function (req, res, next) {
const filename = uuid.v4();
const proxy = http.request({
method: 'PUT',
hostname: 'engci-maven.nabisco.com',
path: `/artifactory/cdt-repo/folder/${filename}`,
headers: {
'Authorization': 'Basic ' + Buffer.from('foo:bar').toString('base64'),
}
});
req.pipe(proxy).pipe(res).once('error', next);
});
the browser initiates the request, but I get an error in the browser saying I get an empty response, the error is:
Does anyone know why this error might occur? Is there something wrong with my proxy code in Node.js? Authorization should be fine, and the requeset url should be fine. Not sure what's going on.

Ok so this worked, but I am not really sure why:
router.post('/image', function (req, res, next) {
const filename = uuid.v4();
const proxy = http.request({
method: 'PUT',
hostname: 'engci-maven.nabisco.com',
path: `/artifactory/cdt-repo/folder/${filename}`,
headers: {
'Authorization': 'Basic ' + Buffer.from('foo:bar').toString('base64'),
}
}, function(resp){
resp.pipe(res).once('error', next);
});
req.pipe(proxy).once('error', next);
});
There is an explanation for why this works on this Node.js help thread:
https://github.com/nodejs/help/issues/760

Related

How do I send a filestream to localhost node-fetch?

On server side, I have this:
app.post('/testReadStream', function(req, res) {
var readStream = req.body;
readStream.pipe(process.stdout);
})
}).listen(443, () => console.log(`Listening on 443`));
I am making the following request from somewhere else:
let readStream = fs.createReadStream(path);
const fileSizeInBytes = fs.statSync(path).size;
fetch('https://localhost:443/testReadStream', {
method: 'POST',
headers: {
"Content-length": fileSizeInBytes
},
body: readStream
}).catch((err) => {
console.log(err);
})
I get the following error.
'request to https://localhost:443/testReadStream failed, reason: write EPROTO 4365467072:error:1408F10B:SSL routines:ssl3_get_record:wrong version number:../deps/openssl/openssl/ssl/record/ssl3_record.c:332:\n',
From this link https://github.com/openssl/openssl/issues/10938 it seems I did something wrong with filestreams. I copied it from here How to send a file in request node-fetch or Node?
What did i do wrong?
Looks like an SSL problem.
Can you try a simple string body
body: "text"
The SSL problem came from me putting "https" + localhost instead of "http://localhost". .-.
After that, all I had to change was req.body to req.

Node.js send post with array parameter

Hello and happy new year!
I'm trying to send a post petition in Node.js. The version I need to replicate in javascript looks like this:
$.post('website.com/api/buy.php', {
action: order,
'items[]': cart_i,
time: localtime,
utb: x //I don't know why that parameter is sent. It's always 0 ._.
} ... //rest of the code of that website
I'm trying to do this in Node.js to replicate that:
var postData = querystring.stringify({
action: 'order',
"items[]": item.i,
time: local_time,
utb: 0
});
var https = require('https');
var options = { method: 'POST', host: 'website.com', port: 443, path: '/api/buy.php', headers: { 'Cache-Control': 'no-cache', 'Cookie': cookies, 'Accept': '/', 'Connection': 'keep-alive' } };
var req = https.request(options, function (res) {
res.setEncoding('utf8');
res.on('data', function (chunk) {
content = content+ chunk;
});
res.on('end', function () {
console.log(content)
});
}
);
req.write(postData);
req.end();
But I always get an error telling me that I didnt send anything. I think the problem could be in items[] because I see it sends "items%5B%5D", but I dont know if I'm doing something wrong. I think is is not about cookies, because if I'm not logged I get other error.
I'm doing the request well? Or I'm missing something that is not about the request? Is there other way to send "post" data easier?
Any help would be appreciated :)

client (fetch) and server (nodejs http) don't understand each other?

I try to wrap my mind around nodejs at the moment.
So I've created a client:
let myHeaders = {
'Content-Type': 'application/json',
'Accept': 'application/json'
};
let myBody = {
aString: "Test"
};
fetch("http://localhost:8099/", {
method: 'post',
mode: 'no-cors',
headers: myHeaders,
body: JSON.stringify(myBody)
})
.then(result => {
return result.text();
})
.then(text => {
// do stuff with text from server
});
And I have created a server:
// request needed modules
const http = require('http');
// init server
let server = http.createServer(logic);
server.listen(8099);
// server logic
function logic (req, res) {
var body = req.body;
res.end("Hello");
}
Two problems:
1) The sever does not get the body (req.body is undefined).
UPDATE
See my answer below.
--
2) The client does not receive "Hello" (result.text() returns "").
UPDATE
2 is solved by:
Changing this on the client
fetch("http://localhost:8099/", {
method: 'post',
mode: 'no-cors', <-- CHANGE to: mode: 'cors'
...
Adding this on server
res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader('Access-Control-Allow-Headers', 'Content-Type');
--
I don't get what I do wrong here...
Your Node.js code has nothing which would generate the HTML document containing the JS that calls fetch.
This means you must be making a cross-origin request (this is supported by the absolute URL you pass to fetch).
You also set mode: 'no-cors' which means "Don't throw a security exception for trying to access a cross-origin resource, and don't make the response available to JS".
Consequently, when you try to read the response: You can't.
Set the mode to "cors" and change the Node.js code to follow the CORS specification to grant permission to the page trying to read the data.
I try to wrap my mind around nodejs at the moment.
There is nothing particular to Node.js here. The problems are related to security restrictions on what JavaScript running in the browser can do unless granted permission by the HTTP server.
To not completely mess up my question, I post my solution for problem number one as separate answer:
SOLUTION 1) The sever does not get the body (req.body is undefined)
As request is a stream, I need to treat it like one (notice "req.on('data'...)
This is how the server works as expected:
// request needed modules
const http = require('http');
// init server
let server = http.createServer(handler);
server.listen(8099);
// server logic
function handler (req, res) {
// Set CORS headers
let headers = {
'Access-Control-Allow-Origin' : '*',
'Access-Control-Allow-Methods' : 'POST, OPTIONS',
'Access-Control-Allow-Headers' : 'Content-Type, Accept'
};
res.writeHead(200, headers);
if(req.method == 'POST'){
var body = '';
req.on('data', data => {
body += JSON.parse(data).aString;
});
req.on('end', () => {
res.end(body.toString().toUpperCase());
});
} else if (req.method == 'OPTIONS'){
res.end();
}
}

Node.js equivalent of this curl request

I'm trying to use the HTML validator API. The curl examples work fine for me and I can run them find in Node as a child process. Here is the code for that:
var command = ('curl -H "Content-Type:text/html; charset=utf-8" --data-binary #' + file +
' https://validator.w3.org/nu/?out=json');
exec(command, function(err1, out, err2) {
console.log(out);
console.log('done');
});
However, when I tried to use a standard HTTP request, I couldn't get it working. I tried it with the Unirest library for Node. Here is the code I used:
var source = '<html><head><title>a</title></head><body>a</body></html>';
var url = 'http://validator.w3.org/nu/?out=json';
var Request = unirest.post(url);
Request.headers({'Content-Type': 'text/html', 'charset': 'utf-8'});
Request.send(source);
Request.end(res => console.log(res));
The response body is undefined and the response raw_body is empty. I don't know what I'm doing wrong and would appreciate any help.
Seems validator.w3.org won't respond to requests without a user-agent header. Add this header:
Request.headers({'Content-Type': 'text/html; charset=utf-8', 'user-agent': 'Node.js'});
Or use whatever useragent you want.
With super agent:
const request = require('superagent');
const body = '<html><head><title>a</title></head><body>a</body></html>';
request.post('https://validator.w3.org/nu/?out=json')
.set('Content-Type', 'text/html; charset=utf-8')
.send(body)
.end((err, res) => {
console.log('got body: ' + JSON.stringify(res.body));
});

Node.js: Cannot do PROFIND with request module

I'm trying to access content of my WebDAV server in node (server OK, I can net use it). I'm using the request module:
path = url.join(this._options.rootUrl, path || "");
var data =
"<?xml version=\"1.0\" encoding=\"utf-8\" ?>" +
"<propfind xmlns=\"DAV:\">" +
"<propname/>" +
"</propfind>";
var headers = {
"Content-Type": "text/xml",
"Depth": depth || 1
};
var req = request({
url: path,
data: data,
headers: headers,
method: "PROPFIND",
json: false,
encoding: "utf8",
auth: {
user: this._options.user,
password: this._options.password
}
});
req.on("response", ...);
req.on("error", ...);
The problem is I'm getting HTTP 405 instead of the result. I've tried bundled https module, same result.
Is it possible that Node.js cannot invoke costom verbs like PROPFIND?
UPDATE 1:
This is stated that node can do PROFIND. So my question is, how do you people do correct WebDAV PROPFIND client request in node/io.js by using request module? (Or anything that works for this purpose.)
PROPFIND or any other verb is supported just fine for outbound requests in node and iojs. There is either something else wrong with your request (wrong/bad headers or payload for example) or configuration on the server.
Example of PROPFIND working:
// client.js
require('http').request({
host: '127.0.0.1',
port: 8000,
method: 'PROPFIND'
}, function(res) {
res.resume();
}).end();
// server.js
require('http').createServer(function(req,res) {
// echoes "PROPFIND" to stdout
console.log(req.method);
res.writeHead(200, { 'Connection': 'close' });
res.end();
}).listen(8000);

Categories