mirror of
https://github.com/wxWidgets/wxWidgets.git
synced 2026-08-18 01:19:45 +08:00
Allow reusing POST data when using wxWebRequestCURL
Set seek callback to allow libcurl to reuse the data being uploaded when it has to redo the HTTP request, e.g. because of redirection after a 301 or resubmitting it with correct authentication data after a 401. Add a test checking that this works correctly, although it has to be disabled for WinHTTP for now as it doesn't handle 307/308 redirects automatically (see #26046).
This commit is contained in:
@@ -89,8 +89,9 @@ public:
|
||||
|
||||
wxString GetError() const;
|
||||
|
||||
// Method called from libcurl callback
|
||||
// These functions implement libcurl callbacks.
|
||||
size_t CURLOnRead(char* buffer, size_t size);
|
||||
int CURLOnSeek(curl_off_t offset, int origin);
|
||||
|
||||
private:
|
||||
// Common initialization for sync and async requests performed when the
|
||||
|
||||
@@ -50,6 +50,10 @@
|
||||
#define CURLOPT_ACCEPT_ENCODING CURLOPT_ENCODING
|
||||
#endif
|
||||
|
||||
#if wxUSE_LOG_TRACE
|
||||
constexpr const char* TRACE_CURL = "curl";
|
||||
#endif
|
||||
|
||||
// Define libcurl timeout constants
|
||||
static constexpr int LIBCURL_DEFAULT_CONNECT_TIMEOUT = 300000; // 5m in ms.
|
||||
|
||||
@@ -335,6 +339,13 @@ static size_t wxCURLRead(char *buffer, size_t size, size_t nitems, void *userdat
|
||||
return static_cast<wxWebRequestCURL*>(userdata)->CURLOnRead(buffer, size * nitems);
|
||||
}
|
||||
|
||||
static int wxCURLSeek(void* userdata, curl_off_t offset, int origin)
|
||||
{
|
||||
wxCHECK_MSG( userdata, CURL_SEEKFUNC_CANTSEEK, "invalid curl seek callback data" );
|
||||
|
||||
return static_cast<wxWebRequestCURL*>(userdata)->CURLOnSeek(offset, origin);
|
||||
}
|
||||
|
||||
wxWebRequestCURL::wxWebRequestCURL(wxWebSession & session,
|
||||
wxWebSessionCURL& sessionImpl,
|
||||
wxEvtHandler* handler,
|
||||
@@ -377,6 +388,8 @@ void wxWebRequestCURL::DoStartPrepare(const wxString& url)
|
||||
wxCURLSetOpt(m_handle, CURLOPT_HEADERFUNCTION, wxCURLHeader);
|
||||
wxCURLSetOpt(m_handle, CURLOPT_READFUNCTION, wxCURLRead);
|
||||
wxCURLSetOpt(m_handle, CURLOPT_READDATA, this);
|
||||
wxCURLSetOpt(m_handle, CURLOPT_SEEKFUNCTION, wxCURLSeek);
|
||||
wxCURLSetOpt(m_handle, CURLOPT_SEEKDATA, this);
|
||||
// Enable gzip, etc decompression
|
||||
wxCURLSetOpt(m_handle, CURLOPT_ACCEPT_ENCODING, "");
|
||||
// Enable redirection handling
|
||||
@@ -618,6 +631,34 @@ size_t wxWebRequestCURL::CURLOnRead(char* buffer, size_t size)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int wxWebRequestCURL::CURLOnSeek(curl_off_t offset, int origin)
|
||||
{
|
||||
wxSeekMode mode = wxFromStart;
|
||||
switch ( origin )
|
||||
{
|
||||
case SEEK_SET:
|
||||
mode = wxFromStart;
|
||||
break;
|
||||
|
||||
case SEEK_CUR:
|
||||
mode = wxFromCurrent;
|
||||
break;
|
||||
|
||||
case SEEK_END:
|
||||
mode = wxFromEnd;
|
||||
break;
|
||||
|
||||
default:
|
||||
wxLogTrace(TRACE_CURL, "Seek function: unknown origin %d", origin);
|
||||
return CURL_SEEKFUNC_CANTSEEK;
|
||||
}
|
||||
|
||||
if ( m_dataStream->SeekI(offset, mode) == wxInvalidOffset )
|
||||
return CURL_SEEKFUNC_CANTSEEK;
|
||||
|
||||
return CURL_SEEKFUNC_OK;
|
||||
}
|
||||
|
||||
wxFileOffset wxWebRequestCURL::GetBytesSent() const
|
||||
{
|
||||
return m_bytesSent;
|
||||
@@ -875,10 +916,6 @@ using SocketPollerBase = WinSock1SocketPoller;
|
||||
|
||||
#else
|
||||
|
||||
#if wxUSE_LOG_TRACE
|
||||
constexpr const char* TRACE_CURL = "curl";
|
||||
#endif
|
||||
|
||||
// SocketPollerSourceHandler - a source handler used by the SocketPoller class.
|
||||
|
||||
class SourceSocketPoller;
|
||||
|
||||
@@ -1064,6 +1064,30 @@ TEST_CASE_METHOD(SyncRequestFixture,
|
||||
CHECK( response.GetStatus() == 200 );
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(SyncRequestFixture,
|
||||
"WebRequest::Sync::PostAfterRedirect", "[net][webrequest][sync]")
|
||||
{
|
||||
if ( !InitBaseURL() )
|
||||
return;
|
||||
|
||||
// We can't test this when using WinHTTP because we need to use either 307
|
||||
// or 308 redirect status code to preserve the POST method across the
|
||||
// redirect (all backends switch to GET for 301 and 302, although it would
|
||||
// be possible to configure this to preserve POST when using libcurl) and
|
||||
// WinHTTP doesn't handle them automatically.
|
||||
const auto& versionInfo = wxWebSession::GetDefault().GetLibraryVersionInfo();
|
||||
if ( versionInfo.GetName() == "WinHTTP" )
|
||||
{
|
||||
WARN("Skipping POST with redirect test with WinHTTP backend");
|
||||
return;
|
||||
}
|
||||
|
||||
Create("redirect-to?url=post&status_code=307");
|
||||
request.SetData("app=WebRequestRedirect&version=1", "application/x-www-form-urlencoded");
|
||||
REQUIRE( Execute() );
|
||||
CHECK( response.GetStatus() == 200 );
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(SyncRequestFixture,
|
||||
"WebRequest::Sync::Put", "[net][webrequest][sync]")
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user