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


SimpleXMLRPCServer オブジェクト
===============================

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

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

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

   This method can also be used as a decorator.  When used as a
   decorator, *name* can only be given as a keyword argument to
   register *function* under *name*.  If no *name* is given,
   "function.__name__" will be used.

   バージョン 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 の例
-----------------------

サーバーのコード:

   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" モジュール内にある以下の例はドット付名前を許容
し複数呼び出し関数を登録するサーバです。

警告:

  *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


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

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

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

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

   This method can also be used as a decorator.  When used as a
   decorator, *name* can only be given as a keyword argument to
   register *function* under *name*.  If no *name* is given,
   "function.__name__" will be used.

   バージョン 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 オブジェクト
============================

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