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