4 int is_urlschemechar(int first_flag
, int ch
)
7 * The set of valid URL schemes, as per STD66 (RFC3986) is
8 * '[A-Za-z][A-Za-z0-9+.-]*'. But use sightly looser check
9 * of '[A-Za-z0-9][A-Za-z0-9+.-]*' because earlier version
10 * of check used '[A-Za-z0-9]+' so not to break any remote
13 int alphanumeric
, special
;
14 alphanumeric
= ch
> 0 && isalnum(ch
);
15 special
= ch
== '+' || ch
== '-' || ch
== '.';
16 return alphanumeric
|| (!first_flag
&& special
);
19 int is_url(const char *url
)
21 const char *url2
, *first_slash
;
26 first_slash
= strchr(url
, '/');
28 /* Input with no slash at all or slash first can't be URL. */
29 if (!first_slash
|| first_slash
== url
)
31 /* Character before must be : and next must be /. */
32 if (first_slash
[-1] != ':' || first_slash
[1] != '/')
34 /* There must be something before the :// */
35 if (first_slash
== url
+ 1)
38 * Check all characters up to first slash - 1. Only alphanum
42 while (url2
< first_slash
- 1) {
43 if (!is_urlschemechar(url2
== url
, (unsigned char)*url2
))
52 static int url_decode_char(const char *q
)
55 unsigned char val
= 0;
56 for (i
= 0; i
< 2; i
++) {
57 unsigned char c
= *q
++;
59 if (c
>= '0' && c
<= '9')
61 else if (c
>= 'a' && c
<= 'f')
63 else if (c
>= 'A' && c
<= 'F')
71 static char *url_decode_internal(const char **query
, int len
,
72 const char *stop_at
, struct strbuf
*out
,
75 const char *q
= *query
;
82 if (stop_at
&& strchr(stop_at
, c
)) {
89 int val
= url_decode_char(q
+ 1);
91 strbuf_addch(out
, val
);
98 if (decode_plus
&& c
== '+')
99 strbuf_addch(out
, ' ');
101 strbuf_addch(out
, c
);
106 return strbuf_detach(out
, NULL
);
109 char *url_decode(const char *url
)
111 return url_decode_mem(url
, strlen(url
));
114 char *url_decode_mem(const char *url
, int len
)
116 struct strbuf out
= STRBUF_INIT
;
117 const char *colon
= memchr(url
, ':', len
);
119 /* Skip protocol part if present */
120 if (colon
&& url
< colon
) {
121 strbuf_add(&out
, url
, colon
- url
);
125 return url_decode_internal(&url
, len
, NULL
, &out
, 0);
128 char *url_decode_parameter_name(const char **query
)
130 struct strbuf out
= STRBUF_INIT
;
131 return url_decode_internal(query
, -1, "&=", &out
, 1);
134 char *url_decode_parameter_value(const char **query
)
136 struct strbuf out
= STRBUF_INIT
;
137 return url_decode_internal(query
, -1, "&", &out
, 1);
140 void end_url_with_slash(struct strbuf
*buf
, const char *url
)
142 strbuf_addstr(buf
, url
);
143 if (buf
->len
&& buf
->buf
[buf
->len
- 1] != '/')
144 strbuf_addstr(buf
, "/");
147 void str_end_url_with_slash(const char *url
, char **dest
) {
148 struct strbuf buf
= STRBUF_INIT
;
149 end_url_with_slash(&buf
, url
);
151 *dest
= strbuf_detach(&buf
, NULL
);