Use soup_uri_set_auth().
[platform/upstream/libsoup.git] / libsoup / soup-uri.c
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /* soup-uri.c : utility functions to parse URLs */
3
4 /*
5  * Authors :
6  *  Bertrand Guiheneuf <bertrand@helixcode.com>
7  *  Dan Winship <danw@helixcode.com>
8  *  Alex Graveley <alex@ximian.com>
9  *
10  * Copyright 1999, 2000 Helix Code, Inc. (http://www.helixcode.com)
11  *
12  * This program is free software; you can redistribute it and/or
13  * modify it under the terms of the GNU General Public License as
14  * published by the Free Software Foundation; either version 2 of the
15  * License, or (at your option) any later version.
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with this program; if not, write to the Free Software
24  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
25  * USA
26  */
27
28
29
30 /*
31  * Here we deal with URLs following the general scheme:
32  *   protocol://user;AUTH=mech:password@host:port/name
33  * where name is a path-like string (ie dir1/dir2/....) See RFC 1738
34  * for the complete description of Uniform Resource Locators. The
35  * ";AUTH=mech" addition comes from RFC 2384, "POP URL Scheme".
36  */
37
38 /* XXX TODO:
39  * recover the words between #'s or ?'s after the path
40  * % escapes
41  */
42
43 #include <string.h>
44 #include <stdlib.h>
45
46 #include "soup-uri.h"
47 #include "soup-misc.h"
48
49 typedef struct {
50         SoupProtocol  proto;
51         gchar        *str;
52         gint          port;
53 } SoupKnownProtocols;
54
55 SoupKnownProtocols known_protocols [] = {
56         { SOUP_PROTOCOL_HTTP,   "http://",   80 },
57         { SOUP_PROTOCOL_HTTPS,  "https://",  443 },
58         { SOUP_PROTOCOL_SMTP,   "mailto:",   25 },
59         { SOUP_PROTOCOL_SOCKS4, "socks4://", -1 },
60         { SOUP_PROTOCOL_SOCKS5, "socks5://", -1 },
61         { 0 }
62 };
63
64 static SoupProtocol
65 soup_uri_get_protocol (const gchar *proto, int *len)
66 {
67         SoupKnownProtocols *known = known_protocols;
68
69         while (known->proto) {
70                 if (!g_strncasecmp (proto, known->str, strlen (known->str))) {
71                         *len = strlen (known->str);
72                         return known->proto;
73                 }
74                 known++;
75         }
76
77         *len = 0;
78         return 0;
79 }
80
81 static gchar *
82 soup_uri_protocol_to_string (SoupProtocol proto)
83 {
84         SoupKnownProtocols *known = known_protocols;
85
86         while (known->proto) {
87                 if (known->proto == proto) return known->str;
88                 known++;
89         }
90
91         return "";
92 }
93
94 static gint
95 soup_uri_get_default_port (SoupProtocol proto)
96 {
97         SoupKnownProtocols *known = known_protocols;
98
99         while (known->proto) {
100                 if (known->proto == proto) return known->port;
101                 known++;
102         }
103
104         return -1;
105 }
106
107 /**
108  * soup_uri_new: create a SoupUri object from a string
109  * @uri_string: The string containing the URL to scan
110  *
111  * This routine takes a gchar and parses it as a
112  * URL of the form:
113  *   protocol://user;AUTH=mech:password@host:port/path?querystring
114  * There is no test on the values. For example,
115  * "port" can be a string, not only a number!
116  * The SoupUri structure fields are filled with
117  * the scan results. When a member of the
118  * general URL can not be found, the corresponding
119  * SoupUri member is NULL.
120  * Fields filled in the SoupUri structure are allocated
121  * and url_string is not modified.
122  *
123  * Return value: a SoupUri structure containing the URL items.
124  **/
125 SoupUri *
126 soup_uri_new (const gchar* uri_string)
127 {
128         SoupUri *g_uri;
129         char *semi, *colon, *at, *slash, *path, *query = NULL;
130         char **split;
131
132         g_uri = g_new0 (SoupUri,1);
133
134         /* Find protocol: initial substring until "://" */
135         colon = strchr (uri_string, ':');
136         if (colon) {
137                 gint protolen;
138                 g_uri->protocol = soup_uri_get_protocol (uri_string, &protolen);
139                 uri_string += protolen;
140         }
141
142         /* Must have a protocol */
143         if (!g_uri->protocol) return NULL;
144
145         /* If there is an @ sign, look for user, authmech, and
146          * password before it.
147          */
148         slash = strchr (uri_string, '/');
149         at = strchr (uri_string, '@');
150         if (at && (!slash || at < slash)) {
151                 colon = strchr (uri_string, ':');
152                 if (colon && colon < at)
153                         g_uri->passwd = g_strndup (colon + 1, at - colon - 1);
154                 else {
155                         g_uri->passwd = NULL;
156                         colon = at;
157                 }
158
159                 semi = strchr(uri_string, ';');
160                 if (semi && semi < colon && !g_strncasecmp (semi, ";auth=", 6))
161                         g_uri->authmech = g_strndup (semi + 6,
162                                                      colon - semi - 6);
163                 else {
164                         g_uri->authmech = NULL;
165                         semi = colon;
166                 }
167
168                 g_uri->user = g_strndup (uri_string, semi - uri_string);
169                 uri_string = at + 1;
170         } else
171                 g_uri->user = g_uri->passwd = g_uri->authmech = NULL;
172
173         /* Find host (required) and port. */
174         colon = strchr (uri_string, ':');
175         if (slash && colon > slash)
176                 colon = 0;
177
178         if (colon) {
179                 g_uri->host = g_strndup (uri_string, colon - uri_string);
180                 if (slash)
181                         g_uri->port = atoi(colon + 1);
182                 else
183                         g_uri->port = atoi(colon + 1);
184         } else if (slash) {
185                 g_uri->host = g_strndup (uri_string, slash - uri_string);
186                 g_uri->port = soup_uri_get_default_port (g_uri->protocol);
187         } else {
188                 g_uri->host = g_strdup (uri_string);
189                 g_uri->port = soup_uri_get_default_port (g_uri->protocol);
190         }
191
192         /* setup a fallback, if relative, then empty string, else
193            it will be from root */
194         if (slash == NULL) {
195                 slash = "/";
196         }
197         if (slash && *slash && !g_uri->protocol)
198                 slash++;
199
200         split = g_strsplit(slash, " ", 0);
201         path = g_strjoinv("%20", split);
202         g_strfreev(split);
203
204         if (path)
205                 query = strchr (path, '?');
206
207         if (path && query) {
208                 g_uri->path = g_strndup (path, query - path);
209                 g_uri->querystring = g_strdup (++query);
210                 g_uri->query_elems = g_strsplit (g_uri->querystring, "&", 0);
211                 g_free (path);
212         } else {
213                 g_uri->path = path;
214                 g_uri->querystring = NULL;
215         }
216
217         return g_uri;
218 }
219
220 /* Need to handle mailto which apparantly doesn't use the "//" after the : */
221 gchar *
222 soup_uri_to_string (const SoupUri *uri, gboolean show_passwd)
223 {
224         g_return_val_if_fail (uri != NULL, NULL);
225
226         if (uri->port != -1 &&
227             uri->port != soup_uri_get_default_port (uri->protocol))
228                 return g_strdup_printf(
229                         "%s%s%s%s%s%s%s%s:%d%s%s%s%s",
230                         soup_uri_protocol_to_string (uri->protocol),
231                         uri->user ? uri->user : "",
232                         uri->authmech ? ";auth=" : "",
233                         uri->authmech ? uri->authmech : "",
234                         uri->passwd && show_passwd ? ":" : "",
235                         uri->passwd && show_passwd ? uri->passwd : "",
236                         uri->user ? "@" : "",
237                         uri->host,
238                         uri->port,
239                         uri->path && *uri->path != '/' ? "/" : "",
240                         uri->path ? uri->path : "",
241                         uri->querystring ? "?" : "",
242                         uri->querystring ? uri->querystring : "");
243         else
244                 return g_strdup_printf(
245                         "%s%s%s%s%s%s%s%s%s%s%s%s",
246                         soup_uri_protocol_to_string (uri->protocol),
247                         uri->user ? uri->user : "",
248                         uri->authmech ? ";auth=" : "",
249                         uri->authmech ? uri->authmech : "",
250                         uri->passwd && show_passwd ? ":" : "",
251                         uri->passwd && show_passwd ? uri->passwd : "",
252                         uri->user ? "@" : "",
253                         uri->host,
254                         uri->path && *uri->path != '/' ? "/" : "",
255                         uri->path ? uri->path : "",
256                         uri->querystring ? "?" : "",
257                         uri->querystring ? uri->querystring : "");
258 }
259
260 SoupUri *
261 soup_uri_copy (const SoupUri* uri)
262 {
263         gchar *uri_str;
264         SoupUri *dup;
265
266         g_return_val_if_fail (uri != NULL, NULL);
267
268         uri_str = soup_uri_to_string (uri, TRUE);
269         dup = soup_uri_new (uri_str);
270         g_free (uri_str);
271
272         return dup;
273 }
274
275 void
276 soup_uri_free (SoupUri *uri)
277 {
278         g_return_if_fail (uri != NULL);
279
280         g_free (uri->user);
281         g_free (uri->authmech);
282         g_free (uri->passwd);
283         g_free (uri->host);
284         g_free (uri->path);
285         g_free (uri->querystring);
286         g_strfreev (uri->query_elems);
287
288         g_free (uri);
289 }
290
291 void
292 soup_uri_set_auth  (SoupUri       *uri, 
293                     const gchar   *user, 
294                     const gchar   *passwd, 
295                     const gchar   *authmech)
296 {
297         g_return_if_fail (uri != NULL);
298
299         g_free (uri->user);
300         g_free (uri->passwd);
301         g_free (uri->authmech);
302
303         uri->user = g_strdup (user);
304         uri->passwd = g_strdup (passwd);
305         uri->authmech = g_strdup (authmech);
306 }
307
308 void
309 soup_debug_print_uri (SoupUri *uri)
310 {
311         g_return_if_fail (uri != NULL);
312
313         g_print ("Protocol: %s\n", soup_uri_protocol_to_string (uri->protocol));
314         g_print ("User:     %s\n", uri->user);
315         g_print ("Authmech: %s\n", uri->authmech);
316         g_print ("Password: %s\n", uri->passwd);
317         g_print ("Host:     %s\n", uri->host);
318         g_print ("Path:     %s\n", uri->path);
319         g_print ("Querystr: %s\n", uri->querystring);
320 }
321