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