nix_compat/nix_http/
mod.rs1use tracing::trace;
2
3use crate::nixbase32;
4
5pub const MIME_TYPE_NAR: &str = "application/x-nix-nar";
7pub const MIME_TYPE_NARINFO: &str = "text/x-nix-narinfo";
9pub const MIME_TYPE_CACHE_INFO: &str = "text/x-nix-cache-info";
11
12pub fn parse_nar_str(s: &str) -> Option<([u8; 32], &str)> {
16 if !s.is_char_boundary(52) {
17 trace!("invalid string, no char boundary at 52");
18 return None;
19 }
20
21 let (hash_str, suffix) = s.split_at(52);
22
23 let hash_str_fixed: [u8; 52] = hash_str.as_bytes().try_into().unwrap();
25
26 match suffix.strip_prefix(".nar") {
27 Some(compression_suffix) => match nixbase32::decode_fixed(hash_str_fixed) {
28 Err(e) => {
29 trace!(err=%e, "invalid nixbase32 encoding");
30 None
31 }
32 Ok(digest) => Some((digest, compression_suffix)),
33 },
34 None => {
35 trace!("no .nar suffix");
36 None
37 }
38 }
39}
40
41pub fn parse_narinfo_str(s: &str) -> Option<[u8; 20]> {
44 if !s.is_char_boundary(32) {
45 trace!("invalid string, no char boundary at 32");
46 return None;
47 }
48
49 match s.split_at(32) {
50 (hash_str, ".narinfo") => {
51 let hash_str_fixed: [u8; 32] = hash_str.as_bytes().try_into().unwrap();
53
54 match nixbase32::decode_fixed(hash_str_fixed) {
55 Err(e) => {
56 trace!(err=%e, "invalid nixbase32 encoding");
57 None
58 }
59 Ok(digest) => Some(digest),
60 }
61 }
62 _ => {
63 trace!("invalid string, no .narinfo suffix");
64 None
65 }
66 }
67}
68
69#[cfg(test)]
70mod test {
71 use super::{parse_nar_str, parse_narinfo_str};
72 use hex_literal::hex;
73
74 #[test]
75 fn parse_nar_str_success() {
76 assert_eq!(
77 (
78 hex!("13a8cf7ca57f68a9f1752acee36a72a55187d3a954443c112818926f26109d91"),
79 ""
80 ),
81 parse_nar_str("14cx20k6z4hq508kqi2lm79qfld5f9mf7kiafpqsjs3zlmycza0k.nar").unwrap()
82 );
83
84 assert_eq!(
85 (
86 hex!("13a8cf7ca57f68a9f1752acee36a72a55187d3a954443c112818926f26109d91"),
87 ".xz"
88 ),
89 parse_nar_str("14cx20k6z4hq508kqi2lm79qfld5f9mf7kiafpqsjs3zlmycza0k.nar.xz").unwrap()
90 )
91 }
92
93 #[test]
94 fn parse_nar_str_failure() {
95 assert!(parse_nar_str("14cx20k6z4hq508kqi2lm79qfld5f9mf7kiafpqsjs3zlmycza0").is_none());
96 assert!(
97 parse_nar_str("14cx20k6z4hq508kqi2lm79qfld5f9mf7kiafpqsjs3zlmycza0š¦.nar").is_none()
98 )
99 }
100 #[test]
101 fn parse_narinfo_str_success() {
102 assert_eq!(
103 hex!("8a12321522fd91efbd60ebb2481af88580f61600"),
104 parse_narinfo_str("00bgd045z0d4icpbc2yyz4gx48ak44la.narinfo").unwrap()
105 );
106 }
107
108 #[test]
109 fn parse_narinfo_str_failure() {
110 assert!(parse_narinfo_str("00bgd045z0d4icpbc2yyz4gx48ak44la").is_none());
111 assert!(parse_narinfo_str("/00bgd045z0d4icpbc2yyz4gx48ak44la").is_none());
112 assert!(parse_narinfo_str("000000").is_none());
113 assert!(parse_narinfo_str("00bgd045z0d4icpbc2yyz4gx48ak44lš¦.narinfo").is_none());
114 }
115}