Skip to main content

qubit_http/options/
http_retry_method_policy.rs

1/*******************************************************************************
2 *
3 *    Copyright (c) 2025 - 2026 Haixing Hu.
4 *
5 *    SPDX-License-Identifier: Apache-2.0
6 *
7 *    Licensed under the Apache License, Version 2.0.
8 *
9 ******************************************************************************/
10
11use std::str::FromStr;
12
13use http::Method;
14use parse_display::FromStr as DeriveFromStr;
15use serde::{
16    Deserialize,
17    Serialize,
18};
19
20use super::HttpConfigError;
21
22/// HTTP method policy used to decide whether a request can be retried.
23#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize, DeriveFromStr)]
24#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
25pub enum HttpRetryMethodPolicy {
26    /// Retry only HTTP methods that are safe to replay by default.
27    #[default]
28    #[display("IDEMPOTENT_ONLY")]
29    #[from_str(regex = "(?i)IDEMPOTENT_ONLY|IDEMPOTENT")]
30    IdempotentOnly,
31    /// Retry all HTTP methods, including `POST` and `PATCH`.
32    #[display("ALL_METHODS")]
33    #[from_str(regex = "(?i)ALL_METHODS|ALL")]
34    AllMethods,
35    /// Disable method-level retry eligibility.
36    #[display("NONE")]
37    #[from_str(regex = "(?i)NONE|DISABLED")]
38    None,
39}
40
41impl HttpRetryMethodPolicy {
42    pub(super) fn from_config_value(value: &str) -> Result<Self, HttpConfigError> {
43        Self::from_str(value.trim()).map_err(|_| {
44            HttpConfigError::invalid_value(
45                "method_policy",
46                format!("Unsupported retry method policy: {value}"),
47            )
48        })
49    }
50
51    /// Returns whether the retry executor permits replaying `method`.
52    ///
53    /// # Parameters
54    /// - `method`: HTTP method to evaluate.
55    ///
56    /// # Returns
57    /// `true` when automatic retry may replay the method.
58    pub fn allows_method(&self, method: &Method) -> bool {
59        match self {
60            Self::IdempotentOnly => matches!(
61                *method,
62                Method::GET
63                    | Method::HEAD
64                    | Method::PUT
65                    | Method::DELETE
66                    | Method::OPTIONS
67                    | Method::TRACE
68            ),
69            Self::AllMethods => true,
70            Self::None => false,
71        }
72    }
73}