root/cherokee/trunk/cget/main.c

Revision 2157, 10.2 kB (checked in by alo, 2 months ago)

--

Line 
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2
3 /* Cherokee
4  *
5  * Authors:
6  *      Alvaro Lopez Ortega <alvaro@alobbs.com>
7  *
8  * Copyright (C) 2001-2008 Alvaro Lopez Ortega
9  *
10  * This program is free software; you can redistribute it and/or
11  * modify it under the terms of version 2 of the GNU General Public
12  * License as published by the Free Software Foundation.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
22  * USA
23  */
24
25 #include "common-internal.h"
26
27 #ifdef HAVE_SYS_TYPES_H
28 # include <sys/types.h>
29 #endif
30
31 #ifdef HAVE_SYS_STAT_H
32 # include <sys/stat.h>
33 #endif
34
35 #ifdef HAVE_FCNTL_H
36 # include <fcntl.h>
37 #endif
38
39 #ifdef HAVE_TIME_H
40 # include <time.h>
41 #endif
42
43 #ifdef HAVE_GETOPT_LONG
44 # include <getopt.h>
45 #else
46 # include "getopt/getopt.h"
47 #endif
48
49 #include <stdio.h>
50 #include <stdlib.h>
51 #include <unistd.h>
52 #include <strings.h>
53
54 #include "init.h"
55 #include "util.h"
56 #include "url.h"
57 #include "header.h"
58 #include "fdpoll.h"
59 #include "request.h"
60 #include "downloader.h"
61 #include "downloader-protected.h"
62 #include "socket.h"
63 #include "header-protected.h"      /* FIXME! */
64
65 #include "proxy.h"
66
67 #define EXIT_OK    0
68 #define EXIT_ERROR 1
69 #define POLL_TIME  1000
70 #define UNSET_FD   -1
71 #define COLUM_NUM  20
72 #define COLUM_SEP  ":"
73 #define ENTRIES    "cget"
74
75
76 /* Globals..
77  */
78 static int                output_fd    = UNSET_FD;
79 static int                global_fd    = UNSET_FD;
80 static cherokee_boolean_t quiet        = false;
81 static cherokee_boolean_t save_headers = false;
82
83
84 static void
85 print_help (void)
86 {
87         printf ("Cherokee Downloader %s\n"
88                 "Usage: cget [options] URL\n\n"
89                 "Mandatory arguments to long options are mandatory for short options too.\n\n"
90                 "Startup:\n"
91                 "  -V,  --version                Print version and exit\n"
92                 "  -h,  --help                   Print this help\n"
93                 "\n"
94                 "Logging and input file:\n"
95                 "  -q,  --quiet                  Quiet (no output)\n"
96                 "\n"
97                 "Download:\n"
98                 "  -O   --output-document=FILE   Write documents to FILE\n"
99                 "\n"
100                 "HTTP options:\n"
101                 "  -s,  --save-headers           Save the HTTP headers to file\n"
102                 "       --header=STRING          insert STRING among the headers\n"
103                 "\n"
104                 "Report bugs to alvaro@gnu.org\n", PACKAGE_VERSION);
105 }
106
107
108 static void
109 print_usage (void)
110 {
111         printf ("Cherokee Downloader %s\n"
112                 "Usage: cget [options] URL\n\n"
113                 "Try `cget --help' for more options.\n", PACKAGE_VERSION);
114 }
115
116
117 static void
118 print_tuple_str (const char *title, const char *info)
119 {
120         int   whites;
121         char *tmp;
122
123         if (quiet == true)
124                 return;
125        
126         whites = COLUM_NUM - strlen(title);
127
128         fprintf (stderr, "%s ", title);
129
130         if (whites > 0) {
131                 tmp = (char *) malloc (whites +1);
132                 memset (tmp, ' ', whites);
133                 tmp[whites] = '\0';
134                 fprintf (stderr, "%s", tmp);
135                 free (tmp);
136         }
137
138         fprintf (stderr, COLUM_SEP " %s\n", info);
139 }
140
141
142 static void
143 print_tuple_int (const char *title, int num)
144 {
145         char tmp[128];
146        
147         snprintf (tmp, 128, "%d", num);
148         print_tuple_str (title, tmp);
149 }
150
151
152 static ret_t
153 do_download__init (cherokee_downloader_t *downloader, void *param)
154 {
155         cherokee_url_t *url;
156
157         UNUSED(param);
158
159         url = &downloader->request.url;
160        
161         print_tuple_str ("Host",    url->host.buf);
162         print_tuple_str ("Request", url->request.buf);
163         print_tuple_int ("Port",    url->port);
164
165         return ret_ok;
166 }
167
168
169 static ret_t
170 do_download__has_headers (cherokee_downloader_t *downloader, void *param)
171 {
172         cherokee_url_t    *url;
173         cherokee_buffer_t *req;
174         cherokee_header_t *hdr;
175
176         UNUSED(param);
177
178         url = &downloader->request.url;
179         req = &url->request;
180         hdr = downloader->header;
181
182         TRACE(ENTRIES, "quiet=%d http_code=%d\n", quiet, hdr->response);
183
184         /* Check the response
185          */
186         if (quiet == false) {
187                 cherokee_buffer_t tmp = CHEROKEE_BUF_INIT;
188
189                 cherokee_http_code_copy (HDR_RESPONSE(hdr), &tmp);
190                 print_tuple_str ("Response", tmp.buf);
191                 cherokee_buffer_mrproper (&tmp);
192         }
193
194         /* Open a new file if needed
195          */
196         if (global_fd == UNSET_FD) {
197                 char *name;
198                
199                 name = strrchr (req->buf, '/');
200                 if (name == NULL) {
201                         name = "index.html";
202                 }
203
204                 output_fd = open (name, O_WRONLY, O_CREAT);
205                 if (output_fd < 0) {
206                         return ret_error;
207                 }
208
209         } else {
210                 output_fd = global_fd;
211         }
212
213         /* Save the headers?
214          */
215         if (save_headers == true) {
216                 ssize_t  written;
217                 uint32_t len;
218
219                 cherokee_header_get_length (hdr, &len);
220                 written = write (output_fd, hdr->input_buffer->buf, len);
221                 if (written < 0) {
222                         PRINT_ERROR_S ("Can not write to output file\n");
223                         return ret_error;
224                 }
225         }
226
227         return ret_ok;
228 }
229
230
231 static ret_t
232 do_download__read_body (cherokee_downloader_t *downloader, void *param)
233 {
234         ret_t             ret;
235         ssize_t           len;
236         cherokee_buffer_t tmp = CHEROKEE_BUF_INIT;
237
238         UNUSED(param);
239
240         /* Write down
241          */
242         len = write (output_fd, downloader->body.buf, downloader->body.len);
243         if (len > 0) {
244                 ret = cherokee_buffer_move_to_begin (&downloader->body, len);
245                 if (ret != ret_ok) return ret;
246         }
247
248         /* Print info
249          */
250         cherokee_buffer_add_fsize (&tmp, downloader->content_length);
251         cherokee_buffer_add_str   (&tmp, " of ");
252         cherokee_buffer_add_fsize (&tmp, downloader->info.body_recv);
253
254         if (! quiet) {
255                 fprintf (stderr, "\rDownloading: %s", tmp.buf);
256                 fflush(stderr);
257         }
258
259         cherokee_buffer_mrproper (&tmp);
260         return ret_ok; 
261 }
262
263
264 static ret_t
265 do_download__finish (cherokee_downloader_t *downloader, void *param)
266 {
267         UNUSED (downloader);
268         UNUSED (param);
269
270         fprintf (stderr, "\n");
271         return ret_ok;
272 }
273
274
275 static ret_t
276 do_download (cherokee_downloader_t *downloader)
277 {
278         ret_t                        ret;
279         cherokee_downloader_status_t status;
280         cherokee_boolean_t           got_headers = false;
281         cherokee_boolean_t           reading     = false;
282
283         do_download__init(downloader,NULL);
284
285         for (;;) {
286                 /* Do some real work
287                  */
288                 ret = cherokee_downloader_step (downloader, NULL, NULL);
289
290                 cherokee_downloader_get_status(downloader, &status);
291                 TRACE(ENTRIES, "ret=%d status=%d\n", ret, status);
292
293                 switch (ret) {
294                 case ret_ok:
295                         if ( !reading && (status & downloader_status_post_sent)) {
296                                 reading = true;
297                         }
298                        
299                         if ( (status & downloader_status_headers_received) && !got_headers) {
300                                 do_download__has_headers (downloader, NULL);
301                                 got_headers = true;
302                         }
303
304                         if (status & downloader_status_data_available) {
305                                 do_download__read_body (downloader, NULL);
306                         }
307
308                         if (status & downloader_status_finished) {
309                                 do_download__finish (downloader, NULL);
310                         }
311                         break;
312                        
313                 case ret_eagain:
314                         /* It's going on..
315                          */
316                         break;
317                        
318                 case ret_eof_have_data:
319                         if ((status & downloader_status_headers_received) && !got_headers) {
320                                 do_download__has_headers (downloader, NULL);
321                                 got_headers = true;                             
322                         }
323                         if (status & downloader_status_data_available) {
324                                 do_download__read_body (downloader, NULL);
325                         }
326                         /* fall down */
327
328                 case ret_eof:
329                         if (status & downloader_status_finished) {
330                                 do_download__finish (downloader, NULL);
331                         }
332                         /* fall down */
333
334                 case ret_error:
335                         /* Finished or critical error
336                          */
337                         return ret;
338                        
339                 default:
340                         SHOULDNT_HAPPEN;
341                         return ret_error;
342                 }
343         }
344
345         return ret_ok;
346 }
347
348
349 int
350 main (int argc, char **argv)
351 {
352         int                    re;
353         ret_t                  ret;
354         cint_t                 val;
355         cint_t                 param_num;
356         cint_t                 long_index;
357         cherokee_downloader_t *downloader;
358         cherokee_buffer_t      proxy       = CHEROKEE_BUF_INIT;
359         cuint_t                proxy_port;
360
361         struct option long_options[] = {
362                 /* Options without arguments */
363                 {"help",          no_argument,       NULL, 'h'},
364                 {"version",       no_argument,       NULL, 'V'},
365                 {"quiet",         no_argument,       NULL, 'q'},
366                 {"save-headers",  no_argument,       NULL, 's'},
367                 {"header",        required_argument, NULL,  0 },
368                 {NULL, 0, NULL, 0}
369         };
370
371         /* Parse known parameters
372          */
373         while ((val = getopt_long (argc, argv, "VshqO:", long_options, &long_index)) != -1) {
374                 switch (val) {
375                 case 'V':
376                         printf ("Cherokee Downloader %s\n"
377                                 "Written by Alvaro Lopez Ortega <alvaro@gnu.org>\n\n"
378                                 "Copyright (C) 2001-2008 Alvaro Lopez Ortega.\n"
379                                 "This is free software; see the source for copying conditions.  There is NO\n"
380                                 "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n",
381                                 PACKAGE_VERSION);
382                         return EXIT_OK;
383
384                 case 'O':
385                         if (! strncmp (optarg, "-", 1)) {
386                                 global_fd = fileno(stdout);
387                         } else {
388                                 global_fd = open (optarg, O_WRONLY | O_CREAT, 0644);
389                                 if (global_fd < 0) {
390                                         PRINT_ERROR ("ERROR: Can not open %s\n", optarg);
391                                         return EXIT_ERROR;
392                                 }
393                         }
394                         break;
395
396                 case 0:
397                         break;
398                        
399                 case 'q':
400                         quiet = true;
401                         break;
402
403                 case 's':
404                         save_headers = true;
405                         break;
406
407                 case 'h':
408                 case '?':
409                 default:
410                         print_help();
411                         return EXIT_OK;
412                 }
413         }
414
415         /* The rest..
416          */
417         param_num = argc - optind;
418        
419         if (param_num <= 0) {
420                 print_usage();
421                 return EXIT_OK;
422         }
423
424         /* Tracing and proxy discovering..
425          */
426         cherokee_init();
427         cget_find_proxy (&proxy, &proxy_port);
428
429         for (val=optind; val<optind+param_num; val++) {
430                 cherokee_buffer_t url = CHEROKEE_BUF_INIT;
431                
432                 /* Build the url buffer
433                  */
434                 ret = cherokee_buffer_add_va (&url, "%s", argv[val]);
435                 if (ret != ret_ok)
436                         exit (EXIT_ERROR);
437
438                 /* Create the downloader object..
439                  */
440                 ret = cherokee_downloader_new (&downloader);
441                 if (ret != ret_ok)
442                         exit (EXIT_ERROR);
443
444                 ret = cherokee_downloader_init(downloader);
445                 if (ret != ret_ok)
446                         exit (EXIT_ERROR);
447
448                 if (! cherokee_buffer_is_empty (&proxy)) {
449                         ret = cherokee_downloader_set_proxy (downloader, &proxy, proxy_port);
450                         if (ret != ret_ok)
451                                 exit (EXIT_ERROR);
452                 }
453
454                 ret = cherokee_downloader_set_url (downloader, &url);
455                 if (ret != ret_ok)
456                         exit (EXIT_ERROR);
457
458                 ret = cherokee_downloader_connect (downloader);
459                 if (ret != ret_ok)
460                         exit (EXIT_ERROR);
461
462                 /* Download it!
463                  */
464                 ret = do_download (downloader);
465                 if ((ret != ret_ok) && (ret != ret_eof)) {
466                         exit (EXIT_ERROR);
467                 }
468
469                 /* Free the objects..
470                  */
471                 cherokee_buffer_mrproper (&url);
472                 cherokee_downloader_free (downloader);
473         }
474
475         /* Close the output file
476          */
477         re = close (output_fd);
478         if (re != 0)
479                 exit (EXIT_ERROR);
480
481         cherokee_mrproper();
482         return EXIT_OK;
483 }
Note: See TracBrowser for help on using the browser.