2020-10-30 02:12:30 +03:00
/ * *
* Copyright ( c ) Microsoft Corporation .
*
* Licensed under the Apache License , Version 2.0 ( the "License" ) ;
* you may not use this file except in compliance with the License .
* You may obtain a copy of the License at
*
* http : //www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing , software
* distributed under the License is distributed on an "AS IS" BASIS ,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND , either express or implied .
* See the License for the specific language governing permissions and
* limitations under the License .
* /
2021-04-29 21:11:32 +03:00
import { browserTest as it , expect } from './config/browserTest' ;
2021-04-06 04:48:46 +03:00
2021-10-26 23:45:53 +03:00
it . use ( {
launchOptions : async ( { launchOptions } , use ) = > {
await use ( {
. . . launchOptions ,
proxy : { server : 'per-context' }
} ) ;
}
} ) ;
2020-10-30 02:12:30 +03:00
2021-08-19 23:34:32 +03:00
it . beforeEach ( ( { server } ) = > {
server . setRoute ( '/target.html' , async ( req , res ) = > {
res . end ( '<html><title>Served by the proxy</title></html>' ) ;
} ) ;
} ) ;
2021-04-30 01:02:48 +03:00
it ( 'should throw for missing global proxy on Chromium Windows' , async ( { browserName , platform , browserType , browserOptions , server } ) = > {
it . skip ( browserName !== 'chromium' || platform !== 'win32' ) ;
2021-07-19 18:50:14 +03:00
let browser ;
try {
browser = await browserType . launch ( {
. . . browserOptions ,
proxy : undefined ,
} ) ;
const error = await browser . newContext ( { proxy : { server : ` localhost: ${ server . PORT } ` } } ) . catch ( e = > e ) ;
expect ( error . toString ( ) ) . toContain ( 'Browser needs to be launched with the global proxy' ) ;
} finally {
await browser . close ( ) ;
}
2020-10-30 02:12:30 +03:00
} ) ;
2021-09-27 19:58:08 +03:00
it ( 'should work when passing the proxy only on the context level' , async ( { browserName , platform , browserType , browserOptions , contextOptions , server , proxyServer } ) = > {
2021-04-30 01:02:48 +03:00
// Currently an upstream bug in the network stack of Chromium which leads that
// the wrong proxy gets used in the BrowserContext.
it . fixme ( browserName === 'chromium' && platform === 'win32' ) ;
2021-08-19 23:34:32 +03:00
proxyServer . forwardTo ( server . PORT ) ;
2021-07-19 18:50:14 +03:00
let browser ;
try {
browser = await browserType . launch ( {
. . . browserOptions ,
proxy : undefined ,
} ) ;
const context = await browser . newContext ( {
. . . contextOptions ,
2021-08-19 23:34:32 +03:00
proxy : { server : ` localhost: ${ proxyServer . PORT } ` }
2021-07-19 18:50:14 +03:00
} ) ;
2021-04-30 01:02:48 +03:00
2021-07-19 18:50:14 +03:00
const page = await context . newPage ( ) ;
await page . goto ( 'http://non-existent.com/target.html' ) ;
2021-08-19 23:34:32 +03:00
expect ( proxyServer . requestUrls ) . toContain ( 'http://non-existent.com/target.html' ) ;
2021-07-19 18:50:14 +03:00
expect ( await page . title ( ) ) . toBe ( 'Served by the proxy' ) ;
} finally {
await browser . close ( ) ;
}
2021-04-30 01:02:48 +03:00
} ) ;
2021-05-10 03:47:20 +03:00
it ( 'should throw for bad server value' , async ( { contextFactory } ) = > {
const error = await contextFactory ( {
2020-10-30 02:12:30 +03:00
// @ts-expect-error server must be a string
proxy : { server : 123 }
} ) . catch ( e = > e ) ;
expect ( error . message ) . toContain ( 'proxy.server: expected string, got number' ) ;
} ) ;
2021-08-19 23:34:32 +03:00
it ( 'should use proxy' , async ( { contextFactory , server , proxyServer } ) = > {
proxyServer . forwardTo ( server . PORT ) ;
2021-05-10 03:47:20 +03:00
const context = await contextFactory ( {
2021-08-19 23:34:32 +03:00
proxy : { server : ` localhost: ${ proxyServer . PORT } ` }
2020-10-30 02:12:30 +03:00
} ) ;
2021-04-06 04:48:46 +03:00
const page = await context . newPage ( ) ;
2020-10-30 02:12:30 +03:00
await page . goto ( 'http://non-existent.com/target.html' ) ;
2021-08-19 23:34:32 +03:00
expect ( proxyServer . requestUrls ) . toContain ( 'http://non-existent.com/target.html' ) ;
2020-10-30 02:12:30 +03:00
expect ( await page . title ( ) ) . toBe ( 'Served by the proxy' ) ;
2021-04-06 04:48:46 +03:00
await context . close ( ) ;
2020-10-30 02:12:30 +03:00
} ) ;
2021-10-13 22:10:09 +03:00
it ( 'should use ipv6 proxy' , async ( { contextFactory , server , proxyServer , browserName } ) = > {
it . fail ( browserName === 'firefox' , 'page.goto: NS_ERROR_UNKNOWN_HOST' ) ;
2021-10-20 12:03:46 +03:00
it . fail ( ! ! process . env . INSIDE_DOCKER , 'docker does not support IPv6 by default' ) ;
2021-10-13 22:10:09 +03:00
proxyServer . forwardTo ( server . PORT ) ;
const context = await contextFactory ( {
proxy : { server : ` [0:0:0:0:0:0:0:1]: ${ proxyServer . PORT } ` }
} ) ;
const page = await context . newPage ( ) ;
await page . goto ( 'http://non-existent.com/target.html' ) ;
expect ( proxyServer . requestUrls ) . toContain ( 'http://non-existent.com/target.html' ) ;
expect ( await page . title ( ) ) . toBe ( 'Served by the proxy' ) ;
await context . close ( ) ;
} ) ;
2021-08-19 23:34:32 +03:00
it ( 'should use proxy twice' , async ( { contextFactory , server , proxyServer } ) = > {
proxyServer . forwardTo ( server . PORT ) ;
2021-05-10 03:47:20 +03:00
const context = await contextFactory ( {
2021-08-19 23:34:32 +03:00
proxy : { server : ` localhost: ${ proxyServer . PORT } ` }
2020-10-30 02:12:30 +03:00
} ) ;
2021-04-06 04:48:46 +03:00
const page = await context . newPage ( ) ;
2020-10-30 02:12:30 +03:00
await page . goto ( 'http://non-existent.com/target.html' ) ;
2021-08-19 23:34:32 +03:00
expect ( proxyServer . requestUrls ) . toContain ( 'http://non-existent.com/target.html' ) ;
2020-10-30 02:12:30 +03:00
await page . goto ( 'http://non-existent-2.com/target.html' ) ;
2021-08-19 23:34:32 +03:00
expect ( proxyServer . requestUrls ) . toContain ( 'http://non-existent-2.com/target.html' ) ;
2020-10-30 02:12:30 +03:00
expect ( await page . title ( ) ) . toBe ( 'Served by the proxy' ) ;
2021-04-06 04:48:46 +03:00
await context . close ( ) ;
2020-10-30 02:12:30 +03:00
} ) ;
2021-09-27 19:58:08 +03:00
it ( 'should use proxy for second page' , async ( { contextFactory , server , proxyServer } ) = > {
2021-08-19 23:34:32 +03:00
proxyServer . forwardTo ( server . PORT ) ;
2021-05-10 03:47:20 +03:00
const context = await contextFactory ( {
2021-08-19 23:34:32 +03:00
proxy : { server : ` localhost: ${ proxyServer . PORT } ` }
2020-10-30 02:12:30 +03:00
} ) ;
2021-04-06 04:48:46 +03:00
const page = await context . newPage ( ) ;
2020-10-30 02:12:30 +03:00
await page . goto ( 'http://non-existent.com/target.html' ) ;
2021-08-19 23:34:32 +03:00
expect ( proxyServer . requestUrls ) . toContain ( 'http://non-existent.com/target.html' ) ;
2020-10-30 02:12:30 +03:00
expect ( await page . title ( ) ) . toBe ( 'Served by the proxy' ) ;
2021-04-06 04:48:46 +03:00
const page2 = await context . newPage ( ) ;
2021-08-19 23:34:32 +03:00
proxyServer . requestUrls = [ ] ;
2020-10-30 02:12:30 +03:00
await page2 . goto ( 'http://non-existent.com/target.html' ) ;
2021-08-19 23:34:32 +03:00
expect ( proxyServer . requestUrls ) . toContain ( 'http://non-existent.com/target.html' ) ;
2020-10-30 02:12:30 +03:00
expect ( await page2 . title ( ) ) . toBe ( 'Served by the proxy' ) ;
2021-04-06 04:48:46 +03:00
await context . close ( ) ;
2020-10-30 02:12:30 +03:00
} ) ;
2021-08-19 17:36:03 +03:00
it ( 'should use proxy for https urls' , async ( { contextFactory , server , httpsServer , proxyServer } ) = > {
httpsServer . setRoute ( '/target.html' , async ( req , res ) = > {
2021-08-19 23:34:32 +03:00
res . end ( '<html><title>Served by https server via proxy</title></html>' ) ;
2021-08-19 17:36:03 +03:00
} ) ;
2021-08-19 23:34:32 +03:00
proxyServer . forwardTo ( httpsServer . PORT ) ;
2021-08-19 17:36:03 +03:00
const context = await contextFactory ( {
ignoreHTTPSErrors : true ,
proxy : { server : ` localhost: ${ proxyServer . PORT } ` }
} ) ;
const page = await context . newPage ( ) ;
await page . goto ( 'https://non-existent.com/target.html' ) ;
2021-08-19 23:34:32 +03:00
expect ( proxyServer . connectHosts ) . toContain ( 'non-existent.com:443' ) ;
expect ( await page . title ( ) ) . toBe ( 'Served by https server via proxy' ) ;
2021-08-19 17:36:03 +03:00
await context . close ( ) ;
} ) ;
2021-09-27 19:58:08 +03:00
it ( 'should work with IP:PORT notion' , async ( { contextFactory , server , proxyServer } ) = > {
2021-08-19 23:34:32 +03:00
proxyServer . forwardTo ( server . PORT ) ;
2021-05-10 03:47:20 +03:00
const context = await contextFactory ( {
2021-08-19 23:34:32 +03:00
proxy : { server : ` 127.0.0.1: ${ proxyServer . PORT } ` }
2020-10-30 02:12:30 +03:00
} ) ;
2021-04-06 04:48:46 +03:00
const page = await context . newPage ( ) ;
2020-10-30 02:12:30 +03:00
await page . goto ( 'http://non-existent.com/target.html' ) ;
2021-08-19 23:34:32 +03:00
expect ( proxyServer . requestUrls ) . toContain ( 'http://non-existent.com/target.html' ) ;
2020-10-30 02:12:30 +03:00
expect ( await page . title ( ) ) . toBe ( 'Served by the proxy' ) ;
2021-04-06 04:48:46 +03:00
await context . close ( ) ;
2020-10-30 02:12:30 +03:00
} ) ;
2021-09-27 19:58:08 +03:00
it ( 'should throw for socks5 authentication' , async ( { contextFactory } ) = > {
2021-05-10 03:47:20 +03:00
const error = await contextFactory ( {
2021-02-08 23:07:45 +03:00
proxy : { server : ` socks5://localhost:1234 ` , username : 'user' , password : 'secret' }
} ) . catch ( e = > e ) ;
expect ( error . message ) . toContain ( 'Browser does not support socks5 proxy authentication' ) ;
} ) ;
2021-09-27 19:58:08 +03:00
it ( 'should throw for socks4 authentication' , async ( { contextFactory } ) = > {
2021-05-10 03:47:20 +03:00
const error = await contextFactory ( {
2021-02-08 23:07:45 +03:00
proxy : { server : ` socks4://localhost:1234 ` , username : 'user' , password : 'secret' }
} ) . catch ( e = > e ) ;
expect ( error . message ) . toContain ( 'Socks4 proxy protocol does not support authentication' ) ;
} ) ;
2021-09-27 19:58:08 +03:00
it ( 'should authenticate' , async ( { contextFactory , server , proxyServer } ) = > {
2021-08-19 23:34:32 +03:00
proxyServer . forwardTo ( server . PORT ) ;
let auth ;
proxyServer . setAuthHandler ( req = > {
auth = req . headers [ 'proxy-authorization' ] ;
return ! ! auth ;
2020-10-30 02:12:30 +03:00
} ) ;
2021-05-10 03:47:20 +03:00
const context = await contextFactory ( {
2021-08-19 23:34:32 +03:00
proxy : { server : ` localhost: ${ proxyServer . PORT } ` , username : 'user' , password : 'secret' }
2020-10-30 02:12:30 +03:00
} ) ;
2021-04-06 04:48:46 +03:00
const page = await context . newPage ( ) ;
2020-10-30 02:12:30 +03:00
await page . goto ( 'http://non-existent.com/target.html' ) ;
2021-08-19 23:34:32 +03:00
expect ( proxyServer . requestUrls ) . toContain ( 'http://non-existent.com/target.html' ) ;
expect ( auth ) . toBe ( 'Basic ' + Buffer . from ( 'user:secret' ) . toString ( 'base64' ) ) ;
expect ( await page . title ( ) ) . toBe ( 'Served by the proxy' ) ;
2021-04-06 04:48:46 +03:00
await context . close ( ) ;
2020-10-30 02:12:30 +03:00
} ) ;
2021-09-27 19:58:08 +03:00
it ( 'should authenticate with empty password' , async ( { contextFactory , server , proxyServer } ) = > {
2021-08-19 23:34:32 +03:00
proxyServer . forwardTo ( server . PORT ) ;
let auth ;
proxyServer . setAuthHandler ( req = > {
auth = req . headers [ 'proxy-authorization' ] ;
return ! ! auth ;
2020-12-21 22:47:13 +03:00
} ) ;
2021-05-10 03:47:20 +03:00
const context = await contextFactory ( {
2021-08-19 23:34:32 +03:00
proxy : { server : ` localhost: ${ proxyServer . PORT } ` , username : 'user' , password : '' }
2020-12-21 22:47:13 +03:00
} ) ;
2021-04-06 04:48:46 +03:00
const page = await context . newPage ( ) ;
2020-12-21 22:47:13 +03:00
await page . goto ( 'http://non-existent.com/target.html' ) ;
2021-08-19 23:34:32 +03:00
expect ( auth ) . toBe ( 'Basic ' + Buffer . from ( 'user:' ) . toString ( 'base64' ) ) ;
expect ( await page . title ( ) ) . toBe ( 'Served by the proxy' ) ;
2021-04-06 04:48:46 +03:00
await context . close ( ) ;
2020-12-21 22:47:13 +03:00
} ) ;
2021-09-27 19:58:08 +03:00
it ( 'should isolate proxy credentials between contexts' , async ( { contextFactory , server , browserName , proxyServer } ) = > {
2021-04-03 07:07:45 +03:00
it . fixme ( browserName === 'firefox' , 'Credentials from the first context stick around' ) ;
2021-08-19 23:34:32 +03:00
proxyServer . forwardTo ( server . PORT ) ;
let auth ;
proxyServer . setAuthHandler ( req = > {
auth = req . headers [ 'proxy-authorization' ] ;
return ! ! auth ;
2020-12-22 01:39:11 +03:00
} ) ;
{
2021-05-10 03:47:20 +03:00
const context = await contextFactory ( {
2021-08-19 23:34:32 +03:00
proxy : { server : ` localhost: ${ proxyServer . PORT } ` , username : 'user1' , password : 'secret1' }
2020-12-22 01:39:11 +03:00
} ) ;
const page = await context . newPage ( ) ;
await page . goto ( 'http://non-existent.com/target.html' ) ;
2021-08-19 23:34:32 +03:00
expect ( auth ) . toBe ( 'Basic ' + Buffer . from ( 'user1:secret1' ) . toString ( 'base64' ) ) ;
expect ( await page . title ( ) ) . toBe ( 'Served by the proxy' ) ;
2020-12-22 01:39:11 +03:00
await context . close ( ) ;
}
2021-08-19 23:34:32 +03:00
auth = undefined ;
2020-12-22 01:39:11 +03:00
{
2021-05-10 03:47:20 +03:00
const context = await contextFactory ( {
2021-08-19 23:34:32 +03:00
proxy : { server : ` localhost: ${ proxyServer . PORT } ` , username : 'user2' , password : 'secret2' }
2020-12-22 01:39:11 +03:00
} ) ;
const page = await context . newPage ( ) ;
await page . goto ( 'http://non-existent.com/target.html' ) ;
2021-08-19 23:34:32 +03:00
expect ( await page . title ( ) ) . toBe ( 'Served by the proxy' ) ;
expect ( auth ) . toBe ( 'Basic ' + Buffer . from ( 'user2:secret2' ) . toString ( 'base64' ) ) ;
2020-12-22 01:39:11 +03:00
await context . close ( ) ;
}
} ) ;
2021-09-27 19:58:08 +03:00
it ( 'should exclude patterns' , async ( { contextFactory , server , browserName , headless , proxyServer } ) = > {
2021-05-13 20:22:23 +03:00
it . fixme ( browserName === 'chromium' && ! headless , 'Chromium headed crashes with CHECK(!in_frame_tree_) in RenderFrameImpl::OnDeleteFrame.' ) ;
2021-04-03 07:07:45 +03:00
2021-08-19 23:34:32 +03:00
proxyServer . forwardTo ( server . PORT ) ;
2020-10-30 02:12:30 +03:00
// FYI: using long and weird domain names to avoid ATT DNS hijacking
// that resolves everything to some weird search results page.
//
// @see https://gist.github.com/CollinChaffin/24f6c9652efb3d6d5ef2f5502720ef00
2021-05-10 03:47:20 +03:00
const context = await contextFactory ( {
2021-08-19 23:34:32 +03:00
proxy : { server : ` localhost: ${ proxyServer . PORT } ` , bypass : '1.non.existent.domain.for.the.test, 2.non.existent.domain.for.the.test, .another.test' }
2020-10-30 02:12:30 +03:00
} ) ;
2021-04-06 04:48:46 +03:00
const page = await context . newPage ( ) ;
2020-10-30 02:12:30 +03:00
await page . goto ( 'http://0.non.existent.domain.for.the.test/target.html' ) ;
2021-08-19 23:34:32 +03:00
expect ( proxyServer . requestUrls ) . toContain ( 'http://0.non.existent.domain.for.the.test/target.html' ) ;
2020-10-30 02:12:30 +03:00
expect ( await page . title ( ) ) . toBe ( 'Served by the proxy' ) ;
2021-08-19 23:34:32 +03:00
proxyServer . requestUrls = [ ] ;
2020-10-30 02:12:30 +03:00
{
const error = await page . goto ( 'http://1.non.existent.domain.for.the.test/target.html' ) . catch ( e = > e ) ;
2021-08-19 23:34:32 +03:00
expect ( proxyServer . requestUrls ) . toEqual ( [ ] ) ;
2020-10-30 02:12:30 +03:00
expect ( error . message ) . toBeTruthy ( ) ;
}
{
const error = await page . goto ( 'http://2.non.existent.domain.for.the.test/target.html' ) . catch ( e = > e ) ;
2021-08-19 23:34:32 +03:00
expect ( proxyServer . requestUrls ) . toEqual ( [ ] ) ;
2020-10-30 02:12:30 +03:00
expect ( error . message ) . toBeTruthy ( ) ;
}
{
const error = await page . goto ( 'http://foo.is.the.another.test/target.html' ) . catch ( e = > e ) ;
2021-08-19 23:34:32 +03:00
expect ( proxyServer . requestUrls ) . toEqual ( [ ] ) ;
2020-10-30 02:12:30 +03:00
expect ( error . message ) . toBeTruthy ( ) ;
}
{
await page . goto ( 'http://3.non.existent.domain.for.the.test/target.html' ) ;
2021-08-19 23:34:32 +03:00
expect ( proxyServer . requestUrls ) . toContain ( 'http://3.non.existent.domain.for.the.test/target.html' ) ;
2020-10-30 02:12:30 +03:00
expect ( await page . title ( ) ) . toBe ( 'Served by the proxy' ) ;
}
2021-04-06 04:48:46 +03:00
await context . close ( ) ;
2020-10-30 02:12:30 +03:00
} ) ;
2021-05-10 03:47:20 +03:00
it ( 'should use socks proxy' , async ( { contextFactory , socksPort } ) = > {
const context = await contextFactory ( {
2020-10-30 02:12:30 +03:00
proxy : { server : ` socks5://localhost: ${ socksPort } ` }
} ) ;
2021-04-06 04:48:46 +03:00
const page = await context . newPage ( ) ;
2020-10-30 02:12:30 +03:00
await page . goto ( 'http://non-existent.com' ) ;
expect ( await page . title ( ) ) . toBe ( 'Served by the SOCKS proxy' ) ;
2021-04-06 04:48:46 +03:00
await context . close ( ) ;
2020-10-30 02:12:30 +03:00
} ) ;
2021-05-10 03:47:20 +03:00
it ( 'should use socks proxy in second page' , async ( { contextFactory , socksPort } ) = > {
const context = await contextFactory ( {
2020-10-30 02:12:30 +03:00
proxy : { server : ` socks5://localhost: ${ socksPort } ` }
} ) ;
2021-04-06 04:48:46 +03:00
const page = await context . newPage ( ) ;
2020-10-30 02:12:30 +03:00
await page . goto ( 'http://non-existent.com' ) ;
expect ( await page . title ( ) ) . toBe ( 'Served by the SOCKS proxy' ) ;
2021-04-06 04:48:46 +03:00
const page2 = await context . newPage ( ) ;
2020-10-30 02:12:30 +03:00
await page2 . goto ( 'http://non-existent.com' ) ;
expect ( await page2 . title ( ) ) . toBe ( 'Served by the SOCKS proxy' ) ;
2021-04-06 04:48:46 +03:00
await context . close ( ) ;
2020-10-30 02:12:30 +03:00
} ) ;
2021-05-10 03:47:20 +03:00
it ( 'does launch without a port' , async ( { contextFactory } ) = > {
const context = await contextFactory ( {
2020-10-30 02:12:30 +03:00
proxy : { server : 'http://localhost' }
} ) ;
2021-04-06 04:48:46 +03:00
await context . close ( ) ;
2020-10-30 02:12:30 +03:00
} ) ;