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