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