设置基于SimpleHTTPRequestHandler的自定义处理程序的协议版本。

huangapple go评论59阅读模式
英文:

Set protocol version for custom handler based on SimpleHTTPRequestHandler

问题

我基于Python的`http.server`模块创建了自己的脚本脚本的主要目标是处理自定义路径"/files"以获取文件列表的JSON格式
在Python 3.11中为`http.server`模块添加了`--protocol`参数我使用的是Python 3.11.4我试图以以下方式在我的脚本中支持此参数

```python
import json
import os
import sys
from functools import partial
from http.server import SimpleHTTPRequestHandler, test
from pathlib import Path


class HTTPRequestHandler(SimpleHTTPRequestHandler):
    def do_GET(self) -> None:
        if self.path == '/files':
            response = bytes(self._get_response(), 'utf-8')
            self.send_response(200)
            self.send_header('Content-Type', 'application/json')
            self.send_header('Content-Length', str(len(response)))
            self.end_headers()
            self.wfile.write(response)

            return

        return super().do_GET()

    def _get_response(self) -> str:
        results = []

        for item in Path(self.directory).rglob('*'):
            if item.is_file():
                if __file__ in str(item):
                    continue

                file_size = str(os.stat(item).st_size)
                relative_file_path = os.path.relpath(item, self.directory)

                if sys.platform == 'win32':
                    relative_file_path = relative_file_path.replace('\\', '/')

                results.append(dict(file=relative_file_path, size=file_size))

        return json.dumps(results)


if __name__ == '__main__':
    import argparse

    parser = argparse.ArgumentParser()
    parser.add_argument('-b', '--bind', metavar='ADDRESS',
                        help='绑定到此地址 (默认: 所有接口)')
    parser.add_argument('-d', '--directory', default=os.getcwd(),
                        help='提供此目录 (默认: 当前目录)')
    parser.add_argument('-p', '--protocol', metavar='VERSION',
                        default='HTTP/1.1',
                        help='符合此HTTP版本 (默认: %(default)s)')
    parser.add_argument('port', default=8000, type=int, nargs='?',
                        help='绑定到此端口 (默认: %(default)s)')
    args = parser.parse_args()

    handler_class = partial(HTTPRequestHandler, directory=args.directory)

    test(HandlerClass=handler_class, port=args.port, bind=args.bind, protocol=args.protocol)
python server.py --bind <ip> <port> -p HTTP/1.1

但由于某种原因,响应头仍然包含"HTTP/1.0"版本。您能否请教我哪里出错了?


<details>
<summary>英文:</summary>
I&#39;ve created my own script based on Python `http.server` module. The main target of script is handling custom path &quot;/files&quot; to get list of files in JSON format.
Parameter `--protocol` was added in Python 3.11 for `http.server` module. I use Python 3.11.4. I&#39;m trying to support this parameter in my script in the following way:
```python
import json
import os
import sys
from functools import partial
from http.server import SimpleHTTPRequestHandler, test
from pathlib import Path
class HTTPRequestHandler(SimpleHTTPRequestHandler):
def do_GET(self) -&gt; None:
if self.path == &#39;/files&#39;:
response = bytes(self._get_response(), &#39;utf-8&#39;)
self.send_response(200)
self.send_header(&#39;Content-Type&#39;, &#39;application/json&#39;)
self.send_header(&#39;Content-Length&#39;, str(len(response)))
self.end_headers()
self.wfile.write(response)
return
return super().do_GET()
def _get_response(self) -&gt; str:
results = []
for item in Path(self.directory).rglob(&#39;*&#39;):
if item.is_file():
if __file__ in str(item):
continue
file_size = str(os.stat(item).st_size)
relative_file_path = os.path.relpath(item, self.directory)
if sys.platform == &#39;win32&#39;:
relative_file_path = relative_file_path.replace(&#39;\\&#39;, &#39;/&#39;)
results.append(dict(file=relative_file_path, size=file_size))
return json.dumps(results)
if __name__ == &#39;__main__&#39;:
import argparse
parser = argparse.ArgumentParser()
parser.add_argument(&#39;-b&#39;, &#39;--bind&#39;, metavar=&#39;ADDRESS&#39;,
help=&#39;bind to this address &#39;
&#39;(default: all interfaces)&#39;)
parser.add_argument(&#39;-d&#39;, &#39;--directory&#39;, default=os.getcwd(),
help=&#39;serve this directory &#39;
&#39;(default: current directory)&#39;)
parser.add_argument(&#39;-p&#39;, &#39;--protocol&#39;, metavar=&#39;VERSION&#39;,
default=&#39;HTTP/1.1&#39;,
help=&#39;conform to this HTTP version &#39;
&#39;(default: %(default)s)&#39;)
parser.add_argument(&#39;port&#39;, default=8000, type=int, nargs=&#39;?&#39;,
help=&#39;bind to this port &#39;
&#39;(default: %(default)s)&#39;)
args = parser.parse_args()
handler_class = partial(HTTPRequestHandler, directory=args.directory)
test(HandlerClass=handler_class, port=args.port, bind=args.bind, protocol=args.protocol)
python server.py --bind &lt;ip&gt; &lt;port&gt; -p HTTP/1.1

But by some reason response header still contains "HTTP/1.0" version.
Could you please advice what I'm doing wrong?

答案1

得分: 1

创建TCPServer实例,并在HTTPRequestHandler类上设置protocol_version为"HTTP/1.1",然后在运行时它将使用HTTP/1.1。

from socketserver import TCPServer
...
handler_class = partial(HTTPRequestHandler, directory=args.directory)
HTTPRequestHandler.protocol_version = args.protocol
PORT = args.port
with TCPServer(("", PORT), handler_class) as httpd:
print("在端口上提供HTTP服务", PORT)
httpd.serve_forever()

如果调用http.server.test()函数,那么它会设置提供的HandlerClass参数上的protocol_version,但如果使用partial来包装类,则不起作用,因此必须显式设置HTTPRequestHandler.protocol_version

英文:

Create TCPServer instance and set protocol_version on the HTTPRequestHandler class to "HTTP/1.1" then it uses HTTP/1.1 when running.

from socketserver import TCPServer
...
handler_class = partial(HTTPRequestHandler, directory=args.directory)
HTTPRequestHandler.protocol_version = args.protocol
PORT = args.port
with TCPServer((&quot;&quot;, PORT), handler_class) as httpd:
print(&quot;Serving HTTP on port&quot;, PORT)
httpd.serve_forever()

If call http.server.test() function then it sets protocol_version on the provided HandlerClass argument, but won't work if using a partial to wrap the class so must explicitly set HTTPRequestHandler.protocol_version.

答案2

得分: 0

问题通过为自定义处理程序设置protocol_version的值来解决:

...

if __name__ == '__main__':
    import argparse

    parser = argparse.ArgumentParser()
    parser.add_argument('-b', '--bind', metavar='ADDRESS',
                        help='绑定到此地址 '
                        '(默认:所有接口)')
    parser.add_argument('-d', '--directory', default=os.getcwd(),
                        help='提供此目录 '
                        '(默认:当前目录)')
    # --protocol 参数在 Python 3.11+ 中引入
    parser.add_argument('-p', '--protocol', metavar='VERSION',
                        default='HTTP/1.1',
                        help='符合此 HTTP 版本 '
                        '(默认:%(default)s)')
    parser.add_argument('port', default=8000, type=int, nargs='?',
                        help='绑定到此端口 '
                        '(默认:%(default)s)')
    args = parser.parse_args()

    HTTPRequestHandler.protocol_version = args.protocol
    handler_class = partial(HTTPRequestHandler, directory=args.directory)

    test(HandlerClass=handler_class, port=args.port, bind=args.bind)

请注意,我已经将代码中的注释翻译成中文。

英文:

Problem was solved by setting value for protocol_version on the custom handler:

...

if __name__ == &#39;__main__&#39;:
    import argparse

    parser = argparse.ArgumentParser()
    parser.add_argument(&#39;-b&#39;, &#39;--bind&#39;, metavar=&#39;ADDRESS&#39;,
                        help=&#39;bind to this address &#39;
                        &#39;(default: all interfaces)&#39;)
    parser.add_argument(&#39;-d&#39;, &#39;--directory&#39;, default=os.getcwd(),
                        help=&#39;serve this directory &#39;
                        &#39;(default: current directory)&#39;)
    # --protocol argument was introduced in Python 3.11+
    parser.add_argument(&#39;-p&#39;, &#39;--protocol&#39;, metavar=&#39;VERSION&#39;,
                        default=&#39;HTTP/1.1&#39;,
                        help=&#39;conform to this HTTP version &#39;
                        &#39;(default: %(default)s)&#39;)
    parser.add_argument(&#39;port&#39;, default=8000, type=int, nargs=&#39;?&#39;,
                        help=&#39;bind to this port &#39;
                        &#39;(default: %(default)s)&#39;)
    args = parser.parse_args()

    HTTPRequestHandler.protocol_version = args.protocol
    handler_class = partial(HTTPRequestHandler, directory=args.directory)

    test(HandlerClass=handler_class, port=args.port, bind=args.bind)

huangapple
  • 本文由 发表于 2023年7月28日 00:02:29
  • 转载请务必保留本文链接:https://go.coder-hub.com/76781562.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定