]> git.ipfire.org Git - thirdparty/openssl.git/commitdiff
http_client.c: fix calculation of Content-Length in set1_content()
authorDr. David von Oheimb <David.von.Oheimb@siemens.com>
Fri, 1 Jul 2022 15:46:36 +0000 (17:46 +0200)
committerDr. David von Oheimb <dev@ddvo.net>
Mon, 11 Jul 2022 09:27:46 +0000 (11:27 +0200)
Work around an inconsistency in the implementations of BIO_CTRL_INFO.

Reviewed-by: Tomas Mraz <tomas@openssl.org>
Reviewed-by: Hugo Landau <hlandau@openssl.org>
Reviewed-by: David von Oheimb <david.von.oheimb@siemens.com>
(Merged from https://github.com/openssl/openssl/pull/18701)

crypto/http/http_client.c

index 1a1a79ace5b0ab1ca816b83d1ce11df4acf4ecb4..b31fee865486313bbc9a7f97672408be1127ec60 100644 (file)
@@ -267,6 +267,7 @@ static int set1_content(OSSL_HTTP_REQ_CTX *rctx,
                         const char *content_type, BIO *req)
 {
     long req_len;
+    FILE *fp = NULL;
 
     if (rctx == NULL || (req == NULL && content_type != NULL)) {
         ERR_raise(ERR_LIB_HTTP, ERR_R_PASSED_NULL_PARAMETER);
@@ -290,14 +291,29 @@ static int set1_content(OSSL_HTTP_REQ_CTX *rctx,
             && BIO_printf(rctx->mem, "Content-Type: %s\r\n", content_type) <= 0)
         return 0;
 
-    /* streaming BIO may not support querying size */
-    if (((req_len = BIO_ctrl(req, BIO_CTRL_INFO, 0, NULL)) <= 0
-         || BIO_printf(rctx->mem, "Content-Length: %ld\r\n", req_len) > 0)
-        && BIO_up_ref(req)) {
-        rctx->req = req;
-        return 1;
+    /*
+     * BIO_CTRL_INFO yields the data length at least for memory BIOs, but for
+     * file-based BIOs it gives the current position, which is not what we need.
+     */
+    if (BIO_get_fp(req, &fp) == 1) {
+        fseek(fp, 0, SEEK_END);
+        req_len = ftell(fp);
+        fseek(fp, 0, SEEK_SET);
+    } else {
+        req_len = BIO_ctrl(req, BIO_CTRL_INFO, 0, NULL);
+        /*
+         * Streaming BIOs likely will not support querying the size at all,
+         * and we assume we got a correct value if req_len > 0.
+         */
     }
-    return 0;
+    if ((fp != NULL /* definitely correct req_len */ || req_len > 0)
+            && BIO_printf(rctx->mem, "Content-Length: %ld\r\n", req_len) < 0)
+        return 0;
+
+    if (!BIO_up_ref(req))
+        return 0;
+    rctx->req = req;
+    return 1;
 }
 
 int OSSL_HTTP_REQ_CTX_set1_req(OSSL_HTTP_REQ_CTX *rctx, const char *content_type,