2016-03-25 29 views
3

我想上傳一個0字節的文件與owncloud請求。我想爲此使用類似文件的對象。通常我會這樣做:上傳一個0字節的文件到owncloud與python請求掛起

file_obj = io.BytesIO(b'') 
response = requests.put('http://localhost/remote.php/webdav', 
            auth=('xxx', 'xxx'), 
            data=file_obj) 

但它凍結。如果我打斷這個過程中,我看到它的堆棧跟蹤掛起:

Traceback (most recent call last): 
    File "/home/julian/cc/client/.venv/lib/python3.5/site-packages/requests/packages/urllib3/connectionpool.py", line 376, in _make_request 
    httplib_response = conn.getresponse(buffering=True) 
TypeError: getresponse() got an unexpected keyword argument 'buffering' 

During handling of the above exception, another exception occurred: 

Traceback (most recent call last): 
    File "/home/julian/cc/client/cc/storage/webdav.py", line 360, in <module> 
    main() 
    File "/home/julian/cc/client/cc/storage/webdav.py", line 351, in main 
    data=file_obj) 
    File "/home/julian/cc/client/.venv/lib/python3.5/site-packages/requests/api.py", line 120, in put 
    return request('put', url, data=data, **kwargs) 
    File "/home/julian/cc/client/.venv/lib/python3.5/site-packages/requests/api.py", line 53, in request 
    return session.request(method=method, url=url, **kwargs) 
    File "/home/julian/cc/client/.venv/lib/python3.5/site-packages/requests/sessions.py", line 468, in request 
    resp = self.send(prep, **send_kwargs) 
    File "/home/julian/cc/client/.venv/lib/python3.5/site-packages/requests/sessions.py", line 576, in send 
    r = adapter.send(request, **kwargs) 
    File "/home/julian/cc/client/.venv/lib/python3.5/site-packages/requests/adapters.py", line 376, in send 
    timeout=timeout 
    File "/home/julian/cc/client/.venv/lib/python3.5/site-packages/requests/packages/urllib3/connectionpool.py", line 559, in urlopen 
    body=body, headers=headers) 
    File "/home/julian/cc/client/.venv/lib/python3.5/site-packages/requests/packages/urllib3/connectionpool.py", line 378, in _make_request 
    httplib_response = conn.getresponse() 
    File "/usr/lib64/python3.5/http/client.py", line 1174, in getresponse 
    response.begin() 
    File "/usr/lib64/python3.5/http/client.py", line 282, in begin 
    version, status, reason = self._read_status() 
    File "/usr/lib64/python3.5/http/client.py", line 243, in _read_status 
    line = str(self.fp.readline(_MAXLINE + 1), "iso-8859-1") 
    File "/usr/lib64/python3.5/socket.py", line 575, in readinto 
    return self._sock.recv_into(b) 
KeyboardInterrupt 

Wireshark的告訴我請求sendet下面的請求,這似乎是罰款,但從來沒有得到一個答案:

PUT /remote.php/webdav/test.txt HTTP/1.1 
Host: localhost 
Connection: keep-alive 
Accept-Encoding: gzip, deflate 
Authorization: Basic *********** 
Transfer-Encoding: chunked 
User-Agent: python-requests/2.9.1 
Accept: */* 
Content-Length: 0 

如果我發送一個空字符串,它的工作原理:

response = requests.put('http://localhost/remote.php/webdav/test.txt', 
            auth=('xxx', 'xxx'), 
            data='') 

HTTP流:

PUT /remote.php/webdav/test.txt HTTP/1.1 
Host: localhost 
Content-Length: 0 
Accept-Encoding: gzip, deflate 
Connection: keep-alive 
User-Agent: python-requests/2.9.1 
Accept: */* 
Authorization: Basic ****** 



HTTP/1.1 204 No Content 
Date: Thu, 24 Mar 2016 16:14:28 GMT 
Server: Apache/2.4.10 (Debian) PHP/5.6.19 
X-Powered-By: PHP/5.6.19 
Set-Cookie: xxx=xxx; path=/; HttpOnly 
Expires: Thu, 19 Nov 1981 08:52:00 GMT 
Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0 
Pragma: no-cache 
Set-Cookie: oc_sessionPassphrase=xxxx; path=/; httponly 
Content-Security-Policy: default-src 'self'; script-src 'self' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; frame-src *; img-src * data: blob:; font-src 'self' data:; media-src *; connect-src * 
X-XSS-Protection: 1; mode=block 
X-Content-Type-Options: nosniff 
X-Frame-Options: Sameorigin 
X-Robots-Tag: none 
X-Download-Options: noopen 
X-Permitted-Cross-Domain-Policies: none 
Set-Cookie: xxx=xxx; path=/; HttpOnly 
OC-FileId: xxxxx 
Content-Length: 0 
ETag: "xxx" 
OC-ETag: "xxx" 
Keep-Alive: timeout=5, max=100 
Connection: Keep-Alive 
Content-Type: text/html; charset=UTF-8 

這工作,以及:

def chunker(file_obj): 
    buf = None 
    while buf != b'': 
     print('iter') 
     buf = file_obj.read(16*1024) 
     yield buf 

file_obj = io.BytesIO(b'') 
response = requests.put('http://localhost/remote.php/webdav/test.txt', 
            auth=('xxx', 'xxx'), 
            data=chunker(file_obj)) 

這是爲什麼不與類文件對象的工作任何想法?我正在使用最新版本的請求(2.9.1)和Python 3.5。

+0

似乎'請求'是b0rken; Transfer-Encoding被設置爲分塊,但這不是正確的分塊體。 –

回答

5

requests中似乎有一個錯誤。如果沒有指定auth,請求將使用Transfer-Encoding: chunked,並在請求結束時發送正確的last-chunk,但使用auth則不會發送last-chunk,並且標頭會混淆。

http://tools.ietf.org/html/rfc7230#section-4.1來自:

chunked-body = *chunk 
        last-chunk 
        trailer-part 
        CRLF 

chunk   = chunk-size [ chunk-ext ] CRLF 
        chunk-data CRLF 
chunk-size  = 1*HEXDIG 
last-chunk  = 1*("0") [ chunk-ext ] CRLF 

chunk-data  = 1*OCTET ; a sequence of chunk-size octets 

http://tools.ietf.org/html/rfc7230#section-3.3.2

發送方不能以任何消息
包含Transfer-Encoding頭字段發送Content-Length頭字段。

沒有auth參數

f = io.BytesIO(b'') 
requests.put('http://localhost:8000/asdf', data=f) 

發送的請求是

PUT /asdf HTTP/1.1⏎ 
Host: localhost:8000⏎ 
User-Agent: python-requests/2.9.1⏎ 
Transfer-Encoding: chunked⏎ 
Accept-Encoding: gzip, deflate⏎ 
Connection: keep-alive⏎ 
Accept: */*⏎ 
⏎ 
0⏎ 
⏎ 

(⏎以上表示CRLF)。但是,如果你指定auth

requests.put('http://localhost:8000/asdf', auth=('asdf', 'fdsa'), data=f) 

請求是

PUT /asdf HTTP/1.1⏎ 
Host: localhost:8000⏎ 
Transfer-Encoding: chunked⏎ 
Accept-Encoding: gzip, deflate⏎ 
User-Agent: python-requests/2.9.1⏎ 
Authorization: Basic YXNkZjpmZHNh⏎ 
Content-Length: 0⏎ 
Connection: keep-alive⏎ 
Accept: */*⏎ 
⏎ 

兩個Transfer-EncodingContent-Length指定,它不應該這樣做,而最後一塊不發送,因此服務器坐等待更多的塊來和requests等待迴應。

+0

感謝您的回答。我報告它:https:// github。COM/kennethreitz /請求/問題/ 3066 – uphill