Internal function to execute the HTTP request
(
client: Client,
method: HttpMethod,
url: String,
headers: Vec<Header>,
body: RequestBody,
)
| 64 | |
| 65 | /// Internal function to execute the HTTP request |
| 66 | async fn execute_request( |
| 67 | client: Client, |
| 68 | method: HttpMethod, |
| 69 | url: String, |
| 70 | headers: Vec<Header>, |
| 71 | body: RequestBody, |
| 72 | ) -> Result<ResponseData> { |
| 73 | // Validate URL |
| 74 | if url.is_empty() { |
| 75 | return Err(anyhow!("URL cannot be empty")); |
| 76 | } |
| 77 | |
| 78 | // Ensure URL has a scheme |
| 79 | let url = if !url.starts_with("http://") && !url.starts_with("https://") { |
| 80 | format!("https://{}", url) |
| 81 | } else { |
| 82 | url.to_string() |
| 83 | }; |
| 84 | |
| 85 | let start = Instant::now(); |
| 86 | let request_url = url.clone(); |
| 87 | |
| 88 | // Build request |
| 89 | let mut request = match method { |
| 90 | HttpMethod::Get => client.get(&url), |
| 91 | HttpMethod::Post => client.post(&url), |
| 92 | HttpMethod::Put => client.put(&url), |
| 93 | HttpMethod::Delete => client.delete(&url), |
| 94 | HttpMethod::Patch => client.patch(&url), |
| 95 | HttpMethod::Head => client.head(&url), |
| 96 | HttpMethod::Options => client.request(reqwest::Method::OPTIONS, &url), |
| 97 | }; |
| 98 | |
| 99 | // Check if this is a multipart request |
| 100 | let is_multipart = matches!(body, RequestBody::MultipartFormData(_)); |
| 101 | |
| 102 | // Track headers we actually send so the Headers tab can show them |
| 103 | let mut request_headers: HashMap<String, String> = HashMap::new(); |
| 104 | |
| 105 | // Add headers (skip Content-Type for multipart - reqwest sets it with boundary) |
| 106 | for header in headers.iter().filter(|h| h.enabled) { |
| 107 | if is_multipart && header.key.to_lowercase() == "content-type" { |
| 108 | continue; |
| 109 | } |
| 110 | request = request.header(&header.key, &header.value); |
| 111 | // Prefer later values if the same key appears twice |
| 112 | request_headers.insert(header.key.to_ascii_lowercase(), header.value.clone()); |
| 113 | } |
| 114 | |
| 115 | // Add body |
| 116 | request = match &body { |
| 117 | RequestBody::None => request, |
| 118 | RequestBody::Text(text) => request.body(text.clone()), |
| 119 | RequestBody::Json(json) => { |
| 120 | let normalized_json = match serde_json::from_str::<serde_json::Value>(json) { |
| 121 | Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| json.clone()), |
| 122 | Err(e) => { |
| 123 | log::warn!("Invalid JSON, sending as-is: {}", e); |