Implement additional storage targets
This commit is contained in:
parent
d4362f4bca
commit
c24efa9821
@ -89,7 +89,6 @@ public:
|
||||
HINTERNET GetHandle() const { return m_request; }
|
||||
|
||||
private:
|
||||
wxWebSessionWinHTTP& m_session;
|
||||
wxString m_url;
|
||||
HINTERNET m_connect;
|
||||
HINTERNET m_request;
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
|
@ -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()
|
||||
{
|
||||
|
@ -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();
|
||||
|
@ -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");
|
||||
|
Loading…
Reference in New Issue
Block a user