NAME

Net::Gemini - a small gemini client

SYNOPSIS

use Net::Gemini;
my ($gem, $code) = Net::Gemini->get('gemini://example.org/');

use Syntax::Keyword::Match;
match($code : ==) {
  case(0) { die "request failed " . $gem->error }
  case(1) { ... $gem->meta as prompt for input ... }
  case(2) { ... $gem->meta and $gem->content and ... }
  case(3) { ... $gem->meta as redirect ... }
  case(4) { ... $gem->meta as temporary failure ... }
  case(5) { ... $gem->meta as permanent failure ... }
  case(6) { ... $gem->meta as client certificate message ... }
}

DESCRIPTION

This module implements code that may help implement a gemini client in Perl.

CAVEATS

It's a pretty beta module.

The default SSL verification is more or less to accept the connection; this is perhaps not ideal. The caller will need to implement TOFU or a similar means of verifying the other end.

gemini://makeworld.space/gemlog/2020-07-03-tofu-rec.gmi

METHODS

get URI [ parameters ... ]

Tries to obtain the given gemini URI.

Returns an object and a result code. The socket is set to use the :raw binmode. The result code will be 0 if there was a problem with the request--that the URI failed to parse, or the connection failed--or otherwise a gemini code in the range of 1 to 6 inclusive, which will indicate the next steps any subsequent code should take.

For code 2 responses the response body may be split between content and whatever remains unread in the socket, if anything.

Parameters include:

bufsize => strictly-positive-integer

Size of buffer to use for requests, 4096 by default. Note that a naughty server may return data in far smaller increments than this.

early_shutdown => boolean

If true, attempts an early shutdown of the SSL connection after the request is sent. This fiddles with the internal state of IO::Socket::SSL as the shutdown call does not appear to be exposed outside the module.

Use with caution.

ssl => { params }

Passes the given parameters to the IO::Socket::SSL constructor. These could be used to configure e.g. the SSL_verify_mode or to set a verification callback, or to specify a custom SNI host via SSL_hostname.

tofu => boolean

If true, only the leaf certificate will be checked. Otherwise, the full certificate chain will be verified by default, which is probably not what you want when trusting the very first leaf certificate seen.

Also with this flag set hostname verification is turned off; the caller can manage SSL_verifycn_scheme and possibly SSL_verifycn_name via the ssl param if this needs to be customized.

verify_ssl => code-reference

Custom callback function to handle SSL verification. The default is to accept the connection (Trust On All Uses), which is perhaps not ideal. The callback function is passed the host, port, certificate digest, and certificate expiration date (compatible with DateTime::Format::RFC3339) and should return a 1 to verify the connection, or 0 to not.

...->get( $url, ..., verify_ssl => sub {
  my ($host, $port, $digest, $not_before, $not_after, $ok, $raw_cert) = @_;
  return 1 if int rand 2; # certificate is OK
  return 0;
} );

The "okay?" boolean and raw certificate is also passed; these could be used to allow certificates that other code was able to verify, or to perform custom checks on the certificate using probably various routines from Net::SSLeay.

Note that some have argued that under TOFU one should not verify the hostname nor the dates (notBefore, notAfter) of the certificate, only to accept the first certificate presented as-is, like SSH does, and to use that certificate thereafter. This has plusses and minuses.

getmore callback [ bufsize => n ]

A callback interface is provided to consume the response body, if any. Generally this should only be present for response code 2. The meta line should be consulted for details on the MIME type and encoding of the bytes; $body in the following code may need to be decoded.

my $body = '';
$gem->getmore(
    sub {
        my ( $buffer, $length ) = @_;
        $body .= $buffer;
        return 1;
    }
);

The bufsize parameter is as for get.

ACCESSORS

code

Code of the request, 0 to 6 inclusive. Pretty important, so is also returned by get. 0 is an extension to the specification, and is used for connection errors (e.g. host not found) and other problems outside the gemini protocol.

content

The content, if any. Raw bytes. Only if the code is 2.

error

The error message, if any.

host

Host used for the request.

meta

Gemini meta line. Use varies depending on the code.

port

Port used for the request.

socket

Socket to the server. May not be of much use after getmore is done with.

status

Status of the request, a two digit number. Only set when the code is a gemini response (that is, not an internal 0 code).

uri

URI used for the request. Probably could be used with any relative URL returned from the server.

BUGS

None known. But it is a rather incomplete module; that may be considered a bug? The interface is very much subject to change.

SEE ALSO

gemini://gemini.circumlunar.space/docs/specification.gmi (v0.16.1)

COPYRIGHT AND LICENSE

Copyright 2022 Jeremy Mates

This program is distributed under the (Revised) BSD License: https://opensource.org/licenses/BSD-3-Clause