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

📄 http.c

📁 Wget很好的处理了http和ftp的下载,很值得学习的经典代码
💻 C
📖 第 1 页 / 共 5 页
字号:
     advance.  This test is a logical followup of the first test, but     is "expensive" and therefore placed at the end of the list.     (Current implementation of test_socket_open has a nice side     effect that it treats sockets with pending data as "closed".     This is exactly what we want: if a broken server sends message     body in response to HEAD, or if it sends more than conent-length     data, we won't reuse the corrupted connection.)  */  if (!test_socket_open (pconn.socket))    {      /* Oops, the socket is no longer open.  Now that we know that,         let's invalidate the persistent connection before returning         0.  */      invalidate_persistent ();      return false;    }  return true;}/* The idea behind these two CLOSE macros is to distinguish between   two cases: one when the job we've been doing is finished, and we   want to close the connection and leave, and two when something is   seriously wrong and we're closing the connection as part of   cleanup.   In case of keep_alive, CLOSE_FINISH should leave the connection   open, while CLOSE_INVALIDATE should still close it.   Note that the semantics of the flag `keep_alive' is "this   connection *will* be reused (the server has promised not to close   the connection once we're done)", while the semantics of   `pc_active_p && (fd) == pc_last_fd' is "we're *now* using an   active, registered connection".  */#define CLOSE_FINISH(fd) do {                   \  if (!keep_alive)                              \    {                                           \      if (pconn_active && (fd) == pconn.socket) \        invalidate_persistent ();               \      else                                      \        {                                       \          fd_close (fd);                        \          fd = -1;                              \        }                                       \    }                                           \} while (0)#define CLOSE_INVALIDATE(fd) do {               \  if (pconn_active && (fd) == pconn.socket)     \    invalidate_persistent ();                   \  else                                          \    fd_close (fd);                              \  fd = -1;                                      \} while (0)struct http_stat{  wgint len;                    /* received length */  wgint contlen;                /* expected length */  wgint restval;                /* the restart value */  int res;                      /* the result of last read */  char *rderrmsg;               /* error message from read error */  char *newloc;                 /* new location (redirection) */  char *remote_time;            /* remote time-stamp string */  char *error;                  /* textual HTTP error */  int statcode;                 /* status code */  wgint rd_size;                /* amount of data read from socket */  double dltime;                /* time it took to download the data */  const char *referer;          /* value of the referer header. */  char *local_file;             /* local file name. */  bool existence_checked;       /* true if we already checked for a file's                                   existence after having begun to download                                   (needed in gethttp for when connection is                                   interrupted/restarted. */  bool timestamp_checked;       /* true if pre-download time-stamping checks                                  * have already been performed */  char *orig_file_name;         /* name of file to compare for time-stamping                                 * (might be != local_file if -K is set) */  wgint orig_file_size;         /* size of file to compare for time-stamping */  time_t orig_file_tstamp;      /* time-stamp of file to compare for                                  * time-stamping */};static voidfree_hstat (struct http_stat *hs){  xfree_null (hs->newloc);  xfree_null (hs->remote_time);  xfree_null (hs->error);  xfree_null (hs->rderrmsg);  xfree_null (hs->local_file);  xfree_null (hs->orig_file_name);  /* Guard against being called twice. */  hs->newloc = NULL;  hs->remote_time = NULL;  hs->error = NULL;}#define BEGINS_WITH(line, string_constant)                               \  (!strncasecmp (line, string_constant, sizeof (string_constant) - 1)    \   && (ISSPACE (line[sizeof (string_constant) - 1])                      \       || !line[sizeof (string_constant) - 1]))#define SET_USER_AGENT(req) do {                                         \  if (!opt.useragent)                                                    \    request_set_header (req, "User-Agent",                               \                        aprintf ("Wget/%s", version_string), rel_value); \  else if (*opt.useragent)                                               \    request_set_header (req, "User-Agent", opt.useragent, rel_none);     \} while (0)/* The flags that allow clobbering the file (opening with "wb").   Defined here to avoid repetition later.  #### This will require   rework.  */#define ALLOW_CLOBBER (opt.noclobber || opt.always_rest || opt.timestamping \                       || opt.dirstruct || opt.output_document)/* Retrieve a document through HTTP protocol.  It recognizes status   code, and correctly handles redirections.  It closes the network   socket.  If it receives an error from the functions below it, it   will print it if there is enough information to do so (almost   always), returning the error to the caller (i.e. http_loop).   Various HTTP parameters are stored to hs.   If PROXY is non-NULL, the connection will be made to the proxy   server, and u->url will be requested.  */static uerr_tgethttp (struct url *u, struct http_stat *hs, int *dt, struct url *proxy){  struct request *req;  char *type;  char *user, *passwd;  char *proxyauth;  int statcode;  int write_error;  wgint contlen, contrange;  struct url *conn;  FILE *fp;  int sock = -1;  int flags;  /* Set to 1 when the authorization has already been sent and should     not be tried again. */  bool auth_finished = false;  /* Set to 1 when just globally-set Basic authorization has been sent;   * should prevent further Basic negotiations, but not other   * mechanisms. */  bool basic_auth_finished = false;  /* Whether NTLM authentication is used for this request. */  bool ntlm_seen = false;  /* Whether our connection to the remote host is through SSL.  */  bool using_ssl = false;  /* Whether a HEAD request will be issued (as opposed to GET or     POST). */  bool head_only = !!(*dt & HEAD_ONLY);  char *head;  struct response *resp;  char hdrval[256];  char *message;  /* Whether this connection will be kept alive after the HTTP request     is done. */  bool keep_alive;  /* Whether keep-alive should be inhibited.     RFC 2068 requests that 1.0 clients not send keep-alive requests     to proxies.  This is because many 1.0 proxies do not interpret     the Connection header and transfer it to the remote server,     causing it to not close the connection and leave both the proxy     and the client hanging.  */  bool inhibit_keep_alive =    !opt.http_keep_alive || opt.ignore_length || proxy != NULL;  /* Headers sent when using POST. */  wgint post_data_size = 0;  bool host_lookup_failed = false;#ifdef HAVE_SSL  if (u->scheme == SCHEME_HTTPS)    {      /* Initialize the SSL context.  After this has once been done,         it becomes a no-op.  */      if (!ssl_init ())        {          scheme_disable (SCHEME_HTTPS);          logprintf (LOG_NOTQUIET,                     _("Disabling SSL due to encountered errors.\n"));          return SSLINITFAILED;        }    }#endif /* HAVE_SSL */  /* Initialize certain elements of struct http_stat.  */  hs->len = 0;  hs->contlen = -1;  hs->res = -1;  hs->rderrmsg = NULL;  hs->newloc = NULL;  hs->remote_time = NULL;  hs->error = NULL;  conn = u;  /* Prepare the request to send. */  req = request_new ();  {    char *meth_arg;    const char *meth = "GET";    if (head_only)      meth = "HEAD";    else if (opt.post_file_name || opt.post_data)      meth = "POST";    /* Use the full path, i.e. one that includes the leading slash and       the query string.  E.g. if u->path is "foo/bar" and u->query is       "param=value", full_path will be "/foo/bar?param=value".  */    if (proxy#ifdef HAVE_SSL        /* When using SSL over proxy, CONNECT establishes a direct           connection to the HTTPS server.  Therefore use the same           argument as when talking to the server directly. */        && u->scheme != SCHEME_HTTPS#endif        )      meth_arg = xstrdup (u->url);    else      meth_arg = url_full_path (u);    request_set_method (req, meth, meth_arg);  }  request_set_header (req, "Referer", (char *) hs->referer, rel_none);  if (*dt & SEND_NOCACHE)    request_set_header (req, "Pragma", "no-cache", rel_none);  if (hs->restval)    request_set_header (req, "Range",                        aprintf ("bytes=%s-",                                 number_to_static_string (hs->restval)),                        rel_value);  SET_USER_AGENT (req);  request_set_header (req, "Accept", "*/*", rel_none);  /* Find the username and password for authentication. */  user = u->user;  passwd = u->passwd;  search_netrc (u->host, (const char **)&user, (const char **)&passwd, 0);  user = user ? user : (opt.http_user ? opt.http_user : opt.user);  passwd = passwd ? passwd : (opt.http_passwd ? opt.http_passwd : opt.passwd);  if (user && passwd      && !u->user) /* We only do "site-wide" authentication with "global"                      user/password values; URL user/password info overrides. */    {      /* If this is a host for which we've already received a Basic       * challenge, we'll go ahead and send Basic authentication creds. */      basic_auth_finished = maybe_send_basic_creds(u->host, user, passwd, req);    }  proxyauth = NULL;  if (proxy)    {      char *proxy_user, *proxy_passwd;      /* For normal username and password, URL components override         command-line/wgetrc parameters.  With proxy         authentication, it's the reverse, because proxy URLs are         normally the "permanent" ones, so command-line args         should take precedence.  */      if (opt.proxy_user && opt.proxy_passwd)        {          proxy_user = opt.proxy_user;          proxy_passwd = opt.proxy_passwd;        }      else        {          proxy_user = proxy->user;          proxy_passwd = proxy->passwd;        }      /* #### This does not appear right.  Can't the proxy request,         say, `Digest' authentication?  */      if (proxy_user && proxy_passwd)        proxyauth = basic_authentication_encode (proxy_user, proxy_passwd);      /* If we're using a proxy, we will be connecting to the proxy         server.  */      conn = proxy;      /* Proxy authorization over SSL is handled below. */#ifdef HAVE_SSL      if (u->scheme != SCHEME_HTTPS)#endif        request_set_header (req, "Proxy-Authorization", proxyauth, rel_value);    }  /* Generate the Host header, HOST:PORT.  Take into account that:     - Broken server-side software often doesn't recognize the PORT       argument, so we must generate "Host: www.server.com" instead of       "Host: www.server.com:80" (and likewise for https port).     - IPv6 addresses contain ":", so "Host: 3ffe:8100:200:2::2:1234"       becomes ambiguous and needs to be rewritten as "Host:       [3ffe:8100:200:2::2]:1234".  */  {    /* Formats arranged for hfmt[add_port][add_squares].  */    static const char *hfmt[][2] = {      { "%s", "[%s]" }, { "%s:%d", "[%s]:%d" }    };    int add_port = u->port != scheme_default_port (u->scheme);    int add_squares = strchr (u->host, ':') != NULL;    request_set_header (req, "Host",                        aprintf (hfmt[add_port][add_squares], u->host, u->port),                        rel_value);  }  if (!inhibit_keep_alive)    request_set_header (req, "Connection", "Keep-Alive", rel_none);  if (opt.cookies)    request_set_header (req, "Cookie",                        cookie_header (wget_cookie_jar,                                       u->host, u->port, u->path,#ifdef HAVE_SSL                                       u->scheme == SCHEME_HTTPS#else                                       0#endif                                       ),                        rel_value);  if (opt.post_data || opt.post_file_name)    {      request_set_header (req, "Content-Type",                          "application/x-www-form-urlencoded", rel_none);      if (opt.post_data)        post_data_size = strlen (opt.post_data);      else        {          post_data_size = file_size (opt.post_file_name);          if (post_data_size == -1)            {              logprintf (LOG_NOTQUIET, _("POST data file `%s' missing: %s\n"),                         opt.post_file_name, strerror (errno));              post_data_size = 0;            }        }      request_set_header (req, "Content-Length",                          xstrdup (number_to_static_string (post_data_size)),                          rel_value);    }  /* Add the user headers. */  if (opt.user_headers)    {      int i;      for (i = 0; opt.user_headers[i]; i++)        request_set_user_header (req, opt.user_headers[i]);    } retry_with_auth:  /* We need to come back here when the initial attempt to retrieve     without authorization header fails.  (Expected to happen at least     for the Digest authorization scheme.)  */  keep_alive = false;  /* Establish the connection.  */  if (!inhibit_keep_alive)    {      /* Look for a persistent connection to target host, unless a         proxy is used.  The exception is when SSL is in use, in which         case the proxy is nothing but a passthrough to the target         host, registered as a connection to the latter.  */      struct url *relevant = conn;#ifdef HAVE_SSL      if (u->scheme == SCHEME_HTTPS)        relevant = u;#endif      if (persistent_available_p (relevant->host, relevant->port,#ifdef HAVE_SSL                                  relevant->scheme == SCHEME_HTTPS,#else                                  0,#endif                                  &host_lookup_failed))        {          sock = pconn.socket;          using_ssl = pconn.ssl;          logprintf (LOG_VERBOSE, _("Reusing existing connection to %s:%d.\n"),                     escnonprint (pconn.host), pconn.port);          DEBUGP (("Reusing fd %d.\n", sock));          if (pconn.authorized)            /* If the connection is already authorized, the "Basic"               authorization added by code above is unnecessary and               only hurts us.  */            request_remove_header (req, "Authorization");        }

⌨️ 快捷键说明

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