URLNormalizer The query is split on `;` as well as `&`, which rewrites URLs
メンテナーはふだん 1 日以内に返信
評価
この issue はまだ評価されていません。
説明
Summary
BasicURLNormalizer parses the query with HttpClient's URLEncodedUtils.parse(query, StandardCharsets.UTF_8). That overload treats both & and ; as parameter separators,
while the matching format(...) only ever writes &. A ; that a site uses as an ordinary
character inside a query is therefore read as the start of a new parameter and written back
as &, so the normalised URL asks the server for something different from the original.
This contradicts the current URL standard, which splits on & only — see
Standards below.
Reproduction
The query is only parsed when queryElementsToRemove is non-empty or removeHashes is
true, so:
BasicURLNormalizer normalizer = new BasicURLNormalizer();
normalizer.configure(
new HashMap<>(),
new ObjectMapper().readTree("{\"queryElementsToRemove\":[\"utm_source\"]}"));
String url = "http://a.example/search?q=a;b";
System.out.println(normalizer.filter(URLUtil.toURL(url), new Metadata(), url));
| input | actual | expected |
|---|---|---|
http://a.example/search?q=a;b |
http://a.example/search?b&q=a |
http://a.example/search?q=a;b |
http://a.example/p?a=1;b=2 |
http://a.example/p?a=1&b=2 |
unchanged |
http://a.example/books?dq=x+;&hl=fr |
http://a.example/books?dq=x+&hl=fr |
unchanged |
http://a.example/p?q=a%3Bb&z=1 |
http://a.example/p?q=a%3Bb&z=1 |
unchanged, correct |
The first row is the clearest: a search term a;b becomes two parameters, q=a and a bare
b. The third shows a value ending in ;, which produces an empty parameter that is then
dropped — the ; disappears from the value. An escaped %3B is safe, as it should be.
(The reordering in the first row comes from the unconditional sort in the same method, not
from this issue.)
Cause
URLEncodedUtils in HttpClient 4.5.14:
private static final char QP_SEP_A = '&';
private static final char QP_SEP_S = ';';
public static List<NameValuePair> parse(final String s, final Charset charset) {
...
return parse(buffer, charset, QP_SEP_A, QP_SEP_S); // ← both separators
}
public static List<NameValuePair> parse(final String s, final Charset charset,
final char... separators) { ... } // ← separators can be chosen
format(...) always joins with QP_SEP_A, which is what turns ; into & on the way out.
Standards
WHATWG is the Web Hypertext Application Technology Working Group, the body (Apple,
Google, Mozilla, Microsoft) that maintains the "living standards" browsers actually
implement — HTML, DOM, Fetch and the URL Standard among them. Its URL Standard is what
defines URL parsing for the web today, in place of the older RFCs.
- URL Standard,
application/x-www-form-urlencodedparsing:
the input is split on0x26 (&), and only on&.;has no special meaning. - RFC 3986 §3.4 lists
;as an
allowed character in a query but gives it no meaning: how a query is divided is left to
the server. - The
;convention comes from
HTML 4.01, appendix B.2.2
(1999), which recommended that servers accept;in place of&so that authors did
not have to write&in HTML attributes. It was a recommendation to server authors,
never a rule for URL parsers, and it is absent from the living standard.
Since a crawler has to ask the server for exactly what the link said, following the URL
Standard here seems the safer reading: a ; that the server treats as data should survive
normalisation.
Impact
Every affected URL is fetched with a different query than the one the link carried, which
can change or break the response. It also splits one page into two entries when the same
content is linked with and without the ; form, and defeats queryElementsToRemove in the
opposite direction: a parameter can appear or vanish depending on where a ; falls.
Suggested fix
Ask for & only — the overload already exists, so it is one argument:
List<NameValuePair> pairs = URLEncodedUtils.parse(query, StandardCharsets.UTF_8, '&');
If some crawls rely on the old behaviour, this could be a parameter
(querySeparators: "&;") defaulting to & alone.
- 主要言語
- Java
- スター
- 1k
- フォーク
- 295
- 平均マージ
- 1日 14時間
- マージ済み PR(30日)
- 62
環境構築
- Dockerfile・Docker Compose ファイルなし
- プルリクエストのテンプレートあり
- コントリビューションガイドを読む
はじめの一歩
- issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
- 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
- リポジトリをフォークし、ブランチを切って変更します。
- issue 番号を参照したプルリクエストを送ります。
apache/stormcrawler のほかの issue
-
Remove dependency on httpcomponents.core5対応中かも @rzo1 が今日担当しました。 オープンBREAKING CHANGE core
難易度 5/5 1週間以上 初心者へのやさしさ 15/100
apache/stormcrawler#2266 ·
メンテナーはふだん 1 日以内に返信
-
[Bug report] BasicURLNormalizer unmangleQueryString inserts a second `?` when a query value contains a `/`対応中かも @jnioche が 27 日前に担当しました。 オープンbug core
apache/stormcrawler#2198 · 担当者 1 名 ·
メンテナーはふだん 1 日以内に返信
-
難易度 3/5 1〜2日 初心者へのやさしさ 70/100
apache/stormcrawler#2131 ·
メンテナーはふだん 1 日以内に返信
-
[Improvement] Work towards Maven 4 Compatibility対応中かも @mvolikas が 352 日前に担当しました。 オープンgood first issue help wanted
apache/stormcrawler#1662 · コメント 2 件 · 担当者 1 名 ·
メンテナーはふだん 1 日以内に返信
-
Delete redirected pages再び着手できるかも @tomatotomata が 85 日前に担当しましたが、オープン中のプルリクエストはありません。 オープンcore good first issue
難易度 4/5 3〜5日 初心者へのやさしさ 48/100
apache/stormcrawler#994 · コメント 3 件 ·
メンテナーはふだん 1 日以内に返信
apache/stormcrawler の issue をすべて見る
似ている issue
-
[BUG] jackson3 JacksonJsonpMapper(ObjectMapper) fails to deserialize `_source` with "Trailing token" error対応中かも @junyeokk が今日担当しました。 オープンbug untriaged
難易度 2/5 1〜3時間 初心者へのやさしさ 82/100
opensearch-project/opensearch-java#2236 ·
メンテナーはふだん 1 日以内に返信
-
難易度 2/5 1〜3時間 初心者へのやさしさ 67/100
-
難易度 2/5 1〜3時間 初心者へのやさしさ 62/100
open-learning-exchange/myplanet#18392 ·
メンテナーはふだん 2 日以内に返信
-
難易度 2/5 1〜3時間 初心者へのやさしさ 76/100
linagora/twake-calendar-side-service#1218 · コメント 1 件 ·
メンテナーはふだん 1 日以内に返信
-
[Bug] [Go] Ack returns nil when the server answers with a non-OK status対応中かも @leizhiyuan が今日担当しました。 オープン
難易度 2/5 1〜3時間 初心者へのやさしさ 84/100
apache/rocketmq-clients#1465 ·
メンテナーはふだん 2 日以内に返信