webservices: Implement WsDecodeUrl.
[wine.git] / dlls / webservices / url.c
blob8884fd11916f89ad415c43c21df79ca177214dae
1 /*
2 * Copyright 2016 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
19 #include <stdarg.h>
21 #include "windef.h"
22 #include "winbase.h"
23 #include "winuser.h"
24 #include "webservices.h"
26 #include "wine/debug.h"
27 #include "wine/list.h"
28 #include "wine/unicode.h"
29 #include "webservices_private.h"
31 WINE_DEFAULT_DEBUG_CHANNEL(webservices);
33 static const WCHAR http[] = {'h','t','t','p'};
34 static const WCHAR https[] = {'h','t','t','p','s'};
35 static const WCHAR nettcp[] = {'n','e','t','.','t','c','p'};
36 static const WCHAR soapudp[] = {'s','o','a','p','.','u','d','p'};
37 static const WCHAR netpipe[] = {'n','e','t','.','p','i','p','e'};
39 static WS_URL_SCHEME_TYPE scheme_type( const WCHAR *str, ULONG len )
41 if (len == sizeof(http)/sizeof(http[0]) && !memicmpW( str, http, sizeof(http)/sizeof(http[0]) ))
42 return WS_URL_HTTP_SCHEME_TYPE;
44 if (len == sizeof(https)/sizeof(https[0]) && !memicmpW( str, https, sizeof(https)/sizeof(https[0]) ))
45 return WS_URL_HTTPS_SCHEME_TYPE;
47 if (len == sizeof(nettcp)/sizeof(nettcp[0]) && !memicmpW( str, nettcp, sizeof(nettcp)/sizeof(nettcp[0]) ))
48 return WS_URL_NETTCP_SCHEME_TYPE;
50 if (len == sizeof(soapudp)/sizeof(soapudp[0]) && !memicmpW( str, soapudp, sizeof(soapudp)/sizeof(soapudp[0]) ))
51 return WS_URL_SOAPUDP_SCHEME_TYPE;
53 if (len == sizeof(netpipe)/sizeof(netpipe[0]) && !memicmpW( str, netpipe, sizeof(netpipe)/sizeof(netpipe[0]) ))
54 return WS_URL_NETPIPE_SCHEME_TYPE;
56 return ~0u;
59 static USHORT default_port( WS_URL_SCHEME_TYPE scheme )
61 switch (scheme)
63 case WS_URL_HTTP_SCHEME_TYPE: return 80;
64 case WS_URL_HTTPS_SCHEME_TYPE: return 443;
65 case WS_URL_NETTCP_SCHEME_TYPE: return 808;
66 case WS_URL_SOAPUDP_SCHEME_TYPE:
67 case WS_URL_NETPIPE_SCHEME_TYPE: return 65535;
68 default:
69 ERR( "unhandled scheme %u\n", scheme );
70 return 0;
74 static WCHAR *url_decode( WCHAR *str, ULONG len, WS_HEAP *heap, ULONG *ret_len )
76 WCHAR *p = str, *q, *ret;
77 BOOL decode = FALSE;
78 ULONG i, val;
80 *ret_len = len;
81 for (i = 0; i < len; i++, p++)
83 if ((len - i) < 3) break;
84 if (p[0] == '%' && isxdigitW( p[1] ) && isxdigitW( p[2] ))
86 decode = TRUE;
87 *ret_len -= 2;
90 if (!decode) return str;
92 if (!(q = ret = ws_alloc( heap, *ret_len * sizeof(WCHAR) ))) return NULL;
93 p = str;
94 while (len)
96 if (len >= 3 && p[0] == '%' && isxdigitW( p[1] ) && isxdigitW( p[2] ))
98 if (p[1] >= '0' && p[1] <= '9') val = (p[1] - '0') * 16;
99 else if (p[1] >= 'a' && p[1] <= 'f') val = (p[1] - 'a') * 16;
100 else val = (p[1] - 'A') * 16;
102 if (p[2] >= '0' && p[2] <= '9') val += p[2] - '0';
103 else if (p[1] >= 'a' && p[1] <= 'f') val += p[2] - 'a';
104 else val += p[1] - 'A';
106 *q++ = val;
107 p += 3;
108 len -= 3;
110 else
112 *q++ = *p++;
113 len -= 1;
117 return ret;
120 /**************************************************************************
121 * WsDecodeUrl [webservices.@]
123 HRESULT WINAPI WsDecodeUrl( const WS_STRING *str, ULONG flags, WS_HEAP *heap, WS_URL **ret,
124 WS_ERROR *error )
126 HRESULT hr = WS_E_QUOTA_EXCEEDED;
127 WCHAR *p, *q, *decoded = NULL;
128 WS_HTTP_URL *url = NULL;
129 ULONG len, port = 0;
131 TRACE( "%s %08x %p %p %p\n", str ? debugstr_wn(str->chars, str->length) : "null", flags,
132 heap, ret, error );
133 if (error) FIXME( "ignoring error parameter\n" );
135 if (!str || !heap) return E_INVALIDARG;
136 if (!str->length) return WS_E_INVALID_FORMAT;
137 if (flags)
139 FIXME( "unimplemented flags %08x\n", flags );
140 return E_NOTIMPL;
142 if (!(decoded = url_decode( str->chars, str->length, heap, &len )) ||
143 !(url = ws_alloc( heap, sizeof(*url) ))) goto error;
145 hr = WS_E_INVALID_FORMAT;
147 p = q = decoded;
148 while (len && *q != ':') { q++; len--; };
149 if (*q != ':') goto error;
150 if ((url->url.scheme = scheme_type( p, q - p )) == ~0u) goto error;
152 if (!--len || *++q != '/') goto error;
153 if (!--len || *++q != '/') goto error;
155 p = ++q; len--;
156 while (len && *q != '/' && *q != ':' && *q != '?' && *q != '#') { q++; len--; };
157 if (q == p) goto error;
158 url->host.length = q - p;
159 url->host.chars = p;
161 if (len && *q == ':')
163 p = ++q; len--;
164 while (len && isdigitW( *q ))
166 if ((port = port * 10 + *q - '0') > 65535) goto error;
167 q++; len--;
169 url->port = port;
170 url->portAsString.length = q - p;
171 url->portAsString.chars = p;
173 if (!port)
175 url->port = default_port( url->url.scheme );
176 url->portAsString.length = 0;
177 url->portAsString.chars = NULL;
180 if (len && *q == '/')
182 p = q;
183 while (len && *q != '?') { q++; len--; };
184 url->path.length = q - p;
185 url->path.chars = p;
187 else url->path.length = 0;
189 if (len && *q == '?')
191 p = ++q; len--;
192 while (len && *q != '#') { q++; len--; };
193 url->query.length = q - p;
194 url->query.chars = p;
196 else url->query.length = 0;
198 if (len && *q == '#')
200 p = ++q; len--;
201 while (len && *q != '#') { q++; len--; };
202 url->fragment.length = q - p;
203 url->fragment.chars = p;
205 else url->fragment.length = 0;
207 *ret = (WS_URL *)url;
208 return S_OK;
210 error:
211 if (decoded != str->chars) ws_free( heap, decoded );
212 ws_free( heap, url );
213 return hr;