a1b12a5405bb09ce33ce81beacb27a3090bfba9f
[platform/upstream/libsoup.git] / tests / get.c
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3  * Copyright (C) 2001-2003, Ximian, Inc.
4  */
5
6 #include <ctype.h>
7 #include <errno.h>
8 #include <fcntl.h>
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <sys/stat.h>
13 #include <unistd.h>
14
15 #include <libsoup/soup.h>
16
17 #ifdef G_OS_WIN32
18 #include <io.h>
19 #define mkdir(path, mode) _mkdir (path)
20 #endif
21
22 SoupSession *session;
23 GMainLoop *loop;
24 gboolean recurse = FALSE, debug = FALSE;
25 const char *method;
26 char *base;
27 SoupURI *base_uri;
28 int pending;
29 GHashTable *fetched_urls;
30
31 static GPtrArray *
32 find_hrefs (SoupURI *base, const char *body, int length)
33 {
34         GPtrArray *hrefs = g_ptr_array_new ();
35         char *buf = g_strndup (body, length);
36         char *start = buf, *end;
37         char *href, *frag;
38         SoupURI *uri;
39
40         while ((start = strstr (start, "href"))) {
41                 start += 4;
42                 while (isspace ((unsigned char) *start))
43                         start++;
44                 if (*start++ != '=') 
45                         continue;
46                 while (isspace ((unsigned char) *start))
47                         start++;
48                 if (*start++ != '"')
49                         continue;
50
51                 end = strchr (start, '"');
52                 if (!end)
53                         break;
54
55                 href = g_strndup (start, end - start);
56                 start = end;
57                 frag = strchr (href, '#');
58                 if (frag)
59                         *frag = '\0';
60
61                 uri = soup_uri_new_with_base (base, href);
62                 g_free (href);
63
64                 if (!uri)
65                         continue;
66                 if (base->scheme != uri->scheme ||
67                     base->port != uri->port ||
68                     g_ascii_strcasecmp (base->host, uri->host) != 0) {
69                         soup_uri_free (uri);
70                         continue;
71                 }
72
73                 if (strncmp (base->path, uri->path, strlen (base->path)) != 0) {
74                         soup_uri_free (uri);
75                         continue;
76                 }
77
78                 g_ptr_array_add (hrefs, soup_uri_to_string (uri, FALSE));
79                 soup_uri_free (uri);
80         }
81         g_free (buf);
82
83         return hrefs;
84 }
85
86 static void
87 mkdirs (const char *path)
88 {
89         char *slash;
90
91         for (slash = strchr (path, '/'); slash; slash = strchr (slash + 1, '/')) {
92                 *slash = '\0';
93                 if (*path && mkdir (path, 0755) == -1 && errno != EEXIST) {
94                         fprintf (stderr, "Could not create '%s'\n", path);
95                         g_main_loop_quit (loop);
96                         return;
97                 }
98                 *slash = '/';
99         }
100 }
101
102 static void
103 get_url (const char *url)
104 {
105         char *url_to_get, *slash, *name;
106         SoupMessage *msg;
107         int fd, i;
108         SoupURI *uri;
109         GPtrArray *hrefs;
110         const char *header;
111
112         if (strncmp (url, base, strlen (base)) != 0)
113                 return;
114         if (strchr (url, '?') && strcmp (url, base) != 0)
115                 return;
116
117         slash = strrchr (url, '/');
118         if (slash && !slash[1])
119                 url_to_get = g_strdup_printf ("%sindex.html", url);
120         else
121                 url_to_get = g_strdup (url);
122
123         if (g_hash_table_lookup (fetched_urls, url_to_get))
124                 return;
125         g_hash_table_insert (fetched_urls, url_to_get, url_to_get);
126
127         if (recurse) {
128                 /* See if we're already downloading it, and create the
129                  * file if not.
130                  */
131
132                 name = url_to_get + strlen (base);
133                 if (*name == '/')
134                         name++;
135                 if (access (name, F_OK) == 0)
136                         return;
137
138                 mkdirs (name);
139                 fd = open (name, O_WRONLY | O_CREAT | O_TRUNC, 0644);
140                 close (fd);
141         }
142
143         msg = soup_message_new (method, url_to_get);
144         soup_message_set_flags (msg, SOUP_MESSAGE_NO_REDIRECT);
145
146         soup_session_send_message (session, msg);
147
148         name = soup_message_get_uri (msg)->path;
149         if (strncmp (base_uri->path, name, strlen (base_uri->path)) != 0) {
150                 fprintf (stderr, "  Error: not under %s\n", base_uri->path);
151                 return;
152         }
153
154         if (debug) {
155                 SoupMessageHeadersIter iter;
156                 const char *name, *value;
157                 char *path = soup_uri_to_string (soup_message_get_uri (msg), TRUE);
158
159                 printf ("%s %s HTTP/1.%d\n\n", method, path,
160                         soup_message_get_http_version (msg));
161                 printf ("HTTP/1.%d %d %s\n",
162                         soup_message_get_http_version (msg),
163                         msg->status_code, msg->reason_phrase);
164
165                 soup_message_headers_iter_init (&iter, msg->response_headers);
166                 while (soup_message_headers_iter_next (&iter, &name, &value))
167                         printf ("%s: %s\r\n", name, value);
168                 printf ("\n");
169         } else
170                 printf ("%s: %d %s\n", name, msg->status_code, msg->reason_phrase);
171
172         name += strlen (base_uri->path);
173         if (*name == '/')
174                 name++;
175
176         if (SOUP_STATUS_IS_REDIRECTION (msg->status_code)) {
177                 if (recurse)
178                         unlink (name);
179                 header = soup_message_headers_get (msg->response_headers, "Location");
180                 if (header) {
181                         if (!debug)
182                                 printf ("  -> %s\n", header);
183                         get_url (header);
184                 }
185                 return;
186         }
187
188         if (!SOUP_STATUS_IS_SUCCESSFUL (msg->status_code))
189                 return;
190
191         if (recurse)
192                 fd = open (name, O_WRONLY | O_CREAT | O_TRUNC, 0644);
193         else
194                 fd = STDOUT_FILENO;
195         write (fd, msg->response_body->data, msg->response_body->length);
196         if (!recurse)
197                 return;
198         close (fd);
199
200         header = soup_message_headers_get (msg->response_headers, "Content-Type");
201         if (header && g_ascii_strncasecmp (header, "text/html", 9) != 0)
202                 return;
203
204         uri = soup_uri_new (url);
205         hrefs = find_hrefs (uri, msg->response_body->data, msg->response_body->length);
206         soup_uri_free (uri);
207         for (i = 0; i < hrefs->len; i++) {
208                 get_url (hrefs->pdata[i]);
209                 g_free (hrefs->pdata[i]);
210         }
211         g_ptr_array_free (hrefs, TRUE);
212 }
213
214 static void
215 usage (void)
216 {
217         fprintf (stderr, "Usage: get [-c CAfile] [-p proxy URL] [-r] [-h] [-d] URL\n");
218         exit (1);
219 }
220
221 int
222 main (int argc, char **argv)
223 {
224         const char *cafile = NULL;
225         SoupURI *proxy = NULL;
226         gboolean synchronous = FALSE;
227         int opt;
228
229         g_type_init ();
230         g_thread_init (NULL);
231
232         method = SOUP_METHOD_GET;
233
234         while ((opt = getopt (argc, argv, "c:dhp:rs")) != -1) {
235                 switch (opt) {
236                 case 'c':
237                         cafile = optarg;
238                         break;
239
240                 case 'd':
241                         debug = TRUE;
242                         break;
243
244                 case 'h':
245                         method = SOUP_METHOD_HEAD;
246                         debug = TRUE;
247                         break;
248
249                 case 'p':
250                         proxy = soup_uri_new (optarg);
251                         if (!proxy) {
252                                 fprintf (stderr, "Could not parse %s as URI\n",
253                                          optarg);
254                                 exit (1);
255                         }
256                         break;
257
258                 case 'r':
259                         recurse = TRUE;
260                         break;
261
262                 case 's':
263                         synchronous = TRUE;
264                         break;
265
266                 case '?':
267                         usage ();
268                         break;
269                 }
270         }
271         argc -= optind;
272         argv += optind;
273
274         if (argc != 1)
275                 usage ();
276         base = argv[0];
277         base_uri = soup_uri_new (base);
278         if (!base_uri) {
279                 fprintf (stderr, "Could not parse '%s' as a URL\n", base);
280                 exit (1);
281         }
282
283         fetched_urls = g_hash_table_new (g_str_hash, g_str_equal);
284
285         if (synchronous) {
286                 session = soup_session_sync_new_with_options (
287                         SOUP_SESSION_SSL_CA_FILE, cafile,
288                         SOUP_SESSION_PROXY_URI, proxy,
289                         SOUP_SESSION_USER_AGENT, "get ",
290                         NULL);
291         } else {
292                 session = soup_session_async_new_with_options (
293                         SOUP_SESSION_SSL_CA_FILE, cafile,
294                         SOUP_SESSION_PROXY_URI, proxy,
295                         SOUP_SESSION_USER_AGENT, "get ",
296                         NULL);
297         }
298
299         if (recurse) {
300                 char *outdir;
301
302                 outdir = g_strdup_printf ("%lu", (unsigned long)getpid ());
303                 if (mkdir (outdir, 0755) != 0) {
304                         fprintf (stderr, "Could not make output directory\n");
305                         exit (1);
306                 }
307                 printf ("Output directory is '%s'\n", outdir);
308                 chdir (outdir);
309                 g_free (outdir);
310         }
311
312         if (!synchronous)
313                 loop = g_main_loop_new (NULL, TRUE);
314
315         get_url (base);
316
317         if (!synchronous)
318                 g_main_loop_unref (loop);
319
320         soup_uri_free (base_uri);
321
322         return 0;
323 }