DoxigAlpha

parseAfterScheme

Parses the URI or returns an error. This function is not compliant, but is required to parse some forms of URIs in the wild, such as HTTP Location headers. The return value will contain strings pointing into the original text. Each component that is provided, will be non-null.

Function parameters

Parameters

#
scheme:[]const u8
text:[]const u8

Type definitions in this namespace

Types

#

Returned value may point into `buffer` or be the original string.

Functions

#
getHost
Returned value may point into `buffer` or be the original string.
getHostAlloc
Returned value may point into `buffer` or be the original string.
percentDecodeBackwards
Percent decodes all %XX where XX is a valid hex number.
percentDecodeInPlace
Percent decodes all %XX where XX is a valid hex number.
parseAfterScheme
Parses the URI or returns an error.
parse
The return value will contain strings pointing into the original `text`.
resolveInPlace
Resolves a URI against a base URI, conforming to

Error sets in this namespace

Error Sets

#

= 255

Values

#

Source

Implementation

#
pub fn parseAfterScheme(scheme: []const u8, text: []const u8) ParseError!Uri {
    var uri: Uri = .{ .scheme = scheme, .path = undefined };
    var i: usize = 0;

    if (std.mem.startsWith(u8, text, "//")) a: {
        i = std.mem.indexOfAnyPos(u8, text, 2, &authority_sep) orelse text.len;
        const authority = text[2..i];
        if (authority.len == 0) {
            if (!std.mem.startsWith(u8, text[2..], "/")) return error.InvalidFormat;
            break :a;
        }

        var start_of_host: usize = 0;
        if (std.mem.indexOf(u8, authority, "@")) |index| {
            start_of_host = index + 1;
            const user_info = authority[0..index];

            if (std.mem.indexOf(u8, user_info, ":")) |idx| {
                uri.user = .{ .percent_encoded = user_info[0..idx] };
                if (idx < user_info.len - 1) { // empty password is also "no password"
                    uri.password = .{ .percent_encoded = user_info[idx + 1 ..] };
                }
            } else {
                uri.user = .{ .percent_encoded = user_info };
                uri.password = null;
            }
        }

        // only possible if uri consists of only `userinfo@`
        if (start_of_host >= authority.len) break :a;

        var end_of_host: usize = authority.len;

        // if  we see `]` first without `@`
        if (authority[start_of_host] == ']') {
            return error.InvalidFormat;
        }

        if (authority.len > start_of_host and authority[start_of_host] == '[') { // IPv6
            end_of_host = std.mem.lastIndexOf(u8, authority, "]") orelse return error.InvalidFormat;
            end_of_host += 1;

            if (std.mem.lastIndexOf(u8, authority, ":")) |index| {
                if (index >= end_of_host) { // if not part of the V6 address field
                    end_of_host = @min(end_of_host, index);
                    uri.port = std.fmt.parseInt(u16, authority[index + 1 ..], 10) catch return error.InvalidPort;
                }
            }
        } else if (std.mem.lastIndexOf(u8, authority, ":")) |index| {
            if (index >= start_of_host) { // if not part of the userinfo field
                end_of_host = @min(end_of_host, index);
                uri.port = std.fmt.parseInt(u16, authority[index + 1 ..], 10) catch return error.InvalidPort;
            }
        }

        if (start_of_host >= end_of_host) return error.InvalidFormat;
        uri.host = .{ .percent_encoded = authority[start_of_host..end_of_host] };
    }

    const path_start = i;
    i = std.mem.indexOfAnyPos(u8, text, path_start, &path_sep) orelse text.len;
    uri.path = .{ .percent_encoded = text[path_start..i] };

    if (std.mem.startsWith(u8, text[i..], "?")) {
        const query_start = i + 1;
        i = std.mem.indexOfScalarPos(u8, text, query_start, '#') orelse text.len;
        uri.query = .{ .percent_encoded = text[query_start..i] };
    }

    if (std.mem.startsWith(u8, text[i..], "#")) {
        uri.fragment = .{ .percent_encoded = text[i + 1 ..] };
    }

    return uri;
}