Author: brane
Date: Sun Jan 4 10:28:45 2026
New Revision: 1931089
Log:
Tie in SSL context error reporting with the context/connection callbacks.
* serf.h
(serf_context_error_callback_set,
serf_connection_error_callback_set,
serf_incoming_error_callback_set): Add a note about baton lifetimes.
* serf_bucket_types.h: Move the encrypt bucket declarations next to the
decrypt bucket declarations, they belong together.
(serf_bucket_ssl_encrypt_create,
serf_bucket_ssl_encrypt_context_get,
serf_bucket_ssl_decrypt_create,
serf_bucket_ssl_decrypt_context_get): Add sorely missing docstrings.
(serf_ssl_use_context_error_callback,
serf_ssl_use_connection_error_callback,
serf_ssl_use_incoming_error_callback): New prototypes.
* serf_private.h
(serf__request_ssl_error,
serf__response_ssl_error,
serf__incoming_request_ssl_error,
serf__incoming_response_ssl_error): Remove prototypes.
* src/error_callbacks.c
(serf__request_ssl_error,
serf__response_ssl_error,
serf__incoming_request_ssl_error,
serf__incoming_response_ssl_error): Remove unused functions.
* buckets/ssl_buckets.c
(serf_ssl_context_t): Add err_ctx, an error context field. Replace almost
all references to global_error_ctx with serf_ssl_context_t::err_ctx.
(ssl_init_context): Initialize err_ctx from global_error_ctx.
(serf_ssl_use_context_error_callback,
serf_ssl_use_connection_error_callback,
serf_ssl_use_incoming_error_callback): Implement here.
* test/serf_get.c: Include serf_bucket_types.h.
(conn_setup): Make new SSL contexts use the connection's error callback.
(global_error_callback,
connection_error_callback): New error callback functions.
(main): Register global and per-connection error callbacks.
Modified:
serf/trunk/buckets/ssl_buckets.c
serf/trunk/serf.h
serf/trunk/serf_bucket_types.h
serf/trunk/serf_private.h
serf/trunk/src/error_callbacks.c
serf/trunk/test/serf_get.c
Modified: serf/trunk/buckets/ssl_buckets.c
==============================================================================
--- serf/trunk/buckets/ssl_buckets.c Sun Jan 4 09:20:25 2026
(r1931088)
+++ serf/trunk/buckets/ssl_buckets.c Sun Jan 4 10:28:45 2026
(r1931089)
@@ -223,6 +223,9 @@ struct serf_ssl_context_t {
void *protocol_userdata;
serf_config_t *config;
+
+ /* The error callback context. */
+ serf__ssl_error_ctx_t err_ctx;
};
/* The fallback SSL error context which logs to the global error callback. */
@@ -231,6 +234,27 @@ static const serf__ssl_error_ctx_t globa
NULL /* baton */
};
+void serf_ssl_use_context_error_callback(serf_ssl_context_t *ssl_ctx,
+ serf_context_t *ctx)
+{
+ ssl_ctx->err_ctx.dispatch = serf__context_ssl_error;
+ ssl_ctx->err_ctx.baton = ctx;
+}
+
+void serf_ssl_use_connection_error_callback(serf_ssl_context_t *ssl_ctx,
+ serf_connection_t *conn)
+{
+ ssl_ctx->err_ctx.dispatch = serf__connection_ssl_error;
+ ssl_ctx->err_ctx.baton = conn;
+}
+
+void serf_ssl_use_incoming_error_callback(serf_ssl_context_t *ssl_ctx,
+ serf_incoming_t *client)
+{
+ ssl_ctx->err_ctx.dispatch = serf__incoming_ssl_error;
+ ssl_ctx->err_ctx.baton = client;
+}
+
static apr_status_t dispatch_ssl_error(const serf__ssl_error_ctx_t *err_ctx,
apr_status_t status,
const char *message)
@@ -1102,7 +1126,7 @@ static apr_status_t status_from_ssl_erro
ctx->fatal_err = SERF_ERROR_SSL_COMM_FAILED;
status = ctx->fatal_err;
- log_ssl_error(&global_error_ctx, status);
+ log_ssl_error(&ctx->err_ctx, status);
}
break;
@@ -1116,7 +1140,7 @@ static apr_status_t status_from_ssl_erro
default:
status = ctx->fatal_err = SERF_ERROR_SSL_COMM_FAILED;
- log_ssl_error(&global_error_ctx, status);
+ log_ssl_error(&ctx->err_ctx, status);
break;
}
@@ -1223,7 +1247,7 @@ static apr_status_t ssl_decrypt(void *ba
} else {
/* A fatal error occurred. */
ctx->fatal_err = status = SERF_ERROR_SSL_COMM_FAILED;
- log_ssl_error(&global_error_ctx, status);
+ log_ssl_error(&ctx->err_ctx, status);
}
} else {
*len = ssl_len;
@@ -1656,9 +1680,9 @@ static int ssl_read_client_cert_uri(serf
char ebuf[1024];
ctx->fatal_err = SERF_ERROR_SSL_CERT_FAILED;
apr_snprintf(ebuf, sizeof(ebuf), "could not open URI: %s", cert_uri);
- dispatch_ssl_error(&global_error_ctx, ctx->fatal_err, ebuf);
+ dispatch_ssl_error(&ctx->err_ctx, ctx->fatal_err, ebuf);
- log_ssl_error(&global_error_ctx, ctx->fatal_err);
+ log_ssl_error(&ctx->err_ctx, ctx->fatal_err);
UI_destroy_method(ui_method);
return 0;
}
@@ -1688,7 +1712,7 @@ static int ssl_read_client_cert_uri(serf
char ebuf[1024];
ctx->fatal_err = SERF_ERROR_SSL_CERT_FAILED;
apr_snprintf(ebuf, sizeof(ebuf), "could not read URI: %s",
cert_uri);
- dispatch_ssl_error(&global_error_ctx, ctx->fatal_err, ebuf);
+ dispatch_ssl_error(&ctx->err_ctx, ctx->fatal_err, ebuf);
store_error = 1;
break;
}
@@ -1739,7 +1763,7 @@ static int ssl_read_client_cert_uri(serf
OSSL_STORE_close(store);
if (store_error || ERR_peek_error()) {
- log_ssl_error(&global_error_ctx, ctx->fatal_err);
+ log_ssl_error(&ctx->err_ctx, ctx->fatal_err);
result = 0;
goto cleanup;
}
@@ -1801,7 +1825,7 @@ static int ssl_read_client_cert_uri(serf
}
if (ERR_peek_error()) {
- log_ssl_error(&global_error_ctx, ctx->fatal_err);
+ log_ssl_error(&ctx->err_ctx, ctx->fatal_err);
result = -1;
goto cleanup;
}
@@ -1902,9 +1926,9 @@ static int ssl_need_client_cert(SSL *ssl
if (status) {
char ebuf[1024];
apr_snprintf(ebuf, sizeof(ebuf), "could not open PKCS12: %s",
cert_path);
- dispatch_ssl_error(&global_error_ctx, status, ebuf);
+ dispatch_ssl_error(&ctx->err_ctx, status, ebuf);
apr_strerror(status, ebuf, sizeof(ebuf));
- dispatch_ssl_error(&global_error_ctx, status, ebuf);
+ dispatch_ssl_error(&ctx->err_ctx, status, ebuf);
ctx->fatal_err = status;
return -1;
@@ -1989,9 +2013,9 @@ static int ssl_need_client_cert(SSL *ssl
else {
ctx->fatal_err = SERF_ERROR_SSL_CERT_FAILED;
apr_snprintf(ebuf, sizeof(ebuf), "could not parse
PKCS12: %s", cert_path);
- dispatch_ssl_error(&global_error_ctx,
ctx->fatal_err, ebuf);
+ dispatch_ssl_error(&ctx->err_ctx, ctx->fatal_err,
ebuf);
- log_ssl_error(&global_error_ctx, ctx->fatal_err);
+ log_ssl_error(&ctx->err_ctx, ctx->fatal_err);
return -1;
}
}
@@ -2001,9 +2025,9 @@ static int ssl_need_client_cert(SSL *ssl
ctx->fatal_err = SERF_ERROR_SSL_CERT_FAILED;
apr_snprintf(ebuf, sizeof(ebuf), "PKCS12 needs a password:
%s", cert_path);
- dispatch_ssl_error(&global_error_ctx, ctx->fatal_err, ebuf);
+ dispatch_ssl_error(&ctx->err_ctx, ctx->fatal_err, ebuf);
- log_ssl_error(&global_error_ctx, ctx->fatal_err);
+ log_ssl_error(&ctx->err_ctx, ctx->fatal_err);
return -1;
}
else {
@@ -2011,9 +2035,9 @@ static int ssl_need_client_cert(SSL *ssl
bio_meth_free(biom);
ctx->fatal_err = SERF_ERROR_SSL_CERT_FAILED;
- dispatch_ssl_error(&global_error_ctx, ctx->fatal_err, ebuf);
+ dispatch_ssl_error(&ctx->err_ctx, ctx->fatal_err, ebuf);
- log_ssl_error(&global_error_ctx, ctx->fatal_err);
+ log_ssl_error(&ctx->err_ctx, ctx->fatal_err);
return -1;
}
}
@@ -2198,6 +2222,8 @@ static serf_ssl_context_t *ssl_init_cont
ssl_ctx->handshake_done = FALSE;
ssl_ctx->hit_eof = FALSE;
+ ssl_ctx->err_ctx = global_error_ctx;
+
return ssl_ctx;
}
@@ -2402,6 +2428,8 @@ apr_status_t serf_ssl_load_cert_file(
return APR_SUCCESS;
}
+ /* We don't have an ssl_context_t here, so log the errors to the global
+ callback. It's better than ignoring them. */
status = SERF_ERROR_SSL_CERT_FAILED;
log_ssl_error(&global_error_ctx, status);
return status;
@@ -2466,7 +2494,7 @@ apr_status_t serf_ssl_add_crl_from_file(
result = X509_STORE_add_crl(store, crl);
if (!result) {
ssl_ctx->fatal_err = status = SERF_ERROR_SSL_CERT_FAILED;
- log_ssl_error(&global_error_ctx, status);
+ log_ssl_error(&ssl_ctx->err_ctx, status);
return status;
}
Modified: serf/trunk/serf.h
==============================================================================
--- serf/trunk/serf.h Sun Jan 4 09:20:25 2026 (r1931088)
+++ serf/trunk/serf.h Sun Jan 4 10:28:45 2026 (r1931089)
@@ -262,6 +262,8 @@ void serf_global_error_callback_set(
* context @a ctx and, since contexts may not be accessed from multiple
* threads, serialization is not a concern.
*
+ * The lifetime of @a baton must be longer than the lifetime of the context.
+ *
* @since New in 1.5.
*/
void serf_context_error_callback_set(
@@ -274,6 +276,8 @@ void serf_context_error_callback_set(
*
* Like serf_context_error_callback_set() but for connections.
*
+ * The lifetime of @a baton must be longer than the lifetime of the connection.
+ *
* @since New in 1.5.
*/
void serf_connection_error_callback_set(
@@ -286,6 +290,9 @@ void serf_connection_error_callback_set(
*
* Like serf_context_error_callback_set() but for incoming connections.
*
+ * The lifetime of @a baton must be longer than the lifetime of the
+ * incoming connection.
+ *
* @since New in 1.5.
*/
void serf_incoming_error_callback_set(
Modified: serf/trunk/serf_bucket_types.h
==============================================================================
--- serf/trunk/serf_bucket_types.h Sun Jan 4 09:20:25 2026
(r1931088)
+++ serf/trunk/serf_bucket_types.h Sun Jan 4 10:28:45 2026
(r1931089)
@@ -585,9 +585,6 @@ serf_bucket_t *serf_bucket_limit_create(
#define SERF_SSL_SIGNATURE_FAILURE 0x0800
-extern const serf_bucket_type_t serf_bucket_type_ssl_encrypt;
-#define SERF_BUCKET_IS_SSL_ENCRYPT(b) SERF_BUCKET_CHECK((b), ssl_encrypt)
-
typedef struct serf_ssl_context_t serf_ssl_context_t;
typedef struct serf_ssl_certificate_t serf_ssl_certificate_t;
@@ -846,14 +843,6 @@ apr_status_t serf_ssl_use_compression(
serf_ssl_context_t *ssl_ctx,
int enabled);
-serf_bucket_t *serf_bucket_ssl_encrypt_create(
- serf_bucket_t *stream,
- serf_ssl_context_t *ssl_context,
- serf_bucket_alloc_t *allocator);
-
-serf_ssl_context_t *serf_bucket_ssl_encrypt_context_get(
- serf_bucket_t *bucket);
-
/* ==================================================================== */
/**
@@ -1009,17 +998,85 @@ apr_status_t serf_ssl_ocsp_response_veri
/* ==================================================================== */
+extern const serf_bucket_type_t serf_bucket_type_ssl_encrypt;
+#define SERF_BUCKET_IS_SSL_ENCRYPT(b) SERF_BUCKET_CHECK((b), ssl_encrypt)
+
+/**
+ * Create an SSL encryption bucket that wraps @a stream.
+ *
+ * If @a ssl_context is not provided, a new one will be created.
+ */
+serf_bucket_t *serf_bucket_ssl_encrypt_create(
+ serf_bucket_t *stream,
+ serf_ssl_context_t *ssl_context,
+ serf_bucket_alloc_t *allocator);
+
+/**
+ * Return the SSL context from an encryption bucket.
+ */
+serf_ssl_context_t *serf_bucket_ssl_encrypt_context_get(
+ serf_bucket_t *bucket);
+
extern const serf_bucket_type_t serf_bucket_type_ssl_decrypt;
#define SERF_BUCKET_IS_SSL_DECRYPT(b) SERF_BUCKET_CHECK((b), ssl_decrypt)
+/**
+ * Create an SSL encryption bucket that wraps @a stream.
+ *
+ * If @a ssl_context is not provided, a new one will be created.
+ */
serf_bucket_t *serf_bucket_ssl_decrypt_create(
serf_bucket_t *stream,
serf_ssl_context_t *ssl_context,
serf_bucket_alloc_t *allocator);
+/**
+ * Return the SSL context from an decryption bucket.
+ */
serf_ssl_context_t *serf_bucket_ssl_decrypt_context_get(
serf_bucket_t *bucket);
+/**
+ * Configure the SSL context to use the error cllback set on @a ctx.
+ *
+ * By default, new SSL contexts send error messages to the global
+ * error callback.
+ *
+ * @see serf_global_error_callback_set()
+ * @see serf_context_error_callback_set()
+ *
+ * @since New in 1.5.
+ */
+void serf_ssl_use_context_error_callback(serf_ssl_context_t *ssl_ctx,
+ serf_context_t *ctx);
+
+/**
+ * Configure the SSL context to use the error callback set on @a conn.
+ *
+ * By default, new SSL contexts send error messages to the global
+ * error callback.
+ *
+ * @see serf_global_error_callback_set()
+ * @see serf_connection_error_callback_set()
+ *
+ * @since New in 1.5.
+ */
+void serf_ssl_use_connection_error_callback(serf_ssl_context_t *ssl_ctx,
+ serf_connection_t *conn);
+
+/**
+ * Configure the SSL context to use the error callback set on @a client.
+ *
+ * By default, new SSL contexts send error messages to the global
+ * error callback.
+ *
+ * @see serf_global_error_callback_set()
+ * @see serf_incoming_error_callback_set()
+ *
+ * @since New in 1.5.
+ */
+void serf_ssl_use_incoming_error_callback(serf_ssl_context_t *ssl_ctx,
+ serf_incoming_t *client);
/* ==================================================================== */
Modified: serf/trunk/serf_private.h
==============================================================================
--- serf/trunk/serf_private.h Sun Jan 4 09:20:25 2026 (r1931088)
+++ serf/trunk/serf_private.h Sun Jan 4 10:28:45 2026 (r1931089)
@@ -178,21 +178,9 @@ apr_status_t serf__context_ssl_error(con
apr_status_t serf__connection_ssl_error(const void *baton,
apr_status_t status,
const char *message);
-apr_status_t serf__request_ssl_error(const void *baton,
- apr_status_t status,
- const char *message);
-apr_status_t serf__response_ssl_error(const void *baton,
- apr_status_t status,
- const char *message);
apr_status_t serf__incoming_ssl_error(const void *baton,
apr_status_t status,
const char *message);
-apr_status_t serf__incoming_request_ssl_error(const void *baton,
- apr_status_t status,
- const char *message);
-apr_status_t serf__incoming_response_ssl_error(const void *baton,
- apr_status_t status,
- const char *message);
/*** Logging facilities ***/
Modified: serf/trunk/src/error_callbacks.c
==============================================================================
--- serf/trunk/src/error_callbacks.c Sun Jan 4 09:20:25 2026
(r1931088)
+++ serf/trunk/src/error_callbacks.c Sun Jan 4 10:28:45 2026
(r1931089)
@@ -208,28 +208,6 @@ apr_status_t serf__connection_ssl_error(
conn, status, message);
}
-apr_status_t serf__request_ssl_error(const void *baton,
- apr_status_t status,
- const char *message)
-{
- const serf_request_t *const req = baton;
- return process_connection_error(SERF_ERROR_CB_SSL_CONTEXT
- | SERF_ERROR_CB_OUTGOING
- | SERF_ERROR_CB_REQUEST,
- req->conn, status, message);
-}
-
-apr_status_t serf__response_ssl_error(const void *baton,
- apr_status_t status,
- const char *message)
-{
- const serf_request_t *const req = baton;
- return process_connection_error(SERF_ERROR_CB_SSL_CONTEXT
- | SERF_ERROR_CB_OUTGOING
- | SERF_ERROR_CB_RESPONSE,
- req->conn, status, message);
-}
-
apr_status_t serf__incoming_ssl_error(const void *baton,
apr_status_t status,
const char *message)
@@ -239,25 +217,3 @@ apr_status_t serf__incoming_ssl_error(co
| SERF_ERROR_CB_INCOMING,
client, status, message);
}
-
-apr_status_t serf__incoming_request_ssl_error(const void *baton,
- apr_status_t status,
- const char *message)
-{
- const serf_incoming_request_t *const req = baton;
- return process_incoming_error(SERF_ERROR_CB_SSL_CONTEXT
- | SERF_ERROR_CB_INCOMING
- | SERF_ERROR_CB_REQUEST,
- req->incoming, status, message);
-}
-
-apr_status_t serf__incoming_response_ssl_error(const void *baton,
- apr_status_t status,
- const char *message)
-{
- const serf_incoming_request_t *const req = baton;
- return process_incoming_error(SERF_ERROR_CB_SSL_CONTEXT
- | SERF_ERROR_CB_INCOMING
- | SERF_ERROR_CB_RESPONSE,
- req->incoming, status, message);
-}
Modified: serf/trunk/test/serf_get.c
==============================================================================
--- serf/trunk/test/serf_get.c Sun Jan 4 09:20:25 2026 (r1931088)
+++ serf/trunk/test/serf_get.c Sun Jan 4 10:28:45 2026 (r1931089)
@@ -29,6 +29,7 @@
#include <apr_version.h>
#include "serf.h"
+#include "serf_bucket_types.h"
/* Add Connection: close header to each request. */
/* #define CONNECTION_CLOSE_HDR */
@@ -230,6 +231,7 @@ static apr_status_t conn_setup(apr_socke
c = serf_bucket_ssl_decrypt_create(c, conn_ctx->ssl_ctx,
ctx->bkt_alloc);
if (!conn_ctx->ssl_ctx) {
conn_ctx->ssl_ctx = serf_bucket_ssl_decrypt_context_get(c);
+ serf_ssl_use_connection_error_callback(conn_ctx->ssl_ctx,
conn_ctx->conn);
}
serf_ssl_server_cert_chain_callback_set(conn_ctx->ssl_ctx,
ignore_all_cert_errors,
@@ -509,6 +511,32 @@ credentials_callback(char **username,
}
}
+static apr_status_t
+global_error_callback(void *baton,
+ unsigned source,
+ apr_status_t status,
+ const char *message)
+{
+ fprintf(stderr, "ERROR%s <%d> %s\n",
+ ((source & SERF_ERROR_CB_SSL_CONTEXT) ? " (SSL)" : ""),
+ status, message);
+ return APR_SUCCESS;
+}
+
+static apr_status_t
+connection_error_callback(void *baton,
+ unsigned source,
+ apr_status_t status,
+ const char *message)
+{
+ const char *const conn_id = baton;
+ fprintf(stderr, "ERROR conn[%s]%s <%d> %s\n",
+ conn_id,
+ ((source & SERF_ERROR_CB_SSL_CONTEXT) ? " (SSL)" : ""),
+ status, message);
+ return APR_SUCCESS;
+}
+
/* Value for 'no short code' should be > 255 */
#define CERTFILE 256
#define CERTPWD 257
@@ -817,7 +845,7 @@ int main(int argc, const char **argv)
serf_config_credentials_callback(context, credentials_callback);
- /* Setup debug logging */
+ /* Setup debug logging and error callbacks */
if (debug)
{
serf_log_output_t *output;
@@ -832,6 +860,8 @@ int main(int argc, const char **argv)
if (!status)
serf_logging_add_output(context, output);
+
+ serf_global_error_callback_set(global_error_callback, NULL);
}
/* ### Connection or Context should have an allocator? */
@@ -857,6 +887,12 @@ int main(int argc, const char **argv)
conn_ctx->conn = connections[i];
serf_connection_set_max_outstanding_requests(connections[i], inflight);
+ if (debug)
+ {
+ serf_connection_error_callback_set(connections[i],
+ connection_error_callback,
+ apr_psprintf(pool, "%02d", i));
+ }
}
handler_ctx.completed_requests = 0;