Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F2916329
url.c
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Size
21 KB
Referenced Files
None
Subscribers
None
url.c
View Options
#include
<compat.h>
// IWYU pragma: keep
#include
<stdlib.h>
#include
<stdio.h>
#include
<string.h>
#include
<ctype.h>
#include
<uriparser/Uri.h>
#include
"ant.h"
#include
"errors.h"
#include
"internal.h"
#include
"runtime.h"
#include
"utils.h"
#include
"descriptors.h"
#include
"modules/url.h"
#include
"modules/symbol.h"
typedef
struct
{
char
*
protocol
;
char
*
username
;
char
*
password
;
char
*
hostname
;
char
*
port
;
char
*
pathname
;
char
*
search
;
char
*
hash
;
}
parsed_url_t
;
static
void
free_parsed_url
(
parsed_url_t
*
p
)
{
if
(
p
->
protocol
)
free
(
p
->
protocol
);
if
(
p
->
username
)
free
(
p
->
username
);
if
(
p
->
password
)
free
(
p
->
password
);
if
(
p
->
hostname
)
free
(
p
->
hostname
);
if
(
p
->
port
)
free
(
p
->
port
);
if
(
p
->
pathname
)
free
(
p
->
pathname
);
if
(
p
->
search
)
free
(
p
->
search
);
if
(
p
->
hash
)
free
(
p
->
hash
);
}
static
char
*
url_encode_component
(
const
char
*
str
)
{
if
(
!
str
)
return
strdup
(
""
);
size_t
len
=
strlen
(
str
);
char
*
out
=
malloc
(
len
*
3
+
1
);
if
(
!
out
)
return
NULL
;
size_t
j
=
0
;
for
(
size_t
i
=
0
;
i
<
len
;
i
++
)
{
unsigned
char
c
=
(
unsigned
char
)
str
[
i
];
if
(
isalnum
(
c
)
||
c
==
'-'
||
c
==
'_'
||
c
==
'.'
||
c
==
'~'
)
{
out
[
j
++
]
=
c
;
}
else
{
snprintf
(
out
+
j
,
4
,
"%%%02X"
,
c
);
j
+=
3
;
}
}
out
[
j
]
=
'\0'
;
return
out
;
}
static
char
*
url_decode_component
(
const
char
*
str
)
{
if
(
!
str
)
return
strdup
(
""
);
size_t
len
=
strlen
(
str
);
char
*
out
=
malloc
(
len
+
1
);
if
(
!
out
)
return
NULL
;
size_t
j
=
0
;
for
(
size_t
i
=
0
;
i
<
len
;
i
++
)
{
if
(
str
[
i
]
==
'%'
&&
i
+
2
<
len
&&
isxdigit
(
str
[
i
+
1
])
&&
isxdigit
(
str
[
i
+
2
]))
{
int
hi
=
isdigit
(
str
[
i
+
1
])
?
str
[
i
+
1
]
-
'0'
:
tolower
(
str
[
i
+
1
])
-
'a'
+
10
;
int
lo
=
isdigit
(
str
[
i
+
2
])
?
str
[
i
+
2
]
-
'0'
:
tolower
(
str
[
i
+
2
])
-
'a'
+
10
;
out
[
j
++
]
=
(
char
)((
hi
<<
4
)
|
lo
);
i
+=
2
;
}
else
if
(
str
[
i
]
==
'+'
)
out
[
j
++
]
=
' '
;
else
out
[
j
++
]
=
str
[
i
];
}
out
[
j
]
=
'\0'
;
return
out
;
}
static
char
*
uri_range_dup
(
const
UriTextRangeA
*
range
)
{
if
(
!
range
->
first
||
!
range
->
afterLast
)
return
strdup
(
""
);
size_t
len
=
(
size_t
)(
range
->
afterLast
-
range
->
first
);
return
strndup
(
range
->
first
,
len
);
}
static
void
uri_to_parsed
(
const
UriUriA
*
uri
,
parsed_url_t
*
out
)
{
char
*
scheme
=
uri_range_dup
(
&
uri
->
scheme
);
size_t
slen
=
strlen
(
scheme
);
out
->
protocol
=
malloc
(
slen
+
2
);
memcpy
(
out
->
protocol
,
scheme
,
slen
);
out
->
protocol
[
slen
]
=
':'
;
out
->
protocol
[
slen
+
1
]
=
'\0'
;
free
(
scheme
);
char
*
userinfo
=
uri_range_dup
(
&
uri
->
userInfo
);
char
*
colon
=
strchr
(
userinfo
,
':'
);
if
(
colon
)
{
*
colon
=
'\0'
;
out
->
username
=
strdup
(
userinfo
);
out
->
password
=
strdup
(
colon
+
1
);
}
else
{
out
->
username
=
strdup
(
userinfo
);
out
->
password
=
strdup
(
""
);
}
free
(
userinfo
);
out
->
hostname
=
uri_range_dup
(
&
uri
->
hostText
);
out
->
port
=
uri_range_dup
(
&
uri
->
portText
);
size_t
path_cap
=
1
;
for
(
UriPathSegmentA
*
seg
=
uri
->
pathHead
;
seg
;
seg
=
seg
->
next
)
path_cap
+=
(
size_t
)(
seg
->
text
.
afterLast
-
seg
->
text
.
first
)
+
1
;
char
*
path
=
malloc
(
path_cap
+
1
);
size_t
pos
=
0
;
for
(
UriPathSegmentA
*
seg
=
uri
->
pathHead
;
seg
;
seg
=
seg
->
next
)
{
path
[
pos
++
]
=
'/'
;
size_t
slen_uri
=
(
size_t
)(
seg
->
text
.
afterLast
-
seg
->
text
.
first
);
memcpy
(
path
+
pos
,
seg
->
text
.
first
,
slen_uri
);
pos
+=
slen_uri
;
}
if
(
pos
==
0
)
path
[
pos
++
]
=
'/'
;
path
[
pos
]
=
'\0'
;
out
->
pathname
=
path
;
char
*
query
=
uri_range_dup
(
&
uri
->
query
);
if
(
*
query
)
{
out
->
search
=
malloc
(
strlen
(
query
)
+
2
);
out
->
search
[
0
]
=
'?'
;
strcpy
(
out
->
search
+
1
,
query
);
}
else
out
->
search
=
strdup
(
""
);
free
(
query
);
char
*
frag
=
uri_range_dup
(
&
uri
->
fragment
);
if
(
*
frag
)
{
out
->
hash
=
malloc
(
strlen
(
frag
)
+
2
);
out
->
hash
[
0
]
=
'#'
;
strcpy
(
out
->
hash
+
1
,
frag
);
}
else
out
->
hash
=
strdup
(
""
);
free
(
frag
);
}
static
const
char
*
coerce_to_string
(
ant_t
*
js
,
jsval_t
val
,
size_t
*
len
)
{
if
(
vtype
(
val
)
==
T_STR
)
return
js_getstr
(
js
,
val
,
len
);
if
(
is_object_type
(
val
))
{
jsval_t
href
=
js_get
(
js
,
val
,
"href"
);
if
(
vtype
(
href
)
==
T_STR
)
return
js_getstr
(
js
,
href
,
len
);
}
return
NULL
;
}
static
int
parse_url
(
const
char
*
url_str
,
const
char
*
base_str
,
parsed_url_t
*
out
)
{
memset
(
out
,
0
,
sizeof
(
*
out
));
UriUriA
uri
;
const
char
*
errorPos
;
if
(
base_str
&&
!
strstr
(
url_str
,
"://"
))
{
UriUriA
base_uri
,
rel_uri
,
resolved
;
if
(
uriParseSingleUriA
(
&
base_uri
,
base_str
,
&
errorPos
)
!=
URI_SUCCESS
)
return
-1
;
if
(
uriParseSingleUriA
(
&
rel_uri
,
url_str
,
&
errorPos
)
!=
URI_SUCCESS
)
{
uriFreeUriMembersA
(
&
base_uri
);
return
-1
;
}
if
(
uriAddBaseUriA
(
&
resolved
,
&
rel_uri
,
&
base_uri
)
!=
URI_SUCCESS
)
{
uriFreeUriMembersA
(
&
base_uri
);
uriFreeUriMembersA
(
&
rel_uri
);
return
-1
;
}
uriNormalizeSyntaxA
(
&
resolved
);
uri_to_parsed
(
&
resolved
,
out
);
uriFreeUriMembersA
(
&
resolved
);
uriFreeUriMembersA
(
&
rel_uri
);
uriFreeUriMembersA
(
&
base_uri
);
return
0
;
}
if
(
uriParseSingleUriA
(
&
uri
,
url_str
,
&
errorPos
)
!=
URI_SUCCESS
)
return
-1
;
uri_to_parsed
(
&
uri
,
out
);
uriFreeUriMembersA
(
&
uri
);
return
0
;
}
static
char
*
build_href
(
const
char
*
protocol
,
const
char
*
username
,
const
char
*
password
,
const
char
*
hostname
,
const
char
*
port
,
const
char
*
pathname
,
const
char
*
search
,
const
char
*
hash
)
{
size_t
len
=
strlen
(
protocol
)
+
2
+
strlen
(
hostname
)
+
strlen
(
pathname
)
+
strlen
(
search
)
+
strlen
(
hash
)
+
32
;
if
(
username
&&
*
username
)
len
+=
strlen
(
username
)
+
strlen
(
password
)
+
2
;
if
(
port
&&
*
port
)
len
+=
strlen
(
port
)
+
1
;
char
*
href
=
malloc
(
len
);
if
(
!
href
)
return
NULL
;
size_t
used
=
0
;
size_t
remaining
=
len
;
int
written
=
snprintf
(
href
+
used
,
remaining
,
"%s//"
,
protocol
);
if
(
written
<
0
)
{
href
[
0
]
=
'\0'
;
return
href
;
}
if
((
size_t
)
written
>=
remaining
)
{
href
[
len
-
1
]
=
'\0'
;
return
href
;
}
used
+=
(
size_t
)
written
;
remaining
-=
(
size_t
)
written
;
if
(
username
&&
*
username
)
{
written
=
snprintf
(
href
+
used
,
remaining
,
"%s"
,
username
);
if
(
written
<
0
)
{
href
[
0
]
=
'\0'
;
return
href
;
}
if
((
size_t
)
written
>=
remaining
)
{
href
[
len
-
1
]
=
'\0'
;
return
href
;
}
used
+=
(
size_t
)
written
;
remaining
-=
(
size_t
)
written
;
if
(
password
&&
*
password
)
{
written
=
snprintf
(
href
+
used
,
remaining
,
":%s"
,
password
);
if
(
written
<
0
)
{
href
[
0
]
=
'\0'
;
return
href
;
}
if
((
size_t
)
written
>=
remaining
)
{
href
[
len
-
1
]
=
'\0'
;
return
href
;
}
used
+=
(
size_t
)
written
;
remaining
-=
(
size_t
)
written
;
}
written
=
snprintf
(
href
+
used
,
remaining
,
"@"
);
if
(
written
<
0
)
{
href
[
0
]
=
'\0'
;
return
href
;
}
if
((
size_t
)
written
>=
remaining
)
{
href
[
len
-
1
]
=
'\0'
;
return
href
;
}
used
+=
(
size_t
)
written
;
remaining
-=
(
size_t
)
written
;
}
written
=
snprintf
(
href
+
used
,
remaining
,
"%s"
,
hostname
);
if
(
written
<
0
)
{
href
[
0
]
=
'\0'
;
return
href
;
}
if
((
size_t
)
written
>=
remaining
)
{
href
[
len
-
1
]
=
'\0'
;
return
href
;
}
used
+=
(
size_t
)
written
;
remaining
-=
(
size_t
)
written
;
if
(
port
&&
*
port
)
{
written
=
snprintf
(
href
+
used
,
remaining
,
":%s"
,
port
);
if
(
written
<
0
)
{
href
[
0
]
=
'\0'
;
return
href
;
}
if
((
size_t
)
written
>=
remaining
)
{
href
[
len
-
1
]
=
'\0'
;
return
href
;
}
used
+=
(
size_t
)
written
;
remaining
-=
(
size_t
)
written
;
}
written
=
snprintf
(
href
+
used
,
remaining
,
"%s%s%s"
,
pathname
,
search
,
hash
);
if
(
written
<
0
)
{
href
[
0
]
=
'\0'
;
return
href
;
}
if
((
size_t
)
written
>=
remaining
)
{
href
[
len
-
1
]
=
'\0'
;
return
href
;
}
return
href
;
}
static
void
update_url_href
(
ant_t
*
js
,
jsval_t
url_obj
)
{
char
*
protocol
=
js_getstr
(
js
,
js_get
(
js
,
url_obj
,
"protocol"
),
NULL
);
char
*
username
=
js_getstr
(
js
,
js_get
(
js
,
url_obj
,
"username"
),
NULL
);
char
*
password
=
js_getstr
(
js
,
js_get
(
js
,
url_obj
,
"password"
),
NULL
);
char
*
hostname
=
js_getstr
(
js
,
js_get
(
js
,
url_obj
,
"hostname"
),
NULL
);
char
*
port
=
js_getstr
(
js
,
js_get
(
js
,
url_obj
,
"port"
),
NULL
);
char
*
pathname
=
js_getstr
(
js
,
js_get
(
js
,
url_obj
,
"pathname"
),
NULL
);
char
*
search
=
js_getstr
(
js
,
js_get
(
js
,
url_obj
,
"search"
),
NULL
);
char
*
hash
=
js_getstr
(
js
,
js_get
(
js
,
url_obj
,
"hash"
),
NULL
);
char
*
host
;
if
(
port
&&
*
port
)
{
size_t
hlen
=
strlen
(
hostname
)
+
strlen
(
port
)
+
2
;
host
=
malloc
(
hlen
);
snprintf
(
host
,
hlen
,
"%s:%s"
,
hostname
,
port
);
}
else
{
host
=
strdup
(
hostname
?
hostname
:
""
);
}
js_set
(
js
,
url_obj
,
"host"
,
js_mkstr
(
js
,
host
,
strlen
(
host
)));
char
*
origin
;
if
(
port
&&
*
port
)
{
size_t
olen
=
strlen
(
protocol
)
+
strlen
(
hostname
)
+
strlen
(
port
)
+
8
;
origin
=
malloc
(
olen
);
snprintf
(
origin
,
olen
,
"%s//%s:%s"
,
protocol
?
protocol
:
""
,
hostname
?
hostname
:
""
,
port
);
}
else
{
size_t
olen
=
strlen
(
protocol
)
+
strlen
(
hostname
)
+
8
;
origin
=
malloc
(
olen
);
snprintf
(
origin
,
olen
,
"%s//%s"
,
protocol
?
protocol
:
""
,
hostname
?
hostname
:
""
);
}
js_set
(
js
,
url_obj
,
"origin"
,
js_mkstr
(
js
,
origin
,
strlen
(
origin
)));
char
*
href
=
build_href
(
protocol
?
protocol
:
""
,
username
?
username
:
""
,
password
?
password
:
""
,
hostname
?
hostname
:
""
,
port
?
port
:
""
,
pathname
?
pathname
:
"/"
,
search
?
search
:
""
,
hash
?
hash
:
""
);
js_set
(
js
,
url_obj
,
"href"
,
js_mkstr
(
js
,
href
,
strlen
(
href
)));
free
(
host
);
free
(
origin
);
free
(
href
);
}
static
jsval_t
url_toString
(
ant_t
*
js
,
jsval_t
*
args
,
int
nargs
)
{
return
js_get
(
js
,
js_getthis
(
js
),
"href"
);
}
static
jsval_t
js_URLSearchParams
(
ant_t
*
js
,
jsval_t
*
args
,
int
nargs
)
{
jsval_t
usp
=
js_mkobj
(
js
);
jsval_t
proto
=
js_get_ctor_proto
(
js
,
"URLSearchParams"
,
15
);
if
(
is_special_object
(
proto
))
js_set_proto
(
js
,
usp
,
proto
);
jsval_t
entries
=
js_mkarr
(
js
);
js_set_slot
(
js
,
usp
,
SLOT_ENTRIES
,
entries
);
if
(
nargs
<
1
||
vtype
(
args
[
0
])
!=
T_STR
)
return
usp
;
char
*
init
=
js_getstr
(
js
,
args
[
0
],
NULL
);
if
(
!
init
)
return
usp
;
const
char
*
p
=
init
;
if
(
*
p
==
'?'
)
p
++
;
parse_pair
:
if
(
!*
p
)
return
usp
;
const
char
*
amp
=
strchr
(
p
,
'&'
);
size_t
plen
=
amp
?
(
size_t
)(
amp
-
p
)
:
strlen
(
p
);
char
*
pair
=
strndup
(
p
,
plen
);
char
*
eq
=
strchr
(
pair
,
'='
);
char
*
key
=
pair
,
*
val
=
eq
?
(
eq
[
0
]
=
'\0'
,
eq
+
1
)
:
""
;
char
*
dk
=
url_decode_component
(
key
);
char
*
dv
=
url_decode_component
(
val
);
jsval_t
entry
=
js_mkarr
(
js
);
js_arr_push
(
js
,
entry
,
js_mkstr
(
js
,
dk
,
strlen
(
dk
)));
js_arr_push
(
js
,
entry
,
js_mkstr
(
js
,
dv
,
strlen
(
dv
)));
js_arr_push
(
js
,
entries
,
entry
);
free
(
pair
);
free
(
dk
);
free
(
dv
);
if
(
!
amp
)
return
usp
;
p
=
amp
+
1
;
goto
parse_pair
;
}
static
jsval_t
js_URL
(
ant_t
*
js
,
jsval_t
*
args
,
int
nargs
)
{
if
(
nargs
<
1
)
return
js_mkerr
(
js
,
"TypeError: URL requires at least 1 argument"
);
char
*
url_str
=
js_getstr
(
js
,
args
[
0
],
NULL
);
char
*
base_str
=
(
nargs
>
1
)
?
(
char
*
)
coerce_to_string
(
js
,
args
[
1
],
NULL
)
:
NULL
;
if
(
!
url_str
)
return
js_mkerr
(
js
,
"TypeError: Invalid URL"
);
parsed_url_t
parsed
;
if
(
parse_url
(
url_str
,
base_str
,
&
parsed
)
<
0
)
{
return
js_mkerr
(
js
,
"TypeError: Invalid URL"
);
}
jsval_t
url_obj
=
js_mkobj
(
js
);
jsval_t
proto
=
js_get_ctor_proto
(
js
,
"URL"
,
3
);
if
(
is_special_object
(
proto
))
js_set_proto
(
js
,
url_obj
,
proto
);
js_set
(
js
,
url_obj
,
"protocol"
,
js_mkstr
(
js
,
parsed
.
protocol
,
strlen
(
parsed
.
protocol
)));
js_set
(
js
,
url_obj
,
"username"
,
js_mkstr
(
js
,
parsed
.
username
,
strlen
(
parsed
.
username
)));
js_set
(
js
,
url_obj
,
"password"
,
js_mkstr
(
js
,
parsed
.
password
,
strlen
(
parsed
.
password
)));
js_set
(
js
,
url_obj
,
"hostname"
,
js_mkstr
(
js
,
parsed
.
hostname
,
strlen
(
parsed
.
hostname
)));
js_set
(
js
,
url_obj
,
"port"
,
js_mkstr
(
js
,
parsed
.
port
,
strlen
(
parsed
.
port
)));
js_set
(
js
,
url_obj
,
"pathname"
,
js_mkstr
(
js
,
parsed
.
pathname
,
strlen
(
parsed
.
pathname
)));
js_set
(
js
,
url_obj
,
"search"
,
js_mkstr
(
js
,
parsed
.
search
,
strlen
(
parsed
.
search
)));
js_set
(
js
,
url_obj
,
"hash"
,
js_mkstr
(
js
,
parsed
.
hash
,
strlen
(
parsed
.
hash
)));
update_url_href
(
js
,
url_obj
);
jsval_t
search_params
=
js_mkobj
(
js
);
jsval_t
usp_proto
=
js_get_ctor_proto
(
js
,
"URLSearchParams"
,
15
);
if
(
is_special_object
(
usp_proto
))
js_set_proto
(
js
,
search_params
,
usp_proto
);
js_set_slot
(
js
,
search_params
,
SLOT_DATA
,
url_obj
);
if
(
parsed
.
search
&&
*
parsed
.
search
)
{
const
char
*
qs
=
parsed
.
search
[
0
]
==
'?'
?
parsed
.
search
+
1
:
parsed
.
search
;
jsval_t
arg
=
js_mkstr
(
js
,
qs
,
strlen
(
qs
));
jsval_t
tmp
=
js_URLSearchParams
(
js
,
&
arg
,
1
);
js_set_slot
(
js
,
search_params
,
SLOT_ENTRIES
,
js_get_slot
(
js
,
tmp
,
SLOT_ENTRIES
));
}
else
{
js_set_slot
(
js
,
search_params
,
SLOT_ENTRIES
,
js_mkarr
(
js
));
}
js_set
(
js
,
url_obj
,
"searchParams"
,
search_params
);
free_parsed_url
(
&
parsed
);
return
url_obj
;
}
static
jsval_t
usp_get
(
ant_t
*
js
,
jsval_t
*
args
,
int
nargs
)
{
if
(
nargs
<
1
)
return
js_mknull
();
jsval_t
this_val
=
js_getthis
(
js
);
char
*
key
=
js_getstr
(
js
,
args
[
0
],
NULL
);
if
(
!
key
)
return
js_mknull
();
jsval_t
entries
=
js_get_slot
(
js
,
this_val
,
SLOT_ENTRIES
);
if
(
!
is_special_object
(
entries
))
return
js_mknull
();
jsoff_t
len
=
js_arr_len
(
js
,
entries
);
for
(
jsoff_t
i
=
0
;
i
<
len
;
i
++
)
{
jsval_t
entry
=
js_arr_get
(
js
,
entries
,
i
);
char
*
ks
=
js_getstr
(
js
,
js_arr_get
(
js
,
entry
,
0
),
NULL
);
if
(
ks
&&
strcmp
(
ks
,
key
)
==
0
)
return
js_arr_get
(
js
,
entry
,
1
);
}
return
js_mknull
();
}
static
jsval_t
usp_getAll
(
ant_t
*
js
,
jsval_t
*
args
,
int
nargs
)
{
if
(
nargs
<
1
)
return
js_mkarr
(
js
);
jsval_t
this_val
=
js_getthis
(
js
);
char
*
key
=
js_getstr
(
js
,
args
[
0
],
NULL
);
if
(
!
key
)
return
js_mkarr
(
js
);
jsval_t
result
=
js_mkarr
(
js
);
jsval_t
entries
=
js_get_slot
(
js
,
this_val
,
SLOT_ENTRIES
);
if
(
!
is_special_object
(
entries
))
return
result
;
jsoff_t
len
=
js_arr_len
(
js
,
entries
);
for
(
jsoff_t
i
=
0
;
i
<
len
;
i
++
)
{
jsval_t
entry
=
js_arr_get
(
js
,
entries
,
i
);
char
*
ks
=
js_getstr
(
js
,
js_arr_get
(
js
,
entry
,
0
),
NULL
);
if
(
ks
&&
strcmp
(
ks
,
key
)
==
0
)
js_arr_push
(
js
,
result
,
js_arr_get
(
js
,
entry
,
1
));
}
return
result
;
}
static
jsval_t
usp_has
(
ant_t
*
js
,
jsval_t
*
args
,
int
nargs
)
{
if
(
nargs
<
1
)
return
js_false
;
jsval_t
this_val
=
js_getthis
(
js
);
char
*
key
=
js_getstr
(
js
,
args
[
0
],
NULL
);
if
(
!
key
)
return
js_false
;
jsval_t
entries
=
js_get_slot
(
js
,
this_val
,
SLOT_ENTRIES
);
if
(
!
is_special_object
(
entries
))
return
js_false
;
jsoff_t
len
=
js_arr_len
(
js
,
entries
);
for
(
jsoff_t
i
=
0
;
i
<
len
;
i
++
)
{
jsval_t
entry
=
js_arr_get
(
js
,
entries
,
i
);
char
*
ks
=
js_getstr
(
js
,
js_arr_get
(
js
,
entry
,
0
),
NULL
);
if
(
ks
&&
strcmp
(
ks
,
key
)
==
0
)
return
js_true
;
}
return
js_false
;
}
static
void
usp_sync_url
(
ant_t
*
js
,
jsval_t
this_val
)
{
jsval_t
url_obj
=
js_get_slot
(
js
,
this_val
,
SLOT_DATA
);
if
(
!
is_special_object
(
url_obj
))
return
;
jsval_t
entries
=
js_get_slot
(
js
,
this_val
,
SLOT_ENTRIES
);
jsoff_t
len
=
js_arr_len
(
js
,
entries
);
size_t
buf_size
=
1024
;
char
*
buf
=
try_oom
(
buf_size
);
size_t
pos
=
0
;
for
(
jsoff_t
i
=
0
;
i
<
len
;
i
++
)
{
jsval_t
entry
=
js_arr_get
(
js
,
entries
,
i
);
char
*
k
=
js_getstr
(
js
,
js_arr_get
(
js
,
entry
,
0
),
NULL
);
char
*
v
=
js_getstr
(
js
,
js_arr_get
(
js
,
entry
,
1
),
NULL
);
if
(
!
k
)
continue
;
char
*
ek
=
url_encode_component
(
k
);
char
*
ev
=
url_encode_component
(
v
?
v
:
""
);
size_t
needed
=
strlen
(
ek
)
+
strlen
(
ev
)
+
3
;
if
(
pos
+
needed
>=
buf_size
)
{
buf_size
=
buf_size
*
2
+
needed
;
buf
=
realloc
(
buf
,
buf_size
);
if
(
!
buf
)
{
free
(
buf
);
return
;
}
}
buf
[
pos
]
=
pos
==
0
?
'?'
:
'&'
;
pos
++
;
pos
+=
sprintf
(
buf
+
pos
,
"%s=%s"
,
ek
,
ev
);
free
(
ek
);
free
(
ev
);
}
buf
[
pos
]
=
'\0'
;
js_set
(
js
,
url_obj
,
"search"
,
js_mkstr
(
js
,
buf
,
pos
));
update_url_href
(
js
,
url_obj
);
free
(
buf
);
}
static
jsval_t
usp_set
(
ant_t
*
js
,
jsval_t
*
args
,
int
nargs
)
{
if
(
nargs
<
2
)
return
js_mkundef
();
jsval_t
this_val
=
js_getthis
(
js
);
char
*
key
=
js_getstr
(
js
,
args
[
0
],
NULL
);
if
(
!
key
)
return
js_mkundef
();
jsval_t
entries
=
js_get_slot
(
js
,
this_val
,
SLOT_ENTRIES
);
jsoff_t
len
=
js_arr_len
(
js
,
entries
);
jsval_t
new_entries
=
js_mkarr
(
js
);
int
found
=
0
;
for
(
jsoff_t
i
=
0
;
i
<
len
;
i
++
)
{
jsval_t
entry
=
js_arr_get
(
js
,
entries
,
i
);
char
*
ks
=
js_getstr
(
js
,
js_arr_get
(
js
,
entry
,
0
),
NULL
);
if
(
ks
&&
strcmp
(
ks
,
key
)
==
0
)
{
if
(
!
found
)
{
jsval_t
new_entry
=
js_mkarr
(
js
);
js_arr_push
(
js
,
new_entry
,
args
[
0
]);
js_arr_push
(
js
,
new_entry
,
args
[
1
]);
js_arr_push
(
js
,
new_entries
,
new_entry
);
found
=
1
;
}
}
else
js_arr_push
(
js
,
new_entries
,
entry
);
}
if
(
!
found
)
{
jsval_t
new_entry
=
js_mkarr
(
js
);
js_arr_push
(
js
,
new_entry
,
args
[
0
]);
js_arr_push
(
js
,
new_entry
,
args
[
1
]);
js_arr_push
(
js
,
new_entries
,
new_entry
);
}
js_set_slot
(
js
,
this_val
,
SLOT_ENTRIES
,
new_entries
);
usp_sync_url
(
js
,
this_val
);
return
js_mkundef
();
}
static
jsval_t
usp_append
(
ant_t
*
js
,
jsval_t
*
args
,
int
nargs
)
{
if
(
nargs
<
2
)
return
js_mkundef
();
jsval_t
this_val
=
js_getthis
(
js
);
jsval_t
entries
=
js_get_slot
(
js
,
this_val
,
SLOT_ENTRIES
);
jsval_t
entry
=
js_mkarr
(
js
);
js_arr_push
(
js
,
entry
,
args
[
0
]);
js_arr_push
(
js
,
entry
,
args
[
1
]);
js_arr_push
(
js
,
entries
,
entry
);
usp_sync_url
(
js
,
this_val
);
return
js_mkundef
();
}
static
jsval_t
usp_delete
(
ant_t
*
js
,
jsval_t
*
args
,
int
nargs
)
{
if
(
nargs
<
1
)
return
js_mkundef
();
jsval_t
this_val
=
js_getthis
(
js
);
char
*
key
=
js_getstr
(
js
,
args
[
0
],
NULL
);
if
(
!
key
)
return
js_mkundef
();
jsval_t
entries
=
js_get_slot
(
js
,
this_val
,
SLOT_ENTRIES
);
jsoff_t
len
=
js_arr_len
(
js
,
entries
);
jsval_t
new_entries
=
js_mkarr
(
js
);
for
(
jsoff_t
i
=
0
;
i
<
len
;
i
++
)
{
jsval_t
entry
=
js_arr_get
(
js
,
entries
,
i
);
char
*
ks
=
js_getstr
(
js
,
js_arr_get
(
js
,
entry
,
0
),
NULL
);
if
(
!
ks
||
strcmp
(
ks
,
key
)
!=
0
)
js_arr_push
(
js
,
new_entries
,
entry
);
}
js_set_slot
(
js
,
this_val
,
SLOT_ENTRIES
,
new_entries
);
usp_sync_url
(
js
,
this_val
);
js
->
needs_gc
=
true
;
return
js_mkundef
();
}
static
jsval_t
usp_toString
(
ant_t
*
js
,
jsval_t
*
args
,
int
nargs
)
{
jsval_t
this_val
=
js_getthis
(
js
);
jsval_t
entries
=
js_get_slot
(
js
,
this_val
,
SLOT_ENTRIES
);
jsoff_t
len
=
js_arr_len
(
js
,
entries
);
size_t
buf_size
=
1024
;
char
*
buf
=
try_oom
(
buf_size
);
size_t
pos
=
0
;
for
(
jsoff_t
i
=
0
;
i
<
len
;
i
++
)
{
jsval_t
entry
=
js_arr_get
(
js
,
entries
,
i
);
char
*
k
=
js_getstr
(
js
,
js_arr_get
(
js
,
entry
,
0
),
NULL
);
char
*
v
=
js_getstr
(
js
,
js_arr_get
(
js
,
entry
,
1
),
NULL
);
if
(
!
k
)
continue
;
char
*
ek
=
url_encode_component
(
k
);
char
*
ev
=
url_encode_component
(
v
?
v
:
""
);
size_t
needed
=
strlen
(
ek
)
+
strlen
(
ev
)
+
3
;
if
(
pos
+
needed
>=
buf_size
)
{
buf_size
=
buf_size
*
2
+
needed
;
buf
=
realloc
(
buf
,
buf_size
);
if
(
!
buf
)
{
free
(
buf
);
return
js_mkstr
(
js
,
""
,
0
);
}
}
if
(
pos
>
0
)
buf
[
pos
++
]
=
'&'
;
pos
+=
sprintf
(
buf
+
pos
,
"%s=%s"
,
ek
,
ev
);
free
(
ek
);
free
(
ev
);
}
buf
[
pos
]
=
'\0'
;
jsval_t
ret
=
js_mkstr
(
js
,
buf
,
pos
);
free
(
buf
);
return
ret
;
}
void
init_url_module
(
void
)
{
ant_t
*
js
=
rt
->
js
;
jsval_t
glob
=
js
->
global
;
jsval_t
url_ctor
=
js_mkobj
(
js
);
jsval_t
url_proto
=
js_mkobj
(
js
);
js_set
(
js
,
url_proto
,
"toString"
,
js_mkfun
(
url_toString
));
js_set_sym
(
js
,
url_proto
,
get_toStringTag_sym
(),
js_mkstr
(
js
,
"URL"
,
3
));
js_set_slot
(
js
,
url_ctor
,
SLOT_CFUNC
,
js_mkfun
(
js_URL
));
js_mkprop_fast
(
js
,
url_ctor
,
"prototype"
,
9
,
url_proto
);
js_mkprop_fast
(
js
,
url_ctor
,
"name"
,
4
,
ANT_STRING
(
"URL"
));
js_set_descriptor
(
js
,
url_ctor
,
"name"
,
4
,
0
);
js_set
(
js
,
glob
,
"URL"
,
js_obj_to_func
(
url_ctor
));
jsval_t
usp_ctor
=
js_mkobj
(
js
);
jsval_t
usp_proto
=
js_mkobj
(
js
);
js_set
(
js
,
usp_proto
,
"get"
,
js_mkfun
(
usp_get
));
js_set
(
js
,
usp_proto
,
"getAll"
,
js_mkfun
(
usp_getAll
));
js_set
(
js
,
usp_proto
,
"has"
,
js_mkfun
(
usp_has
));
js_set
(
js
,
usp_proto
,
"set"
,
js_mkfun
(
usp_set
));
js_set
(
js
,
usp_proto
,
"append"
,
js_mkfun
(
usp_append
));
js_set
(
js
,
usp_proto
,
"delete"
,
js_mkfun
(
usp_delete
));
js_set
(
js
,
usp_proto
,
"toString"
,
js_mkfun
(
usp_toString
));
js_set_sym
(
js
,
usp_proto
,
get_toStringTag_sym
(),
js_mkstr
(
js
,
"URLSearchParams"
,
15
));
js_set_slot
(
js
,
usp_ctor
,
SLOT_CFUNC
,
js_mkfun
(
js_URLSearchParams
));
js_mkprop_fast
(
js
,
usp_ctor
,
"prototype"
,
9
,
usp_proto
);
js_mkprop_fast
(
js
,
usp_ctor
,
"name"
,
4
,
ANT_STRING
(
"URLSearchParams"
));
js_set_descriptor
(
js
,
usp_ctor
,
"name"
,
4
,
0
);
js_set
(
js
,
glob
,
"URLSearchParams"
,
js_obj_to_func
(
usp_ctor
));
}
static
jsval_t
builtin_fileURLToPath
(
ant_t
*
js
,
jsval_t
*
args
,
int
nargs
)
{
if
(
nargs
<
1
)
return
js_mkerr
(
js
,
"fileURLToPath requires a string or URL argument"
);
size_t
len
;
const
char
*
str
=
coerce_to_string
(
js
,
args
[
0
],
&
len
);
if
(
!
str
)
return
js_mkerr
(
js
,
"fileURLToPath requires a string or URL argument"
);
parsed_url_t
parsed
;
if
(
parse_url
(
str
,
NULL
,
&
parsed
)
!=
0
)
return
js_mkerr
(
js
,
"Invalid URL"
);
if
(
strcmp
(
parsed
.
protocol
,
"file:"
)
!=
0
)
{
free_parsed_url
(
&
parsed
);
return
js_mkerr
(
js
,
"fileURLToPath requires a file: URL"
);
}
char
*
decoded
=
url_decode_component
(
parsed
.
pathname
);
free_parsed_url
(
&
parsed
);
if
(
!
decoded
)
return
js_mkerr
(
js
,
"allocation failure"
);
jsval_t
ret
=
js_mkstr
(
js
,
decoded
,
strlen
(
decoded
));
free
(
decoded
);
return
ret
;
}
static
jsval_t
builtin_pathToFileURL
(
ant_t
*
js
,
jsval_t
*
args
,
int
nargs
)
{
if
(
nargs
<
1
||
vtype
(
args
[
0
])
!=
T_STR
)
return
js_mkerr
(
js
,
"pathToFileURL requires a string argument"
);
size_t
len
;
const
char
*
path
=
js_getstr
(
js
,
args
[
0
],
&
len
);
size_t
total
=
7
+
len
;
char
*
buf
=
malloc
(
total
+
1
);
if
(
!
buf
)
return
js_mkerr
(
js
,
"allocation failure"
);
memcpy
(
buf
,
"file://"
,
7
);
memcpy
(
buf
+
7
,
path
,
len
);
buf
[
total
]
=
'\0'
;
jsval_t
url_args
[
1
]
=
{
js_mkstr
(
js
,
buf
,
total
)
};
free
(
buf
);
return
js_URL
(
js
,
url_args
,
1
);
}
jsval_t
url_library
(
ant_t
*
js
)
{
jsval_t
lib
=
js_mkobj
(
js
);
jsval_t
glob
=
js_glob
(
js
);
js_set
(
js
,
lib
,
"URL"
,
js_get
(
js
,
glob
,
"URL"
));
js_set
(
js
,
lib
,
"URLSearchParams"
,
js_get
(
js
,
glob
,
"URLSearchParams"
));
js_set
(
js
,
lib
,
"fileURLToPath"
,
js_mkfun
(
builtin_fileURLToPath
));
js_set
(
js
,
lib
,
"pathToFileURL"
,
js_mkfun
(
builtin_pathToFileURL
));
js_set
(
js
,
lib
,
"default"
,
lib
);
return
lib
;
}
File Metadata
Details
Attached
Mime Type
text/x-c
Expires
Thu, Mar 26, 4:46 PM (2 d)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
511729
Default Alt Text
url.c (21 KB)
Attached To
Mode
rANT Ant
Attached
Detach File
Event Timeline
Log In to Comment