首先我要说的是,我正在使用twisted.web
框架。Twisted.web
的文件上传没有像我想要的那样工作(它只包含文件数据,而不包含任何其他信息),cgi.parse_multipart
没有像我想要的那样工作(同样的事情,twisted.web
使用此功能),cgi.FieldStorage
不起作用(因为我是通过twisted而不是CGI接口获取POST数据——据我所知,FieldStorage
尝试通过 stdin 获取请求),并且twisted.web2
对我不起作用,因为使用Deferred
让我感到困惑和愤怒(对于我想要的来说太复杂了)。
话虽这么说,我决定尝试自己解析 HTTP 请求。
使用 Chrome,HTTP 请求的构成如下:
------WebKitFormBoundary7fouZ8mEjlCe92pq
Content-Disposition: form-data; name="upload_file_nonce"
11b03b61-9252-11df-a357-00266c608adb
------WebKitFormBoundary7fouZ8mEjlCe92pq
Content-Disposition: form-data; name="file"; filename="login.html"
Content-Type: text/html
<!DOCTYPE html>
<html>
<head>
...
------WebKitFormBoundary7fouZ8mEjlCe92pq
Content-Disposition: form-data; name="file"; filename=""
------WebKitFormBoundary7fouZ8mEjlCe92pq--
它总是这样形成的吗?我用正则表达式解析它,如下所示(请原谅代码墙):
(注意,我剪掉了大部分代码,只显示我认为相关的内容(正则表达式(是的,嵌套括号),这是一个__init__
方法(迄今为止唯一的方法)Uploads
我构建的类。完整的代码可以在修订历史中看到(我希望我没有匹配任何括号)
if line == "--{0}--".format(boundary):
finished = True
if in_header == True and not line:
in_header = False
if 'type' not in current_file:
ignore_current_file = True
if in_header == True:
m = re.match(
"Content-Disposition: form-data; name=\"(.*?)\"; filename=\"(.*?)\"$", line)
if m:
input_name, current_file['filename'] = m.group(1), m.group(2)
m = re.match("Content-Type: (.*)$", line)
if m:
current_file['type'] = m.group(1)
else:
if 'data' not in current_file:
current_file['data'] = line
else:
current_file['data'] += line
您可以看到,每当达到边界时,我都会启动一个新的“文件”字典。我设置in_header
to True
说我正在解析标头。当我到达一个空行时,我将其切换到False
-- 但不是在检查是否Content-Type
已设置为该表单值 - 如果没有,我设置ignore_current_file
因为我只是在寻找文件上传。
我知道我应该使用一个库,但是我厌倦了阅读文档,尝试在我的项目中使用不同的解决方案,并且仍然让代码看起来合理。我只是想跳过这一部分——如果解析带有文件上传的 HTTP POST 如此简单,那么我将坚持下去。
注意:此代码目前工作正常,我只是想知道它是否会阻塞/吐出来自某些浏览器的请求。