]> git.ipfire.org Git - thirdparty/openssl.git/commitdiff
http_client.c: Dump response on error when tracing is enabled
authorDr. David von Oheimb <David.von.Oheimb@siemens.com>
Mon, 23 May 2022 17:43:56 +0000 (19:43 +0200)
committerDr. David von Oheimb <dev@ddvo.net>
Mon, 30 May 2022 20:43:44 +0000 (22:43 +0200)
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)

crypto/http/http_client.c
crypto/trace.c
doc/man1/openssl-cmp.pod.in
doc/man1/openssl.pod
doc/man3/OSSL_HTTP_REQ_CTX.pod
doc/man3/OSSL_HTTP_transfer.pod
include/openssl/trace.h

index c2b8f09ac144d140f7ed538f2d2a575ff883b21b..790b03fa93967ba44e686b79938e8021b16a6daa 100644 (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,
index d790409a2d6291bd6d894e838d61adf4cec85833..09a08a6512d4d246a00f4b229cbbdd62b360e644 100644 (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)
 {
index 6bbea0b0891f8b83e32c6e1b3ff9c19ba780b122..17223beea00d4bc353e6705575541a459d62ca1c 100644 (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
index c3a93fdce4b3a581b9a61397d2ef471e0bd4819a..b3de6934e5ee68bf709a234e3beb588420d91ed5 100644 (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
index ecfa44282705710d84eac905106b140f6fc80d13..36b460dbccbe35a72d6364f25a2e7ba4a12194be 100644 (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
 
index 7e823db3eab52581d37402a229ece22c5446dff5..bb29a5d3e65a3a70f977dbb45da45fe05522f0f1 100644 (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
 
index 282001336732e33029495394d84a999e807a4305..059644299e4cf68d3e1e8b01779e3ec4069f9377 100644 (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);