2003-08-26 Dan Winship <danw@ximian.com>
+ * libsoup/soup-message-client-io.c (soup_message_write_request,
+ soup_message_read_response): Higher-than-soup-message-io-level
+ functions to do client-side IO. (Code that used to be in
+ soup-queue.c)
+ (get_request_header_cb): Fix a bug in the generation of the Host:
+ header; need to include the port number if it's not the default.
+
+ * libsoup/soup-message-io.c (soup_message_write,
+ soup_message_write_simple): Take separate user_datas for the get_*
+ callbacks and the done callbacks.
+
+ * libsoup/soup-queue.c: Update to use soup_message_write_request
+ and soup_message_read_response.
+
+ * libsoup/soup-connection.c (soup_connection_new): Change the
+ prototype to take a SoupUri and a callback.
+
+ * libsoup/soup-context.c (try_create_connection,
+ soup_context_connect_cb): Update for soup_connection_new change.
+
+ * libsoup/soup-server.c (read_done_cb, issue_bad_request): Update
+ for soup_message_write changes
+
+ * libsoup/soup-uri.c (soup_uri_uses_default_port): new utility
+ function
+
+2003-08-26 Dan Winship <danw@ximian.com>
+
* libsoup/soup-message-private.h: Define SoupMessage signal stuff
(READ_HEADERS, READ_CHUNK, READ_BODY, READ_ERROR, WROTE_HEADERS,
WROTE_CHUNK, WROTE_BODY, WRITE_ERROR).
$(GLIB_LIBS) \
$(GNUTLS_LIBS)
-libsoup_2_2_la_SOURCES = \
- $(MARSHAL_GENERATED) \
- md5-utils.h \
- md5-utils.c \
- soup-address.c \
- soup-auth.h \
- soup-auth.c \
- soup-auth-basic.h \
- soup-auth-basic.c \
- soup-auth-digest.h \
- soup-auth-digest.c \
- soup-auth-ntlm.h \
- soup-auth-ntlm.c \
- soup-connection.c \
- soup-context.c \
- soup-dns.h \
- soup-dns.c \
- soup-error.c \
- soup-gnutls.h \
- soup-gnutls.c \
- soup-headers.c \
- soup-message-private.h \
- soup-message.c \
- soup-message-handlers.c \
- soup-message-io.c \
- soup-method.c \
- soup-misc.c \
- soup-private.h \
- soup-queue.h \
- soup-queue.c \
- soup-server.c \
- soup-server-auth.c \
- soup-server-message.c \
- soup-socket.c \
- soup-ssl.h \
- soup-ssl.c \
+libsoup_2_2_la_SOURCES = \
+ $(MARSHAL_GENERATED) \
+ md5-utils.h \
+ md5-utils.c \
+ soup-address.c \
+ soup-auth.h \
+ soup-auth.c \
+ soup-auth-basic.h \
+ soup-auth-basic.c \
+ soup-auth-digest.h \
+ soup-auth-digest.c \
+ soup-auth-ntlm.h \
+ soup-auth-ntlm.c \
+ soup-connection.c \
+ soup-context.c \
+ soup-dns.h \
+ soup-dns.c \
+ soup-error.c \
+ soup-gnutls.h \
+ soup-gnutls.c \
+ soup-headers.c \
+ soup-message.c \
+ soup-message-client-io.c \
+ soup-message-handlers.c \
+ soup-message-io.c \
+ soup-message-private.h \
+ soup-method.c \
+ soup-misc.c \
+ soup-private.h \
+ soup-queue.h \
+ soup-queue.c \
+ soup-server.c \
+ soup-server-auth.c \
+ soup-server-message.c \
+ soup-socket.c \
+ soup-ssl.h \
+ soup-ssl.c \
soup-uri.c
EXTRA_DIST= soup-marshal.list
static GObjectClass *parent_class;
enum {
+ CONNECT_RESULT,
DISCONNECTED,
LAST_SIGNAL
};
object_class->finalize = finalize;
/* signals */
+ signals[CONNECT_RESULT] =
+ g_signal_new ("connect_result",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (SoupConnectionClass, connect_result),
+ NULL, NULL,
+ soup_marshal_NONE__INT,
+ G_TYPE_NONE, 1,
+ G_TYPE_INT);
signals[DISCONNECTED] =
g_signal_new ("disconnected",
G_OBJECT_CLASS_TYPE (object_class),
SOUP_MAKE_TYPE (soup_connection, SoupConnection, class_init, init, PARENT_TYPE)
+static void
+socket_disconnected (SoupSocket *sock, gpointer conn)
+{
+ soup_connection_disconnect (conn);
+}
+
+static void
+socket_connected (SoupSocket *sock, SoupKnownErrorCode status, gpointer conn)
+{
+ g_signal_emit (conn, signals[CONNECT_RESULT], 0, status);
+}
+
/**
* soup_connection_new:
- * @sock: a #SoupSocket
+ * @uri: remote machine to connect to
+ * @callback: callback to call after connecting
+ * @user_data: data for @callback
*
- * Creates a new #SoupConnection, wrapped around @sock.
+ * Creates a connection to @uri. @callback will be called when the
+ * connection completes (or fails).
*
- * Return value: the new #SoupConnection
+ * Return value: the new connection (not yet ready for use).
**/
SoupConnection *
-soup_connection_new (SoupSocket *sock)
+soup_connection_new (const SoupUri *uri,
+ SoupConnectionCallback callback, gpointer user_data)
{
SoupConnection *conn;
conn = g_object_new (SOUP_TYPE_CONNECTION, NULL);
- conn->priv->socket = g_object_ref (sock);
+ soup_signal_connect_once (conn, "connect_result",
+ G_CALLBACK (callback), user_data);
+ conn->priv->socket = soup_socket_client_new (uri->host, uri->port,
+ uri->protocol == SOUP_PROTOCOL_HTTPS,
+ socket_connected, conn);
+ g_signal_connect (conn->priv->socket, "disconnected",
+ G_CALLBACK (socket_disconnected), conn);
return conn;
}
#include <glib-object.h>
#include <libsoup/soup-socket.h>
+#include <libsoup/soup-uri.h>
#define SOUP_TYPE_CONNECTION (soup_connection_get_type ())
#define SOUP_CONNECTION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SOUP_TYPE_CONNECTION, SoupConnection))
GObjectClass parent_class;
/* signals */
+ void (*connect_result) (SoupConnection *, SoupKnownErrorCode);
void (*disconnected) (SoupConnection *);
} SoupConnectionClass;
GType soup_connection_get_type (void);
-SoupConnection *soup_connection_new (SoupSocket *sock);
+typedef void (*SoupConnectionCallback) (SoupConnection *sock,
+ SoupKnownErrorCode status,
+ gpointer data);
+
+SoupConnection *soup_connection_new (const SoupUri *uri,
+ SoupConnectionCallback,
+ gpointer data);
+
+gboolean soup_connection_is_proxy (SoupConnection *conn);
+
void soup_connection_disconnect (SoupConnection *conn);
gboolean soup_connection_is_connected (SoupConnection *conn);
SoupSocket *soup_connection_get_socket (SoupConnection *conn);
-void soup_connection_set_in_use (SoupConnection *conn,
+void soup_connection_set_in_use (SoupConnection *conn,
gboolean in_use);
gboolean soup_connection_is_in_use (SoupConnection *conn);
time_t soup_connection_last_used (SoupConnection *conn);
gboolean soup_connection_is_new (SoupConnection *conn);
void soup_connection_mark_old (SoupConnection *conn);
-#endif /*SOUP_CONNECTION_H*/
+#endif /* SOUP_CONNECTION_H */
gpointer user_data;
guint timeout_tag;
- SoupSocket *sock;
+ SoupConnection *conn;
};
static void
static gboolean retry_connect_timeout_cb (struct SoupConnectData *data);
static void
-soup_context_connect_cb (SoupSocket *socket,
+soup_context_connect_cb (SoupConnection *conn,
SoupKnownErrorCode status,
gpointer user_data)
{
struct SoupConnectData *data = user_data;
SoupContext *ctx = data->ctx;
- SoupConnection *new_conn = NULL;
switch (status) {
case SOUP_ERROR_OK:
- new_conn = soup_connection_new (socket);
-
- g_signal_connect (new_conn, "disconnected",
+ g_signal_connect (conn, "disconnected",
G_CALLBACK (connection_disconnected),
ctx->priv->server);
/* FIXME */
- g_object_set_data (G_OBJECT (new_conn), "SoupContext-port",
+ g_object_set_data (G_OBJECT (conn), "SoupContext-port",
GUINT_TO_POINTER (ctx->priv->uri->port));
ctx->priv->server->connections =
- g_slist_prepend (ctx->priv->server->connections, new_conn);
+ g_slist_prepend (ctx->priv->server->connections, conn);
break;
case SOUP_ERROR_CANT_RESOLVE:
connection_count--;
+ g_object_unref (conn);
break;
default:
connection_count--;
+ g_object_unref (conn);
/*
* Check if another connection exists to this server
break;
}
- (*data->cb) (ctx, status, new_conn, data->user_data);
+ (*data->cb) (ctx, status, conn, data->user_data);
g_object_unref (ctx);
- g_object_unref (data->sock);
g_free (data);
}
try_create_connection (struct SoupConnectData *data)
{
int conn_limit = soup_get_connection_limit ();
- SoupUri *uri;
/*
* Check if we are allowed to create a new connection, otherwise wait
if (conn_limit &&
connection_count >= conn_limit &&
!prune_least_used_connection ()) {
- data->sock = NULL;
+ data->conn = NULL;
return FALSE;
}
connection_count++;
data->timeout_tag = 0;
- uri = data->ctx->priv->uri;
- data->sock = soup_socket_client_new (uri->host, uri->port,
- uri->protocol == SOUP_PROTOCOL_HTTPS,
- soup_context_connect_cb, data);
+ data->conn = soup_connection_new (data->ctx->priv->uri,
+ soup_context_connect_cb, data);
return TRUE;
}
if (data->timeout_tag)
g_source_remove (data->timeout_tag);
- else if (data->sock) {
+ else if (data->conn) {
connection_count--;
- g_object_unref (data->sock);
+ g_object_unref (data->conn);
}
g_free (data);
--- /dev/null
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * soup-message-client-io.c: client-side request/response
+ *
+ * Copyright (C) 2000-2003, Ximian, Inc.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "soup-message-private.h"
+#include "soup-auth.h"
+#include "soup-context.h"
+#include "soup-headers.h"
+#include "soup-misc.h"
+#include "soup-private.h"
+
+static SoupKnownErrorCode
+parse_response_headers_cb (SoupMessage *req,
+ char *headers, guint headers_len,
+ SoupTransferEncoding *encoding,
+ guint *content_len,
+ gpointer user_data)
+{
+ const char *length, *enc;
+ SoupHttpVersion version;
+ GHashTable *resp_hdrs;
+ SoupMethodId meth_id;
+
+ if (!soup_headers_parse_response (headers, headers_len,
+ req->response_headers,
+ &version,
+ &req->errorcode,
+ (char **) &req->errorphrase))
+ return SOUP_ERROR_MALFORMED;
+
+ meth_id = soup_method_get_id (req->method);
+ resp_hdrs = req->response_headers;
+
+ req->errorclass = soup_error_get_class (req->errorcode);
+
+ /*
+ * Special case zero body handling for:
+ * - HEAD requests (where content-length must be ignored)
+ * - CONNECT requests (no body expected)
+ * - No Content (204) responses (no message-body allowed)
+ * - Reset Content (205) responses (no entity allowed)
+ * - Not Modified (304) responses (no message-body allowed)
+ * - 1xx Informational responses (where no body is allowed)
+ */
+ if (meth_id == SOUP_METHOD_ID_HEAD ||
+ meth_id == SOUP_METHOD_ID_CONNECT ||
+ req->errorcode == SOUP_ERROR_NO_CONTENT ||
+ req->errorcode == SOUP_ERROR_RESET_CONTENT ||
+ req->errorcode == SOUP_ERROR_NOT_MODIFIED ||
+ req->errorclass == SOUP_ERROR_CLASS_INFORMATIONAL) {
+ *encoding = SOUP_TRANSFER_CONTENT_LENGTH;
+ *content_len = 0;
+ return SOUP_ERROR_OK;
+ }
+
+ /*
+ * Handle Chunked encoding. Prefer Chunked over a Content-Length to
+ * support broken Traffic-Server proxies that supply both.
+ */
+ enc = soup_message_get_header (resp_hdrs, "Transfer-Encoding");
+ if (enc) {
+ if (g_strcasecmp (enc, "chunked") == 0) {
+ *encoding = SOUP_TRANSFER_CHUNKED;
+ return SOUP_ERROR_OK;
+ } else
+ return SOUP_ERROR_MALFORMED;
+ }
+
+ /*
+ * Handle Content-Length encoding
+ */
+ length = soup_message_get_header (resp_hdrs, "Content-Length");
+ if (length) {
+ int len;
+
+ *encoding = SOUP_TRANSFER_CONTENT_LENGTH;
+ len = atoi (length);
+ if (len < 0)
+ return SOUP_ERROR_MALFORMED;
+ else
+ *content_len = len;
+ }
+
+ return SOUP_ERROR_OK;
+}
+
+void
+soup_message_read_response (SoupMessage *msg,
+ SoupMessageCallbackFn read_headers_cb,
+ SoupMessageReadChunkFn read_chunk_cb,
+ SoupMessageCallbackFn read_body_cb,
+ SoupMessageCallbackFn read_error_cb,
+ gpointer user_data)
+{
+ soup_message_read (msg, &msg->response, parse_response_headers_cb,
+ read_headers_cb, read_chunk_cb, read_body_cb,
+ read_error_cb, user_data);
+}
+
+
+static void
+encode_http_auth (SoupMessage *msg, GString *header, gboolean proxy_auth)
+{
+ SoupAuth *auth;
+ SoupContext *ctx;
+ char *token;
+
+ ctx = proxy_auth ? soup_get_proxy () : msg->priv->context;
+
+ auth = soup_context_lookup_auth (ctx, msg);
+ if (!auth)
+ return;
+ if (!soup_auth_is_authenticated (auth) &&
+ !soup_context_authenticate_auth (ctx, auth))
+ return;
+
+ token = soup_auth_get_authorization (auth, msg);
+ if (token) {
+ g_string_sprintfa (header, "%s: %s\r\n",
+ proxy_auth ?
+ "Proxy-Authorization" :
+ "Authorization",
+ token);
+ g_free (token);
+ }
+}
+
+static void
+add_header (gpointer name, gpointer value, gpointer data)
+{
+ GString *headers = data;
+
+ g_string_append_printf (headers, "%s: %s\r\n",
+ (char *)name, (char *)value);
+}
+
+static void
+get_request_header_cb (SoupMessage *req, GString *header, gpointer user_data)
+{
+ const SoupUri *uri = soup_message_get_uri (req);
+ char *uri_string;
+ gboolean proxy = GPOINTER_TO_UINT (user_data);
+
+ if (!strcmp (req->method, "CONNECT")) {
+ /* CONNECT URI is hostname:port for tunnel destination */
+ uri_string = g_strdup_printf ("%s:%d", uri->host, uri->port);
+ } else {
+ /* Proxy expects full URI to destination. Otherwise
+ * just the path.
+ */
+ uri_string = soup_uri_to_string (uri, !proxy);
+ }
+
+ if (req->priv->http_version == SOUP_HTTP_1_0) {
+ g_string_append_printf (header, "%s %s HTTP/1.0\r\n",
+ req->method, uri_string);
+ } else {
+ g_string_append_printf (header, "%s %s HTTP/1.1\r\n",
+ req->method, uri_string);
+ if (soup_uri_uses_default_port (uri)) {
+ g_string_append_printf (header, "Host: %s\r\n",
+ uri->host);
+ } else {
+ g_string_append_printf (header, "Host: %s:%d\r\n",
+ uri->host, uri->port);
+ }
+ }
+ g_free (uri_string);
+
+ if (req->request.length > 0) {
+ if (!soup_message_get_header (req->request_headers,
+ "Content-Type")) {
+ g_string_append (header, "Content-Type: text/xml; "
+ "charset=utf-8\r\n");
+ }
+ g_string_append_printf (header, "Content-Length: %d\r\n",
+ req->request.length);
+ }
+
+ encode_http_auth (req, header, FALSE);
+ if (proxy)
+ encode_http_auth (req, header, TRUE);
+
+ soup_message_foreach_header (req->request_headers, add_header, header);
+ g_string_append (header, "\r\n");
+}
+
+void
+soup_message_write_request (SoupMessage *req, gboolean is_via_proxy,
+ SoupMessageCallbackFn write_done_cb,
+ SoupMessageCallbackFn write_error_cb,
+ gpointer user_data)
+{
+ soup_message_write_simple (req, &req->request,
+ get_request_header_cb,
+ GUINT_TO_POINTER (is_via_proxy),
+ write_done_cb, write_error_cb, user_data);
+}
SoupMessageGetHeadersFn get_header_cb;
SoupMessageGetChunkFn get_chunk_cb;
- gpointer user_data;
+ gpointer get_user_data;
guint wrote_body_id;
guint error_id;
case SOUP_MESSAGE_STATUS_WRITING_HEADERS:
if (w->get_header_cb) {
SOUP_MESSAGE_WRITE_PREPARE_FOR_CALLBACK;
- w->get_header_cb (msg, w->buf, w->user_data);
+ w->get_header_cb (msg, w->buf,
+ w->get_user_data);
SOUP_MESSAGE_WRITE_RETURN_IF_CANCELLED;
w->get_header_cb = NULL;
SOUP_MESSAGE_WRITE_PREPARE_FOR_CALLBACK;
got_chunk = w->get_chunk_cb (msg,
&w->chunk,
- w->user_data);
+ w->get_user_data);
SOUP_MESSAGE_WRITE_RETURN_IF_CANCELLED;
if (!got_chunk) {
SoupTransferEncoding encoding,
SoupMessageGetHeadersFn get_header_cb,
SoupMessageGetChunkFn get_chunk_cb,
+ gpointer get_user_data,
SoupMessageCallbackFn wrote_body_cb,
SoupMessageCallbackFn error_cb,
gpointer user_data)
w->buf = g_string_new (NULL);
w->get_header_cb = get_header_cb;
w->get_chunk_cb = get_chunk_cb;
- w->user_data = user_data;
+ w->get_user_data = get_user_data;
w->wrote_body_id = g_signal_connect (msg, "wrote_body",
G_CALLBACK (wrote_body_cb),
soup_message_write_simple (SoupMessage *msg,
const SoupDataBuffer *body,
SoupMessageGetHeadersFn get_header_cb,
+ gpointer get_user_data,
SoupMessageCallbackFn wrote_body_cb,
SoupMessageCallbackFn error_cb,
gpointer user_data)
SoupMessageWriteState *w;
w = create_writer (msg, SOUP_TRANSFER_CONTENT_LENGTH,
- get_header_cb, NULL, wrote_body_cb,
- error_cb, user_data);
+ get_header_cb, NULL, get_user_data,
+ wrote_body_cb, error_cb, user_data);
w->body = body;
}
SoupTransferEncoding encoding,
SoupMessageGetHeadersFn get_header_cb,
SoupMessageGetChunkFn get_chunk_cb,
+ gpointer get_user_data,
SoupMessageCallbackFn wrote_body_cb,
SoupMessageCallbackFn error_cb,
gpointer user_data)
{
SoupMessageWriteState *w;
- w = create_writer (msg, encoding, get_header_cb, get_chunk_cb,
+ w = create_writer (msg, encoding,
+ get_header_cb, get_chunk_cb, get_user_data,
wrote_body_cb, error_cb, user_data);
}
SoupTransferEncoding encoding,
SoupMessageGetHeadersFn get_header_cb,
SoupMessageGetChunkFn get_chunk_cb,
+ gpointer get_user_data,
SoupCallbackFn write_done_cb,
SoupCallbackFn error_cb,
gpointer user_data);
void soup_message_write_simple (SoupMessage *msg,
const SoupDataBuffer *body,
SoupMessageGetHeadersFn get_header_cb,
+ gpointer get_user_data,
SoupCallbackFn write_done_cb,
SoupCallbackFn error_cb,
gpointer user_data);
void soup_message_write_unpause (SoupMessage *msg);
+/* Higher-level API */
+void soup_message_write_request (SoupMessage *msg,
+ gboolean is_via_proxy,
+ SoupMessageCallbackFn write_done_cb,
+ SoupMessageCallbackFn write_error_cb,
+ gpointer user_data);
+void soup_message_read_response (SoupMessage *msg,
+ SoupMessageCallbackFn read_headers_cb,
+ SoupMessageReadChunkFn read_chunk_cb,
+ SoupMessageCallbackFn read_body_cb,
+ SoupMessageCallbackFn read_error_cb,
+ gpointer user_data);
+
+
+
#endif /* SOUP_MESSAGE_PRIVATE_H */
}
}
-static SoupKnownErrorCode
-soup_queue_parse_headers_cb (SoupMessage *req,
- char *headers, guint headers_len,
- SoupTransferEncoding *encoding,
- guint *content_len,
- gpointer user_data)
-{
- const char *length, *enc;
- SoupHttpVersion version;
- GHashTable *resp_hdrs;
- SoupMethodId meth_id;
-
- if (!soup_headers_parse_response (headers, headers_len,
- req->response_headers,
- &version,
- &req->errorcode,
- (char **) &req->errorphrase))
- return SOUP_ERROR_MALFORMED;
-
- meth_id = soup_method_get_id (req->method);
- resp_hdrs = req->response_headers;
-
- req->errorclass = soup_error_get_class (req->errorcode);
-
- /*
- * Special case zero body handling for:
- * - HEAD requests (where content-length must be ignored)
- * - CONNECT requests (no body expected)
- * - No Content (204) responses (no message-body allowed)
- * - Reset Content (205) responses (no entity allowed)
- * - Not Modified (304) responses (no message-body allowed)
- * - 1xx Informational responses (where no body is allowed)
- */
- if (meth_id == SOUP_METHOD_ID_HEAD ||
- meth_id == SOUP_METHOD_ID_CONNECT ||
- req->errorcode == SOUP_ERROR_NO_CONTENT ||
- req->errorcode == SOUP_ERROR_RESET_CONTENT ||
- req->errorcode == SOUP_ERROR_NOT_MODIFIED ||
- req->errorclass == SOUP_ERROR_CLASS_INFORMATIONAL) {
- *encoding = SOUP_TRANSFER_CONTENT_LENGTH;
- *content_len = 0;
- return SOUP_ERROR_OK;
- }
-
- /*
- * Handle Chunked encoding. Prefer Chunked over a Content-Length to
- * support broken Traffic-Server proxies that supply both.
- */
- enc = soup_message_get_header (resp_hdrs, "Transfer-Encoding");
- if (enc) {
- if (g_strcasecmp (enc, "chunked") == 0) {
- *encoding = SOUP_TRANSFER_CHUNKED;
- return SOUP_ERROR_OK;
- } else
- return SOUP_ERROR_MALFORMED;
- }
-
- /*
- * Handle Content-Length encoding
- */
- length = soup_message_get_header (resp_hdrs, "Content-Length");
- if (length) {
- int len;
-
- *encoding = SOUP_TRANSFER_CONTENT_LENGTH;
- len = atoi (length);
- if (len < 0)
- return SOUP_ERROR_MALFORMED;
- else
- *content_len = len;
- }
-
- return SOUP_ERROR_OK;
-}
-
static void
soup_queue_read_headers_cb (SoupMessage *req, gpointer user_data)
{
soup_message_disconnect (req);
if (req->errorclass == SOUP_ERROR_CLASS_INFORMATIONAL) {
- soup_message_read (req, &req->response,
- soup_queue_parse_headers_cb,
- soup_queue_read_headers_cb,
- soup_queue_read_chunk_cb,
- soup_queue_read_done_cb,
- soup_queue_error_cb,
- NULL);
+ soup_message_read_response (req,
+ soup_queue_read_headers_cb,
+ soup_queue_read_chunk_cb,
+ soup_queue_read_done_cb,
+ soup_queue_error_cb,
+ NULL);
} else
req->priv->status = SOUP_MESSAGE_STATUS_FINISHED;
soup_message_run_handlers (req, SOUP_HANDLER_POST_BODY);
}
-static void
-soup_encode_http_auth (SoupMessage *msg, GString *header, gboolean proxy_auth)
-{
- SoupAuth *auth;
- SoupContext *ctx;
- char *token;
-
- ctx = proxy_auth ? soup_get_proxy () : msg->priv->context;
-
- auth = soup_context_lookup_auth (ctx, msg);
- if (!auth)
- return;
- if (!soup_auth_is_authenticated (auth) &&
- !soup_context_authenticate_auth (ctx, auth))
- return;
-
- token = soup_auth_get_authorization (auth, msg);
- if (token) {
- g_string_sprintfa (header, "%s: %s\r\n",
- proxy_auth ?
- "Proxy-Authorization" :
- "Authorization",
- token);
- g_free (token);
- }
-}
-
-struct SoupUsedHeaders {
- gboolean host;
- gboolean user_agent;
- gboolean content_type;
- gboolean connection;
- gboolean proxy_auth;
- gboolean auth;
-
- GString *out;
-};
-
-static void
-soup_check_used_headers (gchar *key,
- GSList *vals,
- struct SoupUsedHeaders *hdrs)
-{
- switch (toupper (key [0])) {
- case 'H':
- if (!g_strcasecmp (key+1, "ost"))
- hdrs->host = TRUE;
- break;
- case 'U':
- if (!g_strcasecmp (key+1, "ser-Agent"))
- hdrs->user_agent = TRUE;
- break;
- case 'A':
- if (!g_strcasecmp (key+1, "uthorization"))
- hdrs->auth = TRUE;
- break;
- case 'P':
- if (!g_strcasecmp (key+1, "roxy-Authorization"))
- hdrs->proxy_auth = TRUE;
- break;
- case 'C':
- if (!g_strcasecmp (key+1, "onnection"))
- hdrs->connection = TRUE;
- else if (!g_strcasecmp (key+1, "ontent-Type"))
- hdrs->content_type = TRUE;
- else if (!g_strcasecmp (key+1, "ontent-Length")) {
- g_warning ("Content-Length set as custom request "
- "header is not allowed.");
- return;
- }
- break;
- }
-
- while (vals) {
- g_string_sprintfa (hdrs->out,
- "%s: %s\r\n",
- key,
- (gchar *) vals->data);
- vals = vals->next;
- }
-}
-
-static void
-soup_queue_get_request_header_cb (SoupMessage *req, GString *header,
- gpointer user_data)
-{
- char *uri;
- SoupContext *proxy;
- const SoupUri *suri;
- struct SoupUsedHeaders hdrs = {
- FALSE,
- FALSE,
- FALSE,
- FALSE,
- FALSE,
- FALSE,
- NULL
- };
-
- hdrs.out = header;
- proxy = soup_get_proxy ();
- suri = soup_message_get_uri (req);
-
- if (!g_strcasecmp (req->method, "CONNECT")) {
- /* CONNECT URI is hostname:port for tunnel destination */
- uri = g_strdup_printf ("%s:%d", suri->host, suri->port);
- } else {
- /* Proxy expects full URI to destination. Otherwise
- * just the path.
- */
- uri = soup_uri_to_string (suri, !proxy);
- }
-
- g_string_sprintfa (header,
- req->priv->http_version == SOUP_HTTP_1_1 ?
- "%s %s HTTP/1.1\r\n" :
- "%s %s HTTP/1.0\r\n",
- req->method,
- uri);
- g_free (uri);
-
- /*
- * FIXME: Add a 411 "Length Required" response code handler here?
- */
- if (req->request.length > 0) {
- g_string_sprintfa (header,
- "Content-Length: %d\r\n",
- req->request.length);
- }
-
- g_hash_table_foreach (req->request_headers,
- (GHFunc) soup_check_used_headers,
- &hdrs);
-
- /*
- * If we specify an absoluteURI in the request line, the Host header
- * MUST be ignored by the proxy.
- */
- g_string_sprintfa (header,
- "%s%s%s%s%s%s%s",
- hdrs.host ? "" : "Host: ",
- hdrs.host ? "" : suri->host,
- hdrs.host ? "" : "\r\n",
- hdrs.content_type ? "" : "Content-Type: text/xml; ",
- hdrs.content_type ? "" : "charset=utf-8\r\n",
- hdrs.connection ? "" : "Connection: keep-alive\r\n",
- hdrs.user_agent ?
- "" :
- "User-Agent: Soup/" VERSION "\r\n");
-
- /*
- * Proxy-Authorization from the proxy Uri
- */
- if (!hdrs.proxy_auth && proxy && soup_context_get_uri (proxy)->user)
- soup_encode_http_auth (req, header, TRUE);
-
- /*
- * Authorization from the context Uri
- */
- if (!hdrs.auth)
- soup_encode_http_auth (req, header, FALSE);
-
- g_string_append (header, "\r\n");
-}
-
static void
soup_queue_write_done_cb (SoupMessage *req, gpointer user_data)
{
- soup_message_read (req, &req->response,
- soup_queue_parse_headers_cb,
- soup_queue_read_headers_cb,
- soup_queue_read_chunk_cb,
- soup_queue_read_done_cb,
- soup_queue_error_cb,
- NULL);
+ soup_message_read_response (req, soup_queue_read_headers_cb,
+ soup_queue_read_chunk_cb,
+ soup_queue_read_done_cb,
+ soup_queue_error_cb,
+ NULL);
}
static void
return;
}
- soup_message_write_simple (req, &req->request,
- soup_queue_get_request_header_cb,
- soup_queue_write_done_cb,
- soup_queue_error_cb,
- NULL);
+ soup_message_write_request (req, soup_get_proxy () != NULL,
+ soup_queue_write_done_cb,
+ soup_queue_error_cb,
+ NULL);
}
static void
soup_server_message_finish (SOUP_SERVER_MESSAGE (msg));
soup_message_write_simple (msg, &msg->response,
- get_response_header_cb,
- write_done_cb, error_cb,
- NULL);
+ get_response_header_cb, NULL,
+ write_done_cb, error_cb, NULL);
}
static SoupKnownErrorCode
encoding = soup_server_message_get_encoding (smsg);
if (encoding == SOUP_TRANSFER_CONTENT_LENGTH) {
soup_message_write_simple (req, &req->response,
- get_response_header_cb,
- write_done_cb, error_cb,
- NULL);
+ get_response_header_cb, NULL,
+ write_done_cb, error_cb, NULL);
soup_server_message_start (smsg);
} else {
soup_message_write (req, encoding,
- get_response_header_cb, get_chunk_cb,
+ get_response_header_cb, get_chunk_cb, NULL,
write_done_cb, error_cb, NULL);
}
*d++ = *s;
} while (*s++);
}
+
+gboolean
+soup_uri_uses_default_port (const SoupUri *uri)
+{
+ return uri->port == soup_protocol_default_port (uri->protocol);
+}
char *fragment;
} SoupUri;
-SoupUri *soup_uri_new_with_base (const SoupUri *base,
- const char *uri_string);
-SoupUri *soup_uri_new (const char *uri_string);
+SoupUri *soup_uri_new_with_base (const SoupUri *base,
+ const char *uri_string);
+SoupUri *soup_uri_new (const char *uri_string);
-char *soup_uri_to_string (const SoupUri *uri,
- gboolean just_path);
+char *soup_uri_to_string (const SoupUri *uri,
+ gboolean just_path);
-SoupUri *soup_uri_copy (const SoupUri *uri);
+SoupUri *soup_uri_copy (const SoupUri *uri);
-gboolean soup_uri_equal (const SoupUri *uri1,
- const SoupUri *uri2);
+gboolean soup_uri_equal (const SoupUri *uri1,
+ const SoupUri *uri2);
-void soup_uri_free (SoupUri *uri);
+void soup_uri_free (SoupUri *uri);
-void soup_uri_set_auth (SoupUri *uri,
- const char *user,
- const char *passwd,
- const char *authmech);
+void soup_uri_set_auth (SoupUri *uri,
+ const char *user,
+ const char *passwd,
+ const char *authmech);
-char *soup_uri_encode (const char *part,
- const char *escape_extra);
-void soup_uri_decode (char *part);
+char *soup_uri_encode (const char *part,
+ const char *escape_extra);
+void soup_uri_decode (char *part);
+
+gboolean soup_uri_uses_default_port (const SoupUri *uri);
#endif /*SOUP_URI_H*/