"xmlrpc.server" --- 基本 XML-RPC 伺服器
***************************************

**原始碼：**Lib/xmlrpc/server.py

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

"xmlrpc.server" 模組為以 Python 撰寫的 XML-RPC 伺服器提供了基本的伺服
器框架。伺服器可以是獨立執行的（使用 "SimpleXMLRPCServer"），或嵌入在
CGI 環境中（使用 "CGIXMLRPCRequestHandler"）。

警告:

  "xmlrpc.server" 模組對於惡意建構的資料並不安全。如果你需要剖析不受信
  任或未經驗證的資料，請參閱 XML 安全性。

可用性: 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* 參數應該是請求處理器實例的工廠（factory）
   ；它預設為 "SimpleXMLRPCRequestHandler"。*addr* 和 *requestHandler*
   參數會傳遞給 "socketserver.TCPServer" 建構函式。如果 *logRequests*
   為 true（預設值），請求會被記錄；將此參數設定為 false 將關閉記錄。
   *allow_none* 和 *encoding* 參數會傳遞給 "xmlrpc.client" 並控制從伺
   服器回傳的 XML-RPC 回應。*bind_and_activate* 參數控制建構函式是否立
   即呼叫 "server_bind()" 和 "server_activate()"；它預設為 true。將其
   設定為 false 允許程式碼在位址被綁定之前操作 *allow_reuse_address*
   類別變數。*use_builtin_types* 參數會傳遞給 "loads()" 函式，並控制在
   接收到日期/時間值或二進位資料時要處理哪些型別；它預設為 false。

   在 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()" 函式，並控制在
   接收到日期/時間值或二進位資料時要處理哪些型別；它預設為 false。

   在 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 識別符中不合法的字元，包括句點字元。

   此方法也可以用作裝飾器。當用作裝飾器時，*name* 只能作為關鍵字引數給
   定，以在 *name* 下註冊 *function*。如果沒有給定 *name*，將使用
   "function.__name__"。

   在 3.7 版的變更: "register_function()" 也可被當作裝飾器使用。

SimpleXMLRPCServer.register_instance(instance, allow_dotted_names=False)

   註冊一個物件，用於公開尚未使用 "register_function()" 註冊的方法名稱
   。如果 *instance* 包含 "_dispatch()" 方法，它會被呼叫並傳入請求的方
   法名稱和來自請求的參數。其 API 為 "def _dispatch(self, method,
   params)"（注意 *params* 不代表可變引數列表）。如果它呼叫底層函式來
   執行其任務，該函式會以 "func(*params)" 的方式被呼叫，展開參數列表。
   來自 "_dispatch()" 的回傳值會作為結果回傳給用戶端。如果 *instance*
   沒有 "_dispatch()" 方法，則會搜尋與請求方法名稱匹配的屬性。

   如果可選的 *allow_dotted_names* 引數為 true 且實例沒有
   "_dispatch()" 方法，那麼如果請求的方法名稱包含句點，方法名稱的每個
   組成部分會被單獨搜尋，從而執行簡單的階層式搜尋。從此搜尋中找到的值
   會以來自請求的參數被呼叫，並將回傳值傳回給用戶端。

   警告:

     啟用 *allow_dotted_names* 選項允許入侵者存取你模組的全域變數，並
     可能允許入侵者在你的機器上執行任意程式碼。請在安全、封閉的網路上
     才使用此選項。

SimpleXMLRPCServer.register_introspection_functions()

   註冊 XML-RPC 自我檢查函式 (introspection functions)
   "system.listMethods"、"system.methodHelp" 和
   "system.methodSignature"。

SimpleXMLRPCServer.register_multicall_functions()

   註冊 XML-RPC 多重呼叫函式 (multicall function) system.multicall。

SimpleXMLRPCRequestHandler.rpc_paths

   一個屬性值，必須是一個元組，列出接收 XML-RPC 請求的 URL 的有效路徑
   部分。發布到其他路徑的請求將導致 404 "no such page" HTTP 錯誤。如果
   此元組為空，所有路徑都將被視為有效。預設值為 "('/', '/RPC2')"。


SimpleXMLRPCServer 範例
-----------------------

伺服器程式碼：

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

       # 註冊 pow() 函式；這將使用 pow.__name__ 的值作為名稱，即 'pow'。
       server.register_function(pow)

       # 以不同的名稱註冊函式
       def adder_function(x, y):
           return x + y
       server.register_function(adder_function, 'add')

       # 註冊一個實例；該實例的所有方法都會被發布為 XML-RPC 方法（在此例中僅 'mul'）。
       class MyFuncs:
           def mul(self, x, y):
               return x * y

       server.register_instance(MyFuncs())

       # 執行伺服器的主迴圈
       server.serve_forever()

以下用戶端程式碼將呼叫前述伺服器提供的方法：

   import xmlrpc.client

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

   # 印出可用方法列表
   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()

       # 註冊 pow() 函式；這將使用 pow.__name__ 的值作為名稱，即 'pow'。
       server.register_function(pow)

       # 使用 register_function 作為裝飾器以不同的名稱註冊函式。
       # *name* 只能作為關鍵字引數給定。
       @server.register_function(name='add')
       def adder_function(x, y):
           return x + y

       # 以 function.__name__ 註冊函式。
       @server.register_function
       def mul(x, y):
           return x * y

       server.serve_forever()

以下包含在 "Lib/xmlrpc/server.py" 模組中的範例展示了一個允許點分隔名稱
並註冊多重呼叫函式的伺服器。

警告:

  啟用 *allow_dotted_names* 選項來允許入侵者存取你模組的全域變數，並可
  能允許入侵者在你的機器上執行任意程式碼。請在安全、封閉的網路中才使用
  此範例。

   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* 下註冊 *function*。如果沒有給定 *name*，將使用
   "function.__name__"。

   在 3.7 版的變更: "register_function()" 也可被當作裝飾器使用。

CGIXMLRPCRequestHandler.register_instance(instance)

   註冊一個物件，用於公開尚未使用 "register_function()" 註冊的方法名稱
   。如果實例包含 "_dispatch()" 方法，它會以請求的方法名稱和來自請求的
   參數來被呼叫；回傳值會作為結果回傳給用戶端。如果實例沒有
   "_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 資料，否則將使用 stdin 的內容。

範例：

   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 文件。伺服
器可以是獨立執行的（使用 "DocXMLRPCServer"），或嵌入在 CGI 環境中（使
用 "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 環境中處理 XML-RPC 請求。

class xmlrpc.server.DocXMLRPCRequestHandler

   建立一個新的請求處理器實例。此請求處理器支援 XML-RPC POST 請求、文
   件 GET 請求，並修改日誌記錄功能以遵守 "DocXMLRPCServer" 建構函式的
   *logRequests* 參數。


DocXMLRPCServer 物件
====================

"DocXMLRPCServer" 類別衍生自 "SimpleXMLRPCServer"，並提供了建立自我記
錄 (self-documenting) 的獨立 XML-RPC 伺服器的方式。HTTP POST 請求會被
作為 XML-RPC 方法呼叫來處理。HTTP GET 請求會透過產生 pydoc 風格的 HTML
文件來處理。這允許伺服器提供自己的網頁文件。

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-RPC 方法呼叫來處理。HTTP GET 請求會透過產生 pydoc 風格的 HTML 文件
來處理。這允許伺服器提供自己的網頁文件。

DocCGIXMLRPCRequestHandler.set_server_title(server_title)

   設定在產生的 HTML 文件中使用的標題。此標題將用於 HTML "title" 元素
   內。

DocCGIXMLRPCRequestHandler.set_server_name(server_name)

   設定在產生的 HTML 文件中使用的名稱。此名稱將顯示在產生的文件頂部的
   "h1" 元素內。

DocCGIXMLRPCRequestHandler.set_server_documentation(server_documentation)

   設定在產生的 HTML 文件中使用的描述。此描述將作為一個段落顯示在文件
   中伺服器名稱的下方。
