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;