~ubuntu-dev/mplayer/ubuntu-feisty

« back to all changes in this revision

Viewing changes to stream/cookies.c

  • Committer: William Grant
  • Date: 2007-02-03 03:16:07 UTC
  • mto: This revision was merged to the branch mainline in revision 16.
  • Revision ID: william.grant@ubuntu.org.au-20070203031607-08gc2ompbz6spt9i
Update to 1.0rc1.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * HTTP Cookies
 
3
 * Reads Netscape and Mozilla cookies.txt files
 
4
 *
 
5
 * by Dave Lambley <mplayer@davel.me.uk>
 
6
 */
 
7
 
 
8
#include <stdio.h>
 
9
#include <stdlib.h>
 
10
#include <fcntl.h>
 
11
#include <string.h>
 
12
#include <unistd.h>
 
13
#include <sys/types.h>
 
14
#include <dirent.h>
 
15
#include <inttypes.h>
 
16
#include <limits.h>
 
17
 
 
18
#include "cookies.h"
 
19
#include "http.h"
 
20
#include "mp_msg.h"
 
21
 
 
22
#define MAX_COOKIES 20
 
23
 
 
24
char *cookies_file = NULL;
 
25
 
 
26
typedef struct cookie_list_type {
 
27
    char *name;
 
28
    char *value;
 
29
    char *domain;
 
30
    char *path;
 
31
 
 
32
    int secure;
 
33
 
 
34
    struct cookie_list_type *next;
 
35
} cookie_list_t;
 
36
 
 
37
/* Pointer to the linked list of cookies */
 
38
static struct cookie_list_type *cookie_list = NULL;
 
39
 
 
40
 
 
41
/* Like strdup, but stops at anything <31. */
 
42
static char *col_dup(const char *src)
 
43
{
 
44
    char *dst;
 
45
    int length = 0;
 
46
 
 
47
    while (src[length] > 31)
 
48
        length++;
 
49
 
 
50
    dst = malloc(length + 1);
 
51
    strncpy(dst, src, length);
 
52
    dst[length] = 0;
 
53
 
 
54
    return dst;
 
55
}
 
56
 
 
57
static int right_hand_strcmp(const char *cookie_domain, const char *url_domain)
 
58
{
 
59
    int c_l;
 
60
    int u_l;
 
61
 
 
62
    c_l = strlen(cookie_domain);
 
63
    u_l = strlen(url_domain);
 
64
 
 
65
    if (c_l > u_l)
 
66
        return -1;
 
67
    return strcmp(cookie_domain, url_domain + u_l - c_l);
 
68
}
 
69
 
 
70
static int left_hand_strcmp(const char *cookie_path, const char *url_path)
 
71
{
 
72
    return strncmp(cookie_path, url_path, strlen(cookie_path));
 
73
}
 
74
 
 
75
/* Finds the start of all the columns */
 
76
static int parse_line(char **ptr, char *cols[6])
 
77
{
 
78
    int col;
 
79
    cols[0] = *ptr;
 
80
 
 
81
    for (col = 1; col < 7; col++) {
 
82
        for (; (**ptr) > 31; (*ptr)++);
 
83
        if (**ptr == 0)
 
84
            return 0;
 
85
        (*ptr)++;
 
86
        if ((*ptr)[-1] != 9)
 
87
            return 0;
 
88
        cols[col] = (*ptr);
 
89
    }
 
90
 
 
91
    return 1;
 
92
}
 
93
 
 
94
/* Loads a file into RAM */
 
95
static char *load_file(const char *filename, off_t * length)
 
96
{
 
97
    int fd;
 
98
    char *buffer;
 
99
 
 
100
    mp_msg(MSGT_NETWORK, MSGL_V, "Loading cookie file: %s\n", filename);
 
101
 
 
102
    fd = open(filename, O_RDONLY);
 
103
    if (fd < 0) {
 
104
        mp_msg(MSGT_NETWORK, MSGL_V, "Could not open");
 
105
        return NULL;
 
106
    }
 
107
 
 
108
    *length = lseek(fd, 0, SEEK_END);
 
109
 
 
110
    if (*length < 0) {
 
111
        mp_msg(MSGT_NETWORK, MSGL_V, "Could not find EOF");
 
112
        return NULL;
 
113
    }
 
114
 
 
115
    if (*length > SIZE_MAX - 1) {
 
116
        mp_msg(MSGT_NETWORK, MSGL_V, "File too big, could not malloc.");
 
117
        return NULL;
 
118
    }
 
119
 
 
120
    lseek(fd, SEEK_SET, 0);
 
121
 
 
122
    if (!(buffer = malloc(*length + 1))) {
 
123
        mp_msg(MSGT_NETWORK, MSGL_V, "Could not malloc.");
 
124
        return NULL;
 
125
    }
 
126
 
 
127
    if (read(fd, buffer, *length) != *length) {
 
128
        mp_msg(MSGT_NETWORK, MSGL_V, "Read is behaving funny.");
 
129
        return NULL;
 
130
    }
 
131
    close(fd);
 
132
    buffer[*length] = 0;
 
133
 
 
134
    return buffer;
 
135
}
 
136
 
 
137
/* Loads a cookies.txt file into a linked list. */
 
138
static struct cookie_list_type *load_cookies_from(const char *filename,
 
139
                                                  struct cookie_list_type
 
140
                                                  *list)
 
141
{
 
142
    char *ptr;
 
143
    off_t length;
 
144
 
 
145
    mp_msg(MSGT_NETWORK, MSGL_V, "Loading cookie file: %s\n", filename);
 
146
 
 
147
    ptr = load_file(filename, &length);
 
148
    if (!ptr)
 
149
        return list;
 
150
 
 
151
    while (*ptr > 0) {
 
152
        char *cols[7];
 
153
        if (parse_line(&ptr, cols)) {
 
154
            struct cookie_list_type *new;
 
155
            new = malloc(sizeof(cookie_list_t));
 
156
            new->name = col_dup(cols[5]);
 
157
            new->value = col_dup(cols[6]);
 
158
            new->path = col_dup(cols[2]);
 
159
            new->domain = col_dup(cols[0]);
 
160
            new->secure = (*(cols[3]) == 't') || (*(cols[3]) == 'T');
 
161
            new->next = list;
 
162
            list = new;
 
163
        }
 
164
    }
 
165
    return list;
 
166
}
 
167
 
 
168
/* Attempt to load cookies.txt from various locations. Returns a pointer to the linked list contain the cookies. */
 
169
static struct cookie_list_type *load_cookies(void)
 
170
{
 
171
    DIR *dir;
 
172
    struct dirent *ent;
 
173
    struct cookie_list_type *list = NULL;
 
174
    char *buf;
 
175
 
 
176
    char *homedir;
 
177
 
 
178
    if (cookies_file)
 
179
        return load_cookies_from(cookies_file, list);
 
180
 
 
181
    homedir = getenv("HOME");
 
182
    if (!homedir)
 
183
        return list;
 
184
 
 
185
 
 
186
    buf = malloc(strlen(homedir) + sizeof("/.mozilla/default") + 1);
 
187
    sprintf(buf, "%s/.mozilla/default", homedir);
 
188
    dir = opendir(buf);
 
189
    free(buf);
 
190
 
 
191
    if (dir) {
 
192
        while ((ent = readdir(dir)) != NULL) {
 
193
            if ((ent->d_name)[0] != '.') {
 
194
                buf = malloc(strlen(getenv("HOME")) + 
 
195
                             sizeof("/.mozilla/default/") + 
 
196
                             strlen(ent->d_name) + sizeof("cookies.txt") + 1);
 
197
                sprintf(buf, "%s/.mozilla/default/%s/cookies.txt",
 
198
                         getenv("HOME"), ent->d_name);
 
199
                list = load_cookies_from(buf, list);
 
200
                free(buf);
 
201
            }
 
202
        }
 
203
        closedir(dir);
 
204
    }
 
205
 
 
206
    buf = malloc(strlen(homedir) + sizeof("/.netscape/cookies.txt") + 1);
 
207
    sprintf(buf, "%s/.netscape/cookies.txt", homedir);
 
208
    list = load_cookies_from(buf, list);
 
209
    free(buf);
 
210
 
 
211
    return list;
 
212
}
 
213
 
 
214
/* Take an HTTP_header_t, and insert the correct headers. The cookie files are read if necessary. */
 
215
void
 
216
cookies_set(HTTP_header_t * http_hdr, const char *domain, const char *url)
 
217
{
 
218
    int found_cookies = 0;
 
219
    struct cookie_list_type *cookies[MAX_COOKIES];
 
220
    struct cookie_list_type *list, *start;
 
221
    int i;
 
222
    char *path;
 
223
    char *buf;
 
224
 
 
225
    path = strchr(url, '/');
 
226
    if (!path)
 
227
        path = "";
 
228
 
 
229
    if (!cookie_list)
 
230
        cookie_list = load_cookies();
 
231
 
 
232
 
 
233
    list = start = cookie_list;
 
234
 
 
235
    /* Find which cookies we want, removing duplicates. Cookies with the longest domain, then longest path take priority */
 
236
    while (list) {
 
237
        /* Check the cookie domain and path. Also, we never send "secure" cookies. These should only be sent over HTTPS. */
 
238
        if ((right_hand_strcmp(list->domain, domain) == 0)
 
239
            && (left_hand_strcmp(list->path, path) == 0) && !list->secure) {
 
240
            int replacing = 0;
 
241
            for (i = 0; i < found_cookies; i++) {
 
242
                if (strcmp(list->name, cookies[i]->name) == 0) {
 
243
                    replacing = 0;
 
244
                    if (strlen(list->domain) <= strlen(cookies[i]->domain)) {
 
245
                        cookies[i] = list;
 
246
                    } else if (strlen(list->path) <= strlen(cookies[i]->path)) {
 
247
                        cookies[i] = list;
 
248
                    }
 
249
                }
 
250
            }
 
251
            if (found_cookies > MAX_COOKIES) {
 
252
                /* Cookie jar overflow! */
 
253
                break;
 
254
            }
 
255
            if (!replacing)
 
256
                cookies[found_cookies++] = list;
 
257
        }
 
258
        list = list->next;
 
259
    }
 
260
 
 
261
 
 
262
    buf = strdup("Cookie:");
 
263
 
 
264
    for (i = 0; i < found_cookies; i++) {
 
265
        char *nbuf;
 
266
 
 
267
        nbuf = malloc(strlen(buf) + strlen(" ") + strlen(cookies[i]->name) +
 
268
                    strlen("=") + strlen(cookies[i]->value) + strlen(";") + 1);
 
269
        sprintf(nbuf, "%s %s=%s;", buf, cookies[i]->name,
 
270
                 cookies[i]->value);
 
271
        free(buf);
 
272
        buf = nbuf;
 
273
    }
 
274
 
 
275
    if (found_cookies)
 
276
        http_set_field(http_hdr, buf);
 
277
    else
 
278
        free(buf);
 
279
}