1 ///////////////////////////////////////////////////////////////////////////////
2 // Name:        wx/webrequest_curl.h
3 // Purpose:     wxWebRequest implementation using libcurl
4 // Author:      Tobias Taschner
5 // Created:     2018-10-25
6 // Copyright:   (c) 2018 wxWidgets development team
7 // Licence:     wxWindows licence
8 ///////////////////////////////////////////////////////////////////////////////
9 
10 #ifndef _WX_WEBREQUEST_CURL_H
11 #define _WX_WEBREQUEST_CURL_H
12 
13 #if wxUSE_WEBREQUEST_CURL
14 
15 #include "wx/private/webrequest.h"
16 
17 #include "wx/thread.h"
18 #include "wx/vector.h"
19 #include "wx/timer.h"
20 #include "wx/hashmap.h"
21 
22 #include "curl/curl.h"
23 
24 class wxWebRequestCURL;
25 class wxWebResponseCURL;
26 class wxWebSessionCURL;
27 class SocketPoller;
28 
29 class wxWebAuthChallengeCURL : public wxWebAuthChallengeImpl
30 {
31 public:
32     wxWebAuthChallengeCURL(wxWebAuthChallenge::Source source,
33                            wxWebRequestCURL& request);
34 
35     void SetCredentials(const wxWebCredentials& cred) wxOVERRIDE;
36 
37 private:
38     wxWebRequestCURL& m_request;
39 
40     wxDECLARE_NO_COPY_CLASS(wxWebAuthChallengeCURL);
41 };
42 
43 class wxWebRequestCURL : public wxWebRequestImpl
44 {
45 public:
46     wxWebRequestCURL(wxWebSession& session,
47                      wxWebSessionCURL& sessionImpl,
48                      wxEvtHandler* handler,
49                      const wxString& url,
50                      int id);
51 
52     ~wxWebRequestCURL();
53 
54     void Start() wxOVERRIDE;
55 
GetResponse()56     wxWebResponseImplPtr GetResponse() const wxOVERRIDE
57         { return m_response; }
58 
GetAuthChallenge()59     wxWebAuthChallengeImplPtr GetAuthChallenge() const wxOVERRIDE
60         { return m_authChallenge; }
61 
62     wxFileOffset GetBytesSent() const wxOVERRIDE;
63 
64     wxFileOffset GetBytesExpectedToSend() const wxOVERRIDE;
65 
GetHandle()66     CURL* GetHandle() const { return m_handle; }
67 
GetNativeHandle()68     wxWebRequestHandle GetNativeHandle() const wxOVERRIDE
69     {
70         return (wxWebRequestHandle)GetHandle();
71     }
72 
73     bool StartRequest();
74 
75     void HandleCompletion();
76 
77     wxString GetError() const;
78 
79     // Method called from libcurl callback
80     size_t CURLOnRead(char* buffer, size_t size);
81 
82 private:
83     void DoCancel() wxOVERRIDE;
84 
85     wxWebSessionCURL& m_sessionImpl;
86 
87     CURL* m_handle;
88     char m_errorBuffer[CURL_ERROR_SIZE];
89     struct curl_slist *m_headerList;
90     wxObjectDataPtr<wxWebResponseCURL> m_response;
91     wxObjectDataPtr<wxWebAuthChallengeCURL> m_authChallenge;
92     wxFileOffset m_bytesSent;
93 
94     void DestroyHeaderList();
95 
96     wxDECLARE_NO_COPY_CLASS(wxWebRequestCURL);
97 };
98 
99 class wxWebResponseCURL : public wxWebResponseImpl
100 {
101 public:
102     explicit wxWebResponseCURL(wxWebRequestCURL& request);
103 
104     wxFileOffset GetContentLength() const wxOVERRIDE;
105 
106     wxString GetURL() const wxOVERRIDE;
107 
108     wxString GetHeader(const wxString& name) const wxOVERRIDE;
109 
110     int GetStatus() const wxOVERRIDE;
111 
GetStatusText()112     wxString GetStatusText() const wxOVERRIDE { return m_statusText; }
113 
114 
115     // Methods called from libcurl callbacks
116     size_t CURLOnWrite(void *buffer, size_t size);
117     size_t CURLOnHeader(const char* buffer, size_t size);
118     int CURLOnProgress(curl_off_t);
119 
120 private:
121     wxWebRequestHeaderMap m_headers;
122     wxString m_statusText;
123     wxFileOffset m_knownDownloadSize;
124 
GetHandle()125     CURL* GetHandle() const
126     { return static_cast<wxWebRequestCURL&>(m_request).GetHandle(); }
127 
128     wxDECLARE_NO_COPY_CLASS(wxWebResponseCURL);
129 };
130 
131 class wxWebSessionCURL : public wxWebSessionImpl, public wxEvtHandler
132 {
133 public:
134     wxWebSessionCURL();
135 
136     ~wxWebSessionCURL();
137 
138     wxWebRequestImplPtr
139     CreateRequest(wxWebSession& session,
140                   wxEvtHandler* handler,
141                   const wxString& url,
142                   int id = wxID_ANY) wxOVERRIDE;
143 
144     wxVersionInfo GetLibraryVersionInfo() wxOVERRIDE;
145 
GetNativeHandle()146     wxWebSessionHandle GetNativeHandle() const wxOVERRIDE
147     {
148         return (wxWebSessionHandle)m_handle;
149     }
150 
151     bool StartRequest(wxWebRequestCURL& request);
152 
153     void CancelRequest(wxWebRequestCURL* request);
154 
155     void RequestHasTerminated(wxWebRequestCURL* request);
156 
157     static bool CurlRuntimeAtLeastVersion(unsigned int, unsigned int,
158                                           unsigned int);
159 
160 private:
161     static int TimerCallback(CURLM*, long, void*);
162     static int SocketCallback(CURL*, curl_socket_t, int, void*, void*);
163 
164     void ProcessTimerCallback(long);
165     void TimeoutNotification(wxTimerEvent&);
166     void ProcessTimeoutNotification();
167     void ProcessSocketCallback(CURL*, curl_socket_t, int);
168     void ProcessSocketPollerResult(wxThreadEvent&);
169     void CheckForCompletedTransfers();
170     void FailRequest(CURL*, const wxString&);
171     void StopActiveTransfer(CURL*);
172     void RemoveActiveSocket(CURL*);
173 
174     WX_DECLARE_HASH_MAP(CURL*, wxWebRequestCURL*, wxPointerHash, \
175                         wxPointerEqual, TransferSet);
176 
177     WX_DECLARE_HASH_MAP(CURL*, curl_socket_t, wxPointerHash, \
178                         wxPointerEqual, CurlSocketMap);
179 
180     TransferSet m_activeTransfers;
181     CurlSocketMap m_activeSockets;
182 
183     SocketPoller* m_socketPoller;
184     wxTimer m_timeoutTimer;
185     CURLM* m_handle;
186 
187     static int ms_activeSessions;
188     static unsigned int ms_runtimeVersion;
189 
190     wxDECLARE_NO_COPY_CLASS(wxWebSessionCURL);
191 };
192 
193 class wxWebSessionFactoryCURL : public wxWebSessionFactory
194 {
195 public:
Create()196     wxWebSessionImpl* Create() wxOVERRIDE
197     { return new wxWebSessionCURL(); }
198 };
199 
200 #endif // wxUSE_WEBREQUEST_CURL
201 
202 #endif
203