PawelAdamski / HttpClientMock

Library for mocking Apache HttpClient.
MIT License
44 stars 9 forks source link

Path matching does not work with special chars like semicolon in URL (matrix parameters) #40

Closed ipichris closed 2 years ago

ipichris commented 3 years ago

If the path contains a semicolon the path matching does not work, i.e. http://myHost/api/x;myParam1=a;myParam2=b

...withPath(Matchers.containsString("api/x;myParam1=a;myParam2=b")) => Rule does not match

...withPath(Matchers.containsString("myParam1=a;myParam2=b")) => Rule does not match

...withPath(Matches.containsString("http://myHost/api/x")) => Rule DOES match

I found similar issues when escape characters are used in the url for whitespace, ?, & and others

PawelAdamski commented 3 years ago

Hi @ipichris Thanks for finding that issues. I will try to look on it during the weekend.

PawelAdamski commented 3 years ago

I've checked it on my machine and all seems to work fine.

    HttpClientMock httpClientMock = new HttpClientMock();
    httpClientMock.onGet().withPath(Matchers.containsString("api/x;myParam1=a;myParam2=b")).doReturn("test1");
    httpClientMock.onGet().withPath(Matchers.containsString("myParam1=c;myParam2=d")).doReturn("test2");
    httpClientMock.onGet().withPath(Matchers.containsString("myParam1=e&myParam2=f")).doReturn("test3");
    httpClientMock.onGet().withPath(Matchers.containsString("myParam1=g%3FmyParam2=h")).doReturn("test4");

    HttpResponse test1 = httpClientMock.execute(new HttpGet("http://myHost/api/x;myParam1=a;myParam2=b"));
    HttpResponse test2 = httpClientMock.execute(new HttpGet("http://myHost/api/x;myParam1=c;myParam2=d"));
    HttpResponse test3 = httpClientMock.execute(new HttpGet("http://myHost/api/x;myParam1=e&myParam2=f"));
    HttpResponse test4 = httpClientMock.execute(new HttpGet("http://myHost/api/x;myParam1=g%3FmyParam2=h"));
    assertThat(test1, hasContent("test1"));
    assertThat(test2, hasContent("test2"));
    assertThat(test3, hasContent("test3"));
    assertThat(test4, hasContent("test4"));

This test uses following special characters ;&% and all of them are matched. The only character that you mentioned and which is not matched is ? but this character can never appear in the path because it separates path from the query part.

Can I ask you to provided HttpClientMock version that you are using and the full example where it is not working correctly?

ipichris commented 3 years ago

Hi @PawelAdamski

I can confirm your test case works for me using the current version 1.8.1 (i converted it from TestNG to JUnit as we cannot easily use TestNG) Additionally i wasn't able to reproduce my problems matching paths with special characters, i'm sorry and will make sure to provide an accurate test case next time.

I might have been a bit sloppy with my test and it's easy to fall into the rabbit hole of escaping problems. Consider the following test:

  @Test
  public void testGet() throws Exception {
    final String path = "/api/x;myParam=a%b";

    final HttpClientMock httpClientMock = new HttpClientMock();
    httpClientMock.onGet().withPath(path).doReturn("test1");

    final URI uri = new URI("http", "myHost", path, null);
    final HttpResponse test1 = httpClientMock.execute(new HttpGet(uri));

    httpClientMock.verify().get().withPath(path).called(1);
  }

This fails as the % is escaped to %25

Request: GET http://myHost/api/x;myParam=a%25b
Rule 1:
    MATCHES     EXPECTED
    true        HTTP method is GET
    true        schema is an instance of java.lang.String
    true        host is 
    false       path is "/api/x;myParam=a%b"
    true        port is empty

=> /api/x;myParam=a%25b vs /api/x;myParam=a%b

The test fails also when replacing the % with

but will succeed for

Do you see a possibility to ease this issue? For example automatically escaping the given path or throwing an exception if an invalid path is provided? However both would not reliably work when using a Matcher

ipichris commented 3 years ago

I just noticed that 1.8.1 is in fact not the most recent version, it seems Github isn't tracking the releases since 1.8.1 and still shows this as most recent release

PawelAdamski commented 2 years ago

Closing. Works in latest version.