Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to forward to a absolute PATH? because thenForwardTo() only accepts host url without PATH. #153

Open
rivudutta opened this issue Jul 19, 2023 · 5 comments

Comments

@rivudutta
Copy link

I want to forward requests to a particular path but I am not able to do it using thenForwardTo(). It is throwing error and it only accepts hostname (without path).

For example, I want to match one absolute URL & forward it to another absolute URL.

// Redirect any github/login requests to github.com/signup
server.anyRequest().forHost("https://github.com/login").thenForwardTo("https://github.com/signup");

@rivudutta
Copy link
Author

rivudutta commented Jul 19, 2023

Hi @pimterry , please let me know if it is possible?

@rivudutta rivudutta changed the title Is there any way to forward to an absolute path using thenForwardTo()? as it only accepts hostname without path How to forward to a absolute PATH? because thenForwardTo() only accepts host url without PATH. Jul 19, 2023
@pimterry
Copy link
Member

Hi @rivudutta. If you want to do this, you'll need to do so with a beforeRequest callback. Unfortunately it's not possible with thenForwardTo right now. You just need to provide a callback that returns { url: yourTargetUrl } and the request will be redirected. That way you can include any custom logic you like in that callback for all sorts of other advanced mappings 😄

@rivudutta
Copy link
Author

rivudutta commented Jul 20, 2023

@pimterry thanks for the solution, I have tried this but it also changes the URL with the targetURL in the chrome address bar.

For example,
If I redirect to "github.com/signup", browsers address bar URL is also getting changed, however while using .thenForwardTo() it doesn't change the URL in the browser addressbar. Any idea how to achieve the same behaviour with beforeRequest, where I can show "github.com/login" URL in the address bar but render "github.com/signup" as the body.

beforeRequest: (req) => {
 return {
        url: "https://github.com/signup/"
  };
}

@pimterry
Copy link
Member

If the addressbar is being changed, that means the way you're rewriting the request is making github return a redirect response (e.g. a 301/302/307 status) for some reason. You'll probably be able to see that in the network inspector in the browser.

It's hard to know exactly why that might happen I'm afraid, I'd recommend testing out different requests and rewritings manually and see if you can tell what's causing that. As far as I'm aware though, returning a URL there should do almost exactly the same as using thenForwardTo.

The code for each is here:

  • Forwarding:
    if (this.forwarding) {
    const { targetHost, updateHostHeader } = this.forwarding;
    if (!targetHost.includes('/')) {
    // We're forwarding to a bare hostname
    [hostname, port] = targetHost.split(':');
    } else {
    // We're forwarding to a fully specified URL; override the host etc, but never the path.
    ({ protocol, hostname, port } = url.parse(targetHost));
    }
    const hostHeaderName = isH2Downstream ? ':authority' : 'host';
    let hostHeaderIndex = findRawHeaderIndex(rawHeaders, hostHeaderName);
    let hostHeader: [string, string];
    if (hostHeaderIndex === -1) {
    // Should never happen really, but just in case:
    hostHeader = [hostHeaderName, hostname!];
    hostHeaderIndex = rawHeaders.length;
    } else {
    // Clone this - we don't want to modify the original headers, as they're used for events
    hostHeader = _.clone(rawHeaders[hostHeaderIndex]);
    }
    rawHeaders[hostHeaderIndex] = hostHeader;
    if (updateHostHeader === undefined || updateHostHeader === true) {
    // If updateHostHeader is true, or just not specified, match the new target
    hostHeader[1] = hostname + (port ? `:${port}` : '');
    } else if (updateHostHeader) {
    // If it's an explicit custom value, use that directly.
    hostHeader[1] = updateHostHeader;
    } // Otherwise: falsey means don't touch it.
    reqUrl = new URL(`${protocol}//${hostname}${(port ? `:${port}` : '')}${path}`).toString();
    }
  • beforeRequest URL rewriting:
    reqUrl = modifiedReq?.url || reqUrl;
    +
    Object.assign(headers,
    isH2Downstream
    ? getH2HeadersAfterModification(expectedTargetUrl, clientHeaders, modifiedReq?.headers)
    : { 'host': getHostAfterModification(expectedTargetUrl, clientHeaders, modifiedReq?.headers) }
    );
    +
    // Reparse the new URL, if necessary
    if (modifiedReq?.url) {
    if (!isAbsoluteUrl(modifiedReq?.url)) throw new Error("Overridden request URLs must be absolute");
    ({ protocol, hostname, port, path } = url.parse(reqUrl));
    }

To debug this further, you might want to try logging the received & forwarded requests using mockttpServer.on(event, callback) to examine the raw traffic. The request event will tell you exactly what Mockttp receives, and the rule-event event will call the callback with a series of processing events, including a passthrough-request-head event with the final modified version of that request. There's more info in the docs here: https://httptoolkit.github.io/mockttp/interfaces/Mockttp.html#on. You could use that to compare exactly what gets sent in the forwarding & beforeRequest cases.

@rivudutta
Copy link
Author

Thank you for the debugging steps, I will try them.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants