libsoup r1243 - in trunk: . libsoup tests
- From: danw svn gnome org
- To: svn-commits-list gnome org
- Subject: libsoup r1243 - in trunk: . libsoup tests
- Date: Thu, 19 Feb 2009 18:55:49 +0000 (UTC)
Author: danw
Date: Thu Feb 19 18:55:49 2009
New Revision: 1243
URL: http://svn.gnome.org/viewvc/libsoup?rev=1243&view=rev
Log:
Bug 572153 â SoupServer doesn't support SOUP_ENCODING_EOF
* libsoup/soup-message-io.c (io_write): Various fixes to make
SOUP_ENCODING_EOF work correctly when sending response
bodies. (Previously, the code assumed that SoupServer responses
would always be chunked or Content-Length-encoded.)
* libsoup/soup-message-client-io.c (get_request_headers): when
changing a request body from SOUP_ENCODING_NONE to
SOUP_ENCODING_CONTENT_LENGTH, return the new encoding value to
soup-message-io, not the old one.
* libsoup/soup-message.c (set_property): when setting
priv->server_side to TRUE, set the default encoding on the
response headers to CONTENT_LENGTH. (Moved from SoupServer.)
(soup_message_cleanup_response): If priv->server_side is TRUE,
re-fix the response header encoding after clearing the headers.
Otherwise the response headers revert to SOUP_ENCODING_EOF after
sending a "100 Continue".
(soup_message_is_keepalive): reorganize a little, fix a bug in the
HTTP/1.0 case.
* libsoup/soup-server.c (start_request): remove request encoding
override from here.
* tests/streaming-test.c: new test of SoupServer response
streaming, testing chunked, content-length, and eof-terminated
responses
Added:
trunk/tests/streaming-test.c
Modified:
trunk/ChangeLog
trunk/libsoup/soup-message-client-io.c
trunk/libsoup/soup-message-headers.c
trunk/libsoup/soup-message-io.c
trunk/libsoup/soup-message.c
trunk/libsoup/soup-server.c
trunk/tests/ (props changed)
trunk/tests/Makefile.am
Modified: trunk/libsoup/soup-message-client-io.c
==============================================================================
--- trunk/libsoup/soup-message-client-io.c (original)
+++ trunk/libsoup/soup-message-client-io.c Thu Feb 19 18:55:49 2009
@@ -107,9 +107,11 @@
g_free (uri_host);
*encoding = soup_message_headers_get_encoding (req->request_headers);
- if (*encoding != SOUP_ENCODING_CHUNKED &&
+ if ((*encoding == SOUP_ENCODING_CONTENT_LENGTH ||
+ *encoding == SOUP_ENCODING_NONE) &&
req->request_body->length > 0 &&
!soup_message_headers_get_content_length (req->request_headers)) {
+ *encoding = SOUP_ENCODING_CONTENT_LENGTH;
soup_message_headers_set_content_length (req->request_headers,
req->request_body->length);
}
Modified: trunk/libsoup/soup-message-headers.c
==============================================================================
--- trunk/libsoup/soup-message-headers.c (original)
+++ trunk/libsoup/soup-message-headers.c Thu Feb 19 18:55:49 2009
@@ -515,6 +515,13 @@
return hdrs->encoding;
}
+ /* Per RFC 2616 4.4, a response body that doesn't indicate its
+ * encoding otherwise is terminated by connection close, and a
+ * request that doesn't indicate otherwise has no body. Note
+ * that SoupMessage calls soup_message_headers_set_encoding()
+ * to override the response body default for our own
+ * server-side messages.
+ */
hdrs->encoding = (hdrs->type == SOUP_MESSAGE_HEADERS_RESPONSE) ?
SOUP_ENCODING_EOF : SOUP_ENCODING_NONE;
return hdrs->encoding;
Modified: trunk/libsoup/soup-message-io.c
==============================================================================
--- trunk/libsoup/soup-message-io.c (original)
+++ trunk/libsoup/soup-message-io.c Thu Feb 19 18:55:49 2009
@@ -453,7 +453,7 @@
g_string_truncate (io->write_buf, 0);
- if (io->write_encoding != SOUP_ENCODING_CHUNKED) {
+ if (io->write_encoding == SOUP_ENCODING_CONTENT_LENGTH) {
SoupMessageHeaders *hdrs =
(io->mode == SOUP_MESSAGE_IO_CLIENT) ?
msg->request_headers : msg->response_headers;
@@ -516,7 +516,8 @@
case SOUP_MESSAGE_IO_STATE_BODY:
- if (!io->write_length) {
+ if (!io->write_length && io->write_encoding != SOUP_ENCODING_EOF) {
+ wrote_body:
io->write_state = SOUP_MESSAGE_IO_STATE_FINISHING;
SOUP_MESSAGE_IO_PREPARE_FOR_CALLBACK;
@@ -531,7 +532,8 @@
soup_message_io_pause (msg);
return;
}
- if (io->write_chunk->length > io->write_length) {
+ if (io->write_chunk->length > io->write_length &&
+ io->write_encoding != SOUP_ENCODING_EOF) {
/* App is trying to write more than it
* claimed it would; we have to truncate.
*/
@@ -540,7 +542,9 @@
0, io->write_length);
soup_buffer_free (io->write_chunk);
io->write_chunk = truncated;
- }
+ } else if (io->write_encoding == SOUP_ENCODING_EOF &&
+ !io->write_chunk->length)
+ goto wrote_body;
}
if (!write_data (msg, io->write_chunk->data,
Modified: trunk/libsoup/soup-message.c
==============================================================================
--- trunk/libsoup/soup-message.c (original)
+++ trunk/libsoup/soup-message.c Thu Feb 19 18:55:49 2009
@@ -499,6 +499,10 @@
break;
case PROP_SERVER_SIDE:
priv->server_side = g_value_get_boolean (value);
+ if (priv->server_side) {
+ soup_message_headers_set_encoding (msg->response_headers,
+ SOUP_ENCODING_CONTENT_LENGTH);
+ }
break;
case PROP_STATUS_CODE:
soup_message_set_status (msg, g_value_get_uint (value));
@@ -1101,6 +1105,10 @@
soup_message_body_truncate (req->response_body);
soup_message_headers_clear (req->response_headers);
+ if (priv->server_side) {
+ soup_message_headers_set_encoding (req->response_headers,
+ SOUP_ENCODING_CONTENT_LENGTH);
+ }
req->status_code = SOUP_STATUS_NONE;
if (req->reason_phrase) {
@@ -1237,6 +1245,10 @@
msg->method == SOUP_METHOD_CONNECT)
return TRUE;
+ /* Not persistent if the server sent a terminate-by-EOF response */
+ if (soup_message_headers_get_encoding (msg->response_headers) == SOUP_ENCODING_EOF)
+ return FALSE;
+
if (SOUP_MESSAGE_GET_PRIVATE (msg)->http_version == SOUP_HTTP_1_0) {
/* Only persistent if the client requested keepalive
* and the server agreed.
@@ -1244,11 +1256,9 @@
if (!c_conn || !s_conn)
return FALSE;
- if (soup_header_contains (c_conn, "Keep-Alive") ||
- soup_header_contains (s_conn, "Keep-Alive"))
+ if (!soup_header_contains (c_conn, "Keep-Alive") ||
+ !soup_header_contains (s_conn, "Keep-Alive"))
return FALSE;
-
- return TRUE;
} else {
/* Normally persistent unless either side requested otherwise */
if (c_conn && soup_header_contains (c_conn, "close"))
@@ -1256,12 +1266,10 @@
if (s_conn && soup_header_contains (s_conn, "close"))
return FALSE;
- /* But not if the server sent a terminate-by-EOF response */
- if (soup_message_headers_get_encoding (msg->response_headers) == SOUP_ENCODING_EOF)
- return FALSE;
-
return TRUE;
}
+
+ return TRUE;
}
/**
Modified: trunk/libsoup/soup-server.c
==============================================================================
--- trunk/libsoup/soup-server.c (original)
+++ trunk/libsoup/soup-server.c Thu Feb 19 18:55:49 2009
@@ -810,8 +810,6 @@
msg = g_object_new (SOUP_TYPE_MESSAGE,
SOUP_MESSAGE_SERVER_SIDE, TRUE,
NULL);
- soup_message_headers_set_encoding (msg->response_headers,
- SOUP_ENCODING_CONTENT_LENGTH);
if (priv->server_header) {
soup_message_headers_append (msg->response_headers, "Server",
priv->server_header);
Modified: trunk/tests/Makefile.am
==============================================================================
--- trunk/tests/Makefile.am (original)
+++ trunk/tests/Makefile.am Thu Feb 19 18:55:49 2009
@@ -26,6 +26,7 @@
redirect-test \
simple-httpd \
simple-proxy \
+ streaming-test \
uri-parsing \
$(CURL_TESTS) \
$(APACHE_TESTS) \
@@ -57,6 +58,7 @@
simple_httpd_SOURCES = simple-httpd.c
simple_proxy_SOURCES = simple-proxy.c
ssl_test_SOURCES = ssl-test.c $(TEST_SRCS)
+streaming_test_SOURCES = streaming-test.c $(TEST_SRCS)
uri_parsing_SOURCES = uri-parsing.c $(TEST_SRCS)
xmlrpc_test_SOURCES = xmlrpc-test.c $(TEST_SRCS)
xmlrpc_server_test_SOURCES = xmlrpc-server-test.c $(TEST_SRCS)
@@ -83,6 +85,7 @@
misc-test \
ntlm-test \
redirect-test \
+ streaming-test \
uri-parsing \
$(APACHE_TESTS) \
$(CURL_TESTS) \
Added: trunk/tests/streaming-test.c
==============================================================================
--- (empty file)
+++ trunk/tests/streaming-test.c Thu Feb 19 18:55:49 2009
@@ -0,0 +1,187 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2008 Red Hat, Inc.
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <glib.h>
+#include <libsoup/soup.h>
+
+#include "test-utils.h"
+
+#define RESPONSE_CHUNK_SIZE 1024
+
+char *full_response, *full_response_md5;
+gsize full_response_length;
+
+static void
+get_full_response (void)
+{
+ GError *error = NULL;
+
+ if (!g_file_get_contents (SRCDIR "/index.txt",
+ &full_response,
+ &full_response_length,
+ &error)) {
+ fprintf (stderr, "Could not read index file %s: %s\n",
+ SRCDIR "/index.txt", error->message);
+ g_error_free (error);
+ exit (1);
+ }
+
+ full_response_md5 = g_compute_checksum_for_data (G_CHECKSUM_MD5,
+ (guchar *)full_response,
+ full_response_length);
+}
+
+static void
+write_next_chunk (SoupMessage *msg, gpointer user_data)
+{
+ gsize *offset = user_data;
+ gsize chunk_length;
+
+ chunk_length = MIN (RESPONSE_CHUNK_SIZE, full_response_length - *offset);
+ if (chunk_length > 0) {
+ debug_printf (2, " writing chunk\n");
+ soup_message_body_append (msg->response_body,
+ SOUP_MEMORY_STATIC,
+ full_response + *offset,
+ chunk_length);
+ *offset += chunk_length;
+ } else {
+ debug_printf (2, " done\n");
+ /* This is only actually needed in the chunked and eof
+ * cases, but it's harmless in the content-length
+ * case.
+ */
+ soup_message_body_complete (msg->response_body);
+ }
+}
+
+static void
+free_offset (SoupMessage *msg, gpointer offset)
+{
+ g_free (offset);
+}
+
+static void
+server_callback (SoupServer *server, SoupMessage *msg,
+ const char *path, GHashTable *query,
+ SoupClientContext *context, gpointer data)
+{
+ gsize *offset;
+
+ if (!strcmp (path, "/chunked")) {
+ soup_message_headers_set_encoding (msg->response_headers,
+ SOUP_ENCODING_CHUNKED);
+ } else if (!strcmp (path, "/content-length")) {
+ soup_message_headers_set_encoding (msg->response_headers,
+ SOUP_ENCODING_CONTENT_LENGTH);
+ soup_message_headers_set_content_length (msg->response_headers,
+ full_response_length);
+ } else if (!strcmp (path, "/eof")) {
+ soup_message_headers_set_encoding (msg->response_headers,
+ SOUP_ENCODING_EOF);
+ } else {
+ soup_message_set_status (msg, SOUP_STATUS_NOT_FOUND);
+ return;
+ }
+ soup_message_set_status (msg, SOUP_STATUS_OK);
+
+ offset = g_new0 (gsize, 1);
+ g_signal_connect (msg, "wrote_headers",
+ G_CALLBACK (write_next_chunk), offset);
+ g_signal_connect (msg, "wrote_chunk",
+ G_CALLBACK (write_next_chunk), offset);
+ g_signal_connect (msg, "finished",
+ G_CALLBACK (free_offset), offset);
+}
+
+static void
+do_request (SoupSession *session, SoupURI *base_uri, char *path)
+{
+ SoupURI *uri;
+ SoupMessage *msg;
+ char *md5;
+
+ uri = soup_uri_new_with_base (base_uri, path);
+ msg = soup_message_new_from_uri ("GET", uri);
+ soup_uri_free (uri);
+
+ soup_session_send_message (session, msg);
+
+ if (!SOUP_STATUS_IS_SUCCESSFUL (msg->status_code)) {
+ debug_printf (1, " message failed: %d %s\n",
+ msg->status_code, msg->reason_phrase);
+ errors++;
+ }
+
+ if (msg->response_body->length != full_response_length) {
+ debug_printf (1, " received length mismatch: expected %d, got %d\n",
+ (int)full_response_length, (int)msg->request_body->length);
+ errors++;
+ }
+
+ md5 = g_compute_checksum_for_data (G_CHECKSUM_MD5,
+ (guchar *)msg->response_body->data,
+ msg->response_body->length);
+ if (strcmp (md5, full_response_md5) != 0) {
+ debug_printf (1, " data mismatch: expected %s, got %s\n",
+ full_response_md5, md5);
+ errors++;
+ }
+ g_free (md5);
+
+ g_object_unref (msg);
+}
+
+static void
+do_tests (SoupURI *base_uri)
+{
+ SoupSession *session;
+
+ session = soup_test_session_new (SOUP_TYPE_SESSION_ASYNC, NULL);
+ debug_printf (1, "Chunked encoding\n");
+ do_request (session, base_uri, "chunked");
+ debug_printf (1, "\n");
+ debug_printf (1, "Content-Length encoding\n");
+ do_request (session, base_uri, "content-length");
+ debug_printf (1, "\n");
+ debug_printf (1, "EOF encoding\n");
+ do_request (session, base_uri, "eof");
+ soup_test_session_abort_unref (session);
+}
+
+int
+main (int argc, char **argv)
+{
+ GMainLoop *loop;
+ SoupServer *server;
+ guint port;
+ SoupURI *base_uri;
+
+ test_init (argc, argv, NULL);
+ get_full_response ();
+
+ server = soup_test_server_new (FALSE);
+ soup_server_add_handler (server, NULL,
+ server_callback, NULL, NULL);
+ port = soup_server_get_port (server);
+
+ loop = g_main_loop_new (NULL, TRUE);
+
+ base_uri = soup_uri_new ("http://localhost");
+ soup_uri_set_port (base_uri, port);
+ do_tests (base_uri);
+ soup_uri_free (base_uri);
+
+ g_main_loop_unref (loop);
+
+ test_cleanup ();
+ return errors != 0;
+}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]