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