3 * Reads Netscape and Mozilla cookies.txt files
5 * Copyright (c) 2003 Dave Lambley <mplayer@davel.me.uk>
7 * This file is part of MPlayer.
9 * MPlayer is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * MPlayer is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License along
20 * with MPlayer; if not, write to the Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
29 #include <sys/types.h>
38 #define MAX_COOKIES 20
40 char *cookies_file
= NULL
;
42 typedef struct cookie_list_type
{
50 struct cookie_list_type
*next
;
53 /* Pointer to the linked list of cookies */
54 static struct cookie_list_type
*cookie_list
= NULL
;
57 /* Like strdup, but stops at anything <31. */
58 static char *col_dup(const char *src
)
63 while (src
[length
] > 31)
66 dst
= malloc(length
+ 1);
67 strncpy(dst
, src
, length
);
73 static int right_hand_strcmp(const char *cookie_domain
, const char *url_domain
)
78 c_l
= strlen(cookie_domain
);
79 u_l
= strlen(url_domain
);
83 return strcmp(cookie_domain
, url_domain
+ u_l
- c_l
);
86 static int left_hand_strcmp(const char *cookie_path
, const char *url_path
)
88 return strncmp(cookie_path
, url_path
, strlen(cookie_path
));
91 /* Finds the start of all the columns */
92 static int parse_line(char **ptr
, char *cols
[6])
97 for (col
= 1; col
< 7; col
++) {
98 for (; (**ptr
) > 31; (*ptr
)++);
110 /* Loads a file into RAM */
111 static char *load_file(const char *filename
, off_t
* length
)
116 mp_msg(MSGT_NETWORK
, MSGL_V
, "Loading cookie file: %s\n", filename
);
118 fd
= open(filename
, O_RDONLY
);
120 mp_msg(MSGT_NETWORK
, MSGL_V
, "Could not open");
124 *length
= lseek(fd
, 0, SEEK_END
);
127 mp_msg(MSGT_NETWORK
, MSGL_V
, "Could not find EOF");
131 if (*length
> SIZE_MAX
- 1) {
132 mp_msg(MSGT_NETWORK
, MSGL_V
, "File too big, could not malloc.");
136 lseek(fd
, 0, SEEK_SET
);
138 if (!(buffer
= malloc(*length
+ 1))) {
139 mp_msg(MSGT_NETWORK
, MSGL_V
, "Could not malloc.");
143 if (read(fd
, buffer
, *length
) != *length
) {
144 mp_msg(MSGT_NETWORK
, MSGL_V
, "Read is behaving funny.");
153 /* Loads a cookies.txt file into a linked list. */
154 static struct cookie_list_type
*load_cookies_from(const char *filename
,
155 struct cookie_list_type
161 ptr
= load_file(filename
, &length
);
167 if (parse_line(&ptr
, cols
)) {
168 struct cookie_list_type
*new;
169 new = malloc(sizeof(cookie_list_t
));
170 new->name
= col_dup(cols
[5]);
171 new->value
= col_dup(cols
[6]);
172 new->path
= col_dup(cols
[2]);
173 new->domain
= col_dup(cols
[0]);
174 new->secure
= (*(cols
[3]) == 't') || (*(cols
[3]) == 'T');
182 /* Attempt to load cookies.txt from various locations. Returns a pointer to the linked list contain the cookies. */
183 static struct cookie_list_type
*load_cookies(void)
187 struct cookie_list_type
*list
= NULL
;
193 return load_cookies_from(cookies_file
, list
);
195 homedir
= getenv("HOME");
200 buf
= malloc(strlen(homedir
) + sizeof("/.mozilla/default") + 1);
201 sprintf(buf
, "%s/.mozilla/default", homedir
);
206 while ((ent
= readdir(dir
)) != NULL
) {
207 if ((ent
->d_name
)[0] != '.') {
208 buf
= malloc(strlen(getenv("HOME")) +
209 sizeof("/.mozilla/default/") +
210 strlen(ent
->d_name
) + sizeof("cookies.txt") + 1);
211 sprintf(buf
, "%s/.mozilla/default/%s/cookies.txt",
212 getenv("HOME"), ent
->d_name
);
213 list
= load_cookies_from(buf
, list
);
220 buf
= malloc(strlen(homedir
) + sizeof("/.netscape/cookies.txt") + 1);
221 sprintf(buf
, "%s/.netscape/cookies.txt", homedir
);
222 list
= load_cookies_from(buf
, list
);
228 /* Take an HTTP_header_t, and insert the correct headers. The cookie files are read if necessary. */
230 cookies_set(HTTP_header_t
* http_hdr
, const char *domain
, const char *url
)
232 int found_cookies
= 0;
233 struct cookie_list_type
*cookies
[MAX_COOKIES
];
234 struct cookie_list_type
*list
, *start
;
239 path
= strchr(url
, '/');
244 cookie_list
= load_cookies();
247 list
= start
= cookie_list
;
249 /* Find which cookies we want, removing duplicates. Cookies with the longest domain, then longest path take priority */
251 /* Check the cookie domain and path. Also, we never send "secure" cookies. These should only be sent over HTTPS. */
252 if ((right_hand_strcmp(list
->domain
, domain
) == 0)
253 && (left_hand_strcmp(list
->path
, path
) == 0) && !list
->secure
) {
255 for (i
= 0; i
< found_cookies
; i
++) {
256 if (strcmp(list
->name
, cookies
[i
]->name
) == 0) {
258 if (strlen(list
->domain
) <= strlen(cookies
[i
]->domain
)) {
260 } else if (strlen(list
->path
) <= strlen(cookies
[i
]->path
)) {
265 if (found_cookies
> MAX_COOKIES
) {
266 /* Cookie jar overflow! */
270 cookies
[found_cookies
++] = list
;
276 buf
= strdup("Cookie:");
278 for (i
= 0; i
< found_cookies
; i
++) {
281 nbuf
= malloc(strlen(buf
) + strlen(" ") + strlen(cookies
[i
]->name
) +
282 strlen("=") + strlen(cookies
[i
]->value
) + strlen(";") + 1);
283 sprintf(nbuf
, "%s %s=%s;", buf
, cookies
[i
]->name
,
290 http_set_field(http_hdr
, buf
);