2014-04-11 90 views
0

我有一段PHP代碼,可以將二進制代碼上傳到遠程服務器,我沒有shell訪問權限。 PHP代碼是:POST二進制(視頻)文件使用Python請求

function upload($uri, $filename) { 
$ch = curl_init(); 
curl_setopt($ch, CURLOPT_URL, $uri); 
curl_setopt($ch, CURLOPT_POST, true); 
curl_setopt($ch, CURLOPT_POSTFIELDS, array('file' => '@' . $filename)); 
curl_exec($ch); 
curl_close($ch); 
} 

這導致像頭:

HTTP/1.1 
Host: XXXXXXXXX 
Accept: */* 
Content-Length: 208045596 
Expect: 100-continue 
Content-Type: multipart/form-data; boundary=----------------------------360aaccde050 

我使用請求試圖端口這個交給Python和我不能讓服務器接受我的職務。我已經嘗試過使用requests.post的每種方式,但是頭文件不會模仿上述內容。

這將成功地將二進制文件傳輸到服務器(可以通過觀看Wireshark進行分析),但是由於標題並不是服務器期望被拒絕的。 response_code雖然是200。

files = {'bulk_test2.mov': ('bulk_test2.mov', open('bulk_test2.mov', 'rb'))} 
response = requests.post(url, files=files) 

的請求的代碼導致的頭:

HTTP/1.1 
Host: XXXX 
Content-Length: 160 
Content-Type: multipart/form-data; boundary=250852d250b24399977f365f35c4e060 
Accept-Encoding: gzip, deflate, compress 
Accept: */* 
User-Agent: python-requests/2.2.1 CPython/2.7.5 Darwin/13.1.0 

--250852d250b24399977f365f35c4e060 
Content-Disposition: form-data; name="bulk_test2.mov"; filename="bulk_test2.mov" 


--250852d250b24399977f365f35c4e060-- 

如何提出請求的任何想法,PHP代碼生成的頭相匹配?

+2

拒絕*和*迴應代碼是200?大概會返回錯誤消息頁面? –

+1

我注意到你的'Content-Length'只有160字節。這正是多部分邊界和元數據以及換行符的大小。 **您的文件似乎爲空**。 –

+0

所以如果我使用'res = requests.post(url,data = open_file,headers = {'Content-Type':'multipart/form-data; boundary = -------------- -------------- 360aaccde050'})'我得到'Content-Length:208045390',這是準確的。但是標題又與服務器預期的不同 – user3524641

回答

4

有兩個大的差異:

  1. 的PHP代碼的帖子名爲file場,Python代碼的帖子名爲bulk_test2.mov場。

  2. 您的Python代碼發佈空的文件。 Content-Length頭是160字節,正好是多部分邊界和Content-Disposition聲部佔用的空間量。 bulk_test2.mov文件確實是空的,或者您嘗試多次發佈文件而不回捲或重新打開文件對象。

要解決的第一個問題,在你的字典files使用'file'的關鍵:

files = {'file': open('bulk_test2.mov', 'rb')} 
response = requests.post(url, files=files) 

我以前只是打開的文件對象的價值;在這種情況下,requests將直接從文件對象獲取文件名。

第二個問題是隻有你可以解決的問題。確保你沒有重複使用files時重複張貼。重新打開,或使用files['file'].seek(0)將讀取位置倒回到開始位置。

Expect: 100-continue標頭是一個可選的客戶端功能,要求服務器confirm that the body upload can go ahead;它是而不是所需的標題,並且任何未能發佈文件對象的情況都不會由於requests使用此功能而導致。如果您不使用此功能會導致HTTP服務器行爲異常,那麼它將違反HTTP RFC,您將面臨更大的問題。它肯定不會是requests可以爲你解決的問題。

如果您確實設法發佈實際文件數據,則Content-Length中的任何小變化都是由於Python和PHP之間的(隨機)邊界長度不同造成的。這是正常,而不是上傳問題的原因,除非您的目標服務器非常破碎。再次,不要試圖用Python修復這種破碎。

但是,我會假設你忽略了更簡單的事情。例如,服務器黑名單可能包含某些User-Agent標題。您可以通過使用Session object清除一些默認的標題requests套:

files = {'file': open('bulk_test2.mov', 'rb')} 
session = requests.Session() 
del session.headers['User-Agent'] 
del session.headers['Accept-Encoding'] 
response = session.post(url, files=files) 

,看看是否有差別。

如果服務器失敗,因爲它無法處理HTTP persistent connections處理您的要求,您可以嘗試使用該會話的上下文管理,以確保所有的會話連接都是關閉的:

files = {'file': open('bulk_test2.mov', 'rb')} 
with requests.Session() as session: 
    response = session.post(url, files=files, stream=True) 

,你可以添加:

response.raw.close() 

的好辦法。

+0

因此,上面創建了一個類似Content-Length的標題:208045540 Content-Type:multipart/form-data;邊界= bd19b64db83e4ebbaadc4835f9727856 接受編碼:gzip,放氣,壓縮 接受:*/* 的User-Agent:蟒-請求/ 2.2.1 CPython的/ 2.7.5達爾文/ 13.1.0 --bd19b64db83e4ebbaadc4835f9727856 內容處置:form-data; NAME = 「文件」;文件名=「bulk_test2.mov」這與我所需要的不同(如下所示) 內容長度:208045596 期望值:100-繼續 內容類型:multipart/fo ... – user3524641

+0

不要太注意*精確*標題! '期望:100-continue'不是必需的標題,唯一的做法是暫停上傳正文,直到服務器說可以上傳正文爲止。如果您的HTTP上傳失敗,因爲該標題丟失,您的服務器有更大的問題比這個職位。 –

+0

而16字節的內容長度差異完全可以通過以下事實來解釋:正確生成的多部分邊界在PHP和Python之間相差8個字符。這永遠不會是問題的原因。 –

相關問題