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 | 84 | // V1 |
| 85 | 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 | 87 | /// This types sole purpose is to 'disable' the destructor on the Box provided in the `SetServiceResponse` type |
| 118 | 88 | /// by leaking the box. We provide a method to restore the box and drop it right away to not actually leak. |
| 119 | 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 | 110 | if let Some(b) = self.refs.take() { |
| 141 | 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 | 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 | 116 | #[allow(unsafe_code)] |
| 145 | 117 | unsafe { |
| 146 | 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 | 126 | mut delegate: impl Delegate, |
| 155 | 127 | mut authenticate: F, |
| 156 | 128 | ) -> Result<(), Error> { |
| 157 | − let mut next = None; | |
| 158 | − let mut res: LeakedSetServiceResponse = | |
| 159 | − match perform_handshake(&mut transport, &mut delegate, None::<&mut F>, &mut next).map(Into::into) { | |
| 160 | − Ok(v) => Ok(v), | |
| 161 | − Err(Error::Transport(client::Error::Io { err })) if err.kind() == io::ErrorKind::PermissionDenied => { | |
| 162 | − perform_handshake(&mut transport, &mut delegate, Some(&mut authenticate), &mut next) | |
| 163 | − .map_err(|err| { | |
| 164 | − if let Some(next) = next { | |
| 165 | − match &err { | |
| 166 | − // Still no permission? Reject the credentials | |
| 167 | − Error::Transport(client::Error::Io { err }) | |
| 168 | − if err.kind() == io::ErrorKind::PermissionDenied => | |
| 169 | − { | |
| 170 | − authenticate(next.reject()) | |
| 171 | − } | |
| 172 | − // Otherwise it's some other error, still OK to approve the credentials | |
| 173 | − _ => authenticate(next.approve()), | |
| 174 | − } | |
| 175 | − .ok(); | |
| 176 | − }; | |
| 177 | − err | |
| 178 | − }) | |
| 179 | − .map(Into::into) | |
| 129 | + let mut res: LeakedSetServiceResponse = match transport.handshake(Service::UploadPack).map(Into::into) { | |
| 130 | + Ok(v) => Ok(v), | |
| 131 | + Err(client::Error::Io { err }) if err.kind() == io::ErrorKind::PermissionDenied => { | |
| 132 | + let url = transport.to_url(); | |
| 133 | + let credentials::Outcome { identity, next } = authenticate(credentials::Action::Fill(&url))?; | |
| 134 | + transport.set_identity(identity)?; | |
| 135 | + match transport.handshake(Service::UploadPack).map(Into::into) { | |
| 136 | + Ok(v) => { | |
| 137 | + authenticate(next.approve())?; | |
| 138 | + Ok(v) | |
| 139 | + } | |
| 140 | + // Still no permission? Reject the credentials. | |
| 141 | + Err(client::Error::Io { err }) if err.kind() == io::ErrorKind::PermissionDenied => { | |
| 142 | + authenticate(next.reject())?; | |
| 143 | + Err(client::Error::Io { err }.into()) | |
| 144 | + } | |
| 145 | + // Otherwise it's some other error, still OK to approve the credentials. We also do this to not accidentally | |
| 146 | + // discard credentials that have been previously stored. | |
| 147 | + Err(err) => { | |
| 148 | + authenticate(next.approve())?; | |
| 149 | + Err(err.into()) | |
| 150 | + } | |
| 180 | 151 | } |
| 181 | − Err(err) => Err(err), | |
| 182 | − }?; | |
| 152 | + } | |
| 153 | + Err(err) => Err(err), | |
| 154 | + }?; | |
| 183 | 155 | |
| 184 | 156 | delegate.adjust_capabilities(res.actual_protocol, &mut res.capabilities); |
| 185 | 157 | res.capabilities.set_agent_version(); |