3 * Reads Netscape and Mozilla cookies.txt files
5 * by Dave Lambley <mplayer@davel.me.uk>
13 #include <sys/types.h>
22 #define MAX_COOKIES 20
24 char *cookies_file
= NULL
;
26 typedef struct cookie_list_type
{
34 struct cookie_list_type
*next
;
37 /* Pointer to the linked list of cookies */
38 static struct cookie_list_type
*cookie_list
= NULL
;
41 /* Like strdup, but stops at anything <31. */
42 static char *col_dup(const char *src
)
47 while (src
[length
] > 31)
50 dst
= malloc(length
+ 1);
51 strncpy(dst
, src
, length
);
57 static int right_hand_strcmp(const char *cookie_domain
, const char *url_domain
)
62 c_l
= strlen(cookie_domain
);
63 u_l
= strlen(url_domain
);
67 return strcmp(cookie_domain
, url_domain
+ u_l
- c_l
);
70 static int left_hand_strcmp(const char *cookie_path
, const char *url_path
)
72 return strncmp(cookie_path
, url_path
, strlen(cookie_path
));
75 /* Finds the start of all the columns */
76 static int parse_line(char **ptr
, char *cols
[6])
81 for (col
= 1; col
< 7; col
++) {
82 for (; (**ptr
) > 31; (*ptr
)++);
94 /* Loads a file into RAM */
95 static char *load_file(const char *filename
, off_t
* length
)
100 mp_msg(MSGT_NETWORK
, MSGL_V
, "Loading cookie file: %s\n", filename
);
102 fd
= open(filename
, O_RDONLY
);
104 mp_msg(MSGT_NETWORK
, MSGL_V
, "Could not open");
108 *length
= lseek(fd
, 0, SEEK_END
);
111 mp_msg(MSGT_NETWORK
, MSGL_V
, "Could not find EOF");
115 if (*length
> SIZE_MAX
- 1) {
116 mp_msg(MSGT_NETWORK
, MSGL_V
, "File too big, could not malloc.");
120 lseek(fd
, SEEK_SET
, 0);
122 if (!(buffer
= malloc(*length
+ 1))) {
123 mp_msg(MSGT_NETWORK
, MSGL_V
, "Could not malloc.");
127 if (read(fd
, buffer
, *length
) != *length
) {
128 mp_msg(MSGT_NETWORK
, MSGL_V
, "Read is behaving funny.");
137 /* Loads a cookies.txt file into a linked list. */
138 static struct cookie_list_type
*load_cookies_from(const char *filename
,
139 struct cookie_list_type
145 mp_msg(MSGT_NETWORK
, MSGL_V
, "Loading cookie file: %s\n", filename
);
147 ptr
= load_file(filename
, &length
);
153 if (parse_line(&ptr
, cols
)) {
154 struct cookie_list_type
*new;
155 new = malloc(sizeof(cookie_list_t
));
156 new->name
= col_dup(cols
[5]);
157 new->value
= col_dup(cols
[6]);
158 new->path
= col_dup(cols
[2]);
159 new->domain
= col_dup(cols
[0]);
160 new->secure
= (*(cols
[3]) == 't') || (*(cols
[3]) == 'T');
168 /* Attempt to load cookies.txt from various locations. Returns a pointer to the linked list contain the cookies. */
169 static struct cookie_list_type
*load_cookies(void)
173 struct cookie_list_type
*list
= NULL
;
179 return load_cookies_from(cookies_file
, list
);
181 homedir
= getenv("HOME");
186 buf
= malloc(strlen(homedir
) + sizeof("/.mozilla/default") + 1);
187 sprintf(buf
, "%s/.mozilla/default", homedir
);
192 while ((ent
= readdir(dir
)) != NULL
) {
193 if ((ent
->d_name
)[0] != '.') {
194 buf
= malloc(strlen(getenv("HOME")) +
195 sizeof("/.mozilla/default/") +
196 strlen(ent
->d_name
) + sizeof("cookies.txt") + 1);
197 sprintf(buf
, "%s/.mozilla/default/%s/cookies.txt",
198 getenv("HOME"), ent
->d_name
);
199 list
= load_cookies_from(buf
, list
);
206 buf
= malloc(strlen(homedir
) + sizeof("/.netscape/cookies.txt") + 1);
207 sprintf(buf
, "%s/.netscape/cookies.txt", homedir
);
208 list
= load_cookies_from(buf
, list
);
214 /* Take an HTTP_header_t, and insert the correct headers. The cookie files are read if necessary. */
216 cookies_set(HTTP_header_t
* http_hdr
, const char *domain
, const char *url
)
218 int found_cookies
= 0;
219 struct cookie_list_type
*cookies
[MAX_COOKIES
];
220 struct cookie_list_type
*list
, *start
;
225 path
= strchr(url
, '/');
230 cookie_list
= load_cookies();
233 list
= start
= cookie_list
;
235 /* Find which cookies we want, removing duplicates. Cookies with the longest domain, then longest path take priority */
237 /* Check the cookie domain and path. Also, we never send "secure" cookies. These should only be sent over HTTPS. */
238 if ((right_hand_strcmp(list
->domain
, domain
) == 0)
239 && (left_hand_strcmp(list
->path
, path
) == 0) && !list
->secure
) {
241 for (i
= 0; i
< found_cookies
; i
++) {
242 if (strcmp(list
->name
, cookies
[i
]->name
) == 0) {
244 if (strlen(list
->domain
) <= strlen(cookies
[i
]->domain
)) {
246 } else if (strlen(list
->path
) <= strlen(cookies
[i
]->path
)) {
251 if (found_cookies
> MAX_COOKIES
) {
252 /* Cookie jar overflow! */
256 cookies
[found_cookies
++] = list
;
262 buf
= strdup("Cookie:");
264 for (i
= 0; i
< found_cookies
; i
++) {
267 nbuf
= malloc(strlen(buf
) + strlen(" ") + strlen(cookies
[i
]->name
) +
268 strlen("=") + strlen(cookies
[i
]->value
) + strlen(";") + 1);
269 sprintf(nbuf
, "%s %s=%s;", buf
, cookies
[i
]->name
,
276 http_set_field(http_hdr
, buf
);