2010-07-18 63 views
3

讓我開始說,我正在使用twisted.web框架。的Twisted.web文件上傳沒有工作,就像我想它(只包括文件數據,而不是任何其他信息),cgi.parse_multipart不起作用像我希望它(同樣的事情,twisted.web使用此功能),cgi.FieldStorage沒有工作(因爲我通過扭曲而不是CGI接口獲取POST數據 - 據我所知,FieldStorage試圖通過stdin獲取請求),並且twisted.web2對我不起作用,因爲使用Deferred困惑和激怒我(對於我想要的太複雜)。我正確解析這個HTTP POST請求嗎?

話雖這麼說,我決定嘗試,只是解析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 I類建造的。完整的代碼可以在修訂歷史記錄中可以看出(我希望我沒有任何錯配括號)

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_headerTrue說我解析頭。當我到了一個空行,我切換到False - 但在檢查是否爲該表單值設置了Content-Type之前沒有 - 如果沒有,我設置了ignore_current_file,因爲我只查找文件上傳。

我知道我應該使用一個圖書館,但我生病閱讀文檔的死亡,試圖讓不同的解決方案,在我的項目工作,仍然有代碼看起來合理。我只想通過這個部分 - 而且如果解析帶有文件上傳的HTTP POST這很簡單,那麼我會堅持下去。

注:該代碼完全適用於現在,我只是想知道它是否會嗆/從某些瀏覽器吐出的請求。

+0

遞延實際上是要走的路,因爲這是異步的魔法是如何發生的。 – pcurry 2017-05-18 19:50:36

回答

1

你試圖避免讀取文檔,但我認爲最好的建議是實際讀取:

,以確保你不不會錯過任何情況。更簡單的路線可能是使用poster庫。

+0

這並不是說我試圖避免文檔,而是要麼找不到足夠的文檔,要麼導致死路一條(不做我想做的事)。我一定會給那些閱讀,雖然 – 2010-07-18 10:40:11

+0

明白了,我誤解了那一點。肯定閱讀RFC,因爲它們是關於這些事情的官方文字,但是您很有可能懷疑實際的瀏覽器在野外實施是否存在陰暗的角落。 – ars 2010-07-18 10:46:38

+0

此外,它似乎只是爲了創建HTTP請求的海報 - 我看不出有關解碼的任何文檔。它可以解碼嗎? – 2010-07-18 10:47:34

1

內容處置頭具有用於字段沒有定義命令,再加上它可能包含不只是文件名多個字段。所以你的文件名匹配可能會失敗 - 甚至可能沒有文件名!

rfc2183編輯這對郵件,看rfc1806rfc2616,也許更多用於HTTP)

另外我想在這些類型的正則表達式的建議,以取代每一個空間由\ S *,而不是依賴特徵案例。

+0

這些都指定郵件或附件,我主要在尋找'form-data' Content-Disposition。但他們看起來一樣,我可能會看看所有的例子 – 2010-07-18 11:15:31

+0

無論確切的rfc,我認爲依靠字段的可用性/缺席和確切的順序是不是非常明智的。即使「filename」是現在唯一的字段,將來也可能會添加更多,並且代碼會中斷。 – mvds 2010-07-18 12:24:00

7

我對這個問題的解決方案與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 '' 
+0

即使我使用扭曲和克萊恩作爲網絡服務器,這對我來說仍然適用。 – Sergey 2016-05-25 13:11:18