python - 将 BaseHTTPRequestHandler 与 UnixStreamServer 一起使用会导致异常

python - using BaseHTTPRequestHandler with UnixStreamServer causes exception

我正在尝试创建一个绑定到 Unix 域套接字的基本 HTTP 服务器,但是将 BaseHTTPRequestHandler 子类与 UnixStreamServer 一起使用会创建一个异常,表明它们无法协同工作。

玩具server.py:

from SocketServer import UnixStreamServer
from BaseHTTPServer import BaseHTTPRequestHandler

class MyHandler(BaseHTTPRequestHandler):
  def do_GET(self):
    self.send_response(200)
    self.send_header("Content-Type", "text/plain")
    self.end_headers()
    self.wfile.write("Hi!")

server = UnixStreamServer('./mysocket.sock', MyHandler)
server.serve_forever()

然后我发送一个带有 curl --unix-socket ./mysocket.sock http:/hello 的请求,这导致服务器出现以下异常(使用 Python 2.7.11):

Exception happened during processing of request from 
Traceback (most recent call last):
  File "/usr/lib/python2.7/SocketServer.py", line 290, in _handle_request_noblock
    self.process_request(request, client_address)
  File "/usr/lib/python2.7/SocketServer.py", line 318, in process_request
    self.finish_request(request, client_address)
  File "/usr/lib/python2.7/SocketServer.py", line 331, in finish_request
    self.RequestHandlerClass(request, client_address, self)
  File "/usr/lib/python2.7/SocketServer.py", line 652, in __init__
    self.handle()
  File "/usr/lib/python2.7/BaseHTTPServer.py", line 340, in handle
    self.handle_one_request()
  File "/usr/lib/python2.7/BaseHTTPServer.py", line 328, in handle_one_request
    method()
  File "server.py", line 6, in do_GET
    self.send_response(200)
  File "/usr/lib/python2.7/BaseHTTPServer.py", line 385, in send_response
    self.log_request(code)
  File "/usr/lib/python2.7/BaseHTTPServer.py", line 422, in log_request
    self.requestline, str(code), str(size))
  File "/usr/lib/python2.7/BaseHTTPServer.py", line 456, in log_message
    (self.client_address[0],
IndexError: string index out of range

我做了一些挖掘,问题与 sock.accept() returns 空字符串作为地址这一事实有关,大概是因为 UDS 调用没有客户端地址的概念。然而,BaseHTTPRequestHandler 期望一个用于日志记录(可能还有其他事情)

有没有一种方法可以解决这个问题,而不涉及猴子补丁或通过这个小改动重新实现 BaseHTTPServer? BaseHTTPRequestHandler 甚至打算与 UnixDataStream 一起使用吗? Python?

中关于轻量级 UDS HTTP 服务器的更好建议

谢谢!

我结束了 UnixStreamServer 的子类化并覆盖了 get_request(这是打算被覆盖的 TCPServer 方法之一):

class UnixHTTPServer(UnixStreamServer):
  def get_request(self):
    request, client_address = self.socket.accept()
    # BaseHTTPRequestHandler expects a tuple with the client address at index
    # 0, so we fake one
    if len(client_address) == 0:
      client_address = (self.server_address,)
    return (request, client_address)

(注意 self.server_address 给出了用于 UDS 的文件描述符的路径)

这不是最干净的解决方案,但也不是最骇人听闻的解决方案。

您可以将 BaseHTTPRequestHandler 与 HTTPServer 一起使用。

import os, socket, BaseHTTPServer


class HTTPHandler(BaseHTTPServer.BaseHTTPRequestHandler):

    def do_GET(self):
        self.send(200,'Success')

    def do_POST(self):
        size = int(self.headers.get('Content-Length',0))
        body = self.rfile.read(size)
        self.send(200,'Success')

    def send(self,code,reply):
        self.client_address=('',) # avoid exception in BaseHTTPServer.py log_message()
        self.send_response(code)
        self.end_headers()
        self.wfile.write(reply)


sock_file = 'socket'
try: os.remove(sock_file)
except OSError: pass
sock = socket.socket(socket.AF_UNIX,socket.SOCK_STREAM)
sock.bind(sock_file)
sock.listen(0)

server = BaseHTTPServer.HTTPServer(sock_file,HTTPHandler,False)
server.socket = sock
server.serve_forever()

sock.shutdown(socket.SHUT_RDWR)
sock.close()
os.remove(sock_file)