]> git.saurik.com Git - wxWidgets.git/blame_incremental - src/common/url.cpp
fixing overrelease and out-of-bounds write, fixes #13725
[wxWidgets.git] / src / common / url.cpp
... / ...
CommitLineData
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
33IMPLEMENT_CLASS(wxURL, wxURI)
34
35// Protocols list
36wxProtoInfo *wxURL::ms_protocols = NULL;
37
38// Enforce linking of protocol classes:
39USE_PROTOCOL(wxFileProto)
40
41#if wxUSE_PROTOCOL_HTTP
42USE_PROTOCOL(wxHTTP)
43
44 wxHTTP *wxURL::ms_proxyDefault = NULL;
45 bool wxURL::ms_useDefaultProxy = false;
46#endif
47
48#if wxUSE_PROTOCOL_FTP
49USE_PROTOCOL(wxFTP)
50#endif
51
52// --------------------------------------------------------------
53//
54// wxURL
55//
56// --------------------------------------------------------------
57
58// --------------------------------------------------------------
59// Construction
60// --------------------------------------------------------------
61
62wxURL::wxURL(const wxString& url) : wxURI(url)
63{
64 Init(url);
65 ParseURL();
66}
67
68wxURL::wxURL(const wxURI& uri) : wxURI(uri)
69{
70 Init(uri.BuildURI());
71 ParseURL();
72}
73
74wxURL::wxURL(const wxURL& url) : wxURI(url)
75{
76 Init(url.GetURL());
77 ParseURL();
78}
79
80void 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
111wxURL& wxURL::operator = (const wxString& url)
112{
113 wxURI::operator = (url);
114 Free();
115 Init(url);
116 ParseURL();
117
118 return *this;
119}
120
121wxURL& 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
134wxURL& 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
153bool 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
210void 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
225void 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
237wxURL::~wxURL()
238{
239 Free();
240}
241
242// --------------------------------------------------------------
243// FetchProtocol
244// --------------------------------------------------------------
245
246bool 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
269wxInputStream *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
361void 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
396void 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
449class wxURLModule : public wxModule
450{
451public:
452 wxURLModule();
453
454 virtual bool OnInit();
455 virtual void OnExit();
456
457private:
458 DECLARE_DYNAMIC_CLASS(wxURLModule)
459};
460
461IMPLEMENT_DYNAMIC_CLASS(wxURLModule, wxModule)
462
463wxURLModule::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
470bool 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
486void 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