The Guppy Protocol Specification v0.1

(I don't know if anyone is interested in this, but let's give it a try. It started as a thought experiment, when I looked for 'lighter' protocols I can implement on the Pico W. I see Spartan mentioned here and there, and I wonder if there's any interest in going even more ... spartan. If you find this interesting, useful or fun, and have ideas how to improve this protocol, I'd love to hear from you at my-first-name@dimakrasner.com!)

Overview

Guppy is a simple unencrypted client-to-server protocol, for download of text and text-based interfaces that require upload of short input. It uses UDP and inspired by TFTP, DNS and Spartan. The goal is to design a simple, text-based protocol that is easy to implement and can be used to host a "guplog" on a microcontroller (like a Raspberry Pi Pico W, ESP32 or ESP8266) without the overhead of cryptography and TCP sockets.

Requests are always sent as a single packet, while responses can be chunked and each chunk must be acknowledged by the client. The protocol is designed for short-lived sessions that transfer small text files, therefore it doesn't allow failed downloads to be resumed, and doesn't allow upload of big chunks of data.

URLs

If no port is specified in a guppy:// URL, clients and servers must fall back to 6775 ('gu').

The fragment component a guppy:// URL has no special meaning, but clients must not remove it when following links.

MIME Types

The client must support at least text/plain or text/gemini (without the Spartan := type) documents.

If encoding is unspecified, the client may assume it's UTF-8 or ASCII.

Download vs. Upload

In Guppy, all URLs can be (theoretically) be accompanied by user-provided input. The client must provide the user with means for sending a request with user-provided input, to any link line.

Server and content authors should inform users when input is required and describe what kind of input, using the link's user-friendly description.

If input is expected but not provided by the user, the server must respond with an error packet.

Clients may cache the returned error and present it to the user on attempt to access the same page without providing input.

Security and Privacy

The protocol is unencrypted, and these concerns are beyond the scope of this document.

Implementers should use encrypted file formats for input and downloaded content, and arbitrary or even randomized paths (for example, /a.gmi rather than /my-post-about-chess.gmi), if eavesdropping is a concern.

Implementers should use external means, like digitally-signed documents or PGP, as proof of authenticity.

Limitations

Clients and servers should restrict packets to 512 bytes.

Client and servers should handle timeouts gracefully and must distinguish between timeout and proper termination of the session.

Packet Types

There are 6 packet types:

All packets begin with a "status line", followed by \r\n.

Requests

url\r\n

The query part specifies user-provided input, percent-encoded.

The server must respond with a success, redirect or error packet.

Success

2 type\r\n

$data

The type field specifies the response MIME type and must not be empty.

The server may send a chunked response, by sending continuation packets after the success packet.

Clients should start displaying the response as soon as possible.

Continuation

arbitrary\r\n

$data

The status line contains arbitrary data, and must be unique.

If the client begins to display a textual response before the entire response has been received, it must not assume that the response is split on a line boundary: a long line may be sent in multiple response packets.

End-of-file

arbitrary\r\n

The server must mark the end of the transmission by sending a continuation packet without any data, even if the response fits in a single packet.

Clients must wait for the "end of file" packet, to differentiate between timeout, a partially received response and a successfully received response.

Acknowledgement

arbitrary\r\n

The client must acknowledge every success, continuation or end-of-file packet by echoing its status line back to the server.

The server must wait for the client to acknowledge the previous chunk of the response (the success packet or the previous continuation packet) before sending the next continuation packet.

The client may attempt re-transmission of an acknowledgement packet and the server must ignore acknowledgement packets it's not waiting for.

Redirect

3 url\r\n

The URL may be relative.

The client must inform the user of the redirection.

The client may remember redirected URLs. The server must not assume clients don't do this.

The client should limit the number of redirects during the handling of a single request.

The client may forbid a series of redirects, and may prompt the user to confirm each redirect.

Error

4 error\r\n

Clients must display the error to the user.

Examples

Success - Single Packet

If the URL is guppy://localhost/a and the response is "# Title 1\n":

> guppy://localhost/a\r\n

< 2 text/gemini\r\n# Title 1\n

> 2 text/gemini\r\n

< eof\r\n

Success - Single Packet with User Input

If the URL is guppy://localhost/a and input is "b c":

> guppy://localhost/a?b%20c\r\n

< 2 text/gemini\r\n# Title 1\n

> 2 text/gemini\r\n

< eof\r\n

Success - Multiple Packets

If the URL is guppy://localhost/a and the response is "# Title 1\nParagraph 1\n":

> guppy://localhost/a\r\n

< 2 text/gemini\r\n# Title 1\n

> 2 text/gemini\r\n

< 1000\r\nParagraph 1

> 1000\r\n\r\n

< 1001\r\n\n

> 1001\r\n

< eof\r\n

Redirect - Absolute URL

> guppy://localhost/a\r\n

< 3 guppy://localhost/b\r\n

Redirect - Relative URL

> guppy://localhost/a\r\n

< 3 /b\r\n

Error

> guppy://localhost/search\r\n

< 4 No search keywords specified\r\n