Fix vf_tcdump's compilation
[mplayer/kovensky.git] / stream / cookies.c
blobb7e89c79e600717c7c00e633e3cac890c47647e1
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 mp_msg(MSGT_NETWORK, MSGL_V, "Loading cookie file: %s\n", filename);
163 ptr = load_file(filename, &length);
164 if (!ptr)
165 return list;
167 while (*ptr > 0) {
168 char *cols[7];
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');
177 new->next = list;
178 list = new;
181 return list;
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)
187 DIR *dir;
188 struct dirent *ent;
189 struct cookie_list_type *list = NULL;
190 char *buf;
192 char *homedir;
194 if (cookies_file)
195 return load_cookies_from(cookies_file, list);
197 homedir = getenv("HOME");
198 if (!homedir)
199 return list;
202 buf = malloc(strlen(homedir) + sizeof("/.mozilla/default") + 1);
203 sprintf(buf, "%s/.mozilla/default", homedir);
204 dir = opendir(buf);
205 free(buf);
207 if (dir) {
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);
216 free(buf);
219 closedir(dir);
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);
225 free(buf);
227 return list;
230 /* Take an HTTP_header_t, and insert the correct headers. The cookie files are read if necessary. */
231 void
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;
237 int i;
238 char *path;
239 char *buf;
241 path = strchr(url, '/');
242 if (!path)
243 path = "";
245 if (!cookie_list)
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 */
252 while (list) {
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) {
256 int replacing = 0;
257 for (i = 0; i < found_cookies; i++) {
258 if (strcmp(list->name, cookies[i]->name) == 0) {
259 replacing = 0;
260 if (strlen(list->domain) <= strlen(cookies[i]->domain)) {
261 cookies[i] = list;
262 } else if (strlen(list->path) <= strlen(cookies[i]->path)) {
263 cookies[i] = list;
267 if (found_cookies > MAX_COOKIES) {
268 /* Cookie jar overflow! */
269 break;
271 if (!replacing)
272 cookies[found_cookies++] = list;
274 list = list->next;
278 buf = strdup("Cookie:");
280 for (i = 0; i < found_cookies; i++) {
281 char *nbuf;
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,
286 cookies[i]->value);
287 free(buf);
288 buf = nbuf;
291 if (found_cookies)
292 http_set_field(http_hdr, buf);
293 else
294 free(buf);