Now its possible to run wxHTML without wxSockets
[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 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/url.h>
30
31 #if !USE_SHARED_LIBRARY
32 IMPLEMENT_CLASS(wxProtoInfo, wxObject)
33 IMPLEMENT_CLASS(wxURL, wxObject)
34 #endif
35
36 // Protocols list
37 wxProtoInfo *wxURL::g_protocols = NULL;
38
39 #if wxUSE_SOCKETS
40 wxHTTP *wxURL::g_proxy = NULL;
41 #endif
42
43 // --------------------------------------------------------------
44 // wxURL
45 // --------------------------------------------------------------
46
47 // --------------------------------------------------------------
48 // --------- wxURL CONSTRUCTOR DESTRUCTOR -----------------------
49 // --------------------------------------------------------------
50
51 wxURL::wxURL(const wxString& url)
52 {
53 m_protocol = NULL;
54 m_error = wxURL_NOERR;
55 m_url = url;
56 #if wxUSE_SOCKETS
57 m_useProxy = (g_proxy != NULL);
58 m_proxy = g_proxy;
59 #endif
60 ParseURL();
61 }
62
63 bool wxURL::ParseURL()
64 {
65 wxString last_url = m_url;
66
67 // If the URL was already parsed (so m_protocol != NULL), we pass this section.
68 if (!m_protocol) {
69
70 // Clean up
71 CleanData();
72
73 // Extract protocol name
74 if (!PrepProto(last_url)) {
75 m_error = wxURL_SNTXERR;
76 return FALSE;
77 }
78
79 // Find and create the protocol object
80 if (!FetchProtocol()) {
81 m_error = wxURL_NOPROTO;
82 return FALSE;
83 }
84
85 // Do we need a host name ?
86 if (m_protoinfo->m_needhost) {
87 // Extract it
88 if (!PrepHost(last_url)) {
89 m_error = wxURL_SNTXERR;
90 return FALSE;
91 }
92 }
93
94 // Extract full path
95 if (!PrepPath(last_url)) {
96 m_error = wxURL_NOPATH;
97 return FALSE;
98 }
99 }
100 // URL parse finished.
101
102 #if wxUSE_SOCKETS
103 if (m_useProxy) {
104 // We destroy the newly created protocol.
105 CleanData();
106
107 // Third, we rebuild the URL.
108 m_url = m_protoname + _T(":");
109 if (m_protoinfo->m_needhost)
110 m_url = m_url + _T("//") + m_hostname;
111
112 m_url += m_path;
113
114 // We initialize specific variables.
115 m_protocol = m_proxy; // FIXME: we should clone the protocol
116 }
117 #endif
118
119 m_error = wxURL_NOERR;
120 return TRUE;
121 }
122
123 void wxURL::CleanData()
124 {
125 #if wxUSE_SOCKETS
126 if (!m_useProxy)
127 #endif
128 delete m_protocol;
129 }
130
131 wxURL::~wxURL()
132 {
133 CleanData();
134 #if wxUSE_SOCKETS
135 if (m_proxy && m_proxy != g_proxy)
136 delete m_proxy;
137 #endif
138 }
139
140 // --------------------------------------------------------------
141 // --------- wxURL urls decoders --------------------------------
142 // --------------------------------------------------------------
143
144 bool wxURL::PrepProto(wxString& url)
145 {
146 int pos;
147
148 // Find end
149 pos = url.Find(_T(':'));
150 if (pos == -1)
151 return FALSE;
152
153 m_protoname = url(0, pos);
154
155 url = url(pos+1, url.Length());
156
157 return TRUE;
158 }
159
160 bool wxURL::PrepHost(wxString& url)
161 {
162 wxString temp_url;
163 int pos, pos2;
164
165 if ((url.GetChar(0) != '/') || (url.GetChar(1) != '/'))
166 return FALSE;
167
168 url = url(2, url.Length());
169
170 pos = url.Find(_T('/'));
171 if (pos == -1)
172 pos = url.Length();
173
174 if (pos == 0)
175 return FALSE;
176
177 temp_url = url(0, pos);
178 url = url(url.Find(_T('/')), url.Length());
179
180 // Retrieve service number
181 pos2 = temp_url.Find(_T(':'), TRUE);
182 if (pos2 != -1 && pos2 < pos) {
183 m_servname = temp_url(pos2+1, pos);
184 if (!m_servname.IsNumber())
185 return FALSE;
186 temp_url = temp_url(0, pos2);
187 }
188
189 // Retrieve user and password.
190 pos2 = temp_url.Find(_T('@'));
191 // Even if pos2 equals -1, this code is right.
192 m_hostname = temp_url(pos2+1, temp_url.Length());
193
194 m_user = _T("");
195 m_password = _T("");
196
197 if (pos2 == -1)
198 return TRUE;
199
200 temp_url = temp_url(0, pos2);
201 pos2 = temp_url.Find(_T(':'));
202
203 if (pos2 == -1)
204 return FALSE;
205
206 m_user = temp_url(0, pos2);
207 m_password = temp_url(pos2+1, url.Length());
208
209 return TRUE;
210 }
211
212 bool wxURL::PrepPath(wxString& url)
213 {
214 if (url.Length() != 0)
215 m_path = ConvertToValidURI(url);
216 else
217 m_path = _T("/");
218 return TRUE;
219 }
220
221 bool wxURL::FetchProtocol()
222 {
223 wxProtoInfo *info = g_protocols;
224
225 while (info) {
226 if (m_protoname == info->m_protoname) {
227 if (m_servname.IsNull())
228 m_servname = info->m_servname;
229
230 m_protoinfo = info;
231 m_protocol = (wxProtocol *)m_protoinfo->m_cinfo->CreateObject();
232 return TRUE;
233 }
234 info = info->next;
235 }
236 return FALSE;
237 }
238
239 // --------------------------------------------------------------
240 // --------- wxURL get ------------------------------------------
241 // --------------------------------------------------------------
242
243 wxInputStream *wxURL::GetInputStream(void)
244 {
245 wxInputStream *the_i_stream = NULL;
246
247 if (!m_protocol) {
248 m_error = wxURL_NOPROTO;
249 return NULL;
250 }
251
252 m_error = wxURL_NOERR;
253 if (m_user != _T("")) {
254 m_protocol->SetUser(m_user);
255 m_protocol->SetPassword(m_password);
256 }
257
258 #if wxUSE_SOCKETS
259 // m_protoinfo is NULL when we use a proxy
260 if (!m_useProxy && m_protoinfo->m_needhost) {
261 if (!addr.Hostname(m_hostname)) {
262 m_error = wxURL_NOHOST;
263 return NULL;
264 }
265
266 wxIPV4address addr;
267 addr.Service(m_servname);
268
269 if (!m_protocol->Connect(addr, TRUE)) // Watcom needs the 2nd arg for some reason
270 {
271 m_error = wxURL_CONNERR;
272 return NULL;
273 }
274 }
275 #endif
276
277 // When we use a proxy, we have to pass the whole URL to it.
278 if (m_useProxy)
279 the_i_stream = m_protocol->GetInputStream(m_url);
280 else
281 the_i_stream = m_protocol->GetInputStream(m_path);
282
283 if (!the_i_stream) {
284 m_error = wxURL_PROTOERR;
285 return NULL;
286 }
287
288 return the_i_stream;
289 }
290
291 #if wxUSE_SOCKETS
292 void wxURL::SetDefaultProxy(const wxString& url_proxy)
293 {
294 if (url_proxy.IsNull()) {
295 g_proxy->Close();
296 delete g_proxy;
297 g_proxy = NULL;
298 return;
299 }
300
301 wxString tmp_str = url_proxy;
302 int pos = tmp_str.Find(_T(':'));
303 if (pos == -1)
304 return;
305
306 wxString hostname = tmp_str(0, pos),
307 port = tmp_str(pos+1, tmp_str.Length()-pos);
308 wxIPV4address addr;
309
310 if (!addr.Hostname(hostname))
311 return;
312 if (!addr.Service(port))
313 return;
314
315 if (g_proxy)
316 // Finally, when all is right, we connect the new proxy.
317 g_proxy->Close();
318 else
319 g_proxy = new wxHTTP();
320 g_proxy->Connect(addr, TRUE); // Watcom needs the 2nd arg for some reason
321 }
322
323 void wxURL::SetProxy(const wxString& url_proxy)
324 {
325 if (url_proxy.IsNull()) {
326 if (m_proxy) {
327 m_proxy->Close();
328 delete m_proxy;
329 }
330 m_useProxy = FALSE;
331 return;
332 }
333
334 wxString tmp_str;
335 wxString hostname, port;
336 int pos;
337 wxIPV4address addr;
338
339 tmp_str = url_proxy;
340 pos = tmp_str.Find(_T(':'));
341 // This is an invalid proxy name.
342 if (pos == -1)
343 return;
344
345 hostname = tmp_str(0, pos);
346 port = tmp_str(pos, tmp_str.Length()-pos);
347
348 addr.Hostname(hostname);
349 addr.Service(port);
350
351 // Finally, create the whole stuff.
352 if (m_proxy && m_proxy != g_proxy)
353 delete m_proxy;
354 m_proxy = new wxHTTP();
355 m_proxy->Connect(addr, TRUE); // Watcom needs the 2nd arg for some reason
356
357 CleanData();
358 // Reparse url.
359 m_useProxy = TRUE;
360 ParseURL();
361 }
362 #endif
363
364 wxString wxURL::ConvertToValidURI(const wxString& uri)
365 {
366 wxString out_str;
367 wxString hexa_code;
368 size_t i;
369
370 for (i=0;i<uri.Len();i++) {
371 wxChar c = uri.GetChar(i);
372
373 if (c == _T(' '))
374 out_str += _T('+');
375 else {
376 if (!isalpha(c) && c != _T('.') && c != _T('+') && c != _T('/')) {
377 hexa_code.Printf(_T("%%%02X"), c);
378 out_str += hexa_code;
379 } else
380 out_str += c;
381 }
382 }
383
384 return out_str;
385 }
386