1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3 * soup-message-client-io.c: client-side request/response
4 *
5 * Copyright (C) 2000-2003, Ximian, Inc.
6 */
7
8 #ifdef HAVE_CONFIG_H
9 #include "config.h"
10 #endif
11
12 #include <string.h>
13
14 #include <glib/gi18n-lib.h>
15
16 #include "soup.h"
17 #include "soup-connection.h"
18 #include "soup-message-queue.h"
19 #include "soup-socket-private.h"
20
21 static guint
parse_response_headers(SoupMessage * msg,char * headers,guint headers_len,SoupEncoding * encoding,gpointer user_data,GError ** error)22 parse_response_headers (SoupMessage *msg,
23 char *headers, guint headers_len,
24 SoupEncoding *encoding,
25 gpointer user_data,
26 GError **error)
27 {
28 SoupHTTPVersion version;
29
30 g_free(msg->reason_phrase);
31 msg->reason_phrase = NULL;
32 if (!soup_headers_parse_response (headers, headers_len,
33 msg->response_headers,
34 &version,
35 &msg->status_code,
36 &msg->reason_phrase)) {
37 g_set_error_literal (error, SOUP_REQUEST_ERROR,
38 SOUP_REQUEST_ERROR_PARSING,
39 _("Could not parse HTTP response"));
40 return SOUP_STATUS_MALFORMED;
41 }
42
43 g_object_notify (G_OBJECT (msg), SOUP_MESSAGE_STATUS_CODE);
44 g_object_notify (G_OBJECT (msg), SOUP_MESSAGE_REASON_PHRASE);
45
46 if (version < soup_message_get_http_version (msg))
47 soup_message_set_http_version (msg, version);
48
49 if ((msg->method == SOUP_METHOD_HEAD ||
50 msg->status_code == SOUP_STATUS_NO_CONTENT ||
51 msg->status_code == SOUP_STATUS_NOT_MODIFIED ||
52 SOUP_STATUS_IS_INFORMATIONAL (msg->status_code)) ||
53 (msg->method == SOUP_METHOD_CONNECT &&
54 SOUP_STATUS_IS_SUCCESSFUL (msg->status_code)))
55 *encoding = SOUP_ENCODING_NONE;
56 else
57 *encoding = soup_message_headers_get_encoding (msg->response_headers);
58
59 if (*encoding == SOUP_ENCODING_UNRECOGNIZED) {
60 g_set_error_literal (error, SOUP_REQUEST_ERROR,
61 SOUP_REQUEST_ERROR_ENCODING,
62 _("Unrecognized HTTP response encoding"));
63 return SOUP_STATUS_MALFORMED;
64 }
65
66 return SOUP_STATUS_OK;
67 }
68
69 static void
get_request_headers(SoupMessage * msg,GString * header,SoupEncoding * encoding,gpointer user_data)70 get_request_headers (SoupMessage *msg, GString *header,
71 SoupEncoding *encoding, gpointer user_data)
72 {
73 SoupMessageQueueItem *item = user_data;
74 SoupURI *uri = soup_message_get_uri (msg);
75 char *uri_host;
76 char *uri_string;
77 SoupMessageHeadersIter iter;
78 const char *name, *value;
79
80 if (strchr (uri->host, ':'))
81 uri_host = g_strdup_printf ("[%.*s]", (int) strcspn (uri->host, "%"), uri->host);
82 else if (g_hostname_is_non_ascii (uri->host))
83 uri_host = g_hostname_to_ascii (uri->host);
84 else
85 uri_host = uri->host;
86
87 if (msg->method == SOUP_METHOD_CONNECT) {
88 /* CONNECT URI is hostname:port for tunnel destination */
89 uri_string = g_strdup_printf ("%s:%d", uri_host, uri->port);
90 } else {
91 gboolean proxy = soup_connection_is_via_proxy (item->conn);
92
93 /* Proxy expects full URI to destination. Otherwise
94 * just the path.
95 */
96 uri_string = soup_uri_to_string (uri, !proxy);
97
98 if (proxy && uri->fragment) {
99 /* Strip fragment */
100 char *fragment = strchr (uri_string, '#');
101 if (fragment)
102 *fragment = '\0';
103 }
104 }
105
106 g_string_append_printf (header, "%s %s HTTP/1.%d\r\n",
107 msg->method, uri_string,
108 (soup_message_get_http_version (msg) == SOUP_HTTP_1_0) ? 0 : 1);
109
110 if (!soup_message_headers_get_one (msg->request_headers, "Host")) {
111 if (soup_uri_uses_default_port (uri)) {
112 g_string_append_printf (header, "Host: %s\r\n",
113 uri_host);
114 } else {
115 g_string_append_printf (header, "Host: %s:%d\r\n",
116 uri_host, uri->port);
117 }
118 }
119 g_free (uri_string);
120 if (uri_host != uri->host)
121 g_free (uri_host);
122
123 *encoding = soup_message_headers_get_encoding (msg->request_headers);
124 if ((*encoding == SOUP_ENCODING_CONTENT_LENGTH ||
125 *encoding == SOUP_ENCODING_NONE) &&
126 (msg->request_body->length > 0 ||
127 soup_message_headers_get_one (msg->request_headers, "Content-Type")) &&
128 !soup_message_headers_get_content_length (msg->request_headers)) {
129 *encoding = SOUP_ENCODING_CONTENT_LENGTH;
130 soup_message_headers_set_content_length (msg->request_headers,
131 msg->request_body->length);
132 }
133
134 soup_message_headers_iter_init (&iter, msg->request_headers);
135 while (soup_message_headers_iter_next (&iter, &name, &value))
136 g_string_append_printf (header, "%s: %s\r\n", name, value);
137 g_string_append (header, "\r\n");
138 }
139
140 void
soup_message_send_request(SoupMessageQueueItem * item,SoupMessageCompletionFn completion_cb,gpointer user_data)141 soup_message_send_request (SoupMessageQueueItem *item,
142 SoupMessageCompletionFn completion_cb,
143 gpointer user_data)
144 {
145 GMainContext *async_context;
146 GIOStream *iostream;
147
148 if (!SOUP_IS_SESSION_SYNC (item->session)) {
149 async_context = soup_session_get_async_context (item->session);
150 if (!async_context)
151 async_context = g_main_context_default ();
152 } else
153 async_context = NULL;
154 iostream = soup_socket_get_iostream (soup_connection_get_socket (item->conn));
155
156 soup_message_io_client (item, iostream, async_context,
157 get_request_headers,
158 parse_response_headers,
159 item,
160 completion_cb, user_data);
161 }
162