2 * Copyright 2008 Hans Leidekker for CodeWeavers
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.
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.
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
22 #include "wine/debug.h"
28 #include "winhttp_private.h"
30 WINE_DEFAULT_DEBUG_CHANNEL(winhttp
);
33 #define SCHEME_HTTPS 4
35 BOOL WINAPI
InternetCrackUrlW( LPCWSTR
, DWORD
, DWORD
, LPURL_COMPONENTSW
);
37 /***********************************************************************
38 * WinHttpCrackUrl (winhttp.@)
40 BOOL WINAPI
WinHttpCrackUrl( LPCWSTR url
, DWORD len
, DWORD flags
, LPURL_COMPONENTSW components
)
44 TRACE("%s, %d, %x, %p\n", debugstr_w(url
), len
, flags
, components
);
46 if ((ret
= InternetCrackUrlW( url
, len
, flags
, components
)))
48 /* fix up an incompatibility between wininet and winhttp */
49 if (components
->nScheme
== SCHEME_HTTP
) components
->nScheme
= INTERNET_SCHEME_HTTP
;
50 else if (components
->nScheme
== SCHEME_HTTPS
) components
->nScheme
= INTERNET_SCHEME_HTTPS
;
53 set_last_error( ERROR_WINHTTP_UNRECOGNIZED_SCHEME
);
60 static const WCHAR scheme_http
[] = {'h','t','t','p',0};
61 static const WCHAR scheme_https
[] = {'h','t','t','p','s',0};
63 static INTERNET_SCHEME
get_scheme( const WCHAR
*scheme
, DWORD len
)
65 if (!strncmpW( scheme
, scheme_http
, len
)) return INTERNET_SCHEME_HTTP
;
66 if (!strncmpW( scheme
, scheme_https
, len
)) return INTERNET_SCHEME_HTTPS
;
70 static const WCHAR
*get_scheme_string( INTERNET_SCHEME scheme
)
72 if (scheme
== INTERNET_SCHEME_HTTP
) return scheme_http
;
73 if (scheme
== INTERNET_SCHEME_HTTPS
) return scheme_https
;
77 static BOOL
uses_default_port( INTERNET_SCHEME scheme
, INTERNET_PORT port
)
79 if ((scheme
== INTERNET_SCHEME_HTTP
) && (port
== INTERNET_DEFAULT_HTTP_PORT
)) return TRUE
;
80 if ((scheme
== INTERNET_SCHEME_HTTPS
) && (port
== INTERNET_DEFAULT_HTTPS_PORT
)) return TRUE
;
84 static BOOL
need_escape( WCHAR c
)
86 if (isalnumW( c
)) return FALSE
;
88 if (c
<= 31 || c
>= 127) return TRUE
;
115 static DWORD
copy_escape( WCHAR
*dst
, const WCHAR
*src
, DWORD len
)
117 static const WCHAR hex
[] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
122 for (i
= 0; i
< len
; i
++, p
++)
124 if (need_escape( src
[i
] ))
127 p
[1] = hex
[(src
[i
] >> 4) & 0xf];
128 p
[2] = hex
[src
[i
] & 0xf];
138 static DWORD
comp_length( DWORD len
, DWORD flags
, WCHAR
*comp
)
143 ret
= len
? len
: strlenW( comp
);
144 if (!(flags
& ICU_ESCAPE
)) return ret
;
145 for (i
= 0; i
< len
; i
++) if (need_escape( comp
[i
] )) ret
+= 2;
149 static BOOL
calc_length( URL_COMPONENTS
*uc
, DWORD flags
, LPDWORD len
)
151 static const WCHAR formatW
[] = {'%','d',0};
152 INTERNET_SCHEME scheme
;
157 DWORD scheme_len
= comp_length( uc
->dwSchemeLength
, 0, uc
->lpszScheme
);
159 scheme
= get_scheme( uc
->lpszScheme
, scheme_len
);
163 scheme
= uc
->nScheme
;
164 if (!scheme
) scheme
= INTERNET_SCHEME_HTTP
;
165 *len
+= strlenW( get_scheme_string( scheme
) );
168 if (uc
->lpszHostName
) *len
+= 2; /* "//" */
170 if (uc
->lpszUserName
)
172 *len
+= comp_length( uc
->dwUserNameLength
, 0, uc
->lpszUserName
);
177 if (uc
->lpszPassword
)
179 set_last_error( ERROR_INVALID_PARAMETER
);
183 if (uc
->lpszPassword
)
186 *len
+= comp_length( uc
->dwPasswordLength
, 0, uc
->lpszPassword
);
188 if (uc
->lpszHostName
)
190 *len
+= comp_length( uc
->dwHostNameLength
, 0, uc
->lpszHostName
);
192 if (!uses_default_port( scheme
, uc
->nPort
))
194 WCHAR port
[sizeof("65535")];
196 sprintfW( port
, formatW
, uc
->nPort
);
197 *len
+= strlenW( port
);
200 if (uc
->lpszUrlPath
&& *uc
->lpszUrlPath
!= '/') *len
+= 1; /* '/' */
202 if (uc
->lpszUrlPath
) *len
+= comp_length( uc
->dwUrlPathLength
, flags
, uc
->lpszUrlPath
);
203 if (uc
->lpszExtraInfo
) *len
+= comp_length( uc
->dwExtraInfoLength
, flags
, uc
->lpszExtraInfo
);
207 /***********************************************************************
208 * WinHttpCreateUrl (winhttp.@)
210 BOOL WINAPI
WinHttpCreateUrl( LPURL_COMPONENTS uc
, DWORD flags
, LPWSTR url
, LPDWORD required
)
212 static const WCHAR formatW
[] = {'%','d',0};
213 static const WCHAR twoslashW
[] = {'/','/'};
216 INTERNET_SCHEME scheme
;
218 TRACE("%p, 0x%08x, %p, %p\n", uc
, flags
, url
, required
);
220 if (!uc
|| uc
->dwStructSize
!= sizeof(URL_COMPONENTS
) || !required
)
222 set_last_error( ERROR_INVALID_PARAMETER
);
226 if (!calc_length( uc
, flags
, &len
)) return FALSE
;
228 if (!url
|| *required
< len
)
231 set_last_error( ERROR_INSUFFICIENT_BUFFER
);
239 len
= comp_length( uc
->dwSchemeLength
, 0, uc
->lpszScheme
);
240 memcpy( url
, uc
->lpszScheme
, len
* sizeof(WCHAR
) );
243 scheme
= get_scheme( uc
->lpszScheme
, len
);
247 const WCHAR
*schemeW
;
248 scheme
= uc
->nScheme
;
250 if (!scheme
) scheme
= INTERNET_SCHEME_HTTP
;
252 schemeW
= get_scheme_string( scheme
);
253 len
= strlenW( schemeW
);
254 memcpy( url
, schemeW
, len
* sizeof(WCHAR
) );
258 /* all schemes are followed by at least a colon */
262 if (uc
->lpszHostName
)
264 memcpy( url
, twoslashW
, sizeof(twoslashW
) );
265 url
+= sizeof(twoslashW
) / sizeof(twoslashW
[0]);
267 if (uc
->lpszUserName
)
269 len
= comp_length( uc
->dwUserNameLength
, 0, uc
->lpszUserName
);
270 memcpy( url
, uc
->lpszUserName
, len
* sizeof(WCHAR
) );
273 if (uc
->lpszPassword
)
278 len
= comp_length( uc
->dwPasswordLength
, 0, uc
->lpszPassword
);
279 memcpy( url
, uc
->lpszPassword
, len
* sizeof(WCHAR
) );
285 if (uc
->lpszHostName
)
287 len
= comp_length( uc
->dwHostNameLength
, 0, uc
->lpszHostName
);
288 memcpy( url
, uc
->lpszHostName
, len
* sizeof(WCHAR
) );
291 if (!uses_default_port( scheme
, uc
->nPort
))
293 WCHAR port
[sizeof("65535")];
295 sprintfW( port
, formatW
, uc
->nPort
);
299 len
= strlenW( port
);
300 memcpy( url
, port
, len
* sizeof(WCHAR
) );
304 /* add slash between hostname and path if necessary */
305 if (uc
->lpszUrlPath
&& *uc
->lpszUrlPath
!= '/')
313 len
= comp_length( uc
->dwUrlPathLength
, 0, uc
->lpszUrlPath
);
314 if (flags
& ICU_ESCAPE
) url
+= copy_escape( url
, uc
->lpszUrlPath
, len
);
317 memcpy( url
, uc
->lpszUrlPath
, len
* sizeof(WCHAR
) );
321 if (uc
->lpszExtraInfo
)
323 len
= comp_length( uc
->dwExtraInfoLength
, 0, uc
->lpszExtraInfo
);
324 if (flags
& ICU_ESCAPE
) url
+= copy_escape( url
, uc
->lpszExtraInfo
, len
);
327 memcpy( url
, uc
->lpszExtraInfo
, len
* sizeof(WCHAR
) );