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

📄 cookies.c

📁 wget (command line browser) source code
💻 C
📖 第 1 页 / 共 3 页
字号:
     "tortoise".  If a duplicate is found, the hare skips it.     Non-duplicate entries are copied to the tortoise ptr.  */  for (h = t = outgoing; h < end; h++)    {      if (h != end - 1)	{	  struct cookie *c0 = h[0].cookie;	  struct cookie *c1 = h[1].cookie;	  if (!strcmp (c0->attr, c1->attr) && !strcmp (c0->value, c1->value))	    continue;		/* ignore the duplicate */	}      /* If the hare has advanced past the tortoise (because of	 previous dups), make sure the values get copied.  Otherwise,	 no copying is necessary.  */      if (h != t)	*t++ = *h;      else	t++;    }  return t - outgoing;}/* Comparator used for sorting by quality. */static intgoodness_comparator (const void *p1, const void *p2){  struct weighed_cookie *wc1 = (struct weighed_cookie *)p1;  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_jar_generate_cookie_header (struct cookie_jar *jar, const char *host,				   int port, const char *path,				   int connection_secure_p){  struct cookie **chains;  int chain_count;  struct cookie *cookie;  struct weighed_cookie *outgoing;  int count, i, ocnt;  char *result;  int result_size, pos;  /* 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, connection_secure_p,			      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,				 connection_secure_p, &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:     "Cookie: "       -- 8     name=value pairs -- result_size     "; " separators  -- (count - 1) * 2     \r\n line ending -- 2     \0 terminator    -- 1 */  result_size = 8 + result_size + (count - 1) * 2 + 2 + 1;  result = xmalloc (result_size);  pos = 0;  strcpy (result, "Cookie: ");  pos += 8;  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++] = '\r';  result[pos++] = '\n';  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 < cookies_now)	/* ignore stale cookie. */	goto abort;      cookie->expiry_time = expiry;      /* If the cookie has survived being saved into an external file,	 it is obviously permanent.  */      cookie->permanent = 1;      store_cookie (jar, cookie);    next:      continue;    abort:      delete_cookie (cookie);    }  fclose (fp);}/* Mapper for save_cookies callable by hash_table_map.  VALUE points   to the head in a chain of cookies.  The function prints the entire   chain.  */static intsave_cookies_mapper (void *key, void *value, void *arg){  FILE *fp = (FILE *)arg;  char *domain = (char *)key;  struct cookie *cookie = (struct cookie *)value;  for (; cookie; cookie = cookie->next)    {      if (!cookie->permanent)	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))	return 1;		/* stop mapping */    }  return 0;}/* Save cookies, in format described above, to FILE. */voidcookie_jar_save (struct cookie_jar *jar, const char *file){  FILE *fp;  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 (NULL));  fputs ("# Edit at your own risk.\n\n", fp);  hash_table_map (jar->chains, save_cookies_mapper, fp);  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"));}/* Destroy all the elements in the chain and unhook it from the cookie   jar.  This is written in the form of a callback to hash_table_map   and used by cookie_jar_delete to delete all the cookies in a   jar.  */static intnuke_cookie_chain (void *value, void *key, void *arg){  char *chain_key = (char *)value;  struct cookie *chain = (struct cookie *)key;  struct cookie_jar *jar = (struct cookie_jar *)arg;  /* Remove the chain from the table and free the key. */  hash_table_remove (jar->chains, chain_key);  xfree (chain_key);  /* Then delete all the cookies in the chain. */  while (chain)    {      struct cookie *next = chain->next;      delete_cookie (chain);      chain = next;    }  /* Keep mapping. */  return 0;}/* Clean up cookie-related data. */voidcookie_jar_delete (struct cookie_jar *jar){  hash_table_map (jar->chains, nuke_cookie_chain, jar);  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_COOKIESint test_count;char *test_results[10];static int test_parse_cookies_callback (struct cookie *ignored,					const char *nb, const char *ne,					const char *vb, const char *ve){  test_results[test_count++] = strdupdelim (nb, ne);  test_results[test_count++] = strdupdelim (vb, ve);  return 1;}voidtest_cookies (void){  /* Tests expected to succeed: */  static struct {    char *data;    char *results[10];  } tests_succ[] = {    { "", {NULL} },    { "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;      char *data = tests_succ[i].data;      char **expected = tests_succ[i].results;      struct cookie *c;      test_count = 0;      c = parse_set_cookies (data, test_parse_cookies_callback, 1);      if (!c)	{	  printf ("NULL cookie returned for valid data: %s\n", data);	  continue;	}      for (ind = 0; ind < test_count; ind += 2)	{	  if (!expected[ind])	    break;	  if (0 != strcmp (expected[ind], test_results[ind]))	    printf ("Invalid name %d for '%s' (expected '%s', got '%s')\n",		    ind / 2 + 1, data, expected[ind], test_results[ind]);	  if (0 != strcmp (expected[ind + 1], test_results[ind + 1]))	    printf ("Invalid value %d for '%s' (expected '%s', got '%s')\n",		    ind / 2 + 1, data, expected[ind + 1], test_results[ind + 1]);	}      if (ind < test_count || expected[ind])	printf ("Unmatched number of results: %s\n", data);    }  for (i = 0; i < countof (tests_fail); i++)    {      struct cookie *c;      char *data = tests_fail[i];      test_count = 0;      c = parse_set_cookies (data, test_parse_cookies_callback, 1);      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 + -