"http.server" --- HTTP 服务器
*****************************

**源代码：** Lib/http/server.py

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

这个模块定义了用于实现 HTTP 服务器的类。

警告:

  不建议将 "http.server" 用于生产环境。 它仅实现了 基本安全检测。

适用范围: not WASI.

此模块在 WebAssembly 平台上无效或不可用。请参阅 WebAssembly 平台 了解
详情。

"HTTPServer" 是 "socketserver.TCPServer" 的一个子类。它会创建和侦听
HTTP 套接字，并将请求分发给处理程序。创建和运行 HTTP 服务器的代码类似
如下所示:

   def run(server_class=HTTPServer, handler_class=BaseHTTPRequestHandler):
       server_address = ('', 8000)
       httpd = server_class(server_address, handler_class)
       httpd.serve_forever()

class http.server.HTTPServer(server_address, RequestHandlerClass)

   该类基于 "TCPServer" 类，并在实例变量 "server_name" 和
   "server_port" 中保存 HTTP 服务器地址。处理程序可通过实例变量
   "server" 访问 HTTP 服务器。

class http.server.ThreadingHTTPServer(server_address, RequestHandlerClass)

   该类与 HTTPServer 相同，只是会利用 "ThreadingMixIn" 对请求进行多线
   程处理。当需要对 Web 浏览器预先打开套接字进行处理时，这就很有用，这
   时 "HTTPServer" 会一直等待请求。

   Added in version 3.7.

class http.server.HTTPSServer(server_address, RequestHandlerClass, bind_and_activate=True, *, certfile, keyfile=None, password=None, alpn_protocols=None)

   使用 "ssl" 模块的封装套接字的 "HTTPServer" 子类。如果 "ssl" 模块不
   可用，实例化 "HTTPSServer" 对象将失败，并返回 "RuntimeError"。

   *certfile* 参数是 SSL 证书链文件的路径，*keyfile* 是包含私钥的文件
   的路径。

   可以为受PKCS#8保护和包装的文件指定 *password* ，但要注意，这可能会
   以明文形式暴露硬编码的密码。

   参见:

     参见 "ssl.SSLContext.load_cert_chain()" 获取有关 *certfile*、
     *keyfile* 和 *password* 的可接受值的更多信息。

   当指定时，*alpn_protocols* 参数必须是指定服务器支持的“应用层协议协
   商”（ALPN）协议的字符串序列。ALPN 允许服务器和客户端在 TLS 握手期间
   协商应用协议。

   默认情况下，它将被设为 "["http/1.1"]"，表示服务器支持 HTTP/1.1。

   Added in version 3.14.

class http.server.ThreadingHTTPSServer(server_address, RequestHandlerClass, bind_and_activate=True, *, certfile, keyfile=None, password=None, alpn_protocols=None)

   此类与 "HTTPSServer" 相同，但通过继承 "ThreadingMixIn" 使用线程来处
   理请求。这类似于仅使用 "HTTPSServer" 的 "ThreadingHTTPServer"。

   Added in version 3.14.

实例化 "HTTPServer"、 "ThreadingHTTPServer"、"HTTPSServer" 和
"ThreadingHTTPSServer" 时，必须给出一个 *RequestHandlerClass*，该模块
提供了三种不同的变体：

class http.server.BaseHTTPRequestHandler(request, client_address, server)

   This class is used to handle the HTTP requests that arrive at the
   server.  By itself, it cannot respond to any actual HTTP requests;
   it must be subclassed to handle each request method (for example,
   "'GET'" or "'POST'"). "BaseHTTPRequestHandler" provides a number of
   class and instance variables, and methods for use by subclasses.

   这个处理器将解析请求和标头，然后调用特定请求类型对应的方法。方法名
   称将根据请求来构造。例如，对于请求方法 "SPAM"，将不带参数地调用
   "do_SPAM()" 方法。所有相关信息会被保存在该处理器的实例变量中。子类
   不应需要重写或扩展 "__init__()" 方法。

   "BaseHTTPRequestHandler" 具有下列实例变量：

   client_address

      包含 "(host, port)" 形式的指向客户端地址的元组。

   server

      包含服务器实例。

   close_connection

      应当在 "handle_one_request()" 返回之前设定的布尔值，指明是否要期
      待另一个请求，还是应当关闭连接。

   requestline

      包含 HTTP 请求行的字符串表示。末尾的 CRLF 会被去除。该属性应当由
      "handle_one_request()" 来设定。 如果无有效请求行被处理，则它应当
      被设为空字符串。

   command

      包含具体的命令（请求类型）。例如 "'GET'"。

   path

      包含请求路径。如果 URL 的查询部分存在，"path" 会包含这个查询部分
      。使用 **RFC 3986** 的术语来说，在这里，"path" 包含 "hier-part"
      和 "query"。

   request_version

      包含请求的版本字符串。例如 "'HTTP/1.0'"。

   headers

      存放由 "MessageClass" 类变量所指定的类的实例。该实例会解析并管理
      HTTP 请求中的标头。 "http.client" 中的 "parse_headers()" 函数将
      被用来解析标头并且它需要 HTTP 请求提供有效的 **RFC 5322** 风格的
      标头。

   rfile

      一个 "io.BufferedIOBase" 输入流，准备从可选的输入数据的开头进行
      读取。

   wfile

      包含用于写入响应并发回给客户端的输出流。在写入流时必须正确遵守
      HTTP 协议以便成功地实现与 HTTP 客户端的互操作。

      在 3.6 版本发生变更: 这是一个 "io.BufferedIOBase" 流。

   "BaseHTTPRequestHandler" 具有下列属性：

   server_version

      指定服务器软件版本。你可能会想要重写该属性。该属性的格式为多个以
      空格分隔的字符串，其中每个字符串的形式为 name[/version]。例如
      "'BaseHTTP/0.2'".

   sys_version

      包含 Python 系统版本，采用 "version_string" 方法和
      "server_version" 类变量所支持的形式。例如 "'Python/1.4'"。

   error_message_format

      指定应当被 "send_error()" 方法用来构建发给客户端的错误响应的格式
      字符串。该字符串应使用来自 "responses" 的变量根据传给
      "send_error()" 的状态码来填充默认值。

   error_content_type

      指定发送给客户端的错误响应的 Content-Type HTTP 标头。默认值为
      "'text/html'"。

   protocol_version

      指定服务器所符合的 HTTP 版本。它会在响应中发送以便让客户端知道服
      务器对于未来请求的通信能力。如果设置为 "'HTTP/1.1'"，服务器将允
      许 HTTP 持久连接；但是，你的服务器 *必须* 在所有对客户端的响应中
      包括一个准确的 "Content-Length" 标头 (使用 "send_header()")。为
      了保持向下兼容性，该设置默认为 "'HTTP/1.0'"。

   MessageClass

      指定一个 "email.message.Message" 这样的类来解析 HTTP 标头。通常
      该属性不会被重写，其默认值为 "http.client.HTTPMessage".

   responses

      该属性包含一个整数错误代码与由短消息和长消息组成的二元组的映射。
      例如，"{code: (shortmessage, longmessage)}"。 *shortmessage* 通
      常是作为消息响应中的 *message* 键，而 *longmessage* 则是作为
      *explain* 键。 该属性会被 "send_response_only()" 和
      "send_error()" 方法所使用。

   "BaseHTTPRequestHandler" 实例具有下列方法：

   handle()

      调用 "handle_one_request()" 一次（或者如果启用了永久连接则为多次
      ）来处理传入的 HTTP 请求。 你应该永远不需要重写它；而是要实现适
      当的 "do_*()" 方法。

   handle_one_request()

      此方法将解析请求并将其分配给适当的 "do_*()" 方法。你应该永远不需
      要重写它。

   handle_expect_100()

      When an HTTP/1.1 conformant server receives an "Expect:
      100-continue" request header it responds back with a "100
      Continue" followed by "200 OK" headers. This method can be
      overridden to raise an error if the server does not want the
      client to continue.  For example, the server can choose to send
      "417 Expectation Failed" as a response header and "return
      False".

      Added in version 3.2.

   send_error(code, message=None, explain=None)

      发送并记录回复给客户端的完整的错误信息。数字形式的 *code* 指明
      HTTP 错误代码，可选的 *message* 为简短的易于人类阅读的错误描述。
      *explain* 参数可被用于提供更详细的错误信息；它将使用
      "error_message_format" 属性来进行格式化并在一组完整的标头之后作
      为响应体被发送。 "responses" 属性保存了 *message* 和 *explain*
      的默认值并将在未提供值时被使用；对于未知代码这两者的默认值均为字
      符串 "???"。 如果方法为 HEAD 或响应代码为下列值之一则响应体将为
      空："1*xx*", "204 No Content", "205 Reset Content", "304 Not
      Modified".

      在 3.4 版本发生变更: 错误响应包括一个 Content-Length 标头。增加
      了 *explain* 参数。

   send_response(code, message=None)

      将一个响应标头添加到标头缓冲区并记录被接受的请求。HTTP 响应行会
      被写入到内部缓冲区，后面是 *Server* 和 *Date* 标头。 这两个标头
      的值将分别通过 "version_string()" 和 "date_time_string()" 方法获
      取。 如果服务器不打算使用 "send_header()" 方法发送任何其他标头，
      则 "send_response()" 后面应该跟一个 "end_headers()" 调用。

      在 3.3 版本发生变更: 标头会被存储到内部缓冲区并且需要显式地调用
      "end_headers()"。

   send_header(keyword, value)

      将 HTTP 标头添加到内部缓冲区，它将在 "end_headers()" 或
      "flush_headers()" 被调用时写入输出流。 *keyword* 应当指定标头关
      键字，并以 *value* 指定其值。请注意，在 send_header 调用结束之后
      ，必须调用 "end_headers()" 以便完成操作。

      此方法不会拒绝包含 CRLF 序列的输入。

      在 3.2 版本发生变更: 标头将被存入内部缓冲区。

   send_response_only(code, message=None)

      只发送响应标头，用于当 "100 Continue" 响应被服务器发送给客户端的
      场合。标头不会被缓冲而是直接发送到输出流。如果未指定 *message*，
      则会发送与响应 *code*  相对应的 HTTP 消息。

      此方法不会拒绝包含 CRLF 序列的 *message*。

      Added in version 3.2.

   end_headers()

      将一个空行（指明响应中 HTTP 标头的结束) 添加到标头缓冲区并调用
      "flush_headers()"。

      在 3.2 版本发生变更: 已缓冲的标头会被写入到输出流。

   flush_headers()

      最终将标头发送到输出流并清空内部标头缓冲区。

      Added in version 3.3.

   log_request(code='-', size='-')

      记录一次被接受（成功）的请求。 *code* 应当指定与响应相关联的
      HTTP 代码。如果响应的大小可用，则它应当作为 *size* 形参传入。

   log_error(...)

      当请求无法完成时记录一次错误。默认情况下，它会将消息传给
      "log_message()"，因此它接受同样的参数 (*format* 和一些额外的值)
      。

   log_message(format, ...)

      将任意一条消息记录到 "sys.stderr"。此方法通常会被重写以创建自定
      义的错误日志记录机制。 *format* 参数是标准 printf 风格的格式字符
      串，其中会将传给 "log_message()" 的额外参数用作格式化操作的输入
      。每条消息日志记录的开头都会加上客户端 IP 地址和当前日期时间。

   version_string()

      返回服务器软件的版本字符串。该值为 "server_version" 与
      "sys_version" 属性的组合。

   date_time_string(timestamp=None)

      返回由 *timestamp* 所给定的日期和时间（参数应为 "None" 或为
      "time.time()" 所返回的格式），格式化为一个消息标头。如果省略
      *timestamp*，则会使用当前日期和时间。

      结果看起来像 "'Sun, 06 Nov 1994 08:49:37 GMT'"。

   log_date_time_string()

      返回当前的日期和时间，为日志格式化。

   address_string()

      返回客户端的地址。

      在 3.3 版本发生变更: 在之前版本中，会执行一次名称查找。为了避免
      名称解析的时延，现在将总是返回 IP 地址。

class http.server.SimpleHTTPRequestHandler(request, client_address, server, directory=None)

   这个类会为目录 *directory* 及以下的文件提供发布服务，或者如果未提供
   *directory* 则为当前目录，直接将目录结构映射到 HTTP 请求。

   在 3.7 版本发生变更: 增加了 *directory* 形参。

   在 3.9 版本发生变更: *directory* 形参接受一个 *path-like object*。

   诸如解析请求之类的大量工作都是由基类 "BaseHTTPRequestHandler" 完成
   的。本类实现了 "do_GET()" 和 "do_HEAD()" 函数。

   以下是 "SimpleHTTPRequestHandler" 的类属性。

   server_version

      这会是 ""SimpleHTTP/" + __version__"，其中 "__version__" 定义于
      模块级别。

   extensions_map

      将后缀映射为 MIME 类型的字典，其中包含了覆盖系统默认值的自定义映
      射关系。不区分大小写，因此字典键只应为小写值。

      在 3.9 版本发生变更: 此字典不再填充默认的系统映射，而只包含覆盖
      值。

   "SimpleHTTPRequestHandler" 类定义了以下方法：

   do_HEAD()

      本方法为 "'HEAD'" 请求提供服务：它将发送等同于 "GET" 请求的标头
      。关于可能的标头的更完整解释，请参阅 "do_GET()" 方法。

   do_GET()

      通过将请求解释为相对于当前工作目录的路径，将请求映射到某个本地文
      件。

      如果请求被映射到目录，则会依次检查该目录是否存在 "index.html" 或
      "index.htm" 文件。若存在则返回文件内容；否则会调用
      "list_directory()" 方法生成目录列表。本方法将利用 "os.listdir()"
      扫描目录，如果 "listdir()" 失败，则返回 "404" 出错应答。

      如果请求被映射到文件，则会打开该文件。打开文件时的任何 "OSError"
      异常都会被映射为 "404", "'File not found'" 错误。如果请求中带有
      "'If-Modified-Since'" 标头，而在此时间点之后文件未作修改，则会发
      送 "304", "'Not Modified'" 的响应。否则会调用 "guess_type()" 方
      法猜测内容的类型，该方法会反过来用到 *extensions_map* 变量，并返
      回文件内容。

      将会输出 "'Content-type:'" 头部信息，带上猜出的内容类型，然后是
      "'Content-Length:'" 头部信息，带有文件的大小，以及 "'Last-
      Modified:'" 头部信息，带有文件的修改时间。

      随后跟一个空行来指明标头的结束，再随后是输出文件内容。

      示例用法请见在 Lib/http/server.py 中 "test" 函数的实现。

      在 3.7 版本发生变更: 为 "'If-Modified-Since'" 头部信息提供支持。

"SimpleHTTPRequestHandler" 类的用法可如下所示，以便创建一个非常简单的
Web 服务，为相对于当前目录的文件提供服务:

   import http.server
   import socketserver

   PORT = 8000

   Handler = http.server.SimpleHTTPRequestHandler

   with socketserver.TCPServer(("", PORT), Handler) as httpd:
       print("serving at port", PORT)
       httpd.serve_forever()

"SimpleHTTPRequestHandler" 也可以被子类化以便增强其行为，例如通过重写
类属性 "index_pages" 以使用不同的 index 文件名。

class http.server.CGIHTTPRequestHandler(request, client_address, server)

   This class is used to serve either files or output of CGI scripts
   from the current directory and below. Note that mapping HTTP
   hierarchic structure to local directory structure is exactly as in
   "SimpleHTTPRequestHandler".

   备注:

     CGI scripts run by the "CGIHTTPRequestHandler" class cannot
     execute redirects (HTTP code 302), because code 200 (script
     output follows) is sent prior to execution of the CGI script.
     This pre-empts the status code.

   The class will however, run the CGI script, instead of serving it
   as a file, if it guesses it to be a CGI script.  Only directory-
   based CGI are used --- the other common server configuration is to
   treat special extensions as denoting CGI scripts.

   The "do_GET()" and "do_HEAD()" functions are modified to run CGI
   scripts and serve the output, instead of serving files, if the
   request leads to somewhere below the "cgi_directories" path.

   The "CGIHTTPRequestHandler" defines the following data member:

   cgi_directories

      This defaults to "['/cgi-bin', '/htbin']" and describes
      directories to treat as containing CGI scripts.

   The "CGIHTTPRequestHandler" defines the following method:

   do_POST()

      This method serves the "'POST'" request type, only allowed for
      CGI scripts.  Error 501, "Can only POST to CGI scripts", is
      output when trying to POST to a non-CGI url.

   Note that CGI scripts will be run with UID of user nobody, for
   security reasons.  Problems with the CGI script will be translated
   to error 403.

   从 3.13 版起已弃用，将在 3.15 版中移除: "CGIHTTPRequestHandler" is
   being removed in 3.15.  CGI has not been considered a good way to
   do things for well over a decade. This code has been unmaintained
   for a while now and sees very little practical use. Retaining it
   could lead to further security considerations.


命令行接口
==========

"http.server" can also be invoked directly using the "-m" switch of
the interpreter.  The following example illustrates how to serve files
relative to the current directory:

   python -m http.server [OPTIONS] [port]

可以接受以下选项：

port

   The server listens to port 8000 by default. The default can be
   overridden by passing the desired port number as an argument:

      python -m http.server 9000

-b, --bind <address>

   Specifies a specific address to which it should bind. Both IPv4 and
   IPv6 addresses are supported. By default, the server binds itself
   to all interfaces. For example, the following command causes the
   server to bind to localhost only:

      python -m http.server --bind 127.0.0.1

   Added in version 3.4.

   在 3.8 版本发生变更: 在 "--bind" 选项中支持 IPv6。

-d, --directory <dir>

   Specifies a directory to which it should serve the files. By
   default, the server uses the current directory. For example, the
   following command uses a specific directory:

      python -m http.server --directory /tmp/

   Added in version 3.7.

-p, --protocol <version>

   Specifies the HTTP version to which the server is conformant. By
   default, the server is conformant to HTTP/1.0. For example, the
   following command runs an HTTP/1.1 conformant server:

      python -m http.server --protocol HTTP/1.1

   Added in version 3.11.

--cgi

   "CGIHTTPRequestHandler" can be enabled in the command line by
   passing the "--cgi" option:

      python -m http.server --cgi

   从 3.13 版起已弃用，将在 3.15 版中移除: "http.server" command line
   "--cgi" support is being removed because "CGIHTTPRequestHandler" is
   being removed.

警告:

  "CGIHTTPRequestHandler" and the "--cgi" command-line option are not
  intended for use by untrusted clients and may be vulnerable to
  exploitation. Always use within a secure environment.

--tls-cert

   Specifies a TLS certificate chain for HTTPS connections:

      python -m http.server --tls-cert fullchain.pem

   Added in version 3.14.

--tls-key

   为 HTTPS 连接指定一个私有密钥文件。

   该选项要求已指定 "--tls-cert"。

   Added in version 3.14.

--tls-password-file

   Specifies the password file for password-protected private keys:

      python -m http.server \
             --tls-cert cert.pem \
             --tls-key key.pem \
             --tls-password-file password.txt

   该选项要求已指定 "--tls-cert"。

   Added in version 3.14.


安全考量
========

当处理请求时，"SimpleHTTPRequestHandler" 会解析符号链接，这有可能使得
指定文件夹以外的文件被暴露。

Methods "BaseHTTPRequestHandler.send_header()" and
"BaseHTTPRequestHandler.send_response_only()" assume sanitized input
and do not perform input validation such as checking for the presence
of CRLF sequences. Untrusted input may result in HTTP Header injection
attacks.

较早版本的 Python 不会擦除从 "python -m http.server" 或默认的
"BaseHTTPRequestHandler" ".log_message" 实现发送到 stderr 的日志消息中
的控制字符。 这可能允许连接到你的服务器的远程客户端向你的终端发送恶意
的控制代码。

在 3.12 版本发生变更: 控制字符会在 stderr 日志中被擦除。
