diff --git a/dlls/mshtml/binding.h b/dlls/mshtml/binding.h index cfae014206..d990750af5 100644 --- a/dlls/mshtml/binding.h +++ b/dlls/mshtml/binding.h @@ -106,6 +106,7 @@ typedef struct { #define BINDING_REPLACE 0x0002 #define BINDING_FROMHIST 0x0004 #define BINDING_REFRESH 0x0008 +#define BINDING_SUBMIT 0x0010 HRESULT set_http_header(struct list*,const WCHAR*,int,const WCHAR*,int) DECLSPEC_HIDDEN; HRESULT create_redirect_nschannel(const WCHAR*,nsChannel*,nsChannel**) DECLSPEC_HIDDEN; @@ -120,6 +121,7 @@ HRESULT super_navigate(HTMLOuterWindow*,IUri*,DWORD,const WCHAR*,BYTE*,DWORD) DE HRESULT load_uri(HTMLOuterWindow*,IUri*,DWORD) DECLSPEC_HIDDEN; HRESULT navigate_new_window(HTMLOuterWindow*,IUri*,const WCHAR*,IHTMLWindow2**) DECLSPEC_HIDDEN; HRESULT navigate_url(HTMLOuterWindow*,const WCHAR*,IUri*,DWORD) DECLSPEC_HIDDEN; +HRESULT submit_form(HTMLOuterWindow*,IUri*,nsIInputStream*) DECLSPEC_HIDDEN; HRESULT create_channelbsc(IMoniker*,const WCHAR*,BYTE*,DWORD,BOOL,nsChannelBSC**) DECLSPEC_HIDDEN; HRESULT channelbsc_load_stream(HTMLInnerWindow*,IMoniker*,IStream*) DECLSPEC_HIDDEN; diff --git a/dlls/mshtml/htmlform.c b/dlls/mshtml/htmlform.c index c38de5c90d..65db2b2f9f 100644 --- a/dlls/mshtml/htmlform.c +++ b/dlls/mshtml/htmlform.c @@ -30,6 +30,7 @@ #include "mshtml_private.h" #include "htmlevent.h" +#include "binding.h" WINE_DEFAULT_DEBUG_CHANNEL(mshtml); @@ -361,17 +362,61 @@ static HRESULT WINAPI HTMLFormElement_get_onreset(IHTMLFormElement *iface, VARIA static HRESULT WINAPI HTMLFormElement_submit(IHTMLFormElement *iface) { HTMLFormElement *This = impl_from_IHTMLFormElement(iface); + HTMLOuterWindow *window = NULL; + nsIInputStream *post_stream; + nsAString action_uri_str; + IUri *uri; nsresult nsres; + HRESULT hres; TRACE("(%p)->()\n", This); - nsres = nsIDOMHTMLFormElement_Submit(This->nsform); - if(NS_FAILED(nsres)) { - ERR("Submit failed: %08x\n", nsres); - return E_FAIL; + if(This->element.node.doc) { + HTMLDocumentNode *doc = This->element.node.doc; + if(doc->window && doc->window->base.outer_window) + window = doc->window->base.outer_window; + } + if(!window) { + TRACE("No outer window\n"); + return S_OK; } - return S_OK; + /* + * FIXME: We currently don't use our submit implementation for sub-windows because + * load_nsuri can't support post data. We should fix it. + */ + if(!window->doc_obj || window->doc_obj->basedoc.window != window) { + nsres = nsIDOMHTMLFormElement_Submit(This->nsform); + if(NS_FAILED(nsres)) { + ERR("Submit failed: %08x\n", nsres); + return E_FAIL; + } + + return S_OK; + } + + nsAString_Init(&action_uri_str, NULL); + nsres = nsIDOMHTMLFormElement_GetFormData(This->nsform, NULL, &action_uri_str, &post_stream); + if(NS_SUCCEEDED(nsres)) { + const PRUnichar *action_uri; + + nsAString_GetData(&action_uri_str, &action_uri); + hres = create_uri(action_uri, 0, &uri); + }else { + ERR("GetFormData failed: %08x\n", nsres); + hres = E_FAIL; + } + nsAString_Finish(&action_uri_str); + if(SUCCEEDED(hres)) { + window->readystate_locked++; + hres = submit_form(window, uri, post_stream); + window->readystate_locked--; + IUri_Release(uri); + } + + if(post_stream) + nsIInputStream_Release(post_stream); + return hres; } static HRESULT WINAPI HTMLFormElement_reset(IHTMLFormElement *iface) diff --git a/dlls/mshtml/mshtml_private.h b/dlls/mshtml/mshtml_private.h index df7b600023..ff10c5ce75 100644 --- a/dlls/mshtml/mshtml_private.h +++ b/dlls/mshtml/mshtml_private.h @@ -385,7 +385,10 @@ struct HTMLOuterWindow { nsIDOMWindow *nswindow; HTMLOuterWindow *parent; HTMLFrameBase *frame_element; + READYSTATE readystate; + BOOL readystate_locked; + unsigned readystate_pending; HTMLInnerWindow *pending_window; IMoniker *mon; diff --git a/dlls/mshtml/navigate.c b/dlls/mshtml/navigate.c index be3d1a8a6c..f84af32a79 100644 --- a/dlls/mshtml/navigate.c +++ b/dlls/mshtml/navigate.c @@ -2238,7 +2238,32 @@ HRESULT super_navigate(HTMLOuterWindow *window, IUri *uri, DWORD flags, const WC prepare_for_binding(&window->doc_obj->basedoc, mon, flags); hres = IUri_GetScheme(uri, &scheme); - if(SUCCEEDED(hres) && scheme != URL_SCHEME_JAVASCRIPT) { + if(SUCCEEDED(hres) && scheme == URL_SCHEME_JAVASCRIPT) { + navigate_javascript_task_t *task; + + IBindStatusCallback_Release(&bsc->bsc.IBindStatusCallback_iface); + IMoniker_Release(mon); + + task = heap_alloc(sizeof(*task)); + if(!task) + return E_OUTOFMEMORY; + + /* Why silently? */ + window->readystate = READYSTATE_COMPLETE; + if(!(flags & BINDING_FROMHIST)) + call_docview_84(window->doc_obj); + + IUri_AddRef(uri); + task->window = window; + task->uri = uri; + hres = push_task(&task->header, navigate_javascript_proc, navigate_javascript_task_destr, window->task_magic); + }else if(flags & BINDING_SUBMIT) { + hres = set_moniker(window, mon, uri, NULL, bsc, TRUE); + if(SUCCEEDED(hres)) + hres = start_binding(window->pending_window, &bsc->bsc, NULL); + IBindStatusCallback_Release(&bsc->bsc.IBindStatusCallback_iface); + IMoniker_Release(mon); + }else { navigate_task_t *task; task = heap_alloc(sizeof(*task)); @@ -2261,25 +2286,6 @@ HRESULT super_navigate(HTMLOuterWindow *window, IUri *uri, DWORD flags, const WC IUri_AddRef(uri); task->uri = uri; hres = push_task(&task->header, navigate_proc, navigate_task_destr, window->task_magic); - }else { - navigate_javascript_task_t *task; - - IBindStatusCallback_Release(&bsc->bsc.IBindStatusCallback_iface); - IMoniker_Release(mon); - - task = heap_alloc(sizeof(*task)); - if(!task) - return E_OUTOFMEMORY; - - /* Why silently? */ - window->readystate = READYSTATE_COMPLETE; - if(!(flags & BINDING_FROMHIST)) - call_docview_84(window->doc_obj); - - IUri_AddRef(uri); - task->window = window; - task->uri = uri; - hres = push_task(&task->header, navigate_javascript_proc, navigate_javascript_task_destr, window->task_magic); } return hres; @@ -2396,7 +2402,8 @@ HRESULT hlink_frame_navigate(HTMLDocument *doc, LPCWSTR url, nsChannel *nschanne return hres; } -static HRESULT navigate_uri(HTMLOuterWindow *window, IUri *uri, const WCHAR *display_uri, DWORD flags) +static HRESULT navigate_uri(HTMLOuterWindow *window, IUri *uri, const WCHAR *display_uri, const request_data_t *request_data, + DWORD flags) { nsWineURI *nsuri; HRESULT hres; @@ -2404,18 +2411,22 @@ static HRESULT navigate_uri(HTMLOuterWindow *window, IUri *uri, const WCHAR *dis TRACE("%s\n", debugstr_w(display_uri)); if(window->doc_obj && window->doc_obj->webbrowser && window == window->doc_obj->basedoc.window) { + DWORD post_data_len = request_data ? request_data->post_data_len : 0; + void *post_data = post_data_len ? request_data->post_data : NULL; + const WCHAR *headers = request_data ? request_data->headers : NULL; + if(!(flags & BINDING_REFRESH)) { BOOL cancel = FALSE; hres = IDocObjectService_FireBeforeNavigate2(window->doc_obj->doc_object_service, NULL, display_uri, 0x40, - NULL, NULL, 0, NULL, TRUE, &cancel); + NULL, post_data, post_data_len ? post_data_len+1 : 0, headers, TRUE, &cancel); if(SUCCEEDED(hres) && cancel) { TRACE("Navigation canceled\n"); return S_OK; } } - return super_navigate(window, uri, flags, NULL, NULL, 0); + return super_navigate(window, uri, flags, headers, post_data, post_data_len); } if(window->doc_obj && window == window->doc_obj->basedoc.window) { @@ -2449,31 +2460,21 @@ HRESULT load_uri(HTMLOuterWindow *window, IUri *uri, DWORD flags) if(FAILED(hres)) return hres; - hres = navigate_uri(window, uri, display_uri, flags); + hres = navigate_uri(window, uri, display_uri, NULL, flags); SysFreeString(display_uri); return hres; } -HRESULT navigate_url(HTMLOuterWindow *window, const WCHAR *new_url, IUri *base_uri, DWORD flags) +static HRESULT translate_uri(HTMLOuterWindow *window, IUri *orig_uri, BSTR *ret_display_uri, IUri **ret_uri) { + IUri *uri = NULL; BSTR display_uri; - IUri *uri; HRESULT hres; - if(new_url && base_uri) - hres = CoInternetCombineUrlEx(base_uri, new_url, URL_ESCAPE_SPACES_ONLY|URL_DONT_ESCAPE_EXTRA_INFO, - &uri, 0); - else - hres = create_uri(new_url, 0, &uri); + hres = IUri_GetDisplayUri(orig_uri, &display_uri); if(FAILED(hres)) return hres; - hres = IUri_GetDisplayUri(uri, &display_uri); - if(FAILED(hres)) { - IUri_Release(uri); - return hres; - } - if(window->doc_obj && window->doc_obj->hostui) { OLECHAR *translated_url = NULL; @@ -2482,7 +2483,6 @@ HRESULT navigate_url(HTMLOuterWindow *window, const WCHAR *new_url, IUri *base_u if(hres == S_OK) { TRACE("%08x %s -> %s\n", hres, debugstr_w(display_uri), debugstr_w(translated_url)); SysFreeString(display_uri); - IUri_Release(uri); hres = create_uri(translated_url, 0, &uri); CoTaskMemFree(translated_url); if(FAILED(hres)) @@ -2496,8 +2496,57 @@ HRESULT navigate_url(HTMLOuterWindow *window, const WCHAR *new_url, IUri *base_u } } - hres = navigate_uri(window, uri, display_uri, flags); + if(!uri) { + IUri_AddRef(orig_uri); + uri = orig_uri; + } + *ret_display_uri = display_uri; + *ret_uri = uri; + return S_OK; +} + +HRESULT submit_form(HTMLOuterWindow *window, IUri *submit_uri, nsIInputStream *post_stream) +{ + request_data_t request_data = {NULL}; + BSTR display_uri; + IUri *uri; + HRESULT hres; + + hres = read_post_data_stream(post_stream, TRUE, NULL, &request_data); + if(FAILED(hres)) + return hres; + + hres = translate_uri(window, submit_uri, &display_uri, &uri); + if(SUCCEEDED(hres)) { + hres = navigate_uri(window, uri, display_uri, &request_data, BINDING_NAVIGATED|BINDING_SUBMIT); + IUri_Release(uri); + SysFreeString(display_uri); + } + release_request_data(&request_data); + return hres; +} + +HRESULT navigate_url(HTMLOuterWindow *window, const WCHAR *new_url, IUri *base_uri, DWORD flags) +{ + IUri *uri, *nav_uri; + BSTR display_uri; + HRESULT hres; + + if(new_url && base_uri) + hres = CoInternetCombineUrlEx(base_uri, new_url, URL_ESCAPE_SPACES_ONLY|URL_DONT_ESCAPE_EXTRA_INFO, + &nav_uri, 0); + else + hres = create_uri(new_url, 0, &nav_uri); + if(FAILED(hres)) + return hres; + + hres = translate_uri(window, nav_uri, &display_uri, &uri); + IUri_Release(nav_uri); + if(FAILED(hres)) + return hres; + + hres = navigate_uri(window, uri, display_uri, NULL, flags); IUri_Release(uri); SysFreeString(display_uri); return hres; diff --git a/dlls/mshtml/persist.c b/dlls/mshtml/persist.c index 8c0ad68396..5123e6cdfd 100644 --- a/dlls/mshtml/persist.c +++ b/dlls/mshtml/persist.c @@ -438,9 +438,9 @@ HRESULT set_moniker(HTMLOuterWindow *window, IMoniker *mon, IUri *nav_uri, IBind return S_OK; } -void set_ready_state(HTMLOuterWindow *window, READYSTATE readystate) +static void notif_readystate(HTMLOuterWindow *window) { - window->readystate = readystate; + window->readystate_pending = FALSE; if(window->doc_obj && window->doc_obj->basedoc.window == window) call_property_onchanged(&window->doc_obj->basedoc.cp_container, DISPID_READYSTATE); @@ -453,6 +453,52 @@ void set_ready_state(HTMLOuterWindow *window, READYSTATE readystate) TRUE, window->frame_element->element.node.nsnode, NULL, NULL); } +typedef struct { + task_t header; + HTMLOuterWindow *window; +} readystate_task_t; + +static void notif_readystate_proc(task_t *_task) +{ + readystate_task_t *task = (readystate_task_t*)_task; + notif_readystate(task->window); +} + +static void notif_readystate_destr(task_t *_task) +{ + readystate_task_t *task = (readystate_task_t*)_task; + IHTMLWindow2_Release(&task->window->base.IHTMLWindow2_iface); +} + +void set_ready_state(HTMLOuterWindow *window, READYSTATE readystate) +{ + READYSTATE prev_state = window->readystate; + + window->readystate = readystate; + + if(window->readystate_locked) { + readystate_task_t *task; + HRESULT hres; + + if(window->readystate_pending || prev_state == readystate) + return; + + task = heap_alloc(sizeof(*task)); + if(!task) + return; + + IHTMLWindow2_AddRef(&window->base.IHTMLWindow2_iface); + task->window = window; + + hres = push_task(&task->header, notif_readystate_proc, notif_readystate_destr, window->task_magic); + if(SUCCEEDED(hres)) + window->readystate_pending = TRUE; + return; + } + + notif_readystate(window); +} + static HRESULT get_doc_string(HTMLDocumentNode *This, char **str) { nsIDOMNode *nsnode;