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