Skip to content

Commit 0d4e3f9

Browse files
authored
Add feature: --base-url (#50)
1 parent 4b0eef9 commit 0d4e3f9

File tree

3 files changed

+54
-21
lines changed

3 files changed

+54
-21
lines changed

src/main.rs

Lines changed: 44 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,8 @@ use termcolor::{Color, ColorSpec};
3232

3333
use color::{build_spec, Printer};
3434
use util::{
35-
enable_string, encode_link_path, error_io2iron, error_resp, now_string,
36-
system_time_to_date_time, StringError, ROOT_LINK,
35+
enable_string, encode_link_path, error_io2iron, error_resp, now_string, root_link,
36+
system_time_to_date_time, StringError,
3737
};
3838

3939
use middlewares::{AuthChecker, CompressionHandler, RequestLogger};
@@ -209,6 +209,12 @@ fn main() {
209209
.long("open")
210210
.short("o")
211211
.help("Open the page in the default browser"))
212+
.arg(clap::Arg::with_name("base-url")
213+
.short("b")
214+
.long("base-url")
215+
.default_value("/")
216+
.takes_value(true)
217+
.help("Base URL to prepend in directory indexes. For reverse proxying. This prefix is supposed to be pre-stripped when reaching simple-http-server."))
212218
.get_matches();
213219

214220
let root = matches
@@ -273,6 +279,7 @@ fn main() {
273279
}
274280

275281
let silent = matches.is_present("silent");
282+
let base_url: &str = matches.value_of("base-url").unwrap();
276283

277284
let upload: Option<Upload> = if upload_arg {
278285
let token: String = thread_rng()
@@ -353,6 +360,7 @@ fn main() {
353360
.map(|exts| exts.iter().map(|s| format!(".{}", s)).collect()),
354361
try_file_404: try_file_404.map(PathBuf::from),
355362
upload_size_limit,
363+
base_url: base_url.to_string(),
356364
});
357365
if cors {
358366
chain.link_around(CorsMiddleware::with_allow_any());
@@ -376,6 +384,7 @@ fn main() {
376384
if !silent {
377385
chain.link_after(RequestLogger {
378386
printer: Printer::new(),
387+
base_url: base_url.to_string(),
379388
});
380389
}
381390
let mut server = Iron::new(chain);
@@ -433,6 +442,7 @@ struct MainHandler {
433442
compress: Option<Vec<String>>,
434443
try_file_404: Option<PathBuf>,
435444
upload_size_limit: u64,
445+
base_url: String,
436446
}
437447

438448
impl Handler for MainHandler {
@@ -475,9 +485,19 @@ impl Handler for MainHandler {
475485

476486
if self.upload.is_some() && req.method == method::Post {
477487
if let Err((s, msg)) = self.save_files(req, &fs_path) {
478-
return Ok(error_resp(s, &msg));
479-
} else {
488+
return Ok(error_resp(s, &msg, &self.base_url));
489+
} else if self.base_url == "/" {
480490
return Ok(Response::with((status::Found, Redirect(req.url.clone()))));
491+
} else {
492+
let mut inner_url: iron::url::Url = req.url.clone().into();
493+
let mut path: &str = inner_url.path();
494+
if path.starts_with('/') {
495+
path = &path[1..];
496+
}
497+
let new_path = format!("{}{}", self.base_url, path);
498+
inner_url.set_path(&new_path);
499+
let new_url = iron::Url::from_generic_url(inner_url).unwrap();
500+
return Ok(Response::with((status::Found, Redirect(new_url))));
481501
}
482502
}
483503

@@ -505,7 +525,7 @@ impl Handler for MainHandler {
505525
.iter()
506526
.map(|s| s.to_string_lossy().to_string())
507527
.collect();
508-
self.list_directory(req, &fs_path, &path_prefix)
528+
self.list_directory(req, &fs_path, &path_prefix, &self.base_url[..])
509529
} else {
510530
self.send_file(req, &fs_path)
511531
}
@@ -602,6 +622,7 @@ impl MainHandler {
602622
req: &mut Request,
603623
fs_path: &Path,
604624
path_prefix: &[String],
625+
base_url: &str,
605626
) -> IronResult<Response> {
606627
struct Entry {
607628
filename: String,
@@ -628,16 +649,17 @@ impl MainHandler {
628649
let mut bread_links: Vec<String> = vec![breadcrumb.pop().unwrap()];
629650
while !breadcrumb.is_empty() {
630651
bread_links.push(format!(
631-
r#"<a href="/{link}/"><strong>{label}</strong></a>"#,
652+
r#"<a href="{base_url}{link}/"><strong>{label}</strong></a>"#,
632653
link = encode_link_path(&breadcrumb),
633654
label = encode_minimal(&breadcrumb.pop().unwrap().to_owned()),
655+
base_url = base_url,
634656
));
635657
}
636-
bread_links.push(ROOT_LINK.to_owned());
658+
bread_links.push(root_link(base_url));
637659
bread_links.reverse();
638660
bread_links.join(" / ")
639661
} else {
640-
ROOT_LINK.to_owned()
662+
root_link(base_url)
641663
};
642664

643665
// Sort links
@@ -709,16 +731,17 @@ impl MainHandler {
709731
format!(
710732
r#"
711733
<tr>
712-
<th><a href="/{link}?sort=name&order={name_order}">Name</a></th>
713-
<th><a href="/{link}?sort=modified&order={modified_order}">Last modified</a></th>
714-
<th><a href="/{link}?sort=size&order={size_order}">Size</a></th>
734+
<th><a href="{base_url}{link}?sort=name&order={name_order}">Name</a></th>
735+
<th><a href="{base_url}{link}?sort=modified&order={modified_order}">Last modified</a></th>
736+
<th><a href="{base_url}{link}?sort=size&order={size_order}">Size</a></th>
715737
</tr>
716738
<tr><td style="border-top:1px dashed #BBB;" colspan="5"></td></tr>
717739
"#,
718740
link = encode_link_path(&current_link),
719741
name_order = order_labels.get("name").unwrap_or(&DEFAULT_ORDER),
720742
modified_order = order_labels.get("modified").unwrap_or(&DEFAULT_ORDER),
721-
size_order = order_labels.get("size").unwrap_or(&DEFAULT_ORDER)
743+
size_order = order_labels.get("size").unwrap_or(&DEFAULT_ORDER),
744+
base_url = base_url,
722745
)
723746
} else {
724747
"".to_owned()
@@ -734,12 +757,13 @@ impl MainHandler {
734757
rows.push(format!(
735758
r#"
736759
<tr>
737-
<td><a href="/{link}"><strong>[Up]</strong></a></td>
760+
<td><a href="{base_url}{link}"><strong>[Up]</strong></a></td>
738761
<td></td>
739762
<td></td>
740763
</tr>
741764
"#,
742-
link = encode_link_path(&link)
765+
link = encode_link_path(&link),
766+
base_url = base_url,
743767
));
744768
} else {
745769
rows.push(r#"<tr><td>&nbsp;</td></tr>"#.to_owned());
@@ -789,7 +813,7 @@ impl MainHandler {
789813
rows.push(format!(
790814
r#"
791815
<tr>
792-
<td><a {linkstyle} href="/{link}">{label}</a></td>
816+
<td><a {linkstyle} href="{base_url}{link}">{label}</a></td>
793817
<td style="color:#888;">[{modified}]</td>
794818
<td><bold>{filesize}</bold></td>
795819
</tr>
@@ -798,22 +822,24 @@ impl MainHandler {
798822
link = encode_link_path(&link),
799823
label = encode_minimal(&file_name_label),
800824
modified = file_modified,
801-
filesize = file_size
825+
filesize = file_size,
826+
base_url = base_url,
802827
));
803828
}
804829

805830
// Optional upload form
806831
let upload_form = if self.upload.is_some() {
807832
format!(
808833
r#"
809-
<form style="margin-top:1em; margin-bottom:1em;" action="/{path}" method="POST" enctype="multipart/form-data">
834+
<form style="margin-top:1em; margin-bottom:1em;" action="{base_url}{path}" method="POST" enctype="multipart/form-data">
810835
<input type="file" name="files" accept="*" multiple />
811836
<input type="hidden" name="csrf" value="{csrf}"/>
812837
<input type="submit" value="Upload" />
813838
</form>
814839
"#,
815840
path = encode_link_path(path_prefix),
816-
csrf = self.upload.as_ref().unwrap().csrf_token
841+
csrf = self.upload.as_ref().unwrap().csrf_token,
842+
base_url = base_url,
817843
)
818844
} else {
819845
"".to_owned()

src/middlewares/logger.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ lazy_static! {
1717

1818
pub struct RequestLogger {
1919
pub printer: Printer,
20+
pub base_url: String,
2021
}
2122

2223
impl RequestLogger {
@@ -68,6 +69,7 @@ impl AfterMiddleware for RequestLogger {
6869
Ok(error_resp(
6970
err.response.status.unwrap_or(status::InternalServerError),
7071
err.error.to_string().as_str(),
72+
&self.base_url,
7173
))
7274
}
7375
}

src/util.rs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,12 @@ const FRAGMENT_ENCODE_SET: &AsciiSet = &percent_encoding::CONTROLS
2121
const PATH_ENCODE_SET: &AsciiSet = &FRAGMENT_ENCODE_SET.add(b'#').add(b'?').add(b'{').add(b'}');
2222
const PATH_SEGMENT_ENCODE_SET: &AsciiSet = &PATH_ENCODE_SET.add(b'/').add(b'%').add(b'[').add(b']');
2323

24-
pub const ROOT_LINK: &str = r#"<a href="/"><strong>[Root]</strong></a>"#;
24+
pub fn root_link(baseurl: &str) -> String {
25+
format!(
26+
r#"<a href="{baseurl}"><strong>[Root]</strong></a>"#,
27+
baseurl = baseurl,
28+
)
29+
}
2530

2631
#[derive(Debug)]
2732
pub struct StringError(pub String);
@@ -136,7 +141,7 @@ pub fn system_time_to_date_time(t: SystemTime) -> DateTime<Local> {
136141
Local.timestamp_opt(sec, nsec).unwrap()
137142
}
138143

139-
pub fn error_resp(s: status::Status, msg: &str) -> Response {
144+
pub fn error_resp(s: status::Status, msg: &str, baseurl: &str) -> Response {
140145
let mut resp = Response::with((
141146
s,
142147
format!(
@@ -152,7 +157,7 @@ pub fn error_resp(s: status::Status, msg: &str) -> Response {
152157
</body>
153158
</html>
154159
"#,
155-
root_link = ROOT_LINK,
160+
root_link = root_link(baseurl),
156161
code = s.to_u16(),
157162
msg = msg
158163
),

0 commit comments

Comments
 (0)