Implement wxDocument::Revert() and show its use in the sample.
[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 if (m_protocol)
170 m_protocol->Destroy();
171 m_protocol = m_proxy; // FIXME: we should clone the protocol
172 }
173 #endif // wxUSE_PROTOCOL_HTTP
174
175 m_error = wxURL_NOERR;
176 return true;
177 }
178
179 // --------------------------------------------------------------
180 // Destruction/Cleanup
181 // --------------------------------------------------------------
182
183 void wxURL::CleanData()
184 {
185 #if wxUSE_PROTOCOL_HTTP
186 if (!m_useProxy)
187 #endif // wxUSE_PROTOCOL_HTTP
188 {
189 if (m_protocol)
190 {
191 // Need to safely delete the socket (pending events)
192 m_protocol->Destroy();
193 m_protocol = NULL;
194 }
195 }
196 }
197
198 wxURL::~wxURL()
199 {
200 CleanData();
201 #if wxUSE_PROTOCOL_HTTP
202 if (m_proxy && m_proxy != ms_proxyDefault)
203 delete m_proxy;
204 #endif // wxUSE_PROTOCOL_HTTP
205 #if wxUSE_URL_NATIVE
206 delete m_nativeImp;
207 #endif
208 }
209
210 // --------------------------------------------------------------
211 // FetchProtocol
212 // --------------------------------------------------------------
213
214 bool wxURL::FetchProtocol()
215 {
216 wxProtoInfo *info = ms_protocols;
217
218 while (info)
219 {
220 if (m_scheme == info->m_protoname)
221 {
222 if (m_port.IsNull())
223 m_port = info->m_servname;
224 m_protoinfo = info;
225 m_protocol = (wxProtocol *)m_protoinfo->m_cinfo->CreateObject();
226 return true;
227 }
228 info = info->next;
229 }
230 return false;
231 }
232
233 // --------------------------------------------------------------
234 // GetInputStream
235 // --------------------------------------------------------------
236
237 wxInputStream *wxURL::GetInputStream()
238 {
239 if (!m_protocol)
240 {
241 m_error = wxURL_NOPROTO;
242 return NULL;
243 }
244
245 m_error = wxURL_NOERR;
246 if (HasUserInfo())
247 {
248 size_t dwPasswordPos = m_userinfo.find(':');
249
250 if (dwPasswordPos == wxString::npos)
251 m_protocol->SetUser(Unescape(m_userinfo));
252 else
253 {
254 m_protocol->SetUser(Unescape(m_userinfo(0, dwPasswordPos)));
255 m_protocol->SetPassword(Unescape(m_userinfo(dwPasswordPos+1, m_userinfo.length() + 1)));
256 }
257 }
258
259 #if wxUSE_URL_NATIVE
260 // give the native implementation to return a better stream
261 // such as the native WinINet functionality under MS-Windows
262 if (m_nativeImp)
263 {
264 wxInputStream *rc;
265 rc = m_nativeImp->GetInputStream(this);
266 if (rc != 0)
267 return rc;
268 }
269 // else use the standard behaviour
270 #endif // wxUSE_URL_NATIVE
271
272 #if wxUSE_SOCKETS
273 wxIPV4address addr;
274
275 // m_protoinfo is NULL when we use a proxy
276 if (
277 #if wxUSE_PROTOCOL_HTTP
278 !m_useProxy &&
279 #endif // wxUSE_PROTOCOL_HTTP
280 m_protoinfo->m_needhost )
281 {
282 if (!addr.Hostname(m_server))
283 {
284 m_error = wxURL_NOHOST;
285 return NULL;
286 }
287
288 addr.Service(m_port);
289
290 if (!m_protocol->Connect(addr, true)) // Watcom needs the 2nd arg for some reason
291 {
292 m_error = wxURL_CONNERR;
293 return NULL;
294 }
295 }
296 #endif // wxUSE_SOCKETS
297
298 wxString fullPath;
299
300 #if wxUSE_PROTOCOL_HTTP
301 // When we use a proxy, we have to pass the whole URL to it.
302 if (m_useProxy)
303 fullPath += m_url;
304 #endif // wxUSE_PROTOCOL_HTTP
305
306 if(m_path.empty())
307 fullPath += wxT("/");
308 else
309 fullPath += m_path;
310
311 if (HasQuery())
312 fullPath += wxT("?") + m_query;
313
314 if (HasFragment())
315 fullPath += wxT("#") + m_fragment;
316
317 wxInputStream *the_i_stream = m_protocol->GetInputStream(fullPath);
318
319 if (!the_i_stream)
320 {
321 m_error = wxURL_PROTOERR;
322 return NULL;
323 }
324
325 return the_i_stream;
326 }
327
328 #if wxUSE_PROTOCOL_HTTP
329 void wxURL::SetDefaultProxy(const wxString& url_proxy)
330 {
331 if ( !url_proxy )
332 {
333 if ( ms_proxyDefault )
334 {
335 ms_proxyDefault->Close();
336 delete ms_proxyDefault;
337 ms_proxyDefault = NULL;
338 }
339 }
340 else
341 {
342 wxString tmp_str = url_proxy;
343 int pos = tmp_str.Find(wxT(':'));
344 if (pos == wxNOT_FOUND)
345 return;
346
347 wxString hostname = tmp_str(0, pos),
348 port = tmp_str(pos+1, tmp_str.length()-pos);
349 wxIPV4address addr;
350
351 if (!addr.Hostname(hostname))
352 return;
353 if (!addr.Service(port))
354 return;
355
356 if (ms_proxyDefault)
357 // Finally, when all is right, we connect the new proxy.
358 ms_proxyDefault->Close();
359 else
360 ms_proxyDefault = new wxHTTP();
361 ms_proxyDefault->Connect(addr, true); // Watcom needs the 2nd arg for some reason
362 }
363 }
364
365 void wxURL::SetProxy(const wxString& url_proxy)
366 {
367 if ( !url_proxy )
368 {
369 if ( m_proxy && m_proxy != ms_proxyDefault )
370 {
371 m_proxy->Close();
372 delete m_proxy;
373 }
374
375 m_useProxy = false;
376 }
377 else
378 {
379 wxString tmp_str;
380 wxString hostname, port;
381 int pos;
382 wxIPV4address addr;
383
384 tmp_str = url_proxy;
385 pos = tmp_str.Find(wxT(':'));
386 // This is an invalid proxy name.
387 if (pos == wxNOT_FOUND)
388 return;
389
390 hostname = tmp_str(0, pos);
391 port = tmp_str(pos+1, tmp_str.length()-pos);
392
393 addr.Hostname(hostname);
394 addr.Service(port);
395
396 // Finally, create the whole stuff.
397 if (m_proxy && m_proxy != ms_proxyDefault)
398 delete m_proxy;
399 m_proxy = new wxHTTP();
400 m_proxy->Connect(addr, true); // Watcom needs the 2nd arg for some reason
401
402 CleanData();
403 // Reparse url.
404 m_useProxy = true;
405 ParseURL();
406 }
407 }
408 #endif // wxUSE_PROTOCOL_HTTP
409
410 // ----------------------------------------------------------------------
411 // wxURLModule
412 //
413 // A module which deletes the default proxy if we created it
414 // ----------------------------------------------------------------------
415
416 #if wxUSE_SOCKETS
417
418 class wxURLModule : public wxModule
419 {
420 public:
421 wxURLModule();
422
423 virtual bool OnInit();
424 virtual void OnExit();
425
426 private:
427 DECLARE_DYNAMIC_CLASS(wxURLModule)
428 };
429
430 IMPLEMENT_DYNAMIC_CLASS(wxURLModule, wxModule)
431
432 wxURLModule::wxURLModule()
433 {
434 // we must be cleaned up before wxSocketModule as otherwise deleting
435 // ms_proxyDefault from our OnExit() won't work (and can actually crash)
436 AddDependency(wxClassInfo::FindClass(wxT("wxSocketModule")));
437 }
438
439 bool wxURLModule::OnInit()
440 {
441 #if wxUSE_PROTOCOL_HTTP
442 // env var HTTP_PROXY contains the address of the default proxy to use if
443 // set, but don't try to create this proxy right now because it will slow
444 // down the program startup (especially if there is no DNS server
445 // available, in which case it may take up to 1 minute)
446
447 if ( wxGetenv(wxT("HTTP_PROXY")) )
448 {
449 wxURL::ms_useDefaultProxy = true;
450 }
451 #endif // wxUSE_PROTOCOL_HTTP
452 return true;
453 }
454
455 void wxURLModule::OnExit()
456 {
457 #if wxUSE_PROTOCOL_HTTP
458 delete wxURL::ms_proxyDefault;
459 wxURL::ms_proxyDefault = NULL;
460 #endif // wxUSE_PROTOCOL_HTTP
461 }
462
463 #endif // wxUSE_SOCKETS
464
465
466 #endif // wxUSE_URL