📄 cookies.c
字号:
{ int i; for (i = 1; i <= 12; i++) { if (!g_strncasecmp(months[i], month_name, 3)) return i; } return 0;}/* * Return a local timestamp from a GMT date string * Accept: RFC-1123 | RFC-850 | ANSI asctime | Old Netscape format. * * Wdy, DD-Mon-YY HH:MM:SS GMT * Wdy, DD-Mon-YYYY HH:MM:SS GMT * Weekday, DD-Mon-YY HH:MM:SS GMT * Weekday, DD-Mon-YYYY HH:MM:SS GMT * Tue May 21 13:46:22 1991\n * Tue May 21 13:46:22 1991 * * (return 0 on malformed date string syntax) */static time_t Cookies_create_timestamp(const char *expires){ time_t ret; int day, month, year, hour, minutes, seconds; gchar *cp; gchar *E_msg = "Expire date is malformed!\n" " (should be RFC-1123 | RFC-850 | ANSI asctime)\n" " Ignoring cookie: "; cp = strchr(expires, ','); if (!cp && (strlen(expires) == 24 || strlen(expires) == 25)) { /* Looks like ANSI asctime format... */ cp = (gchar *)expires; day = strtol(cp + 8, NULL, 10); /* day */ month = Cookies_get_month(cp + 4); /* month */ year = strtol(cp + 20, NULL, 10); /* year */ hour = strtol(cp + 11, NULL, 10); /* hour */ minutes = strtol(cp + 14, NULL, 10); /* minutes */ seconds = strtol(cp + 17, NULL, 10); /* seconds */ } else if (cp && (cp - expires == 3 || cp - expires > 5) && (strlen(cp) == 24 || strlen(cp) == 26)) { /* RFC-1123 | RFC-850 format | Old Netscape format */ day = strtol(cp + 2, NULL, 10); month = Cookies_get_month(cp + 5); year = strtol(cp + 9, &cp, 10); /* todo: tricky, because two digits for year IS ambiguous! */ year += (year < 70) ? 2000 : ((year < 100) ? 1900 : 0); hour = strtol(cp + 1, NULL, 10); minutes = strtol(cp + 4, NULL, 10); seconds = strtol(cp + 7, NULL, 10); } else { MSG("%s%s\n", E_msg, expires); return (time_t) 0; } /* Error checks --this may be overkill */ if (!(day > 0 && day < 32 && month > 0 && month < 13 && year > 1970 && hour >= 0 && hour < 24 && minutes >= 0 && minutes < 60 && seconds >= 0 && seconds < 60)) { MSG("%s%s\n", E_msg, expires); return (time_t) 0; } /* Calculate local timestamp. * [stolen from Lynx... (http://lynx.browser.org)] */ month -= 3; if (month < 0) { month += 12; year--; } day += (year - 1968) * 1461 / 4; day += ((((month * 153) + 2) / 5) - 672); ret = (time_t)((day * 60 * 60 * 24) + (hour * 60 * 60) + (minutes * 60) + seconds); MSG("Expires in %ld seconds, at %s", (long)ret - time(NULL), ctime(&ret)); return ret;}/* * Parse a string containing a list of port numbers. */static void Cookies_parse_ports(gint url_port, CookieData_t *cookie, const char *port_str){ if ((!port_str || !port_str[0]) && url_port != 0) { /* There was no list, so only the calling urls port should be allowed. */ cookie->ports = g_list_append(cookie->ports, GINT_TO_POINTER(url_port)); } else if (port_str[0] == '"' && port_str[1] != '"') { char **tokens, **i; int port; tokens = g_strsplit(port_str + 1, ",", -1); for (i = tokens; *i; ++i) { port = strtol(*i, NULL, 10); if (port > 0) { cookie->ports = g_list_append(cookie->ports, GINT_TO_POINTER(port)); } } g_strfreev(tokens); }}/* * Build a string of the ports in 'cookie'. */static char *Cookies_build_ports_str(CookieData_t *cookie){ GString *gstr; GList *list; char *ret; gstr = g_string_new("\""); for (list = cookie->ports; list; list = g_list_next(list)) g_string_sprintfa(gstr, "%d,", GPOINTER_TO_INT(list->data)); /* Remove any trailing comma */ if (gstr->len > 1) g_string_erase(gstr, gstr->len - 1, 1); g_string_append(gstr, "\""); ret = gstr->str; g_string_free(gstr, FALSE); return ret;}/* * Used by g_list_insert_sorted() to sort the cookies by most specific path */static gint Cookies_compare(gconstpointer a, gconstpointer b){ const CookieData_t *ca = a, *cb = b; return strcmp(ca->path, cb->path);}static void Cookies_add_cookie(CookieData_t *cookie){ GList *domain_cookies, *tmp; char *domain_str; /* Don't add an expired cookie */ if (!cookie->session_only && cookie->expires_at < time(NULL)) { Cookies_free_cookie(cookie); return; } domain_cookies = g_hash_table_lookup(cookies, cookie->domain); if (domain_cookies) { /* Respect the limit of 20 cookies per domain */ if (g_list_length(domain_cookies) > 20) { MSG("There are too many cookies for this domain (%s)\n", cookie->domain); Cookies_free_cookie(cookie); return; } /* Remove any cookies with the same name and path */ while ((tmp = g_list_find_custom(domain_cookies, cookie, Cookies_equals))) { Cookies_remove_cookie(tmp->data); domain_cookies = g_hash_table_lookup(cookies, cookie->domain); } } /* Allocate string key when no domain_cookies are left * (because remove_cookie has then killed the key, when it was there) */ domain_str = domain_cookies ? cookie->domain : g_strdup(cookie->domain); domain_cookies = g_list_insert_sorted(domain_cookies, cookie, Cookies_compare); g_hash_table_insert(cookies, domain_str, domain_cookies);}/* * Remove the cookie from the domain list. * If the domain list is empty, free the hash table entry. * Free the cookie. */static void Cookies_remove_cookie(CookieData_t *cookie){ GList *list; gpointer orig_key; gpointer orig_val; if (g_hash_table_lookup_extended(cookies, cookie->domain, &orig_key, &orig_val)) { list = g_list_remove(orig_val, cookie); if (list) { /* Make sure that we have the correct start of the list stored */ g_hash_table_insert(cookies, cookie->domain, list); } else { g_hash_table_remove(cookies, cookie->domain); g_free(orig_key); } } else { MSG("Attempting to remove a cookie that doesn't exist!\n"); } Cookies_free_cookie(cookie);}/* * Return the attribute that is present at *cookie_str. This function * will also attempt to advance cookie_str past any equal-sign. */static char *Cookies_parse_attr(char **cookie_str){ char *str = *cookie_str; guint i, end = 0; gboolean got_attr = FALSE; for (i = 0; ; i++) { switch (str[i]) { case ' ': case '\t': case '=': case ';': got_attr = TRUE; if (end == 0) end = i; break; case ',': *cookie_str = str + i; return g_strndup(str, i); break; case '\0': if (!got_attr) { end = i; got_attr = TRUE; } /* fall through! */ default: if (got_attr) { *cookie_str = str + i; return g_strndup(str, end); } break; } } return NULL;}/* * Get the value starting at *cookie_str. * broken_syntax: watch out for stupid syntax (comma in unquoted string...) */static char *Cookies_parse_value(char **cookie_str, gboolean broken_syntax, gboolean keep_quotes){ guint i, end; char *str = *cookie_str; for (i = end = 0; !end; ++i) { switch (str[i]) { case ' ': case '\t': if (!broken_syntax && str[0] != '\'' && str[0] != '"') { *cookie_str = str + i + 1; end = 1; } break; case '\'': case '"': if (i != 0 && str[i] == str[0]) { char *tmp = str + i; while (*tmp != '\0' && *tmp != ';' && *tmp != ',') tmp++; *cookie_str = (*tmp == ';') ? tmp + 1 : tmp; if (keep_quotes) i++; end = 1; } break; case '\0': *cookie_str = str + i; end = 1; break; case ',': if (str[0] != '\'' && str[0] != '"' && !broken_syntax) { /* A new cookie starts here! */ *cookie_str = str + i; end = 1; } break; case ';': if (str[0] != '\'' && str[0] != '"') { *cookie_str = str + i + 1; end = 1; } break; default: break; } } /* keep i as an index to the last char */ --i; if ((str[0] == '\'' || str[0] == '"') && !keep_quotes) { return i > 1 ? g_strndup(str + 1, i - 1) : NULL; } else { return g_strndup(str, i); }}/* * Parse one cookie... */static CookieData_t *Cookies_parse_one(gint url_port, char **cookie_str){ CookieData_t *cookie; char *str = *cookie_str; char *attr; char *value; int num_attr = 0; gboolean max_age = FALSE; gboolean discard = FALSE; cookie = g_new0(CookieData_t, 1); cookie->session_only = TRUE; /* Iterate until there is nothing left of the string OR we come * across a comma representing the start of another cookie */ while (*str != '\0' && *str != ',') { /* Skip whitespace */ while (isspace(*str)) str++; /* Get attribute */ attr = Cookies_parse_attr(&str); if (!attr) { MSG("Failed to parse cookie attribute!\n"); Cookies_free_cookie(cookie); return NULL; } /* Get the value for the attribute and store it */ if (num_attr == 0) { /* The first attr, which always is the user supplied attr, may * have the same name as an ordinary attr. Hence this workaround. */ cookie->name = g_strdup(attr); cookie->value = Cookies_parse_value(&str, FALSE, TRUE); } else if (g_strcasecmp(attr, "Path") == 0) { value = Cookies_parse_value(&str, FALSE, FALSE); cookie->path = value; } else if (g_strcasecmp(attr, "Domain") == 0) { value = Cookies_parse_value(&str, FALSE, FALSE); cookie->domain = value; } else if (g_strcasecmp(attr, "Discard") == 0) { cookie->session_only = TRUE; discard = TRUE; } else if (g_strcasecmp(attr, "Max-Age") == 0) { if (!discard) { value = Cookies_parse_value(&str, FALSE, FALSE); if (value) { cookie->expires_at = time(NULL) + strtol(value, NULL, 10); cookie->session_only = FALSE; max_age = TRUE; g_free(value); } else { MSG("Failed to parse cookie value!\n"); Cookies_free_cookie(cookie); return NULL; } } } else if (g_strcasecmp(attr, "Expires") == 0) { if (!max_age && !discard) { MSG("Old netscape-style cookie...\n"); value = Cookies_parse_value(&str, TRUE, FALSE); if (value) { cookie->expires_at = Cookies_create_timestamp(value); cookie->session_only = FALSE; g_free(value); } else { MSG("Failed to parse cookie value!\n"); Cookies_free_cookie(cookie); return NULL; } } } else if (g_strcasecmp(attr, "Port") == 0) { value = Cookies_parse_value(&str, FALSE, TRUE); Cookies_parse_ports(url_port, cookie, value); g_free(value); } else if (g_strcasecmp(attr, "Comment") == 0) { value = Cookies_parse_value(&str, FALSE, FALSE); cookie->comment = value; } else if (g_strcasecmp(attr, "CommentURL") == 0) { value = Cookies_parse_value(&str, FALSE, FALSE); cookie->comment_url = value; } else if (g_strcasecmp(attr, "Version") == 0) { value = Cookies_parse_value(&str, FALSE, FALSE); if (value) { cookie->version = strtol(value, NULL, 10); g_free(value); } else { MSG("Failed to parse cookie value!\n"); Cookies_free_cookie(cookie); return NULL; } } else if (g_strcasecmp(attr, "Secure") == 0) { cookie->secure = TRUE; } else { /* Oops! this can't be good... */ g_free(attr); Cookies_free_cookie(cookie); MSG("Cookie contains illegal attribute!\n"); return NULL; } g_free(attr); num_attr++; } *cookie_str = (*str == ',') ? str + 1 : str; if (cookie->name && cookie->value) { return cookie; } else { MSG("Cookie missing name and/or value!\n"); Cookies_free_cookie(cookie); return NULL; }}/* * Iterate the cookie string until we catch all cookies. * Return Value: a list with all the cookies! (or NULL upon error) */static GSList *Cookies_parse_string(gint url_port, char *cookie_string){ CookieData_t *cookie; GSList *ret = NULL; char *str = cookie_string; /* The string may contain several cookies separated by comma. * We'll iterate until we've catched them all */ while (*str) { cookie = Cookies_parse_one(url_port, &str); if (cookie) { ret = g_slist_append(ret, cookie); } else { MSG("Malformed cookie field, ignoring cookie: %s\n", cookie_string); return NULL; } } return ret;}/* * Compare cookies by name and path (return 0 if equal) */static gint Cookies_equals(gconstpointer a, gconstpointer b){ const CookieData_t *ca = a, *cb = b; return (strcmp(ca->name, cb->name) || strcmp(ca->path, cb->path));}/* * Validate cookies domain against some security checks. */static gboolean Cookies_validate_domain(CookieData_t *cookie, gchar *host, gchar *url_path){ int dots, diff, i; gboolean is_ip;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -