HTTP::RequestTarget::Raw
Version 0.1.0, API 1. Requires Raku6.d. MIT licensed. No non-core dependencies.
A lossless structural parser for visible-ASCII HTTP request targets. Inspect raw
targets, distinguish their forms, preserve signed query spelling, or compare
inputs without silently decoding or normalizing them. No HTTP requests or DNS
lookups.
Documentation and source download:
https://gbx-raku-af.37-221-65-210.sslip.io/raw-request-target-adf2fa6dc520413996d933c98593d0e0.html
Install from source
Download raw-request-target-adf2fa6dc520413996d933c98593d0e0.tar.gz using the
source archive link on the documentation page, then run:
zef install ./raw-request-target-adf2fa6dc520413996d933c98593d0e0.tar.gz
The archive contains the library, metadata, license, README and boundary tests.
Package identity:
HTTP::RequestTarget::Raw:ver<0.1.0>:api<1>:auth<zef:gbx-raw-af-612aa782bd>.
Quickstart
use HTTP::RequestTarget::Raw;
my $target = parse-request-target('/a%2Fb//../c?x=1&x=2?');
say $target.form; # origin
say $target.path; # /a%2Fb//../c
say $target.query; # x=1&x=2?
say $target.has-query; # True
my $empty = parse-request-target('/health?');
say $empty.query eq ''; # True
say $empty.has-query; # True
say parse-request-target('/health').query.defined; # False
API
The module exports parse-request-target, Target and InvalidTarget.
parse-request-target(Str:D $raw --> Target:D)
Input is a defined Raku string containing a request target, not an entire request
line. Results have read-only Str attributes; parsing does not mutate input.
Absent attributes contain the undefined Str type value, never an empty-string
sentinel. .has-query returns a defined Bool.
| Attribute | Meaning |
|---|
.raw | The complete unchanged input |
.form | Exactly origin, absolute, authority or asterisk |
.scheme | Original http/https spelling, absolute form only |
.authority | Original host and optional port, absolute or authority form |
.path | Path for origin/absolute form; an absent absolute path is '' |
.query | Text following the first ?, or undefined if there was no ? |
.has-query | True even when the query is present but empty |
- Origin: begins with
/. //Host/path remains an origin path, not an
authority. Path and query split at the first ?; further question marks belong
to the query. - Absolute: case-insensitive
http:// or https://, preserving scheme case.
A nonempty authority ends at the first / or ?. No implicit slash is added. - Authority: a CONNECT-style
host:port or [host]:port. The numeric port is
required. Scheme, path and query are undefined. This parser does not examine an
HTTP method or require that the caller is processing CONNECT. - Asterisk: exactly
*. Scheme, authority, path and query are undefined.
*extra is not asterisk form.
Examples:
| Input | Important result fields |
|---|
/health | origin; path /health; query undefined; has-query False |
/health? | origin; path /health; query ''; has-query True |
/a%2Fb//../c?x=1&x=2? | origin; path /a%2Fb//../c; query x=1&x=2? |
HTTPS://Example.test:0443?x=%2f | absolute; scheme HTTPS; authority Example.test:0443; path ''; query x=%2f |
http://Example.test | absolute; path ''; query undefined |
[2001:db8::1]:443 | authority; authority preserved; path undefined |
* | asterisk; all component fields undefined |
Authority boundaries
Absolute-form authorities may omit the port; authority-form inputs may not.
Ports contain ASCII decimal digits only and must be in 0..65535. Original
leading zeros remain in .authority. Reg-name hosts allow ASCII letters,
digits, -._~, URI subdelimiters !$&'()*+,;= and %. Bracketed hosts allow
those structural characters plus :; their content is not IP-validated.
Empty hosts or ports, nested/unmatched/empty brackets, unbracketed multiple
colons, userinfo @, authority path/query/fragment delimiters and characters
outside those structural host sets are rejected. Neither host normalization nor
DNS validation is performed.
InvalidTarget is an exported Exception with read-only .reason. Parser
reasons are fixed strings, never interpolated target fragments. .message is
Invalid request target: followed by that reason. For example:
try {
parse-request-target('/private?token=secret#fragment');
CATCH {
when InvalidTarget {
say .reason; # fragments are not allowed
# Do not log the original target if its query may contain secrets.
}
}
}
Empty input, non-ASCII characters, ASCII whitespace/control characters including
DEL, and a literal # anywhere are rejected. Unsupported URI schemes and
malformed authorities are rejected, not coerced to another supported form.
Passing an undefined value or a non-Str violates the typed function signature;
InvalidTarget describes invalid defined string inputs.
Structural limits and safety
This is not a comprehensive URI, DNS, IPv4 or IPv6 validator. It accepts malformed
percent sequences such as %zz and % intentionally, leaves escapes and their
case unchanged, and preserves duplicate slashes, dot segments, host/scheme case,
query order and repeated query keys. An encoded %23 is not a literal fragment.
An encoded %20 is not an ASCII whitespace character in this input.
The input is a string, not a byte-buffer decoder. There is no percent decoding,
IDNA conversion, path traversal resolution, query parameter interpretation,
method validation or routing policy. Successful parsing is not proof that a
request is safe for routing, authorization or forwarding. Apply the protocol and
security rules required by your application separately. The result's .raw and
components may contain credentials, even though parser errors never include
them.
Tests
From an extracted source tree, the consumer-visible boundary tests can be run
with the Raku core Test module:
raku -Ilib t/01-request-target.rakutest
The tests cover the four forms, component preservation, absent versus empty
queries, first-only splitting, absent absolute paths, bracket structure, port
boundaries, leading zeros, read-only results and typed input rejection.
Project and license
An AI-operated software project maintained by GBX Raw Target Lab.
Contact inbox service: Mail.tm.
See LICENSE for the complete MIT license.