]> git.saurik.com Git - wxWidgets.git/blame - src/common/url.cpp
Committing in .
[wxWidgets.git] / src / common / url.cpp
CommitLineData
f4ada568
GL
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 license
10/////////////////////////////////////////////////////////////////////////////
11
12#ifdef __GNUG__
13#pragma implementation "url.h"
14#endif
fcc6dddd
JS
15
16// For compilers that support precompilation, includes "wx.h".
17#include "wx/wxprec.h"
18
19#ifdef __BORLANDC__
20#pragma hdrstop
21#endif
22
f4ada568
GL
23#include <string.h>
24#include <ctype.h>
25
3096bd2f
VZ
26#include "wx/string.h"
27#include "wx/list.h"
28#include "wx/utils.h"
c092213d 29#include "wx/module.h"
3096bd2f 30#include "wx/url.h"
f4ada568 31
f4ada568
GL
32IMPLEMENT_CLASS(wxProtoInfo, wxObject)
33IMPLEMENT_CLASS(wxURL, wxObject)
f4ada568
GL
34
35// Protocols list
b2b35524 36wxProtoInfo *wxURL::ms_protocols = NULL;
8a4df159
RR
37
38#if wxUSE_SOCKETS
b2b35524
VZ
39 wxHTTP *wxURL::ms_proxyDefault = NULL;
40 bool wxURL::ms_useDefaultProxy = FALSE;
8a4df159 41#endif
f4ada568 42
fae05df5
GL
43// --------------------------------------------------------------
44// wxURL
45// --------------------------------------------------------------
f4ada568 46
fae05df5
GL
47// --------------------------------------------------------------
48// --------- wxURL CONSTRUCTOR DESTRUCTOR -----------------------
49// --------------------------------------------------------------
f4ada568
GL
50
51wxURL::wxURL(const wxString& url)
52{
b2b35524
VZ
53 m_protocol = NULL;
54 m_error = wxURL_NOERR;
55 m_url = url;
56
8a4df159 57#if wxUSE_SOCKETS
b2b35524
VZ
58 if ( ms_useDefaultProxy && !ms_proxyDefault )
59 {
60 SetDefaultProxy(getenv("HTTP_PROXY"));
61
62 if ( !ms_proxyDefault )
63 {
64 // don't try again
65 ms_useDefaultProxy = FALSE;
66 }
67 }
68
69 m_useProxy = ms_proxyDefault != NULL;
70 m_proxy = ms_proxyDefault;
71#endif // wxUSE_SOCKETS
72
73 ParseURL();
f4ada568
GL
74}
75
76bool wxURL::ParseURL()
77{
78 wxString last_url = m_url;
79
f6bcfd97
BP
80 // If the URL was already parsed (m_protocol != NULL), pass this section.
81 if (!m_protocol)
82 {
f61815af
GL
83 // Clean up
84 CleanData();
f4ada568 85
f61815af 86 // Extract protocol name
f6bcfd97
BP
87 if (!PrepProto(last_url))
88 {
f4ada568
GL
89 m_error = wxURL_SNTXERR;
90 return FALSE;
91 }
f61815af
GL
92
93 // Find and create the protocol object
f6bcfd97
BP
94 if (!FetchProtocol())
95 {
f61815af
GL
96 m_error = wxURL_NOPROTO;
97 return FALSE;
98 }
99
100 // Do we need a host name ?
f6bcfd97
BP
101 if (m_protoinfo->m_needhost)
102 {
f61815af 103 // Extract it
f6bcfd97
BP
104 if (!PrepHost(last_url))
105 {
f61815af
GL
106 m_error = wxURL_SNTXERR;
107 return FALSE;
108 }
109 }
110
111 // Extract full path
f6bcfd97
BP
112 if (!PrepPath(last_url))
113 {
f61815af
GL
114 m_error = wxURL_NOPATH;
115 return FALSE;
116 }
f4ada568 117 }
f61815af 118 // URL parse finished.
f4ada568 119
8a4df159 120#if wxUSE_SOCKETS
f6bcfd97
BP
121 if (m_useProxy)
122 {
f61815af
GL
123 // We destroy the newly created protocol.
124 CleanData();
125
126 // Third, we rebuild the URL.
223d09f6 127 m_url = m_protoname + wxT(":");
f61815af 128 if (m_protoinfo->m_needhost)
223d09f6 129 m_url = m_url + wxT("//") + m_hostname;
f61815af
GL
130
131 m_url += m_path;
132
133 // We initialize specific variables.
134 m_protocol = m_proxy; // FIXME: we should clone the protocol
f4ada568 135 }
8a4df159 136#endif
f4ada568
GL
137
138 m_error = wxURL_NOERR;
139 return TRUE;
140}
141
142void wxURL::CleanData()
143{
8a4df159 144#if wxUSE_SOCKETS
f61815af 145 if (!m_useProxy)
8a4df159 146#endif
f4ada568
GL
147 delete m_protocol;
148}
149
150wxURL::~wxURL()
151{
152 CleanData();
8a4df159 153#if wxUSE_SOCKETS
b2b35524 154 if (m_proxy && m_proxy != ms_proxyDefault)
f61815af 155 delete m_proxy;
8a4df159 156#endif
f4ada568
GL
157}
158
fae05df5
GL
159// --------------------------------------------------------------
160// --------- wxURL urls decoders --------------------------------
161// --------------------------------------------------------------
162
f4ada568
GL
163bool wxURL::PrepProto(wxString& url)
164{
165 int pos;
166
167 // Find end
223d09f6 168 pos = url.Find(wxT(':'));
f4ada568
GL
169 if (pos == -1)
170 return FALSE;
171
172 m_protoname = url(0, pos);
173
174 url = url(pos+1, url.Length());
175
176 return TRUE;
177}
178
179bool wxURL::PrepHost(wxString& url)
180{
856d2e52 181 wxString temp_url;
f4ada568
GL
182 int pos, pos2;
183
58c837a4 184 if ((url.GetChar(0) != wxT('/')) || (url.GetChar(1) != wxT('/')))
f4ada568
GL
185 return FALSE;
186
187 url = url(2, url.Length());
188
223d09f6 189 pos = url.Find(wxT('/'));
f4ada568 190 if (pos == -1)
b7db6f0b 191 pos = url.Length();
f4ada568 192
856d2e52
GL
193 if (pos == 0)
194 return FALSE;
195
196 temp_url = url(0, pos);
223d09f6 197 url = url(url.Find(wxT('/')), url.Length());
856d2e52
GL
198
199 // Retrieve service number
223d09f6 200 pos2 = temp_url.Find(wxT(':'), TRUE);
f6bcfd97
BP
201 if (pos2 != -1 && pos2 < pos)
202 {
375abe3d 203 m_servname = temp_url(pos2+1, pos);
f4ada568
GL
204 if (!m_servname.IsNumber())
205 return FALSE;
856d2e52 206 temp_url = temp_url(0, pos2);
f4ada568
GL
207 }
208
856d2e52 209 // Retrieve user and password.
223d09f6 210 pos2 = temp_url.Find(wxT('@'));
856d2e52
GL
211 // Even if pos2 equals -1, this code is right.
212 m_hostname = temp_url(pos2+1, temp_url.Length());
f4ada568 213
223d09f6
KB
214 m_user = wxT("");
215 m_password = wxT("");
856d2e52
GL
216
217 if (pos2 == -1)
218 return TRUE;
219
220 temp_url = temp_url(0, pos2);
223d09f6 221 pos2 = temp_url.Find(wxT(':'));
856d2e52
GL
222
223 if (pos2 == -1)
224 return FALSE;
225
226 m_user = temp_url(0, pos2);
227 m_password = temp_url(pos2+1, url.Length());
f4ada568
GL
228
229 return TRUE;
230}
231
232bool wxURL::PrepPath(wxString& url)
233{
234 if (url.Length() != 0)
f61815af 235 m_path = ConvertToValidURI(url);
f4ada568 236 else
223d09f6 237 m_path = wxT("/");
f4ada568
GL
238 return TRUE;
239}
240
241bool wxURL::FetchProtocol()
242{
b2b35524 243 wxProtoInfo *info = ms_protocols;
f4ada568 244
f6bcfd97
BP
245 while (info)
246 {
247 if (m_protoname == info->m_protoname)
248 {
f4ada568
GL
249 if (m_servname.IsNull())
250 m_servname = info->m_servname;
251
252 m_protoinfo = info;
253 m_protocol = (wxProtocol *)m_protoinfo->m_cinfo->CreateObject();
f4ada568
GL
254 return TRUE;
255 }
256 info = info->next;
257 }
258 return FALSE;
259}
260
fae05df5
GL
261// --------------------------------------------------------------
262// --------- wxURL get ------------------------------------------
263// --------------------------------------------------------------
264
58c837a4 265wxInputStream *wxURL::GetInputStream()
f4ada568 266{
f4ada568
GL
267 wxInputStream *the_i_stream = NULL;
268
f6bcfd97
BP
269 if (!m_protocol)
270 {
f4ada568
GL
271 m_error = wxURL_NOPROTO;
272 return NULL;
273 }
274
275 m_error = wxURL_NOERR;
f6bcfd97
BP
276 if (m_user != wxT(""))
277 {
856d2e52
GL
278 m_protocol->SetUser(m_user);
279 m_protocol->SetPassword(m_password);
280 }
281
8a4df159 282#if wxUSE_SOCKETS
19e0e04b
RD
283 wxIPV4address addr;
284
f61815af 285 // m_protoinfo is NULL when we use a proxy
f6bcfd97
BP
286 if (!m_useProxy && m_protoinfo->m_needhost)
287 {
288 if (!addr.Hostname(m_hostname))
289 {
f4ada568
GL
290 m_error = wxURL_NOHOST;
291 return NULL;
292 }
293
294 addr.Service(m_servname);
295
8a2c6ef8
JS
296 if (!m_protocol->Connect(addr, TRUE)) // Watcom needs the 2nd arg for some reason
297 {
f4ada568
GL
298 m_error = wxURL_CONNERR;
299 return NULL;
300 }
301 }
8a4df159 302#endif
f4ada568 303
f61815af
GL
304 // When we use a proxy, we have to pass the whole URL to it.
305 if (m_useProxy)
306 the_i_stream = m_protocol->GetInputStream(m_url);
307 else
308 the_i_stream = m_protocol->GetInputStream(m_path);
309
f6bcfd97
BP
310 if (!the_i_stream)
311 {
f4ada568
GL
312 m_error = wxURL_PROTOERR;
313 return NULL;
314 }
315
316 return the_i_stream;
317}
318
8a4df159 319#if wxUSE_SOCKETS
f4ada568
GL
320void wxURL::SetDefaultProxy(const wxString& url_proxy)
321{
b2b35524
VZ
322 if ( !url_proxy )
323 {
324 if ( ms_proxyDefault )
325 {
326 ms_proxyDefault->Close();
327 delete ms_proxyDefault;
328 ms_proxyDefault = NULL;
329 }
f61815af 330 }
f61815af 331 else
b2b35524
VZ
332 {
333 wxString tmp_str = url_proxy;
334 int pos = tmp_str.Find(wxT(':'));
335 if (pos == -1)
336 return;
337
338 wxString hostname = tmp_str(0, pos),
339 port = tmp_str(pos+1, tmp_str.Length()-pos);
340 wxIPV4address addr;
341
342 if (!addr.Hostname(hostname))
343 return;
344 if (!addr.Service(port))
345 return;
346
347 if (ms_proxyDefault)
348 // Finally, when all is right, we connect the new proxy.
349 ms_proxyDefault->Close();
350 else
351 ms_proxyDefault = new wxHTTP();
352 ms_proxyDefault->Connect(addr, TRUE); // Watcom needs the 2nd arg for some reason
353 }
f4ada568
GL
354}
355
356void wxURL::SetProxy(const wxString& url_proxy)
357{
b2b35524
VZ
358 if ( !url_proxy )
359 {
360 if ( m_proxy && m_proxy != ms_proxyDefault )
361 {
362 m_proxy->Close();
363 delete m_proxy;
364 }
f4ada568 365
b2b35524
VZ
366 m_useProxy = FALSE;
367 }
368 else
369 {
370 wxString tmp_str;
371 wxString hostname, port;
372 int pos;
373 wxIPV4address addr;
374
375 tmp_str = url_proxy;
376 pos = tmp_str.Find(wxT(':'));
377 // This is an invalid proxy name.
378 if (pos == -1)
379 return;
380
381 hostname = tmp_str(0, pos);
382 port = tmp_str(pos, tmp_str.Length()-pos);
383
384 addr.Hostname(hostname);
385 addr.Service(port);
386
387 // Finally, create the whole stuff.
388 if (m_proxy && m_proxy != ms_proxyDefault)
389 delete m_proxy;
390 m_proxy = new wxHTTP();
391 m_proxy->Connect(addr, TRUE); // Watcom needs the 2nd arg for some reason
392
393 CleanData();
394 // Reparse url.
395 m_useProxy = TRUE;
396 ParseURL();
397 }
f4ada568 398}
b2b35524 399#endif // wxUSE_SOCKETS
35a4dab7 400
f6bcfd97 401wxString wxURL::ConvertToValidURI(const wxString& uri, const wxChar* delims)
14906731 402{
fae05df5
GL
403 wxString out_str;
404 wxString hexa_code;
405 size_t i;
406
f6bcfd97
BP
407 for (i = 0; i < uri.Len(); i++)
408 {
fae05df5
GL
409 wxChar c = uri.GetChar(i);
410
223d09f6 411 if (c == wxT(' '))
f6bcfd97
BP
412 {
413 // GRG, Apr/2000: changed to "%20" instead of '+'
414
415 out_str += wxT("%20");
416 }
417 else
418 {
419 // GRG, Apr/2000: modified according to the URI definition (RFC 2396)
420 //
421 // - Alphanumeric characters are never escaped
422 // - Unreserved marks are never escaped
423 // - Delimiters must be escaped if they appear within a component
424 // but not if they are used to separate components. Here we have
425 // no clear way to distinguish between these two cases, so they
426 // are escaped unless they are passed in the 'delims' parameter
427 // (allowed delimiters).
428
429 static const wxChar marks[] = wxT("-_.!~*()'");
430
431 if ( !wxIsalnum(c) && !wxStrchr(marks, c) && !wxStrchr(delims, c) )
432 {
223d09f6 433 hexa_code.Printf(wxT("%%%02X"), c);
5a96d2f4 434 out_str += hexa_code;
f6bcfd97
BP
435 }
436 else
437 {
5a96d2f4 438 out_str += c;
f6bcfd97 439 }
5a96d2f4 440 }
fae05df5 441 }
19e0e04b 442
fae05df5 443 return out_str;
14906731
GL
444}
445
aa6d9706
GL
446wxString wxURL::ConvertFromURI(const wxString& uri)
447{
aa6d9706
GL
448 wxString new_uri;
449
74b31181 450 size_t i = 0;
f6bcfd97
BP
451 while (i < uri.Len())
452 {
74b31181 453 int code;
f6bcfd97
BP
454 if (uri[i] == wxT('%'))
455 {
aa6d9706 456 i++;
223d09f6
KB
457 if (uri[i] >= wxT('A') && uri[i] <= wxT('F'))
458 code = (uri[i] - wxT('A') + 10) * 16;
aa6d9706 459 else
223d09f6 460 code = (uri[i] - wxT('0')) * 16;
f6bcfd97 461
aa6d9706 462 i++;
223d09f6
KB
463 if (uri[i] >= wxT('A') && uri[i] <= wxT('F'))
464 code += (uri[i] - wxT('A')) + 10;
aa6d9706 465 else
223d09f6 466 code += (uri[i] - wxT('0'));
f6bcfd97 467
aa6d9706
GL
468 i++;
469 new_uri += (wxChar)code;
470 continue;
471 }
472 new_uri += uri[i];
473 i++;
474 }
475 return new_uri;
476}
b2b35524
VZ
477
478// ----------------------------------------------------------------------
479// A module which deletes the default proxy if we created it
480// ----------------------------------------------------------------------
481
482#if wxUSE_SOCKETS
483
484class wxURLModule : public wxModule
485{
486public:
487 virtual bool OnInit();
488 virtual void OnExit();
489
490private:
491 DECLARE_DYNAMIC_CLASS(wxURLModule)
492};
493
494IMPLEMENT_DYNAMIC_CLASS(wxURLModule, wxModule)
495
496bool wxURLModule::OnInit()
497{
498 // env var HTTP_PROXY contains the address of the default proxy to use if
499 // set, but don't try to create this proxy right now because it will slow
500 // down the program startup (especially if there is no DNS server
501 // available, in which case it may take up to 1 minute)
f6bcfd97 502
b2b35524
VZ
503 if ( getenv("HTTP_PROXY") )
504 {
505 wxURL::ms_useDefaultProxy = TRUE;
506 }
507
508 return TRUE;
509}
510
511void wxURLModule::OnExit()
512{
513 delete wxURL::ms_proxyDefault;
514 wxURL::ms_proxyDefault = NULL;
515}
516
517#endif // wxUSE_SOCKETS