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