url.c 13.2 KB
Newer Older
1
2
3
4
5
6
/*****************************************************************************
 * url.c: Test for url encoding/decoding stuff
 *****************************************************************************
 * Copyright (C) 2006 Rémi Denis-Courmont
 * $Id$
 *
Jean-Baptiste Kempf's avatar
LGPL    
Jean-Baptiste Kempf committed
7
8
9
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either version 2.1 of the License, or
10
11
12
13
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Jean-Baptiste Kempf's avatar
LGPL    
Jean-Baptiste Kempf committed
14
15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Lesser General Public License for more details.
16
 *
Jean-Baptiste Kempf's avatar
LGPL    
Jean-Baptiste Kempf committed
17
18
19
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
20
21
 *****************************************************************************/

22
23
24
25
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

26
27
#undef NDEBUG

28
29
#include <assert.h>
#include <errno.h>
30
31
#include <stdio.h>
#include <stdlib.h>
32
33
34
35
36
37

#include <vlc_common.h>
#include <vlc_url.h>
#include <vlc_strings.h>

static int exitcode = 0;
38

39
40
41
typedef char * (*conv_t) (const char *);

static void test (conv_t f, const char *in, const char *out)
42
{
43
    char *res = f(in);
44
45

    if (res == NULL)
46
47
48
    {
        if (out == NULL)
            return; /* good: NULL -> NULL */
49
50
51

        fprintf(stderr, "\"%s\" returned NULL, expected \"%s\"", in, out);
        exit(2);
52
    }
53
54
55
56
57
58
59
60
61

    if (out == NULL)
    {
        fprintf(stderr, "\"%s\" returned \"%s\", expected NULL", in, res);
        free(res);
        exit(2);
    }

    if (strcmp(res, out))
62
    {
63
64
65
66
        fprintf(stderr, "\"%s\" returned \"%s\", expected \"%s\"\n", in, res,
                out);
        free(res);
        exit(2);
67
    }
68

69
    free(res);
70
}
71

72
73
static inline void test_decode (const char *in, const char *out)
{
74
    test (vlc_uri_decode_duplicate, in, out);
75
76
77
78
79
80
81
}

static inline void test_b64 (const char *in, const char *out)
{
    test (vlc_b64_encode, in, out);
}

82
83
static char *make_URI_def (const char *in)
{
84
    return vlc_path2uri (in, NULL);
85
86
}

87
88
static inline void test_path (const char *in, const char *out)
{
89
    test (make_URI_def, in, out);
90
91
}

Pierre's avatar
Pierre committed
92
93
static inline void test_current_directory_path (const char *in, const char *cwd, const char *out)
{
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
94
95
    char *expected_result;
    int val = asprintf (&expected_result, "file://%s/%s", cwd, out);
Pierre's avatar
Pierre committed
96
    assert (val != -1);
97

98
    test (make_URI_def, in, expected_result);
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
99
    free(expected_result);
Pierre's avatar
Pierre committed
100
101
}

Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
102
103
104
105
static void test_url_parse(const char* in, const char* protocol, const char* user,
                           const char* pass, const char* host, unsigned i_port,
                           const char* path, const char* option )
{
106
107
108
109
110
111
#define CHECK( a, b ) \
    if (a == NULL) \
        assert(b == NULL); \
    else \
        assert(b != NULL && !strcmp((a), (b)))

Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
112
    vlc_url_t url;
113
114
    int ret = vlc_UrlParse(&url, in);

115
116
117
118
119
120
121
122
123
    /* XXX: only checking that the port-part is parsed correctly, and
     *      equal to 0, is currently not supported due to the below. */
    if( !protocol && !user && !pass && !host && !i_port && !path && !option )
    {
        vlc_UrlClean( &url );
        assert( ret == -1 );
        return;
    }

Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
124
125
126
    CHECK( url.psz_protocol, protocol );
    CHECK( url.psz_username, user );
    CHECK( url.psz_password, pass );
127
128
129
130
131
132
133
134
135

    if (ret != 0 && errno == ENOSYS)
    {
        assert(url.psz_host == NULL);
        exitcode = 77;
    }
    else
        CHECK(url.psz_host, host);

Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
136
137
138
139
140
141
142
143
144
    CHECK( url.psz_path, path );
    assert( url.i_port == i_port );
    CHECK( url.psz_option, option );

    vlc_UrlClean( &url );

#undef CHECK
}

145
static char *vlc_uri_resolve_rfc3986_test(const char *in)
146
{
147
    return vlc_uri_resolve("http://a/b/c/d;p?q", in);
148
149
150
151
}

static void test_rfc3986(const char *reference, const char *expected)
{
152
    test(vlc_uri_resolve_rfc3986_test, reference, expected);
153
154
}

155
156
static void test_fixup_noop(const char *expected)
{
157
    test(vlc_uri_fixup, expected, expected);
158
159
}

160
161
int main (void)
{
162
163
    int val;

164
165
166
167
168
169
170
    (void)setvbuf (stdout, NULL, _IONBF, 0);
    test_decode ("this_should_not_be_modified_1234",
                 "this_should_not_be_modified_1234");

    test_decode ("This%20should%20be%20modified%201234!",
                 "This should be modified 1234!");

Rémi Denis-Courmont's avatar
Lalala    
Rémi Denis-Courmont committed
171
172
    test_decode ("%7E", "~");

173
    /* tests with invalid input */
174
175
    test_decode ("%", NULL);
    test_decode ("%2", NULL);
176
177
    test_decode ("%0000", "");

178
    /* Non-ASCII tests */
179
    test_decode ("T%C3%a9l%c3%A9vision %e2%82%Ac", "Télévision €");
180
    test_decode ("T%E9l%E9vision", "T\xe9l\xe9vision");
181

182
183
    /* Base 64 tests */
    test_b64 ("", "");
184
185
186
187
188
189
    test_b64 ("f", "Zg==");
    test_b64 ("fo", "Zm8=");
    test_b64 ("foo", "Zm9v");
    test_b64 ("foob", "Zm9vYg==");
    test_b64 ("fooba", "Zm9vYmE=");
    test_b64 ("foobar", "Zm9vYmFy");
190

191
    /* Path test */
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
192
#ifndef _WIN32
193
194
    test_path ("/", "file:///");
    test_path ("/home/john/", "file:///home/john/");
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
195
196
    test_path ("/home/john//too///many//slashes",
               "file:///home/john//too///many//slashes");
197
    test_path ("/home/john/music.ogg", "file:///home/john/music.ogg");
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
198
199
200
201
202
203
204
205
#else
    test_path ("C:\\", "file:///C:/");
    test_path ("C:\\Users\\john\\", "file:///C:/Users/john/");
    test_path ("C:\\Users\\john\\music.ogg",
               "file:///C:/Users/john/music.ogg");
    test_path ("\\\\server\\share\\dir\\file.ext",
               "file://server/share/dir/file.ext");
#endif
206
207
208
209
210

    /*int fd = open (".", O_RDONLY);
    assert (fd != -1);*/
    val = chdir ("/tmp");
    assert (val != -1);
Pierre's avatar
Pierre committed
211
212
213
214
215
216

    char buf[256];
    char * tmpdir;
    tmpdir = getcwd(buf, sizeof(buf)/sizeof(*buf));
    assert (tmpdir);

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
217
#ifndef _WIN32 /* FIXME: deal with anti-slashes */
Pierre's avatar
Pierre committed
218
219
220
    test_current_directory_path ("movie.ogg", tmpdir, "movie.ogg");
    test_current_directory_path (".", tmpdir, ".");
    test_current_directory_path ("", tmpdir, "");
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
221
#endif
Pierre's avatar
Pierre committed
222

223
224
225
    /*val = fchdir (fd);
    assert (val != -1);*/

226
    /* URI to path tests */
227
#define test( a, b ) test (vlc_uri2path, a, b)
228
229
230
    test ("mailto:john@example.com", NULL);
    test ("http://www.example.com/file.html#ref", NULL);
    test ("file://", NULL);
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
231
#ifndef _WIN32
232
233
234
    test ("file:///", "/");
    test ("file://localhost/home/john/music%2Eogg", "/home/john/music.ogg");
    test ("file://localhost/home/john/text#ref", "/home/john/text");
235
236
237
238
    test ("file://localhost/home/john/text?name=value", "/home/john/text");
    test ("file://localhost/home/john/text?name=value#ref", "/home/john/text");
    test ("file://?name=value", NULL);
    test ("file:///?name=value", "/");
239
240
241
242
    test ("fd://0foobar", NULL);
    test ("fd://0#ref", "/dev/stdin");
    test ("fd://1", "/dev/stdout");
    test ("fd://12345", "/dev/fd/12345");
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
#else
    test ("file:///C:", "C:");
    test ("file:///C:/Users/john/music%2Eogg", "C:\\Users\\john\\music.ogg");
    test ("file://server/share/dir/file%2Eext",
          "\\\\server\\share\\dir\\file.ext");
    test ("file:///C:/Users/john/text#ref", "C:\\Users\\john\\text");
    test ("file:///C:/Users/john/text?name=value", "C:\\Users\\john\\text");
    test ("file:///C:/Users/john/text?name=value#ref",
          "C:\\Users\\john\\text");
    test ("file://?name=value", NULL);
    test ("file:///C:?name=value", "C:");
    test ("fd://0foobar", NULL);
    test ("fd://0#ref", "CON");
    test ("fd://1", "CON");
    test ("fd://12345", NULL);
#endif
259
260
#undef test

261
262
263
264
265
266
    test_url_parse("http://example.com", "http", NULL, NULL, "example.com", 0,
                   NULL, NULL);
    test_url_parse("http://example.com/", "http", NULL, NULL, "example.com", 0,
                   "/", NULL);
    test_url_parse("http://[2001:db8::1]", "http", NULL, NULL, "2001:db8::1",
                   0, NULL, NULL);
267
268
    test_url_parse("http://example.com:", "http", NULL, NULL, "example.com", 0,
                    NULL, NULL);
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
269
270
271
    test_url_parse("protocol://john:doe@1.2.3.4:567", "protocol", "john", "doe", "1.2.3.4", 567, NULL, NULL);
    test_url_parse("http://a.b/?opt=val", "http", NULL, NULL, "a.b", 0, "/", "opt=val");
    test_url_parse("p://u:p@host:123/a/b/c?o=v", "p", "u", "p", "host", 123, "/a/b/c", "o=v");
272
273
274
275
    test_url_parse("p://?o=v", "p", NULL, NULL, "", 0, NULL, "o=v");
    test_url_parse("p://h?o=v", "p", NULL, NULL, "h", 0, NULL, "o=v");
    test_url_parse("p://h:123?o=v", "p", NULL, NULL, "h", 123, NULL, "o=v");
    test_url_parse("p://u:p@h:123?o=v", "p", "u", "p", "h", 123, NULL, "o=v");
276
277
    test_url_parse("p://caf\xc3\xa9.example.com", "p", NULL, NULL,
                   "xn--caf-dma.example.com", 0, NULL, NULL);
278
279
280
281
    test_url_parse("p://caf%C3%A9.example.com", "p", NULL, NULL,
                   "xn--caf-dma.example.com", 0, NULL, NULL);
    test_url_parse("p://www.example.com/caf\xc3\xa9/", "p", NULL, NULL,
                   "www.example.com", 0, "/caf%C3%A9/", NULL);
282
283
    test_url_parse("p://h/white%20spaced", "p", NULL, NULL, "h", 0,
                   "/white%20spaced", NULL);
284
285
286
287
288
    /* Relative URIs */
    test_url_parse("//example.com", NULL, NULL, NULL, "example.com", 0,
                   NULL, NULL);
    test_url_parse("/file", NULL, NULL, NULL, NULL, 0, "/file", NULL);
    test_url_parse("?opt=val", NULL, NULL, NULL, NULL, 0, "", "opt=val");
289
290
    test_url_parse("?o1=v1&o2=v2", NULL, NULL, NULL, NULL, 0, "",
                   "o1=v1&o2=v2");
291
292
293
294
295
296
297
    test_url_parse("/f?o=v", NULL, NULL, NULL, NULL, 0, "/f", "o=v");
    test_url_parse("//example.com/file", NULL, NULL, NULL, "example.com", 0,
                   "/file", NULL);
    test_url_parse("//example.com?opt=val", NULL, NULL, NULL, "example.com", 0,
                   NULL, "opt=val");
    test_url_parse("//example.com/f?o=v", NULL, NULL, NULL, "example.com", 0,
                   "/f", "o=v");
298
    /* Invalid URIs */
299
300
301
    test_url_parse("p://G a r b a g e", NULL, NULL, NULL, NULL, 0, NULL, NULL);
    test_url_parse("p://h/G a r b a g e", NULL, NULL, NULL, NULL, 0, NULL, NULL);
    test_url_parse("http://example.com:123xyz", NULL, NULL, NULL, NULL, 0, NULL, NULL);
302
303
304
305
306
    test_url_parse("http://example.com: 123", NULL, NULL, NULL, NULL, 0, NULL, NULL );
    test_url_parse("http://example.com:+123", NULL, NULL, NULL, NULL, 0, NULL, NULL );
    test_url_parse("http://example.com:-123", NULL, NULL, NULL, NULL, 0, NULL, NULL );
    test_url_parse("http://example.com:-4294967298", NULL, NULL, NULL, NULL, 0, NULL, NULL );
    test_url_parse("http://example.com:-18446744073709551615", NULL, NULL, NULL, NULL, 0, NULL, NULL );
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360

    /* Reference test cases for reference URI resolution */
    static const char *rfc3986_cases[] =
    {
        "g:h",           "g:h",
        "g",             "http://a/b/c/g",
        "./g",           "http://a/b/c/g",
        "g/",            "http://a/b/c/g/",
        "/g",            "http://a/g",
        "//g",           "http://g",
        "?y",            "http://a/b/c/d;p?y",
        "g?y",           "http://a/b/c/g?y",
        //"#s",            "http://a/b/c/d;p?q#s",
        //"g#s",           "http://a/b/c/g#s",
        //"g?y#s",         "http://a/b/c/g?y#s",
        ";x",            "http://a/b/c/;x",
        "g;x",           "http://a/b/c/g;x",
        //"g;x?y#s",       "http://a/b/c/g;x?y#s",
        "",              "http://a/b/c/d;p?q",
        ".",             "http://a/b/c/",
        "./",            "http://a/b/c/",
        "..",            "http://a/b/",
        "../",           "http://a/b/",
        "../g",          "http://a/b/g",
        "../..",         "http://a/",
        "../../",        "http://a/",
        "../../g",       "http://a/g",

        "../../../g",    "http://a/g",
        "../../../../g", "http://a/g",

        "/./g",          "http://a/g",
        "/../g",         "http://a/g",
        "g.",            "http://a/b/c/g.",
        ".g",            "http://a/b/c/.g",
        "g..",           "http://a/b/c/g..",
        "..g",           "http://a/b/c/..g",

        "./../g",        "http://a/b/g",
        "./g/.",         "http://a/b/c/g/",
        "g/./h",         "http://a/b/c/g/h",
        "g/../h",        "http://a/b/c/h",
        "g;x=1/./y",     "http://a/b/c/g;x=1/y",
        "g;x=1/../y",    "http://a/b/c/y",

        "g?y/./x",       "http://a/b/c/g?y/./x",
        "g?y/../x",      "http://a/b/c/g?y/../x",
        //"g#s/./x",       "http://a/b/c/g#s/./x",
        //"g#s/../x",      "http://a/b/c/g#s/../x",
    };

    for (size_t i = 0; i < ARRAY_SIZE(rfc3986_cases); i += 2)
        test_rfc3986(rfc3986_cases[i], rfc3986_cases[i + 1]);

361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
    /* Check that fixup does not mangle valid URIs */
    static const char *valid_uris[] =
    {
        "#href", "?opt=val",
        ".", "..", "/", "../../dir/subdir/subsubdir/file.ext",
        "//example.com?q=info",
        "//192.0.2.1/index.html",
        "//[2001:db8::1]/index.html",
        "https://www.example.com:8443/?opt1=val1&opt2=val2",
        "https://192.0.2.1:8443/#foobar",
        "https://[2001:db8::1]:8443/file?opt=val#foobar",
        "https://[v9.abcd:efgh]:8443/welcome?to=the#future",
        "mailto:john@example.com",
        "mailto:mailman@example.com?subject=help",
        "mailto:mailman@example.com?body=subscribe%20news-flash",
        "mailto:literal@[192.0.2.1],literal@[IPv6:2001:db8::1]",
    };

    for (size_t i = 0; i < ARRAY_SIZE(valid_uris); i++)
        test_fixup_noop(valid_uris[i]);

382
    return exitcode;
383
}