]> git.saurik.com Git - wxWidgets.git/blame - src/common/url.cpp
don't crash when loading images with verbose==false (patch 1449823)
[wxWidgets.git] / src / common / url.cpp
CommitLineData
f4ada568
GL
1/////////////////////////////////////////////////////////////////////////////
2// Name: 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
65571936 9// Licence: wxWindows licence
f4ada568
GL
10/////////////////////////////////////////////////////////////////////////////
11
fcc6dddd
JS
12// For compilers that support precompilation, includes "wx.h".
13#include "wx/wxprec.h"
14
15#ifdef __BORLANDC__
16#pragma hdrstop
17#endif
18
a5d46b73 19#if wxUSE_URL
f4ada568 20
3096bd2f
VZ
21#include "wx/string.h"
22#include "wx/list.h"
23#include "wx/utils.h"
c092213d 24#include "wx/module.h"
3096bd2f 25#include "wx/url.h"
f4ada568 26
a5d46b73
VZ
27#include <string.h>
28#include <ctype.h>
29
f4ada568 30IMPLEMENT_CLASS(wxProtoInfo, wxObject)
b60b2ec8 31IMPLEMENT_CLASS(wxURL, wxURI)
f4ada568
GL
32
33// Protocols list
b2b35524 34wxProtoInfo *wxURL::ms_protocols = NULL;
8a4df159 35
f92f546c 36// Enforce linking of protocol classes:
f92f546c
VS
37USE_PROTOCOL(wxFileProto)
38
ce195ee6 39#if wxUSE_PROTOCOL_HTTP
f80eabe5 40USE_PROTOCOL(wxHTTP)
f80eabe5 41
b2b35524 42 wxHTTP *wxURL::ms_proxyDefault = NULL;
cb719f2e 43 bool wxURL::ms_useDefaultProxy = false;
8a4df159 44#endif
f4ada568 45
ce195ee6
MB
46#if wxUSE_PROTOCOL_FTP
47USE_PROTOCOL(wxFTP)
48#endif
49
fae05df5 50// --------------------------------------------------------------
b60b2ec8
RN
51//
52// wxURL
53//
fae05df5 54// --------------------------------------------------------------
f4ada568 55
ce321570
RN
56// --------------------------------------------------------------
57// Construction
58// --------------------------------------------------------------
59
b60b2ec8
RN
60wxURL::wxURL(const wxString& url) : wxURI(url)
61{
62 Init(url);
63 ParseURL();
64}
65
66wxURL::wxURL(const wxURI& url) : wxURI(url)
67{
86470d43 68 Init(url.BuildURI());
b60b2ec8
RN
69 ParseURL();
70}
71
b60b2ec8 72void wxURL::Init(const wxString& url)
f4ada568 73{
b2b35524
VZ
74 m_protocol = NULL;
75 m_error = wxURL_NOERR;
76 m_url = url;
25959b95
VZ
77#if wxUSE_URL_NATIVE
78 m_nativeImp = CreateNativeImpObject();
79#endif
b2b35524 80
ce195ee6 81#if wxUSE_PROTOCOL_HTTP
b2b35524
VZ
82 if ( ms_useDefaultProxy && !ms_proxyDefault )
83 {
2b5f62a0 84 SetDefaultProxy( wxGetenv(wxT("HTTP_PROXY")) );
b2b35524
VZ
85
86 if ( !ms_proxyDefault )
87 {
88 // don't try again
cb719f2e 89 ms_useDefaultProxy = false;
b2b35524
VZ
90 }
91 }
92
93 m_useProxy = ms_proxyDefault != NULL;
94 m_proxy = ms_proxyDefault;
ce195ee6 95#endif // wxUSE_PROTOCOL_HTTP
b2b35524 96
f4ada568 97}
ce321570
RN
98
99// --------------------------------------------------------------
100// Assignment
101// --------------------------------------------------------------
102
103wxURL& wxURL::operator = (const wxURI& url)
104{
105 wxURI::operator = (url);
106 Init(url.BuildURI());
107 ParseURL();
108 return *this;
109}
110wxURL& wxURL::operator = (const wxString& url)
111{
112 wxURI::operator = (url);
113 Init(url);
114 ParseURL();
115 return *this;
116}
117
b60b2ec8
RN
118// --------------------------------------------------------------
119// ParseURL
120//
121// Builds the URL and takes care of the old protocol stuff
122// --------------------------------------------------------------
f4ada568
GL
123
124bool wxURL::ParseURL()
125{
fd725bce
WS
126 // If the URL was already parsed (m_protocol != NULL), pass this section.
127 if (!m_protocol)
f6bcfd97 128 {
fd725bce
WS
129 // Clean up
130 CleanData();
f61815af 131
fd725bce
WS
132 // Make sure we have a protocol/scheme
133 if (!HasScheme())
134 {
135 m_error = wxURL_SNTXERR;
136 return false;
137 }
f61815af 138
fd725bce
WS
139 // Find and create the protocol object
140 if (!FetchProtocol())
141 {
142 m_error = wxURL_NOPROTO;
143 return false;
144 }
145
146 // Do we need a host name ?
147 if (m_protoinfo->m_needhost)
148 {
149 // Make sure we have one, then
150 if (!HasServer())
151 {
152 m_error = wxURL_SNTXERR;
153 return false;
154 }
155 }
f61815af 156 }
f4ada568 157
ce195ee6 158#if wxUSE_PROTOCOL_HTTP
fd725bce
WS
159 if (m_useProxy)
160 {
161 // Third, we rebuild the URL.
162 m_url = m_scheme + wxT(":");
163 if (m_protoinfo->m_needhost)
164 m_url = m_url + wxT("//") + m_server;
165
166 // We initialize specific variables.
167 m_protocol = m_proxy; // FIXME: we should clone the protocol
168 }
ce195ee6 169#endif // wxUSE_PROTOCOL_HTTP
f4ada568 170
fd725bce
WS
171 m_error = wxURL_NOERR;
172 return true;
f4ada568
GL
173}
174
ce321570
RN
175// --------------------------------------------------------------
176// Destruction/Cleanup
177// --------------------------------------------------------------
178
f4ada568
GL
179void wxURL::CleanData()
180{
ce195ee6 181#if wxUSE_PROTOCOL_HTTP
fd725bce 182 if (!m_useProxy)
ce195ee6 183#endif // wxUSE_PROTOCOL_HTTP
fd725bce 184 delete m_protocol;
f4ada568
GL
185}
186
187wxURL::~wxURL()
188{
25959b95 189 CleanData();
ce195ee6 190#if wxUSE_PROTOCOL_HTTP
25959b95
VZ
191 if (m_proxy && m_proxy != ms_proxyDefault)
192 delete m_proxy;
ce195ee6 193#endif // wxUSE_PROTOCOL_HTTP
25959b95
VZ
194#if wxUSE_URL_NATIVE
195 delete m_nativeImp;
8a4df159 196#endif
f4ada568
GL
197}
198
ce321570
RN
199// --------------------------------------------------------------
200// FetchProtocol
201// --------------------------------------------------------------
f4ada568
GL
202
203bool wxURL::FetchProtocol()
204{
fd725bce 205 wxProtoInfo *info = ms_protocols;
f4ada568 206
fd725bce 207 while (info)
f6bcfd97 208 {
fd725bce
WS
209 if (m_scheme == info->m_protoname)
210 {
211 if (m_port.IsNull())
212 m_port = info->m_servname;
213 m_protoinfo = info;
214 m_protocol = (wxProtocol *)m_protoinfo->m_cinfo->CreateObject();
215 return true;
216 }
217 info = info->next;
f4ada568 218 }
fd725bce 219 return false;
f4ada568
GL
220}
221
fae05df5 222// --------------------------------------------------------------
ce321570 223// GetInputStream
fae05df5
GL
224// --------------------------------------------------------------
225
58c837a4 226wxInputStream *wxURL::GetInputStream()
f4ada568 227{
fd725bce
WS
228 if (!m_protocol)
229 {
230 m_error = wxURL_NOPROTO;
231 return NULL;
232 }
233
234 m_error = wxURL_NOERR;
235 if (HasUserInfo())
236 {
237 size_t dwPasswordPos = m_userinfo.find(':');
238
239 if (dwPasswordPos == wxString::npos)
240 m_protocol->SetUser(m_userinfo);
241 else
242 {
243 m_protocol->SetUser(m_userinfo(0, dwPasswordPos));
244 m_protocol->SetPassword(m_userinfo(dwPasswordPos+1, m_userinfo.length() + 1));
245 }
246 }
856d2e52 247
25959b95 248#if wxUSE_URL_NATIVE
fd725bce
WS
249 // give the native implementation to return a better stream
250 // such as the native WinINet functionality under MS-Windows
251 if (m_nativeImp)
252 {
253 wxInputStream *rc;
254 rc = m_nativeImp->GetInputStream(this);
255 if (rc != 0)
256 return rc;
257 }
258 // else use the standard behaviour
25959b95
VZ
259#endif // wxUSE_URL_NATIVE
260
8a4df159 261#if wxUSE_SOCKETS
19e0e04b
RD
262 wxIPV4address addr;
263
fd725bce
WS
264 // m_protoinfo is NULL when we use a proxy
265 if (!m_useProxy && m_protoinfo->m_needhost)
f6bcfd97 266 {
fd725bce
WS
267 if (!addr.Hostname(m_server))
268 {
269 m_error = wxURL_NOHOST;
270 return NULL;
271 }
272
273 addr.Service(m_port);
274
275 if (!m_protocol->Connect(addr, true)) // Watcom needs the 2nd arg for some reason
276 {
277 m_error = wxURL_CONNERR;
278 return NULL;
279 }
f4ada568 280 }
fd725bce
WS
281#endif
282
283 wxString fullPath;
f4ada568 284
fd725bce
WS
285 // When we use a proxy, we have to pass the whole URL to it.
286 if (m_useProxy)
287 fullPath += m_url;
f4ada568 288
fd725bce
WS
289 if(m_path.empty())
290 fullPath += wxT("/");
291 else
292 fullPath += m_path;
293
294 if (HasQuery())
295 fullPath += wxT("?") + m_query;
296
297 if (HasFragment())
298 fullPath += wxT("#") + m_fragment;
299
300 wxInputStream *the_i_stream = m_protocol->GetInputStream(fullPath);
301
302 if (!the_i_stream)
8a2c6ef8 303 {
fd725bce
WS
304 m_error = wxURL_PROTOERR;
305 return NULL;
f4ada568 306 }
f4ada568 307
fd725bce 308 return the_i_stream;
f4ada568
GL
309}
310
ce195ee6 311#if wxUSE_PROTOCOL_HTTP
f4ada568
GL
312void wxURL::SetDefaultProxy(const wxString& url_proxy)
313{
fd725bce
WS
314 if ( !url_proxy )
315 {
316 if ( ms_proxyDefault )
317 {
318 ms_proxyDefault->Close();
319 delete ms_proxyDefault;
320 ms_proxyDefault = NULL;
321 }
322 }
323 else
324 {
325 wxString tmp_str = url_proxy;
326 int pos = tmp_str.Find(wxT(':'));
327 if (pos == wxNOT_FOUND)
328 return;
329
330 wxString hostname = tmp_str(0, pos),
331 port = tmp_str(pos+1, tmp_str.Length()-pos);
332 wxIPV4address addr;
333
334 if (!addr.Hostname(hostname))
335 return;
336 if (!addr.Service(port))
337 return;
338
339 if (ms_proxyDefault)
340 // Finally, when all is right, we connect the new proxy.
341 ms_proxyDefault->Close();
342 else
343 ms_proxyDefault = new wxHTTP();
344 ms_proxyDefault->Connect(addr, true); // Watcom needs the 2nd arg for some reason
345 }
f4ada568
GL
346}
347
348void wxURL::SetProxy(const wxString& url_proxy)
349{
b2b35524
VZ
350 if ( !url_proxy )
351 {
352 if ( m_proxy && m_proxy != ms_proxyDefault )
353 {
354 m_proxy->Close();
355 delete m_proxy;
356 }
f4ada568 357
cb719f2e 358 m_useProxy = false;
b2b35524
VZ
359 }
360 else
361 {
362 wxString tmp_str;
363 wxString hostname, port;
364 int pos;
365 wxIPV4address addr;
366
367 tmp_str = url_proxy;
368 pos = tmp_str.Find(wxT(':'));
369 // This is an invalid proxy name.
cb719f2e 370 if (pos == wxNOT_FOUND)
b2b35524
VZ
371 return;
372
373 hostname = tmp_str(0, pos);
bb80bb5b 374 port = tmp_str(pos+1, tmp_str.Length()-pos);
b2b35524
VZ
375
376 addr.Hostname(hostname);
377 addr.Service(port);
378
379 // Finally, create the whole stuff.
380 if (m_proxy && m_proxy != ms_proxyDefault)
381 delete m_proxy;
382 m_proxy = new wxHTTP();
cb719f2e 383 m_proxy->Connect(addr, true); // Watcom needs the 2nd arg for some reason
b2b35524
VZ
384
385 CleanData();
386 // Reparse url.
cb719f2e 387 m_useProxy = true;
b2b35524
VZ
388 ParseURL();
389 }
f4ada568 390}
ce195ee6 391#endif // wxUSE_PROTOCOL_HTTP
35a4dab7 392
b2b35524 393// ----------------------------------------------------------------------
ce321570
RN
394// wxURLModule
395//
b2b35524
VZ
396// A module which deletes the default proxy if we created it
397// ----------------------------------------------------------------------
398
399#if wxUSE_SOCKETS
400
401class wxURLModule : public wxModule
402{
403public:
404 virtual bool OnInit();
405 virtual void OnExit();
406
407private:
408 DECLARE_DYNAMIC_CLASS(wxURLModule)
409};
410
411IMPLEMENT_DYNAMIC_CLASS(wxURLModule, wxModule)
412
413bool wxURLModule::OnInit()
414{
ce195ee6 415#if wxUSE_PROTOCOL_HTTP
b2b35524
VZ
416 // env var HTTP_PROXY contains the address of the default proxy to use if
417 // set, but don't try to create this proxy right now because it will slow
418 // down the program startup (especially if there is no DNS server
419 // available, in which case it may take up to 1 minute)
f6bcfd97 420
67acaf80 421 if ( wxGetenv(_T("HTTP_PROXY")) )
b2b35524 422 {
cb719f2e 423 wxURL::ms_useDefaultProxy = true;
b2b35524 424 }
ce195ee6 425#endif // wxUSE_PROTOCOL_HTTP
cb719f2e 426 return true;
b2b35524
VZ
427}
428
429void wxURLModule::OnExit()
430{
ce195ee6 431#if wxUSE_PROTOCOL_HTTP
b2b35524
VZ
432 delete wxURL::ms_proxyDefault;
433 wxURL::ms_proxyDefault = NULL;
ce195ee6 434#endif // wxUSE_PROTOCOL_HTTP
b2b35524
VZ
435}
436
437#endif // wxUSE_SOCKETS
a5d46b73 438
97d8fe87
VZ
439// ---------------------------------------------------------------------------
440//
441// wxURL Compatibility
442//
443// ---------------------------------------------------------------------------
444
445#if WXWIN_COMPATIBILITY_2_4
446
447#include "wx/url.h"
448
449wxString wxURL::GetProtocolName() const
450{
451 return m_scheme;
452}
453
454wxString wxURL::GetHostName() const
455{
456 return m_server;
457}
458
459wxString wxURL::GetPath() const
460{
461 return m_path;
462}
463
464//Note that this old code really doesn't convert to a URI that well and looks
465//more like a dirty hack than anything else...
466
467wxString wxURL::ConvertToValidURI(const wxString& uri, const wxChar* delims)
468{
469 wxString out_str;
470 wxString hexa_code;
471 size_t i;
472
473 for (i = 0; i < uri.Len(); i++)
474 {
475 wxChar c = uri.GetChar(i);
476
477 if (c == wxT(' '))
478 {
479 // GRG, Apr/2000: changed to "%20" instead of '+'
480
481 out_str += wxT("%20");
482 }
483 else
484 {
485 // GRG, Apr/2000: modified according to the URI definition (RFC 2396)
486 //
487 // - Alphanumeric characters are never escaped
488 // - Unreserved marks are never escaped
489 // - Delimiters must be escaped if they appear within a component
490 // but not if they are used to separate components. Here we have
491 // no clear way to distinguish between these two cases, so they
492 // are escaped unless they are passed in the 'delims' parameter
493 // (allowed delimiters).
494
495 static const wxChar marks[] = wxT("-_.!~*()'");
496
497 if ( !wxIsalnum(c) && !wxStrchr(marks, c) && !wxStrchr(delims, c) )
498 {
499 hexa_code.Printf(wxT("%%%02X"), c);
500 out_str += hexa_code;
501 }
502 else
503 {
504 out_str += c;
505 }
506 }
507 }
508
509 return out_str;
510}
511
512wxString wxURL::ConvertFromURI(const wxString& uri)
513{
514 return wxURI::Unescape(uri);
515}
516
517#endif //WXWIN_COMPATIBILITY_2_4
518
a5d46b73 519#endif // wxUSE_URL