DataSnap バイト ストリームのフィルタリング
DataSnap クライアントと DataSnap サーバーの間の通信は、一連のフィルタでインターセプトすることができます。 各フィルタは、バイト ストリームに対して暗号化や圧縮などの変換を行うことができ、バイト ストリームは、1 つ以上のフィルタでインターセプトすることができます(1 つのフィルタの出力が次のフィルタの入力となります)。 Datasnap.DSTCPServerTransport.TDSTCPServerTransport などの DataSnap サーバー トランスポート コンポーネントの[Filters]プロパティを設定することで、設計時に(またはコードで)フィルタをバイト ストリームに付加することができます。
設計時に利用するには、RAD Studio に登録されたパッケージにフィルタが含まれていなければなりません。 フィルタをパッケージに組み込み、そのパッケージを Delphi にインストールする必要があります。 サーバー側の設計時サポートでは、フィルタ リスト エディタにフィルタを表示することができます。 クライアント側の設計時サポートでは、TSQLConnection を使って設計時の接続を行うことができます。
フィルタはクライアントとサーバーの間のハンドシェイク プロトコルに基づいて自動的にインスタンス化されるため、クライアント側でフィルタを関連付ける必要はありません。 そのため、クライアント コードでは、フィルタ付きのサーバーに接続する前に(ユニット名を uses 句に追加するか、初期化時など早い段階で)フィルタを登録することが重要です。
メモ: [データ エクスプローラ] は、ネイティブ コード フィルタでサーバーに接続することができません。これは、DataExplorer が管理対象クライアントを使用しているためです。
メモ: このチュートリアルを理解する助けとして、ビデオ:『Delphi ラボ - エピソード 3』(Paweł Głowacki 解説)もご覧ください。
フィルタの定義
フィルタはいずれも、TTransportFilter クラスを拡張し、実装では、最低限、自分自身を一意に識別する ID と、2 つのメソッド ProcessInput と ProcessOutput を用意する必要があります。
public
function ProcessInput(const Data: TBytes): TBytes; override;
function ProcessOutput(const Data: TBytes): TBytes; override;
function Id: UnicodeString; override;
この 2 つのメソッドは互いの逆の処理をします。つまり、1 つのメソッドの結果をもう 1 つのメソッドに入力として渡すと、その結果は最初の入力になります。
接続ごとに 1 つのフィルタがインスタンス化されるため、これらの関数をスレッド セーフにする必要はありません。インスタンスではローカル変数を利用できますが、このローカル変数はインスタンスのステートフルの状態とは見なされません。
パラメータを取らないデフォルトのコンストラクタを使って、フィルタ インスタンスをインスタンス化します。 クライアント インスタンスとサーバー インスタンスの互換性を保つために、パラメータを追加しなければならない場合もあります。 パラメータ値は、サーバー側のフィルタとクライアント側のフィルタの間で交換することができます。 たとえば、対称鍵暗号のフィルタを実装するために、暗号化キーの場所を渡さなければならないときには、これが必要になります。
すべてのパラメータは名前と文字列の組み合わせとして公開されます。 名前は GetParameters メソッドで取得することができ、値は GetParameterValue や SetParameterValue で問い合わせたり変更することができます。
protected
function GetParameters: TDBXStringArray; override;
public
function GetParameterValue(const ParamName: UnicodeString): UnicodeString; override;
function SetParameterValue(const ParamName: UnicodeString; const ParamValue: UnicodeString): Boolean; override;
設計時にすべてまたは一部のパラメータを変更しなければならない場合には、GetUserParameters メソッドでその名前を取得することができます。
protected
function GetUserParameters: TDBXStringArray; override;
メモ: このメソッドで返されないパラメータ名は、設計時に表示したり編集することができません。
フィルタの登録
フィルタは、TTransportFilterFactory シングルトンを使用して登録する必要があります。フィルタの登録は、ユニットの初期化部(initialization)と終了処理部(finalization)で行うことをお勧めしますが、ユーザーのアプリケーションの初期化段階でコーディングすることも可能です。
付属の圧縮フィルタを登録するためのコードを以下に示します。
initialization
TTransportFilterFactory.RegisterFilter(TTransportCompressionFilter);
finalization
TTransportFilterFactory.UnregisterFilter(TTransportCompressionFilter);
暗号化フィルタ
暗号化フィルタは、DataSnap バイト ストリームを暗号化するために使用します。 暗号化フィルタは、クライアント側だけでなくサーバー側でも動作します。 以下に、暗号化フィルタの動作を示します。
サーバー側:
- Datasnap.DSTCPServerTransport.TDSTCPServerTransport と Datasnap.DSHTTP.TDSHTTPService コンポーネントは、共に、Filters プロパティを持っています。
- このフィルタ プロパティを選択すると、表示されるダイアログで新規フィルタを追加できます。 [FilterId]プロパティでは、[PC1]または[RSA]を選択できます。
- [PC1]暗号化フィルタを使用する場合、[Properties]プロパティには、暗号化に使用する[Key]値が保持されます。 [RSA]フィルタを使用する場合は、[Properties]プロパティには、[UseGlobalKey]、[KeyLength]、[KeyExponent]という 3 つのプロパティのリストが保持されます。
クライアント側:
- TSQLConnection の Driver プロパティが、Filters プロパティを持っています。
このようにして、実際にクライアントとサーバーを実行すると、それらの間の通信が暗号化されます。
補足情報
DataSnap クライアント/サーバー アプリケーションで暗号化フィルタを使用している場合は、以下のことを考慮する必要があります。
- シン クライアントではデータの暗号化は利用できません。
- サーバーが暗号化フィルタを持っていて、クライアントがそれを持っていない場合、クライアントは自動的に暗号化フィルタを追加します。
- クライアントが暗号化フィルタを持っていて、サーバーがそれを持っていない場合、クライアントは暗号化フィルタを無効にしてそれを使用しません。
圧縮フィルタ
圧縮フィルタは ZLib をベースにしたもので、DataSnap バイト ストリームの圧縮機能を提供します。 圧縮フィルタはサーバー側とクライアント側の双方で機能します。
Datasnap.DSTCPServerTransport.TDSTCPServerTransport と Datasnap.DSHTTP.TDSHTTPService コンポーネントが共に、Filters プロパティを持っています。ここに新しいフィルタを追加し、その[FilterId]プロパティを[ZLibCompression]に設定します。 また、[Properties]プロパティを設定することで、圧縮フィルタのプロパティを指定することもできます。