Skip to main content

atmos/os_lib/web_engine/
referrer.rs

1//! 参照元(`Referer` ヘッダ・`document.referrer`)の値を決める。
2//!
3//! ブラウザ既定の参照元ポリシー `strict-origin-when-cross-origin`(Referrer Policy 仕様):
4//! - 同一 origin への要求: 参照元ページの完全な URL(フラグメントは除く)
5//! - 別 origin への要求: 参照元ページの origin(`scheme://host[:port]/`)だけ
6//! - HTTPS のページから HTTP への要求(格下げ): 送らない
7//!
8//! 【2026-10-17】YouTube の埋め込み(`/embed/ID`)は、埋め込み元ページの `Referer` が無いと
9//! 「動画プレーヤーの設定エラー」(エラー 153)を返す。iframe の文書を読み込むときに、
10//! 実ブラウザと同じくこの値を送る。URL を直接入力した読み込みには参照元が無いので送らない。
11
12use alloc::format;
13use alloc::string::String;
14
15/// 参照元ページ(`from_*`)から `to_is_https`/`to_host` への要求に付ける `Referer` の値。
16///
17/// `from_host` が空(参照元ページが無い)なら None。`from_path` はパス・クエリ
18/// (`#` 以降は捨てる)。ホストはポート付きのまま比べる(origin はポートを含む)。
19pub fn referrer_for(
20    from_is_https: bool,
21    from_host: &str,
22    from_path: &str,
23    to_is_https: bool,
24    to_host: &str,
25) -> Option<String> {
26    if from_host.is_empty() {
27        return None;
28    }
29    if from_is_https && !to_is_https {
30        return None;
31    }
32    let scheme = if from_is_https { "https" } else { "http" };
33    let same_origin = from_is_https == to_is_https && from_host.eq_ignore_ascii_case(to_host);
34    if same_origin {
35        let path = from_path.split('#').next().unwrap_or("");
36        let path = if path.starts_with('/') { String::from(path) } else { format!("/{}", path) };
37        Some(format!("{}://{}{}", scheme, from_host, path))
38    } else {
39        Some(format!("{}://{}/", scheme, from_host))
40    }
41}