options: move various mplayer.c options to option struct
[mplayer.git] / stream / cookies.c
blob3b266a5ca2ba34327c50d65f6339b7973be84aeb
1 /*
2 * HTTP Cookies
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.
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <fcntl.h>
27 #include <string.h>
28 #include <unistd.h>
29 #include <sys/types.h>
30 #include <dirent.h>
31 #include <inttypes.h>
32 #include <limits.h>
34 #include "cookies.h"
35 #include "http.h"
36 #include "mp_msg.h"
38 #define MAX_COOKIES 20
40 char *cookies_file = NULL;
42 typedef struct cookie_list_type {
43 char *name;
44 char *value;
45 char *domain;
46 char *path;
48 int secure;
50 struct cookie_list_type *next;
51 } cookie_list_t;
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)
60 char *dst;
61 int length = 0;
63 while (src[length] > 31)
64 length++;
66 dst = malloc(length + 1);
67 strncpy(dst, src, length);
68 dst[length] = 0;
70 return dst;
73 static int right_hand_strcmp(const char *cookie_domain, const char *url_domain)
75 int c_l;
76 int u_l;
78 c_l = strlen(cookie_domain);
79 u_l = strlen(url_domain);
81 if (c_l > u_l)
82 return -1;
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])
94 int col;
95 cols[0] = *ptr;
97 for (col = 1; col < 7; col++) {
98 for (; (**ptr) > 31; (*ptr)++);
99 if (**ptr == 0)
100 return 0;
101 (*ptr)++;
102 if ((*ptr)[-1] != 9)
103 return 0;
104 cols[col] = (*ptr);
107 return 1;
110 /* Loads a file into RAM */
111 static char *load_file(const char *filename, off_t * length)
113 int fd;
114 char *buffer;
116 mp_msg(MSGT_NETWORK, MSGL_V, "Loading cookie file: %s\n", filename);
118 fd = open(filename, O_RDONLY);
119 if (fd < 0) {
120 mp_msg(MSGT_NETWORK, MSGL_V, "Could not open");
121 return NULL;
124 *length = lseek(fd, 0, SEEK_END);
126 if (*length < 0) {
127 mp_msg(MSGT_NETWORK, MSGL_V, "Could not find EOF");
128 return NULL;
131 if (*length > SIZE_MAX - 1) {
132 mp_msg(MSGT_NETWORK, MSGL_V, "File too big, could not malloc.");
133 return NULL;
136 lseek(fd, 0, SEEK_SET);
138 if (!(buffer = malloc(*length + 1))) {
139 mp_msg(MSGT_NETWORK, MSGL_V, "Could not malloc.");
140 return NULL;
143 if (read(fd, buffer, *length) != *length) {
144 mp_msg(MSGT_NETWORK, MSGL_V, "Read is behaving funny.");
145 return NULL;
147 close(fd);
148 buffer[*length] = 0;
150 return buffer;
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
156 *list)
158 char *ptr;
159 off_t length;
161 ptr = load_file(filename, &length);
162 if (!ptr)
163 return list;
165 while (*ptr > 0) {
166 char *cols[7];
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');
175 new->next = list;
176 list = new;
179 return list;
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)
185 DIR *dir;
186 struct dirent *ent;
187 struct cookie_list_type *list = NULL;
188 char *buf;
190 char *homedir;
192 if (cookies_file)
193 return load_cookies_from(cookies_file, list);
195 homedir = getenv("HOME");
196 if (!homedir)
197 return list;
200 buf = malloc(strlen(homedir) + sizeof("/.mozilla/default") + 1);
201 sprintf(buf, "%s/.mozilla/default", homedir);
202 dir = opendir(buf);
203 free(buf);
205 if (dir) {
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);
214 free(buf);
217 closedir(dir);
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);
223 free(buf);
225 return list;
228 /* Take an HTTP_header_t, and insert the correct headers. The cookie files are read if necessary. */
229 void
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;
235 int i;
236 char *path;
237 char *buf;
239 path = strchr(url, '/');
240 if (!path)
241 path = "";
243 if (!cookie_list)
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 */
250 while (list) {
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) {
254 int replacing = 0;
255 for (i = 0; i < found_cookies; i++) {
256 if (strcmp(list->name, cookies[i]->name) == 0) {
257 replacing = 0;
258 if (strlen(list->domain) <= strlen(cookies[i]->domain)) {
259 cookies[i] = list;
260 } else if (strlen(list->path) <= strlen(cookies[i]->path)) {
261 cookies[i] = list;
265 if (found_cookies > MAX_COOKIES) {
266 /* Cookie jar overflow! */
267 break;
269 if (!replacing)
270 cookies[found_cookies++] = list;
272 list = list->next;
276 buf = strdup("Cookie:");
278 for (i = 0; i < found_cookies; i++) {
279 char *nbuf;
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,
284 cookies[i]->value);
285 free(buf);
286 buf = nbuf;
289 if (found_cookies)
290 http_set_field(http_hdr, buf);
291 else
292 free(buf);