dsound: Don't specify period size for the IAudioClient.
[wine] / dlls / mshtml / nsio.c
1 /*
2  * Copyright 2006-2010 Jacek Caban 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 #include "config.h"
20
21 #include <stdarg.h>
22 #include <assert.h>
23
24 #define COBJMACROS
25
26 #include "windef.h"
27 #include "winbase.h"
28 #include "winuser.h"
29 #include "winreg.h"
30 #include "ole2.h"
31 #include "shlguid.h"
32 #include "wininet.h"
33 #include "shlwapi.h"
34
35 #include "wine/debug.h"
36
37 #include "mshtml_private.h"
38 #include "binding.h"
39
40 WINE_DEFAULT_DEBUG_CHANNEL(mshtml);
41
42 #define NS_IOSERVICE_CLASSNAME "nsIOService"
43 #define NS_IOSERVICE_CONTRACTID "@mozilla.org/network/io-service;1"
44
45 static const IID NS_IOSERVICE_CID =
46     {0x9ac9e770, 0x18bc, 0x11d3, {0x93, 0x37, 0x00, 0x10, 0x4b, 0xa0, 0xfd, 0x40}};
47 static const IID IID_nsWineURI =
48     {0x5088272e, 0x900b, 0x11da, {0xc6,0x87, 0x00,0x0f,0xea,0x57,0xf2,0x1a}};
49
50 static nsIIOService *nsio = NULL;
51 static nsINetUtil *net_util;
52
53 static const WCHAR about_blankW[] = {'a','b','o','u','t',':','b','l','a','n','k',0};
54
55 static const char *request_method_strings[] = {"GET", "PUT", "POST"};
56
57 struct  nsWineURI {
58     nsIURL nsIURL_iface;
59
60     LONG ref;
61
62     nsIURI *nsuri;
63     nsIURL *nsurl;
64     NSContainer *container;
65     windowref_t *window_ref;
66     nsChannelBSC *channel_bsc;
67     IUri *uri;
68     IUriBuilder *uri_builder;
69     BOOL is_doc_uri;
70 };
71
72 static BOOL ensure_uri(nsWineURI *This)
73 {
74     HRESULT hres;
75
76     assert(This->uri || This->uri_builder);
77
78     if(!This->uri) {
79         hres = IUriBuilder_CreateUriSimple(This->uri_builder, 0, 0, &This->uri);
80         if(FAILED(hres)) {
81             WARN("CreateUriSimple failed: %08x\n", hres);
82             return FALSE;
83         }
84     }
85
86     return TRUE;
87 }
88
89 static IUri *get_uri_nofrag(IUri *uri)
90 {
91     IUriBuilder *uri_builder;
92     IUri *ret;
93     BOOL b;
94     HRESULT hres;
95
96     hres = IUri_HasProperty(uri, Uri_PROPERTY_FRAGMENT, &b);
97     if(SUCCEEDED(hres) && !b) {
98         IUri_AddRef(uri);
99         return uri;
100     }
101
102     hres = CreateIUriBuilder(uri, 0, 0, &uri_builder);
103     if(FAILED(hres))
104         return NULL;
105
106     hres = IUriBuilder_RemoveProperties(uri_builder, Uri_HAS_FRAGMENT);
107     if(SUCCEEDED(hres))
108         hres = IUriBuilder_CreateUriSimple(uri_builder, 0, 0, &ret);
109     IUriBuilder_Release(uri_builder);
110     if(FAILED(hres))
111         return NULL;
112
113     return ret;
114 }
115
116 BOOL compare_ignoring_frag(IUri *uri1, IUri *uri2)
117 {
118     IUri *uri_nofrag1, *uri_nofrag2;
119     BOOL ret = FALSE;
120
121     uri_nofrag1 = get_uri_nofrag(uri1);
122     if(!uri_nofrag1)
123         return FALSE;
124
125     uri_nofrag2 = get_uri_nofrag(uri2);
126     if(uri_nofrag2) {
127         IUri_IsEqual(uri_nofrag1, uri_nofrag2, &ret);
128         IUri_Release(uri_nofrag2);
129     }
130
131     IUri_Release(uri_nofrag1);
132     return ret;
133 }
134
135 static nsresult create_nsuri(IUri*,nsIURI*,HTMLWindow*,NSContainer*,nsWineURI**);
136
137 static const char *debugstr_nsacstr(const nsACString *nsstr)
138 {
139     const char *data;
140
141     nsACString_GetData(nsstr, &data);
142     return debugstr_a(data);
143 }
144
145 HRESULT nsuri_to_url(LPCWSTR nsuri, BOOL ret_empty, BSTR *ret)
146 {
147     const WCHAR *ptr = nsuri;
148
149     static const WCHAR wine_prefixW[] = {'w','i','n','e',':'};
150
151     if(!strncmpW(nsuri, wine_prefixW, sizeof(wine_prefixW)/sizeof(WCHAR)))
152         ptr += sizeof(wine_prefixW)/sizeof(WCHAR);
153
154     if(*ptr || ret_empty) {
155         *ret = SysAllocString(ptr);
156         if(!*ret)
157             return E_OUTOFMEMORY;
158     }else {
159         *ret = NULL;
160     }
161
162     TRACE("%s -> %s\n", debugstr_w(nsuri), debugstr_w(*ret));
163     return S_OK;
164 }
165
166 static BOOL exec_shldocvw_67(HTMLDocumentObj *doc, BSTR url)
167 {
168     IOleCommandTarget *cmdtrg = NULL;
169     HRESULT hres;
170
171     hres = IOleClientSite_QueryInterface(doc->client, &IID_IOleCommandTarget, (void**)&cmdtrg);
172     if(SUCCEEDED(hres)) {
173         VARIANT varUrl, varRes;
174
175         V_VT(&varUrl) = VT_BSTR;
176         V_BSTR(&varUrl) = url;
177         V_VT(&varRes) = VT_BOOL;
178
179         hres = IOleCommandTarget_Exec(cmdtrg, &CGID_ShellDocView, 67, 0, &varUrl, &varRes);
180
181         IOleCommandTarget_Release(cmdtrg);
182
183         if(SUCCEEDED(hres) && !V_BOOL(&varRes)) {
184             TRACE("got VARIANT_FALSE, do not load\n");
185             return FALSE;
186         }
187     }
188
189     return TRUE;
190 }
191
192 static nsresult before_async_open(nsChannel *channel, NSContainer *container, BOOL *cancel)
193 {
194     HTMLDocumentObj *doc = container->doc;
195     BSTR display_uri;
196     DWORD hlnf = 0;
197     HRESULT hres;
198
199     if(!doc) {
200         NSContainer *container_iter = container;
201
202         hlnf = HLNF_OPENINNEWWINDOW;
203         while(!container_iter->doc)
204             container_iter = container_iter->parent;
205         doc = container_iter->doc;
206     }
207
208     if(!doc->client) {
209         *cancel = TRUE;
210         return NS_OK;
211     }
212
213     hres = IUri_GetDisplayUri(channel->uri->uri, &display_uri);
214     if(FAILED(hres))
215         return NS_ERROR_FAILURE;
216
217     if(!hlnf) {
218         BOOL b;
219
220         b = !exec_shldocvw_67(doc, display_uri);
221         if(b) {
222             SysFreeString(display_uri);
223             *cancel = FALSE;
224             return NS_OK;
225         }
226     }
227
228     hres = hlink_frame_navigate(&doc->basedoc, display_uri, channel, hlnf, cancel);
229     SysFreeString(display_uri);
230     if(FAILED(hres))
231         *cancel = TRUE;
232     return NS_OK;
233 }
234
235 HRESULT load_nsuri(HTMLWindow *window, nsWineURI *uri, nsChannelBSC *channelbsc, DWORD flags)
236 {
237     nsIWebNavigation *web_navigation;
238     nsIDocShell *doc_shell;
239     HTMLDocumentNode *doc;
240     nsresult nsres;
241
242     nsres = get_nsinterface((nsISupports*)window->nswindow, &IID_nsIWebNavigation, (void**)&web_navigation);
243     if(NS_FAILED(nsres)) {
244         ERR("Could not get nsIWebNavigation interface: %08x\n", nsres);
245         return E_FAIL;
246     }
247
248     nsres = nsIWebNavigation_QueryInterface(web_navigation, &IID_nsIDocShell, (void**)&doc_shell);
249     nsIWebNavigation_Release(web_navigation);
250     if(NS_FAILED(nsres)) {
251         ERR("Could not get nsIDocShell: %08x\n", nsres);
252         return E_FAIL;
253     }
254
255     uri->channel_bsc = channelbsc;
256     doc = window->doc;
257     doc->skip_mutation_notif = TRUE;
258     nsres = nsIDocShell_LoadURI(doc_shell, (nsIURI*)&uri->nsIURL_iface, NULL, flags, FALSE);
259     if(doc == window->doc)
260         doc->skip_mutation_notif = FALSE;
261     uri->channel_bsc = NULL;
262     nsIDocShell_Release(doc_shell);
263     if(NS_FAILED(nsres)) {
264         WARN("LoadURI failed: %08x\n", nsres);
265         return E_FAIL;
266     }
267
268     return S_OK;
269 }
270
271 static void set_uri_nscontainer(nsWineURI *This, NSContainer *nscontainer)
272 {
273     if(This->container) {
274         if(This->container == nscontainer)
275             return;
276         TRACE("Changing %p -> %p\n", This->container, nscontainer);
277         nsIWebBrowserChrome_Release(&This->container->nsIWebBrowserChrome_iface);
278     }
279
280     if(nscontainer)
281         nsIWebBrowserChrome_AddRef(&nscontainer->nsIWebBrowserChrome_iface);
282     This->container = nscontainer;
283 }
284
285 static void set_uri_window(nsWineURI *This, HTMLWindow *window)
286 {
287     if(This->window_ref) {
288         if(This->window_ref->window == window)
289             return;
290         TRACE("Changing %p -> %p\n", This->window_ref->window, window);
291         windowref_release(This->window_ref);
292     }
293
294     if(window) {
295         windowref_addref(window->window_ref);
296         This->window_ref = window->window_ref;
297
298         if(window->doc_obj)
299             set_uri_nscontainer(This, window->doc_obj->nscontainer);
300     }else {
301         This->window_ref = NULL;
302     }
303 }
304
305 static inline BOOL is_http_channel(nsChannel *This)
306 {
307     return This->url_scheme == URL_SCHEME_HTTP || This->url_scheme == URL_SCHEME_HTTPS;
308 }
309
310 static http_header_t *find_http_header(struct list *headers, const WCHAR *name, int len)
311 {
312     http_header_t *iter;
313
314     LIST_FOR_EACH_ENTRY(iter, headers, http_header_t, entry) {
315         if(!strcmpiW(iter->header, name))
316             return iter;
317     }
318
319     return NULL;
320 }
321
322 static nsresult get_channel_http_header(struct list *headers, const nsACString *header_name_str,
323         nsACString *_retval)
324 {
325     const char *header_namea;
326     http_header_t *header;
327     WCHAR *header_name;
328     char *data;
329
330     nsACString_GetData(header_name_str, &header_namea);
331     header_name = heap_strdupAtoW(header_namea);
332     if(!header_name)
333         return NS_ERROR_UNEXPECTED;
334
335     header = find_http_header(headers, header_name, strlenW(header_name));
336     heap_free(header_name);
337     if(!header)
338         return NS_ERROR_NOT_AVAILABLE;
339
340     data = heap_strdupWtoA(header->data);
341     if(!data)
342         return NS_ERROR_UNEXPECTED;
343
344     nsACString_SetData(_retval, data);
345     heap_free(data);
346     return NS_OK;
347 }
348
349 HRESULT set_http_header(struct list *headers, const WCHAR *name, int name_len,
350         const WCHAR *value, int value_len)
351 {
352     http_header_t *header;
353
354     TRACE("%s: %s\n", debugstr_wn(name, name_len), debugstr_wn(value, value_len));
355
356     header = find_http_header(headers, name, name_len);
357     if(header) {
358         WCHAR *new_data;
359
360         new_data = heap_strndupW(value, value_len);
361         if(!new_data)
362             return E_OUTOFMEMORY;
363
364         heap_free(header->data);
365         header->data = new_data;
366     }else {
367         header = heap_alloc(sizeof(http_header_t));
368         if(!header)
369             return E_OUTOFMEMORY;
370
371         header->header = heap_strndupW(name, name_len);
372         header->data = heap_strndupW(value, value_len);
373         if(!header->header || !header->data) {
374             heap_free(header->header);
375             heap_free(header->data);
376             heap_free(header);
377             return E_OUTOFMEMORY;
378         }
379
380         list_add_tail(headers, &header->entry);
381     }
382
383     return S_OK;
384 }
385
386 static nsresult set_channel_http_header(struct list *headers, const nsACString *name_str,
387         const nsACString *value_str)
388 {
389     const char *namea, *valuea;
390     WCHAR *name, *value;
391     HRESULT hres;
392
393     nsACString_GetData(name_str, &namea);
394     name = heap_strdupAtoW(namea);
395     if(!name)
396         return NS_ERROR_UNEXPECTED;
397
398     nsACString_GetData(value_str, &valuea);
399     value = heap_strdupAtoW(valuea);
400     if(!value) {
401         heap_free(name);
402         return NS_ERROR_UNEXPECTED;
403     }
404
405     hres = set_http_header(headers, name, strlenW(name), value, strlenW(value));
406
407     heap_free(name);
408     heap_free(value);
409     return SUCCEEDED(hres) ? NS_OK : NS_ERROR_UNEXPECTED;
410 }
411
412 static nsresult visit_http_headers(struct list *headers, nsIHttpHeaderVisitor *visitor)
413 {
414     nsACString header_str, value_str;
415     char *header, *value;
416     http_header_t *iter;
417     nsresult nsres;
418
419     LIST_FOR_EACH_ENTRY(iter, headers, http_header_t, entry) {
420         header = heap_strdupWtoA(iter->header);
421         if(!header)
422             return NS_ERROR_OUT_OF_MEMORY;
423
424         value = heap_strdupWtoA(iter->data);
425         if(!value) {
426             heap_free(header);
427             return NS_ERROR_OUT_OF_MEMORY;
428         }
429
430         nsACString_InitDepend(&header_str, header);
431         nsACString_InitDepend(&value_str, value);
432         nsres = nsIHttpHeaderVisitor_VisitHeader(visitor, &header_str, &value_str);
433         nsACString_Finish(&header_str);
434         nsACString_Finish(&value_str);
435         heap_free(header);
436         heap_free(value);
437         if(NS_FAILED(nsres))
438             break;
439     }
440
441     return NS_OK;
442 }
443
444 static void free_http_headers(struct list *list)
445 {
446     http_header_t *iter, *iter_next;
447
448     LIST_FOR_EACH_ENTRY_SAFE(iter, iter_next, list, http_header_t, entry) {
449         list_remove(&iter->entry);
450         heap_free(iter->header);
451         heap_free(iter->data);
452         heap_free(iter);
453     }
454 }
455
456 static inline nsChannel *impl_from_nsIHttpChannel(nsIHttpChannel *iface)
457 {
458     return CONTAINING_RECORD(iface, nsChannel, nsIHttpChannel_iface);
459 }
460
461 static nsresult NSAPI nsChannel_QueryInterface(nsIHttpChannel *iface, nsIIDRef riid, void **result)
462 {
463     nsChannel *This = impl_from_nsIHttpChannel(iface);
464
465     if(IsEqualGUID(&IID_nsISupports, riid)) {
466         TRACE("(%p)->(IID_nsISupports %p)\n", This, result);
467         *result = &This->nsIHttpChannel_iface;
468     }else if(IsEqualGUID(&IID_nsIRequest, riid)) {
469         TRACE("(%p)->(IID_nsIRequest %p)\n", This, result);
470         *result = &This->nsIHttpChannel_iface;
471     }else if(IsEqualGUID(&IID_nsIChannel, riid)) {
472         TRACE("(%p)->(IID_nsIChannel %p)\n", This, result);
473         *result = &This->nsIHttpChannel_iface;
474     }else if(IsEqualGUID(&IID_nsIHttpChannel, riid)) {
475         TRACE("(%p)->(IID_nsIHttpChannel %p)\n", This, result);
476         *result = is_http_channel(This) ? &This->nsIHttpChannel_iface : NULL;
477     }else if(IsEqualGUID(&IID_nsIUploadChannel, riid)) {
478         TRACE("(%p)->(IID_nsIUploadChannel %p)\n", This, result);
479         *result = &This->nsIUploadChannel_iface;
480     }else if(IsEqualGUID(&IID_nsIHttpChannelInternal, riid)) {
481         TRACE("(%p)->(IID_nsIHttpChannelInternal %p)\n", This, result);
482         *result = is_http_channel(This) ? &This->nsIHttpChannelInternal_iface : NULL;
483     }else {
484         TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), result);
485         *result = NULL;
486     }
487
488     if(*result) {
489         nsIChannel_AddRef(&This->nsIHttpChannel_iface);
490         return NS_OK;
491     }
492
493     return NS_NOINTERFACE;
494 }
495
496 static nsrefcnt NSAPI nsChannel_AddRef(nsIHttpChannel *iface)
497 {
498     nsChannel *This = impl_from_nsIHttpChannel(iface);
499     nsrefcnt ref = InterlockedIncrement(&This->ref);
500
501     TRACE("(%p) ref=%d\n", This, ref);
502
503     return ref;
504 }
505
506 static nsrefcnt NSAPI nsChannel_Release(nsIHttpChannel *iface)
507 {
508     nsChannel *This = impl_from_nsIHttpChannel(iface);
509     LONG ref = InterlockedDecrement(&This->ref);
510
511     if(!ref) {
512         nsIURI_Release(&This->uri->nsIURL_iface);
513         if(This->owner)
514             nsISupports_Release(This->owner);
515         if(This->post_data_stream)
516             nsIInputStream_Release(This->post_data_stream);
517         if(This->load_group)
518             nsILoadGroup_Release(This->load_group);
519         if(This->notif_callback)
520             nsIInterfaceRequestor_Release(This->notif_callback);
521         if(This->original_uri)
522             nsIURI_Release(This->original_uri);
523         if(This->referrer)
524             nsIURI_Release(This->referrer);
525
526         free_http_headers(&This->response_headers);
527         free_http_headers(&This->request_headers);
528
529         heap_free(This->content_type);
530         heap_free(This->charset);
531         heap_free(This);
532     }
533
534     return ref;
535 }
536
537 static nsresult NSAPI nsChannel_GetName(nsIHttpChannel *iface, nsACString *aName)
538 {
539     nsChannel *This = impl_from_nsIHttpChannel(iface);
540
541     TRACE("(%p)->(%p)\n", This, aName);
542
543     return nsIURI_GetSpec(&This->uri->nsIURL_iface, aName);
544 }
545
546 static nsresult NSAPI nsChannel_IsPending(nsIHttpChannel *iface, PRBool *_retval)
547 {
548     nsChannel *This = impl_from_nsIHttpChannel(iface);
549
550     FIXME("(%p)->(%p)\n", This, _retval);
551
552     return NS_ERROR_NOT_IMPLEMENTED;
553 }
554
555 static nsresult NSAPI nsChannel_GetStatus(nsIHttpChannel *iface, nsresult *aStatus)
556 {
557     nsChannel *This = impl_from_nsIHttpChannel(iface);
558
559     WARN("(%p)->(%p) returning NS_OK\n", This, aStatus);
560
561     return *aStatus = NS_OK;
562 }
563
564 static nsresult NSAPI nsChannel_Cancel(nsIHttpChannel *iface, nsresult aStatus)
565 {
566     nsChannel *This = impl_from_nsIHttpChannel(iface);
567
568     FIXME("(%p)->(%08x)\n", This, aStatus);
569
570     return NS_ERROR_NOT_IMPLEMENTED;
571 }
572
573 static nsresult NSAPI nsChannel_Suspend(nsIHttpChannel *iface)
574 {
575     nsChannel *This = impl_from_nsIHttpChannel(iface);
576
577     FIXME("(%p)\n", This);
578
579     return NS_ERROR_NOT_IMPLEMENTED;
580 }
581
582 static nsresult NSAPI nsChannel_Resume(nsIHttpChannel *iface)
583 {
584     nsChannel *This = impl_from_nsIHttpChannel(iface);
585
586     FIXME("(%p)\n", This);
587
588     return NS_ERROR_NOT_IMPLEMENTED;
589 }
590
591 static nsresult NSAPI nsChannel_GetLoadGroup(nsIHttpChannel *iface, nsILoadGroup **aLoadGroup)
592 {
593     nsChannel *This = impl_from_nsIHttpChannel(iface);
594
595     TRACE("(%p)->(%p)\n", This, aLoadGroup);
596
597     if(This->load_group)
598         nsILoadGroup_AddRef(This->load_group);
599
600     *aLoadGroup = This->load_group;
601     return NS_OK;
602 }
603
604 static nsresult NSAPI nsChannel_SetLoadGroup(nsIHttpChannel *iface, nsILoadGroup *aLoadGroup)
605 {
606     nsChannel *This = impl_from_nsIHttpChannel(iface);
607
608     TRACE("(%p)->(%p)\n", This, aLoadGroup);
609
610     if(This->load_group)
611         nsILoadGroup_Release(This->load_group);
612     if(aLoadGroup)
613         nsILoadGroup_AddRef(aLoadGroup);
614     This->load_group = aLoadGroup;
615
616     return NS_OK;
617 }
618
619 static nsresult NSAPI nsChannel_GetLoadFlags(nsIHttpChannel *iface, nsLoadFlags *aLoadFlags)
620 {
621     nsChannel *This = impl_from_nsIHttpChannel(iface);
622
623     TRACE("(%p)->(%p)\n", This, aLoadFlags);
624
625     *aLoadFlags = This->load_flags;
626     return NS_OK;
627 }
628
629 static nsresult NSAPI nsChannel_SetLoadFlags(nsIHttpChannel *iface, nsLoadFlags aLoadFlags)
630 {
631     nsChannel *This = impl_from_nsIHttpChannel(iface);
632
633     TRACE("(%p)->(%08x)\n", This, aLoadFlags);
634
635     This->load_flags = aLoadFlags;
636     return NS_OK;
637 }
638
639 static nsresult NSAPI nsChannel_GetOriginalURI(nsIHttpChannel *iface, nsIURI **aOriginalURI)
640 {
641     nsChannel *This = impl_from_nsIHttpChannel(iface);
642
643     TRACE("(%p)->(%p)\n", This, aOriginalURI);
644
645     if(This->original_uri)
646         nsIURI_AddRef(This->original_uri);
647
648     *aOriginalURI = This->original_uri;
649     return NS_OK;
650 }
651
652 static nsresult NSAPI nsChannel_SetOriginalURI(nsIHttpChannel *iface, nsIURI *aOriginalURI)
653 {
654     nsChannel *This = impl_from_nsIHttpChannel(iface);
655
656     TRACE("(%p)->(%p)\n", This, aOriginalURI);
657
658     if(This->original_uri)
659         nsIURI_Release(This->original_uri);
660
661     nsIURI_AddRef(aOriginalURI);
662     This->original_uri = aOriginalURI;
663     return NS_OK;
664 }
665
666 static nsresult NSAPI nsChannel_GetURI(nsIHttpChannel *iface, nsIURI **aURI)
667 {
668     nsChannel *This = impl_from_nsIHttpChannel(iface);
669
670     TRACE("(%p)->(%p)\n", This, aURI);
671
672     nsIURI_AddRef(&This->uri->nsIURL_iface);
673     *aURI = (nsIURI*)This->uri;
674
675     return NS_OK;
676 }
677
678 static nsresult NSAPI nsChannel_GetOwner(nsIHttpChannel *iface, nsISupports **aOwner)
679 {
680     nsChannel *This = impl_from_nsIHttpChannel(iface);
681
682     TRACE("(%p)->(%p)\n", This, aOwner);
683
684     if(This->owner)
685         nsISupports_AddRef(This->owner);
686     *aOwner = This->owner;
687
688     return NS_OK;
689 }
690
691 static nsresult NSAPI nsChannel_SetOwner(nsIHttpChannel *iface, nsISupports *aOwner)
692 {
693     nsChannel *This = impl_from_nsIHttpChannel(iface);
694
695     TRACE("(%p)->(%p)\n", This, aOwner);
696
697     if(aOwner)
698         nsISupports_AddRef(aOwner);
699     if(This->owner)
700         nsISupports_Release(This->owner);
701     This->owner = aOwner;
702
703     return NS_OK;
704 }
705
706 static nsresult NSAPI nsChannel_GetNotificationCallbacks(nsIHttpChannel *iface,
707         nsIInterfaceRequestor **aNotificationCallbacks)
708 {
709     nsChannel *This = impl_from_nsIHttpChannel(iface);
710
711     TRACE("(%p)->(%p)\n", This, aNotificationCallbacks);
712
713     if(This->notif_callback)
714         nsIInterfaceRequestor_AddRef(This->notif_callback);
715     *aNotificationCallbacks = This->notif_callback;
716
717     return NS_OK;
718 }
719
720 static nsresult NSAPI nsChannel_SetNotificationCallbacks(nsIHttpChannel *iface,
721         nsIInterfaceRequestor *aNotificationCallbacks)
722 {
723     nsChannel *This = impl_from_nsIHttpChannel(iface);
724
725     TRACE("(%p)->(%p)\n", This, aNotificationCallbacks);
726
727     if(This->notif_callback)
728         nsIInterfaceRequestor_Release(This->notif_callback);
729     if(aNotificationCallbacks)
730         nsIInterfaceRequestor_AddRef(aNotificationCallbacks);
731
732     This->notif_callback = aNotificationCallbacks;
733
734     return NS_OK;
735 }
736
737 static nsresult NSAPI nsChannel_GetSecurityInfo(nsIHttpChannel *iface, nsISupports **aSecurityInfo)
738 {
739     nsChannel *This = impl_from_nsIHttpChannel(iface);
740
741     TRACE("(%p)->(%p)\n", This, aSecurityInfo);
742
743     return NS_ERROR_NOT_IMPLEMENTED;
744 }
745
746 static nsresult NSAPI nsChannel_GetContentType(nsIHttpChannel *iface, nsACString *aContentType)
747 {
748     nsChannel *This = impl_from_nsIHttpChannel(iface);
749
750     TRACE("(%p)->(%p)\n", This, aContentType);
751
752     if(This->content_type) {
753         nsACString_SetData(aContentType, This->content_type);
754         return S_OK;
755     }
756
757     WARN("unknown type\n");
758     return NS_ERROR_FAILURE;
759 }
760
761 static nsresult NSAPI nsChannel_SetContentType(nsIHttpChannel *iface,
762                                                const nsACString *aContentType)
763 {
764     nsChannel *This = impl_from_nsIHttpChannel(iface);
765     const char *content_type;
766
767     TRACE("(%p)->(%s)\n", This, debugstr_nsacstr(aContentType));
768
769     nsACString_GetData(aContentType, &content_type);
770     heap_free(This->content_type);
771     This->content_type = heap_strdupA(content_type);
772
773     return NS_OK;
774 }
775
776 static nsresult NSAPI nsChannel_GetContentCharset(nsIHttpChannel *iface,
777                                                   nsACString *aContentCharset)
778 {
779     nsChannel *This = impl_from_nsIHttpChannel(iface);
780
781     TRACE("(%p)->(%p)\n", This, aContentCharset);
782
783     if(This->charset) {
784         nsACString_SetData(aContentCharset, This->charset);
785         return NS_OK;
786     }
787
788     nsACString_SetData(aContentCharset, "");
789     return NS_OK;
790 }
791
792 static nsresult NSAPI nsChannel_SetContentCharset(nsIHttpChannel *iface,
793                                                   const nsACString *aContentCharset)
794 {
795     nsChannel *This = impl_from_nsIHttpChannel(iface);
796
797     FIXME("(%p)->(%s)\n", This, debugstr_nsacstr(aContentCharset));
798
799     return NS_ERROR_NOT_IMPLEMENTED;
800 }
801
802 static nsresult NSAPI nsChannel_GetContentLength(nsIHttpChannel *iface, PRInt32 *aContentLength)
803 {
804     nsChannel *This = impl_from_nsIHttpChannel(iface);
805
806     FIXME("(%p)->(%p)\n", This, aContentLength);
807
808     return NS_ERROR_NOT_IMPLEMENTED;
809 }
810
811 static nsresult NSAPI nsChannel_SetContentLength(nsIHttpChannel *iface, PRInt32 aContentLength)
812 {
813     nsChannel *This = impl_from_nsIHttpChannel(iface);
814
815     FIXME("(%p)->(%d)\n", This, aContentLength);
816
817     return NS_ERROR_NOT_IMPLEMENTED;
818 }
819
820 static nsresult NSAPI nsChannel_Open(nsIHttpChannel *iface, nsIInputStream **_retval)
821 {
822     nsChannel *This = impl_from_nsIHttpChannel(iface);
823
824     FIXME("(%p)->(%p)\n", This, _retval);
825
826     return NS_ERROR_NOT_IMPLEMENTED;
827 }
828
829 static HTMLWindow *get_window_from_load_group(nsChannel *This)
830 {
831     HTMLWindow *window;
832     nsIChannel *channel;
833     nsIRequest *req;
834     nsWineURI *wine_uri;
835     nsIURI *uri;
836     nsresult nsres;
837
838     nsres = nsILoadGroup_GetDefaultLoadRequest(This->load_group, &req);
839     if(NS_FAILED(nsres)) {
840         ERR("GetDefaultLoadRequest failed: %08x\n", nsres);
841         return NULL;
842     }
843
844     if(!req)
845         return NULL;
846
847     nsres = nsIRequest_QueryInterface(req, &IID_nsIChannel, (void**)&channel);
848     nsIRequest_Release(req);
849     if(NS_FAILED(nsres)) {
850         WARN("Could not get nsIChannel interface: %08x\n", nsres);
851         return NULL;
852     }
853
854     nsres = nsIChannel_GetURI(channel, &uri);
855     nsIChannel_Release(channel);
856     if(NS_FAILED(nsres)) {
857         ERR("GetURI failed: %08x\n", nsres);
858         return NULL;
859     }
860
861     nsres = nsIURI_QueryInterface(uri, &IID_nsWineURI, (void**)&wine_uri);
862     nsIURI_Release(uri);
863     if(NS_FAILED(nsres)) {
864         TRACE("Could not get nsWineURI: %08x\n", nsres);
865         return NULL;
866     }
867
868     window = wine_uri->window_ref ? wine_uri->window_ref->window : NULL;
869     if(window)
870         IHTMLWindow2_AddRef(&window->IHTMLWindow2_iface);
871     nsIURI_Release(&wine_uri->nsIURL_iface);
872
873     return window;
874 }
875
876 static HTMLWindow *get_channel_window(nsChannel *This)
877 {
878     nsIWebProgress *web_progress;
879     nsIDOMWindow *nswindow;
880     HTMLWindow *window;
881     nsresult nsres;
882
883     if(This->load_group) {
884         nsIRequestObserver *req_observer;
885
886         nsres = nsILoadGroup_GetGroupObserver(This->load_group, &req_observer);
887         if(NS_FAILED(nsres) || !req_observer) {
888             ERR("GetGroupObserver failed: %08x\n", nsres);
889             return NULL;
890         }
891
892         nsres = nsIRequestObserver_QueryInterface(req_observer, &IID_nsIWebProgress, (void**)&web_progress);
893         nsIRequestObserver_Release(req_observer);
894         if(NS_FAILED(nsres)) {
895             ERR("Could not get nsIWebProgress iface: %08x\n", nsres);
896             return NULL;
897         }
898     }else if(This->notif_callback) {
899         nsres = nsIInterfaceRequestor_GetInterface(This->notif_callback, &IID_nsIWebProgress, (void**)&web_progress);
900         if(NS_FAILED(nsres)) {
901             ERR("GetInterface(IID_nsIWebProgress failed: %08x\n", nsres);
902             return NULL;
903         }
904     }else {
905         ERR("no load group nor notif callback\n");
906         return NULL;
907     }
908
909     nsres = nsIWebProgress_GetDOMWindow(web_progress, &nswindow);
910     nsIWebProgress_Release(web_progress);
911     if(NS_FAILED(nsres) || !nswindow) {
912         ERR("GetDOMWindow failed: %08x\n", nsres);
913         return NULL;
914     }
915
916     window = nswindow_to_window(nswindow);
917     nsIDOMWindow_Release(nswindow);
918
919     if(window)
920         IHTMLWindow2_AddRef(&window->IHTMLWindow2_iface);
921     else
922         FIXME("NULL window for %p\n", nswindow);
923     return window;
924 }
925
926 typedef struct {
927     task_t header;
928     HTMLDocumentNode *doc;
929     nsChannelBSC *bscallback;
930 } start_binding_task_t;
931
932 static void start_binding_proc(task_t *_task)
933 {
934     start_binding_task_t *task = (start_binding_task_t*)_task;
935
936     start_binding(NULL, task->doc, (BSCallback*)task->bscallback, NULL);
937 }
938
939 static void start_binding_task_destr(task_t *_task)
940 {
941     start_binding_task_t *task = (start_binding_task_t*)_task;
942
943     IBindStatusCallback_Release(&task->bscallback->bsc.IBindStatusCallback_iface);
944     heap_free(task);
945 }
946
947 static nsresult async_open(nsChannel *This, HTMLWindow *window, BOOL is_doc_channel, nsIStreamListener *listener,
948         nsISupports *context)
949 {
950     nsChannelBSC *bscallback;
951     IMoniker *mon = NULL;
952     HRESULT hres;
953
954     hres = CreateURLMonikerEx2(NULL, This->uri->uri, &mon, 0);
955     if(FAILED(hres)) {
956         WARN("CreateURLMoniker failed: %08x\n", hres);
957         return NS_ERROR_UNEXPECTED;
958     }
959
960     if(is_doc_channel)
961         set_current_mon(window, mon);
962
963     hres = create_channelbsc(mon, NULL, NULL, 0, &bscallback);
964     IMoniker_Release(mon);
965     if(FAILED(hres))
966         return NS_ERROR_UNEXPECTED;
967
968     channelbsc_set_channel(bscallback, This, listener, context);
969
970     if(is_doc_channel) {
971         set_window_bscallback(window, bscallback);
972         async_start_doc_binding(window, bscallback);
973         IUnknown_Release((IUnknown*)bscallback);
974     }else {
975         start_binding_task_t *task = heap_alloc(sizeof(start_binding_task_t));
976
977         task->doc = window->doc;
978         task->bscallback = bscallback;
979         push_task(&task->header, start_binding_proc, start_binding_task_destr, window->doc->basedoc.task_magic);
980     }
981
982     return NS_OK;
983 }
984
985 static nsresult NSAPI nsChannel_AsyncOpen(nsIHttpChannel *iface, nsIStreamListener *aListener,
986                                           nsISupports *aContext)
987 {
988     nsChannel *This = impl_from_nsIHttpChannel(iface);
989     HTMLWindow *window = NULL;
990     BOOL cancel = FALSE;
991     nsresult nsres = NS_OK;
992
993     TRACE("(%p)->(%p %p)\n", This, aListener, aContext);
994
995     if(!ensure_uri(This->uri))
996         return NS_ERROR_FAILURE;
997
998     if(TRACE_ON(mshtml)) {
999         BSTR uri_str;
1000         IUri_GetDisplayUri(This->uri->uri, &uri_str);
1001         TRACE("opening %s\n", debugstr_w(uri_str));
1002         SysFreeString(uri_str);
1003     }
1004
1005     if(This->uri->is_doc_uri) {
1006         window = get_channel_window(This);
1007         if(window) {
1008             set_uri_window(This->uri, window);
1009         }else if(This->uri->container) {
1010             BOOL b;
1011
1012             /* nscontainer->doc should be NULL which means navigation to a new window */
1013             if(This->uri->container->doc)
1014                 FIXME("nscontainer->doc = %p\n", This->uri->container->doc);
1015
1016             nsres = before_async_open(This, This->uri->container, &b);
1017             if(NS_FAILED(nsres))
1018                 return nsres;
1019             if(b)
1020                 FIXME("Navigation not cancelled\n");
1021             return NS_ERROR_UNEXPECTED;
1022         }
1023     }
1024
1025     if(!window) {
1026         if(This->uri->window_ref && This->uri->window_ref->window) {
1027             window = This->uri->window_ref->window;
1028             IHTMLWindow2_AddRef(&window->IHTMLWindow2_iface);
1029         }else {
1030             /* FIXME: Analyze removing get_window_from_load_group call */
1031             if(This->load_group)
1032                 window = get_window_from_load_group(This);
1033             if(!window)
1034                 window = get_channel_window(This);
1035             if(window)
1036                 set_uri_window(This->uri, window);
1037         }
1038     }
1039
1040     if(!window) {
1041         ERR("window = NULL\n");
1042         return NS_ERROR_UNEXPECTED;
1043     }
1044
1045     if(This->uri->is_doc_uri && window == window->doc_obj->basedoc.window) {
1046         if(This->uri->channel_bsc) {
1047             channelbsc_set_channel(This->uri->channel_bsc, This, aListener, aContext);
1048
1049             if(window->doc_obj->mime) {
1050                 heap_free(This->content_type);
1051                 This->content_type = heap_strdupWtoA(window->doc_obj->mime);
1052             }
1053
1054             cancel = TRUE;
1055         }else {
1056             nsres = before_async_open(This, window->doc_obj->nscontainer, &cancel);
1057             if(NS_SUCCEEDED(nsres)  && cancel) {
1058                 TRACE("canceled\n");
1059                 nsres = NS_BINDING_ABORTED;
1060             }
1061         }
1062     }
1063
1064     if(!cancel)
1065         nsres = async_open(This, window, This->uri->is_doc_uri, aListener, aContext);
1066
1067     if(NS_SUCCEEDED(nsres) && This->load_group) {
1068         nsres = nsILoadGroup_AddRequest(This->load_group, (nsIRequest*)&This->nsIHttpChannel_iface,
1069                 aContext);
1070         if(NS_FAILED(nsres))
1071             ERR("AddRequest failed: %08x\n", nsres);
1072     }
1073
1074     IHTMLWindow2_Release(&window->IHTMLWindow2_iface);
1075     return nsres;
1076 }
1077
1078 static nsresult NSAPI nsChannel_GetRequestMethod(nsIHttpChannel *iface, nsACString *aRequestMethod)
1079 {
1080     nsChannel *This = impl_from_nsIHttpChannel(iface);
1081
1082     TRACE("(%p)->(%p)\n", This, aRequestMethod);
1083
1084     nsACString_SetData(aRequestMethod, request_method_strings[This->request_method]);
1085     return NS_OK;
1086 }
1087
1088 static nsresult NSAPI nsChannel_SetRequestMethod(nsIHttpChannel *iface,
1089                                                  const nsACString *aRequestMethod)
1090 {
1091     nsChannel *This = impl_from_nsIHttpChannel(iface);
1092     const char *method;
1093     unsigned i;
1094
1095     TRACE("(%p)->(%s)\n", This, debugstr_nsacstr(aRequestMethod));
1096
1097     nsACString_GetData(aRequestMethod, &method);
1098     for(i=0; i < sizeof(request_method_strings)/sizeof(*request_method_strings); i++) {
1099         if(!strcasecmp(method, request_method_strings[i])) {
1100             This->request_method = i;
1101             return NS_OK;
1102         }
1103     }
1104
1105     ERR("Invalid method %s\n", debugstr_a(method));
1106     return NS_ERROR_UNEXPECTED;
1107 }
1108
1109 static nsresult NSAPI nsChannel_GetReferrer(nsIHttpChannel *iface, nsIURI **aReferrer)
1110 {
1111     nsChannel *This = impl_from_nsIHttpChannel(iface);
1112
1113     TRACE("(%p)->(%p)\n", This, aReferrer);
1114
1115     if(This->referrer)
1116         nsIURI_AddRef(This->referrer);
1117     *aReferrer = This->referrer;
1118     return NS_OK;
1119 }
1120
1121 static nsresult NSAPI nsChannel_SetReferrer(nsIHttpChannel *iface, nsIURI *aReferrer)
1122 {
1123     nsChannel *This = impl_from_nsIHttpChannel(iface);
1124
1125     TRACE("(%p)->(%p)\n", This, aReferrer);
1126
1127     if(aReferrer)
1128         nsIURI_AddRef(aReferrer);
1129     if(This->referrer)
1130         nsIURI_Release(This->referrer);
1131     This->referrer = aReferrer;
1132     return NS_OK;
1133 }
1134
1135 static nsresult NSAPI nsChannel_GetRequestHeader(nsIHttpChannel *iface,
1136          const nsACString *aHeader, nsACString *_retval)
1137 {
1138     nsChannel *This = impl_from_nsIHttpChannel(iface);
1139
1140     TRACE("(%p)->(%s %p)\n", This, debugstr_nsacstr(aHeader), _retval);
1141
1142     return get_channel_http_header(&This->request_headers, aHeader, _retval);
1143 }
1144
1145 static nsresult NSAPI nsChannel_SetRequestHeader(nsIHttpChannel *iface,
1146          const nsACString *aHeader, const nsACString *aValue, PRBool aMerge)
1147 {
1148     nsChannel *This = impl_from_nsIHttpChannel(iface);
1149
1150     TRACE("(%p)->(%s %s %x)\n", This, debugstr_nsacstr(aHeader), debugstr_nsacstr(aValue), aMerge);
1151
1152     if(aMerge)
1153         FIXME("aMerge not supported\n");
1154
1155     return set_channel_http_header(&This->request_headers, aHeader, aValue);
1156 }
1157
1158 static nsresult NSAPI nsChannel_VisitRequestHeaders(nsIHttpChannel *iface,
1159                                                     nsIHttpHeaderVisitor *aVisitor)
1160 {
1161     nsChannel *This = impl_from_nsIHttpChannel(iface);
1162
1163     FIXME("(%p)->(%p)\n", This, aVisitor);
1164
1165     return NS_ERROR_NOT_IMPLEMENTED;
1166 }
1167
1168 static nsresult NSAPI nsChannel_GetAllowPipelining(nsIHttpChannel *iface, PRBool *aAllowPipelining)
1169 {
1170     nsChannel *This = impl_from_nsIHttpChannel(iface);
1171
1172     FIXME("(%p)->(%p)\n", This, aAllowPipelining);
1173
1174     return NS_ERROR_NOT_IMPLEMENTED;
1175 }
1176
1177 static nsresult NSAPI nsChannel_SetAllowPipelining(nsIHttpChannel *iface, PRBool aAllowPipelining)
1178 {
1179     nsChannel *This = impl_from_nsIHttpChannel(iface);
1180
1181     FIXME("(%p)->(%x)\n", This, aAllowPipelining);
1182
1183     return NS_ERROR_NOT_IMPLEMENTED;
1184 }
1185
1186 static nsresult NSAPI nsChannel_GetRedirectionLimit(nsIHttpChannel *iface, PRUint32 *aRedirectionLimit)
1187 {
1188     nsChannel *This = impl_from_nsIHttpChannel(iface);
1189
1190     FIXME("(%p)->(%p)\n", This, aRedirectionLimit);
1191
1192     return NS_ERROR_NOT_IMPLEMENTED;
1193 }
1194
1195 static nsresult NSAPI nsChannel_SetRedirectionLimit(nsIHttpChannel *iface, PRUint32 aRedirectionLimit)
1196 {
1197     nsChannel *This = impl_from_nsIHttpChannel(iface);
1198
1199     FIXME("(%p)->(%u)\n", This, aRedirectionLimit);
1200
1201     return NS_ERROR_NOT_IMPLEMENTED;
1202 }
1203
1204 static nsresult NSAPI nsChannel_GetResponseStatus(nsIHttpChannel *iface, PRUint32 *aResponseStatus)
1205 {
1206     nsChannel *This = impl_from_nsIHttpChannel(iface);
1207
1208     TRACE("(%p)->(%p)\n", This, aResponseStatus);
1209
1210     if(This->response_status) {
1211         *aResponseStatus = This->response_status;
1212         return NS_OK;
1213     }
1214
1215     WARN("No response status\n");
1216     return NS_ERROR_UNEXPECTED;
1217 }
1218
1219 static nsresult NSAPI nsChannel_GetResponseStatusText(nsIHttpChannel *iface,
1220                                                       nsACString *aResponseStatusText)
1221 {
1222     nsChannel *This = impl_from_nsIHttpChannel(iface);
1223
1224     FIXME("(%p)->(%p)\n", This, aResponseStatusText);
1225
1226     return NS_ERROR_NOT_IMPLEMENTED;
1227 }
1228
1229 static nsresult NSAPI nsChannel_GetRequestSucceeded(nsIHttpChannel *iface,
1230                                                     PRBool *aRequestSucceeded)
1231 {
1232     nsChannel *This = impl_from_nsIHttpChannel(iface);
1233
1234     TRACE("(%p)->(%p)\n", This, aRequestSucceeded);
1235
1236     if(!This->response_status)
1237         return NS_ERROR_NOT_AVAILABLE;
1238
1239     *aRequestSucceeded = This->response_status/100 == 2;
1240
1241     return NS_OK;
1242 }
1243
1244 static nsresult NSAPI nsChannel_GetResponseHeader(nsIHttpChannel *iface,
1245          const nsACString *header, nsACString *_retval)
1246 {
1247     nsChannel *This = impl_from_nsIHttpChannel(iface);
1248
1249     TRACE("(%p)->(%s %p)\n", This, debugstr_nsacstr(header), _retval);
1250
1251     return get_channel_http_header(&This->response_headers, header, _retval);
1252 }
1253
1254 static nsresult NSAPI nsChannel_SetResponseHeader(nsIHttpChannel *iface,
1255         const nsACString *header, const nsACString *value, PRBool merge)
1256 {
1257     nsChannel *This = impl_from_nsIHttpChannel(iface);
1258
1259     FIXME("(%p)->(%s %s %x)\n", This, debugstr_nsacstr(header), debugstr_nsacstr(value), merge);
1260
1261     return NS_ERROR_NOT_IMPLEMENTED;
1262 }
1263
1264 static nsresult NSAPI nsChannel_VisitResponseHeaders(nsIHttpChannel *iface,
1265         nsIHttpHeaderVisitor *aVisitor)
1266 {
1267     nsChannel *This = impl_from_nsIHttpChannel(iface);
1268
1269     TRACE("(%p)->(%p)\n", This, aVisitor);
1270
1271     return visit_http_headers(&This->response_headers, aVisitor);
1272 }
1273
1274 static nsresult NSAPI nsChannel_IsNoStoreResponse(nsIHttpChannel *iface, PRBool *_retval)
1275 {
1276     nsChannel *This = impl_from_nsIHttpChannel(iface);
1277     http_header_t *header;
1278
1279     static const WCHAR cache_controlW[] = {'C','a','c','h','e','-','C','o','n','t','r','o','l'};
1280     static const WCHAR no_storeW[] = {'n','o','-','s','t','o','r','e',0};
1281
1282     TRACE("(%p)->(%p)\n", This, _retval);
1283
1284     header = find_http_header(&This->response_headers, cache_controlW, sizeof(cache_controlW)/sizeof(WCHAR));
1285     *_retval = header && !strcmpiW(header->data, no_storeW);
1286     return NS_OK;
1287 }
1288
1289 static nsresult NSAPI nsChannel_IsNoCacheResponse(nsIHttpChannel *iface, PRBool *_retval)
1290 {
1291     nsChannel *This = impl_from_nsIHttpChannel(iface);
1292
1293     FIXME("(%p)->(%p)\n", This, _retval);
1294
1295     return NS_ERROR_NOT_IMPLEMENTED;
1296 }
1297
1298 static const nsIHttpChannelVtbl nsChannelVtbl = {
1299     nsChannel_QueryInterface,
1300     nsChannel_AddRef,
1301     nsChannel_Release,
1302     nsChannel_GetName,
1303     nsChannel_IsPending,
1304     nsChannel_GetStatus,
1305     nsChannel_Cancel,
1306     nsChannel_Suspend,
1307     nsChannel_Resume,
1308     nsChannel_GetLoadGroup,
1309     nsChannel_SetLoadGroup,
1310     nsChannel_GetLoadFlags,
1311     nsChannel_SetLoadFlags,
1312     nsChannel_GetOriginalURI,
1313     nsChannel_SetOriginalURI,
1314     nsChannel_GetURI,
1315     nsChannel_GetOwner,
1316     nsChannel_SetOwner,
1317     nsChannel_GetNotificationCallbacks,
1318     nsChannel_SetNotificationCallbacks,
1319     nsChannel_GetSecurityInfo,
1320     nsChannel_GetContentType,
1321     nsChannel_SetContentType,
1322     nsChannel_GetContentCharset,
1323     nsChannel_SetContentCharset,
1324     nsChannel_GetContentLength,
1325     nsChannel_SetContentLength,
1326     nsChannel_Open,
1327     nsChannel_AsyncOpen,
1328     nsChannel_GetRequestMethod,
1329     nsChannel_SetRequestMethod,
1330     nsChannel_GetReferrer,
1331     nsChannel_SetReferrer,
1332     nsChannel_GetRequestHeader,
1333     nsChannel_SetRequestHeader,
1334     nsChannel_VisitRequestHeaders,
1335     nsChannel_GetAllowPipelining,
1336     nsChannel_SetAllowPipelining,
1337     nsChannel_GetRedirectionLimit,
1338     nsChannel_SetRedirectionLimit,
1339     nsChannel_GetResponseStatus,
1340     nsChannel_GetResponseStatusText,
1341     nsChannel_GetRequestSucceeded,
1342     nsChannel_GetResponseHeader,
1343     nsChannel_SetResponseHeader,
1344     nsChannel_VisitResponseHeaders,
1345     nsChannel_IsNoStoreResponse,
1346     nsChannel_IsNoCacheResponse
1347 };
1348
1349 static inline nsChannel *impl_from_nsIUploadChannel(nsIUploadChannel *iface)
1350 {
1351     return CONTAINING_RECORD(iface, nsChannel, nsIUploadChannel_iface);
1352 }
1353
1354 static nsresult NSAPI nsUploadChannel_QueryInterface(nsIUploadChannel *iface, nsIIDRef riid,
1355         void **result)
1356 {
1357     nsChannel *This = impl_from_nsIUploadChannel(iface);
1358     return nsIChannel_QueryInterface(&This->nsIHttpChannel_iface, riid, result);
1359 }
1360
1361 static nsrefcnt NSAPI nsUploadChannel_AddRef(nsIUploadChannel *iface)
1362 {
1363     nsChannel *This = impl_from_nsIUploadChannel(iface);
1364     return nsIChannel_AddRef(&This->nsIHttpChannel_iface);
1365 }
1366
1367 static nsrefcnt NSAPI nsUploadChannel_Release(nsIUploadChannel *iface)
1368 {
1369     nsChannel *This = impl_from_nsIUploadChannel(iface);
1370     return nsIChannel_Release(&This->nsIHttpChannel_iface);
1371 }
1372
1373 static nsresult NSAPI nsUploadChannel_SetUploadStream(nsIUploadChannel *iface,
1374         nsIInputStream *aStream, const nsACString *aContentType, PRInt32 aContentLength)
1375 {
1376     nsChannel *This = impl_from_nsIUploadChannel(iface);
1377     const char *content_type;
1378
1379     static const WCHAR content_typeW[] =
1380         {'C','o','n','t','e','n','t','-','T','y','p','e',0};
1381
1382     TRACE("(%p)->(%p %s %d)\n", This, aStream, debugstr_nsacstr(aContentType), aContentLength);
1383
1384     This->post_data_contains_headers = TRUE;
1385
1386     if(aContentType) {
1387         nsACString_GetData(aContentType, &content_type);
1388         if(*content_type) {
1389             WCHAR *ct;
1390
1391             ct = heap_strdupAtoW(content_type);
1392             if(!ct)
1393                 return NS_ERROR_UNEXPECTED;
1394
1395             set_http_header(&This->request_headers, content_typeW,
1396                     sizeof(content_typeW)/sizeof(WCHAR), ct, strlenW(ct));
1397             heap_free(ct);
1398             This->post_data_contains_headers = FALSE;
1399         }
1400     }
1401
1402     if(This->post_data_stream)
1403         nsIInputStream_Release(This->post_data_stream);
1404
1405     if(aContentLength != -1)
1406         FIXME("Unsupported acontentLength = %d\n", aContentLength);
1407
1408     if(This->post_data_stream)
1409         nsIInputStream_Release(This->post_data_stream);
1410     This->post_data_stream = aStream;
1411     if(aStream)
1412         nsIInputStream_AddRef(aStream);
1413
1414     This->request_method = METHOD_POST;
1415     return NS_OK;
1416 }
1417
1418 static nsresult NSAPI nsUploadChannel_GetUploadStream(nsIUploadChannel *iface,
1419         nsIInputStream **aUploadStream)
1420 {
1421     nsChannel *This = impl_from_nsIUploadChannel(iface);
1422
1423     TRACE("(%p)->(%p)\n", This, aUploadStream);
1424
1425     if(This->post_data_stream)
1426         nsIInputStream_AddRef(This->post_data_stream);
1427
1428     *aUploadStream = This->post_data_stream;
1429     return NS_OK;
1430 }
1431
1432 static const nsIUploadChannelVtbl nsUploadChannelVtbl = {
1433     nsUploadChannel_QueryInterface,
1434     nsUploadChannel_AddRef,
1435     nsUploadChannel_Release,
1436     nsUploadChannel_SetUploadStream,
1437     nsUploadChannel_GetUploadStream
1438 };
1439
1440 static inline nsChannel *impl_from_nsIHttpChannelInternal(nsIHttpChannelInternal *iface)
1441 {
1442     return CONTAINING_RECORD(iface, nsChannel, nsIHttpChannelInternal_iface);
1443 }
1444
1445 static nsresult NSAPI nsHttpChannelInternal_QueryInterface(nsIHttpChannelInternal *iface, nsIIDRef riid,
1446         void **result)
1447 {
1448     nsChannel *This = impl_from_nsIHttpChannelInternal(iface);
1449     return nsIChannel_QueryInterface(&This->nsIHttpChannel_iface, riid, result);
1450 }
1451
1452 static nsrefcnt NSAPI nsHttpChannelInternal_AddRef(nsIHttpChannelInternal *iface)
1453 {
1454     nsChannel *This = impl_from_nsIHttpChannelInternal(iface);
1455     return nsIChannel_AddRef(&This->nsIHttpChannel_iface);
1456 }
1457
1458 static nsrefcnt NSAPI nsHttpChannelInternal_Release(nsIHttpChannelInternal *iface)
1459 {
1460     nsChannel *This = impl_from_nsIHttpChannelInternal(iface);
1461     return nsIChannel_Release(&This->nsIHttpChannel_iface);
1462 }
1463
1464 static nsresult NSAPI nsHttpChannelInternal_GetDocumentURI(nsIHttpChannelInternal *iface, nsIURI **aDocumentURI)
1465 {
1466     nsChannel *This = impl_from_nsIHttpChannelInternal(iface);
1467
1468     FIXME("(%p)->()\n", This);
1469
1470     return NS_ERROR_NOT_IMPLEMENTED;
1471 }
1472
1473 static nsresult NSAPI nsHttpChannelInternal_SetDocumentURI(nsIHttpChannelInternal *iface, nsIURI *aDocumentURI)
1474 {
1475     nsChannel *This = impl_from_nsIHttpChannelInternal(iface);
1476
1477     FIXME("(%p)->()\n", This);
1478
1479     return NS_ERROR_NOT_IMPLEMENTED;
1480 }
1481
1482 static nsresult NSAPI nsHttpChannelInternal_GetRequestVersion(nsIHttpChannelInternal *iface, PRUint32 *major, PRUint32 *minor)
1483 {
1484     nsChannel *This = impl_from_nsIHttpChannelInternal(iface);
1485
1486     FIXME("(%p)->()\n", This);
1487
1488     return NS_ERROR_NOT_IMPLEMENTED;
1489 }
1490
1491 static nsresult NSAPI nsHttpChannelInternal_GetResponseVersion(nsIHttpChannelInternal *iface, PRUint32 *major, PRUint32 *minor)
1492 {
1493     nsChannel *This = impl_from_nsIHttpChannelInternal(iface);
1494
1495     FIXME("(%p)->()\n", This);
1496
1497     return NS_ERROR_NOT_IMPLEMENTED;
1498 }
1499
1500 static nsresult NSAPI nsHttpChannelInternal_SetCookie(nsIHttpChannelInternal *iface, const char *aCookieHeader)
1501 {
1502     nsChannel *This = impl_from_nsIHttpChannelInternal(iface);
1503
1504     FIXME("(%p)->()\n", This);
1505
1506     return NS_ERROR_NOT_IMPLEMENTED;
1507 }
1508
1509 static nsresult NSAPI nsHttpChannelInternal_SetupFallbackChannel(nsIHttpChannelInternal *iface, const char *aFallbackKey)
1510 {
1511     nsChannel *This = impl_from_nsIHttpChannelInternal(iface);
1512
1513     FIXME("(%p)->()\n", This);
1514
1515     return NS_ERROR_NOT_IMPLEMENTED;
1516 }
1517
1518 static nsresult NSAPI nsHttpChannelInternal_GetForceAllowThirdPartyCookie(nsIHttpChannelInternal *iface, PRBool *aForceThirdPartyCookie)
1519 {
1520     nsChannel *This = impl_from_nsIHttpChannelInternal(iface);
1521
1522     FIXME("(%p)->()\n", This);
1523
1524     return NS_ERROR_NOT_IMPLEMENTED;
1525 }
1526
1527 static nsresult NSAPI nsHttpChannelInternal_SetForceAllowThirdPartyCookie(nsIHttpChannelInternal *iface, PRBool aForceThirdPartyCookie)
1528 {
1529     nsChannel *This = impl_from_nsIHttpChannelInternal(iface);
1530
1531     FIXME("(%p)->()\n", This);
1532
1533     return NS_ERROR_NOT_IMPLEMENTED;
1534 }
1535
1536 static nsresult NSAPI nsHttpChannelInternal_GetCanceled(nsIHttpChannelInternal *iface, PRBool *aCanceled)
1537 {
1538     nsChannel *This = impl_from_nsIHttpChannelInternal(iface);
1539
1540     FIXME("(%p)->(%p)\n", This, aCanceled);
1541
1542     return NS_ERROR_NOT_IMPLEMENTED;
1543 }
1544
1545 static nsresult NSAPI nsHttpChannelInternal_GetChannelIsForDownload(nsIHttpChannelInternal *iface, PRBool *aCanceled)
1546 {
1547     nsChannel *This = impl_from_nsIHttpChannelInternal(iface);
1548
1549     FIXME("(%p)->(%p)\n", This, aCanceled);
1550
1551     return NS_ERROR_NOT_IMPLEMENTED;
1552 }
1553
1554 static nsresult NSAPI nsHttpChannelInternal_SetChannelIsForDownload(nsIHttpChannelInternal *iface, PRBool aCanceled)
1555 {
1556     nsChannel *This = impl_from_nsIHttpChannelInternal(iface);
1557
1558     FIXME("(%p)->(%x)\n", This, aCanceled);
1559
1560     return NS_ERROR_NOT_IMPLEMENTED;
1561 }
1562
1563 static nsresult NSAPI nsHttpChannelInternal_GetLocalAddress(nsIHttpChannelInternal *iface, nsACString *aLocalAddress)
1564 {
1565     nsChannel *This = impl_from_nsIHttpChannelInternal(iface);
1566
1567     FIXME("(%p)->(%p)\n", This, aLocalAddress);
1568
1569     return NS_ERROR_NOT_IMPLEMENTED;
1570 }
1571
1572 static nsresult NSAPI nsHttpChannelInternal_GetLocalPort(nsIHttpChannelInternal *iface, PRInt32 *aLocalPort)
1573 {
1574     nsChannel *This = impl_from_nsIHttpChannelInternal(iface);
1575
1576     FIXME("(%p)->(%p)\n", This, aLocalPort);
1577
1578     return NS_ERROR_NOT_IMPLEMENTED;
1579 }
1580
1581 static nsresult NSAPI nsHttpChannelInternal_GetRemoteAddress(nsIHttpChannelInternal *iface, nsACString *aRemoteAddress)
1582 {
1583     nsChannel *This = impl_from_nsIHttpChannelInternal(iface);
1584
1585     FIXME("(%p)->(%p)\n", This, aRemoteAddress);
1586
1587     return NS_ERROR_NOT_IMPLEMENTED;
1588 }
1589
1590 static nsresult NSAPI nsHttpChannelInternal_GetRemotePort(nsIHttpChannelInternal *iface, PRInt32 *aRemotePort)
1591 {
1592     nsChannel *This = impl_from_nsIHttpChannelInternal(iface);
1593
1594     FIXME("(%p)->(%p)\n", This, aRemotePort);
1595
1596     return NS_ERROR_NOT_IMPLEMENTED;
1597 }
1598
1599 static nsresult NSAPI nsHttpChannelInternal_SetCacheKeysRedirectChain(nsIHttpChannelInternal *iface, void *cacheKeys)
1600 {
1601     nsChannel *This = impl_from_nsIHttpChannelInternal(iface);
1602
1603     FIXME("(%p)->(%p)\n", This, cacheKeys);
1604
1605     return NS_ERROR_NOT_IMPLEMENTED;
1606 }
1607
1608 static const nsIHttpChannelInternalVtbl nsHttpChannelInternalVtbl = {
1609     nsHttpChannelInternal_QueryInterface,
1610     nsHttpChannelInternal_AddRef,
1611     nsHttpChannelInternal_Release,
1612     nsHttpChannelInternal_GetDocumentURI,
1613     nsHttpChannelInternal_SetDocumentURI,
1614     nsHttpChannelInternal_GetRequestVersion,
1615     nsHttpChannelInternal_GetResponseVersion,
1616     nsHttpChannelInternal_SetCookie,
1617     nsHttpChannelInternal_SetupFallbackChannel,
1618     nsHttpChannelInternal_GetForceAllowThirdPartyCookie,
1619     nsHttpChannelInternal_SetForceAllowThirdPartyCookie,
1620     nsHttpChannelInternal_GetCanceled,
1621     nsHttpChannelInternal_GetChannelIsForDownload,
1622     nsHttpChannelInternal_SetChannelIsForDownload,
1623     nsHttpChannelInternal_GetLocalAddress,
1624     nsHttpChannelInternal_GetLocalPort,
1625     nsHttpChannelInternal_GetRemoteAddress,
1626     nsHttpChannelInternal_GetRemotePort,
1627     nsHttpChannelInternal_SetCacheKeysRedirectChain
1628 };
1629
1630
1631 static void invalidate_uri(nsWineURI *This)
1632 {
1633     if(This->uri) {
1634         IUri_Release(This->uri);
1635         This->uri = NULL;
1636     }
1637 }
1638
1639 static BOOL ensure_uri_builder(nsWineURI *This)
1640 {
1641     if(!This->uri_builder) {
1642         HRESULT hres;
1643
1644         if(!ensure_uri(This))
1645             return FALSE;
1646
1647         hres = CreateIUriBuilder(This->uri, 0, 0, &This->uri_builder);
1648         if(FAILED(hres)) {
1649             WARN("CreateIUriBuilder failed: %08x\n", hres);
1650             return FALSE;
1651         }
1652     }
1653
1654     invalidate_uri(This);
1655     return TRUE;
1656 }
1657
1658 static nsresult get_uri_string(nsWineURI *This, Uri_PROPERTY prop, nsACString *ret)
1659 {
1660     char *vala;
1661     BSTR val;
1662     HRESULT hres;
1663
1664     if(!ensure_uri(This))
1665         return NS_ERROR_UNEXPECTED;
1666
1667     hres = IUri_GetPropertyBSTR(This->uri, prop, &val, 0);
1668     if(FAILED(hres)) {
1669         WARN("GetPropertyBSTR failed: %08x\n", hres);
1670         return NS_ERROR_UNEXPECTED;
1671     }
1672
1673     vala = heap_strdupWtoA(val);
1674     SysFreeString(val);
1675     if(!vala)
1676         return NS_ERROR_OUT_OF_MEMORY;
1677
1678     TRACE("ret %s\n", debugstr_a(vala));
1679     nsACString_SetData(ret, vala);
1680     heap_free(vala);
1681     return NS_OK;
1682 }
1683
1684 static inline nsWineURI *impl_from_nsIURL(nsIURL *iface)
1685 {
1686     return CONTAINING_RECORD(iface, nsWineURI, nsIURL_iface);
1687 }
1688
1689 static nsresult NSAPI nsURI_QueryInterface(nsIURL *iface, nsIIDRef riid, void **result)
1690 {
1691     nsWineURI *This = impl_from_nsIURL(iface);
1692
1693     *result = NULL;
1694
1695     if(IsEqualGUID(&IID_nsISupports, riid)) {
1696         TRACE("(%p)->(IID_nsISupports %p)\n", This, result);
1697         *result = &This->nsIURL_iface;
1698     }else if(IsEqualGUID(&IID_nsIURI, riid)) {
1699         TRACE("(%p)->(IID_nsIURI %p)\n", This, result);
1700         *result = &This->nsIURL_iface;
1701     }else if(IsEqualGUID(&IID_nsIURL, riid)) {
1702         TRACE("(%p)->(IID_nsIURL %p)\n", This, result);
1703         *result = &This->nsIURL_iface;
1704     }else if(IsEqualGUID(&IID_nsWineURI, riid)) {
1705         TRACE("(%p)->(IID_nsWineURI %p)\n", This, result);
1706         *result = This;
1707     }
1708
1709     if(*result) {
1710         nsIURI_AddRef(&This->nsIURL_iface);
1711         return NS_OK;
1712     }
1713
1714     TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), result);
1715     return This->nsuri ? nsIURI_QueryInterface(This->nsuri, riid, result) : NS_NOINTERFACE;
1716 }
1717
1718 static nsrefcnt NSAPI nsURI_AddRef(nsIURL *iface)
1719 {
1720     nsWineURI *This = impl_from_nsIURL(iface);
1721     LONG ref = InterlockedIncrement(&This->ref);
1722
1723     TRACE("(%p) ref=%d\n", This, ref);
1724
1725     return ref;
1726 }
1727
1728 static nsrefcnt NSAPI nsURI_Release(nsIURL *iface)
1729 {
1730     nsWineURI *This = impl_from_nsIURL(iface);
1731     LONG ref = InterlockedDecrement(&This->ref);
1732
1733     TRACE("(%p) ref=%d\n", This, ref);
1734
1735     if(!ref) {
1736         if(This->window_ref)
1737             windowref_release(This->window_ref);
1738         if(This->container)
1739             nsIWebBrowserChrome_Release(&This->container->nsIWebBrowserChrome_iface);
1740         if(This->nsurl)
1741             nsIURL_Release(This->nsurl);
1742         if(This->nsuri)
1743             nsIURI_Release(This->nsuri);
1744         if(This->uri)
1745             IUri_Release(This->uri);
1746         heap_free(This);
1747     }
1748
1749     return ref;
1750 }
1751
1752 static nsresult NSAPI nsURI_GetSpec(nsIURL *iface, nsACString *aSpec)
1753 {
1754     nsWineURI *This = impl_from_nsIURL(iface);
1755
1756     TRACE("(%p)->(%p)\n", This, aSpec);
1757
1758     return get_uri_string(This, Uri_PROPERTY_DISPLAY_URI, aSpec);
1759 }
1760
1761 static nsresult NSAPI nsURI_SetSpec(nsIURL *iface, const nsACString *aSpec)
1762 {
1763     nsWineURI *This = impl_from_nsIURL(iface);
1764     const char *speca;
1765     WCHAR *spec;
1766     IUri *uri;
1767     HRESULT hres;
1768
1769     TRACE("(%p)->(%s)\n", This, debugstr_nsacstr(aSpec));
1770
1771     nsACString_GetData(aSpec, &speca);
1772     spec = heap_strdupAtoW(speca);
1773     if(!spec)
1774         return NS_ERROR_OUT_OF_MEMORY;
1775
1776     hres = CreateUri(spec, 0, 0, &uri);
1777     heap_free(spec);
1778     if(FAILED(hres)) {
1779         WARN("CreateUri failed: %08x\n", hres);
1780         return NS_ERROR_FAILURE;
1781     }
1782
1783     invalidate_uri(This);
1784     if(This->uri_builder) {
1785         IUriBuilder_Release(This->uri_builder);
1786         This->uri_builder = NULL;
1787     }
1788
1789     This->uri = uri;
1790     return NS_OK;
1791 }
1792
1793 static nsresult NSAPI nsURI_GetPrePath(nsIURL *iface, nsACString *aPrePath)
1794 {
1795     nsWineURI *This = impl_from_nsIURL(iface);
1796
1797     TRACE("(%p)->(%p)\n", This, aPrePath);
1798
1799     if(This->nsuri)
1800         return nsIURI_GetPrePath(This->nsuri, aPrePath);
1801
1802     FIXME("default action not implemented\n");
1803     return NS_ERROR_NOT_IMPLEMENTED;
1804 }
1805
1806 static nsresult NSAPI nsURI_GetScheme(nsIURL *iface, nsACString *aScheme)
1807 {
1808     nsWineURI *This = impl_from_nsIURL(iface);
1809     DWORD scheme;
1810     HRESULT hres;
1811
1812     TRACE("(%p)->(%p)\n", This, aScheme);
1813
1814     if(!ensure_uri(This))
1815         return NS_ERROR_UNEXPECTED;
1816
1817     hres = IUri_GetScheme(This->uri, &scheme);
1818     if(FAILED(hres)) {
1819         WARN("GetScheme failed: %08x\n", hres);
1820         return NS_ERROR_UNEXPECTED;
1821     }
1822
1823     if(scheme == URL_SCHEME_ABOUT) {
1824         nsACString_SetData(aScheme, "wine");
1825         return NS_OK;
1826     }
1827
1828     return get_uri_string(This, Uri_PROPERTY_SCHEME_NAME, aScheme);
1829 }
1830
1831 static nsresult NSAPI nsURI_SetScheme(nsIURL *iface, const nsACString *aScheme)
1832 {
1833     nsWineURI *This = impl_from_nsIURL(iface);
1834     const char *schemea;
1835     WCHAR *scheme;
1836     HRESULT hres;
1837
1838     TRACE("(%p)->(%s)\n", This, debugstr_nsacstr(aScheme));
1839
1840     if(!ensure_uri_builder(This))
1841         return NS_ERROR_UNEXPECTED;
1842
1843     nsACString_GetData(aScheme, &schemea);
1844     scheme = heap_strdupAtoW(schemea);
1845     if(!scheme)
1846         return NS_ERROR_OUT_OF_MEMORY;
1847
1848     hres = IUriBuilder_SetSchemeName(This->uri_builder, scheme);
1849     heap_free(scheme);
1850     if(FAILED(hres))
1851         return NS_ERROR_UNEXPECTED;
1852
1853     return NS_OK;
1854 }
1855
1856 static nsresult NSAPI nsURI_GetUserPass(nsIURL *iface, nsACString *aUserPass)
1857 {
1858     nsWineURI *This = impl_from_nsIURL(iface);
1859     BSTR user, pass;
1860     HRESULT hres;
1861
1862     TRACE("(%p)->(%p)\n", This, aUserPass);
1863
1864     if(!ensure_uri(This))
1865         return NS_ERROR_UNEXPECTED;
1866
1867     hres = IUri_GetUserName(This->uri, &user);
1868     if(FAILED(hres))
1869         return NS_ERROR_FAILURE;
1870
1871     hres = IUri_GetPassword(This->uri, &pass);
1872     if(FAILED(hres)) {
1873         SysFreeString(user);
1874         return NS_ERROR_FAILURE;
1875     }
1876
1877     if(*user || *pass) {
1878         FIXME("Construct user:pass string\n");
1879     }else {
1880         nsACString_SetData(aUserPass, "");
1881     }
1882
1883     SysFreeString(user);
1884     SysFreeString(pass);
1885     return NS_OK;
1886 }
1887
1888 static nsresult NSAPI nsURI_SetUserPass(nsIURL *iface, const nsACString *aUserPass)
1889 {
1890     nsWineURI *This = impl_from_nsIURL(iface);
1891     WCHAR *user = NULL, *pass = NULL, *buf = NULL;
1892     const char *user_pass;
1893     HRESULT hres;
1894
1895     TRACE("(%p)->(%s)\n", This, debugstr_nsacstr(aUserPass));
1896
1897     if(!ensure_uri_builder(This))
1898         return NS_ERROR_UNEXPECTED;
1899
1900     nsACString_GetData(aUserPass, &user_pass);
1901     if(*user_pass) {
1902         WCHAR *ptr;
1903
1904         buf = heap_strdupAtoW(user_pass);
1905         if(!buf)
1906             return NS_ERROR_OUT_OF_MEMORY;
1907
1908         ptr = strchrW(buf, ':');
1909         if(!ptr) {
1910             user = buf;
1911         }else if(ptr != buf) {
1912             *ptr++ = 0;
1913             user = buf;
1914             if(*ptr)
1915                 pass = ptr;
1916         }else {
1917             pass = buf+1;
1918         }
1919     }
1920
1921     hres = IUriBuilder_SetUserName(This->uri_builder, user);
1922     if(SUCCEEDED(hres))
1923         hres = IUriBuilder_SetPassword(This->uri_builder, pass);
1924
1925     heap_free(buf);
1926     return SUCCEEDED(hres) ? NS_OK : NS_ERROR_FAILURE;
1927 }
1928
1929 static nsresult NSAPI nsURI_GetUsername(nsIURL *iface, nsACString *aUsername)
1930 {
1931     nsWineURI *This = impl_from_nsIURL(iface);
1932
1933     TRACE("(%p)->(%p)\n", This, aUsername);
1934
1935     return get_uri_string(This, Uri_PROPERTY_USER_NAME, aUsername);
1936 }
1937
1938 static nsresult NSAPI nsURI_SetUsername(nsIURL *iface, const nsACString *aUsername)
1939 {
1940     nsWineURI *This = impl_from_nsIURL(iface);
1941     const char *usera;
1942     WCHAR *user;
1943     HRESULT hres;
1944
1945     TRACE("(%p)->(%s)\n", This, debugstr_nsacstr(aUsername));
1946
1947     if(!ensure_uri_builder(This))
1948         return NS_ERROR_UNEXPECTED;
1949
1950     nsACString_GetData(aUsername, &usera);
1951     user = heap_strdupAtoW(usera);
1952     if(!user)
1953         return NS_ERROR_OUT_OF_MEMORY;
1954
1955     hres = IUriBuilder_SetUserName(This->uri_builder, user);
1956     heap_free(user);
1957     if(FAILED(hres))
1958         return NS_ERROR_UNEXPECTED;
1959
1960     return NS_OK;
1961 }
1962
1963 static nsresult NSAPI nsURI_GetPassword(nsIURL *iface, nsACString *aPassword)
1964 {
1965     nsWineURI *This = impl_from_nsIURL(iface);
1966
1967     TRACE("(%p)->(%p)\n", This, aPassword);
1968
1969     return get_uri_string(This, Uri_PROPERTY_PASSWORD, aPassword);
1970 }
1971
1972 static nsresult NSAPI nsURI_SetPassword(nsIURL *iface, const nsACString *aPassword)
1973 {
1974     nsWineURI *This = impl_from_nsIURL(iface);
1975     const char *passa;
1976     WCHAR *pass;
1977     HRESULT hres;
1978
1979     TRACE("(%p)->(%s)\n", This, debugstr_nsacstr(aPassword));
1980
1981     if(!ensure_uri_builder(This))
1982         return NS_ERROR_UNEXPECTED;
1983
1984     nsACString_GetData(aPassword, &passa);
1985     pass = heap_strdupAtoW(passa);
1986     if(!pass)
1987         return NS_ERROR_OUT_OF_MEMORY;
1988
1989     hres = IUriBuilder_SetPassword(This->uri_builder, pass);
1990     heap_free(pass);
1991     if(FAILED(hres))
1992         return NS_ERROR_UNEXPECTED;
1993
1994     return NS_OK;
1995 }
1996
1997 static nsresult NSAPI nsURI_GetHostPort(nsIURL *iface, nsACString *aHostPort)
1998 {
1999     nsWineURI *This = impl_from_nsIURL(iface);
2000     const WCHAR *ptr;
2001     char *vala;
2002     BSTR val;
2003     HRESULT hres;
2004
2005     TRACE("(%p)->(%p)\n", This, aHostPort);
2006
2007     if(!ensure_uri(This))
2008         return NS_ERROR_UNEXPECTED;
2009
2010     hres = IUri_GetAuthority(This->uri, &val);
2011     if(FAILED(hres)) {
2012         WARN("GetAuthority failed: %08x\n", hres);
2013         return NS_ERROR_UNEXPECTED;
2014     }
2015
2016     ptr = strchrW(val, '@');
2017     if(!ptr)
2018         ptr = val;
2019
2020     vala = heap_strdupWtoA(ptr);
2021     SysFreeString(val);
2022     if(!vala)
2023         return NS_ERROR_OUT_OF_MEMORY;
2024
2025     TRACE("ret %s\n", debugstr_a(vala));
2026     nsACString_SetData(aHostPort, vala);
2027     heap_free(vala);
2028     return NS_OK;
2029 }
2030
2031 static nsresult NSAPI nsURI_SetHostPort(nsIURL *iface, const nsACString *aHostPort)
2032 {
2033     nsWineURI *This = impl_from_nsIURL(iface);
2034
2035     WARN("(%p)->(%s)\n", This, debugstr_nsacstr(aHostPort));
2036
2037     /* Not implemented by Gecko */
2038     return NS_ERROR_NOT_IMPLEMENTED;
2039 }
2040
2041 static nsresult NSAPI nsURI_GetHost(nsIURL *iface, nsACString *aHost)
2042 {
2043     nsWineURI *This = impl_from_nsIURL(iface);
2044
2045     TRACE("(%p)->(%p)\n", This, aHost);
2046
2047     return get_uri_string(This, Uri_PROPERTY_HOST, aHost);
2048 }
2049
2050 static nsresult NSAPI nsURI_SetHost(nsIURL *iface, const nsACString *aHost)
2051 {
2052     nsWineURI *This = impl_from_nsIURL(iface);
2053     const char *hosta;
2054     WCHAR *host;
2055     HRESULT hres;
2056
2057     TRACE("(%p)->(%s)\n", This, debugstr_nsacstr(aHost));
2058
2059     if(!ensure_uri_builder(This))
2060         return NS_ERROR_UNEXPECTED;
2061
2062     nsACString_GetData(aHost, &hosta);
2063     host = heap_strdupAtoW(hosta);
2064     if(!host)
2065         return NS_ERROR_OUT_OF_MEMORY;
2066
2067     hres = IUriBuilder_SetHost(This->uri_builder, host);
2068     heap_free(host);
2069     if(FAILED(hres))
2070         return NS_ERROR_UNEXPECTED;
2071
2072     return NS_OK;
2073 }
2074
2075 static nsresult NSAPI nsURI_GetPort(nsIURL *iface, PRInt32 *aPort)
2076 {
2077     nsWineURI *This = impl_from_nsIURL(iface);
2078     DWORD port;
2079     HRESULT hres;
2080
2081     TRACE("(%p)->(%p)\n", This, aPort);
2082
2083     if(!ensure_uri(This))
2084         return NS_ERROR_UNEXPECTED;
2085
2086     hres = IUri_GetPort(This->uri, &port);
2087     if(FAILED(hres)) {
2088         WARN("GetPort failed: %08x\n", hres);
2089         return NS_ERROR_UNEXPECTED;
2090     }
2091
2092     *aPort = port ? port : -1;
2093     return NS_OK;
2094 }
2095
2096 static nsresult NSAPI nsURI_SetPort(nsIURL *iface, PRInt32 aPort)
2097 {
2098     nsWineURI *This = impl_from_nsIURL(iface);
2099     HRESULT hres;
2100
2101     TRACE("(%p)->(%d)\n", This, aPort);
2102
2103     if(!ensure_uri_builder(This))
2104         return NS_ERROR_UNEXPECTED;
2105
2106     hres = IUriBuilder_SetPort(This->uri_builder, aPort != -1, aPort);
2107     return SUCCEEDED(hres) ? NS_OK : NS_ERROR_FAILURE;
2108 }
2109
2110 static nsresult NSAPI nsURI_GetPath(nsIURL *iface, nsACString *aPath)
2111 {
2112     nsWineURI *This = impl_from_nsIURL(iface);
2113
2114     TRACE("(%p)->(%p)\n", This, aPath);
2115
2116     return get_uri_string(This, Uri_PROPERTY_PATH, aPath);
2117 }
2118
2119 static nsresult NSAPI nsURI_SetPath(nsIURL *iface, const nsACString *aPath)
2120 {
2121     nsWineURI *This = impl_from_nsIURL(iface);
2122     const char *patha;
2123     WCHAR *path;
2124     HRESULT hres;
2125
2126     TRACE("(%p)->(%s)\n", This, debugstr_nsacstr(aPath));
2127
2128     if(!ensure_uri_builder(This))
2129         return NS_ERROR_UNEXPECTED;
2130
2131     nsACString_GetData(aPath, &patha);
2132     path = heap_strdupAtoW(patha);
2133     if(!path)
2134         return NS_ERROR_OUT_OF_MEMORY;
2135
2136     hres = IUriBuilder_SetPath(This->uri_builder, path);
2137     heap_free(path);
2138     if(FAILED(hres))
2139         return NS_ERROR_UNEXPECTED;
2140
2141     return NS_OK;
2142 }
2143
2144 static nsresult NSAPI nsURL_GetRef(nsIURL *iface, nsACString *aRef)
2145 {
2146     nsWineURI *This = impl_from_nsIURL(iface);
2147     char *refa = NULL;
2148     BSTR ref;
2149     HRESULT hres;
2150
2151     TRACE("(%p)->(%p)\n", This, aRef);
2152
2153     if(!ensure_uri(This))
2154         return NS_ERROR_UNEXPECTED;
2155
2156     hres = IUri_GetFragment(This->uri, &ref);
2157     if(FAILED(hres))
2158         return NS_ERROR_UNEXPECTED;
2159
2160     refa = heap_strdupWtoA(ref);
2161     SysFreeString(ref);
2162     if(ref && !refa)
2163         return NS_ERROR_OUT_OF_MEMORY;
2164
2165     nsACString_SetData(aRef, refa && *refa == '#' ? refa+1 : refa);
2166     heap_free(refa);
2167     return NS_OK;
2168 }
2169
2170 static nsresult NSAPI nsURL_SetRef(nsIURL *iface, const nsACString *aRef)
2171 {
2172     nsWineURI *This = impl_from_nsIURL(iface);
2173     const char *refa;
2174     WCHAR *ref;
2175     HRESULT hres;
2176
2177     TRACE("(%p)->(%s)\n", This, debugstr_nsacstr(aRef));
2178
2179     if(!ensure_uri_builder(This))
2180         return NS_ERROR_UNEXPECTED;
2181
2182     nsACString_GetData(aRef, &refa);
2183     ref = heap_strdupAtoW(refa);
2184     if(!ref)
2185         return NS_ERROR_OUT_OF_MEMORY;
2186
2187     hres = IUriBuilder_SetFragment(This->uri_builder, ref);
2188     heap_free(ref);
2189     if(FAILED(hres))
2190         return NS_ERROR_UNEXPECTED;
2191
2192     return NS_OK;
2193 }
2194
2195 static nsresult NSAPI nsURI_Equals(nsIURL *iface, nsIURI *other, PRBool *_retval)
2196 {
2197     nsWineURI *This = impl_from_nsIURL(iface);
2198     nsWineURI *other_obj;
2199     nsresult nsres;
2200     HRESULT hres;
2201
2202     TRACE("(%p)->(%p %p)\n", This, other, _retval);
2203
2204     nsres = nsIURI_QueryInterface(other, &IID_nsWineURI, (void**)&other_obj);
2205     if(NS_FAILED(nsres)) {
2206         TRACE("Could not get nsWineURI interface\n");
2207         *_retval = FALSE;
2208         return NS_OK;
2209     }
2210
2211     if(ensure_uri(This) && ensure_uri(other_obj)) {
2212         hres = IUri_IsEqual(This->uri, other_obj->uri, _retval);
2213         nsres = SUCCEEDED(hres) ? NS_OK : NS_ERROR_FAILURE;
2214     }else {
2215         nsres = NS_ERROR_UNEXPECTED;
2216     }
2217
2218     nsIURI_Release(&other_obj->nsIURL_iface);
2219     return nsres;
2220 }
2221
2222 static nsresult NSAPI nsURI_SchemeIs(nsIURL *iface, const char *scheme, PRBool *_retval)
2223 {
2224     nsWineURI *This = impl_from_nsIURL(iface);
2225     WCHAR buf[INTERNET_MAX_SCHEME_LENGTH];
2226     BSTR scheme_name;
2227     HRESULT hres;
2228
2229     TRACE("(%p)->(%s %p)\n", This, debugstr_a(scheme), _retval);
2230
2231     if(!ensure_uri(This))
2232         return NS_ERROR_UNEXPECTED;
2233
2234     hres = IUri_GetSchemeName(This->uri, &scheme_name);
2235     if(FAILED(hres))
2236         return NS_ERROR_UNEXPECTED;
2237
2238     MultiByteToWideChar(CP_ACP, 0, scheme, -1, buf, sizeof(buf)/sizeof(WCHAR));
2239     *_retval = !strcmpW(scheme_name, buf);
2240     SysFreeString(scheme_name);
2241     return NS_OK;
2242 }
2243
2244 static nsresult NSAPI nsURI_Clone(nsIURL *iface, nsIURI **_retval)
2245 {
2246     nsWineURI *This = impl_from_nsIURL(iface);
2247     nsIURI *nsuri = NULL;
2248     nsWineURI *wine_uri;
2249     nsresult nsres;
2250
2251     TRACE("(%p)->(%p)\n", This, _retval);
2252
2253     if(!ensure_uri(This))
2254         return NS_ERROR_UNEXPECTED;
2255
2256     if(This->nsuri) {
2257         nsres = nsIURI_Clone(This->nsuri, &nsuri);
2258         if(NS_FAILED(nsres)) {
2259             WARN("Clone failed: %08x\n", nsres);
2260             return nsres;
2261         }
2262     }
2263
2264     nsres = create_nsuri(This->uri, nsuri, This->window_ref ? This->window_ref->window : NULL, This->container, &wine_uri);
2265     if(NS_FAILED(nsres)) {
2266         WARN("create_nsuri failed: %08x\n", nsres);
2267         return nsres;
2268     }
2269
2270     *_retval = (nsIURI*)&wine_uri->nsIURL_iface;
2271     return NS_OK;
2272 }
2273
2274 static nsresult NSAPI nsURI_Resolve(nsIURL *iface, const nsACString *aRelativePath,
2275         nsACString *_retval)
2276 {
2277     nsWineURI *This = impl_from_nsIURL(iface);
2278     const char *patha;
2279     IUri *new_uri;
2280     WCHAR *path;
2281     char *reta;
2282     BSTR ret;
2283     HRESULT hres;
2284
2285     TRACE("(%p)->(%s %p)\n", This, debugstr_nsacstr(aRelativePath), _retval);
2286
2287     if(!ensure_uri(This))
2288         return NS_ERROR_UNEXPECTED;
2289
2290     nsACString_GetData(aRelativePath, &patha);
2291     path = heap_strdupAtoW(patha);
2292     if(!path)
2293         return NS_ERROR_OUT_OF_MEMORY;
2294
2295     hres = CoInternetCombineUrlEx(This->uri, path, URL_ESCAPE_SPACES_ONLY|URL_DONT_ESCAPE_EXTRA_INFO, &new_uri, 0);
2296     heap_free(path);
2297     if(FAILED(hres)) {
2298         ERR("CoIntenetCombineUrlEx failed: %08x\n", hres);
2299         return NS_ERROR_FAILURE;
2300     }
2301
2302     hres = IUri_GetDisplayUri(new_uri, &ret);
2303     IUri_Release(new_uri);
2304     if(FAILED(hres))
2305         return NS_ERROR_FAILURE;
2306
2307     reta = heap_strdupWtoA(ret);
2308     SysFreeString(ret);
2309     if(!reta)
2310         return NS_ERROR_OUT_OF_MEMORY;
2311
2312     TRACE("returning %s\n", debugstr_a(reta));
2313     nsACString_SetData(_retval, reta);
2314     heap_free(reta);
2315     return NS_OK;
2316 }
2317
2318 static nsresult NSAPI nsURI_GetAsciiSpec(nsIURL *iface, nsACString *aAsciiSpec)
2319 {
2320     nsWineURI *This = impl_from_nsIURL(iface);
2321
2322     TRACE("(%p)->(%p)\n", This, aAsciiSpec);
2323
2324     return nsIURI_GetSpec(&This->nsIURL_iface, aAsciiSpec);
2325 }
2326
2327 static nsresult NSAPI nsURI_GetAsciiHost(nsIURL *iface, nsACString *aAsciiHost)
2328 {
2329     nsWineURI *This = impl_from_nsIURL(iface);
2330
2331     WARN("(%p)->(%p) FIXME: Use Uri_PUNYCODE_IDN_HOST flag\n", This, aAsciiHost);
2332
2333     return get_uri_string(This, Uri_PROPERTY_HOST, aAsciiHost);
2334 }
2335
2336 static nsresult NSAPI nsURI_GetOriginCharset(nsIURL *iface, nsACString *aOriginCharset)
2337 {
2338     nsWineURI *This = impl_from_nsIURL(iface);
2339
2340     TRACE("(%p)->(%p)\n", This, aOriginCharset);
2341
2342     if(This->nsuri)
2343         return nsIURI_GetOriginCharset(This->nsuri, aOriginCharset);
2344
2345     FIXME("default action not implemented\n");
2346     return NS_ERROR_NOT_IMPLEMENTED;
2347 }
2348
2349 static nsresult NSAPI nsURI_EqualsExceptRef(nsIURL *iface, nsIURI *other, PRBool *_retval)
2350 {
2351     nsWineURI *This = impl_from_nsIURL(iface);
2352     nsWineURI *other_obj;
2353     nsresult nsres;
2354
2355     TRACE("(%p)->(%p %p)\n", This, other, _retval);
2356
2357     nsres = nsIURI_QueryInterface(other, &IID_nsWineURI, (void**)&other_obj);
2358     if(NS_FAILED(nsres)) {
2359         TRACE("Could not get nsWineURI interface\n");
2360         *_retval = FALSE;
2361         return NS_OK;
2362     }
2363
2364     if(ensure_uri(This) && ensure_uri(other_obj)) {
2365         *_retval = compare_ignoring_frag(This->uri, other_obj->uri);
2366         nsres = NS_OK;
2367     }else {
2368         nsres = NS_ERROR_UNEXPECTED;
2369     }
2370
2371     nsIURI_Release(&other_obj->nsIURL_iface);
2372     return nsres;
2373 }
2374
2375 static nsresult NSAPI nsURI_CloneIgnoreRef(nsIURL *iface, nsIURI **_retval)
2376 {
2377     nsWineURI *This = impl_from_nsIURL(iface);
2378     nsWineURI *wine_uri;
2379     IUri *uri;
2380     nsresult nsres;
2381
2382     TRACE("(%p)->(%p)\n", This, _retval);
2383
2384     if(!ensure_uri(This))
2385         return NS_ERROR_UNEXPECTED;
2386
2387     uri = get_uri_nofrag(This->uri);
2388     if(!uri)
2389         return NS_ERROR_FAILURE;
2390
2391     nsres = create_nsuri(uri, NULL, This->window_ref ? This->window_ref->window : NULL, This->container, &wine_uri);
2392     IUri_Release(uri);
2393     if(NS_FAILED(nsres)) {
2394         WARN("create_nsuri failed: %08x\n", nsres);
2395         return nsres;
2396     }
2397
2398     *_retval = (nsIURI*)&wine_uri->nsIURL_iface;
2399     return NS_OK;
2400 }
2401
2402 static nsresult NSAPI nsURI_GetSpecIgnoringRef(nsIURL *iface, nsACString *aSpecIgnoringRef)
2403 {
2404     nsWineURI *This = impl_from_nsIURL(iface);
2405
2406     FIXME("(%p)->(%p)\n", This, aSpecIgnoringRef);
2407
2408     return nsIURL_GetSpec(&This->nsIURL_iface, aSpecIgnoringRef);
2409 }
2410
2411 static nsresult NSAPI nsURI_GetHasRef(nsIURL *iface, PRBool *aHasRef)
2412 {
2413     nsWineURI *This = impl_from_nsIURL(iface);
2414     BOOL b;
2415     HRESULT hres;
2416
2417     TRACE("(%p)->(%p)\n", This, aHasRef);
2418
2419     if(!ensure_uri(This))
2420         return NS_ERROR_UNEXPECTED;
2421
2422     hres = IUri_HasProperty(This->uri, Uri_PROPERTY_FRAGMENT, &b);
2423     if(FAILED(hres))
2424         return NS_ERROR_FAILURE;
2425
2426     *aHasRef = b;
2427     return NS_OK;
2428 }
2429
2430 static nsresult NSAPI nsURL_GetFilePath(nsIURL *iface, nsACString *aFilePath)
2431 {
2432     nsWineURI *This = impl_from_nsIURL(iface);
2433
2434     TRACE("(%p)->(%p)\n", This, aFilePath);
2435
2436     return nsIURL_GetPath(&This->nsIURL_iface, aFilePath);
2437 }
2438
2439 static nsresult NSAPI nsURL_SetFilePath(nsIURL *iface, const nsACString *aFilePath)
2440 {
2441     nsWineURI *This = impl_from_nsIURL(iface);
2442
2443     TRACE("(%p)->(%s)\n", This, debugstr_nsacstr(aFilePath));
2444
2445     return nsIURL_SetPath(&This->nsIURL_iface, aFilePath);
2446 }
2447
2448 static nsresult NSAPI nsURL_GetParam(nsIURL *iface, nsACString *aParam)
2449 {
2450     nsWineURI *This = impl_from_nsIURL(iface);
2451
2452     WARN("(%p)->(%p)\n", This, aParam);
2453
2454     /* This is a leftover of ';' special handling in URLs. It will be removed from Gecko soon */
2455     nsACString_SetData(aParam, "");
2456     return NS_OK;
2457 }
2458
2459 static nsresult NSAPI nsURL_SetParam(nsIURL *iface, const nsACString *aParam)
2460 {
2461     nsWineURI *This = impl_from_nsIURL(iface);
2462
2463     WARN("(%p)->(%s)\n", This, debugstr_nsacstr(aParam));
2464
2465     /* Not implemented by Gecko */
2466     return NS_ERROR_NOT_IMPLEMENTED;
2467 }
2468
2469 static nsresult NSAPI nsURL_GetQuery(nsIURL *iface, nsACString *aQuery)
2470 {
2471     nsWineURI *This = impl_from_nsIURL(iface);
2472
2473     TRACE("(%p)->(%p)\n", This, aQuery);
2474
2475     return get_uri_string(This, Uri_PROPERTY_QUERY, aQuery);
2476 }
2477
2478 static nsresult NSAPI nsURL_SetQuery(nsIURL *iface, const nsACString *aQuery)
2479 {
2480     nsWineURI *This = impl_from_nsIURL(iface);
2481     const char *querya;
2482     WCHAR *query;
2483     HRESULT hres;
2484
2485     TRACE("(%p)->(%s)\n", This, debugstr_nsacstr(aQuery));
2486
2487     if(!ensure_uri_builder(This))
2488         return NS_ERROR_UNEXPECTED;
2489
2490     nsACString_GetData(aQuery, &querya);
2491     query = heap_strdupAtoW(querya);
2492     if(!query)
2493         return NS_ERROR_OUT_OF_MEMORY;
2494
2495     hres = IUriBuilder_SetQuery(This->uri_builder, query);
2496     heap_free(query);
2497     if(FAILED(hres))
2498         return NS_ERROR_UNEXPECTED;
2499
2500     return NS_OK;
2501 }
2502
2503 static nsresult NSAPI nsURL_GetDirectory(nsIURL *iface, nsACString *aDirectory)
2504 {
2505     nsWineURI *This = impl_from_nsIURL(iface);
2506     char *dir = NULL;
2507     WCHAR *ptr;
2508     BSTR path;
2509     HRESULT hres;
2510
2511     TRACE("(%p)->(%p)\n", This, aDirectory);
2512
2513     if(!ensure_uri(This))
2514         return NS_ERROR_UNEXPECTED;
2515
2516     hres = IUri_GetPath(This->uri, &path);
2517     if(FAILED(hres))
2518         return NS_ERROR_FAILURE;
2519
2520     ptr = strrchrW(path, '/');
2521     if(ptr) {
2522         if(ptr[1])
2523             *ptr = 0;
2524         dir = heap_strdupWtoA(path);
2525         if(!dir) {
2526             SysFreeString(path);
2527             return NS_ERROR_OUT_OF_MEMORY;
2528         }
2529     }
2530
2531     SysFreeString(path);
2532     TRACE("ret %s\n", debugstr_a(dir));
2533     nsACString_SetData(aDirectory, dir ? dir : "");
2534     heap_free(dir);
2535     return NS_OK;
2536 }
2537
2538 static nsresult NSAPI nsURL_SetDirectory(nsIURL *iface, const nsACString *aDirectory)
2539 {
2540     nsWineURI *This = impl_from_nsIURL(iface);
2541
2542     WARN("(%p)->(%s)\n", This, debugstr_nsacstr(aDirectory));
2543
2544     /* Not implemented by Gecko */
2545     return NS_ERROR_NOT_IMPLEMENTED;
2546 }
2547
2548 static nsresult NSAPI nsURL_GetFileName(nsIURL *iface, nsACString *aFileName)
2549 {
2550     nsWineURI *This = impl_from_nsIURL(iface);
2551
2552     TRACE("(%p)->(%p)\n", This, aFileName);
2553
2554     if(This->nsurl)
2555         return nsIURL_GetFileName(This->nsurl, aFileName);
2556
2557     FIXME("default action not implemented\n");
2558     return NS_ERROR_NOT_IMPLEMENTED;
2559 }
2560
2561 static nsresult NSAPI nsURL_SetFileName(nsIURL *iface, const nsACString *aFileName)
2562 {
2563     nsWineURI *This = impl_from_nsIURL(iface);
2564
2565     TRACE("(%p)->(%s)\n", This, debugstr_nsacstr(aFileName));
2566
2567     if(This->nsurl) {
2568         invalidate_uri(This);
2569         return nsIURL_SetFileName(This->nsurl, aFileName);
2570     }
2571
2572     FIXME("default action not implemented\n");
2573     return NS_ERROR_NOT_IMPLEMENTED;
2574 }
2575
2576 static nsresult NSAPI nsURL_GetFileBaseName(nsIURL *iface, nsACString *aFileBaseName)
2577 {
2578     nsWineURI *This = impl_from_nsIURL(iface);
2579
2580     TRACE("(%p)->(%p)\n", This, aFileBaseName);
2581
2582     if(This->nsurl)
2583         return nsIURL_GetFileBaseName(This->nsurl, aFileBaseName);
2584
2585     FIXME("default action not implemented\n");
2586     return NS_ERROR_NOT_IMPLEMENTED;
2587 }
2588
2589 static nsresult NSAPI nsURL_SetFileBaseName(nsIURL *iface, const nsACString *aFileBaseName)
2590 {
2591     nsWineURI *This = impl_from_nsIURL(iface);
2592
2593     TRACE("(%p)->(%s)\n", This, debugstr_nsacstr(aFileBaseName));
2594
2595     if(This->nsurl) {
2596         invalidate_uri(This);
2597         return nsIURL_SetFileBaseName(This->nsurl, aFileBaseName);
2598     }
2599
2600     FIXME("default action not implemented\n");
2601     return NS_ERROR_NOT_IMPLEMENTED;
2602 }
2603
2604 static nsresult NSAPI nsURL_GetFileExtension(nsIURL *iface, nsACString *aFileExtension)
2605 {
2606     nsWineURI *This = impl_from_nsIURL(iface);
2607
2608     TRACE("(%p)->(%p)\n", This, aFileExtension);
2609
2610     return get_uri_string(This, Uri_PROPERTY_EXTENSION, aFileExtension);
2611 }
2612
2613 static nsresult NSAPI nsURL_SetFileExtension(nsIURL *iface, const nsACString *aFileExtension)
2614 {
2615     nsWineURI *This = impl_from_nsIURL(iface);
2616
2617     TRACE("(%p)->(%s)\n", This, debugstr_nsacstr(aFileExtension));
2618
2619     if(This->nsurl) {
2620         invalidate_uri(This);
2621         return nsIURL_SetFileExtension(This->nsurl, aFileExtension);
2622     }
2623
2624     FIXME("default action not implemented\n");
2625     return NS_ERROR_NOT_IMPLEMENTED;
2626 }
2627
2628 static nsresult NSAPI nsURL_GetCommonBaseSpec(nsIURL *iface, nsIURI *aURIToCompare, nsACString *_retval)
2629 {
2630     nsWineURI *This = impl_from_nsIURL(iface);
2631
2632     TRACE("(%p)->(%p %p)\n", This, aURIToCompare, _retval);
2633
2634     if(This->nsurl)
2635         return nsIURL_GetCommonBaseSpec(This->nsurl, aURIToCompare, _retval);
2636
2637     FIXME("default action not implemented\n");
2638     return NS_ERROR_NOT_IMPLEMENTED;
2639 }
2640
2641 static nsresult NSAPI nsURL_GetRelativeSpec(nsIURL *iface, nsIURI *aURIToCompare, nsACString *_retval)
2642 {
2643     nsWineURI *This = impl_from_nsIURL(iface);
2644
2645     TRACE("(%p)->(%p %p)\n", This, aURIToCompare, _retval);
2646
2647     if(This->nsurl)
2648         return nsIURL_GetRelativeSpec(This->nsurl, aURIToCompare, _retval);
2649
2650     FIXME("default action not implemented\n");
2651     return NS_ERROR_NOT_IMPLEMENTED;
2652 }
2653
2654 static const nsIURLVtbl nsURLVtbl = {
2655     nsURI_QueryInterface,
2656     nsURI_AddRef,
2657     nsURI_Release,
2658     nsURI_GetSpec,
2659     nsURI_SetSpec,
2660     nsURI_GetPrePath,
2661     nsURI_GetScheme,
2662     nsURI_SetScheme,
2663     nsURI_GetUserPass,
2664     nsURI_SetUserPass,
2665     nsURI_GetUsername,
2666     nsURI_SetUsername,
2667     nsURI_GetPassword,
2668     nsURI_SetPassword,
2669     nsURI_GetHostPort,
2670     nsURI_SetHostPort,
2671     nsURI_GetHost,
2672     nsURI_SetHost,
2673     nsURI_GetPort,
2674     nsURI_SetPort,
2675     nsURI_GetPath,
2676     nsURI_SetPath,
2677     nsURI_Equals,
2678     nsURI_SchemeIs,
2679     nsURI_Clone,
2680     nsURI_Resolve,
2681     nsURI_GetAsciiSpec,
2682     nsURI_GetAsciiHost,
2683     nsURI_GetOriginCharset,
2684     nsURL_GetRef,
2685     nsURL_SetRef,
2686     nsURI_EqualsExceptRef,
2687     nsURI_CloneIgnoreRef,
2688     nsURI_GetSpecIgnoringRef,
2689     nsURI_GetHasRef,
2690     nsURL_GetFilePath,
2691     nsURL_SetFilePath,
2692     nsURL_GetParam,
2693     nsURL_SetParam,
2694     nsURL_GetQuery,
2695     nsURL_SetQuery,
2696     nsURL_GetDirectory,
2697     nsURL_SetDirectory,
2698     nsURL_GetFileName,
2699     nsURL_SetFileName,
2700     nsURL_GetFileBaseName,
2701     nsURL_SetFileBaseName,
2702     nsURL_GetFileExtension,
2703     nsURL_SetFileExtension,
2704     nsURL_GetCommonBaseSpec,
2705     nsURL_GetRelativeSpec
2706 };
2707
2708 static nsresult create_nsuri(IUri *iuri, nsIURI *nsuri, HTMLWindow *window, NSContainer *container, nsWineURI **_retval)
2709 {
2710     nsWineURI *ret = heap_alloc_zero(sizeof(nsWineURI));
2711
2712     ret->nsIURL_iface.lpVtbl = &nsURLVtbl;
2713     ret->ref = 1;
2714     ret->nsuri = nsuri;
2715
2716     set_uri_nscontainer(ret, container);
2717     set_uri_window(ret, window);
2718
2719     IUri_AddRef(iuri);
2720     ret->uri = iuri;
2721
2722     if(nsuri)
2723         nsIURI_QueryInterface(nsuri, &IID_nsIURL, (void**)&ret->nsurl);
2724
2725     TRACE("retval=%p\n", ret);
2726     *_retval = ret;
2727     return NS_OK;
2728 }
2729
2730 HRESULT create_doc_uri(HTMLWindow *window, WCHAR *url, nsWineURI **ret)
2731 {
2732     nsWineURI *uri;
2733     IUri *iuri;
2734     nsresult nsres;
2735     HRESULT hres;
2736
2737     hres = CreateUri(url, 0, 0, &iuri);
2738     if(FAILED(hres))
2739         return hres;
2740
2741     nsres = create_nsuri(iuri, NULL, window, window->doc_obj->nscontainer, &uri);
2742     IUri_Release(iuri);
2743     if(NS_FAILED(nsres))
2744         return E_FAIL;
2745
2746     uri->is_doc_uri = TRUE;
2747
2748     *ret = uri;
2749     return S_OK;
2750 }
2751
2752 static nsresult create_nschannel(nsWineURI *uri, nsChannel **ret)
2753 {
2754     nsChannel *channel;
2755     HRESULT hres;
2756
2757     if(!ensure_uri(uri))
2758         return NS_ERROR_UNEXPECTED;
2759
2760     channel = heap_alloc_zero(sizeof(nsChannel));
2761     if(!channel)
2762         return NS_ERROR_OUT_OF_MEMORY;
2763
2764     channel->nsIHttpChannel_iface.lpVtbl = &nsChannelVtbl;
2765     channel->nsIUploadChannel_iface.lpVtbl = &nsUploadChannelVtbl;
2766     channel->nsIHttpChannelInternal_iface.lpVtbl = &nsHttpChannelInternalVtbl;
2767     channel->ref = 1;
2768     channel->request_method = METHOD_GET;
2769     list_init(&channel->response_headers);
2770     list_init(&channel->request_headers);
2771
2772     nsIURL_AddRef(&uri->nsIURL_iface);
2773     channel->uri = uri;
2774
2775     hres = IUri_GetScheme(uri->uri, &channel->url_scheme);
2776     if(FAILED(hres))
2777         channel->url_scheme = URL_SCHEME_UNKNOWN;
2778
2779     *ret = channel;
2780     return NS_OK;
2781 }
2782
2783 HRESULT create_redirect_nschannel(const WCHAR *url, nsChannel *orig_channel, nsChannel **ret)
2784 {
2785     HTMLWindow *window = NULL;
2786     nsChannel *channel;
2787     nsWineURI *uri;
2788     IUri *iuri;
2789     nsresult nsres;
2790     HRESULT hres;
2791
2792     hres = CreateUri(url, 0, 0, &iuri);
2793     if(FAILED(hres))
2794         return hres;
2795
2796     if(orig_channel->uri->window_ref)
2797         window = orig_channel->uri->window_ref->window;
2798     nsres = create_nsuri(iuri, NULL, window, NULL, &uri);
2799     IUri_Release(iuri);
2800     if(NS_FAILED(nsres))
2801         return E_FAIL;
2802
2803     nsres = create_nschannel(uri, &channel);
2804     nsIURL_Release(&uri->nsIURL_iface);
2805     if(NS_FAILED(nsres))
2806         return E_FAIL;
2807
2808     if(orig_channel->load_group) {
2809         nsILoadGroup_AddRef(orig_channel->load_group);
2810         channel->load_group = orig_channel->load_group;
2811     }
2812
2813     if(orig_channel->notif_callback) {
2814         nsIInterfaceRequestor_AddRef(orig_channel->notif_callback);
2815         channel->notif_callback = orig_channel->notif_callback;
2816     }
2817
2818     channel->load_flags = orig_channel->load_flags | LOAD_REPLACE;
2819
2820     if(orig_channel->request_method == METHOD_POST)
2821         FIXME("unsupported POST method\n");
2822
2823     if(orig_channel->original_uri) {
2824         nsIURI_AddRef(orig_channel->original_uri);
2825         channel->original_uri = orig_channel->original_uri;
2826     }
2827
2828     if(orig_channel->referrer) {
2829         nsIURI_AddRef(orig_channel->referrer);
2830         channel->referrer = orig_channel->referrer;
2831     }
2832
2833     *ret = channel;
2834     return S_OK;
2835 }
2836
2837 typedef struct {
2838     nsIProtocolHandler nsIProtocolHandler_iface;
2839
2840     LONG ref;
2841
2842     nsIProtocolHandler *nshandler;
2843 } nsProtocolHandler;
2844
2845 static inline nsProtocolHandler *impl_from_nsIProtocolHandler(nsIProtocolHandler *iface)
2846 {
2847     return CONTAINING_RECORD(iface, nsProtocolHandler, nsIProtocolHandler_iface);
2848 }
2849
2850 static nsresult NSAPI nsProtocolHandler_QueryInterface(nsIProtocolHandler *iface, nsIIDRef riid,
2851         void **result)
2852 {
2853     nsProtocolHandler *This = impl_from_nsIProtocolHandler(iface);
2854
2855     *result = NULL;
2856
2857     if(IsEqualGUID(&IID_nsISupports, riid)) {
2858         TRACE("(%p)->(IID_nsISupports %p)\n", This, result);
2859         *result = &This->nsIProtocolHandler_iface;
2860     }else if(IsEqualGUID(&IID_nsIProtocolHandler, riid)) {
2861         TRACE("(%p)->(IID_nsIProtocolHandler %p)\n", This, result);
2862         *result = &This->nsIProtocolHandler_iface;
2863     }else if(IsEqualGUID(&IID_nsIExternalProtocolHandler, riid)) {
2864         TRACE("(%p)->(IID_nsIExternalProtocolHandler %p), returning NULL\n", This, result);
2865         return NS_NOINTERFACE;
2866     }
2867
2868     if(*result) {
2869         nsISupports_AddRef((nsISupports*)*result);
2870         return NS_OK;
2871     }
2872
2873     WARN("(%s %p)\n", debugstr_guid(riid), result);
2874     return NS_NOINTERFACE;
2875 }
2876
2877 static nsrefcnt NSAPI nsProtocolHandler_AddRef(nsIProtocolHandler *iface)
2878 {
2879     nsProtocolHandler *This = impl_from_nsIProtocolHandler(iface);
2880     LONG ref = InterlockedIncrement(&This->ref);
2881
2882     TRACE("(%p) ref=%d\n", This, ref);
2883
2884     return ref;
2885 }
2886
2887 static nsrefcnt NSAPI nsProtocolHandler_Release(nsIProtocolHandler *iface)
2888 {
2889     nsProtocolHandler *This = impl_from_nsIProtocolHandler(iface);
2890     LONG ref = InterlockedDecrement(&This->ref);
2891
2892     TRACE("(%p) ref=%d\n", This, ref);
2893
2894     if(!ref) {
2895         if(This->nshandler)
2896             nsIProtocolHandler_Release(This->nshandler);
2897         heap_free(This);
2898     }
2899
2900     return ref;
2901 }
2902
2903 static nsresult NSAPI nsProtocolHandler_GetScheme(nsIProtocolHandler *iface, nsACString *aScheme)
2904 {
2905     nsProtocolHandler *This = impl_from_nsIProtocolHandler(iface);
2906
2907     TRACE("(%p)->(%p)\n", This, aScheme);
2908
2909     if(This->nshandler)
2910         return nsIProtocolHandler_GetScheme(This->nshandler, aScheme);
2911     return NS_ERROR_NOT_IMPLEMENTED;
2912 }
2913
2914 static nsresult NSAPI nsProtocolHandler_GetDefaultPort(nsIProtocolHandler *iface,
2915         PRInt32 *aDefaultPort)
2916 {
2917     nsProtocolHandler *This = impl_from_nsIProtocolHandler(iface);
2918
2919     TRACE("(%p)->(%p)\n", This, aDefaultPort);
2920
2921     if(This->nshandler)
2922         return nsIProtocolHandler_GetDefaultPort(This->nshandler, aDefaultPort);
2923     return NS_ERROR_NOT_IMPLEMENTED;
2924 }
2925
2926 static nsresult NSAPI nsProtocolHandler_GetProtocolFlags(nsIProtocolHandler *iface,
2927                                                          PRUint32 *aProtocolFlags)
2928 {
2929     nsProtocolHandler *This = impl_from_nsIProtocolHandler(iface);
2930
2931     TRACE("(%p)->(%p)\n", This, aProtocolFlags);
2932
2933     if(This->nshandler)
2934         return nsIProtocolHandler_GetProtocolFlags(This->nshandler, aProtocolFlags);
2935     return NS_ERROR_NOT_IMPLEMENTED;
2936 }
2937
2938 static nsresult NSAPI nsProtocolHandler_NewURI(nsIProtocolHandler *iface,
2939         const nsACString *aSpec, const char *aOriginCharset, nsIURI *aBaseURI, nsIURI **_retval)
2940 {
2941     nsProtocolHandler *This = impl_from_nsIProtocolHandler(iface);
2942
2943     TRACE("((%p)->%s %s %p %p)\n", This, debugstr_nsacstr(aSpec), debugstr_a(aOriginCharset),
2944           aBaseURI, _retval);
2945
2946     if(This->nshandler)
2947         return nsIProtocolHandler_NewURI(This->nshandler, aSpec, aOriginCharset, aBaseURI, _retval);
2948     return NS_ERROR_NOT_IMPLEMENTED;
2949 }
2950
2951 static nsresult NSAPI nsProtocolHandler_NewChannel(nsIProtocolHandler *iface,
2952         nsIURI *aURI, nsIChannel **_retval)
2953 {
2954     nsProtocolHandler *This = impl_from_nsIProtocolHandler(iface);
2955
2956     TRACE("(%p)->(%p %p)\n", This, aURI, _retval);
2957
2958     if(This->nshandler)
2959         return nsIProtocolHandler_NewChannel(This->nshandler, aURI, _retval);
2960     return NS_ERROR_NOT_IMPLEMENTED;
2961 }
2962
2963 static nsresult NSAPI nsProtocolHandler_AllowPort(nsIProtocolHandler *iface,
2964         PRInt32 port, const char *scheme, PRBool *_retval)
2965 {
2966     nsProtocolHandler *This = impl_from_nsIProtocolHandler(iface);
2967
2968     TRACE("(%p)->(%d %s %p)\n", This, port, debugstr_a(scheme), _retval);
2969
2970     if(This->nshandler)
2971         return nsIProtocolHandler_AllowPort(This->nshandler, port, scheme, _retval);
2972     return NS_ERROR_NOT_IMPLEMENTED;
2973 }
2974
2975 static const nsIProtocolHandlerVtbl nsProtocolHandlerVtbl = {
2976     nsProtocolHandler_QueryInterface,
2977     nsProtocolHandler_AddRef,
2978     nsProtocolHandler_Release,
2979     nsProtocolHandler_GetScheme,
2980     nsProtocolHandler_GetDefaultPort,
2981     nsProtocolHandler_GetProtocolFlags,
2982     nsProtocolHandler_NewURI,
2983     nsProtocolHandler_NewChannel,
2984     nsProtocolHandler_AllowPort
2985 };
2986
2987 static nsIProtocolHandler *create_protocol_handler(nsIProtocolHandler *nshandler)
2988 {
2989     nsProtocolHandler *ret = heap_alloc(sizeof(nsProtocolHandler));
2990
2991     ret->nsIProtocolHandler_iface.lpVtbl = &nsProtocolHandlerVtbl;
2992     ret->ref = 1;
2993     ret->nshandler = nshandler;
2994
2995     return &ret->nsIProtocolHandler_iface;
2996 }
2997
2998 static nsresult NSAPI nsIOService_QueryInterface(nsIIOService*,nsIIDRef,void**);
2999
3000 static nsrefcnt NSAPI nsIOService_AddRef(nsIIOService *iface)
3001 {
3002     return 2;
3003 }
3004
3005 static nsrefcnt NSAPI nsIOService_Release(nsIIOService *iface)
3006 {
3007     return 1;
3008 }
3009
3010 static nsresult NSAPI nsIOService_GetProtocolHandler(nsIIOService *iface, const char *aScheme,
3011                                                      nsIProtocolHandler **_retval)
3012 {
3013     nsIExternalProtocolHandler *nsexthandler;
3014     nsIProtocolHandler *nshandler;
3015     nsresult nsres;
3016
3017     TRACE("(%s %p)\n", debugstr_a(aScheme), _retval);
3018
3019     nsres = nsIIOService_GetProtocolHandler(nsio, aScheme, &nshandler);
3020     if(NS_FAILED(nsres)) {
3021         WARN("GetProtocolHandler failed: %08x\n", nsres);
3022         return nsres;
3023     }
3024
3025     nsres = nsIProtocolHandler_QueryInterface(nshandler, &IID_nsIExternalProtocolHandler,
3026                                               (void**)&nsexthandler);
3027     if(NS_FAILED(nsres)) {
3028         *_retval = nshandler;
3029         return NS_OK;
3030     }
3031
3032     nsIExternalProtocolHandler_Release(nsexthandler);
3033     *_retval = create_protocol_handler(nshandler);
3034     TRACE("return %p\n", *_retval);
3035     return NS_OK;
3036 }
3037
3038 static nsresult NSAPI nsIOService_GetProtocolFlags(nsIIOService *iface, const char *aScheme,
3039                                                     PRUint32 *_retval)
3040 {
3041     TRACE("(%s %p)\n", debugstr_a(aScheme), _retval);
3042     return nsIIOService_GetProtocolFlags(nsio, aScheme, _retval);
3043 }
3044
3045 static BOOL is_gecko_special_uri(const char *spec)
3046 {
3047     static const char *special_schemes[] = {"chrome:", "jar:", "moz-safe-about", "resource:", "javascript:", "wyciwyg:"};
3048     int i;
3049
3050     for(i=0; i < sizeof(special_schemes)/sizeof(*special_schemes); i++) {
3051         if(!strncasecmp(spec, special_schemes[i], strlen(special_schemes[i])))
3052             return TRUE;
3053     }
3054
3055     if(!strncasecmp(spec, "file:", 5)) {
3056         const char *ptr = spec+5;
3057         while(*ptr == '/')
3058             ptr++;
3059         return is_gecko_path(ptr);
3060     }
3061
3062     return FALSE;
3063 }
3064
3065 static nsresult NSAPI nsIOService_NewURI(nsIIOService *iface, const nsACString *aSpec,
3066         const char *aOriginCharset, nsIURI *aBaseURI, nsIURI **_retval)
3067 {
3068     nsWineURI *wine_uri, *base_wine_uri = NULL;
3069     WCHAR new_spec[INTERNET_MAX_URL_LENGTH];
3070     HTMLWindow *window = NULL;
3071     const char *spec = NULL;
3072     nsIURI *uri = NULL;
3073     IUri *urlmon_uri;
3074     nsresult nsres;
3075     HRESULT hres;
3076
3077     TRACE("(%s %s %p %p)\n", debugstr_nsacstr(aSpec), debugstr_a(aOriginCharset),
3078           aBaseURI, _retval);
3079
3080     nsACString_GetData(aSpec, &spec);
3081     if(is_gecko_special_uri(spec))
3082         return nsIIOService_NewURI(nsio, aSpec, aOriginCharset, aBaseURI, _retval);
3083
3084     if(!strncmp(spec, "wine:", 5))
3085         spec += 5;
3086
3087     if(aBaseURI) {
3088         nsres = nsIURI_QueryInterface(aBaseURI, &IID_nsWineURI, (void**)&base_wine_uri);
3089         if(NS_SUCCEEDED(nsres)) {
3090             if(!ensure_uri(base_wine_uri))
3091                 return NS_ERROR_UNEXPECTED;
3092             if(base_wine_uri->window_ref)
3093                 window = base_wine_uri->window_ref->window;
3094         }else {
3095             WARN("Could not get base nsWineURI: %08x\n", nsres);
3096         }
3097     }
3098
3099     MultiByteToWideChar(CP_ACP, 0, spec, -1, new_spec, sizeof(new_spec)/sizeof(WCHAR));
3100
3101     if(base_wine_uri) {
3102         hres = CoInternetCombineUrlEx(base_wine_uri->uri, new_spec, URL_ESCAPE_SPACES_ONLY|URL_DONT_ESCAPE_EXTRA_INFO,
3103                 &urlmon_uri, 0);
3104         if(FAILED(hres))
3105             WARN("CoInternetCombineUrlEx failed: %08x\n", hres);
3106     }else {
3107         hres = CreateUri(new_spec, 0, 0, &urlmon_uri);
3108         if(FAILED(hres))
3109             WARN("CreateUri failed: %08x\n", hres);
3110     }
3111
3112     nsres = nsIIOService_NewURI(nsio, aSpec, aOriginCharset, aBaseURI, &uri);
3113     if(NS_FAILED(nsres))
3114         TRACE("NewURI failed: %08x\n", nsres);
3115
3116     if(FAILED(hres)) {
3117         *_retval = uri;
3118         return nsres;
3119     }
3120
3121     nsres = create_nsuri(urlmon_uri, uri, window, NULL, &wine_uri);
3122     IUri_Release(urlmon_uri);
3123     if(base_wine_uri)
3124         nsIURI_Release(&base_wine_uri->nsIURL_iface);
3125     if(NS_FAILED(nsres))
3126         return nsres;
3127
3128     *_retval = (nsIURI*)&wine_uri->nsIURL_iface;
3129     return nsres;
3130 }
3131
3132 static nsresult NSAPI nsIOService_NewFileURI(nsIIOService *iface, nsIFile *aFile,
3133                                              nsIURI **_retval)
3134 {
3135     TRACE("(%p %p)\n", aFile, _retval);
3136     return nsIIOService_NewFileURI(nsio, aFile, _retval);
3137 }
3138
3139 static nsresult NSAPI nsIOService_NewChannelFromURI(nsIIOService *iface, nsIURI *aURI,
3140                                                      nsIChannel **_retval)
3141 {
3142     nsWineURI *wine_uri;
3143     nsChannel *ret;
3144     nsresult nsres;
3145
3146     TRACE("(%p %p)\n", aURI, _retval);
3147
3148     nsres = nsIURI_QueryInterface(aURI, &IID_nsWineURI, (void**)&wine_uri);
3149     if(NS_FAILED(nsres)) {
3150         TRACE("Could not get nsWineURI: %08x\n", nsres);
3151         return nsIIOService_NewChannelFromURI(nsio, aURI, _retval);
3152     }
3153
3154     nsres = create_nschannel(wine_uri, &ret);
3155     nsIURL_Release(&wine_uri->nsIURL_iface);
3156     if(NS_FAILED(nsres))
3157         return nsres;
3158
3159     nsIURI_AddRef(aURI);
3160     ret->original_uri = aURI;
3161
3162     *_retval = (nsIChannel*)&ret->nsIHttpChannel_iface;
3163     return NS_OK;
3164 }
3165
3166 static nsresult NSAPI nsIOService_NewChannel(nsIIOService *iface, const nsACString *aSpec,
3167         const char *aOriginCharset, nsIURI *aBaseURI, nsIChannel **_retval)
3168 {
3169     TRACE("(%s %s %p %p)\n", debugstr_nsacstr(aSpec), debugstr_a(aOriginCharset), aBaseURI, _retval);
3170     return nsIIOService_NewChannel(nsio, aSpec, aOriginCharset, aBaseURI, _retval);
3171 }
3172
3173 static nsresult NSAPI nsIOService_GetOffline(nsIIOService *iface, PRBool *aOffline)
3174 {
3175     TRACE("(%p)\n", aOffline);
3176     return nsIIOService_GetOffline(nsio, aOffline);
3177 }
3178
3179 static nsresult NSAPI nsIOService_SetOffline(nsIIOService *iface, PRBool aOffline)
3180 {
3181     TRACE("(%x)\n", aOffline);
3182     return nsIIOService_SetOffline(nsio, aOffline);
3183 }
3184
3185 static nsresult NSAPI nsIOService_AllowPort(nsIIOService *iface, PRInt32 aPort,
3186                                              const char *aScheme, PRBool *_retval)
3187 {
3188     TRACE("(%d %s %p)\n", aPort, debugstr_a(aScheme), _retval);
3189     return nsIIOService_AllowPort(nsio, aPort, debugstr_a(aScheme), _retval);
3190 }
3191
3192 static nsresult NSAPI nsIOService_ExtractScheme(nsIIOService *iface, const nsACString *urlString,
3193                                                  nsACString * _retval)
3194 {
3195     TRACE("(%s %p)\n", debugstr_nsacstr(urlString), _retval);
3196     return nsIIOService_ExtractScheme(nsio, urlString, _retval);
3197 }
3198
3199 static const nsIIOServiceVtbl nsIOServiceVtbl = {
3200     nsIOService_QueryInterface,
3201     nsIOService_AddRef,
3202     nsIOService_Release,
3203     nsIOService_GetProtocolHandler,
3204     nsIOService_GetProtocolFlags,
3205     nsIOService_NewURI,
3206     nsIOService_NewFileURI,
3207     nsIOService_NewChannelFromURI,
3208     nsIOService_NewChannel,
3209     nsIOService_GetOffline,
3210     nsIOService_SetOffline,
3211     nsIOService_AllowPort,
3212     nsIOService_ExtractScheme
3213 };
3214
3215 static nsIIOService nsIOService = { &nsIOServiceVtbl };
3216
3217 static nsresult NSAPI nsNetUtil_QueryInterface(nsINetUtil *iface, nsIIDRef riid,
3218         void **result)
3219 {
3220     return nsIIOService_QueryInterface(&nsIOService, riid, result);
3221 }
3222
3223 static nsrefcnt NSAPI nsNetUtil_AddRef(nsINetUtil *iface)
3224 {
3225     return 2;
3226 }
3227
3228 static nsrefcnt NSAPI nsNetUtil_Release(nsINetUtil *iface)
3229 {
3230     return 1;
3231 }
3232
3233 static nsresult NSAPI nsNetUtil_ParseContentType(nsINetUtil *iface, const nsACString *aTypeHeader,
3234         nsACString *aCharset, PRBool *aHadCharset, nsACString *aContentType)
3235 {
3236     TRACE("(%s %p %p %p)\n", debugstr_nsacstr(aTypeHeader), aCharset, aHadCharset, aContentType);
3237
3238     return nsINetUtil_ParseContentType(net_util, aTypeHeader, aCharset, aHadCharset, aContentType);
3239 }
3240
3241 static nsresult NSAPI nsNetUtil_ProtocolHasFlags(nsINetUtil *iface, nsIURI *aURI, PRUint32 aFlags, PRBool *_retval)
3242 {
3243     TRACE("()\n");
3244
3245     return nsINetUtil_ProtocolHasFlags(net_util, aURI, aFlags, _retval);
3246 }
3247
3248 static nsresult NSAPI nsNetUtil_URIChainHasFlags(nsINetUtil *iface, nsIURI *aURI, PRUint32 aFlags, PRBool *_retval)
3249 {
3250     TRACE("(%p %08x %p)\n", aURI, aFlags, _retval);
3251
3252     if(aFlags == (1<<11)) {
3253         *_retval = FALSE;
3254         return NS_OK;
3255     }
3256
3257     return nsINetUtil_URIChainHasFlags(net_util, aURI, aFlags, _retval);
3258 }
3259
3260 static nsresult NSAPI nsNetUtil_ToImmutableURI(nsINetUtil *iface, nsIURI *aURI, nsIURI **_retval)
3261 {
3262     TRACE("(%p %p)\n", aURI, _retval);
3263
3264     return nsINetUtil_ToImmutableURI(net_util, aURI, _retval);
3265 }
3266
3267 static nsresult NSAPI nsNetUtil_NewSimpleNestedURI(nsINetUtil *iface, nsIURI *aURI, nsIURI **_retval)
3268 {
3269     TRACE("(%p %p)\n", aURI, _retval);
3270
3271     return nsINetUtil_NewSimpleNestedURI(net_util, aURI, _retval);
3272 }
3273
3274 static nsresult NSAPI nsNetUtil_EscapeString(nsINetUtil *iface, const nsACString *aString,
3275                                              PRUint32 aEscapeType, nsACString *_retval)
3276 {
3277     TRACE("(%s %x %p)\n", debugstr_nsacstr(aString), aEscapeType, _retval);
3278
3279     return nsINetUtil_EscapeString(net_util, aString, aEscapeType, _retval);
3280 }
3281
3282 static nsresult NSAPI nsNetUtil_EscapeURL(nsINetUtil *iface, const nsACString *aStr, PRUint32 aFlags,
3283                                           nsACString *_retval)
3284 {
3285     TRACE("(%s %08x %p)\n", debugstr_nsacstr(aStr), aFlags, _retval);
3286
3287     return nsINetUtil_EscapeURL(net_util, aStr, aFlags, _retval);
3288 }
3289
3290 static nsresult NSAPI nsNetUtil_UnescapeString(nsINetUtil *iface, const nsACString *aStr,
3291                                                PRUint32 aFlags, nsACString *_retval)
3292 {
3293     TRACE("(%s %08x %p)\n", debugstr_nsacstr(aStr), aFlags, _retval);
3294
3295     return nsINetUtil_UnescapeString(net_util, aStr, aFlags, _retval);
3296 }
3297
3298 static nsresult NSAPI nsNetUtil_ExtractCharsetFromContentType(nsINetUtil *iface, const nsACString *aTypeHeader,
3299         nsACString *aCharset, PRInt32 *aCharsetStart, PRInt32 *aCharsetEnd, PRBool *_retval)
3300 {
3301     TRACE("(%s %p %p %p %p)\n", debugstr_nsacstr(aTypeHeader), aCharset, aCharsetStart,
3302           aCharsetEnd, _retval);
3303
3304     return nsINetUtil_ExtractCharsetFromContentType(net_util, aTypeHeader, aCharset, aCharsetStart, aCharsetEnd, _retval);
3305 }
3306
3307 static const nsINetUtilVtbl nsNetUtilVtbl = {
3308     nsNetUtil_QueryInterface,
3309     nsNetUtil_AddRef,
3310     nsNetUtil_Release,
3311     nsNetUtil_ParseContentType,
3312     nsNetUtil_ProtocolHasFlags,
3313     nsNetUtil_URIChainHasFlags,
3314     nsNetUtil_ToImmutableURI,
3315     nsNetUtil_NewSimpleNestedURI,
3316     nsNetUtil_EscapeString,
3317     nsNetUtil_EscapeURL,
3318     nsNetUtil_UnescapeString,
3319     nsNetUtil_ExtractCharsetFromContentType
3320 };
3321
3322 static nsINetUtil nsNetUtil = { &nsNetUtilVtbl };
3323
3324 static nsresult NSAPI nsIOService_QueryInterface(nsIIOService *iface, nsIIDRef riid,
3325         void **result)
3326 {
3327     *result = NULL;
3328
3329     if(IsEqualGUID(&IID_nsISupports, riid))
3330         *result = &nsIOService;
3331     else if(IsEqualGUID(&IID_nsIIOService, riid))
3332         *result = &nsIOService;
3333     else if(IsEqualGUID(&IID_nsINetUtil, riid))
3334         *result = &nsNetUtil;
3335
3336     if(*result) {
3337         nsISupports_AddRef((nsISupports*)*result);
3338         return NS_OK;
3339     }
3340
3341     FIXME("(%s %p)\n", debugstr_guid(riid), result);
3342     return NS_NOINTERFACE;
3343 }
3344
3345 static nsresult NSAPI nsIOServiceFactory_QueryInterface(nsIFactory *iface, nsIIDRef riid,
3346         void **result)
3347 {
3348     *result = NULL;
3349
3350     if(IsEqualGUID(&IID_nsISupports, riid)) {
3351         TRACE("(IID_nsISupports %p)\n", result);
3352         *result = iface;
3353     }else if(IsEqualGUID(&IID_nsIFactory, riid)) {
3354         TRACE("(IID_nsIFactory %p)\n", result);
3355         *result = iface;
3356     }
3357
3358     if(*result) {
3359         nsIFactory_AddRef(iface);
3360         return NS_OK;
3361     }
3362
3363     WARN("(%s %p)\n", debugstr_guid(riid), result);
3364     return NS_NOINTERFACE;
3365 }
3366
3367 static nsrefcnt NSAPI nsIOServiceFactory_AddRef(nsIFactory *iface)
3368 {
3369     return 2;
3370 }
3371
3372 static nsrefcnt NSAPI nsIOServiceFactory_Release(nsIFactory *iface)
3373 {
3374     return 1;
3375 }
3376
3377 static nsresult NSAPI nsIOServiceFactory_CreateInstance(nsIFactory *iface,
3378         nsISupports *aOuter, const nsIID *iid, void **result)
3379 {
3380     return nsIIOService_QueryInterface(&nsIOService, iid, result);
3381 }
3382
3383 static nsresult NSAPI nsIOServiceFactory_LockFactory(nsIFactory *iface, PRBool lock)
3384 {
3385     WARN("(%x)\n", lock);
3386     return NS_OK;
3387 }
3388
3389 static const nsIFactoryVtbl nsIOServiceFactoryVtbl = {
3390     nsIOServiceFactory_QueryInterface,
3391     nsIOServiceFactory_AddRef,
3392     nsIOServiceFactory_Release,
3393     nsIOServiceFactory_CreateInstance,
3394     nsIOServiceFactory_LockFactory
3395 };
3396
3397 static nsIFactory nsIOServiceFactory = { &nsIOServiceFactoryVtbl };
3398
3399 static BOOL translate_url(HTMLDocumentObj *doc, nsWineURI *uri)
3400 {
3401     OLECHAR *new_url = NULL;
3402     WCHAR *url;
3403     BOOL ret = FALSE;
3404     HRESULT hres;
3405
3406     if(!doc->hostui || !ensure_uri(uri))
3407         return FALSE;
3408
3409     hres = IUri_GetDisplayUri(uri->uri, &url);
3410     if(FAILED(hres))
3411         return FALSE;
3412
3413     hres = IDocHostUIHandler_TranslateUrl(doc->hostui, 0, url, &new_url);
3414     if(hres == S_OK && new_url) {
3415         if(strcmpW(url, new_url)) {
3416             FIXME("TranslateUrl returned new URL %s -> %s\n", debugstr_w(url), debugstr_w(new_url));
3417             ret = TRUE;
3418         }
3419         CoTaskMemFree(new_url);
3420     }
3421
3422     SysFreeString(url);
3423     return ret;
3424 }
3425
3426 nsresult on_start_uri_open(NSContainer *nscontainer, nsIURI *uri, PRBool *_retval)
3427 {
3428     nsWineURI *wine_uri;
3429     nsresult nsres;
3430
3431     *_retval = FALSE;
3432
3433     nsres = nsIURI_QueryInterface(uri, &IID_nsWineURI, (void**)&wine_uri);
3434     if(NS_FAILED(nsres)) {
3435         WARN("Could not get nsWineURI: %08x\n", nsres);
3436         return NS_ERROR_NOT_IMPLEMENTED;
3437     }
3438
3439     if(!wine_uri->is_doc_uri) {
3440         wine_uri->is_doc_uri = TRUE;
3441
3442         if(!wine_uri->container) {
3443             nsIWebBrowserChrome_AddRef(&nscontainer->nsIWebBrowserChrome_iface);
3444             wine_uri->container = nscontainer;
3445         }
3446
3447         if(nscontainer->doc)
3448             *_retval = translate_url(nscontainer->doc, wine_uri);
3449     }
3450
3451     nsIURI_Release(&wine_uri->nsIURL_iface);
3452     return NS_OK;
3453 }
3454
3455 void init_nsio(nsIComponentManager *component_manager, nsIComponentRegistrar *registrar)
3456 {
3457     nsIFactory *old_factory = NULL;
3458     nsresult nsres;
3459
3460     nsres = nsIComponentManager_GetClassObject(component_manager, &NS_IOSERVICE_CID,
3461                                                &IID_nsIFactory, (void**)&old_factory);
3462     if(NS_FAILED(nsres)) {
3463         ERR("Could not get factory: %08x\n", nsres);
3464         return;
3465     }
3466
3467     nsres = nsIFactory_CreateInstance(old_factory, NULL, &IID_nsIIOService, (void**)&nsio);
3468     if(NS_FAILED(nsres)) {
3469         ERR("Couldn not create nsIOService instance %08x\n", nsres);
3470         nsIFactory_Release(old_factory);
3471         return;
3472     }
3473
3474     nsres = nsIIOService_QueryInterface(nsio, &IID_nsINetUtil, (void**)&net_util);
3475     if(NS_FAILED(nsres)) {
3476         WARN("Could not get nsINetUtil interface: %08x\n", nsres);
3477         nsIIOService_Release(nsio);
3478         return;
3479     }
3480
3481     nsres = nsIComponentRegistrar_UnregisterFactory(registrar, &NS_IOSERVICE_CID, old_factory);
3482     nsIFactory_Release(old_factory);
3483     if(NS_FAILED(nsres))
3484         ERR("UnregisterFactory failed: %08x\n", nsres);
3485
3486     nsres = nsIComponentRegistrar_RegisterFactory(registrar, &NS_IOSERVICE_CID,
3487             NS_IOSERVICE_CLASSNAME, NS_IOSERVICE_CONTRACTID, &nsIOServiceFactory);
3488     if(NS_FAILED(nsres))
3489         ERR("RegisterFactory failed: %08x\n", nsres);
3490 }
3491
3492 void release_nsio(void)
3493 {
3494     if(net_util) {
3495         nsINetUtil_Release(net_util);
3496         net_util = NULL;
3497     }
3498
3499     if(nsio) {
3500         nsIIOService_Release(nsio);
3501         nsio = NULL;
3502     }
3503 }