[libsoup] data: URL requests should serve the whole decoded URL



commit c1c58c9fc79562b0da4ceeeb3fc378407f8b9c85
Author: Zan Dobersek <zandobersek gmail com>
Date:   Thu Mar 7 21:23:15 2013 +0100

    data: URL requests should serve the whole decoded URL
    
    Address the possibility of data: URLs containing null characters when the data
    request is being performed. The uri_decoded_copy method is enhanced with a
    third argument, a pointer to an integer that should be set to the length of
    decoded data when provided. This length is then set as the request's content
    length.
    
    A test checking the correct behavior is added in requester-test. Calls to
    uri_decoded_copy where the length of the decoded output is not required are
    adjusted to provide NULL as the third argument.

 libsoup/soup-misc-private.h |    2 +-
 libsoup/soup-request-data.c |    7 ++-
 libsoup/soup-uri.c          |   13 ++++--
 tests/requester-test.c      |   86 +++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 99 insertions(+), 9 deletions(-)
---
diff --git a/libsoup/soup-misc-private.h b/libsoup/soup-misc-private.h
index b9f0724..cd83618 100644
--- a/libsoup/soup-misc-private.h
+++ b/libsoup/soup-misc-private.h
@@ -9,7 +9,7 @@
 
 #include "soup-socket.h"
 
-char *uri_decoded_copy (const char *str, int length);
+char *uri_decoded_copy (const char *str, int length, int *decoded_length);
 
 guint soup_socket_handshake_sync  (SoupSocket         *sock,
                                   GCancellable       *cancellable);
diff --git a/libsoup/soup-request-data.c b/libsoup/soup-request-data.c
index 66836a5..246854a 100644
--- a/libsoup/soup-request-data.c
+++ b/libsoup/soup-request-data.c
@@ -96,7 +96,7 @@ soup_request_data_send (SoupRequest   *request,
                        end = comma;
 
                if (end != start)
-                       data->priv->content_type = uri_decoded_copy (start, end - start);
+                       data->priv->content_type = uri_decoded_copy (start, end - start, NULL);
        }
 
        memstream = g_memory_input_stream_new ();
@@ -105,12 +105,13 @@ soup_request_data_send (SoupRequest   *request,
                start = comma + 1;
 
        if (*start) {
-               guchar *buf = (guchar *) soup_uri_decode (start);
+               int decoded_length = 0;
+               guchar *buf = (guchar *) uri_decoded_copy (start, strlen (start), &decoded_length);
 
                if (base64)
                        buf = g_base64_decode_inplace ((gchar*) buf, &data->priv->content_length);
                else
-                       data->priv->content_length = strlen ((const char *) buf);
+                       data->priv->content_length = decoded_length;
 
                g_memory_input_stream_add_data (G_MEMORY_INPUT_STREAM (memstream),
                                                buf, data->priv->content_length,
diff --git a/libsoup/soup-uri.c b/libsoup/soup-uri.c
index 28b3025..723e361 100644
--- a/libsoup/soup-uri.c
+++ b/libsoup/soup-uri.c
@@ -291,14 +291,14 @@ soup_uri_new_with_base (SoupURI *base, const char *uri_string)
                        colon = strchr (uri_string, ':');
                        if (colon && colon < at) {
                                uri->password = uri_decoded_copy (colon + 1,
-                                                                 at - colon - 1);
+                                                                 at - colon - 1, NULL);
                        } else {
                                uri->password = NULL;
                                colon = at;
                        }
 
                        uri->user = uri_decoded_copy (uri_string,
-                                                     colon - uri_string);
+                                                     colon - uri_string, NULL);
                        uri_string = at + 1;
                } else
                        uri->user = uri->password = NULL;
@@ -320,7 +320,7 @@ soup_uri_new_with_base (SoupURI *base, const char *uri_string)
                        hostend = colon ? colon : path;
                }
 
-               uri->host = uri_decoded_copy (uri_string, hostend - uri_string);
+               uri->host = uri_decoded_copy (uri_string, hostend - uri_string, NULL);
 
                if (colon && colon != path - 1) {
                        char *portend;
@@ -694,7 +694,7 @@ soup_uri_encode (const char *part, const char *escape_extra)
 #define HEXCHAR(s) ((XDIGIT (s[1]) << 4) + XDIGIT (s[2]))
 
 char *
-uri_decoded_copy (const char *part, int length)
+uri_decoded_copy (const char *part, int length, int *decoded_length)
 {
        unsigned char *s, *d;
        char *decoded = g_strndup (part, length);
@@ -715,6 +715,9 @@ uri_decoded_copy (const char *part, int length)
                        *d++ = *s;
        } while (*s++);
 
+       if (decoded_length)
+               *decoded_length = d - (unsigned char *)decoded - 1;
+
        return decoded;
 }
 
@@ -735,7 +738,7 @@ soup_uri_decode (const char *part)
 {
        g_return_val_if_fail (part != NULL, NULL);
 
-       return uri_decoded_copy (part, strlen (part));
+       return uri_decoded_copy (part, strlen (part), NULL);
 }
 
 static char *
diff --git a/tests/requester-test.c b/tests/requester-test.c
index a4bb5b6..147ba4c 100644
--- a/tests/requester-test.c
+++ b/tests/requester-test.c
@@ -649,6 +649,90 @@ do_sync_test (const char *uri_string, gboolean plain_session)
        soup_uri_free (uri);
 }
 
+
+static void
+do_null_char_request (SoupSession *session, const char *encoded_data,
+                      const char *expected_data, int expected_len)
+{
+       GError *error = NULL;
+       GInputStream *stream;
+       SoupRequest *request;
+       SoupURI *uri;
+       char *uri_string, buf[256];
+       gsize nread;
+
+       uri_string = g_strdup_printf ("data:text/html,%s", encoded_data);
+       uri = soup_uri_new (uri_string);
+       g_free (uri_string);
+
+       request = soup_session_request_uri (session, uri, NULL);
+       stream = soup_test_request_send (request, NULL, 0, &error);
+
+       if (error) {
+               debug_printf (1, "  could not send request: %s\n", error->message);
+               g_error_free (error);
+               g_object_unref (request);
+               soup_uri_free (uri);
+               return;
+       }
+
+       g_input_stream_read_all (stream, buf, sizeof (buf), &nread, NULL, &error);
+       if (error) {
+               debug_printf (1, "      could not read response: %s\n", error->message);
+               errors++;
+               g_clear_error (&error);
+       }
+
+       soup_test_request_close_stream (request, stream, NULL, &error);
+       if (error) {
+               debug_printf (1, "      could not close stream: %s\n", error->message);
+               errors++;
+               g_clear_error (&error);
+       }
+
+       if (nread != expected_len) {
+               debug_printf (1, "      response length mismatch: expected %d, got %lu\n", expected_len, 
nread);
+               errors++;
+       } else if (memcmp (buf, expected_data, nread) != 0) {
+               debug_printf (1, "      response data mismatch\n");
+               errors++;
+       }
+
+       g_object_unref (stream);
+       g_object_unref (request);
+       soup_uri_free (uri);
+}
+
+static void
+do_null_char_test (gboolean plain_session)
+{
+       SoupSession *session;
+       int i;
+       static struct {
+               const char *encoded_data;
+               const char *expected_data;
+               int expected_len;
+       } test_cases[] = {
+               { "%3Cscript%3Ea%3D'%00'%3C%2Fscript%3E", "<script>a='\0'</script>", 22 },
+               { "%00%3Cscript%3Ea%3D42%3C%2Fscript%3E", "\0<script>a=42</script>", 22 },
+               { "%3Cscript%3E%00%3Cbr%2F%3E%3C%2Fscript%3E%00", "<script>\0<br/></script>\0", 24 },
+       };
+       static int num_test_cases = G_N_ELEMENTS(test_cases);
+
+       debug_printf (1, "Streaming data URLs containing null chars with %s\n",
+                     plain_session ? "SoupSession" : "SoupSessionSync");
+
+       session = soup_test_session_new (plain_session ? SOUP_TYPE_SESSION : SOUP_TYPE_SESSION_ASYNC,
+                                        SOUP_SESSION_USE_THREAD_CONTEXT, TRUE,
+                                        NULL);
+
+       for (i = 0; i < num_test_cases; i++)
+               do_null_char_request (session, test_cases[i].encoded_data,
+                                     test_cases[i].expected_data, test_cases[i].expected_len);
+
+       soup_test_session_abort_unref (session);
+}
+
 int
 main (int argc, char **argv)
 {
@@ -666,11 +750,13 @@ main (int argc, char **argv)
        do_thread_test (uri, FALSE);
        do_context_test (uri, FALSE);
        do_sync_test (uri, FALSE);
+       do_null_char_test (FALSE);
 
        do_simple_test (uri, TRUE);
        do_thread_test (uri, TRUE);
        do_context_test (uri, TRUE);
        do_sync_test (uri, TRUE);
+       do_null_char_test (TRUE);
 
        g_free (uri);
        soup_buffer_free (response);


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