Implement sending request data with wxWebRequest

This commit is contained in:
Tobias Taschner
2018-10-22 21:39:30 +02:00
parent 3971a9ef7f
commit d7dee7019e
5 changed files with 110 additions and 50 deletions

View File

@@ -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();

View File

@@ -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();

View File

@@ -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";

View File

@@ -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)

View File

@@ -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);