Python CGI脚本IOError破管

2 投票
2 回答
2587 浏览
提问于 2025-04-15 16:23

我有一个旧的基于Python的网页表单,我正在更新它,让它使用GPG来加密,而不是使用一个已经不再支持的Python包。当我通过命令行调用这个脚本时,一切都很好,但通过网页浏览器和CGI调用时却出现了一个错误:IOError: [Errno 32] Broken pipe。这个错误在我使用gnupg包或者直接通过子进程与gpg通信时都会出现。

版本信息:

Python 2.4.1 
gnupg 0.2.2 (python GPG wrapper)
Apache/2.2.9 
gpg 1.4.9

这里有一个简化的脚本:

#!/usr/bin/python 

import sys
# send python tracebacks out to the web browser
sys.stderr = sys.stdout
import gnupg
gpg = gnupg.GPG()
gpgkey = 'np'
message = 'Our secret message!'
print "Content-type: text/html\r\n"
print '''<html><head><title>Test GPG access via cgi</title>
          </head><body><pre>'''
print 'message in the clear:'
print message
encrypted = str(gpg.encrypt(message, 'np'))
print 'message encrypted:' 
print encrypted
print '''</pre></body></html>'''sf

当通过命令行调用上面的脚本时,它运行得很好,但通过CGI调用时却产生了以下错误:

message in the clear:
Our secret message!
Traceback (most recent call last):
  File "/home/dkmaster/www/nickads/secure-cgi/gpgtest.py", line 23, in 
    encrypted = str(gpg.encrypt(message, 'np'))
  File "/home/dkmaster/www/nickads/secure-cgi/gnupg.py", line 517, in encrypt
    return self.encrypt_file(StringIO(data), recipients, **kwargs)
  File "/home/dkmaster/www/nickads/secure-cgi/gnupg.py", line 467, in encrypt_file
    self._handle_io(args, file, result, passphrase=passphrase)
  File "/home/dkmaster/www/nickads/secure-cgi/gnupg.py", line 201, in _handle_io
    _copy_data(file, stdin)
  File "/home/dkmaster/www/nickads/secure-cgi/gnupg.py", line 75, in _copy_data
    outstream.write(data)
IOError: [Errno 32] Broken pipe

我还尝试直接通过子进程与GPG通信,而不是使用gnupg模块。

#!/usr/bin/python

import sys
import subprocess
sys.stderr = sys.stdout
print "Content-type: text/html\r\n"
print '''<html><head><title>Test subprocess via cgi</title>
           </head><body><pre>'''

plain_text = 'the quick fox ' * 10
print plain_text
gpgCommand = "/usr/bin/gpg --quiet -a -e -r 'np' "
gpgProcess = subprocess.Popen(
                      gpgCommand,
                      stdin=subprocess.PIPE, 
                      stdout=subprocess.PIPE, 
                      stderr=subprocess.PIPE, 
                      shell=True
                      )
encrypted_text = gpgProcess.communicate(plain_text)[0]
print encrypted_text

同样,这在命令行中运行良好,但通过CGI调用时会产生类似的错误:

Traceback (most recent call last):
  File "/home/dkmaster/www/nickads/secure-cgi/subprocesstest.py", line 20, in 
    encrypted_text = gpgProcess.communicate(plain_text)[0]
  File "/usr/lib/python2.5/subprocess.py", line 670, in communicate
    return self._communicate(input)
  File "/usr/lib/python2.5/subprocess.py", line 1220, in _communicate
    bytes_written = self._write_no_intr(self.stdin.fileno(), buffer(input, input_offset, 512))
  File "/usr/lib/python2.5/subprocess.py", line 999, in _write_no_intr
    return os.write(fd, s)
OSError: [Errno 32] Broken pipe

那么,我该如何修复CGI中的管道问题呢?

2 个回答

0

这是个好问题 - 我不太确定这是不是 python-gnupg 的问题,或者说 gpg 的问题。可能是 subprocesscgi 的问题,或者是它们之间的某种互动。你可以试试用一个非常简单的脚本,读取标准输入(stdin)并把输出写到一个文件里,这样能正常工作吗?

另外,开启日志记录也是个好主意,这样可以看看有没有什么错误信息。可以参考 test_gnupg.py 脚本,里面有关于如何做的例子。

2

我知道我的回答可能来得有点晚,但我最近也遇到了同样的问题,我想我找到了解决办法。

GPG似乎会在终端输出一些信息(比如“你需要一个密码”之类的),即使你把标准输出重定向了——别问我怎么回事 :)

不过,出现“Broken Pipe”的问题似乎是因为在cgi环境下,gpg无法输出这些信息(我在使用uwsgi时遇到的)。即使你加上了--quiet,它还是会打印这些信息。只有当你额外加上--batch时,它才会真的安静下来。

撰写回答