2 * Copyright 2008 Hans Leidekker for CodeWeavers
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.
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.
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
22 #include "wine/debug.h"
23 #include "wine/list.h"
29 #include "winhttp_private.h"
31 WINE_DEFAULT_DEBUG_CHANNEL(winhttp
);
33 static domain_t
*add_domain( session_t
*session
, WCHAR
*name
)
37 if (!(domain
= heap_alloc_zero( sizeof(domain_t
) ))) return NULL
;
39 list_init( &domain
->entry
);
40 list_init( &domain
->cookies
);
42 domain
->name
= strdupW( name
);
43 list_add_tail( &session
->cookie_cache
, &domain
->entry
);
45 TRACE("%s\n", debugstr_w(domain
->name
));
49 static cookie_t
*find_cookie( domain_t
*domain
, const WCHAR
*path
, const WCHAR
*name
)
54 LIST_FOR_EACH( item
, &domain
->cookies
)
56 cookie
= LIST_ENTRY( item
, cookie_t
, entry
);
57 if (!strcmpW( cookie
->path
, path
) && !strcmpW( cookie
->name
, name
))
59 TRACE("found %s=%s\n", debugstr_w(cookie
->name
), debugstr_w(cookie
->value
));
66 static BOOL
domain_match( const WCHAR
*name
, domain_t
*domain
, BOOL partial
)
68 TRACE("comparing %s with %s\n", debugstr_w(name
), debugstr_w(domain
->name
));
70 if (partial
&& !strstrW( name
, domain
->name
)) return FALSE
;
71 else if (!partial
&& strcmpW( name
, domain
->name
)) return FALSE
;
75 static void free_cookie( cookie_t
*cookie
)
77 heap_free( cookie
->name
);
78 heap_free( cookie
->value
);
79 heap_free( cookie
->path
);
83 static void delete_cookie( cookie_t
*cookie
)
85 list_remove( &cookie
->entry
);
86 free_cookie( cookie
);
89 void delete_domain( domain_t
*domain
)
92 struct list
*item
, *next
;
94 LIST_FOR_EACH_SAFE( item
, next
, &domain
->cookies
)
96 cookie
= LIST_ENTRY( item
, cookie_t
, entry
);
97 delete_cookie( cookie
);
100 list_remove( &domain
->entry
);
101 heap_free( domain
->name
);
105 static BOOL
add_cookie( session_t
*session
, cookie_t
*cookie
, WCHAR
*domain_name
, WCHAR
*path
)
107 domain_t
*domain
= NULL
;
108 cookie_t
*old_cookie
;
111 LIST_FOR_EACH( item
, &session
->cookie_cache
)
113 domain
= LIST_ENTRY( item
, domain_t
, entry
);
114 if (domain_match( domain_name
, domain
, FALSE
)) break;
119 if (!(domain
= add_domain( session
, domain_name
))) return FALSE
;
121 else if ((old_cookie
= find_cookie( domain
, path
, cookie
->name
))) delete_cookie( old_cookie
);
123 cookie
->path
= strdupW( path
);
124 list_add_head( &domain
->cookies
, &cookie
->entry
);
126 TRACE("domain %s path %s <- %s=%s\n", debugstr_w(domain_name
), debugstr_w(cookie
->path
),
127 debugstr_w(cookie
->name
), debugstr_w(cookie
->value
));
131 static cookie_t
*parse_cookie( const WCHAR
*string
)
137 if (!(p
= strchrW( string
, '=' ))) p
= string
+ strlenW( string
);
139 while (len
&& string
[len
- 1] == ' ') len
--;
140 if (!len
) return NULL
;
142 if (!(cookie
= heap_alloc_zero( sizeof(cookie_t
) ))) return NULL
;
143 list_init( &cookie
->entry
);
145 if (!(cookie
->name
= heap_alloc( (len
+ 1) * sizeof(WCHAR
) )))
150 memcpy( cookie
->name
, string
, len
* sizeof(WCHAR
) );
151 cookie
->name
[len
] = 0;
155 while (*p
== ' ') p
++;
157 while (len
&& p
[len
- 1] == ' ') len
--;
159 if (!(cookie
->value
= heap_alloc( (len
+ 1) * sizeof(WCHAR
) )))
161 free_cookie( cookie
);
164 memcpy( cookie
->value
, p
, len
* sizeof(WCHAR
) );
165 cookie
->value
[len
] = 0;
176 static void free_attr( struct attr
*attr
)
179 heap_free( attr
->name
);
180 heap_free( attr
->value
);
184 static struct attr
*parse_attr( const WCHAR
*str
, int *used
)
186 const WCHAR
*p
= str
, *q
;
190 while (*p
== ' ') p
++;
192 while (*q
&& *q
!= ' ' && *q
!= '=' && *q
!= ';') q
++;
194 if (!len
) return NULL
;
196 if (!(attr
= heap_alloc( sizeof(struct attr
) ))) return NULL
;
197 if (!(attr
->name
= heap_alloc( (len
+ 1) * sizeof(WCHAR
) )))
202 memcpy( attr
->name
, p
, len
* sizeof(WCHAR
) );
207 while (*p
== ' ') p
++;
210 while (*p
== ' ') p
++;
212 while (*q
&& *q
!= ';') q
++;
214 while (len
&& p
[len
- 1] == ' ') len
--;
216 if (!(attr
->value
= heap_alloc( (len
+ 1) * sizeof(WCHAR
) )))
221 memcpy( attr
->value
, p
, len
* sizeof(WCHAR
) );
222 attr
->value
[len
] = 0;
225 while (*q
== ' ') q
++;
232 BOOL
set_cookies( request_t
*request
, const WCHAR
*cookies
)
234 static const WCHAR pathW
[] = {'p','a','t','h',0};
235 static const WCHAR domainW
[] = {'d','o','m','a','i','n',0};
238 WCHAR
*cookie_domain
= NULL
, *cookie_path
= NULL
;
239 struct attr
*attr
, *domain
= NULL
, *path
= NULL
;
240 session_t
*session
= request
->connect
->session
;
244 len
= strlenW( cookies
);
245 if (!(buffer
= heap_alloc( (len
+ 1) * sizeof(WCHAR
) ))) return FALSE
;
246 strcpyW( buffer
, cookies
);
249 while (*p
&& *p
!= ';') p
++;
250 if (*p
== ';') *p
++ = 0;
251 if (!(cookie
= parse_cookie( buffer
)))
257 while (len
&& (attr
= parse_attr( p
, &used
)))
259 if (!strcmpiW( attr
->name
, domainW
))
262 cookie_domain
= attr
->value
;
264 else if (!strcmpiW( attr
->name
, pathW
))
267 cookie_path
= attr
->value
;
271 FIXME( "unhandled attribute %s\n", debugstr_w(attr
->name
) );
277 if (!cookie_domain
&& !(cookie_domain
= strdupW( request
->connect
->servername
))) goto end
;
278 if (!cookie_path
&& !(cookie_path
= strdupW( request
->path
))) goto end
;
280 if ((p
= strrchrW( cookie_path
, '/' )) && p
!= cookie_path
) *p
= 0;
281 ret
= add_cookie( session
, cookie
, cookie_domain
, cookie_path
);
284 if (!ret
) free_cookie( cookie
);
285 if (domain
) free_attr( domain
);
286 else heap_free( cookie_domain
);
287 if (path
) free_attr( path
);
288 else heap_free( cookie_path
);
293 BOOL
add_cookie_headers( request_t
*request
)
295 struct list
*domain_cursor
;
296 session_t
*session
= request
->connect
->session
;
298 LIST_FOR_EACH( domain_cursor
, &session
->cookie_cache
)
300 domain_t
*domain
= LIST_ENTRY( domain_cursor
, domain_t
, entry
);
301 if (domain_match( request
->connect
->servername
, domain
, TRUE
))
303 struct list
*cookie_cursor
;
304 TRACE("found domain %s\n", debugstr_w(domain
->name
));
306 LIST_FOR_EACH( cookie_cursor
, &domain
->cookies
)
308 cookie_t
*cookie
= LIST_ENTRY( cookie_cursor
, cookie_t
, entry
);
310 TRACE("comparing path %s with %s\n", debugstr_w(request
->path
), debugstr_w(cookie
->path
));
312 if (strstrW( request
->path
, cookie
->path
) == request
->path
)
314 const WCHAR cookieW
[] = {'C','o','o','k','i','e',':',' '};
315 int len
, len_cookie
= sizeof(cookieW
) / sizeof(cookieW
[0]), len_name
= strlenW( cookie
->name
);
318 len
= len_cookie
+ len_name
;
319 if (cookie
->value
) len
+= strlenW( cookie
->value
) + 1;
320 if (!(header
= heap_alloc( (len
+ 1) * sizeof(WCHAR
) ))) return FALSE
;
322 memcpy( header
, cookieW
, len_cookie
* sizeof(WCHAR
) );
323 strcpyW( header
+ len_cookie
, cookie
->name
);
326 header
[len_cookie
+ len_name
] = '=';
327 strcpyW( header
+ len_cookie
+ len_name
+ 1, cookie
->value
);
330 TRACE("%s\n", debugstr_w(header
));
331 add_request_headers( request
, header
, len
,
332 WINHTTP_ADDREQ_FLAG_ADD
| WINHTTP_ADDREQ_FLAG_COALESCE_WITH_SEMICOLON
);