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 mp_msg(MSGT_NETWORK
, MSGL_V
, "Loading cookie file: %s\n", filename
);
163 ptr
= load_file(filename
, &length
);
169 if (parse_line(&ptr
, cols
)) {
170 struct cookie_list_type
*new;
171 new = malloc(sizeof(cookie_list_t
));
172 new->name
= col_dup(cols
[5]);
173 new->value
= col_dup(cols
[6]);
174 new->path
= col_dup(cols
[2]);
175 new->domain
= col_dup(cols
[0]);
176 new->secure
= (*(cols
[3]) == 't') || (*(cols
[3]) == 'T');
184 /* Attempt to load cookies.txt from various locations. Returns a pointer to the linked list contain the cookies. */
185 static struct cookie_list_type
*load_cookies(void)
189 struct cookie_list_type
*list
= NULL
;
195 return load_cookies_from(cookies_file
, list
);
197 homedir
= getenv("HOME");
202 buf
= malloc(strlen(homedir
) + sizeof("/.mozilla/default") + 1);
203 sprintf(buf
, "%s/.mozilla/default", homedir
);
208 while ((ent
= readdir(dir
)) != NULL
) {
209 if ((ent
->d_name
)[0] != '.') {
210 buf
= malloc(strlen(getenv("HOME")) +
211 sizeof("/.mozilla/default/") +
212 strlen(ent
->d_name
) + sizeof("cookies.txt") + 1);
213 sprintf(buf
, "%s/.mozilla/default/%s/cookies.txt",
214 getenv("HOME"), ent
->d_name
);
215 list
= load_cookies_from(buf
, list
);
222 buf
= malloc(strlen(homedir
) + sizeof("/.netscape/cookies.txt") + 1);
223 sprintf(buf
, "%s/.netscape/cookies.txt", homedir
);
224 list
= load_cookies_from(buf
, list
);
230 /* Take an HTTP_header_t, and insert the correct headers. The cookie files are read if necessary. */
232 cookies_set(HTTP_header_t
* http_hdr
, const char *domain
, const char *url
)
234 int found_cookies
= 0;
235 struct cookie_list_type
*cookies
[MAX_COOKIES
];
236 struct cookie_list_type
*list
, *start
;
241 path
= strchr(url
, '/');
246 cookie_list
= load_cookies();
249 list
= start
= cookie_list
;
251 /* Find which cookies we want, removing duplicates. Cookies with the longest domain, then longest path take priority */
253 /* Check the cookie domain and path. Also, we never send "secure" cookies. These should only be sent over HTTPS. */
254 if ((right_hand_strcmp(list
->domain
, domain
) == 0)
255 && (left_hand_strcmp(list
->path
, path
) == 0) && !list
->secure
) {
257 for (i
= 0; i
< found_cookies
; i
++) {
258 if (strcmp(list
->name
, cookies
[i
]->name
) == 0) {
260 if (strlen(list
->domain
) <= strlen(cookies
[i
]->domain
)) {
262 } else if (strlen(list
->path
) <= strlen(cookies
[i
]->path
)) {
267 if (found_cookies
> MAX_COOKIES
) {
268 /* Cookie jar overflow! */
272 cookies
[found_cookies
++] = list
;
278 buf
= strdup("Cookie:");
280 for (i
= 0; i
< found_cookies
; i
++) {
283 nbuf
= malloc(strlen(buf
) + strlen(" ") + strlen(cookies
[i
]->name
) +
284 strlen("=") + strlen(cookies
[i
]->value
) + strlen(";") + 1);
285 sprintf(nbuf
, "%s %s=%s;", buf
, cookies
[i
]->name
,
292 http_set_field(http_hdr
, buf
);