apr-0.3.4/.cargo_vcs_info.json0000644000000001360000000000100116220ustar { "git": { "sha1": "46ebe67c5c38b3bcfbddd097e078ae4516ceab0d" }, "path_in_vcs": "" }apr-0.3.4/.github/CODEOWNERS000064400000000000000000000000121046102023000133360ustar 00000000000000* @jelmer apr-0.3.4/.github/FUNDING.yml000064400000000000000000000000171046102023000135650ustar 00000000000000github: jelmer apr-0.3.4/.github/dependabot.yml000064400000000000000000000006251046102023000146050ustar 00000000000000# Please see the documentation for all configuration options: # https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates version: 2 updates: - package-ecosystem: "cargo" directory: "/" schedule: interval: "weekly" rebase-strategy: "disabled" - package-ecosystem: "github-actions" directory: "/" schedule: interval: weekly apr-0.3.4/.github/workflows/publish.yaml000064400000000000000000000012211046102023000163350ustar 00000000000000on: push: tags: - 'v*' # Push events to every tag not containing / workflow_dispatch: name: Publish jobs: publish: name: Publish runs-on: ubuntu-latest steps: - name: Checkout sources uses: actions/checkout@v5 - name: Install apr run: sudo apt install -y libapr1-dev libaprutil1-dev libutf8proc-dev - name: Install stable toolchain uses: actions-rs/toolchain@v1 with: profile: minimal toolchain: stable override: true - run: cargo publish --token ${CRATES_TOKEN} env: CRATES_TOKEN: ${{ secrets.CRATES_TOKEN }} apr-0.3.4/.github/workflows/rust.yml000064400000000000000000000017251046102023000155340ustar 00000000000000name: Rust on: push: branches: [ "master" ] pull_request: branches: [ "master" ] env: CARGO_TERM_COLOR: always jobs: build: strategy: matrix: os: [ubuntu-latest, macos-latest] runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v5 - name: Install apr run: sudo apt install -y libapr1-dev libaprutil1-dev libutf8proc-dev if: "matrix.os == 'ubuntu-latest'" - name: Install apr (Mac OS) run: | brew install apr-util apr pkg-config utf8proc echo "$(brew --prefix)/opt/pkg-config/bin" >> $GITHUB_PATH echo "PKG_CONFIG_PATH=/opt/homebrew/opt/apr-util/lib/pkgconfig:/opt/homebrew/opt/apr/lib/pkgconfig" >> $GITHUB_ENV pkg-config --list-all if: "matrix.os == 'macos-latest'" - name: Build run: cargo build --verbose - name: Run tests run: cargo test --verbose - name: Run tests with all features run: cargo test --all-features --verbose apr-0.3.4/.gitignore000064400000000000000000000000131046102023000123740ustar 00000000000000/target *~ apr-0.3.4/Cargo.lock0000644000000430030000000000100075750ustar # This file is automatically @generated by Cargo. # It is not intended for manual editing. version = 4 [[package]] name = "aho-corasick" version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" dependencies = [ "memchr", ] [[package]] name = "apr" version = "0.3.4" dependencies = [ "apr-sys", "ctor", "url", ] [[package]] name = "apr-sys" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "edccb3d92ae38dd713e46ea192cf3a2fb3ffa387817691816cef9a3b5ebb8b7c" dependencies = [ "bindgen", "system-deps", ] [[package]] name = "bindgen" version = "0.72.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "993776b509cfb49c750f11b8f07a46fa23e0a1386ffc01fb1e7d343efc387895" dependencies = [ "bitflags", "cexpr", "clang-sys", "itertools", "log", "prettyplease", "proc-macro2", "quote", "regex", "rustc-hash", "shlex", "syn", ] [[package]] name = "bitflags" version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" [[package]] name = "cexpr" version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" dependencies = [ "nom", ] [[package]] name = "cfg-expr" version = "0.20.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9acd0bdbbf4b2612d09f52ba61da432140cb10930354079d0d53fafc12968726" dependencies = [ "smallvec", "target-lexicon", ] [[package]] name = "cfg-if" version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" [[package]] name = "clang-sys" version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4" dependencies = [ "glob", "libc", "libloading", ] [[package]] name = "ctor" version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3ffc71fcdcdb40d6f087edddf7f8f1f8f79e6cf922f555a9ee8779752d4819bd" dependencies = [ "ctor-proc-macro", "dtor", ] [[package]] name = "ctor-proc-macro" version = "0.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "52560adf09603e58c9a7ee1fe1dcb95a16927b17c127f0ac02d6e768a0e25bc1" [[package]] name = "displaydoc" version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "dtor" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "404d02eeb088a82cfd873006cb713fe411306c7d182c344905e101fb1167d301" dependencies = [ "dtor-proc-macro", ] [[package]] name = "dtor-proc-macro" version = "0.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f678cf4a922c215c63e0de95eb1ff08a958a81d47e485cf9da1e27bf6305cfa5" [[package]] name = "either" version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" [[package]] name = "equivalent" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" [[package]] name = "form_urlencoded" version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" dependencies = [ "percent-encoding", ] [[package]] name = "glob" version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" [[package]] name = "hashbrown" version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5419bdc4f6a9207fbeba6d11b604d481addf78ecd10c11ad51e76c2f6482748d" [[package]] name = "heck" version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" [[package]] name = "icu_collections" version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4c6b649701667bbe825c3b7e6388cb521c23d88644678e83c0c4d0a621a34b43" dependencies = [ "displaydoc", "potential_utf", "yoke", "zerofrom", "zerovec", ] [[package]] name = "icu_locale_core" version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "edba7861004dd3714265b4db54a3c390e880ab658fec5f7db895fae2046b5bb6" dependencies = [ "displaydoc", "litemap", "tinystr", "writeable", "zerovec", ] [[package]] name = "icu_normalizer" version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5f6c8828b67bf8908d82127b2054ea1b4427ff0230ee9141c54251934ab1b599" dependencies = [ "icu_collections", "icu_normalizer_data", "icu_properties", "icu_provider", "smallvec", "zerovec", ] [[package]] name = "icu_normalizer_data" version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7aedcccd01fc5fe81e6b489c15b247b8b0690feb23304303a9e560f37efc560a" [[package]] name = "icu_properties" version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e93fcd3157766c0c8da2f8cff6ce651a31f0810eaa1c51ec363ef790bbb5fb99" dependencies = [ "icu_collections", "icu_locale_core", "icu_properties_data", "icu_provider", "zerotrie", "zerovec", ] [[package]] name = "icu_properties_data" version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "02845b3647bb045f1100ecd6480ff52f34c35f82d9880e029d329c21d1054899" [[package]] name = "icu_provider" version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "85962cf0ce02e1e0a629cc34e7ca3e373ce20dda4c4d7294bbd0bf1fdb59e614" dependencies = [ "displaydoc", "icu_locale_core", "writeable", "yoke", "zerofrom", "zerotrie", "zerovec", ] [[package]] name = "idna" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" dependencies = [ "idna_adapter", "smallvec", "utf8_iter", ] [[package]] name = "idna_adapter" version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" dependencies = [ "icu_normalizer", "icu_properties", ] [[package]] name = "indexmap" version = "2.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6717a8d2a5a929a1a2eb43a12812498ed141a0bcfb7e8f7844fbdbe4303bba9f" dependencies = [ "equivalent", "hashbrown", ] [[package]] name = "itertools" version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" dependencies = [ "either", ] [[package]] name = "libc" version = "0.2.177" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976" [[package]] name = "libloading" version = "0.8.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d7c4b02199fee7c5d21a5ae7d8cfa79a6ef5bb2fc834d6e9058e89c825efdc55" dependencies = [ "cfg-if", "windows-link", ] [[package]] name = "litemap" version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6373607a59f0be73a39b6fe456b8192fcc3585f602af20751600e974dd455e77" [[package]] name = "log" version = "0.4.28" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432" [[package]] name = "memchr" version = "2.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" [[package]] name = "minimal-lexical" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] name = "nom" version = "7.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" dependencies = [ "memchr", "minimal-lexical", ] [[package]] name = "percent-encoding" version = "2.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" [[package]] name = "pkg-config" version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" [[package]] name = "potential_utf" version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b73949432f5e2a09657003c25bca5e19a0e9c84f8058ca374f49e0ebe605af77" dependencies = [ "zerovec", ] [[package]] name = "prettyplease" version = "0.2.37" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" dependencies = [ "proc-macro2", "syn", ] [[package]] name = "proc-macro2" version = "1.0.103" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8" dependencies = [ "unicode-ident", ] [[package]] name = "quote" version = "1.0.41" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ce25767e7b499d1b604768e7cde645d14cc8584231ea6b295e9c9eb22c02e1d1" dependencies = [ "proc-macro2", ] [[package]] name = "regex" version = "1.12.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "843bc0191f75f3e22651ae5f1e72939ab2f72a4bc30fa80a066bd66edefc24d4" dependencies = [ "aho-corasick", "memchr", "regex-automata", "regex-syntax", ] [[package]] name = "regex-automata" version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5276caf25ac86c8d810222b3dbb938e512c55c6831a10f3e6ed1c93b84041f1c" dependencies = [ "aho-corasick", "memchr", "regex-syntax", ] [[package]] name = "regex-syntax" version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58" [[package]] name = "rustc-hash" version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" [[package]] name = "serde" version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" dependencies = [ "serde_core", "serde_derive", ] [[package]] name = "serde_core" version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "serde_spanned" version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e24345aa0fe688594e73770a5f6d1b216508b4f93484c0026d521acd30134392" dependencies = [ "serde_core", ] [[package]] name = "shlex" version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" [[package]] name = "smallvec" version = "1.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" [[package]] name = "stable_deref_trait" version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" [[package]] name = "syn" version = "2.0.108" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "da58917d35242480a05c2897064da0a80589a2a0476c9a3f2fdc83b53502e917" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] [[package]] name = "synstructure" version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "system-deps" version = "7.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "48c8f33736f986f16d69b6cb8b03f55ddcad5c41acc4ccc39dd88e84aa805e7f" dependencies = [ "cfg-expr", "heck", "pkg-config", "toml", "version-compare", ] [[package]] name = "target-lexicon" version = "0.13.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df7f62577c25e07834649fc3b39fafdc597c0a3527dc1c60129201ccfcbaa50c" [[package]] name = "tinystr" version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42d3e9c45c09de15d06dd8acf5f4e0e399e85927b7f00711024eb7ae10fa4869" dependencies = [ "displaydoc", "zerovec", ] [[package]] name = "toml" version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0dc8b1fb61449e27716ec0e1bdf0f6b8f3e8f6b05391e8497b8b6d7804ea6d8" dependencies = [ "indexmap", "serde_core", "serde_spanned", "toml_datetime", "toml_parser", "toml_writer", "winnow", ] [[package]] name = "toml_datetime" version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f2cdb639ebbc97961c51720f858597f7f24c4fc295327923af55b74c3c724533" dependencies = [ "serde_core", ] [[package]] name = "toml_parser" version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c0cbe268d35bdb4bb5a56a2de88d0ad0eb70af5384a99d648cd4b3d04039800e" dependencies = [ "winnow", ] [[package]] name = "toml_writer" version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df8b2b54733674ad286d16267dcfc7a71ed5c776e4ac7aa3c3e2561f7c637bf2" [[package]] name = "unicode-ident" version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" [[package]] name = "url" version = "2.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08bc136a29a3d1758e07a9cca267be308aeebf5cfd5a10f3f67ab2097683ef5b" dependencies = [ "form_urlencoded", "idna", "percent-encoding", "serde", ] [[package]] name = "utf8_iter" version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" [[package]] name = "version-compare" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "03c2856837ef78f57382f06b2b8563a2f512f7185d732608fd9176cb3b8edf0e" [[package]] name = "windows-link" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" [[package]] name = "winnow" version = "0.7.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "21a0236b59786fed61e2a80582dd500fe61f18b5dca67a4a067d0bc9039339cf" [[package]] name = "writeable" version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9edde0db4769d2dc68579893f2306b26c6ecfbe0ef499b013d731b7b9247e0b9" [[package]] name = "yoke" version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72d6e5c6afb84d73944e5cedb052c4680d5657337201555f9f2a16b7406d4954" dependencies = [ "stable_deref_trait", "yoke-derive", "zerofrom", ] [[package]] name = "yoke-derive" version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d" dependencies = [ "proc-macro2", "quote", "syn", "synstructure", ] [[package]] name = "zerofrom" version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" dependencies = [ "zerofrom-derive", ] [[package]] name = "zerofrom-derive" version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" dependencies = [ "proc-macro2", "quote", "syn", "synstructure", ] [[package]] name = "zerotrie" version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2a59c17a5562d507e4b54960e8569ebee33bee890c70aa3fe7b97e85a9fd7851" dependencies = [ "displaydoc", "yoke", "zerofrom", ] [[package]] name = "zerovec" version = "0.11.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c28719294829477f525be0186d13efa9a3c602f7ec202ca9e353d310fb9a002" dependencies = [ "yoke", "zerofrom", "zerovec-derive", ] [[package]] name = "zerovec-derive" version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3" dependencies = [ "proc-macro2", "quote", "syn", ] apr-0.3.4/Cargo.toml0000644000000025020000000000100076170ustar # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies. # # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2021" name = "apr" version = "0.3.4" authors = ["Jelmer Vernooij "] build = false autolib = false autobins = false autoexamples = false autotests = false autobenches = false description = "Rust bindings for Apache Portable Runtime" homepage = "https://github.com/jelmer/apr-rs" documentation = "https://docs.rs/apr" readme = "README.md" license = "Apache-2.0" repository = "https://github.com/jelmer/apr-rs.git" [features] pool-debug = ["apr-sys/pool-debug"] url = ["dep:url"] [lib] name = "apr" path = "src/lib.rs" doctest = false [[example]] name = "basic_usage" path = "examples/basic_usage.rs" [[example]] name = "c_library_integration" path = "examples/c_library_integration.rs" [dependencies.apr-sys] version = "0.2.1" [dependencies.ctor] version = "0.6" [dependencies.url] version = "2" optional = true [build-dependencies] apr-0.3.4/Cargo.toml.orig000064400000000000000000000011241046102023000132770ustar 00000000000000[workspace] members = [".", "apr-sys"] [package] name = "apr" version = "0.3.4" edition = "2021" authors = ["Jelmer Vernooij "] repository = "https://github.com/jelmer/apr-rs.git" homepage = "https://github.com/jelmer/apr-rs" license = "Apache-2.0" description = "Rust bindings for Apache Portable Runtime" documentation = "https://docs.rs/apr" [lib] doctest = false [dependencies] apr-sys = { version = "0.2.1", path = "apr-sys" } ctor = "0.6" url = { version = "2", optional = true } [features] url = ["dep:url"] pool-debug = ["apr-sys/pool-debug"] [build-dependencies] apr-0.3.4/README.md000064400000000000000000000140361046102023000116750ustar 00000000000000# apr-rs Rust bindings for the Apache Portable Runtime (APR) library and the associated APR-Util library. [![Crates.io](https://img.shields.io/crates/v/apr.svg)](https://crates.io/crates/apr) [![Documentation](https://docs.rs/apr/badge.svg)](https://docs.rs/apr) [![License](https://img.shields.io/badge/license-Apache%202.0-blue.svg)](LICENSE) ## Overview This crate provides safe Rust bindings to the Apache Portable Runtime (APR), a C library that forms the foundation of the Apache HTTP Server and other Apache projects. APR provides a predictable and consistent interface to underlying platform-specific implementations for: - Memory management and pool allocation - File and network I/O - Process and thread management - Time handling - String manipulation - Data structures (hash tables, arrays, etc.) - Cryptographic functions ## Primary Use Case: C Library Interoperability **This crate is primarily useful when developing Rust bindings for C libraries that depend on APR.** Many Apache projects and other C libraries use APR for cross-platform compatibility and memory management. If you're creating Rust bindings for such libraries, this crate provides the necessary APR functionality with a safe Rust interface. ### Examples of C libraries that use APR: - Apache HTTP Server modules - Subversion (SVN) libraries - Apache Serf - Any custom C library built on top of APR ## Features - **Safe Rust API**: Wraps APR's C API with safe Rust abstractions - **Memory pools**: APR's hierarchical memory management system - **Cross-platform**: Inherits APR's platform abstraction layer - **Comprehensive coverage**: Bindings for most commonly-used APR and APR-Util functionality ## Installation Add this to your `Cargo.toml`: ```toml [dependencies] apr = "0.3" ``` ### Prerequisites You need to have APR and APR-Util installed on your system: #### Ubuntu/Debian ```bash sudo apt-get install libapr1-dev libaprutil1-dev ``` #### Fedora/RHEL/CentOS ```bash sudo dnf install apr-devel apr-util-devel ``` #### macOS (using Homebrew) ```bash brew install apr apr-util ``` #### Building from source If you need to build APR from source, download it from the [Apache APR website](https://apr.apache.org/). ## Usage Examples ### Basic Pool Usage APR uses memory pools for all memory allocation. This is fundamental when working with APR-based C libraries: ```rust use apr::Pool; fn main() -> apr::Result<()> { // Create a root memory pool let pool = Pool::new(); // Pools can have child pools for hierarchical memory management let subpool = pool.create_subpool()?; // Memory allocated from pools is automatically freed when the pool is dropped Ok(()) } ``` ### Working with APR-based C Libraries When creating bindings for C libraries that use APR, you'll typically need to: 1. Initialize APR (handled automatically by this crate) 2. Create memory pools for the C library to use 3. Pass APR types between Rust and C Example of integrating with a hypothetical APR-based C library: ```rust use apr::{Pool, Status}; use std::ptr; // Hypothetical C library that uses APR extern "C" { fn some_c_function(pool: *mut apr_sys::apr_pool_t) -> apr_sys::apr_status_t; } fn main() -> apr::Result<()> { let pool = Pool::new(); // Get raw APR pool pointer to pass to C functions let status = unsafe { Status::from(some_c_function(pool.as_mut_ptr())) }; if status.is_success() { println!("C function succeeded!"); } else { return Err(status.into()); } Ok(()) } ``` ### File Operations ```rust use apr::{Pool, file::File}; fn main() -> apr::Result<()> { let pool = Pool::new(); // Open a file using APR let file = File::open("example.txt", apr::file::Flag::READ, 0, &pool)?; // Read file contents let mut buffer = vec![0u8; 1024]; let bytes_read = file.read(&mut buffer)?; println!("Read {} bytes", bytes_read); Ok(()) } ``` ### Hash Tables ```rust use apr::{Pool, hash::Hash}; fn main() -> apr::Result<()> { let pool = Pool::new(); // Create a hash table let mut hash = Hash::::new(&pool); // Insert key-value pairs hash.set("key1", "value1".to_string()); hash.set("key2", "value2".to_string()); // Retrieve values if let Some(value) = hash.get("key1") { println!("Found: {}", value); } Ok(()) } ``` ## Module Organization The crate is organized into modules that mirror APR's structure: - `pool` - Memory pool management - `file` - File I/O operations - `network` - Network I/O and socket operations - `hash` - Hash table implementation - `tables` - APR table (ordered key-value pairs) - `strings` - String manipulation utilities - `time` - Time handling functions - `error` - Error handling and status codes - `crypto` - Cryptographic functions (MD5, SHA1, etc.) - `base64` - Base64 encoding/decoding - `uri` - URI parsing and manipulation - `uuid` - UUID generation - `xml` - XML parsing utilities ## Safety This crate aims to provide safe Rust abstractions over APR's C API. However, when interfacing with C libraries: - Some operations require `unsafe` blocks when dealing with raw pointers - The crate handles APR initialization automatically using Rust's standard library features - Memory management through pools helps prevent memory leaks - Rust's ownership system is leveraged to ensure proper resource cleanup ## Contributing Contributions are welcome! Please feel free to submit pull requests or open issues for bugs and feature requests. When contributing, please: - Add tests for new functionality - Update documentation as needed - Follow Rust naming conventions and idioms - Ensure all tests pass with `cargo test` ## License This project is licensed under the Apache License 2.0 - see the [LICENSE](LICENSE) file for details. ## Related Projects - [apr-sys](https://crates.io/crates/apr-sys) - Low-level FFI bindings to APR (used by this crate) - [Apache APR](https://apr.apache.org/) - The underlying C library ## Support For questions and discussions, please use the GitHub issues tracker.apr-0.3.4/disperse.conf000064400000000000000000000001171046102023000130760ustar 00000000000000# See https://github.com/jelmer/disperse timeout_days: 5 tag_name: "v$VERSION" apr-0.3.4/examples/basic_usage.rs000064400000000000000000000036131046102023000150460ustar 00000000000000//! Basic usage examples for the apr-rs crate. //! //! This example demonstrates fundamental APR concepts that are essential //! when working with APR-based C libraries. use apr::hash::{Hash, TypedHash}; use apr::tables::StringTable; use apr::{Pool, Result, Status}; use std::ffi::c_void; fn main() -> Result<()> { // Memory Pools - The foundation of APR memory management let root_pool = Pool::new(); let subpool = Pool::new(); let _pool_ptr = root_pool.as_mut_ptr(); // Raw pointer for C interop drop(subpool); // Subpool cleaned up // Hash Tables - using TypedHash for string keys and values let config_path = "/etc/myapp.conf".to_string(); let log_level = "debug".to_string(); let port = "8080".to_string(); let mut hash = TypedHash::new(&root_pool); hash.insert_ref("config_path", &config_path); hash.insert_ref("log_level", &log_level); hash.insert_ref("port", &port); if let Some(path) = hash.get_ref("config_path") { println!("Config path: {}", path); } // Raw Hash example - stores raw pointers let mut raw_hash = Hash::new(&root_pool); unsafe { raw_hash.insert(b"key1", &config_path as *const _ as *mut c_void); if let Some(ptr) = raw_hash.get(b"key1") { let value = &*(ptr as *const String); println!("Raw hash value: {}", value); } } // APR Tables (allows duplicate keys) - using StringTable for convenience let mut table = StringTable::new(&root_pool, 10); table.set("Content-Type", "text/html"); table.add("Cache-Control", "no-cache"); if let Some(content_type) = table.get("Content-Type") { println!("Content-Type: {}", content_type); } // Error Handling let error_status = Status::from(apr_sys::APR_ENOENT as i32); if !error_status.is_success() { println!("Error: {}", apr::Error::from(error_status)); } Ok(()) } apr-0.3.4/examples/c_library_integration.rs000064400000000000000000000121041046102023000171450ustar 00000000000000//! Example demonstrating how to use apr-rs when creating bindings for C libraries that use APR. //! //! This example shows the typical pattern for integrating with APR-based C libraries: //! 1. Creating APR memory pools //! 2. Passing APR types to C functions //! 3. Handling APR status codes //! 4. Managing memory lifecycle use apr::{Pool, Result, Status}; use std::ffi::CString; // Example: Simulating bindings for a hypothetical C library that uses APR // In a real scenario, these would be actual FFI declarations to your C library #[allow(dead_code)] mod ffi { use std::os::raw::{c_char, c_int}; // Simulated C function signatures that would come from your C library // In reality, these would be: // extern "C" { // pub fn library_init(pool: *mut apr_sys::apr_pool_t) -> apr_sys::apr_status_t; // pub fn library_process_data( // data: *const c_char, // len: c_int, // pool: *mut apr_sys::apr_pool_t // ) -> apr_sys::apr_status_t; // pub fn library_cleanup(pool: *mut apr_sys::apr_pool_t) -> apr_sys::apr_status_t; // } // For this example, we'll simulate these functions pub unsafe fn library_init(_pool: *mut apr_sys::apr_pool_t) -> apr_sys::apr_status_t { 0 // APR_SUCCESS } pub unsafe fn library_process_data( _data: *const c_char, _len: c_int, _pool: *mut apr_sys::apr_pool_t, ) -> apr_sys::apr_status_t { 0 // APR_SUCCESS } pub unsafe fn library_cleanup(_pool: *mut apr_sys::apr_pool_t) -> apr_sys::apr_status_t { 0 // APR_SUCCESS } } /// Wrapper struct for our C library pub struct CLibraryWrapper { pool: Pool, } impl CLibraryWrapper { /// Initialize the C library with its own memory pool pub fn new() -> Result { // Create a dedicated pool for this library instance let pool = Pool::new(); // Initialize the C library let status = unsafe { Status::from(ffi::library_init(pool.as_mut_ptr())) }; if !status.is_success() { return Err(status.into()); } Ok(CLibraryWrapper { pool }) } /// Process data using the C library pub fn process_data(&self, data: &str) -> Result<()> { // Convert Rust string to C string let c_data = CString::new(data) .map_err(|_| apr::Error::from(Status::from(apr_sys::APR_EINVAL as i32)))?; // Call the C function let status = unsafe { Status::from(ffi::library_process_data( c_data.as_ptr(), data.len() as i32, self.pool.as_mut_ptr(), )) }; if status.is_success() { Ok(()) } else { Err(status.into()) } } /// Create a sub-operation with its own memory scope pub fn scoped_operation(&self, operation: F) -> Result where F: FnOnce(&Pool) -> Result, { // Create a subpool for this operation let subpool = Pool::new(); // Execute the operation with the subpool // Subpool is automatically cleaned up when dropped operation(&subpool) } } impl Drop for CLibraryWrapper { fn drop(&mut self) { // Clean up the C library unsafe { let _ = ffi::library_cleanup(self.pool.as_mut_ptr()); } // Pool is automatically cleaned up when dropped } } fn main() -> Result<()> { println!("Demonstrating C library integration with APR...\n"); // Initialize our wrapped C library let library = CLibraryWrapper::new()?; println!("✓ C library initialized with APR pool"); // Process some data library.process_data("Hello from Rust!")?; println!("✓ Processed data through C library"); // Demonstrate scoped memory management library.scoped_operation(|subpool| { println!("✓ Created subpool for scoped operation"); // In a real scenario, you might pass this subpool to C functions // that need temporary memory let _subpool_ptr = subpool.as_mut_ptr(); // Simulate some work... println!(" Performing work with subpool..."); Ok(()) })?; println!("✓ Subpool automatically cleaned up"); // Demonstrate error handling match library.process_data("Another message") { Ok(()) => println!("✓ Successfully processed second message"), Err(e) => eprintln!("✗ Error processing message: {}", e), } println!("\n✓ Library will be cleaned up when dropped"); Ok(()) } #[cfg(test)] mod tests { use super::*; #[test] fn test_library_lifecycle() { // Test that we can create and destroy the library wrapper let library = CLibraryWrapper::new().expect("Failed to create library"); drop(library); } #[test] fn test_scoped_operations() { let library = CLibraryWrapper::new().expect("Failed to create library"); let result = library.scoped_operation(|_pool| { // Simulate some operation Ok(42) }); assert_eq!(result.unwrap(), 42); } } apr-0.3.4/src/base64.rs000064400000000000000000000077101046102023000126400ustar 00000000000000//! Base64 encoding and decoding functionality from apr-util. use crate::{Error, Status}; use std::ffi::c_char; use std::ffi::CString; /// Get the length of the encoded base64 string for a given input length. pub fn base64_encode_len(len: usize) -> usize { unsafe { apr_sys::apr_base64_encode_len(len as i32) as usize } } /// Get the maximum length of the decoded data for a given base64 string. pub fn base64_decode_len(encoded: &str) -> usize { let c_str = match CString::new(encoded) { Ok(s) => s, Err(_) => return 0, }; unsafe { apr_sys::apr_base64_decode_len(c_str.as_ptr()) as usize } } /// Encode binary data to base64. pub fn base64_encode(data: &[u8]) -> String { let encoded_len = base64_encode_len(data.len()); let mut encoded = vec![0u8; encoded_len]; unsafe { apr_sys::apr_base64_encode_binary( encoded.as_mut_ptr() as *mut c_char, data.as_ptr(), data.len() as i32, ); } // Remove trailing null terminator encoded.truncate(encoded_len - 1); String::from_utf8(encoded).unwrap_or_default() } /// Encode a string to base64. pub fn base64_encode_string(s: &str) -> String { base64_encode(s.as_bytes()) } /// Decode a base64 string to binary data. pub fn base64_decode(encoded: &str) -> Result, Error> { let c_str = CString::new(encoded) .map_err(|_| Error::from_status(Status::from(apr_sys::APR_EINVAL as i32)))?; let decoded_len = base64_decode_len(encoded); if decoded_len == 0 { return Ok(Vec::new()); } let mut decoded = vec![0u8; decoded_len]; let actual_len = unsafe { apr_sys::apr_base64_decode_binary(decoded.as_mut_ptr(), c_str.as_ptr()) }; if actual_len < 0 { Err(Error::from_status(Status::from(apr_sys::APR_EINVAL as i32))) } else { decoded.truncate(actual_len as usize); Ok(decoded) } } /// Decode a base64 string to a UTF-8 string. pub fn base64_decode_string(encoded: &str) -> Result { let decoded = base64_decode(encoded)?; String::from_utf8(decoded) .map_err(|_| Error::from_status(Status::from(apr_sys::APR_EINVAL as i32))) } #[cfg(test)] mod tests { use super::*; #[test] fn test_base64_encode_empty() { assert_eq!(base64_encode(b""), ""); } #[test] fn test_base64_encode_hello() { assert_eq!(base64_encode(b"Hello, World!"), "SGVsbG8sIFdvcmxkIQ=="); } #[test] fn test_base64_encode_binary() { let data = vec![0xFF, 0x00, 0xAB, 0xCD, 0xEF]; let encoded = base64_encode(&data); assert!(!encoded.is_empty()); } #[test] fn test_base64_decode_hello() { let decoded = base64_decode("SGVsbG8sIFdvcmxkIQ==").unwrap(); assert_eq!(decoded, b"Hello, World!"); } #[test] fn test_base64_round_trip() { let original = b"The quick brown fox jumps over the lazy dog"; let encoded = base64_encode(original); let decoded = base64_decode(&encoded).unwrap(); assert_eq!(decoded, original); } #[test] fn test_base64_string_round_trip() { let original = "Hello, 世界! 🦀"; let encoded = base64_encode_string(original); let decoded = base64_decode_string(&encoded).unwrap(); assert_eq!(decoded, original); } #[test] fn test_base64_decode_invalid() { // Invalid base64 - APR may not validate input strictly let result = base64_decode("!@#$%^&*()"); // Some APR implementations may decode what they can, so we just check it doesn't crash let _ = result; } #[test] fn test_base64_encode_len() { assert_eq!(base64_encode_len(0), 1); // Just null terminator assert_eq!(base64_encode_len(1), 5); // 4 chars + null assert_eq!(base64_encode_len(2), 5); // 4 chars + null assert_eq!(base64_encode_len(3), 5); // 4 chars + null assert_eq!(base64_encode_len(4), 9); // 8 chars + null } } apr-0.3.4/src/callbacks.rs000064400000000000000000000030141046102023000134640ustar 00000000000000//! Callback support infrastructure for C callbacks with Rust closures. //! //! This module provides safe abstractions for passing Rust closures to C functions //! that expect callback function pointers with void* baton parameters. use std::ffi::c_void; /// Simple wrapper for passing Rust closures as C callbacks. /// /// Boxes the closure and provides the pointer as a baton. pub struct CallbackHandle { boxed: Box, } impl CallbackHandle { /// Create a new callback handle from a closure pub fn new(callback: F) -> Self { CallbackHandle { boxed: Box::new(callback), } } /// Get the baton pointer to pass to C functions pub fn baton(&self) -> *mut c_void { &*self.boxed as *const F as *mut c_void } } // Example of how to create extern "C" trampolines for callbacks: // // type CancelFn = dyn FnMut() -> bool; // // extern "C" fn cancel_trampoline(baton: *mut c_void) -> i32 { // if baton.is_null() { // return 0; // } // unsafe { // let cancel_fn = &mut *(baton as *mut Box); // if cancel_fn() { 1 } else { 0 } // } // } // // The CallbackHandle above can be used to manage the boxed closure lifetime. #[cfg(test)] mod tests { use super::*; #[test] fn test_callback_handle() { let mut counter = 0; let callback = move || { counter += 1; counter }; let handle = CallbackHandle::new(callback); assert!(!handle.baton().is_null()); } } apr-0.3.4/src/crypto.rs000064400000000000000000000557051046102023000131030ustar 00000000000000//! Cryptographic functionality from apr-util. //! //! Provides symmetric encryption and decryption using various crypto backends //! (OpenSSL, NSS, CommonCrypto, etc.). use crate::pool::Pool; use crate::{Error, Status}; use std::ffi::c_char; use std::ffi::CString; use std::marker::PhantomData; use std::ptr; /// Crypto driver/factory handle. pub struct CryptoDriver<'pool> { driver: *const apr_sys::apr_crypto_driver_t, _pool: PhantomData<&'pool Pool>, } /// Crypto context handle. pub struct Crypto<'pool> { factory: *mut apr_sys::apr_crypto_t, _pool: PhantomData<&'pool Pool>, } /// Encryption/decryption block handle. pub struct CryptoBlock<'pool> { block: *mut apr_sys::apr_crypto_block_t, _pool: PhantomData<&'pool Pool>, } /// Key for encryption/decryption. pub struct CryptoKey<'pool> { key: *mut apr_sys::apr_crypto_key_t, _pool: PhantomData<&'pool Pool>, } /// Block cipher mode. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum BlockCipherMode { /// Electronic Codebook mode ECB, /// Cipher Block Chaining mode CBC, } impl From for apr_sys::apr_crypto_block_key_mode_e { fn from(mode: BlockCipherMode) -> Self { match mode { BlockCipherMode::ECB => apr_sys::apr_crypto_block_key_mode_e_APR_MODE_ECB, BlockCipherMode::CBC => apr_sys::apr_crypto_block_key_mode_e_APR_MODE_CBC, } } } /// Block cipher algorithm. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum BlockCipherAlgorithm { /// AES with 128-bit key AES128, /// AES with 192-bit key AES192, /// AES with 256-bit key AES256, /// Triple DES DES3, } impl From for apr_sys::apr_crypto_block_key_type_e { fn from(algo: BlockCipherAlgorithm) -> Self { match algo { BlockCipherAlgorithm::AES128 => apr_sys::apr_crypto_block_key_type_e_APR_KEY_AES_128, BlockCipherAlgorithm::AES192 => apr_sys::apr_crypto_block_key_type_e_APR_KEY_AES_192, BlockCipherAlgorithm::AES256 => apr_sys::apr_crypto_block_key_type_e_APR_KEY_AES_256, BlockCipherAlgorithm::DES3 => apr_sys::apr_crypto_block_key_type_e_APR_KEY_3DES_192, } } } /// Initialize the crypto library (pool-less API). pub fn init() -> Result<(), Error> { crate::pool::with_tmp_pool(|pool| { let status = unsafe { apr_sys::apr_crypto_init(pool.as_ptr() as *mut apr_sys::apr_pool_t) }; if status == apr_sys::APR_SUCCESS as i32 { Ok(()) } else { Err(Error::from_status(Status::from(status))) } }) } /// Encrypt data using a simple API (pool-less). pub fn encrypt_aes256(key: &[u8], data: &[u8], iv: Option<&[u8]>) -> Result, Error> { crate::pool::with_tmp_pool(|pool| { let driver = get_driver("openssl", pool)?; let crypto = driver.make_crypto(pool)?; let crypto_key = crypto.make_key( BlockCipherAlgorithm::AES256, BlockCipherMode::CBC, key, pool, )?; crypto.encrypt(&crypto_key, data, iv, pool) }) } /// Decrypt data using a simple API (pool-less). pub fn decrypt_aes256(key: &[u8], data: &[u8], iv: Option<&[u8]>) -> Result, Error> { crate::pool::with_tmp_pool(|pool| { let driver = get_driver("openssl", pool)?; let crypto = driver.make_crypto(pool)?; let crypto_key = crypto.make_key( BlockCipherAlgorithm::AES256, BlockCipherMode::CBC, key, pool, )?; crypto.decrypt(&crypto_key, data, iv, pool) }) } /// Get a crypto driver by name (pool-exposed API). pub fn get_driver<'pool>(name: &str, pool: &'pool Pool) -> Result, Error> { let name_cstr = CString::new(name) .map_err(|_| Error::from_status(Status::from(apr_sys::APR_EINVAL as i32)))?; let mut driver: *const apr_sys::apr_crypto_driver_t = ptr::null(); let params_ptr: *const c_char = ptr::null(); let mut error_ptr: *const apr_sys::apu_err_t = ptr::null(); let status = unsafe { apr_sys::apr_crypto_get_driver( &mut driver, name_cstr.as_ptr(), params_ptr, &mut error_ptr, pool.as_ptr() as *mut apr_sys::apr_pool_t, ) }; if status == apr_sys::APR_SUCCESS as i32 { Ok(CryptoDriver { driver, _pool: PhantomData, }) } else { Err(Error::from_status(Status::from(status))) } } impl Crypto<'_> { /// Initialize the crypto library (pool-exposed API). pub fn init(pool: &Pool) -> Result<(), Error> { let status = unsafe { apr_sys::apr_crypto_init(pool.as_ptr() as *mut apr_sys::apr_pool_t) }; if status == apr_sys::APR_SUCCESS as i32 { Ok(()) } else { Err(Error::from_status(Status::from(status))) } } } impl<'pool> CryptoDriver<'pool> { /// Create a crypto factory from this driver. pub fn make_crypto(&self, pool: &'pool Pool) -> Result, Error> { let mut factory: *mut apr_sys::apr_crypto_t = ptr::null_mut(); let params_ptr: *const c_char = ptr::null(); let status = unsafe { apr_sys::apr_crypto_make( &mut factory, self.driver, params_ptr, pool.as_ptr() as *mut apr_sys::apr_pool_t, ) }; if status == apr_sys::APR_SUCCESS as i32 { Ok(Crypto { factory, _pool: PhantomData, }) } else { Err(Error::from_status(Status::from(status))) } } } impl<'pool> Crypto<'pool> { /// Create a key for encryption/decryption. pub fn make_key( &self, algorithm: BlockCipherAlgorithm, mode: BlockCipherMode, key_data: &[u8], pool: &'pool Pool, ) -> Result, Error> { let mut key: *mut apr_sys::apr_crypto_key_t = ptr::null_mut(); let mut iv_size: apr_sys::apr_size_t = 0; let status = unsafe { apr_sys::apr_crypto_passphrase( &mut key, &mut iv_size, key_data.as_ptr() as *const c_char, key_data.len() as apr_sys::apr_size_t, ptr::null(), // salt 0, // saltLen algorithm.into(), mode.into(), 1, // doPad 4096, // iterations self.factory, pool.as_ptr() as *mut apr_sys::apr_pool_t, ) }; if status == apr_sys::APR_SUCCESS as i32 { Ok(CryptoKey { key, _pool: PhantomData, }) } else { Err(Error::from_status(Status::from(status))) } } /// Encrypt data. pub fn encrypt( &self, key: &CryptoKey, plaintext: &[u8], iv: Option<&[u8]>, pool: &Pool, ) -> Result, Error> { let mut block: *mut apr_sys::apr_crypto_block_t = ptr::null_mut(); let mut block_size: apr_sys::apr_size_t = 0; let mut iv_ptr = iv.map(|v| v.as_ptr()).unwrap_or(ptr::null()); // Initialize encryption let status = unsafe { apr_sys::apr_crypto_block_encrypt_init( &mut block, &mut iv_ptr, key.key, &mut block_size, pool.as_ptr() as *mut apr_sys::apr_pool_t, ) }; if status != apr_sys::APR_SUCCESS as i32 { return Err(Error::from_status(Status::from(status))); } // Get block size unsafe { apr_sys::apr_crypto_block_encrypt( &mut ptr::null_mut(), &mut block_size, ptr::null(), 0, block, ); } // Allocate output buffer let mut ciphertext = vec![0u8; plaintext.len() + block_size as usize]; let mut out_ptr = ciphertext.as_mut_ptr(); let mut out_len = ciphertext.len() as apr_sys::apr_size_t; // Encrypt data let status = unsafe { apr_sys::apr_crypto_block_encrypt( &mut out_ptr, &mut out_len, plaintext.as_ptr(), plaintext.len() as apr_sys::apr_size_t, block, ) }; if status != apr_sys::APR_SUCCESS as i32 { return Err(Error::from_status(Status::from(status))); } // Finalize encryption let mut final_len = ciphertext.len() as apr_sys::apr_size_t - out_len; let status = unsafe { apr_sys::apr_crypto_block_encrypt_finish(out_ptr, &mut final_len, block) }; if status != apr_sys::APR_SUCCESS as i32 { return Err(Error::from_status(Status::from(status))); } // Clean up block unsafe { apr_sys::apr_crypto_block_cleanup(block); } ciphertext.truncate((out_len + final_len) as usize); Ok(ciphertext) } /// Decrypt data. pub fn decrypt( &self, key: &CryptoKey, ciphertext: &[u8], iv: Option<&[u8]>, pool: &Pool, ) -> Result, Error> { let mut block: *mut apr_sys::apr_crypto_block_t = ptr::null_mut(); let mut block_size: apr_sys::apr_size_t = 0; let iv_ptr = iv.map(|v| v.as_ptr()).unwrap_or(ptr::null()); // Initialize decryption let status = unsafe { apr_sys::apr_crypto_block_decrypt_init( &mut block, &mut block_size, iv_ptr, key.key, pool.as_ptr() as *mut apr_sys::apr_pool_t, ) }; if status != apr_sys::APR_SUCCESS as i32 { return Err(Error::from_status(Status::from(status))); } // Allocate output buffer let mut plaintext = vec![0u8; ciphertext.len()]; let mut out_ptr = plaintext.as_mut_ptr(); let mut out_len = plaintext.len() as apr_sys::apr_size_t; // Decrypt data let status = unsafe { apr_sys::apr_crypto_block_decrypt( &mut out_ptr, &mut out_len, ciphertext.as_ptr(), ciphertext.len() as apr_sys::apr_size_t, block, ) }; if status != apr_sys::APR_SUCCESS as i32 { return Err(Error::from_status(Status::from(status))); } // Finalize decryption let mut final_len = plaintext.len() as apr_sys::apr_size_t - out_len; let status = unsafe { apr_sys::apr_crypto_block_decrypt_finish(out_ptr, &mut final_len, block) }; if status != apr_sys::APR_SUCCESS as i32 { return Err(Error::from_status(Status::from(status))); } // Clean up block unsafe { apr_sys::apr_crypto_block_cleanup(block); } plaintext.truncate((out_len + final_len) as usize); Ok(plaintext) } } impl<'pool> CryptoBlock<'pool> { /// Create a new encryption block. pub fn encrypt_init( key: &CryptoKey, iv: Option<&[u8]>, pool: &'pool Pool, ) -> Result { let mut block: *mut apr_sys::apr_crypto_block_t = ptr::null_mut(); let mut block_size: apr_sys::apr_size_t = 0; let mut iv_ptr = iv.map(|v| v.as_ptr()).unwrap_or(ptr::null()); let status = unsafe { apr_sys::apr_crypto_block_encrypt_init( &mut block, &mut iv_ptr, key.key, &mut block_size, pool.as_ptr() as *mut apr_sys::apr_pool_t, ) }; if status == apr_sys::APR_SUCCESS as i32 { Ok(CryptoBlock { block, _pool: PhantomData, }) } else { Err(Error::from_status(Status::from(status))) } } /// Create a new decryption block. pub fn decrypt_init( key: &CryptoKey, iv: Option<&[u8]>, pool: &'pool Pool, ) -> Result { let mut block: *mut apr_sys::apr_crypto_block_t = ptr::null_mut(); let mut block_size: apr_sys::apr_size_t = 0; let iv_ptr = iv.map(|v| v.as_ptr()).unwrap_or(ptr::null()); let status = unsafe { apr_sys::apr_crypto_block_decrypt_init( &mut block, &mut block_size, iv_ptr, key.key, pool.as_ptr() as *mut apr_sys::apr_pool_t, ) }; if status == apr_sys::APR_SUCCESS as i32 { Ok(CryptoBlock { block, _pool: PhantomData, }) } else { Err(Error::from_status(Status::from(status))) } } /// Encrypt data using this block. pub fn encrypt(&mut self, plaintext: &[u8]) -> Result, Error> { // Get required buffer size let mut block_size: apr_sys::apr_size_t = 0; unsafe { apr_sys::apr_crypto_block_encrypt( &mut ptr::null_mut(), &mut block_size, ptr::null(), 0, self.block, ); } let mut ciphertext = vec![0u8; plaintext.len() + block_size as usize]; let mut out_ptr = ciphertext.as_mut_ptr(); let mut out_len = ciphertext.len() as apr_sys::apr_size_t; let status = unsafe { apr_sys::apr_crypto_block_encrypt( &mut out_ptr, &mut out_len, plaintext.as_ptr(), plaintext.len() as apr_sys::apr_size_t, self.block, ) }; if status != apr_sys::APR_SUCCESS as i32 { return Err(Error::from_status(Status::from(status))); } let mut final_len = ciphertext.len() as apr_sys::apr_size_t - out_len; let status = unsafe { apr_sys::apr_crypto_block_encrypt_finish(out_ptr, &mut final_len, self.block) }; if status != apr_sys::APR_SUCCESS as i32 { return Err(Error::from_status(Status::from(status))); } ciphertext.truncate((out_len + final_len) as usize); Ok(ciphertext) } /// Decrypt data using this block. pub fn decrypt(&mut self, ciphertext: &[u8]) -> Result, Error> { let mut plaintext = vec![0u8; ciphertext.len()]; let mut out_ptr = plaintext.as_mut_ptr(); let mut out_len = plaintext.len() as apr_sys::apr_size_t; let status = unsafe { apr_sys::apr_crypto_block_decrypt( &mut out_ptr, &mut out_len, ciphertext.as_ptr(), ciphertext.len() as apr_sys::apr_size_t, self.block, ) }; if status != apr_sys::APR_SUCCESS as i32 { return Err(Error::from_status(Status::from(status))); } let mut final_len = plaintext.len() as apr_sys::apr_size_t - out_len; let status = unsafe { apr_sys::apr_crypto_block_decrypt_finish(out_ptr, &mut final_len, self.block) }; if status != apr_sys::APR_SUCCESS as i32 { return Err(Error::from_status(Status::from(status))); } plaintext.truncate((out_len + final_len) as usize); Ok(plaintext) } /// Get the raw APR crypto block pointer. pub fn as_ptr(&self) -> *mut apr_sys::apr_crypto_block_t { self.block } } impl<'pool> Drop for CryptoBlock<'pool> { fn drop(&mut self) { unsafe { apr_sys::apr_crypto_block_cleanup(self.block); } } } /// Get list of available crypto drivers. pub fn crypto_drivers(pool: &Pool) -> Vec { // Common driver names to try let drivers = ["openssl", "nss", "commoncrypto", "mscapi", "mscng"]; let mut available = Vec::new(); for name in &drivers { if get_driver(name, pool).is_ok() { available.push(name.to_string()); } } available } #[cfg(test)] mod tests { use super::*; #[test] fn test_crypto_init() { let pool = Pool::new(); // Crypto init may fail if no drivers available let _ = Crypto::init(&pool); } #[test] fn test_crypto_drivers() { let pool = Pool::new(); let _ = Crypto::init(&pool); let drivers = crypto_drivers(&pool); // May be empty if no drivers available println!("Available crypto drivers: {:?}", drivers); } #[test] fn test_encrypt_decrypt() { let pool = Pool::new(); // Try to initialize crypto if Crypto::init(&pool).is_err() { return; // Skip if crypto not available } // Try to get a driver let driver = match get_driver("openssl", &pool) .or_else(|_| get_driver("nss", &pool)) .or_else(|_| get_driver("commoncrypto", &pool)) { Ok(d) => d, Err(_) => return, // No drivers available }; let crypto = match driver.make_crypto(&pool) { Ok(c) => c, Err(_) => return, }; let key_data = b"thisisasecretkey"; let key = match crypto.make_key( BlockCipherAlgorithm::AES128, BlockCipherMode::CBC, key_data, &pool, ) { Ok(k) => k, Err(_) => return, }; let plaintext = b"Hello, World! This is a test."; let iv = b"1234567890123456"; // 16 bytes for AES // Encrypt let ciphertext = match crypto.encrypt(&key, plaintext, Some(iv), &pool) { Ok(c) => c, Err(_) => return, }; assert!(!ciphertext.is_empty()); assert_ne!(&ciphertext[..], plaintext); // Decrypt let decrypted = match crypto.decrypt(&key, &ciphertext, Some(iv), &pool) { Ok(p) => p, Err(_) => return, }; assert_eq!(&decrypted[..], plaintext); } #[test] fn test_crypto_block_encrypt_decrypt() { let pool = Pool::new(); // Try to initialize crypto if Crypto::init(&pool).is_err() { return; // Skip if crypto not available } // Try to get a driver let driver = match get_driver("openssl", &pool) .or_else(|_| get_driver("nss", &pool)) .or_else(|_| get_driver("commoncrypto", &pool)) { Ok(d) => d, Err(_) => return, // No drivers available }; let crypto = match driver.make_crypto(&pool) { Ok(c) => c, Err(_) => return, }; let key_data = b"thisisasecretkey"; let key = match crypto.make_key( BlockCipherAlgorithm::AES128, BlockCipherMode::CBC, key_data, &pool, ) { Ok(k) => k, Err(_) => return, }; let plaintext = b"Hello, World! This is a test."; let iv = b"1234567890123456"; // 16 bytes for AES // Create encryption block let mut encrypt_block = match CryptoBlock::encrypt_init(&key, Some(iv), &pool) { Ok(b) => b, Err(_) => return, }; // Encrypt using block let ciphertext = match encrypt_block.encrypt(plaintext) { Ok(c) => c, Err(_) => return, }; assert!(!ciphertext.is_empty()); assert_ne!(&ciphertext[..], plaintext); // Create decryption block let mut decrypt_block = match CryptoBlock::decrypt_init(&key, Some(iv), &pool) { Ok(b) => b, Err(_) => return, }; // Decrypt using block let decrypted = match decrypt_block.decrypt(&ciphertext) { Ok(p) => p, Err(_) => return, }; assert_eq!(&decrypted[..], plaintext); } #[test] fn test_crypto_block_as_ptr() { let pool = Pool::new(); // Try to initialize crypto if Crypto::init(&pool).is_err() { return; // Skip if crypto not available } // Try to get a driver let driver = match get_driver("openssl", &pool) .or_else(|_| get_driver("nss", &pool)) .or_else(|_| get_driver("commoncrypto", &pool)) { Ok(d) => d, Err(_) => return, // No drivers available }; let crypto = match driver.make_crypto(&pool) { Ok(c) => c, Err(_) => return, }; let key_data = b"thisisasecretkey"; let key = match crypto.make_key( BlockCipherAlgorithm::AES128, BlockCipherMode::CBC, key_data, &pool, ) { Ok(k) => k, Err(_) => return, }; let iv = b"1234567890123456"; // Create encryption block and check pointer let block = match CryptoBlock::encrypt_init(&key, Some(iv), &pool) { Ok(b) => b, Err(_) => return, }; let ptr = block.as_ptr(); assert!(!ptr.is_null()); } #[test] fn test_crypto_block_multiple_operations() { let pool = Pool::new(); // Try to initialize crypto if Crypto::init(&pool).is_err() { return; // Skip if crypto not available } // Try to get a driver let driver = match get_driver("openssl", &pool) .or_else(|_| get_driver("nss", &pool)) .or_else(|_| get_driver("commoncrypto", &pool)) { Ok(d) => d, Err(_) => return, // No drivers available }; let crypto = match driver.make_crypto(&pool) { Ok(c) => c, Err(_) => return, }; let key_data = b"thisisasecretkey"; let key = match crypto.make_key( BlockCipherAlgorithm::AES256, BlockCipherMode::CBC, key_data, &pool, ) { Ok(k) => k, Err(_) => return, }; // Test multiple messages with different IVs let messages = [ (b"First message".as_ref(), b"1234567890123456"), (b"Second message here", b"6543210987654321"), (b"Third and final message!", b"abcdefghijklmnop"), ]; for (plaintext, iv) in &messages { let mut encrypt_block = match CryptoBlock::encrypt_init(&key, Some(*iv), &pool) { Ok(b) => b, Err(_) => return, }; let ciphertext = match encrypt_block.encrypt(plaintext) { Ok(c) => c, Err(_) => return, }; let mut decrypt_block = match CryptoBlock::decrypt_init(&key, Some(*iv), &pool) { Ok(b) => b, Err(_) => return, }; let decrypted = match decrypt_block.decrypt(&ciphertext) { Ok(p) => p, Err(_) => return, }; assert_eq!(&decrypted[..], *plaintext); } } } apr-0.3.4/src/date.rs000064400000000000000000000053421046102023000124700ustar 00000000000000//! Date parsing functions use crate::time::Time; use apr_sys::apr_date_checkmask; /// Check if the given data matches the mask. pub fn checkmask(data: &str, mask: &str) -> bool { let (data, mask) = ( std::ffi::CString::new(data).unwrap(), std::ffi::CString::new(mask).unwrap(), ); unsafe { apr_date_checkmask( data.as_ptr() as *const std::ffi::c_char, mask.as_ptr() as *const std::ffi::c_char, ) != 0 } } /// Parse the given data as an HTTP date. pub fn parse_http(data: &str) -> Option