Filtering...

url-encode

books/std/strings/url-encode
other
(in-package "STR")
other
(include-book "cat")
other
(include-book "hex")
other
(include-book "std/util/defval" :dir :system)
other
(include-book "centaur/fty/fixequiv" :dir :system)
other
(include-book "centaur/fty/basetypes" :dir :system)
other
(local (include-book "std/lists/nthcdr" :dir :system))
other
(local (include-book "std/typed-lists/character-listp" :dir :system))
other
(local (add-default-post-define-hook :fix))
other
(defsection url-encoding
  :parents (std/strings)
  :short "Functions for % encoding strings for use in URLs, as described in <a
href='http://tools.ietf.org/html/rfc3986'>RFC 3986</a>."
  :long "<p>Per <a href='https://www.ietf.org/rfc/rfc3986.txt'>RFC 3986</a>,
the only unreserved characters are ALPHA, DIGIT, @('-'), @('.'), @('_'), and
@('~').  We implement some functions to percent-encode other characters in
character lists and strings.</p>")
other
(order-subtopics url-encoding
  (url-encode-string url-encode-chars
    url-encode-char))
other
(local (set-default-parents url-encoding))
other
(define url-encode-char
  ((x characterp))
  :short "URL encode a single character. (slow, logically nice version)."
  :returns (encoding character-listp
    "Encoded version of X, in proper order.")
  :long "<p>See @(see fast-url-encode-char) for an faster, array-lookup
  alternative.</p>"
  (b* ((x (char-fix x)) ((when (or (and (char<= #\A x) (char<= x #\Z))
           (and (char<= #\a x) (char<= x #\z))
           (and (char<= #\0 x) (char<= x #\9))
           (member x '(#\- #\_ #\. #\~)))) (list x))
      (hex-code (nat-to-hex-chars (char-code x)))
      (hex-code (if (eql (len hex-code) 1)
          (cons #\0 hex-code)
          hex-code)))
    (cons #\% hex-code)))
other
(define make-url-encode-array
  ((n natp))
  :parents (*url-encode-array*)
  :guard (<= n 255)
  :hooks nil
  (if (zp n)
    (list (cons n (url-encode-char (code-char n))))
    (cons (cons n (url-encode-char (code-char n)))
      (make-url-encode-array (- n 1)))))
other
(defval *url-encode-array*
  :short "Array binding character codes to the pre-computed URL encodings."
  :showval t
  (compress1 'url-encode-array
    (cons '(:header :dimensions (256)
        :maximum-length 257
        :name url-encode-array)
      (make-url-encode-array 255))))
other
(define fast-url-encode-char
  ((x :type character))
  :short "URL encode a single character. (fast, array-based version)"
  :inline t
  :enabled t
  :verify-guards nil
  :hooks nil
  (mbe :logic (url-encode-char x)
    :exec (aref1 'url-encode-array
      *url-encode-array*
      (char-code x)))
  ///
  (local (in-theory (disable aref1)))
  (local (defun test
      (n)
      (and (equal (aref1 'url-encode-array
            *url-encode-array*
            n)
          (url-encode-char (code-char n)))
        (if (zp n)
          t
          (test (- n 1))))))
  (local (defthm l0
      (implies (and (test n)
          (natp n)
          (natp i)
          (<= i n))
        (equal (aref1 'url-encode-array
            *url-encode-array*
            i)
          (url-encode-char (code-char i))))))
  (local (defthm l1
      (implies (and (natp i) (<= i 255))
        (equal (aref1 'url-encode-array
            *url-encode-array*
            i)
          (url-encode-char (code-char i))))
      :hints (("Goal" :use ((:instance l0 (n 255)))))))
  (local (defthm l2
      (implies (characterp x)
        (equal (aref1 'url-encode-array
            *url-encode-array*
            (char-code x))
          (url-encode-char x)))))
  (verify-guards fast-url-encode-char$inline))
other
(define url-encode-chars-aux
  ((chars character-listp) acc)
  :short "URL encode a list of characters onto an accumulator in reverse order."
  :returns (encoded character-listp
    :hyp (character-listp acc))
  (if (atom chars)
    acc
    (url-encode-chars-aux (cdr chars)
      (revappend (fast-url-encode-char (car chars))
        acc)))
  ///
  (defthm true-listp-of-url-encode-chars-aux
    (equal (true-listp (url-encode-chars-aux x acc))
      (true-listp acc))))
other
(define url-encode-chars
  ((x character-listp))
  :short "Simple way to URL encode a list of characters."
  :returns (encoded character-listp)
  :inline t
  (reverse (url-encode-chars-aux x nil))
  ///
  (defthm true-listp-of-url-encode-chars
    (true-listp (url-encode-chars x))
    :rule-classes :type-prescription))
other
(define url-encode-string-aux
  :short "Efficiently way to URL encode a string, in reverse order, without
  exploding it."
  ((x stringp) (n natp)
    (xl (eql xl (length x)))
    acc)
  :guard (<= n xl)
  :long "<p>This has such a nice logical definition that we just leave it enabled.</p>"
  :enabled t
  :verify-guards nil
  :hooks nil
  (mbe :logic (url-encode-chars-aux (nthcdr n (explode x))
      acc)
    :exec (b* (((when (mbe :logic (zp (- (nfix xl) (nfix n)))
            :exec (eql n xl))) acc) (char (char x n))
        (encoding (fast-url-encode-char char))
        (acc (revappend encoding acc)))
      (url-encode-string-aux x
        (+ 1 (lnfix n))
        xl
        acc)))
  ///
  (local (in-theory (enable url-encode-string-aux
        url-encode-chars-aux)))
  (verify-guards url-encode-string-aux))
other
(define url-encode-string
  :short "Simple way to URL encode a string."
  ((x stringp :type string))
  :returns (encoded stringp :rule-classes :type-prescription)
  :split-types t
  :inline t
  (let ((x (mbe :logic (str-fix x) :exec x)))
    (rchars-to-string (url-encode-string-aux x 0 (length x) nil))))