Exemple #1
0
static void
get_user_info_ready_cb (SoupSession *session,
			SoupMessage *msg,
			gpointer     user_data)
{
	FacebookService      *self = user_data;
	GSimpleAsyncResult *result;
	SoupBuffer         *body;
	DomDocument        *doc = NULL;
	GError             *error = NULL;

	result = facebook_connection_get_result (self->priv->conn);

	if (msg->status_code != 200) {
		g_simple_async_result_set_error (result,
						 SOUP_HTTP_ERROR,
						 msg->status_code,
						 "%s",
						 soup_status_get_phrase (msg->status_code));
		g_simple_async_result_complete_in_idle (result);
		return;
	}

	body = soup_message_body_flatten (msg->response_body);
	if (facebook_utils_parse_response (body, &doc, &error)) {
		DomElement   *node;
		FacebookUser *user = NULL;

		for (node = DOM_ELEMENT (doc)->first_child; node; node = node->next_sibling) {
			if (g_strcmp0 (node->tag_name, "users_getInfo_response") == 0) {
				DomElement *child;

				for (child = node->first_child; child; child = child->next_sibling) {
					if (g_strcmp0 (child->tag_name, "user") == 0) {
						user = facebook_user_new ();
						dom_domizable_load_from_element (DOM_DOMIZABLE (user), child);
						g_simple_async_result_set_op_res_gpointer (result, user, (GDestroyNotify) g_object_unref);
					}
				}
			}
		}

		if (user == NULL) {
			error = g_error_new_literal (FACEBOOK_CONNECTION_ERROR, 0, _("Unknown error"));
			g_simple_async_result_set_from_error (result, error);
		}

		g_object_unref (doc);
	}
	else
		g_simple_async_result_set_from_error (result, error);

	g_simple_async_result_complete_in_idle (result);

	soup_buffer_free (body);
}
Exemple #2
0
static void _process_check_resp(SoupSession *ss, SoupMessage *msg,  gpointer user_data)
{
    GWQSession *wqs;
    const guint8* data;
    gsize size;
    SoupBuffer *sBuf;
    int i;
    
    wqs = (GWQSession*)user_data;
    sBuf = soup_message_body_flatten(msg->response_body);
    GWQ_DBG("check responsed, retcode=%d, reason:%s\n", msg->status_code, msg->reason_phrase);
    if (sBuf) {
        soup_buffer_get_data(sBuf, &data, &size);
        GWQ_DBG("bodySize=%d\nbody:%s\n", size, data);
        if (size>0) {
        	const gchar *tmpCStr, *vc, *end;
        	
        	tmpCStr = (const gchar*)data;
        	end = (gchar*)(data+size-1);
        	if (tmpCStr 
        			&& (tmpCStr = g_strstr_len(tmpCStr, size, ","))
        			&& tmpCStr < end
        			&& *(++tmpCStr)
        			&& (tmpCStr = g_strstr_len(tmpCStr, size, "'"))
        			&& tmpCStr < end
        			&& *(vc = ++tmpCStr)
        			&& (tmpCStr = g_strstr_len(tmpCStr, size, "'"))
        			&& tmpCStr < end) {
        		g_string_assign(wqs->verifyCode, "");
        		g_string_append_len(wqs->verifyCode, vc, tmpCStr-vc);
                GWQ_DBG("vc.verifyCode: %s\n", wqs->verifyCode->str);
        	}
            if (tmpCStr
                    && (tmpCStr = g_strstr_len(tmpCStr, size, ","))
        			&& tmpCStr < end
        			&& *(++tmpCStr)
        			&& (tmpCStr = g_strstr_len(tmpCStr, size, "'"))
        			&& tmpCStr < end
        			&& *(vc = ++tmpCStr)
        			&& (tmpCStr = g_strstr_len(tmpCStr, size, "'"))
        			&& tmpCStr < end) {
                g_string_assign(wqs->vcUin, "");
                g_string_append_len(wqs->vcUin, vc, tmpCStr-vc);
                GWQ_DBG("vc.uin:%s\n", wqs->vcUin->str);
                wqs->vcUinAryLen = (wqs->vcUin->len)>>2;
                if (wqs->vcUinAryLen < sizeof(wqs->vcUinAry)) {
                    for (i=0; i<wqs->vcUinAryLen; i++) {
                        wqs->vcUinAry[i] = DigestCharToChar(wqs->vcUin->str[(i<<2)+2], wqs->vcUin->str[(i<<2)+3]);
                        GWQ_DBG("%x\n", wqs->vcUinAry[i]);
                    }
                }
            }
        }
        soup_buffer_free(sBuf);
    }
Exemple #3
0
int
main (int argc, char **argv)
{
	SoupSession *session;
	const char *base_uri;

	test_init (argc, argv, NULL);
	apache_init ();

	base_uri = "http://127.0.0.1:47524/";
	get_correct_response (base_uri);

	debug_printf (1, "\nFully async, fast requests\n");
	session = soup_test_session_new (SOUP_TYPE_SESSION_ASYNC, NULL);
	g_signal_connect (session, "authenticate",
			  G_CALLBACK (authenticate), NULL);
	do_fully_async_test (session, base_uri, "/",
			     TRUE, SOUP_STATUS_OK);
	do_fully_async_test (session, base_uri, "/Basic/realm1/",
			     TRUE, SOUP_STATUS_UNAUTHORIZED);
	do_fully_async_test (session, base_uri, "/Basic/realm2/",
			     TRUE, SOUP_STATUS_OK);
	soup_test_session_abort_unref (session);

	debug_printf (1, "\nFully async, slow requests\n");
	session = soup_test_session_new (SOUP_TYPE_SESSION_ASYNC, NULL);
	g_signal_connect (session, "authenticate",
			  G_CALLBACK (authenticate), NULL);
	do_fully_async_test (session, base_uri, "/",
			     FALSE, SOUP_STATUS_OK);
	do_fully_async_test (session, base_uri, "/Basic/realm1/",
			     FALSE, SOUP_STATUS_UNAUTHORIZED);
	do_fully_async_test (session, base_uri, "/Basic/realm2/",
			     FALSE, SOUP_STATUS_OK);
	soup_test_session_abort_unref (session);

	debug_printf (1, "\nSynchronously async\n");
	session = soup_test_session_new (SOUP_TYPE_SESSION_ASYNC, NULL);
	g_signal_connect (session, "authenticate",
			  G_CALLBACK (authenticate), NULL);
	do_synchronously_async_test (session, base_uri, "/",
				     SOUP_STATUS_OK);
	do_synchronously_async_test (session, base_uri, "/Basic/realm1/",
				     SOUP_STATUS_UNAUTHORIZED);
	do_synchronously_async_test (session, base_uri, "/Basic/realm2/",
				     SOUP_STATUS_OK);
	soup_test_session_abort_unref (session);

	soup_buffer_free (correct_response);

	test_cleanup ();
	return errors != 0;
}
Exemple #4
0
void trex_callback(SoupServer *server, SoupMessage *msg,
	const char *path, GHashTable *query, const char *dest)
{
	SoupMessage *new_msg;
	SoupSession *session;
	char *uri_str;

	struct destination_info *to = malloc(sizeof(struct destination_info));
	to->server = server;
	to->msg = msg;

	session = soup_session_async_new();

	uri_str = soup_uri_to_string(soup_message_get_uri(msg), true);
	/*
	 * TODO Memory Leak :-)
	*/
	uri_str = g_strjoin(NULL, dest, uri_str, NULL);

	g_print("[%p] %s %s HTTP/1.%d\n", msg, msg->method, uri_str,
		soup_message_get_http_version(msg));

	/* build new request */
	new_msg = soup_message_new(msg->method, uri_str);
	soup_message_headers_foreach(msg->request_headers, copy_header,
		new_msg->request_headers);
	soup_message_headers_remove(new_msg->request_headers, "Host");
	if (msg->request_body->length) {
		SoupBuffer *request =
			soup_message_body_flatten(msg->request_body);
		soup_message_body_append_buffer(new_msg->request_body,
			request);
		soup_buffer_free(request);
	}
	soup_message_headers_set_encoding(msg->response_headers,
		SOUP_ENCODING_CHUNKED);

	soup_server_pause_message(server, msg);

	g_signal_connect(new_msg, "got_headers",
		G_CALLBACK(recv_headers), to);
	g_signal_connect(new_msg, "got_chunk",
		G_CALLBACK(recv_chunk), to);

	soup_session_queue_message(session, new_msg, finish_msg, to);

	g_object_ref(msg);

	g_object_unref(session);
}
Exemple #5
0
/*
 * If there is a mismatch or an error, then gda_connection_add_event_string() is used
 *
 *  - if all OK, extracs the <challenge> value and replace cdata->next_challenge with it (or simply
 *    reset cdata->next_challenge to NULL)
 *
 * Returns: a new #xmlDocPtr, or %NULL on error
 */
xmlDocPtr
_gda_web_decode_response (GdaConnection *cnc, WebConnectionData *cdata, SoupMessageBody *body,
			  gchar *out_status_chr, guint *out_counter_id)
{
	SoupBuffer *sbuffer;
	xmlDocPtr doc;
	sbuffer = soup_message_body_flatten (body);
#ifdef DEBUG_WEB_PROV
	g_print ("=== START of response ===\n%s\n=== END of response ===\n", (gchar*) sbuffer->data);
#endif
	doc = decode_buffer_response (cnc, cdata, sbuffer, out_status_chr, out_counter_id);
	soup_buffer_free (sbuffer);
	return doc;
}
static gssize
webkit_soup_directory_input_stream_read (GInputStream  *input,
					 void          *buffer,
					 gsize count,
					 GCancellable  *cancellable,
					 GError       **error)
{
	WebKitSoupDirectoryInputStream *stream = WEBKIT_SOUP_DIRECTORY_INPUT_STREAM (input);
	gsize total, size;

	for (total = 0; total < count; total += size) {
		if (stream->buffer == NULL) {
			stream->buffer = webkit_soup_directory_input_stream_read_next_file (stream, cancellable, error);
			if (stream->buffer == NULL) {
				/* FIXME: Is this correct or should we forward the error? */
				if (total)
					g_clear_error (error);
				return total;
			}
		}

		size = MIN (stream->buffer->length, count - total);
		memcpy ((char *)buffer + total, stream->buffer->data, size);
		if (size == stream->buffer->length) {
			soup_buffer_free (stream->buffer);
			stream->buffer = NULL;
		} else {
			SoupBuffer *sub = soup_buffer_new_subbuffer (stream->buffer,
								     size,
								     stream->buffer->length - size);
			soup_buffer_free (stream->buffer);
			stream->buffer = sub;
		}
	}

	return total;
}
static void
soup_soap_message_constructed (GObject *object)
{
	SoupSoapMessage *msg = SOUP_SOAP_MESSAGE (object);
	SoupSoapMessagePrivate *priv = msg->priv;

	soup_buffer_free (soup_message_body_flatten (priv->message_body));

	xmlNodePtr current_node, op_node;

	xmlDocPtr doc = xmlParseDoc (BAD_CAST priv->message_body->data);

	if (doc)
	{
		current_node = xmlDocGetRootElement (doc);

		if (current_node &&
		    current_node->name &&
		    xmlStrEqual (current_node->name, BAD_CAST "Envelope"))
		{
			for (current_node = current_node->children;
			     current_node != NULL;
			     current_node = current_node->next)
			{
				if (current_node->type == XML_ELEMENT_NODE)
				{
					if (xmlStrEqual (current_node->name, BAD_CAST "Header"))
						parse_param (priv->header,
						             current_node);
					else if (xmlStrEqual (current_node->name, BAD_CAST "Body"))
					{
						op_node = current_node->children;
						if (op_node)
						{
							soup_soap_param_set_name (SOUP_SOAP_PARAM (priv->body),
							                          (gchar *) op_node->name);
							parse_param (priv->body,
							             op_node);
						}
					}
				}
			}
		}
	}

	xmlFreeDoc (doc);

	G_OBJECT_CLASS (soup_soap_message_parent_class)->constructed (object);
}
Exemple #8
0
static void
md5_post_callback (SoupServer *server, SoupMessage *msg,
                   const char *path, GHashTable *query,
                   SoupClientContext *context, gpointer data)
{
    const char *content_type;
    GHashTable *params;
    const char *fmt;
    char *filename, *md5sum, *redirect_uri;
    SoupBuffer *file;
    SoupURI *uri;

    content_type = soup_message_headers_get_content_type (msg->request_headers, NULL);
    if (!content_type || strcmp (content_type, "multipart/form-data") != 0) {
        soup_message_set_status (msg, SOUP_STATUS_BAD_REQUEST);
        return;
    }

    params = soup_form_decode_multipart (msg, "file",
                                         &filename, NULL, &file);
    if (!params) {
        soup_message_set_status (msg, SOUP_STATUS_BAD_REQUEST);
        return;
    }
    fmt = g_hash_table_lookup (params, "fmt");

    md5sum = g_compute_checksum_for_data (G_CHECKSUM_MD5,
                                          (gpointer)file->data,
                                          file->length);
    soup_buffer_free (file);

    uri = soup_uri_copy (soup_message_get_uri (msg));
    soup_uri_set_query_from_fields (uri,
                                    "file", filename ? filename : "",
                                    "md5sum", md5sum,
                                    "fmt", fmt ? fmt : "html",
                                    NULL);
    redirect_uri = soup_uri_to_string (uri, FALSE);

    soup_message_set_status (msg, SOUP_STATUS_SEE_OTHER);
    soup_message_headers_replace (msg->response_headers, "Location",
                                  redirect_uri);

    g_free (redirect_uri);
    soup_uri_free (uri);
    g_free (md5sum);
    g_free (filename);
    g_hash_table_destroy (params);
}
Exemple #9
0
static void
get_logged_in_user_ready_cb (SoupSession *session,
			     SoupMessage *msg,
			     gpointer     user_data)
{
	FacebookService    *self = user_data;
	GSimpleAsyncResult *result;
	SoupBuffer         *body;
	DomDocument        *doc = NULL;
	GError             *error = NULL;

	result = facebook_connection_get_result (self->priv->conn);

	if (msg->status_code != 200) {
		g_simple_async_result_set_error (result,
						 SOUP_HTTP_ERROR,
						 msg->status_code,
						 "%s",
						 soup_status_get_phrase (msg->status_code));
		g_simple_async_result_complete_in_idle (result);
		return;
	}

	body = soup_message_body_flatten (msg->response_body);
	if (facebook_utils_parse_response (body, &doc, &error)) {
		DomElement *root;
		char       *uid = NULL;

		root = DOM_ELEMENT (doc)->first_child;
		if (g_strcmp0 (root->tag_name, "users_getLoggedInUser_response") == 0)
			uid = g_strdup (dom_element_get_inner_text (root));

		if (uid == NULL) {
			error = g_error_new_literal (FACEBOOK_CONNECTION_ERROR, 0, _("Unknown error"));
			g_simple_async_result_set_from_error (result, error);
		}
		else
			g_simple_async_result_set_op_res_gpointer (result, uid, g_free);

		g_object_unref (doc);
	}
	else
		g_simple_async_result_set_from_error (result, error);

	g_simple_async_result_complete_in_idle (result);

	soup_buffer_free (body);
}
Exemple #10
0
static gboolean
picasa_web_utils_parse_json_response (SoupMessage  *msg,
				      JsonNode    **node,
				      GError      **error)
{
	JsonParser *parser;
	SoupBuffer *body;

	g_return_val_if_fail (msg != NULL, FALSE);
	g_return_val_if_fail (node != NULL, FALSE);

	*node = NULL;

	if ((msg->status_code != 200) && (msg->status_code != 400)) {
		*error = g_error_new (SOUP_HTTP_ERROR,
				      msg->status_code,
				      "%s",
				      soup_status_get_phrase (msg->status_code));
		return FALSE;
	}

	body = soup_message_body_flatten (msg->response_body);
	parser = json_parser_new ();
	if (json_parser_load_from_data (parser, body->data, body->length, error)) {
		JsonObject *obj;

		*node = json_node_copy (json_parser_get_root (parser));

		obj = json_node_get_object (*node);
		if (json_object_has_member (obj, "error")) {
			JsonObject *error_obj;

			error_obj = json_object_get_object_member (obj, "error");
			*error = g_error_new (WEB_SERVICE_ERROR,
					      json_object_get_int_member (error_obj, "code"),
					      "%s",
					      json_object_get_string_member (error_obj, "message"));

			json_node_free (*node);
			*node = NULL;
		}
	}

	g_object_unref (parser);
	soup_buffer_free (body);

	return *node != NULL;
}
Exemple #11
0
/* Attempts to write @len bytes from @data. See the note at
 * read_metadata() for an explanation of the return value.
 */
static gboolean
write_data (SoupMessage *msg, const char *data, guint len, gboolean body)
{
	SoupMessagePrivate *priv = SOUP_MESSAGE_GET_PRIVATE (msg);
	SoupMessageIOData *io = priv->io_data;
	SoupSocketIOStatus status;
	gsize nwrote;
	GError *error = NULL;
	SoupBuffer *chunk;
	const char *start;

	while (len > io->written) {
		status = soup_socket_write (io->sock,
					    data + io->written,
					    len - io->written,
					    &nwrote, NULL, &error);
		switch (status) {
		case SOUP_SOCKET_EOF:
		case SOUP_SOCKET_ERROR:
			io_error (io->sock, msg, error);
			return FALSE;

		case SOUP_SOCKET_WOULD_BLOCK:
			return FALSE;

		case SOUP_SOCKET_OK:
			start = data + io->written;
			io->written += nwrote;

			if (body) {
				if (io->write_length)
					io->write_length -= nwrote;

				chunk = soup_buffer_new (SOUP_MEMORY_TEMPORARY,
							 start, nwrote);
				SOUP_MESSAGE_IO_PREPARE_FOR_CALLBACK;
				soup_message_wrote_body_data (msg, chunk);
				soup_buffer_free (chunk);
				SOUP_MESSAGE_IO_RETURN_VAL_IF_CANCELLED_OR_PAUSED (FALSE);
			}
			break;
		}
	}

	io->written = 0;
	return TRUE;
}
Exemple #12
0
static void
_oauth_service_get_request_token_ready_cb (SoupSession *session,
					   SoupMessage *msg,
					   gpointer     user_data)
{
	OAuthService       *self = user_data;
	GSimpleAsyncResult *result;
	SoupBuffer         *body;
	GHashTable         *values;
	char               *token;
	char               *token_secret;

	result = _web_service_get_result (WEB_SERVICE (self));

	if (msg->status_code != 200) {
		g_simple_async_result_set_error (result,
						 SOUP_HTTP_ERROR,
						 msg->status_code,
						 "%s",
						 soup_status_get_phrase (msg->status_code));
		g_simple_async_result_complete_in_idle (result);
		return;
	}

	body = soup_message_body_flatten (msg->response_body);
	values = soup_form_decode (body->data);
	token = g_hash_table_lookup (values, "oauth_token");
	token_secret = g_hash_table_lookup (values, "oauth_token_secret");
	if ((token != NULL) && (token_secret != NULL)) {
		oauth_service_set_token (self, token);
		oauth_service_set_token_secret (self, token_secret);
		g_simple_async_result_set_op_res_gboolean (result, TRUE);
	}
	else {
		GError *error;

		error = g_error_new_literal (WEB_SERVICE_ERROR, WEB_SERVICE_ERROR_GENERIC, _("Unknown error"));
		g_simple_async_result_set_from_error (result, error);
	}

	g_simple_async_result_complete_in_idle (result);

	g_hash_table_destroy (values);
	soup_buffer_free (body);
}
/* This is not a supported part of the API. Use SOUP_MESSAGE_CAN_REBUILD
 * instead.
 */
static void
write_next_chunk_streaming_hack (SoupMessage *msg, gpointer user_data)
{
	PutTestData *ptd = user_data;
	SoupBuffer *chunk;

	debug_printf (2, "  freeing chunk at %d\n", ptd->nfreed);
	chunk = soup_message_body_get_chunk (msg->request_body, ptd->nfreed);
	if (chunk) {
		ptd->nfreed += chunk->length;
		soup_message_body_wrote_chunk (msg->request_body, chunk);
		soup_buffer_free (chunk);
	} else {
		debug_printf (1, "  error: written chunk does not exist!\n");
		errors++;
	}
	write_next_chunk (msg, user_data);
}
Exemple #14
0
static void
append_buffer (SoupMessageBody *body, SoupBuffer *buffer)
{
	SoupMessageBodyPrivate *priv = (SoupMessageBodyPrivate *)body;

	if (priv->last) {
		priv->last = g_slist_append (priv->last, buffer);
		priv->last = priv->last->next;
	} else
		priv->chunks = priv->last = g_slist_append (NULL, buffer);

	if (priv->flattened) {
		soup_buffer_free (priv->flattened);
		priv->flattened = NULL;
		body->data = NULL;
	}
	body->length += buffer->length;
}
static gssize
read_and_sniff (GInputStream *stream, gboolean blocking,
		GCancellable *cancellable, GError **error)
{
	SoupContentSnifferStreamPrivate *priv = SOUP_CONTENT_SNIFFER_STREAM (stream)->priv;
	gssize nread;
	GError *my_error = NULL;
	SoupBuffer *buf;

	do {
		nread = g_pollable_stream_read (G_FILTER_INPUT_STREAM (stream)->base_stream,
						priv->buffer + priv->buffer_nread,
						priv->buffer_size - priv->buffer_nread,
						blocking, cancellable, &my_error);
		if (nread <= 0)
			break;
		priv->buffer_nread += nread;
	} while (priv->buffer_nread < priv->buffer_size);

	/* If we got EAGAIN or cancellation before filling the buffer,
	 * just return that right away. Likewise if we got any other
	 * error without ever reading any data. Otherwise, save the
	 * error to return after we're done sniffing.
	 */
	if (my_error) {
		if (g_error_matches (my_error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK) ||
		    g_error_matches (my_error, G_IO_ERROR, G_IO_ERROR_CANCELLED) ||
		    priv->buffer_nread == 0) {
			g_propagate_error (error, my_error);
			return -1;
		} else
			priv->error = my_error;
	}

	/* Sniff, then return the data */
	buf = soup_buffer_new (SOUP_MEMORY_TEMPORARY, priv->buffer, priv->buffer_nread);
	priv->sniffed_type =
		soup_content_sniffer_sniff (priv->sniffer, priv->msg, buf,
					    &priv->sniffed_params);
	soup_buffer_free (buf);
	priv->sniffing = FALSE;

	return priv->buffer_nread;
}	
Exemple #16
0
static void
server_callback (SoupServer *server, SoupMessage *msg,
		 const char *path, GHashTable *query,
		 SoupClientContext *context, gpointer data)
{
	SoupMessage *msg2;
	char *uristr;

	uristr = soup_uri_to_string (soup_message_get_uri (msg), FALSE);
	printf ("[%p] %s %s HTTP/1.%d\n", msg, msg->method, uristr,
		soup_message_get_http_version (msg));

	if (msg->method == SOUP_METHOD_CONNECT) {
		soup_message_set_status (msg, SOUP_STATUS_NOT_IMPLEMENTED);
		return;
	}

	msg2 = soup_message_new (msg->method, uristr);
        msg2 = soup_message_new (msg->method, uristr);
	soup_message_headers_foreach (msg->request_headers, copy_header,
				      msg2->request_headers);
	soup_message_headers_remove (msg2->request_headers, "Host");
	soup_message_headers_remove (msg2->request_headers, "Connection");

	if (msg->request_body->length) {
		SoupBuffer *request = soup_message_body_flatten (msg->request_body);
		soup_message_body_append_buffer (msg2->request_body, request);
		soup_buffer_free (request);
	}
	soup_message_headers_set_encoding (msg->response_headers,
					   SOUP_ENCODING_CHUNKED);

	g_signal_connect (msg2, "got_headers",
			  G_CALLBACK (send_headers), msg);
	g_signal_connect (msg2, "got_chunk",
			  G_CALLBACK (send_chunk), msg);

	g_signal_connect (msg, "finished", G_CALLBACK (client_msg_failed), msg2);

	soup_session_queue_message (session, msg2, finish_msg, msg);

	g_object_ref (msg);
	soup_server_pause_message (server, msg);
}
Exemple #17
0
void
e_gw_message_write_footer (SoupSoapMessage *msg)
{
	soup_soap_message_end_element (msg);
	soup_soap_message_end_body (msg);
	soup_soap_message_end_envelope (msg);

	soup_soap_message_persist (msg);

	if (g_getenv ("GROUPWISE_DEBUG") && (atoi (g_getenv ("GROUPWISE_DEBUG")) == 1)) {
		const gchar *header = soup_message_headers_get (SOUP_MESSAGE (msg)->request_headers, "SOAPAction");

		soup_buffer_free (soup_message_body_flatten (SOUP_MESSAGE (msg)->request_body));
		if (header && g_str_equal (header, "loginRequest")) {
			gchar *body;
			gchar *begin = NULL;
			gchar *end = NULL;

			body = g_strdup (SOUP_MESSAGE (msg)->request_body->data);
			begin = g_strrstr (body, "<types:password>");
			if (begin)
				begin = begin + strlen ("<types:password>");
			end = g_strrstr (body , "</types:password>");
			if (begin && end) {
				gchar *tmp;
				for (tmp = begin; tmp < end; tmp++)
					*tmp='X';

			}
			fputc ('\n', stdout);
			fputs (body, stdout);
			fputc ('\n', stdout);
			g_free (body);
		}
		else {

			/* print request's body */
			fputc ('\n', stdout);
			fputs (SOUP_MESSAGE (msg)->request_body->data, stdout);
			fputc ('\n', stdout);
		}
	}
}
Exemple #18
0
/**
 * soup_message_body_wrote_chunk:
 * @body: a #SoupMessageBody
 * @chunk: a #SoupBuffer returned from soup_message_body_get_chunk()
 *
 * Handles the #SoupMessageBody part of writing a chunk of data to the
 * network. Normally this is a no-op, but if you have set @body's
 * accumulate flag to %FALSE, then this will cause @chunk to be
 * discarded to free up memory.
 *
 * This is a low-level method which you should not need to use, and
 * there are further restrictions on its proper use which are not
 * documented here.
 *
 * Since: 2.4.1
 **/
void
soup_message_body_wrote_chunk (SoupMessageBody *body, SoupBuffer *chunk)
{
	SoupMessageBodyPrivate *priv = (SoupMessageBodyPrivate *)body;
	SoupBuffer *chunk2;

	if (priv->accumulate)
		return;

	chunk2 = priv->chunks->data;
	g_return_if_fail (chunk->length == chunk2->length);
	g_return_if_fail (chunk == chunk2 || ((SoupBufferPrivate *)chunk2)->use == SOUP_MEMORY_TEMPORARY);

	priv->chunks = g_slist_remove (priv->chunks, chunk2);
	if (!priv->chunks)
		priv->last = NULL;

	priv->base_offset += chunk2->length;
	soup_buffer_free (chunk2);
}
Exemple #19
0
static void
create_album_ready_cb (SoupSession *session,
		       SoupMessage *msg,
		       gpointer     user_data)
{
	PicasaWebService   *self = user_data;
	GSimpleAsyncResult *result;
	SoupBuffer         *body;
	DomDocument        *doc;
	GError             *error = NULL;

	result = _web_service_get_result (WEB_SERVICE (self));

	if (msg->status_code != 201) {
		g_simple_async_result_set_error (result,
						 SOUP_HTTP_ERROR,
						 msg->status_code,
						 "%s",
						 soup_status_get_phrase (msg->status_code));
		g_simple_async_result_complete_in_idle (result);
		return;
	}

	body = soup_message_body_flatten (msg->response_body);
	doc = dom_document_new ();
	if (dom_document_load (doc, body->data, body->length, &error)) {
		PicasaWebAlbum *album;

		album = picasa_web_album_new ();
		dom_domizable_load_from_element (DOM_DOMIZABLE (album), DOM_ELEMENT (doc)->first_child);
		g_simple_async_result_set_op_res_gpointer (result, album, (GDestroyNotify) g_object_unref);
	}
	else {
		g_simple_async_result_set_from_error (result, error);
		g_error_free (error);
	}
	g_simple_async_result_complete_in_idle (result);

	g_object_unref (doc);
	soup_buffer_free (body);
}
static void
write_next_chunk (SoupMessage *msg, gpointer user_data)
{
	PutTestData *ptd = user_data;

	debug_printf (2, "  writing chunk %d\n", ptd->next);

	if (ptd->streaming && ptd->next > 0 && ptd->chunks[ptd->next - 1]) {
		debug_printf (1, "  error: next chunk requested before last one freed!\n");
		errors++;
	}

	if (ptd->next < G_N_ELEMENTS (ptd->chunks)) {
		soup_message_body_append_buffer (msg->request_body,
						 ptd->chunks[ptd->next]);
		soup_buffer_free (ptd->chunks[ptd->next]);
		ptd->next++;
	} else
		soup_message_body_complete (msg->request_body);
	soup_session_unpause_message (ptd->session, msg);
}
static void
temp_test_wrote_chunk (SoupMessage *msg, gpointer session)
{
	SoupBuffer *chunk;

	chunk = soup_message_body_get_chunk (msg->request_body, 5);

	/* When the bug is present, the second chunk will also be
	 * discarded after the first is written, which will cause
	 * the I/O to stall since soup-message-io will think it's
	 * done, but it hasn't written Content-Length bytes yet.
	 */
	if (!chunk) {
		debug_printf (1, "  Lost second chunk!\n");
		errors++;
		soup_session_abort (session);
	} else
		soup_buffer_free (chunk);

	g_signal_handlers_disconnect_by_func (msg, temp_test_wrote_chunk, session);
}
Exemple #22
0
static void
do_md5_test_libsoup (const char *uri, const char *contents,
                     gsize length, const char *md5)
{
    SoupMultipart *multipart;
    SoupBuffer *buffer;
    SoupMessage *msg;
    SoupSession *session;

    debug_printf (1, "  via libsoup: ");

    multipart = soup_multipart_new (SOUP_FORM_MIME_TYPE_MULTIPART);
    buffer = soup_buffer_new (SOUP_MEMORY_COPY, contents, length);
    soup_multipart_append_form_file (multipart, "file",
                                     MD5_TEST_FILE_BASENAME,
                                     MD5_TEST_FILE_MIME_TYPE,
                                     buffer);
    soup_buffer_free (buffer);
    soup_multipart_append_form_string (multipart, "fmt", "text");

    msg = soup_form_request_new_from_multipart (uri, multipart);
    soup_multipart_free (multipart);

    session = soup_test_session_new (SOUP_TYPE_SESSION_ASYNC, NULL);
    soup_session_send_message (session, msg);

    if (!SOUP_STATUS_IS_SUCCESSFUL (msg->status_code)) {
        debug_printf (1, "ERROR: Unexpected status %d %s\n",
                      msg->status_code, msg->reason_phrase);
        errors++;
    } else if (strcmp (msg->response_body->data, md5) != 0) {
        debug_printf (1, "ERROR: Incorrect response: expected '%s' got '%s'\n",
                      md5, msg->response_body->data);
        errors++;
    } else
        debug_printf (1, "OK!\n");

    g_object_unref (msg);
    soup_test_session_abort_unref (session);
}
static gboolean
download_file (const gchar *source, const gchar *dest)
{
	g_return_val_if_fail (source && dest, FALSE);

//	g_debug ("download_file %s to %s\n", source, dest);

	SoupSession *session;
	SoupBuffer *buf;
	gchar *cafile;
	gboolean sync;
	FILE *fp;

	buf = NULL;
	sync = TRUE;
	cafile = NULL;
/*TODO: should we have the static session? */
	session = open_app_soup_session_new (sync, cafile);

	gint retry;
	for (retry = 0; retry <3; retry ++) {
		buf = open_app_get_data_by_request (session, source);
		if (buf)
			break;
		g_debug ("retry %d\n", retry);
	}
	g_object_unref (session);
	if (!buf)
		return FALSE;

	fp = fopen (dest, "w");
	if (fp) {
		fwrite (buf->data, 1, buf->length, fp);
		fclose (fp);
	}

	soup_buffer_free (buf);

	return TRUE;
}
static void
gss_program_finalize (GObject * object)
{
  GssProgram *program = GSS_PROGRAM (object);

  gss_program_stop (program);

  g_list_free_full (program->streams, g_object_unref);

  if (program->hls.variant_buffer) {
    soup_buffer_free (program->hls.variant_buffer);
  }

  gss_metrics_free (program->metrics);
  g_free (program->follow_uri);
  g_free (program->follow_host);
  g_free (program->description);
  g_free (program->safe_description);
  g_free (program->uuid);

  parent_class->finalize (object);
}
void
soup_message_io_cleanup (SoupMessage *msg)
{
	SoupMessagePrivate *priv = SOUP_MESSAGE_GET_PRIVATE (msg);
	SoupMessageIOData *io;

	soup_message_io_stop (msg);

	io = priv->io_data;
	if (!io)
		return;
	priv->io_data = NULL;

	if (io->iostream)
		g_object_unref (io->iostream);
	if (io->body_istream)
		g_object_unref (io->body_istream);
	if (io->body_ostream)
		g_object_unref (io->body_ostream);
	if (io->async_context)
		g_main_context_unref (io->async_context);
	if (io->item)
		soup_message_queue_item_unref (io->item);

	g_byte_array_free (io->read_header_buf, TRUE);

	g_string_free (io->write_buf, TRUE);
	if (io->write_chunk)
		soup_buffer_free (io->write_chunk);

	if (io->async_close_wait) {
		g_cancellable_cancel (io->async_close_wait);
		g_clear_object (&io->async_close_wait);
	}
	g_clear_error (&io->async_close_error);

	g_slice_free (SoupMessageIOData, io);
}
Exemple #26
0
static void
server_callback (SoupServer *server, SoupMessage *msg,
		 const char *path, GHashTable *query,
		 SoupClientContext *context, gpointer data)
{
	SoupMessageBody *md5_body;
	char *md5;

	if (g_str_has_prefix (path, "/redirect")) {
		soup_message_set_status (msg, SOUP_STATUS_FOUND);
		soup_message_headers_replace (msg->response_headers,
					      "Location", "/");
		return;
	}

	if (msg->method == SOUP_METHOD_GET) {
		soup_message_set_response (msg, "text/plain",
					   SOUP_MEMORY_STATIC,
					   "three\r\ntwo\r\none\r\n",
					   strlen ("three\r\ntwo\r\none\r\n"));
		soup_buffer_free (soup_message_body_flatten (msg->response_body));
		md5_body = msg->response_body;
		soup_message_set_status (msg, SOUP_STATUS_OK);
	} else if (msg->method == SOUP_METHOD_PUT) {
		soup_message_set_status (msg, SOUP_STATUS_CREATED);
		md5_body = msg->request_body;
	} else {
		soup_message_set_status (msg, SOUP_STATUS_METHOD_NOT_ALLOWED);
		return;
	}

	md5 = g_compute_checksum_for_data (G_CHECKSUM_MD5,
					   (guchar *)md5_body->data,
					   md5_body->length);
	soup_message_headers_append (msg->response_headers,
				     "Content-MD5", md5);
	g_free (md5);
}
GHashTable *
gss_config_get_post_hash (GssTransaction * t)
{
  GHashTable *hash;
  const char *content_type;

  content_type = soup_message_headers_get_one (t->msg->request_headers,
      "Content-Type");

  hash = NULL;
  if (g_str_equal (content_type, "application/x-www-form-urlencoded")) {
    hash = soup_form_decode (t->msg->request_body->data);
  } else if (g_str_has_prefix (content_type, "multipart/form-data")) {
    SoupBuffer *buffer;

    hash = soup_form_decode_multipart (t->msg, "none", NULL, NULL, &buffer);

    if (buffer && buffer->length > 0) {
      soup_buffer_free (buffer);
    }
  }

  return hash;
}
static gboolean
webkit_soup_directory_input_stream_close (GInputStream  *input,
					  GCancellable  *cancellable,
					  GError       **error)
{
	WebKitSoupDirectoryInputStream *stream = WEBKIT_SOUP_DIRECTORY_INPUT_STREAM (input);
	gboolean result;

	if (stream->buffer) {
		soup_buffer_free (stream->buffer);
		stream->buffer = NULL;
	}

	result = g_file_enumerator_close (stream->enumerator,
					  cancellable,
					  error);
	g_object_unref (stream->enumerator);
	stream->enumerator = NULL;

	g_free (stream->uri);
	stream->uri = NULL;

	return result;
}
/* Attempts to push forward the reading side of @msg's I/O. Returns
 * %TRUE if it manages to make some progress, and it is likely that
 * further progress can be made. Returns %FALSE if it has reached a
 * stopping point of some sort (need input from the application,
 * socket not readable, read is complete, etc).
 */
static gboolean
io_read (SoupMessage *msg, gboolean blocking,
	 GCancellable *cancellable, GError **error)
{
	SoupMessagePrivate *priv = SOUP_MESSAGE_GET_PRIVATE (msg);
	SoupMessageIOData *io = priv->io_data;
	guchar *stack_buf = NULL;
	gssize nread;
	SoupBuffer *buffer;
	guint status;

	switch (io->read_state) {
	case SOUP_MESSAGE_IO_STATE_HEADERS:
		if (!read_headers (msg, blocking, cancellable, error))
			return FALSE;

		status = io->parse_headers_cb (msg, (char *)io->read_header_buf->data,
					       io->read_header_buf->len,
					       &io->read_encoding,
					       io->header_data, error);
		g_byte_array_set_size (io->read_header_buf, 0);

		if (status != SOUP_STATUS_OK) {
			/* Either we couldn't parse the headers, or they
			 * indicated something that would mean we wouldn't
			 * be able to parse the body. (Eg, unknown
			 * Transfer-Encoding.). Skip the rest of the
			 * reading, and make sure the connection gets
			 * closed when we're done.
			 */
			soup_message_set_status (msg, status);
			soup_message_headers_append (msg->request_headers,
						     "Connection", "close");
			io->read_state = SOUP_MESSAGE_IO_STATE_FINISHING;
			break;
		}

		if (io->mode == SOUP_MESSAGE_IO_CLIENT &&
		    SOUP_STATUS_IS_INFORMATIONAL (msg->status_code)) {
			if (msg->status_code == SOUP_STATUS_CONTINUE &&
			    io->write_state == SOUP_MESSAGE_IO_STATE_BLOCKING) {
				/* Pause the reader, unpause the writer */
				io->read_state =
					SOUP_MESSAGE_IO_STATE_BLOCKING;
				io->write_state =
					SOUP_MESSAGE_IO_STATE_BODY_START;
			} else {
				/* Just stay in HEADERS */
				io->read_state = SOUP_MESSAGE_IO_STATE_HEADERS;
			}

			/* Informational responses have no bodies, so
			 * bail out here rather than parsing encoding, etc
			 */
			soup_message_got_informational (msg);

			/* If this was "101 Switching Protocols", then
			 * the session may have stolen the connection...
			 */
			if (io != priv->io_data)
				return FALSE;

			soup_message_cleanup_response (msg);
			break;
		} else if (io->mode == SOUP_MESSAGE_IO_SERVER &&
			   soup_message_headers_get_expectations (msg->request_headers) & SOUP_EXPECTATION_CONTINUE) {
			/* We must return a status code and response
			 * headers to the client; either an error to
			 * be set by a got-headers handler below, or
			 * else %SOUP_STATUS_CONTINUE otherwise.
			 */
			io->write_state = SOUP_MESSAGE_IO_STATE_HEADERS;
			io->read_state = SOUP_MESSAGE_IO_STATE_BLOCKING;
		} else {
			io->read_state = SOUP_MESSAGE_IO_STATE_BODY_START;

			/* If the client was waiting for a Continue
			 * but got something else, then it's done
			 * writing.
			 */
			if (io->mode == SOUP_MESSAGE_IO_CLIENT &&
			    io->write_state == SOUP_MESSAGE_IO_STATE_BLOCKING)
				io->write_state = SOUP_MESSAGE_IO_STATE_FINISHING;
		}

		if (io->read_encoding == SOUP_ENCODING_CONTENT_LENGTH) {
			SoupMessageHeaders *hdrs =
				(io->mode == SOUP_MESSAGE_IO_CLIENT) ?
				msg->response_headers : msg->request_headers;
			io->read_length = soup_message_headers_get_content_length (hdrs);

			if (io->mode == SOUP_MESSAGE_IO_CLIENT &&
			    !soup_message_is_keepalive (msg)) {
				/* Some servers suck and send
				 * incorrect Content-Length values, so
				 * allow EOF termination in this case
				 * (iff the message is too short) too.
				 */
				io->read_encoding = SOUP_ENCODING_EOF;
			}
		} else
			io->read_length = -1;

		soup_message_got_headers (msg);
		break;


	case SOUP_MESSAGE_IO_STATE_BODY_START:
		if (!io->body_istream) {
			GInputStream *body_istream = soup_body_input_stream_new (G_INPUT_STREAM (io->istream),
										 io->read_encoding,
										 io->read_length);

			/* TODO: server-side messages do not have a io->item. This means
			 * that we cannot use content processors for them right now.
			 */
			if (io->mode == SOUP_MESSAGE_IO_CLIENT) {
				io->body_istream = soup_message_setup_body_istream (body_istream, msg,
										    io->item->session,
										    SOUP_STAGE_MESSAGE_BODY);
				g_object_unref (body_istream);
			} else {
				io->body_istream = body_istream;
			}
		}

		if (priv->sniffer) {
			SoupContentSnifferStream *sniffer_stream = SOUP_CONTENT_SNIFFER_STREAM (io->body_istream);
			const char *content_type;
			GHashTable *params;

			if (!soup_content_sniffer_stream_is_ready (sniffer_stream, blocking,
								   cancellable, error))
				return FALSE;

			content_type = soup_content_sniffer_stream_sniff (sniffer_stream, &params);
			soup_message_content_sniffed (msg, content_type, params);
		}

		io->read_state = SOUP_MESSAGE_IO_STATE_BODY;
		break;


	case SOUP_MESSAGE_IO_STATE_BODY:
		if (priv->chunk_allocator) {
			buffer = priv->chunk_allocator (msg, io->read_length, priv->chunk_allocator_data);
			if (!buffer) {
				g_return_val_if_fail (!io->item || !io->item->new_api, FALSE);
				soup_message_io_pause (msg);
				return FALSE;
			}
		} else {
			if (!stack_buf)
				stack_buf = alloca (RESPONSE_BLOCK_SIZE);
			buffer = soup_buffer_new (SOUP_MEMORY_TEMPORARY,
						  stack_buf,
						  RESPONSE_BLOCK_SIZE);
		}

		nread = g_pollable_stream_read (io->body_istream,
						(guchar *)buffer->data,
						buffer->length,
						blocking,
						cancellable, error);
		if (nread > 0) {
			buffer->length = nread;
			soup_message_body_got_chunk (io->read_body, buffer);
			soup_message_got_chunk (msg, buffer);
			soup_buffer_free (buffer);
			break;
		}

		soup_buffer_free (buffer);
		if (nread == -1)
			return FALSE;

		/* else nread == 0 */
		io->read_state = SOUP_MESSAGE_IO_STATE_BODY_DONE;
		break;


	case SOUP_MESSAGE_IO_STATE_BODY_DONE:
		io->read_state = SOUP_MESSAGE_IO_STATE_FINISHING;
		soup_message_got_body (msg);
		break;


	case SOUP_MESSAGE_IO_STATE_FINISHING:
		io->read_state = SOUP_MESSAGE_IO_STATE_DONE;

		if (io->mode == SOUP_MESSAGE_IO_SERVER)
			io->write_state = SOUP_MESSAGE_IO_STATE_HEADERS;
		break;


	default:
		g_return_val_if_reached (FALSE);
	}

	return TRUE;
}
/* Attempts to push forward the writing side of @msg's I/O. Returns
 * %TRUE if it manages to make some progress, and it is likely that
 * further progress can be made. Returns %FALSE if it has reached a
 * stopping point of some sort (need input from the application,
 * socket not writable, write is complete, etc).
 */
static gboolean
io_write (SoupMessage *msg, gboolean blocking,
	  GCancellable *cancellable, GError **error)
{
	SoupMessagePrivate *priv = SOUP_MESSAGE_GET_PRIVATE (msg);
	SoupMessageIOData *io = priv->io_data;
	SoupBuffer *chunk;
	gssize nwrote;

	if (io->async_close_error) {
		g_propagate_error (error, io->async_close_error);
		io->async_close_error = NULL;
		return FALSE;
	} else if (io->async_close_wait) {
		g_set_error_literal (error, G_IO_ERROR,
				     G_IO_ERROR_WOULD_BLOCK,
				     _("Operation would block"));
		return FALSE;
	}

	switch (io->write_state) {
	case SOUP_MESSAGE_IO_STATE_HEADERS:
		if (io->mode == SOUP_MESSAGE_IO_SERVER &&
		    io->read_state == SOUP_MESSAGE_IO_STATE_BLOCKING &&
		    msg->status_code == 0) {
			/* Client requested "Expect: 100-continue", and
			 * server did not set an error.
			 */
			soup_message_set_status (msg, SOUP_STATUS_CONTINUE);
		}

		if (!io->write_buf->len) {
			io->get_headers_cb (msg, io->write_buf,
					    &io->write_encoding,
					    io->header_data);
		}

		while (io->written < io->write_buf->len) {
			nwrote = g_pollable_stream_write (io->ostream,
							  io->write_buf->str + io->written,
							  io->write_buf->len - io->written,
							  blocking,
							  cancellable, error);
			if (nwrote == -1)
				return FALSE;
			io->written += nwrote;
		}

		io->written = 0;
		g_string_truncate (io->write_buf, 0);

		if (io->mode == SOUP_MESSAGE_IO_SERVER &&
		    SOUP_STATUS_IS_INFORMATIONAL (msg->status_code)) {
			if (msg->status_code == SOUP_STATUS_CONTINUE) {
				/* Stop and wait for the body now */
				io->write_state =
					SOUP_MESSAGE_IO_STATE_BLOCKING;
				io->read_state = SOUP_MESSAGE_IO_STATE_BODY_START;
			} else {
				/* We just wrote a 1xx response
				 * header, so stay in STATE_HEADERS.
				 * (The caller will pause us from the
				 * wrote_informational callback if he
				 * is not ready to send the final
				 * response.)
				 */
			}

			soup_message_wrote_informational (msg);

			/* If this was "101 Switching Protocols", then
			 * the server probably stole the connection...
			 */
			if (io != priv->io_data)
				return FALSE;

			soup_message_cleanup_response (msg);
			break;
		}

		if (io->write_encoding == SOUP_ENCODING_CONTENT_LENGTH) {
			SoupMessageHeaders *hdrs =
				(io->mode == SOUP_MESSAGE_IO_CLIENT) ?
				msg->request_headers : msg->response_headers;
			io->write_length = soup_message_headers_get_content_length (hdrs);
		}

		if (io->mode == SOUP_MESSAGE_IO_CLIENT &&
		    soup_message_headers_get_expectations (msg->request_headers) & SOUP_EXPECTATION_CONTINUE) {
			/* Need to wait for the Continue response */
			io->write_state = SOUP_MESSAGE_IO_STATE_BLOCKING;
			io->read_state = SOUP_MESSAGE_IO_STATE_HEADERS;
		} else {
			io->write_state = SOUP_MESSAGE_IO_STATE_BODY_START;

			/* If the client was waiting for a Continue
			 * but we sent something else, then they're
			 * now done writing.
			 */
			if (io->mode == SOUP_MESSAGE_IO_SERVER &&
			    io->read_state == SOUP_MESSAGE_IO_STATE_BLOCKING)
				io->read_state = SOUP_MESSAGE_IO_STATE_DONE;
		}

		soup_message_wrote_headers (msg);
		break;


	case SOUP_MESSAGE_IO_STATE_BODY_START:
		io->body_ostream = soup_body_output_stream_new (io->ostream,
								io->write_encoding,
								io->write_length);
		io->write_state = SOUP_MESSAGE_IO_STATE_BODY;
		break;


	case SOUP_MESSAGE_IO_STATE_BODY:
		if (!io->write_length &&
		    io->write_encoding != SOUP_ENCODING_EOF &&
		    io->write_encoding != SOUP_ENCODING_CHUNKED) {
			io->write_state = SOUP_MESSAGE_IO_STATE_BODY_FLUSH;
			break;
		}

		if (!io->write_chunk) {
			io->write_chunk = soup_message_body_get_chunk (io->write_body, io->write_body_offset);
			if (!io->write_chunk) {
				g_return_val_if_fail (!io->item || !io->item->new_api, FALSE);
				soup_message_io_pause (msg);
				return FALSE;
			}
			if (!io->write_chunk->length) {
				io->write_state = SOUP_MESSAGE_IO_STATE_BODY_FLUSH;
				break;
			}
		}

		nwrote = g_pollable_stream_write (io->body_ostream,
						  io->write_chunk->data + io->written,
						  io->write_chunk->length - io->written,
						  blocking,
						  cancellable, error);
		if (nwrote == -1)
			return FALSE;

		chunk = soup_buffer_new_subbuffer (io->write_chunk,
						   io->written, nwrote);
		io->written += nwrote;
		if (io->write_length)
			io->write_length -= nwrote;

		if (io->written == io->write_chunk->length)
			io->write_state = SOUP_MESSAGE_IO_STATE_BODY_DATA;

		soup_message_wrote_body_data (msg, chunk);
		soup_buffer_free (chunk);
		break;


	case SOUP_MESSAGE_IO_STATE_BODY_DATA:
		io->written = 0;
		if (io->write_chunk->length == 0) {
			io->write_state = SOUP_MESSAGE_IO_STATE_BODY_FLUSH;
			break;
		}

		if (io->mode == SOUP_MESSAGE_IO_SERVER ||
		    priv->msg_flags & SOUP_MESSAGE_CAN_REBUILD)
			soup_message_body_wrote_chunk (io->write_body, io->write_chunk);
		io->write_body_offset += io->write_chunk->length;
		soup_buffer_free (io->write_chunk);
		io->write_chunk = NULL;

		io->write_state = SOUP_MESSAGE_IO_STATE_BODY;
		soup_message_wrote_chunk (msg);
		break;


	case SOUP_MESSAGE_IO_STATE_BODY_FLUSH:
		if (io->body_ostream) {
			if (blocking || io->write_encoding != SOUP_ENCODING_CHUNKED) {
				if (!g_output_stream_close (io->body_ostream, cancellable, error))
					return FALSE;
				g_clear_object (&io->body_ostream);
			} else {
				io->async_close_wait = g_cancellable_new ();
				if (io->async_context)
					g_main_context_push_thread_default (io->async_context);
				g_output_stream_close_async (io->body_ostream,
							     G_PRIORITY_DEFAULT, cancellable,
							     closed_async, g_object_ref (msg));
				if (io->async_context)
					g_main_context_pop_thread_default (io->async_context);
			}
		}

		io->write_state = SOUP_MESSAGE_IO_STATE_BODY_DONE;
		break;


	case SOUP_MESSAGE_IO_STATE_BODY_DONE:
		io->write_state = SOUP_MESSAGE_IO_STATE_FINISHING;
		soup_message_wrote_body (msg);
		break;


	case SOUP_MESSAGE_IO_STATE_FINISHING:
		io->write_state = SOUP_MESSAGE_IO_STATE_DONE;

		if (io->mode == SOUP_MESSAGE_IO_CLIENT)
			io->read_state = SOUP_MESSAGE_IO_STATE_HEADERS;
		break;


	default:
		g_return_val_if_reached (FALSE);
	}

	return TRUE;
}