[WININET]
[reactos.git] / reactos / dll / win32 / wininet / cookie.c
index 7595495..ddbc92a 100644 (file)
  *     Cookies could use A LOT OF MEMORY. We need some kind of memory management here!
  */
 
-typedef struct _cookie_domain cookie_domain;
-typedef struct _cookie cookie;
+struct _cookie_domain_t;
+struct _cookie_container_t;
 
-struct _cookie
-{
+typedef struct _cookie_t {
     struct list entry;
 
-    struct _cookie_domain *parent;
+    struct _cookie_container_t *container;
 
-    LPWSTR lpCookieName;
-    LPWSTR lpCookieData;
+    WCHAR *name;
+    WCHAR *data;
     DWORD flags;
     FILETIME expiry;
     FILETIME create;
-};
+} cookie_t;
 
-struct _cookie_domain
-{
+typedef struct _cookie_container_t {
     struct list entry;
 
-    LPWSTR lpCookieDomain;
-    LPWSTR lpCookiePath;
+    WCHAR *path;
+    struct _cookie_domain_t *domain;
+
     struct list cookie_list;
-};
+} cookie_container_t;
+
+typedef struct _cookie_domain_t {
+    struct list entry;
+
+    WCHAR *domain;
+    unsigned subdomain_len;
+
+    struct _cookie_domain_t *parent;
+    struct list subdomain_list;
+
+    /* List of stored paths sorted by length of the path. */
+    struct list path_list;
+} cookie_domain_t;
 
 static CRITICAL_SECTION cookie_cs;
 static CRITICAL_SECTION_DEBUG cookie_cs_debug =
@@ -63,14 +75,172 @@ static CRITICAL_SECTION_DEBUG cookie_cs_debug =
 static CRITICAL_SECTION cookie_cs = { &cookie_cs_debug, -1, 0, 0, 0, 0 };
 static struct list domain_list = LIST_INIT(domain_list);
 
-static cookie *COOKIE_addCookie(cookie_domain *domain, LPCWSTR name, LPCWSTR data,
-        FILETIME expiry, FILETIME create, DWORD flags);
-static cookie *COOKIE_findCookie(cookie_domain *domain, LPCWSTR lpszCookieName);
-static void COOKIE_deleteCookie(cookie *deadCookie, BOOL deleteDomain);
-static cookie_domain *COOKIE_addDomain(LPCWSTR domain, LPCWSTR path);
-static void COOKIE_deleteDomain(cookie_domain *deadDomain);
-static BOOL COOKIE_matchDomain(LPCWSTR lpszCookieDomain, LPCWSTR lpszCookiePath,
-        cookie_domain *searchDomain, BOOL allow_partial);
+static cookie_domain_t *get_cookie_domain(const WCHAR *domain, BOOL create)
+{
+    const WCHAR *ptr = domain + strlenW(domain), *ptr_end, *subdomain_ptr;
+    cookie_domain_t *iter, *current_domain, *prev_domain = NULL;
+    struct list *current_list = &domain_list;
+
+    while(1) {
+        for(ptr_end = ptr--; ptr > domain && *ptr != '.'; ptr--);
+        subdomain_ptr = *ptr == '.' ? ptr+1 : ptr;
+
+        current_domain = NULL;
+        LIST_FOR_EACH_ENTRY(iter, current_list, cookie_domain_t, entry) {
+            if(ptr_end-subdomain_ptr == iter->subdomain_len && !memcmp(subdomain_ptr, iter->domain, iter->subdomain_len)) {
+                current_domain = iter;
+                break;
+            }
+        }
+
+        if(!current_domain) {
+            if(!create)
+                return prev_domain;
+
+            current_domain = heap_alloc(sizeof(*current_domain));
+            if(!current_domain)
+                return NULL;
+
+            current_domain->domain = heap_strdupW(subdomain_ptr);
+            if(!current_domain->domain) {
+                heap_free(current_domain);
+                return NULL;
+            }
+
+            current_domain->subdomain_len = ptr_end-subdomain_ptr;
+
+            current_domain->parent = prev_domain;
+            list_init(&current_domain->path_list);
+            list_init(&current_domain->subdomain_list);
+
+            list_add_tail(current_list, &current_domain->entry);
+        }
+
+        if(ptr == domain)
+            return current_domain;
+
+        prev_domain = current_domain;
+        current_list = &current_domain->subdomain_list;
+    }
+}
+
+static cookie_container_t *get_cookie_container(const WCHAR *domain, const WCHAR *path, BOOL create)
+{
+    cookie_domain_t *cookie_domain;
+    cookie_container_t *cookie_container, *iter;
+    size_t path_len, len;
+
+    cookie_domain = get_cookie_domain(domain, create);
+    if(!cookie_domain)
+        return NULL;
+
+    path_len = strlenW(path);
+
+    LIST_FOR_EACH_ENTRY(cookie_container, &cookie_domain->path_list, cookie_container_t, entry) {
+        len = strlenW(cookie_container->path);
+        if(len < path_len)
+            break;
+
+        if(!strcmpiW(cookie_container->path, path))
+            return cookie_container;
+    }
+
+    if(!create)
+        return NULL;
+
+    cookie_container = heap_alloc(sizeof(*cookie_container));
+    if(!cookie_container)
+        return NULL;
+
+    cookie_container->path = heap_strdupW(path);
+    if(!cookie_container->path) {
+        heap_free(cookie_container);
+        return NULL;
+    }
+
+    cookie_container->domain = cookie_domain;
+    list_init(&cookie_container->cookie_list);
+
+
+    LIST_FOR_EACH_ENTRY(iter, &cookie_domain->path_list, cookie_container_t, entry) {
+        if(strlenW(iter->path) <= path_len) {
+            list_add_before(&iter->entry, &cookie_container->entry);
+            return cookie_container;
+        }
+    }
+
+    list_add_tail(&cookie_domain->path_list, &cookie_container->entry);
+    return cookie_container;
+}
+
+static void delete_cookie(cookie_t *cookie)
+{
+    list_remove(&cookie->entry);
+
+    heap_free(cookie->name);
+    heap_free(cookie->data);
+    heap_free(cookie);
+}
+
+static cookie_t *alloc_cookie(const WCHAR *name, const WCHAR *data, FILETIME expiry, FILETIME create_time, DWORD flags)
+{
+    cookie_t *new_cookie;
+
+    new_cookie = heap_alloc(sizeof(*new_cookie));
+    if(!new_cookie)
+        return NULL;
+
+    new_cookie->expiry = expiry;
+    new_cookie->create = create_time;
+    new_cookie->flags = flags;
+    list_init(&new_cookie->entry);
+
+    new_cookie->name = heap_strdupW(name);
+    new_cookie->data = heap_strdupW(data);
+    if((name && !new_cookie->name) || (data && !new_cookie->data)) {
+        delete_cookie(new_cookie);
+        return NULL;
+    }
+
+    return new_cookie;
+}
+
+static cookie_t *find_cookie(cookie_container_t *container, const WCHAR *name)
+{
+    cookie_t *iter;
+
+    LIST_FOR_EACH_ENTRY(iter, &container->cookie_list, cookie_t, entry) {
+        if(!strcmpiW(iter->name, name))
+            return iter;
+    }
+
+    return NULL;
+}
+
+static void add_cookie(cookie_container_t *container, cookie_t *new_cookie)
+{
+    TRACE("Adding %s=%s to %s %s\n", debugstr_w(new_cookie->name), debugstr_w(new_cookie->data),
+          debugstr_w(container->domain->domain), debugstr_w(container->path));
+
+    list_add_tail(&container->cookie_list, &new_cookie->entry);
+    new_cookie->container = container;
+}
+
+static void replace_cookie(cookie_container_t *container, cookie_t *new_cookie)
+{
+    cookie_t *old_cookie;
+
+    old_cookie = find_cookie(container, new_cookie->name);
+    if(old_cookie)
+        delete_cookie(old_cookie);
+
+    add_cookie(container, new_cookie);
+}
+
+static BOOL cookie_match_path(cookie_container_t *container, const WCHAR *path)
+{
+    return !strncmpiW(container->path, path, strlenW(container->path));
+}
 
 static BOOL create_cookie_url(LPCWSTR domain, LPCWSTR path, WCHAR *buf, DWORD buf_len)
 {
@@ -120,9 +290,8 @@ static BOOL create_cookie_url(LPCWSTR domain, LPCWSTR path, WCHAR *buf, DWORD bu
 static BOOL load_persistent_cookie(LPCWSTR domain, LPCWSTR path)
 {
     INTERNET_CACHE_ENTRY_INFOW *info;
-    cookie_domain *domain_container = NULL;
-    cookie *old_cookie;
-    struct list *iter;
+    cookie_container_t *cookie_container;
+    cookie_t *new_cookie;
     WCHAR cookie_url[MAX_PATH];
     HANDLE cookie;
     char *str = NULL, *pbeg, *pend;
@@ -154,19 +323,9 @@ static BOOL load_persistent_cookie(LPCWSTR domain, LPCWSTR path)
     str[size] = 0;
     UnlockUrlCacheEntryStream(cookie, 0);
 
-    LIST_FOR_EACH(iter, &domain_list)
-    {
-        domain_container = LIST_ENTRY(iter, cookie_domain, entry);
-        if(COOKIE_matchDomain(domain, path, domain_container, FALSE))
-            break;
-        domain_container = NULL;
-    }
-    if(!domain_container)
-        domain_container = COOKIE_addDomain(domain, path);
-    if(!domain_container) {
-        heap_free(str);
+    cookie_container = get_cookie_container(domain, path, TRUE);
+    if(!cookie_container)
         return FALSE;
-    }
 
     GetSystemTimeAsFileTime(&time);
     for(pbeg=str; pbeg && *pbeg; name=data=NULL) {
@@ -202,12 +361,18 @@ static BOOL load_persistent_cookie(LPCWSTR domain, LPCWSTR path)
             break;
 
         if(CompareFileTime(&time, &expiry) <= 0) {
-            if((old_cookie = COOKIE_findCookie(domain_container, name)))
-                COOKIE_deleteCookie(old_cookie, FALSE);
-            COOKIE_addCookie(domain_container, name, data, expiry, create, flags);
+            new_cookie = alloc_cookie(NULL, NULL, expiry, create, flags);
+            if(!new_cookie)
+                break;
+
+            new_cookie->name = name;
+            new_cookie->data = data;
+
+            replace_cookie(cookie_container, new_cookie);
+        }else {
+            heap_free(name);
+            heap_free(data);
         }
-        heap_free(name);
-        heap_free(data);
     }
     heap_free(str);
     heap_free(name);
@@ -216,28 +381,28 @@ static BOOL load_persistent_cookie(LPCWSTR domain, LPCWSTR path)
     return TRUE;
 }
 
-static BOOL save_persistent_cookie(cookie_domain *domain)
+static BOOL save_persistent_cookie(cookie_container_t *container)
 {
     static const WCHAR txtW[] = {'t','x','t',0};
 
     WCHAR cookie_url[MAX_PATH], cookie_file[MAX_PATH];
     HANDLE cookie_handle;
-    cookie *cookie_container = NULL, *cookie_iter;
+    cookie_t *cookie_container = NULL, *cookie_iter;
     BOOL do_save = FALSE;
     char buf[64], *dyn_buf;
     FILETIME time;
-    DWORD dwBytesWritten;
+    DWORD bytes_written;
 
-    if (!create_cookie_url(domain->lpCookieDomain, domain->lpCookiePath, cookie_url, sizeof(cookie_url)/sizeof(cookie_url[0])))
+    if (!create_cookie_url(container->domain->domain, container->path, cookie_url, sizeof(cookie_url)/sizeof(cookie_url[0])))
         return FALSE;
 
     /* check if there's anything to save */
     GetSystemTimeAsFileTime(&time);
-    LIST_FOR_EACH_ENTRY_SAFE(cookie_container, cookie_iter, &domain->cookie_list, cookie, entry)
+    LIST_FOR_EACH_ENTRY_SAFE(cookie_container, cookie_iter, &container->cookie_list, cookie_t, entry)
     {
         if((cookie_container->expiry.dwLowDateTime || cookie_container->expiry.dwHighDateTime)
                 && CompareFileTime(&time, &cookie_container->expiry) > 0) {
-            COOKIE_deleteCookie(cookie_container, FALSE);
+            delete_cookie(cookie_container);
             continue;
         }
 
@@ -259,45 +424,45 @@ static BOOL save_persistent_cookie(cookie_domain *domain)
         return FALSE;
     }
 
-    LIST_FOR_EACH_ENTRY(cookie_container, &domain->cookie_list, cookie, entry)
+    LIST_FOR_EACH_ENTRY(cookie_container, &container->cookie_list, cookie_t, entry)
     {
         if(cookie_container->flags & INTERNET_COOKIE_IS_SESSION)
             continue;
 
-        dyn_buf = heap_strdupWtoA(cookie_container->lpCookieName);
-        if(!dyn_buf || !WriteFile(cookie_handle, dyn_buf, strlen(dyn_buf), &dwBytesWritten, NULL)) {
+        dyn_buf = heap_strdupWtoA(cookie_container->name);
+        if(!dyn_buf || !WriteFile(cookie_handle, dyn_buf, strlen(dyn_buf), &bytes_written, NULL)) {
             heap_free(dyn_buf);
             do_save = FALSE;
             break;
         }
         heap_free(dyn_buf);
-        if(!WriteFile(cookie_handle, "\n", 1, &dwBytesWritten, NULL)) {
+        if(!WriteFile(cookie_handle, "\n", 1, &bytes_written, NULL)) {
             do_save = FALSE;
             break;
         }
 
-        dyn_buf = heap_strdupWtoA(cookie_container->lpCookieData);
-        if(!dyn_buf || !WriteFile(cookie_handle, dyn_buf, strlen(dyn_buf), &dwBytesWritten, NULL)) {
+        dyn_buf = heap_strdupWtoA(cookie_container->data);
+        if(!dyn_buf || !WriteFile(cookie_handle, dyn_buf, strlen(dyn_buf), &bytes_written, NULL)) {
             heap_free(dyn_buf);
             do_save = FALSE;
             break;
         }
         heap_free(dyn_buf);
-        if(!WriteFile(cookie_handle, "\n", 1, &dwBytesWritten, NULL)) {
+        if(!WriteFile(cookie_handle, "\n", 1, &bytes_written, NULL)) {
             do_save = FALSE;
             break;
         }
 
-        dyn_buf = heap_strdupWtoA(domain->lpCookieDomain);
-        if(!dyn_buf || !WriteFile(cookie_handle, dyn_buf, strlen(dyn_buf), &dwBytesWritten, NULL)) {
+        dyn_buf = heap_strdupWtoA(container->domain->domain);
+        if(!dyn_buf || !WriteFile(cookie_handle, dyn_buf, strlen(dyn_buf), &bytes_written, NULL)) {
             heap_free(dyn_buf);
             do_save = FALSE;
             break;
         }
         heap_free(dyn_buf);
 
-        dyn_buf = heap_strdupWtoA(domain->lpCookiePath);
-        if(!dyn_buf || !WriteFile(cookie_handle, dyn_buf, strlen(dyn_buf), &dwBytesWritten, NULL)) {
+        dyn_buf = heap_strdupWtoA(container->path);
+        if(!dyn_buf || !WriteFile(cookie_handle, dyn_buf, strlen(dyn_buf), &bytes_written, NULL)) {
             heap_free(dyn_buf);
             do_save = FALSE;
             break;
@@ -307,7 +472,7 @@ static BOOL save_persistent_cookie(cookie_domain *domain)
         sprintf(buf, "\n%u\n%u\n%u\n%u\n%u\n*\n", cookie_container->flags,
                 cookie_container->expiry.dwLowDateTime, cookie_container->expiry.dwHighDateTime,
                 cookie_container->create.dwLowDateTime, cookie_container->create.dwHighDateTime);
-        if(!WriteFile(cookie_handle, buf, strlen(buf), &dwBytesWritten, NULL)) {
+        if(!WriteFile(cookie_handle, buf, strlen(buf), &bytes_written, NULL)) {
             do_save = FALSE;
             break;
         }
@@ -324,90 +489,6 @@ static BOOL save_persistent_cookie(cookie_domain *domain)
     return CommitUrlCacheEntryW(cookie_url, cookie_file, time, time, 0, NULL, 0, txtW, 0);
 }
 
-/* adds a cookie to the domain */
-static cookie *COOKIE_addCookie(cookie_domain *domain, LPCWSTR name, LPCWSTR data,
-        FILETIME expiry, FILETIME create, DWORD flags)
-{
-    cookie *newCookie = heap_alloc(sizeof(cookie));
-    if (!newCookie)
-        return NULL;
-
-    newCookie->lpCookieName = heap_strdupW(name);
-    newCookie->lpCookieData = heap_strdupW(data);
-
-    if (!newCookie->lpCookieName || !newCookie->lpCookieData)
-    {
-        heap_free(newCookie->lpCookieName);
-        heap_free(newCookie->lpCookieData);
-        heap_free(newCookie);
-
-        return NULL;
-    }
-
-    newCookie->flags = flags;
-    newCookie->expiry = expiry;
-    newCookie->create = create;
-
-    TRACE("added cookie %p (data is %s)\n", newCookie, debugstr_w(data) );
-
-    list_add_tail(&domain->cookie_list, &newCookie->entry);
-    newCookie->parent = domain;
-    return newCookie;
-}
-
-
-/* finds a cookie in the domain matching the cookie name */
-static cookie *COOKIE_findCookie(cookie_domain *domain, LPCWSTR lpszCookieName)
-{
-    struct list * cursor;
-    TRACE("(%p, %s)\n", domain, debugstr_w(lpszCookieName));
-
-    LIST_FOR_EACH(cursor, &domain->cookie_list)
-    {
-        cookie *searchCookie = LIST_ENTRY(cursor, cookie, entry);
-       BOOL candidate = TRUE;
-       if (candidate && lpszCookieName)
-       {
-           if (candidate && !searchCookie->lpCookieName)
-               candidate = FALSE;
-           if (candidate && strcmpW(lpszCookieName, searchCookie->lpCookieName) != 0)
-                candidate = FALSE;
-       }
-       if (candidate)
-           return searchCookie;
-    }
-    return NULL;
-}
-
-/* removes a cookie from the list, if its the last cookie we also remove the domain */
-static void COOKIE_deleteCookie(cookie *deadCookie, BOOL deleteDomain)
-{
-    heap_free(deadCookie->lpCookieName);
-    heap_free(deadCookie->lpCookieData);
-    list_remove(&deadCookie->entry);
-
-    /* special case: last cookie, lets remove the domain to save memory */
-    if (list_empty(&deadCookie->parent->cookie_list) && deleteDomain)
-        COOKIE_deleteDomain(deadCookie->parent);
-    heap_free(deadCookie);
-}
-
-/* allocates a domain and adds it to the end */
-static cookie_domain *COOKIE_addDomain(LPCWSTR domain, LPCWSTR path)
-{
-    cookie_domain *newDomain = heap_alloc(sizeof(cookie_domain));
-
-    list_init(&newDomain->entry);
-    list_init(&newDomain->cookie_list);
-    newDomain->lpCookieDomain = heap_strdupW(domain);
-    newDomain->lpCookiePath = heap_strdupW(path);
-
-    list_add_tail(&domain_list, &newDomain->entry);
-
-    TRACE("Adding domain: %p\n", newDomain);
-    return newDomain;
-}
-
 static BOOL COOKIE_crackUrlSimple(LPCWSTR lpszUrl, LPWSTR hostName, int hostNameLen, LPWSTR path, int pathLen)
 {
     URL_COMPONENTSW UrlComponents;
@@ -449,78 +530,27 @@ static BOOL COOKIE_crackUrlSimple(LPCWSTR lpszUrl, LPWSTR hostName, int hostName
     return TRUE;
 }
 
-/* match a domain. domain must match if the domain is not NULL. path must match if the path is not NULL */
-static BOOL COOKIE_matchDomain(LPCWSTR lpszCookieDomain, LPCWSTR lpszCookiePath,
-                               cookie_domain *searchDomain, BOOL allow_partial)
-{
-    TRACE("searching on domain %p\n", searchDomain);
-       if (lpszCookieDomain)
-       {
-           if (!searchDomain->lpCookieDomain)
-            return FALSE;
-
-           TRACE("comparing domain %s with %s\n",
-            debugstr_w(lpszCookieDomain),
-            debugstr_w(searchDomain->lpCookieDomain));
-
-        if (allow_partial && !strstrW(lpszCookieDomain, searchDomain->lpCookieDomain))
-            return FALSE;
-        else if (!allow_partial && lstrcmpW(lpszCookieDomain, searchDomain->lpCookieDomain) != 0)
-            return FALSE;
-       }
-    if (lpszCookiePath)
-    {
-        INT len;
-        TRACE("comparing paths: %s with %s\n", debugstr_w(lpszCookiePath), debugstr_w(searchDomain->lpCookiePath));
-        /* paths match at the beginning.  so a path of  /foo would match
-         * /foobar and /foo/bar
-         */
-        if (!searchDomain->lpCookiePath)
-            return FALSE;
-        if (allow_partial)
-        {
-            len = lstrlenW(searchDomain->lpCookiePath);
-            if (strncmpiW(searchDomain->lpCookiePath, lpszCookiePath, len)!=0)
-                return FALSE;
-        }
-        else if (strcmpW(lpszCookiePath, searchDomain->lpCookiePath))
-            return FALSE;
+typedef struct {
+    cookie_t **cookies;
+    unsigned cnt;
+    unsigned size;
 
-       }
-       return TRUE;
-}
+    unsigned string_len;
+} cookie_set_t;
 
-/* remove a domain from the list and delete it */
-static void COOKIE_deleteDomain(cookie_domain *deadDomain)
-{
-    struct list * cursor;
-    while ((cursor = list_tail(&deadDomain->cookie_list)))
-    {
-        COOKIE_deleteCookie(LIST_ENTRY(cursor, cookie, entry), FALSE);
-        list_remove(cursor);
-    }
-    heap_free(deadDomain->lpCookieDomain);
-    heap_free(deadDomain->lpCookiePath);
-
-    list_remove(&deadDomain->entry);
-
-    heap_free(deadDomain);
-}
-
-DWORD get_cookie(const WCHAR *host, const WCHAR *path, WCHAR *cookie_data, DWORD *size)
+static DWORD get_cookie(const WCHAR *host, const WCHAR *path, DWORD flags, cookie_set_t *res)
 {
     static const WCHAR empty_path[] = { '/',0 };
 
-    unsigned cnt = 0, len, name_len, domain_count = 0, cookie_count = 0;
     WCHAR *ptr, subpath[INTERNET_MAX_PATH_LENGTH];
     const WCHAR *p;
-    cookie_domain *domain;
+    cookie_domain_t *domain;
+    cookie_container_t *container;
+    unsigned len;
     FILETIME tm;
 
     GetSystemTimeAsFileTime(&tm);
 
-    EnterCriticalSection(&cookie_cs);
-
     len = strlenW(host);
     p = host+len;
     while(p>host && p[-1]!='.') p--;
@@ -544,88 +574,139 @@ DWORD get_cookie(const WCHAR *host, const WCHAR *path, WCHAR *cookie_data, DWORD
         while(ptr>subpath && ptr[-1]!='/') ptr--;
     }while(ptr != subpath);
 
-    ptr = cookie_data;
-    LIST_FOR_EACH_ENTRY(domain, &domain_list, cookie_domain, entry) {
-        struct list *cursor, *cursor2;
+    domain = get_cookie_domain(host, FALSE);
+    if(!domain) {
+        TRACE("Unknown host %s\n", debugstr_w(host));
+        return ERROR_NO_MORE_ITEMS;
+    }
 
-        if(!COOKIE_matchDomain(host, path, domain, TRUE))
-            continue;
+    for(domain = get_cookie_domain(host, FALSE); domain; domain = domain->parent) {
+        TRACE("Trying %s domain...\n", debugstr_w(domain->domain));
 
-        domain_count++;
-        TRACE("found domain %p\n", domain);
+        LIST_FOR_EACH_ENTRY(container, &domain->path_list, cookie_container_t, entry) {
+            struct list *cursor, *cursor2;
 
-        LIST_FOR_EACH_SAFE(cursor, cursor2, &domain->cookie_list) {
-            cookie *cookie_iter = LIST_ENTRY(cursor, cookie, entry);
+            TRACE("path %s\n", debugstr_w(container->path));
 
-            /* check for expiry */
-            if((cookie_iter->expiry.dwLowDateTime != 0 || cookie_iter->expiry.dwHighDateTime != 0)
-                && CompareFileTime(&tm, &cookie_iter->expiry)  > 0)
-            {
-                TRACE("Found expired cookie. deleting\n");
-                COOKIE_deleteCookie(cookie_iter, FALSE);
+            if(!cookie_match_path(container, path))
                 continue;
-            }
-
-            if (cookie_count)
-                cnt += 2; /* '; ' */
-            cnt += name_len = strlenW(cookie_iter->lpCookieName);
-            if ((len = strlenW(cookie_iter->lpCookieData))) {
-                cnt += 1; /* = */
-                cnt += len;
-            }
 
-            if(ptr) {
-                if(*size > cnt) {
-                    if(cookie_count) {
-                        *ptr++ = ';';
-                        *ptr++ = ' ';
-                    }
+            TRACE("found domain %p\n", domain->domain);
 
-                    memcpy(ptr, cookie_iter->lpCookieName, name_len*sizeof(WCHAR));
-                    ptr += name_len;
+            LIST_FOR_EACH_SAFE(cursor, cursor2, &container->cookie_list) {
+                cookie_t *cookie_iter = LIST_ENTRY(cursor, cookie_t, entry);
 
-                    if(len) {
-                        *ptr++ = '=';
-                        memcpy(ptr, cookie_iter->lpCookieData, len*sizeof(WCHAR));
-                        ptr += len;
-                    }
+                /* check for expiry */
+                if((cookie_iter->expiry.dwLowDateTime != 0 || cookie_iter->expiry.dwHighDateTime != 0)
+                    && CompareFileTime(&tm, &cookie_iter->expiry)  > 0) {
+                    TRACE("Found expired cookie. deleting\n");
+                    delete_cookie(cookie_iter);
+                    continue;
+                }
 
-                    assert(cookie_data+cnt == ptr);
-                    TRACE("Cookie: %s\n", debugstr_wn(cookie_data, cnt));
-                }else {
-                    /* Stop writing data, just compute the size */
-                    ptr = NULL;
+                if((cookie_iter->flags & INTERNET_COOKIE_HTTPONLY) && !(flags & INTERNET_COOKIE_HTTPONLY))
+                    continue;
+
+
+                if(!res->size) {
+                    res->cookies = heap_alloc(4*sizeof(*res->cookies));
+                    if(!res->cookies)
+                        continue;
+                    res->size = 4;
+                }else if(res->cnt == res->size) {
+                    cookie_t **new_cookies = heap_realloc(res->cookies, res->size*2*sizeof(*res->cookies));
+                    if(!new_cookies)
+                        continue;
+                    res->cookies = new_cookies;
+                    res->size *= 2;
                 }
-            }
 
-            cookie_count++;
+                if(res->cnt)
+                    res->string_len += 2; /* '; ' */
+                res->cookies[res->cnt++] = cookie_iter;
+
+                res->string_len += strlenW(cookie_iter->name);
+                if(*cookie_iter->data)
+                    res->string_len += 1 /* = */ + strlenW(cookie_iter->data);
+            }
         }
     }
 
-    LeaveCriticalSection(&cookie_cs);
+    return ERROR_SUCCESS;
+}
 
-    if(ptr)
-        *ptr = 0;
+static void cookie_set_to_string(const cookie_set_t *cookie_set, WCHAR *str)
+{
+    WCHAR *ptr = str;
+    unsigned i, len;
 
-    if (!cnt) {
-        TRACE("no cookies found for %s\n", debugstr_w(host));
-        return ERROR_NO_MORE_ITEMS;
+    for(i=0; i<cookie_set->cnt; i++) {
+        if(i) {
+            *ptr++ = ';';
+            *ptr++ = ' ';
+        }
+
+        len = strlenW(cookie_set->cookies[i]->name);
+        memcpy(ptr, cookie_set->cookies[i]->name, len*sizeof(WCHAR));
+        ptr += len;
+
+        if(*cookie_set->cookies[i]->data) {
+            *ptr++ = '=';
+            len = strlenW(cookie_set->cookies[i]->data);
+            memcpy(ptr, cookie_set->cookies[i]->data, len*sizeof(WCHAR));
+            ptr += len;
+        }
     }
 
-    if(!cookie_data || !ptr) {
-        *size = (cnt + 1) * sizeof(WCHAR);
-        TRACE("returning %u\n", *size);
-        return cookie_data ? ERROR_INSUFFICIENT_BUFFER : ERROR_SUCCESS;
+    assert(ptr-str == cookie_set->string_len);
+    TRACE("%s\n", debugstr_wn(str, ptr-str));
+}
+
+DWORD get_cookie_header(const WCHAR *host, const WCHAR *path, WCHAR **ret)
+{
+    cookie_set_t cookie_set = {0};
+    DWORD res;
+
+    static const WCHAR cookieW[] = {'C','o','o','k','i','e',':',' '};
+
+    EnterCriticalSection(&cookie_cs);
+
+    res = get_cookie(host, path, INTERNET_COOKIE_HTTPONLY, &cookie_set);
+    if(res != ERROR_SUCCESS) {
+        LeaveCriticalSection(&cookie_cs);
+        return res;
     }
 
-    *size = cnt + 1;
+    if(cookie_set.cnt) {
+        WCHAR *header, *ptr;
+
+        ptr = header = heap_alloc(sizeof(cookieW) + (cookie_set.string_len + 3 /* crlf0 */) * sizeof(WCHAR));
+        if(header) {
+            memcpy(ptr, cookieW, sizeof(cookieW));
+            ptr += sizeof(cookieW)/sizeof(*cookieW);
 
-    TRACE("Returning %u (from %u domains): %s\n", cnt, domain_count, debugstr_w(cookie_data));
+            cookie_set_to_string(&cookie_set, ptr);
+            heap_free(cookie_set.cookies);
+            ptr += cookie_set.string_len;
+
+            *ptr++ = '\r';
+            *ptr++ = '\n';
+            *ptr++ = 0;
+
+            *ret = header;
+        }else {
+            res = ERROR_NOT_ENOUGH_MEMORY;
+        }
+    }else {
+        *ret = NULL;
+    }
+
+    LeaveCriticalSection(&cookie_cs);
     return ERROR_SUCCESS;
 }
 
 /***********************************************************************
- *           InternetGetCookieW (WININET.@)
+ *           InternetGetCookieExW (WININET.@)
  *
  * Retrieve cookie from the specified url
  *
@@ -637,14 +718,18 @@ DWORD get_cookie(const WCHAR *host, const WCHAR *path, WCHAR *cookie_data, DWORD
  *    FALSE on failure
  *
  */
-BOOL WINAPI InternetGetCookieW(LPCWSTR lpszUrl, LPCWSTR lpszCookieName,
-    LPWSTR lpCookieData, LPDWORD lpdwSize)
+BOOL WINAPI InternetGetCookieExW(LPCWSTR lpszUrl, LPCWSTR lpszCookieName,
+        LPWSTR lpCookieData, LPDWORD lpdwSize, DWORD flags, void *reserved)
 {
     WCHAR host[INTERNET_MAX_HOST_NAME_LENGTH], path[INTERNET_MAX_PATH_LENGTH];
+    cookie_set_t cookie_set = {0};
     DWORD res;
     BOOL ret;
 
-    TRACE("(%s, %s, %p, %p)\n", debugstr_w(lpszUrl),debugstr_w(lpszCookieName), lpCookieData, lpdwSize);
+    TRACE("(%s, %s, %p, %p, %x, %p)\n", debugstr_w(lpszUrl),debugstr_w(lpszCookieName), lpCookieData, lpdwSize, flags, reserved);
+
+    if (flags)
+        FIXME("flags 0x%08x not supported\n", flags);
 
     if (!lpszUrl)
     {
@@ -659,15 +744,53 @@ BOOL WINAPI InternetGetCookieW(LPCWSTR lpszUrl, LPCWSTR lpszCookieName,
         return FALSE;
     }
 
-    res = get_cookie(host, path, lpCookieData, lpdwSize);
-    if(res != ERROR_SUCCESS)
+    EnterCriticalSection(&cookie_cs);
+
+    res = get_cookie(host, path, flags, &cookie_set);
+    if(res != ERROR_SUCCESS) {
+        LeaveCriticalSection(&cookie_cs);
         SetLastError(res);
-    return res == ERROR_SUCCESS;
+        return FALSE;
+    }
+
+    if(cookie_set.cnt) {
+        if(!lpCookieData || cookie_set.string_len+1 > *lpdwSize) {
+            *lpdwSize = (cookie_set.string_len + 1) * sizeof(WCHAR);
+            TRACE("returning %u\n", *lpdwSize);
+            if(lpCookieData) {
+                SetLastError(ERROR_INSUFFICIENT_BUFFER);
+                ret = FALSE;
+            }
+        }else {
+            *lpdwSize = cookie_set.string_len + 1;
+            cookie_set_to_string(&cookie_set, lpCookieData);
+            lpCookieData[cookie_set.string_len] = 0;
+        }
+    }else {
+        TRACE("no cookies found for %s\n", debugstr_w(host));
+        SetLastError(ERROR_NO_MORE_ITEMS);
+        ret = FALSE;
+    }
+
+    heap_free(cookie_set.cookies);
+    LeaveCriticalSection(&cookie_cs);
+    return ret;
 }
 
+/***********************************************************************
+ *           InternetGetCookieW (WININET.@)
+ *
+ * Retrieve cookie for the specified URL.
+ */
+BOOL WINAPI InternetGetCookieW(const WCHAR *url, const WCHAR *name, WCHAR *data, DWORD *size)
+{
+    TRACE("(%s, %s, %s, %p)\n", debugstr_w(url), debugstr_w(name), debugstr_w(data), size);
+
+    return InternetGetCookieExW(url, name, data, size, 0, NULL);
+}
 
 /***********************************************************************
- *           InternetGetCookieA (WININET.@)
+ *           InternetGetCookieExA (WININET.@)
  *
  * Retrieve cookie from the specified url
  *
@@ -676,20 +799,20 @@ BOOL WINAPI InternetGetCookieW(LPCWSTR lpszUrl, LPCWSTR lpszCookieName,
  *    FALSE on failure
  *
  */
-BOOL WINAPI InternetGetCookieA(LPCSTR lpszUrl, LPCSTR lpszCookieName,
-    LPSTR lpCookieData, LPDWORD lpdwSize)
+BOOL WINAPI InternetGetCookieExA(LPCSTR lpszUrl, LPCSTR lpszCookieName,
+        LPSTR lpCookieData, LPDWORD lpdwSize, DWORD flags, void *reserved)
 {
     WCHAR *url, *name;
     DWORD len, size;
     BOOL r;
 
-    TRACE("(%s %s %p %p(%u))\n", debugstr_a(lpszUrl), debugstr_a(lpszCookieName),
-          lpCookieData, lpdwSize, lpdwSize ? *lpdwSize : 0);
+    TRACE("(%s %s %p %p(%u) %x %p)\n", debugstr_a(lpszUrl), debugstr_a(lpszCookieName),
+          lpCookieData, lpdwSize, lpdwSize ? *lpdwSize : 0, flags, reserved);
 
     url = heap_strdupAtoW(lpszUrl);
     name = heap_strdupAtoW(lpszCookieName);
 
-    r = InternetGetCookieW( url, name, NULL, &len );
+    r = InternetGetCookieExW( url, name, NULL, &len, flags, reserved );
     if( r )
     {
         WCHAR *szCookieData;
@@ -701,7 +824,7 @@ BOOL WINAPI InternetGetCookieA(LPCSTR lpszUrl, LPCSTR lpszCookieName,
         }
         else
         {
-            r = InternetGetCookieW( url, name, szCookieData, &len );
+            r = InternetGetCookieExW( url, name, szCookieData, &len, flags, reserved );
 
             if(r) {
                 size = WideCharToMultiByte( CP_ACP, 0, szCookieData, len, NULL, 0, NULL, NULL);
@@ -724,6 +847,17 @@ BOOL WINAPI InternetGetCookieA(LPCSTR lpszUrl, LPCSTR lpszCookieName,
     return r;
 }
 
+/***********************************************************************
+ *           InternetGetCookieA (WININET.@)
+ *
+ * See InternetGetCookieW.
+ */
+BOOL WINAPI InternetGetCookieA(const char *url, const char *name, char *data, DWORD *size)
+{
+    TRACE("(%s, %s, %s, %p)\n", debugstr_a(url), debugstr_a(name), debugstr_a(data), size);
+
+    return InternetGetCookieExA(url, name, data, size, 0, NULL);
+}
 
 /***********************************************************************
  *           IsDomainLegalCookieDomainW (WININET.@)
@@ -761,22 +895,23 @@ BOOL WINAPI IsDomainLegalCookieDomainW( LPCWSTR s1, LPCWSTR s2 )
     return TRUE;
 }
 
-BOOL set_cookie(LPCWSTR domain, LPCWSTR path, LPCWSTR cookie_name, LPCWSTR cookie_data)
+DWORD set_cookie(const WCHAR *domain, const WCHAR *path, const WCHAR *cookie_name, const WCHAR *cookie_data, DWORD flags)
 {
-    cookie_domain *thisCookieDomain = NULL;
-    cookie *thisCookie;
-    struct list *cursor;
+    cookie_container_t *container;
+    cookie_t *thisCookie;
     LPWSTR data, value;
     WCHAR *ptr;
     FILETIME expiry, create;
     BOOL expired = FALSE, update_persistent = FALSE;
-    DWORD flags = 0;
+    DWORD cookie_flags = 0;
+
+    TRACE("%s %s %s=%s %x\n", debugstr_w(domain), debugstr_w(path), debugstr_w(cookie_name), debugstr_w(cookie_data), flags);
 
     value = data = heap_strdupW(cookie_data);
     if (!data)
     {
         ERR("could not allocate the cookie data buffer\n");
-        return FALSE;
+        return COOKIE_STATE_UNKNOWN;
     }
 
     memset(&expiry,0,sizeof(expiry));
@@ -802,7 +937,7 @@ BOOL set_cookie(LPCWSTR domain, LPCWSTR path, LPCWSTR cookie_name, LPCWSTR cooki
         {
             heap_free(data);
             ERR("could not allocate the cookie value buffer\n");
-            return FALSE;
+            return COOKIE_STATE_UNKNOWN;
         }
         strcpyW(value, data);
 
@@ -824,7 +959,7 @@ BOOL set_cookie(LPCWSTR domain, LPCWSTR path, LPCWSTR cookie_name, LPCWSTR cooki
                 if(value != data)
                     heap_free(value);
                 heap_free(data);
-                return FALSE;
+                return COOKIE_STATE_UNKNOWN;
             }
 
             if(end_ptr)
@@ -861,7 +996,15 @@ BOOL set_cookie(LPCWSTR domain, LPCWSTR path, LPCWSTR cookie_name, LPCWSTR cooki
         }
         else if (strncmpiW(ptr, szHttpOnly, 8) == 0)
         {
-            FIXME("httponly not handled (%s)\n",debugstr_w(ptr));
+            if(!(flags & INTERNET_COOKIE_HTTPONLY)) {
+                WARN("HTTP only cookie added without INTERNET_COOKIE_HTTPONLY flag\n");
+                heap_free(data);
+                if (value != data) heap_free(value);
+                SetLastError(ERROR_INVALID_OPERATION);
+                return COOKIE_STATE_REJECT;
+            }
+
+            cookie_flags |= INTERNET_COOKIE_HTTPONLY;
             ptr += strlenW(szHttpOnly);
         }
         else if (*ptr)
@@ -875,99 +1018,99 @@ BOOL set_cookie(LPCWSTR domain, LPCWSTR path, LPCWSTR cookie_name, LPCWSTR cooki
 
     load_persistent_cookie(domain, path);
 
-    LIST_FOR_EACH(cursor, &domain_list)
-    {
-        thisCookieDomain = LIST_ENTRY(cursor, cookie_domain, entry);
-        if (COOKIE_matchDomain(domain, path, thisCookieDomain, FALSE))
-            break;
-        thisCookieDomain = NULL;
-    }
-
-    if (!thisCookieDomain)
-    {
-        if (!expired)
-            thisCookieDomain = COOKIE_addDomain(domain, path);
-        else
-        {
-            heap_free(data);
-            if (value != data) heap_free(value);
-            LeaveCriticalSection(&cookie_cs);
-            return TRUE;
-        }
+    container = get_cookie_container(domain, path, !expired);
+    if(!container) {
+        heap_free(data);
+        if (value != data) heap_free(value);
+        LeaveCriticalSection(&cookie_cs);
+        return COOKIE_STATE_ACCEPT;
     }
 
     if(!expiry.dwLowDateTime && !expiry.dwHighDateTime)
-        flags |= INTERNET_COOKIE_IS_SESSION;
+        cookie_flags |= INTERNET_COOKIE_IS_SESSION;
     else
         update_persistent = TRUE;
 
-    if ((thisCookie = COOKIE_findCookie(thisCookieDomain, cookie_name)))
+    if ((thisCookie = find_cookie(container, cookie_name)))
     {
+        if ((thisCookie->flags & INTERNET_COOKIE_HTTPONLY) && !(flags & INTERNET_COOKIE_HTTPONLY)) {
+            WARN("An attempt to override httponly cookie\n");
+            SetLastError(ERROR_INVALID_OPERATION);
+            heap_free(data);
+            if (value != data) heap_free(value);
+            return COOKIE_STATE_REJECT;
+        }
+
         if (!(thisCookie->flags & INTERNET_COOKIE_IS_SESSION))
             update_persistent = TRUE;
-        COOKIE_deleteCookie(thisCookie, FALSE);
+        delete_cookie(thisCookie);
     }
 
     TRACE("setting cookie %s=%s for domain %s path %s\n", debugstr_w(cookie_name),
-          debugstr_w(value), debugstr_w(thisCookieDomain->lpCookieDomain),debugstr_w(thisCookieDomain->lpCookiePath));
+          debugstr_w(value), debugstr_w(container->domain->domain),debugstr_w(container->path));
 
-    if (!expired && !COOKIE_addCookie(thisCookieDomain, cookie_name, value, expiry, create, flags))
-    {
-        heap_free(data);
-        if (value != data) heap_free(value);
-        LeaveCriticalSection(&cookie_cs);
-        return FALSE;
+    if (!expired) {
+        cookie_t *new_cookie;
+
+        new_cookie = alloc_cookie(cookie_name, value, expiry, create, cookie_flags);
+        if(!new_cookie) {
+            heap_free(data);
+            if (value != data) heap_free(value);
+            LeaveCriticalSection(&cookie_cs);
+            return COOKIE_STATE_UNKNOWN;
+        }
+
+        add_cookie(container, new_cookie);
     }
     heap_free(data);
     if (value != data) heap_free(value);
 
-    if (!update_persistent || save_persistent_cookie(thisCookieDomain))
+    if (!update_persistent || save_persistent_cookie(container))
     {
         LeaveCriticalSection(&cookie_cs);
-        return TRUE;
+        return COOKIE_STATE_ACCEPT;
     }
     LeaveCriticalSection(&cookie_cs);
-    return FALSE;
+    return COOKIE_STATE_UNKNOWN;
 }
 
 /***********************************************************************
- *           InternetSetCookieW (WININET.@)
+ *           InternetSetCookieExW (WININET.@)
  *
  * Sets cookie for the specified url
- *
- * RETURNS
- *    TRUE  on success
- *    FALSE on failure
- *
  */
-BOOL WINAPI InternetSetCookieW(LPCWSTR lpszUrl, LPCWSTR lpszCookieName,
-    LPCWSTR lpCookieData)
+DWORD WINAPI InternetSetCookieExW(LPCWSTR lpszUrl, LPCWSTR lpszCookieName,
+        LPCWSTR lpCookieData, DWORD flags, DWORD_PTR reserved)
 {
     BOOL ret;
     WCHAR hostName[INTERNET_MAX_HOST_NAME_LENGTH], path[INTERNET_MAX_PATH_LENGTH];
 
-    TRACE("(%s,%s,%s)\n", debugstr_w(lpszUrl),
-        debugstr_w(lpszCookieName), debugstr_w(lpCookieData));
+    TRACE("(%s, %s, %s, %x, %lx)\n", debugstr_w(lpszUrl), debugstr_w(lpszCookieName),
+          debugstr_w(lpCookieData), flags, reserved);
+
+    if (flags & ~INTERNET_COOKIE_HTTPONLY)
+        FIXME("flags %x not supported\n", flags);
 
     if (!lpszUrl || !lpCookieData)
     {
         SetLastError(ERROR_INVALID_PARAMETER);
-        return FALSE;
+        return COOKIE_STATE_UNKNOWN;
     }
 
     hostName[0] = 0;
     ret = COOKIE_crackUrlSimple(lpszUrl, hostName, sizeof(hostName)/sizeof(hostName[0]), path, sizeof(path)/sizeof(path[0]));
-    if (!ret || !hostName[0]) return FALSE;
+    if (!ret || !hostName[0]) return COOKIE_STATE_UNKNOWN;
 
     if (!lpszCookieName)
     {
         WCHAR *cookie, *data;
+        DWORD res;
 
         cookie = heap_strdupW(lpCookieData);
         if (!cookie)
         {
             SetLastError(ERROR_OUTOFMEMORY);
-            return FALSE;
+            return COOKIE_STATE_UNKNOWN;
         }
 
         /* some apps (or is it us??) try to add a cookie with no cookie name, but
@@ -976,14 +1119,25 @@ BOOL WINAPI InternetSetCookieW(LPCWSTR lpszUrl, LPCWSTR lpszCookieName,
         if (!(data = strchrW(cookie, '='))) data = cookie + strlenW(cookie);
         else *data++ = 0;
 
-        ret = set_cookie(hostName, path, cookie, data);
+        res = set_cookie(hostName, path, cookie, data, flags);
 
         heap_free(cookie);
-        return ret;
+        return res;
     }
-    return set_cookie(hostName, path, lpszCookieName, lpCookieData);
+    return set_cookie(hostName, path, lpszCookieName, lpCookieData, flags);
 }
 
+/***********************************************************************
+ *           InternetSetCookieW (WININET.@)
+ *
+ * Sets a cookie for the specified URL.
+ */
+BOOL WINAPI InternetSetCookieW(const WCHAR *url, const WCHAR *name, const WCHAR *data)
+{
+    TRACE("(%s, %s, %s)\n", debugstr_w(url), debugstr_w(name), debugstr_w(data));
+
+    return InternetSetCookieExW(url, name, data, 0, 0) == COOKIE_STATE_ACCEPT;
+}
 
 /***********************************************************************
  *           InternetSetCookieA (WININET.@)
@@ -1024,70 +1178,22 @@ BOOL WINAPI InternetSetCookieA(LPCSTR lpszUrl, LPCSTR lpszCookieName,
 DWORD WINAPI InternetSetCookieExA( LPCSTR lpszURL, LPCSTR lpszCookieName, LPCSTR lpszCookieData,
                                    DWORD dwFlags, DWORD_PTR dwReserved)
 {
-    TRACE("(%s, %s, %s, 0x%08x, 0x%08lx)\n",
-          debugstr_a(lpszURL), debugstr_a(lpszCookieName), debugstr_a(lpszCookieData),
-          dwFlags, dwReserved);
-
-    if (dwFlags) FIXME("flags 0x%08x not supported\n", dwFlags);
-    return InternetSetCookieA(lpszURL, lpszCookieName, lpszCookieData);
-}
-
-/***********************************************************************
- *           InternetSetCookieExW (WININET.@)
- *
- * Sets a cookie for the specified URL.
- *
- * RETURNS
- *    TRUE  on success
- *    FALSE on failure
- *
- */
-DWORD WINAPI InternetSetCookieExW( LPCWSTR lpszURL, LPCWSTR lpszCookieName, LPCWSTR lpszCookieData,
-                                   DWORD dwFlags, DWORD_PTR dwReserved)
-{
-    TRACE("(%s, %s, %s, 0x%08x, 0x%08lx)\n",
-          debugstr_w(lpszURL), debugstr_w(lpszCookieName), debugstr_w(lpszCookieData),
-          dwFlags, dwReserved);
+    WCHAR *data, *url, *name;
+    DWORD r;
 
-    if (dwFlags) FIXME("flags 0x%08x not supported\n", dwFlags);
-    return InternetSetCookieW(lpszURL, lpszCookieName, lpszCookieData);
-}
+    TRACE("(%s, %s, %s, %x, %lx)\n", debugstr_a(lpszURL), debugstr_a(lpszCookieName),
+          debugstr_a(lpszCookieData), dwFlags, dwReserved);
 
-/***********************************************************************
- *           InternetGetCookieExA (WININET.@)
- *
- * See InternetGetCookieExW.
- */
-BOOL WINAPI InternetGetCookieExA( LPCSTR pchURL, LPCSTR pchCookieName, LPSTR pchCookieData,
-                                  LPDWORD pcchCookieData, DWORD dwFlags, LPVOID lpReserved)
-{
-    TRACE("(%s, %s, %s, %p, 0x%08x, %p)\n",
-          debugstr_a(pchURL), debugstr_a(pchCookieName), debugstr_a(pchCookieData),
-          pcchCookieData, dwFlags, lpReserved);
-
-    if (dwFlags) FIXME("flags 0x%08x not supported\n", dwFlags);
-    return InternetGetCookieA(pchURL, pchCookieName, pchCookieData, pcchCookieData);
-}
+    url = heap_strdupAtoW(lpszURL);
+    name = heap_strdupAtoW(lpszCookieName);
+    data = heap_strdupAtoW(lpszCookieData);
 
-/***********************************************************************
- *           InternetGetCookieExW (WININET.@)
- *
- * Retrieve cookie for the specified URL.
- *
- * RETURNS
- *    TRUE  on success
- *    FALSE on failure
- *
- */
-BOOL WINAPI InternetGetCookieExW( LPCWSTR pchURL, LPCWSTR pchCookieName, LPWSTR pchCookieData,
-                                  LPDWORD pcchCookieData, DWORD dwFlags, LPVOID lpReserved)
-{
-    TRACE("(%s, %s, %s, %p, 0x%08x, %p)\n",
-          debugstr_w(pchURL), debugstr_w(pchCookieName), debugstr_w(pchCookieData),
-          pcchCookieData, dwFlags, lpReserved);
+    r = InternetSetCookieExW(url, name, data, dwFlags, dwReserved);
 
-    if (dwFlags) FIXME("flags 0x%08x not supported\n", dwFlags);
-    return InternetGetCookieW(pchURL, pchCookieName, pchCookieData, pcchCookieData);
+    heap_free( data );
+    heap_free( name );
+    heap_free( url );
+    return r;
 }
 
 /***********************************************************************