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

📄 cookies.c

📁 Wget很好的处理了http和ftp的下载,很值得学习的经典代码
💻 C
📖 第 1 页 / 共 3 页
字号:
  struct weighed_cookie *wc2 = (struct weighed_cookie *)p2;  /* Subtractions take `wc2' as the first argument becauase we want a     sort in *decreasing* order of goodness.  */  int dgdiff = wc2->domain_goodness - wc1->domain_goodness;  int pgdiff = wc2->path_goodness - wc1->path_goodness;  /* Sort by domain goodness; if these are the same, sort by path     goodness.  (The sorting order isn't really specified; maybe it     should be the other way around.)  */  return dgdiff ? dgdiff : pgdiff;}/* Generate a `Cookie' header for a request that goes to HOST:PORT and   requests PATH from the server.  The resulting string is allocated   with `malloc', and the caller is responsible for freeing it.  If no   cookies pertain to this request, i.e. no cookie header should be   generated, NULL is returned.  */char *cookie_header (struct cookie_jar *jar, const char *host,               int port, const char *path, bool secflag){  struct cookie **chains;  int chain_count;  struct cookie *cookie;  struct weighed_cookie *outgoing;  int count, i, ocnt;  char *result;  int result_size, pos;  PREPEND_SLASH (path);         /* see cookie_handle_set_cookie */  /* First, find the cookie chains whose domains match HOST. */  /* Allocate room for find_chains_of_host to write to.  The number of     chains can at most equal the number of subdomains, hence     1+<number of dots>.  */  chains = alloca_array (struct cookie *, 1 + count_char (host, '.'));  chain_count = find_chains_of_host (jar, host, chains);  /* No cookies for this host. */  if (!chain_count)    return NULL;  cookies_now = time (NULL);  /* Now extract from the chains those cookies that match our host     (for domain_exact cookies), port (for cookies with port other     than PORT_ANY), etc.  See matching_cookie for details.  */  /* Count the number of matching cookies. */  count = 0;  for (i = 0; i < chain_count; i++)    for (cookie = chains[i]; cookie; cookie = cookie->next)      if (cookie_matches_url (cookie, host, port, path, secflag, NULL))        ++count;  if (!count)    return NULL;                /* no cookies matched */  /* Allocate the array. */  outgoing = alloca_array (struct weighed_cookie, count);  /* Fill the array with all the matching cookies from the chains that     match HOST. */  ocnt = 0;  for (i = 0; i < chain_count; i++)    for (cookie = chains[i]; cookie; cookie = cookie->next)      {        int pg;        if (!cookie_matches_url (cookie, host, port, path, secflag, &pg))          continue;        outgoing[ocnt].cookie = cookie;        outgoing[ocnt].domain_goodness = strlen (cookie->domain);        outgoing[ocnt].path_goodness   = pg;        ++ocnt;      }  assert (ocnt == count);  /* Eliminate duplicate cookies; that is, those whose name and value     are the same.  */  count = eliminate_dups (outgoing, count);  /* Sort the array so that best-matching domains come first, and     that, within one domain, best-matching paths come first. */  qsort (outgoing, count, sizeof (struct weighed_cookie), goodness_comparator);  /* Count the space the name=value pairs will take. */  result_size = 0;  for (i = 0; i < count; i++)    {      struct cookie *c = outgoing[i].cookie;      /* name=value */      result_size += strlen (c->attr) + 1 + strlen (c->value);    }  /* Allocate output buffer:     name=value pairs -- result_size     "; " separators  -- (count - 1) * 2     \0 terminator    -- 1 */  result_size = result_size + (count - 1) * 2 + 1;  result = xmalloc (result_size);  pos = 0;  for (i = 0; i < count; i++)    {      struct cookie *c = outgoing[i].cookie;      int namlen = strlen (c->attr);      int vallen = strlen (c->value);      memcpy (result + pos, c->attr, namlen);      pos += namlen;      result[pos++] = '=';      memcpy (result + pos, c->value, vallen);      pos += vallen;      if (i < count - 1)        {          result[pos++] = ';';          result[pos++] = ' ';        }    }  result[pos++] = '\0';  assert (pos == result_size);  return result;}/* Support for loading and saving cookies.  The format used for   loading and saving should be the format of the `cookies.txt' file   used by Netscape and Mozilla, at least the Unix versions.   (Apparently IE can export cookies in that format as well.)  The   format goes like this:       DOMAIN DOMAIN-FLAG PATH SECURE-FLAG TIMESTAMP ATTR-NAME ATTR-VALUE     DOMAIN      -- cookie domain, optionally followed by :PORT     DOMAIN-FLAG -- whether all hosts in the domain match     PATH        -- cookie path     SECURE-FLAG -- whether cookie requires secure connection     TIMESTAMP   -- expiry timestamp, number of seconds since epoch     ATTR-NAME   -- name of the cookie attribute     ATTR-VALUE  -- value of the cookie attribute (empty if absent)   The fields are separated by TABs.  All fields are mandatory, except   for ATTR-VALUE.  The `-FLAG' fields are boolean, their legal values   being "TRUE" and "FALSE'.  Empty lines, lines consisting of   whitespace only, and comment lines (beginning with # optionally   preceded by whitespace) are ignored.   Example line from cookies.txt (split in two lines for readability):       .google.com      TRUE    /       FALSE   2147368447      \       PREF     ID=34bb47565bbcd47b:LD=en:NR=20:TM=985172580:LM=985739012*//* If the region [B, E) ends with :<digits>, parse the number, return   it, and store new boundary (location of the `:') to DOMAIN_E_PTR.   If port is not specified, return 0.  */static intdomain_port (const char *domain_b, const char *domain_e,             const char **domain_e_ptr){  int port = 0;  const char *p;  const char *colon = memchr (domain_b, ':', domain_e - domain_b);  if (!colon)    return 0;  for (p = colon + 1; p < domain_e && ISDIGIT (*p); p++)    port = 10 * port + (*p - '0');  if (p < domain_e)    /* Garbage following port number. */    return 0;  *domain_e_ptr = colon;  return port;}#define GET_WORD(p, b, e) do {                  \  b = p;                                        \  while (*p && *p != '\t')                      \    ++p;                                        \  e = p;                                        \  if (b == e || !*p)                            \    goto next;                                  \  ++p;                                          \} while (0)/* Load cookies from FILE.  */voidcookie_jar_load (struct cookie_jar *jar, const char *file){  char *line;  FILE *fp = fopen (file, "r");  if (!fp)    {      logprintf (LOG_NOTQUIET, _("Cannot open cookies file `%s': %s\n"),                 file, strerror (errno));      return;    }  cookies_now = time (NULL);  for (; ((line = read_whole_line (fp)) != NULL); xfree (line))    {      struct cookie *cookie;      char *p = line;      double expiry;      int port;      char *domain_b  = NULL, *domain_e  = NULL;      char *domflag_b = NULL, *domflag_e = NULL;      char *path_b    = NULL, *path_e    = NULL;      char *secure_b  = NULL, *secure_e  = NULL;      char *expires_b = NULL, *expires_e = NULL;      char *name_b    = NULL, *name_e    = NULL;      char *value_b   = NULL, *value_e   = NULL;      /* Skip leading white-space. */      while (*p && ISSPACE (*p))        ++p;      /* Ignore empty lines.  */      if (!*p || *p == '#')        continue;      GET_WORD (p, domain_b,  domain_e);      GET_WORD (p, domflag_b, domflag_e);      GET_WORD (p, path_b,    path_e);      GET_WORD (p, secure_b,  secure_e);      GET_WORD (p, expires_b, expires_e);      GET_WORD (p, name_b,    name_e);      /* Don't use GET_WORD for value because it ends with newline,         not TAB.  */      value_b = p;      value_e = p + strlen (p);      if (value_e > value_b && value_e[-1] == '\n')        --value_e;      if (value_e > value_b && value_e[-1] == '\r')        --value_e;      /* Empty values are legal (I think), so don't bother checking. */      cookie = cookie_new ();      cookie->attr    = strdupdelim (name_b, name_e);      cookie->value   = strdupdelim (value_b, value_e);      cookie->path    = strdupdelim (path_b, path_e);      cookie->secure  = BOUNDED_EQUAL (secure_b, secure_e, "TRUE");      /* Curl source says, quoting Andre Garcia: "flag: A TRUE/FALSE         value indicating if all machines within a given domain can         access the variable.  This value is set automatically by the         browser, depending on the value set for the domain."  */      cookie->domain_exact = !BOUNDED_EQUAL (domflag_b, domflag_e, "TRUE");      /* DOMAIN needs special treatment because we might need to         extract the port.  */      port = domain_port (domain_b, domain_e, (const char **)&domain_e);      if (port)        cookie->port = port;      if (*domain_b == '.')        ++domain_b;             /* remove leading dot internally */      cookie->domain  = strdupdelim (domain_b, domain_e);      /* safe default in case EXPIRES field is garbled. */      expiry = (double)cookies_now - 1;      /* I don't like changing the line, but it's safe here.  (line is         malloced.)  */      *expires_e = '\0';      sscanf (expires_b, "%lf", &expiry);      if (expiry == 0)        {          /* EXPIRY can be 0 for session cookies saved because the             user specified `--keep-session-cookies' in the past.             They remain session cookies, and will be saved only if             the user has specified `keep-session-cookies' again.  */        }      else        {          if (expiry < cookies_now)            goto abort_cookie;  /* ignore stale cookie. */          cookie->expiry_time = expiry;          cookie->permanent = 1;        }      store_cookie (jar, cookie);    next:      continue;    abort_cookie:      delete_cookie (cookie);    }  fclose (fp);}/* Save cookies, in format described above, to FILE. */voidcookie_jar_save (struct cookie_jar *jar, const char *file){  FILE *fp;  hash_table_iterator iter;  DEBUGP (("Saving cookies to %s.\n", file));  cookies_now = time (NULL);  fp = fopen (file, "w");  if (!fp)    {      logprintf (LOG_NOTQUIET, _("Cannot open cookies file `%s': %s\n"),                 file, strerror (errno));      return;    }  fputs ("# HTTP cookie file.\n", fp);  fprintf (fp, "# Generated by Wget on %s.\n", datetime_str (cookies_now));  fputs ("# Edit at your own risk.\n\n", fp);  for (hash_table_iterate (jar->chains, &iter);       hash_table_iter_next (&iter);       )    {      const char *domain = iter.key;      struct cookie *cookie = iter.value;      for (; cookie; cookie = cookie->next)        {          if (!cookie->permanent && !opt.keep_session_cookies)            continue;          if (cookie_expired_p (cookie))            continue;          if (!cookie->domain_exact)            fputc ('.', fp);          fputs (domain, fp);          if (cookie->port != PORT_ANY)            fprintf (fp, ":%d", cookie->port);          fprintf (fp, "\t%s\t%s\t%s\t%.0f\t%s\t%s\n",                   cookie->domain_exact ? "FALSE" : "TRUE",                   cookie->path, cookie->secure ? "TRUE" : "FALSE",                   (double)cookie->expiry_time,                   cookie->attr, cookie->value);          if (ferror (fp))            goto out;        }    } out:  if (ferror (fp))    logprintf (LOG_NOTQUIET, _("Error writing to `%s': %s\n"),               file, strerror (errno));  if (fclose (fp) < 0)    logprintf (LOG_NOTQUIET, _("Error closing `%s': %s\n"),               file, strerror (errno));  DEBUGP (("Done saving cookies.\n"));}/* Clean up cookie-related data. */voidcookie_jar_delete (struct cookie_jar *jar){  /* Iterate over chains (indexed by domain) and free them. */  hash_table_iterator iter;  for (hash_table_iterate (jar->chains, &iter); hash_table_iter_next (&iter); )    {      struct cookie *chain = iter.value;      xfree (iter.key);      /* Then all cookies in this chain. */      while (chain)        {          struct cookie *next = chain->next;          delete_cookie (chain);          chain = next;        }    }  hash_table_destroy (jar->chains);  xfree (jar);}/* Test cases.  Currently this is only tests parse_set_cookies.  To   use, recompile Wget with -DTEST_COOKIES and call test_cookies()   from main.  */#ifdef TEST_COOKIESvoidtest_cookies (void){  /* Tests expected to succeed: */  static struct {    const char *data;    const char *results[10];  } tests_succ[] = {    { "arg=value", {"arg", "value", NULL} },    { "arg1=value1;arg2=value2", {"arg1", "value1", "arg2", "value2", NULL} },    { "arg1=value1; arg2=value2", {"arg1", "value1", "arg2", "value2", NULL} },    { "arg1=value1;  arg2=value2;", {"arg1", "value1", "arg2", "value2", NULL} },    { "arg1=value1;  arg2=value2;  ", {"arg1", "value1", "arg2", "value2", NULL} },    { "arg1=\"value1\"; arg2=\"\"", {"arg1", "value1", "arg2", "", NULL} },    { "arg=", {"arg", "", NULL} },    { "arg1=; arg2=", {"arg1", "", "arg2", "", NULL} },    { "arg1 = ; arg2= ", {"arg1", "", "arg2", "", NULL} },  };  /* Tests expected to fail: */  static char *tests_fail[] = {    ";",    "arg=\"unterminated",    "=empty-name",    "arg1=;=another-empty-name",  };  int i;  for (i = 0; i < countof (tests_succ); i++)    {      int ind;      const char *data = tests_succ[i].data;      const char **expected = tests_succ[i].results;      struct cookie *c;      c = parse_set_cookie (data, true);      if (!c)        {          printf ("NULL cookie returned for valid data: %s\n", data);          continue;        }      /* Test whether extract_param handles these cases correctly. */      {        param_token name, value;        const char *ptr = data;        int j = 0;        while (extract_param (&ptr, &name, &value, ';'))          {            char *n = strdupdelim (name.b, name.e);            char *v = strdupdelim (value.b, value.e);            if (!expected[j])              {                printf ("Too many parameters for '%s'\n", data);                break;              }            if (0 != strcmp (expected[j], n))              printf ("Invalid name %d for '%s' (expected '%s', got '%s')\n",                      j / 2 + 1, data, expected[j], n);            if (0 != strcmp (expected[j + 1], v))              printf ("Invalid value %d for '%s' (expected '%s', got '%s')\n",                      j / 2 + 1, data, expected[j + 1], v);            j += 2;            free (n);            free (v);          }        if (expected[j])          printf ("Too few parameters for '%s'\n", data);      }    }  for (i = 0; i < countof (tests_fail); i++)    {      struct cookie *c;      char *data = tests_fail[i];      c = parse_set_cookie (data, true);      if (c)        printf ("Failed to report error on invalid data: %s\n", data);    }}#endif /* TEST_COOKIES */

⌨️ 快捷键说明

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