When using node new http2 server, I encountered this error when attempting to call it from the browser: ERR_INVALID_HTTP_RESPONSE.
The code:
const http2 = require('http2');
// Create a plain-text HTTP/2 server
const server = http2.createServer();
server.on('stream', (stream, headers) => {
console.log('headers: ', headers);
stream.respond({
'content-type': 'text/html',
':status': 200
});
stream.end('<h1>Hello World</h1>');
});
server.listen(80);
Turns out, chrome won't allow you to access insecure http2 servers, I had to change the code to:
const server = http2.createSecureServer({
key,
cert
});
and then it worked.
Related
I am building an HTTP2 client-server communication using nodeJS. My server is built but when i try to connect to the server from chrome, i get -
127.0.0.1 sent an invalid response.
ERR_INVALID_HTTP_RESPONSE
Below is my server code. Do i need to install a self signing certificate since its an HTTP2 connection?
const http2 = require('node:http2');
const server = http2.createServer();
server.on('connection',(stream)=>{
console.log("Someone connected",stream.remoteAddress);
})
server.on('error',(error) => {
console.log("There is an error",error);
})
server.on('stream', (stream,headers,flags)=>{
stream.respond({
'content-type': 'text/html; charset=utf-8',
':status': 200
});
stream.end('<html><body><h1>Hello World</h1></body></html>');
})
server.listen(8443,'127.0.0.1',() =>{
console.log("server listening on port 8443");
});
I am using this code to connect to a 3rd party server via HTTP GET. Locally on my MacOS this script works perfectly and I get statusCode:200 together with a valid message from the server. Am I missing something which should be added to this request when connecting from AWS?
const https = require("https");
var fs = require("fs");
var httpsAgent = require("https-agent");
var agent = httpsAgent({
pfx: fs.readFileSync("certs/test.com.pfx"),
passphrase: "xxxxxx",
rejectUnauthorized: true,
//enableTrace: true,
ca: fs.readFileSync("certs/ca-bundle.pem"),
});
const path = "/testapp?application=TEST&method=send&message=TEST"
const options = {
hostname: "test.server.com",
port: 443,
path: path,
method: "GET",
agent: agent,
};
''
console.log("Connecting to: https://test.server.com" + path)
const req = https.request(options, (res) => {
console.log(`statusCode: ${res.statusCode}`);
res.on("data", (d) => {
process.stdout.write(d);
});
});
req.on("error", (error) => {
console.error(error);
});
req.end();
Issue Solved: Issue was actually not related to SSL. Packet was being reject to invalid MTU size. Adjusted MTU value and worked as expected.
I'm trying to setup an HTTPS server that proxies requests to changing targets that also enforce HTTPS. this is because I want to setup an intercepting https proxy, terminate ssl, modify data and send encrypted modifications to target server (or backwards through the response).
Example:
Browser --> myHTTPSProxy(modify request) --> https://targethost.com --> myHTTPSProxy(modify response) --> Browser
This is sample implementation for the task from the node-http-proxy library:
const https = require('https'),
fs = require('fs'),
colors = require('colors'),
httpProxy = require('http-proxy'),
httpsOpts = {
key: fs.readFileSync('agent2-key.pem', 'utf8'),
cert: fs.readFileSync('agent2-cert.pem', 'utf8')
};
// Create DUMMY HTTPS SRV
https.createServer(httpsOpts, function (req, res) {
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.write('hello https\n');
res.end();
}).listen(3000);
// PROXY
httpProxy.createServer({
ssl: httpsOpts,
target: 'https://localhost:3000',
secure: false
}).listen(8080);
console.log('https proxy server'.blue + ' started '.green.bold + 'on port '.blue + '8080'.yellow);
console.log('https server '.blue + 'started '.green.bold + 'on port '.blue + '3000 '.yellow);
Certificates are also taken from the library, and I tried using valid ones as well that works on a straight https server but no as a proxy.
as a proxy - I get Secure Connection Failed.
TL;DR Question
Does anyone know how to implement a HTTPS proxy server using nodejs?
Similar unresolved posts:
Https proxy server(secure proxy server) in Nodejs with http-proxy is not working
https://github.com/http-party/node-http-proxy/issues/1456
https://github.com/http-party/node-http-proxy/issues/1506
I created a local HTTP Proxy server for the test, which works fine for my Firefox and Chrome browsers, however, when I tried the following code, the server simply replied a 400 error.
const http = require("http");
const req = http.request({
host: "localhost",
port: 8001,
method: "CONNECT",
path: "sfnjs.com:443"
})
req.end();
req.on("error", err => {
console.log(err);
}).on('connect', (res, socket, head) => {
// Make a request over an HTTP tunnel
socket.write('GET / HTTP/1.1\r\n' +
'Host: sfnjs.com:443\r\n' +
'Connection: close\r\n' +
'\r\n');
socket.on('data', (chunk) => {
console.log(chunk.toString());
});
});
And the server responded
HTTP/1.1 400 Bad Request
Server: nginx/1.16.1
Date: Mon, 22 Jun 2020 03:00:49 GMT
Content-Type: text/html
Content-Length: 255
Connection: close
<html>
<head><title>400 The plain HTTP request was sent to HTTPS port</title></head>
<body>
<center><h1>400 Bad Request</h1></center>
<center>The plain HTTP request was sent to HTTPS port</center>
<hr><center>nginx/1.16.1</center>
</body>
</html>
And I wasn't able to use the https module to connect the proxy server since the proxy server only accepts HTTP messages. If I trying so, for example:
const https = require("https");
const req = https.request({
host: "localhost",
port: 8001,
method: "CONNECT",
path: "sfnjs.com:443"
})
The proxy server would simply close the connection and throws an error like this:
Error: Client network socket disconnected before secure TLS connection was established
at connResetException (internal/errors.js:570:14)
at TLSSocket.onConnectEnd (_tls_wrap.js:1361:19)
at Object.onceWrapper (events.js:312:28)
at TLSSocket.emit (events.js:228:7)
at endReadableNT (_stream_readable.js:1185:12)
at processTicksAndRejections (internal/process/task_queues.js:81:21) {
code: 'ECONNRESET',
path: null,
host: 'localhost',
port: 8001,
localAddress: undefined
}
However, if I configure this proxy in Firefox or Chrome and visit the target website, it will work very well, so how does the browser do this and how can I implement it in a Node.js application?
And I wasn't able to use the https module to connect the proxy server since the proxy server only accepts HTTP messages
It sounds like you are using the https module at the wrong place. You should be using the http module to connect to the proxy then the https module where you now are using your own custom code: socket.write('GET / HTTP/1.1\r\n' ...
req.on("error", err => {
console.log(err);
}).on('connect', (res, socket, head) => {
// Make a request over an HTTP tunnel
const req2 = https.request({ // HTTPS
host: 'sfnjs.com:443',
method: 'GET',
createConnection: () => { return socket }, // tunnel
path: '/'
}, res2 => {
res2.on('data', (chunk) => {
console.log(chunk.toString());
});
});
req2.end()
});
Note that the code above is untested but should illustrate the general idea.
I need to send my client HTTPS requests through an intranet proxy to a server.
I use both https and request+global-tunnel and neither solutions seem to work.
The similar code with 'http' works. Is there other settings I missed?
The code failed with an error:
REQUEST:
problem with request: tunneling socket could not be established, cause=socket hang up
HTTPS:
events.js:72
throw er; // Unhandled 'error' event
^
Error: socket hang up
at SecurePair.error (tls.js:1011:23)
at EncryptedStream.CryptoStream._done (tls.js:703:22)
at CleartextStream.read [as _read] (tls.js:499:24)
The code is the simple https test.
var http = require("https");
var options = {
host: "proxy.myplace.com",
port: 912,
path: "https://www.google.com",
headers: {
Host: "www.google.com"
}
};
http.get(options, function(res) {
console.log(res);
res.pipe(process.stdout);
});
You probably want to establish a TLS encrypted connection between your node app and target destination through a proxy.
In order to do this you need to send a CONNECT request with the target destination host name and port. The proxy will create a TCP connection to the target host and then simply forwards packs between you and the target destination.
I highly recommend using the request client. This package simplifies the process and handling of making HTTP/S requests.
Example code using request client:
var request = require('request');
request({
url: 'https://www.google.com',
proxy: 'http://97.77.104.22:3128'
}, function (error, response, body) {
if (error) {
console.log(error);
} else {
console.log(response);
}
});
Example code using no external dependencies:
var http = require('http'),
tls = require('tls');
var req = http.request({
host: '97.77.104.22',
port: 3128,
method: 'CONNECT',
path: 'twitter.com:443'
});
req.on('connect', function (res, socket, head) {
var tlsConnection = tls.connect({
host: 'twitter.com',
socket: socket
}, function () {
tlsConnection.write('GET / HTTP/1.1\r\nHost: twitter.com\r\n\r\n');
});
tlsConnection.on('data', function (data) {
console.log(data.toString());
});
});
req.end();