~nytpu/smallnet

d4cb2fd7b826ff7e20ae336546665fa76dee96ce — nytpu a month ago 56a47f3 master
gemini, gopher: add FORCE-DECODE option
2 files changed, 13 insertions(+), 9 deletions(-)

M src/gemini.lisp
M src/gopher.lisp
M src/gemini.lisp => src/gemini.lisp +9 -7
@@ 1,4 1,4 @@
;;;; Copyright (c) 2024 nytpu <alex [at] nytpu.com>
;;;; Copyright (c) 2023 nytpu <alex [at] nytpu.com>
;;;; SPDX-License-Identifier: MPL-2.0
;;;; For more license details, see LICENSE or <https://www.mozilla.org/en-US/MPL/2.0/>.
(in-package #:smallnet.gemini)


@@ 145,9 145,10 @@
            (copy-seq meta))))


(defun decode-body-if-possible (body meta &optional override-encoding)
(defun decode-body-if-possible (body meta &optional force-decode override-encoding)
  (when body
    (if (string= "text" (mimeparse::media-type meta))
    (if (or force-decode
            (string= "text" (mimeparse::media-type meta)))
        (restart-case
            (let* ((encoding-id
                     (alexandria:make-keyword


@@ 172,17 173,18 @@
                           (format t "Enter an encoding: ")
                           (force-output)
                           (list (read-line)))
            (decode-body-if-possible body meta encoding)))
            (decode-body-if-possible body meta force-decode encoding)))
        body)))


(defun gemini-request (uri &key host port (follow-redirects 5) no-decode timeout nodelay client-cert client-cert-key client-cert-password (ignore-read/close-ssl-error t))
(defun gemini-request (uri &key host port (follow-redirects 5) no-decode force-decode timeout nodelay client-cert client-cert-key client-cert-password (ignore-read/close-ssl-error t))
  "Perform a Gemini request against URI.  Returns the response body (or NIL if the response doesn't have a body), the response status keyword, the parsed response meta, and the unmodified response meta as multiple values.  The response body is decoded to string if the response type is textual, otherwise it is an octet vector.  Meta is a MIMEPARSE:MEDIA-RANGE if status is :SUCCESS, otherwise it's a string (the unmodified response meta is always a string).

- HOST specifies the host to connect to, overriding the URI's HOST.
- PORT specifies the port to connect to, overriding the URI's PORT.  If no PORT is given and URI doesn't contain a PORT, then 1965 is used.
- FOLLOW-REDIRECTS specifies the number of redirects to follow, or set to NIL to not automatically follow them and just return the redirect status code.
- NO-DECODE, if T, will always return the body as a raw octet vector rather than trying to decode text/* MIME types.
- NO-DECODE, if T, will always return the body as a raw octet vector rather than trying to decode text/* MIME types.  Overrides FORCE-DECODE.
- FORCE-DECODE, if T, will force trying to decode the body as text even if it is not indicated as such.
- TIMEOUT specifies a timeout to use on the socket connection.
- NODELAY disables Nagle's algorithm on the socket used for connection.
- CLIENT-CERT specifies the path to the client certificate to use on most systems, or the identifier in the Windows certificate repository on Windows.


@@ 236,7 238,7 @@
                              :ignore-read/close-ssl-error ignore-read/close-ssl-error)
              (values (if no-decode
                          body
                          (decode-body-if-possible body meta))
                          (decode-body-if-possible body meta force-decode))
                      status meta unparsed-meta)))))))



M src/gopher.lisp => src/gopher.lisp +4 -2
@@ 67,7 67,8 @@
- PORT specifies the port to connect to, overriding the URI's PORT.  If no PORT is given and URI doesn't contain a PORT, then 70 is used.
- RESPONSE-TYPE overrides the response type extracted from the URI, or overrides the default type if URI doesn't have a response type.
- SELECTOR overrides the selector parsed from the URI
- NO-DECODE, if T, will always return the body as a raw octet vector rather than trying to decode text/* MIME types.
- NO-DECODE, if T, will always return the body as a raw octet vector rather than trying to decode text/* MIME types.  Overrides FORCE-DECODE
- FORCE-DECODE, if T, will always try and decode the body as text.
- TIMEOUT specifies a timeout to use on the socket connection.
- NODELAY disables Nagle's algorithm on the socket used for connection.



@@ 101,7 102,8 @@ Note that providing *all* of HOST, PORT, RESPONSE-TYPE, and SELECTOR means that 
             (decf (fill-pointer response) 2)))

          (values
            (if (and (not no-decode) (textual-gophertype? response-type))
            (if (and (not no-decode)
                     (or force-decode (textual-gophertype? response-type)))
                ;; try decoding with UTF-8, if that errors out then try Latin-1
                (handler-case
                    (babel:octets-to-string response :encoding utf-8)