Fix processing of events for MRU entries #10 and more in docview.
[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.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;
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 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),
380 port = tmp_str(pos+1, tmp_str.length()-pos);
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 }
395 }
396
397 void wxURL::SetProxy(const wxString& url_proxy)
398 {
399 if ( !url_proxy )
400 {
401 if ( m_proxy && m_proxy != ms_proxyDefault )
402 {
403 m_proxy->Close();
404 delete m_proxy;
405 }
406
407 m_useProxy = false;
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.
419 if (pos == wxNOT_FOUND)
420 return;
421
422 hostname = tmp_str(0, pos);
423 port = tmp_str(pos+1, tmp_str.length()-pos);
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();
432 m_proxy->Connect(addr, true); // Watcom needs the 2nd arg for some reason
433
434 CleanData();
435 // Reparse url.
436 m_useProxy = true;
437 ParseURL();
438 }
439 }
440 #endif // wxUSE_PROTOCOL_HTTP
441
442 // ----------------------------------------------------------------------
443 // wxURLModule
444 //
445 // A module which deletes the default proxy if we created it
446 // ----------------------------------------------------------------------
447
448 #if wxUSE_SOCKETS
449
450 class wxURLModule : public wxModule
451 {
452 public:
453 wxURLModule();
454
455 virtual bool OnInit();
456 virtual void OnExit();
457
458 private:
459 DECLARE_DYNAMIC_CLASS(wxURLModule)
460 };
461
462 IMPLEMENT_DYNAMIC_CLASS(wxURLModule, wxModule)
463
464 wxURLModule::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)
468 AddDependency(wxClassInfo::FindClass(wxT("wxSocketModule")));
469 }
470
471 bool wxURLModule::OnInit()
472 {
473 #if wxUSE_PROTOCOL_HTTP
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)
478
479 if ( wxGetenv(wxT("HTTP_PROXY")) )
480 {
481 wxURL::ms_useDefaultProxy = true;
482 }
483 #endif // wxUSE_PROTOCOL_HTTP
484 return true;
485 }
486
487 void wxURLModule::OnExit()
488 {
489 #if wxUSE_PROTOCOL_HTTP
490 delete wxURL::ms_proxyDefault;
491 wxURL::ms_proxyDefault = NULL;
492 #endif // wxUSE_PROTOCOL_HTTP
493 }
494
495 #endif // wxUSE_SOCKETS
496
497
498 #endif // wxUSE_URL