代码之家  ›  专栏  ›  技术社区  ›  Carson Myers

我是否正确解析了这个HTTPPOST请求?

  •  3
  • Carson Myers  · 技术社区  · 14 年前

    让我先说,我在用 twisted.web 框架。 Twisted.web 的文件上传没有按我所希望的那样工作(它只包含文件数据,没有任何其他信息), cgi.parse_multipart 不像我想要的那样工作(同样的事情, 使用此函数), cgi.FieldStorage FieldStorage twisted.web2 Deferred 困惑和激怒了我(太复杂了我想要的)。

    也就是说,我决定尝试自己解析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
    

    您可以看到,每当到达边界时,我就会启动一个新的“文件”dict。我准备好了 in_header True 说我在分析标题。当我到达一个空行时,我把它切换到 False --但在检查 Content-Type 是为表单值设置的——如果不是,我设置 ignore_current_file

    我知道我应该使用一个库,但是我已经厌倦了阅读文档,尝试在我的项目中使用不同的解决方案,并且仍然让代码看起来合理。我只想讲完这一部分——如果用文件上传解析HTTP POST这么简单,那么我将坚持这一点。

    注意:这段代码目前运行得很好,我只是想知道它是否会阻塞来自某些浏览器的请求。

    3 回复  |  直到 14 年前
        1
  •  1
  •   ars    14 年前

    您试图避免阅读文档,但我认为最好的建议是实际阅读:

    以确保你不会错过任何案子。更简单的方法是使用 poster

        2
  •  7
  •   laidback    12 年前

    我解决这个问题的方法是用cgi.FieldStorage解析内容,比如:

    class Root(Resource):
    
    def render_POST(self, request):
    
        self.headers = request.getAllHeaders()
        # For the parsing part look at [PyMOTW by Doug Hellmann][1]
        img = cgi.FieldStorage(
            fp = request.content,
            headers = self.headers,
            environ = {'REQUEST_METHOD':'POST',
                     'CONTENT_TYPE': self.headers['content-type'],
                     }
        )
    
        print img["upl_file"].name, img["upl_file"].filename,
        print img["upl_file"].type, img["upl_file"].type
        out = open(img["upl_file"].filename, 'wb')
        out.write(img["upl_file"].value)
        out.close()
        request.redirect('/tests')
        return ''
    
        3
  •  1
  •   mvds    14 年前

    contentdisposition头没有定义字段的顺序,而且它可能包含的字段多于文件名。所以你的文件名匹配可能会失败-甚至可能没有一个文件名!

    看到了吗 rfc2183 ( 那是邮寄的,看到了吗 rfc1806 , rfc2616

    另外,我建议在此类regexp中,用\s*替换每个空格,而不要依赖字符大小写。