{"action":"created","issue":{"url":"https://api.github.com/repos/kraih/mojo/issues/887","labels_url":"https://api.github.com/repos/kraih/mojo/issues/887/labels{/name}","comments_url":"https://api.github.com/repos/kraih/mojo/issues/887/comments","events_url":"https://api.github.com/repos/kraih/mojo/issues/887/events","html_url":"https://github.com/kraih/mojo/pull/887","id":122305575,"number":887,"title":"Allow developers to override url_escape() chars","user":{"login":"DabeDotCom","id":201473,"avatar_url":"https://avatars.githubusercontent.com/u/201473?v=3","gravatar_id":"","url":"https://api.github.com/users/DabeDotCom","html_url":"https://github.com/DabeDotCom","followers_url":"https://api.github.com/users/DabeDotCom/followers","following_url":"https://api.github.com/users/DabeDotCom/following{/other_user}","gists_url":"https://api.github.com/users/DabeDotCom/gists{/gist_id}","starred_url":"https://api.github.com/users/DabeDotCom/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/DabeDotCom/subscriptions","organizations_url":"https://api.github.com/users/DabeDotCom/orgs","repos_url":"https://api.github.com/users/DabeDotCom/repos","events_url":"https://api.github.com/users/DabeDotCom/events{/privacy}","received_events_url":"https://api.github.com/users/DabeDotCom/received_events","type":"User","site_admin":false},"labels":[],"state":"closed","locked":false,"assignee":null,"milestone":null,"comments":2,"created_at":"2015-12-15T16:06:54Z","updated_at":"2015-12-15T17:57:34Z","closed_at":"2015-12-15T16:15:54Z","pull_request":{"url":"https://api.github.com/repos/kraih/mojo/pulls/887","html_url":"https://github.com/kraih/mojo/pull/887","diff_url":"https://github.com/kraih/mojo/pull/887.diff","patch_url":"https://github.com/kraih/mojo/pull/887.patch"},"body":"This is to \"fix\" a problem with URLs that included %28/%29 parentheses.  For example:\r\n```\r\n  $self->redirect_to(\"http://example.org/foo%20%28bar%29.txt\");\r\n```\r\nwould always send back:\r\n```\r\n  302 Found\r\n  Location: http://example.org/foo%20(bar).txt\r\n```\r\nAlthough that's not *strictly* invalid, I was having trouble downstream, where a third-party app [over which I have no control] was cutting it off, thusly:\r\n```\r\n  BAD:  <a href=\"http://example.org/foo%20\">foo </a>(bar).txt\r\n\r\n  GOOD: <a href=\"http://example.org/foo%20%28bar%29.txt\">foo (bar).txt</a>\r\n```\r\nRather than hard-coding a different set of escape characters globally, which has the potential to break something, this patch allows developers to remove those characters -- or add other ones -- if they choose:\r\n```\r\n  $app->hook( after_dispatch => sub {\r\n      $Mojo::Path::url_escape_chars =~ s/[()]//g;\r\n  } );\r\n```"},"comment":{"url":"https://api.github.com/repos/kraih/mojo/issues/comments/164841551","html_url":"https://github.com/kraih/mojo/pull/887#issuecomment-164841551","issue_url":"https://api.github.com/repos/kraih/mojo/issues/887","id":164841551,"user":{"login":"DabeDotCom","id":201473,"avatar_url":"https://avatars.githubusercontent.com/u/201473?v=3","gravatar_id":"","url":"https://api.github.com/users/DabeDotCom","html_url":"https://github.com/DabeDotCom","followers_url":"https://api.github.com/users/DabeDotCom/followers","following_url":"https://api.github.com/users/DabeDotCom/following{/other_user}","gists_url":"https://api.github.com/users/DabeDotCom/gists{/gist_id}","starred_url":"https://api.github.com/users/DabeDotCom/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/DabeDotCom/subscriptions","organizations_url":"https://api.github.com/users/DabeDotCom/orgs","repos_url":"https://api.github.com/users/DabeDotCom/repos","events_url":"https://api.github.com/users/DabeDotCom/events{/privacy}","received_events_url":"https://api.github.com/users/DabeDotCom/received_events","type":"User","site_admin":false},"created_at":"2015-12-15T17:57:34Z","updated_at":"2015-12-15T17:57:34Z","body":"(Sorry for the missing tests; I've since added a couple, but I won't bother submitting a new PR until the actual implementation Best Practices are sorted out, below.)\r\n\r\nI had initially attempted to use an attribute, but I don't actually have easy access to the `Mojo::Path` *instance* from within my app...\r\n\r\nAll my app does is call `Mojolicious::Controller::redirect_to(\"http://example.org/foo%28bar%29.txt\")`.  After that, `M::C::redirect_to()` calls `M::C::url_for()`, which instantiates a new `Mojo::URL` object, whose `Mojo::URL::parse()` method calls `Mojo::URL::path()`, which finally instantiates the new `Mojo::Path` object, which is where said attribute would ultimately live.\r\n\r\nThat's **WAY** farther down the rabbit hole than I wanted to venture...  :-}\r\n\r\nI also considered sticking something in the stash — `mojo.path_escape_chars` perhaps? — but I wasn't sure if adding another reserved stash value was a good idea (and besides, `Mojo::*` packages shouldn't have access to controller-level data, anyway...)\r\n\r\nAlthough it *is* \"spooky action at a distance\", I figured a package variable (à la `$Data::Dumper::Maxdepth`) was the 'least ugly' solution.\r\n\r\nBut I'm certainly open to other suggestions, hehe...  Cheers!"}}