#lang racket/gui (require openssl net/url-string) (require "strings.rkt") (provide request-url request-url-str) (define (format-request url) (~a (url->string url) "\r\n")) (define (request-url-str url-str) (let ([url (string->url (if (equal? "gemini://" (substring url-str 0 9)) url-str (~a "gemini://" url-str)))]) (unless (url-port url) (set-url-port! url 1965)) (request-url (url-host url) (url-port url) (format-request url)))) (define (request-url host port request) (let-values ([(in out) (ssl-connect/enable-break host port)]) (file-stream-buffer-mode out 'none) (display request out) (flush-output out) (let* ( [response-head (read-line in)] [status (string->number (substring response-head 0 2))] [status-first (quotient status 10)] [status-last (modulo status 10)] [info (if (> (string-length response-head) 2) (string-trim (substring response-head 2)) none-given)]) (case status-first [(1) (case status-last [(1) (~a sensitive-input info)] [else (~a normal-input info)])] [(2) (case info [("text/gemini" "text/plain") (port->string in)] [else (~a unhandled-mimetype info)])] [(3) (case status-last [(1) (displayln (~a permanently-redirecting info))] [else (displayln (~a temporarily-redirecting info))]) (request-url-str info)] [(4) (case status-last [(1) (~a server-unavailable info)] [(2) (~a cgi-error info)] [(3) (~a proxy-error info)] [(4) (~a slow-down info)] [else (~a temporary-unspecified info)])] [(5) (case status-last [(1) (~a file-not-found info)] [(2) (~a file-gone info)] [(3) (~a proxy-refused info)] [(9) (~a bad-request info)] [else (~a permanent-unspecified info)])] [(6) (case status-last [(1) (~a cert-unauthorized info)] [(2) (~a cert-invalid info)] [else (~a cert-required info)])] [else (~a bad-status status)]))))