3 * Reads Netscape and Mozilla cookies.txt files
5 * by Dave Lambley <mplayer@davel.me.uk>
13 #include <sys/types.h>
21 #define MAX_COOKIES 20
23 char *cookies_file
= NULL
;
25 typedef struct cookie_list_type
{
33 struct cookie_list_type
*next
;
36 /* Pointer to the linked list of cookies */
37 static struct cookie_list_type
*cookie_list
= NULL
;
40 /* Like strdup, but stops at anything <31. */
41 static char *col_dup(const char *src
)
46 while (src
[length
] > 31)
49 dst
= malloc(length
+ 1);
50 strncpy(dst
, src
, length
);
56 static int right_hand_strcmp(const char *cookie_domain
, const char *url_domain
)
61 c_l
= strlen(cookie_domain
);
62 u_l
= strlen(url_domain
);
66 return strcmp(cookie_domain
, url_domain
+ u_l
- c_l
);
69 static int left_hand_strcmp(const char *cookie_path
, const char *url_path
)
71 return strncmp(cookie_path
, url_path
, strlen(cookie_path
));
74 /* Finds the start of all the columns */
75 static int parse_line(char **ptr
, char *cols
[6])
80 for (col
= 1; col
< 7; col
++) {
81 for (; (**ptr
) > 31; (*ptr
)++);
93 /* Loads a file into RAM */
94 static char *load_file(const char *filename
, off_t
* length
)
99 mp_msg(MSGT_NETWORK
, MSGL_V
, "Loading cookie file: %s\n", filename
);
101 fd
= open(filename
, O_RDONLY
);
103 mp_msg(MSGT_NETWORK
, MSGL_V
, "Could not open");
107 *length
= lseek(fd
, 0, SEEK_END
);
110 mp_msg(MSGT_NETWORK
, MSGL_V
, "Could not find EOF");
114 if (*length
> SIZE_MAX
- 1) {
115 mp_msg(MSGT_NETWORK
, MSGL_V
, "File too big, could not malloc.");
119 lseek(fd
, SEEK_SET
, 0);
121 if (!(buffer
= malloc(*length
+ 1))) {
122 mp_msg(MSGT_NETWORK
, MSGL_V
, "Could not malloc.");
126 if (read(fd
, buffer
, *length
) != *length
) {
127 mp_msg(MSGT_NETWORK
, MSGL_V
, "Read is behaving funny.");
136 /* Loads a cookies.txt file into a linked list. */
137 static struct cookie_list_type
*load_cookies_from(const char *filename
,
138 struct cookie_list_type
144 mp_msg(MSGT_NETWORK
, MSGL_V
, "Loading cookie file: %s\n", filename
);
146 ptr
= load_file(filename
, &length
);
152 if (parse_line(&ptr
, cols
)) {
153 struct cookie_list_type
*new;
154 new = malloc(sizeof(cookie_list_t
));
155 new->name
= col_dup(cols
[5]);
156 new->value
= col_dup(cols
[6]);
157 new->path
= col_dup(cols
[2]);
158 new->domain
= col_dup(cols
[0]);
159 new->secure
= (*(cols
[3]) == 't') || (*(cols
[3]) == 'T');
167 /* Attempt to load cookies.txt from various locations. Returns a pointer to the linked list contain the cookies. */
168 static struct cookie_list_type
*load_cookies(void)
172 struct cookie_list_type
*list
= NULL
;
178 return load_cookies_from(cookies_file
, list
);
180 homedir
= getenv("HOME");
185 buf
= malloc(strlen(homedir
) + sizeof("/.mozilla/default") + 1);
186 sprintf(buf
, "%s/.mozilla/default", homedir
);
191 while ((ent
= readdir(dir
)) != NULL
) {
192 if ((ent
->d_name
)[0] != '.') {
193 buf
= malloc(strlen(getenv("HOME")) +
194 sizeof("/.mozilla/default/") +
195 strlen(ent
->d_name
) + sizeof("cookies.txt") + 1);
196 sprintf(buf
, "%s/.mozilla/default/%s/cookies.txt",
197 getenv("HOME"), ent
->d_name
);
198 list
= load_cookies_from(buf
, list
);
205 buf
= malloc(strlen(homedir
) + sizeof("/.netscape/cookies.txt") + 1);
206 sprintf(buf
, "%s/.netscape/cookies.txt", homedir
);
207 list
= load_cookies_from(buf
, list
);
213 /* Take an HTTP_header_t, and insert the correct headers. The cookie files are read if necessary. */
215 cookies_set(HTTP_header_t
* http_hdr
, const char *domain
, const char *url
)
217 int found_cookies
= 0;
218 struct cookie_list_type
*cookies
[MAX_COOKIES
];
219 struct cookie_list_type
*list
, *start
;
224 path
= strchr(url
, '/');
229 cookie_list
= load_cookies();
232 list
= start
= cookie_list
;
234 /* Find which cookies we want, removing duplicates. Cookies with the longest domain, then longest path take priority */
236 /* Check the cookie domain and path. Also, we never send "secure" cookies. These should only be sent over HTTPS. */
237 if ((right_hand_strcmp(list
->domain
, domain
) == 0)
238 && (left_hand_strcmp(list
->path
, path
) == 0) && !list
->secure
) {
240 for (i
= 0; i
< found_cookies
; i
++) {
241 if (strcmp(list
->name
, cookies
[i
]->name
) == 0) {
243 if (strlen(list
->domain
) <= strlen(cookies
[i
]->domain
)) {
245 } else if (strlen(list
->path
) <= strlen(cookies
[i
]->path
)) {
250 if (found_cookies
> MAX_COOKIES
) {
251 /* Cookie jar overflow! */
255 cookies
[found_cookies
++] = list
;
261 buf
= strdup("Cookie:");
263 for (i
= 0; i
< found_cookies
; i
++) {
266 nbuf
= malloc(strlen(buf
) + strlen(" ") + strlen(cookies
[i
]->name
) +
267 strlen("=") + strlen(cookies
[i
]->value
) + strlen(";") + 1);
268 sprintf(nbuf
, "%s %s=%s;", buf
, cookies
[i
]->name
,
275 http_set_field(http_hdr
, buf
);