diff --git a/firmware/src/http.rs b/firmware/src/http.rs index 4ec7a84..723ad67 100644 --- a/firmware/src/http.rs +++ b/firmware/src/http.rs @@ -1,6 +1,6 @@ use core::fmt; -const MAX_PATH: usize = 128; +const MAX_QUERY: usize = 128; #[derive(Debug,Clone,Copy,PartialEq,Eq)] enum State { @@ -8,7 +8,7 @@ enum State { WaitE, WaitT, WaitSpace, - GetPath, + GetQuery, WaitCR1, WaitLF1, WaitCR2, @@ -18,22 +18,22 @@ enum State { pub struct Request { state: State, - path_idx: usize, - path: [u8; MAX_PATH] + query_idx: usize, + query: [u8; MAX_QUERY] } impl Request { pub fn new() -> Request { Request { state: State::WaitG, - path_idx: 0, - path: [0; MAX_PATH] + query_idx: 0, + query: [0; MAX_QUERY] } } pub fn reset(&mut self) { self.state = State::WaitG; - self.path_idx = 0; + self.query_idx = 0; } pub fn input_char(&mut self, c: u8) -> Result { @@ -61,26 +61,26 @@ impl Request { } State::WaitSpace => { if c == b' ' { - self.state = State::GetPath; + self.state = State::GetQuery; } else { return Err("invalid character in method") } } - State::GetPath => { + State::GetQuery => { if c == b'\r' || c == b'\n' { return Err("GET ended prematurely") } else if c == b' ' { - if self.path_idx == 0 { - return Err("path is empty") + if self.query_idx == 0 { + return Err("query is empty") } else { self.state = State::WaitCR1; } } else { - if self.path_idx >= self.path.len() { - return Err("path is too long") + if self.query_idx >= self.query.len() { + return Err("query is too long") } else { - self.path[self.path_idx] = c; - self.path_idx += 1; + self.query[self.query_idx] = c; + self.query_idx += 1; } } } @@ -127,14 +127,42 @@ impl Request { result } - pub fn get_path<'a>(&'a self) -> Result<&'a [u8], &'static str> { + pub fn get_query<'a>(&'a self) -> Result<&'a [u8], &'static str> { if self.state != State::Finished { return Err("request is not finished") } - Ok(&self.path[..self.path_idx]) + Ok(&self.query[..self.query_idx]) + } + + pub fn get_path<'a>(&'a self) -> Result<&'a [u8], &'static str> { + let query = self.get_query()?; + Ok(query.split(|b| *b == '?' as u8).next().unwrap()) + } + + // FIXME: this yields some empty strings + pub fn iter_args<'a>(&'a self) -> Result, &'static str> { + let query = self.get_query()?; + let mut qs = query.split(|b| *b == '?' as u8); + qs.next(); + let args = qs.next().unwrap_or(b""); + let args_it = args.split(|b| *b == '&' as u8); + Ok(args_it.map(|arg| { + let mut eqs = arg.split(|b| *b == '=' as u8); + (eqs.next().unwrap(), eqs.next().unwrap_or(b"")) + })) + } + + pub fn get_arg<'a>(&'a self, name: &[u8]) -> Result<&'a [u8], &'static str> { + for (current_name, current_value) in self.iter_args()? { + if current_name == name { + return Ok(current_value) + } + } + Err("argument not found") } } + pub fn write_reply_header(output: &mut fmt::Write, status: u16, content_type: &str, gzip: bool) -> fmt::Result { let status_text = match status { 200 => "OK", diff --git a/firmware/src/main.rs b/firmware/src/main.rs index 3f3a577..cd2c996 100644 --- a/firmware/src/main.rs +++ b/firmware/src/main.rs @@ -1,4 +1,4 @@ -#![feature(used, const_fn, core_float, asm, lang_items)] +#![feature(used, const_fn, core_float, asm, lang_items, conservative_impl_trait)] #![no_std] extern crate cortex_m;