http_client.c: fix calculation of Content-Length in set1_content()
Work around an inconsistency in the implementations of BIO_CTRL_INFO.
@@ -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.
+ */
}
+ 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,
