Merge branch 'webview_improved_handlers' of https://github.com/TcT2k/wxWidgets
WebView handler improvements for advanced requests and Edge handler implementation. See #22797.
This commit is contained in:
commit
6f615cbd09
11 changed files with 1039 additions and 54 deletions
|
|
@ -153,7 +153,7 @@ wx_add_sample(uiaction DEPENDS wxUSE_UIACTIONSIMULATOR)
|
|||
wx_add_sample(validate validate.cpp validate.h DEPENDS wxUSE_VALIDATORS)
|
||||
wx_add_sample(vscroll vstest.cpp)
|
||||
wx_add_sample(webview LIBRARIES wxwebview
|
||||
DATA ../help/doc.zip:doc.zip
|
||||
DATA ../help/doc.zip:doc.zip handler_advanced.html
|
||||
NAME webviewsample DEPENDS wxUSE_WEBVIEW)
|
||||
if(TARGET webviewsample AND wxUSE_STC)
|
||||
wx_exe_link_libraries(webviewsample wxstc)
|
||||
|
|
|
|||
203
include/wx/msw/private/comstream.h
Normal file
203
include/wx/msw/private/comstream.h
Normal file
|
|
@ -0,0 +1,203 @@
|
|||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Name: wx/msw/private/comstream.h
|
||||
// Purpose: COM Stream adapter to wxStreamBase based streams
|
||||
// Created: 2021-01-15
|
||||
// Copyright: (c) 2021 wxWidgets team
|
||||
// Licence: wxWindows licence
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef WX_COMSTREAM_H
|
||||
#define WX_COMSTREAM_H
|
||||
|
||||
#include "wx/stream.h"
|
||||
#include "wx/msw/ole/comimpl.h"
|
||||
|
||||
class wxCOMBaseStreamAdapter : public IStream
|
||||
{
|
||||
public:
|
||||
wxCOMBaseStreamAdapter(wxStreamBase* stream):
|
||||
m_stream(stream)
|
||||
{ }
|
||||
|
||||
virtual ~wxCOMBaseStreamAdapter() { }
|
||||
|
||||
// IUnknown
|
||||
STDMETHODIMP QueryInterface(REFIID riid, void** ppv) wxOVERRIDE
|
||||
{
|
||||
if (riid == IID_IUnknown ||
|
||||
riid == IID_ISequentialStream ||
|
||||
riid == IID_IStream)
|
||||
{
|
||||
*ppv = this;
|
||||
AddRef();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
*ppv = NULL;
|
||||
return E_NOINTERFACE;
|
||||
}
|
||||
|
||||
STDMETHODIMP_(ULONG) AddRef() wxOVERRIDE
|
||||
{
|
||||
return ++m_cRef;
|
||||
}
|
||||
|
||||
STDMETHODIMP_(ULONG) Release() wxOVERRIDE
|
||||
{
|
||||
if (--m_cRef == wxAutoULong(0))
|
||||
{
|
||||
delete this;
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
return m_cRef;
|
||||
}
|
||||
|
||||
// IStream
|
||||
virtual HRESULT STDMETHODCALLTYPE Seek(
|
||||
LARGE_INTEGER WXUNUSED(dlibMove), DWORD WXUNUSED(dwOrigin),
|
||||
ULARGE_INTEGER *WXUNUSED(plibNewPosition)) wxOVERRIDE
|
||||
{
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
virtual HRESULT STDMETHODCALLTYPE SetSize(ULARGE_INTEGER WXUNUSED(libNewSize))
|
||||
{
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
virtual HRESULT STDMETHODCALLTYPE CopyTo(IStream *WXUNUSED(pstm),
|
||||
ULARGE_INTEGER WXUNUSED(cb), ULARGE_INTEGER *WXUNUSED(pcbRead),
|
||||
ULARGE_INTEGER *WXUNUSED(pcbWritten)) wxOVERRIDE
|
||||
{
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
virtual HRESULT STDMETHODCALLTYPE Commit(DWORD WXUNUSED(grfCommitFlags)) wxOVERRIDE
|
||||
{
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
virtual HRESULT STDMETHODCALLTYPE Revert(void) wxOVERRIDE
|
||||
{
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
virtual HRESULT STDMETHODCALLTYPE LockRegion(ULARGE_INTEGER WXUNUSED(libOffset),
|
||||
ULARGE_INTEGER WXUNUSED(cb), DWORD WXUNUSED(dwLockType)) wxOVERRIDE
|
||||
{
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
virtual HRESULT STDMETHODCALLTYPE UnlockRegion(ULARGE_INTEGER WXUNUSED(libOffset),
|
||||
ULARGE_INTEGER WXUNUSED(cb), DWORD WXUNUSED(dwLockType)) wxOVERRIDE
|
||||
{
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
virtual HRESULT STDMETHODCALLTYPE Stat(STATSTG *pstatstg, DWORD WXUNUSED(grfStatFlag)) wxOVERRIDE
|
||||
{
|
||||
pstatstg->type = STGTY_STREAM;
|
||||
pstatstg->cbSize.QuadPart = m_stream->GetSize();
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
virtual HRESULT STDMETHODCALLTYPE Clone(IStream **WXUNUSED(ppstm)) wxOVERRIDE
|
||||
{
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
// ISequentialStream
|
||||
|
||||
virtual HRESULT STDMETHODCALLTYPE Read(void *WXUNUSED(pv),
|
||||
ULONG WXUNUSED(cb), ULONG *WXUNUSED(pcbRead)) wxOVERRIDE
|
||||
{
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
virtual HRESULT STDMETHODCALLTYPE Write(const void *WXUNUSED(pv),
|
||||
ULONG WXUNUSED(cb), ULONG *WXUNUSED(pcbWritten)) wxOVERRIDE
|
||||
{
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
|
||||
protected:
|
||||
wxStreamBase* m_stream;
|
||||
|
||||
static wxSeekMode OriginToSeekMode(DWORD origin)
|
||||
{
|
||||
switch (origin)
|
||||
{
|
||||
case STREAM_SEEK_SET:
|
||||
return wxFromStart;
|
||||
case STREAM_SEEK_CUR:
|
||||
return wxFromCurrent;
|
||||
case STREAM_SEEK_END:
|
||||
return wxFromEnd;
|
||||
}
|
||||
|
||||
return wxFromStart;
|
||||
}
|
||||
private:
|
||||
wxAutoULong m_cRef;
|
||||
};
|
||||
|
||||
class wxCOMInputStreamAdapter : public wxCOMBaseStreamAdapter
|
||||
{
|
||||
public:
|
||||
wxCOMInputStreamAdapter(wxInputStream* stream):
|
||||
wxCOMBaseStreamAdapter(stream)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
virtual HRESULT STDMETHODCALLTYPE Seek(
|
||||
LARGE_INTEGER dlibMove, DWORD dwOrigin,
|
||||
ULARGE_INTEGER *plibNewPosition) wxOVERRIDE
|
||||
{
|
||||
wxFileOffset newOffset = reinterpret_cast<wxInputStream*>(m_stream)->SeekI(dlibMove.QuadPart, OriginToSeekMode(dwOrigin));
|
||||
if (plibNewPosition)
|
||||
plibNewPosition->QuadPart = newOffset;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
virtual HRESULT STDMETHODCALLTYPE Read(void *pv, ULONG cb, ULONG *pcbRead) wxOVERRIDE
|
||||
{
|
||||
wxInputStream* inputStr = reinterpret_cast<wxInputStream*>(m_stream);
|
||||
inputStr->Read(pv, cb);
|
||||
*pcbRead = inputStr->LastRead();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
class wxCOMOutputStreamAdapter : public wxCOMBaseStreamAdapter
|
||||
{
|
||||
public:
|
||||
wxCOMOutputStreamAdapter(wxOutputStream* stream) :
|
||||
wxCOMBaseStreamAdapter(stream)
|
||||
{ }
|
||||
|
||||
virtual HRESULT STDMETHODCALLTYPE Seek(
|
||||
LARGE_INTEGER dlibMove, DWORD dwOrigin,
|
||||
ULARGE_INTEGER *plibNewPosition) wxOVERRIDE
|
||||
{
|
||||
wxFileOffset newOffset = reinterpret_cast<wxOutputStream*>(m_stream)->SeekO(dlibMove.QuadPart, OriginToSeekMode(dwOrigin));
|
||||
if (plibNewPosition)
|
||||
plibNewPosition->QuadPart = newOffset;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
virtual HRESULT STDMETHODCALLTYPE Write(const void *pv, ULONG cb, ULONG *pcbWritten) wxOVERRIDE
|
||||
{
|
||||
wxOutputStream* outputStr = reinterpret_cast<wxOutputStream*>(m_stream);
|
||||
outputStr->Write(pv, cb);
|
||||
*pcbWritten = outputStr->LastWrite();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
#endif // WX_COMSTREAM_H
|
||||
|
|
@ -14,6 +14,7 @@
|
|||
#include "wx/dynlib.h"
|
||||
#endif
|
||||
#include "wx/msw/private/comptr.h"
|
||||
#include "wx/hashmap.h"
|
||||
|
||||
#include <WebView2.h>
|
||||
|
||||
|
|
@ -40,6 +41,8 @@ __CRT_UUID_DECL(ICoreWebView2SourceChangedEventHandler, 0x3c067f9f, 0x5388, 0x47
|
|||
__CRT_UUID_DECL(ICoreWebView2WebMessageReceivedEventHandler, 0x57213f19, 0x00e6, 0x49fa, 0x8e,0x07, 0x89,0x8e,0xa0,0x1e,0xcb,0xd2);
|
||||
#endif
|
||||
|
||||
WX_DECLARE_STRING_HASH_MAP(wxSharedPtr<wxWebViewHandler>, wxStringToWebHandlerMap);
|
||||
|
||||
class wxWebViewEdgeImpl
|
||||
{
|
||||
public:
|
||||
|
|
@ -65,6 +68,7 @@ public:
|
|||
wxVector<wxString> m_userScriptIds;
|
||||
wxString m_scriptMsgHandlerName;
|
||||
wxString m_customUserAgent;
|
||||
wxStringToWebHandlerMap m_handlers;
|
||||
|
||||
// WebView Events tokens
|
||||
EventRegistrationToken m_navigationStartingToken = { };
|
||||
|
|
@ -75,6 +79,7 @@ public:
|
|||
EventRegistrationToken m_DOMContentLoadedToken = { };
|
||||
EventRegistrationToken m_containsFullScreenElementChangedToken = { };
|
||||
EventRegistrationToken m_webMessageReceivedToken = { };
|
||||
EventRegistrationToken m_webResourceRequestedToken = { };
|
||||
|
||||
// WebView Event handlers
|
||||
HRESULT OnNavigationStarting(ICoreWebView2* sender, ICoreWebView2NavigationStartingEventArgs* args);
|
||||
|
|
@ -85,6 +90,7 @@ public:
|
|||
HRESULT OnDOMContentLoaded(ICoreWebView2* sender, ICoreWebView2DOMContentLoadedEventArgs* args);
|
||||
HRESULT OnContainsFullScreenElementChanged(ICoreWebView2* sender, IUnknown* args);
|
||||
HRESULT OnWebMessageReceived(ICoreWebView2* sender, ICoreWebView2WebMessageReceivedEventArgs* args);
|
||||
HRESULT OnWebResourceRequested(ICoreWebView2* sender, ICoreWebView2WebResourceRequestedEventArgs* args);
|
||||
HRESULT OnAddScriptToExecuteOnDocumentedCreatedCompleted(HRESULT errorCode, LPCWSTR id);
|
||||
|
||||
HRESULT OnEnvironmentCreated(HRESULT result, ICoreWebView2Environment* environment);
|
||||
|
|
|
|||
|
|
@ -92,6 +92,37 @@ enum wxWebViewUserScriptInjectionTime
|
|||
wxWEBVIEW_INJECT_AT_DOCUMENT_END
|
||||
};
|
||||
|
||||
class WXDLLIMPEXP_WEBVIEW wxWebViewHandlerRequest
|
||||
{
|
||||
public:
|
||||
virtual ~wxWebViewHandlerRequest() { }
|
||||
virtual wxString GetRawURI() const = 0;
|
||||
virtual wxString GetURI() const { return GetRawURI(); }
|
||||
virtual wxInputStream* GetData() const = 0;
|
||||
virtual wxString GetDataString(const wxMBConv& conv = wxConvUTF8) const;
|
||||
virtual wxString GetMethod() const = 0;
|
||||
virtual wxString GetHeader(const wxString& name) const = 0;
|
||||
};
|
||||
|
||||
class WXDLLIMPEXP_WEBVIEW wxWebViewHandlerResponseData
|
||||
{
|
||||
public:
|
||||
virtual ~wxWebViewHandlerResponseData() { }
|
||||
virtual wxInputStream* GetStream() = 0;
|
||||
};
|
||||
|
||||
class WXDLLIMPEXP_WEBVIEW wxWebViewHandlerResponse
|
||||
{
|
||||
public:
|
||||
virtual ~wxWebViewHandlerResponse() { }
|
||||
virtual void SetStatus(int status) = 0;
|
||||
virtual void SetContentType(const wxString& contentType) = 0;
|
||||
virtual void SetHeader(const wxString& name, const wxString& value) = 0;
|
||||
virtual void Finish(wxSharedPtr<wxWebViewHandlerResponseData> data) = 0;
|
||||
virtual void Finish(const wxString& text, const wxMBConv& conv = wxConvUTF8);
|
||||
virtual void FinishWithError() = 0;
|
||||
};
|
||||
|
||||
//Base class for custom scheme handlers
|
||||
class WXDLLIMPEXP_WEBVIEW wxWebViewHandler
|
||||
{
|
||||
|
|
@ -100,12 +131,17 @@ public:
|
|||
: m_scheme(scheme), m_securityURL() {}
|
||||
virtual ~wxWebViewHandler() {}
|
||||
virtual wxString GetName() const { return m_scheme; }
|
||||
virtual wxFSFile* GetFile(const wxString &uri) = 0;
|
||||
virtual wxFSFile* GetFile(const wxString &uri);
|
||||
virtual void SetSecurityURL(const wxString& url) { m_securityURL = url; }
|
||||
virtual wxString GetSecurityURL() const { return m_securityURL; }
|
||||
virtual void SetVirtualHost(const wxString& host) { m_virtualHost = host; }
|
||||
virtual wxString GetVirtualHost() const;
|
||||
virtual void StartRequest(const wxWebViewHandlerRequest& request,
|
||||
wxSharedPtr<wxWebViewHandlerResponse> response);
|
||||
private:
|
||||
wxString m_scheme;
|
||||
wxString m_securityURL;
|
||||
wxString m_virtualHost;
|
||||
};
|
||||
|
||||
extern WXDLLIMPEXP_DATA_WEBVIEW(const char) wxWebViewNameStr[];
|
||||
|
|
|
|||
|
|
@ -161,6 +161,157 @@ enum wxWebViewIE_EmulationLevel
|
|||
wxWEBVIEWIE_EMU_IE11_FORCE = 11001
|
||||
};
|
||||
|
||||
/**
|
||||
@class wxWebViewHandlerRequest
|
||||
|
||||
A class giving access to various parameters of a webview request.
|
||||
|
||||
@since 3.3.0
|
||||
@library{wxwebview}
|
||||
@category{webview}
|
||||
|
||||
@see wxWebViewHandler::StartRequest()
|
||||
*/
|
||||
class WXDLLIMPEXP_WEBVIEW wxWebViewHandlerRequest
|
||||
{
|
||||
public:
|
||||
/**
|
||||
@return The unmodified url of the request.
|
||||
*/
|
||||
virtual wxString GetRawURI() const = 0;
|
||||
|
||||
/**
|
||||
@return The url of the request. Can be modified by the backend for
|
||||
compatibility.
|
||||
*/
|
||||
virtual wxString GetURI() const { return GetRawURI(); }
|
||||
|
||||
/**
|
||||
@return The body data of the request of @c null if nothing was posted.
|
||||
*/
|
||||
virtual wxInputStream* GetData() const = 0;
|
||||
|
||||
/**
|
||||
@return The body data of the request as a string. The returned string
|
||||
is empty if the supplied @c conv doesn't match the encoding.
|
||||
*/
|
||||
virtual wxString GetDataString(const wxMBConv& conv = wxConvUTF8) const;
|
||||
|
||||
/**
|
||||
@return The requests HTTP method (e.g. POST, GET, OPTIONS).
|
||||
*/
|
||||
virtual wxString GetMethod() const = 0;
|
||||
|
||||
/**
|
||||
Returns a header from the request or an empty string if the header
|
||||
could not be found.
|
||||
|
||||
@param name Name of the header field
|
||||
*/
|
||||
virtual wxString GetHeader(const wxString& name) const = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
@class wxWebViewHandlerResponseData
|
||||
|
||||
A class holding the response data. Stream must be available until
|
||||
this object is destroyed.
|
||||
|
||||
@since 3.3.0
|
||||
@library{wxwebview}
|
||||
@category{webview}
|
||||
|
||||
@see wxWebViewHandlerResponse::Finish(wxSharedPtr<wxWebViewHandlerResponseData>)
|
||||
*/
|
||||
class WXDLLIMPEXP_WEBVIEW wxWebViewHandlerResponseData
|
||||
{
|
||||
public:
|
||||
/**
|
||||
@return returns pointer to the stream.
|
||||
|
||||
@see wxWebViewHandlerResponse::Finish()
|
||||
*/
|
||||
virtual wxInputStream* GetStream() = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
@class wxWebViewHandlerResponse
|
||||
|
||||
A class giving access to various webview response parameters.
|
||||
|
||||
Usually a wxWebViewHandler() would set various parameters required
|
||||
for the response like HTTP status, various headers and must then
|
||||
call Finish() to complete the response or call FinishWithError() to
|
||||
abort the request.
|
||||
|
||||
@since 3.3.0
|
||||
@library{wxwebview}
|
||||
@category{webview}
|
||||
|
||||
@see wxWebViewHandler::StartRequest()
|
||||
*/
|
||||
class WXDLLIMPEXP_WEBVIEW wxWebViewHandlerResponse
|
||||
{
|
||||
public:
|
||||
/**
|
||||
Sets the status code of the response.
|
||||
|
||||
@param status HTTP status code
|
||||
*/
|
||||
virtual void SetStatus(int status) = 0;
|
||||
|
||||
/**
|
||||
Sets the MIME type of the response.
|
||||
|
||||
@param contentType MIME type of the response content
|
||||
*/
|
||||
virtual void SetContentType(const wxString& contentType) = 0;
|
||||
|
||||
/**
|
||||
Sets a response header which will be sent to the web view.
|
||||
|
||||
The header will be added if it hasn't been set before or replaced
|
||||
otherwise.
|
||||
|
||||
@param name
|
||||
Name of the header
|
||||
@param value
|
||||
String value of the header
|
||||
*/
|
||||
virtual void SetHeader(const wxString& name, const wxString& value) = 0;
|
||||
|
||||
/**
|
||||
Finishes the request with binary data.
|
||||
|
||||
@param data
|
||||
The data object will be dereferenced when the request is completed
|
||||
|
||||
@see Finish(const wxString&, const wxMBConv&)
|
||||
*/
|
||||
virtual void Finish(wxSharedPtr<wxWebViewHandlerResponseData> data) = 0;
|
||||
|
||||
/**
|
||||
Finishes the request with text data.
|
||||
|
||||
@param text
|
||||
Text content of the response (can be empty)
|
||||
@param conv
|
||||
Conversion used when sending the text in the response
|
||||
|
||||
@see Finish(wxSharedPtr<wxWebViewHandlerResponseData>)
|
||||
*/
|
||||
virtual void Finish(const wxString& text, const wxMBConv& conv = wxConvUTF8);
|
||||
|
||||
/**
|
||||
Finishes the request as an error.
|
||||
|
||||
This will notify that the request could not produce any data.
|
||||
|
||||
@see Finish()
|
||||
*/
|
||||
virtual void FinishWithError() = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
@class wxWebViewHistoryItem
|
||||
|
||||
|
|
@ -259,6 +410,10 @@ public:
|
|||
The base class for handling custom schemes in wxWebView, for example to
|
||||
allow virtual file system support.
|
||||
|
||||
A new handler should either implement GetFile() or if a more detailed
|
||||
request handling is required (access to headers, post data)
|
||||
StartRequest() has to be implemented.
|
||||
|
||||
@since 2.9.3
|
||||
@library{wxwebview}
|
||||
@category{webview}
|
||||
|
|
@ -277,7 +432,7 @@ public:
|
|||
/**
|
||||
@return A pointer to the file represented by @c uri.
|
||||
*/
|
||||
virtual wxFSFile* GetFile(const wxString &uri) = 0;
|
||||
virtual wxFSFile* GetFile(const wxString &uri);
|
||||
|
||||
/**
|
||||
@return The name of the scheme, as passed to the constructor.
|
||||
|
|
@ -297,6 +452,81 @@ public:
|
|||
@since 3.1.5
|
||||
*/
|
||||
virtual wxString GetSecurityURL() const;
|
||||
|
||||
/**
|
||||
When using the edge backend handler urls are https urls with a
|
||||
virtual host. As default @c name.wxsite is used as the virtual hostname.
|
||||
If you customize this host, use a non existing site (ideally a reserved
|
||||
subdomain of a domain you control). If @c localassests.domain.example is
|
||||
used the handlers content will be available under
|
||||
%https://localassets.domain.example/
|
||||
|
||||
This has to be set @b before registering the handler via
|
||||
wxWebView::RegisterHandler().
|
||||
|
||||
@since 3.3.0
|
||||
*/
|
||||
virtual void SetVirtualHost(const wxString& host);
|
||||
|
||||
/**
|
||||
@return The virtual host of this handler
|
||||
|
||||
@see SetVirtualHost()
|
||||
@since 3.3.0
|
||||
*/
|
||||
virtual wxString GetVirtualHost() const;
|
||||
|
||||
/**
|
||||
Implementing this method allows for more control over requests from
|
||||
the backend then GetFile(). More details of the request are available
|
||||
from the request object which allows access to URL, method, postdata
|
||||
and headers.
|
||||
|
||||
A response can be send via the response object. The response does not
|
||||
have to be finished from this method and it's possible to be finished
|
||||
asynchronously via wxWebViewHandlerResponse::Finish().
|
||||
|
||||
The following pseudo code demonstrates a typical implementation:
|
||||
@code
|
||||
void StartRequest(const wxWebViewHandlerRequest& request,
|
||||
wxSharedPtr<wxWebViewHandlerResponse> response) wxOVERRIDE
|
||||
{
|
||||
// Set common headers allowing access from XMLHTTPRequests()
|
||||
response->SetHeader("Access-Control-Allow-Origin", "*");
|
||||
response->SetHeader("Access-Control-Allow-Headers", "*");
|
||||
|
||||
// Handle options request
|
||||
if (request.GetMethod().IsSameAs("options", false))
|
||||
{
|
||||
response->Finish("");
|
||||
return;
|
||||
}
|
||||
|
||||
// Check the post data type
|
||||
if (!request.GetHeader("Content-Type").StartsWith("application/json"))
|
||||
{
|
||||
response->FinishWithError();
|
||||
return;
|
||||
}
|
||||
|
||||
// Process input data
|
||||
wxString postData = request.GetDataString();
|
||||
|
||||
...
|
||||
|
||||
// Send result
|
||||
response->SetContentType("application/json");
|
||||
response->Finish("{ result: true }");
|
||||
}
|
||||
@endcode
|
||||
|
||||
@note This is only usesd by macOS and the Edge backend.
|
||||
|
||||
@see GetFile()
|
||||
@since 3.3.0
|
||||
*/
|
||||
virtual void StartRequest(const wxWebViewHandlerRequest& request,
|
||||
wxSharedPtr<wxWebViewHandlerResponse> response);
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -341,7 +571,9 @@ public:
|
|||
<a href="https://docs.microsoft.com/en-us/microsoft-edge/hosting/webview2">Edge WebView2</a>.
|
||||
It is available for Windows 7 and newer.
|
||||
|
||||
This backend does not support custom schemes and virtual file systems.
|
||||
This backend does not support custom schemes. When using handlers see
|
||||
wxWebViewHandler::SetVirtualHost() for more details on how to access
|
||||
handler provided URLs.
|
||||
|
||||
This backend is not enabled by default, to build it follow these steps:
|
||||
- Visual Studio 2015 or newer, or GCC/Clang with c++11 is required
|
||||
|
|
@ -440,7 +672,8 @@ public:
|
|||
wxWebView supports the registering of custom scheme handlers, for example
|
||||
@c file or @c http. To do this create a new class which inherits from
|
||||
wxWebViewHandler, where wxWebHandler::GetFile() returns a pointer to a
|
||||
wxFSFile which represents the given url. You can then register your handler
|
||||
wxFSFile which represents the given url or wxWebHandler::StartRequest() for
|
||||
more complex requests. You can then register your handler
|
||||
with RegisterHandler() it will be called for all pages and resources.
|
||||
|
||||
wxWebViewFSHandler is provided to access the virtual file system encapsulated by
|
||||
|
|
@ -708,6 +941,12 @@ public:
|
|||
@note On macOS in order to use handlers two-step creation has to be
|
||||
used and RegisterHandler() has to be called before Create().
|
||||
With the other backends it has to be called after Create().
|
||||
|
||||
@note The Edge backend does not support custom schemes, but the
|
||||
handler is available as a virtual host under
|
||||
%https://scheme.wxsite to customize this virtual host call
|
||||
wxWebViewHandler::SetVirtualHost() before registering the
|
||||
handler.
|
||||
*/
|
||||
virtual void RegisterHandler(wxSharedPtr<wxWebViewHandler> handler) = 0;
|
||||
|
||||
|
|
|
|||
55
samples/webview/handler_advanced.html
Normal file
55
samples/webview/handler_advanced.html
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
<head>
|
||||
<title>Advanced Handler Sample</title>
|
||||
|
||||
<style>
|
||||
.mono {
|
||||
font-family: monospace;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
function sendRequest() {
|
||||
let url = document.getElementById("request_url").value;
|
||||
let request_content_type = document.getElementById("request_content_type").value;
|
||||
let request_data = document.getElementById("request_data").value;
|
||||
console.log("clicked");
|
||||
|
||||
const req = new XMLHttpRequest();
|
||||
req.addEventListener("load", (ev) => {
|
||||
document.getElementById("response_response").value = req.responseText;
|
||||
});
|
||||
req.open("POST", url);
|
||||
req.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
|
||||
req.send(request_data);
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<p>
|
||||
This sample demonstrates how to use <i>wxWebViewHandler::StartRequest()</i>
|
||||
to enable advanced requests from html and javascript in the web view.
|
||||
</p>
|
||||
|
||||
Request URL<br />
|
||||
<input id="request_url" size="40" value=""><br />
|
||||
Request content type<br />
|
||||
<input id="request_content_type" size="40" value="application/json"><br />
|
||||
Request Data<br />
|
||||
<textarea class="mono" cols="60" rows="8" id="request_data">{ param1: "wxwidgets", param2: "webview" }</textarea>
|
||||
<br />
|
||||
<button onclick="sendRequest()">Start request</button><br />
|
||||
Response Data<br />
|
||||
<textarea class="mono" cols="60" rows="8" id="response_response"></textarea>
|
||||
|
||||
<script>
|
||||
// init request_url
|
||||
let postURL;
|
||||
if (navigator.userAgent.indexOf("Edg") > 0)
|
||||
postURL = "https://wxpost.wxsite//main/test/1";
|
||||
else
|
||||
postURL = "wxpost://main/test/1";
|
||||
|
||||
document.getElementById("request_url").value = postURL;
|
||||
</script>
|
||||
</body>
|
||||
|
|
@ -17,4 +17,10 @@
|
|||
</if>
|
||||
</exe>
|
||||
|
||||
<wx-data id="data">
|
||||
<files>
|
||||
handler_advanced.html
|
||||
</files>
|
||||
</wx-data>
|
||||
|
||||
</makefile>
|
||||
|
|
|
|||
|
|
@ -164,6 +164,7 @@ public:
|
|||
void OnSelectAll(wxCommandEvent& evt);
|
||||
void OnLoadScheme(wxCommandEvent& evt);
|
||||
void OnUseMemoryFS(wxCommandEvent& evt);
|
||||
void OnLoadAdvancedHandler(wxCommandEvent& evt);
|
||||
void OnFind(wxCommandEvent& evt);
|
||||
void OnFindDone(wxCommandEvent& evt);
|
||||
void OnFindText(wxCommandEvent& evt);
|
||||
|
|
@ -257,6 +258,40 @@ public:
|
|||
SourceViewDialog(wxWindow* parent, wxString source);
|
||||
};
|
||||
|
||||
// AdvancedWebViewHandler is a sample handler used by handler_advanced.html
|
||||
// to show a sample implementation of wxWebViewHandler::StartRequest().
|
||||
// see the documentation for additional details.
|
||||
class AdvancedWebViewHandler: public wxWebViewHandler
|
||||
{
|
||||
public:
|
||||
AdvancedWebViewHandler():
|
||||
wxWebViewHandler("wxpost")
|
||||
{ }
|
||||
|
||||
virtual void StartRequest(const wxWebViewHandlerRequest& request,
|
||||
wxSharedPtr<wxWebViewHandlerResponse> response) wxOVERRIDE
|
||||
{
|
||||
response->SetHeader("Access-Control-Allow-Origin", "*");
|
||||
response->SetHeader("Access-Control-Allow-Headers", "*");
|
||||
|
||||
// Handle options request
|
||||
if (request.GetMethod().IsSameAs("options", false))
|
||||
{
|
||||
response->Finish("");
|
||||
return;
|
||||
}
|
||||
|
||||
response->SetContentType("application/json");
|
||||
response->Finish(
|
||||
wxString::Format(
|
||||
"{\n contentType: \"%s\",\n method: \"%s\",\n data: \"%s\"\n}",
|
||||
request.GetHeader("Content-Type"),
|
||||
request.GetMethod(),
|
||||
request.GetDataString()
|
||||
));
|
||||
}
|
||||
};
|
||||
|
||||
wxIMPLEMENT_APP(WebApp);
|
||||
|
||||
// ============================================================================
|
||||
|
|
@ -383,6 +418,7 @@ WebFrame::WebFrame(const wxString& url) :
|
|||
// With WKWebView handlers need to be registered before creation
|
||||
m_browser->RegisterHandler(wxSharedPtr<wxWebViewHandler>(new wxWebViewArchiveHandler("wxfs")));
|
||||
m_browser->RegisterHandler(wxSharedPtr<wxWebViewHandler>(new wxWebViewFSHandler("memory")));
|
||||
m_browser->RegisterHandler(wxSharedPtr<wxWebViewHandler>(new AdvancedWebViewHandler()));
|
||||
#endif
|
||||
m_browser->Create(this, wxID_ANY, url, wxDefaultPosition, wxDefaultSize);
|
||||
topsizer->Add(m_browser, wxSizerFlags().Expand().Proportion(1));
|
||||
|
|
@ -397,6 +433,7 @@ WebFrame::WebFrame(const wxString& url) :
|
|||
m_browser->RegisterHandler(wxSharedPtr<wxWebViewHandler>(new wxWebViewArchiveHandler("wxfs")));
|
||||
//And the memory: file system
|
||||
m_browser->RegisterHandler(wxSharedPtr<wxWebViewHandler>(new wxWebViewFSHandler("memory")));
|
||||
m_browser->RegisterHandler(wxSharedPtr<wxWebViewHandler>(new AdvancedWebViewHandler()));
|
||||
#endif
|
||||
if (!m_browser->AddScriptMessageHandler("wx"))
|
||||
wxLogError("Could not add script message handler");
|
||||
|
|
@ -492,8 +529,11 @@ WebFrame::WebFrame(const wxString& url) :
|
|||
|
||||
editmenu->AppendSubMenu(selection, "Selection");
|
||||
|
||||
wxMenuItem* loadscheme = m_tools_menu->Append(wxID_ANY, _("Custom Scheme Example"));
|
||||
wxMenuItem* usememoryfs = m_tools_menu->Append(wxID_ANY, _("Memory File System Example"));
|
||||
wxMenu* handlers = new wxMenu();
|
||||
wxMenuItem* loadscheme = handlers->Append(wxID_ANY, _("Custom Scheme"));
|
||||
wxMenuItem* usememoryfs = handlers->Append(wxID_ANY, _("Memory File System"));
|
||||
wxMenuItem* advancedHandler = handlers->Append(wxID_ANY, _("Advanced Handler"));
|
||||
m_tools_menu->AppendSubMenu(handlers, _("Handler Examples"));
|
||||
|
||||
m_context_menu = m_tools_menu->AppendCheckItem(wxID_ANY, _("Enable Context Menu"));
|
||||
m_dev_tools = m_tools_menu->AppendCheckItem(wxID_ANY, _("Enable Dev Tools"));
|
||||
|
|
@ -591,6 +631,7 @@ WebFrame::WebFrame(const wxString& url) :
|
|||
Bind(wxEVT_MENU, &WebFrame::OnSelectAll, this, selectall->GetId());
|
||||
Bind(wxEVT_MENU, &WebFrame::OnLoadScheme, this, loadscheme->GetId());
|
||||
Bind(wxEVT_MENU, &WebFrame::OnUseMemoryFS, this, usememoryfs->GetId());
|
||||
Bind(wxEVT_MENU, &WebFrame::OnLoadAdvancedHandler, this, advancedHandler->GetId());
|
||||
Bind(wxEVT_MENU, &WebFrame::OnFind, this, m_find->GetId());
|
||||
Bind(wxEVT_MENU, &WebFrame::OnEnableContextMenu, this, m_context_menu->GetId());
|
||||
Bind(wxEVT_MENU, &WebFrame::OnEnableDevTools, this, m_dev_tools->GetId());
|
||||
|
|
@ -748,6 +789,17 @@ void WebFrame::OnUseMemoryFS(wxCommandEvent& WXUNUSED(evt))
|
|||
m_browser->LoadURL("memory:page1.htm");
|
||||
}
|
||||
|
||||
void WebFrame::OnLoadAdvancedHandler(wxCommandEvent& WXUNUSED(evt))
|
||||
{
|
||||
wxPathList pathlist;
|
||||
pathlist.Add(".");
|
||||
pathlist.Add("..");
|
||||
|
||||
wxString path = wxFileName(pathlist.FindValidPath("handler_advanced.html")).GetAbsolutePath();
|
||||
path = "file://" + path;
|
||||
m_browser->LoadURL(path);
|
||||
}
|
||||
|
||||
void WebFrame::OnEnableContextMenu(wxCommandEvent& evt)
|
||||
{
|
||||
m_browser->EnableContextMenu(evt.IsChecked());
|
||||
|
|
|
|||
|
|
@ -13,6 +13,8 @@
|
|||
|
||||
|
||||
#include "wx/webview.h"
|
||||
#include "wx/filesys.h"
|
||||
#include "wx/mstream.h"
|
||||
|
||||
#if defined(__WXOSX__)
|
||||
#include "wx/osx/webview_webkit.h"
|
||||
|
|
@ -52,6 +54,92 @@ wxDEFINE_EVENT( wxEVT_WEBVIEW_FULLSCREEN_CHANGED, wxWebViewEvent);
|
|||
wxDEFINE_EVENT( wxEVT_WEBVIEW_SCRIPT_MESSAGE_RECEIVED, wxWebViewEvent);
|
||||
wxDEFINE_EVENT( wxEVT_WEBVIEW_SCRIPT_RESULT, wxWebViewEvent);
|
||||
|
||||
// wxWebViewHandlerRequest
|
||||
wxString wxWebViewHandlerRequest::GetDataString(const wxMBConv& conv) const
|
||||
{
|
||||
wxInputStream* data = GetData();
|
||||
if (!data)
|
||||
return wxString();
|
||||
|
||||
size_t length = data->GetLength();
|
||||
wxMemoryBuffer buffer;
|
||||
data->ReadAll(buffer.GetWriteBuf(length), length);
|
||||
wxString dataStr(static_cast<const char*>(buffer.GetData()), conv, length);
|
||||
return dataStr;
|
||||
}
|
||||
|
||||
// wxWebViewHandlerResponseDataStream
|
||||
class wxWebViewHandlerResponseDataString : public wxWebViewHandlerResponseData
|
||||
{
|
||||
public:
|
||||
wxWebViewHandlerResponseDataString(const wxCharBuffer& data): m_data(data)
|
||||
{
|
||||
m_stream = new wxMemoryInputStream(m_data, m_data.length());
|
||||
}
|
||||
|
||||
~wxWebViewHandlerResponseDataString() { delete m_stream; }
|
||||
|
||||
virtual wxInputStream* GetStream() wxOVERRIDE
|
||||
{
|
||||
return m_stream;
|
||||
}
|
||||
|
||||
wxCharBuffer m_data;
|
||||
wxInputStream* m_stream;
|
||||
};
|
||||
|
||||
// wxWebViewHandlerResponse
|
||||
void wxWebViewHandlerResponse::Finish(const wxString& text,
|
||||
const wxMBConv& conv)
|
||||
{
|
||||
Finish(wxSharedPtr<wxWebViewHandlerResponseData>(
|
||||
new wxWebViewHandlerResponseDataString(text.mb_str(conv))));
|
||||
}
|
||||
|
||||
// wxWebViewHandlerResponseDataFile
|
||||
class wxWebViewHandlerResponseDataFile : public wxWebViewHandlerResponseData
|
||||
{
|
||||
public:
|
||||
wxWebViewHandlerResponseDataFile(wxFSFile* file): m_file(file) { }
|
||||
|
||||
~wxWebViewHandlerResponseDataFile() { delete m_file; }
|
||||
|
||||
virtual wxInputStream* GetStream() wxOVERRIDE
|
||||
{ return m_file->GetStream(); }
|
||||
|
||||
wxFSFile* m_file;
|
||||
};
|
||||
|
||||
// wxWebViewHandler
|
||||
wxString wxWebViewHandler::GetVirtualHost() const
|
||||
{
|
||||
if (m_virtualHost.empty())
|
||||
return GetName() + ".wxsite";
|
||||
else
|
||||
return m_virtualHost;
|
||||
}
|
||||
|
||||
wxFSFile* wxWebViewHandler::GetFile(const wxString& WXUNUSED(uri))
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void wxWebViewHandler::StartRequest(const wxWebViewHandlerRequest& request,
|
||||
wxSharedPtr<wxWebViewHandlerResponse> response)
|
||||
{
|
||||
wxFSFile* file = GetFile(request.GetURI());
|
||||
if (file)
|
||||
{
|
||||
response->SetContentType(file->GetMimeType());
|
||||
response->Finish(wxSharedPtr<wxWebViewHandlerResponseData>(
|
||||
new wxWebViewHandlerResponseDataFile(file)));
|
||||
}
|
||||
else
|
||||
response->FinishWithError();
|
||||
}
|
||||
|
||||
// wxWebView
|
||||
|
||||
wxStringWebViewFactoryMap wxWebView::m_factoryMap;
|
||||
|
||||
wxWebViewZoom wxWebView::GetZoom() const
|
||||
|
|
|
|||
|
|
@ -16,15 +16,18 @@
|
|||
|
||||
#include "wx/filename.h"
|
||||
#include "wx/module.h"
|
||||
#include "wx/mstream.h"
|
||||
#include "wx/log.h"
|
||||
#include "wx/stdpaths.h"
|
||||
#include "wx/thread.h"
|
||||
#include "wx/tokenzr.h"
|
||||
#include "wx/uri.h"
|
||||
#include "wx/private/jsscriptwrapper.h"
|
||||
#include "wx/private/json.h"
|
||||
#include "wx/msw/private.h"
|
||||
#include "wx/msw/private/cotaskmemptr.h"
|
||||
#include "wx/msw/private/webview_edge.h"
|
||||
#include "wx/msw/private/comstream.h"
|
||||
|
||||
#ifdef __VISUALC__
|
||||
#include <wrl/event.h>
|
||||
|
|
@ -64,6 +67,185 @@ GetAvailableCoreWebView2BrowserVersionString_t wxGetAvailableCoreWebView2Browser
|
|||
wxDynamicLibrary wxWebViewEdgeImpl::ms_loaderDll;
|
||||
#endif // wxUSE_WEBVIEW_EDGE_STATIC
|
||||
|
||||
class wxWebViewEdgeHandlerRequest : public wxWebViewHandlerRequest
|
||||
{
|
||||
public:
|
||||
wxWebViewEdgeHandlerRequest(ICoreWebView2WebResourceRequest* request):
|
||||
m_request(request),
|
||||
m_handler(NULL),
|
||||
m_dataStream(NULL)
|
||||
{ }
|
||||
|
||||
~wxWebViewEdgeHandlerRequest()
|
||||
{
|
||||
wxDELETE(m_dataStream);
|
||||
}
|
||||
|
||||
void SetHandler(wxWebViewHandler* handler) { m_handler = handler; }
|
||||
|
||||
virtual wxString GetRawURI() const wxOVERRIDE
|
||||
{
|
||||
wxCoTaskMemPtr<wchar_t> uri;
|
||||
if (SUCCEEDED(m_request->get_Uri(&uri)))
|
||||
return wxString(uri);
|
||||
else
|
||||
return wxString();
|
||||
}
|
||||
|
||||
virtual wxString GetURI() const wxOVERRIDE
|
||||
{
|
||||
wxURI rawURI(GetRawURI());
|
||||
wxString path = rawURI.GetPath();
|
||||
if (!path.empty()) // Remove / in front
|
||||
path.erase(0, 1);
|
||||
wxString uri = wxString::Format("%s:%s", m_handler->GetName(), path);
|
||||
return uri;
|
||||
}
|
||||
|
||||
virtual wxInputStream* GetData() const wxOVERRIDE
|
||||
{
|
||||
if (!m_dataStream)
|
||||
{
|
||||
wxCOMPtr<IStream> dataStream;
|
||||
if (SUCCEEDED(m_request->get_Content(&dataStream)) && dataStream)
|
||||
{
|
||||
ULARGE_INTEGER size;
|
||||
LARGE_INTEGER pos;
|
||||
pos.QuadPart = 0;
|
||||
HRESULT hr = dataStream->Seek(pos, STREAM_SEEK_END, &size);
|
||||
if (FAILED(hr))
|
||||
return NULL;
|
||||
hr = dataStream->Seek(pos, STREAM_SEEK_SET, NULL);
|
||||
if (FAILED(hr))
|
||||
return NULL;
|
||||
hr = dataStream->Read(m_data.GetWriteBuf(size.QuadPart), size.QuadPart, NULL);
|
||||
if (FAILED(hr))
|
||||
return NULL;
|
||||
m_dataStream = new wxMemoryInputStream(m_data.GetData(), size.QuadPart);
|
||||
}
|
||||
}
|
||||
|
||||
return m_dataStream;
|
||||
}
|
||||
|
||||
virtual wxString GetMethod() const wxOVERRIDE
|
||||
{
|
||||
wxCoTaskMemPtr<wchar_t> method;
|
||||
if (SUCCEEDED(m_request->get_Method(&method)))
|
||||
return wxString(method);
|
||||
else
|
||||
return wxString();
|
||||
}
|
||||
|
||||
virtual wxString GetHeader(const wxString& name) const wxOVERRIDE
|
||||
{
|
||||
wxCOMPtr<ICoreWebView2HttpRequestHeaders> headers;
|
||||
if (SUCCEEDED(m_request->get_Headers(&headers)))
|
||||
{
|
||||
wxCoTaskMemPtr<wchar_t> value;
|
||||
if (SUCCEEDED(headers->GetHeader(name.wc_str(), &value)))
|
||||
return wxString(value);
|
||||
}
|
||||
|
||||
return wxString();
|
||||
}
|
||||
|
||||
wxCOMPtr<ICoreWebView2WebResourceRequest> m_request;
|
||||
wxWebViewHandler* m_handler;
|
||||
mutable wxInputStream* m_dataStream;
|
||||
mutable wxMemoryBuffer m_data;
|
||||
};
|
||||
|
||||
class wxWebViewEdgeHandlerResponseStream : public wxCOMInputStreamAdapter
|
||||
{
|
||||
public:
|
||||
wxWebViewEdgeHandlerResponseStream(wxSharedPtr<wxWebViewHandlerResponseData> data):
|
||||
m_data(data),
|
||||
wxCOMInputStreamAdapter(data->GetStream())
|
||||
{ }
|
||||
|
||||
wxSharedPtr<wxWebViewHandlerResponseData> m_data;
|
||||
};
|
||||
|
||||
class wxWebViewEdgeHandlerResponse : public wxWebViewHandlerResponse
|
||||
{
|
||||
public:
|
||||
wxWebViewEdgeHandlerResponse(ICoreWebView2WebResourceRequestedEventArgs* args, ICoreWebView2Environment* env):
|
||||
m_args(args),
|
||||
m_env(env)
|
||||
{
|
||||
m_args->GetDeferral(&m_deferral);
|
||||
|
||||
// Create response
|
||||
HRESULT hr = m_env->CreateWebResourceResponse(NULL, 200, NULL, NULL, &m_response);
|
||||
if (FAILED(hr))
|
||||
wxLogApiError("CreateWebResourceResponse", hr);
|
||||
}
|
||||
|
||||
void SetReason(const wxString& reason)
|
||||
{ m_response->put_ReasonPhrase(reason.wc_str()); }
|
||||
|
||||
virtual void SetStatus(int status) wxOVERRIDE
|
||||
{ m_response->put_StatusCode(status); }
|
||||
|
||||
virtual void SetContentType(const wxString& contentType) wxOVERRIDE
|
||||
{ SetHeader("Content-Type", contentType); }
|
||||
|
||||
virtual void SetHeader(const wxString& name, const wxString& value) wxOVERRIDE
|
||||
{
|
||||
wxCOMPtr<ICoreWebView2HttpResponseHeaders> headers;
|
||||
if (SUCCEEDED(m_response->get_Headers(&headers)))
|
||||
headers->AppendHeader(name.wc_str(), value.wc_str());
|
||||
}
|
||||
|
||||
bool SendResponse()
|
||||
{
|
||||
// put response
|
||||
HRESULT hr = m_args->put_Response(m_response);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
wxLogApiError("put_Response", hr);
|
||||
return false;
|
||||
}
|
||||
// Mark event as completed
|
||||
hr = m_deferral->Complete();
|
||||
if (FAILED(hr))
|
||||
{
|
||||
wxLogApiError("deferral->Complete()", hr);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual void Finish(wxSharedPtr<wxWebViewHandlerResponseData> data) wxOVERRIDE
|
||||
{
|
||||
SetReason("OK");
|
||||
// put content
|
||||
if (data)
|
||||
{
|
||||
IStream* stream = new wxWebViewEdgeHandlerResponseStream(data);
|
||||
HRESULT hr = m_response->put_Content(stream);
|
||||
if (FAILED(hr))
|
||||
wxLogApiError("put_Content", hr);
|
||||
}
|
||||
SendResponse();
|
||||
}
|
||||
|
||||
virtual void FinishWithError() wxOVERRIDE
|
||||
{
|
||||
SetStatus(500);
|
||||
SetReason("Error");
|
||||
SendResponse();
|
||||
}
|
||||
|
||||
int m_status;
|
||||
wxCOMPtr<ICoreWebView2WebResourceResponse> m_response;
|
||||
wxCOMPtr<ICoreWebView2Deferral> m_deferral;
|
||||
wxCOMPtr<ICoreWebView2Environment> m_env;
|
||||
wxCOMPtr<ICoreWebView2WebResourceRequestedEventArgs> m_args;
|
||||
};
|
||||
|
||||
wxString wxWebViewEdgeImpl::ms_browserExecutableDir;
|
||||
|
||||
wxWebViewEdgeImpl::wxWebViewEdgeImpl(wxWebViewEdge* webview):
|
||||
|
|
@ -86,6 +268,7 @@ wxWebViewEdgeImpl::~wxWebViewEdgeImpl()
|
|||
m_webView->remove_DOMContentLoaded(m_DOMContentLoadedToken);
|
||||
m_webView->remove_ContainsFullScreenElementChanged(m_containsFullScreenElementChangedToken);
|
||||
m_webView->remove_WebMessageReceived(m_webMessageReceivedToken);
|
||||
m_webView->remove_WebResourceRequested(m_webResourceRequestedToken);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -370,6 +553,28 @@ wxWebViewEdgeImpl::OnWebMessageReceived(ICoreWebView2* WXUNUSED(sender),
|
|||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT wxWebViewEdgeImpl::OnWebResourceRequested(ICoreWebView2* WXUNUSED(sender), ICoreWebView2WebResourceRequestedEventArgs* args)
|
||||
{
|
||||
wxCOMPtr<ICoreWebView2WebResourceRequest> apiRequest;
|
||||
HRESULT hr = args->get_Request(&apiRequest);
|
||||
if (FAILED(hr))
|
||||
return hr;
|
||||
wxWebViewEdgeHandlerRequest request(apiRequest);
|
||||
|
||||
// Find handler
|
||||
wxURI uri(request.GetRawURI());
|
||||
if (!uri.HasServer())
|
||||
return E_INVALIDARG;
|
||||
wxSharedPtr<wxWebViewHandler> handler = m_handlers[uri.GetServer()];
|
||||
if (!handler)
|
||||
return E_INVALIDARG;
|
||||
request.SetHandler(handler.get());
|
||||
|
||||
wxSharedPtr<wxWebViewHandlerResponse> resp(new wxWebViewEdgeHandlerResponse(args, m_webViewEnvironment));
|
||||
handler->StartRequest(request, resp);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT wxWebViewEdgeImpl::OnWebViewCreated(HRESULT result, ICoreWebView2Controller* webViewController)
|
||||
{
|
||||
if (FAILED(result))
|
||||
|
|
@ -431,6 +636,17 @@ HRESULT wxWebViewEdgeImpl::OnWebViewCreated(HRESULT result, ICoreWebView2Control
|
|||
Callback<ICoreWebView2WebMessageReceivedEventHandler>(
|
||||
this, &wxWebViewEdgeImpl::OnWebMessageReceived).Get(),
|
||||
&m_webMessageReceivedToken);
|
||||
m_webView->add_WebResourceRequested(
|
||||
Callback<ICoreWebView2WebResourceRequestedEventHandler>(
|
||||
this, &wxWebViewEdgeImpl::OnWebResourceRequested).Get(),
|
||||
&m_webResourceRequestedToken);
|
||||
|
||||
// Register handlers
|
||||
for (wxStringToWebHandlerMap::iterator it = m_handlers.begin(); it != m_handlers.end(); it++)
|
||||
{
|
||||
wxString filterURI = wxString::Format("*://%s/*", it->first);
|
||||
m_webView->AddWebResourceRequestedFilter(filterURI.wc_str(), COREWEBVIEW2_WEB_RESOURCE_CONTEXT_ALL);
|
||||
}
|
||||
|
||||
if (m_pendingContextMenuEnabled != -1)
|
||||
{
|
||||
|
|
@ -591,7 +807,23 @@ void wxWebViewEdge::LoadURL(const wxString& url)
|
|||
m_impl->m_pendingURL = url;
|
||||
return;
|
||||
}
|
||||
HRESULT hr = m_impl->m_webView->Navigate(url.wc_str());
|
||||
wxString navURL = url;
|
||||
if (!m_impl->m_handlers.empty())
|
||||
{
|
||||
// Emulate custom protocol support for LoadURL()
|
||||
for (wxStringToWebHandlerMap::iterator it = m_impl->m_handlers.begin();
|
||||
it != m_impl->m_handlers.end(); it++)
|
||||
{
|
||||
wxString scheme = it->second->GetName() + ":";
|
||||
if (navURL.StartsWith(scheme))
|
||||
{
|
||||
navURL.Remove(0, scheme.Length());
|
||||
navURL.insert(0, "https://" + it->second->GetVirtualHost() + "/");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
HRESULT hr = m_impl->m_webView->Navigate(navURL.wc_str());
|
||||
if (FAILED(hr))
|
||||
wxLogApiError("WebView2::Navigate", hr);
|
||||
}
|
||||
|
|
@ -949,10 +1181,16 @@ void wxWebViewEdge::RemoveAllUserScripts()
|
|||
m_impl->m_userScriptIds.clear();
|
||||
}
|
||||
|
||||
void wxWebViewEdge::RegisterHandler(wxSharedPtr<wxWebViewHandler> WXUNUSED(handler))
|
||||
void wxWebViewEdge::RegisterHandler(wxSharedPtr<wxWebViewHandler> handler)
|
||||
{
|
||||
// TODO: could maybe be implemented via IWebView2WebView5::add_WebResourceRequested
|
||||
wxLogDebug("Registering handlers is not supported");
|
||||
wxString handlerHost = handler->GetVirtualHost();
|
||||
m_impl->m_handlers[handlerHost] = handler;
|
||||
|
||||
if (m_impl->m_webView)
|
||||
{
|
||||
wxString filterURI = wxString::Format("*://%s/*", handlerHost);
|
||||
m_impl->m_webView->AddWebResourceRequestedFilter(filterURI.wc_str(), COREWEBVIEW2_WEB_RESOURCE_CONTEXT_ALL);
|
||||
}
|
||||
}
|
||||
|
||||
void wxWebViewEdge::DoSetPage(const wxString& html, const wxString& WXUNUSED(baseUrl))
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@
|
|||
#include "wx/hashmap.h"
|
||||
#include "wx/filesys.h"
|
||||
#include "wx/msgdlg.h"
|
||||
#include "wx/mstream.h"
|
||||
#include "wx/textdlg.h"
|
||||
#include "wx/filedlg.h"
|
||||
|
||||
|
|
@ -847,6 +848,107 @@ wxString nsErrorToWxHtmlError(NSError* error, wxWebViewNavigationError* out)
|
|||
@end
|
||||
|
||||
#if __MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_13
|
||||
|
||||
class wxWebViewWebKitHandlerRequest: public wxWebViewHandlerRequest
|
||||
{
|
||||
public:
|
||||
wxWebViewWebKitHandlerRequest(NSURLRequest* request):
|
||||
m_data(NULL),
|
||||
m_request(request)
|
||||
{ }
|
||||
|
||||
~wxWebViewWebKitHandlerRequest()
|
||||
{ wxDELETE(m_data); }
|
||||
|
||||
virtual wxString GetRawURI() const wxOVERRIDE
|
||||
{ return wxCFStringRef::AsString(m_request.URL.absoluteString); }
|
||||
|
||||
virtual wxInputStream* GetData() const wxOVERRIDE
|
||||
{
|
||||
if (!m_data && m_request.HTTPBody)
|
||||
m_data = new wxMemoryInputStream(m_request.HTTPBody.bytes, m_request.HTTPBody.length);
|
||||
|
||||
return m_data;
|
||||
}
|
||||
|
||||
virtual wxString GetMethod() const wxOVERRIDE
|
||||
{ return wxCFStringRef::AsString(m_request.HTTPMethod); }
|
||||
|
||||
virtual wxString GetHeader(const wxString& name) const wxOVERRIDE
|
||||
{
|
||||
return wxCFStringRef::AsString(
|
||||
[m_request valueForHTTPHeaderField:wxCFStringRef(name).AsNSString()]);
|
||||
}
|
||||
|
||||
mutable wxInputStream* m_data;
|
||||
NSURLRequest* m_request;
|
||||
};
|
||||
|
||||
class API_AVAILABLE(macos(10.13)) wxWebViewWebkitHandlerResponse: public wxWebViewHandlerResponse
|
||||
{
|
||||
public:
|
||||
wxWebViewWebkitHandlerResponse(id<WKURLSchemeTask> task):
|
||||
m_status(200),
|
||||
m_task([task retain])
|
||||
{
|
||||
m_headers = [[NSMutableDictionary alloc] init];
|
||||
}
|
||||
|
||||
~wxWebViewWebkitHandlerResponse()
|
||||
{
|
||||
[m_headers release];
|
||||
[m_task release];
|
||||
}
|
||||
|
||||
virtual void SetStatus(int status) wxOVERRIDE
|
||||
{ m_status = status; }
|
||||
|
||||
virtual void SetContentType(const wxString& contentType) wxOVERRIDE
|
||||
{ SetHeader("Content-Type", contentType); }
|
||||
|
||||
virtual void SetHeader(const wxString& name, const wxString& value) wxOVERRIDE
|
||||
{
|
||||
[m_headers setValue:wxCFStringRef(value).AsNSString()
|
||||
forKey:wxCFStringRef(name).AsNSString()];
|
||||
}
|
||||
|
||||
virtual void Finish(wxSharedPtr<wxWebViewHandlerResponseData> data) wxOVERRIDE
|
||||
{
|
||||
m_data = data;
|
||||
wxInputStream* stream = data->GetStream();
|
||||
size_t length = stream->GetLength();
|
||||
NSHTTPURLResponse* response = [[NSHTTPURLResponse alloc] initWithURL:m_task.request.URL
|
||||
statusCode:m_status
|
||||
HTTPVersion:nil
|
||||
headerFields:m_headers];
|
||||
[m_task didReceiveResponse:response];
|
||||
[response release];
|
||||
|
||||
//Load the data, we malloc it so it is tidied up properly
|
||||
void* buffer = malloc(length);
|
||||
stream->Read(buffer, length);
|
||||
NSData *taskData = [[NSData alloc] initWithBytesNoCopy:buffer length:length];
|
||||
[m_task didReceiveData:taskData];
|
||||
[taskData release];
|
||||
|
||||
[m_task didFinish];
|
||||
}
|
||||
|
||||
virtual void FinishWithError() wxOVERRIDE
|
||||
{
|
||||
NSError *error = [[NSError alloc] initWithDomain:NSURLErrorDomain
|
||||
code:NSURLErrorFileDoesNotExist
|
||||
userInfo:nil];
|
||||
[m_task didFailWithError:error];
|
||||
[error release];
|
||||
}
|
||||
|
||||
int m_status;
|
||||
NSMutableDictionary* m_headers;
|
||||
id<WKURLSchemeTask> m_task;
|
||||
wxSharedPtr<wxWebViewHandlerResponseData> m_data;
|
||||
};
|
||||
|
||||
@implementation WebViewCustomProtocol
|
||||
|
||||
- (id)initWithHandler:(wxWebViewHandler *)handler
|
||||
|
|
@ -858,49 +960,9 @@ wxString nsErrorToWxHtmlError(NSError* error, wxWebViewNavigationError* out)
|
|||
- (void)webView:(WKWebView *)webView startURLSchemeTask:(id<WKURLSchemeTask>)urlSchemeTask
|
||||
WX_API_AVAILABLE_MACOS(10, 13)
|
||||
{
|
||||
NSURLRequest *request = urlSchemeTask.request;
|
||||
NSString* path = [[request URL] absoluteString];
|
||||
|
||||
wxString wxpath = wxCFStringRef::AsString(path);
|
||||
|
||||
wxFSFile* file = m_handler->GetFile(wxpath);
|
||||
|
||||
if (!file)
|
||||
{
|
||||
NSError *error = [[NSError alloc] initWithDomain:NSURLErrorDomain
|
||||
code:NSURLErrorFileDoesNotExist
|
||||
userInfo:nil];
|
||||
|
||||
[urlSchemeTask didFailWithError:error];
|
||||
|
||||
[error release];
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
size_t length = file->GetStream()->GetLength();
|
||||
|
||||
|
||||
NSURLResponse *response = [[NSURLResponse alloc] initWithURL:[request URL]
|
||||
MIMEType:wxCFStringRef(file->GetMimeType()).AsNSString()
|
||||
expectedContentLength:length
|
||||
textEncodingName:nil];
|
||||
|
||||
//Load the data, we malloc it so it is tidied up properly
|
||||
void* buffer = malloc(length);
|
||||
file->GetStream()->Read(buffer, length);
|
||||
NSData *data = [[NSData alloc] initWithBytesNoCopy:buffer length:length];
|
||||
|
||||
//Set the data
|
||||
[urlSchemeTask didReceiveResponse:response];
|
||||
[urlSchemeTask didReceiveData:data];
|
||||
|
||||
//Notify that we have finished
|
||||
[urlSchemeTask didFinish];
|
||||
|
||||
[data release];
|
||||
|
||||
[response release];
|
||||
wxWebViewWebKitHandlerRequest request(urlSchemeTask.request);
|
||||
wxSharedPtr<wxWebViewHandlerResponse> response(new wxWebViewWebkitHandlerResponse(urlSchemeTask));
|
||||
m_handler->StartRequest(request, response);
|
||||
}
|
||||
|
||||
- (void)webView:(WKWebView *)webView stopURLSchemeTask:(id<WKURLSchemeTask>)urlSchemeTask
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue