Skip to content

Release v0.10.2

Latest

Choose a tag to compare

@github-actions github-actions released this 08 Sep 15:04
· 1 commit to main since this release

Fixed

  • A lang parameter the parser could not read no longer discards the MIME type
    that carries it. lang is cosmetic -- it says what language the body is
    written in, not what the body is -- but failing to validate it returned
    "invalid MIME type" for the whole header, and the caller answers that by
    falling through to the spec's text/gemini default. So a text/plain
    document came back with kind: gemtext, its declared charset dropped, and
    its ordinary lines parsed as gemtext: any line beginning => became an entry
    in document.links, a followable gemini:// target indistinguishable from a
    link the capsule actually published. That is the hazard the truncation path
    already refuses -- half a link must not be presented as a whole one -- arrived
    at from the other side.
    The trigger did not even have to be malformed. The Gemini spec permits a
    comma-separated list of tags, and the list was split on the comma but never
    stripped, so lang=en,fr was accepted and lang=en, fr -- the natural
    spelling, and the one a server emits following ordinary parameter
    conventions -- was not. An unusable value is now dropped at parse time and the
    content type survives it.
    The value that survives is rebuilt from the tags that were checked, so
    lang=en, fr is reported as en,fr. That is not cosmetic: validating a
    stripped value while storing the raw one would admit every character
    strip removes -- CR, LF, U+2028, the separator controls -- into a field
    that rides the one response path which does not otherwise sanitize, and so
    reaches the model verbatim.
    One behaviour change worth naming: a response whose lang was malformed
    used to reach the body-sniffing fallback, so a text/gemini header over gzip
    bytes was reported as binary. That was the bug's side effect, not a
    safeguard -- the same body under lang=en was decoded as gemtext, because
    binary detection was never meant to hinge on the spelling of a language tag.
    Sniffing now happens where it always should have: when the type itself is
    unparseable.
  • A Gemini status line is checked for two ASCII digits. str.isdigit() is
    true of every Unicode decimal, so ٢٠ passed it and int() read it as 20 --
    a status line the spec forbids was honoured as 20 SUCCESS and its body
    rendered. A different spelling of the same malformation, ²⁰, passed the
    check and then failed inside int(), escaping as a bare ValueError that
    was reported to the caller as INVALID_REQUEST: the model was told its own
    valid URL was malformed and sent to rewrite the one thing that was not the
    problem. Both now raise a protocol error naming the response as the fault.
    The Gopher parser already guarded its port field this way.
  • The Gopher cache is keyed on the parsed request rather than on the caller's
    URL string, so refresh invalidates the resource instead of one spelling of
    it. Host case was already folded, but nothing else was: gopher://host/0/a
    and gopher://host:70/0/a are the same request and opened two entries, which
    cost a second download and -- the sharp half -- meant a refresh spelled one
    way left the other's copy in place. The next read was served the pre-refresh
    body marked cached: true, which reads as merely old rather than superseded.
    This is the same defect 0.10.1 fixed for windows of a resource, one level up;
    the Gemini client already built its key from parsed components.
    An internationalized host is folded to its A-label while parsing, which
    parse_gemini_url already did and the Gopher parser did not. socket
    IDNA-encodes a non-ASCII host before resolving it and Gopher sends no host
    header, so gopher://bücher.example/… and gopher://xn--bcher-kva.example/…
    reach the same server over byte-identical wire content -- one request, and so
    one cache entry. Error messages and request_info now report the A-label for
    such a host.

Release Information:

Installation:

pip install gopher-mcp==0.10.2

Verification:
All packages are signed and can be verified using Sigstore.