...
/* Where was this error generated? FILE is static/forever. */
const char *file;
int lineno;
}
Not sure about file/line, either. That's something you write in a log
(and we can automagically log when the callbacks are invoked), but a
library consumer won't care. Though, I agree, it's useful info to have
in an error report. *THAT SAID*, however: __FILE__ exposes information
about the machine this was built on. If it was relative to the source
directory, that'd be ok. But it usually isn't. This is a problem in the
logs, too, but they're turned off/compiled out by default. If we want
the location info, there are better ways than using __FILE__. Yes, I
understand that you didn't literally mean __FILE__, but still, it bears
pointing out. It's one of the things that ticks me off about
Subversion's error tracing, for example.
I saw your work on Subversion trimming the root of the path. Totally agree
with that idea. I wonder if we can *inject* a CPP symbol into each file
build, so that we don't even have to bother with runtime path processing
(and potential failures/leaks). "SERF_FILE" or such.
Serf doesn't have the capability to create stack traces like svn has. But I
*do* think we can specify where an error originated, which helps with
debug. Serf's logging might capture some of this, but that is a separate
system which might not be configured. It would also help to pass this
information to the APP, so that the APP can incorporate the error into its
own logs.
If we're going to use a callback approach, then let's do it right. I
disagree with this one-off.
You only have to write some code to make it more agreeable. ;
serf_error_t acceptable conceptually?
I believe our initial use would be for the SSL callback that Graham is
working on. Then we could grow usage over time/interest, as we run into
issues. I really have a problem with a one-off callback suitable only for
one edge case.
Cheers,
-g
I tried to follow the code and I can't figure out if there is a place where
we can store the callback function pointer, except in the
serf_ssl_context_t, just like it is done right now. So if my understanding
is correct, we probably have to add a function pointer to any and all other
context_t:s where we might want to have an error callback. Is this correct?
Assuming my understanding is correct, and the goal is to enable
applications to have only ONE error callback, would it make sense to rename
the function pointer type from serf_ssl_error_cb_t to serf_error_cb_t? To
differentiate between the kind of error, we could add an additional
parameter error_type.
We still need to have setter functions for each context_t that support
error callbacks and the baton will thus be context dependent. The
application using Serf will be able to figure out the type of the baton
based on the error_type.
[[[
Index: serf_bucket_types.h
===================================================================
--- serf_bucket_types.h (revision 1927380)
+++ serf_bucket_types.h (working copy)
@@ -687,16 +687,30 @@
void *data);
/**
- * Callback type for detailed TLS error strings. This callback will be
fired
- * every time the underlying crypto library encounters an error. The
message
- * lasts only as long as the callback, if the caller wants to set aside the
- * message for later use, a copy must be made.
+ * Type of error in the serf_error_cb_t callback
+ */
+typedef enum serf_error_type_t {
+ SERF_SSL_ERROR
+} serf_error_type_t;
+
+/**
+ * Callback type for detailed error strings.
*
+ * Depending on @a error_type the baton may be of different types.
+ *
+ * The message lasts only as long as the callback, if the caller wants to
+ * set aside the message for later use, a copy must be made.
+ *
* It is possible that for a given error multiple strings will be returned
* in multiple callbacks. The caller may choose to handle all strings, or
* may choose to ignore all strings but the last most detailed one.
+ *
+ * SERF_SSL_ERROR
+ * This callback will be fired every time the underlying crypto library
+ * encounters an error.
*/
-typedef apr_status_t (*serf_ssl_error_cb_t)(
+typedef apr_status_t (*serf_error_cb_t)(
+ serf_error_type_t error_type,
void *baton,
apr_status_t status,
const char *message);
@@ -710,7 +724,7 @@
*/
void serf_ssl_error_cb_set(
serf_ssl_context_t *context,
- serf_ssl_error_cb_t callback,
+ serf_error_cb_t callback,
void *baton);
/**
]]]
The code in ssl_buckets is more or less a search/replace based on the
changes above:
[[[
Index: buckets/ssl_buckets.c
===================================================================
--- buckets/ssl_buckets.c (revision 1927380)
+++ buckets/ssl_buckets.c (working copy)
@@ -207,7 +207,7 @@
EVP_PKEY *cached_cert_pw;
/* Error callback */
- serf_ssl_error_cb_t error_callback;
+ serf_error_cb_t error_callback;
void *error_baton;
apr_status_t pending_err;
@@ -364,7 +364,7 @@
if (err && ctx->error_callback) {
char ebuf[256];
ERR_error_string_n(err, ebuf, sizeof(ebuf));
- ctx->error_callback(ctx->error_baton, ctx->fatal_err, ebuf);
+ ctx->error_callback(SERF_SSL_ERROR, ctx->error_baton,
ctx->fatal_err, ebuf);
}
}
@@ -1677,7 +1677,7 @@
char ebuf[1024];
ctx->fatal_err = SERF_ERROR_SSL_CERT_FAILED;
apr_snprintf(ebuf, sizeof(ebuf), "could not open URI: %s",
cert_uri);
- ctx->error_callback(ctx->error_baton, ctx->fatal_err,
ebuf);
+ ctx->error_callback(SERF_SSL_ERROR, ctx->error_baton,
ctx->fatal_err, ebuf);
}
break;
@@ -1694,7 +1694,7 @@
char ebuf[1024];
ctx->fatal_err = SERF_ERROR_SSL_CERT_FAILED;
apr_snprintf(ebuf, sizeof(ebuf), "could not read URI:
%s", cert_uri);
- ctx->error_callback(ctx->error_baton, ctx->fatal_err,
ebuf);
+ ctx->error_callback(SERF_SSL_ERROR, ctx->error_baton,
ctx->fatal_err, ebuf);
}
break;
@@ -1883,9 +1883,9 @@
if (ctx->error_callback) {
char ebuf[1024];
apr_snprintf(ebuf, sizeof(ebuf), "could not open PKCS12:
%s", cert_path);
- ctx->error_callback(ctx->error_baton, ctx->fatal_err,
ebuf);
+ ctx->error_callback(SERF_SSL_ERROR, ctx->error_baton,
ctx->fatal_err, ebuf);
apr_strerror(status, ebuf, sizeof(ebuf));
- ctx->error_callback(ctx->error_baton, ctx->fatal_err,
ebuf);
+ ctx->error_callback(SERF_SSL_ERROR, ctx->error_baton,
ctx->fatal_err, ebuf);
}
return -1;
}
@@ -1970,7 +1970,7 @@
char ebuf[1024];
ctx->fatal_err =
SERF_ERROR_SSL_CERT_FAILED;
apr_snprintf(ebuf, sizeof(ebuf), "could
not parse PKCS12: %s", cert_path);
- ctx->error_callback(ctx->error_baton,
ctx->fatal_err, ebuf);
+ ctx->error_callback(SERF_SSL_ERROR,
ctx->error_baton, ctx->fatal_err, ebuf);
}
log_ssl_error(ctx);
@@ -1985,7 +1985,7 @@
char ebuf[1024];
ctx->fatal_err = SERF_ERROR_SSL_CERT_FAILED;
apr_snprintf(ebuf, sizeof(ebuf), "PKCS12 needs a
password: %s", cert_path);
- ctx->error_callback(ctx->error_baton, ctx->fatal_err,
ebuf);
+ ctx->error_callback(SERF_SSL_ERROR, ctx->error_baton,
ctx->fatal_err, ebuf);
}
log_ssl_error(ctx);
@@ -1999,7 +1999,7 @@
char ebuf[1024];
ctx->fatal_err = SERF_ERROR_SSL_CERT_FAILED;
apr_snprintf(ebuf, sizeof(ebuf), "could not parse
PKCS12: %s", cert_path);
- ctx->error_callback(ctx->error_baton, ctx->fatal_err,
ebuf);
+ ctx->error_callback(SERF_SSL_ERROR, ctx->error_baton,
ctx->fatal_err, ebuf);
}
log_ssl_error(ctx);
@@ -2082,7 +2082,7 @@
void serf_ssl_error_cb_set(
serf_ssl_context_t *context,
- serf_ssl_error_cb_t callback,
+ serf_error_cb_t callback,
void *baton)
{
context->error_callback = callback;
]]]
Would this satisfy Greg's concern about having a more generalised solution?
Cheers,
Daniel