#lang racket (provide request) (require openssl) (require net/url-string) ;; sends a request to a gemini server, and returns the status, header, ;; and the input port for the rest of the body. ;; this procedure will fail if the response is malformed, however, it ;; is not up to it to validate the contents of the response. (define (request url-str) (define url (string->url url-str)) (define-values (c-in c-out) (ssl-connect (url-host url) (or (url-port url) 1965))) (write-string url-str c-out) (write-string "\r\n" c-out) (define-values (status header) (read-response c-in)) (values status header c-in)) (define (read-response (c-in (current-input-port))) (define maxlen 1027) (let ([header (peek-string maxlen 0 c-in)]) (if (not (string-contains? header "\r\n")) (error "header exceeds maximum length") (let ([header (read-line c-in 'return-linefeed)]) (define-values (status meta) (let ([status-meta (string-split header " ")]) (values (car status-meta) (string-join (cdr status-meta))))) (cond [(> (string-length status) 2) (error "status code exceeds maximum length")] [(andmap (compose not char-numeric?) (string->list status)) (error "status code is not numeric")] [else (values (string->number status) meta)])))))