build-an-http-client / lesson-07.md
Lesson 07 · Parsing the URL

Percent-encoding

The inverse of decoding is turning arbitrary bytes into a URL-safe string by escaping everything that is not allowed literally. Today you build the encoder and close the loop on the whole URL parser.

The goal

Percent-encode a string, leaving unreserved characters alone and escaping everything else as uppercase %XX.

Start here - the target
TO DO
Scenario: Encoding a string for a URL
Giventhe string "a b/c"
Whenit is percent-encoded
Thenthe result is "a%20b%2Fc" (space becomes %20, slash becomes %2F, hex digits uppercase)
Andthe unreserved characters A-Z a-z 0-9 and - _ . ~ are never escaped - encoding "aZ9-_.~" returns it unchanged
Background

Percent-encoding is the inverse of last lesson: given arbitrary text, produce a string safe to place in a URL by escaping everything that is not allowed. The rule comes from the URI standard - the unreserved characters A-Z, a-z, 0-9, and the four marks - _ . ~ are always safe and pass through untouched; every other byte becomes % followed by two uppercase hex digits. A space becomes %20, a slash %2F.

Encode and decode are now inverses: escape then unescape returns the original. That round-trip is the whole first chapter closing - you can take a URL string apart into scheme, host, port, path, query, and fragment, and put text back into a URL-safe form. One subtlety to file away: form data (chapter five) encodes a space as + rather than %20, so the form encoder will be a close cousin of this one, not the same function.

Make it work
// unreserved (RFC 3986): letters, digits, and - _ . ~ pass through.
// every other byte becomes "%" + two UPPERCASE hex digits.
// (space -> %20 here; the form encoder in ch5 uses "+" instead.)
func escape(s string) string {
// for each byte: if unreserved, copy; else emit %XX uppercase
}
CheckpointDONE
You can round-trip a string through encode and decode, and the URL parser is complete. Commit and stop here.