1use super::{lalrpop_util, CookieLexer, CookieLexerError, CookieToken};
2use std::fmt::{Display, Error as FormatterError, Formatter};
3
4const BASIC_COOKIE_ERROR_DESCRIPTION: &'static str = "Cookie Parsing Error";
5const INTERNAL_ERROR_DESCRIPTION: &'static str = "Internal Error";
6const PARSE_ERROR_DESCRIPTION: &'static str = "Parse Error";
7
8lalrpop_mod!(cookie_grammar);
9
10#[derive(Debug)]
11pub struct Cookie<'a> {
12 name: &'a str,
13 value: &'a str,
14}
15
16impl<'a> Cookie<'a> {
17 pub fn parse(input: &'a str) -> Result<Vec<Cookie<'a>>, Error> {
33 Ok(cookie_grammar::CookiesParser::new()
34 .parse(CookieLexer::new(input))
35 .map_err(ParseError::from_lalrpop_parse_error_to_error)?
36 .clone_to_vec()
37 .iter()
38 .rev()
39 .map(|tok| tok.with_str(input))
40 .collect::<Result<Vec<Cookie>, Error>>()?)
41 }
42
43 pub fn get_name(&self) -> &'a str {
54 self.name
55 }
56
57 pub fn get_value(&self) -> &'a str {
68 self.value
69 }
70}
71
72#[derive(Debug)]
73pub enum Error {
74 InternalError(InternalError),
75 ParseError(ParseError),
76}
77
78impl Display for Error {
79 fn fmt(&self, f: &mut Formatter) -> Result<(), FormatterError> {
80 f.write_str(BASIC_COOKIE_ERROR_DESCRIPTION)?;
81 f.write_str(": ")?;
82 match self {
83 Error::InternalError(err) => err.fmt(f),
84 Error::ParseError(err) => err.fmt(f),
85 }
86 }
87}
88
89impl std::error::Error for Error {
90 fn description(&self) -> &str {
91 BASIC_COOKIE_ERROR_DESCRIPTION
92 }
93
94 fn cause(&self) -> Option<&dyn std::error::Error> {
95 self.source()
96 }
97
98 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
99 match self {
100 Error::InternalError(err) => Some(err),
101 Error::ParseError(err) => Some(err),
102 }
103 }
104}
105
106#[derive(Debug)]
107pub struct InternalError(InternalErrorKind);
108
109impl InternalError {
110 pub(crate) fn to_error(self) -> Error {
111 Error::InternalError(self)
112 }
113}
114
115impl Display for InternalError {
116 fn fmt(&self, f: &mut Formatter) -> Result<(), FormatterError> {
117 f.write_str(INTERNAL_ERROR_DESCRIPTION)
118 }
119}
120
121impl std::error::Error for InternalError {
122 fn description(&self) -> &str {
123 INTERNAL_ERROR_DESCRIPTION
124 }
125
126 fn cause(&self) -> Option<&dyn std::error::Error> {
127 None
128 }
129
130 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
131 None
132 }
133}
134
135#[derive(Debug)]
136enum InternalErrorKind {
137 NonTerminalIndexBeyondBoundaries,
138}
139
140type LalrpopError = lalrpop_util::ParseError<usize, CookieToken, CookieLexerError>;
141
142#[derive(Debug)]
143pub struct ParseError {
144 lalrpop_error: LalrpopError,
145}
146
147impl ParseError {
148 pub(crate) fn from_lalrpop_parse_error_to_error(src: LalrpopError) -> Error {
149 ParseError { lalrpop_error: src }.to_error()
150 }
151
152 fn to_error(self) -> Error {
153 Error::ParseError(self)
154 }
155}
156
157impl Display for ParseError {
158 fn fmt(&self, f: &mut Formatter) -> Result<(), FormatterError> {
159 f.write_str(PARSE_ERROR_DESCRIPTION)?;
160 f.write_str(": ")?;
161 self.lalrpop_error.fmt(f)
162 }
163}
164
165impl std::error::Error for ParseError {
166 fn description(&self) -> &str {
167 PARSE_ERROR_DESCRIPTION
168 }
169
170 fn cause(&self) -> Option<&dyn std::error::Error> {
171 Some(&self.lalrpop_error)
172 }
173
174 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
175 Some(&self.lalrpop_error)
176 }
177}
178
179mod terminals {
180 use super::nonterminals::NonTerminalSpan;
181 use super::Cookie as FullyParsedCookie;
182 use super::{Error, InternalError};
183
184 #[derive(Clone, Debug)]
185 pub struct Cookie {
186 pub(super) key: NonTerminalSpan,
187 pub(super) value: NonTerminalSpan,
188 }
189
190 impl Cookie {
191 pub(super) fn with_str<'a>(&self, data: &'a str) -> Result<FullyParsedCookie<'a>, Error> {
192 Ok(FullyParsedCookie {
193 name: self.key.as_str(data).map_err(InternalError::to_error)?,
194 value: self.value.as_str(data).map_err(InternalError::to_error)?,
195 })
196 }
197 }
198}
199
200mod nonterminals {
201 use super::{InternalError, InternalErrorKind};
202
203 #[derive(Clone, Debug)]
204 pub struct NonTerminalSpan {
205 start: usize,
206 end: usize,
207 }
208
209 impl NonTerminalSpan {
210 pub(crate) fn new(start: usize, end: usize) -> NonTerminalSpan {
211 NonTerminalSpan {
212 start: start,
213 end: end,
214 }
215 }
216
217 pub(crate) fn as_str<'a>(&self, data: &'a str) -> Result<&'a str, InternalError> {
218 match data.get(self.start..self.end) {
219 Some(res) => Ok(res),
220 None => Err(InternalError(
221 InternalErrorKind::NonTerminalIndexBeyondBoundaries,
222 )),
223 }
224 }
225 }
226}
227
228#[cfg(test)]
229mod tests {
230 use super::Cookie;
231
232 #[test]
233 fn get_name() {
234 const COOKIE_KEY: &'static str = "cookie_key";
235 const COOKIE_VALUE: &'static str = "cookie_value";
236
237 let cookie = Cookie {
238 name: COOKIE_KEY,
239 value: COOKIE_VALUE,
240 };
241
242 assert_eq!(COOKIE_KEY, cookie.get_name());
243 }
244
245 #[test]
246 fn get_value() {
247 const COOKIE_KEY: &'static str = "cookie_key";
248 const COOKIE_VALUE: &'static str = "cookie_value";
249
250 let cookie = Cookie {
251 name: COOKIE_KEY,
252 value: COOKIE_VALUE,
253 };
254
255 assert_eq!(COOKIE_VALUE, cookie.get_value());
256 }
257
258 #[test]
259 fn single_cookie() {
260 const COOKIE_STR: &'static str = "test=1234";
261 let parsed_cookies = Cookie::parse(COOKIE_STR).unwrap();
262 assert_eq!(1, parsed_cookies.len());
263
264 let parsed_cookie = &parsed_cookies[0];
265 assert_eq!("test", parsed_cookie.name);
266 assert_eq!("1234", parsed_cookie.value);
267 }
268
269 #[test]
270 fn single_cookie_quoted() {
271 const COOKIE_STR: &'static str = "quoted_test=\"quotedval\"";
272 let parsed_cookies = Cookie::parse(COOKIE_STR).unwrap();
273 assert_eq!(1, parsed_cookies.len());
274
275 let parsed_cookie = &parsed_cookies[0];
276 assert_eq!("quoted_test", parsed_cookie.name);
277 assert_eq!("quotedval", parsed_cookie.value);
278 }
279
280 #[test]
281 fn single_cookie_with_equals_in_value() {
282 const COOKIE_STR: &'static str = "test=abc=123";
283 let parsed_cookies = Cookie::parse(COOKIE_STR).unwrap();
284 assert_eq!(1, parsed_cookies.len());
285
286 let parsed_cookie = &parsed_cookies[0];
287 assert_eq!("test", parsed_cookie.name);
288 assert_eq!("abc=123", parsed_cookie.value);
289 }
290
291 #[test]
292 fn single_cookie_ows_before() {
293 const COOKIE_STR: &'static str = " \x09 ztest=9876";
294 let parsed_cookies = Cookie::parse(COOKIE_STR).unwrap();
295 assert_eq!(1, parsed_cookies.len());
296
297 let parsed_cookie = &parsed_cookies[0];
298 assert_eq!("ztest", parsed_cookie.name);
299 assert_eq!("9876", parsed_cookie.value);
300 }
301
302 #[test]
303 fn single_cookie_ows_with_single_space_before() {
304 const COOKIE_STR: &'static str = " qtest=9878";
305 let parsed_cookies = Cookie::parse(COOKIE_STR).unwrap();
306 assert_eq!(1, parsed_cookies.len());
307
308 let parsed_cookie = &parsed_cookies[0];
309 assert_eq!("qtest", parsed_cookie.name);
310 assert_eq!("9878", parsed_cookie.value);
311 }
312
313 #[test]
314 fn single_cookie_ows_after() {
315 const COOKIE_STR: &'static str = "abcde=77766test \x09\x09 ";
316 let parsed_cookies = Cookie::parse(COOKIE_STR).unwrap();
317 assert_eq!(1, parsed_cookies.len());
318
319 let parsed_cookie = &parsed_cookies[0];
320 assert_eq!("abcde", parsed_cookie.name);
321 assert_eq!("77766test", parsed_cookie.value);
322 }
323
324 #[test]
325 fn single_cookie_ows_with_single_space_after() {
326 const COOKIE_STR: &'static str = "xyzzz=test3 ";
327 let parsed_cookies = Cookie::parse(COOKIE_STR).unwrap();
328 assert_eq!(1, parsed_cookies.len());
329
330 let parsed_cookie = &parsed_cookies[0];
331 assert_eq!("xyzzz", parsed_cookie.name);
332 assert_eq!("test3", parsed_cookie.value);
333 }
334
335 #[test]
336 fn single_cookie_ows_before_and_after() {
337 const COOKIE_STR: &'static str = " \x09 ztest=9876 ";
338 let parsed_cookies = Cookie::parse(COOKIE_STR).unwrap();
339 assert_eq!(1, parsed_cookies.len());
340
341 let parsed_cookie = &parsed_cookies[0];
342 assert_eq!("ztest", parsed_cookie.name);
343 assert_eq!("9876", parsed_cookie.value);
344 }
345
346 #[test]
347 fn single_cookie_empty_name() {
348 const COOKIE_STR: &'static str = "=nokey";
349 let parsed_cookies = Cookie::parse(COOKIE_STR).unwrap();
350 assert_eq!(1, parsed_cookies.len());
351
352 let parsed_cookie = &parsed_cookies[0];
353 assert_eq!("", parsed_cookie.name);
354 assert_eq!("nokey", parsed_cookie.value);
355 }
356
357 #[test]
358 fn single_cookie_empty_name_with_ows_before() {
359 const COOKIE_STR: &'static str = " =nokey";
360 let parsed_cookies = Cookie::parse(COOKIE_STR).unwrap();
361 assert_eq!(1, parsed_cookies.len());
362
363 let parsed_cookie = &parsed_cookies[0];
364 assert_eq!("", parsed_cookie.name);
365 assert_eq!("nokey", parsed_cookie.value);
366 }
367
368 #[test]
369 fn single_cookie_empty_value() {
370 const COOKIE_STR: &'static str = "noval=";
371 let parsed_cookies = Cookie::parse(COOKIE_STR).unwrap();
372 assert_eq!(1, parsed_cookies.len());
373
374 let parsed_cookie = &parsed_cookies[0];
375 assert_eq!("noval", parsed_cookie.name);
376 assert_eq!("", parsed_cookie.value);
377 }
378
379 #[test]
380 fn single_cookie_empty_value_with_ows_after() {
381 const COOKIE_STR: &'static str = "noval= ";
382 let parsed_cookies = Cookie::parse(COOKIE_STR).unwrap();
383 assert_eq!(1, parsed_cookies.len());
384
385 let parsed_cookie = &parsed_cookies[0];
386 assert_eq!("noval", parsed_cookie.name);
387 assert_eq!("", parsed_cookie.value);
388 }
389
390 #[test]
391 fn single_cookie_empty_name_and_val() {
392 const COOKIE_STR: &'static str = "=";
393 let parsed_cookies = Cookie::parse(COOKIE_STR).unwrap();
394 assert_eq!(1, parsed_cookies.len());
395
396 let parsed_cookie = &parsed_cookies[0];
397 assert_eq!("", parsed_cookie.name);
398 assert_eq!("", parsed_cookie.value);
399 }
400
401 #[test]
402 fn single_cookie_empty_name_no_equals() {
403 const COOKIE_STR: &'static str = "nokey";
404 let parsed_cookies = Cookie::parse(COOKIE_STR).unwrap();
405 assert_eq!(1, parsed_cookies.len());
406
407 let parsed_cookie = &parsed_cookies[0];
408 assert_eq!("", parsed_cookie.name);
409 assert_eq!("nokey", parsed_cookie.value);
410 }
411
412 #[test]
413 fn two_cookies() {
414 const COOKIE_STR: &'static str = "test1=01234; test2=testval";
415 let parsed_cookies = Cookie::parse(COOKIE_STR).unwrap();
416 assert_eq!(2, parsed_cookies.len());
417
418 let parsed_cookie_0 = &parsed_cookies[0];
419 assert_eq!("test1", parsed_cookie_0.name);
420 assert_eq!("01234", parsed_cookie_0.value);
421
422 let parsed_cookie_1 = &parsed_cookies[1];
423 assert_eq!("test2", parsed_cookie_1.name);
424 assert_eq!("testval", parsed_cookie_1.value);
425 }
426
427 #[test]
428 fn three_cookies() {
429 const COOKIE_STR: &'static str = "test1=0x1234; test2=test2; third_val=v4lue";
430 let parsed_cookies = Cookie::parse(COOKIE_STR).unwrap();
431 assert_eq!(3, parsed_cookies.len());
432
433 let parsed_cookie_0 = &parsed_cookies[0];
434 assert_eq!("test1", parsed_cookie_0.name);
435 assert_eq!("0x1234", parsed_cookie_0.value);
436
437 let parsed_cookie_1 = &parsed_cookies[1];
438 assert_eq!("test2", parsed_cookie_1.name);
439 assert_eq!("test2", parsed_cookie_1.value);
440
441 let parsed_cookie_2 = &parsed_cookies[2];
442 assert_eq!("third_val", parsed_cookie_2.name);
443 assert_eq!("v4lue", parsed_cookie_2.value);
444 }
445
446 #[test]
447 fn three_cookies_ows_before() {
448 const COOKIE_STR: &'static str = " test1=0x1234; test2=test2; third_val=v4lue";
449 let parsed_cookies = Cookie::parse(COOKIE_STR).unwrap();
450 assert_eq!(3, parsed_cookies.len());
451
452 let parsed_cookie_0 = &parsed_cookies[0];
453 assert_eq!("test1", parsed_cookie_0.name);
454 assert_eq!("0x1234", parsed_cookie_0.value);
455
456 let parsed_cookie_1 = &parsed_cookies[1];
457 assert_eq!("test2", parsed_cookie_1.name);
458 assert_eq!("test2", parsed_cookie_1.value);
459
460 let parsed_cookie_2 = &parsed_cookies[2];
461 assert_eq!("third_val", parsed_cookie_2.name);
462 assert_eq!("v4lue", parsed_cookie_2.value);
463 }
464
465 #[test]
466 fn three_cookies_ows_after() {
467 const COOKIE_STR: &'static str = "test1=0x1234; test2=test2; third_val=v4lue ";
468 let parsed_cookies = Cookie::parse(COOKIE_STR).unwrap();
469 assert_eq!(3, parsed_cookies.len());
470
471 let parsed_cookie_0 = &parsed_cookies[0];
472 assert_eq!("test1", parsed_cookie_0.name);
473 assert_eq!("0x1234", parsed_cookie_0.value);
474
475 let parsed_cookie_1 = &parsed_cookies[1];
476 assert_eq!("test2", parsed_cookie_1.name);
477 assert_eq!("test2", parsed_cookie_1.value);
478
479 let parsed_cookie_2 = &parsed_cookies[2];
480 assert_eq!("third_val", parsed_cookie_2.name);
481 assert_eq!("v4lue", parsed_cookie_2.value);
482 }
483
484 #[test]
485 fn three_cookies_ows_before_and_after() {
486 const COOKIE_STR: &'static str = " test1=0x1234; test2=test2; third_val=v4lue ";
487 let parsed_cookies = Cookie::parse(COOKIE_STR).unwrap();
488 assert_eq!(3, parsed_cookies.len());
489
490 let parsed_cookie_0 = &parsed_cookies[0];
491 assert_eq!("test1", parsed_cookie_0.name);
492 assert_eq!("0x1234", parsed_cookie_0.value);
493
494 let parsed_cookie_1 = &parsed_cookies[1];
495 assert_eq!("test2", parsed_cookie_1.name);
496 assert_eq!("test2", parsed_cookie_1.value);
497
498 let parsed_cookie_2 = &parsed_cookies[2];
499 assert_eq!("third_val", parsed_cookie_2.name);
500 assert_eq!("v4lue", parsed_cookie_2.value);
501 }
502
503 #[test]
504 fn three_cookies_no_spacing() {
505 const COOKIE_STR: &'static str = "test1=0x1234;test2=test2;third_val=v4lue";
506 let parsed_cookies = Cookie::parse(COOKIE_STR).unwrap();
507 assert_eq!(3, parsed_cookies.len());
508
509 let parsed_cookie_0 = &parsed_cookies[0];
510 assert_eq!("test1", parsed_cookie_0.name);
511 assert_eq!("0x1234", parsed_cookie_0.value);
512
513 let parsed_cookie_1 = &parsed_cookies[1];
514 assert_eq!("test2", parsed_cookie_1.name);
515 assert_eq!("test2", parsed_cookie_1.value);
516
517 let parsed_cookie_2 = &parsed_cookies[2];
518 assert_eq!("third_val", parsed_cookie_2.name);
519 assert_eq!("v4lue", parsed_cookie_2.value);
520 }
521}