mshtml: Better support for HTTP redirection.
This commit is contained in:
parent
f24be9fa54
commit
0613a82671
|
@ -481,7 +481,6 @@ struct NSContainer {
|
|||
|
||||
typedef struct nsWineURI nsWineURI;
|
||||
|
||||
HRESULT set_wine_url(nsWineURI*,LPCWSTR);
|
||||
nsresult on_start_uri_open(NSContainer*,nsIURI*,PRBool*);
|
||||
|
||||
/* Keep sync with request_method_strings in nsio.c */
|
||||
|
@ -523,6 +522,7 @@ typedef struct {
|
|||
} http_header_t;
|
||||
|
||||
HRESULT set_http_header(struct list*,const WCHAR*,int,const WCHAR*,int);
|
||||
HRESULT create_redirect_nschannel(const WCHAR*,nsChannel*,nsChannel**);
|
||||
|
||||
typedef struct {
|
||||
HRESULT (*qi)(HTMLDOMNode*,REFIID,void**);
|
||||
|
|
|
@ -1089,6 +1089,118 @@ static HRESULT read_stream_data(nsChannelBSC *This, IStream *stream)
|
|||
return S_OK;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
nsIAsyncVerifyRedirectCallback nsIAsyncVerifyRedirectCallback_iface;
|
||||
|
||||
LONG ref;
|
||||
|
||||
nsChannel *nschannel;
|
||||
nsChannelBSC *bsc;
|
||||
} nsRedirectCallback;
|
||||
|
||||
static nsRedirectCallback *impl_from_nsIAsyncVerifyRedirectCallback(nsIAsyncVerifyRedirectCallback *iface)
|
||||
{
|
||||
return CONTAINING_RECORD(iface, nsRedirectCallback, nsIAsyncVerifyRedirectCallback_iface);
|
||||
}
|
||||
|
||||
static nsresult NSAPI nsAsyncVerifyRedirectCallback_QueryInterface(nsIAsyncVerifyRedirectCallback *iface,
|
||||
nsIIDRef riid, void **result)
|
||||
{
|
||||
nsRedirectCallback *This = impl_from_nsIAsyncVerifyRedirectCallback(iface);
|
||||
|
||||
if(IsEqualGUID(&IID_nsISupports, riid)) {
|
||||
TRACE("(%p)->(IID_nsISuports %p)\n", This, result);
|
||||
*result = &This->nsIAsyncVerifyRedirectCallback_iface;
|
||||
}else if(IsEqualGUID(&IID_nsIAsyncVerifyRedirectCallback, riid)) {
|
||||
TRACE("(%p)->(IID_nsIAsyncVerifyRedirectCallback %p)\n", This, result);
|
||||
*result = &This->nsIAsyncVerifyRedirectCallback_iface;
|
||||
}else {
|
||||
*result = NULL;
|
||||
WARN("unimplmented iface %s\n", debugstr_guid(riid));
|
||||
return NS_NOINTERFACE;
|
||||
}
|
||||
|
||||
nsISupports_AddRef((nsISupports*)*result);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
static nsrefcnt NSAPI nsAsyncVerifyRedirectCallback_AddRef(nsIAsyncVerifyRedirectCallback *iface)
|
||||
{
|
||||
nsRedirectCallback *This = impl_from_nsIAsyncVerifyRedirectCallback(iface);
|
||||
LONG ref = InterlockedIncrement(&This->ref);
|
||||
|
||||
TRACE("(%p) ref=%d\n", This, ref);
|
||||
|
||||
return ref;
|
||||
}
|
||||
|
||||
static nsrefcnt NSAPI nsAsyncVerifyRedirectCallback_Release(nsIAsyncVerifyRedirectCallback *iface)
|
||||
{
|
||||
nsRedirectCallback *This = impl_from_nsIAsyncVerifyRedirectCallback(iface);
|
||||
LONG ref = InterlockedDecrement(&This->ref);
|
||||
|
||||
TRACE("(%p) ref=%d\n", This, ref);
|
||||
|
||||
if(!ref) {
|
||||
IBindStatusCallback_Release(&This->bsc->bsc.IBindStatusCallback_iface);
|
||||
nsIChannel_Release(&This->nschannel->nsIHttpChannel_iface);
|
||||
heap_free(This);
|
||||
}
|
||||
|
||||
return ref;
|
||||
}
|
||||
|
||||
static nsresult NSAPI nsAsyncVerifyRedirectCallback_AsyncOnChannelRedirect(nsIAsyncVerifyRedirectCallback *iface, nsresult result)
|
||||
{
|
||||
nsRedirectCallback *This = impl_from_nsIAsyncVerifyRedirectCallback(iface);
|
||||
|
||||
TRACE("(%p)->(%08x)\n", This, result);
|
||||
|
||||
if(This->bsc->nschannel)
|
||||
nsIHttpChannel_Release(&This->bsc->nschannel->nsIHttpChannel_iface);
|
||||
nsIChannel_AddRef(&This->nschannel->nsIHttpChannel_iface);
|
||||
This->bsc->nschannel = This->nschannel;
|
||||
|
||||
if(This->nschannel->load_group) {
|
||||
nsresult nsres;
|
||||
|
||||
nsres = nsILoadGroup_AddRequest(This->nschannel->load_group, (nsIRequest*)&This->nschannel->nsIHttpChannel_iface,
|
||||
NULL);
|
||||
if(NS_FAILED(nsres))
|
||||
ERR("AddRequest failed: %08x\n", nsres);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
static const nsIAsyncVerifyRedirectCallbackVtbl nsAsyncVerifyRedirectCallbackVtbl = {
|
||||
nsAsyncVerifyRedirectCallback_QueryInterface,
|
||||
nsAsyncVerifyRedirectCallback_AddRef,
|
||||
nsAsyncVerifyRedirectCallback_Release,
|
||||
nsAsyncVerifyRedirectCallback_AsyncOnChannelRedirect
|
||||
};
|
||||
|
||||
static HRESULT create_redirect_callback(nsChannel *nschannel, nsChannelBSC *bsc, nsRedirectCallback **ret)
|
||||
{
|
||||
nsRedirectCallback *callback;
|
||||
|
||||
callback = heap_alloc(sizeof(*callback));
|
||||
if(!callback)
|
||||
return E_OUTOFMEMORY;
|
||||
|
||||
callback->nsIAsyncVerifyRedirectCallback_iface.lpVtbl = &nsAsyncVerifyRedirectCallbackVtbl;
|
||||
callback->ref = 1;
|
||||
|
||||
nsIChannel_AddRef(&nschannel->nsIHttpChannel_iface);
|
||||
callback->nschannel = nschannel;
|
||||
|
||||
IBindStatusCallback_AddRef(&bsc->bsc.IBindStatusCallback_iface);
|
||||
callback->bsc = bsc;
|
||||
|
||||
*ret = callback;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static inline nsChannelBSC *nsChannelBSC_from_BSCallback(BSCallback *iface)
|
||||
{
|
||||
return CONTAINING_RECORD(iface, nsChannelBSC, bsc);
|
||||
|
@ -1279,6 +1391,45 @@ static HRESULT nsChannelBSC_read_data(BSCallback *bsc, IStream *stream)
|
|||
return read_stream_data(This, stream);
|
||||
}
|
||||
|
||||
static HRESULT handle_redirect(nsChannelBSC *This, const WCHAR *new_url)
|
||||
{
|
||||
nsRedirectCallback *callback;
|
||||
nsIChannelEventSink *sink;
|
||||
nsChannel *new_channel;
|
||||
nsresult nsres;
|
||||
HRESULT hres;
|
||||
|
||||
TRACE("(%p)->(%s)\n", This, debugstr_w(new_url));
|
||||
|
||||
if(!This->nschannel || !This->nschannel->notif_callback)
|
||||
return S_OK;
|
||||
|
||||
nsres = nsIInterfaceRequestor_GetInterface(This->nschannel->notif_callback, &IID_nsIChannelEventSink, (void**)&sink);
|
||||
if(NS_FAILED(nsres))
|
||||
return S_OK;
|
||||
|
||||
hres = create_redirect_nschannel(new_url, This->nschannel, &new_channel);
|
||||
if(SUCCEEDED(hres)) {
|
||||
hres = create_redirect_callback(new_channel, This, &callback);
|
||||
nsIChannel_Release(&new_channel->nsIHttpChannel_iface);
|
||||
}
|
||||
|
||||
if(SUCCEEDED(hres)) {
|
||||
nsres = nsIChannelEventSink_AsyncOnChannelRedirect(sink, (nsIChannel*)&This->nschannel->nsIHttpChannel_iface,
|
||||
(nsIChannel*)&callback->nschannel->nsIHttpChannel_iface, REDIRECT_TEMPORARY, /* FIXME */
|
||||
&callback->nsIAsyncVerifyRedirectCallback_iface);
|
||||
|
||||
if(NS_FAILED(nsres))
|
||||
FIXME("AsyncOnChannelRedirect failed: %08x\n", hres);
|
||||
else if(This->nschannel != callback->nschannel)
|
||||
FIXME("nschannel not updated\n");
|
||||
}
|
||||
|
||||
nsIAsyncVerifyRedirectCallback_Release(&callback->nsIAsyncVerifyRedirectCallback_iface);
|
||||
nsIChannelEventSink_Release(sink);
|
||||
return hres;
|
||||
}
|
||||
|
||||
static HRESULT nsChannelBSC_on_progress(BSCallback *bsc, ULONG status_code, LPCWSTR status_text)
|
||||
{
|
||||
nsChannelBSC *This = nsChannelBSC_from_BSCallback(bsc);
|
||||
|
@ -1292,11 +1443,7 @@ static HRESULT nsChannelBSC_on_progress(BSCallback *bsc, ULONG status_code, LPCW
|
|||
This->nschannel->content_type = heap_strdupWtoA(status_text);
|
||||
break;
|
||||
case BINDSTATUS_REDIRECTING:
|
||||
TRACE("redirect to %s\n", debugstr_w(status_text));
|
||||
|
||||
/* FIXME: We should find a better way to handle this */
|
||||
set_wine_url(This->nschannel->uri, status_text);
|
||||
break;
|
||||
return handle_redirect(This, status_text);
|
||||
case BINDSTATUS_BEGINDOWNLOADDATA: {
|
||||
IWinInetHttpInfo *http_info;
|
||||
DWORD status, size = sizeof(DWORD);
|
||||
|
|
|
@ -493,6 +493,31 @@ interface nsIUploadChannel : nsISupports
|
|||
nsresult GetUploadStream(nsIInputStream **aUploadStream);
|
||||
}
|
||||
|
||||
[
|
||||
object,
|
||||
uuid(8d171460-a716-41f1-92be-8c659db39b45),
|
||||
local
|
||||
]
|
||||
interface nsIAsyncVerifyRedirectCallback : nsISupports
|
||||
{
|
||||
nsresult OnRedirectVerifyCallback(nsresult result);
|
||||
}
|
||||
|
||||
[
|
||||
object,
|
||||
uuid(a430d870-df77-4502-9570-d46a8de33154),
|
||||
local
|
||||
]
|
||||
interface nsIChannelEventSink : nsISupports
|
||||
{
|
||||
cpp_quote("#define REDIRECT_TEMPORARY 1")
|
||||
cpp_quote("#define REDIRECT_PERMANENT 2")
|
||||
cpp_quote("#define REDIRECT_INTERNAL 4")
|
||||
|
||||
nsresult AsyncOnChannelRedirect(nsIChannel *oldChannel, nsIChannel *newChannel, PRUint32 flags,
|
||||
nsIAsyncVerifyRedirectCallback *callback);
|
||||
}
|
||||
|
||||
[
|
||||
object,
|
||||
uuid(a6cf90c1-15b3-11d2-932e-00805f8add32),
|
||||
|
@ -1856,8 +1881,9 @@ interface nsIBaseWindow : nsISupports
|
|||
nsresult SetTitle(const PRUnichar *aTitle);
|
||||
}
|
||||
|
||||
cpp_quote("#define LOAD_FLAGS_NONE 0x00000")
|
||||
cpp_quote("#define LOAD_INITIAL_DOCUMENT_URI 0x80000")
|
||||
cpp_quote("#define LOAD_FLAGS_NONE 0x00000000")
|
||||
cpp_quote("#define LOAD_REPLACE 0x00040000")
|
||||
cpp_quote("#define LOAD_INITIAL_DOCUMENT_URI 0x00080000")
|
||||
|
||||
[
|
||||
object,
|
||||
|
|
|
@ -189,7 +189,7 @@ HRESULT load_nsuri(HTMLWindow *window, nsWineURI *uri, nsChannelBSC *channelbsc,
|
|||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT set_wine_url(nsWineURI *This, LPCWSTR url)
|
||||
static HRESULT set_wine_url(nsWineURI *This, LPCWSTR url)
|
||||
{
|
||||
TRACE("(%p)->(%s)\n", This, debugstr_w(url));
|
||||
|
||||
|
@ -2563,6 +2563,59 @@ static nsresult create_nschannel(nsWineURI *uri, nsChannel **ret)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
HRESULT create_redirect_nschannel(const WCHAR *url, nsChannel *orig_channel, nsChannel **ret)
|
||||
{
|
||||
HTMLWindow *window = NULL;
|
||||
nsChannel *channel;
|
||||
nsWineURI *uri;
|
||||
nsresult nsres;
|
||||
HRESULT hres;
|
||||
|
||||
if(orig_channel->uri->window_ref)
|
||||
window = orig_channel->uri->window_ref->window;
|
||||
nsres = create_uri(NULL, window, NULL, &uri);
|
||||
if(NS_FAILED(nsres))
|
||||
return E_FAIL;
|
||||
|
||||
hres = CreateUri(url, 0, 0, &uri->uri);
|
||||
if(SUCCEEDED(hres))
|
||||
nsres = create_nschannel(uri, &channel);
|
||||
sync_wine_url(uri);
|
||||
nsIURL_Release(&uri->nsIURL_iface);
|
||||
if(FAILED(hres))
|
||||
return hres;
|
||||
if(NS_FAILED(nsres))
|
||||
return E_FAIL;
|
||||
|
||||
if(orig_channel->load_group) {
|
||||
nsILoadGroup_AddRef(orig_channel->load_group);
|
||||
channel->load_group = orig_channel->load_group;
|
||||
}
|
||||
|
||||
if(orig_channel->notif_callback) {
|
||||
nsIInterfaceRequestor_AddRef(orig_channel->notif_callback);
|
||||
channel->notif_callback = orig_channel->notif_callback;
|
||||
}
|
||||
|
||||
channel->load_flags = orig_channel->load_flags | LOAD_REPLACE;
|
||||
|
||||
if(orig_channel->request_method == METHOD_POST)
|
||||
FIXME("unsupported POST method\n");
|
||||
|
||||
if(orig_channel->original_uri) {
|
||||
nsIURI_AddRef(orig_channel->original_uri);
|
||||
channel->original_uri = orig_channel->original_uri;
|
||||
}
|
||||
|
||||
if(orig_channel->referrer) {
|
||||
nsIURI_AddRef(orig_channel->referrer);
|
||||
channel->referrer = orig_channel->referrer;
|
||||
}
|
||||
|
||||
*ret = channel;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
nsIProtocolHandler nsIProtocolHandler_iface;
|
||||
|
||||
|
|
Loading…
Reference in New Issue