Showing the changes to git-protocol/src (1 of 1 file). Show all
Unified · Split
| @@ -84,36 +84,6 @@ impl From<client::Capabilities> for Capabilities { · 83 unmodified lines | |||
| 84 | // V1 | 84 | // V1 |
| 85 | // 0098want 808e50d724f604f69ab93c6da2919c014667bedb multi_ack_detailed no-done side-band-64k thin-pack ofs-delta deepen-since deepen-not agent=git/2.28.0 | 85 | // 0098want 808e50d724f604f69ab93c6da2919c014667bedb multi_ack_detailed no-done side-band-64k thin-pack ofs-delta deepen-since deepen-not agent=git/2.28.0 |
| 86 | 86 | ||
| 87 | /// This is only needed because for some reason, a match statement takes the drop scope of the enclosing scope, and not of | ||
| 88 | /// the match arm. This makes it think that a borrowed Ok(value) is still in scope, even though we are in the Err(err) branch. | ||
| 89 | /// The idea here is that we can workaround this by setting the scope to the level of the function, by splitting everything up accordingly. | ||
| 90 | /// Tracking issue: https://github.com/rust-lang/rust/issues/76149 - discarded, as currently documented/known behaviour. | ||
| 91 | fn perform_handshake<'a, F: FnMut(credentials::Action) -> credentials::Result>( | ||
| 92 | transport: &'a mut impl client::Transport, | ||
| 93 | delegate: &mut impl Delegate, | ||
| 94 | mut authenticate: Option<&mut F>, | ||
| 95 | out: &mut Option<credentials::NextAction>, | ||
| 96 | ) -> Result<client::SetServiceResponse<'a>, Error> { | ||
| 97 | if let Some(authenticate) = authenticate.as_mut() { | ||
| 98 | let url = transport.to_url(); | ||
| 99 | let credentials::Outcome { identity, next } = authenticate(credentials::Action::Fill(&url))?; | ||
| 100 | transport.set_identity(identity)?; | ||
| 101 | // Remember the output of the authentication function to provide in case we still error with | ||
| 102 | // a permission issue. | ||
| 103 | *out = Some(next); | ||
| 104 | }; | ||
| 105 | |||
| 106 | let response = transport.handshake(Service::UploadPack)?; | ||
| 107 | if let Some(authenticate) = authenticate { | ||
| 108 | authenticate( | ||
| 109 | out.take() | ||
| 110 | .expect("we put next action in before if an authenticator is present") | ||
| 111 | .approve(), | ||
| 112 | )?; | ||
| 113 | } | ||
| 114 | Ok(response) | ||
| 115 | } | ||
| 116 | |||
| 117 | /// This types sole purpose is to 'disable' the destructor on the Box provided in the `SetServiceResponse` type | 87 | /// This types sole purpose is to 'disable' the destructor on the Box provided in the `SetServiceResponse` type |
| 118 | /// by leaking the box. We provide a method to restore the box and drop it right away to not actually leak. | 88 | /// by leaking the box. We provide a method to restore the box and drop it right away to not actually leak. |
| 119 | /// However, we do leak in error cases because we don't call the manual destructor then. | 89 | /// However, we do leak in error cases because we don't call the manual destructor then. |
| @@ -140,7 +110,9 @@ impl<'a> LeakedSetServiceResponse<'a> { · 20 unmodified lines | |||
| 140 | if let Some(b) = self.refs.take() { | 110 | if let Some(b) = self.refs.take() { |
| 141 | // SAFETY: We are bound to lifetime 'a, which is the lifetime of the thing pointed to by the trait object in the box. | 111 | // SAFETY: We are bound to lifetime 'a, which is the lifetime of the thing pointed to by the trait object in the box. |
| 142 | // Thus we can only drop the box while that thing is indeed valid, due to Rusts standard lifetime rules. | 112 | // Thus we can only drop the box while that thing is indeed valid, due to Rusts standard lifetime rules. |
| 143 | // The box itself was leaked by us | 113 | // The box itself was leaked by us. |
| 114 | // Note that this is only required because Drop scopes are the outer ones in the match, not the match arms, making them | ||
| 115 | // too broad to be usable intuitively. I consider this a technical shortcoming and hope there is a way to resolve it. | ||
| 144 | #[allow(unsafe_code)] | 116 | #[allow(unsafe_code)] |
| 145 | unsafe { | 117 | unsafe { |
| 146 | drop(Box::from_raw(b as *mut _)) | 118 | drop(Box::from_raw(b as *mut _)) |
| @@ -154,32 +126,32 @@ pub fn fetch<F: FnMut(credentials::Action) -> credentials::Result>( · 7 unmodified lines | |||
| 154 | mut delegate: impl Delegate, | 126 | mut delegate: impl Delegate, |
| 155 | mut authenticate: F, | 127 | mut authenticate: F, |
| 156 | ) -> Result<(), Error> { | 128 | ) -> Result<(), Error> { |
| 157 | let mut next = None; | 129 | let mut res: LeakedSetServiceResponse = match transport.handshake(Service::UploadPack).map(Into::into) { |
| 158 | let mut res: LeakedSetServiceResponse = | 130 | Ok(v) => Ok(v), |
| 159 | match perform_handshake(&mut transport, &mut delegate, None::<&mut F>, &mut next).map(Into::into) { | 131 | Err(client::Error::Io { err }) if err.kind() == io::ErrorKind::PermissionDenied => { |
| 160 | Ok(v) => Ok(v), | 132 | let url = transport.to_url(); |
| 161 | Err(Error::Transport(client::Error::Io { err })) if err.kind() == io::ErrorKind::PermissionDenied => { | 133 | let credentials::Outcome { identity, next } = authenticate(credentials::Action::Fill(&url))?; |
| 162 | perform_handshake(&mut transport, &mut delegate, Some(&mut authenticate), &mut next) | 134 | transport.set_identity(identity)?; |
| 163 | .map_err(|err| { | 135 | match transport.handshake(Service::UploadPack).map(Into::into) { |
| 164 | if let Some(next) = next { | 136 | Ok(v) => { |
| 165 | match &err { | 137 | authenticate(next.approve())?; |
| 166 | // Still no permission? Reject the credentials | 138 | Ok(v) |
| 167 | Error::Transport(client::Error::Io { err }) | 139 | } |
| 168 | if err.kind() == io::ErrorKind::PermissionDenied => | 140 | // Still no permission? Reject the credentials. |
| 169 | { | 141 | Err(client::Error::Io { err }) if err.kind() == io::ErrorKind::PermissionDenied => { |
| 170 | authenticate(next.reject()) | 142 | authenticate(next.reject())?; |
| 171 | } | 143 | Err(client::Error::Io { err }.into()) |
| 172 | // Otherwise it's some other error, still OK to approve the credentials | 144 | } |
| 173 | _ => authenticate(next.approve()), | 145 | // Otherwise it's some other error, still OK to approve the credentials. We also do this to not accidentally |
| 174 | } | 146 | // discard credentials that have been previously stored. |
| 175 | .ok(); | 147 | Err(err) => { |
| 176 | }; | 148 | authenticate(next.approve())?; |
| 177 | err | 149 | Err(err.into()) |
| 178 | }) | 150 | } |
| 179 | .map(Into::into) | ||
| 180 | } | 151 | } |
| 181 | Err(err) => Err(err), | 152 | } |
| 182 | }?; | 153 | Err(err) => Err(err), |
| 154 | }?; | ||
| 183 | 155 | ||
| 184 | delegate.adjust_capabilities(res.actual_protocol, &mut res.capabilities); | 156 | delegate.adjust_capabilities(res.actual_protocol, &mut res.capabilities); |
| 185 | res.capabilities.set_agent_version(); | 157 | res.capabilities.set_agent_version(); |