Skip to content

Commit 5b78680

Browse files
committed
Prevent cloning paste on show where not necessary
1 parent c2219e1 commit 5b78680

4 files changed

Lines changed: 82 additions & 60 deletions

File tree

Cargo.lock

Lines changed: 48 additions & 35 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,10 @@ authors = ["Jordan Doyle <jordan@doyle.la>"]
88
edition = "2018"
99

1010
[dependencies]
11+
owning_ref = "0.4"
1112
linked-hash-map = "0.5"
1213
rocket = { version = "0.4", default-features = false }
13-
askama = "0.7"
14+
askama = "0.8"
1415
lazy_static = "1.2"
1516
rand = { version = "0.6", features = ["nightly"] }
1617
gpw = "0.1"

src/io.rs

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,18 @@
11
extern crate gpw;
22
extern crate linked_hash_map;
3+
extern crate owning_ref;
34
extern crate rand;
45

56
use rand::distributions::Alphanumeric;
67
use rand::{thread_rng, Rng};
78

89
use linked_hash_map::LinkedHashMap;
910

11+
use owning_ref::RwLockReadGuardRef;
12+
1013
use std::cell::RefCell;
1114
use std::env;
12-
use std::sync::RwLock;
15+
use std::sync::{PoisonError, RwLock};
1316

1417
lazy_static! {
1518
static ref ENTRIES: RwLock<LinkedHashMap<String, String>> = RwLock::new(LinkedHashMap::new());
@@ -25,12 +28,12 @@ lazy_static! {
2528
///
2629
/// During the purge, `ENTRIES` is locked and the current thread will block.
2730
fn purge_old() {
28-
let entries_len = ENTRIES.read().unwrap_or_else(|p| p.into_inner()).len();
31+
let entries_len = ENTRIES.read().unwrap_or_else(PoisonError::into_inner).len();
2932

3033
if entries_len > *BUFFER_SIZE {
3134
let to_remove = entries_len - *BUFFER_SIZE;
3235

33-
let mut entries = ENTRIES.write().unwrap_or_else(|p| p.into_inner());
36+
let mut entries = ENTRIES.write().unwrap_or_else(PoisonError::into_inner);
3437

3538
for _ in 0..to_remove {
3639
entries.pop_front();
@@ -54,17 +57,19 @@ pub fn store_paste(id: String, content: String) {
5457
purge_old();
5558
ENTRIES
5659
.write()
57-
.unwrap_or_else(|p| p.into_inner())
60+
.unwrap_or_else(PoisonError::into_inner)
5861
.insert(id, content);
5962
}
6063

6164
/// Get a paste by id.
6265
///
6366
/// Returns `None` if the paste doesn't exist.
64-
pub fn get_paste(id: &str) -> Option<String> {
65-
ENTRIES
66-
.read()
67-
.unwrap_or_else(|p| p.into_inner())
68-
.get(id)
69-
.cloned()
67+
pub fn get_paste(id: &str) -> Option<RwLockReadGuardRef<LinkedHashMap<String, String>, String>> {
68+
let or = RwLockReadGuardRef::new(ENTRIES.read().unwrap_or_else(PoisonError::into_inner));
69+
70+
if or.contains_key(id) {
71+
Some(or.map(|x| x.get(id).unwrap()))
72+
} else {
73+
None
74+
}
7075
}

src/main.rs

Lines changed: 17 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,15 @@ use highlight::highlight;
1717
use io::{generate_id, get_paste, store_paste};
1818
use params::{HostHeader, IsPlaintextRequest};
1919

20-
use askama::{MarkupDisplay, Template};
20+
use askama::{Html as AskamaHtml, MarkupDisplay, Template};
2121

2222
use rocket::http::{ContentType, Status};
2323
use rocket::request::Form;
2424
use rocket::response::content::{Content, Html};
2525
use rocket::response::Redirect;
2626
use rocket::Data;
2727

28+
use std::borrow::Cow;
2829
use std::io::Read;
2930

3031
///
@@ -39,7 +40,7 @@ struct Index;
3940
fn index() -> Result<Html<String>, Status> {
4041
Index
4142
.render()
42-
.map(|h| Html(h))
43+
.map(Html)
4344
.map_err(|_| Status::InternalServerError)
4445
}
4546

@@ -82,8 +83,8 @@ fn submit_raw(input: Data, host: HostHeader) -> std::io::Result<String> {
8283
8384
#[derive(Template)]
8485
#[template(path = "paste.html")]
85-
struct ShowPaste {
86-
content: MarkupDisplay<String>,
86+
struct ShowPaste<'a> {
87+
content: MarkupDisplay<AskamaHtml, Cow<'a, String>>,
8788
}
8889

8990
#[get("/<key>")]
@@ -94,22 +95,24 @@ fn show_paste(key: String, plaintext: IsPlaintextRequest) -> Result<Content<Stri
9495

9596
// get() returns a read-only lock, we're not going to be writing to this key
9697
// again so we can hold this for as long as we want
97-
let entry = get_paste(key).ok_or_else(|| Status::NotFound)?;
98+
let entry = &*get_paste(key).ok_or_else(|| Status::NotFound)?;
9899

99100
if *plaintext {
100-
Ok(Content(ContentType::Plain, entry))
101+
Ok(Content(ContentType::Plain, entry.to_string()))
101102
} else {
102103
let content = match ext {
103-
None => MarkupDisplay::Unsafe(entry),
104-
Some(extension) => highlight(&entry, extension)
105-
.map(|h| MarkupDisplay::Safe(h))
106-
.ok_or_else(|| Status::NotFound)?,
104+
Some(extension) => match highlight(&entry, extension) {
105+
Some(html) => MarkupDisplay::new_safe(Cow::Owned(html), AskamaHtml),
106+
None => return Err(Status::NotFound),
107+
},
108+
None => MarkupDisplay::new_unsafe(Cow::Borrowed(entry), AskamaHtml),
107109
};
108110

109-
ShowPaste { content }
110-
.render()
111-
.map(|html| Content(ContentType::HTML, html))
112-
.map_err(|_| Status::InternalServerError)
111+
let template = ShowPaste { content };
112+
match template.render() {
113+
Ok(html) => Ok(Content(ContentType::HTML, html)),
114+
Err(_) => Err(Status::InternalServerError),
115+
}
113116
}
114117
}
115118

0 commit comments

Comments
 (0)