~holger-seelig/cobweb.js/trunk

« back to all changes in this revision

Viewing changes to src/standard/Networking/URI.js

  • Committer: Holger Seelig
  • Date: 2017-08-22 04:53:24 UTC
  • Revision ID: holger.seelig@yahoo.de-20170822045324-4of4xxgt79669gbt
Switched to npm.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* -*- Mode: JavaScript; coding: utf-8; tab-width: 3; indent-tabs-mode: tab; c-basic-offset: 3 -*-
 
2
 *******************************************************************************
 
3
 *
 
4
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 
5
 *
 
6
 * Copyright create3000, Scheffelstraße 31a, Leipzig, Germany 2011.
 
7
 *
 
8
 * All rights reserved. Holger Seelig <holger.seelig@yahoo.de>.
 
9
 *
 
10
 * The copyright notice above does not evidence any actual of intended
 
11
 * publication of such source code, and is an unpublished work by create3000.
 
12
 * This material contains CONFIDENTIAL INFORMATION that is the property of
 
13
 * create3000.
 
14
 *
 
15
 * No permission is granted to copy, distribute, or create derivative works from
 
16
 * the contents of this software, in whole or in part, without the prior written
 
17
 * permission of create3000.
 
18
 *
 
19
 * NON-MILITARY USE ONLY
 
20
 *
 
21
 * All create3000 software are effectively free software with a non-military use
 
22
 * restriction. It is free. Well commented source is provided. You may reuse the
 
23
 * source in any way you please with the exception anything that uses it must be
 
24
 * marked to indicate is contains 'non-military use only' components.
 
25
 *
 
26
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 
27
 *
 
28
 * Copyright 2015, 2016 Holger Seelig <holger.seelig@yahoo.de>.
 
29
 *
 
30
 * This file is part of the Cobweb Project.
 
31
 *
 
32
 * Cobweb is free software: you can redistribute it and/or modify it under the
 
33
 * terms of the GNU General Public License version 3 only, as published by the
 
34
 * Free Software Foundation.
 
35
 *
 
36
 * Cobweb is distributed in the hope that it will be useful, but WITHOUT ANY
 
37
 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
 
38
 * A PARTICULAR PURPOSE. See the GNU General Public License version 3 for more
 
39
 * details (a copy is included in the LICENSE file that accompanied this code).
 
40
 *
 
41
 * You should have received a copy of the GNU General Public License version 3
 
42
 * along with Cobweb.  If not, see <http://www.gnu.org/licenses/gpl.html> for a
 
43
 * copy of the GPLv3 License.
 
44
 *
 
45
 * For Silvio, Joy and Adi.
 
46
 *
 
47
 ******************************************************************************/
 
48
 
 
49
 
 
50
define ([
 
51
        "jquery",
 
52
],
 
53
function ($)
 
54
{
 
55
"use strict";
 
56
 
 
57
        /*
 
58
         *  Path
 
59
         */
 
60
 
 
61
        function Path (path, separator)
 
62
        {
 
63
                switch (arguments .length)
 
64
                {
 
65
                        case 2:
 
66
                        {
 
67
                                this .value                    = path .split (separator);
 
68
                                this .value .separator         = separator;
 
69
                                this .value .leadingSeparator  = false;
 
70
                                this .value .trailingSeparator = false;
 
71
                                
 
72
                                if (this .value .length)
 
73
                                {
 
74
                                        if (this .value [0] === "")
 
75
                                        {
 
76
                                                this .value .shift ();
 
77
                                                this .value .leadingSeparator = true;
 
78
                                        }
 
79
                                }
 
80
                                
 
81
                                if (this .value .length)
 
82
                                {
 
83
                                        if (this .value [this .value .length - 1] === "")
 
84
                                        {
 
85
                                                this .value .pop ();
 
86
                                                this .value .trailingSeparator = true;
 
87
                                        }               
 
88
                                }
 
89
                                
 
90
                                break;
 
91
                        }
 
92
                        case 4:
 
93
                        {
 
94
                                this .value                    = arguments [0];
 
95
                                this .value .separator         = arguments [1];
 
96
                                this .value .leadingSeparator  = arguments [2];
 
97
                                this .value .trailingSeparator = arguments [3];                                 
 
98
                                break;
 
99
                        }
 
100
                }
 
101
        }
 
102
 
 
103
        Path .prototype =
 
104
        {
 
105
                copy: function ()
 
106
                {
 
107
                        return new Path (this .value .slice (0, this .value .length), 
 
108
                                    this .value .separator,
 
109
                                    this .value .leadingSeparator,
 
110
                                    this .value .trailingSeparator);
 
111
                },
 
112
                get origin ()
 
113
                {
 
114
                        return new Path ([ ], 
 
115
                                    this .value .separator,
 
116
                                    true,
 
117
                                    false);
 
118
                },
 
119
                get base ()
 
120
                {
 
121
                        if (this .value .trailingSeparator)
 
122
                                return this .copy ();
 
123
 
 
124
                        return this .parent;    
 
125
                },
 
126
                get parent ()
 
127
                {
 
128
                        switch (this .value .length)
 
129
                        {
 
130
                                case 0:
 
131
                                case 1:
 
132
                                {
 
133
                                        if (this .value .leadingSeparator)
 
134
                                                return this .origin;
 
135
 
 
136
                                        return new Path ([ ".." ], this .value .separator, false, false);
 
137
                                }
 
138
 
 
139
                                default:
 
140
                                        return new Path (this .value .slice (0, this .value .length - 1), 
 
141
                                                    this .value .separator,
 
142
                                                    this .value .leadingSeparator,
 
143
                                                    true);
 
144
                        }
 
145
 
 
146
                },
 
147
                isRelative: function ()
 
148
                {
 
149
                        return ! this .value .length || this .value [0] == "..";
 
150
                },
 
151
                getRelativePath: function (descendant)
 
152
                {
 
153
                        if (this .isRelative ())
 
154
                                return descendant;
 
155
                
 
156
                        var path = new Path ([ ], "/", false, false);
 
157
 
 
158
                        var basePath       = this .removeDotSegments () .base;
 
159
                        var descendantPath = descendant .removeDotSegments ();
 
160
 
 
161
                        var i, j;
 
162
 
 
163
                        for (i = 0; i < basePath .value .length && i < descendantPath .value .length; ++ i)
 
164
                        {
 
165
                                if (basePath .value [i] !== descendantPath .value [i])
 
166
                                        break;
 
167
                        }
 
168
 
 
169
                        for (j = i; j < basePath .value .length; ++ j)
 
170
                                path .value .push ("..");
 
171
 
 
172
                        for (j = i; j < descendantPath .value .length; ++ j)
 
173
                                path .value .push (descendantPath .value [j]);
 
174
 
 
175
                        return path;
 
176
                },
 
177
                removeDotSegments: function ()
 
178
                {
 
179
                        var path = new Path ([ ], this .value .separator, this .value .leadingSeparator, this .value .trailingSeparator);
 
180
 
 
181
                        if (this .value .length)
 
182
                        {
 
183
                                for (var i = 0; i < this .value .length; ++ i)
 
184
                                {
 
185
                                        var segment = this .value [i];
 
186
                                
 
187
                                        if (segment === ".")
 
188
                                                path .value .trailingSeparator = true;
 
189
 
 
190
                                        else if (segment === "..")
 
191
                                        {
 
192
                                                path .value .trailingSeparator = true;
 
193
 
 
194
                                                if (path .value .length)
 
195
                                                        path .value .pop ();
 
196
                                        }
 
197
 
 
198
                                        else
 
199
                                        {
 
200
                                                path .value .trailingSeparator = false;
 
201
                                                path .value .push (segment);
 
202
                                        }
 
203
                                }
 
204
 
 
205
                                path .value .trailingSeparator |= this .value .trailingSeparator;
 
206
                        }
 
207
 
 
208
                        return path;
 
209
                },
 
210
                toString: function ()
 
211
                {
 
212
                        var string = "";
 
213
                
 
214
                        if (this .value .leadingSeparator)
 
215
                                string += this .value .separator;
 
216
 
 
217
                        string += this .value .join (this .value .separator);
 
218
 
 
219
                        if (this .value .trailingSeparator)
 
220
                                string += this .value .separator;
 
221
 
 
222
                        return string;
 
223
                },
 
224
        };
 
225
 
 
226
        /*
 
227
         *  URI
 
228
         *  https://tools.ietf.org/html/rfc3986
 
229
         */
 
230
 
 
231
        var wellKnownPorts =
 
232
        {
 
233
                ftp:   21,
 
234
                http:  80,
 
235
                https: 443,
 
236
                ftps:  990,
 
237
        };
 
238
 
 
239
        var address   = /^(?:([^:\/?#]*?):)?(?:(\/\/)([^\/?#]*))?([^?#]*)(?:\?([^#]*))?(?:#(.*))?$/;
 
240
        var authority = /^(.*?)(?:\:([^:]*))?$/;
 
241
 
 
242
        function parse (uri, string)
 
243
        {
 
244
                var result = address .exec (string);
 
245
        
 
246
                if (result)
 
247
                {
 
248
                        uri .scheme    = result [1] || "";
 
249
                        uri .slashs    = result [2] || "";
 
250
                        uri .authority = result [3] || "";
 
251
                        uri .path      = result [4] || "";
 
252
                        uri .query     = result [5] || "";
 
253
                        uri .fragment  = result [6] || "";
 
254
                        
 
255
                        var result = authority .exec (uri .authority);
 
256
                        
 
257
                        if (result)
 
258
                        {
 
259
                                uri .host      = result [1] || "";
 
260
                                uri .port      = result [2] ? parseInt (result [2]) : 0;
 
261
                                uri .authority = uri .host;
 
262
 
 
263
                                if (uri .port)
 
264
                                        uri .authority += ":" + uri .port;
 
265
                        }
 
266
                        
 
267
                        uri .absolute = Boolean (uri .slashs .length) || uri .path [0] === "/";
 
268
                        uri .local    = /^(?:file|data)$/ .test (uri .scheme) || (! uri .scheme && ! uri .authority)
 
269
                }
 
270
 
 
271
                uri .string = string;
 
272
        }
 
273
 
 
274
        function removeDotSegments (path)
 
275
        {
 
276
                return new Path (path, "/") .removeDotSegments () .toString ();
 
277
        }
 
278
 
 
279
        function URI (uri)
 
280
        {
 
281
                this .value =
 
282
                {
 
283
                        local:     true,
 
284
                        absolute:  true,
 
285
                        scheme:    "",
 
286
                        slashs:    "",
 
287
                        authority: "",
 
288
                        host:      "",
 
289
                        port:      0,
 
290
                        path:      "",
 
291
                        query:     "",
 
292
                        fragment:  "",
 
293
                        string:    "",
 
294
                };
 
295
 
 
296
                switch (arguments .length)
 
297
                {
 
298
                        case 0:
 
299
                                break;
 
300
                        case 1:
 
301
                        {
 
302
                                parse (this .value, uri);
 
303
                                break;
 
304
                        }
 
305
                        case 10:
 
306
                        {
 
307
                                this .value .local     = arguments [0];
 
308
                                this .value .absolute  = arguments [1];
 
309
                                this .value .scheme    = arguments [2];
 
310
                                this .value .slashs    = arguments [3];
 
311
                                this .value .authority = arguments [4];
 
312
                                this .value .host      = arguments [5];
 
313
                                this .value .port      = arguments [6];
 
314
                                this .value .path      = arguments [7];
 
315
                                this .value .query     = arguments [8];
 
316
                                this .value .fragment  = arguments [9];
 
317
                                this .value .string    = this .toString ();
 
318
                                break;
 
319
                        }
 
320
                }
 
321
        };
 
322
 
 
323
        URI .prototype =
 
324
        {
 
325
                copy: function ()
 
326
                {
 
327
                        return new URI (this .value .local,
 
328
                                        this .value .absolute,
 
329
                                        this .value .scheme,
 
330
                                        this .value .slashs,
 
331
                                        this .value .authority,
 
332
                                        this .value .host,
 
333
                                        this .value .port,
 
334
                                        this .value .path,
 
335
                                        this .value .query,
 
336
                                        this .value .fragment);
 
337
                },
 
338
                get length ()
 
339
                {
 
340
                        return this .value .string .length;
 
341
                },
 
342
                isRelative: function ()
 
343
                {
 
344
                        return ! this .value .absolute ();
 
345
                },
 
346
                isAbsolute: function ()
 
347
                {
 
348
                        return ! this .value .absolute;
 
349
                },
 
350
                isLocal: function ()
 
351
                {
 
352
                        return this .value .local;
 
353
                },
 
354
                isNetwork: function ()
 
355
                {
 
356
                        return ! this .value .local;
 
357
                },
 
358
                isDirectory: function ()
 
359
                {
 
360
                        if (this .value .path .length == 0)
 
361
                                return this .isNetwork ();
 
362
 
 
363
                        return this .value .path [this .value .path .length - 1] === "/";
 
364
                },
 
365
                isFile: function ()
 
366
                {
 
367
                        return ! this .isDirectory ();
 
368
                },
 
369
                get hierarchy ()
 
370
                {
 
371
                        var hierarchy = "";
 
372
 
 
373
                        hierarchy += this .value .slashs;
 
374
                        hierarchy += this .value .authority;
 
375
                        hierarchy += this .value .path;
 
376
 
 
377
                        return hierarchy;
 
378
                },
 
379
                get authority ()
 
380
                {
 
381
                        return this .value .authority;
 
382
                },
 
383
                get scheme ()
 
384
                {
 
385
                        return this .value .scheme;
 
386
                },
 
387
                get host ()
 
388
                {
 
389
                        return this .value .host;
 
390
                },
 
391
                get port ()
 
392
                {
 
393
                        return this .value .port;
 
394
                },
 
395
                get wellKnownPort ()
 
396
                {
 
397
                        var wellKnownPort = wellKnownPorts [this .value .scheme];
 
398
 
 
399
                        if (wellKnownPort !== undefined)
 
400
                                return wellKnownPort;
 
401
 
 
402
                        return 0;
 
403
                },
 
404
                get path ()
 
405
                {
 
406
                        return this .value .path;
 
407
                },
 
408
                set query (value)
 
409
                {
 
410
                        this .value .query = value;
 
411
                },
 
412
                get query ()
 
413
                {
 
414
                        return this .value .query;
 
415
                },
 
416
                set fragment (value)
 
417
                {
 
418
                        this .value .fragment = value;
 
419
                },
 
420
                get fragment ()
 
421
                {
 
422
                        return this .value .fragment;
 
423
                },
 
424
                get location ()
 
425
                {
 
426
                        return this .toString ();
 
427
                },
 
428
                get origin ()
 
429
                {
 
430
                        return new URI (this .value .local,
 
431
                                        this .value .absolute,
 
432
                                        this .value .scheme,
 
433
                                        this .value .slashs,
 
434
                                        this .value .authority,
 
435
                                        this .value .host,
 
436
                                        this .value .port,
 
437
                                        this .value .local ? "/" : "",
 
438
                                        "",
 
439
                                        "");
 
440
                },
 
441
                get base ()
 
442
                {
 
443
                        if (this .isDirectory ())
 
444
                                return new URI (this .value .local,
 
445
                                                this .value .absolute,
 
446
                                                this .value .scheme,
 
447
                                                this .value .slashs,
 
448
                                                this .value .authority,
 
449
                                                this .value .host,
 
450
                                                this .value .port,
 
451
                                                this .value .path,
 
452
                                                "",
 
453
                                                "");
 
454
 
 
455
                        return this .parent;
 
456
                },
 
457
                get parent ()
 
458
                {
 
459
                        var path;
 
460
                        
 
461
                        if (this .isDirectory ())
 
462
                        {
 
463
                                if (this .value .path .length == 1)
 
464
                                        return "/";
 
465
 
 
466
                                path = this .value .path .substr (0, this .value .path .length - 1);
 
467
                        }
 
468
                        else
 
469
                                path = this .path;
 
470
 
 
471
                        var slash = path .lastIndexOf ("/");
 
472
                        
 
473
                        path = slash == -1 ? "" : path .substring (0, path .lastIndexOf ("/") + 1);
 
474
 
 
475
                        return new URI (this .value .local,
 
476
                                        this .value .absolute,
 
477
                                        this .value .scheme,
 
478
                                        this .value .slashs,
 
479
                                        this .value .authority,
 
480
                                        this .value .host,
 
481
                                        this .value .port,
 
482
                                        path,
 
483
                                        "",
 
484
                                        "");    
 
485
                },
 
486
                get filename ()
 
487
                {
 
488
                        return new URI (this .value .local,
 
489
                                        this .value .absolute,
 
490
                                        this .value .scheme,
 
491
                                        this .value .slashs,
 
492
                                        this .value .authority,
 
493
                                        this .value .host,
 
494
                                        this .value .port,
 
495
                                        this .value .path,
 
496
                                        "",
 
497
                                        "");
 
498
                },
 
499
                get basename ()
 
500
                {
 
501
                        if (this .value .path)
 
502
                                return this .value .path .substr (this .value .path. lastIndexOf ("/") + 1);
 
503
 
 
504
                        return "";
 
505
                },
 
506
                get prefix ()
 
507
                {
 
508
                        if (this .value .path .length && this .isFile ())
 
509
                        {
 
510
                                var basename = this .basename;
 
511
                                var suffix   = this .suffix;
 
512
 
 
513
                                return basename .substr (0, basename .length - suffix .length);
 
514
                        }
 
515
 
 
516
                        return this .basename;
 
517
                },
 
518
                get suffix ()
 
519
                {
 
520
                        var dot   = this .value .path .lastIndexOf (".");
 
521
                        var slash = this .value .path .lastIndexOf ("/");
 
522
 
 
523
                        if (slash < dot)
 
524
                                return this .value .path .substr (dot);
 
525
 
 
526
                        return "";
 
527
                },
 
528
                transform: function (reference)
 
529
                {
 
530
                        var T_local    = false;
 
531
                        var T_absolute = false;
 
532
 
 
533
                        var T_scheme    = "";
 
534
                        var T_slashs    = "";
 
535
                        var T_authority = "";
 
536
                        var T_host      = "";
 
537
                        var T_port      = 0;
 
538
                        var T_path      = "";
 
539
                        var T_query     = "";
 
540
                        var T_fragment  = "";
 
541
 
 
542
                        if (reference .scheme .length)
 
543
                        {
 
544
                                T_local     = reference .isLocal ();
 
545
                                T_absolute  = reference .isAbsolute ();
 
546
                                T_scheme    = reference .scheme;
 
547
                                T_slashs    = reference .value .slashs;
 
548
                                T_authority = reference .authority;
 
549
                                T_host      = reference .host;
 
550
                                T_port      = reference .port;
 
551
                                T_path      = reference .path;
 
552
                                T_query     = reference .query;
 
553
                        }
 
554
                        else
 
555
                        {
 
556
                                if (reference .authority .length)
 
557
                                {
 
558
                                        T_local     = reference .isLocal ();
 
559
                                        T_absolute  = reference .isAbsolute ();
 
560
                                        T_authority = reference .authority;
 
561
                                        T_host      = reference .host;
 
562
                                        T_port      = reference .port;
 
563
                                        T_path      = reference .path;
 
564
                                        T_query     = reference .query;
 
565
                                }
 
566
                                else
 
567
                                {
 
568
                                        if (reference .path .length === 0)
 
569
                                        {
 
570
                                                var T_path = this .value .path;
 
571
 
 
572
                                                if (reference .query .length)
 
573
                                                        T_query = reference .query;
 
574
                                                else
 
575
                                                        T_query = this .value .query;
 
576
                                        }
 
577
                                        else
 
578
                                        {
 
579
                                                if (reference .path [0] === "/")
 
580
                                                {
 
581
                                                        T_path = reference .path;
 
582
                                                }
 
583
                                                else
 
584
                                                {
 
585
                                                        // merge (Base .path (), reference .path ());
 
586
 
 
587
                                                        var base = this .base;
 
588
 
 
589
                                                        if (base .path .length === 0)
 
590
                                                                T_path = "/";
 
591
                                                        else
 
592
                                                                T_path += base .path;
 
593
 
 
594
                                                        T_path += reference .path;
 
595
                                                }
 
596
 
 
597
                                                T_query = reference .query;
 
598
                                        }
 
599
 
 
600
                                        T_local     = this .isLocal ();
 
601
                                        T_absolute  = this .isAbsolute () || reference .isAbsolute ();
 
602
                                        T_authority = this .value .authority;
 
603
                                        T_host      = this .value .host;
 
604
                                        T_port      = this .value .port;
 
605
                                }
 
606
 
 
607
                                T_scheme = this .value .scheme;
 
608
                                T_slashs = this .value .slashs;
 
609
                        }
 
610
 
 
611
                        T_fragment = reference .fragment;
 
612
 
 
613
                        return new URI (T_local,
 
614
                                        T_absolute,
 
615
                                        T_scheme,
 
616
                                        T_slashs,
 
617
                                        T_authority,
 
618
                                        T_host,
 
619
                                        T_port,
 
620
                                        removeDotSegments (T_path),
 
621
                                        T_query,
 
622
                                        T_fragment);
 
623
                },
 
624
                removeDotSegments: function ()
 
625
                {
 
626
                        return new URI (this .value .local,
 
627
                                        this .value .absolute,
 
628
                                        this .value .scheme,
 
629
                                        this .value .slashs,
 
630
                                        this .value .authority,
 
631
                                        this .value .host,
 
632
                                        this .value .port,
 
633
                                        removeDotSegments (this .value .path),
 
634
                                        this .value .query,
 
635
                                        this .value .fragment);
 
636
                },
 
637
                getRelativePath: function (descendant)
 
638
                {
 
639
                        if (this .value .scheme !== descendant .scheme)
 
640
                                return descendant;
 
641
 
 
642
                        if (this .value .authority !== descendant .authority)
 
643
                                return descendant;
 
644
 
 
645
                        var path           = new Path (this .value .path, "/");
 
646
                        var descendantPath = new Path (descendant .path,  "/");
 
647
 
 
648
                        return new URI (true,
 
649
                                        false,
 
650
                                        "",
 
651
                                        "",
 
652
                                        "",
 
653
                                        "",
 
654
                                        0,
 
655
                                        path .getRelativePath (descendantPath) .toString (),
 
656
                                        descendant .query,
 
657
                                        descendant .fragment);
 
658
                },
 
659
                escape: function ()
 
660
                {
 
661
                        return new URI (escape (this .location));
 
662
                },
 
663
                unescape: function ()
 
664
                {
 
665
                        return new URI (unescape (this .location));     
 
666
                },
 
667
                toString: function ()
 
668
                {
 
669
                        var string = this .value .scheme;
 
670
 
 
671
                        if (this .value .scheme .length)
 
672
                                string += ":";
 
673
 
 
674
                        string += this .hierarchy;
 
675
 
 
676
                        if (this .value .query .length)
 
677
                                string += "?" + this .value .query;
 
678
 
 
679
                        if (this .value .fragment .length)
 
680
                                string += "#" + this .value .fragment;
 
681
 
 
682
                        return string;
 
683
                },
 
684
        };
 
685
 
 
686
        return URI;
 
687
});