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