package Net::Hawk::Utils { use v6; use URI; use Net::Hawk::Errors; proto parse_content_type($) returns Str is export {*} multi parse_content_type(Str:U) returns Str { return '' } multi parse_content_type(Str:D $header) returns Str { my $ret = $header ~~ m{^ \s* (\S+?) \s* (\;|$) }; return $ret[0].lc; } sub now_msecs(Int $offset_ms=0) returns Int is export { return floor(now*1000) + $offset_ms; } sub now_secs(Int $offset_ms=0) returns Int is export { return floor(now_msecs($offset_ms)/1000); } proto parse_authorization_header($,*@) returns Hash is export {*} multi parse_authorization_header(Str:U,*@) returns Hash { Net::Hawk::Errors::UnAuthorized.new(text=>'no header').throw } multi parse_authorization_header(Str:D $header, @keys=qw) returns Hash { my $valid_keys = Set(@keys); my ($attr_string) = @($header ~~ m:i{^ hawk [ \s+ (.+) ]? $} or Net::Hawk::Errors::BadRequest.new( text => 'invalid header syntax', value => $header, ).throw ); my %attributes; my @attr_strings = split /\s* ',' \s*/, $attr_string; for @attr_strings -> $attr { my ($key, $value) = @( $attr ~~ m{^ (\w+) '="' (<-["\\]>*) '"' } or Net::Hawk::Errors::BadRequest.new( text => 'Bad header format', value => $header, ).throw ); Net::Hawk::Errors::BadRequest.new( text => "Unknown attribute $key", value => $header, ).throw unless $valid_keys{~$key} :exists; Net::Hawk::Errors::BadRequest.new( text => "Bad attribute value $value", value => $header, ).throw unless $value ~~ m{^<[ \w \ !#$%&'()*+,\-./:;\<=\>?@\[\]^`{|}~ ]>+$}; Net::Hawk::Errors::BadRequest.new( text => "Duplicate attribute $key", value => $header, ).throw if %attributes{$key} :exists; %attributes{$key} = ~$value; } return %attributes; } } 1;