Sunc with trunk revision 58971.
[reactos.git] / dll / win32 / winhttp / cookie.c
1 /*
2 * Copyright 2008 Hans Leidekker for CodeWeavers
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
17 */
18
19 #define WIN32_NO_STATUS
20 #define _INC_WINDOWS
21 #define COM_NO_WINDOWS_H
22
23 #include <config.h>
24 //#include <stdarg.h>
25
26 #include <wine/debug.h>
27 //#include "wine/list.h"
28
29 //#include "windef.h"
30 #include <winbase.h>
31 #include <winhttp.h>
32
33 #include "winhttp_private.h"
34
35 WINE_DEFAULT_DEBUG_CHANNEL(winhttp);
36
37 static domain_t *add_domain( session_t *session, WCHAR *name )
38 {
39 domain_t *domain;
40
41 if (!(domain = heap_alloc_zero( sizeof(domain_t) ))) return NULL;
42
43 list_init( &domain->entry );
44 list_init( &domain->cookies );
45
46 domain->name = strdupW( name );
47 list_add_tail( &session->cookie_cache, &domain->entry );
48
49 TRACE("%s\n", debugstr_w(domain->name));
50 return domain;
51 }
52
53 static cookie_t *find_cookie( domain_t *domain, const WCHAR *path, const WCHAR *name )
54 {
55 struct list *item;
56 cookie_t *cookie;
57
58 LIST_FOR_EACH( item, &domain->cookies )
59 {
60 cookie = LIST_ENTRY( item, cookie_t, entry );
61 if (!strcmpW( cookie->path, path ) && !strcmpiW( cookie->name, name ))
62 {
63 TRACE("found %s=%s\n", debugstr_w(cookie->name), debugstr_w(cookie->value));
64 return cookie;
65 }
66 }
67 return NULL;
68 }
69
70 static BOOL domain_match( const WCHAR *name, domain_t *domain, BOOL partial )
71 {
72 TRACE("comparing %s with %s\n", debugstr_w(name), debugstr_w(domain->name));
73
74 if (partial && !strstrW( name, domain->name )) return FALSE;
75 else if (!partial && strcmpW( name, domain->name )) return FALSE;
76 return TRUE;
77 }
78
79 static void free_cookie( cookie_t *cookie )
80 {
81 heap_free( cookie->name );
82 heap_free( cookie->value );
83 heap_free( cookie->path );
84 heap_free( cookie );
85 }
86
87 static void delete_cookie( cookie_t *cookie )
88 {
89 list_remove( &cookie->entry );
90 free_cookie( cookie );
91 }
92
93 void delete_domain( domain_t *domain )
94 {
95 cookie_t *cookie;
96 struct list *item, *next;
97
98 LIST_FOR_EACH_SAFE( item, next, &domain->cookies )
99 {
100 cookie = LIST_ENTRY( item, cookie_t, entry );
101 delete_cookie( cookie );
102 }
103
104 list_remove( &domain->entry );
105 heap_free( domain->name );
106 heap_free( domain );
107 }
108
109 static BOOL add_cookie( session_t *session, cookie_t *cookie, WCHAR *domain_name, WCHAR *path )
110 {
111 domain_t *domain = NULL;
112 cookie_t *old_cookie;
113 struct list *item;
114
115 LIST_FOR_EACH( item, &session->cookie_cache )
116 {
117 domain = LIST_ENTRY( item, domain_t, entry );
118 if (domain_match( domain_name, domain, FALSE )) break;
119 domain = NULL;
120 }
121 if (!domain)
122 {
123 if (!(domain = add_domain( session, domain_name ))) return FALSE;
124 }
125 else if ((old_cookie = find_cookie( domain, path, cookie->name ))) delete_cookie( old_cookie );
126
127 cookie->path = strdupW( path );
128 list_add_tail( &domain->cookies, &cookie->entry );
129
130 TRACE("domain %s path %s <- %s=%s\n", debugstr_w(domain_name), debugstr_w(cookie->path),
131 debugstr_w(cookie->name), debugstr_w(cookie->value));
132 return TRUE;
133 }
134
135 static cookie_t *parse_cookie( const WCHAR *string )
136 {
137 cookie_t *cookie;
138 const WCHAR *p;
139 int len;
140
141 if (!(cookie = heap_alloc_zero( sizeof(cookie_t) ))) return NULL;
142
143 list_init( &cookie->entry );
144
145 if (!(p = strchrW( string, '=' )))
146 {
147 WARN("no '=' in %s\n", debugstr_w(string));
148 return NULL;
149 }
150 if (p == string)
151 {
152 WARN("empty cookie name in %s\n", debugstr_w(string));
153 return NULL;
154 }
155 len = p - string;
156 if (!(cookie->name = heap_alloc( (len + 1) * sizeof(WCHAR) )))
157 {
158 heap_free( cookie );
159 return NULL;
160 }
161 memcpy( cookie->name, string, len * sizeof(WCHAR) );
162 cookie->name[len] = 0;
163
164 p++; /* skip '=' */
165 while (*p == ' ') p++;
166
167 len = strlenW( p );
168 if (!(cookie->value = heap_alloc( (len + 1) * sizeof(WCHAR) )))
169 {
170 free_cookie( cookie );
171 return NULL;
172 }
173 memcpy( cookie->value, p, len * sizeof(WCHAR) );
174 cookie->value[len] = 0;
175
176 return cookie;
177 }
178
179 BOOL set_cookies( request_t *request, const WCHAR *cookies )
180 {
181 static const WCHAR pathW[] = {'p','a','t','h',0};
182 static const WCHAR domainW[] = {'d','o','m','a','i','n',0};
183
184 BOOL ret = FALSE;
185 WCHAR *buffer, *p, *q, *r;
186 WCHAR *cookie_domain = NULL, *cookie_path = NULL;
187 session_t *session = request->connect->session;
188 cookie_t *cookie;
189 int len;
190
191 len = strlenW( cookies );
192 if (!(buffer = heap_alloc( (len + 1) * sizeof(WCHAR) ))) return FALSE;
193 strcpyW( buffer, cookies );
194
195 p = buffer;
196 while (*p && *p != ';') p++;
197 if (*p == ';') *p++ = 0;
198 if (!(cookie = parse_cookie( buffer )))
199 {
200 heap_free( buffer );
201 return FALSE;
202 }
203 if ((q = strstrW( p, domainW ))) /* FIXME: do real attribute parsing */
204 {
205 while (*q && *q != '=') q++;
206 if (!*q) goto end;
207
208 r = ++q;
209 while (*r && *r != ';') r++;
210 len = r - q;
211
212 if (!(cookie_domain = heap_alloc( (len + 1) * sizeof(WCHAR) ))) goto end;
213 memcpy( cookie_domain, q, len * sizeof(WCHAR) );
214 cookie_domain[len] = 0;
215
216 }
217 if ((q = strstrW( p, pathW )))
218 {
219 while (*q && *q != '=') q++;
220 if (!*q) goto end;
221
222 r = ++q;
223 while (*r && *r != ';') r++;
224 len = r - q;
225
226 if (!(cookie_path = heap_alloc( (len + 1) * sizeof(WCHAR) ))) goto end;
227 memcpy( cookie_path, q, len * sizeof(WCHAR) );
228 cookie_path[len] = 0;
229 }
230 if (!cookie_domain && !(cookie_domain = strdupW( request->connect->servername ))) goto end;
231 if (!cookie_path && !(cookie_path = strdupW( request->path ))) goto end;
232
233 if ((p = strrchrW( cookie_path, '/' )) && p != cookie_path) *p = 0;
234 ret = add_cookie( session, cookie, cookie_domain, cookie_path );
235
236 end:
237 if (!ret) free_cookie( cookie );
238 heap_free( cookie_domain );
239 heap_free( cookie_path );
240 heap_free( buffer );
241 return ret;
242 }
243
244 BOOL add_cookie_headers( request_t *request )
245 {
246 struct list *domain_cursor;
247 session_t *session = request->connect->session;
248
249 LIST_FOR_EACH( domain_cursor, &session->cookie_cache )
250 {
251 domain_t *domain = LIST_ENTRY( domain_cursor, domain_t, entry );
252 if (domain_match( request->connect->servername, domain, TRUE ))
253 {
254 struct list *cookie_cursor;
255 TRACE("found domain %s\n", debugstr_w(domain->name));
256
257 LIST_FOR_EACH( cookie_cursor, &domain->cookies )
258 {
259 cookie_t *cookie = LIST_ENTRY( cookie_cursor, cookie_t, entry );
260
261 TRACE("comparing path %s with %s\n", debugstr_w(request->path), debugstr_w(cookie->path));
262
263 if (strstrW( request->path, cookie->path ) == request->path)
264 {
265 const WCHAR format[] = {'C','o','o','k','i','e',':',' ','%','s','=','%','s',0};
266 int len;
267 WCHAR *header;
268
269 len = strlenW( cookie->name ) + strlenW( format ) + strlenW( cookie->value );
270 if (!(header = heap_alloc( (len + 1) * sizeof(WCHAR) ))) return FALSE;
271
272 sprintfW( header, format, cookie->name, cookie->value );
273
274 TRACE("%s\n", debugstr_w(header));
275 add_request_headers( request, header, len, WINHTTP_ADDREQ_FLAG_ADD );
276 heap_free( header );
277 }
278 }
279 }
280 }
281 return TRUE;
282 }