⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 http-retr.c

📁 prozgui是一款Linxu下著名的下载工具
💻 C
字号:
/****************************************************************************** libprozilla - a download accelerator library Copyright (C) 2001 Kalum Somaratna This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA******************************************************************************//* $Id: http-retr.c,v 1.18 2001/09/23 01:39:16 kalum Exp $ */#include "common.h"#include "prozilla.h"#include "connect.h"#include "misc.h"#include "url.h"#include "netrc.h"#include "debug.h"#include "http.h"#include "http-retr.h"/* Will download a portion of/or the full file from the connection->url. */uerr_t proz_http_get_file(connection_t * connection){  uerr_t err;  int remote_port_len;  char *user, *passwd, *www_auth = NULL, *proxy_auth = NULL, *range =      NULL, *location = NULL, *referer = NULL, *pragma_no_cache = NULL;  char *request, *remote_port;  netrc_entry *netrc_ent;  char buffer[HTTP_BUFFER_SIZE];  /*The http stats that were returned after the call with GET */  http_stat_t hs_after_get;  /* we want it to terminate immediately */  pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);  assert(connection->localfile != NULL);  assert(connection->file_mode != NULL);  /*clear the socks */  connection->data_sock = 0;  memset(&hs_after_get, 0, sizeof(hs_after_get));  /* if there is nothing to download then return  */  if (connection->status == COMPLETED)  {    pthread_mutex_lock(&connection->access_mutex);    gettimeofday(&connection->time_begin, NULL);    pthread_mutex_unlock(&connection->access_mutex);    return HOK;  }  connection_change_status(connection, CONNECTING);  if (http_use_proxy(connection))  {    connection_show_message(connection, _("Connecting to %s"),			    connection->http_proxy->proxy_url.host);    err = connect_to_server(&connection->data_sock,			    connection->http_proxy->proxy_url.host,			    connection->http_proxy->proxy_url.port,			    &connection->xfer_timeout);    if (err != NOCONERROR)    {      proz_debug(_("Error connecting to %s"),		 connection->http_proxy->proxy_url.host);      connection_change_status(connection, REMOTEFATAL);      return err;    }  } else  {    connection_show_message(connection, _("Connecting to %s"),			    connection->u.host);    err = connect_to_server(&connection->data_sock, connection->u.host,			    connection->u.port, &connection->xfer_timeout);    if (err != NOCONERROR)    {      proz_debug(_("Error connecting to %s"), connection->u.host);      connection_change_status(connection, REMOTEFATAL);      return err;    }  }  user = connection->u.user;  passwd = connection->u.passwd;  /* Use .netrc if asked to do so. */  if (connection->use_netrc == TRUE)  {    netrc_ent = search_netrc(libprozrtinfo.netrc_list, connection->u.host);    if (netrc_ent != NULL)    {      user = netrc_ent->account;      passwd = netrc_ent->password;    }  }  user = user ? user : "";  passwd = passwd ? passwd : "";  if (strlen(user) || strlen(passwd))  {    /* Construct the necessary header. */    www_auth = get_basic_auth_str(user, passwd, "Authorization");    proz_debug(_("Authenticating as user %s password %s"), user, passwd);    proz_debug(_("Authentification string=%s"), www_auth);  } else    www_auth = 0;  if (http_use_proxy(connection))  {    if (strlen(connection->http_proxy->username)	|| strlen(connection->http_proxy->passwd))      proxy_auth =	  get_basic_auth_str(connection->http_proxy->username,			     connection->http_proxy->passwd,			     "Proxy-Authorization");  }  if (connection->u.port == 80)  {    remote_port = NULL;    remote_port_len = 0;  } else  {    remote_port = (char *) alloca(64);    remote_port_len = sprintf(remote_port, ":%d", connection->u.port);  }  if (connection->hs.accept_ranges == 1)  {    range = (char *) alloca(18 + 64);    sprintf(range, "Range: bytes=%ld-\r\n", connection->remote_startpos);  }  if (connection->u.referer)  {    referer = (char *) alloca(13 + strlen(connection->u.referer));    sprintf(referer, "Referer: %s\r\n", connection->u.referer);  }  /* If we go through a proxy the request for the URL is different */  if (http_use_proxy(connection))  {    location = (char *) alloca(strlen(connection->u.url) + 1);    strcpy(location, connection->u.url);  } else  {    location = (char *) alloca(strlen(connection->u.path) + 1);    strcpy(location, connection->u.path);  }  /*Use no-cache directive for proxy servers? */  if (http_use_proxy(connection)      && (connection->http_no_cache || connection->attempts > 0))  {    pragma_no_cache = (char *) alloca(21);    sprintf(pragma_no_cache, "Pragma: no-cache\r\n");  }  request = (char *) alloca(strlen(location)			    + strlen(connection->user_agent)			    + strlen(connection->u.host) + remote_port_len			    + (range ? strlen(range) : 0)			    + (referer ? strlen(referer) : 0)			    + (www_auth ? strlen(www_auth) : 0)			    + (proxy_auth ? strlen(proxy_auth) : 0)			    + 64			    +			    (pragma_no_cache ? strlen(pragma_no_cache) :			     0));  /* TODO Add referrer tag. */  sprintf(request,	  "GET %s HTTP/1.0\r\nUser-Agent: %s\r\nHost: %s%s\r\nAccept: */*\r\n%s%s%s%s%s\r\n",	  location, connection->user_agent, connection->u.host,	  remote_port ? remote_port : "", range ? range : "",	  referer ? referer : "",	  www_auth ? www_auth : "", proxy_auth ? proxy_auth : "",	  pragma_no_cache ? pragma_no_cache : "");  proz_debug("HTTP request = %s", request);  connection_show_message(connection, _("Sending HTTP request"));  err = http_fetch_headers(connection, &hs_after_get, request);/* What hapenned ? */  if (err != HOK)  {    /*Check if we authenticated using any user or password and if we        were kicked out, if so return HAUTHFAIL */    if (err == HAUTHREQ && (strlen(user) || strlen(passwd)))      err = HAUTHFAIL;    /*     * a error occured druing the process      */    close_sock(&connection->data_sock);    connection_change_status(connection, REMOTEFATAL);    return err;  }  /*Check for the server lying about it being able to handle ranges */  if (hs_after_get.contlen != -1)  {    if (connection->resume_support == TRUE)    {      if (hs_after_get.contlen !=	  connection->main_file_size - connection->remote_startpos)      {	proz_debug("Error contlen does not match the requested range!");	close_sock(&connection->data_sock);	connection_change_status(connection, REMOTEFATAL);	return CANTRESUME;      }    }  }/* which routine to call */  if (connection->main_file_size == -1)    err =	connection_retr_fsize_not_known(connection, buffer,					sizeof(buffer));  else    err = connection_retr_fsize_known(connection, buffer, sizeof(buffer));  close_sock(&connection->data_sock);  if (err == FILEGETOK)    return HOK;  else    return err;}/* A genuine loop ;) It willed be called by the main thread, and this will handle all possible errors itself, retrying until the number of maximum tries for the  connection is realised*/uerr_t http_loop(connection_t * connection){  boolean retrying_from_loop = FALSE;  assert(connection->max_attempts >= 0);  assert(connection->attempts >= 0);  pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);  do  {    if (connection->attempts > 0)    {      if (retrying_from_loop == TRUE)      {	connection_show_message(connection,				_("Retrying...Attempt %d in %d seconds"),				connection->attempts,				connection->retry_delay.tv_sec);	delay_ms(connection->retry_delay.tv_sec * 1000);      }      if (connection->resume_support == TRUE)      {	if (connection_load_resume_info(connection) == -1)	{	  connection_show_message(connection,				  _				  ("Error while attemting to process download file "));	}      } else      {	/*If we cant resume then reset the connections bytesreceived to 0 */	connection->remote_bytes_received = 0;      }    }    /*Push the handler which will cleanup any sockets that are left open */    pthread_cleanup_push(cleanup_socks, (void *) connection);    connection->err = proz_http_get_file(connection);    /*pop the handler */    pthread_cleanup_pop(0);    connection->attempts++;    /*Should the error be handled at this level ? */    if (!http_loop_handle_error(connection->err))    {      connection_show_message(connection, _("Will be handled in main "));      return connection->err;	/*If not return and the main thread will handle it */    }    switch (connection->err)    {    case HOK:      connection_show_message(connection, _("Successfully got download"));      return connection->err;      break;      /*TODO : What should we do if the file is not found, well pass it up to the main routine */    default:      connection_show_message(connection, proz_strerror(connection->err));      break;    }    retrying_from_loop = TRUE;  }  while ((connection->attempts < connection->max_attempts)	 || connection->max_attempts == 0);  connection_show_message(connection,			  _			  ("I have tried %d attempt(s) and have failed, aborting"),			  connection->attempts);  return connection->err;}/*Return true if it is a error which can be handled within the htp_loop,or false if it should be passed upwards so that the main download thread can restart it when necessary after processing other threads status too */boolean http_loop_handle_error(uerr_t err){  proz_debug("Error encountered in http_loop is %d", err);  if (err == HTTPNSFOD || err == FWRITEERR || err == FOPENERR      || err == CANTRESUME)    return FALSE;  else    return TRUE;}/*  I am writing a seperate function to handle FTP proxying through HTTP, I  MHO whoever thought of using HTTP to proxy FTP is a shithead,   its such a PITA ;) */uerr_t ftp_get_file_from_http_proxy(connection_t * connection){  uerr_t err;  int remote_port_len;  char *user, *passwd, *www_auth = NULL, *proxy_auth = NULL, *range =      NULL, *pragma_no_cache = NULL;  char *request, *remote_port;  netrc_entry *netrc_ent;  char buffer[HTTP_BUFFER_SIZE];  /*The http stats that were returned after the call with GET */  http_stat_t hs_after_get;  /* we want it to terminate immediately */  pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);  memset(&connection->hs, 0, sizeof(connection->hs));  memset(&hs_after_get, 0, sizeof(hs_after_get));  /* if there is nothing to download then return  */  if (connection->status == COMPLETED)  {    pthread_mutex_lock(&connection->access_mutex);    gettimeofday(&connection->time_begin, NULL);    pthread_mutex_unlock(&connection->access_mutex);    return FTPOK;  }  err = connect_to_server(&connection->data_sock,			  connection->ftp_proxy->proxy_url.host,			  connection->ftp_proxy->proxy_url.port,			  &connection->xfer_timeout);  if (err != NOCONERROR)  {    connection_show_message(connection, _("Error connecting to %s"),			    connection->ftp_proxy->proxy_url.host);    return err;  }  user = connection->u.user;  passwd = connection->u.passwd;  /* Use .netrc if asked to do so. */  if (connection->use_netrc == TRUE)  {    netrc_ent = search_netrc(libprozrtinfo.netrc_list, connection->u.host);    if (netrc_ent != NULL)    {      user = netrc_ent->account;      passwd = netrc_ent->password;    }  }  user = user ? user : "";  passwd = passwd ? passwd : "";  if (strlen(user) || strlen(passwd))  {    /* Construct the necessary header. */    www_auth = get_basic_auth_str(user, passwd, "Authorization");    proz_debug(_("Authenticating as user %s password %s"), user, passwd);    proz_debug(_("Authentification string=%s"), www_auth);  } else    www_auth = 0;  if (strlen(connection->ftp_proxy->username)      || strlen(connection->ftp_proxy->passwd))    proxy_auth =	get_basic_auth_str(connection->ftp_proxy->username,			   connection->ftp_proxy->passwd,			   "Proxy-Authorization");  remote_port = (char *) alloca(64);  remote_port_len = sprintf(remote_port, ":%d", connection->u.port);  if (connection->hs.accept_ranges == 1)  {    range = (char *) alloca(18 + 64);    sprintf(range, "Range: bytes=%ld-\r\n", connection->remote_startpos);  }  /*Use no-cache directive for proxy servers? */  if (http_use_proxy(connection)      && (connection->http_no_cache || connection->attempts > 0))  {    pragma_no_cache = (char *) alloca(21);    sprintf(pragma_no_cache, "Pragma: no-cache\r\n");  }  /*Referrer TAG should not be needed in FTP through HTTP proxy..right */  request = (char *) alloca(strlen(connection->u.url)			    + strlen(connection->user_agent)			    + strlen(connection->u.host) + remote_port_len			    + (range ? strlen(range) : 0)			    + (www_auth ? strlen(www_auth) : 0)			    + (proxy_auth ? strlen(proxy_auth) : 0)			    + 64			    +			    (pragma_no_cache ? strlen(pragma_no_cache) :			     0));  /* TODO Add referrer tag. */  sprintf(request,	  "GET %s HTTP/1.0\r\nUser-Agent: %s\r\nHost: %s%s\r\nAccept: */*\r\n%s%s%s%s\r\n",	  connection->u.url, connection->user_agent, connection->u.host,	  remote_port ? remote_port : "", range ? range : "",	  www_auth ? www_auth : "", proxy_auth ? proxy_auth : "",	  pragma_no_cache ? pragma_no_cache : "");  proz_debug("HTTP request = %s", request);  connection_show_message(connection, _("Sending HTTP request"));  err = http_fetch_headers(connection, &hs_after_get, request);  if (err == HAUTHREQ)  {    connection_change_status(connection, LOGINFAIL);    return FTPLOGREFUSED;  } else if (err == HTTPNSFOD)  {    connection_change_status(connection, REMOTEFATAL);    return FTPNSFOD;  } else if (err != HOK)  {    connection_change_status(connection, REMOTEFATAL);    return FTPERR;  }  /*Check for the server lying about it being able to handle ranges */  if (hs_after_get.contlen != -1)  {    if (connection->resume_support == TRUE)    {      if (hs_after_get.contlen !=	  connection->main_file_size - connection->remote_startpos)      {	proz_debug("Error contlen does not match the requested range!");	connection_change_status(connection, REMOTEFATAL);	return CANTRESUME;      }    }  }/* which routine to call */  if (connection->main_file_size == -1)    err =	connection_retr_fsize_not_known(connection, buffer,					sizeof(buffer));  else    err = connection_retr_fsize_known(connection, buffer, sizeof(buffer));  close_sock(&connection->data_sock);  if (err == FILEGETOK)    return FTPOK;  else    return err;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -