add http 206 partial content
This commit is contained in:
parent
c4e190f8bb
commit
de29747dd1
@ -129,7 +129,7 @@ class HttpCli(object):
|
|||||||
response.extend(headers)
|
response.extend(headers)
|
||||||
response_str = "\r\n".join(response).encode("utf-8")
|
response_str = "\r\n".join(response).encode("utf-8")
|
||||||
try:
|
try:
|
||||||
self.s.send(response_str + b"\r\n\r\n" + body)
|
self.s.sendall(response_str + b"\r\n\r\n" + body)
|
||||||
except:
|
except:
|
||||||
raise Pebkac("client disconnected before http response")
|
raise Pebkac("client disconnected before http response")
|
||||||
|
|
||||||
@ -140,7 +140,17 @@ class HttpCli(object):
|
|||||||
self.reply(b"<pre>" + body.encode("utf-8"), *list(args), **kwargs)
|
self.reply(b"<pre>" + body.encode("utf-8"), *list(args), **kwargs)
|
||||||
|
|
||||||
def handle_get(self):
|
def handle_get(self):
|
||||||
self.log("{:4} {}".format(self.mode, self.req))
|
logmsg = "{:4} {}".format(self.mode, self.req)
|
||||||
|
|
||||||
|
if "range" in self.headers:
|
||||||
|
try:
|
||||||
|
rval = self.headers["range"].split("=", 1)[1]
|
||||||
|
except:
|
||||||
|
rval += self.headers["range"]
|
||||||
|
|
||||||
|
logmsg += " [\033[36m" + rval + "\033[0m]"
|
||||||
|
|
||||||
|
self.log(logmsg)
|
||||||
|
|
||||||
# "embedded" resources
|
# "embedded" resources
|
||||||
if self.vpath.startswith(".cpr"):
|
if self.vpath.startswith(".cpr"):
|
||||||
@ -183,7 +193,7 @@ class HttpCli(object):
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
if self.headers["expect"].lower() == "100-continue":
|
if self.headers["expect"].lower() == "100-continue":
|
||||||
self.s.send(b"HTTP/1.1 100 Continue\r\n\r\n")
|
self.s.sendall(b"HTTP/1.1 100 Continue\r\n\r\n")
|
||||||
except KeyError:
|
except KeyError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@ -317,6 +327,13 @@ class HttpCli(object):
|
|||||||
file_lastmod = file_dt.strftime("%a, %b %d %Y %H:%M:%S GMT")
|
file_lastmod = file_dt.strftime("%a, %b %d %Y %H:%M:%S GMT")
|
||||||
|
|
||||||
do_send = True
|
do_send = True
|
||||||
|
status = "200 OK"
|
||||||
|
extra_headers = []
|
||||||
|
logmsg = "{:4} {} {}".format("", self.req, status)
|
||||||
|
|
||||||
|
#
|
||||||
|
# if-modified
|
||||||
|
|
||||||
if "if-modified-since" in self.headers:
|
if "if-modified-since" in self.headers:
|
||||||
cli_lastmod = self.headers["if-modified-since"]
|
cli_lastmod = self.headers["if-modified-since"]
|
||||||
try:
|
try:
|
||||||
@ -327,38 +344,85 @@ class HttpCli(object):
|
|||||||
self.log("bad lastmod format: {}".format(cli_lastmod))
|
self.log("bad lastmod format: {}".format(cli_lastmod))
|
||||||
do_send = file_lastmod != cli_lastmod
|
do_send = file_lastmod != cli_lastmod
|
||||||
|
|
||||||
status = "200 OK"
|
|
||||||
if not do_send:
|
if not do_send:
|
||||||
status = "304 Not Modified"
|
status = "304 Not Modified"
|
||||||
|
|
||||||
|
#
|
||||||
|
# partial
|
||||||
|
|
||||||
|
file_sz = os.path.getsize(fsenc(path))
|
||||||
|
lower = 0
|
||||||
|
upper = file_sz
|
||||||
|
|
||||||
|
if do_send and "range" in self.headers:
|
||||||
|
try:
|
||||||
|
hrange = self.headers["range"]
|
||||||
|
a, b = hrange.split("=", 1)[1].split("-")
|
||||||
|
|
||||||
|
if a.strip():
|
||||||
|
lower = int(a.strip())
|
||||||
|
else:
|
||||||
|
lower = 0
|
||||||
|
|
||||||
|
if b.strip():
|
||||||
|
upper = int(b.strip()) + 1
|
||||||
|
else:
|
||||||
|
upper = file_sz
|
||||||
|
|
||||||
|
if lower < 0 or lower >= file_sz or upper < 0 or upper > file_sz:
|
||||||
|
raise Pebkac("na")
|
||||||
|
|
||||||
|
except:
|
||||||
|
self.loud_reply("invalid range requested: " + hrange)
|
||||||
|
|
||||||
|
status = "206 Partial Content"
|
||||||
|
extra_headers.append(
|
||||||
|
"Content-Range: bytes {}-{}/{}".format(lower, upper - 1, file_sz)
|
||||||
|
)
|
||||||
|
|
||||||
|
logmsg += " [\033[36m" + str(lower) + "-" + str(upper) + "\033[0m]"
|
||||||
|
|
||||||
|
#
|
||||||
|
# send reply
|
||||||
|
|
||||||
mime = mimetypes.guess_type(path)[0] or "application/octet-stream"
|
mime = mimetypes.guess_type(path)[0] or "application/octet-stream"
|
||||||
|
|
||||||
headers = [
|
headers = [
|
||||||
"HTTP/1.1 " + status,
|
"HTTP/1.1 " + status,
|
||||||
"Connection: Keep-Alive",
|
"Connection: Keep-Alive",
|
||||||
"Content-Type: " + mime,
|
"Content-Type: " + mime,
|
||||||
"Content-Length: " + str(os.path.getsize(fsenc(path))),
|
"Content-Length: " + str(upper - lower),
|
||||||
|
"Accept-Ranges: bytes",
|
||||||
"Last-Modified: " + file_lastmod,
|
"Last-Modified: " + file_lastmod,
|
||||||
]
|
]
|
||||||
|
headers.extend(extra_headers)
|
||||||
headers = "\r\n".join(headers).encode("utf-8") + b"\r\n\r\n"
|
headers = "\r\n".join(headers).encode("utf-8") + b"\r\n\r\n"
|
||||||
self.s.send(headers)
|
self.s.sendall(headers)
|
||||||
|
|
||||||
logmsg = "{:4} {} {}".format("", self.req, status)
|
|
||||||
|
|
||||||
if self.mode == "HEAD" or not do_send:
|
if self.mode == "HEAD" or not do_send:
|
||||||
self.log(logmsg)
|
self.log(logmsg)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
with open(fsenc(path), "rb") as f:
|
# 512 kB is optimal for huge files, use 64k
|
||||||
while True:
|
with open(fsenc(path), "rb", 64 * 1024) as f:
|
||||||
|
remains = upper - lower
|
||||||
|
f.seek(lower)
|
||||||
|
while remains > 0:
|
||||||
|
# time.sleep(0.01)
|
||||||
buf = f.read(4096)
|
buf = f.read(4096)
|
||||||
if not buf:
|
if not buf:
|
||||||
break
|
break
|
||||||
|
|
||||||
|
if remains < len(buf):
|
||||||
|
buf = buf[:remains]
|
||||||
|
|
||||||
|
remains -= len(buf)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
self.s.send(buf)
|
self.s.sendall(buf)
|
||||||
except:
|
except:
|
||||||
|
logmsg += " \033[31m" + str(upper - remains) + "\033[0m"
|
||||||
|
self.log(logmsg)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
self.log(logmsg)
|
self.log(logmsg)
|
||||||
|
Loading…
Reference in New Issue
Block a user