diff --git a/docs/doxygen/mainpages/samples.h b/docs/doxygen/mainpages/samples.h index f7d7fd1b2e..81eaf04106 100644 --- a/docs/doxygen/mainpages/samples.h +++ b/docs/doxygen/mainpages/samples.h @@ -902,6 +902,15 @@ archives. @sampledir{webview} +@section page_samples_webrequest Web Request Sample + +This sample demonstrates the various capabilities of the +wxWebRequest class. It shows how to handle simple text HTTP and HTTPS requests, +downloading files, showing download progress and processing downloaded +data while it's being downloaded. + +@sampledir{webrequest} + @section page_samples_widgets Widgets Sample The widgets sample is the main presentation program for most simple and advanced @@ -962,4 +971,3 @@ other resources. From its menu or toolbar you can then run the following dialogs @sampledir{xrc} */ - diff --git a/include/wx/private/webrequest.h b/include/wx/private/webrequest.h index b68c9c8b79..0812304fac 100644 --- a/include/wx/private/webrequest.h +++ b/include/wx/private/webrequest.h @@ -96,6 +96,10 @@ public: virtual wxWebRequestHandle GetNativeHandle() const = 0; + void DisablePeerVerify(bool disable) { m_peerVerifyDisabled = disable; } + + bool IsPeerVerifyDisabled() const { return m_peerVerifyDisabled; } + void SetState(wxWebRequest::State state, const wxString& failMsg = wxString()); void ReportDataReceived(size_t sizeReceived); @@ -110,6 +114,7 @@ protected: wxWebRequestHeaderMap m_headers; wxFileOffset m_dataSize; wxScopedPtr m_dataStream; + bool m_peerVerifyDisabled; wxWebRequestImpl(wxWebSession& session, wxWebSessionImpl& sessionImpl, diff --git a/include/wx/webrequest.h b/include/wx/webrequest.h index ffeabf7036..349c0372a9 100644 --- a/include/wx/webrequest.h +++ b/include/wx/webrequest.h @@ -188,6 +188,10 @@ public: wxWebRequestHandle GetNativeHandle() const; + void DisablePeerVerify(bool disable = true); + + bool IsPeerVerifyDisabled() const; + private: // Ctor is only used by wxWebSession. friend class wxWebSession; diff --git a/interface/wx/protocol/http.h b/interface/wx/protocol/http.h index 07295dde44..e5ba4d5962 100644 --- a/interface/wx/protocol/http.h +++ b/interface/wx/protocol/http.h @@ -12,6 +12,9 @@ wxHTTP can thus be used to create a (basic) HTTP @b client. + @note In practice, for any but the most trivial cases, e.g. if you need HTTPS, HTTP/2 or IPv6, + proxy detection, authentication, etc. support please use wxWebRequest instead. + @library{wxnet} @category{net} @@ -173,4 +176,3 @@ public: const wxString& data, const wxMBConv& conv = wxConvUTF8); }; - diff --git a/interface/wx/webrequest.h b/interface/wx/webrequest.h index 79ed1ac312..98713392d8 100644 --- a/interface/wx/webrequest.h +++ b/interface/wx/webrequest.h @@ -61,6 +61,14 @@ request.Start(); @endcode + @section apple_http macOS and iOS App Transport Security + + Starting with macOS 10.11 and iOS 9 an application cannot create unsecure + connections (this includes HTTP and unverified HTTPS). You have to include + additional fields in your Info.plist to enable such connections. + For further details see the documentation on NSAppTransportSecurity + here + @section descriptions Implementation Descriptions The following APIs are used per platform, additional details @@ -391,6 +399,22 @@ public: server. */ void SetStorage(Storage storage); + + /** + Disable SSL certificate verification. + + This can be used to connect to self signed servers or other invalid + SSL connections. Disabling verification makes the communication + insecure. + */ + void DisablePeerVerify(bool disable = true); + + /** + Returns if peer verification has been disabled. + + @see DisablePeerVerify() + */ + bool IsPeerVerifyDisabled() const; ///@} /** @name Progress methods diff --git a/src/common/webrequest.cpp b/src/common/webrequest.cpp index 50cae4b05f..351a4b76ae 100644 --- a/src/common/webrequest.cpp +++ b/src/common/webrequest.cpp @@ -62,6 +62,7 @@ wxWebRequestImpl::wxWebRequestImpl(wxWebSession& session, : m_storage(wxWebRequest::Storage_Memory), m_headers(sessionImpl.GetHeaders()), m_dataSize(0), + m_peerVerifyDisabled(false), m_session(session), m_handler(handler), m_id(id), @@ -516,6 +517,18 @@ wxWebRequestHandle wxWebRequest::GetNativeHandle() const return m_impl ? m_impl->GetNativeHandle() : NULL; } +void wxWebRequest::DisablePeerVerify(bool disable) +{ + m_impl->DisablePeerVerify(disable); +} + +bool wxWebRequest::IsPeerVerifyDisabled() const +{ + return m_impl->IsPeerVerifyDisabled(); +} + + + // // wxWebAuthChallenge diff --git a/src/common/webrequest_curl.cpp b/src/common/webrequest_curl.cpp index 47264ff12b..e9e2a135f3 100644 --- a/src/common/webrequest_curl.cpp +++ b/src/common/webrequest_curl.cpp @@ -247,6 +247,9 @@ void wxWebRequestCURL::Start() } curl_easy_setopt(m_handle, CURLOPT_HTTPHEADER, m_headerList); + if ( IsPeerVerifyDisabled() ) + curl_easy_setopt(m_handle, CURLOPT_SSL_VERIFYPEER, 0); + StartRequest(); } @@ -468,7 +471,7 @@ wxThread::ExitCode wxWebSessionCURL::Entry() { // Handle cancelled requests { - wxCriticalSectionLocker lock(m_cancelled.cs); + wxCriticalSectionLocker cancelledLock(m_cancelled.cs); while ( !m_cancelled.requests.empty() ) { wxObjectDataPtr request(m_cancelled.requests.back()); diff --git a/src/msw/webrequest_winhttp.cpp b/src/msw/webrequest_winhttp.cpp index 2a46cdf2d4..7c087a833b 100644 --- a/src/msw/webrequest_winhttp.cpp +++ b/src/msw/webrequest_winhttp.cpp @@ -364,6 +364,16 @@ void wxWebRequestWinHTTP::Start() return; } + if ( IsPeerVerifyDisabled() ) + { + wxWinHTTPSetOption(m_request, WINHTTP_OPTION_SECURITY_FLAGS, + SECURITY_FLAG_IGNORE_CERT_CN_INVALID | + SECURITY_FLAG_IGNORE_CERT_DATE_INVALID | + SECURITY_FLAG_IGNORE_UNKNOWN_CA | + SECURITY_FLAG_IGNORE_CERT_WRONG_USAGE + ); + } + SendRequest(); } diff --git a/src/osx/webrequest_urlsession.mm b/src/osx/webrequest_urlsession.mm index 43b1dcdcee..f522d41391 100644 --- a/src/osx/webrequest_urlsession.mm +++ b/src/osx/webrequest_urlsession.mm @@ -150,6 +150,12 @@ *request )); } + else if ( authMethod == NSURLAuthenticationMethodServerTrust ) + { + if (request->IsPeerVerifyDisabled()) + completionHandler(NSURLSessionAuthChallengeUseCredential, + [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust]); + } completionHandler(NSURLSessionAuthChallengePerformDefaultHandling, nil); } diff --git a/tests/net/webrequest.cpp b/tests/net/webrequest.cpp index 64cf7afcab..974a0d3b93 100644 --- a/tests/net/webrequest.cpp +++ b/tests/net/webrequest.cpp @@ -262,6 +262,27 @@ TEST_CASE_METHOD(RequestFixture, Run(wxWebRequest::State_Failed, 0); } +TEST_CASE_METHOD(RequestFixture, + "WebRequest::SSL::Error", "[net][webrequest][error]") +{ + if (!InitBaseURL()) + return; + + CreateAbs("https://self-signed.badssl.com/"); + Run(wxWebRequest::State_Failed, 0); +} + +TEST_CASE_METHOD(RequestFixture, + "WebRequest::SSL::Ignore", "[net][webrequest]") +{ + if (!InitBaseURL()) + return; + + CreateAbs("https://self-signed.badssl.com/"); + request.DisablePeerVerify(); + Run(wxWebRequest::State_Completed, 200); +} + TEST_CASE_METHOD(RequestFixture, "WebRequest::Post", "[net][webrequest]") {