Implement sending request data with wxWebRequest
This commit is contained in:
@@ -59,12 +59,6 @@ public:
|
|||||||
|
|
||||||
~wxWebRequestWinHTTP();
|
~wxWebRequestWinHTTP();
|
||||||
|
|
||||||
void SetMethod(const wxString& method) wxOVERRIDE;
|
|
||||||
|
|
||||||
void SetData(const wxString& text, const wxString& contentType) wxOVERRIDE;
|
|
||||||
|
|
||||||
void SetData(const wxInputStream& dataStream, const wxString& contentType) wxOVERRIDE;
|
|
||||||
|
|
||||||
void Start() wxOVERRIDE;
|
void Start() wxOVERRIDE;
|
||||||
|
|
||||||
void Cancel() wxOVERRIDE;
|
void Cancel() wxOVERRIDE;
|
||||||
@@ -82,6 +76,12 @@ private:
|
|||||||
HINTERNET m_connect;
|
HINTERNET m_connect;
|
||||||
HINTERNET m_request;
|
HINTERNET m_request;
|
||||||
wxScopedPtr<wxWebResponseWinHTTP> m_response;
|
wxScopedPtr<wxWebResponseWinHTTP> m_response;
|
||||||
|
wxMemoryBuffer m_dataWriteBuffer;
|
||||||
|
wxFileOffset m_dataWritten;
|
||||||
|
|
||||||
|
void WriteData();
|
||||||
|
|
||||||
|
void CreateResponse();
|
||||||
|
|
||||||
void SetFailedWithLastError();
|
void SetFailedWithLastError();
|
||||||
|
|
||||||
|
@@ -42,11 +42,11 @@ public:
|
|||||||
virtual void SetHeader(const wxString& name, const wxString& value)
|
virtual void SetHeader(const wxString& name, const wxString& value)
|
||||||
{ m_headers[name] = value; }
|
{ m_headers[name] = value; }
|
||||||
|
|
||||||
virtual void SetMethod(const wxString& method) = 0;
|
virtual void SetMethod(const wxString& method) { m_method = method; }
|
||||||
|
|
||||||
virtual void SetData(const wxString& text, const wxString& contentType) = 0;
|
void SetData(const wxString& text, const wxString& contentType, const wxMBConv& conv = wxConvUTF8);
|
||||||
|
|
||||||
virtual void SetData(const wxInputStream& dataStream, const wxString& contentType) = 0;
|
void SetData(wxSharedPtr<wxInputStream> dataStream, const wxString& contentType, wxFileOffset dataSize = wxInvalidOffset);
|
||||||
|
|
||||||
void SetIgnoreServerErrorStatus(bool ignore) { m_ignoreServerErrorStatus = ignore; }
|
void SetIgnoreServerErrorStatus(bool ignore) { m_ignoreServerErrorStatus = ignore; }
|
||||||
|
|
||||||
@@ -61,12 +61,16 @@ public:
|
|||||||
State GetState() const { return m_state; }
|
State GetState() const { return m_state; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
wxString m_method;
|
||||||
wxWebRequestHeaderMap m_headers;
|
wxWebRequestHeaderMap m_headers;
|
||||||
|
wxFileOffset m_dataSize;
|
||||||
|
wxSharedPtr<wxInputStream> m_dataStream;
|
||||||
|
|
||||||
wxWebRequest(int id):
|
wxWebRequest(int id):
|
||||||
m_id(id),
|
m_id(id),
|
||||||
m_state(State_Idle),
|
m_state(State_Idle),
|
||||||
m_ignoreServerErrorStatus(false) { }
|
m_ignoreServerErrorStatus(false),
|
||||||
|
m_dataSize(0) { }
|
||||||
|
|
||||||
void SetState(State state, const wxString& failMsg = "");
|
void SetState(State state, const wxString& failMsg = "");
|
||||||
|
|
||||||
@@ -77,6 +81,7 @@ private:
|
|||||||
State m_state;
|
State m_state;
|
||||||
wxString m_failMessage;
|
wxString m_failMessage;
|
||||||
bool m_ignoreServerErrorStatus;
|
bool m_ignoreServerErrorStatus;
|
||||||
|
wxCharBuffer m_dataText;
|
||||||
|
|
||||||
void ProcessReadyEvent();
|
void ProcessReadyEvent();
|
||||||
|
|
||||||
|
@@ -77,15 +77,16 @@ public:
|
|||||||
textSizer->Add(m_postCheckBox, wxSizerFlags().Border());
|
textSizer->Add(m_postCheckBox, wxSizerFlags().Border());
|
||||||
m_postCheckBox->Bind(wxEVT_CHECKBOX, &WebRequestFrame::OnPostCheckBox, this);
|
m_postCheckBox->Bind(wxEVT_CHECKBOX, &WebRequestFrame::OnPostCheckBox, this);
|
||||||
|
|
||||||
m_postRequestTextCtrl = new wxTextCtrl(textPanel, wxID_ANY, "",
|
m_postRequestTextCtrl = new wxTextCtrl(textPanel, wxID_ANY,
|
||||||
wxDefaultPosition, wxDefaultSize, wxTE_MULTILINE);
|
"app=WebRequestSample&version=1",
|
||||||
|
wxDefaultPosition, wxSize(-1, FromDIP(60)), wxTE_MULTILINE);
|
||||||
textSizer->Add(m_postRequestTextCtrl,
|
textSizer->Add(m_postRequestTextCtrl,
|
||||||
wxSizerFlags(1).Expand().Border(wxLEFT | wxRIGHT));
|
wxSizerFlags().Expand().Border(wxLEFT | wxRIGHT));
|
||||||
|
|
||||||
textSizer->Add(new wxStaticText(textPanel, wxID_ANY, "Request body content type:"),
|
textSizer->Add(new wxStaticText(textPanel, wxID_ANY, "Request body content type:"),
|
||||||
wxSizerFlags().Border());
|
wxSizerFlags().Border());
|
||||||
m_postContentTypeTextCtrl = new wxTextCtrl(textPanel, wxID_ANY,
|
m_postContentTypeTextCtrl = new wxTextCtrl(textPanel, wxID_ANY,
|
||||||
"application/json");
|
"application/x-www-form-urlencoded");
|
||||||
textSizer->Add(m_postContentTypeTextCtrl,
|
textSizer->Add(m_postContentTypeTextCtrl,
|
||||||
wxSizerFlags().Expand().Border(wxLEFT | wxRIGHT));
|
wxSizerFlags().Expand().Border(wxLEFT | wxRIGHT));
|
||||||
|
|
||||||
@@ -142,10 +143,16 @@ public:
|
|||||||
switch (m_notebook->GetSelection())
|
switch (m_notebook->GetSelection())
|
||||||
{
|
{
|
||||||
case Page_Image:
|
case Page_Image:
|
||||||
|
// Reset static bitmap image
|
||||||
|
m_imageStaticBitmap->SetBitmap(wxArtProvider::GetBitmap(wxART_MISSING_IMAGE));
|
||||||
// Bind completion event to response as image
|
// Bind completion event to response as image
|
||||||
request->Bind(wxEVT_WEBREQUEST_READY, &WebRequestFrame::OnImageRequestReady, this);
|
request->Bind(wxEVT_WEBREQUEST_READY, &WebRequestFrame::OnImageRequestReady, this);
|
||||||
break;
|
break;
|
||||||
case Page_Text:
|
case Page_Text:
|
||||||
|
// Reset response text control
|
||||||
|
m_textResponseTextCtrl->Clear();
|
||||||
|
|
||||||
|
// Set postdata if checked
|
||||||
if (m_postCheckBox->IsChecked())
|
if (m_postCheckBox->IsChecked())
|
||||||
{
|
{
|
||||||
request->SetData(m_postRequestTextCtrl->GetValue(),
|
request->SetData(m_postRequestTextCtrl->GetValue(),
|
||||||
@@ -214,7 +221,7 @@ public:
|
|||||||
defaultURL = "https://www.wxwidgets.org/downloads/logos/blocks.png";
|
defaultURL = "https://www.wxwidgets.org/downloads/logos/blocks.png";
|
||||||
break;
|
break;
|
||||||
case Page_Text:
|
case Page_Text:
|
||||||
defaultURL = "https://api.github.com";
|
defaultURL = "https://httpbin.org/post";
|
||||||
break;
|
break;
|
||||||
case Page_Download:
|
case Page_Download:
|
||||||
defaultURL = "https://www.wxwidgets.com/download.zip";
|
defaultURL = "https://www.wxwidgets.com/download.zip";
|
||||||
|
@@ -17,6 +17,7 @@
|
|||||||
#if wxUSE_WEBREQUEST
|
#if wxUSE_WEBREQUEST
|
||||||
|
|
||||||
#include "wx/webrequest.h"
|
#include "wx/webrequest.h"
|
||||||
|
#include "wx/mstream.h"
|
||||||
|
|
||||||
#ifndef WX_PRECOMP
|
#ifndef WX_PRECOMP
|
||||||
#include "wx/app.h"
|
#include "wx/app.h"
|
||||||
@@ -55,6 +56,32 @@ bool wxWebRequest::CheckServerStatus()
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void wxWebRequest::SetData(const wxString& text, const wxString& contentType, const wxMBConv& conv)
|
||||||
|
{
|
||||||
|
m_dataText = text.mb_str(conv);
|
||||||
|
SetData(wxSharedPtr<wxInputStream>(new wxMemoryInputStream(m_dataText, m_dataText.length())), contentType);
|
||||||
|
}
|
||||||
|
|
||||||
|
void wxWebRequest::SetData(wxSharedPtr<wxInputStream> dataStream, const wxString& contentType, wxFileOffset dataSize)
|
||||||
|
{
|
||||||
|
m_dataStream = dataStream;
|
||||||
|
if ( m_dataStream.get() )
|
||||||
|
{
|
||||||
|
if ( dataSize == wxInvalidOffset )
|
||||||
|
{
|
||||||
|
// Determine data size
|
||||||
|
m_dataSize = m_dataStream->SeekI(0, wxFromEnd);
|
||||||
|
m_dataStream->SeekI(0);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
m_dataSize = dataSize;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
m_dataSize = 0;
|
||||||
|
|
||||||
|
SetHeader("Content-Type", contentType);
|
||||||
|
}
|
||||||
|
|
||||||
void wxWebRequest::SetState(State state, const wxString & failMsg)
|
void wxWebRequest::SetState(State state, const wxString & failMsg)
|
||||||
{
|
{
|
||||||
switch (state)
|
switch (state)
|
||||||
|
@@ -163,30 +163,19 @@ wxWebRequestWinHTTP::~wxWebRequestWinHTTP()
|
|||||||
void wxWebRequestWinHTTP::HandleCallback(DWORD dwInternetStatus,
|
void wxWebRequestWinHTTP::HandleCallback(DWORD dwInternetStatus,
|
||||||
LPVOID lpvStatusInformation, DWORD dwStatusInformationLength)
|
LPVOID lpvStatusInformation, DWORD dwStatusInformationLength)
|
||||||
{
|
{
|
||||||
bool handleLastError = false;
|
|
||||||
static const int readSize = 8 * 1024;
|
|
||||||
|
|
||||||
switch ( dwInternetStatus )
|
switch ( dwInternetStatus )
|
||||||
{
|
{
|
||||||
case WINHTTP_CALLBACK_STATUS_SENDREQUEST_COMPLETE:
|
case WINHTTP_CALLBACK_STATUS_SENDREQUEST_COMPLETE:
|
||||||
if ( ::WinHttpReceiveResponse(m_request, NULL) )
|
if ( m_dataSize )
|
||||||
{
|
WriteData();
|
||||||
m_response.reset(new wxWebResponseWinHTTP(*this));
|
|
||||||
if ( CheckServerStatus() )
|
|
||||||
{
|
|
||||||
// Start reading the response
|
|
||||||
if ( !m_response->ReadData() )
|
|
||||||
handleLastError = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
handleLastError = true;
|
CreateResponse();
|
||||||
break;
|
break;
|
||||||
case WINHTTP_CALLBACK_STATUS_READ_COMPLETE:
|
case WINHTTP_CALLBACK_STATUS_READ_COMPLETE:
|
||||||
if ( dwStatusInformationLength > 0 )
|
if ( dwStatusInformationLength > 0 )
|
||||||
{
|
{
|
||||||
if ( !m_response->ReportAvailableData(dwStatusInformationLength) )
|
if ( !m_response->ReportAvailableData(dwStatusInformationLength) )
|
||||||
handleLastError = true;
|
SetFailedWithLastError();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -194,6 +183,9 @@ void wxWebRequestWinHTTP::HandleCallback(DWORD dwInternetStatus,
|
|||||||
SetState(State_Ready);
|
SetState(State_Ready);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case WINHTTP_CALLBACK_STATUS_WRITE_COMPLETE:
|
||||||
|
WriteData();
|
||||||
|
break;
|
||||||
case WINHTTP_CALLBACK_STATUS_REQUEST_ERROR:
|
case WINHTTP_CALLBACK_STATUS_REQUEST_ERROR:
|
||||||
{
|
{
|
||||||
LPWINHTTP_ASYNC_RESULT asyncResult = reinterpret_cast<LPWINHTTP_ASYNC_RESULT>(lpvStatusInformation);
|
LPWINHTTP_ASYNC_RESULT asyncResult = reinterpret_cast<LPWINHTTP_ASYNC_RESULT>(lpvStatusInformation);
|
||||||
@@ -201,32 +193,49 @@ void wxWebRequestWinHTTP::HandleCallback(DWORD dwInternetStatus,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (handleLastError)
|
|
||||||
SetFailedWithLastError();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void wxWebRequestWinHTTP::WriteData()
|
||||||
|
{
|
||||||
|
int dataWriteSize = 8 * 1024;
|
||||||
|
if ( m_dataWritten + dataWriteSize > m_dataSize )
|
||||||
|
dataWriteSize = m_dataSize - m_dataWritten;
|
||||||
|
if ( dataWriteSize )
|
||||||
|
{
|
||||||
|
m_dataWriteBuffer.Clear();
|
||||||
|
m_dataWriteBuffer.GetWriteBuf(dataWriteSize);
|
||||||
|
m_dataStream->Read(m_dataWriteBuffer.GetData(), dataWriteSize);
|
||||||
|
|
||||||
|
if ( !::WinHttpWriteData(m_request, m_dataWriteBuffer.GetData(), dataWriteSize, NULL) )
|
||||||
|
SetFailedWithLastError();
|
||||||
|
m_dataWritten += dataWriteSize;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
CreateResponse();
|
||||||
|
}
|
||||||
|
|
||||||
|
void wxWebRequestWinHTTP::CreateResponse()
|
||||||
|
{
|
||||||
|
if (::WinHttpReceiveResponse(m_request, NULL))
|
||||||
|
{
|
||||||
|
m_response.reset(new wxWebResponseWinHTTP(*this));
|
||||||
|
if (CheckServerStatus())
|
||||||
|
{
|
||||||
|
// Start reading the response
|
||||||
|
if (!m_response->ReadData())
|
||||||
|
SetFailedWithLastError();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
SetFailedWithLastError();
|
||||||
|
}
|
||||||
|
|
||||||
void wxWebRequestWinHTTP::SetFailedWithLastError()
|
void wxWebRequestWinHTTP::SetFailedWithLastError()
|
||||||
{
|
{
|
||||||
wxString failMessage = wxWinHTTPErrorToString(::GetLastError());
|
wxString failMessage = wxWinHTTPErrorToString(::GetLastError());
|
||||||
SetState(State_Failed, failMessage);
|
SetState(State_Failed, failMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
void wxWebRequestWinHTTP::SetMethod(const wxString& method)
|
|
||||||
{
|
|
||||||
// TODO: implement
|
|
||||||
}
|
|
||||||
|
|
||||||
void wxWebRequestWinHTTP::SetData(const wxString& text, const wxString& contentType)
|
|
||||||
{
|
|
||||||
// TODO: implement
|
|
||||||
}
|
|
||||||
|
|
||||||
void wxWebRequestWinHTTP::SetData(const wxInputStream& dataStream, const wxString& contentType)
|
|
||||||
{
|
|
||||||
// TODO: implement
|
|
||||||
}
|
|
||||||
|
|
||||||
void wxWebRequestWinHTTP::Start()
|
void wxWebRequestWinHTTP::Start()
|
||||||
{
|
{
|
||||||
if ( GetState() != State_Idle ) // Completed requests can not be restarted
|
if ( GetState() != State_Idle ) // Completed requests can not be restarted
|
||||||
@@ -251,9 +260,17 @@ void wxWebRequestWinHTTP::Start()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
wxString method;
|
||||||
|
if ( !m_method.empty() )
|
||||||
|
method = m_method;
|
||||||
|
else if ( m_dataSize )
|
||||||
|
method = "POST";
|
||||||
|
else
|
||||||
|
method = "GET";
|
||||||
|
|
||||||
// Open a request
|
// Open a request
|
||||||
m_request = ::WinHttpOpenRequest(m_connect,
|
m_request = ::WinHttpOpenRequest(m_connect,
|
||||||
L"GET", uri.GetPath().wc_str(),
|
method.wc_str(), uri.GetPath().wc_str(),
|
||||||
NULL, WINHTTP_NO_REFERER,
|
NULL, WINHTTP_NO_REFERER,
|
||||||
WINHTTP_DEFAULT_ACCEPT_TYPES,
|
WINHTTP_DEFAULT_ACCEPT_TYPES,
|
||||||
(isSecure) ? WINHTTP_FLAG_SECURE : 0);
|
(isSecure) ? WINHTTP_FLAG_SECURE : 0);
|
||||||
@@ -267,6 +284,7 @@ void wxWebRequestWinHTTP::Start()
|
|||||||
if ( ::WinHttpSetStatusCallback(m_request,
|
if ( ::WinHttpSetStatusCallback(m_request,
|
||||||
(WINHTTP_STATUS_CALLBACK)wxRequestStatusCallback,
|
(WINHTTP_STATUS_CALLBACK)wxRequestStatusCallback,
|
||||||
WINHTTP_CALLBACK_FLAG_READ_COMPLETE |
|
WINHTTP_CALLBACK_FLAG_READ_COMPLETE |
|
||||||
|
WINHTTP_CALLBACK_FLAG_WRITE_COMPLETE |
|
||||||
WINHTTP_CALLBACK_FLAG_SENDREQUEST_COMPLETE |
|
WINHTTP_CALLBACK_FLAG_SENDREQUEST_COMPLETE |
|
||||||
WINHTTP_CALLBACK_FLAG_REQUEST_ERROR,
|
WINHTTP_CALLBACK_FLAG_REQUEST_ERROR,
|
||||||
0) == WINHTTP_INVALID_STATUS_CALLBACK )
|
0) == WINHTTP_INVALID_STATUS_CALLBACK )
|
||||||
@@ -280,10 +298,13 @@ void wxWebRequestWinHTTP::Start()
|
|||||||
for (wxWebRequestHeaderMap::const_iterator header = m_headers.begin(); header != m_headers.end(); ++header)
|
for (wxWebRequestHeaderMap::const_iterator header = m_headers.begin(); header != m_headers.end(); ++header)
|
||||||
allHeaders.append(wxString::Format("%s: %s\n", header->first, header->second));
|
allHeaders.append(wxString::Format("%s: %s\n", header->first, header->second));
|
||||||
|
|
||||||
|
if ( m_dataSize )
|
||||||
|
m_dataWritten = 0;
|
||||||
|
|
||||||
// Send request
|
// Send request
|
||||||
if ( WinHttpSendRequest(m_request,
|
if ( WinHttpSendRequest(m_request,
|
||||||
allHeaders.wc_str(), allHeaders.length(),
|
allHeaders.wc_str(), allHeaders.length(),
|
||||||
NULL, 0, 0,
|
NULL, 0, m_dataSize,
|
||||||
(DWORD_PTR)this) )
|
(DWORD_PTR)this) )
|
||||||
{
|
{
|
||||||
SetState(State_Active);
|
SetState(State_Active);
|
||||||
|
Reference in New Issue
Block a user