diff --git a/include/wx/webview.h b/include/wx/webview.h index 5ea5f03f74..a3be733d0c 100644 --- a/include/wx/webview.h +++ b/include/wx/webview.h @@ -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 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 response); private: wxString m_scheme; wxString m_securityURL; + wxString m_virtualHost; }; extern WXDLLIMPEXP_DATA_WEBVIEW(const char) wxWebViewNameStr[]; diff --git a/src/common/webview.cpp b/src/common/webview.cpp index dbf8ed8451..fba1496b66 100644 --- a/src/common/webview.cpp +++ b/src/common/webview.cpp @@ -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((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( + 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 response) +{ + wxFSFile* file = GetFile(request.GetURI()); + if (file) + { + response->SetContentType(file->GetMimeType()); + response->Finish(wxSharedPtr( + new wxWebViewHandlerResponseDataFile(file))); + } + else + response->FinishWithError(); +} + +// wxWebView + wxStringWebViewFactoryMap wxWebView::m_factoryMap; wxWebViewZoom wxWebView::GetZoom() const diff --git a/src/osx/webview_webkit.mm b/src/osx/webview_webkit.mm index d5f78341c7..87a3dffe69 100644 --- a/src/osx/webview_webkit.mm +++ b/src/osx/webview_webkit.mm @@ -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 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 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 m_task; + wxSharedPtr m_data; +}; + @implementation WebViewCustomProtocol - (id)initWithHandler:(wxWebViewHandler *)handler @@ -858,49 +960,9 @@ wxString nsErrorToWxHtmlError(NSError* error, wxWebViewNavigationError* out) - (void)webView:(WKWebView *)webView startURLSchemeTask:(id)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 response(new wxWebViewWebkitHandlerResponse(urlSchemeTask)); + m_handler->StartRequest(request, response); } - (void)webView:(WKWebView *)webView stopURLSchemeTask:(id)urlSchemeTask