Skip to content

Commit 302e02b

Browse files
committed
ensure relative file path given to read_file_* functions are always interpreted relative to the web root.
also adds support for reading files from the databases file table
1 parent e669011 commit 302e02b

File tree

2 files changed

+35
-6
lines changed

2 files changed

+35
-6
lines changed

examples/official-site/sqlpage/migrations/25_read_file_as_text.sql

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,19 @@ VALUES (
1313
1414
The file must be a raw text file using UTF-8 encoding.
1515
16+
The file path is relative to the `web root` directory, which is the directory from which your website is served
17+
(not necessarily the directory SQLPage is launched from).
18+
19+
If the given argument is null, the function will return null.
20+
21+
As with other functions, if an error occurs during execution
22+
(because the file does not exist, for instance),
23+
the function will display an error message and the
24+
database query will not be executed.
25+
26+
If `database_filesystem_table` is set to a table name in SQLPage''s configuration,
27+
the function will attempt to read the file from the database filesystem if it is not found on the local disk.
28+
1629
## Example
1730
1831
### Rendering a markdown file

src/webserver/database/sql_pseudofunctions.rs

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,26 @@ async fn exec_external_command<'a>(
189189
)))
190190
}
191191

192+
async fn read_file_bytes<'a>(
193+
path_str: &str,
194+
request: &'a RequestInfo,
195+
) -> Result<Vec<u8>, anyhow::Error> {
196+
let path = std::path::Path::new(path_str);
197+
// If the path is relative, it's relative to the web root, not the current working directory,
198+
// and it can be fetched from the on-database filesystem table
199+
if path.is_relative() {
200+
request
201+
.app_state
202+
.file_system
203+
.read_file(&request.app_state, path, true)
204+
.await
205+
} else {
206+
tokio::fs::read(path)
207+
.await
208+
.with_context(|| format!("Unable to read file {path:?}"))
209+
}
210+
}
211+
192212
async fn read_file_as_text<'a>(
193213
param0: &StmtParam,
194214
request: &'a RequestInfo,
@@ -197,9 +217,7 @@ async fn read_file_as_text<'a>(
197217
log::debug!("read_file: first argument is NULL, returning NULL");
198218
return Ok(None);
199219
};
200-
let bytes = tokio::fs::read(evaluated_param.as_ref())
201-
.await
202-
.with_context(|| format!("Unable to read file {evaluated_param}"))?;
220+
let bytes = read_file_bytes(&evaluated_param, request).await?;
203221
let as_str = String::from_utf8(bytes)
204222
.with_context(|| format!("read_file_as_text: {param0:?} does not contain raw UTF8 text"))?;
205223
Ok(Some(Cow::Owned(as_str)))
@@ -213,9 +231,7 @@ async fn read_file_as_data_url<'a>(
213231
log::debug!("read_file: first argument is NULL, returning NULL");
214232
return Ok(None);
215233
};
216-
let bytes = tokio::fs::read(evaluated_param.as_ref())
217-
.await
218-
.with_context(|| format!("Unable to read file {evaluated_param}"))?;
234+
let bytes = read_file_bytes(&evaluated_param, request).await?;
219235
let mime = mime_from_upload(param0, request).map_or_else(
220236
|| Cow::Owned(mime_guess_from_filename(&evaluated_param)),
221237
Cow::Borrowed,

0 commit comments

Comments
 (0)