Host completeness for clj-http-lite: with-open/slurp on shims, charset, exc classes
Gaps the clj-http-lite suite hit running over jolt-lang/http-client: - with-open now closes a tagged-table stream shim via its .close method (was a :close field lookup that only matched the Janet-era tables). - slurp accepts a bytevector / jolt byte-array / a byte input-stream shim and honors :encoding — clj-http-lite slurps response bodies and :as :stream bodies. - (.getBytes s charset) and Charset/forName respect the charset (ISO-8859-1 etc., one byte per char), not always UTF-8; Charset/forName returns the name string. - (class e) reads the JVM :class off a throwable tagged-table, so clojure.test's (thrown? Class …) / (= Class (class e)) match a library's typed exceptions. - Registered the HTTP/IO exception class names (IOException, UnknownHostException, SocketTimeoutException, SSLException, …) so the FQ literals self-evaluate. All runtime .ss shims, no re-mint. Full gate green.
This commit is contained in:
parent
5bcfc629fc
commit
13aaf74c4b
5 changed files with 64 additions and 2 deletions
|
|
@ -49,7 +49,16 @@
|
||||||
("Charset" . "java.nio.charset.Charset") ("Base64" . "java.util.Base64")
|
("Charset" . "java.nio.charset.Charset") ("Base64" . "java.util.Base64")
|
||||||
("Exception" . "java.lang.Exception")
|
("Exception" . "java.lang.Exception")
|
||||||
("IllegalArgumentException" . "java.lang.IllegalArgumentException")
|
("IllegalArgumentException" . "java.lang.IllegalArgumentException")
|
||||||
|
("IllegalStateException" . "java.lang.IllegalStateException")
|
||||||
|
("RuntimeException" . "java.lang.RuntimeException")
|
||||||
|
("UnsupportedOperationException" . "java.lang.UnsupportedOperationException")
|
||||||
("InterruptedException" . "java.lang.InterruptedException")
|
("InterruptedException" . "java.lang.InterruptedException")
|
||||||
|
("IOException" . "java.io.IOException")
|
||||||
|
("UnknownHostException" . "java.net.UnknownHostException")
|
||||||
|
("ConnectException" . "java.net.ConnectException")
|
||||||
|
("SocketTimeoutException" . "java.net.SocketTimeoutException")
|
||||||
|
("MalformedURLException" . "java.net.MalformedURLException")
|
||||||
|
("SSLException" . "javax.net.ssl.SSLException")
|
||||||
("Throwable" . "java.lang.Throwable")))
|
("Throwable" . "java.lang.Throwable")))
|
||||||
(for-each
|
(for-each
|
||||||
(lambda (pair) (def-var! "clojure.core" (car pair) (cdr pair)))
|
(lambda (pair) (def-var! "clojure.core" (car pair) (cdr pair)))
|
||||||
|
|
@ -74,4 +83,11 @@
|
||||||
'("java.lang.Long" "java.lang.Integer" "java.lang.Double" "java.lang.Float"
|
'("java.lang.Long" "java.lang.Integer" "java.lang.Double" "java.lang.Float"
|
||||||
"java.lang.Number" "java.lang.String" "java.lang.Boolean" "java.lang.Character"
|
"java.lang.Number" "java.lang.String" "java.lang.Boolean" "java.lang.Character"
|
||||||
"java.lang.Object"
|
"java.lang.Object"
|
||||||
|
;; exception classes compared against (class e): (= java.net.SocketTimeoutException (class e))
|
||||||
|
"java.lang.Exception" "java.lang.Throwable" "java.lang.RuntimeException"
|
||||||
|
"java.lang.IllegalArgumentException" "java.lang.IllegalStateException"
|
||||||
|
"java.lang.UnsupportedOperationException" "java.io.IOException"
|
||||||
|
"java.net.UnknownHostException" "java.net.ConnectException"
|
||||||
|
"java.net.SocketTimeoutException" "java.net.MalformedURLException"
|
||||||
|
"javax.net.ssl.SSLException"
|
||||||
"clojure.lang.Keyword" "clojure.lang.Symbol" "clojure.lang.Ratio" "clojure.lang.Atom"))
|
"clojure.lang.Keyword" "clojure.lang.Symbol" "clojure.lang.Ratio" "clojure.lang.Atom"))
|
||||||
|
|
|
||||||
|
|
@ -583,7 +583,9 @@
|
||||||
(let loop ((l lst) (i 0)) (if (null? l) bv (begin (bytevector-u8-set! bv i (car l)) (loop (cdr l) (+ i 1)))))))
|
(let loop ((l lst) (i 0)) (if (null? l) bv (begin (bytevector-u8-set! bv i (car l)) (loop (cdr l) (+ i 1)))))))
|
||||||
(register-class-statics! "URLEncoder" (list (cons "encode" url-encode)))
|
(register-class-statics! "URLEncoder" (list (cons "encode" url-encode)))
|
||||||
(register-class-statics! "URLDecoder" (list (cons "decode" url-decode)))
|
(register-class-statics! "URLDecoder" (list (cons "decode" url-decode)))
|
||||||
(register-class-statics! "Charset" (list (cons "forName" (lambda (nm) (make-jhost "charset" (list (cons 'name nm)))))))
|
;; Charset/forName yields the canonical name STRING (not an opaque object) so it
|
||||||
|
;; threads straight into (.getBytes s cs) / (String. bytes cs), which take a name.
|
||||||
|
(register-class-statics! "Charset" (list (cons "forName" (lambda (nm) (jolt-str-render-one nm)))))
|
||||||
|
|
||||||
;; ---- Base64 (RFC 4648) ------------------------------------------------------
|
;; ---- Base64 (RFC 4648) ------------------------------------------------------
|
||||||
(define b64-alphabet "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/")
|
(define b64-alphabet "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/")
|
||||||
|
|
|
||||||
|
|
@ -176,3 +176,12 @@
|
||||||
((htable-sorted-set? obj) '("PersistentTreeSet" "Sorted" "IPersistentSet"
|
((htable-sorted-set? obj) '("PersistentTreeSet" "Sorted" "IPersistentSet"
|
||||||
"Set" "java.util.Set" "Collection" "IPersistentCollection" "Object"))
|
"Set" "java.util.Set" "Collection" "IPersistentCollection" "Object"))
|
||||||
(else (%h-value-host-tags obj)))))
|
(else (%h-value-host-tags obj)))))
|
||||||
|
|
||||||
|
;; (class e) on a throwable tagged-table (a library's ex-info envelope carrying a
|
||||||
|
;; JVM :class, e.g. jolt-lang/http-client's UnknownHostException) reads that
|
||||||
|
;; class name, so clojure.test's (thrown? Class …) / (= Class (class e)) match.
|
||||||
|
(define %h-class jolt-class)
|
||||||
|
(set! jolt-class (lambda (x)
|
||||||
|
(let ((c (and (htable? x) (hashtable-ref (htable-h x) "class" #f))))
|
||||||
|
(if (and c (string? c)) c (%h-class x)))))
|
||||||
|
(def-var! "clojure.core" "class" jolt-class)
|
||||||
|
|
|
||||||
|
|
@ -151,10 +151,32 @@
|
||||||
((reader-jhost? rdr) (drain-reader rdr))
|
((reader-jhost? rdr) (drain-reader rdr))
|
||||||
(else (jolt-str-render-one rdr))))))
|
(else (jolt-str-render-one rdr))))))
|
||||||
|
|
||||||
|
;; (slurp src :encoding "...") — pull the charset from the trailing kwargs.
|
||||||
|
(define (slurp-encoding opts)
|
||||||
|
(let loop ((o opts))
|
||||||
|
(cond ((or (null? o) (null? (cdr o))) '())
|
||||||
|
((and (keyword-t? (car o)) (string=? (keyword-t-name (car o)) "encoding"))
|
||||||
|
(list (jolt-str-render-one (cadr o))))
|
||||||
|
(else (loop (cddr o))))))
|
||||||
|
;; drain a byte input-stream shim (tagged-table) one byte at a time to a bytevector.
|
||||||
|
(define (drain-byte-stream src)
|
||||||
|
(let loop ((acc '()))
|
||||||
|
(let ((b (record-method-dispatch src "read" jolt-nil)))
|
||||||
|
(if (or (jolt-nil? b) (and (number? b) (< b 0)))
|
||||||
|
(u8-list->bytevector (reverse acc))
|
||||||
|
(loop (cons (bitwise-and (jnum->exact b) #xff) acc))))))
|
||||||
(define (jolt-slurp src . opts)
|
(define (jolt-slurp src . opts)
|
||||||
(cond
|
(cond
|
||||||
((jfile? src) (read-file-string (jfile-path src)))
|
((jfile? src) (read-file-string (jfile-path src)))
|
||||||
((reader-jhost? src) (drain-reader src))
|
((reader-jhost? src) (drain-reader src))
|
||||||
|
;; bytes (a bytevector or a jolt byte-array): decode with :encoding (UTF-8
|
||||||
|
;; default). clj-http-lite slurps response-body byte arrays.
|
||||||
|
((bytevector? src) (decode-bytevector src (slurp-encoding opts)))
|
||||||
|
((and (jolt-array? src) (eq? (jolt-array-kind src) 'byte))
|
||||||
|
(decode-bytevector (na-bytearray->bv src) (slurp-encoding opts)))
|
||||||
|
;; a byte input-stream shim (e.g. clj-http-lite's :as :stream body): drain it.
|
||||||
|
((and (htable? src) (jolt-truthy? (jolt-ref-get src (keyword "jolt" "input-stream"))))
|
||||||
|
(decode-bytevector (drain-byte-stream src) (slurp-encoding opts)))
|
||||||
((string? src) (read-file-string src))
|
((string? src) (read-file-string src))
|
||||||
(else (error #f "slurp: unsupported source" src))))
|
(else (error #f "slurp: unsupported source" src))))
|
||||||
|
|
||||||
|
|
@ -230,6 +252,9 @@
|
||||||
((jolt-nil? x) jolt-nil)
|
((jolt-nil? x) jolt-nil)
|
||||||
((and (jhost? x) (member (jhost-tag x) '("string-reader" "pushback-reader" "writer")))
|
((and (jhost? x) (member (jhost-tag x) '("string-reader" "pushback-reader" "writer")))
|
||||||
(record-method-dispatch x "close" jolt-nil) jolt-nil)
|
(record-method-dispatch x "close" jolt-nil) jolt-nil)
|
||||||
|
;; a library's stream shim (tagged-table) closes via its registered .close
|
||||||
|
;; method (a no-op for in-memory streams); absent method -> no-op.
|
||||||
|
((htable? x) (guard (e (#t jolt-nil)) (record-method-dispatch x "close" jolt-nil)) jolt-nil)
|
||||||
((jfile? x) jolt-nil)
|
((jfile? x) jolt-nil)
|
||||||
(else
|
(else
|
||||||
(let ((closef (jolt-get x (keyword #f "close") jolt-nil)))
|
(let ((closef (jolt-get x (keyword #f "close") jolt-nil)))
|
||||||
|
|
|
||||||
|
|
@ -117,7 +117,17 @@
|
||||||
(string=? (ascii-string-down s) (ascii-string-down (arg 0))))
|
(string=? (ascii-string-down s) (ascii-string-down (arg 0))))
|
||||||
((string=? method "compareTo")
|
((string=? method "compareTo")
|
||||||
(let ((o (arg 0))) (cond ((string<? s o) -1.0) ((string>? s o) 1.0) (else 0.0))))
|
(let ((o (arg 0))) (cond ((string<? s o) -1.0) ((string>? s o) 1.0) (else 0.0))))
|
||||||
((string=? method "getBytes") (string->utf8 s))
|
((string=? method "getBytes")
|
||||||
|
;; (.getBytes s) / (.getBytes s charset). UTF-8 default; ISO-8859-1/latin1/
|
||||||
|
;; ascii encode one byte per char (clj-http-lite's body-encoding path).
|
||||||
|
(if (null? rest)
|
||||||
|
(string->utf8 s)
|
||||||
|
(let ((cn (ascii-string-down (if (string? (arg 0)) (arg 0) (jolt-str-render-one (arg 0))))))
|
||||||
|
(if (member cn '("iso-8859-1" "latin1" "iso8859-1" "us-ascii" "ascii"))
|
||||||
|
(let* ((n (string-length s)) (bv (make-bytevector n)))
|
||||||
|
(do ((i 0 (+ i 1))) ((= i n) bv)
|
||||||
|
(bytevector-u8-set! bv i (bitwise-and (char->integer (string-ref s i)) #xff))))
|
||||||
|
(string->utf8 s)))))
|
||||||
((string=? method "matches") (if (irregex-match (str-irx (arg 0)) s) #t #f))
|
((string=? method "matches") (if (irregex-match (str-irx (arg 0)) s) #t #f))
|
||||||
((string=? method "replaceAll") (irregex-replace/all (str-irx (arg 0)) s (arg 1)))
|
((string=? method "replaceAll") (irregex-replace/all (str-irx (arg 0)) s (arg 1)))
|
||||||
((string=? method "replaceFirst") (irregex-replace (str-irx (arg 0)) s (arg 1)))
|
((string=? method "replaceFirst") (irregex-replace (str-irx (arg 0)) s (arg 1)))
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue