unofficial mirror of guile-devel@gnu.org 
 help / color / mirror / Atom feed
From: Skyler <skyvine@protonmail.com>
To: "guile-devel@gnu.org" <guile-devel@gnu.org>
Subject: [PATCH] Make HTTP header symbols case-insensitive
Date: Sun, 10 Sep 2023 22:34:35 +0000	[thread overview]
Message-ID: <ua8ZKLJQY8AZjq-JzcisRQGtms3Iw-ljjFRNlEeestQzF6hr1i40J5STuz7pHw3RV-7f0f7hcoFydku42tuiUGtaocTd9Vi9JUAIk1v5Q6w=@protonmail.com> (raw)

[-- Attachment #1: Type: text/plain, Size: 4938 bytes --]

The web modules contain logic for operating on headers, including logic
to convert Scheme data to header values, validate the values of
well-known headers, and automatically add missing headers. When working
with headers internally, they are stored as lowercase symbols as is
idiomatic for Scheme code. When writing out the requests, the headers
are converted to title-case, as is idiomatic to HTTP (although HTTP
header names are technically defined to be case-insensitive, unlike
Scheme symbols).

This can cause issues if titlecase symbols are used in the header lists
of functions such as http-request from the (web client) module. In this
case, the headers will not be recognized as well-defined headers, and
they will be validated with the generic validators instead of the
specific ones.

This commit converts header symbols to be all lowercase in the
build-request and build-response functions, to make sure that the system
handles the headers consistently.
---
doc/ref/web.texi | 4 ++++
module/web/http.scm | 8 ++++++++
module/web/request.scm | 9 +++++----
module/web/response.scm | 27 ++++++++++++++-------------
4 files changed, 31 insertions(+), 17 deletions(-)

diff --git a/doc/ref/web.texi b/doc/ref/web.texi
index 607c855..4572b5a 100644
--- a/doc/ref/web.texi
+++ b/doc/ref/web.texi
@@ -471,6 +471,10 @@ Return a true value if @var{val} is a valid Scheme value for the header
with name @var{sym}, or @code{#f} otherwise.
@end deffn

+@deffn {Scheme Procedure} canonicalize-headers headers
+Ensure that the headers are in a canonical Scheme format, in particular
+this converts all header names to lowercase.
+
Now that we have a generic interface for reading and writing headers, we
do just that.

diff --git a/module/web/http.scm b/module/web/http.scm
index 24a4312..9b241dc 100644
--- a/module/web/http.scm
+++ b/module/web/http.scm
@@ -40,6 +40,7 @@
#:use-module (web uri)
#:export (string->header
header->string
+ canonicalize-headers

declare-header!
declare-opaque-header!
@@ -80,6 +81,13 @@
(define (put-non-negative-integer port i)
(put-string port (number->string i)))

+(define (canonicalize-headers headers)
+ "Ensure that the symbolic header name is in lowercase."
+ (map (lambda (header)
+ (cons (string->symbol (string-downcase (symbol->string (car header))))
+ (cdr header)))
+ headers))
+
(define (string->header name)
"Parse NAME to a symbolic header name."
(string->symbol (string-downcase name)))
diff --git a/module/web/request.scm b/module/web/request.scm
index ff4b944..c7366da 100644
--- a/module/web/request.scm
+++ b/module/web/request.scm
@@ -162,7 +162,8 @@
(validate-headers? #t))
"Construct an HTTP request object. If VALIDATE-HEADERS? is true,
the headers are each run through their respective validators."
- (let ((needs-host? (and (equal? version '(1 . 1))
+ (let ((canonicalized-headers (canonicalize-headers headers))
+ (needs-host? (and (equal? version '(1 . 1))
(not (assq-ref headers 'host)))))
(cond
((not (and (pair? version)
@@ -180,12 +181,12 @@ the headers are each run through their respective validators."
uri))
(else
(if validate-headers?
- (validate-headers headers))))
+ (validate-headers canonicalized-headers))))
(make-request method uri version
(if needs-host?
(acons 'host (cons (uri-host uri) (uri-port uri))
- headers)
- headers)
+ canonicalized-headers)
+ canonicalized-headers)
meta port)))

(define* (read-request port #:optional (meta '()))
diff --git a/module/web/response.scm b/module/web/response.scm
index 4ac4d74..9cf9dbd 100644
--- a/module/web/response.scm
+++ b/module/web/response.scm
@@ -111,19 +111,20 @@
(headers '()) port (validate-headers? #t))
"Construct an HTTP response object. If VALIDATE-HEADERS? is true,
the headers are each run through their respective validators."
- (cond
- ((not (and (pair? version)
- (non-negative-integer? (car version))
- (non-negative-integer? (cdr version))))
- (bad-response "Bad version: ~a" version))
- ((not (and (non-negative-integer? code) (< code 600)))
- (bad-response "Bad code: ~a" code))
- ((and reason-phrase (not (string? reason-phrase)))
- (bad-response "Bad reason phrase" reason-phrase))
- (else
- (if validate-headers?
- (validate-headers headers))))
- (make-response version code reason-phrase headers port))
+ (let ((canonicalized-headers (canonicalize-headers headers)))
+ (cond
+ ((not (and (pair? version)
+ (non-negative-integer? (car version))
+ (non-negative-integer? (cdr version))))
+ (bad-response "Bad version: ~a" version))
+ ((not (and (non-negative-integer? code) (< code 600)))
+ (bad-response "Bad code: ~a" code))
+ ((and reason-phrase (not (string? reason-phrase)))
+ (bad-response "Bad reason phrase" reason-phrase))
+ (else
+ (if validate-headers?
+ (validate-headers canonicalized-headers))))
+ (make-response version code reason-phrase canonicalized-headers port)))

(define *reason-phrases*
'((100 . "Continue")

base-commit: f31819b6b179429a617c8bd881dbb61219823e39
--
2.41.0

[-- Attachment #2: Type: text/html, Size: 10376 bytes --]

             reply	other threads:[~2023-09-10 22:34 UTC|newest]

Thread overview: 2+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-09-10 22:34 Skyler [this message]
2023-09-10 22:46 ` [PATCH] Make HTTP header symbols case-insensitive Skyler

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: https://www.gnu.org/software/guile/

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to='ua8ZKLJQY8AZjq-JzcisRQGtms3Iw-ljjFRNlEeestQzF6hr1i40J5STuz7pHw3RV-7f0f7hcoFydku42tuiUGtaocTd9Vi9JUAIk1v5Q6w=@protonmail.com' \
    --to=skyvine@protonmail.com \
    --cc=guile-devel@gnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).