mirror of
https://github.com/flatpak/flatpak.git
synced 2026-10-28 18:40:32 -04:00
Curl's partial-file, empty-reply and send/receive errors were mapped to G_IO_ERROR_FAILED, so the existing transient-error retry policy skipped connection losses. Map them to partial-input and connection-closed errors without changing the retry limit or retrying streams already written to. Test recovery from empty and truncated replies, including compressed cache output, and verify no partial contents survive the retry.
128 lines
3.9 KiB
Python
Executable File
128 lines
3.9 KiB
Python
Executable File
#!/usr/bin/python3
|
|
|
|
from wsgiref.handlers import format_date_time
|
|
from email.utils import parsedate
|
|
from calendar import timegm
|
|
import gzip
|
|
import sys
|
|
import time
|
|
import zlib
|
|
import os
|
|
|
|
from urllib.parse import parse_qs
|
|
import http.server as http_server
|
|
from io import BytesIO
|
|
|
|
server_start_time = int(time.time())
|
|
|
|
def parse_http_date(date):
|
|
parsed = parsedate(date)
|
|
if parsed is not None:
|
|
return timegm(parsed)
|
|
else:
|
|
return None
|
|
|
|
class RequestHandler(http_server.BaseHTTPRequestHandler):
|
|
attempts = {}
|
|
|
|
def do_GET(self):
|
|
parts = self.path.split('?', 1)
|
|
path = parts[0]
|
|
if len(parts) == 1:
|
|
query = {}
|
|
else:
|
|
query = parse_qs(parts[1], keep_blank_values=True)
|
|
|
|
response = 200
|
|
add_headers = {}
|
|
|
|
attempt = self.attempts.get(self.path, 0)
|
|
self.attempts[self.path] = attempt + 1
|
|
if attempt == 0 and path == '/empty-reply':
|
|
self.close_connection = True
|
|
return
|
|
if attempt == 0 and path == '/partial-reply':
|
|
self.send_response(200)
|
|
self.send_header('Content-Length', '100')
|
|
self.end_headers()
|
|
self.wfile.write(b'incomplete')
|
|
self.close_connection = True
|
|
return
|
|
|
|
if 'modified-time' in query:
|
|
modified_since = self.headers.get("If-Modified-Since")
|
|
if modified_since:
|
|
modified_since_time = parse_http_date(modified_since)
|
|
if modified_since_time <= server_start_time:
|
|
response = 304
|
|
add_headers["Last-Modified"] = format_date_time(server_start_time)
|
|
|
|
if 'etag' in query:
|
|
etag = str(server_start_time)
|
|
|
|
if self.headers.get("If-None-Match") == etag:
|
|
response = 304
|
|
add_headers['Etag'] = etag
|
|
|
|
self.send_response(response)
|
|
for k, v in list(add_headers.items()):
|
|
self.send_header(k, v)
|
|
|
|
if 'max-age' in query:
|
|
self.send_header('Cache-Control', 'max-age=' + query['max-age'][0])
|
|
if 'no-cache' in query:
|
|
self.send_header('Cache-Control', 'no-cache')
|
|
if 'expires-past' in query:
|
|
self.send_header('Expires', format_date_time(server_start_time - 3600))
|
|
if 'expires-future' in query:
|
|
self.send_header('Expires', format_date_time(server_start_time + 3600))
|
|
|
|
if response == 200:
|
|
self.send_header("Content-Type", "text/plain; charset=UTF-8")
|
|
|
|
contents = "path=" + self.path + "\n"
|
|
|
|
if not 'ignore-accept-encoding' in query:
|
|
accept_encoding = self.headers.get("Accept-Encoding")
|
|
if accept_encoding and accept_encoding == 'gzip':
|
|
self.send_header("Content-Encoding", "gzip")
|
|
|
|
buf = BytesIO()
|
|
gzfile = gzip.GzipFile(mode='wb', fileobj=buf)
|
|
if isinstance(contents, bytes):
|
|
gzfile.write(contents)
|
|
else:
|
|
gzfile.write(contents.encode('utf-8'))
|
|
gzfile.close()
|
|
contents = buf.getvalue()
|
|
|
|
self.end_headers()
|
|
|
|
if response == 200:
|
|
if isinstance(contents, bytes):
|
|
self.wfile.write(contents)
|
|
else:
|
|
self.wfile.write(contents.encode('utf-8'))
|
|
|
|
def run(dir):
|
|
RequestHandler.protocol_version = "HTTP/1.0"
|
|
httpd = http_server.HTTPServer( ("127.0.0.1", 0), RequestHandler)
|
|
host, port = httpd.socket.getsockname()[:2]
|
|
with open("httpd-port", 'w') as file:
|
|
file.write("%d" % port)
|
|
try:
|
|
os.write(3, bytes("Started\n", 'utf-8'));
|
|
except:
|
|
pass
|
|
print("Serving HTTP on port %d" % port);
|
|
if dir:
|
|
os.chdir(dir)
|
|
httpd.serve_forever()
|
|
|
|
if __name__ == '__main__':
|
|
dir = None
|
|
if len(sys.argv) >= 2 and len(sys.argv[1]) > 0:
|
|
dir = sys.argv[1]
|
|
|
|
run(dir)
|