Edge 151のRust XMLパーサー移行とは?DOMParser・XHR・SVGの回帰テスト手順

Microsoft Edge 151では、XSLTを必要としないXML解析がRustベースのパーサーへ移行します。対象は主に、DOMParserXMLHttpRequest.responseXML、SVG文書の解析です。狙いは、XML解析で発生し得るメモリ破損系の脆弱性を減らし、ブラウザの安全性を高めることにあります。(Microsoft Learn)

Web APIの使い方を変更するアップデートではないため、多くのWebサイトではコード修正は不要です。ただし、名前空間を多用するXML、解析結果を文字列として比較する処理、大容量XML、外部SVGを利用しているシステムでは、Edge 151で回帰テストを行っておくと安心です。

日程Fit。無料・登録不要。「いつ空いてる?」を、ひとつのリンクで。リンクを送って、○△×でかんたん日程調整。無料で日程を作る。
目次

Edge 151のRust XMLパーサー移行で変わること

今回の変更は、新しいJavaScript APIを追加するものではありません。従来のXML解析処理を、メモリ安全性を重視したRust実装へ置き換える、ブラウザ内部の変更です。

項目Edge 151での扱い
DOMParserによるXML解析Rustベースのパーサーを使用
XMLHttpRequest.responseXMLRustベースのパーサーを使用
SVG文書のXML解析Rustベースのパーサーを使用
XSLTを必要とする処理今回の移行対象外
JavaScript APIの変更原則なし
Webサイト側の必須対応なし
管理ポリシーの設定原則不要
Microsoftの位置づけ情報提供

Chromium側でも、この変更は既存実装と機能的に同等であり、Webサイトから見える動作変更は想定されていません。試験段階で確認された互換性問題も修正され、残る互換性リスクは低いと評価されています。(Google グループ)

ただし、実装が変わる以上、すべての入力で解析結果が完全に同一になることを無条件に保証できるわけではありません。業務システムやXMLを中心に構築されたWebアプリでは、対象経路を特定して確認することが重要です。

Rust XMLパーサーの対象となる3つの経路

DOMParserでXML文字列を解析する処理

DOMParserは、文字列として受け取ったXMLをDOMへ変換するときに使われます。

const parser = new DOMParser();

const documentXml = parser.parseFromString(
  '<items><item id="1">Sample</item></items>',
  'application/xml'
);

const item = documentXml.querySelector('item');
console.log(item.textContent);

次のようなWebアプリでは、Edge 151の影響範囲に入ります。

  • APIから取得したXML文字列をDOMParserで解析している
  • ブラウザ内で設定ファイルやメタデータをXMLとして読み込んでいる
  • SVG文字列をimage/svg+xmlとして解析している
  • XMLの解析後にXPathや名前空間APIを使っている
  • 解析したDOMをXMLSerializerで再び文字列へ戻している

fetch()自体にはresponseXMLに相当する機能がありません。ただし、fetch()で取得した文字列をDOMParserへ渡している場合は、DOMParserの解析経路が今回の対象になります。

const xmlText = await fetch('/data/items.xml').then(
  response => response.text()
);

const xmlDocument = new DOMParser().parseFromString(
  xmlText,
  'application/xml'
);

XMLHttpRequest.responseXMLを使う処理

従来型のAjax処理や長期間運用されている業務システムでは、XMLHttpRequestresponseXMLが使われていることがあります。

const xhr = new XMLHttpRequest();

xhr.open('GET', '/data/items.xml', true);
xhr.responseType = 'document';

xhr.onload = () => {
  if (xhr.status < 200 || xhr.status >= 300) {
    console.error(`HTTPエラー: ${xhr.status}`);
    return;
  }

  const xmlDocument = xhr.responseXML;

  if (!xmlDocument) {
    console.error('XMLを解析できませんでした');
    return;
  }

  const items = xmlDocument.getElementsByTagName('item');
  console.log(items.length);
};

xhr.onerror = () => {
  console.error('通信に失敗しました');
};

xhr.send();

Edge 151では、responseXMLとして返すDocumentを構築するXML解析にRustベースのパーサーが使われます。

この経路では、パーサー変更だけでなく、次の条件も結果に影響します。

  • レスポンスのContent-Type
  • responseTypeの指定
  • XMLの文字コード
  • XML宣言と実際のエンコーディングの一致
  • CORSや認証の成否
  • XML自体が整形式であるか

responseXMLnullになった場合、すぐにRustパーサーの不具合と判断してはいけません。最初にネットワークタブでHTTPステータス、レスポンス本文、MIMEタイプを確認してください。

SVG文書のXML解析

SVGはXMLを基盤とする形式です。Edge 151では、SVG文書を解析する経路もRustベースのXMLパーサーへ移行します。Microsoftのリリースノートでは、SVG文書が明示的に対象として挙げられています。(Microsoft Learn)

特に確認したいのは、HTML内に直接記述した単純なインラインSVGよりも、次のような外部SVGです。

<img src="/assets/chart.svg" alt="グラフ">

<object
  data="/assets/map.svg"
  type="image/svg+xml">
</object>

このほか、次の利用方法も確認候補になります。

  • CSSのbackground-imageから読み込むSVG
  • SVGファイルをURLから直接開く処理
  • 外部SVGのシンボルを参照する処理
  • JavaScriptで取得したSVGをDOMとして加工する処理
  • グラデーション、フィルター、マスク、クリッピングを含むSVG
  • 名前空間を独自に定義したSVG
  • 外部フォントや画像を参照するSVG

SVGが表示されるかだけでなく、寸法、色、フィルター、参照画像、クリック領域まで確認してください。複雑なSVGでは、スクリーンショットを使ったビジュアルリグレッションテストが有効です。

XSLTは今回の移行対象ではない

Edge 151の変更で重要なのは、非XSLTのXML解析だけが対象である点です。

次のような処理は、今回のRust XMLパーサー移行と同一視しないでください。

  • XSLTProcessorを使った変換
  • XSLスタイルシートを適用する処理
  • xml-stylesheet処理命令を利用するXML
  • XMLからHTMLや別形式のXMLを生成するXSLT処理

今回の変更は、「Edge 151でXSLTがRust化された」という意味ではありません。また、この情報だけを根拠にXSLTが削除されたと判断することもできません。

コード調査では、非XSLT経路とXSLT経路を分けて整理します。

rg -n \
  "DOMParser|responseXML|XMLSerializer|XSLTProcessor|xml-stylesheet|\.svg" \
  src public tests

XSLTProcessorxml-stylesheetが見つかった箇所は、今回の対象外として別のテスト項目に分離すると、問題の切り分けがしやすくなります。

Rustへの移行で安全性が向上する理由

従来のChromium系ブラウザでは、XML解析の一部にC言語で実装されたライブラリが使われてきました。C言語では、メモリの確保や解放、ポインターの扱いに誤りがあると、解放済み領域へのアクセスやバッファー境界外へのアクセスなどにつながる可能性があります。

Rustは、所有権や型の仕組みによって、こうしたメモリ操作上の問題をコンパイル段階で防ぎやすい言語です。Edge 151の変更は、XML解析に由来するメモリ破損バグの一群を排除することを目的としています。(Google グループ)

ただし、Rustパーサーになったからといって、Webアプリ側のセキュリティ対策が不要になるわけではありません。

たとえば、XMLから取得した値を次のようにHTMLへ直接挿入するコードは、引き続き避ける必要があります。

resultElement.innerHTML = xmlDocument.querySelector('message').textContent;

単純なテキストを表示するだけなら、textContentを使います。

resultElement.textContent =
  xmlDocument.querySelector('message')?.textContent ?? '';

ブラウザ内部のメモリ安全性向上と、Webアプリによる入力検証・出力処理は別の問題です。

優先的に回帰テストすべきWebサイト

すべてのWebサイトで大規模なテストを行う必要はありません。次の基準で優先順位を付けると効率的です。

優先度該当するWebサイトやシステム
DOMParserresponseXMLを主要機能で使っている
名前空間、CDATA、XPath、XMLSerializerを多用している
複雑な外部SVGを画面や帳票に利用している
数MB以上のXMLをブラウザ上で解析している
単純な外部SVGアイコンや図を利用している
XMLを補助的な設定ファイルとして読み込んでいる
JSONのみを扱い、XML解析を行っていない
PNGやWebPなど、XMLではない画像だけを使っている

社内システムでは、古いAjaxライブラリや独自フレームワークの内部でresponseXMLが使われていることがあります。アプリケーションコードだけでなく、共通ライブラリや依存パッケージも検索してください。

DOMParserの回帰テスト手順

正常なXMLを解析する

名前空間、属性、CDATAを含むXMLをテストデータにすると、単純な要素だけを使うより広い範囲を確認できます。

const source = `<?xml version="1.0" encoding="UTF-8"?>
<catalog
  xmlns="urn:example:catalog"
  xmlns:meta="urn:example:meta">
  <item id="A001" meta:status="active"><![CDATA[A&B]]></item>
</catalog>`;

const documentXml = new DOMParser().parseFromString(
  source,
  'application/xml'
);

const parseError =
  documentXml.getElementsByTagName('parsererror')[0];

console.assert(!parseError, parseError?.textContent);

const item = documentXml.getElementsByTagNameNS(
  'urn:example:catalog',
  'item'
)[0];

console.assert(item?.textContent === 'A&B');
console.assert(item?.getAttribute('id') === 'A001');
console.assert(
  item?.getAttributeNS('urn:example:meta', 'status') === 'active'
);

最低限、次の結果を確認します。

  • パースエラーが発生しない
  • ルート要素を取得できる
  • 名前空間URIとローカル名が正しい
  • 属性値を取得できる
  • CDATAの内容が保持される
  • 日本語や絵文字が文字化けしない

不正なXMLもテストする

正常なXMLだけでは、エラー処理の回帰を見つけられません。

const invalidXml = '<items><item></items>';

const documentXml = new DOMParser().parseFromString(
  invalidXml,
  'application/xml'
);

const hasParseError =
  documentXml.getElementsByTagName('parsererror').length > 0;

console.assert(
  hasParseError,
  '不正なXMLがエラーとして検出されませんでした'
);

アプリ側がパースエラーを検出せず、そのままDOMを参照していると、ブラウザ更新後に画面が空になるだけで原因が分からないことがあります。エラー検出とログ出力を明示的に実装してください。

シリアライズは文字列の完全一致だけで判定しない

XMLをXMLSerializerで文字列化しているシステムでは、結果を元のXML文字列と完全一致させるテストに注意が必要です。

const serialized = new XMLSerializer().serializeToString(
  documentXml
);

XMLでは、次のような違いがあっても意味が同じ場合があります。

  • 名前空間宣言の位置
  • 不要な名前空間宣言の追加
  • 属性の表現方法
  • 空要素の表記
  • XML宣言の有無
  • 改行やインデント

Chromiumの検証過程でも、名前空間を含む文書を再シリアライズした際の表現差が検討されました。文書の意味には影響しない差であるため、テストでは文字列だけでなく、名前空間URI、要素名、属性値、テキスト内容を比較する方法が適しています。(Google グループ)

XMLHttpRequest.responseXMLの確認項目

responseXMLを使うシステムでは、実際のサーバー応答を使って次の項目を確認します。

  1. 正常なXMLでresponseXMLが取得できる
  2. 不正なXMLで期待どおりエラー処理される
  3. 日本語を含むXMLが文字化けしない
  4. 名前空間付き要素を取得できる
  5. 認証後のXMLレスポンスでも動作する
  6. キャッシュ利用時と未利用時の結果が同じ
  7. 大容量レスポンスでタイムアウトや画面停止が起きない

問題が発生した場合は、次の順序で切り分けます。

症状最初に確認する項目
responseXMLnullHTTPステータス、MIMEタイプ、XML構文
文字化けするHTTPヘッダー、XML宣言、実際の文字コード
要素を取得できないデフォルト名前空間、名前空間URI
一部の属性だけ取れない接頭辞ではなく名前空間URIで取得しているか
Edgeだけ通信に失敗するCORS、認証、証明書、CSP
大容量XMLだけ遅い通信時間と解析時間を分けて計測

SVGは表示結果を画像で比較する

SVGの回帰テストでは、DOMの検査だけでなく実際の描画結果を比較します。

確認用ページには、少なくとも次のパターンを用意してください。

<h2>img要素</h2>
<img src="/fixtures/complex.svg" alt="検証用SVG">

<h2>object要素</h2>
<object
  data="/fixtures/complex.svg"
  type="image/svg+xml">
</object>

<h2>CSS背景</h2>
<div class="svg-background"></div>
.svg-background {
  width: 320px;
  height: 180px;
  background-image: url("/fixtures/complex.svg");
  background-repeat: no-repeat;
  background-size: contain;
}

比較する内容は次のとおりです。

  • SVG全体が表示されるか
  • viewBoxに基づく拡大縮小が正しいか
  • グラデーションやフィルターが欠落していないか
  • マスクやクリッピングがずれていないか
  • テキストやフォントが正しく表示されるか
  • 外部画像や外部リソースが読み込まれるか
  • <use>で参照した図形が表示されるか
  • 直接URLを開いた場合も表示されるか

Edge 151だけでなく、更新前のEdgeでも同じページを表示し、同じ画面サイズと倍率でスクリーンショットを取得します。目視確認に加え、Playwrightなどを使った画像差分テストを組み込むと、わずかな描画差も検出できます。

大容量XMLでは処理時間も確認する

Rustへの移行目的は安全性向上であり、高速化ではありません。

Chromiumの事前検証では、XMLパーサー単体の処理時間に低下が確認された一方、主要な品質指標への影響は見られず、実際の処理時間は多くのケースで数十ミリ秒程度と報告されています。(Google グループ)

そのため、小さなXMLを扱う一般的なWebサイトで体感差が生じる可能性は低いものの、数MB以上のXMLを繰り返し解析するシステムでは実測が必要です。

const source = await fetch('/fixtures/large.xml').then(
  response => response.text()
);

const start = performance.now();

const documentXml = new DOMParser().parseFromString(
  source,
  'application/xml'
);

const elapsed = performance.now() - start;

console.log(`XML解析時間: ${elapsed.toFixed(2)}ms`);

const hasError =
  documentXml.getElementsByTagName('parsererror').length > 0;

console.assert(!hasError);

計測時は、次の条件をそろえます。

  • 同じPCと同じXMLを使う
  • 開発者ツールのCPUスロットリングを統一する
  • 初回だけでなく複数回実行する
  • 通信時間と解析時間を分ける
  • Edge更新前後の中央値を比較する
  • 実際の利用端末でも確認する

解析時間が業務に影響する場合は、XMLを小分けにする、サーバー側で必要部分だけ抽出する、JSONへ変換して配信するなど、ブラウザで解析するデータ量を減らす方法も検討します。

Edge 151移行時に起こりやすい誤解

RustになればXML入力を信頼してよい

Rust化されるのはブラウザ内部のパーサーです。XMLに含まれる値の正当性や、アプリ固有の権限、表示内容まで保証されるわけではありません。

入力値の検証、アクセス制御、出力時のエスケープは引き続き必要です。

すべてのXML処理がRustへ移行する

対象はXSLTを必要としない経路です。XSLT処理まで含めて一括で移行したわけではありません。

Edge 151を判定して処理を分岐すべき

Rust XMLパーサーはブラウザ内部の実装詳細です。Webページからパーサーの種類を判定してコードを分岐するのではなく、標準APIの結果を確認してください。

バージョン判定による回避コードを追加すると、将来のEdgeや他のChromium系ブラウザで保守負担が増えます。

XML文字列が完全一致しなければ不具合

名前空間宣言や空要素の表現が異なっても、DOMとして同じ意味を持つ場合があります。XMLの文字列だけでなく、要素、属性、名前空間、テキスト内容を比較してください。

SVGが表示されれば確認完了

静止状態で表示できても、拡大縮小、外部参照、フィルター、クリック操作などで問題が出る可能性があります。実際の利用場面を再現したテストが必要です。

管理者と開発者が取るべき対応

Edge 151のRust XMLパーサー移行は情報提供として扱われており、直ちに設定変更やコード修正を求めるものではありません。

一般利用者は特別な操作をする必要はありません。Webサイト管理者や企業のIT管理者は、次の順序で対応すると効率的です。

  1. ソースコードからDOMParserresponseXML、外部SVGの利用箇所を探す
  2. XSLTProcessorなどのXSLT経路を分離する
  3. 名前空間、不正XML、日本語、大容量XMLを含むテストデータを用意する
  4. Edge更新前後で同じ自動テストを実行する
  5. SVGはスクリーンショットでも比較する
  6. 問題がなければ通常どおりEdge 151を展開する
  7. 差異が出た場合は、通信、MIMEタイプ、文字コード、XML構文から順に切り分ける

Edge 151の変更は、Web開発者に新しいAPIへの書き換えを求めるものではなく、XML解析の内部実装をより安全なものへ置き換えるアップデートです。まずは、自社サイトやWebアプリがDOMParserXMLHttpRequest.responseXML、外部SVGを使っているかを確認してください。該当する場合は、名前空間、エラー処理、シリアライズ、大容量XML、SVG描画を中心に回帰テストを行えば、実務上必要な確認を過不足なく進められます。

この記事を書いた人

実務の現場で詰まりがちなポイントを地図にするITブログ「IT trip」を運営。Windows/Office(Teams・Excel)からSQL、サーバ運用、ガジェットまで、再現性のある手順と“なぜそうなるか”を丁寧に解説します。読んだらすぐ試せること、そして迷った人の次の一歩が見えることを大切にしています。

コメント

コメントする

目次