Skip to content

Commit f9bb654

Browse files
committed
Sec header: two more tests passing
1 parent 48cac65 commit f9bb654

2 files changed

Lines changed: 323 additions & 2 deletions

File tree

src/main/java/org/htmlunit/html/HtmlImage.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import static org.htmlunit.BrowserVersionFeatures.HTMLIMAGE_EMPTY_SRC_DISPLAY_FALSE;
1919
import static org.htmlunit.BrowserVersionFeatures.HTMLIMAGE_HTMLELEMENT;
2020
import static org.htmlunit.BrowserVersionFeatures.HTMLIMAGE_HTMLUNKNOWNELEMENT;
21+
import static org.htmlunit.BrowserVersionFeatures.HTTP_HEADER_CH_UA;
2122
import static org.htmlunit.BrowserVersionFeatures.JS_IMAGE_WIDTH_HEIGHT_RETURNS_16x16_0x0;
2223
import static org.htmlunit.BrowserVersionFeatures.JS_IMAGE_WIDTH_HEIGHT_RETURNS_24x24_0x0;
2324

@@ -34,6 +35,7 @@
3435
import org.apache.commons.logging.Log;
3536
import org.apache.commons.logging.LogFactory;
3637
import org.htmlunit.BrowserVersion;
38+
import org.htmlunit.HttpHeader;
3739
import org.htmlunit.Page;
3840
import org.htmlunit.ScriptResult;
3941
import org.htmlunit.SgmlPage;
@@ -687,6 +689,10 @@ private void downloadImageIfNeeded() throws IOException {
687689
browser.getAcceptEncodingHeader());
688690
request.setCharset(page.getCharset());
689691
request.setRefererHeader(page.getUrl());
692+
if (browser.hasFeature(HTTP_HEADER_CH_UA)) {
693+
request.setAdditionalHeader(HttpHeader.ORIGIN,
694+
UrlUtils.getUrlWithProtocolAndAuthority(page.getUrl()).toExternalForm());
695+
}
690696

691697
// Sec-Fetch-* support (https://www.w3.org/TR/fetch-metadata/):
692698
// an <img> load is never user-activated, and is initiated by the

src/test/java/org/htmlunit/HttpWebConnection3Test.java

Lines changed: 317 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1686,8 +1686,6 @@ public void loadJavascriptCharset() throws Exception {
16861686
* Tests the Sec-Fetch-* headers sent for an &lt;img&gt; request.
16871687
* Real browsers: Sec-Fetch-Mode: no-cors, Sec-Fetch-Dest: image, no Sec-Fetch-User
16881688
* (the image was not requested by direct user activation).
1689-
* HtmlUnit currently hardcodes Sec-Fetch-Mode: navigate, Sec-Fetch-Dest: document
1690-
* and always adds Sec-Fetch-User: ?1.
16911689
*
16921690
* @throws Exception if the test fails
16931691
*/
@@ -2479,4 +2477,321 @@ public void anchorClickFromScript() throws Exception {
24792477
assertEquals(Arrays.asList(expectedHeaders).toString(), Arrays.asList(headers).toString());
24802478
}
24812479
}
2480+
2481+
/**
2482+
* Tests a link with {@code rel="noreferrer"}. This suppresses the {@code Referer}
2483+
* header entirely, but must not affect {@code Sec-Fetch-Site}: that header reflects
2484+
* the true relationship between initiator and target regardless of referrer-policy
2485+
* stripping, so it is still sent as {@code same-origin} here.
2486+
*
2487+
* @throws Exception if the test fails
2488+
*/
2489+
@Test
2490+
@Alerts(CHROME = {"GET /2.html HTTP/1.1",
2491+
"Host: localhost:§§PORT§§",
2492+
"Connection: keep-alive",
2493+
"sec-ch-ua: §§SEC_USER_AGENT§§",
2494+
"sec-ch-ua-mobile: ?0",
2495+
"sec-ch-ua-platform: \"Windows\"",
2496+
"Upgrade-Insecure-Requests: 1",
2497+
"User-Agent: §§USER_AGENT§§",
2498+
"Accept: §§ACCEPT§§",
2499+
"Sec-Fetch-Site: same-origin",
2500+
"Sec-Fetch-Mode: navigate",
2501+
"Sec-Fetch-User: ?1",
2502+
"Sec-Fetch-Dest: document",
2503+
"Accept-Encoding: gzip, deflate, br, zstd",
2504+
"Accept-Language: en-US,en;q=0.9"},
2505+
EDGE = {"GET /2.html HTTP/1.1",
2506+
"Host: localhost:§§PORT§§",
2507+
"Connection: keep-alive",
2508+
"sec-ch-ua: §§SEC_USER_AGENT§§",
2509+
"sec-ch-ua-mobile: ?0",
2510+
"sec-ch-ua-platform: \"Windows\"",
2511+
"Upgrade-Insecure-Requests: 1",
2512+
"User-Agent: §§USER_AGENT§§",
2513+
"Accept: §§ACCEPT§§",
2514+
"Sec-Fetch-Site: same-origin",
2515+
"Sec-Fetch-Mode: navigate",
2516+
"Sec-Fetch-User: ?1",
2517+
"Sec-Fetch-Dest: document",
2518+
"Accept-Encoding: gzip, deflate, br, zstd",
2519+
"Accept-Language: en-US,en;q=0.9"},
2520+
FF = {"GET /2.html HTTP/1.1",
2521+
"Host: localhost:§§PORT§§",
2522+
"User-Agent: §§USER_AGENT§§",
2523+
"Accept: §§ACCEPT§§",
2524+
"Accept-Language: en-US,en;q=0.9",
2525+
"Accept-Encoding: gzip, deflate, br, zstd",
2526+
"Connection: keep-alive",
2527+
"Upgrade-Insecure-Requests: 1",
2528+
"Sec-Fetch-Dest: document",
2529+
"Sec-Fetch-Mode: navigate",
2530+
"Sec-Fetch-Site: same-origin",
2531+
"Sec-Fetch-User: ?1",
2532+
"Priority: u=0, i"},
2533+
FF_ESR = {"GET /2.html HTTP/1.1",
2534+
"Host: localhost:§§PORT§§",
2535+
"User-Agent: §§USER_AGENT§§",
2536+
"Accept: §§ACCEPT§§",
2537+
"Accept-Language: en-US,en;q=0.5",
2538+
"Accept-Encoding: gzip, deflate, br, zstd",
2539+
"Connection: keep-alive",
2540+
"Upgrade-Insecure-Requests: 1",
2541+
"Sec-Fetch-Dest: document",
2542+
"Sec-Fetch-Mode: navigate",
2543+
"Sec-Fetch-Site: same-origin",
2544+
"Sec-Fetch-User: ?1",
2545+
"Priority: u=0, i"})
2546+
@HtmlUnitNYI(
2547+
CHROME = {"GET /2.html HTTP/1.1",
2548+
"Host: localhost:§§PORT§§",
2549+
"Connection: keep-alive",
2550+
"sec-ch-ua: §§SEC_USER_AGENT§§",
2551+
"sec-ch-ua-mobile: ?0",
2552+
"sec-ch-ua-platform: \"Windows\"",
2553+
"Upgrade-Insecure-Requests: 1",
2554+
"User-Agent: §§USER_AGENT§§",
2555+
"Accept: §§ACCEPT§§",
2556+
"Sec-Fetch-Site: same-origin",
2557+
"Sec-Fetch-Mode: navigate",
2558+
"Sec-Fetch-User: ?1",
2559+
"Sec-Fetch-Dest: document",
2560+
"Accept-Encoding: gzip, deflate, br",
2561+
"Accept-Language: en-US,en;q=0.9"},
2562+
EDGE = {"GET /2.html HTTP/1.1",
2563+
"Host: localhost:§§PORT§§",
2564+
"Connection: keep-alive",
2565+
"sec-ch-ua: §§SEC_USER_AGENT§§",
2566+
"sec-ch-ua-mobile: ?0",
2567+
"sec-ch-ua-platform: \"Windows\"",
2568+
"Upgrade-Insecure-Requests: 1",
2569+
"User-Agent: §§USER_AGENT§§",
2570+
"Accept: §§ACCEPT§§",
2571+
"Sec-Fetch-Site: same-origin",
2572+
"Sec-Fetch-Mode: navigate",
2573+
"Sec-Fetch-User: ?1",
2574+
"Sec-Fetch-Dest: document",
2575+
"Accept-Encoding: gzip, deflate, br",
2576+
"Accept-Language: en-US,en;q=0.9"},
2577+
FF = {"GET /2.html HTTP/1.1",
2578+
"Host: localhost:§§PORT§§",
2579+
"User-Agent: §§USER_AGENT§§",
2580+
"Accept: §§ACCEPT§§",
2581+
"Accept-Language: en-US,en;q=0.9",
2582+
"Accept-Encoding: gzip, deflate, br",
2583+
"Connection: keep-alive",
2584+
"Upgrade-Insecure-Requests: 1",
2585+
"Sec-Fetch-Dest: document",
2586+
"Sec-Fetch-Mode: navigate",
2587+
"Sec-Fetch-Site: same-origin",
2588+
"Sec-Fetch-User: ?1",
2589+
"Priority: u=0, i"},
2590+
FF_ESR = {"GET /2.html HTTP/1.1",
2591+
"Host: localhost:§§PORT§§",
2592+
"User-Agent: §§USER_AGENT§§",
2593+
"Accept: §§ACCEPT§§",
2594+
"Accept-Language: en-US,en;q=0.5",
2595+
"Accept-Encoding: gzip, deflate, br",
2596+
"Connection: keep-alive",
2597+
"Upgrade-Insecure-Requests: 1",
2598+
"Sec-Fetch-Dest: document",
2599+
"Sec-Fetch-Mode: navigate",
2600+
"Sec-Fetch-Site: same-origin",
2601+
"Sec-Fetch-User: ?1",
2602+
"Priority: u=0, i"})
2603+
public void anchorRelNoreferrer() throws Exception {
2604+
String html = DOCTYPE_HTML
2605+
+ "<html><body><a id='my' href='2.html' rel='noreferrer'>Click me</a></body></html>";
2606+
html = "HTTP/1.1 200 OK\r\n"
2607+
+ "Content-Length: " + (html.length()) + "\r\n"
2608+
+ "Content-Type: text/html\r\n"
2609+
+ "Connection: close\r\n"
2610+
+ "\r\n"
2611+
+ html;
2612+
final String hi = "HTTP/1.1 200 OK\r\n"
2613+
+ "Content-Length: 2\r\n"
2614+
+ "Content-Type: text/plain\r\n"
2615+
+ "Connection: close\r\n"
2616+
+ "\r\n"
2617+
+ "Hi";
2618+
2619+
shutDownAll();
2620+
try (PrimitiveWebServer primitiveWebServer = new PrimitiveWebServer(null, html, hi)) {
2621+
final WebDriver driver = getWebDriver();
2622+
2623+
driver.get("http://localhost:" + primitiveWebServer.getPort());
2624+
driver.findElement(By.id("my")).click();
2625+
2626+
final String[] expectedHeaders = getExpectedAlerts();
2627+
for (int i = 0; i < expectedHeaders.length; i++) {
2628+
expectedHeaders[i] = expectedHeaders[i].replaceAll("§§PORT§§", "" + primitiveWebServer.getPort());
2629+
expectedHeaders[i] = expectedHeaders[i].replaceAll("§§USER_AGENT§§",
2630+
getBrowserVersion().getUserAgent());
2631+
expectedHeaders[i] = expectedHeaders[i].replaceAll("§§SEC_USER_AGENT§§",
2632+
getBrowserVersion().getSecClientHintUserAgentHeader());
2633+
expectedHeaders[i] = expectedHeaders[i].replaceAll("§§ACCEPT§§",
2634+
getBrowserVersion().getHtmlAcceptHeader());
2635+
}
2636+
final String request = primitiveWebServer.getRequests().get(1);
2637+
final String[] headers = request.split("\\r\\n");
2638+
assertEquals(Arrays.asList(expectedHeaders).toString(), Arrays.asList(headers).toString());
2639+
}
2640+
}
2641+
2642+
/**
2643+
* Tests the Sec-Fetch-* headers sent for an &lt;img crossorigin&gt; request. The
2644+
* presence of the {@code crossorigin} attribute (regardless of its value) forces
2645+
* CORS mode, unlike a plain &lt;img&gt; which uses no-cors (see {@link #image()}).
2646+
*
2647+
* @throws Exception if the test fails
2648+
*/
2649+
@Test
2650+
@Alerts(CHROME = {"GET /image.png HTTP/1.1",
2651+
"Host: localhost:§§PORT§§",
2652+
"Connection: keep-alive",
2653+
"Origin: http://localhost:22225",
2654+
"sec-ch-ua-platform: \"Windows\"",
2655+
"User-Agent: §§USER_AGENT§§",
2656+
"sec-ch-ua: §§SEC_USER_AGENT§§",
2657+
"sec-ch-ua-mobile: ?0",
2658+
"Accept: image/avif,image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8",
2659+
"Sec-Fetch-Site: same-origin",
2660+
"Sec-Fetch-Mode: cors",
2661+
"Sec-Fetch-Dest: image",
2662+
"Referer: http://localhost:§§PORT§§/",
2663+
"Accept-Encoding: gzip, deflate, br, zstd",
2664+
"Accept-Language: en-US,en;q=0.9"},
2665+
EDGE = {"GET /image.png HTTP/1.1",
2666+
"Host: localhost:§§PORT§§",
2667+
"Connection: keep-alive",
2668+
"Origin: http://localhost:22225",
2669+
"sec-ch-ua-platform: \"Windows\"",
2670+
"User-Agent: §§USER_AGENT§§",
2671+
"sec-ch-ua: §§SEC_USER_AGENT§§",
2672+
"sec-ch-ua-mobile: ?0",
2673+
"Accept: image/avif,image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8",
2674+
"Sec-Fetch-Site: same-origin",
2675+
"Sec-Fetch-Mode: cors",
2676+
"Sec-Fetch-Dest: image",
2677+
"Referer: http://localhost:§§PORT§§/",
2678+
"Accept-Encoding: gzip, deflate, br, zstd",
2679+
"Accept-Language: en-US,en;q=0.9"},
2680+
FF = {"GET /image.png HTTP/1.1",
2681+
"Host: localhost:§§PORT§§",
2682+
"User-Agent: §§USER_AGENT§§",
2683+
"Accept: image/avif,image/webp,image/png,image/svg+xml,image/*;q=0.8,*/*;q=0.5",
2684+
"Accept-Language: en-US,en;q=0.9",
2685+
"Accept-Encoding: gzip, deflate, br, zstd",
2686+
"Connection: keep-alive",
2687+
"Referer: http://localhost:§§PORT§§/",
2688+
"Sec-Fetch-Dest: image",
2689+
"Sec-Fetch-Mode: cors",
2690+
"Sec-Fetch-Site: same-origin",
2691+
"Priority: u=4, i"},
2692+
FF_ESR = {"GET /image.png HTTP/1.1",
2693+
"Host: localhost:§§PORT§§",
2694+
"User-Agent: §§USER_AGENT§§",
2695+
"Accept: image/avif,image/webp,image/png,image/svg+xml,image/*;q=0.8,*/*;q=0.5",
2696+
"Accept-Language: en-US,en;q=0.5",
2697+
"Accept-Encoding: gzip, deflate, br, zstd",
2698+
"Connection: keep-alive",
2699+
"Referer: http://localhost:§§PORT§§/",
2700+
"Sec-Fetch-Dest: image",
2701+
"Sec-Fetch-Mode: cors",
2702+
"Sec-Fetch-Site: same-origin",
2703+
"Priority: u=4, i"})
2704+
@HtmlUnitNYI(
2705+
CHROME = {"GET /image.png HTTP/1.1",
2706+
"Host: localhost:§§PORT§§",
2707+
"Connection: keep-alive",
2708+
"sec-ch-ua: §§SEC_USER_AGENT§§",
2709+
"sec-ch-ua-mobile: ?0",
2710+
"sec-ch-ua-platform: \"Windows\"",
2711+
"User-Agent: §§USER_AGENT§§",
2712+
"Accept: image/avif,image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8",
2713+
"Sec-Fetch-Site: same-origin",
2714+
"Sec-Fetch-Mode: cors",
2715+
"Sec-Fetch-Dest: image",
2716+
"Referer: http://localhost:§§PORT§§/",
2717+
"Accept-Encoding: gzip, deflate, br",
2718+
"Accept-Language: en-US,en;q=0.9",
2719+
"Origin: http://localhost:22225"},
2720+
EDGE = {"GET /image.png HTTP/1.1",
2721+
"Host: localhost:§§PORT§§",
2722+
"Connection: keep-alive",
2723+
"sec-ch-ua: §§SEC_USER_AGENT§§",
2724+
"sec-ch-ua-mobile: ?0",
2725+
"sec-ch-ua-platform: \"Windows\"",
2726+
"User-Agent: §§USER_AGENT§§",
2727+
"Accept: image/avif,image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8",
2728+
"Sec-Fetch-Site: same-origin",
2729+
"Sec-Fetch-Mode: cors",
2730+
"Sec-Fetch-Dest: image",
2731+
"Referer: http://localhost:§§PORT§§/",
2732+
"Accept-Encoding: gzip, deflate, br",
2733+
"Accept-Language: en-US,en;q=0.9",
2734+
"Origin: http://localhost:22225"},
2735+
FF = {"GET /image.png HTTP/1.1",
2736+
"Host: localhost:§§PORT§§",
2737+
"User-Agent: §§USER_AGENT§§",
2738+
"Accept: image/avif,image/webp,image/png,image/svg+xml,image/*;q=0.8,*/*;q=0.5",
2739+
"Accept-Language: en-US,en;q=0.9",
2740+
"Accept-Encoding: gzip, deflate, br",
2741+
"Connection: keep-alive",
2742+
"Referer: http://localhost:§§PORT§§/",
2743+
"Sec-Fetch-Dest: image",
2744+
"Sec-Fetch-Mode: cors",
2745+
"Sec-Fetch-Site: same-origin",
2746+
"Priority: u=0, i"},
2747+
FF_ESR = {"GET /image.png HTTP/1.1",
2748+
"Host: localhost:§§PORT§§",
2749+
"User-Agent: §§USER_AGENT§§",
2750+
"Accept: image/avif,image/webp,image/png,image/svg+xml,image/*;q=0.8,*/*;q=0.5",
2751+
"Accept-Language: en-US,en;q=0.5",
2752+
"Accept-Encoding: gzip, deflate, br",
2753+
"Connection: keep-alive",
2754+
"Referer: http://localhost:§§PORT§§/",
2755+
"Sec-Fetch-Dest: image",
2756+
"Sec-Fetch-Mode: cors",
2757+
"Sec-Fetch-Site: same-origin",
2758+
"Priority: u=0, i"})
2759+
public void imageCrossOrigin() throws Exception {
2760+
final String html = DOCTYPE_HTML
2761+
+ "<html><head></head><body><img crossorigin='anonymous' src='image.png'></body></html>";
2762+
final String htmlResponse = "HTTP/1.1 200 OK\r\n"
2763+
+ "Content-Length: " + html.length() + "\r\n"
2764+
+ "Content-Type: text/html\r\n"
2765+
+ "Connection: close\r\n"
2766+
+ "\r\n"
2767+
+ html;
2768+
final String imageResponse = "HTTP/1.1 200 OK\r\n"
2769+
+ "Content-Length: 2\r\n"
2770+
+ "Content-Type: image/png\r\n"
2771+
+ "Connection: close\r\n"
2772+
+ "\r\n"
2773+
+ "Hi";
2774+
2775+
shutDownAll();
2776+
try (PrimitiveWebServer primitiveWebServer = new PrimitiveWebServer(null, htmlResponse, imageResponse)) {
2777+
final WebDriver driver = getWebDriver();
2778+
2779+
driver.get("http://localhost:" + primitiveWebServer.getPort());
2780+
2781+
// force image download in htmlunit
2782+
driver.findElement(By.tagName("img")).getAttribute("height");
2783+
2784+
final String[] expectedHeaders = getExpectedAlerts();
2785+
for (int i = 0; i < expectedHeaders.length; i++) {
2786+
expectedHeaders[i] = expectedHeaders[i].replaceAll("§§PORT§§", "" + primitiveWebServer.getPort());
2787+
expectedHeaders[i] = expectedHeaders[i].replaceAll("§§USER_AGENT§§",
2788+
getBrowserVersion().getUserAgent());
2789+
expectedHeaders[i] = expectedHeaders[i].replaceAll("§§SEC_USER_AGENT§§",
2790+
getBrowserVersion().getSecClientHintUserAgentHeader());
2791+
}
2792+
final String request = primitiveWebServer.getRequests().get(1);
2793+
final String[] headers = request.split("\\r\\n");
2794+
assertEquals(Arrays.asList(expectedHeaders).toString(), Arrays.asList(headers).toString());
2795+
}
2796+
}
24822797
}

0 commit comments

Comments
 (0)