From mboxrd@z Thu Jan  1 00:00:00 1970
Path: news.gmane.io!.POSTED.blaine.gmane.org!not-for-mail
From: Christopher Baines <mail@cbaines.net>
Newsgroups: gmane.lisp.guile.devel
Subject: [PATCH] web: Support reading chunked request bodies.
Date: Thu, 20 Jul 2023 15:02:38 +0100
Message-ID: <20230720140240.23588-1-mail@cbaines.net>
Mime-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Injection-Info: ciao.gmane.io; posting-host="blaine.gmane.org:116.202.254.214";
	logging-data="35017"; mail-complaints-to="usenet@ciao.gmane.io"
To: guile-devel@gnu.org
Original-X-From: guile-devel-bounces+guile-devel=m.gmane-mx.org@gnu.org Thu Jul 20 16:03:04 2023
Return-path: <guile-devel-bounces+guile-devel=m.gmane-mx.org@gnu.org>
Envelope-to: guile-devel@m.gmane-mx.org
Original-Received: from lists.gnu.org ([209.51.188.17])
	by ciao.gmane.io with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
	(Exim 4.92)
	(envelope-from <guile-devel-bounces+guile-devel=m.gmane-mx.org@gnu.org>)
	id 1qMUFC-0008uZ-MS
	for guile-devel@m.gmane-mx.org; Thu, 20 Jul 2023 16:03:02 +0200
Original-Received: from localhost ([::1] helo=lists1p.gnu.org)
	by lists.gnu.org with esmtp (Exim 4.90_1)
	(envelope-from <guile-devel-bounces@gnu.org>)
	id 1qMUEz-0002fq-0X; Thu, 20 Jul 2023 10:02:50 -0400
Original-Received: from eggs.gnu.org ([2001:470:142:3::10])
 by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <mail@cbaines.net>) id 1qMUEt-0002cb-Hw
 for guile-devel@gnu.org; Thu, 20 Jul 2023 10:02:43 -0400
Original-Received: from mira.cbaines.net ([212.71.252.8])
 by eggs.gnu.org with esmtp (Exim 4.90_1)
 (envelope-from <mail@cbaines.net>) id 1qMUEs-0005vR-1K
 for guile-devel@gnu.org; Thu, 20 Jul 2023 10:02:43 -0400
Original-Received: from localhost (unknown [IPv6:2a02:8010:68c1:0:54d1:d5d4:280e:f699])
 by mira.cbaines.net (Postfix) with ESMTPSA id A13D227BBE2
 for <guile-devel@gnu.org>; Thu, 20 Jul 2023 15:02:40 +0100 (BST)
Original-Received: from localhost (localhost [local])
 by localhost (OpenSMTPD) with ESMTPA id 30483633
 for <guile-devel@gnu.org>; Thu, 20 Jul 2023 14:02:40 +0000 (UTC)
X-Mailer: git-send-email 2.41.0
Received-SPF: pass client-ip=212.71.252.8; envelope-from=mail@cbaines.net;
 helo=mira.cbaines.net
X-Spam_score_int: -18
X-Spam_score: -1.9
X-Spam_bar: -
X-Spam_report: (-1.9 / 5.0 requ) BAYES_00=-1.9, SPF_HELO_PASS=-0.001,
 SPF_PASS=-0.001, T_SCC_BODY_TEXT_LINE=-0.01,
 UNPARSEABLE_RELAY=0.001 autolearn=ham autolearn_force=no
X-Spam_action: no action
X-BeenThere: guile-devel@gnu.org
X-Mailman-Version: 2.1.29
Precedence: list
List-Id: "Developers list for Guile,
 the GNU extensibility library" <guile-devel.gnu.org>
List-Unsubscribe: <https://lists.gnu.org/mailman/options/guile-devel>,
 <mailto:guile-devel-request@gnu.org?subject=unsubscribe>
List-Archive: <https://lists.gnu.org/archive/html/guile-devel>
List-Post: <mailto:guile-devel@gnu.org>
List-Help: <mailto:guile-devel-request@gnu.org?subject=help>
List-Subscribe: <https://lists.gnu.org/mailman/listinfo/guile-devel>,
 <mailto:guile-devel-request@gnu.org?subject=subscribe>
Errors-To: guile-devel-bounces+guile-devel=m.gmane-mx.org@gnu.org
Original-Sender: guile-devel-bounces+guile-devel=m.gmane-mx.org@gnu.org
Xref: news.gmane.io gmane.lisp.guile.devel:21903
Archived-At: <http://permalink.gmane.org/gmane.lisp.guile.devel/21903>

Guile already supports chunked response bodies, but chunked request
bodies are allowed as well.  This is useful when you're sending an
unknown amount of data in the request.

* module/web/request.scm (read-request-body): Support the request body
being chunked.
---
 module/web/request.scm | 26 +++++++++++++++++---------
 1 file changed, 17 insertions(+), 9 deletions(-)

diff --git a/module/web/request.scm b/module/web/request.scm
index ff4b94485..b24bc0d77 100644
--- a/module/web/request.scm
+++ b/module/web/request.scm
@@ -221,15 +221,23 @@ on PORT, perhaps using some transfer encoding."
                     (request-headers r) (request-meta r) port)))
 
 (define (read-request-body r)
-  "Reads the request body from R, as a bytevector.  Return ‘#f’
-if there was no request body."
-  (let ((nbytes (request-content-length r)))
-    (and nbytes
-         (let ((bv (get-bytevector-n (request-port r) nbytes)))
-           (if (= (bytevector-length bv) nbytes)
-               bv
-               (bad-request "EOF while reading request body: ~a bytes of ~a"
-                            (bytevector-length bv) nbytes))))))
+  "Reads the request body from R.  If the request body is chunked, a port
+will be returned.  Otherwise, if the request body is present, it will be
+returned as a bytevector or ‘#f’ will be returned if there was no
+request body."
+  (cond
+   ((member '(chunked) (request-transfer-encoding r))
+    (make-chunked-input-port (request-port r)
+                             ;; closing the port is handled elsewhere
+                             #:keep-alive? #t))
+   (else
+    (let ((nbytes (request-content-length r)))
+      (and nbytes
+           (let ((bv (get-bytevector-n (request-port r) nbytes)))
+             (if (= (bytevector-length bv) nbytes)
+                 bv
+                 (bad-request "EOF while reading request body: ~a bytes of ~a"
+                              (bytevector-length bv) nbytes))))))))
 
 (define (write-request-body r bv)
   "Write BV, a bytevector, to the port corresponding to the HTTP
-- 
2.41.0