ref: 22d71e9e0471402b4d9e918f4f10683137ee9121
dir: /lib/http/url.myr/
use std use "types" use "parse" pkg http = const parseurl : (url : byte[:] -> std.result(url#, err)) const urlfree : (url : url# -> void) ;; const parseurl = {url var schema, host, path, port match parseschema(&url) | `std.Ok s: schema = s | `std.Fail e: -> `std.Fail e ;; match parsehostname(&url) | `std.Ok h: host = h | `std.Fail e: -> `std.Fail e ;; match parseport(&url) | `std.Ok p: port = p | `std.Fail e: -> `std.Fail e ;; match parsepath(&url) | `std.Ok p: path = p | `std.Fail e: -> `std.Fail e ;; /* todo: params */ -> `std.Ok std.mk([ .schema=schema, .host=std.sldup(host), .path=std.sldup(path), ]) } const urlfree = {url std.slfree(url.host) std.slfree(url.path) std.free(url) } const parseschema = {url if std.chomp(url, "http://") -> `std.Ok `Http elif std.chomp(url, "https://") -> `std.Fail `Eunsupp else -> `std.Fail `Eproto ;; } const parsehostname = {url if std.chomp(url, "[") -> ipv6hostname(url) else -> hostname(url) ;; } const parsepath = {url if url#.len == 0 -> `std.Ok "/" elif std.decode(url#) == '/' -> `std.Ok url# else -> `std.Fail `Esyntax ;; } const hostname = {url var len, host len = 0 for c in std.bychar(url#) match c | ':': break | '/': break | chr: if ishostchar(chr) len += std.charlen(chr) else -> `std.Fail `Esyntax ;; ;; ;; host = url#[:len] url# = url#[len:] -> `std.Ok host } const ipv6hostname = {url -> std.result(byte[:], err) var ip match std.strfind(url#, "]") | `std.None: -> `std.Fail `Esyntax | `std.Some idx: ip = url#[:idx] url# = url#[idx+1:] match std.ip6parse(url#[:idx]) | `std.Some _: -> `std.Ok ip | `std.None: -> `std.Fail `Esyntax ;; ;; } const parseport = {url if std.chomp(url, ":") match parsenumber(url, 10) | `std.Some n: -> `std.Ok n | `std.None: -> `std.Fail `Esyntax ;; else -> `std.Ok 80 ;; } const ishostchar = {c if !std.isascii(c) -> false else -> std.isalnum(c) || unreserved(c) || subdelim(c) ;; } const unreserved = {c -> c == '.' || c == '-' || c == '_' || c == '~' } const subdelim = {c -> c == '.' || c == '-' || c == '_' || c == '~' || c == '!' || \ c == '$' || c == '&' || c == '\'' || c == '(' || c == ')' \ || c == '*' || c == '+' || c == ',' || c == ';' || c == '=' }