use syntax::ast::*;
use syntax::codemap::{Span, Spanned, dummy_spanned};
use syntax::ext::base::ExtCtxt;
use rocket::http::uri::URI;
use super::route::param_to_ident;
use utils::{span, SpanExt, is_valid_ident};
fn valid_path(ecx: &ExtCtxt, uri: &URI, sp: Span) -> bool {
let cleaned = uri.to_string();
if !uri.as_str().starts_with('/') {
ecx.struct_span_err(sp, "route paths must be absolute")
.note(&format!("expected {:?}, found {:?}", cleaned, uri.as_str()))
.emit()
} else if cleaned != uri.as_str() {
ecx.struct_span_err(sp, "paths cannot contain empty segments")
.note(&format!("expected {:?}, found {:?}", cleaned, uri.as_str()))
.emit()
} else {
return true;
}
false
}
fn valid_segments(ecx: &ExtCtxt, uri: &URI, sp: Span) -> bool {
let mut validated = true;
let mut segments_span = None;
for segment in uri.segments() {
let index = segment.as_ptr() as usize - uri.path().as_ptr() as usize;
let span = sp.trim_left(index + 1).shorten_to(segment.len());
if let Some(span) = segments_span {
let rem_sp = sp.trim_left(index).trim_right(1);
ecx.struct_span_err(rem_sp, "text after a trailing '..' param")
.help("a segments param must be the final text in a path")
.span_note(span, "trailing param is here")
.emit();
return false;
}
if segment.starts_with("<") && segment.ends_with(">") {
let mut param = &segment[1..(segment.len() - 1)];
if segment.ends_with("..>") {
segments_span = Some(span);
param = ¶m[..(param.len() - 2)];
}
if param.is_empty() {
ecx.span_err(span, "parameters cannot be empty");
} else if !is_valid_ident(param) {
ecx.struct_span_err(span, "parameter names must be valid identifiers")
.note(&format!("{:?} is not a valid identifier", param))
.emit();
} else if param.starts_with('_') {
ecx.struct_span_err(span, "parameters cannot be ignored")
.note(&format!("{:?} is being ignored", param))
.emit();
} else {
continue
}
validated = false;
} else if segment.starts_with("<") {
if segment[1..].contains("<") || segment.contains(">") {
ecx.struct_span_err(span, "malformed parameter")
.help("parameters must be of the form '<param>'")
.emit();
} else {
ecx.struct_span_err(span, "parameter is missing a closing bracket")
.help(&format!("perhaps you meant '{}>'?", segment))
.emit();
}
validated = false;
} else if URI::percent_encode(segment) != segment {
if segment.contains("<") || segment.contains(">") {
ecx.struct_span_err(span, "malformed parameter")
.help("parameters must be of the form '<param>'")
.emit();
} else {
ecx.span_err(span, "segment contains invalid characters");
}
validated = false;
}
}
validated
}
pub fn validate_uri(ecx: &ExtCtxt,
string: &str,
sp: Span)
-> (Spanned<URI<'static>>, Option<Spanned<Ident>>) {
let uri = URI::from(string.to_string());
let query_param = string.find('?')
.map(|i| span(&string[(i + 1)..], sp.trim_left(i + 1)))
.and_then(|spanned_q_param| param_to_ident(ecx, spanned_q_param));
if valid_segments(ecx, &uri, sp) && valid_path(ecx, &uri, sp) {
(span(uri, sp), query_param)
} else {
(dummy_spanned(URI::new("")), query_param)
}
}