2016-03-25 14 views
3

Ich versuche, eine 0-Byte-Datei mit Anforderungen an owncloud hochzuladen. Ich würde gerne ein dateiähnliches Objekt dafür verwenden. Normalerweise würde ich es so machen:Das Hochladen einer 0-Byte-Datei in owncloud mit Python-Anfragen hängt

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

Aber es friert ein. Wenn ich den Prozess unterbrechen, sehe ich, wo es mit dem Stack-Trace hängt:

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 sagt mir folgende Anfrage sendet Anträge, die in Ordnung zu sein scheint, aber wird nie eine Antwort:

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 

Wenn ich eine leere Zeichenfolge senden, es funktioniert:

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

HTTP Stream:

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 

Dies funktioniert auch:

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)) 

Irgendwelche Ideen, warum dies mit dateiähnliche Objekte nicht funktioniert? Ich verwende die neueste Version der Anfragen (2.9.1) und Python 3.5.

+0

Scheint, dass "Anfragen" b0rken ist; Transfer-Encoding ist auf Chunked gesetzt, aber das ist kein richtiger Chunked-Body. –

Antwort

5

Es scheint einen Fehler in requests zu geben. Ohne Angabe von auth verwendet die Anfrage Transfer-Encoding: chunked und sendet die richtige last-chunk am Ende der Anfrage, aber mit auth wird keine last-chunk gesendet und die Header sind verwirrt.

Von 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 

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

Ein Sender darf kein Content-Length-Header-Feld in jeder Nachricht senden
, die einen Transfer-Encoding-Header-Feld enthält.

Ohne das Argument auth

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

die Anforderung gesendet wird

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⏎ 
⏎ 

(⏎ bedeutet CRLF oben). Aber wenn Sie auth

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

die Anforderung angeben ist

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: */*⏎ 
⏎ 

Sowohl Transfer-Encoding und Content-Length angegeben sind, die es nicht tun sollte, und die letzten Brocken wird nicht gesendet, so dass der Server sitzt auf weitere Brocken warten und requests wartet auf eine Antwort.

+0

Danke für Ihre Antwort. Ich habe es gemeldet: https: // github.com/kennethreitz/Anfragen/Ausgaben/3066 – uphill