grantila / fetch-h2

HTTP/1+2 Fetch API client for Node.js
MIT License
336 stars 16 forks source link

SNI support #34

Closed timdp closed 5 years ago

timdp commented 5 years ago

So I'm trying to achieve a bit of an edge case.

I need to make a request to a server and override the Host header (for HTTP) and the SNI server name (for HTTPS). (My use case is that I want to spoof the hostname for testing an HTTP server.)

I briefly experimented with passing headers.host as an option, but fetch-h2 doesn't allow that header, which makes sense because its value is already in the URL.

In pure Node (which is used underneath), you would pass headers.host for HTTP and servername for HTTPS/TLS.

I can see how this is not a feature of the browser's fetch, so fundamentally, there's a discrepancy between my requirement and the API. However, I wanted to check what the philosophy is here. Should I use a different library (happy to do this if it makes more sense!) or is there a way to get fetch-h2 to pass the relevant options to the http and https Node modules?

Thanks!

grantila commented 5 years ago

Yeah this is (currently) not the library, since it tries to adhere to Fetch which is a "safe library" which intentionally limits what you can do, to reduce mistakes and security issues.

Naturally, Fetch isn't always what you want in the Node.js, when you need full control, but in most cases, it's very handy.

I'm planning on adding "hooks" which would allow for some customization and overriding of built-in logic (e.g. to mock requests with fake responses). One such hook could be a custom provided socket, so that you can manually perform the net connect and SNI spoofing, and then handover to fetch-h2 for the actual http logic.

But right now, there's nothing like this..

timdp commented 5 years ago

Fair enough. I'll keep using got in my tests. :slightly_smiling_face:

colinbendell commented 4 years ago

@timdp you can accomplish this by overriding the lookup function. This is particularly useful if you want to force DoH instead of standard DNS. It also allows you to point to a staging/alternative server. The one caveat is that the expectation is that the servername is still based on the 'host' header (aka :authority) and that this value matches the serveraltname in the certificate. Here is a partial code fragment:

let lookup = async function(hostname, options, callback) {
    let ip = await doh.resolveOne('A', hostname); //internal doh lookup
    callback(null, ip, 4);
};
let ctx = context({session:{lookup}})