]> git.saurik.com Git - wxWidgets.git/blob - src/common/url.cpp
added missing consts and pass objects by const reference instead of by value (patch...
[wxWidgets.git] / src / common / url.cpp
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
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/string.h"
22 #include "wx/list.h"
23 #include "wx/utils.h"
24 #include "wx/module.h"
25 #include "wx/url.h"
26
27 #include <string.h>
28 #include <ctype.h>
29
30 IMPLEMENT_CLASS(wxProtoInfo, wxObject)
31 IMPLEMENT_CLASS(wxURL, wxURI)
32
33 // Protocols list
34 wxProtoInfo *wxURL::ms_protocols = NULL;
35
36 // Enforce linking of protocol classes:
37 USE_PROTOCOL(wxFileProto)
38
39 #if wxUSE_PROTOCOL_HTTP
40 USE_PROTOCOL(wxHTTP)
41
42 wxHTTP *wxURL::ms_proxyDefault = NULL;
43 bool wxURL::ms_useDefaultProxy = false;
44 #endif
45
46 #if wxUSE_PROTOCOL_FTP
47 USE_PROTOCOL(wxFTP)
48 #endif
49
50 // --------------------------------------------------------------
51 //
52 // wxURL
53 //
54 // --------------------------------------------------------------
55
56 // --------------------------------------------------------------
57 // Construction
58 // --------------------------------------------------------------
59
60 wxURL::wxURL(const wxString& url) : wxURI(url)
61 {
62 Init(url);
63 ParseURL();
64 }
65
66 wxURL::wxURL(const wxURI& url) : wxURI(url)
67 {
68 Init(url.BuildURI());
69 ParseURL();
70 }
71
72 void wxURL::Init(const wxString& url)
73 {
74 m_protocol = NULL;
75 m_error = wxURL_NOERR;
76 m_url = url;
77 #if wxUSE_URL_NATIVE
78 m_nativeImp = CreateNativeImpObject();
79 #endif
80
81 #if wxUSE_PROTOCOL_HTTP
82 if ( ms_useDefaultProxy && !ms_proxyDefault )
83 {
84 SetDefaultProxy( wxGetenv(wxT("HTTP_PROXY")) );
85
86 if ( !ms_proxyDefault )
87 {
88 // don't try again
89 ms_useDefaultProxy = false;
90 }
91 }
92
93 m_useProxy = ms_proxyDefault != NULL;
94 m_proxy = ms_proxyDefault;
95 #endif // wxUSE_PROTOCOL_HTTP
96
97 }
98
99 // --------------------------------------------------------------
100 // Assignment
101 // --------------------------------------------------------------
102
103 wxURL& wxURL::operator = (const wxURI& url)
104 {
105 wxURI::operator = (url);
106 Init(url.BuildURI());
107 ParseURL();
108 return *this;
109 }
110 wxURL& wxURL::operator = (const wxString& url)
111 {
112 wxURI::operator = (url);
113 Init(url);
114 ParseURL();
115 return *this;
116 }
117
118 // --------------------------------------------------------------
119 // ParseURL
120 //
121 // Builds the URL and takes care of the old protocol stuff
122 // --------------------------------------------------------------
123
124 bool wxURL::ParseURL()
125 {
126 // If the URL was already parsed (m_protocol != NULL), pass this section.
127 if (!m_protocol)
128 {
129 // Clean up
130 CleanData();
131
132 // Make sure we have a protocol/scheme
133 if (!HasScheme())
134 {
135 m_error = wxURL_SNTXERR;
136 return false;
137 }
138
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 }
156 }
157
158 #if wxUSE_PROTOCOL_HTTP
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 }
169 #endif // wxUSE_PROTOCOL_HTTP
170
171 m_error = wxURL_NOERR;
172 return true;
173 }
174
175 // --------------------------------------------------------------
176 // Destruction/Cleanup
177 // --------------------------------------------------------------
178
179 void wxURL::CleanData()
180 {
181 #if wxUSE_PROTOCOL_HTTP
182 if (!m_useProxy)
183 #endif // wxUSE_PROTOCOL_HTTP
184 delete m_protocol;
185 }
186
187 wxURL::~wxURL()
188 {
189 CleanData();
190 #if wxUSE_PROTOCOL_HTTP
191 if (m_proxy && m_proxy != ms_proxyDefault)
192 delete m_proxy;
193 #endif // wxUSE_PROTOCOL_HTTP
194 #if wxUSE_URL_NATIVE
195 delete m_nativeImp;
196 #endif
197 }
198
199 // --------------------------------------------------------------
200 // FetchProtocol
201 // --------------------------------------------------------------
202
203 bool wxURL::FetchProtocol()
204 {
205 wxProtoInfo *info = ms_protocols;
206
207 while (info)
208 {
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;
218 }
219 return false;
220 }
221
222 // --------------------------------------------------------------
223 // GetInputStream
224 // --------------------------------------------------------------
225
226 wxInputStream *wxURL::GetInputStream()
227 {
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 }
247
248 #if wxUSE_URL_NATIVE
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
259 #endif // wxUSE_URL_NATIVE
260
261 #if wxUSE_SOCKETS
262 wxIPV4address addr;
263
264 // m_protoinfo is NULL when we use a proxy
265 if (!m_useProxy && m_protoinfo->m_needhost)
266 {
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 }
280 }
281 #endif
282
283 wxString fullPath;
284
285 // When we use a proxy, we have to pass the whole URL to it.
286 if (m_useProxy)
287 fullPath += m_url;
288
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)
303 {
304 m_error = wxURL_PROTOERR;
305 return NULL;
306 }
307
308 return the_i_stream;
309 }
310
311 #if wxUSE_PROTOCOL_HTTP
312 void wxURL::SetDefaultProxy(const wxString& url_proxy)
313 {
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 }
346 }
347
348 void wxURL::SetProxy(const wxString& url_proxy)
349 {
350 if ( !url_proxy )
351 {
352 if ( m_proxy && m_proxy != ms_proxyDefault )
353 {
354 m_proxy->Close();
355 delete m_proxy;
356 }
357
358 m_useProxy = false;
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.
370 if (pos == wxNOT_FOUND)
371 return;
372
373 hostname = tmp_str(0, pos);
374 port = tmp_str(pos+1, tmp_str.Length()-pos);
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();
383 m_proxy->Connect(addr, true); // Watcom needs the 2nd arg for some reason
384
385 CleanData();
386 // Reparse url.
387 m_useProxy = true;
388 ParseURL();
389 }
390 }
391 #endif // wxUSE_PROTOCOL_HTTP
392
393 // ----------------------------------------------------------------------
394 // wxURLModule
395 //
396 // A module which deletes the default proxy if we created it
397 // ----------------------------------------------------------------------
398
399 #if wxUSE_SOCKETS
400
401 class wxURLModule : public wxModule
402 {
403 public:
404 virtual bool OnInit();
405 virtual void OnExit();
406
407 private:
408 DECLARE_DYNAMIC_CLASS(wxURLModule)
409 };
410
411 IMPLEMENT_DYNAMIC_CLASS(wxURLModule, wxModule)
412
413 bool wxURLModule::OnInit()
414 {
415 #if wxUSE_PROTOCOL_HTTP
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)
420
421 if ( wxGetenv(_T("HTTP_PROXY")) )
422 {
423 wxURL::ms_useDefaultProxy = true;
424 }
425 #endif // wxUSE_PROTOCOL_HTTP
426 return true;
427 }
428
429 void wxURLModule::OnExit()
430 {
431 #if wxUSE_PROTOCOL_HTTP
432 delete wxURL::ms_proxyDefault;
433 wxURL::ms_proxyDefault = NULL;
434 #endif // wxUSE_PROTOCOL_HTTP
435 }
436
437 #endif // wxUSE_SOCKETS
438
439 // ---------------------------------------------------------------------------
440 //
441 // wxURL Compatibility
442 //
443 // ---------------------------------------------------------------------------
444
445 #if WXWIN_COMPATIBILITY_2_4
446
447 #include "wx/url.h"
448
449 wxString wxURL::GetProtocolName() const
450 {
451 return m_scheme;
452 }
453
454 wxString wxURL::GetHostName() const
455 {
456 return m_server;
457 }
458
459 wxString 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
467 wxString 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
512 wxString wxURL::ConvertFromURI(const wxString& uri)
513 {
514 return wxURI::Unescape(uri);
515 }
516
517 #endif //WXWIN_COMPATIBILITY_2_4
518
519 #endif // wxUSE_URL