-- Leo's gemini proxy

-- Connecting to guppy.000090000.xyz:1965...

-- Connected

-- Sending request

-- Meta line: 20 text/gemini


import socket

import sys

from urllib.parse import urlparse

import select


s = socket.socket(type=socket.SOCK_DGRAM)

url = urlparse(sys.argv[1])

s.connect((url.hostname, 6775))


request = (sys.argv[1] + "\r\n").encode('utf-8')


sys.stderr.write(f"Sending request for {sys.argv[1]}\n")

s.send(request)


buffered = b''

mime_type = None

tries = 0

last_buffered = 0

chunks = {}

while True:

ready, _, _ = select.select([s.fileno()], [], [], 2)


if we still haven't received anything from the server, retry the request

if len(chunks) == 0 and not ready:

if tries > 5:

raise Exception("All 5 tries have failed")


sys.stderr.write(f"Retrying request for {sys.argv[1]}\n")

s.send(request)

tries += 1

continue


if we're waiting for packet n+1, retry ack packet n

if not ready and last_buffered > 0:

sys.stderr.write(f"Retrying ack for packet {last_buffered}\n")

s.send(f"{last_buffered}\r\n".encode('utf-8'))

continue


receive and parse the next packet

pkt = s.recv(4096)

crlf = pkt.index(b'\r\n')

header = pkt[:crlf]


try:

parse the success packet header

space = header.index(b' ')

seq = int(header[:space])

mime_type = header[space + 1:]


if seq == 4:

raise Exception(f"Error: {mime_type.decode('utf-8')}")


if seq == 3:

raise Exception(f"Redirected to {mime_type.decode('utf-8')}")


if seq == 1:

raise Exception(f"Input required: {mime_type.decode('utf-8')}")


if seq < 6:

raise Exception(f"Invalid status code: {seq}")

except ValueError as e:

parse the continuation or EOF packet header

seq = int(header)


if seq in chunks:

sys.stderr.write(f"Ignoring duplicate packet {seq} and resending ack\n")

s.send(f"{seq}\r\n".encode('utf-8'))

continue


if last_buffered == 0 and mime_type is not None:

sys.stderr.write(f"Response is of type {mime_type.decode('utf-8')}\n")


sys.stderr.write(f"Sending ack for packet {seq}\n")

s.send(f"{seq}\r\n".encode('utf-8'))


data = pkt[crlf + 2:]

if last_buffered == 0 or seq == last_buffered + 1:

sys.stderr.write(f"Received packet {seq} with {len(data)} bytes of data\n")

else:

sys.stderr.write(f"Received out-of-order packet {seq} with {len(data)} bytes of data\n")


chunks[seq] = data


concatenate the consequentive response chunks we have

while (last_buffered == 0 and mime_type is not None) or seq == last_buffered + 1:

data = chunks[seq]

sys.stderr.write(f"Queueing packet {seq} for display\n")

buffered += data

last_buffered = seq


print the buffered text if we can

try:

print(buffered.decode('utf-8'))

last_buffered = seq

sys.stderr.write("Flushed the buffer to screen\n")

buffered = b''

except UnicodeDecodeError:

sys.stderr.write("Cannot print buffered text until valid UTF-8\n")

continue


stop once we printed everything until the end-of-file packet

if not chunks[last_buffered]:

sys.stderr.write("Reached end of document\n")

break

-- Response ended

-- Page fetched on Fri May 10 13:51:56 2024