]> git.saurik.com Git - wxWidgets.git/blame_incremental - src/common/url.cpp
fix Borland bug http://news.gmane.org/find-root.php?message_id=%3c43A0B07F.8010204...
[wxWidgets.git] / src / common / url.cpp
... / ...
CommitLineData
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
30IMPLEMENT_CLASS(wxProtoInfo, wxObject)
31IMPLEMENT_CLASS(wxURL, wxURI)
32
33// Protocols list
34wxProtoInfo *wxURL::ms_protocols = NULL;
35
36// Enforce linking of protocol classes:
37USE_PROTOCOL(wxFileProto)
38
39#if wxUSE_PROTOCOL_HTTP
40USE_PROTOCOL(wxHTTP)
41
42 wxHTTP *wxURL::ms_proxyDefault = NULL;
43 bool wxURL::ms_useDefaultProxy = false;
44#endif
45
46#if wxUSE_PROTOCOL_FTP
47USE_PROTOCOL(wxFTP)
48#endif
49
50// --------------------------------------------------------------
51//
52// wxURL
53//
54// --------------------------------------------------------------
55
56// --------------------------------------------------------------
57// Construction
58// --------------------------------------------------------------
59
60wxURL::wxURL(const wxString& url) : wxURI(url)
61{
62 Init(url);
63 ParseURL();
64}
65
66wxURL::wxURL(const wxURI& url) : wxURI(url)
67{
68 Init(url.BuildURI());
69 ParseURL();
70}
71
72void 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
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
118// --------------------------------------------------------------
119// ParseURL
120//
121// Builds the URL and takes care of the old protocol stuff
122// --------------------------------------------------------------
123
124bool 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
179void wxURL::CleanData()
180{
181#if wxUSE_PROTOCOL_HTTP
182 if (!m_useProxy)
183#endif // wxUSE_PROTOCOL_HTTP
184 delete m_protocol;
185}
186
187wxURL::~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
203bool 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
226wxInputStream *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
312void 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
348void 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
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{
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
429void 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
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
519#endif // wxUSE_URL