]> git.saurik.com Git - wxWidgets.git/blob - src/common/url.cpp
fixing overrelease and out-of-bounds write, fixes #13725
[wxWidgets.git] / src / common / url.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/common/url.cpp
3 // Purpose: URL parser
4 // Author: Guilhem Lavaux
5 // Modified by:
6 // Created: 20/07/1997
7 // RCS-ID: $Id$
8 // Copyright: (c) 1997, 1998 Guilhem Lavaux
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 // For compilers that support precompilation, includes "wx.h".
13 #include "wx/wxprec.h"
14
15 #ifdef __BORLANDC__
16 #pragma hdrstop
17 #endif
18
19 #if wxUSE_URL
20
21 #include "wx/url.h"
22
23 #ifndef WX_PRECOMP
24 #include "wx/list.h"
25 #include "wx/string.h"
26 #include "wx/utils.h"
27 #include "wx/module.h"
28 #endif
29
30 #include <string.h>
31 #include <ctype.h>
32
33 IMPLEMENT_CLASS(wxURL, wxURI)
34
35 // Protocols list
36 wxProtoInfo *wxURL::ms_protocols = NULL;
37
38 // Enforce linking of protocol classes:
39 USE_PROTOCOL(wxFileProto)
40
41 #if wxUSE_PROTOCOL_HTTP
42 USE_PROTOCOL(wxHTTP)
43
44 wxHTTP *wxURL::ms_proxyDefault = NULL;
45 bool wxURL::ms_useDefaultProxy = false;
46 #endif
47
48 #if wxUSE_PROTOCOL_FTP
49 USE_PROTOCOL(wxFTP)
50 #endif
51
52 // --------------------------------------------------------------
53 //
54 // wxURL
55 //
56 // --------------------------------------------------------------
57
58 // --------------------------------------------------------------
59 // Construction
60 // --------------------------------------------------------------
61
62 wxURL::wxURL(const wxString& url) : wxURI(url)
63 {
64 Init(url);
65 ParseURL();
66 }
67
68 wxURL::wxURL(const wxURI& uri) : wxURI(uri)
69 {
70 Init(uri.BuildURI());
71 ParseURL();
72 }
73
74 wxURL::wxURL(const wxURL& url) : wxURI(url)
75 {
76 Init(url.GetURL());
77 ParseURL();
78 }
79
80 void wxURL::Init(const wxString& url)
81 {
82 m_protocol = NULL;
83 m_error = wxURL_NOERR;
84 m_url = url;
85 #if wxUSE_URL_NATIVE
86 m_nativeImp = CreateNativeImpObject();
87 #endif
88
89 #if wxUSE_PROTOCOL_HTTP
90 if ( ms_useDefaultProxy && !ms_proxyDefault )
91 {
92 SetDefaultProxy( wxGetenv(wxT("HTTP_PROXY")) );
93
94 if ( !ms_proxyDefault )
95 {
96 // don't try again
97 ms_useDefaultProxy = false;
98 }
99 }
100
101 m_useProxy = ms_proxyDefault != NULL;
102 m_proxy = ms_proxyDefault;
103 #endif // wxUSE_PROTOCOL_HTTP
104
105 }
106
107 // --------------------------------------------------------------
108 // Assignment
109 // --------------------------------------------------------------
110
111 wxURL& wxURL::operator = (const wxString& url)
112 {
113 wxURI::operator = (url);
114 Free();
115 Init(url);
116 ParseURL();
117
118 return *this;
119 }
120
121 wxURL& wxURL::operator = (const wxURI& uri)
122 {
123 if (&uri != this)
124 {
125 wxURI::operator = (uri);
126 Free();
127 Init(uri.BuildURI());
128 ParseURL();
129 }
130
131 return *this;
132 }
133
134 wxURL& wxURL::operator = (const wxURL& url)
135 {
136 if (&url != this)
137 {
138 wxURI::operator = (url);
139 Free();
140 Init(url.GetURL());
141 ParseURL();
142 }
143
144 return *this;
145 }
146
147 // --------------------------------------------------------------
148 // ParseURL
149 //
150 // Builds the URL and takes care of the old protocol stuff
151 // --------------------------------------------------------------
152
153 bool wxURL::ParseURL()
154 {
155 // If the URL was already parsed (m_protocol != NULL), pass this section.
156 if (!m_protocol)
157 {
158 // Clean up
159 CleanData();
160
161 // Make sure we have a protocol/scheme
162 if (!HasScheme())
163 {
164 m_error = wxURL_SNTXERR;
165 return false;
166 }
167
168 // Find and create the protocol object
169 if (!FetchProtocol())
170 {
171 m_error = wxURL_NOPROTO;
172 return false;
173 }
174
175 // Do we need a host name ?
176 if (m_protoinfo->m_needhost)
177 {
178 // Make sure we have one, then
179 if (!HasServer())
180 {
181 m_error = wxURL_SNTXERR;
182 return false;
183 }
184 }
185 }
186
187 #if wxUSE_PROTOCOL_HTTP
188 if (m_useProxy)
189 {
190 // Third, we rebuild the URL.
191 m_url = m_scheme + wxT(":");
192 if (m_protoinfo->m_needhost)
193 m_url = m_url + wxT("//") + m_server;
194
195 // We initialize specific variables.
196 if (m_protocol)
197 m_protocol->Destroy();
198 m_protocol = m_proxy; // FIXME: we should clone the protocol
199 }
200 #endif // wxUSE_PROTOCOL_HTTP
201
202 m_error = wxURL_NOERR;
203 return true;
204 }
205
206 // --------------------------------------------------------------
207 // Destruction/Cleanup
208 // --------------------------------------------------------------
209
210 void wxURL::CleanData()
211 {
212 #if wxUSE_PROTOCOL_HTTP
213 if (!m_useProxy)
214 #endif // wxUSE_PROTOCOL_HTTP
215 {
216 if (m_protocol)
217 {
218 // Need to safely delete the socket (pending events)
219 m_protocol->Destroy();
220 m_protocol = NULL;
221 }
222 }
223 }
224
225 void wxURL::Free()
226 {
227 CleanData();
228 #if wxUSE_PROTOCOL_HTTP
229 if (m_proxy && m_proxy != ms_proxyDefault)
230 delete m_proxy;
231 #endif // wxUSE_PROTOCOL_HTTP
232 #if wxUSE_URL_NATIVE
233 delete m_nativeImp;
234 #endif
235 }
236
237 wxURL::~wxURL()
238 {
239 Free();
240 }
241
242 // --------------------------------------------------------------
243 // FetchProtocol
244 // --------------------------------------------------------------
245
246 bool wxURL::FetchProtocol()
247 {
248 wxProtoInfo *info = ms_protocols;
249
250 while (info)
251 {
252 if (m_scheme == info->m_protoname)
253 {
254 if ( m_port.empty() )
255 m_port = info->m_servname;
256 m_protoinfo = info;
257 m_protocol = (wxProtocol *)m_protoinfo->m_cinfo->CreateObject();
258 return true;
259 }
260 info = info->next;
261 }
262 return false;
263 }
264
265 // --------------------------------------------------------------
266 // GetInputStream
267 // --------------------------------------------------------------
268
269 wxInputStream *wxURL::GetInputStream()
270 {
271 if (!m_protocol)
272 {
273 m_error = wxURL_NOPROTO;
274 return NULL;
275 }
276
277 m_error = wxURL_NOERR;
278 if (HasUserInfo())
279 {
280 size_t dwPasswordPos = m_userinfo.find(':');
281
282 if (dwPasswordPos == wxString::npos)
283 m_protocol->SetUser(Unescape(m_userinfo));
284 else
285 {
286 m_protocol->SetUser(Unescape(m_userinfo(0, dwPasswordPos)));
287 m_protocol->SetPassword(Unescape(m_userinfo(dwPasswordPos+1, m_userinfo.length() + 1)));
288 }
289 }
290
291 #if wxUSE_URL_NATIVE
292 // give the native implementation to return a better stream
293 // such as the native WinINet functionality under MS-Windows
294 if (m_nativeImp)
295 {
296 wxInputStream *rc;
297 rc = m_nativeImp->GetInputStream(this);
298 if (rc != 0)
299 return rc;
300 }
301 // else use the standard behaviour
302 #endif // wxUSE_URL_NATIVE
303
304 #if wxUSE_SOCKETS
305 wxIPV4address addr;
306
307 // m_protoinfo is NULL when we use a proxy
308 if (
309 #if wxUSE_PROTOCOL_HTTP
310 !m_useProxy &&
311 #endif // wxUSE_PROTOCOL_HTTP
312 m_protoinfo->m_needhost )
313 {
314 if (!addr.Hostname(m_server))
315 {
316 m_error = wxURL_NOHOST;
317 return NULL;
318 }
319
320 addr.Service(m_port);
321
322 if (!m_protocol->Connect(addr, true)) // Watcom needs the 2nd arg for some reason
323 {
324 m_error = wxURL_CONNERR;
325 return NULL;
326 }
327 }
328 #endif // wxUSE_SOCKETS
329
330 wxString fullPath;
331
332 #if wxUSE_PROTOCOL_HTTP
333 // When we use a proxy, we have to pass the whole URL to it.
334 if (m_useProxy)
335 fullPath += m_url;
336 #endif // wxUSE_PROTOCOL_HTTP
337
338 if(m_path.empty())
339 fullPath += wxT("/");
340 else
341 fullPath += m_path;
342
343 if (HasQuery())
344 fullPath += wxT("?") + m_query;
345
346 if (HasFragment())
347 fullPath += wxT("#") + m_fragment;
348
349 wxInputStream *the_i_stream = m_protocol->GetInputStream(fullPath);
350
351 if (!the_i_stream)
352 {
353 m_error = wxURL_PROTOERR;
354 return NULL;
355 }
356
357 return the_i_stream;
358 }
359
360 #if wxUSE_PROTOCOL_HTTP
361 void wxURL::SetDefaultProxy(const wxString& url_proxy)
362 {
363 if ( !url_proxy )
364 {
365 if ( ms_proxyDefault )
366 {
367 ms_proxyDefault->Close();
368 wxDELETE(ms_proxyDefault);
369 }
370 }
371 else
372 {
373 wxString tmp_str = url_proxy;
374 int pos = tmp_str.Find(wxT(':'));
375 if (pos == wxNOT_FOUND)
376 return;
377
378 wxString hostname = tmp_str(0, pos),
379 port = tmp_str(pos+1, tmp_str.length()-pos);
380 wxIPV4address addr;
381
382 if (!addr.Hostname(hostname))
383 return;
384 if (!addr.Service(port))
385 return;
386
387 if (ms_proxyDefault)
388 // Finally, when all is right, we connect the new proxy.
389 ms_proxyDefault->Close();
390 else
391 ms_proxyDefault = new wxHTTP();
392 ms_proxyDefault->Connect(addr, true); // Watcom needs the 2nd arg for some reason
393 }
394 }
395
396 void wxURL::SetProxy(const wxString& url_proxy)
397 {
398 if ( !url_proxy )
399 {
400 if ( m_proxy && m_proxy != ms_proxyDefault )
401 {
402 m_proxy->Close();
403 delete m_proxy;
404 }
405
406 m_useProxy = false;
407 }
408 else
409 {
410 wxString tmp_str;
411 wxString hostname, port;
412 int pos;
413 wxIPV4address addr;
414
415 tmp_str = url_proxy;
416 pos = tmp_str.Find(wxT(':'));
417 // This is an invalid proxy name.
418 if (pos == wxNOT_FOUND)
419 return;
420
421 hostname = tmp_str(0, pos);
422 port = tmp_str(pos+1, tmp_str.length()-pos);
423
424 addr.Hostname(hostname);
425 addr.Service(port);
426
427 // Finally, create the whole stuff.
428 if (m_proxy && m_proxy != ms_proxyDefault)
429 delete m_proxy;
430 m_proxy = new wxHTTP();
431 m_proxy->Connect(addr, true); // Watcom needs the 2nd arg for some reason
432
433 CleanData();
434 // Reparse url.
435 m_useProxy = true;
436 ParseURL();
437 }
438 }
439 #endif // wxUSE_PROTOCOL_HTTP
440
441 // ----------------------------------------------------------------------
442 // wxURLModule
443 //
444 // A module which deletes the default proxy if we created it
445 // ----------------------------------------------------------------------
446
447 #if wxUSE_SOCKETS
448
449 class wxURLModule : public wxModule
450 {
451 public:
452 wxURLModule();
453
454 virtual bool OnInit();
455 virtual void OnExit();
456
457 private:
458 DECLARE_DYNAMIC_CLASS(wxURLModule)
459 };
460
461 IMPLEMENT_DYNAMIC_CLASS(wxURLModule, wxModule)
462
463 wxURLModule::wxURLModule()
464 {
465 // we must be cleaned up before wxSocketModule as otherwise deleting
466 // ms_proxyDefault from our OnExit() won't work (and can actually crash)
467 AddDependency(wxClassInfo::FindClass(wxT("wxSocketModule")));
468 }
469
470 bool wxURLModule::OnInit()
471 {
472 #if wxUSE_PROTOCOL_HTTP
473 // env var HTTP_PROXY contains the address of the default proxy to use if
474 // set, but don't try to create this proxy right now because it will slow
475 // down the program startup (especially if there is no DNS server
476 // available, in which case it may take up to 1 minute)
477
478 if ( wxGetenv(wxT("HTTP_PROXY")) )
479 {
480 wxURL::ms_useDefaultProxy = true;
481 }
482 #endif // wxUSE_PROTOCOL_HTTP
483 return true;
484 }
485
486 void wxURLModule::OnExit()
487 {
488 #if wxUSE_PROTOCOL_HTTP
489 wxDELETE(wxURL::ms_proxyDefault);
490 #endif // wxUSE_PROTOCOL_HTTP
491 }
492
493 #endif // wxUSE_SOCKETS
494
495
496 #endif // wxUSE_URL