History

fix: make it possible to parse handshakes without newlines in packetlines #(639)

Sebastian Thiel committed 3 years ago

Commit 4927adf1 parent 7ab7c243 files · +100 −4Browse files

Unified · Split

3 files
  1. git-transport/src/client/capabilities.rs +26 −4
  2. git-transport/tests/client/blocking_io/http/mod.rs +59 −0
  3. git-transport/tests/fixtures/v2/http-no-newlines-handshake.response +15 −0
git-transport/src/client/capabilities.rs+26−4
@@ -152,8 +152,8 @@ impl Capabilities { · 151 unmodified lines
152#[cfg(feature = "blocking-client")]152#[cfg(feature = "blocking-client")]
153///153///
154pub mod recv {154pub mod recv {
155 use bstr::ByteVec;
155 use std::io;156 use std::io;
156 use std::io::Read;
157 157
158 use crate::{client, client::Capabilities, Protocol};158 use crate::{client, client::Capabilities, Protocol};
159 159
@@ -204,7 +204,18 @@ pub mod recv { · 44 unmodified lines
204 capabilities: {204 capabilities: {
205 let mut rd = rd.as_read();205 let mut rd = rd.as_read();
206 let mut buf = Vec::new();206 let mut buf = Vec::new();
207 rd.read_to_end(&mut buf)?;207 while let Some(line) = rd.read_data_line() {
208 let line = line??;
209 match line.as_bstr() {
210 Some(line) => {
211 buf.push_str(line);
212 if buf.last() != Some(&b'\n') {
213 buf.push(b'\n');
214 }
215 }
216 None => break,
217 }
218 }
208 Capabilities::from_lines(buf.into())?219 Capabilities::from_lines(buf.into())?
209 },220 },
210 refs: None,221 refs: None,
@@ -220,9 +231,9 @@ pub mod recv { · 9 unmodified lines
220///231///
221pub mod recv {232pub mod recv {
222 use futures_io::AsyncRead;233 use futures_io::AsyncRead;
223 use futures_lite::AsyncReadExt;
224 234
225 use crate::{client, client::Capabilities, Protocol};235 use crate::{client, client::Capabilities, Protocol};
236 use bstr::ByteVec;
226 237
227 /// Success outcome of [`Capabilities::from_lines_with_version_detection`].238 /// Success outcome of [`Capabilities::from_lines_with_version_detection`].
228 pub struct Outcome<'a> {239 pub struct Outcome<'a> {
@@ -272,7 +283,18 @@ pub mod recv { · 43 unmodified lines
272 capabilities: {283 capabilities: {
273 let mut rd = rd.as_read();284 let mut rd = rd.as_read();
274 let mut buf = Vec::new();285 let mut buf = Vec::new();
275 rd.read_to_end(&mut buf).await?;286 while let Some(line) = rd.read_data_line().await {
287 let line = line??;
288 match line.as_bstr() {
289 Some(line) => {
290 buf.push_str(line);
291 if buf.last() != Some(&b'\n') {
292 buf.push(b'\n');
293 }
294 }
295 None => break,
296 }
297 }
276 Capabilities::from_lines(buf.into())?298 Capabilities::from_lines(buf.into())?
277 },299 },
278 refs: None,300 refs: None,
git-transport/tests/client/blocking_io/http/mod.rs+59−0
@@ -335,6 +335,65 @@ fn handshake_and_lsrefs_and_fetch_v2() -> crate::Result { · 334 unmodified lines
335 handshake_and_lsrefs_and_fetch_v2_impl("v2/http-handshake.response")335 handshake_and_lsrefs_and_fetch_v2_impl("v2/http-handshake.response")
336}336}
337 337
338#[test]
339fn handshake_and_lsrefs_and_fetch_v2_googlesource() -> crate::Result {
340 let (_server, mut c) = mock::serve_and_connect(
341 "v2/http-no-newlines-handshake.response",
342 "path/not/important/due/to/mock",
343 Protocol::V2,
344 )?;
345 assert!(
346 !c.connection_persists_across_multiple_requests(),
347 "http connections are never stateful"
348 );
349 let SetServiceResponse {
350 actual_protocol,
351 capabilities,
352 refs,
353 } = c.handshake(Service::UploadPack, &[("value-only", None), ("key", Some("value"))])?;
354 assert_eq!(actual_protocol, Protocol::V2);
355 assert!(
356 refs.is_none(),
357 "refs are only returned in V1, as V2 favors a separate command (with more options)"
358 );
359 assert_eq!(
360 capabilities
361 .iter()
362 .map(|v| {
363 (
364 v.name().to_owned(),
365 v.values().map(|v| v.map(ToOwned::to_owned).collect::<Vec<_>>()),
366 )
367 })
368 .collect::<Vec<_>>(),
369 [
370 ("ls-refs", None),
371 (
372 "fetch",
373 Some(
374 &[
375 "filter",
376 "ref-in-want",
377 "sideband-all",
378 "packfile-uris",
379 "wait-for-done",
380 "shallow"
381 ][..]
382 )
383 ),
384 ("server-option", None),
385 ("session-id", None),
386 ]
387 .iter()
388 .map(|(k, v)| (
389 k.as_bytes().into(),
390 v.map(|v| v.iter().map(|v| v.as_bytes().into()).collect::<Vec<_>>())
391 ))
392 .collect::<Vec<_>>()
393 );
394 Ok(())
395}
396
338#[test]397#[test]
339fn handshake_and_lsrefs_and_fetch_v2_service_announced() -> crate::Result {398fn handshake_and_lsrefs_and_fetch_v2_service_announced() -> crate::Result {
340 handshake_and_lsrefs_and_fetch_v2_impl("v2/http-handshake-service-announced.response")399 handshake_and_lsrefs_and_fetch_v2_impl("v2/http-handshake-service-announced.response")
git-transport/tests/fixtures/v2/http-no-newlines-handshake.response+15−0
@@ -0,0 +1,15 @@
1HTTP/1.1 200 OK
2Cache-Control: no-cache, max-age=0, must-revalidate
3Content-Length: 136
4Content-Security-Policy-Report-Only: script-src 'nonce-3J1VJWYTKuii1QtanCSwhA' 'unsafe-inline' 'strict-dynamic' https: http: 'unsafe-eval';object-src 'none';base-uri 'self';report-uri https://csp.withgoogle.com/csp/gerritcodereview/1
5Content-Type: application/x-git-upload-pack-advertisement
6Expires: Fri, 01 Jan 1980 00:00:00 GMT
7Pragma: no-cache
8Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
9X-Content-Type-Options: nosniff
10X-Frame-Options: SAMEORIGIN
11X-Xss-Protection: 0
12Date: Sun, 04 Dec 2022 10:16:06 GMT
13Alt-Svc: h3=":443"; ma=2592000,h3-29=":443"; ma=2592000,h3-Q050=":443"; ma=2592000,h3-Q046=":443"; ma=2592000,h3-Q043=":443"; ma=2592000,quic=":443"; ma=2592000; v="46,43"
14
15000dversion 2000bls-refs004dfetch=filter ref-in-want sideband-all packfile-uris wait-for-done shallow0011server-option000esession-id0000