]> git.saurik.com Git - wxWidgets.git/blame_incremental - src/common/url.cpp
Tried to fix GTK+ 2.0 compilos
[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 license
10/////////////////////////////////////////////////////////////////////////////
11
12#ifdef __GNUG__
13#pragma implementation "url.h"
14#endif
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
23#include <string.h>
24#include <ctype.h>
25
26#include "wx/string.h"
27#include "wx/list.h"
28#include "wx/utils.h"
29#include "wx/module.h"
30#include "wx/url.h"
31
32IMPLEMENT_CLASS(wxProtoInfo, wxObject)
33IMPLEMENT_CLASS(wxURL, wxObject)
34
35// Protocols list
36wxProtoInfo *wxURL::ms_protocols = NULL;
37
38#if wxUSE_SOCKETS
39 wxHTTP *wxURL::ms_proxyDefault = NULL;
40 bool wxURL::ms_useDefaultProxy = FALSE;
41#endif
42
43// --------------------------------------------------------------
44// wxURL
45// --------------------------------------------------------------
46
47// --------------------------------------------------------------
48// --------- wxURL CONSTRUCTOR DESTRUCTOR -----------------------
49// --------------------------------------------------------------
50
51wxURL::wxURL(const wxString& url)
52{
53 m_protocol = NULL;
54 m_error = wxURL_NOERR;
55 m_url = url;
56
57#if wxUSE_SOCKETS
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();
74}
75
76bool wxURL::ParseURL()
77{
78 wxString last_url = m_url;
79
80 // If the URL was already parsed (m_protocol != NULL), pass this section.
81 if (!m_protocol)
82 {
83 // Clean up
84 CleanData();
85
86 // Extract protocol name
87 if (!PrepProto(last_url))
88 {
89 m_error = wxURL_SNTXERR;
90 return FALSE;
91 }
92
93 // Find and create the protocol object
94 if (!FetchProtocol())
95 {
96 m_error = wxURL_NOPROTO;
97 return FALSE;
98 }
99
100 // Do we need a host name ?
101 if (m_protoinfo->m_needhost)
102 {
103 // Extract it
104 if (!PrepHost(last_url))
105 {
106 m_error = wxURL_SNTXERR;
107 return FALSE;
108 }
109 }
110
111 // Extract full path
112 if (!PrepPath(last_url))
113 {
114 m_error = wxURL_NOPATH;
115 return FALSE;
116 }
117 }
118 // URL parse finished.
119
120#if wxUSE_SOCKETS
121 if (m_useProxy)
122 {
123 // We destroy the newly created protocol.
124 CleanData();
125
126 // Third, we rebuild the URL.
127 m_url = m_protoname + wxT(":");
128 if (m_protoinfo->m_needhost)
129 m_url = m_url + wxT("//") + m_hostname;
130
131 m_url += m_path;
132
133 // We initialize specific variables.
134 m_protocol = m_proxy; // FIXME: we should clone the protocol
135 }
136#endif
137
138 m_error = wxURL_NOERR;
139 return TRUE;
140}
141
142void wxURL::CleanData()
143{
144#if wxUSE_SOCKETS
145 if (!m_useProxy)
146#endif
147 delete m_protocol;
148}
149
150wxURL::~wxURL()
151{
152 CleanData();
153#if wxUSE_SOCKETS
154 if (m_proxy && m_proxy != ms_proxyDefault)
155 delete m_proxy;
156#endif
157}
158
159// --------------------------------------------------------------
160// --------- wxURL urls decoders --------------------------------
161// --------------------------------------------------------------
162
163bool wxURL::PrepProto(wxString& url)
164{
165 int pos;
166
167 // Find end
168 pos = url.Find(wxT(':'));
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{
181 wxString temp_url;
182 int pos, pos2;
183
184 if ((url.GetChar(0) != wxT('/')) || (url.GetChar(1) != wxT('/')))
185 return FALSE;
186
187 url = url(2, url.Length());
188
189 pos = url.Find(wxT('/'));
190 if (pos == -1)
191 pos = url.Length();
192
193 if (pos == 0)
194 return FALSE;
195
196 temp_url = url(0, pos);
197 url = url(url.Find(wxT('/')), url.Length());
198
199 // Retrieve service number
200 pos2 = temp_url.Find(wxT(':'), TRUE);
201 if (pos2 != -1 && pos2 < pos)
202 {
203 m_servname = temp_url(pos2+1, pos);
204 if (!m_servname.IsNumber())
205 return FALSE;
206 temp_url = temp_url(0, pos2);
207 }
208
209 // Retrieve user and password.
210 pos2 = temp_url.Find(wxT('@'));
211 // Even if pos2 equals -1, this code is right.
212 m_hostname = temp_url(pos2+1, temp_url.Length());
213
214 m_user = wxT("");
215 m_password = wxT("");
216
217 if (pos2 == -1)
218 return TRUE;
219
220 temp_url = temp_url(0, pos2);
221 pos2 = temp_url.Find(wxT(':'));
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());
228
229 return TRUE;
230}
231
232bool wxURL::PrepPath(wxString& url)
233{
234 if (url.Length() != 0)
235 m_path = ConvertToValidURI(url);
236 else
237 m_path = wxT("/");
238 return TRUE;
239}
240
241bool wxURL::FetchProtocol()
242{
243 wxProtoInfo *info = ms_protocols;
244
245 while (info)
246 {
247 if (m_protoname == info->m_protoname)
248 {
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();
254 return TRUE;
255 }
256 info = info->next;
257 }
258 return FALSE;
259}
260
261// --------------------------------------------------------------
262// --------- wxURL get ------------------------------------------
263// --------------------------------------------------------------
264
265wxInputStream *wxURL::GetInputStream()
266{
267 wxInputStream *the_i_stream = NULL;
268
269 if (!m_protocol)
270 {
271 m_error = wxURL_NOPROTO;
272 return NULL;
273 }
274
275 m_error = wxURL_NOERR;
276 if (m_user != wxT(""))
277 {
278 m_protocol->SetUser(m_user);
279 m_protocol->SetPassword(m_password);
280 }
281
282#if wxUSE_SOCKETS
283 wxIPV4address addr;
284
285 // m_protoinfo is NULL when we use a proxy
286 if (!m_useProxy && m_protoinfo->m_needhost)
287 {
288 if (!addr.Hostname(m_hostname))
289 {
290 m_error = wxURL_NOHOST;
291 return NULL;
292 }
293
294 addr.Service(m_servname);
295
296 if (!m_protocol->Connect(addr, TRUE)) // Watcom needs the 2nd arg for some reason
297 {
298 m_error = wxURL_CONNERR;
299 return NULL;
300 }
301 }
302#endif
303
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
310 if (!the_i_stream)
311 {
312 m_error = wxURL_PROTOERR;
313 return NULL;
314 }
315
316 return the_i_stream;
317}
318
319#if wxUSE_SOCKETS
320void wxURL::SetDefaultProxy(const wxString& url_proxy)
321{
322 if ( !url_proxy )
323 {
324 if ( ms_proxyDefault )
325 {
326 ms_proxyDefault->Close();
327 delete ms_proxyDefault;
328 ms_proxyDefault = NULL;
329 }
330 }
331 else
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 }
354}
355
356void wxURL::SetProxy(const wxString& url_proxy)
357{
358 if ( !url_proxy )
359 {
360 if ( m_proxy && m_proxy != ms_proxyDefault )
361 {
362 m_proxy->Close();
363 delete m_proxy;
364 }
365
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 }
398}
399#endif // wxUSE_SOCKETS
400
401wxString wxURL::ConvertToValidURI(const wxString& uri, const wxChar* delims)
402{
403 wxString out_str;
404 wxString hexa_code;
405 size_t i;
406
407 for (i = 0; i < uri.Len(); i++)
408 {
409 wxChar c = uri.GetChar(i);
410
411 if (c == wxT(' '))
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 {
433 hexa_code.Printf(wxT("%%%02X"), c);
434 out_str += hexa_code;
435 }
436 else
437 {
438 out_str += c;
439 }
440 }
441 }
442
443 return out_str;
444}
445
446wxString wxURL::ConvertFromURI(const wxString& uri)
447{
448 wxString new_uri;
449
450 size_t i = 0;
451 while (i < uri.Len())
452 {
453 int code;
454 if (uri[i] == wxT('%'))
455 {
456 i++;
457 if (uri[i] >= wxT('A') && uri[i] <= wxT('F'))
458 code = (uri[i] - wxT('A') + 10) * 16;
459 else
460 code = (uri[i] - wxT('0')) * 16;
461
462 i++;
463 if (uri[i] >= wxT('A') && uri[i] <= wxT('F'))
464 code += (uri[i] - wxT('A')) + 10;
465 else
466 code += (uri[i] - wxT('0'));
467
468 i++;
469 new_uri += (wxChar)code;
470 continue;
471 }
472 new_uri += uri[i];
473 i++;
474 }
475 return new_uri;
476}
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)
502
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