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