49 if ((digit >=
'0' && digit <=
'9')) {
52 if ((digit >=
'A' && digit <=
'F')) {
53 return digit -
'A' + 10;
55 if ((digit >=
'a' && digit <=
'f')) {
56 return digit -
'a' + 10;
67 if (str[
pos] !=
'%') {
72 char digit1 = str[
pos + 1];
73 char digit2 = str[
pos + 2];
91 intptr_t buffer_pos = 0;
95 if (escaped_value >= 0) {
100 buffer[buffer_pos] = escaped_value;
123 buffer[buffer_pos] =
'\0';
129 const intptr_t len = strlen(str);
133 if (escaped_value >= 0) {
140 if (c >=
'A' && c <=
'Z') {
141 str[i] = c + (
'a' -
'A');
149 parsed_uri->
scheme =
nullptr;
151 parsed_uri->
host =
nullptr;
152 parsed_uri->
port =
nullptr;
153 parsed_uri->
path =
nullptr;
154 parsed_uri->
query =
nullptr;
160 const char* current = authority;
163 size_t userinfo_len = strcspn(current,
"@/");
164 if (current[userinfo_len] ==
'@') {
167 current += userinfo_len + 1;
168 len += userinfo_len + 1;
173 size_t host_len = strcspn(current,
":/");
176 parsed_uri->
host = host;
179 if (current[host_len] ==
':') {
181 const char* port_start = current + host_len + 1;
182 size_t port_len = strcspn(port_start,
"/");
186 parsed_uri->
port =
nullptr;
198 size_t scheme_len = strcspn(uri,
":/");
199 const char* rest = uri;
200 if (uri[scheme_len] ==
':') {
203 parsed_uri->
scheme = scheme;
204 rest = uri + scheme_len + 1;
206 parsed_uri->
scheme =
nullptr;
210 const char* hash_pos = rest + strcspn(rest,
"#");
211 if (*hash_pos ==
'#') {
213 const char* fragment_start = hash_pos + 1;
222 const char* question_pos = rest + strcspn(rest,
"?#");
223 if (*question_pos ==
'?') {
225 const char* query_start = question_pos + 1;
228 parsed_uri->
query =
nullptr;
231 const char* path_start = rest;
232 if (rest[0] ==
'/' && rest[1] ==
'/') {
234 const char* authority_start = rest + 2;
236 intptr_t authority_len =
ParseAuthority(authority_start, parsed_uri);
237 if (authority_len < 0) {
241 path_start = authority_start + authority_len;
244 parsed_uri->
host =
nullptr;
245 parsed_uri->
port =
nullptr;
254 if (current ==
base) {
258 for (current--; current >
base; current--) {
259 if (*current ==
'/') {
269 const char* cp = input;
277 cp += strcspn(cp,
"/");
283 const char* input = path;
288 char*
buffer = zone->
Alloc<
char>(strlen(path) + 1);
291 while (*input !=
'\0') {
292 if (strncmp(
"../", input, 3) == 0) {
296 }
else if (strncmp(
"./", input, 3) == 0) {
300 }
else if (strncmp(
"/./", input, 3) == 0) {
304 }
else if (strcmp(
"/.", input) == 0) {
308 }
else if (strncmp(
"/../", input, 4) == 0) {
314 }
else if (strcmp(
"/..", input) == 0) {
320 }
else if (strcmp(
"..", input) == 0) {
324 }
else if (strcmp(
".", input) == 0) {
330 if (input[0] !=
'/' && output !=
buffer) {
334 strncpy(output, input, segment_len);
335 output += segment_len;
336 input += segment_len;
344static const char*
MergePaths(
const char* base_path,
const char* ref_path) {
346 if (base_path[0] ==
'\0') {
352 const char* last_slash = strrchr(base_path,
'/');
353 if (last_slash ==
nullptr) {
360 intptr_t truncated_base_len = last_slash - base_path;
361 intptr_t ref_path_len = strlen(ref_path);
362 intptr_t len = truncated_base_len + ref_path_len + 1;
366 strncpy(
buffer, base_path, truncated_base_len);
369 buffer[truncated_base_len] =
'/';
372 strncpy((
buffer + truncated_base_len + 1), ref_path, ref_path_len + 1);
382 const char* fragment_separator = uri.
fragment ==
nullptr ?
"" :
"#";
383 const char* query = uri.
query ==
nullptr ?
"" : uri.
query;
384 const char* query_separator = uri.
query ==
nullptr ?
"" :
"?";
389 if (uri.
scheme ==
nullptr) {
391 uri.
port ==
nullptr);
393 fragment_separator, fragment);
397 if (uri.
host ==
nullptr) {
400 query_separator, query, fragment_separator,
405 const char* user_separator = uri.
userinfo ==
nullptr ?
"" :
"@";
406 const char* port = uri.
port ==
nullptr ?
"" : uri.
port;
407 const char* port_separator = uri.
port ==
nullptr ?
"" :
":";
411 const char* path_separator =
412 ((uri.
path[0] ==
'\0' || uri.
path[0] ==
'/') ?
"" :
"/");
417 "%s://%s%s%s%s%s%s%s%s%s%s%s",
418 uri.
scheme, user, user_separator, uri.
host, port_separator, port,
419 path_separator, uri.
path, query_separator, query, fragment_separator,
425 const char* base_uri,
426 const char** target_uri) {
430 *target_uri =
nullptr;
435 if (ref.
scheme !=
nullptr) {
436 if (strcmp(ref.
scheme,
"dart") == 0) {
457 *target_uri =
nullptr;
461 if ((
base.scheme !=
nullptr) && strcmp(
base.scheme,
"dart") == 0) {
467 if (ref.
host !=
nullptr) {
480 if (ref.
path[0] ==
'\0') {
492 }
else if (ref.
path[0] ==
'/') {
507 if (
base.scheme ==
nullptr &&
base.host ==
nullptr &&
base.path[0] !=
'/') {
513 *target_uri =
nullptr;
static ThreadState * Current()
static int SNPrint(char *str, size_t size, const char *format,...) PRINTF_ATTRIBUTE(3
char * PrintToString(const char *format,...) PRINTF_ATTRIBUTE(2
char * MakeCopyOfStringN(const char *str, intptr_t len)
char * MakeCopyOfString(const char *str)
ElementType * Alloc(intptr_t length)
static const uint8_t buffer[]
static int GetEscapedValue(const char *str, intptr_t pos, intptr_t len)
bool ResolveUri(const char *ref_uri, const char *base_uri, const char **target_uri)
static intptr_t HexValue(uint32_t c)
static bool IsHexDigit(char value)
bool ParseUri(const char *uri, ParsedUri *parsed_uri)
static const char * RemoveDotSegments(const char *path)
static bool IsDelimiter(intptr_t value)
static void StringLower(char *str)
static bool IsUnreservedChar(intptr_t value)
static char * NormalizeEscapes(const char *str, intptr_t len)
static const char * MergePaths(const char *base_path, const char *ref_path)
static char * RemoveLastSegment(char *current, char *base)
static intptr_t ParseAuthority(const char *authority, ParsedUri *parsed_uri)
static intptr_t SegmentLength(const char *input)
static char * BuildUri(const ParsedUri &uri)
static void ClearParsedUri(ParsedUri *parsed_uri)