2020-07-15に更新

続・ブラウザ(chrome)のデフォルトエンコードってUTF-8じゃないの?

かなり雑な考察ですのでご注意ください。

今は昔

かつてブラウザ(chrome)のデフォルトエンコードってUTF-8じゃないの?という記事を書いたのですが。
こちら、タイトルが疑問文であることからもわかる通り、単なる疑問を書き殴った記事で、解決していません。
ですが、私が書いた他の記事の3倍、4倍ものアクセスがあり、心苦しいというか、「なんだよ、結局わからなかったじゃねえかよ、XXX」みたいに思われてるんだろうなあ、みたいな被害妄想をする日々でして。
なので、もう少しだけ頑張ってみようと思います。

先に結論(推測)

  • もはやchromeにデフォルトエンコードというものはない。(たぶん)
  • 何もエンコードに関する指定がない場合に採用されるのは、自動判別の結果(の内のどれか)である。判別できなかったらデフォルトエンコードになる、みたいな挙動ではない。(おそらく)
  • ぶっちゃけ、ちゃんとWEBサイトを作っていれば直面しない問題なので、わかってもあまり意味はない

とりあえず

もぎゃさんの提示してくれたソースを読もうと思ったんですけど……。
なんだろう、これ。C++かな? 僕、C++やったことないんだよねえ……。
これを機に覚えるというのも手ですが、正直そこまでの気力も時間もないし、機というほどのものでもないし、いきなりこのコードを読むのは辛いので、エンジニアらしからぬ感じで調べていこうと思います。

とりあえず、ソースを落としてきます。
で、調べます。
状況としては、「UTF-8になって欲しいものがShift_JISになってしまっている」ということなので、Shift_JISでgrepかけます。
馬鹿みたいで、期待薄ですが、とりあえずかけます。
VSCodeとか駆使しても良いですが、C++の拡張とかよくわからないので原始的にいきます。

$ grep -Ir Shift_JIS .
./platform/text/TextEncodingDetector.cpp:    // a child frame in Shift_JIS and both frames do NOT specify the encoding
./wtf/text/TextCodecICU.cpp:    registrar("shift-jis", "Shift_JIS");

……お?
下のはshift-jisを正しくShift_JISにしている感じ? ちょっと関係なさそう。
では、上のを見てみますか。TextEncodingDetectorなんて、いかにもそれっぽいじゃないですか。見るとなんか、コメントっぽいですね。

    // If no match is found so far, just pick the top match.
    // This can happen, say, when a parent frame in EUC-JP refers to
    // a child frame in Shift_JIS and both frames do NOT specify the encoding
    // making us resort to auto-detection (when it IS turned on).
    if (!encoding && matchesCount > 0)
        encoding = ucsdet_getName(matches[0], &status);

とりあえずGoogle翻訳にかけます。
これまでに一致するものが見つからない場合は、一番上の一致を選択します。
これは、たとえばEUC-JPの親フレームが
Shift_JISの子フレームで、両方のフレームでエンコードが指定されていない
自動検出機能がオンになっている場合。

ふむふむ。たぶん、「一番上」ってのは

matches[0]

のことでしょう。では、matchesを入れてるのはというと、ちょい上に

const UCharsetMatch** matches = ucsdet_detectAll(detector, &matchesCount, &status);

おー。……なんでしょうucsdet_detectAllって?
grepかけても出てこないので、何かのライブラリかな?
ということでググります。

どうやらICUというもので、文字コード判定ができるもののようです。
なんかそれっぽい。
ただ、100%の精度ではないようで、複数の結果が返ってきたりすると。つまり、UTF-8だとかShift_JISだとかが配列になって返ってくるのかな。

で、

WTF::TextEncoding hintEncoding(hintEncodingName);
// (中略)
const char* matchEncoding = ucsdet_getName(matches[i], &status);
//(中略)
if (WTF::TextEncoding(matchEncoding) == hintEncoding) {
    encoding = hintEncodingName;
    break;
}

んー、hintEncodingは引数で受け取ったhintEncodingNameからゴニョゴニョした感じっぽい。
こいつ自身は/core/html/parser/TextResourceDecoder.cppから呼ばれてるっぽいな。

if (detectTextEncoding(data, len, m_hintEncoding, &detectedEncoding))
    setEncoding(detectedEncoding, EncodingFromContentSniffing);

それっぽい。

そろそろ限界

そろそろ雰囲気だけで読むのは限界です……。
何となく、metaタグやwebサーバーのレスポンスヘッダなどで指定されたエンコードと、ICUの判定結果を突合して一致したものをエンコードとしてるような気がする。
で、一致しなかった場合、ICUの判定結果の0番目を採用する感じかな。
これ以上は限界。

遊んでみる

こんなコードを書いてみます。で、いろんなエンコードで保存します。

<html>
    <head>
    </head>
    <body>
        てすと
        <p id="charset"></p>
    </body>
    <script type="text/javascript">
        document.getElementById('charset').innerText = document.characterSet
    </script>
</html>

UTF-8

image
たぶん、UTF-8もShift_JISも検出してるけど、Shift_JISの方が先って感じなのかな? アルファベット順かな?

Shift_JIS

image
なるほどそうなるよね

EUC

image
おっと? 一応表示されたけどGBKって何?
と思ったら簡体字用のエンコードなのね。まさかの中国語判定。

ちなみにutf-8のファイルをwebサーバー通さずにファイル表示すると

image
なんで?
きっとhintEncodingに何か入ってるんだろうけど……。確かに、ファイルを直で見れるので、Webサーバー通すより何かしらの情報はありそう。ただ、調べるにはちょっと力量の限界。

その他

前の記事のコメントで、apacheでは文字化けしてIISでは文字化けしなかったみたいなこと言いましたけど、改めて検証したらIISでもちゃんと?文字化けしました。(この調査結果だとそりゃそうなんですが)
たぶん、何か環境構築とか検証方法を間違えてたんだと思いますが……。
もちろん、nginxでも文字化けします。

まとめ

  • 結論としては最初に言った通り
  • 雑な考察なので信用に足るかは怪しい
  • わかる人は優しく教えてください
  • metaタグ等でエンコードはちゃんと設定しよう
ツイッターでシェア
みんなに共有、忘れないようにメモ

hammhiko

恥を晒して生きていきます。

Crieitは誰でも投稿できるサービスです。 是非記事の投稿をお願いします。どんな軽い内容でも投稿できます。

また、「こんな記事が読みたいけど見つからない!」という方は是非記事投稿リクエストボードへ!

有料記事を販売できるようになりました!

こじんまりと作業ログやメモ、進捗を書き残しておきたい方はボード機能をご利用ください。
ボードとは?

コメント