在使用Django 1.2.3,PyISAPIe v1.1.0-rc4和IIS 7.5时,我遇到了大型POST数据(>16384字节(的问题。
例如,当使用 POST 提交大约 60kB 的表单数据时,会发生以下情况:
- 开机自检数据的第一个 16kB 块是正确的
- 下一个 16kB 块是第一个块的重复
- 下一个16kB是第一个块的另一个重复
- 其余的(<16kB(再次正确
有趣的是,当使用 content-type="multipart/form-data"
,它工作正常。
利用这些信息,我在 django\core\handlers\wsgi.py 中追踪了要WSGIRequest._get_raw_post_data的错误可能位置,它与默认(无内容类型(情况分开处理content-type="multipart/form-data"
。
这两种情况都从设置为 PyISAPIe 对象的 self.environ['wsgi.input']
读取。 不同之处在于,默认情况似乎以 16kB 的块读取,而多部分处理程序似乎以略低于 2GB 的块读取。
我对C和Python接口的了解还不够多,无法进一步深入研究,但我猜这个错误在ReadWrite.cpp的ReadClient函数中的PyISAPIe中的某个地方。
我目前的解决方法是向可能产生超过 16kB 数据的表单添加content-type="multipart/form-data"
。
有没有人也遇到过这个问题,或者有人知道如何确定该错误是否实际上在 PyISAPIe 中?
谢谢!
PyISAPIe 作者在这里。
这在存储库的修订版 184 中得到了修复,但在可下载版本中没有修复,如邮件列表中所讨论的那样。
它解决了以前记录的一个错误,该错误显然没有得到太多关注,因为许多用户正在签出源代码而不是下载软件包。或者,无论如何,这是我最好的猜测;无论如何,我计划提供固定代码的可下载版本。
感谢您提请我注意这一点,以便提醒我保持该项目的版本处于正常运行状态。
我挖得更深了一点,我想我发现了这个问题。
在 PyISAPIe\Readwrite.cpp 中:
PyISAPIe_Func(DWORD) ReadClient( Context &Ctx, DWORD Length, void *const Data )
{
if ( !Length )
Length = Ctx.ECB->cbTotalBytes;
if ( !Data )
// Return the size of the the data that would be read
return min(Length, Ctx.ECB->cbTotalBytes);
DWORD Ret, Total = 0;
if ( Length > Ctx.ECB->cbAvailable )
{
[...snip...]
}
else
{
memcpy(Data, Ctx.ECB->lpbData, Length);
Ctx.ECB->cbTotalBytes -= Length;
Ctx.ECB->cbAvailable -= Length;
return Length;
}
如果使用 Length <= Ctx.ECB->cbAvailable 重复调用该方法,它似乎总是将 Ctx.ECB->lpbData 缓冲区的开头复制到 Data 中,而不是从缓冲区中删除该数据或前进指针。 只有当数据耗尽 (cbAvailable == 0( 时,新数据才会在代码的后面正确读入 Data。
仍然不确定如何解决它,但至少我可以通过读取足够大的数据块来解决它,以便一个块将读取所有数据。