将0字节的文件上载到owncloud时,python请求将挂起

2024-09-27 20:16:19 发布

您现在位置:Python中文网/ 问答频道 /正文

我正在尝试上载一个0字节的文件,其中包含对owncloud的请求。我想用一个类似文件的对象。通常我会这样做:

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

但它冻结了。如果我中断进程,我会看到它与堆栈跟踪挂起的位置:

^{pr2}$

Wireshark告诉我请求发送以下请求,看起来不错,但始终没有得到答复:

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

你知道为什么这不适用于类似文件的对象吗?我使用的是最新版本的requests(2.9.1)和python3.5。在


Tags: testsrctxtobjlocalhosthttpdataremote
1条回答
网友
1楼 · 发布于 2024-09-27 20:16:19

requests中似乎有一个bug。在没有指定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

A sender MUST NOT send a Content-Length header field in any message
that contains a Transfer-Encoding header field.

没有auth参数

^{pr2}$

发送的请求是

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等待响应。在

相关问题 更多 >

    热门问题