diff options
Diffstat (limited to '')
-rw-r--r-- | vendor/gix-url/.cargo-checksum.json | 2 | ||||
-rw-r--r-- | vendor/gix-url/CHANGELOG.md | 162 | ||||
-rw-r--r-- | vendor/gix-url/Cargo.toml | 12 | ||||
-rw-r--r-- | vendor/gix-url/src/expand_path.rs | 15 | ||||
-rw-r--r-- | vendor/gix-url/src/lib.rs | 99 | ||||
-rw-r--r-- | vendor/gix-url/src/parse.rs | 349 | ||||
-rw-r--r-- | vendor/gix-url/src/scheme.rs | 3 | ||||
-rw-r--r-- | vendor/gix-url/tests/baseline/main.rs | 217 |
8 files changed, 469 insertions, 390 deletions
diff --git a/vendor/gix-url/.cargo-checksum.json b/vendor/gix-url/.cargo-checksum.json index c08420faf..be0da2737 100644 --- a/vendor/gix-url/.cargo-checksum.json +++ b/vendor/gix-url/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"CHANGELOG.md":"338023cb41d05fc178ad5e7df70a104269322894e1d46d61ebb277e2a4bcd353","Cargo.toml":"fa44109c10a7f056540bb2adef13defb6907ca69690def04ecb10ae254bd7496","LICENSE-APACHE":"cb4780590812826851ba250f90bed0ed19506ec98f6865a0e2e20bbf62391ff9","LICENSE-MIT":"49df47913ab2beafe8dc45607877ae64198bf0eee64aaad3e82ed9e4d27424e8","src/expand_path.rs":"b0d2fe688c170dfa1381b3cb7add373a618a8ac2520ebdeb2ea721318bb88566","src/impls.rs":"3e47180ec440b42bbd0ba2bdbcbfc247fbfd4020066ce5ca0f4c137b36807323","src/lib.rs":"62e4beec340b5ab0debd6e36207c50634207b33c94c07ff74b2db7ddd70bf22d","src/parse.rs":"0dd96b53e86df347388c9d05be66e49cc2aa4bdec439304c53d4e28664644a14","src/scheme.rs":"02a6a230eea7459b05959ff4e8ce30f4d45526e1f1a47ff88b260bb1943d2433","tests/baseline/main.rs":"2826825460579010a346fba32a875f28e35addb55c1ef7882e5c622943352ec0"},"package":"6125ecf46e8c68bf7202da6cad239831daebf0247ffbab30210d72f3856e420f"}
\ No newline at end of file +{"files":{"CHANGELOG.md":"fd99224bb13c423da1438bbf9eee77ff16f0c4830d3adb594aecacd64f4baed3","Cargo.toml":"4a79cde98365962dc3ed2a9de3d135fd050ffe31294115b4d2d11b1b30f76b30","LICENSE-APACHE":"cb4780590812826851ba250f90bed0ed19506ec98f6865a0e2e20bbf62391ff9","LICENSE-MIT":"49df47913ab2beafe8dc45607877ae64198bf0eee64aaad3e82ed9e4d27424e8","src/expand_path.rs":"237e0507aca81bd2f8cc36c9007780808763f1fe42ec3f63b08657fe91edebbf","src/impls.rs":"3e47180ec440b42bbd0ba2bdbcbfc247fbfd4020066ce5ca0f4c137b36807323","src/lib.rs":"f3b7b61875350f3575b888acd89a697cbe978e46ce51d16e5b24cba3d39e5894","src/parse.rs":"dd5e0329b07ed7ee587a3909303cb6a7944728fffa1cf60e14cb03b589ca48cc","src/scheme.rs":"1c094d383a0af2fce2bd7411fdd4766ba13e70e03bf7f778b07d2a496f01c404"},"package":"b1b9ac8ed32ad45f9fc6c5f8c0be2ed911e544a5a19afd62d95d524ebaa95671"}
\ No newline at end of file diff --git a/vendor/gix-url/CHANGELOG.md b/vendor/gix-url/CHANGELOG.md index ce61c98c0..607887d28 100644 --- a/vendor/gix-url/CHANGELOG.md +++ b/vendor/gix-url/CHANGELOG.md @@ -5,6 +5,94 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## 0.25.1 (2023-10-14) + +### Bug Fixes + + - <csr-id-562b0c931db1d22b8e59903cb59afa9a36d5884c/> make file:// url parsing with full backslashed path more robust on windows. + +### Commit Statistics + +<csr-read-only-do-not-edit/> + + - 3 commits contributed to the release. + - 1 day passed between releases. + - 1 commit was understood as [conventional](https://www.conventionalcommits.org). + - 1 unique issue was worked on: [#1063](https://github.com/Byron/gitoxide/issues/1063) + +### Commit Details + +<csr-read-only-do-not-edit/> + +<details><summary>view details</summary> + + * **[#1063](https://github.com/Byron/gitoxide/issues/1063)** + - Make file:// url parsing with full backslashed path more robust on windows. ([`562b0c9`](https://github.com/Byron/gitoxide/commit/562b0c931db1d22b8e59903cb59afa9a36d5884c)) + * **Uncategorized** + - Merge branch 'head-conversions' ([`c2cf20c`](https://github.com/Byron/gitoxide/commit/c2cf20cd2d685c2c24527729fff35fd0a7903742)) + - Fix yet another fuzzed test-case related to url::parse DoS ([`21729ed`](https://github.com/Byron/gitoxide/commit/21729edb0c12831eb9ea488cc3b66b5e79eacfae)) +</details> + +## 0.25.0 (2023-10-12) + +This release contains a complete rewrite of the internal url parsing logic, the public interface stays mostly the same however. Gitoxide will now be +more correct, interpreting more urls the same way Git does. Improvements include the added support for ssh aliases (`github:byron/gitoxide` has previously +been parsed as local path), adjustments around the interpretation of colons in file names (previously we disallowed colons that were not followed up +with a slash character) and some smaller changes that bring the interpretation of file urls more in line with Git's implementation. Additionally, the +error types have been adjusted to print a more comprehensive message by default, making sure they stay helpful even when bubbled up through multiple abstraction +layers. + +There are still many (edge) cases in Git's url parsing implementation which are not handled correctly by Gitoxide. If you notice any such deviation please +open a new issue to help us making Gitoxide even more correct. + +### Bug Fixes + + - <csr-id-ea0ea88dfc232601b462fcf52fed4d34a17bc116/> another fuzz-issue that could cause long parse times of URLs + - <csr-id-60126d7097280bf364fb83ef73588df414198855/> denial of service attack by passing a URL with a very long host. + We now check for certain size limits and prevent passing long URLs to + the `url` crate. + +### New Features + + - <csr-id-4184a5e9019f2ac20213b5362d60c71e0bf295d3/> enable fuzzing for git url parsing + +### Commit Statistics + +<csr-read-only-do-not-edit/> + + - 19 commits contributed to the release over the course of 17 calendar days. + - 17 days passed between releases. + - 3 commits were understood as [conventional](https://www.conventionalcommits.org). + - 0 issues like '(#ID)' were seen in commit messages + +### Commit Details + +<csr-read-only-do-not-edit/> + +<details><summary>view details</summary> + + * **Uncategorized** + - Release gix-hash v0.13.1, gix-features v0.36.0, gix-actor v0.28.0, gix-object v0.38.0, gix-glob v0.14.0, gix-attributes v0.20.0, gix-command v0.2.10, gix-filter v0.6.0, gix-fs v0.8.0, gix-commitgraph v0.22.0, gix-revwalk v0.9.0, gix-traverse v0.34.0, gix-worktree-stream v0.6.0, gix-archive v0.6.0, gix-tempfile v11.0.0, gix-lock v11.0.0, gix-ref v0.38.0, gix-config v0.31.0, gix-url v0.25.0, gix-credentials v0.21.0, gix-diff v0.37.0, gix-discover v0.26.0, gix-ignore v0.9.0, gix-index v0.26.0, gix-mailmap v0.20.0, gix-negotiate v0.9.0, gix-pack v0.44.0, gix-odb v0.54.0, gix-pathspec v0.4.0, gix-packetline v0.16.7, gix-transport v0.37.0, gix-protocol v0.41.0, gix-revision v0.23.0, gix-refspec v0.19.0, gix-worktree v0.27.0, gix-status v0.2.0, gix-submodule v0.5.0, gix-worktree-state v0.4.0, gix v0.55.0, safety bump 37 crates ([`68e5432`](https://github.com/Byron/gitoxide/commit/68e54326e527a55dd5b5079921fc251615833040)) + - Prepare changelogs prior to release ([`1347a54`](https://github.com/Byron/gitoxide/commit/1347a54f84599d8f0aa935d6e64b16c2298d25cf)) + - Another fuzz-issue that could cause long parse times of URLs ([`ea0ea88`](https://github.com/Byron/gitoxide/commit/ea0ea88dfc232601b462fcf52fed4d34a17bc116)) + - Add yet another bypass attack that runs into the `url` DoS issue ([`6aa63b1`](https://github.com/Byron/gitoxide/commit/6aa63b19338d1b4d86906a1e16eeb7b48cbc83a4)) + - Merge branch 'improvements' ([`3939a45`](https://github.com/Byron/gitoxide/commit/3939a455be2269280248cdfed4a5983f8d178141)) + - Assure we don't accidentally parse a valid-looking URL to `url` and cause long compute times. ([`7497553`](https://github.com/Byron/gitoxide/commit/7497553e753dcff92cc7c78941d8bbef8b97bdb7)) + - Merge branch 'gix-url-fixture-improvements' ([`3d60c02`](https://github.com/Byron/gitoxide/commit/3d60c0245ec4b787cfcb111319d730a6e5031ef4)) + - Fix panics not shown in gix-url baseline generation ([`2488ad9`](https://github.com/Byron/gitoxide/commit/2488ad9f5ca2913a1a67f40b91291463602a3f21)) + - Improve output of the gix-url baseline test ([`a530037`](https://github.com/Byron/gitoxide/commit/a5300378899d205ce96f53581b98d3149e1e8c66)) + - Denial of service attack by passing a URL with a very long host. ([`60126d7`](https://github.com/Byron/gitoxide/commit/60126d7097280bf364fb83ef73588df414198855)) + - Merge branch 'gix-url-parse-rewrite' ([`a12e4a8`](https://github.com/Byron/gitoxide/commit/a12e4a88d5f5636cd694c72ce45a8b75aa754d28)) + - Enable fuzzing for git url parsing ([`4184a5e`](https://github.com/Byron/gitoxide/commit/4184a5e9019f2ac20213b5362d60c71e0bf295d3)) + - Assure we don't loose test coverage; possibly adjust expecations ([`30bb7dc`](https://github.com/Byron/gitoxide/commit/30bb7dc27f4b5def6abb91adc81ff49a1b935cff)) + - Refactor ([`e318a4c`](https://github.com/Byron/gitoxide/commit/e318a4c243f67807bee55ea4571dfb1c068f1d09)) + - Refactor baseline tests ([`4b4ac8a`](https://github.com/Byron/gitoxide/commit/4b4ac8abee65a27f8677ef25f4f127bf6f6416b7)) + - Add platform specific baseline tests and run always run them. ([`e9aa690`](https://github.com/Byron/gitoxide/commit/e9aa690d7c0692e5476c2065feb31b0c75e81128)) + - Update changelogs ([`4349353`](https://github.com/Byron/gitoxide/commit/43493531bbf3049bee3d7b14b7a6dbe874e37ebc)) + - Align test with real behavior ([`a31af62`](https://github.com/Byron/gitoxide/commit/a31af624f88f80dab0a3f2ccd36502bb494ab046)) + - Fix absolute windows file urls with extra slash ([`3bf12a3`](https://github.com/Byron/gitoxide/commit/3bf12a3e9bda6ebe0f8942d9b3f1f7c3e357b435)) +</details> + ## 0.24.0 (2023-09-24) ### New Features @@ -22,7 +110,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 <csr-read-only-do-not-edit/> - - 4 commits contributed to the release. + - 14 commits contributed to the release over the course of 14 calendar days. - 16 days passed between releases. - 2 commits were understood as [conventional](https://www.conventionalcommits.org). - 0 issues like '(#ID)' were seen in commit messages @@ -34,10 +122,20 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 <details><summary>view details</summary> * **Uncategorized** + - Release gix-features v0.35.0, gix-actor v0.27.0, gix-object v0.37.0, gix-glob v0.13.0, gix-attributes v0.19.0, gix-filter v0.5.0, gix-fs v0.7.0, gix-commitgraph v0.21.0, gix-revwalk v0.8.0, gix-traverse v0.33.0, gix-worktree-stream v0.5.0, gix-archive v0.5.0, gix-tempfile v10.0.0, gix-lock v10.0.0, gix-ref v0.37.0, gix-config v0.30.0, gix-url v0.24.0, gix-credentials v0.20.0, gix-diff v0.36.0, gix-discover v0.25.0, gix-ignore v0.8.0, gix-index v0.25.0, gix-mailmap v0.19.0, gix-negotiate v0.8.0, gix-pack v0.43.0, gix-odb v0.53.0, gix-pathspec v0.3.0, gix-transport v0.37.0, gix-protocol v0.40.0, gix-revision v0.22.0, gix-refspec v0.18.0, gix-status v0.1.0, gix-submodule v0.4.0, gix-worktree v0.26.0, gix-worktree-state v0.3.0, gix v0.54.0, gitoxide-core v0.32.0, gitoxide v0.30.0, safety bump 37 crates ([`7891fb1`](https://github.com/Byron/gitoxide/commit/7891fb17348ec2f4c997665f9a25be36e2713da4)) - Prepare changelogs prior to release ([`8a60d5b`](https://github.com/Byron/gitoxide/commit/8a60d5b80877c213c3b646d3061e8a33e0e433ec)) - Merge branch 'fix-exploit' ([`c53bbd2`](https://github.com/Byron/gitoxide/commit/c53bbd265005c7eedc316205b217e137e2b9896e)) - Prevent hosts or paths that look like arguments to be passed to invoked commands. ([`b06a0dd`](https://github.com/Byron/gitoxide/commit/b06a0dd781accad317fdec5f86f069df4c21875c)) - Add `Url::host_argument_safe()` and `Url::path_argument_safe()` ([`d80b5f6`](https://github.com/Byron/gitoxide/commit/d80b5f69772a6e36b0131d3a538e896a8a6a29b1)) + - Parse absolute paths in file urls on Windows ([`637e1ae`](https://github.com/Byron/gitoxide/commit/637e1ae996610b28812cf27efe13777666b44cc9)) + - Parse absolute paths as local urls on Windows ([`3af8834`](https://github.com/Byron/gitoxide/commit/3af8834a4a6ee33473d1690fd98b40b22d41a55d)) + - Create test urls from raw parts directly ([`5ac705c`](https://github.com/Byron/gitoxide/commit/5ac705cfaf8932469115f25b54a47f444c163bc0)) + - Fix file urls with dos driver letter on unix ([`99f4447`](https://github.com/Byron/gitoxide/commit/99f444799d44bbe54ac05307b79da6add9181b8b)) + - Fix dropping of host during file url conversion ([`f3e1331`](https://github.com/Byron/gitoxide/commit/f3e13312c2f0ea50b716189902c8b809a1a98cbc)) + - Use helper function for common url parsing steps ([`2344f91`](https://github.com/Byron/gitoxide/commit/2344f913b0539942ae852e2b093558e04c79bb8a)) + - Thanks clippy ([`d077f56`](https://github.com/Byron/gitoxide/commit/d077f56aa220d83f46e8d318c7bf48ec77072fdc)) + - Add missing slash to file url test ([`ffaead6`](https://github.com/Byron/gitoxide/commit/ffaead685b49d6c6eebdf5c563d2dc3cdbfb9e13)) + - Remove wrong ssh alias url test ([`4da440d`](https://github.com/Byron/gitoxide/commit/4da440d0f81a2fc462b2c04840a83beb7a738344)) </details> ## 0.23.0 (2023-09-08) @@ -51,7 +149,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 <csr-read-only-do-not-edit/> - - 5 commits contributed to the release over the course of 17 calendar days. + - 8 commits contributed to the release over the course of 17 calendar days. - 17 days passed between releases. - 1 commit was understood as [conventional](https://www.conventionalcommits.org). - 0 issues like '(#ID)' were seen in commit messages @@ -67,17 +165,66 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Prepare changelogs for release ([`375db06`](https://github.com/Byron/gitoxide/commit/375db06a8442378c3f7a922fae38e2a6694d9d04)) - Merge branch `dyn`ification ([`f658fcc`](https://github.com/Byron/gitoxide/commit/f658fcc52dc2200ae34ca53dc10be97fb9012057)) - Use `dyn` trait where possible. ([`072ee32`](https://github.com/Byron/gitoxide/commit/072ee32f693a31161cd6a843da6582d13efbb20b)) + - Handle missing host and path separator in file url ([`f05edae`](https://github.com/Byron/gitoxide/commit/f05edaef5e8d6a2d90adc84c8dc5c4b5ab0017b6)) + - Use same logic for file urls and local file paths ([`679a7f4`](https://github.com/Byron/gitoxide/commit/679a7f46e8121b5a0a5a396c2ce89f6706068507)) + - Return errors for empty paths and relative urls ([`8af79ec`](https://github.com/Byron/gitoxide/commit/8af79ec98d82f3d2542fc43928103a20c2e4fc1a)) - Merge branch 'gix-submodule' ([`363ee77`](https://github.com/Byron/gitoxide/commit/363ee77400805f473c9ad66eadad9214e7ab66f4)) </details> ## 0.22.0 (2023-08-22) <csr-id-229bd4899213f749a7cc124aa2b82a1368fba40f/> +<csr-id-313a7b3ddc5786af1f120fa99dd659d725b6845a/> ### Chore - <csr-id-229bd4899213f749a7cc124aa2b82a1368fba40f/> don't call crate 'WIP' in manifest anymore. +### Reverted (BREAKING) + + - <csr-id-fb0b8a769a8992e8079c66fea7d4708d9db0323d/> url parsing error NotALocalFile + The `NotALocalFile` error variant was previously returned if the input + url contained a colon but the slice after that character contained no + slash character (`/` or `\`). This behavior is wrong. + + SCP like URLs may not need a slash character to specify the repositories + location. Similarly, a local directory that contains a colon in its name + is a valid repository path as well. + + The new implementation correctly parses such URLs. + - <csr-id-dd1a1257d66d2f280be0adfce0a100a6a83e1c65/> url parsing error MissingResourceLocation + The `MissingResourceLocation` error variant was previously returned if + the input URL had either scheme ssh (no matter if URL or SCP format) or + git and the URL contained no or an empty path section. In the future we + will instead return the `MissingRepositoryPath` error in such a case. + + The only benefit of such a seperation is that it allows the caller to + infer the kind of URL we tried to parse. A future commit will add a new + field to the `MissingRepositoryPath` error variant which will clearly + communicate this information and can therefore be used instead for this + purpose. + +### Chore (BREAKING) + + - <csr-id-313a7b3ddc5786af1f120fa99dd659d725b6845a/> restructure gix-url parsing error variants + All error variants now own a copy of the input which is used in their + display implementation. I noticed that URL parsing errors are almost never + acted upon but only wrapped and bubbled up to the user. It therefore + makes sense to ensure the message for this error is informative enough + by default. + + If an error can be thrown for different types of URLs it now also + includes a kind field. With this field the caller can determine what + kind of URL we tried to parse. Additionally, this information is used + for the error message too. + + For testing the assert_matches crate was added which implements the + unstable feature with the same name in stable rust. It makes testing the + invalid variants much more convenient. + + BREAKING because public fields of some error variants are now no longer + available + ### Bug Fixes (BREAKING) - <csr-id-8857580cb270b737bf04437a6f5e65307df1c99b/> let `Url::canonicalize(d)()` take the current working dir as argument. @@ -87,9 +234,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 <csr-read-only-do-not-edit/> - - 21 commits contributed to the release over the course of 17 calendar days. + - 28 commits contributed to the release over the course of 17 calendar days. - 30 days passed between releases. - - 2 commits were understood as [conventional](https://www.conventionalcommits.org). + - 5 commits were understood as [conventional](https://www.conventionalcommits.org). - 0 issues like '(#ID)' were seen in commit messages ### Commit Details @@ -103,11 +250,18 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Make `gix-url` publishable by adding baseline test ([`d3746df`](https://github.com/Byron/gitoxide/commit/d3746df5dd402d8a461c2b07eaa0f8d8803fadf8)) - Release gix-date v0.7.3, gix-hash v0.12.0, gix-features v0.33.0, gix-actor v0.25.0, gix-object v0.35.0, gix-path v0.9.0, gix-glob v0.11.0, gix-quote v0.4.7, gix-attributes v0.17.0, gix-command v0.2.9, gix-packetline-blocking v0.16.5, gix-filter v0.3.0, gix-fs v0.5.0, gix-commitgraph v0.19.0, gix-hashtable v0.3.0, gix-revwalk v0.6.0, gix-traverse v0.31.0, gix-worktree-stream v0.3.0, gix-archive v0.3.0, gix-config-value v0.13.0, gix-tempfile v8.0.0, gix-lock v8.0.0, gix-ref v0.35.0, gix-sec v0.9.0, gix-config v0.28.0, gix-prompt v0.6.0, gix-url v0.22.0, gix-credentials v0.18.0, gix-diff v0.34.0, gix-discover v0.23.0, gix-ignore v0.6.0, gix-bitmap v0.2.7, gix-index v0.22.0, gix-mailmap v0.17.0, gix-negotiate v0.6.0, gix-pack v0.41.0, gix-odb v0.51.0, gix-pathspec v0.1.0, gix-packetline v0.16.5, gix-transport v0.35.0, gix-protocol v0.38.0, gix-revision v0.20.0, gix-refspec v0.16.0, gix-submodule v0.2.0, gix-worktree v0.24.0, gix-worktree-state v0.1.0, gix v0.52.0, gitoxide-core v0.31.0, gitoxide v0.29.0, safety bump 41 crates ([`30b2761`](https://github.com/Byron/gitoxide/commit/30b27615047692d3ced1b2d9c2ac15a80f79fbee)) - Update changelogs prior to release ([`f23ea88`](https://github.com/Byron/gitoxide/commit/f23ea8828f2d9ba7559973daca388c9591bcc5fc)) + - Restructure gix-url parsing error variants ([`313a7b3`](https://github.com/Byron/gitoxide/commit/313a7b3ddc5786af1f120fa99dd659d725b6845a)) + - Url parsing error NotALocalFile ([`fb0b8a7`](https://github.com/Byron/gitoxide/commit/fb0b8a769a8992e8079c66fea7d4708d9db0323d)) + - Url parsing error MissingResourceLocation ([`dd1a125`](https://github.com/Byron/gitoxide/commit/dd1a1257d66d2f280be0adfce0a100a6a83e1c65)) + - Rewrite gix-url parsing ([`14facd9`](https://github.com/Byron/gitoxide/commit/14facd98632b44eb350c33a5aa425d2e68d25889)) - Merge branch 'gix-url-fixture-tests' ([`1b957c5`](https://github.com/Byron/gitoxide/commit/1b957c524cae288ac2063f6ba7e4d10d523eb8f3)) - For now, ignore baseline tests as most of them fail. ([`c0be6ab`](https://github.com/Byron/gitoxide/commit/c0be6aba49d734d166f279933220b02989c584de)) - Don't call crate 'WIP' in manifest anymore. ([`229bd48`](https://github.com/Byron/gitoxide/commit/229bd4899213f749a7cc124aa2b82a1368fba40f)) - Merge branch 'submodule-active' ([`a3afaa4`](https://github.com/Byron/gitoxide/commit/a3afaa42741616a0f1abeef9b54557e7c2b800cb)) + - Add support for "git+ssh" and "ssh+git" urls ([`3faac36`](https://github.com/Byron/gitoxide/commit/3faac3648b4d39bff4a05602b481bf8e6d71b77e)) - Let `Url::canonicalize(d)()` take the current working dir as argument. ([`8857580`](https://github.com/Byron/gitoxide/commit/8857580cb270b737bf04437a6f5e65307df1c99b)) + - Fix wrong assertion in gix-url baseline test ([`f18bfd8`](https://github.com/Byron/gitoxide/commit/f18bfd8d81a56e9a68d465c49ef2da192de6c279)) + - Improve error printing for gix-url baseline test ([`0e9a18e`](https://github.com/Byron/gitoxide/commit/0e9a18ed6921116cca6e48345d6937ad7120e83e)) - Fix prints of panics in gix-url baseline test ([`938baee`](https://github.com/Byron/gitoxide/commit/938baee58383fd995d39c5528e2a104d33de8826)) - Add assert output to failures in gix-url baseline test ([`163e139`](https://github.com/Byron/gitoxide/commit/163e1391526dad528e0bca0cc876e50e48381e74)) - Thanks clippy ([`fe5dbe1`](https://github.com/Byron/gitoxide/commit/fe5dbe16b5a8cfefa31a561506218ede73f3ec7e)) diff --git a/vendor/gix-url/Cargo.toml b/vendor/gix-url/Cargo.toml index e3a109e8c..cc301a278 100644 --- a/vendor/gix-url/Cargo.toml +++ b/vendor/gix-url/Cargo.toml @@ -13,7 +13,7 @@ edition = "2021" rust-version = "1.65" name = "gix-url" -version = "0.24.0" +version = "0.25.1" authors = ["Sebastian Thiel <sebastian.thiel@icloud.com>"] include = [ "src/**/*", @@ -36,10 +36,6 @@ rustdoc-args = [ [lib] doctest = false -[[test]] -name = "baseline" -harness = false - [dependencies.bstr] version = "1.3.0" features = ["std"] @@ -50,7 +46,7 @@ version = "0.2.0" optional = true [dependencies.gix-features] -version = "^0.35.0" +version = "^0.36.0" [dependencies.gix-path] version = "^0.10.0" @@ -73,8 +69,8 @@ version = "1.0.32" [dependencies.url] version = "2.1.1" -[dev-dependencies.libtest-mimic] -version = "0.6.1" +[dev-dependencies.assert_matches] +version = "1.5.0" [features] serde = [ diff --git a/vendor/gix-url/src/expand_path.rs b/vendor/gix-url/src/expand_path.rs index 85fb0da50..e62a8b51e 100644 --- a/vendor/gix-url/src/expand_path.rs +++ b/vendor/gix-url/src/expand_path.rs @@ -22,7 +22,7 @@ impl From<ForUser> for Option<BString> { } } -/// The error used by [`parse()`], [`with()`] and [`expand_path()`]. +/// The error used by [`parse()`], [`with()`] and [`expand_path()`](crate::expand_path()). #[derive(Debug, thiserror::Error)] #[allow(missing_docs)] pub enum Error { @@ -112,16 +112,3 @@ pub fn with( None => path.into(), }) } - -/// Expand `path` for the given `user`, which can be obtained by [`parse()`], resolving the home directories -/// of `user` automatically. -/// -/// If more precise control of the resolution mechanism is needed, then use the [`with()`] function. -pub fn expand_path(user: Option<&ForUser>, path: &BStr) -> Result<PathBuf, Error> { - with(user, path, |user| match user { - ForUser::Current => home::home_dir(), - ForUser::Name(user) => { - home::home_dir().and_then(|home| home.parent().map(|home_dirs| home_dirs.join(user.to_string()))) - } - }) -} diff --git a/vendor/gix-url/src/lib.rs b/vendor/gix-url/src/lib.rs index 1d90689ae..a86713e85 100644 --- a/vendor/gix-url/src/lib.rs +++ b/vendor/gix-url/src/lib.rs @@ -10,28 +10,58 @@ use bstr::{BStr, BString}; use std::borrow::Cow; - -/// -pub mod parse; -#[doc(inline)] -pub use parse::parse; +use std::path::PathBuf; /// pub mod expand_path; -#[doc(inline)] -pub use expand_path::expand_path; mod scheme; pub use scheme::Scheme; +mod impls; + +/// +pub mod parse; + +/// Parse the given `bytes` as a [git url](Url). +/// +/// # Note +/// +/// We cannot and should never have to deal with UTF-16 encoded windows strings, so bytes input is acceptable. +/// For file-paths, we don't expect UTF8 encoding either. +pub fn parse(input: &BStr) -> Result<Url, parse::Error> { + use parse::InputScheme; + match parse::find_scheme(input) { + InputScheme::Local => parse::local(input), + InputScheme::Url { protocol_end } if input[..protocol_end].eq_ignore_ascii_case(b"file") => { + parse::file_url(input, protocol_end) + } + InputScheme::Url { protocol_end } => parse::url(input, protocol_end), + InputScheme::Scp { colon } => parse::scp(input, colon), + } +} + +/// Expand `path` for the given `user`, which can be obtained by [`parse()`], resolving the home directories +/// of `user` automatically. +/// +/// If more precise control of the resolution mechanism is needed, then use the [expand_path::with()] function. +pub fn expand_path(user: Option<&expand_path::ForUser>, path: &BStr) -> Result<PathBuf, expand_path::Error> { + expand_path::with(user, path, |user| match user { + expand_path::ForUser::Current => home::home_dir(), + expand_path::ForUser::Name(user) => { + home::home_dir().and_then(|home| home.parent().map(|home_dirs| home_dirs.join(user.to_string()))) + } + }) +} /// A URL with support for specialized git related capabilities. /// -/// Additionally there is support for [deserialization][Url::from_bytes()] and serialization -/// (_see the `Display::fmt()` implementation_). +/// Additionally there is support for [deserialization](Url::from_bytes()) and serialization +/// (_see the [`std::fmt::Display::fmt()`] implementation_). /// -/// # Deviation +/// # Security Warning /// -/// Note that we do not support passing the password using the URL as it's likely leading to accidents. +/// URLs may contain passwords and we serialize them when [formatting](std::fmt::Display) or +/// [serializing losslessly](Url::to_bstring()). #[derive(PartialEq, Eq, Debug, Hash, Ord, PartialOrd, Clone)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct Url { @@ -55,7 +85,7 @@ pub struct Url { /// the invocation of programs from an attacker controlled URL. See <https://secure.phabricator.com/T12961> for details. /// /// If this value is going to be used in a command-line application, call [Self::path_argument_safe()] instead. - pub path: bstr::BString, + pub path: BString, } /// Instantiation @@ -88,7 +118,7 @@ impl Url { /// Modification impl Url { - /// Set the given `user`, with `None` unsetting it. Returns the previous value. + /// Set the given `user`, or unset it with `None`. Return the previous value. pub fn set_user(&mut self, user: Option<String>) -> Option<String> { let prev = self.user.take(); self.user = user; @@ -228,7 +258,7 @@ impl Url { } /// Transform ourselves into a binary string, losslessly, or fail if the URL is malformed due to host or user parts being incorrect. - pub fn to_bstring(&self) -> bstr::BString { + pub fn to_bstring(&self) -> BString { let mut buf = Vec::with_capacity( (5 + 3) + self.user.as_ref().map(String::len).unwrap_or_default() @@ -250,4 +280,43 @@ impl Url { } } -mod impls; +/// This module contains extensions to the [Url] struct which are only intended to be used +/// for testing code. Do not use this module in production! For all intends and purposes the APIs of +/// all functions and types exposed by this module are considered unstable and are allowed to break +/// even in patch releases! +#[doc(hidden)] +#[cfg(debug_assertions)] +pub mod testing { + use bstr::BString; + + use crate::{Scheme, Url}; + + /// Additional functions for [Url] which are only intended to be used for tests. + pub trait TestUrlExtension { + /// Create a new instance from the given parts without validating them. + /// + /// This function is primarily intended for testing purposes. For production code please + /// consider using [Url::from_parts] instead! + fn from_parts_unchecked( + scheme: Scheme, + user: Option<String>, + password: Option<String>, + host: Option<String>, + port: Option<u16>, + path: BString, + serialize_alternative_form: bool, + ) -> Url { + Url { + scheme, + user, + password, + host, + port, + path, + serialize_alternative_form, + } + } + } + + impl TestUrlExtension for Url {} +} diff --git a/vendor/gix-url/src/parse.rs b/vendor/gix-url/src/parse.rs index e6e7d4872..382666368 100644 --- a/vendor/gix-url/src/parse.rs +++ b/vendor/gix-url/src/parse.rs @@ -1,25 +1,30 @@ -use std::{borrow::Cow, convert::Infallible}; - -pub use bstr; -use bstr::{BStr, BString, ByteSlice}; +use std::convert::Infallible; use crate::Scheme; +use bstr::{BStr, BString, ByteSlice}; -/// The Error returned by [`parse()`] +/// The error returned by [parse()](crate::parse()). #[derive(Debug, thiserror::Error)] #[allow(missing_docs)] pub enum Error { - #[error("Could not decode URL as UTF8")] - Utf8(#[from] std::str::Utf8Error), - #[error(transparent)] - Url(#[from] url::ParseError), - #[error("URLs need to specify the path to the repository")] - MissingResourceLocation, - #[error("file URLs require an absolute or relative path to the repository")] - MissingRepositoryPath, - #[error("\"{url}\" is not a valid local path")] - NotALocalFile { url: BString }, - #[error("Relative URLs are not permitted: {url:?}")] + #[error("{} \"{url}\" is not valid UTF-8", kind.as_str())] + Utf8 { + url: BString, + kind: UrlKind, + source: std::str::Utf8Error, + }, + #[error("{} {url:?} can not be parsed as valid URL", kind.as_str())] + Url { + url: String, + kind: UrlKind, + source: url::ParseError, + }, + + #[error("The host portion of the following URL is too long ({} bytes, {len} bytes total): {truncated_url:?}", truncated_url.len())] + TooLong { truncated_url: BString, len: usize }, + #[error("{} \"{url}\" does not specify a path to a repository", kind.as_str())] + MissingRepositoryPath { url: BString, kind: UrlKind }, + #[error("URL {url:?} is relative which is not allowed in this context")] RelativeUrl { url: String }, } @@ -29,145 +34,229 @@ impl From<Infallible> for Error { } } -fn str_to_protocol(s: &str) -> Scheme { - Scheme::from(s) +/// +#[derive(Debug, Clone, Copy)] +pub enum UrlKind { + /// + Url, + /// + Scp, + /// + Local, } -fn guess_protocol(url: &[u8]) -> Option<&str> { - match url.find_byte(b':') { - Some(colon_pos) => { - if url[..colon_pos].find_byteset(b"@.").is_some() { - "ssh" - } else { - url.get(colon_pos + 1..).and_then(|from_colon| { - (from_colon.contains(&b'/') || from_colon.contains(&b'\\')).then_some("file") - })? - } +impl UrlKind { + fn as_str(&self) -> &'static str { + match self { + UrlKind::Url => "URL", + UrlKind::Scp => "SCP-like target", + UrlKind::Local => "local path", } - None => "file", } - .into() } -/// Extract the path part from an SCP-like URL `[user@]host.xz:path/to/repo.git/` -fn extract_scp_path(url: &str) -> Option<&str> { - url.splitn(2, ':').last() +pub(crate) enum InputScheme { + Url { protocol_end: usize }, + Scp { colon: usize }, + Local, } -fn sanitize_for_protocol<'a>(protocol: &str, url: &'a str) -> Cow<'a, str> { - match protocol { - "ssh" => url.replacen(':', "/", 1).into(), - _ => url.into(), +pub(crate) fn find_scheme(input: &BStr) -> InputScheme { + // TODO: url's may only contain `:/`, we should additionally check if the characters used for + // protocol are all valid + if let Some(protocol_end) = input.find("://") { + return InputScheme::Url { protocol_end }; } -} -fn has_no_explicit_protocol(url: &[u8]) -> bool { - url.find(b"://").is_none() + if let Some(colon) = input.find_byte(b':') { + // allow user to select files containing a `:` by passing them as absolute or relative path + // this is behavior explicitly mentioned by the scp and git manuals + let explicitly_local = &input[..colon].contains(&b'/'); + let dos_driver_letter = cfg!(windows) && input[..colon].len() == 1; + + if !explicitly_local && !dos_driver_letter { + return InputScheme::Scp { colon }; + } + } + + InputScheme::Local } -fn to_owned_url(url: url::Url) -> Result<crate::Url, Error> { - let password = url.password(); +pub(crate) fn url(input: &BStr, protocol_end: usize) -> Result<crate::Url, Error> { + const MAX_LEN: usize = 1024; + let bytes_to_path = input[protocol_end + "://".len()..] + .iter() + .filter(|b| !b.is_ascii_whitespace()) + .skip_while(|b| **b == b'/' || **b == b'\\') + .position(|b| *b == b'/') + .unwrap_or(input.len() - protocol_end); + if bytes_to_path > MAX_LEN || protocol_end > MAX_LEN { + return Err(Error::TooLong { + truncated_url: input[..(protocol_end + "://".len() + MAX_LEN).min(input.len())].into(), + len: input.len(), + }); + } + let (input, url) = input_to_utf8_and_url(input, UrlKind::Url)?; + let scheme = url.scheme().into(); + + if matches!(scheme, Scheme::Git | Scheme::Ssh) && url.path().is_empty() { + return Err(Error::MissingRepositoryPath { + url: input.into(), + kind: UrlKind::Url, + }); + } + + if url.cannot_be_a_base() { + return Err(Error::RelativeUrl { url: input.to_owned() }); + } + Ok(crate::Url { serialize_alternative_form: false, - scheme: str_to_protocol(url.scheme()), - password: password.map(ToOwned::to_owned), - user: if url.username().is_empty() && password.is_none() { - None - } else { - Some(url.username().into()) - }, + scheme, + user: url_user(&url), + password: url.password().map(Into::into), host: url.host_str().map(Into::into), port: url.port(), path: url.path().into(), }) } -/// Parse the given `bytes` as git url. -/// -/// # Note -/// -/// We cannot and should never have to deal with UTF-16 encoded windows strings, so bytes input is acceptable. -/// For file-paths, we don't expect UTF8 encoding either. -pub fn parse(input: &BStr) -> Result<crate::Url, Error> { - let guessed_protocol = guess_protocol(input).ok_or_else(|| Error::NotALocalFile { url: input.into() })?; - let path_without_file_protocol = input.strip_prefix(b"file://"); - if path_without_file_protocol.is_some() || (has_no_explicit_protocol(input) && guessed_protocol == "file") { - let path: BString = path_without_file_protocol.map_or_else( - || input.into(), - |stripped_path| { - #[cfg(windows)] - { - if stripped_path.starts_with(b"/") { - input - .to_str() - .ok() - .and_then(|url| { - let path = url::Url::parse(url).ok()?.to_file_path().ok()?; - path.is_absolute().then(|| gix_path::into_bstr(path).into_owned()) - }) - .unwrap_or_else(|| stripped_path.into()) - } else { - stripped_path.into() - } - } - #[cfg(not(windows))] - { - stripped_path.into() - } - }, - ); - if path.is_empty() { - return Err(Error::MissingRepositoryPath); - } - let input_starts_with_file_protocol = input.starts_with(b"file://"); - if input_starts_with_file_protocol { - let wanted = cfg!(windows).then(|| &[b'\\', b'/'] as &[_]).unwrap_or(&[b'/']); - if !wanted.iter().any(|w| path.contains(w)) { - return Err(Error::MissingRepositoryPath); - } - } - return Ok(crate::Url { - scheme: Scheme::File, - path, - serialize_alternative_form: !input_starts_with_file_protocol, - ..Default::default() +pub(crate) fn scp(input: &BStr, colon: usize) -> Result<crate::Url, Error> { + let input = input_to_utf8(input, UrlKind::Scp)?; + + // TODO: this incorrectly splits at IPv6 addresses, check for `[]` before splitting + let (host, path) = input.split_at(colon); + debug_assert_eq!(path.get(..1), Some(":"), "{path} should start with :"); + let path = &path[1..]; + + if path.is_empty() { + return Err(Error::MissingRepositoryPath { + url: input.to_owned().into(), + kind: UrlKind::Scp, }); } - let url_str = std::str::from_utf8(input)?; - let (mut url, mut scp_path) = match url::Url::parse(url_str) { - Ok(url) => (url, None), - Err(url::ParseError::RelativeUrlWithoutBase) => { - // happens with bare paths as well as scp like paths. The latter contain a ':' past the host portion, - // which we are trying to detect. - ( - url::Url::parse(&format!( - "{}://{}", - guessed_protocol, - sanitize_for_protocol(guessed_protocol, url_str) - ))?, - extract_scp_path(url_str), - ) + // The path returned by the parsed url often has the wrong number of leading `/` characters but + // should never differ in any other way (ssh URLs should not contain a query or fragment part). + // To avoid the various off-by-one errors caused by the `/` characters, we keep using the path + // determined above and can therefore skip parsing it here as well. + let url = url::Url::parse(&format!("ssh://{host}")).map_err(|source| Error::Url { + url: input.to_owned(), + kind: UrlKind::Scp, + source, + })?; + + Ok(crate::Url { + serialize_alternative_form: true, + scheme: url.scheme().into(), + user: url_user(&url), + password: url.password().map(Into::into), + host: url.host_str().map(Into::into), + port: url.port(), + path: path.into(), + }) +} + +fn url_user(url: &url::Url) -> Option<String> { + if url.username().is_empty() && url.password().is_none() { + None + } else { + Some(url.username().into()) + } +} + +pub(crate) fn file_url(input: &BStr, protocol_colon: usize) -> Result<crate::Url, Error> { + let input = input_to_utf8(input, UrlKind::Url)?; + let input_after_protocol = &input[protocol_colon + "://".len()..]; + + let Some(first_slash) = input_after_protocol + .find('/') + .or_else(|| cfg!(windows).then(|| input_after_protocol.find('\\')).flatten()) + else { + return Err(Error::MissingRepositoryPath { + url: input.to_owned().into(), + kind: UrlKind::Url, + }); + }; + + // We cannot use the url crate to parse host and path because it special cases Windows + // driver letters. With the url crate an input of `file://x:/path/to/git` is parsed as empty + // host and with `x:/path/to/git` as path. This behavior is wrong for Git which only follows + // that rule on Windows and parses `x:` as host on Unix platforms. Additionally the url crate + // does not account for Windows special UNC path support. + + // TODO: implement UNC path special case + let windows_special_path = if cfg!(windows) { + // Inputs created via url::Url::from_file_path contain an additional `/` between the + // protocol and the absolute path. Make sure we ignore that first slash character to avoid + // producing invalid paths. + let input_after_protocol = if first_slash == 0 { + &input_after_protocol[1..] + } else { + input_after_protocol + }; + // parse `file://x:/path/to/git` as explained above + if input_after_protocol.chars().nth(1) == Some(':') { + Some(input_after_protocol) + } else { + None } - Err(err) => return Err(err.into()), + } else { + None }; - // SCP like URLs without user parse as 'something' with the scheme being the 'host'. Hosts always have dots. - if url.scheme().find('.').is_some() { - // try again with prefixed protocol - url = url::Url::parse(&format!("ssh://{}", sanitize_for_protocol("ssh", url_str)))?; - scp_path = extract_scp_path(url_str); - } - if url.path().is_empty() && ["ssh", "git"].contains(&url.scheme()) { - return Err(Error::MissingResourceLocation); - } - if url.cannot_be_a_base() { - return Err(Error::RelativeUrl { url: url.into() }); - } - let mut url = to_owned_url(url)?; - if let Some(path) = scp_path { - url.path = path.into(); - url.serialize_alternative_form = true; + let host = if windows_special_path.is_some() || first_slash == 0 { + // `file:///path/to/git` or a windows special case was triggered + None + } else { + // `file://host/path/to/git` + Some(&input_after_protocol[..first_slash]) + }; + + // default behavior on Unix platforms and if no Windows special case was triggered + let path = windows_special_path.unwrap_or(&input_after_protocol[first_slash..]); + + Ok(crate::Url { + serialize_alternative_form: false, + host: host.map(Into::into), + ..local(path.into())? + }) +} + +pub(crate) fn local(input: &BStr) -> Result<crate::Url, Error> { + if input.is_empty() { + return Err(Error::MissingRepositoryPath { + url: input.to_owned(), + kind: UrlKind::Local, + }); } - Ok(url) + + Ok(crate::Url { + serialize_alternative_form: true, + scheme: Scheme::File, + password: None, + user: None, + host: None, + port: None, + path: input.to_owned(), + }) +} + +fn input_to_utf8(input: &BStr, kind: UrlKind) -> Result<&str, Error> { + std::str::from_utf8(input).map_err(|source| Error::Utf8 { + url: input.to_owned(), + kind, + source, + }) +} + +fn input_to_utf8_and_url(input: &BStr, kind: UrlKind) -> Result<(&str, url::Url), Error> { + let input = input_to_utf8(input, kind)?; + url::Url::parse(input) + .map(|url| (input, url)) + .map_err(|source| Error::Url { + url: input.to_owned(), + kind, + source, + }) } diff --git a/vendor/gix-url/src/scheme.rs b/vendor/gix-url/src/scheme.rs index 1c5f04526..a50b735c7 100644 --- a/vendor/gix-url/src/scheme.rs +++ b/vendor/gix-url/src/scheme.rs @@ -24,7 +24,8 @@ pub enum Scheme { impl<'a> From<&'a str> for Scheme { fn from(value: &'a str) -> Self { match value { - "ssh" => Scheme::Ssh, + // "ssh+git" and "git+ssh" are legacy, but Git still allows them and so should we + "ssh" | "ssh+git" | "git+ssh" => Scheme::Ssh, "file" => Scheme::File, "git" => Scheme::Git, "http" => Scheme::Http, diff --git a/vendor/gix-url/tests/baseline/main.rs b/vendor/gix-url/tests/baseline/main.rs deleted file mode 100644 index 7843e6e18..000000000 --- a/vendor/gix-url/tests/baseline/main.rs +++ /dev/null @@ -1,217 +0,0 @@ -use bstr::ByteSlice; -use libtest_mimic::{Arguments, Failed, Trial}; - -fn main() { - // We do not need to set this hook back to its default, because this test gets compiled to its - // own binary and does therefore not interfere with other tests. - std::panic::set_hook(Box::new(|_| {})); - - let args = Arguments::from_args(); - let tests = get_baseline_test_cases(); - - libtest_mimic::run(&args, tests).exit(); -} - -fn get_baseline_test_cases() -> Vec<Trial> { - baseline::URLS - .iter() - .map(|(url, expected)| { - Trial::test( - format!("baseline {}", url.to_str().expect("url is valid utf-8")), - move || { - std::panic::catch_unwind(|| { - assert_urls_equal(expected, &gix_url::parse(url).expect("valid urls can be parsed")) - }) - .map_err(|err| { - // Succeeds whenever `panic!` was given a string literal (for example if - // `assert!` is given a string literal). - match err.downcast_ref::<&str>() { - Some(panic_message) => panic_message.into(), - None => { - // Succeeds whenever `panic!` was given an owned String (for - // example when using the `format!` syntax and always for - // `assert_*!` macros). - match err.downcast_ref::<String>() { - Some(panic_message) => panic_message.into(), - None => Failed::without_message(), - } - } - } - }) - }, - ) - .with_ignored_flag(true /* currently most of these fail */) - }) - .collect::<_>() -} - -fn assert_urls_equal(expected: &baseline::GitDiagUrl<'_>, actual: &gix_url::Url) { - assert_eq!( - gix_url::Scheme::from(expected.protocol.to_str().unwrap()), - actual.scheme - ); - - match expected.host { - baseline::GitDiagHost::NonSsh { host_and_port } => match host_and_port { - Some(host_and_port) => { - assert!(actual.host().is_some()); - - let mut gix_host_and_port = String::with_capacity(host_and_port.len()); - - if let Some(user) = actual.user() { - gix_host_and_port.push_str(user); - gix_host_and_port.push('@'); - } - - gix_host_and_port.push_str(actual.host().unwrap()); - - if let Some(port) = actual.port { - gix_host_and_port.push(':'); - gix_host_and_port.push_str(&port.to_string()); - } - - assert_eq!(host_and_port, gix_host_and_port); - } - None => { - assert!(actual.host().is_none()); - assert!(actual.port.is_none()); - } - }, - baseline::GitDiagHost::Ssh { user_and_host, port } => { - match user_and_host { - Some(user_and_host) => { - assert!(actual.host().is_some()); - - let mut gix_user_and_host = String::with_capacity(user_and_host.len()); - if let Some(user) = actual.user() { - gix_user_and_host.push_str(user); - gix_user_and_host.push('@'); - } - gix_user_and_host.push_str(actual.host().unwrap()); - - assert_eq!(user_and_host, gix_user_and_host); - } - None => { - assert!(actual.host().is_none()); - assert!(actual.user().is_none()); - } - } - match port { - Some(port) => { - assert!(actual.port.is_some()); - assert_eq!(port, actual.port.unwrap().to_string()); - } - None => { - assert!(actual.port.is_none()); - } - } - } - } - - match expected.path { - Some(path) => { - assert_eq!(path, actual.path); - } - None => { - // I guess? This case does not happen a single time in the current fixtures... - assert!(actual.path.is_empty()); - } - } -} - -mod baseline { - use bstr::{BStr, BString, ByteSlice}; - use gix_testtools::once_cell::sync::Lazy; - - static BASELINE: Lazy<BString> = Lazy::new(|| { - let base = gix_testtools::scripted_fixture_read_only("make_baseline.sh").unwrap(); - BString::from(std::fs::read(base.join("git-baseline.generic")).expect("fixture file exists")) - }); - - pub static URLS: Lazy<Vec<(&'static BStr, GitDiagUrl<'static>)>> = Lazy::new(|| { - let mut out = Vec::new(); - - let url_block = BASELINE - .split(|c| c == &b';') - .filter(|url| !url.is_empty()) - .map(ByteSlice::trim); - - for block in url_block { - let (url, diag_url) = GitDiagUrl::parse(block.as_bstr()); - out.push((url, diag_url)); - } - out - }); - - #[derive(Debug)] - pub struct GitDiagUrl<'a> { - pub protocol: &'a BStr, - pub host: GitDiagHost<'a>, - pub path: Option<&'a BStr>, - } - - impl GitDiagUrl<'_> { - /// Parses the given string into a [GitDiagUrl] according to the format - /// specified in [Git's `connect.c`][git_src]. - /// - /// [git_src]: https://github.com/git/git/blob/master/connect.c#L1415 - fn parse(diag_url: &BStr) -> (&'_ BStr, GitDiagUrl<'_>) { - let mut lines = diag_url.lines().map(ByteSlice::trim); - let mut next_attr = |name: &str| { - lines - .next() - .expect("well-known format") - .strip_prefix(format!("Diag: {name}=").as_bytes()) - .expect("attribute is at the correct location") - .as_bstr() - }; - - let url = next_attr("url"); - let protocol = next_attr("protocol"); - - let host = if protocol == "ssh" { - let user_and_host = next_attr("userandhost"); - let port = next_attr("port"); - GitDiagHost::Ssh { - user_and_host: if user_and_host == "NULL" { - None - } else { - Some(user_and_host) - }, - port: if port == "NONE" { None } else { Some(port) }, - } - } else { - let host_and_port = next_attr("hostandport"); - GitDiagHost::NonSsh { - host_and_port: if host_and_port == "NULL" { - None - } else { - Some(host_and_port) - }, - } - }; - - let path = next_attr("path"); - assert!(lines.next().is_none(), "we consume everything"); - ( - url, - GitDiagUrl { - protocol, - host, - path: if path == "NULL" { None } else { Some(path) }, - }, - ) - } - } - - #[derive(Debug)] - pub enum GitDiagHost<'a> { - NonSsh { - host_and_port: Option<&'a BStr>, - }, - Ssh { - user_and_host: Option<&'a BStr>, - port: Option<&'a BStr>, - }, - } -} |