Skip to content

Commit 13823fb

Browse files
committed
new sqlpage.url_encode() function
1 parent 2a0646d commit 13823fb

File tree

3 files changed

+79
-6
lines changed

3 files changed

+79
-6
lines changed

CHANGELOG.md

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
- **variables** . SQLPage now support setting and reusing variables between statements. This allows you to write more complex SQL queries, and to reuse the result of a query in multiple places.
66
```sql
77
-- Set a variable
8-
SET person = 'Alice';
8+
SET person = (select username from users where id = $id);
99
-- Use it in a query
1010
SELECT 'text' AS component, 'Hello ' || $person AS contents;
1111
```
@@ -20,6 +20,11 @@
2020
from json_each(sqlpage.exec('curl', 'https://jsonplaceholder.typicode.com/users'));
2121
```
2222
This function is disabled by default for security reasons. To enable it, set the `allow_exec` configuration parameter to `true` in the [configuration](./configuration.md). Enabling it gives full access to the server to anyone who can write SQL queries on your website (this includes users with access to the local filesystem and users with write access to the `sqlpage_files` table on your database), so be careful !
23+
- New `sqlpage.url_encode` function to percent-encode URL parameters.
24+
```sql
25+
select 'card' as component;
26+
select 'More...' as title, 'advanced_search.sql?query=' || sqlpage.url_encode($query)
27+
```
2328

2429
## 0.11.0 (2023-09-17)
2530
- Support for **environment variables** ! You can now read environment variables from sql code using `sqlpage.environment_variable('VAR_NAME')`.

examples/official-site/sqlpage/migrations/08_functions.sql

Lines changed: 43 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -284,11 +284,11 @@ VALUES (
284284
'Returns the current version of SQLPage as a string.'
285285
);
286286
INSERT INTO sqlpage_functions (
287-
"name",
288-
"introduced_in_version",
289-
"icon",
290-
"description_md"
291-
)
287+
"name",
288+
"introduced_in_version",
289+
"icon",
290+
"description_md"
291+
)
292292
VALUES (
293293
'exec',
294294
'0.12.0',
@@ -341,4 +341,42 @@ VALUES (
341341
'arguments...',
342342
'The arguments to pass to the program.',
343343
'TEXT'
344+
);
345+
INSERT INTO sqlpage_functions (
346+
"name",
347+
"introduced_in_version",
348+
"icon",
349+
"description_md"
350+
)
351+
VALUES (
352+
'url_encode',
353+
'0.12.0',
354+
'percentage',
355+
'Returns the given string, with all characters that are not allowed in a URL encoded.
356+
357+
### Example
358+
359+
```sql
360+
select ''text'' as component;
361+
select ''https://example.com/?q='' || sqlpage.url_encode($user_search) as contents;
362+
```
363+
364+
#### Result
365+
366+
`https://example.com/?q=hello%20world`
367+
'
368+
);
369+
INSERT INTO sqlpage_function_parameters (
370+
"function",
371+
"index",
372+
"name",
373+
"description_md",
374+
"type"
375+
)
376+
VALUES (
377+
'url_encode',
378+
1,
379+
'string',
380+
'The string to encode.',
381+
'TEXT'
344382
);

src/webserver/database/sql_pseudofunctions.rs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ pub(super) enum StmtParam {
2626
BasicAuthPassword,
2727
BasicAuthUsername,
2828
HashPassword(Box<StmtParam>),
29+
UrlEncode(Box<StmtParam>),
2930
Exec(Vec<StmtParam>),
3031
RandomString(usize),
3132
CurrentWorkingDir,
@@ -57,6 +58,9 @@ pub(super) fn func_call_to_param(func_name: &str, arguments: &mut [FunctionArg])
5758
"current_working_directory" => StmtParam::CurrentWorkingDir,
5859
"environment_variable" => extract_single_quoted_string("environment_variable", arguments)
5960
.map_or_else(StmtParam::Error, StmtParam::EnvironmentVariable),
61+
"url_encode" => {
62+
StmtParam::UrlEncode(Box::new(extract_variable_argument("url_encode", arguments)))
63+
}
6064
"version" => StmtParam::SqlPageVersion,
6165
unknown_name => StmtParam::Error(format!(
6266
"Unknown function {unknown_name}({})",
@@ -74,10 +78,35 @@ pub(super) async fn extract_req_param<'a>(
7478
Ok(match param {
7579
StmtParam::HashPassword(inner) => has_password_param(inner, request).await?,
7680
StmtParam::Exec(args_params) => exec_external_command(args_params, request).await?,
81+
StmtParam::UrlEncode(inner) => url_encode(inner, request).await?,
7782
_ => extract_req_param_non_nested(param, request)?,
7883
})
7984
}
8085

86+
async fn url_encode<'a>(
87+
inner: &Box<StmtParam>,
88+
request: &'a RequestInfo,
89+
) -> Result<Option<Cow<'a, str>>, anyhow::Error> {
90+
let param = extract_req_param_non_nested(inner, request);
91+
match param {
92+
Ok(Some(Cow::Borrowed(inner))) => {
93+
let encoded = percent_encoding::percent_encode(
94+
inner.as_bytes(),
95+
percent_encoding::NON_ALPHANUMERIC,
96+
);
97+
Ok(Some(encoded.into()))
98+
}
99+
Ok(Some(Cow::Owned(inner))) => {
100+
let encoded = percent_encoding::percent_encode(
101+
inner.as_bytes(),
102+
percent_encoding::NON_ALPHANUMERIC,
103+
);
104+
Ok(Some(Cow::Owned(encoded.to_string())))
105+
}
106+
param => param,
107+
}
108+
}
109+
81110
async fn exec_external_command<'a>(
82111
args_params: &[StmtParam],
83112
request: &'a RequestInfo,
@@ -141,6 +170,7 @@ pub(super) fn extract_req_param_non_nested<'a>(
141170
.map(Some)?,
142171
StmtParam::HashPassword(_) => bail!("Nested hash_password() function not allowed"),
143172
StmtParam::Exec(_) => bail!("Nested exec() function not allowed"),
173+
StmtParam::UrlEncode(_) => bail!("Nested url_encode() function not allowed"),
144174
StmtParam::RandomString(len) => Some(Cow::Owned(random_string(*len))),
145175
StmtParam::CurrentWorkingDir => cwd()?,
146176
StmtParam::EnvironmentVariable(var) => std::env::var(var)

0 commit comments

Comments
 (0)