Fix using wxHTTP and wxFTP from worker thread in Unix ports.
This backportse18c8fd29a,d421373c2eand6c43aa90b6from master to avoid crashes when using wxHTTP or wxFTP from threads other than main. See #17031.
This commit is contained in:
@@ -608,6 +608,7 @@ wxGTK:
|
|||||||
- Fix crashes in wxGTK3 when running with non-X11 backend (Marco Trevisan).
|
- Fix crashes in wxGTK3 when running with non-X11 backend (Marco Trevisan).
|
||||||
- Fix coordinates of wxSetCursorEvent propagated to parent windows.
|
- Fix coordinates of wxSetCursorEvent propagated to parent windows.
|
||||||
- Fix GTK+ warnings when refreshing wxListCtrl items (Scott Talbert).
|
- Fix GTK+ warnings when refreshing wxListCtrl items (Scott Talbert).
|
||||||
|
- Fix using wxHTTP and wxFTP from worker thread.
|
||||||
|
|
||||||
wxMSW:
|
wxMSW:
|
||||||
|
|
||||||
@@ -632,6 +633,7 @@ wxOSX:
|
|||||||
|
|
||||||
- Compilation fix for wxWebView under 10.10.
|
- Compilation fix for wxWebView under 10.10.
|
||||||
- Fix conversion of wxBitmap to wxImage in 64 bit builds.
|
- Fix conversion of wxBitmap to wxImage in 64 bit builds.
|
||||||
|
- Fix using wxHTTP and wxFTP from worker thread.
|
||||||
- Fix wxFileDialog::GetFilterIndex() for file open dialogs (phsilva).
|
- Fix wxFileDialog::GetFilterIndex() for file open dialogs (phsilva).
|
||||||
- Fix custom paper support (tijsv).
|
- Fix custom paper support (tijsv).
|
||||||
|
|
||||||
|
|||||||
@@ -308,6 +308,9 @@ public:
|
|||||||
protected:
|
protected:
|
||||||
wxSocketImpl(wxSocketBase& wxsocket);
|
wxSocketImpl(wxSocketBase& wxsocket);
|
||||||
|
|
||||||
|
// get the associated socket flags
|
||||||
|
wxSocketFlags GetSocketFlags() const { return m_wxsocket->GetFlags(); }
|
||||||
|
|
||||||
// true if we're a listening stream socket
|
// true if we're a listening stream socket
|
||||||
bool m_server;
|
bool m_server;
|
||||||
|
|
||||||
|
|||||||
@@ -31,6 +31,7 @@
|
|||||||
#include "wx/socket.h"
|
#include "wx/socket.h"
|
||||||
#include "wx/url.h"
|
#include "wx/url.h"
|
||||||
#include "wx/sstream.h"
|
#include "wx/sstream.h"
|
||||||
|
#include "wx/thread.h"
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
// --------------------------------------------------------------------------
|
// --------------------------------------------------------------------------
|
||||||
@@ -575,23 +576,13 @@ void MyFrame::OnDatagram(wxCommandEvent& WXUNUSED(event))
|
|||||||
|
|
||||||
#if wxUSE_URL
|
#if wxUSE_URL
|
||||||
|
|
||||||
void MyFrame::OnTestURL(wxCommandEvent& WXUNUSED(event))
|
void DoDownload(const wxString& urlname)
|
||||||
{
|
{
|
||||||
// Ask for the URL
|
wxString testname("URL");
|
||||||
static wxString s_urlname("http://www.google.com/");
|
if ( !wxIsMainThread() )
|
||||||
wxString urlname = wxGetTextFromUser
|
testname += " in worker thread";
|
||||||
(
|
|
||||||
_("Enter an URL to get"),
|
|
||||||
_("URL:"),
|
|
||||||
s_urlname
|
|
||||||
);
|
|
||||||
if ( urlname.empty() )
|
|
||||||
return; // cancelled by user
|
|
||||||
|
|
||||||
s_urlname = urlname;
|
TestLogger logtest(testname);
|
||||||
|
|
||||||
|
|
||||||
TestLogger logtest("URL");
|
|
||||||
|
|
||||||
// Parse the URL
|
// Parse the URL
|
||||||
wxURL url(urlname);
|
wxURL url(urlname);
|
||||||
@@ -626,6 +617,51 @@ void MyFrame::OnTestURL(wxCommandEvent& WXUNUSED(event))
|
|||||||
urlname, sout.GetString());
|
urlname, sout.GetString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MyFrame::OnTestURL(wxCommandEvent& WXUNUSED(event))
|
||||||
|
{
|
||||||
|
// Ask for the URL
|
||||||
|
static wxString s_urlname("http://www.google.com/");
|
||||||
|
wxString urlname = wxGetTextFromUser
|
||||||
|
(
|
||||||
|
_("Enter an URL to get"),
|
||||||
|
_("URL:"),
|
||||||
|
s_urlname
|
||||||
|
);
|
||||||
|
if ( urlname.empty() )
|
||||||
|
return; // cancelled by user
|
||||||
|
|
||||||
|
s_urlname = urlname;
|
||||||
|
|
||||||
|
// First do it in this thread.
|
||||||
|
DoDownload(urlname);
|
||||||
|
|
||||||
|
// And then also in a worker thread.
|
||||||
|
#if wxUSE_THREADS
|
||||||
|
class DownloadThread : public wxThread
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit DownloadThread(const wxString& url): m_url(url)
|
||||||
|
{
|
||||||
|
Run();
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void* Entry() wxOVERRIDE
|
||||||
|
{
|
||||||
|
DoDownload(m_url);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
const wxString m_url;
|
||||||
|
};
|
||||||
|
|
||||||
|
// NB: there is a race condition here, we don't check for this thread
|
||||||
|
// termination before exiting the application, don't do this in real code!
|
||||||
|
new DownloadThread(urlname);
|
||||||
|
#endif // wxUSE_THREADS
|
||||||
|
}
|
||||||
|
|
||||||
#endif // wxUSE_URL
|
#endif // wxUSE_URL
|
||||||
|
|
||||||
void MyFrame::OnSocketEvent(wxSocketEvent& event)
|
void MyFrame::OnSocketEvent(wxSocketEvent& event)
|
||||||
|
|||||||
@@ -79,8 +79,6 @@ wxFTP::wxFTP()
|
|||||||
m_username = wxT("anonymous");
|
m_username = wxT("anonymous");
|
||||||
m_password << wxGetUserId() << wxT('@') << wxGetFullHostName();
|
m_password << wxGetUserId() << wxT('@') << wxGetFullHostName();
|
||||||
|
|
||||||
SetNotify(0);
|
|
||||||
SetFlags(wxSOCKET_NOWAIT);
|
|
||||||
m_bPassive = true;
|
m_bPassive = true;
|
||||||
m_bEncounteredError = false;
|
m_bEncounteredError = false;
|
||||||
}
|
}
|
||||||
@@ -782,8 +780,6 @@ wxInputStream *wxFTP::GetInputStream(const wxString& path)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
sock->SetFlags(wxSOCKET_WAITALL);
|
|
||||||
|
|
||||||
m_streaming = true;
|
m_streaming = true;
|
||||||
|
|
||||||
wxInputFTPStream *in_stream = new wxInputFTPStream(this, sock);
|
wxInputFTPStream *in_stream = new wxInputFTPStream(this, sock);
|
||||||
|
|||||||
@@ -22,7 +22,6 @@
|
|||||||
|
|
||||||
#ifndef WX_PRECOMP
|
#ifndef WX_PRECOMP
|
||||||
#include "wx/string.h"
|
#include "wx/string.h"
|
||||||
#include "wx/app.h"
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "wx/tokenzr.h"
|
#include "wx/tokenzr.h"
|
||||||
@@ -48,8 +47,6 @@ wxHTTP::wxHTTP()
|
|||||||
m_read = false;
|
m_read = false;
|
||||||
m_proxy_mode = false;
|
m_proxy_mode = false;
|
||||||
m_http_response = 0;
|
m_http_response = 0;
|
||||||
|
|
||||||
SetNotify(wxSOCKET_LOST_FLAG);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
wxHTTP::~wxHTTP()
|
wxHTTP::~wxHTTP()
|
||||||
@@ -370,16 +367,6 @@ bool wxHTTP::BuildRequest(const wxString& path, const wxString& method)
|
|||||||
SetHeader(wxT("Authorization"), GenerateAuthString(m_username, m_password));
|
SetHeader(wxT("Authorization"), GenerateAuthString(m_username, m_password));
|
||||||
}
|
}
|
||||||
|
|
||||||
SaveState();
|
|
||||||
|
|
||||||
// we may use non blocking sockets only if we can dispatch events from them
|
|
||||||
int flags = wxIsMainThread() && wxApp::IsMainLoopRunning() ? wxSOCKET_NONE
|
|
||||||
: wxSOCKET_BLOCK;
|
|
||||||
// and we must use wxSOCKET_WAITALL to ensure that all data is sent
|
|
||||||
flags |= wxSOCKET_WAITALL;
|
|
||||||
SetFlags(flags);
|
|
||||||
Notify(false);
|
|
||||||
|
|
||||||
wxString buf;
|
wxString buf;
|
||||||
buf.Printf(wxT("%s %s HTTP/1.0\r\n"), method, path);
|
buf.Printf(wxT("%s %s HTTP/1.0\r\n"), method, path);
|
||||||
const wxWX2MBbuf pathbuf = buf.mb_str();
|
const wxWX2MBbuf pathbuf = buf.mb_str();
|
||||||
@@ -395,10 +382,8 @@ bool wxHTTP::BuildRequest(const wxString& path, const wxString& method)
|
|||||||
|
|
||||||
wxString tmp_str;
|
wxString tmp_str;
|
||||||
m_lastError = ReadLine(this, tmp_str);
|
m_lastError = ReadLine(this, tmp_str);
|
||||||
if (m_lastError != wxPROTO_NOERR) {
|
if (m_lastError != wxPROTO_NOERR)
|
||||||
RestoreState();
|
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
if (!tmp_str.Contains(wxT("HTTP/"))) {
|
if (!tmp_str.Contains(wxT("HTTP/"))) {
|
||||||
// TODO: support HTTP v0.9 which can have no header.
|
// TODO: support HTTP v0.9 which can have no header.
|
||||||
@@ -441,7 +426,7 @@ bool wxHTTP::BuildRequest(const wxString& path, const wxString& method)
|
|||||||
|
|
||||||
m_lastError = wxPROTO_NOERR;
|
m_lastError = wxPROTO_NOERR;
|
||||||
ret_value = ParseHeaders();
|
ret_value = ParseHeaders();
|
||||||
RestoreState();
|
|
||||||
return ret_value;
|
return ret_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -540,9 +525,6 @@ wxInputStream *wxHTTP::GetInputStream(const wxString& path)
|
|||||||
|
|
||||||
inp_stream->m_read_bytes = 0;
|
inp_stream->m_read_bytes = 0;
|
||||||
|
|
||||||
Notify(false);
|
|
||||||
SetFlags(wxSOCKET_BLOCK | wxSOCKET_WAITALL);
|
|
||||||
|
|
||||||
// no error; reset m_lastError
|
// no error; reset m_lastError
|
||||||
m_lastError = wxPROTO_NOERR;
|
m_lastError = wxPROTO_NOERR;
|
||||||
return inp_stream;
|
return inp_stream;
|
||||||
|
|||||||
@@ -21,6 +21,7 @@
|
|||||||
#include "wx/protocol/log.h"
|
#include "wx/protocol/log.h"
|
||||||
|
|
||||||
#ifndef WX_PRECOMP
|
#ifndef WX_PRECOMP
|
||||||
|
#include "wx/app.h"
|
||||||
#include "wx/module.h"
|
#include "wx/module.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -63,7 +64,10 @@ IMPLEMENT_ABSTRACT_CLASS(wxProtocol, wxObject)
|
|||||||
|
|
||||||
wxProtocol::wxProtocol()
|
wxProtocol::wxProtocol()
|
||||||
#if wxUSE_SOCKETS
|
#if wxUSE_SOCKETS
|
||||||
: wxSocketClient()
|
// Only use non blocking sockets if we can dispatch events.
|
||||||
|
: wxSocketClient((wxIsMainThread() && wxApp::IsMainLoopRunning()
|
||||||
|
? wxSOCKET_NONE
|
||||||
|
: wxSOCKET_BLOCK) | wxSOCKET_WAITALL)
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
m_lastError = wxPROTO_NOERR;
|
m_lastError = wxPROTO_NOERR;
|
||||||
|
|||||||
@@ -98,6 +98,11 @@ wxSocketError wxSocketImplUnix::GetLastError() const
|
|||||||
|
|
||||||
void wxSocketImplUnix::DoEnableEvents(int flags, bool enable)
|
void wxSocketImplUnix::DoEnableEvents(int flags, bool enable)
|
||||||
{
|
{
|
||||||
|
// No events for blocking sockets, they should be usable from the other
|
||||||
|
// threads and the events only work for the sockets used by the main one.
|
||||||
|
if ( GetSocketFlags() & wxSOCKET_BLOCK )
|
||||||
|
return;
|
||||||
|
|
||||||
wxSocketManager * const manager = wxSocketManager::Get();
|
wxSocketManager * const manager = wxSocketManager::Get();
|
||||||
if (!manager)
|
if (!manager)
|
||||||
return;
|
return;
|
||||||
|
|||||||
Reference in New Issue
Block a user