From b10a55895e9b606bbbbb8310107c959ef9c8eb88 Mon Sep 17 00:00:00 2001 From: Yury Semikhatsky Date: Fri, 2 Oct 2020 11:41:16 -0700 Subject: [PATCH] feat: support http credentials --- .../microsoft/playwright/impl/FrameImpl.java | 4 +- .../microsoft/playwright/impl/PageImpl.java | 2 +- .../playwright/impl/PlaywrightImpl.java | 2 +- .../java/com/microsoft/playwright/Server.java | 42 ++++++++++++++++++- .../com/microsoft/playwright/TestPopup.java | 20 +++++++-- 5 files changed, 62 insertions(+), 8 deletions(-) diff --git a/lib/src/main/java/com/microsoft/playwright/impl/FrameImpl.java b/lib/src/main/java/com/microsoft/playwright/impl/FrameImpl.java index 0219b983..17f06959 100644 --- a/lib/src/main/java/com/microsoft/playwright/impl/FrameImpl.java +++ b/lib/src/main/java/com/microsoft/playwright/impl/FrameImpl.java @@ -415,7 +415,9 @@ public class FrameImpl extends ChannelOwner implements Frame { @Override public String title() { - return null; + JsonElement json = sendMessage("title", new JsonObject()); + System.out.println(new Gson().toJson(json)); + return json.getAsJsonObject().get("value").getAsString(); } @Override diff --git a/lib/src/main/java/com/microsoft/playwright/impl/PageImpl.java b/lib/src/main/java/com/microsoft/playwright/impl/PageImpl.java index 84c52900..12133f81 100644 --- a/lib/src/main/java/com/microsoft/playwright/impl/PageImpl.java +++ b/lib/src/main/java/com/microsoft/playwright/impl/PageImpl.java @@ -358,7 +358,7 @@ public class PageImpl extends ChannelOwner implements Page { @Override public String title() { - return null; + return mainFrame.title(); } @Override diff --git a/lib/src/main/java/com/microsoft/playwright/impl/PlaywrightImpl.java b/lib/src/main/java/com/microsoft/playwright/impl/PlaywrightImpl.java index 549ab2e9..0ea6c9f9 100644 --- a/lib/src/main/java/com/microsoft/playwright/impl/PlaywrightImpl.java +++ b/lib/src/main/java/com/microsoft/playwright/impl/PlaywrightImpl.java @@ -38,7 +38,7 @@ public class PlaywrightImpl extends ChannelOwner implements Playwright { System.out.println("driver = " + driver.getCanonicalPath()); ProcessBuilder pb = new ProcessBuilder("node", driver.getCanonicalPath()); pb.redirectError(ProcessBuilder.Redirect.INHERIT); -// pb.environment().put("DEBUG", "pw:pro*"); +// pb.environment().put("DEBUG", "pw:pro*"); Process p = pb.start(); Connection connection = new Connection(p.getInputStream(), p.getOutputStream()); PlaywrightImpl playwright = (PlaywrightImpl)connection.waitForObjectWithKnownName("Playwright"); diff --git a/lib/src/test/java/com/microsoft/playwright/Server.java b/lib/src/test/java/com/microsoft/playwright/Server.java index 2ba67d99..0af625f8 100644 --- a/lib/src/test/java/com/microsoft/playwright/Server.java +++ b/lib/src/test/java/com/microsoft/playwright/Server.java @@ -28,7 +28,6 @@ import java.util.*; import java.util.concurrent.CompletableFuture; import java.util.concurrent.Future; -import static java.util.Collections.checkedCollection; import static java.util.Collections.singletonList; public class Server implements HttpHandler { @@ -43,6 +42,17 @@ public class Server implements HttpHandler { private final File resourcesDir; private final Map> requestSubscribers = Collections.synchronizedMap(new HashMap<>()); + private final Map auths = Collections.synchronizedMap(new HashMap<>()); + + private static class Auth { + public final String user; + public final String password; + + private Auth(String user, String password) { + this.user = user; + this.password = password; + } + } Server(int port) throws IOException { PORT = port; @@ -63,9 +73,12 @@ public class Server implements HttpHandler { server.stop(0); } + void setAuth(String path, String user, String password) { + auths.put(path, new Auth(user, password)); + } public static class Request { - // TODO: make a copy to ensure thread safety + // TODO: make a copy to ensure thread safety? public final Headers headers; public Request(Headers headers) { @@ -85,6 +98,31 @@ public class Server implements HttpHandler { @Override public void handle(HttpExchange exchange) throws IOException { String path = exchange.getRequestURI().getPath(); + + if (auths.containsKey(path)) { + List header = exchange.getRequestHeaders().get("authorization"); + boolean authorized = false; + if (header != null) { + String v = header.get(0); + String[] splits = v.split(" "); + if (splits.length == 2) { + String credentials = new String(Base64.getDecoder().decode(splits[1])); + Auth auth = auths.get(path); + authorized = credentials.equals(auth.user + ":" + auth.password); + } + } + if (!authorized) { + exchange.getResponseHeaders().put("WWW-Authenticate", Arrays.asList("Basic realm=\"Secure Area\"")); + exchange.sendResponseHeaders(401, 0); + try (Writer writer = new OutputStreamWriter(exchange.getResponseBody())) { + writer.write("HTTP Error 401 Unauthorized: Access is denied"); + // TODO: notify subscriber? + exchange.getResponseBody().close(); + } + return; + } + } + File file = new File(resourcesDir, path.substring(1)); exchange.getResponseHeaders().put("Content-Type", singletonList(mimeType(file))); try (FileInputStream input = new FileInputStream(file)) { diff --git a/lib/src/test/java/com/microsoft/playwright/TestPopup.java b/lib/src/test/java/com/microsoft/playwright/TestPopup.java index 917bffce..c5266d60 100644 --- a/lib/src/test/java/com/microsoft/playwright/TestPopup.java +++ b/lib/src/test/java/com/microsoft/playwright/TestPopup.java @@ -26,6 +26,7 @@ import java.util.Map; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; +import static com.microsoft.playwright.Page.LoadState.DOMCONTENTLOADED; import static org.junit.jupiter.api.Assertions.*; public class TestPopup { @@ -81,7 +82,7 @@ public class TestPopup { Deferred popupPromise = context.waitForPage(); page.click("a"); Page popup = popupPromise.get(); - popup.waitForLoadState(Page.LoadState.DOMCONTENTLOADED); + popup.waitForLoadState(DOMCONTENTLOADED); String userAgent = (String) popup.evaluate("() => window['initialUserAgent']"); Server.Request request = requestPromise.get(); context.close(); @@ -100,7 +101,6 @@ public class TestPopup { route.continue_(); intercepted[0] = true; }); - Deferred popup = context.waitForPage(); page.click("a"); popup.get(); @@ -111,7 +111,7 @@ public class TestPopup { @Test void should_inherit_extra_headers_from_browser_context() throws ExecutionException, InterruptedException { - Map headers = new HashMap(); + Map headers = new HashMap<>(); headers.put("foo", "bar"); BrowserContext context = browser.newContext(new Browser.NewContextOptions().withExtraHTTPHeaders(headers)); Page page = context.newPage(); @@ -136,4 +136,18 @@ public class TestPopup { context.close(); assertFalse(online); } + + @Test + void should_inherit_http_credentials_from_browser_context() { + server.setAuth("/title.html", "user", "pass"); + BrowserContext context = browser.newContext(new Browser.NewContextOptions() + .setHttpCredentials().withUsername("user").withPassword("pass").done()); + Page page = context.newPage(); + page.navigate(server.EMPTY_PAGE); + Deferred popup = page.waitForPopup(); + page.evaluate("url => window['_popup'] = window.open(url)", server.PREFIX + "/title.html"); + popup.get().waitForLoadState(DOMCONTENTLOADED); + assertEquals("Woof-Woof", popup.get().title()); + context.close(); + } }