string url1 = "http://localhost/contents/?registered_date_from=2016-12-26T15%3A00%3A00.000Z®istered_date_to=2016-12-27T15%3A00%3A00.000Z&keywords=%EA%B3%84%ED%9A%8D%EC%84%9C";
string url2 = "http://localhost/contents/?registered_date_from=2016-12-26T15%3A00%3A00.000Z®istered_date_to=2016-12-27T15%3A00%3A00.000Z";
var uri1 = new Uri(url1);
var uri2 = new Uri(url2);
Console.WriteLine(uri1.PathAndQuery);
Console.WriteLine(uri2.PathAndQuery);
// uri1.PathAndQuery
--> /contents/?registered_date_from=2016-12-26T15:00:00.000Z®istered_date_to=2016-12-27T15:00:00.000Z&keywords=%EA%B3%84%ED%9A%8D%EC%84%9C
// uri2.PathAndQuery
--> /contents/?registered_date_from=2016-12-26T15%3A00%3A00.000Z®istered_date_to=2016-12-27T15%3A00%3A00.000Z
쿼리 스트링의 구성에 따라서(현상으로는 UTF-8 한글이 인코딩된 쿼리스트링이 있는지의 여부에 따라) System.Uri 가 쿼리스트링을 이상하게 처리하는 문제다.
System.Uri 는 매우 광범위하게 사용되고 있어서, UriBuilder, HttpClient 도 이 문제의 영향을 받는 것을 확인했다.
OAuth 등 URL hash 해서 서명하는 방식의 경우 바로 문제가 드러나는데, 일단 이번 경우는 query string 파싱을 직접 구현하는 것으로 대체해서 해결은 되기는 했다. 닷넷 소스를 들여다보고 싶긴 한데 지금은 시간이 없어서 보질 못하겠네.
이 문제를 발견한 프로젝트는 닷넷 4.5 를 타겟으로 개발된 프로젝트이고, 닷넷 4.5.1, 4.5.2 설치된 환경에서 이 문제가 발생하는 것을 확인했다.
LINQPad 로 확인해보면 동일 PC에서 Linqpad 4 에서는 아래의 문제가 발생하지 않고, Linqpad 5 에서는 아래의 문제가 재현된다.
registered_date_from, registered_date_to 는 두 경우 모두 동일하게 url encode 되어 있는 상태인데, uri1 번의 PathAndQuery 에 포함된 것은 url decode 되어 버린 상태이고 uri2 번의 경우 그렇지 않다.
uri1 번의 PathAndQuery 의 경우 더더욱 웃긴 건 일부는 url decode 되어 있고 일부는 아니라는 점.