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