1 /*
2 * Copyright 2008 Hans Leidekker for CodeWeavers
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
17 */
18
19 #include "config.h"
20 #include <stdarg.h>
21
22 #include "wine/debug.h"
23
24 #include "windef.h"
25 #include "winbase.h"
26 #include "winreg.h"
27 #include "winhttp.h"
28 #include "shlwapi.h"
29
30 #include "winhttp_private.h"
31
32 WINE_DEFAULT_DEBUG_CHANNEL(winhttp);
33
34 static const WCHAR scheme_http[] = {'h','t','t','p',0};
35 static const WCHAR scheme_https[] = {'h','t','t','p','s',0};
36
37 static BOOL set_component( WCHAR **str, DWORD *str_len, WCHAR *value, DWORD len, DWORD flags )
38 {
39 if (!*str)
40 {
41 if (len && (flags & ICU_DECODE))
42 {
43 set_last_error( ERROR_INVALID_PARAMETER );
44 return FALSE;
45 }
46 *str = value;
47 *str_len = len;
48 }
49 else
50 {
51 if (len > (*str_len) - 1)
52 {
53 *str_len = len + 1;
54 set_last_error( ERROR_INSUFFICIENT_BUFFER );
55 return FALSE;
56 }
57 memcpy( *str, value, len * sizeof(WCHAR) );
58 (*str)[len] = 0;
59 *str_len = len;
60 }
61 return TRUE;
62 }
63
64 static BOOL decode_url( LPCWSTR url, LPWSTR buffer, LPDWORD buflen )
65 {
66 HRESULT hr = UrlCanonicalizeW( url, buffer, buflen, URL_WININET_COMPATIBILITY | URL_UNESCAPE );
67 if (hr == E_POINTER) set_last_error( ERROR_INSUFFICIENT_BUFFER );
68 if (hr == E_INVALIDARG) set_last_error( ERROR_INVALID_PARAMETER );
69 return (SUCCEEDED(hr)) ? TRUE : FALSE;
70 }
71
72 /***********************************************************************
73 * WinHttpCrackUrl (winhttp.@)
74 */
75 BOOL WINAPI WinHttpCrackUrl( LPCWSTR url, DWORD len, DWORD flags, LPURL_COMPONENTSW uc )
76 {
77 BOOL ret = FALSE;
78 WCHAR *p, *q, *r;
79 WCHAR *url_decoded = NULL;
80
81 TRACE("%s, %d, %x, %p\n", debugstr_w(url), len, flags, uc);
82
83 if (flags & ICU_ESCAPE) FIXME("flag ICU_ESCAPE not supported\n");
84
85 if (!url || !url[0] || !uc || uc->dwStructSize != sizeof(URL_COMPONENTS))
86 {
87 set_last_error( ERROR_INVALID_PARAMETER );
88 return FALSE;
89 }
90 if (!len) len = strlenW( url );
91
92 if (flags & ICU_DECODE)
93 {
94 WCHAR *url_tmp;
95 DWORD url_len = len + 1;
96
97 if (!(url_tmp = HeapAlloc( GetProcessHeap(), 0, url_len * sizeof(WCHAR) )))
98 {
99 set_last_error( ERROR_OUTOFMEMORY );
100 return FALSE;
101 }
102 memcpy( url_tmp, url, len * sizeof(WCHAR) );
103 url_tmp[len] = 0;
104 if (!(url_decoded = HeapAlloc( GetProcessHeap(), 0, url_len * sizeof(WCHAR) )))
105 {
106 HeapFree( GetProcessHeap(), 0, url_tmp );
107 set_last_error( ERROR_OUTOFMEMORY );
108 return FALSE;
109 }
110 if (decode_url( url_tmp, url_decoded, &url_len ))
111 {
112 len = url_len;
113 url = url_decoded;
114 }
115 HeapFree( GetProcessHeap(), 0, url_tmp );
116 }
117 if (!(p = strchrW( url, ':' ))) return FALSE;
118
119 if (p - url == 4 && !strncmpiW( url, scheme_http, 4 )) uc->nScheme = INTERNET_SCHEME_HTTP;
120 else if (p - url == 5 && !strncmpiW( url, scheme_https, 5 )) uc->nScheme = INTERNET_SCHEME_HTTPS;
121 else goto exit;
122
123 if (!(set_component( &uc->lpszScheme, &uc->dwSchemeLength, (WCHAR *)url, p - url, flags ))) goto exit;
124
125 p++; /* skip ':' */
126 if (!p[0] || p[0] != '/' || p[1] != '/') goto exit;
127 p += 2;
128
129 if (!p[0]) goto exit;
130 if ((q = memchrW( p, '@', len - (p - url) )))
131 {
132 if ((r = memchrW( p, ':', q - p )))
133 {
134 if (!(set_component( &uc->lpszUserName, &uc->dwUserNameLength, p, r - p, flags ))) goto exit;
135 r++;
136 if (!(set_component( &uc->lpszPassword, &uc->dwPasswordLength, r, q - r, flags ))) goto exit;
137 }
138 else
139 {
140 if (!(set_component( &uc->lpszUserName, &uc->dwUserNameLength, p, q - p, flags ))) goto exit;
141 if (!(set_component( &uc->lpszPassword, &uc->dwPasswordLength, NULL, 0, flags ))) goto exit;
142 }
143 p = q + 1;
144 }
145 else
146 {
147 if (!(set_component( &uc->lpszUserName, &uc->dwUserNameLength, NULL, 0, flags ))) goto exit;
148 if (!(set_component( &uc->lpszPassword, &uc->dwPasswordLength, NULL, 0, flags ))) goto exit;
149 }
150 if ((q = memchrW( p, '/', len - (p - url) )))
151 {
152 if ((r = memchrW( p, ':', q - p )))
153 {
154 if (!(set_component( &uc->lpszHostName, &uc->dwHostNameLength, p, r - p, flags ))) goto exit;
155 r++;
156 uc->nPort = atoiW( r );
157 }
158 else
159 {
160 if (!(set_component( &uc->lpszHostName, &uc->dwHostNameLength, p, q - p, flags ))) goto exit;
161 if (uc->nScheme == INTERNET_SCHEME_HTTP) uc->nPort = INTERNET_DEFAULT_HTTP_PORT;
162 if (uc->nScheme == INTERNET_SCHEME_HTTPS) uc->nPort = INTERNET_DEFAULT_HTTPS_PORT;
163 }
164
165 if ((r = memchrW( q, '?', len - (q - url) )))
166 {
167 if (!(set_component( &uc->lpszUrlPath, &uc->dwUrlPathLength, q, r - q, flags ))) goto exit;
168 if (!(set_component( &uc->lpszExtraInfo, &uc->dwExtraInfoLength, r, len - (r - url), flags ))) goto exit;
169 }
170 else
171 {
172 if (!(set_component( &uc->lpszUrlPath, &uc->dwUrlPathLength, q, len - (q - url), flags ))) goto exit;
173 if (!(set_component( &uc->lpszExtraInfo, &uc->dwExtraInfoLength, (WCHAR *)url + len, 0, flags ))) goto exit;
174 }
175 }
176 else
177 {
178 if ((r = memchrW( p, ':', len - (p - url) )))
179 {
180 if (!(set_component( &uc->lpszHostName, &uc->dwHostNameLength, p, r - p, flags ))) goto exit;
181 r++;
182 uc->nPort = atoiW( r );
183 }
184 else
185 {
186 if (!(set_component( &uc->lpszHostName, &uc->dwHostNameLength, p, len - (p - url), flags ))) goto exit;
187 if (uc->nScheme == INTERNET_SCHEME_HTTP) uc->nPort = INTERNET_DEFAULT_HTTP_PORT;
188 if (uc->nScheme == INTERNET_SCHEME_HTTPS) uc->nPort = INTERNET_DEFAULT_HTTPS_PORT;
189 }
190 if (!(set_component( &uc->lpszUrlPath, &uc->dwUrlPathLength, (WCHAR *)url + len, 0, flags ))) goto exit;
191 if (!(set_component( &uc->lpszExtraInfo, &uc->dwExtraInfoLength, (WCHAR *)url + len, 0, flags ))) goto exit;
192 }
193
194 ret = TRUE;
195
196 TRACE("scheme(%s) host(%s) port(%d) path(%s) extra(%s)\n",
197 debugstr_wn( uc->lpszScheme, uc->dwSchemeLength ),
198 debugstr_wn( uc->lpszHostName, uc->dwHostNameLength ),
199 uc->nPort,
200 debugstr_wn( uc->lpszUrlPath, uc->dwUrlPathLength ),
201 debugstr_wn( uc->lpszExtraInfo, uc->dwExtraInfoLength ));
202
203 exit:
204 HeapFree( GetProcessHeap(), 0, url_decoded );
205 return ret;
206 }
207
208 static INTERNET_SCHEME get_scheme( const WCHAR *scheme, DWORD len )
209 {
210 if (!strncmpW( scheme, scheme_http, len )) return INTERNET_SCHEME_HTTP;
211 if (!strncmpW( scheme, scheme_https, len )) return INTERNET_SCHEME_HTTPS;
212 return 0;
213 }
214
215 static const WCHAR *get_scheme_string( INTERNET_SCHEME scheme )
216 {
217 if (scheme == INTERNET_SCHEME_HTTP) return scheme_http;
218 if (scheme == INTERNET_SCHEME_HTTPS) return scheme_https;
219 return NULL;
220 }
221
222 static BOOL uses_default_port( INTERNET_SCHEME scheme, INTERNET_PORT port )
223 {
224 if ((scheme == INTERNET_SCHEME_HTTP) && (port == INTERNET_DEFAULT_HTTP_PORT)) return TRUE;
225 if ((scheme == INTERNET_SCHEME_HTTPS) && (port == INTERNET_DEFAULT_HTTPS_PORT)) return TRUE;
226 return FALSE;
227 }
228
229 static BOOL need_escape( WCHAR c )
230 {
231 if (isalnumW( c )) return FALSE;
232
233 if (c <= 31 || c >= 127) return TRUE;
234 else
235 {
236 switch (c)
237 {
238 case ' ':
239 case '"':
240 case '#':
241 case '%':
242 case '<':
243 case '>':
244 case ']':
245 case '\\':
246 case '[':
247 case '^':
248 case '`':
249 case '{':
250 case '|':
251 case '}':
252 case '~':
253 return TRUE;
254 default:
255 return FALSE;
256 }
257 }
258 }
259
260 static DWORD copy_escape( WCHAR *dst, const WCHAR *src, DWORD len )
261 {
262 static const WCHAR hex[] = {'','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
263 DWORD ret = len;
264 unsigned int i;
265 WCHAR *p = dst;
266
267 for (i = 0; i < len; i++, p++)
268 {
269 if (need_escape( src[i] ))
270 {
271 p[0] = '%';
272 p[1] = hex[(src[i] >> 4) & 0xf];
273 p[2] = hex[src[i] & 0xf];
274 ret += 2;
275 p += 2;
276 }
277 else *p = src[i];
278 }
279 dst[ret] = 0;
280 return ret;
281 }
282
283 static DWORD comp_length( DWORD len, DWORD flags, WCHAR *comp )
284 {
285 DWORD ret;
286 unsigned int i;
287
288 ret = len ? len : strlenW( comp );
289 if (!(flags & ICU_ESCAPE)) return ret;
290 for (i = 0; i < len; i++) if (need_escape( comp[i] )) ret += 2;
291 return ret;
292 }
293
294 static BOOL calc_length( URL_COMPONENTS *uc, DWORD flags, LPDWORD len )
295 {
296 static const WCHAR formatW[] = {'%','d',0};
297 INTERNET_SCHEME scheme;
298
299 *len = 0;
300 if (uc->lpszScheme)
301 {
302 DWORD scheme_len = comp_length( uc->dwSchemeLength, 0, uc->lpszScheme );
303 *len += scheme_len;
304 scheme = get_scheme( uc->lpszScheme, scheme_len );
305 }
306 else
307 {
308 scheme = uc->nScheme;
309 if (!scheme) scheme = INTERNET_SCHEME_HTTP;
310 *len += strlenW( get_scheme_string( scheme ) );
311 }
312 *len += 1; /* ':' */
313 if (uc->lpszHostName) *len += 2; /* "//" */
314
315 if (uc->lpszUserName)
316 {
317 *len += comp_length( uc->dwUserNameLength, 0, uc->lpszUserName );
318 *len += 1; /* "@" */
319 }
320 else
321 {
322 if (uc->lpszPassword)
323 {
324 set_last_error( ERROR_INVALID_PARAMETER );
325 return FALSE;
326 }
327 }
328 if (uc->lpszPassword)
329 {
330 *len += 1; /* ":" */
331 *len += comp_length( uc->dwPasswordLength, 0, uc->lpszPassword );
332 }
333 if (uc->lpszHostName)
334 {
335 *len += comp_length( uc->dwHostNameLength, 0, uc->lpszHostName );
336
337 if (!uses_default_port( scheme, uc->nPort ))
338 {
339 WCHAR port[sizeof("65535")];
340
341 sprintfW( port, formatW, uc->nPort );
342 *len += strlenW( port );
343 *len += 1; /* ":" */
344 }
345 if (uc->lpszUrlPath && *uc->lpszUrlPath != '/') *len += 1; /* '/' */
346 }
347 if (uc->lpszUrlPath) *len += comp_length( uc->dwUrlPathLength, flags, uc->lpszUrlPath );
348 if (uc->lpszExtraInfo) *len += comp_length( uc->dwExtraInfoLength, flags, uc->lpszExtraInfo );
349 return TRUE;
350 }
351
352 /***********************************************************************
353 * WinHttpCreateUrl (winhttp.@)
354 */
355 BOOL WINAPI WinHttpCreateUrl( LPURL_COMPONENTS uc, DWORD flags, LPWSTR url, LPDWORD required )
356 {
357 static const WCHAR formatW[] = {'%','d',0};
358 static const WCHAR twoslashW[] = {'/','/'};
359
360 DWORD len;
361 INTERNET_SCHEME scheme;
362
363 TRACE("%p, 0x%08x, %p, %p\n", uc, flags, url, required);
364
365 if (!uc || uc->dwStructSize != sizeof(URL_COMPONENTS) || !required)
366 {
367 set_last_error( ERROR_INVALID_PARAMETER );
368 return FALSE;
369 }
370
371 if (!calc_length( uc, flags, &len )) return FALSE;
372
373 if (!url || *required < len)
374 {
375 *required = len + 1;
376 set_last_error( ERROR_INSUFFICIENT_BUFFER );
377 return FALSE;
378 }
379
380 url[0] = 0;
381 *required = len;
382 if (uc->lpszScheme)
383 {
384 len = comp_length( uc->dwSchemeLength, 0, uc->lpszScheme );
385 memcpy( url, uc->lpszScheme, len * sizeof(WCHAR) );
386 url += len;
387
388 scheme = get_scheme( uc->lpszScheme, len );
389 }
390 else
391 {
392 const WCHAR *schemeW;
393 scheme = uc->nScheme;
394
395 if (!scheme) scheme = INTERNET_SCHEME_HTTP;
396
397 schemeW = get_scheme_string( scheme );
398 len = strlenW( schemeW );
399 memcpy( url, schemeW, len * sizeof(WCHAR) );
400 url += len;
401 }
402
403 /* all schemes are followed by at least a colon */
404 *url = ':';
405 url++;
406
407 if (uc->lpszHostName)
408 {
409 memcpy( url, twoslashW, sizeof(twoslashW) );
410 url += sizeof(twoslashW) / sizeof(twoslashW[0]);
411 }
412 if (uc->lpszUserName)
413 {
414 len = comp_length( uc->dwUserNameLength, 0, uc->lpszUserName );
415 memcpy( url, uc->lpszUserName, len * sizeof(WCHAR) );
416 url += len;
417
418 if (uc->lpszPassword)
419 {
420 *url = ':';
421 url++;
422
423 len = comp_length( uc->dwPasswordLength, 0, uc->lpszPassword );
424 memcpy( url, uc->lpszPassword, len * sizeof(WCHAR) );
425 url += len;
426 }
427 *url = '@';
428 url++;
429 }
430 if (uc->lpszHostName)
431 {
432 len = comp_length( uc->dwHostNameLength, 0, uc->lpszHostName );
433 memcpy( url, uc->lpszHostName, len * sizeof(WCHAR) );
434 url += len;
435
436 if (!uses_default_port( scheme, uc->nPort ))
437 {
438 WCHAR port[sizeof("65535")];
439
440 sprintfW( port, formatW, uc->nPort );
441 *url = ':';
442 url++;
443
444 len = strlenW( port );
445 memcpy( url, port, len * sizeof(WCHAR) );
446 url += len;
447 }
448
449 /* add slash between hostname and path if necessary */
450 if (uc->lpszUrlPath && *uc->lpszUrlPath != '/')
451 {
452 *url = '/';
453 url++;
454 }
455 }
456 if (uc->lpszUrlPath)
457 {
458 len = comp_length( uc->dwUrlPathLength, 0, uc->lpszUrlPath );
459 if (flags & ICU_ESCAPE) url += copy_escape( url, uc->lpszUrlPath, len );
460 else
461 {
462 memcpy( url, uc->lpszUrlPath, len * sizeof(WCHAR) );
463 url += len;
464 }
465 }
466 if (uc->lpszExtraInfo)
467 {
468 len = comp_length( uc->dwExtraInfoLength, 0, uc->lpszExtraInfo );
469 if (flags & ICU_ESCAPE) url += copy_escape( url, uc->lpszExtraInfo, len );
470 else
471 {
472 memcpy( url, uc->lpszExtraInfo, len * sizeof(WCHAR) );
473 url += len;
474 }
475 }
476 *url = 0;
477 return TRUE;
478 }
479
This page was automatically generated by the
LXR engine.
Visit the LXR main site for more
information.