从 curl的网页
使用"-C - "告诉curl自动找出恢复传输的方法。然后它使用给定的outputinput文件来计算。
因此,如果使用"-C-"来告诉curl自动找到恢复传输的方法,那么它就会使用给定的输出文件来计算。
curl \
--retry 9999 \
--continue-at - \
https://mydomain.test/some.file.bin \
| target-program
和下载失败(一次)的半途而废,而服务器支持范围请求,会通过一个范围请求,进行curl重试,所以说 target-program
接收全字节的 some.file.bin
作为它的输入?
根据测试,curl会 不 使用范围请求重试。
我写了一个破损的HTTP服务器,要求客户端使用range-request重试以获得完整的响应。使用wget
wget -O - http://127.0.0.1:8888/ | less
结果是,全部答复
abcdefghijklmnopqrstuvwxyz
我可以看到在服务器端,有一种方式的请求与 'Range': 'bytes=24-'
的请求头中。
然而,使用curl
curl --retry 9999 --continue-at - http://127.0.0.1:8888/ | less
导致只有不完整的响应,而服务器日志中没有范围请求。
abcdefghijklmnopqrstuvwx
使用的Python服务器
import asyncio
import re
from aiohttp import web
async def main():
data = b'abcdefghijklmnopqrstuvwxyz'
async def handle(request):
print(request.headers)
# A too-short response with an exception that will close the
# connection, so the client should retry
if 'Range' not in request.headers:
start = 0
end = len(data) - 2
data_to_send = data[start:end]
headers = {
'Content-Length': str(len(data)),
'Accept-Ranges': 'bytes',
}
print('Sending headers', headers)
print('Sending data', data_to_send)
response = web.StreamResponse(
headers=headers,
status=200,
)
await response.prepare(request)
await response.write(data_to_send)
raise Exception()
# Any range request
match = re.match(r'^bytes=(?P<start>\d+)-(?P<end>\d+)?$', request.headers['Range'])
start = int(match['start'])
end = \
int(match['end']) + 1 if match['end'] else \
len(data)
data_to_send = data[start:end + 1]
headers = {
'Content-Range': 'bytes {}-{}/{}'.format(start, end - 1, len(data)),
'Content-Length': str(len(data_to_send)),
}
print('Sending headers', headers)
print('Sending data', data_to_send)
response = web.StreamResponse(
headers=headers,
status=206
)
await response.prepare(request)
await response.write(data_to_send)
await response.write_eof()
return response
app = web.Application()
app.add_routes([web.get(r'/', handle)])
runner = web.AppRunner(app)
await runner.setup()
site = web.TCPSite(runner, '0.0.0.0', 8888)
await site.start()
await asyncio.Future()
asyncio.run(main())