!/usr/bin/env python3

"""

A reference spartan:// protocol client.

Copyright (c) Michael Lazar

Blue Oak Model License 1.0.0

"""

import argparse

import shutil

import socket

import sys

from urllib.parse import urlparse, unquote_to_bytes, quote_from_bytes

def fetch_url(url, infile=None):

url_parts = urlparse(url)

if url_parts.scheme != "spartan":

    raise ValueError("Unrecognized URL scheme")

host = url_parts.hostname

port = url_parts.port or 300

path = url_parts.path or "/"

query = url_parts.query

redirect_url = None

with socket.create_connection((host, port)) as sock:

    if infile:

        data = infile.read()

    elif query:

        data = unquote_to_bytes(query)

    else:

        data = b""

    encoded_host = host.encode("idna")

    encoded_path = quote_from_bytes(unquote_to_bytes(path)).encode("ascii")

    sock.send(b"%s %s %d\r\n" % (encoded_host, encoded_path, len(data)))

    sock.send(data)

    fp = sock.makefile("rb")

    response = fp.readline(4096).decode("ascii").strip("\r\n")

    print(response, file=sys.stderr, flush=True)

    parts = response.split(" ", maxsplit=1)

    code, meta = int(parts[0]), parts[1]

    if code == 2:

        shutil.copyfileobj(fp, sys.stdout.buffer)

    elif code == 3:

        redirect_url = url_parts._replace(path=meta).geturl()

if redirect_url:

    fetch_url(redirect_url)

parser = argparse.ArgumentParser(description="A spartan client")

parser.add_argument("url")

parser.add_argument("--infile", type=argparse.FileType("rb"))

args = parser.parse_args()

try:

fetch_url(args.url, args.infile)

except ValueError as e:

print(f"Error: {e}", file=sys.stderr)

except KeyboardInterrupt:

pass

Proxy Information
Original URL
gemini://spartan.mozz.us/spartan_client.py
Status Code
Success (20)
Meta
text/x-python
Capsule Response Time
702.628327 milliseconds
Gemini-to-HTML Time
0.698958 milliseconds

This content has been proxied by September (3851b).