Implement additional storage targets

This commit is contained in:
Tobias Taschner 2018-10-30 21:54:40 +01:00
parent d4362f4bca
commit c24efa9821
No known key found for this signature in database
GPG Key ID: AE6ECD71294F87FD
5 changed files with 188 additions and 17 deletions

View File

@ -89,7 +89,6 @@ public:
HINTERNET GetHandle() const { return m_request; }
private:
wxWebSessionWinHTTP& m_session;
wxString m_url;
HINTERNET m_connect;
HINTERNET m_request;

View File

@ -15,6 +15,7 @@
#if wxUSE_WEBREQUEST
#include "wx/event.h"
#include "wx/ffile.h"
#include "wx/object.h"
#include "wx/scopedptr.h"
#include "wx/sharedptr.h"
@ -74,6 +75,8 @@ public:
int GetId() const { return m_id; }
wxWebSession& GetSession() const { return m_session; }
State GetState() const { return m_state; }
virtual wxFileOffset GetBytesSent() const = 0;
@ -84,6 +87,8 @@ public:
virtual wxFileOffset GetBytesExpectedToReceive() const = 0;
void SetState(State state, const wxString& failMsg = "");
protected:
wxString m_method;
Storage m_storage;
@ -91,18 +96,18 @@ protected:
wxFileOffset m_dataSize;
wxSharedPtr<wxInputStream> m_dataStream;
wxWebRequest(int id):
wxWebRequest(wxWebSession& session, int id):
m_session(session),
m_id(id),
m_state(State_Idle),
m_ignoreServerErrorStatus(false),
m_dataSize(0),
m_storage(Storage_Memory) { }
void SetState(State state, const wxString& failMsg = "");
bool CheckServerStatus();
private:
wxWebSession& m_session;
int m_id;
State m_state;
bool m_ignoreServerErrorStatus;
@ -116,7 +121,7 @@ private:
class WXDLLIMPEXP_NET wxWebResponse
{
public:
virtual ~wxWebResponse() { }
virtual ~wxWebResponse();
virtual wxInt64 GetContentLength() const = 0;
@ -136,12 +141,17 @@ public:
wxString AsString(wxMBConv* conv = NULL) const;
void ReportDataCompleted();
bool Init();
virtual wxString GetFileName() const;
protected:
wxWebRequest& m_request;
size_t m_readSize;
wxWebResponse(wxWebRequest& request):
m_request(request), m_readSize(8 * 1024) { }
wxWebResponse(wxWebRequest& request);
void* GetDataBuffer(size_t sizeNeeded);
@ -149,6 +159,7 @@ protected:
private:
wxMemoryBuffer m_readBuffer;
mutable wxFFile m_file;
mutable wxScopedPtr<wxInputStream> m_stream;
wxDECLARE_NO_COPY_CLASS(wxWebResponse);
@ -205,6 +216,10 @@ public:
const wxWebRequestHeaderMap& GetHeaders() const { return m_headers; }
void SetTempDir(const wxString& dir) { m_tempDir = dir; }
wxString GetTempDir() const;
static wxWebSession& GetDefault();
static wxWebSession* New(const wxString& backend = wxWebSessionBackendDefault);
@ -218,6 +233,7 @@ protected:
private:
wxWebRequestHeaderMap m_headers;
wxString m_tempDir;
static wxScopedPtr<wxWebSession> ms_defaultSession;
static wxStringWebSessionFactoryMap ms_factoryMap;
@ -232,7 +248,8 @@ public:
wxWebRequestEvent(wxEventType type, int id, wxWebRequest::State state,
wxWebResponse* response = NULL, const wxString& errorDesc = "")
: wxEvent(id, type),
m_state(state), m_response(response), m_errorDescription(errorDesc)
m_state(state), m_response(response), m_data(NULL), m_dataSize(0),
m_errorDescription(errorDesc)
{ }
wxWebRequest::State GetState() const { return m_state; }
@ -241,11 +258,25 @@ public:
const wxString& GetErrorDescription() const { return m_errorDescription; }
const wxString& GetResponseFileName() const { return m_responseFileName; }
void SetResponseFileName(const wxString& filename) { m_responseFileName = filename; }
const void* GetDataBuffer() const { return m_data; }
size_t GetDataSize() const { return m_dataSize; }
void SetDataBuffer(const void* buffer, size_t size)
{ m_data = buffer; m_dataSize = size; }
wxEvent* Clone() const wxOVERRIDE { return new wxWebRequestEvent(*this); }
private:
wxWebRequest::State m_state;
wxWebResponse* m_response;
wxString m_responseFileName;
const void* m_data;
size_t m_dataSize;
wxString m_errorDescription;
};

View File

@ -19,7 +19,10 @@
#include "wx/webrequest.h"
#include "wx/mstream.h"
#include "wx/uri.h"
#include "wx/filefn.h"
#include "wx/filename.h"
#include "wx/stdpaths.h"
#include "wx/wfstream.h"
#ifndef WX_PRECOMP
#include "wx/app.h"
@ -105,9 +108,23 @@ void wxWebRequest::SetState(State state, const wxString & failMsg)
void wxWebRequest::ProcessStateEvent(State state, const wxString& failMsg)
{
wxString responseFileName;
wxWebRequestEvent evt(wxEVT_WEBREQUEST_STATE, GetId(), state,
GetResponse(), failMsg);
if ( state == State_Completed && m_storage == Storage::Storage_File )
{
responseFileName = GetResponse()->GetFileName();
evt.SetResponseFileName(responseFileName);
}
ProcessEvent(evt);
// Remove temporary file if it still exists
if ( state == State_Completed && m_storage == Storage::Storage_File &&
wxFileExists(responseFileName) )
wxRemove(responseFileName);
// Remove reference after the request is no longer active
if (state == State_Completed || state == State_Failed ||
state == State_Cancelled)
@ -118,6 +135,43 @@ void wxWebRequest::ProcessStateEvent(State state, const wxString& failMsg)
//
// wxWebResponse
//
wxWebResponse::wxWebResponse(wxWebRequest& request) :
m_request(request),
m_readSize(8 * 1024)
{
}
wxWebResponse::~wxWebResponse()
{
if ( wxFileExists(m_file.GetName()) )
wxRemove(m_file.GetName());
}
bool wxWebResponse::Init()
{
if (m_request.GetStorage() == wxWebRequest::Storage_File)
{
wxFileName tmpPrefix;
tmpPrefix.AssignDir(m_request.GetSession().GetTempDir());
if ( GetContentLength() > 0 )
{
// Check available disk space
wxLongLong freeSpace;
if ( wxGetDiskSpace(tmpPrefix.GetFullPath(), NULL, &freeSpace) &&
GetContentLength() > freeSpace )
{
m_request.SetState(wxWebRequest::State_Failed, _("Not enough free disk space for download."));
return false;
}
}
tmpPrefix.SetName("wxd");
wxFileName::CreateTempFileName(tmpPrefix.GetFullPath(), &m_file);
}
return true;
}
wxString wxWebResponse::GetMimeType() const
{
return GetHeader("Mime-Type");
@ -128,7 +182,20 @@ wxInputStream * wxWebResponse::GetStream() const
if ( !m_stream.get() )
{
// Create stream
m_stream.reset(new wxMemoryInputStream(m_readBuffer.GetData(), m_readBuffer.GetDataLen()));
switch (m_request.GetStorage())
{
case wxWebRequest::Storage_Memory:
m_stream.reset(new wxMemoryInputStream(m_readBuffer.GetData(), m_readBuffer.GetDataLen()));
break;
case wxWebRequest::Storage_File:
m_stream.reset(new wxFFileInputStream(m_file));
m_stream->SeekI(0);
break;
case wxWebRequest::Storage_None:
// No stream available
break;
}
}
return m_stream.get();
@ -155,10 +222,10 @@ wxString wxWebResponse::GetSuggestedFileName() const
wxString wxWebResponse::AsString(wxMBConv * conv) const
{
// TODO: try to determine encoding type from content-type header
if (!conv)
if ( !conv )
conv = &wxConvUTF8;
if (m_request.GetStorage() == wxWebRequest::Storage_Memory)
if ( m_request.GetStorage() == wxWebRequest::Storage_Memory )
{
size_t outLen = 0;
return conv->cMB2WC((const char*)m_readBuffer.GetData(), m_readBuffer.GetDataLen(), &outLen);
@ -175,8 +242,30 @@ void* wxWebResponse::GetDataBuffer(size_t sizeNeeded)
void wxWebResponse::ReportDataReceived(size_t sizeReceived)
{
m_readBuffer.UngetAppendBuf(sizeReceived);
if ( m_request.GetStorage() == wxWebRequest::Storage_File )
m_file.Write(m_readBuffer.GetData(), m_readBuffer.GetDataLen());
else if ( m_request.GetStorage() == wxWebRequest::Storage_None )
{
wxWebRequestEvent evt(wxEVT_WEBREQUEST_DATA, m_request.GetId(), wxWebRequest::State_Active);
evt.SetDataBuffer(m_readBuffer.GetData(), m_readBuffer.GetDataLen());
m_request.ProcessEvent(evt);
}
if ( m_request.GetStorage() != wxWebRequest::Storage_Memory )
m_readBuffer.Clear();
}
wxString wxWebResponse::GetFileName() const
{
return m_file.GetName();
}
void wxWebResponse::ReportDataCompleted()
{
if ( m_request.GetStorage() == wxWebRequest::Storage_File )
m_file.Close();
}
//
// wxWebSession
@ -193,6 +282,14 @@ wxWebSession::wxWebSession()
wxMAJOR_VERSION, wxMINOR_VERSION, wxRELEASE_NUMBER));
}
wxString wxWebSession::GetTempDir() const
{
if ( m_tempDir.empty() )
return wxStandardPaths::Get().GetTempDir();
else
return m_tempDir;
}
// static
wxWebSession& wxWebSession::GetDefault()
{

View File

@ -143,8 +143,7 @@ static void CALLBACK wxRequestStatusCallback(
//
wxWebRequestWinHTTP::wxWebRequestWinHTTP(int id, wxWebSessionWinHTTP& session, const wxString& url):
wxWebRequest(id),
m_session(session),
wxWebRequest(session, id),
m_url(url),
m_connect(NULL),
m_request(NULL),
@ -181,7 +180,10 @@ void wxWebRequestWinHTTP::HandleCallback(DWORD dwInternetStatus,
SetFailedWithLastError();
}
else
{
m_response->ReportDataCompleted();
SetState(State_Completed);
}
break;
case WINHTTP_CALLBACK_STATUS_WRITE_COMPLETE:
WriteData();
@ -216,9 +218,11 @@ void wxWebRequestWinHTTP::WriteData()
void wxWebRequestWinHTTP::CreateResponse()
{
if (::WinHttpReceiveResponse(m_request, NULL))
if ( ::WinHttpReceiveResponse(m_request, NULL) )
{
m_response.reset(new wxWebResponseWinHTTP(*this));
if ( !m_response->Init() )
return;
m_bytesExpectedToReceive = m_response->GetContentLength();
int status = m_response->GetStatus();
if ( status == 401 || status == 407)
@ -263,8 +267,9 @@ void wxWebRequestWinHTTP::Start()
port = wxAtoi(uri.GetPort());
// Open a connction
m_connect = ::WinHttpConnect(m_session.GetHandle(), uri.GetServer().wc_str(),
port, 0);
m_connect = ::WinHttpConnect(
static_cast<wxWebSessionWinHTTP&>(GetSession()).GetHandle(),
uri.GetServer().wc_str(), port, 0);
if ( m_connect == NULL )
{
SetFailedWithLastError();

View File

@ -22,6 +22,7 @@
#endif // WX_PRECOMP
#include "wx/webrequest.h"
#include "wx/filename.h"
#include "wx/wfstream.h"
// This test requires the URL to an httpbin instance.
@ -38,7 +39,11 @@
class RequestFixture
{
public:
RequestFixture() { }
RequestFixture()
{
expectedFileSize = 0;
dataSize = 0;
}
void Create(const wxString& subURL)
{
@ -51,6 +56,7 @@ public:
{
request.reset(wxWebSession::GetDefault().CreateRequest(url));
request->Bind(wxEVT_WEBREQUEST_STATE, &RequestFixture::OnRequestState, this);
request->Bind(wxEVT_WEBREQUEST_DATA, &RequestFixture::OnData, this);
}
void OnRequestState(wxWebRequestEvent& evt)
@ -59,6 +65,12 @@ public:
{
case wxWebRequest::State_Unauthorized:
case wxWebRequest::State_Completed:
if ( request->GetStorage() == wxWebRequest::Storage_File )
{
wxFileName fn(evt.GetResponseFileName());
REQUIRE( fn.GetSize() == expectedFileSize );
}
wxFALLTHROUGH;
case wxWebRequest::State_Failed:
case wxWebRequest::State_Cancelled:
loop.Exit();
@ -66,6 +78,12 @@ public:
}
}
void OnData(wxWebRequestEvent& evt)
{
// Count all bytes recieved via data event for Storage_None
dataSize += evt.GetDataSize();
}
void Run(wxWebRequest::State requiredState = wxWebRequest::State_Completed,
int requiredStatus = 200)
{
@ -79,6 +97,8 @@ public:
wxEventLoop loop;
wxObjectDataPtr<wxWebRequest> request;
wxInt64 expectedFileSize;
wxInt64 dataSize;
};
TEST_CASE_METHOD(RequestFixture, "WebRequest", "[net][.]")
@ -126,6 +146,25 @@ TEST_CASE_METHOD(RequestFixture, "WebRequest", "[net][.]")
REQUIRE( request->GetResponse()->AsString() == "The quick brown fox jumps over the lazy dog" );
}
SECTION("GET 99KB to file")
{
expectedFileSize = 99 * 1024;
Create(wxString::Format("/bytes/%lld", expectedFileSize));
request->SetStorage(wxWebRequest::Storage_File);
Run();
REQUIRE( request->GetBytesReceived() == expectedFileSize );
}
SECTION("Process 99KB data")
{
int processingSize = 99 * 1024;
Create(wxString::Format("/bytes/%d", processingSize));
request->SetStorage(wxWebRequest::Storage_None);
Run();
REQUIRE( request->GetBytesReceived() == processingSize );
REQUIRE( dataSize == processingSize );
}
SECTION("PUT file data")
{
Create("/put");