| 866 | 866 | | default_branch: Option<&str>, |
| 867 | 867 | | limits: PushLimits, |
| 868 | 868 | | scan: impl AsyncFnOnce(&[u8]) -> Result<Option<Response>>, |
| 869 | + | timing: &mut Timing, |
| 869 | 870 | | ) -> Result<Push> { |
| 870 | 871 | | let headers = Headers::new(); |
| 871 | 872 | | headers.set("authorization", &format!("Bearer {}", access.token))?; |
| ⋯ |
| 881 | 882 | | let namespace = crate::store::health_namespace(&access.remote); |
| 882 | 883 | | |
| 883 | 884 | | if method == Method::Post && git.endpoint == "git-receive-pack" { |
| 884 | | − | return push(request, &url, headers, rules, limits, scan, &namespace).await; |
| 885 | + | return push(request, &url, headers, rules, limits, scan, &namespace, timing).await; |
| 885 | 886 | | } |
| 886 | 887 | | |
| 887 | 888 | | // A read: the ref advertisement, `ls-refs`, or a fetch of objects. |
| ⋯ |
| 962 | 963 | | })) |
| 963 | 964 | | } |
| 964 | 965 | | |
| 965 | | − | /// A receive-pack request; see [`forward`]. |
| 966 | + | /// A receive-pack request; see [`forward`]. Its steps: `recv` (the push |
| 967 | + | /// read), `rules`, `scan` (push protection), `upload` (the store's answer). |
| 966 | 968 | | #[allow(clippy::too_many_arguments)] |
| 967 | 969 | | async fn push( |
| 968 | 970 | | mut request: Request, |
| ⋯ |
| 972 | 974 | | limits: PushLimits, |
| 973 | 975 | | scan: impl AsyncFnOnce(&[u8]) -> Result<Option<Response>>, |
| 974 | 976 | | namespace: &str, |
| 977 | + | timing: &mut Timing, |
| 975 | 978 | | ) -> Result<Push> { |
| 976 | 979 | | let mut stream = request.stream()?; |
| 977 | 980 | | let mut head: Vec<u8> = Vec::new(); |
| ⋯ |
| 993 | 996 | | } |
| 994 | 997 | | } |
| 995 | 998 | | } |
| 999 | + | timing.mark("recv"); |
| 996 | 1000 | | // The rules of the branches and tags it changes, first: what they |
| 997 | 1001 | | // refuse is refused whatever else is wrong with it. |
| 998 | | − | if let Some(response) = rules(&head, ended).await? { |
| 1002 | + | let ruled = rules(&head, ended).await?; |
| 1003 | + | timing.mark("rules"); |
| 1004 | + | if let Some(response) = ruled { |
| 999 | 1005 | | if !ended { |
| 1000 | 1006 | | drain(&mut stream).await?; |
| 1001 | 1007 | | } |
| ⋯ |
| 1018 | 1024 | | init.with_method(Method::Post).with_headers(headers); |
| 1019 | 1025 | | let started = g1t_kit::now_ms(); |
| 1020 | 1026 | | let (answered, pack_bytes, sent, unscanned) = if ended { |
| 1021 | | − | if let Some(response) = scan(&head).await? { |
| 1027 | + | let scanned = scan(&head).await?; |
| 1028 | + | timing.mark("scan"); |
| 1029 | + | if let Some(response) = scanned { |
| 1022 | 1030 | | return Ok(Push::Blocked(response)); |
| 1023 | 1031 | | } |
| 1024 | 1032 | | let pack = pack_bytes(&head); |
| ⋯ |
| 1061 | 1069 | | (answered, pack, first + walked.1, true) |
| 1062 | 1070 | | }; |
| 1063 | 1071 | | let ms = g1t_kit::now_ms().saturating_sub(started); |
| 1072 | + | timing.mark("upload"); |
| 1064 | 1073 | | let failure = match &answered { |
| 1065 | 1074 | | Ok(response) => resilience::classify_status(response.status_code()), |
| 1066 | 1075 | | Err(_) => Some(Failure::Transient), |