OSSL_HTTP_TRANSFER(3ossl)
π OSSL_HTTP_TRANSFER(3ossl) π
okay bestie, grab your iced coffee because we're diving into OSSL_HTTP_TRANSFER from the OpenSSL manual, section 3ossl π¦ this is part 1 and there's more coming, so don't you dare scroll away
β¨ NAME β¨
OSSL_HTTP_open, OSSL_HTTP_bio_cb_t, OSSL_HTTP_proxy_connect, OSSL_HTTP_set1_request, OSSL_HTTP_exchange, OSSL_HTTP_get, OSSL_HTTP_transfer, OSSL_HTTP_close β these are the HTTP client high-level functions π
like literally the whole squad of them, all hanging out in one manpage
β¨ SYNOPSIS β¨
first things first, you gotta pull in the header, no cap:
#include <openssl/http.h>
then here's the callback type, she's serving function-pointer realness π:
typedef BIO *(*OSSL_HTTP_bio_cb_t)(BIO *bio, void *arg,
int connect, int detail);
and now the whole friend group, in order, exactly as they show up π
OSSL_HTTP_REQ_CTX *OSSL_HTTP_open(const char *server, const char *port,
const char *proxy, const char *no_proxy,
int use_ssl, BIO *bio, BIO *rbio,
OSSL_HTTP_bio_cb_t bio_update_fn, void *arg,
int buf_size, int overall_timeout);
int OSSL_HTTP_proxy_connect(BIO *bio, const char *server, const char *port,
const char *proxyuser, const char *proxypass,
int timeout, BIO *bio_err, const char *prog);
int OSSL_HTTP_set1_request(OSSL_HTTP_REQ_CTX *rctx, const char *path,
const STACK_OF(CONF_VALUE) *headers,
const char *content_type, BIO *req,
const char *expected_content_type, int expect_asn1,
size_t max_resp_len, int timeout, int keep_alive);
BIO *OSSL_HTTP_exchange(OSSL_HTTP_REQ_CTX *rctx, char **redirection_url);
BIO *OSSL_HTTP_get(const char *url, const char *proxy, const char *no_proxy,
BIO *bio, BIO *rbio,
OSSL_HTTP_bio_cb_t bio_update_fn, void *arg,
int buf_size, const STACK_OF(CONF_VALUE) *headers,
const char *expected_content_type, int expect_asn1,
size_t max_resp_len, int timeout);
BIO *OSSL_HTTP_transfer(OSSL_HTTP_REQ_CTX **prctx,
const char *server, const char *port,
const char *path, int use_ssl,
const char *proxy, const char *no_proxy,
BIO *bio, BIO *rbio,
OSSL_HTTP_bio_cb_t bio_update_fn, void *arg,
int buf_size, const STACK_OF(CONF_VALUE) *headers,
const char *content_type, BIO *req,
const char *expected_content_type, int expect_asn1,
size_t max_resp_len, int timeout, int keep_alive);
int OSSL_HTTP_close(OSSL_HTTP_REQ_CTX *rctx, int ok);
that's the whole cast list, no notes, she ate π β¨ more coming in part 2, stay tuned bestie π«Ά
π« DESCRIPTION π«
Okay bestie, buckle up, this is the meaty part π
OSSL_HTTP_open() kicks off an HTTP session. It uses the bio argument if that's not NULL, and if it is NULL it goes and connects to a server β optionally through a proxy. Main character energy fr fr π
So usually the OpenSSL build supports sockets, and in that case bio is NULL. When that happens, rbio has to be NULL too and server must not be NULL. The function then builds a network BIO internally with BIO_new_connect(3) to connect to the given server and the optionally given port β which defaults to 80 for HTTP or 443 for HTTPS. That internal BIO is what sets up the connection and exchanges one or more request and response. Slay π
If bio is given and rbio is NULL, then that bio gets used instead. And if both bio and rbio are given (they can be memory BIOs, for example) then no explicit connection gets set up at all β bio is for writing requests and rbio is for reading responses. The vibe here is: as soon as the client has flushed bio, the server must be ready to provide a response or signal a waiting condition via rbio. No chill, no waiting around π€
If bio is given, it's an error to also pass non-NULL proxy or no_proxy arguments β but server and port can still be given, they just support diagnostic output. If bio is NULL, the optional proxy parameter sets an HTTP(S) proxy to use (unless it gets overridden by "no_proxy" settings, iykyk). Quick rundown on proxy defaults:
- If TLS is not used, it defaults to the environment variable
"http_proxy"if set, else"HTTP_PROXY". - If
use_ssl != 0, it defaults to"https_proxy"if set, else"HTTPS_PROXY". - An empty proxy string
""forbids using a proxy, periodt. - Otherwise the format is
"[http[s]://][userinfo@]host[:port][/path][?query][#fragment]", where anyuserinfo,path,query, andfragmentgiven is ignored. - If the host string is an IPv6 address, it must be wrapped in
"["and"]"β no exceptions bestie. - The default proxy port number is
80, or443in case"https:"is given.
The HTTP client functions connect via the given proxy unless the server is found in the optional list no_proxy of proxy hostnames or IP addresses separated by "," and/or whitespace (if that's not NULL; default is the environment variable "no_proxy" if set, else "NO_PROXY"). Proxying plain HTTP is supported directly, but using a proxy for HTTPS connections needs a suitable callback function such as OSSL_HTTP_proxy_connect(), which we get to below π¦
If use_ssl is nonzero, a TLS connection is requested and the bio_update_fn parameter must be provided. No ifs, ands, or buts π
β¨ the bio_update_fn callback β¨
The bio_update_fn parameter is optional if use_ssl is 0, and it may be used to modify the connection BIO that the HTTP client uses β but it cannot be used when both bio and rbio are given. It's a BIO connect/disconnect callback function, and here's its prototype:
BIO *(*OSSL_HTTP_bio_cb_t)(BIO *bio, void *arg, int connect, int detail)
The callback may modify the BIO handed to it in the bio argument, and it can use an optional custom defined argument arg β which could, for instance, point to an SSL_CTX structure. Here's the timing, because timing is everything:
- During connection establishment, just after calling
BIO_do_connect_retry(), the callback is invoked withconnectset to1anddetailset to1ifuse_sslis nonzero (i.e., HTTPS is requested), else0. - On disconnect,
connectis0anddetailis1if no error occurred, else0.
So like, on connect the callback may push an SSL BIO to implement HTTPS; after disconnect it may do some diagnostic output and pop and free the SSL BIO. The callback function must return either the potentially modified BIO bio or NULL to indicate failure β and if it's returning NULL, it should not modify the BIO. Rude to modify and bail, bestie π
Here's a simple example that supports TLS connections (but not via a proxy), shown exactly as-is:
BIO *http_tls_cb(BIO *bio, void *arg, int connect, int detail)
{
if (connect && detail) { /* connecting with TLS */
SSL_CTX *ctx = (SSL_CTX *)arg;
BIO *sbio = BIO_new_ssl(ctx, 1);
bio = sbio != NULL ? BIO_push(sbio, bio) : NULL;
} else if (!connect) { /* disconnecting */
BIO *hbio;
if (!detail) { /* an error has occurred */
/* optionally add diagnostics here */
}
BIO_ssl_shutdown(bio);
hbio = BIO_pop(bio);
BIO_free(bio); /* SSL BIO */
bio = hbio;
}
return bio;
}
After disconnect, the modified BIO gets deallocated using BIO_free_all(). And heads up β the optional callback function argument arg is not consumed, so the caller has to free it when it's not needed any more. Don't leak, it's not cute πΈ
β¨ buf_size and overall_timeout β¨
The buf_size parameter specifies the response header maximum line length. A value <= 0 means that the OSSL_HTTP_DEFAULT_MAX_LINE_LEN (4KiB) is used. Also, buf_size does double duty β it's the number of content bytes that are read at a time. Multi-tasking icon π
If the overall_timeout parameter is > 0, that indicates the maximum number of seconds the overall HTTP transfer (i.e., connection setup if needed, sending requests, and receiving responses) is allowed to take until completion. A value <= 0 enables waiting indefinitely, i.e., no timeout. Live your truth, wait forever I guess π
β¨ OSSL_HTTP_proxy_connect() β¨
OSSL_HTTP_proxy_connect() may be used by an above BIO connect callback function to set up an SSL/TLS connection via an HTTPS proxy. It promotes the given BIO bio β which represents a connection pre-established with a TLS proxy using the HTTP CONNECT method β optionally using proxy client credentials proxyuser and proxypass, to connect with TLS protection ultimately to server and port.
- If the
portargument isNULLor the empty string, it defaults to"443". - The
serverandportarguments must not contain CR or LF characters. - If the
timeoutparameter is> 0, that indicates the maximum number of seconds the connection setup is allowed to take. A value<= 0enables waiting indefinitely, i.e., no timeout.
Since this function is typically called by applications such as openssl-s_client(1), it uses the bio_err and prog parameters (unless NULL) to print additional diagnostic information in a user-oriented way. So friendly, so demure π
β¨ OSSL_HTTP_set1_request() β¨
OSSL_HTTP_set1_request() sets up in rctx the request header and content data and expectations on the response, using the following parameters. If <rctx> indicates using a proxy for HTTP (but not HTTPS), the server host (and optionally port) needs to be placed in the header β so it must be present in rctx. For backward compatibility, the server (and optional port) may also be given in the path argument beginning with "http://" (which gives you an absoluteURI). Details:
- If
pathisNULLit defaults to"/". - If
reqisNULLthe HTTPGETmethod is used to send the request, else HTTPPOSTwith the contents ofreqand optionalcontent_type. - The length of the data in
reqdoes not need to be determined in advance: the BIO will be read on-the-fly while sending the request, which supports streaming. Streaming queen π - The optional list
headersmay contain additional custom HTTP header lines. - The
path,headersnames and values, andcontent_typemust not contain CR or LF characters. Seriously. - The
max_resp_lenparameter specifies the maximum allowed response content length, where the value0indicates no limit.
For the meaning of the expected_content_type, expect_asn1, timeout, and keep_alive parameters, go see OSSL_HTTP_REQ_CTX_set_expected(3).
β¨ OSSL_HTTP_exchange() β¨
OSSL_HTTP_exchange() exchanges any form of HTTP request and response as specified by rctx, which must include both connection and request data β typically set up using OSSL_HTTP_open() and OSSL_HTTP_set1_request(). It implements the core of the functions described below, so it's basically the main character of this whole operation π
- If the HTTP method is
GETandredirection_urlis notNULL, that pointer is used to provide any new location the server may return with HTTP code301(MOVED_PERMANENTLY) or302(FOUND). In this case the function returnsNULLand the caller is responsible for deallocating the URL withOPENSSL_free(3). - If the response header contains one or more
"Content-Length"lines and/or an ASN.1-encoded response is expected, which should include a total length, the length indications received are checked for consistency and for not exceeding any given maximum response length. - If an ASN.1-encoded response is expected, the function returns on success the contents buffered in a memory BIO, which does not support streaming.
- Otherwise it returns directly the read BIO that holds the response contents, which allows a response of indefinite length and may support streaming.
The caller is responsible for freeing the BIO pointer obtained. Every single time. Don't forget π«Ά
β¨ OSSL_HTTP_get() β¨
OSSL_HTTP_get() uses HTTP GET to obtain data from bio if non-NULL, else from the server contained in the url, and returns it as a BIO.
- It supports redirection via HTTP status code
301or302. - Redirection from HTTPS to HTTP is not allowed. Nope. Blocked.
- It's meant for transfers with a single round trip, so it does not support persistent connections.
- If
biois non-NULL, any host and port components in theurlare not used for connecting, but the hostname is used, as usual, for the"Host"header. - Any userinfo and fragment components in the
urlare ignored. - Any query component is handled as part of the path component.
- If the scheme component of the
urlis"https", a TLS connection is requested and thebio_update_fn, as described forOSSL_HTTP_open(), must be provided.
Also, the remaining parameters are interpreted as described for OSSL_HTTP_open() and OSSL_HTTP_set1_request(), respectively. And you guessed it β the caller is responsible for freeing the BIO pointer obtained π
β¨ OSSL_HTTP_transfer() β¨
OSSL_HTTP_transfer() exchanges an HTTP request and response over a connection managed via prctx without supporting redirection. It's basically a combo meal β it combines OSSL_HTTP_open(), OSSL_HTTP_set1_request(), OSSL_HTTP_exchange(), and OSSL_HTTP_close() π
- If
prctxis notNULLit reuses any open connection represented by a non-NULL*prctx. - It keeps the connection open if a persistent connection is requested or required and this was granted by the server, else it closes the connection and assigns
NULLto*prctx.
The remaining parameters are interpreted as described for OSSL_HTTP_open() and OSSL_HTTP_set1_request(), respectively. And yes β the caller is responsible for freeing the BIO pointer obtained. It's giving "you break it, you bought it" π
β¨ OSSL_HTTP_close() β¨
OSSL_HTTP_close() closes the connection and releases rctx. The ok parameter gets passed to any BIO update function given during setup, as described above for OSSL_HTTP_open(). It must be 1 if no error occurred during the HTTP transfer and 0 otherwise. Be honest about it bestie, no lying to the callback π
π NOTES π
The names of the environment variables used by this implementation β "http_proxy", "HTTP_PROXY", "https_proxy", "HTTPS_PROXY", "no_proxy", and "NO_PROXY" β were chosen for maximal compatibility with other HTTP client implementations such as wget, curl, and git. Networking besties gotta stick together π
When built with tracing enabled, OSSL_HTTP_transfer() and all functions using it may be traced using OSSL_TRACE_CATEGORY_HTTP. See also OSSL_trace_enabled(3) and openssl-env(7). π
π RETURN VALUES π
okay bestie, this is the part where we find out what you actually get back. pay attention, fr fr.
OSSL_HTTP_open()β slays on success and hands you aOSSL_HTTP_REQ_CTX. if it flops? you getNULL. that's it, that's the whole vibe check. πOSSL_HTTP_proxy_connect()andOSSL_HTTP_set1_request()β these two return1when everything goes right, and0when there's an error. classic binary queen behaviour, they don't do in-betweens. β¨OSSL_HTTP_exchange(),OSSL_HTTP_get(), andOSSL_HTTP_transfer()β on success these return a memory BIO, and here's the tea: it buffers all the data received if an ASN.1-encoded response is expected. if not, you get a BIO that may support streaming instead. either way the BIO is yours to deal with, so it must be freed by the caller. π«Ά- on failure, those same three return
NULL. and bestie, failure conditions include connection/transfer timeout, parse errors, etc. so many little ways for things to go sideways π
the caller is responsible for freeing the BIO pointer obtained. not the library. not your future self. you. no cap. π
OSSL_HTTP_close()β returns0if anything went wrong while disconnecting, else1. so a1here is the little victory lap, and a0is the "hmm that didn't go great" moment. π
π SEE ALSO π
go read these too, they're all in the same friend group:
OSSL_HTTP_parse_url(3)BIO_new_connect(3)ASN1_item_i2d_mem_bio(3)ASN1_item_d2i_bio(3)OSSL_HTTP_REQ_CTX_set_expected(3)OSSL_HTTP_is_alive(3)OSSL_trace_enabled(3)- and
openssl-env(7)π
π¦ HISTORY π¦
okay so, lore time: all the functions described here were added in OpenSSL 3.0. so if you're on something older, bestie, this whole page is giving "not for you yet" energy. π
π COPYRIGHT π
Copyright 2019-2026 The OpenSSL Project Authors. All Rights Reserved.
Licensed under the Apache License 2.0 (the "License"). You may not use this file except in compliance with the License. You can obtain a copy in the file LICENSE in the source distribution or at <https://www.openssl.org/source/license.html>.
aaaand that's a wrap on the whole page, bestie!! πβ¨ this one's from 3.5.9, dated 2026-09-29, and it lives under the name OSSL_HTTP_TRANSFER(3ossl). you read the entire thing, which is genuinely iconic of you β go hydrate, free your BIOs, and stan a safe disconnect. ππ«Άπ¦
π¦ where this page comes from
- fedora 43: openssl-devel 1:3.5.9-1.fc43 Β· Apache-2.0
- fedora 43: openssl-devel 1:3.5.9-1.fc43 Β· Apache-2.0
- fedora 44: openssl-devel 1:3.5.9-1.fc44 Β· Apache-2.0
- fedora 44: openssl-devel 1:3.5.9-1.fc44 Β· Apache-2.0
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms