Improve support for headerless freezing (docs, error msgs, etc.)
This commit is contained in:
parent
e580fc6b2b
commit
5690a9611e
1 changed files with 48 additions and 31 deletions
|
|
@ -383,67 +383,83 @@
|
||||||
(defn- try-parse-header [ba]
|
(defn- try-parse-header [ba]
|
||||||
(when-let [[head-ba data-ba] (utils/ba-split ba 4)]
|
(when-let [[head-ba data-ba] (utils/ba-split ba 4)]
|
||||||
(let [[head-sig* [meta-id]] (utils/ba-split head-ba 3)]
|
(let [[head-sig* [meta-id]] (utils/ba-split head-ba 3)]
|
||||||
(when (utils/ba= head-sig* head-sig)
|
(when (utils/ba= head-sig* head-sig) ; Appears to be well-formed
|
||||||
[data-ba (head-meta meta-id {:unrecognized-header? true})]))))
|
[data-ba (head-meta meta-id {:unrecognized-meta? true})]))))
|
||||||
|
|
||||||
(defn thaw
|
(defn thaw
|
||||||
"Deserializes a frozen object from given byte array to its original Clojure
|
"Deserializes a frozen object from given byte array to its original Clojure
|
||||||
data type. Supports data frozen with current and all previous versions of
|
data type. By default[1] supports data frozen with current and all previous
|
||||||
Nippy. For custom types extend the Clojure reader or see `extend-thaw`."
|
versions of Nippy. For custom types extend the Clojure reader or see
|
||||||
[^bytes ba & [{:keys [password compressor encryptor headerless-opts]
|
`extend-thaw`.
|
||||||
:or {headerless-opts {:compressed? true}
|
|
||||||
compressor snappy-compressor
|
[1] :headerless-meta provides a fallback facility for data frozen without a
|
||||||
encryptor aes128-encryptor}
|
standard Nippy header (notably all Nippy v1 data). A default is provided for
|
||||||
|
Nippy v1 thaw compatibility, but it's recommended that you _disable_ this
|
||||||
|
fallback (`{:headerless-meta nil}`) if you're certain you won't be thawing
|
||||||
|
headerless data."
|
||||||
|
[^bytes ba & [{:keys [password compressor encryptor headerless-meta]
|
||||||
|
:or {compressor snappy-compressor
|
||||||
|
encryptor aes128-encryptor
|
||||||
|
headerless-meta ; Recommend set to nil when possible
|
||||||
|
{:version 1
|
||||||
|
:compressed? true
|
||||||
|
:encrypted? false}}
|
||||||
:as opts}]]
|
:as opts}]]
|
||||||
|
|
||||||
(let [;; headerless-opts may be nil, or contain any head-meta keys:
|
(let [headerless-meta (merge headerless-meta (:legacy-opts opts)) ; Deprecated
|
||||||
headerless-opts (merge headerless-opts (:legacy-opts opts)) ; Deprecated
|
|
||||||
ex (fn [msg & [e]] (throw (Exception. (str "Thaw failed: " msg) e)))
|
ex (fn [msg & [e]] (throw (Exception. (str "Thaw failed: " msg) e)))
|
||||||
try-thaw-data
|
try-thaw-data
|
||||||
(fn [data-ba {:keys [compressed? encrypted?] :as head-meta}]
|
(fn [data-ba {:keys [compressed? encrypted?] :as _head-or-headerless-meta}]
|
||||||
(let [password (when encrypted? password) ; => also head-meta
|
(let [password (when encrypted? password)
|
||||||
compressor (if head-meta
|
compressor (when compressed? compressor)]
|
||||||
(when compressed? compressor)
|
|
||||||
(when (:compressed? headerless-opts) snappy-compressor))]
|
|
||||||
(try
|
(try
|
||||||
(let [ba data-ba
|
(let [ba data-ba
|
||||||
ba (if password (encryption/decrypt encryptor password ba) ba)
|
ba (if password (encryption/decrypt encryptor password ba) ba)
|
||||||
ba (if compressor (compression/decompress compressor ba) ba)
|
ba (if compressor (compression/decompress compressor ba) ba)
|
||||||
stream (DataInputStream. (ByteArrayInputStream. ba))]
|
stream (DataInputStream. (ByteArrayInputStream. ba))]
|
||||||
|
|
||||||
(thaw-from-stream! stream))
|
(thaw-from-stream! stream))
|
||||||
|
|
||||||
(catch Exception e
|
(catch Exception e
|
||||||
(cond
|
(cond
|
||||||
password (ex "Wrong password/encryptor?" e)
|
password (if head-meta (ex "Wrong password/encryptor?" e)
|
||||||
|
(ex "Unencrypted data?" e))
|
||||||
compressor (if head-meta (ex "Encrypted data or wrong compressor?" e)
|
compressor (if head-meta (ex "Encrypted data or wrong compressor?" e)
|
||||||
(ex "Uncompressed data?" e))
|
(ex "Uncompressed data?" e))
|
||||||
:else (if head-meta (ex "Corrupt data?" e)
|
:else (if head-meta (ex "Corrupt data?" e)
|
||||||
(ex "Compressed data?" e)))))))]
|
(ex "Data may be unfrozen, corrupt, compressed &/or encrypted.")))))))]
|
||||||
|
|
||||||
(if-let [[data-ba {:keys [unrecognized-header? compressed? encrypted?]
|
(if-let [[data-ba {:keys [unrecognized-meta? compressed? encrypted?]
|
||||||
:as head-meta}] (try-parse-header ba)]
|
:as head-meta}] (try-parse-header ba)]
|
||||||
|
|
||||||
(cond ; Header _appears_ okay
|
(cond ; A well-formed header _appears_ to be present
|
||||||
(and (not headerless-opts) unrecognized-header?) ; Conservative
|
(and (not headerless-meta) ; Cautious. It's unlikely but possible the
|
||||||
(ex "Unrecognized header. Data frozen with newer Nippy version?")
|
; header sig match was a fluke and not an
|
||||||
|
; indication of a real, well-formed header.
|
||||||
|
; May really be headerless.
|
||||||
|
unrecognized-meta?)
|
||||||
|
(ex "Unrecognized (but apparently well-formed) header. Data frozen with newer Nippy version?")
|
||||||
|
|
||||||
|
;;; It's still possible below that the header match was a fluke, but it's
|
||||||
|
;;; _very_ unlikely. Therefore _not_ going to incl.
|
||||||
|
;;; `(not headerless-meta)` conditions below.
|
||||||
|
|
||||||
(and compressed? (not compressor))
|
(and compressed? (not compressor))
|
||||||
(ex "Compressed data. Try again with compressor.")
|
(ex "Compressed data? Try again with compressor.")
|
||||||
(and encrypted? (not password))
|
(and encrypted? (not password))
|
||||||
(if (::tools-thaw? opts) ::need-password
|
(if (::tools-thaw? opts) ::need-password
|
||||||
(ex "Encrypted data. Try again with password."))
|
(ex "Encrypted data? Try again with password."))
|
||||||
:else (try (try-thaw-data data-ba head-meta)
|
:else (try (try-thaw-data data-ba head-meta)
|
||||||
(catch Exception e
|
(catch Exception e
|
||||||
(if headerless-opts
|
(if headerless-meta
|
||||||
(try (try-thaw-data ba nil)
|
(try (try-thaw-data ba headerless-meta)
|
||||||
(catch Exception _
|
(catch Exception _
|
||||||
(throw e)))
|
(throw e)))
|
||||||
(throw e)))))
|
(throw e)))))
|
||||||
|
|
||||||
;; Header definitely not okay
|
;; Well-formed header definitely not present
|
||||||
(if headerless-opts
|
(if headerless-meta
|
||||||
(try-thaw-data ba nil)
|
(try-thaw-data ba headerless-meta)
|
||||||
(ex "Unfrozen or corrupt data?")))))
|
(ex "Data may be unfrozen, corrupt, compressed &/or encrypted.")))))
|
||||||
|
|
||||||
(comment (thaw (freeze "hello"))
|
(comment (thaw (freeze "hello"))
|
||||||
(thaw (freeze "hello" {:compressor nil}))
|
(thaw (freeze "hello" {:compressor nil}))
|
||||||
|
|
@ -624,4 +640,5 @@
|
||||||
[ba & {:keys [compressed?]
|
[ba & {:keys [compressed?]
|
||||||
:or {compressed? true}}]
|
:or {compressed? true}}]
|
||||||
(thaw ba {:headerless-opts {:compressed? compressed?}
|
(thaw ba {:headerless-opts {:compressed? compressed?}
|
||||||
|
:compressor snappy-compressor
|
||||||
:password nil}))
|
:password nil}))
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue