New. An interface for objects that want to act on every message passing
[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 gboolean recurse = FALSE;
18 SoupSession *session;
19 GMainLoop *loop;
20 char *base;
21 SoupUri *base_uri;
22 int pending;
23
24 static GPtrArray *
25 find_hrefs (const SoupUri *base, const char *body, int length)
26 {
27         GPtrArray *hrefs = g_ptr_array_new ();
28         char *buf = g_strndup (body, length);
29         char *start = buf, *end;
30         char *href, *frag;
31         SoupUri *uri;
32
33         while ((start = strstr (start, "href"))) {
34                 start += 4;
35                 while (isspace ((unsigned char) *start))
36                         start++;
37                 if (*start++ != '=') 
38                         continue;
39                 while (isspace ((unsigned char) *start))
40                         start++;
41                 if (*start++ != '"')
42                         continue;
43
44                 end = strchr (start, '"');
45                 if (!end)
46                         break;
47
48                 href = g_strndup (start, end - start);
49                 start = end;
50                 frag = strchr (href, '#');
51                 if (frag)
52                         *frag = '\0';
53
54                 uri = soup_uri_new_with_base (base, href);
55                 g_free (href);
56
57                 if (!uri)
58                         continue;
59                 if (base->protocol != uri->protocol ||
60                     base->port != uri->port ||
61                     g_strcasecmp (base->host, uri->host) != 0) {
62                         soup_uri_free (uri);
63                         continue;
64                 }
65
66                 if (strncmp (base->path, uri->path, strlen (base->path)) != 0) {
67                         soup_uri_free (uri);
68                         continue;
69                 }
70
71                 g_ptr_array_add (hrefs, soup_uri_to_string (uri, FALSE));
72                 soup_uri_free (uri);
73         }
74         g_free (buf);
75
76         return hrefs;
77 }
78
79 static void
80 mkdirs (const char *path)
81 {
82         char *slash;
83
84         for (slash = strchr (path, '/'); slash; slash = strchr (slash + 1, '/')) {
85                 *slash = '\0';
86                 if (*path && mkdir (path, 0755) == -1 && errno != EEXIST) {
87                         fprintf (stderr, "Could not create '%s'\n", path);
88                         g_main_loop_quit (loop);
89                         return;
90                 }
91                 *slash = '/';
92         }
93 }
94
95 static void get_url (const char *url);
96
97 static void
98 got_url (SoupMessage *msg, gpointer uri)
99 {
100         char *name;
101         int fd, i;
102         GPtrArray *hrefs;
103         const char *header;
104
105         name = soup_message_get_uri (msg)->path;
106         if (strncmp (base_uri->path, name, strlen (base_uri->path)) != 0) {
107                 fprintf (stderr, "  Error: not under %s\n", base_uri->path);
108                 goto DONE;
109         }
110         printf ("%s: %d %s\n", name, msg->status_code, msg->reason_phrase);
111
112         name += strlen (base_uri->path);
113         if (*name == '/')
114                 name++;
115
116         if (SOUP_STATUS_IS_REDIRECTION (msg->status_code)) {
117                 unlink (name);
118                 header = soup_message_get_header (msg->response_headers, "Location");
119                 if (header) {
120                         printf ("  -> %s\n", header);
121                         get_url (header);
122                 }
123                 goto DONE;
124         }
125
126         if (!SOUP_STATUS_IS_SUCCESSFUL (msg->status_code))
127                 goto DONE;
128
129         if (recurse)
130                 fd = open (name, O_WRONLY | O_CREAT | O_TRUNC, 0644);
131         else
132                 fd = STDOUT_FILENO;
133         write (fd, msg->response.body, msg->response.length);
134         if (!recurse)
135                 goto DONE;
136         close (fd);
137
138         header = soup_message_get_header (msg->response_headers, "Content-Type");
139         if (header && g_strncasecmp (header, "text/html", 9) != 0)
140                 goto DONE;
141
142         hrefs = find_hrefs (uri, msg->response.body, msg->response.length);
143         for (i = 0; i < hrefs->len; i++) {
144                 get_url (hrefs->pdata[i]);
145                 g_free (hrefs->pdata[i]);
146         }
147         g_ptr_array_free (hrefs, TRUE);
148
149  DONE:
150         soup_uri_free (uri);
151         if (!--pending)
152                 g_main_quit (loop);
153 }
154
155 static void
156 get_url (const char *url)
157 {
158         char *url_to_get, *slash, *name;
159         SoupMessage *msg;
160         int fd;
161
162         if (strncmp (url, base, strlen (base)) != 0)
163                 return;
164
165         slash = strrchr (url, '/');
166         if (slash && !slash[1])
167                 url_to_get = g_strdup_printf ("%sindex.html", url);
168         else
169                 url_to_get = g_strdup (url);
170
171         if (recurse) {
172                 /* See if we're already downloading it, and create the
173                  * file if not.
174                  */
175
176                 name = url_to_get + strlen (base);
177                 if (*name == '/')
178                         name++;
179                 if (access (name, F_OK) == 0) {
180                         g_free (url_to_get);
181                         return;
182                 }
183
184                 mkdirs (name);
185                 fd = open (name, O_WRONLY | O_CREAT | O_TRUNC, 0644);
186                 close (fd);
187         }
188
189         msg = soup_message_new (SOUP_METHOD_GET, url_to_get);
190         soup_message_set_flags (msg, SOUP_MESSAGE_NO_REDIRECT);
191
192         pending++;
193         soup_session_queue_message (session, msg, got_url, soup_uri_new (url));
194         g_free (url_to_get);
195 }
196
197 static void
198 usage (void)
199 {
200         fprintf (stderr, "Usage: get [-c CAfile] [-r] URL\n");
201         exit (1);
202 }
203
204 int
205 main (int argc, char **argv)
206 {
207         const char *cafile = NULL;
208         SoupUri *proxy = NULL;
209         int opt;
210
211         g_type_init ();
212         g_thread_init (NULL);
213
214         while ((opt = getopt (argc, argv, "c:p:r")) != -1) {
215                 switch (opt) {
216                 case 'c':
217                         cafile = optarg;
218                         break;
219
220                 case 'p':
221                         proxy = soup_uri_new (optarg);
222                         if (!proxy) {
223                                 fprintf (stderr, "Could not parse %s as URI\n",
224                                          optarg);
225                                 exit (1);
226                         }
227                         break;
228
229                 case 'r':
230                         recurse = TRUE;
231                         break;
232
233                 case '?':
234                         usage ();
235                         break;
236                 }
237         }
238         argc -= optind;
239         argv += optind;
240
241         if (argc != 1)
242                 usage ();
243         base = argv[0];
244         base_uri = soup_uri_new (base);
245         if (!base_uri) {
246                 fprintf (stderr, "Could not parse '%s' as a URL\n", base);
247                 exit (1);
248         }
249
250         session = soup_session_async_new_with_options (
251                 SOUP_SESSION_SSL_CA_FILE, cafile,
252                 SOUP_SESSION_PROXY_URI, proxy,
253                 NULL);
254
255         if (recurse) {
256                 char *outdir;
257
258                 outdir = g_strdup_printf ("%lu", (unsigned long)getpid ());
259                 if (mkdir (outdir, 0755) != 0) {
260                         fprintf (stderr, "Could not make output directory\n");
261                         exit (1);
262                 }
263                 printf ("Output directory is '%s'\n", outdir);
264                 chdir (outdir);
265                 g_free (outdir);
266         }
267
268         get_url (base);
269
270         loop = g_main_loop_new (NULL, TRUE);
271         g_main_run (loop);
272         g_main_loop_unref (loop);
273
274         soup_uri_free (base_uri);
275
276         return 0;
277 }