Modify server response using node http proxy - node-http-proxy

I am a beginner to node js and this is my first post in here so apologies if this is a stupid question.
The problem I need to solve is to change information in an HTTPS server response before it hits the client. The reason is that my my client (Im developing a GARMIN sports watch application) cannot read the server response as the body data format differs from the content_type as defined in the response header. I have no means of impacting the server code and on the client I am stuck as well, Garmin has acknowledged it should be fixed but have not put it on priority.
I guess that leaves me with having to implement my own http proxy that I can connect in between the client and server to change either the header or the data format in the server response.
I have browsed around a bit and also played around a bit with node-http-proxy but I am not sure what is the best solution approach. Basically, the SERVER expects HTTPS comms, and preferably I also want secured comms between the PROXY and the CLIENT (since they will exchange user credentials).
I guess my first question is if this is a possible use case:
CLIENT -> (HTTPS_POST_req) -> PROXY -> (HTTPS_POST_req) -> SERVER
SERVER -> (HTTPS_resp) -> PROXY -> (modified_HTTPS_resp) -> CLIENT
I took a quick shot at it using node-http-proxy sample code but got stuck. What I did was to create an http server on localhost and a proxy server that would proxy the request to SERVER.
const http = require('http');
const httpProxy = require('http-proxy');
const proxy = httpProxy.createProxyServer({});
http.createServer(function(req, res) {
console.log('incoming request');
console.log('URL:' + req.url);
console.log('Method:' + req.method);
console.log('Headers:' + JSON.stringify(req.headers));
proxy.web(req, res, { target:'SERVER ADDRESS HERE' });
}).listen(8888, () => {
console.log("Waiting for requests...");
});
From the console I can see the incoming request and also read the url, headers and method but then after a short while I get this:
Error: connect ECONNREFUSED 127.0.0.1:80
at TCPConnectWrap.afterConnect [as oncomplete] (net.js:1141:16) {
errno: 'ECONNREFUSED',
code: 'ECONNREFUSED',
syscall: 'connect',
address: '127.0.0.1',
port: 80
}
I have no idea why something want to connect to localhost on port 80.
Perhaps this approach will never work for HTTPS/SSL traffic? For instance, do I have to setup my own server certificate to do this or can node-http-proxy handle it "under the hood"? Need a bit of help, please.
//Fredrik

Related

Connecting to AWS IoT Websocket without MQTT client

I have a client application which runs in the browser which I can't change the implementation of to implement an MQTT client such as mqtt on npm.
The code in the library is as follows and allows me to pass in a socketUrl
const ws = new WebSocket(socketUrl)
I have tried generating a presigned URL for IoT, which seems to work in terms of authenticating (i.e. no Unauthorized response) but I get a 426 Upgrade Required response.
I believe I'm correct in saying that if it were working it'd reply with a 101 Switching protocols but without knowing much about MQTT i'm unsure if this is not happening because I'm doing something wrong or because I'm not using MQTT.
I'm generating a signed URL using the below code (I'll switch to Cognito Identities if I get this working rather than using the fixed key/secret)
const v4 = require('aws-signature-v4')
const crypto = require('crypto')
const socketUrl = v4.createPresignedURL(
'GET',
'myioturl.iot.us-east-1.amazonaws.com',
'/mqtt', // tried just /mytopic, too
'iotdevicegateway',
crypto.createHash('sha256').update('', 'utf8').digest('hex'), {
'key': 'removed',
'secret': 'removed',
'protocol': 'wss',
'region': 'us-east-1'
}
)
The protocols page in the iot documentation seems to suggest that if I point at /mqtt I'm indicating I'll be using MQTT.
mqtt Specifies you will be sending MQTT messages over the WebSocket protocol.
What does this mean if I just specify /foobar? Should I be able to connect to the socket but not using MQTT?
There are quite a few unknowns for me so I'm struggling to work out if it should work at all, and if so, which bit am I doing wrong.

How to allow https to access content from wowza http link?

I have one question. Recently i have get link from my streaming server to play in my website. My streaming server use http link but my website use https ssl. During i get the link to play it cannot get content from my streaming server by show the following error:
enter image description here
I am looking forward to hearing from all of you soon.
Thanks in advance.
Best Regards,
Chhenghong
This error happens because you cannot access HTTP resource from HTTPS page, for security consideration. It is the browser behaviour.
To fix this issue, a proxy endpoint can be made in server side, such as /proxy/playlist.m3u8, which accept HTTP GET request. The browser will fetch the resource from https://<your-server>/proxy/playlist.m3u8, as if it is stored in your host. As it is an HTTPS request, no error.
In the server side, when GET request to /proxy/playlist.m3u8 is listened, the HTTP request would be proxied to your streaming server (send GET request to the streaming server with all headers, parameters and body). When the response from streaming server is received, the response would be returned to browser directly, with all response headers and data.
As the HTTP request to streaming server happens in your server side, the restriction logic from browser does not apply any more.
For example, if the server is written in Node.js, with Express and request module, the proxy endpoint would look like:
app.get('/proxy/playlist.m3u8', function(req, res) {
req.pipe(request('http://<streaming-server>/path/playlist.m3u8')).pipe(res);
});

Capture HTTPS request to nonexistent server with FiddlerCore

I am trying to send a response to an HTTPS request, using FiddlerCore.
I need things to work like this: I put some fake URL in browser, like https://my_url_that_doesnt_exist.com/, then I intercept this request with FiddlerCore and respond to it with my data. But I only see a CONNECT and the host URL. I know this is because of HTTPS and Fiddler being a proxy. But is there a way to get the real full URL and be able to respond to HTTPS request, using FiddlerCore?
Also I use this code to create a root certificate if it's missing:
if (!Fiddler.CertMaker.rootCertExists())
{
if (!Fiddler.CertMaker.createRootCert())
{
throw new Exception("Could not create a certificate.");
}
}
also, I use these startup settings:
FiddlerCoreStartupFlags fcsf = FiddlerCoreStartupFlags.Default | FiddlerCoreStartupFlags.DecryptSSL|FiddlerCoreStartupFlags.AllowRemoteClients;
and CONFIG.IgnoreServerCertErrors = true;
This HTTPS request is not visible in Fiddler itself. I mean when I try some non-existent URL to which I'd like my app to respond with some custom content. It's also HTTP, not HTTPS, and Fiddler itself contains the following in response:
[Fiddler] DNS Lookup for "my_url_that_doesnt_exist.com" failed. The requested name is valid, but no data of the requested type was found
But if I use some existing HTTPS URL, like google plus or anything like that, I can see the HTTPS and all the request details.
So the question follows: How can I intercept HTTPS request to a non-existent URL and serve my content instead?
I can provide any additional details if needed.
Also makecert.exe is in the same folder where all my binaries are.
The problem is that HTTPS traffic flows through a CONNECT tunnel, and by default that secure traffic won't be sent if creating the CONNECT tunnel to the target server doesn't first succeed. Of course, if that target server doesn't exist, you end up with a DNS error in creating the tunnel, so the secure requests are never sent.
The workaround is to tell Fiddler to tell the client that the CONNECT tunnel was created, without even trying to contact the server. Do so by adding this inside the BeforeRequest handler:
if (oSession.HTTPMethodIs("CONNECT"))
{
oSession.oFlags["x-replywithtunnel"] = "GenerateTunnel";
return;
}

dart, turning a http request into a websocket?

I'm picking my way through the dartiverse_search example from the welcome page in dart editor. I see that it uses a path route to decide whether to transform a request into a websocket:
// The client will connect using a WebSocket. Upgrade requests to '/ws' and
// forward them to 'handleWebSocket'.
router.serve('/ws')
.transform(new WebSocketTransformer())
.listen(handleWebSocket);
Is it possible to turn a request into a websocket without using a routing path, for example using a query string to the root url?
You can specify any condition for upgrading to a WebSocket connection. You can even upgrade any connection request to a WebSocket connection without specifying a condition like this:
WebSocketTransformer.upgrade(request).then((WebSocket websocket) {
websocket.listen((String text) {
// process sent data
});
websocket.add(JSON.encode("Hello"));
});
If the request is not a valid web socket upgrade request a HTTP response with status code 500 will be returned. Otherwise the returned future will complete with the [WebSocket] when the upgrade process is complete.

How do I receive an http request with a Node.js server and then pass that request along to another server?

There's a lot going on here so I'll simplify this into a pseudo example. Forget about security and whatnot for a minute here. The point is to understand the functionality.
Let's say I'm running a local web server with node.js to dev a website. In the website, the user should be able to create a new account. The account information will be submitted via ajax to the node server. I then need the node server to take the incoming request and pass it along to another server that gives me access to a database. CouchDB, for example.
So here's a pseudo example of what I'd like to happen.
In the client's browser:
$.ajax({
url: './database_stuff/whatever', // points to the node web server
method: 'POST',
data: {name: 'Billy', age: 24}
});
In the Node web server:
var http = require('http'),
dbServer = 'http://127.0.0.1:5984/database_url';
http.createServer(function (req, res) {
/* figure out that we need to access the database then... */
// magically pass the request on to the db server
http.magicPassAlongMethod(req, dbServer, function (dbResponse) {
// pass the db server's response back to the client
dbResponse.on('data', function (chunk) {
res.end(chunk);
});
})
}).listen(8888);
Make sense? Basically what's the best way to pass the original request along to another server and then pass the response back to the client?
If the server at dbServer url supports streaming you could do something like
var request = require('request');
req.pipe(request.post(dbServer)).pipe(res)
where request is a module, for more info look here https://github.com/mikeal/request
This is quite readable and easy to implement, if for whatever reason you cannot do this then you could take what you need from the request and manually POST it, then take the response and res.send it to the client.
Sorry if there's an error in my code, I haven't tested it but my point should be clear, if it's not then ask away.

Resources