Skip to content

Commit 515931e

Browse files
committed
improve sqlpage.fetch error handling
1 parent 57e3a7e commit 515931e

File tree

2 files changed

+28
-9
lines changed

2 files changed

+28
-9
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
- The previous behavior was to try paresing a new statement after a syntax error, leading to a cascade of irrelevant error messages after a syntax error.
2121
- Allow giving an id to HTML rows in the table component. This allows making links to specific rows in the table using anchor links. (`my-table.sql#myid`)
2222
- Fixed a bug where long menu items in the shell component's menu would wrap on multiple lines.
23+
- Much better error messages when a call to sqlpage.fetch fails.
2324

2425
## 0.26.0 (2024-08-06)
2526
### Components

src/webserver/database/sqlpage_functions/functions.rs

Lines changed: 27 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -133,10 +133,11 @@ async fn fetch(
133133
http_request: super::http_fetch_request::HttpFetchRequest<'_>,
134134
) -> anyhow::Result<String> {
135135
use awc::http::Method;
136-
let client = make_http_client(&request.app_state.config)?;
136+
let client = make_http_client(&request.app_state.config)
137+
.with_context(|| "Unable to create an HTTP client")?;
137138

138139
let method = if let Some(method) = http_request.method {
139-
Method::from_str(&method)?
140+
Method::from_str(&method).with_context(|| format!("Invalid HTTP method: {method}"))?
140141
} else {
141142
Method::GET
142143
};
@@ -152,7 +153,9 @@ async fn fetch(
152153
let val = body.get();
153154
// The body can be either json, or a string representing a raw body
154155
let body = if val.starts_with('"') {
155-
serde_json::from_str::<'_, String>(val)?
156+
serde_json::from_str::<'_, String>(val).with_context(|| {
157+
format!("Invalid JSON string in the body of the HTTP request: {val}")
158+
})?
156159
} else {
157160
req = req.content_type("application/json");
158161
val.to_owned()
@@ -168,26 +171,41 @@ async fn fetch(
168171
http_request.url,
169172
response.status()
170173
);
171-
let body = response.body().await?.to_vec();
172-
let response_str = String::from_utf8(body)?;
174+
let body = response
175+
.body()
176+
.await
177+
.with_context(|| {
178+
format!(
179+
"Unable to read the body of the response from {}",
180+
http_request.url
181+
)
182+
})?
183+
.to_vec();
184+
let response_str = String::from_utf8(body).with_context(
185+
|| format!("Unable to convert the response from {} to a string. Only UTF-8 responses are supported.", http_request.url),
186+
)?;
173187
log::debug!("Fetch response: {response_str}");
174188
Ok(response_str)
175189
}
176190

177-
static NATIVE_CERTS: OnceLock<std::io::Result<rustls::RootCertStore>> = OnceLock::new();
191+
static NATIVE_CERTS: OnceLock<anyhow::Result<rustls::RootCertStore>> = OnceLock::new();
178192

179193
fn make_http_client(config: &crate::app_config::AppConfig) -> anyhow::Result<awc::Client> {
180194
let connector = if config.system_root_ca_certificates {
181195
let roots = NATIVE_CERTS
182196
.get_or_init(|| {
183-
let certs = rustls_native_certs::load_native_certs()?;
197+
let certs = rustls_native_certs::load_native_certs()
198+
.with_context(|| "Initial native certificates load failed")?;
184199
let mut roots = rustls::RootCertStore::empty();
185200
for cert in certs {
186-
roots.add(cert.clone()).unwrap();
201+
roots.add(cert.clone()).with_context(|| {
202+
format!("Unable to add certificate to root store: {cert:?}")
203+
})?;
187204
}
188205
Ok(roots)
189206
})
190-
.as_ref()?;
207+
.as_ref()
208+
.map_err(|e| anyhow!("Unable to load native certificates, make sure the system root CA certificates are available: {e}"))?;
191209

192210
let tls_conf = rustls::ClientConfig::builder()
193211
.with_root_certificates(roots.clone())

0 commit comments

Comments
 (0)