Skip to content

Commit

Permalink
fix: use serde_urlencoded for query matching (#123)
Browse files Browse the repository at this point in the history
* use serde_urlencoded for query matching

* cargo fmt

* write a test specifically for this functionality
  • Loading branch information
cakekindel authored Jun 28, 2020
1 parent 0c24dfc commit 9c43df1
Show file tree
Hide file tree
Showing 3 changed files with 24 additions and 14 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@ serde_json = "1.0.17"
difference = "2.0"
colored = { version = "1.6", optional = true }
log = "0.4.6"
percent-encoding = "2.1.0"
assert-json-diff = "1.0.3"
serde_urlencoded = "0.6.1"

[dev-dependencies]
env_logger = "0.7"
Expand Down
23 changes: 10 additions & 13 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -558,11 +558,11 @@ mod server;
type Request = request::Request;
type Response = response::Response;

use percent_encoding::percent_decode;
use rand::distributions::Alphanumeric;
use rand::{thread_rng, Rng};
use regex::Regex;
use std::cell::RefCell;
use std::collections::HashMap;
use std::convert::{From, Into};
use std::fmt;
use std::io;
Expand Down Expand Up @@ -753,18 +753,15 @@ impl Matcher {
let actual: serde_json::Value = serde_json::from_str(other).unwrap();
assert_json_include_no_panic(&actual, &expected).is_ok()
}
Matcher::UrlEncoded(ref expected_field, ref expected_value) => other
.split('&')
.map(|pair| {
let mut parts = pair.splitn(2, '=');
let field =
percent_decode(parts.next().unwrap().as_bytes()).decode_utf8_lossy();
let value =
percent_decode(parts.next().unwrap_or("").as_bytes()).decode_utf8_lossy();

(field.to_string(), value.to_string())
})
.any(|(ref field, ref value)| field == expected_field && value == expected_value),
Matcher::UrlEncoded(ref expected_field, ref expected_value) => {
serde_urlencoded::from_str::<HashMap<String, String>>(other)
.map(|params: HashMap<_, _>| {
params.into_iter().any(|(ref field, ref value)| {
field == expected_field && value == expected_value
})
})
.unwrap_or(false)
}
Matcher::Any => true,
Matcher::AnyOf(ref matchers) => matchers.iter().any(|m| m.matches_value(other)),
Matcher::AllOf(ref matchers) => matchers.iter().all(|m| m.matches_value(other)),
Expand Down
13 changes: 13 additions & 0 deletions tests/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1296,6 +1296,19 @@ fn test_match_partial_query_by_urlencoded_all_of() {
assert_eq!("HTTP/1.1 501 Mock Not Found\r\n", status_line);
}

#[test]
fn test_match_query_with_non_percent_url_escaping() {
let _m = mock("GET", "/hello")
.match_query(Matcher::AllOf(vec![
Matcher::UrlEncoded("num ber".into(), "o ne".into()),
Matcher::UrlEncoded("hello".into(), "world".into()),
]))
.create();

let (status_line, _, _) = request("GET /hello?hello=world&something=else&num+ber=o+ne", "");
assert_eq!("HTTP/1.1 200 OK\r\n", status_line);
}

#[test]
fn test_match_missing_query() {
let _m = mock("GET", "/hello").match_query(Matcher::Missing).create();
Expand Down

0 comments on commit 9c43df1

Please sign in to comment.