Skip to content
Fetching contributors…
Cannot retrieve contributors at this time
483 lines (387 sloc) 10.1 KB
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/* Cherokee
*
* Authors:
* Alvaro Lopez Ortega <alvaro@alobbs.com>
*
* Copyright (C) 2001-2011 Alvaro Lopez Ortega
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2 of the GNU General Public
* License as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
#include "common-internal.h"
#ifdef HAVE_SYS_TYPES_H
# include <sys/types.h>
#endif
#ifdef HAVE_SYS_STAT_H
# include <sys/stat.h>
#endif
#ifdef HAVE_FCNTL_H
# include <fcntl.h>
#endif
#ifdef HAVE_TIME_H
# include <time.h>
#endif
#ifdef HAVE_GETOPT_LONG
# include <getopt.h>
#else
# include "getopt/getopt.h"
#endif
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <strings.h>
#include "init.h"
#include "util.h"
#include "url.h"
#include "header.h"
#include "fdpoll.h"
#include "request.h"
#include "downloader.h"
#include "downloader-protected.h"
#include "socket.h"
#include "header-protected.h" /* FIXME! */
#include "proxy.h"
#define EXIT_OK 0
#define EXIT_ERROR 1
#define POLL_TIME 1000
#define UNSET_FD -1
#define COLUM_NUM 20
#define COLUM_SEP ":"
#define ENTRIES "cget"
/* Globals..
*/
static int output_fd = UNSET_FD;
static int global_fd = UNSET_FD;
static cherokee_boolean_t quiet = false;
static cherokee_boolean_t save_headers = false;
static void
print_help (void)
{
printf ("Cherokee Downloader %s\n"
"Usage: cget [options] URL\n\n"
"Mandatory arguments to long options are mandatory for short options too.\n\n"
"Startup:\n"
" -V, --version Print version and exit\n"
" -h, --help Print this help\n"
"\n"
"Logging and input file:\n"
" -q, --quiet Quiet (no output)\n"
"\n"
"Download:\n"
" -O --output-document=FILE Write documents to FILE\n"
"\n"
"HTTP options:\n"
" -s, --save-headers Save the HTTP headers to file\n"
" --header=STRING insert STRING among the headers\n"
"\n"
"Report bugs to alvaro@alobbs.com\n", PACKAGE_VERSION);
}
static void
print_usage (void)
{
printf ("Cherokee Downloader %s\n"
"Usage: cget [options] URL\n\n"
"Try `cget --help' for more options.\n", PACKAGE_VERSION);
}
static void
print_tuple_str (const char *title, const char *info)
{
int whites;
char *tmp;
if (quiet == true)
return;
whites = COLUM_NUM - strlen(title);
fprintf (stderr, "%s ", title);
while (whites-- > 0) {
fprintf (stderr, " ");
}
fprintf (stderr, COLUM_SEP " %s\n", info);
}
static void
print_tuple_int (const char *title, int num)
{
char tmp[128];
snprintf (tmp, 128, "%d", num);
print_tuple_str (title, tmp);
}
static ret_t
do_download__init (cherokee_downloader_t *downloader, void *param)
{
cherokee_url_t *url;
UNUSED(param);
url = &downloader->request.url;
print_tuple_str ("Host", url->host.buf);
print_tuple_str ("Request", url->request.buf);
print_tuple_int ("Port", url->port);
return ret_ok;
}
static ret_t
do_download__has_headers (cherokee_downloader_t *downloader, void *param)
{
cherokee_url_t *url;
cherokee_buffer_t *req;
cherokee_header_t *hdr;
UNUSED(param);
url = &downloader->request.url;
req = &url->request;
hdr = downloader->header;
TRACE(ENTRIES, "quiet=%d http_code=%d\n", quiet, hdr->response);
/* Check the response
*/
if (quiet == false) {
cherokee_buffer_t tmp = CHEROKEE_BUF_INIT;
cherokee_http_code_copy (HDR_RESPONSE(hdr), &tmp);
print_tuple_str ("Response", tmp.buf);
cherokee_buffer_mrproper (&tmp);
}
/* Open a new file if needed
*/
if (global_fd == UNSET_FD) {
char *name;
name = strrchr (req->buf, '/');
if (name == NULL) {
name = "index.html";
}
output_fd = open (name, O_WRONLY, O_CREAT);
if (output_fd < 0) {
return ret_error;
}
} else {
output_fd = global_fd;
}
/* Save the headers?
*/
if (save_headers == true) {
ssize_t written;
uint32_t len;
cherokee_header_get_length (hdr, &len);
written = write (output_fd, hdr->input_buffer->buf, len);
if (written < 0) {
PRINT_MSG_S ("ERROR: Can not write to output file\n");
return ret_error;
}
}
return ret_ok;
}
static ret_t
do_download__read_body (cherokee_downloader_t *downloader, void *param)
{
ret_t ret;
ssize_t len;
cherokee_buffer_t tmp = CHEROKEE_BUF_INIT;
UNUSED(param);
/* Write down
*/
len = write (output_fd, downloader->body.buf, downloader->body.len);
if (len > 0) {
ret = cherokee_buffer_move_to_begin (&downloader->body, len);
if (ret != ret_ok) return ret;
}
/* Print info
*/
cherokee_buffer_add_fsize (&tmp, downloader->content_length);
cherokee_buffer_add_str (&tmp, " of ");
cherokee_buffer_add_fsize (&tmp, downloader->info.body_recv);
if (! quiet) {
fprintf (stderr, "\rDownloading: %s", tmp.buf);
fflush(stderr);
}
cherokee_buffer_mrproper (&tmp);
return ret_ok;
}
static ret_t
do_download__finish (cherokee_downloader_t *downloader, void *param)
{
UNUSED (downloader);
UNUSED (param);
fprintf (stderr, "\n");
return ret_ok;
}
static ret_t
do_download (cherokee_downloader_t *downloader)
{
ret_t ret;
cherokee_downloader_status_t status;
cherokee_boolean_t got_headers = false;
cherokee_boolean_t reading = false;
do_download__init(downloader,NULL);
for (;;) {
/* Do some real work
*/
ret = cherokee_downloader_step (downloader, NULL, NULL);
cherokee_downloader_get_status(downloader, &status);
TRACE(ENTRIES, "ret=%d status=%d\n", ret, status);
switch (ret) {
case ret_ok:
if ( !reading && (status & downloader_status_post_sent)) {
reading = true;
}
if ( (status & downloader_status_headers_received) && !got_headers) {
do_download__has_headers (downloader, NULL);
got_headers = true;
}
if (status & downloader_status_data_available) {
do_download__read_body (downloader, NULL);
}
if (status & downloader_status_finished) {
do_download__finish (downloader, NULL);
}
break;
case ret_eagain:
/* It's going on..
*/
break;
case ret_eof_have_data:
if ((status & downloader_status_headers_received) && !got_headers) {
do_download__has_headers (downloader, NULL);
got_headers = true;
}
if (status & downloader_status_data_available) {
do_download__read_body (downloader, NULL);
}
/* fall down */
case ret_eof:
if (status & downloader_status_finished) {
do_download__finish (downloader, NULL);
}
/* fall down */
case ret_error:
/* Finished or critical error
*/
return ret;
default:
SHOULDNT_HAPPEN;
return ret_error;
}
}
return ret_ok;
}
int
main (int argc, char **argv)
{
int re;
ret_t ret;
cint_t val;
cint_t param_num;
cint_t long_index;
cherokee_downloader_t *downloader;
cherokee_buffer_t proxy = CHEROKEE_BUF_INIT;
cuint_t proxy_port;
struct option long_options[] = {
/* Options without arguments */
{"help", no_argument, NULL, 'h'},
{"version", no_argument, NULL, 'V'},
{"quiet", no_argument, NULL, 'q'},
{"save-headers", no_argument, NULL, 's'},
{"header", required_argument, NULL, 0 },
{NULL, 0, NULL, 0}
};
/* Parse known parameters
*/
while ((val = getopt_long (argc, argv, "VshqO:", long_options, &long_index)) != -1) {
switch (val) {
case 'V':
printf ("Cherokee Downloader %s\n"
"Written by Alvaro Lopez Ortega <alvaro@alobbs.com>\n\n"
"Copyright (C) 2001-2011 Alvaro Lopez Ortega.\n"
"This is free software; see the source for copying conditions. There is NO\n"
"warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n",
PACKAGE_VERSION);
return EXIT_OK;
case 'O':
if (global_fd != UNSET_FD) {
close (global_fd);
}
if ((strlen(optarg) == 1) && (optarg[0] == '-')) {
global_fd = fileno(stdout);
} else {
global_fd = open (optarg, O_WRONLY | O_CREAT, 0644);
}
if (global_fd < 0) {
PRINT_MSG ("ERROR: Can not open %s\n", optarg);
return EXIT_ERROR;
}
break;
case 0:
break;
case 'q':
quiet = true;
break;
case 's':
save_headers = true;
break;
case 'h':
case '?':
default:
print_help();
return EXIT_OK;
}
}
/* The rest..
*/
param_num = argc - optind;
if (param_num <= 0) {
print_usage();
return EXIT_OK;
}
/* Tracing and proxy discovering..
*/
cherokee_init();
cget_find_proxy (&proxy, &proxy_port);
for (val=optind; val<optind+param_num; val++) {
cherokee_buffer_t url = CHEROKEE_BUF_INIT;
/* Build the url buffer
*/
ret = cherokee_buffer_add_va (&url, "%s", argv[val]);
if (ret != ret_ok)
exit (EXIT_ERROR);
/* Create the downloader object..
*/
ret = cherokee_downloader_new (&downloader);
if (ret != ret_ok)
exit (EXIT_ERROR);
ret = cherokee_downloader_init(downloader);
if (ret != ret_ok)
exit (EXIT_ERROR);
if (! cherokee_buffer_is_empty (&proxy)) {
ret = cherokee_downloader_set_proxy (downloader, &proxy, proxy_port);
if (ret != ret_ok)
exit (EXIT_ERROR);
}
ret = cherokee_downloader_set_url (downloader, &url);
if (ret != ret_ok)
exit (EXIT_ERROR);
ret = cherokee_downloader_connect (downloader);
if (ret != ret_ok)
exit (EXIT_ERROR);
/* Download it!
*/
ret = do_download (downloader);
if ((ret != ret_ok) && (ret != ret_eof)) {
exit (EXIT_ERROR);
}
/* Free the objects..
*/
cherokee_buffer_mrproper (&url);
cherokee_downloader_free (downloader);
}
/* Close the output file
*/
re = close (output_fd);
if (re != 0)
exit (EXIT_ERROR);
cherokee_mrproper();
return EXIT_OK;
}
Something went wrong with that request. Please try again.