-
Notifications
You must be signed in to change notification settings - Fork 3.4k
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
fix(plugins): follow redirects when checking the webServer url #22035
Conversation
bd7669e
to
c15c3a1
Compare
Signed-off-by: Johannes Loher <johannes.loher@tngtech.com>
c15c3a1
to
f0ca1f7
Compare
'playwright.config.ts': ` | ||
module.exports = { | ||
webServer: { | ||
command: 'node ${JSON.stringify(SIMPLE_SERVER_PATH)} ${server.PORT}', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
command: 'node ${JSON.stringify(SIMPLE_SERVER_PATH)} ${server.PORT}', | |
command: 'exit 1', |
I think we can do this to make clear that we should never run the command, since reuseExistingServer is true.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This could also be done for some of the other tests, e.g., should send Accept header
or should be able to use an existing server when reuseExistingServer:true
. Should I also add it for those tests? If so, should that be done in the same commit or in a separate one?
@@ -595,7 +595,7 @@ export default defineConfig({ | |||
- type: ?<[Object]|[Array]<[Object]>> | |||
- `command` <[string]> Shell command to start. For example `npm run start`.. | |||
- `port` ?<[int]> The port that your http server is expected to appear on. It does wait until it accepts connections. Exactly one of `port` or `url` is required. | |||
- `url` ?<[string]> The url on your http server that is expected to return a 2xx, 3xx, 400, 401, 402, or 403 status code when the server is ready to accept connections. Exactly one of `port` or `url` is required. | |||
- `url` ?<[string]> The url on your http server that is expected to return a 2xx, 3xx, 400, 401, 402, or 403 status code when the server is ready to accept connections. Redirects (3xx status codes) are being followed and the new location is checked. Exactly one of `port` or `url` is required. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like the simple formula that we currently document:
The url on your http server that is expected to return a
2xx, 3xx, 400, 401, 402, or 403 status code when the
server is ready to accept connections.
Does that not work? We can prevent probe from following the redirects if current behavior does not much the doc above.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, I mentioned that in the PR description: At the moment, the docs don’t match reality: redirects are attempted to be followed, but it’s buggy. I am fine with both not following redirects, or fixing redirects. But not following redirects is more work, because the underlying utility (httpRequest) does not support that yet. And I wanted to keep things as simple as possible. But if that’s the preferred solution, I’m also Ok with that. I’d probably need some guidance on how to add that „don’t follow redirects“ option to httpRequest
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
https://github.com/microsoft/playwright/blob/main/packages/playwright-core/src/utils/network.ts#L78 we are using http.request for that, which should not follow redirects. Could you add a failing tests that surfaces the bug?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
http.request
may not follow redirects, but there is dedicated code in httpRequest
to do so: https://github.com/microsoft/playwright/blob/main/packages/playwright-core/src/utils/network.ts#L73
But this code is broken, which is the whole point of this PR. At the moment it fixes the broken redirect implementation. But I’m also happy to remove the redirect behavior, if that’s preferred.
Regarding a test case that fails, here is the simplest one I can think of:
test('should not follow redirects but accept them as "server is available"', async ({ runInlineTest, server }) => {
server.setRedirect('/redirect', '/redirected-to');
const result = await runInlineTest({
'test.spec.ts': `
import { test, expect } from '@playwright/test';
test('dummy test', async () => {
expect(true).toBe(true);
});
`,
'playwright.config.ts': `
module.exports = {
webServer: {
command: 'exit 1',
url: 'http://localhost:${server.PORT}/redirect',
reuseExistingServer: true,
}
};
`,
});
expect(result.exitCode).toBe(0);
});
@@ -71,7 +71,7 @@ export function httpRequest(params: HTTPRequestParams, onResponse: (r: http.Inco | |||
const requestCallback = (res: http.IncomingMessage) => { | |||
const statusCode = res.statusCode || 0; | |||
if (statusCode >= 300 && statusCode < 400 && res.headers.location) | |||
httpRequest({ ...params, url: res.headers.location }, onResponse, onError); | |||
httpRequest({ ...params, url: new URL.URL(res.headers.location, params.url).toString() }, onResponse, onError); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
httpRequest({ ...params, url: new URL.URL(res.headers.location, params.url).toString() }, onResponse, onError); | |
httpRequest({ ...params, url: new URL(res.headers.location, params.url).toString() }, onResponse, onError); |
change this to that and import * as URL from 'url';
to import * as url from 'url';
.
Clarified offline with Pavel that we want to continue to follow redirects.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
actually its fine, we used to do this before. Merging in since require('url').URL === URL
.
Fixes #22144
This change implements following redirects when a 3xx HTTP status code is received, when probing the
url
of awebServer
config.Without this change (i.e., currently), playwright still tries to follow the redirect, but often fails, since it incorrectly uses the received
Location
header as new URL, instead of combining it with the URL from the previous request.For example, if the URL is
http://localhost:8080/some-path
and a redirect withLocation: /some-other-path
is received, playwright incorrectly tries to queryhttp://localhost:80/some-other-path
, which of course fails, due to the incorrect port.An alternative solution would be to not follow redirects at all when probing the URL, and just consider a 3xx status code as "server is available". This is actually what the documentation claims will happen right now, but it's incorrect. I chose this solution over not following the redirect, since it makes sense, in my opinion, and not following the redirect would require more code changes (
httpRequest
would need some kind of option that prevents it from following redirects). But if that solution would be preferred, I am happy to change the implementation.