class URI; use IETF::RFC_Grammar; use IETF::RFC_Grammar::URI; use URI::Escape; need URI::DefaultPort; has $.grammar; has $.is_validating is rw = False; has $!path; has $!is_absolute; has $!scheme; has $!authority; has $!query; has $!frag; has %!query_form; has $!uri; # use of this now deprecated has @.segments; method parse (Str $str) { # clear string before parsing my $c_str = $str; $c_str .= subst(/^ \s* ['<' | '"'] /, ''); $c_str .= subst(/ ['>' | '"'] \s* $/, ''); $!uri = $!path = $!is_absolute = $!scheme = $!authority = $!query = $!frag = Mu; %!query_form = @!segments = Nil; try { if ($.is_validating) { $!grammar.parse_validating($c_str); } else { $!grammar.parse($c_str); } CATCH { default { die "Could not parse URI: $str" } } } # now deprecated $!uri = $!grammar.parse_result; my $comp_container = $!grammar.parse_result<URI_reference><URI> || $!grammar.parse_result<URI_reference><relative_ref>; $!scheme = $comp_container<scheme>; $!query = $comp_container<query>; $!frag = $comp_container<fragment>; $comp_container = $comp_container<hier_part> || $comp_container<relative_part>; $!authority = $comp_container<authority>; $!path = $comp_container<path_abempty> || $comp_container<path_absolute> ; $!is_absolute = ?($!path || $!scheme); $!path ||= $comp_container<path_noscheme> || $comp_container<path_rootless> ; @!segments = $!path<segment>.list() || (''); if my $first_chunk = $!path<segment_nz_nc> || $!path<segment_nz> { unshift @!segments, $first_chunk; } if @!segments.elems == 0 { @!segments = (''); } # @!segments ||= (''); try { %!query_form = split_query( ~$!query ) if $!query; CATCH { default { %!query_form = (); } } } } our sub split_query(Str $query) { my %query_form; for map { [split(/<[=]>/, $_) ]}, split(/<[&;]>/, $query) -> $qmap { for (0, 1) -> $i { # could go past 1 in theory ... $qmap[ $i ] = uri_unescape($qmap[ $i ]); } if %query_form.exists($qmap[0]) { if %query_form{ $qmap[0] } ~~ Array { %query_form{ $qmap[0] }.push($qmap[1]) } else { %query_form{ $qmap[0] } = [ %query_form{ $qmap[0] }, $qmap[1] ] } } else { %query_form{ $qmap[0]} = $qmap[1] } } return %query_form; } # deprecated old call for parse method init ($str) { warn "init method now deprecated in favor of parse method"; $.parse($str); } # new can pass alternate grammars some day ... submethod BUILD(:$!is_validating) { $!grammar = IETF::RFC_Grammar.new('rfc3896'); } method new(Str $uri_pos1?, Str :$uri, :$is_validating) { my $obj = self.bless(*); if $is_validating.defined { $obj.is_validating = ?$is_validating; } if $uri.defined and $uri_pos1.defined { die "Please specify the uri by name or position but not both."; } elsif $uri.defined or $uri_pos1.defined { $obj.parse($uri // $uri_pos1); } return $obj; } method scheme { return ~$!scheme.lc; } method authority { return ~$!authority.lc; } method host { return ($!authority<host> || '').lc; } method default_port { URI::DefaultPort::scheme_port($.scheme) } method _port { # port 0 is off limits and see also RT 96424 # $!authority<port>.Int doesn't work because of RT 96472 $!authority<port> ?? ($!authority<port> ~ '').Int !! Int; } method port { $._port // $.default_port; } method path { return ~($!path || ''); } method absolute { return $!is_absolute; } method relative { return ! $.absolute; } method query { item ~($!query || ''); } method path_query { $.query ?? $.path ~ '?' ~ $.query !! $.path } method frag { return ~($!frag || '').lc; } method fragment { $.frag } method Str() { my $str; $str ~= $.scheme if $.scheme; $str ~= '://' ~ $.authority if $.authority; $str ~= $.path; $str ~= '?' ~ $.query if $.query; $str ~= '#' ~ $.frag if $.frag; return $str; } # chunks now strongly deprecated # it's segments in p5 URI and segment is part of rfc so no more chunks soon! method chunks { warn "chunks attribute now deprecated in favor of segments"; return @!segments; } method uri { warn "uri attribute now deprecated in favor of .grammar.parse_result"; return $!uri; } method query_form { return %!query_form; } =begin pod =head NAME URI — Uniform Resource Identifiers (absolute and relative) =head SYNOPSYS use URI; my $u = URI.new('http://her.com/foo/bar?tag=woow#bla'); my $scheme = $u.scheme; my $authority = $u.authority; my $host = $u.host; my $port = $u.port; my $path = $u.path; my $query = $u.query; my $frag = $u.frag; # or $u.fragment; my $tag = $u.query_form<tag>; # should be woow my $is_absolute = $u.absolute; my $is_relative = $u.relative; # something p5 URI without grammar could not easily do ! my $host_in_grammar = $u.grammar.parse_result<URI_reference><URI><hier_part><authority><host>; if ($host_in_grammar<reg_name>) { say 'Host looks like registered domain name - approved!'; } else { say 'Sorry we do not take ip address hosts at this time.'; say 'Please use registered domain name!'; } # require whole string matches URI and throw exception otherwise .. my $u_v = URI.new('http://?#?#', :is_validating<1>);# throw exception =end pod # vim:ft=perl6