]> git.saurik.com Git - wxWidgets.git/blame - src/common/url.cpp
Quote file names with spaces in wxFileType::ExpandCommand().
[wxWidgets.git] / src / common / url.cpp
CommitLineData
f4ada568 1/////////////////////////////////////////////////////////////////////////////
8ecff181 2// Name: src/common/url.cpp
f4ada568
GL
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__
8ecff181 16 #pragma hdrstop
fcc6dddd
JS
17#endif
18
a5d46b73 19#if wxUSE_URL
f4ada568 20
df91131c
WS
21#include "wx/url.h"
22
8ecff181
WS
23#ifndef WX_PRECOMP
24 #include "wx/list.h"
df91131c 25 #include "wx/string.h"
de6185e2 26 #include "wx/utils.h"
02761f6c 27 #include "wx/module.h"
8ecff181
WS
28#endif
29
a5d46b73
VZ
30#include <string.h>
31#include <ctype.h>
32
b60b2ec8 33IMPLEMENT_CLASS(wxURL, wxURI)
f4ada568
GL
34
35// Protocols list
b2b35524 36wxProtoInfo *wxURL::ms_protocols = NULL;
8a4df159 37
f92f546c 38// Enforce linking of protocol classes:
f92f546c
VS
39USE_PROTOCOL(wxFileProto)
40
ce195ee6 41#if wxUSE_PROTOCOL_HTTP
f80eabe5 42USE_PROTOCOL(wxHTTP)
f80eabe5 43
b2b35524 44 wxHTTP *wxURL::ms_proxyDefault = NULL;
cb719f2e 45 bool wxURL::ms_useDefaultProxy = false;
8a4df159 46#endif
f4ada568 47
ce195ee6
MB
48#if wxUSE_PROTOCOL_FTP
49USE_PROTOCOL(wxFTP)
50#endif
51
fae05df5 52// --------------------------------------------------------------
b60b2ec8
RN
53//
54// wxURL
55//
fae05df5 56// --------------------------------------------------------------
f4ada568 57
ce321570
RN
58// --------------------------------------------------------------
59// Construction
60// --------------------------------------------------------------
61
b60b2ec8
RN
62wxURL::wxURL(const wxString& url) : wxURI(url)
63{
64 Init(url);
65 ParseURL();
66}
67
00e075e5 68wxURL::wxURL(const wxURI& uri) : wxURI(uri)
b60b2ec8 69{
00e075e5
FM
70 Init(uri.BuildURI());
71 ParseURL();
72}
73
74wxURL::wxURL(const wxURL& url) : wxURI(url)
75{
76 Init(url.GetURL());
b60b2ec8
RN
77 ParseURL();
78}
79
b60b2ec8 80void wxURL::Init(const wxString& url)
f4ada568 81{
b2b35524
VZ
82 m_protocol = NULL;
83 m_error = wxURL_NOERR;
84 m_url = url;
25959b95
VZ
85#if wxUSE_URL_NATIVE
86 m_nativeImp = CreateNativeImpObject();
87#endif
b2b35524 88
ce195ee6 89#if wxUSE_PROTOCOL_HTTP
b2b35524
VZ
90 if ( ms_useDefaultProxy && !ms_proxyDefault )
91 {
2b5f62a0 92 SetDefaultProxy( wxGetenv(wxT("HTTP_PROXY")) );
b2b35524
VZ
93
94 if ( !ms_proxyDefault )
95 {
96 // don't try again
cb719f2e 97 ms_useDefaultProxy = false;
b2b35524
VZ
98 }
99 }
100
101 m_useProxy = ms_proxyDefault != NULL;
102 m_proxy = ms_proxyDefault;
ce195ee6 103#endif // wxUSE_PROTOCOL_HTTP
b2b35524 104
f4ada568 105}
ce321570
RN
106
107// --------------------------------------------------------------
108// Assignment
109// --------------------------------------------------------------
110
00e075e5 111wxURL& wxURL::operator = (const wxString& url)
ce321570
RN
112{
113 wxURI::operator = (url);
00e075e5
FM
114 Free();
115 Init(url);
ce321570 116 ParseURL();
00e075e5 117
ce321570
RN
118 return *this;
119}
00e075e5
FM
120
121wxURL& wxURL::operator = (const wxURI& uri)
ce321570 122{
00e075e5
FM
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
ce321570
RN
144 return *this;
145}
146
b60b2ec8
RN
147// --------------------------------------------------------------
148// ParseURL
149//
150// Builds the URL and takes care of the old protocol stuff
151// --------------------------------------------------------------
f4ada568
GL
152
153bool wxURL::ParseURL()
154{
fd725bce
WS
155 // If the URL was already parsed (m_protocol != NULL), pass this section.
156 if (!m_protocol)
f6bcfd97 157 {
fd725bce
WS
158 // Clean up
159 CleanData();
f61815af 160
fd725bce
WS
161 // Make sure we have a protocol/scheme
162 if (!HasScheme())
163 {
164 m_error = wxURL_SNTXERR;
165 return false;
166 }
f61815af 167
fd725bce
WS
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 }
f61815af 185 }
f4ada568 186
ce195ee6 187#if wxUSE_PROTOCOL_HTTP
fd725bce
WS
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.
be103d4a
VZ
196 if (m_protocol)
197 m_protocol->Destroy();
fd725bce
WS
198 m_protocol = m_proxy; // FIXME: we should clone the protocol
199 }
ce195ee6 200#endif // wxUSE_PROTOCOL_HTTP
f4ada568 201
fd725bce
WS
202 m_error = wxURL_NOERR;
203 return true;
f4ada568
GL
204}
205
ce321570
RN
206// --------------------------------------------------------------
207// Destruction/Cleanup
208// --------------------------------------------------------------
209
f4ada568
GL
210void wxURL::CleanData()
211{
ce195ee6 212#if wxUSE_PROTOCOL_HTTP
fd725bce 213 if (!m_useProxy)
ce195ee6 214#endif // wxUSE_PROTOCOL_HTTP
be103d4a 215 {
5f3742c2 216 if (m_protocol)
be103d4a 217 {
5f3742c2
KH
218 // Need to safely delete the socket (pending events)
219 m_protocol->Destroy();
be103d4a
VZ
220 m_protocol = NULL;
221 }
222 }
f4ada568
GL
223}
224
00e075e5 225void wxURL::Free()
f4ada568 226{
25959b95 227 CleanData();
ce195ee6 228#if wxUSE_PROTOCOL_HTTP
25959b95
VZ
229 if (m_proxy && m_proxy != ms_proxyDefault)
230 delete m_proxy;
ce195ee6 231#endif // wxUSE_PROTOCOL_HTTP
25959b95
VZ
232#if wxUSE_URL_NATIVE
233 delete m_nativeImp;
8a4df159 234#endif
f4ada568
GL
235}
236
00e075e5
FM
237wxURL::~wxURL()
238{
239 Free();
240}
241
ce321570
RN
242// --------------------------------------------------------------
243// FetchProtocol
244// --------------------------------------------------------------
f4ada568
GL
245
246bool wxURL::FetchProtocol()
247{
fd725bce 248 wxProtoInfo *info = ms_protocols;
f4ada568 249
fd725bce 250 while (info)
f6bcfd97 251 {
fd725bce
WS
252 if (m_scheme == info->m_protoname)
253 {
254 if (m_port.IsNull())
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;
f4ada568 261 }
fd725bce 262 return false;
f4ada568
GL
263}
264
fae05df5 265// --------------------------------------------------------------
ce321570 266// GetInputStream
fae05df5
GL
267// --------------------------------------------------------------
268
58c837a4 269wxInputStream *wxURL::GetInputStream()
f4ada568 270{
fd725bce
WS
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)
e03e94b0 283 m_protocol->SetUser(Unescape(m_userinfo));
fd725bce
WS
284 else
285 {
e03e94b0
VZ
286 m_protocol->SetUser(Unescape(m_userinfo(0, dwPasswordPos)));
287 m_protocol->SetPassword(Unescape(m_userinfo(dwPasswordPos+1, m_userinfo.length() + 1)));
fd725bce
WS
288 }
289 }
856d2e52 290
25959b95 291#if wxUSE_URL_NATIVE
fd725bce
WS
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
25959b95
VZ
302#endif // wxUSE_URL_NATIVE
303
8a4df159 304#if wxUSE_SOCKETS
19e0e04b
RD
305 wxIPV4address addr;
306
fd725bce 307 // m_protoinfo is NULL when we use a proxy
283965f0
VZ
308 if (
309#if wxUSE_PROTOCOL_HTTP
310 !m_useProxy &&
311#endif // wxUSE_PROTOCOL_HTTP
312 m_protoinfo->m_needhost )
f6bcfd97 313 {
fd725bce
WS
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 }
f4ada568 327 }
283965f0 328#endif // wxUSE_SOCKETS
fd725bce
WS
329
330 wxString fullPath;
f4ada568 331
283965f0 332#if wxUSE_PROTOCOL_HTTP
fd725bce
WS
333 // When we use a proxy, we have to pass the whole URL to it.
334 if (m_useProxy)
335 fullPath += m_url;
283965f0 336#endif // wxUSE_PROTOCOL_HTTP
f4ada568 337
fd725bce
WS
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)
8a2c6ef8 352 {
fd725bce
WS
353 m_error = wxURL_PROTOERR;
354 return NULL;
f4ada568 355 }
f4ada568 356
fd725bce 357 return the_i_stream;
f4ada568
GL
358}
359
ce195ee6 360#if wxUSE_PROTOCOL_HTTP
f4ada568
GL
361void wxURL::SetDefaultProxy(const wxString& url_proxy)
362{
fd725bce
WS
363 if ( !url_proxy )
364 {
365 if ( ms_proxyDefault )
366 {
367 ms_proxyDefault->Close();
368 delete ms_proxyDefault;
369 ms_proxyDefault = NULL;
370 }
371 }
372 else
373 {
374 wxString tmp_str = url_proxy;
375 int pos = tmp_str.Find(wxT(':'));
376 if (pos == wxNOT_FOUND)
377 return;
378
379 wxString hostname = tmp_str(0, pos),
8ecff181 380 port = tmp_str(pos+1, tmp_str.length()-pos);
fd725bce
WS
381 wxIPV4address addr;
382
383 if (!addr.Hostname(hostname))
384 return;
385 if (!addr.Service(port))
386 return;
387
388 if (ms_proxyDefault)
389 // Finally, when all is right, we connect the new proxy.
390 ms_proxyDefault->Close();
391 else
392 ms_proxyDefault = new wxHTTP();
393 ms_proxyDefault->Connect(addr, true); // Watcom needs the 2nd arg for some reason
394 }
f4ada568
GL
395}
396
397void wxURL::SetProxy(const wxString& url_proxy)
398{
b2b35524
VZ
399 if ( !url_proxy )
400 {
401 if ( m_proxy && m_proxy != ms_proxyDefault )
402 {
403 m_proxy->Close();
404 delete m_proxy;
405 }
f4ada568 406
cb719f2e 407 m_useProxy = false;
b2b35524
VZ
408 }
409 else
410 {
411 wxString tmp_str;
412 wxString hostname, port;
413 int pos;
414 wxIPV4address addr;
415
416 tmp_str = url_proxy;
417 pos = tmp_str.Find(wxT(':'));
418 // This is an invalid proxy name.
cb719f2e 419 if (pos == wxNOT_FOUND)
b2b35524
VZ
420 return;
421
422 hostname = tmp_str(0, pos);
8ecff181 423 port = tmp_str(pos+1, tmp_str.length()-pos);
b2b35524
VZ
424
425 addr.Hostname(hostname);
426 addr.Service(port);
427
428 // Finally, create the whole stuff.
429 if (m_proxy && m_proxy != ms_proxyDefault)
430 delete m_proxy;
431 m_proxy = new wxHTTP();
cb719f2e 432 m_proxy->Connect(addr, true); // Watcom needs the 2nd arg for some reason
b2b35524
VZ
433
434 CleanData();
435 // Reparse url.
cb719f2e 436 m_useProxy = true;
b2b35524
VZ
437 ParseURL();
438 }
f4ada568 439}
ce195ee6 440#endif // wxUSE_PROTOCOL_HTTP
35a4dab7 441
b2b35524 442// ----------------------------------------------------------------------
ce321570
RN
443// wxURLModule
444//
b2b35524
VZ
445// A module which deletes the default proxy if we created it
446// ----------------------------------------------------------------------
447
448#if wxUSE_SOCKETS
449
450class wxURLModule : public wxModule
451{
452public:
7921a093
VZ
453 wxURLModule();
454
b2b35524
VZ
455 virtual bool OnInit();
456 virtual void OnExit();
457
458private:
459 DECLARE_DYNAMIC_CLASS(wxURLModule)
460};
461
462IMPLEMENT_DYNAMIC_CLASS(wxURLModule, wxModule)
463
7921a093
VZ
464wxURLModule::wxURLModule()
465{
466 // we must be cleaned up before wxSocketModule as otherwise deleting
467 // ms_proxyDefault from our OnExit() won't work (and can actually crash)
9a83f860 468 AddDependency(wxClassInfo::FindClass(wxT("wxSocketModule")));
7921a093
VZ
469}
470
b2b35524
VZ
471bool wxURLModule::OnInit()
472{
ce195ee6 473#if wxUSE_PROTOCOL_HTTP
b2b35524
VZ
474 // env var HTTP_PROXY contains the address of the default proxy to use if
475 // set, but don't try to create this proxy right now because it will slow
476 // down the program startup (especially if there is no DNS server
477 // available, in which case it may take up to 1 minute)
f6bcfd97 478
9a83f860 479 if ( wxGetenv(wxT("HTTP_PROXY")) )
b2b35524 480 {
cb719f2e 481 wxURL::ms_useDefaultProxy = true;
b2b35524 482 }
ce195ee6 483#endif // wxUSE_PROTOCOL_HTTP
cb719f2e 484 return true;
b2b35524
VZ
485}
486
487void wxURLModule::OnExit()
488{
ce195ee6 489#if wxUSE_PROTOCOL_HTTP
b2b35524
VZ
490 delete wxURL::ms_proxyDefault;
491 wxURL::ms_proxyDefault = NULL;
ce195ee6 492#endif // wxUSE_PROTOCOL_HTTP
b2b35524
VZ
493}
494
495#endif // wxUSE_SOCKETS
a5d46b73 496
97d8fe87 497
a5d46b73 498#endif // wxUSE_URL