• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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