Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -338,7 +338,16 @@ public void execute(Tuple tuple) {
} else {
final Elements links = jsoupDoc.select("a[href]");
slinks = new HashMap<>(links.size());
final URL baseUrl = URLUtil.toURL(url);
// Resolve relative links against the document's base URI
// rather than its URL: when the page contains a <base href>
// element jsoup updates baseUri() accordingly, which is what
// browsers use to resolve relative hrefs. Falls back to the
// document URL when no (valid) <base> is present.
String baseUri = jsoupDoc.baseUri();
if (StringUtils.isBlank(baseUri)) {
baseUri = url;
}
final URL baseUrl = URLUtil.toURL(baseUri);
for (Element link : links) {
// nofollow
String[] relkeywords = link.attr("rel").split(" ");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -304,4 +304,37 @@ void testExecuteWithJavascriptLink() throws IOException {
Assertions.assertEquals(
"http://www.javascriptlinks.com/mylink", statusTuples.get(0).get(0));
}

/**
* Relative outlinks must be resolved against the document's {@code <base href>} element when
* one is present, matching browser behaviour, rather than against the document URL. Otherwise a
* page served from a sub-path with a base pointing at the domain root doubles the path segment.
*/
@Test
void testBaseHrefOutlinkResolution() throws IOException {
bolt.prepare(stormConf, TestUtil.getMockedTopologyContext(), new OutputCollector(output));

String html =
"<html><head>"
+ "<base href=\"https://www.example.be/\">"
+ "</head><body>"
+ "<a href=\"fr/rayons/stockage-archivage-de-donnees/218725\">Stockage</a>"
+ "</body></html>";

Metadata metadata = new Metadata();
metadata.setValue("Content-Type", "text/html; charset=UTF-8");
parse(
"https://www.example.be/fr/rayons/actualites-reportages/216943",
html.getBytes(StandardCharsets.UTF_8),
metadata);

List<List<Object>> statusTuples = output.getEmitted(Constants.StatusStreamName);
Assertions.assertEquals(1, statusTuples.size());
Assertions.assertEquals(Status.DISCOVERED, statusTuples.get(0).get(2));
// resolved against the <base href> (domain root), NOT against the document path,
// which would have produced .../actualites-reportages/fr/rayons/stockage-...
Assertions.assertEquals(
"https://www.example.be/fr/rayons/stockage-archivage-de-donnees/218725",
statusTuples.get(0).get(0));
}
}
Loading