From 6d64ef869dfbcb7aaa802b80ed648393147e40d8 Mon Sep 17 00:00:00 2001 From: Justus Winter Date: Fri, 4 Dec 2015 12:32:20 +0100 Subject: [PATCH] dirmngr: Stricter handling of http error codes. * dirmngr/ks-action.c (ks_action_search): Only retry if the keyserver responded with a '404 Not Found'. * dirmngr/ks-engine-hkp.c (send_request): Return http status code. (ks_hkp_search): Likewise. (ks_hkp_{get,put}): Adapt call to 'send_request'. * dirmngr/ks-engine.h (ks_hkp_search): Update prototype. Signed-off-by: Justus Winter --- dirmngr/ks-action.c | 12 +++++++----- dirmngr/ks-engine-hkp.c | 20 +++++++++++++------- dirmngr/ks-engine.h | 2 +- 3 files changed, 21 insertions(+), 13 deletions(-) diff --git a/dirmngr/ks-action.c b/dirmngr/ks-action.c index 285167a17..1da91cccf 100644 --- a/dirmngr/ks-action.c +++ b/dirmngr/ks-action.c @@ -156,13 +156,13 @@ ks_action_search (ctrl_t ctrl, uri_item_t keyservers, parallel and merge them. We also need to decide what to do with errors - it might not be the best idea to ignore an error from one server and silently continue with another server. For now we - stop at the first error, unless it is GPG_ERR_NO_DATA, in which - case we try the next server. Unfortunately, 'send_requests' - broadly maps all kinds of http errors to GPG_ERR_NO_DATA. */ + stop at the first error, unless the server responds with '404 Not + Found', in which case we try the next server. */ for (uri = keyservers; !err && uri; uri = uri->next) { int is_http = uri->parsed_uri->is_http; int is_ldap = 0; + unsigned int http_status; #if USE_LDAP is_ldap = (strcmp (uri->parsed_uri->scheme, "ldap") == 0 || strcmp (uri->parsed_uri->scheme, "ldaps") == 0 @@ -177,10 +177,12 @@ ks_action_search (ctrl_t ctrl, uri_item_t keyservers, else #endif { - err = ks_hkp_search (ctrl, uri->parsed_uri, patterns->d, &infp); + err = ks_hkp_search (ctrl, uri->parsed_uri, patterns->d, + &infp, &http_status); } - if (err == gpg_error (GPG_ERR_NO_DATA)) + if (err == gpg_error (GPG_ERR_NO_DATA) + && http_status == 404 /* not found */) { /* No record found. Clear error and try next server. */ err = 0; diff --git a/dirmngr/ks-engine-hkp.c b/dirmngr/ks-engine-hkp.c index 0f2021cce..f38f29a6b 100644 --- a/dirmngr/ks-engine-hkp.c +++ b/dirmngr/ks-engine-hkp.c @@ -974,12 +974,13 @@ ks_hkp_housekeeping (time_t curtime) R_FP. HOSTPORTSTR is only used for diagnostics. If HTTPHOST is not NULL it will be used as HTTP "Host" header. If POST_CB is not NULL a post request is used and that callback is called to allow - writing the post data. */ + writing the post data. If R_HTTP_STATUS is not NULL, the http + status code will be stored there. */ static gpg_error_t send_request (ctrl_t ctrl, const char *request, const char *hostportstr, const char *httphost, unsigned int httpflags, gpg_error_t (*post_cb)(void *, http_t), void *post_cb_value, - estream_t *r_fp) + estream_t *r_fp, unsigned int *r_http_status) { gpg_error_t err; http_session_t session = NULL; @@ -1050,6 +1051,9 @@ send_request (ctrl_t ctrl, const char *request, const char *hostportstr, httpflags |= HTTP_FLAG_FORCE_TLS; } + if (r_http_status) + *r_http_status = http_get_status_code (http); + switch (http_get_status_code (http)) { case 200: @@ -1158,10 +1162,12 @@ handle_send_request_error (gpg_error_t err, const char *request, /* Search the keyserver identified by URI for keys matching PATTERN. - On success R_FP has an open stream to read the data. */ + On success R_FP has an open stream to read the data. If + R_HTTP_STATUS is not NULL, the http status code will be stored + there. */ gpg_error_t ks_hkp_search (ctrl_t ctrl, parsed_uri_t uri, const char *pattern, - estream_t *r_fp) + estream_t *r_fp, unsigned int *r_http_status) { gpg_error_t err; KEYDB_SEARCH_DESC desc; @@ -1248,7 +1254,7 @@ ks_hkp_search (ctrl_t ctrl, parsed_uri_t uri, const char *pattern, /* Send the request. */ err = send_request (ctrl, request, hostport, httphost, httpflags, - NULL, NULL, &fp); + NULL, NULL, &fp, r_http_status); if (handle_send_request_error (err, request, &tries)) { reselect = 1; @@ -1381,7 +1387,7 @@ ks_hkp_get (ctrl_t ctrl, parsed_uri_t uri, const char *keyspec, estream_t *r_fp) /* Send the request. */ err = send_request (ctrl, request, hostport, httphost, httpflags, - NULL, NULL, &fp); + NULL, NULL, &fp, NULL); if (handle_send_request_error (err, request, &tries)) { reselect = 1; @@ -1489,7 +1495,7 @@ ks_hkp_put (ctrl_t ctrl, parsed_uri_t uri, const void *data, size_t datalen) /* Send the request. */ err = send_request (ctrl, request, hostport, httphost, 0, - put_post_cb, &parm, &fp); + put_post_cb, &parm, &fp, NULL); if (handle_send_request_error (err, request, &tries)) { reselect = 1; diff --git a/dirmngr/ks-engine.h b/dirmngr/ks-engine.h index 6684a12b2..cb48f7f1f 100644 --- a/dirmngr/ks-engine.h +++ b/dirmngr/ks-engine.h @@ -34,7 +34,7 @@ gpg_error_t ks_hkp_mark_host (ctrl_t ctrl, const char *name, int alive); gpg_error_t ks_hkp_print_hosttable (ctrl_t ctrl); gpg_error_t ks_hkp_help (ctrl_t ctrl, parsed_uri_t uri); gpg_error_t ks_hkp_search (ctrl_t ctrl, parsed_uri_t uri, const char *pattern, - estream_t *r_fp); + estream_t *r_fp, unsigned int *r_http_status); gpg_error_t ks_hkp_get (ctrl_t ctrl, parsed_uri_t uri, const char *keyspec, estream_t *r_fp); gpg_error_t ks_hkp_put (ctrl_t ctrl, parsed_uri_t uri,