# 21.27. `xmlrpc.server` --- 基本的なXML-RPCサーバー

ソースコード: Lib/xmlrpc/server.py

`xmlrpc.server` モジュールはPythonで記述された基本的なXML-RPC サーバーフレームワークを提供します。サーバーはスタンドアロンであるか、 `SimpleXMLRPCServer` を使うか、 `CGIXMLRPCRequestHandler` を使って CGI 環境に組み込まれるかの、いずれかです。

警告

`xmlrpc.server` モジュールは悪意を持って構築されたデータに対して安全ではありません。信頼できないデータや認証されていないデータを解析する必要がある場合は、 XML の脆弱性 を参照してください。

class `xmlrpc.server.``SimpleXMLRPCServer`(addr, requestHandler=SimpleXMLRPCRequestHandler, logRequests=True, allow_none=False, encoding=None, bind_and_activate=True, use_builtin_types=False)

  サーバーインスタンスを新たに作成します。 このクラスは XML-RPC プロトコルで呼ばれる関数の登録のためのメソッドを提供します。 引数 requestHandler にはリクエストハンドラーインスタンスのファクトリーを設定します。 デフォルトは `SimpleXMLRPCRequestHandler` です。 引数 addr と requestHandler は `socketserver.TCPServer` のコンストラクターに渡されます。 logRequests が真の場合 (デフォルト)、 リクエストはログに記録されます。 この引数を偽にするとはログは記録されません。 引数 allow_none と encoding は `xmlrpc.client` に渡され、サーバーが返す XML-RPC 応答を制御します。 bind_and_activate 引数はコンストラクタが直ちに `server_bind()` と `server_activate()` を呼ぶかどうかを制御します。デフォルトでは真です。 この引数に `False` を設定することで、アドレスを束縛する前に allow_reuse_address クラス変数を操作することが出来ます。 use_builtin_types 引数は `loads()` 関数に渡されます。 この引数は日付/時刻の値やバイナリデータを受け取ったときにどの型が処理されるかを制御します。デフォルトでは偽です。

  バージョン 3.3 で変更: use_builtin_types フラグが追加されました。

class `xmlrpc.server.``CGIXMLRPCRequestHandler`(allow_none=False, encoding=None, use_builtin_types=False)

  CGI 環境における XML-RPC リクエストハンドラーを新たに作成します。 引数 allow_none と encoding は `xmlrpc.client` に渡され、サーバーが返す XML-RPC 応答を制御します。 use_builtin_types 引数は `loads()` 関数に渡されます。 この引数は日付/時刻の値やバイナリデータを受け取ったときにどの型が処理されるかを制御します。デフォルトは偽です。

  バージョン 3.3 で変更: use_builtin_types フラグが追加されました。

class `xmlrpc.server.``SimpleXMLRPCRequestHandler`

  リクエストハンドラーインスタンスを新たに作成します。このリクエストハンドラーは `POST` リクエストをサポートし、 `SimpleXMLRPCServer` コンストラクターの引数 logRequests に従ってログ出力を行います。

## 21.27.1. SimpleXMLRPCServer オブジェクト

`SimpleXMLRPCServer` クラスは `socketserver.TCPServer` のサブクラスで、基本的なスタンドアロンの XML-RPC サーバーを作成する手段を提供します。

`SimpleXMLRPCServer.``register_function`(function, name=None)

  XML-RPC リクエストに応じる関数を登録します。引数 name が与えられた場合はそれが関数 function に関連付けられます。 そうでない場合は `function.__name__` の値が用いられます。 name は通常の文字列でもユニコード文字列でも良く、Python 識別子としては不正な文字 (例えばピリオド ".") を含んでいても構いません。

`SimpleXMLRPCServer.``register_instance`(instance, allow_dotted_names=False)

  オブジェクトを登録します。 オブジェクトは `register_function()` を使用して登録されていないメソッド名を公開するのに使われます。 instance に `_dispatch()` メソッドがあった場合、リクエストされたメソッド名と引数で `_dispatch()` を呼び出します。 API は `def _dispatch(self, method, params)` (params 可変引数リストではないことに注意) です。 タスクを実行するのに下層の関数を呼び出す場合、その関数は `func(*params)` のように引数リストを展開して呼び出されます。 `_dispatch()` の返り値は結果としてクライアントに返されます。 instance に `_dispatch()` メソッドがない場合、リクエストされたメソッド名にマッチする属性を検索します。

  オプション引数 allow_dotted_names が真でインスタンスに `_dispatch()` メソッドがない場合、リクエストされたメソッド名がピリオドを含むなら、メソッド名の各要素が個々に検索され、簡単な階層的検索が行われます。 その検索で発見された値をリクエストの引数で呼び出し、クライアントに返り値を返します。

  警告

  allow_dotted_names オプションを有効にすると、侵入者はあなたのモジュールのグローバル変数にアクセスすることができ、あなたのマシンで任意のコードを実行できる可能性があります。このオプションは閉じた安全なネットワークでのみお使い下さい。

`SimpleXMLRPCServer.``register_introspection_functions`()

  XML-RPC のイントロスペクション関数、 `system.listMethods` 、 `system.methodHelp` 、 `system.methodSignature` を登録します。

`SimpleXMLRPCServer.``register_multicall_functions`()

  XML-RPC における複数の要求を処理する関数 system.multicall を登録します。

`SimpleXMLRPCRequestHandler.``rpc_paths`

  この属性値はXML-RPCリクエストを受け付けるURLの有効なパス部分をリストするタプルでなければなりません。これ以外のパスへのリクエストは404「そのようなページはありません」 HTTPエラーになります。このタプルが空の場合は全てのパスが有効であると見なされます。デフォルト値は `('/', '/RPC2')` です。

### 21.27.1.1. SimpleXMLRPCServer の例

サーバーのコード:

    from xmlrpc.server import SimpleXMLRPCServer
    from xmlrpc.server import SimpleXMLRPCRequestHandler

    # Restrict to a particular path.
    class RequestHandler(SimpleXMLRPCRequestHandler):
        rpc_paths = ('/RPC2',)

    # Create server
    with SimpleXMLRPCServer(("localhost", 8000),
                            requestHandler=RequestHandler) as server:
        server.register_introspection_functions()

        # Register pow() function; this will use the value of
        # pow.__name__ as the name, which is just 'pow'.
        server.register_function(pow)

        # Register a function under a different name
        def adder_function(x,y):
            return x + y
        server.register_function(adder_function, 'add')

        # Register an instance; all the methods of the instance are
        # published as XML-RPC methods (in this case, just 'mul').
        class MyFuncs:
            def mul(self, x, y):
                return x * y

        server.register_instance(MyFuncs())

        # Run the server's main loop
        server.serve_forever()

以下のクライアントコードは上のサーバーで使えるようになったメソッドを呼び出します:

    import xmlrpc.client

    s = xmlrpc.client.ServerProxy('http://localhost:8000')
    print(s.pow(2,3))  # Returns 2**3 = 8
    print(s.add(2,3))  # Returns 5
    print(s.mul(5,2))  # Returns 5*2 = 10

    # Print list of available methods
    print(s.system.listMethods())

`Lib/xmlrpc/server.py` モジュール内にある以下の例はドット付名前を許容し複数呼び出し関数を登録するサーバです。

警告

allow_dotted_names オプションを有効にすると、侵入者はあなたのモジュールのグローバル変数にアクセスすることができ、あなたのマシンで任意のコードを実行できる可能性があります。この例は閉じた安全なネットワークでのみお使い下さい。

    import datetime

    class ExampleService:
        def getData(self):
            return '42'

        class currentTime:
            @staticmethod
            def getCurrentTime():
                return datetime.datetime.now()

    with SimpleXMLRPCServer(("localhost", 8000)) as server:
        server.register_function(pow)
        server.register_function(lambda x,y: x+y, 'add')
        server.register_instance(ExampleService(), allow_dotted_names=True)
        server.register_multicall_functions()
        print('Serving XML-RPC on localhost port 8000')
        try:
            server.serve_forever()
        except KeyboardInterrupt:
            print("\nKeyboard interrupt received, exiting.")
            sys.exit(0)

この ExampleService デモはコマンドラインから起動することができます。

    python -m xmlrpc.server

上記のサーバとやりとりするクライアントは Lib/xmlrpc/client.py にあります:

    server = ServerProxy("http://localhost:8000")

    try:
        print(server.currentTime.getCurrentTime())
    except Error as v:
        print("ERROR", v)

    multi = MultiCall(server)
    multi.getData()
    multi.pow(2,9)
    multi.add(1,2)
    try:
        for response in multi():
            print(response)
    except Error as v:
        print("ERROR", v)

デモ XMLRPC サーバとやりとりするクライアントは以下のように呼び出します:

    python -m xmlrpc.client

## 21.27.2. CGIXMLRPCRequestHandler

`CGIXMLRPCRequestHandler` クラスは、Python の CGI スクリプトに送られた XML-RPC リクエストを処理するときに使用できます。

`CGIXMLRPCRequestHandler.``register_function`(function, name=None)

  XML-RPC リクエストに応じる関数を登録します。 与えられた場合 name は関数に関連付けられるメソッド名です。 そうでない場合 `function.__name__` が使われます。 name は通常の文字列でもユニコード文字列でも良く、Python 識別子としては不正な文字 (例えばピリオド ".") を含んでいても構いません。

`CGIXMLRPCRequestHandler.``register_instance`(instance)

  オブジェクトを登録します。 オブジェクトは `register_function()` を使用して登録されていないメソッド名を公開するのに使われます。 instance に `_dispatch()` メソッドがあった場合、リクエストされたメソッド名と引数で `_dispatch()` を呼び出します。 返り値は結果としてクライアントに返されます。 instance に `_dispatch()` メソッドがなかった場合、リクエストされたメソッド名にマッチする属性を検索します。 リクエストされたメソッド名がピリオドを含む場合、モジュール名の各要素が個々に検索され、簡単な階層的検索が実行されます。 その検索で発見された値をリクエストの引数で呼び出し、クライアントに返り値を返します。

`CGIXMLRPCRequestHandler.``register_introspection_functions`()

  XML-RPC のイントロスペクション関数、 `system.listMethods` 、 `system.methodHelp` 、 `system.methodSignature` を登録します。

`CGIXMLRPCRequestHandler.``register_multicall_functions`()

  XML-RPC マルチコール関数 `system.multicall` を登録します。

`CGIXMLRPCRequestHandler.``handle_request`(request_text=None)

  XML-RPC リクエストを処理します。 与えられた場合、 request_text はHTTP サーバが提供する POST データでなければなりません。 そうでない場合、標準入力の内容が使われます。

以下はプログラム例です:

    class MyFuncs:
        def mul(self, x, y):
            return x * y

    handler = CGIXMLRPCRequestHandler()
    handler.register_function(pow)
    handler.register_function(lambda x,y: x+y, 'add')
    handler.register_introspection_functions()
    handler.register_instance(MyFuncs())
    handler.handle_request()

## 21.27.3. XMLRPC サーバの文書化

これらのクラスは HTTP GET 要求への応答内で HTML 文書となるよう上記クラスを拡張します。 サーバは独立していても CGI 環境に埋め込まれていてもかまいません。 前者では `DocXMLRPCServer` を、後者では `DocCGIXMLRPCRequestHandler` を使用します。

class `xmlrpc.server.``DocXMLRPCServer`(addr, requestHandler=DocXMLRPCRequestHandler, logRequests=True, allow_none=False, encoding=None, bind_and_activate=True, use_builtin_types=True)

  サーバ・インスタンスを新たに生成します。全ての引数の意味は `SimpleXMLRPCServer` のものと同じですが、 requestHandler のデフォルトは `DocXMLRPCRequestHandler` になっています。

  バージョン 3.3 で変更: use_builtin_types フラグが追加されました。

class `xmlrpc.server.``DocCGIXMLRPCRequestHandler`

  CGI環境で XMR-RPC リクエストを処理するインスタンスを新たに生成します。

class `xmlrpc.server.``DocXMLRPCRequestHandler`

  リクエスト・ハンドラのインスタンスを新たに生成します。このリクエスト・ハンドラは XML-RPC POST 要求とドキュメントの GET 要求をサポートし、 `DocXMLRPCServer` コンストラクタに与えられた引数 logRequests を優先するためにロギングを変更します。

## 21.27.4. DocXMLRPCServer オブジェクト

`DocXMLRPCServer` は `SimpleXMLRPCServer` の派生クラスで、自己文書化するスタンドアローン XML-RPC サーバの作成手段を提供します。 HTTP POST リクエストは XML-RPC メソッドの呼び出しとして処理されます。 HTTP GET リクエストは pydoc スタイルの HTML 文書の生成に処理されます。 これによりサーバは自身の web ベースの文書を提供できます。

`DocXMLRPCServer.``set_server_title`(server_title)

  生成する HTML 文書で使用されるタイトルを設定します。このタイトルは HTML の title 要素内で使われます。

`DocXMLRPCServer.``set_server_name`(server_name)

  生成する HTML 文書内で使用される名前を設定します。この名前は生成した文書冒頭の h1 要素内で使われます。

`DocXMLRPCServer.``set_server_documentation`(server_documentation)

  生成する HTML 文書内で使用される説明を設定します。この説明は文書中のサーバ名の下にパラグラフとして出力されます。

## 21.27.5. DocCGIXMLRPCRequestHandler

`DocCGIXMLRPCRequestHandler` は `CGIXMLRPCRequestHandler` の派生クラスで、自己文書化する XML-RPC CGI スクリプトの作成手段を提供します。 HTTP POST リクエストは XML-RCP メソッドの呼び出しとして処理されます。 HTTP GET リクエストは pydoc スタイルの HTML 文書の生成に処理されます。 これによりサーバは自身の web ベースの文書を提供できます。

`DocCGIXMLRPCRequestHandler.``set_server_title`(server_title)

  生成する HTML 文書で使用されるタイトルを設定します。このタイトルは HTML の title 要素内で使われます。

`DocCGIXMLRPCRequestHandler.``set_server_name`(server_name)

  生成する HTML 文書内で使用される名前を設定します。この名前は生成した文書冒頭の h1 要素内で使われます。

`DocCGIXMLRPCRequestHandler.``set_server_documentation`(server_documentation)

  生成する HTML 文書内で使用される説明を設定します。この説明は文書中のサーバ名の下にパラグラフとして出力されます。