[libsoup/carlosgc/null-post-content-length] session: Include Content-Length header for put and post requests with no body




commit dde1a85cf5f8bfb042e6c47530c82b5c6c40353e
Author: Carlos Garcia Campos <cgarcia igalia com>
Date:   Wed Feb 3 15:54:38 2021 +0100

    session: Include Content-Length header for put and post requests with no body
    
    As suggested in the HTTP spec.

 libsoup/soup-session.c    | 13 +++++++++++++
 tests/request-body-test.c | 24 ++++++++++++++++++++----
 2 files changed, 33 insertions(+), 4 deletions(-)
---
diff --git a/libsoup/soup-session.c b/libsoup/soup-session.c
index d867684a..4509993a 100644
--- a/libsoup/soup-session.c
+++ b/libsoup/soup-session.c
@@ -1006,6 +1006,7 @@ soup_session_send_queue_item (SoupSession *session,
 {
        SoupSessionPrivate *priv = soup_session_get_instance_private (session);
        SoupMessageHeaders *request_headers;
+       const char *method;
 
        request_headers = soup_message_get_request_headers (item->msg);
        if (priv->user_agent)
@@ -1042,6 +1043,18 @@ soup_session_send_queue_item (SoupSession *session,
                 g_free (host);
         }
 
+       /* A user agent SHOULD send a Content-Length in a request message when
+        * no Transfer-Encoding is sent and the request method defines a meaning
+        * for an enclosed payload body. For example, a Content-Length header
+        * field is normally sent in a POST request even when the value is 0
+        * (indicating an empty payload body).
+        */
+       method = soup_message_get_method (item->msg);
+       if ((method == SOUP_METHOD_POST || method == SOUP_METHOD_PUT) &&
+           soup_message_get_request_body_stream (item->msg) == NULL) {
+               soup_message_headers_set_content_length (request_headers, 0);
+       }
+
        soup_message_starting (item->msg);
        if (item->state == SOUP_MESSAGE_RUNNING)
                soup_connection_send_request (item->conn, item, completion_cb, item);
diff --git a/tests/request-body-test.c b/tests/request-body-test.c
index 091633a9..e5d9ffa1 100644
--- a/tests/request-body-test.c
+++ b/tests/request-body-test.c
@@ -25,6 +25,7 @@ typedef enum {
         LARGE = 1 << 3,
         EMPTY = 1 << 4,
         NO_CONTENT_TYPE = 1 << 5,
+       NULL_STREAM = 1 << 6,
 } RequestTestFlags;
 
 static void
@@ -44,6 +45,14 @@ setup_request_body (PutTestData     *ptd,
 
         ptd->nwrote = 0;
         check = g_checksum_new (G_CHECKSUM_MD5);
+       if (flags & NULL_STREAM) {
+               ptd->bytes = NULL;
+               ptd->stream = NULL;
+               ptd->content_type = NULL;
+
+               return check;
+       }
+
         if (flags & LARGE) {
                 static const unsigned int large_size = 1000000;
                 char *large_data;
@@ -83,7 +92,7 @@ restarted (SoupMessage *msg,
                 g_object_unref (ptd->stream);
                 ptd->stream = g_memory_input_stream_new_from_bytes (ptd->bytes);
                 soup_message_set_request_body (msg, ptd->content_type, ptd->stream, -1);
-        } else {
+        } else if (ptd->bytes) {
                 soup_message_set_request_body_from_bytes (msg, ptd->content_type, ptd->bytes);
         }
 }
@@ -114,7 +123,7 @@ do_request_test (gconstpointer data)
                 soup_message_set_request_body_from_bytes (msg, ptd.content_type, ptd.bytes);
                 g_assert_cmpuint (soup_message_headers_get_content_length (request_headers), ==, 
g_bytes_get_size (ptd.bytes));
                 g_assert_true (soup_message_headers_get_encoding (request_headers) == 
SOUP_ENCODING_CONTENT_LENGTH);
-        } else {
+        } else if (!(flags & NULL_STREAM)) {
                 soup_message_set_request_body (msg, ptd.content_type, ptd.stream, -1);
                 g_assert_cmpuint (soup_message_headers_get_content_length (request_headers), ==, 0);
                 g_assert_true (soup_message_headers_get_encoding (request_headers) == SOUP_ENCODING_CHUNKED);
@@ -134,13 +143,18 @@ do_request_test (gconstpointer data)
         else
                 soup_test_session_send_message (session, msg);
         soup_test_assert_message_status (msg, SOUP_STATUS_CREATED);
-        g_assert_cmpint (g_bytes_get_size (ptd.bytes), ==, ptd.nwrote);
+       if (flags & NULL_STREAM) {
+               g_assert_cmpint (ptd.nwrote, ==, 0);
+               g_assert_cmpstr (soup_message_headers_get_one (request_headers, "Content-Length"), ==, "0");
+       } else {
+               g_assert_cmpint (g_bytes_get_size (ptd.bytes), ==, ptd.nwrote);
+       }
 
         server_md5 = soup_message_headers_get_one (soup_message_get_response_headers (msg),
                                                    "Content-MD5");
         g_assert_cmpstr (client_md5, ==, server_md5);
 
-        g_bytes_unref (ptd.bytes);
+       g_clear_pointer (&ptd.bytes, g_bytes_unref);
         g_clear_object (&ptd.stream);
         g_object_unref (msg);
         g_checksum_free (check);
@@ -204,6 +218,7 @@ main (int argc, char **argv)
         g_test_add_data_func ("/request-body/sync/empty", GINT_TO_POINTER (BYTES | EMPTY), do_request_test);
         g_test_add_data_func ("/request-body/sync/no-content-type-stream", GINT_TO_POINTER 
(NO_CONTENT_TYPE), do_request_test);
         g_test_add_data_func ("/request-body/sync/no-content-type-bytes", GINT_TO_POINTER (BYTES | 
NO_CONTENT_TYPE), do_request_test);
+       g_test_add_data_func ("/request-body/sync/null", GINT_TO_POINTER (NULL_STREAM), do_request_test);
         g_test_add_data_func ("/request-body/async/stream", GINT_TO_POINTER (ASYNC), do_request_test);
         g_test_add_data_func ("/request-body/async/bytes", GINT_TO_POINTER (BYTES | ASYNC), do_request_test);
         g_test_add_data_func ("/request-body/async/restart-stream", GINT_TO_POINTER (RESTART | ASYNC), 
do_request_test);
@@ -212,6 +227,7 @@ main (int argc, char **argv)
         g_test_add_data_func ("/request-body/async/empty", GINT_TO_POINTER (BYTES | EMPTY | ASYNC), 
do_request_test);
         g_test_add_data_func ("/request-body/async/no-content-type-stream", GINT_TO_POINTER (NO_CONTENT_TYPE 
| ASYNC), do_request_test);
         g_test_add_data_func ("/request-body/async/no-content-type-bytes", GINT_TO_POINTER (BYTES | 
NO_CONTENT_TYPE | ASYNC), do_request_test);
+       g_test_add_data_func ("/request-body/async/null", GINT_TO_POINTER (NULL_STREAM | ASYNC), 
do_request_test);
 
         ret = g_test_run ();
 


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]