Improve URL encoding and decoding
This commit is contained in:
parent
26b4b20c1d
commit
2bfdf0ef49
|
@ -15,6 +15,8 @@ askama = "0.10"
|
||||||
argh = "0.1.6"
|
argh = "0.1.6"
|
||||||
serde = "1.0"
|
serde = "1.0"
|
||||||
serde_yaml = "0.8"
|
serde_yaml = "0.8"
|
||||||
|
form_urlencoded = "1.0.1"
|
||||||
|
percent-encoding = "2.1.0"
|
||||||
rusttype = { version = "0.9.2", optional = true }
|
rusttype = { version = "0.9.2", optional = true }
|
||||||
image = { version = "0.23.14", optional = true }
|
image = { version = "0.23.14", optional = true }
|
||||||
lazy_static = { version = "1.4.0", optional = true }
|
lazy_static = { version = "1.4.0", optional = true }
|
||||||
|
|
|
@ -3,13 +3,14 @@ pub mod contrast;
|
||||||
pub mod statics;
|
pub mod statics;
|
||||||
pub mod configuration;
|
pub mod configuration;
|
||||||
|
|
||||||
use std::collections::HashMap;
|
|
||||||
use crate::configuration::Conf;
|
use crate::configuration::Conf;
|
||||||
use std::io::IoSlice;
|
use std::io::IoSlice;
|
||||||
use crate::statics::StaticAsset;
|
use crate::statics::StaticAsset;
|
||||||
use smol::io::AsyncWriteExt;
|
use smol::io::AsyncWriteExt;
|
||||||
use smol::stream::StreamExt;
|
use smol::stream::StreamExt;
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
|
use form_urlencoded;
|
||||||
|
use percent_encoding::{percent_decode_str, percent_encode, NON_ALPHANUMERIC};
|
||||||
use pronouns_today::user_preferences::ParseError;
|
use pronouns_today::user_preferences::ParseError;
|
||||||
use pronouns_today::UserPreferences;
|
use pronouns_today::UserPreferences;
|
||||||
use configuration::ConfigError;
|
use configuration::ConfigError;
|
||||||
|
@ -167,7 +168,7 @@ fn route_request(req: &ScgiRequest) -> Route {
|
||||||
"GET" => (),
|
"GET" => (),
|
||||||
|
|
||||||
// All POST requests are met with link generation
|
// All POST requests are met with link generation
|
||||||
"POST" => return Route::GenerateLink(String::from_utf8_lossy(&req.body).into_owned()),
|
"POST" => return Route::GenerateLink(req.body.clone()),
|
||||||
|
|
||||||
// No other methods are supported
|
// No other methods are supported
|
||||||
_ => return Route::BadRequest(BadRequest::MethodNotAllowed),
|
_ => return Route::BadRequest(BadRequest::MethodNotAllowed),
|
||||||
|
@ -267,7 +268,7 @@ enum Route {
|
||||||
SendThumbnail(Option<String>, Option<UserPreferences>),
|
SendThumbnail(Option<String>, Option<UserPreferences>),
|
||||||
|
|
||||||
/// Generate a link to the appropriate pronoun page based on the user's inputs.
|
/// Generate a link to the appropriate pronoun page based on the user's inputs.
|
||||||
GenerateLink(String),
|
GenerateLink(Vec<u8>),
|
||||||
|
|
||||||
/// There was a problem with the user's request, and an error page should be sent
|
/// There was a problem with the user's request, and an error page should be sent
|
||||||
BadRequest(BadRequest),
|
BadRequest(BadRequest),
|
||||||
|
@ -325,7 +326,11 @@ impl Route {
|
||||||
let pronoun = Route::get_pronoun(name.as_ref(), prefs, settings)?;
|
let pronoun = Route::get_pronoun(name.as_ref(), prefs, settings)?;
|
||||||
|
|
||||||
let body = IndexTemplate {
|
let body = IndexTemplate {
|
||||||
name,
|
name: name.map(
|
||||||
|
|name| percent_decode_str(&name)
|
||||||
|
.decode_utf8_lossy()
|
||||||
|
.into_owned()
|
||||||
|
),
|
||||||
pronoun,
|
pronoun,
|
||||||
pronouns: settings.pronoun_list.iter().enumerate().collect(),
|
pronouns: settings.pronoun_list.iter().enumerate().collect(),
|
||||||
url: format!("{}{}", &conf.base_url, uri),
|
url: format!("{}{}", &conf.base_url, uri),
|
||||||
|
@ -369,32 +374,31 @@ impl Route {
|
||||||
|
|
||||||
/// The method for the [`Route::GenerateLink`] route
|
/// The method for the [`Route::GenerateLink`] route
|
||||||
fn generate_link(
|
fn generate_link(
|
||||||
body: String,
|
body: Vec<u8>,
|
||||||
settings: &InstanceSettings,
|
settings: &InstanceSettings,
|
||||||
) -> Result<Response, BadRequest> {
|
) -> Result<Response, BadRequest> {
|
||||||
let form = body.split('&')
|
let form = form_urlencoded::parse(&body);
|
||||||
.filter_map(|entry| {
|
|
||||||
let mut split = entry.split('=');
|
|
||||||
split.next().map(|key| (
|
|
||||||
key,
|
|
||||||
split.next().unwrap_or("")
|
|
||||||
))
|
|
||||||
})
|
|
||||||
.collect::<HashMap<&str, &str>>();
|
|
||||||
|
|
||||||
let mut weights = vec![0; settings.pronoun_list.len()];
|
let mut weights = vec![0; settings.pronoun_list.len()];
|
||||||
for (k, v) in form.iter() {
|
let mut name = None;
|
||||||
|
for (k, v) in form {
|
||||||
if let Ok(i) = k.parse::<usize>() {
|
if let Ok(i) = k.parse::<usize>() {
|
||||||
let w = v.parse::<u8>().map_err(|_| BadRequest::BadFormData((*v).into()))?;
|
let w = v.parse::<u8>().map_err(|_| BadRequest::BadFormData((*v).into()))?;
|
||||||
if i < weights.len() - 1 {
|
if i < weights.len() - 1 {
|
||||||
weights[i] = w;
|
weights[i] = w;
|
||||||
}
|
}
|
||||||
|
} else if k == "name" {
|
||||||
|
name = Some(v);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let prefs = InstanceSettings::create_preferences(&weights);
|
let prefs = InstanceSettings::create_preferences(&weights);
|
||||||
let pref_string = prefs.as_prefstring();
|
let pref_string = prefs.as_prefstring();
|
||||||
let url = match form.get("name") {
|
let url = match name {
|
||||||
Some(name) if !name.is_empty() => format!("/{}/{}", name, pref_string),
|
Some(name) if !name.is_empty() => format!(
|
||||||
|
"/{}/{}",
|
||||||
|
percent_encode(name.as_bytes(), NON_ALPHANUMERIC),
|
||||||
|
pref_string
|
||||||
|
),
|
||||||
_ => format!("/{}", pref_string),
|
_ => format!("/{}", pref_string),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue