"xmlrpc.server" --- 基本的な XML-RPC サーバー
*********************************************

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

======================================================================

The "xmlrpc.server" module provides a basic server framework for XML-
RPC servers written in Python.  Servers can either be free standing,
using "SimpleXMLRPCServer", or embedded in a CGI environment, using
"CGIXMLRPCRequestHandler".

警告:

  The "xmlrpc.server" module is not secure against maliciously
  constructed data.  If you need to parse untrusted or unauthenticated
  data, see XML security.

Availability: not WASI.

このモジュールは WebAssembly では動作しないか、利用不可です。詳しくは
、WebAssembly プラットフォーム を見てください。

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* に従ってログ出力を行います。


SimpleXMLRPCServer objects
==========================

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

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

   XML-RPC リクエストに応答可能な関数を登録します。引数 *name* が与え
   られた場合は、それが関数 *function* に関連付けられたメソッド名とな
   ります。そうでない場合は、 "function.__name__" の値が用いられます。
   引数 *name* は文字列で、例えばピリオド "." のようなPythonで識別子と
   して正しくない文字を含んでいても構いません。

   このメソッドはデコレーターとしても使用することができます。デコレー
   ターとして使用するときは、 *name* は関数を *name* で登録するキーワ
   ード引数としてのみ渡すことができます。 *name* が与えられていないと
   きは、 "function.__name__" が使用されます。

   バージョン 3.7 で変更: "register_function()" はデコレーターとして使
   用できます。

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')" です。


SimpleXMLRPCServer example
--------------------------

サーバーのコード:

   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())

"register_function()" はデコレーターとしても使用できます。前のサーバー
の例は、デコレーターの方法で関数を登録することもできます。

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

   class RequestHandler(SimpleXMLRPCRequestHandler):
       rpc_paths = ('/RPC2',)

   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, using
       # register_function as a decorator. *name* can only be given
       # as a keyword argument.
       @server.register_function(name='add')
       def adder_function(x, y):
           return x + y

       # Register a function under function.__name__.
       @server.register_function
       def mul(x, y):
           return x * y

       server.serve_forever()

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

警告:

  Enabling the *allow_dotted_names* option allows intruders to access
  your module's global variables and may allow intruders to execute
  arbitrary code on your machine.  Only use this example within a
  secure, closed network.

   import datetime as dt

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

       class currentTime:
           @staticmethod
           def getCurrentTime():
               return dt.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


CGIXMLRPCRequestHandler
=======================

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

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

   XML-RPC リクエストに応答可能な関数を登録します。引数 *name* が与え
   られた場合は、それが関数 *function* に関連付けられたメソッド名とな
   ります。そうでない場合は、 "function.__name__" の値が用いられます。
   引数 *name* は文字列で、例えばピリオド "." のようなPythonで識別子と
   して正しくない文字を含んでいても構いません。

   このメソッドはデコレーターとしても使用することができます。デコレー
   ターとして使用するときは、 *name* は関数を *name* で登録するキーワ
   ード引数としてのみ渡すことができます。 *name* が与えられていないと
   きは、 "function.__name__" が使用されます。

   バージョン 3.7 で変更: "register_function()" はデコレーターとして使
   用できます。

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()


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*
   を優先するためにロギングを変更します。


DocXMLRPCServer objects
=======================

"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 文書内で使用される説明を設定します。この説明は文書中
   のサーバ名の下にパラグラフとして出力されます。


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 文書内で使用される説明を設定します。この説明は文書中
   のサーバ名の下にパラグラフとして出力されます。
