Compilation fix for wxUSE_PROTOCOL && !wxUSE_URL.
[wxWidgets.git] / src / common / url.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/common/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/url.h"
22
23 #ifndef WX_PRECOMP
24 #include "wx/list.h"
25 #include "wx/string.h"
26 #include "wx/utils.h"
27 #include "wx/module.h"
28 #endif
29
30 #include <string.h>
31 #include <ctype.h>
32
33 IMPLEMENT_CLASS(wxURL, wxURI)
34
35 // Protocols list
36 wxProtoInfo *wxURL::ms_protocols = NULL;
37
38 // Enforce linking of protocol classes:
39 USE_PROTOCOL(wxFileProto)
40
41 #if wxUSE_PROTOCOL_HTTP
42 USE_PROTOCOL(wxHTTP)
43
44 wxHTTP *wxURL::ms_proxyDefault = NULL;
45 bool wxURL::ms_useDefaultProxy = false;
46 #endif
47
48 #if wxUSE_PROTOCOL_FTP
49 USE_PROTOCOL(wxFTP)
50 #endif
51
52 // --------------------------------------------------------------
53 //
54 // wxURL
55 //
56 // --------------------------------------------------------------
57
58 // --------------------------------------------------------------
59 // Construction
60 // --------------------------------------------------------------
61
62 wxURL::wxURL(const wxString& url) : wxURI(url)
63 {
64 Init(url);
65 ParseURL();
66 }
67
68 wxURL::wxURL(const wxURI& url) : wxURI(url)
69 {
70 Init(url.BuildURI());
71 ParseURL();
72 }
73
74 void wxURL::Init(const wxString& url)
75 {
76 m_protocol = NULL;
77 m_error = wxURL_NOERR;
78 m_url = url;
79 #if wxUSE_URL_NATIVE
80 m_nativeImp = CreateNativeImpObject();
81 #endif
82
83 #if wxUSE_PROTOCOL_HTTP
84 if ( ms_useDefaultProxy && !ms_proxyDefault )
85 {
86 SetDefaultProxy( wxGetenv(wxT("HTTP_PROXY")) );
87
88 if ( !ms_proxyDefault )
89 {
90 // don't try again
91 ms_useDefaultProxy = false;
92 }
93 }
94
95 m_useProxy = ms_proxyDefault != NULL;
96 m_proxy = ms_proxyDefault;
97 #endif // wxUSE_PROTOCOL_HTTP
98
99 }
100
101 // --------------------------------------------------------------
102 // Assignment
103 // --------------------------------------------------------------
104
105 wxURL& wxURL::operator = (const wxURI& url)
106 {
107 wxURI::operator = (url);
108 Init(url.BuildURI());
109 ParseURL();
110 return *this;
111 }
112 wxURL& wxURL::operator = (const wxString& url)
113 {
114 wxURI::operator = (url);
115 Init(url);
116 ParseURL();
117 return *this;
118 }
119
120 // --------------------------------------------------------------
121 // ParseURL
122 //
123 // Builds the URL and takes care of the old protocol stuff
124 // --------------------------------------------------------------
125
126 bool wxURL::ParseURL()
127 {
128 // If the URL was already parsed (m_protocol != NULL), pass this section.
129 if (!m_protocol)
130 {
131 // Clean up
132 CleanData();
133
134 // Make sure we have a protocol/scheme
135 if (!HasScheme())
136 {
137 m_error = wxURL_SNTXERR;
138 return false;
139 }
140
141 // Find and create the protocol object
142 if (!FetchProtocol())
143 {
144 m_error = wxURL_NOPROTO;
145 return false;
146 }
147
148 // Do we need a host name ?
149 if (m_protoinfo->m_needhost)
150 {
151 // Make sure we have one, then
152 if (!HasServer())
153 {
154 m_error = wxURL_SNTXERR;
155 return false;
156 }
157 }
158 }
159
160 #if wxUSE_PROTOCOL_HTTP
161 if (m_useProxy)
162 {
163 // Third, we rebuild the URL.
164 m_url = m_scheme + wxT(":");
165 if (m_protoinfo->m_needhost)
166 m_url = m_url + wxT("//") + m_server;
167
168 // We initialize specific variables.
169 m_protocol = m_proxy; // FIXME: we should clone the protocol
170 }
171 #endif // wxUSE_PROTOCOL_HTTP
172
173 m_error = wxURL_NOERR;
174 return true;
175 }
176
177 // --------------------------------------------------------------
178 // Destruction/Cleanup
179 // --------------------------------------------------------------
180
181 void wxURL::CleanData()
182 {
183 #if wxUSE_PROTOCOL_HTTP
184 if (!m_useProxy)
185 #endif // wxUSE_PROTOCOL_HTTP
186 if (m_protocol)
187 // Need to safely delete the socket (pending events)
188 m_protocol->Destroy();
189 }
190
191 wxURL::~wxURL()
192 {
193 CleanData();
194 #if wxUSE_PROTOCOL_HTTP
195 if (m_proxy && m_proxy != ms_proxyDefault)
196 delete m_proxy;
197 #endif // wxUSE_PROTOCOL_HTTP
198 #if wxUSE_URL_NATIVE
199 delete m_nativeImp;
200 #endif
201 }
202
203 // --------------------------------------------------------------
204 // FetchProtocol
205 // --------------------------------------------------------------
206
207 bool wxURL::FetchProtocol()
208 {
209 wxProtoInfo *info = ms_protocols;
210
211 while (info)
212 {
213 if (m_scheme == info->m_protoname)
214 {
215 if (m_port.IsNull())
216 m_port = info->m_servname;
217 m_protoinfo = info;
218 m_protocol = (wxProtocol *)m_protoinfo->m_cinfo->CreateObject();
219 return true;
220 }
221 info = info->next;
222 }
223 return false;
224 }
225
226 // --------------------------------------------------------------
227 // GetInputStream
228 // --------------------------------------------------------------
229
230 wxInputStream *wxURL::GetInputStream()
231 {
232 if (!m_protocol)
233 {
234 m_error = wxURL_NOPROTO;
235 return NULL;
236 }
237
238 m_error = wxURL_NOERR;
239 if (HasUserInfo())
240 {
241 size_t dwPasswordPos = m_userinfo.find(':');
242
243 if (dwPasswordPos == wxString::npos)
244 m_protocol->SetUser(Unescape(m_userinfo));
245 else
246 {
247 m_protocol->SetUser(Unescape(m_userinfo(0, dwPasswordPos)));
248 m_protocol->SetPassword(Unescape(m_userinfo(dwPasswordPos+1, m_userinfo.length() + 1)));
249 }
250 }
251
252 #if wxUSE_URL_NATIVE
253 // give the native implementation to return a better stream
254 // such as the native WinINet functionality under MS-Windows
255 if (m_nativeImp)
256 {
257 wxInputStream *rc;
258 rc = m_nativeImp->GetInputStream(this);
259 if (rc != 0)
260 return rc;
261 }
262 // else use the standard behaviour
263 #endif // wxUSE_URL_NATIVE
264
265 #if wxUSE_SOCKETS
266 wxIPV4address addr;
267
268 // m_protoinfo is NULL when we use a proxy
269 if (
270 #if wxUSE_PROTOCOL_HTTP
271 !m_useProxy &&
272 #endif // wxUSE_PROTOCOL_HTTP
273 m_protoinfo->m_needhost )
274 {
275 if (!addr.Hostname(m_server))
276 {
277 m_error = wxURL_NOHOST;
278 return NULL;
279 }
280
281 addr.Service(m_port);
282
283 if (!m_protocol->Connect(addr, true)) // Watcom needs the 2nd arg for some reason
284 {
285 m_error = wxURL_CONNERR;
286 return NULL;
287 }
288 }
289 #endif // wxUSE_SOCKETS
290
291 wxString fullPath;
292
293 #if wxUSE_PROTOCOL_HTTP
294 // When we use a proxy, we have to pass the whole URL to it.
295 if (m_useProxy)
296 fullPath += m_url;
297 #endif // wxUSE_PROTOCOL_HTTP
298
299 if(m_path.empty())
300 fullPath += wxT("/");
301 else
302 fullPath += m_path;
303
304 if (HasQuery())
305 fullPath += wxT("?") + m_query;
306
307 if (HasFragment())
308 fullPath += wxT("#") + m_fragment;
309
310 wxInputStream *the_i_stream = m_protocol->GetInputStream(fullPath);
311
312 if (!the_i_stream)
313 {
314 m_error = wxURL_PROTOERR;
315 return NULL;
316 }
317
318 return the_i_stream;
319 }
320
321 #if wxUSE_PROTOCOL_HTTP
322 void wxURL::SetDefaultProxy(const wxString& url_proxy)
323 {
324 if ( !url_proxy )
325 {
326 if ( ms_proxyDefault )
327 {
328 ms_proxyDefault->Close();
329 delete ms_proxyDefault;
330 ms_proxyDefault = NULL;
331 }
332 }
333 else
334 {
335 wxString tmp_str = url_proxy;
336 int pos = tmp_str.Find(wxT(':'));
337 if (pos == wxNOT_FOUND)
338 return;
339
340 wxString hostname = tmp_str(0, pos),
341 port = tmp_str(pos+1, tmp_str.length()-pos);
342 wxIPV4address addr;
343
344 if (!addr.Hostname(hostname))
345 return;
346 if (!addr.Service(port))
347 return;
348
349 if (ms_proxyDefault)
350 // Finally, when all is right, we connect the new proxy.
351 ms_proxyDefault->Close();
352 else
353 ms_proxyDefault = new wxHTTP();
354 ms_proxyDefault->Connect(addr, true); // Watcom needs the 2nd arg for some reason
355 }
356 }
357
358 void wxURL::SetProxy(const wxString& url_proxy)
359 {
360 if ( !url_proxy )
361 {
362 if ( m_proxy && m_proxy != ms_proxyDefault )
363 {
364 m_proxy->Close();
365 delete m_proxy;
366 }
367
368 m_useProxy = false;
369 }
370 else
371 {
372 wxString tmp_str;
373 wxString hostname, port;
374 int pos;
375 wxIPV4address addr;
376
377 tmp_str = url_proxy;
378 pos = tmp_str.Find(wxT(':'));
379 // This is an invalid proxy name.
380 if (pos == wxNOT_FOUND)
381 return;
382
383 hostname = tmp_str(0, pos);
384 port = tmp_str(pos+1, tmp_str.length()-pos);
385
386 addr.Hostname(hostname);
387 addr.Service(port);
388
389 // Finally, create the whole stuff.
390 if (m_proxy && m_proxy != ms_proxyDefault)
391 delete m_proxy;
392 m_proxy = new wxHTTP();
393 m_proxy->Connect(addr, true); // Watcom needs the 2nd arg for some reason
394
395 CleanData();
396 // Reparse url.
397 m_useProxy = true;
398 ParseURL();
399 }
400 }
401 #endif // wxUSE_PROTOCOL_HTTP
402
403 // ----------------------------------------------------------------------
404 // wxURLModule
405 //
406 // A module which deletes the default proxy if we created it
407 // ----------------------------------------------------------------------
408
409 #if wxUSE_SOCKETS
410
411 class wxURLModule : public wxModule
412 {
413 public:
414 wxURLModule();
415
416 virtual bool OnInit();
417 virtual void OnExit();
418
419 private:
420 DECLARE_DYNAMIC_CLASS(wxURLModule)
421 };
422
423 IMPLEMENT_DYNAMIC_CLASS(wxURLModule, wxModule)
424
425 wxURLModule::wxURLModule()
426 {
427 // we must be cleaned up before wxSocketModule as otherwise deleting
428 // ms_proxyDefault from our OnExit() won't work (and can actually crash)
429 AddDependency(wxClassInfo::FindClass(wxT("wxSocketModule")));
430 }
431
432 bool wxURLModule::OnInit()
433 {
434 #if wxUSE_PROTOCOL_HTTP
435 // env var HTTP_PROXY contains the address of the default proxy to use if
436 // set, but don't try to create this proxy right now because it will slow
437 // down the program startup (especially if there is no DNS server
438 // available, in which case it may take up to 1 minute)
439
440 if ( wxGetenv(wxT("HTTP_PROXY")) )
441 {
442 wxURL::ms_useDefaultProxy = true;
443 }
444 #endif // wxUSE_PROTOCOL_HTTP
445 return true;
446 }
447
448 void wxURLModule::OnExit()
449 {
450 #if wxUSE_PROTOCOL_HTTP
451 delete wxURL::ms_proxyDefault;
452 wxURL::ms_proxyDefault = NULL;
453 #endif // wxUSE_PROTOCOL_HTTP
454 }
455
456 #endif // wxUSE_SOCKETS
457
458
459 #endif // wxUSE_URL