http_client.c: Dump response on error when tracing is enabled

Reviewed-by: Tomas Mraz <tomas@openssl.org>
Reviewed-by: Dmitry Belyavskiy <beldmit@gmail.com>
Reviewed-by: David von Oheimb <david.von.oheimb@siemens.com>
(Merged from https://github.com/openssl/openssl/pull/18386)
This commit is contained in:
Dr. David von Oheimb 2022-05-23 19:43:56 +02:00 committed by Dr. David von Oheimb
parent 3c58d44749
commit e8fdb06035
7 changed files with 64 additions and 16 deletions

View File

@ -20,6 +20,7 @@
#include <openssl/cmperr.h>
#include <openssl/buffer.h>
#include <openssl/http.h>
#include <openssl/trace.h>
#include "internal/sockets.h"
#include "internal/common.h" /* for ossl_assert() */
@ -485,6 +486,7 @@ static int may_still_retry(time_t max_time, int *ptimeout)
int OSSL_HTTP_REQ_CTX_nbio(OSSL_HTTP_REQ_CTX *rctx)
{
int i, found_expected_ct = 0, found_keep_alive = 0;
int found_text_ct = 0;
long n;
size_t resp_len;
const unsigned char *p;
@ -540,6 +542,8 @@ int OSSL_HTTP_REQ_CTX_nbio(OSSL_HTTP_REQ_CTX *rctx)
case OHS_WRITE_INIT:
rctx->len_to_send = BIO_get_mem_data(rctx->mem, &rctx->pos);
rctx->state = OHS_WRITE_HDR;
if (OSSL_TRACE_ENABLED(HTTP))
OSSL_TRACE(HTTP, "Sending request header:\n");
/* fall thru */
case OHS_WRITE_HDR:
@ -548,6 +552,10 @@ int OSSL_HTTP_REQ_CTX_nbio(OSSL_HTTP_REQ_CTX *rctx)
/* Copy some chunk of data from rctx->req to rctx->wbio */
if (rctx->len_to_send > 0) {
if (OSSL_TRACE_ENABLED(HTTP)
&& rctx->state == OHS_WRITE_HDR && rctx->len_to_send <= INT_MAX)
OSSL_TRACE2(HTTP, "%.*s", (int)rctx->len_to_send, rctx->pos);
i = BIO_write(rctx->wbio, rctx->pos, rctx->len_to_send);
if (i <= 0) {
if (BIO_should_retry(rctx->wbio))
@ -631,6 +639,13 @@ int OSSL_HTTP_REQ_CTX_nbio(OSSL_HTTP_REQ_CTX *rctx)
return 0;
}
/* dump all response header lines */
if (OSSL_TRACE_ENABLED(HTTP)) {
if (rctx->state == OHS_FIRSTLINE)
OSSL_TRACE(HTTP, "Received response header:\n");
OSSL_TRACE1(HTTP, "%s", buf);
}
/* First line */
if (rctx->state == OHS_FIRSTLINE) {
switch (parse_http_line1(buf, &found_keep_alive)) {
@ -669,15 +684,20 @@ int OSSL_HTTP_REQ_CTX_nbio(OSSL_HTTP_REQ_CTX *rctx)
rctx->redirection_url = value;
return 0;
}
if (rctx->state == OHS_HEADERS && rctx->expected_ct != NULL
&& OPENSSL_strcasecmp(key, "Content-Type") == 0) {
if (OPENSSL_strcasecmp(rctx->expected_ct, value) != 0) {
ERR_raise_data(ERR_LIB_HTTP, HTTP_R_UNEXPECTED_CONTENT_TYPE,
"expected=%s, actual=%s",
rctx->expected_ct, value);
return 0;
if (OPENSSL_strcasecmp(key, "Content-Type") == 0) {
if (rctx->state == OHS_HEADERS
&& rctx->expected_ct != NULL) {
if (OPENSSL_strcasecmp(rctx->expected_ct, value) != 0) {
ERR_raise_data(ERR_LIB_HTTP,
HTTP_R_UNEXPECTED_CONTENT_TYPE,
"expected=%s, actual=%s",
rctx->expected_ct, value);
return 0;
}
found_expected_ct = 1;
}
found_expected_ct = 1;
if (OPENSSL_strncasecmp(value, "text/", 5) == 0)
found_text_ct = 1;
}
/* https://tools.ietf.org/html/rfc7230#section-6.3 Persistence */
@ -717,8 +737,12 @@ int OSSL_HTTP_REQ_CTX_nbio(OSSL_HTTP_REQ_CTX *rctx)
rctx->keep_alive = 0;
}
if (rctx->state == OHS_ERROR)
if (rctx->state == OHS_ERROR) {
if (OSSL_TRACE_ENABLED(HTTP)
&& found_text_ct && BIO_get_mem_data(rctx->mem, &p) > 0)
OSSL_TRACE1(HTTP, "%s", p);
return 0;
}
if (rctx->expected_ct != NULL && !found_expected_ct) {
ERR_raise_data(ERR_LIB_HTTP, HTTP_R_MISSING_CONTENT_TYPE,

View File

@ -138,8 +138,9 @@ static const struct trace_category_st trace_categories[] = {
TRACE_CATEGORY_(STORE),
TRACE_CATEGORY_(DECODER),
TRACE_CATEGORY_(ENCODER),
TRACE_CATEGORY_(REF_COUNT)
};
TRACE_CATEGORY_(REF_COUNT),
TRACE_CATEGORY_(HTTP),
}; /* KEEP THIS LIST IN SYNC with #define OSSL_TRACE_CATEGORY_... in trace.h */
const char *OSSL_trace_get_category_name(int num)
{

View File

@ -1060,6 +1060,10 @@ although they usually contain hints that would be helpful for diagnostics.
For assisting in such cases the CMP client offers a workaround via the
B<-unprotected_errors> option, which allows accepting such negative messages.
If OpenSSL was built with trace support enabled
and the environment variable B<OPENSSL_TRACE> includes B<HTTP>,
the request and response headers of HTTP transfers are printed.
=head1 EXAMPLES
=head2 Simple examples using the default OpenSSL configuration file

View File

@ -710,8 +710,8 @@ see L<openssl-env(7)>.
Enable tracing output of OpenSSL library, by name.
This output will only make sense if you know OpenSSL internals well.
Also, it might not give you any output at all, depending on how
OpenSSL was built.
Also, it might not give you any output at all
if OpenSSL was built without tracing support.
The value is a comma separated list of names, with the following
available:
@ -766,6 +766,10 @@ policy evaluation.
BIGNUM context.
=item B<HTTP>
HTTP client diagnostics
=back
=back

View File

@ -213,6 +213,13 @@ This may be omitted if the GET method is used and "keep-alive" is not requested.
When the request context is fully prepared, the HTTP exchange may be performed
with OSSL_HTTP_REQ_CTX_nbio() or OSSL_HTTP_REQ_CTX_exchange().
=head1 NOTES
When built with tracing enabled, OSSL_HTTP_REQ_CTX_nbio() and all functions
using it, such as OSSL_HTTP_REQ_CTX_exchange() and L<OSSL_HTTP_transfer(3)>,
may be traced using B<OSSL_TRACE_CATEGORY_HTTP>.
See also L<OSSL_trace_enabled(3)> and L<openssl(1)/ENVIRONMENT>.
=head1 RETURN VALUES
OSSL_HTTP_REQ_CTX_new() returns a pointer to a B<OSSL_HTTP_REQ_CTX>, or NULL
@ -248,7 +255,8 @@ L<ASN1_item_i2d_mem_bio(3)>,
L<OSSL_HTTP_open(3)>,
L<OSSL_HTTP_get(3)>,
L<OSSL_HTTP_transfer(3)>,
L<OSSL_HTTP_close(3)>
L<OSSL_HTTP_close(3)>,
L<OSSL_trace_enabled(3)>
=head1 HISTORY

View File

@ -245,6 +245,10 @@ C<http_proxy>, C<HTTP_PROXY>, C<https_proxy>, C<HTTPS_PROXY>, C<no_proxy>, and
C<NO_PROXY>, have been chosen for maximal compatibility with
other HTTP client implementations such as wget, curl, and git.
When built with tracing enabled, OSSL_HTTP_transfer() and all functions using it
may be traced using B<OSSL_TRACE_CATEGORY_HTTP>.
See also L<OSSL_trace_enabled(3)> and L<openssl(1)/ENVIRONMENT>.
=head1 RETURN VALUES
OSSL_HTTP_open() returns on success a B<OSSL_HTTP_REQ_CTX>, else NULL.
@ -266,7 +270,8 @@ OSSL_HTTP_close() returns 0 if anything went wrong while disconnecting, else 1.
L<OSSL_HTTP_parse_url(3)>, L<BIO_new_connect(3)>,
L<ASN1_item_i2d_mem_bio(3)>, L<ASN1_item_d2i_bio(3)>,
L<OSSL_HTTP_is_alive(3)>
L<OSSL_HTTP_is_alive(3)>,
L<OSSL_trace_enabled(3)>
=head1 HISTORY

View File

@ -57,8 +57,10 @@ extern "C" {
# define OSSL_TRACE_CATEGORY_DECODER 15
# define OSSL_TRACE_CATEGORY_ENCODER 16
# define OSSL_TRACE_CATEGORY_REF_COUNT 17
# define OSSL_TRACE_CATEGORY_HTTP 18
/* Count of available categories. */
# define OSSL_TRACE_CATEGORY_NUM 18
# define OSSL_TRACE_CATEGORY_NUM 19
/* KEEP THIS LIST IN SYNC with trace_categories[] in crypto/trace.c */
/* Returns the trace category number for the given |name| */
int OSSL_trace_get_category_num(const char *name);