Unix3上的Python3 CGI HTTPS服务器失败

这个Python3 CGI HTTPS服务器过去几个星期(或几个月)工作,但现在不再在Linux(Ubuntu)下工作。 我试过在Ubuntu 10.04和Ubuntu 14.04上的行为是一样的。

现在,当我尝试访问任何CGI脚本,我得到:

Secure Connection Failed An error occurred during a connection to 127.0.0.1:4443. SSL received a record that exceeded the maximum permissible length. (Error code: ssl_error_rx_record_too_long) 

以下是服务器的代码:

 import http.server import ssl import os server_address = ('', 4443) cert = os.path.abspath('./server.pem') handler = http.server.CGIHTTPRequestHandler handler.cgi_directories = ['/cgi-bin'] httpd = http.server.HTTPServer(server_address, handler) httpd.socket = ssl.wrap_socket(httpd.socket, server_side=True, certfile=cert) print ("Server started...") httpd.serve_forever() 

服务器logging以下错误:

 File "/usr/lib/python3.4/ssl.py", line 618, in read v = self._sslobj.read(len, buffer) ssl.SSLError: [SSL: SSLV3_ALERT_UNEXPECTED_MESSAGE] sslv3 alert unexpected message (_ssl.c:1767) 

如果我禁用SSL,并且在Windows上使用SSL工作正常,这将起作用。 用Python 3.4testing 奇怪的是,这个工作几个月后任何人都可以得到这个脚本(或任何python3 CGI HTTPS服务器)在更新的Linux系统上运行?

我在以下地方找到了答案:
http://www.castro.aus.net/~maurice/OddsAndEnds/blog/files/d2baf24c48b972f18836cac7a27734e2-35.html

解决方法是添加:

 http.server.CGIHTTPRequestHandler.have_fork=False # Force the use of a subprocess 

在启动服务器之前。

这是Mac和Unix实现所必需的,因为出于效率的原因,他们使用fork来启动执行CGI的进程,而不是创建其他实现(如Windows)所使用的子进程。 在一个非包装的CGI实现中,fork工作正常,并且输出被正确地发送到套接字,然而,当套接字是SSL包装的时候,事情发生了严重的错误。

解决办法是强制Unix和Mac实现使用一个子进程,让SSL套接字高效地工作,让Python服务器将CGI脚本的输出传输到客户端,同时将输出转换成SSL。

我仍然不知道为什么这个工作!

尽管OP已经找到了解决方案,但下面是一些更详细的说明:

  • 普通套接字只是内核,但是sslwraped套接字在顶部放置了一个额外的用户空间层。
  • http.server在最后执行cgi程序之前做了一个fork(在支持fork的平台上,不在windows上)并且把文件描述符重新映射到stdin / stdout。 这样执行的程序在普通(仅内核,无ssl)文件描述符上工作
  • 程序的所有写入都直接进入内核套接字,这是普通的未加密数据。
  • 同行会抨击这个普通的数据,因为它期望SSL帧。 它产生的错误类型取决于它获得的数据,例如ssl_error_rx_record_too_long或“错误的版本号”或类似的东西。