mirror of
https://github.com/9001/copyparty.git
synced 2025-08-17 09:02:15 -06:00
less todo (last-modified / HTTP 304)
This commit is contained in:
parent
5b1e73ff71
commit
d59ad1b119
|
@ -62,9 +62,7 @@ pip install black bandit pylint flake8 # vscode tooling
|
||||||
|
|
||||||
roughly sorted by priority
|
roughly sorted by priority
|
||||||
|
|
||||||
* http error handling (conn.status or handler-retval)
|
|
||||||
* look into android thumbnail cache file format
|
* look into android thumbnail cache file format
|
||||||
* last-modified header
|
|
||||||
* support pillow-simd
|
* support pillow-simd
|
||||||
* figure out the deal with pixel3a not being connectable as hotspot
|
* figure out the deal with pixel3a not being connectable as hotspot
|
||||||
* pixel3a having unpredictable 3sec latency in general :||||
|
* pixel3a having unpredictable 3sec latency in general :||||
|
||||||
|
|
|
@ -8,6 +8,7 @@ __copyright__ = 2019
|
||||||
__license__ = "MIT"
|
__license__ = "MIT"
|
||||||
__url__ = "https://github.com/9001/copyparty/"
|
__url__ = "https://github.com/9001/copyparty/"
|
||||||
|
|
||||||
|
import locale
|
||||||
import argparse
|
import argparse
|
||||||
from textwrap import dedent
|
from textwrap import dedent
|
||||||
|
|
||||||
|
@ -35,6 +36,18 @@ class RiceFormatter(argparse.HelpFormatter):
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
|
for x in [
|
||||||
|
"en_US.UTF-8",
|
||||||
|
"English_United States.UTF8",
|
||||||
|
"English_United States.1252",
|
||||||
|
]:
|
||||||
|
try:
|
||||||
|
locale.setlocale(locale.LC_ALL, x)
|
||||||
|
print("Locale:", x)
|
||||||
|
break
|
||||||
|
except:
|
||||||
|
continue
|
||||||
|
|
||||||
ap = argparse.ArgumentParser(
|
ap = argparse.ArgumentParser(
|
||||||
formatter_class=RiceFormatter,
|
formatter_class=RiceFormatter,
|
||||||
prog="copyparty",
|
prog="copyparty",
|
||||||
|
|
|
@ -6,6 +6,7 @@ import os
|
||||||
import stat
|
import stat
|
||||||
import time
|
import time
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
import calendar
|
||||||
import mimetypes
|
import mimetypes
|
||||||
import cgi
|
import cgi
|
||||||
|
|
||||||
|
@ -45,7 +46,7 @@ class HttpCli(object):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
try:
|
try:
|
||||||
mode, self.req, _ = headerlines[0].split(" ")
|
self.mode, self.req, _ = headerlines[0].split(" ")
|
||||||
except:
|
except:
|
||||||
raise Pebkac("bad headers:\n" + "\n".join(headerlines))
|
raise Pebkac("bad headers:\n" + "\n".join(headerlines))
|
||||||
|
|
||||||
|
@ -99,12 +100,12 @@ class HttpCli(object):
|
||||||
self.vpath = unquotep(vpath)
|
self.vpath = unquotep(vpath)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
if mode == "GET":
|
if self.mode in ["GET", "HEAD"]:
|
||||||
return self.handle_get()
|
return self.handle_get()
|
||||||
elif mode == "POST":
|
elif self.mode == "POST":
|
||||||
return self.handle_post()
|
return self.handle_post()
|
||||||
else:
|
else:
|
||||||
raise Pebkac('invalid HTTP mode "{0}"'.format(mode))
|
raise Pebkac('invalid HTTP mode "{0}"'.format(self.mode))
|
||||||
|
|
||||||
except Pebkac as ex:
|
except Pebkac as ex:
|
||||||
try:
|
try:
|
||||||
|
@ -114,6 +115,8 @@ class HttpCli(object):
|
||||||
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
def reply(self, body, status="200 OK", mime="text/html", headers=[]):
|
def reply(self, body, status="200 OK", mime="text/html", headers=[]):
|
||||||
# TODO something to reply with user-supplied values safely
|
# TODO something to reply with user-supplied values safely
|
||||||
response = [
|
response = [
|
||||||
|
@ -139,7 +142,7 @@ 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("GET " + self.req)
|
self.log("{:4} {}".format(self.mode, self.req))
|
||||||
|
|
||||||
# "embedded" resources
|
# "embedded" resources
|
||||||
if self.vpath.startswith(".cpr"):
|
if self.vpath.startswith(".cpr"):
|
||||||
|
@ -312,15 +315,41 @@ class HttpCli(object):
|
||||||
self.parser.drop()
|
self.parser.drop()
|
||||||
|
|
||||||
def tx_file(self, path):
|
def tx_file(self, path):
|
||||||
sz = os.path.getsize(fsenc(path))
|
file_ts = os.path.getmtime(fsenc(path))
|
||||||
mime = mimetypes.guess_type(path)[0]
|
file_dt = datetime.utcfromtimestamp(file_ts)
|
||||||
header = "HTTP/1.1 200 OK\r\nConnection: Keep-Alive\r\nContent-Type: {}\r\nContent-Length: {}\r\n\r\n".format(
|
file_lastmod = file_dt.strftime("%a, %b %d %Y %H:%M:%S GMT")
|
||||||
mime, sz
|
|
||||||
).encode(
|
|
||||||
"utf-8"
|
|
||||||
)
|
|
||||||
|
|
||||||
self.s.send(header)
|
do_send = True
|
||||||
|
if "if-modified-since" in self.headers:
|
||||||
|
cli_lastmod = self.headers["if-modified-since"]
|
||||||
|
try:
|
||||||
|
cli_dt = time.strptime(cli_lastmod, "%a, %b %d %Y %H:%M:%S GMT")
|
||||||
|
cli_ts = calendar.timegm(cli_dt)
|
||||||
|
do_send = int(file_ts) > int(cli_ts)
|
||||||
|
except:
|
||||||
|
self.log("bad lastmod format: {}".format(cli_lastmod))
|
||||||
|
do_send = file_lastmod != cli_lastmod
|
||||||
|
|
||||||
|
status = "200 OK"
|
||||||
|
if not do_send:
|
||||||
|
status = "304 Not Modified"
|
||||||
|
|
||||||
|
headers = [
|
||||||
|
"HTTP/1.1 " + status,
|
||||||
|
"Connection: Keep-Alive",
|
||||||
|
"Content-Type: " + mimetypes.guess_type(path)[0],
|
||||||
|
"Content-Length: " + str(os.path.getsize(fsenc(path))),
|
||||||
|
"Last-Modified: " + file_lastmod,
|
||||||
|
]
|
||||||
|
|
||||||
|
headers = "\r\n".join(headers).encode("utf-8") + b"\r\n\r\n"
|
||||||
|
self.s.send(headers)
|
||||||
|
|
||||||
|
logmsg = "{:4} {} {}".format("", self.req, status)
|
||||||
|
|
||||||
|
if self.mode == "HEAD" or not do_send:
|
||||||
|
self.log(logmsg)
|
||||||
|
return True
|
||||||
|
|
||||||
with open(fsenc(path), "rb") as f:
|
with open(fsenc(path), "rb") as f:
|
||||||
while True:
|
while True:
|
||||||
|
@ -333,6 +362,9 @@ class HttpCli(object):
|
||||||
except ConnectionResetError:
|
except ConnectionResetError:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
self.log(logmsg)
|
||||||
|
return True
|
||||||
|
|
||||||
def tx_mounts(self):
|
def tx_mounts(self):
|
||||||
html = self.conn.tpl_mounts.render(this=self)
|
html = self.conn.tpl_mounts.render(this=self)
|
||||||
self.reply(html.encode("utf-8"))
|
self.reply(html.encode("utf-8"))
|
||||||
|
|
Loading…
Reference in a new issue