Share via


DIME/WS-Attachments 入門

Matt Powell
Microsoft Corporation

October 2002

記事の対象:
   Web サービス仕様(DIME、WS-Attachments)

概要: 本記事では、(ファイルなどの)添付の必要性、特にパッケージ化とメッセージの境界に関連する諸問題を解説し、DIME と WS-Attachments が作成された理由を概観します。

目次

はじめに
SOAP メッセージと添付ファイル
DIME か MIME か
まとめ

はじめに

XML は、データやデータ同士の関係の表現、それにデータに対する操作を行うための業界標準を確立しました。今や、ほぼすべてのプラットフォームにおいて何らかの XML サポートが提供されています。SOAP と Web サービスが受け入れられた大きな理由の 1 つは、XML が業界横断的に受け入れられており、相互運用性が現実のものになっていたからです。しかし、XML ではないデータを Web サービスに送信したほうがよいケースもたくさんあります。例えば、JPEG 画像のようなバイナリデータを SOAP メッセージと一緒に送信できたら便利でしょう。単純に、別々のデータを一緒にパッケージ化できるだけでも便利かもしれません。例えば、ある SOAP メッセージが別の SOAP メッセージを含んでいるような形態です。電子メールに別の電子メールが添付されているのをよく見かけますが、そのようなイメージです。Direct Internet Message Encapsulation (DIME) 仕様は、データのかたまりをまとめてパッケージ化するメカニズムを提供します。WS-Attachments は DIME を利用して SOAP メッセージにファイルを添付し、それを DIME パッケージの構成情報から参照できるようにする方法を規定します。

この記事では、(ファイルなどの) 添付の必要性、特にパッケージ化とメッセージの境界に関連する諸問題を解説し、DIME と WS-Attachments が作成された理由を概観します。

SOAP メッセージと添付ファイル

ビジネスの世界では、電子メールが常識になる前は備忘録やメモが使われていました。さまざまな人の手に渡ることが想定されていたため、メモはきちんと構造化されていました。メモにはあて先、送り主、件名が書かれたヘッダーがあり、メッセージの本文があり、添付資料のリストがフッターに書かれており、ヘッダーと本文とフッターは区分けされていました。添付資料は、さまざまな理由で本文に含めることができなかった付加情報です。別の人が作成したレポートや、請求書や他の文書のコピー、あるいは他のメモなども添付されていることがありました。これらが添付資料と呼ばれているのは、ホチキスやクリップなどを使って文字通りメモに貼り付けられていたからです。

メモについている添付資料のリストは、メモ本体に書いてあります。資料そのものがメモに物理的に添付されているのに、なぜリストが必要なのか疑問に思うでしょうか。メモをめくって、何がついているか読んでみればいいだけなのでは。しかし、考えてみてください。資料が付いていなければめくりようがありません。メモが送られてくる間に落ちているかもしれないし、コピーするときに付け忘れられているかもしれません。リストがあれば、文書を受け取ったときに資料が欠けていることがわかります。添付資料がなくなることを防ぐメカニズムの1つとして、メモと添付資料を社内メールの封筒にまとめて入れる方法があります。送る情報をすべてパッケージ化する手間をかけることで、すべての情報が受け取り側に確実に届くという安心感が一段と向上します。受け取り側にしても、メモで参照されているレポートが同じ社内メール封筒に入っていれば、それがメモを書いた人が参照したのと同じ版の資料であるという安心感が生まれます。レポートが参照されていながら、メモと一緒に入っていなかった場合、レポートはどこにあるのか、みつかったとしてもそのレポートがメモで参照されているのと同じ正しいレポートであるのかという疑問が必然的に浮かぶことになるわけです。

Web サービスの時代になっても、メッセージに付加的な情報を添付できることが必要です。SOAP メッセージに付加的な情報を添付したい理由はいくつかあります。まず、SOAP メッセージから他の SOAP メッセージを参照するというシナリオがすぐに思い浮かびます。ちょうどメモが他のメモを参照できるのと同じです。もっとも、紙のメモをハードコピーするのとは違い、XML のようにあらゆる場所でサポートされている形式で記述されているデジタルデータであれば、あるXML文書の内部を拡張してその中に埋め込むことも可能です。しかし、元の SOAP メッセージに付加的な情報を埋め込みたくない場合もあるでしょう。例えば、XML化すると冗長になってしまう形式のデータ (マルチメディア・ファイルなど) であれば、それを SOAP メッセージに含めるのは非効率です。XML のデータであっても、元の文書に含めるためにはエンコードとデコードを行わなければならない場合もあります。SOAP メッセージに付加情報を添付できるようにするという考え方は合理的なのです。

SOAP メッセージには、社内メールの封筒のように、メモと添付資料を一緒にパッケージ化する機能も求められます。SOAP メッセージの場合も、転送途中で付加情報が欠けてしまったり、変更されてしまったりする可能性があるからです。例えば、SOAP メッセージから XML 文書を URL で参照していた場合、SOAP メッセージが作成されてから受信者が受信するまでの間に、そのXML文書が変わってしまったらどうなるでしょうか。XML 文書を SOAP メッセージとともにパッケージ化する機能も、添付ファイルのアーキテクチャには必須なのです。

DIME: SOAP メッセージと添付ファイルのパッケージ化

SOAP メッセージと添付ファイルをパッケージ化する方法はたくさんあります。インターネットのようなストリーミング環境では、パッケージ化システムは複数の部品を単一のストリームで配信するメカニズムを持っている必要があります。そうなっていれば、パッケージを TCP や HTTP、SMTP などの今日よく利用されているプロトコルを使って転送できます。どんな場合でも、パッケージ化を行うシステムにはパッケージの1部分が終了して次の部分が始まる点を識別する機能と、パッケージ全体の送信が完了したことを示すメカニズムが必要とされます。

大量のデータを扱うアプリケーションにとっては、データを小さく分割して扱う機能があれば便利でしょう。そのほうが、大量のデータをすべて一度にメモリに読み込まなくても済みます。このような機能を 「チャンク化」 と呼びます。チャンク化ができれば、受信側にとってもメモリの扱いが楽になるというメリットがあります。

ストリーム配信されるパッケージを受け取るアプリケーションにとっては、パッケージに含まれているパーツを識別できる機能も必要です。紙ベースのメモの場合は、添付資料の著者を参照することでメモから資料を指すことができます。ですが、これでは同じ著者が書いた資料が2つ添付されている場合に問題になります。もちろんこの問題は著者と日付、場合によってはタイトルまで参照すれば解決できます。ですが、写真のようにヘッダー情報を持たない資料だったらどうすればいいのでしょう。アプリケーションからすると、パッケージの中の各々のパーツを確実に識別できるメカニズムが必要です。各パーツのデータ種別が分かればもっといいでしょう。

パッケージ化メカニズムが持つこれらの機能は、SOAP メッセージと添付ファイルを処理するアプリケーションにとっては基本機能です。Direct Internet Message Encapsulation (DIME) 仕様はこれらの機能を最小限の労力で効率よくサポートしています。

DIME パッケージ

DIME は、任意の形式のデータからなる複数のレコードをまとめてストリーム化するメカニズムです。レコードは順々にストリームにシリアライズされ、効率よくバイナリのヘッダーで区分けされます。DIME メッセージの最初のレコードには、ヘッダーに MB (Message Begin) フラグが立っており、最後のレコードにはME(Message End)フラグが立っています。ヘッダーにはレコードの長さを示す固定長のデータを記述できます。レコードの長さを効率よく調べられると、データストリームの中でレコードから次のレコードにすばやく移動できるため、この機能はとても重要です。

あらかじめサイズがわからない大きなレコードをサポートするために、DIME には 「レコード・チャンク」 が定義されています。レコード・チャンクは、単一のレコードを小分けするために使われます。

1 つ 1 つのレコード・チャンクには、通常のレコードと同じようにヘッダーとペイロードがあります。レコード・チャンクのヘッダーには CF (Chunk Flag) が立っています。これによって、データが小分けされたレコードの一部であり、まだ続きがあることが分かります。レコード・チャンクのデータは順番に読み取られていきます。CF フラグが立っていないレコードに到達すると、レコード・チャンクが終了したことになります。図 1 の DIME メッセージには 5 つのレコードが含まれています。後の 3 つのレコードはレコード・チャンクで、単一のレコードが小分けされています。

Cc964046.dimewsattch01(ja-jp,MSDN.10).gif

図 1 レコード・チャンクを含む DIME メッセージ

レコード長やフラグのほかに、DIME レコードのヘッダーには利用されている DIME のバージョン、レコードのデータ形式、レコードの識別子 (ID)、その他のレコードが必要とする情報が記述されます。データ形式、ID、追加情報、レコードのペイロードはすべて可変長です。そのため、バージョン、フラグ、可変長の 4 つのパーツそれぞれの長さの全部で 3 つの情報は、レコード・ヘッダーの最初の部分に固定長で記述されています。レコードの先頭が分かれば、次のレコードの先頭はヘッダーの固定長部の長さ(12 バイト)に、固定長部に記述されている可変長データのそれぞれの長さを足せば、すぐに割り出すことできます。

Cc964046.dimewsattch02(ja-jp,MSDN.10).gif

図 2 DIME のデータレコード形式

DIME には、DIME レコードの内容には制限が一切ないという優れた特徴があります。DIME レコードのペイロードに他の DIME メッセージを含むこともできます。外側のレコードは、単にレコードのデータ形式を 「application/dime」 と記述するだけです。

DIME メッセージの詳しい形式については、MSDN Magazine の 2002 年 12 月号 (米国版) に掲載されている、Jeanine Hall Gailey の 「An Introduction to DIME」 を参照してください。

WS-Attachments: DIME を使って SOAP メッセージと添付ファイルを実現する

DIME 自体は任意の形式のデータをパッケージ化するメカニズムでしかありません。レコードのペイロードに関する制限はありませんし、ID 部に指定する値や SOAP メッセージを DIME メッセージに含める方法も指定されていません。WS-Attachments は、前述したメモと添付資料のアイデアを実現するために、複数の文書をまとめる方法、文書がお互いを参照しあう方法、Web サービスで利用するために DIME のパッケージ化機能を利用する方法を定義しています。

SOAP メッセージに添付ファイルを付けるためにまず必要なのは、どれが SOAP メッセージでどれが添付ファイルなのかを区別できるようにすることです。紙のメモをクリップでまとめた場合、どれがメインのメモなのかはすぐに分かります。メインのメモは一番上にあるもので、最後に添付資料の一覧が記述されています。SOAP メッセージに添付資料を付ける場合には、メインのメッセージを 「プライマリ SOAP メッセージ部」 と呼びます。その他の添付文書はすべて 「セカンダリ部」 と呼びます。WS-Attachments では、プライマリ SOAP メッセージ部は DIME メッセージの先頭レコードでなくてはならないと決められています。メモが一番上にあるのと同じです。

次に必要とされるのは、プライマリ SOAP メッセージ部の中から添付ファイルを参照する機能です。メモがホチキス止めされた文書を参照するように、SOAP メッセージも添付ファイルを参照する必要があります。WS-Attachments では、参照を行うために href 属性の使い方を定義しています。href 属性の値は URI です。URI なので、HTTP の URL を指すこともできます。ですが、WS-Attachments では、特定の DIME レコードのヘッダーに記述されている ID を参照することもできるようになっています。DIME メッセージのあるセカンダリ部の ID が次のものだった場合、

uuid:6FF57C24-74A1-426f-92D9-98861E105B4F

プライマリ SOAP メッセージは次のようにして添付ファイルを参照できます。

<?xml version='1.0' ?> 
<s:Envelope 
    xmlns:s="https://schemas.xmlsoap.org/soap/envelope/" 
    xmlns:mes="http://example.org/message/response"> 
  <s:Body> 
    <mes:responseMesssage>
      <responseTo 
          href="uuid:6FF57C24-74A1-426f-92D9-98861E105B4F"/> 
      <messageText>Hello World!</messageText>
    </mes:responseMessage>
  </s:Body> 
</s:Envelope>

メッセージの本文にある responseTo 要素に、DIME レコードの ID を指す href 属性が指定されています。おそらく、DIME レコードのデータは他の SOAP メッセージで、この SOAP メッセージはそれへの返信なのでしょう。この DIME メッセージの受信者はプライマリ SOAP メッセージ部が返信しているメッセージを探し回る必要はありません。DIME メッセージのセカンダリ部に含まれているからです。

ここではプライマリ SOAP メッセージ部からセカンダリ部を参照していますが、2 つのセカンダリ部がお互いを参照したり、セカンダリ部がプライマリ SOAP メッセージ部を参照したりすることもできることに注意してください。

WS-Attachments には、DIME でまとめられた SOAP メッセージを HTTP で送信する方法も定義されています。プライマリ SOAP メッセージ部だけを単純に送信するのとほとんど変わりませんが、HTTP の Content-Type ヘッダーには 「application/dime」 を指定し、HTTP の本文として SOAP メッセージの代わりに DIME メッセージを送信します。

DIME か MIME か

DIME 以外にも、複数のデータをパッケージ化する一般的なメカニズムがあります。Multipurpose Internet Mail Extensions (MIME) 仕様の、特に MIME マルチパート仕様です。MIME マルチパートは様々な目的で利用されていますが、最も一般的な用途は電子メールメッセージへの添付機能です。上述したメモと添付資料の話は、電子メールにファイルを添付する場合にも当てはまることは明白です。DIME が解決しようとしている問題は、MIME でも解決できるでしょう。実際に、SOAPメッセージに添付ファイルをつけるために MIME マルチパートを利用する 「SOAP with Attachments」 仕様が、以前に提出されています。Microsoft もこの仕様に協力しました。それならどうして DIME が作られたのでしょうか。

最初に MIME マルチパートと DIME の重要な違いを抑えておきましょう。DIME と同様に、MIME マルチパートにも複数の 「データレコード」 が含まれています。それぞれのレコードにはヘッダーとペイロードがあります。次のヘッダーの始まりを示すために、MIME マルチパートではセパレータ文字列を利用し、データ長は利用しません。セパレータ文字列は MIME メッセージの最初に指定され、それ以降のデータレコードの区切り部分に挿入されます。MIME メッセージを解析するコードはただデータを読み続け、セパレータ文字列を発見して始めて、次のレコードが始まったということが分かるのです。

MIME マルチパートの方式は、データを MIME メッセージのストリームに変換する送信者にとって効率的になるように設計されています。送信者は送信前にデータのサイズを知っておく必要はありません。単にデータを送信し続けて、データが終わったらセパレータ文字列を追加すればいいのです。

この方式の問題点は、受信側で効率が悪いことです。データレコードを受信しても、データレコードのサイズは分かりません。受信バッファを確保するためには、サイズを予想しなければなりません。同時に、予想を超えたデータが到着した場合にも備えておく必要があります。しかし、バッファを確保しなおしても、それで収まるかどうかはわからないのです。

これに関係する問題として、データレコードの境界を簡単には発見できないことがあります。例えば、あるメッセージを読み取っているアプリケーションにとって、次の 3 つのデータレコードは不要かもしれません。しかし MIME 方式では、不要な 3 つのデータレコードもすべて読み取る必要があります。不要なデータの全バイトを逐一読み取りながらセパレータ文字列を探す作業は、DIME の方式に比べるとはるかに非効率で無駄な作業です。DIME ならレコードのヘッダーにデータ長が埋め込まれているので、レコードからレコードへと直接移動することができます。

もちろん、バッファサイズやセパレータ文字列の探索問題は、MIME ベースで解決できます。MIME では、データレコードのヘッダーの利用方法はかなり柔軟です。MIME データレコードに Content-Length ヘッダーを付けて問題を解決している例も多数見られます。ですが、ここでも問題があります。データレコードのデータ長が分かっているのに、なぜセパレータ文字列が必要なのでしょうか。Content-Length ヘッダーをデータレコードに付加することを強制してしまうと、データが終わるまで送信し続けるだけでいいという、MIME データの送信者が持っている柔軟性が失われてしまうのです。データレコードを送信する前にデータ長を把握しておかなくてはならなくなります。

送信前にデータのサイズを知らなければならないという問題も、もちろん解決可能です。DIME がチャンク化をサポートしているように、MIME マルチパートにもデータをチャンク化するソリューションを作成して、問題を解決できるでしょう。しかし、ここでは私たちが考えた解決法を説明します。

基本的に、私たちは MIME マルチパートに関して次のような結論に達しました。

  1. データレコードにはデータ長が含まれなければならない。
  2. データ長が含まれるなら、セパレータ文字列は必要ない。
  3. データ長がわからない場合のために、チャンクのメカニズムが必要である。

MIME マルチパートのフレームワークの範囲内でこれらの問題をすべて解決することを考えるくらいなら、もっと単純な解決策がないかどうか考えてみるのもそれほど飛躍しすぎではないでしょう。DIME のレコード・ヘッダーの固定長部分の解析や、DIME メッセージのレコード間を行き来する簡単さを考えると、DIME の方式のほうが魅力的に見えても不思議ではないでしょう。

Web サービスにとって、単純さは決定的に重要です。Web サービスの魅力と人気は、相互運用性に負うところが非常に大きいといえます。相互運用を成功させるために重要なのは単純さです。書くのが簡単で設計が単純なコードであれば、複数のプラットフォームで簡単に再作成できます。パッケージの形式が単純で、複雑な解析ルールや解釈の揺らぎの余地がなければ、Windows プラットフォームと Unix プラットフォームの両方で送受信ができるはずです。単純さを図る尺度としては、それを実装するために必要なコードの行数があります。DIME ソリューションを実装するために必要なロジックと、MIME マルチパートソリューションのそれとを比べてみてください。MIME マルチパートでは送信されるデータには含まれないであろう文字列を選んでセパレータ文字列にするための特殊なロジックが必要です。データを逐次探索してセパレータ文字列を探すロジックも必要です。文字列比較を行いながら、可変長の値を持つ可変個のヘッダーを解析するロジックも必要です。DIME レコードを作成したり解析したりする上でもっとも複雑なのは、おそらくデータレコードのヘッダーにある固定長部分に指定されている数値の、バイトオーダーの処理でしょう。複雑さが少ないほどバグも少なくなり、解釈が揺らぐ余地も少なくなります。結果として、相互運用が簡単になるのです。

まとめ

DIME と WS-Attachments によって、SOAP メッセージと添付ファイルをパッケージ化する、単純で効率的なソリューションが得られます。これによって SOAP メッセージにあらゆる形式のデータを含められるようになるので、JPEG イメージや電子署名された文書、他の SOAP メッセージや他の DIME パッケージであっても、メインの SOAP メッセージと一緒にまとめて受信することが可能になります。また、パッケージ内部の SOAP メッセージから添付されたデータを参照するメカニズムも提供されています。今や多くの Web サービス・ツールキットが DIME と WS-Attachments をサポートしていますし、その数は今後も増えていくことが予想されます。SOAP メッセージに添付ファイルを含めるということは、Web サービスの機能として、またあらゆるプラットフォーム上で Web サービスを利用する人々にとって標準的なアイデアになっていくでしょう。