Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

url encode stateparams #1119

Closed
pdeva opened this issue Jun 3, 2014 · 68 comments
Closed

url encode stateparams #1119

pdeva opened this issue Jun 3, 2014 · 68 comments
Assignees
Labels
Milestone

Comments

@pdeva
Copy link

pdeva commented Jun 3, 2014

If i pass a string like /default to $stateParams, it seems to mess up the routing:

var name = "/default";
this.$state.go("app.transactions.detail", { txnName: name });

While the controller is invoked, the url is unable to switch to.
when i encode the value before passing it to $stateparams, it works.

however, ui-router should take care of doing the encoding/decoding for me.

@johnmckay-reward
Copy link

Did you ever get anywhere with this? Having the same issue

@christopherthielen
Copy link
Contributor

Can I see your state definitions? Does this work for querystring params but not path params?

@tmair
Copy link

tmair commented Nov 14, 2014

Somehow this bugfix introduced some new issues. When transitioning to a state with state.go and a state parameter that contains a / the / is being first encoded as %2F but is then passed to encodeURIComponent which will in turn also encode the % character and break the URL

@christopherthielen
Copy link
Contributor

Doesn't this encode to "%252F" which is valid encoded in a url?

@christopherthielen
Copy link
Contributor

I should mention why it encodes / to %2F, then passes to encodeURIComponent. If you run $location.url("/foo/%2F"), the slash is automatically decoded and appears in the browser bar as "/foo//" which is the same as the original behavior. Encoding the slash before running the string through encodeURIComponent is necessary to get the slash encoded into the url parameter.

  • $location.url("/foo/%2F"): browser location is /foo//
  • $location.url("/foo/%2F"): browser location is /foo/%252F
    • decodeURIComponent: /foo/%2F
    • match and capture: /foo/ { fooid: "%25F" }
    • String type replace %2f: /foo/ {fooid: "/" }

@tmair
Copy link

tmair commented Nov 15, 2014

Indeed it encodes to ´%252F´ within the URL if one of the parameters contains a /. I did not have enough time to investigate what states are activated and why in the end my app breaks. I will look into it more during the next days.

What is the difference in your example? As you write twice $location.url("/foo/%2F")

@tmair
Copy link

tmair commented Nov 17, 2014

I had more time to look at the issue and came across the String.replace function, which replaces just the first occurence of /. Is that the desired behaviour or is the global flag missing?

In my use case the last parameter of the URL contains a path which may have more than one / within the parameter e.g. (paramId = 'path/whith/slashes'). What is the URL intended to be when this gets passed to state.go via a state parameter?

@christopherthielen
Copy link
Contributor

Thank you for checking, that is likely the issue

@tmair
Copy link

tmair commented Nov 18, 2014

Thanks for fixing the issue.

Actually my problems are almost the same as #1557. I have a URL like the following /{foo}/*path, where path should match the rest of the url. I solved the issue by defining a custom path type, which will not encode the URL for me. That solved the issue and is acually a really neat way to state that I want to match the path as a custom type.

@christopherthielen
Copy link
Contributor

Custom type, cool :)

@kumarharsh
Copy link

@christopherthielen I think there is one scenario which is still broken... or atleast, I can't get it working...

I have objects which have a / in their IDs.
Now, I have these states:

.state('base.list'
  url: '/list?page&limit'
)
.state('base.list.item',
  url: '/{item_id:(?:[^/]+\/[^/]+)}'
)

So, the url constructed by the ui-sref for base.list.item({item_id: abc/001}) is ...

https://example.com/list/abc%252F001

... which does transition to the correct state, but when I reload the page, the regex match for the base.list.item fails, and my application is redirected to the default route....

@kumarharsh
Copy link

And as far as I remember, it was working perfectly in 0.2.11

@christopherthielen
Copy link
Contributor

@kumarharsh yeah that's a corner case I didn't think about. You don't actually need a regexp for item_id, now that the "string" parameter Type (the default type) encodes the slashes. just use url: '/{item_id}'.

If you really don't want the slash encoded for you, register a custom type with your regexp and declare item_id to be your custom type, i.e., url: /{item_id:MyType}

  function valToString(val) { return val != null ? val.toString() : val; }
  function valFromString(val) { return val != null ? val.toString() : val; }
  function regexpMatches(val) { /*jshint validthis:true */ return this.pattern.test(val); }
  $urlMatcherFactory.type("MyType", {
      encode: valToString,
      decode: valFromString,
      is: regexpMatches,
      pattern: /[^/]+\/[^/]+/
    });

@panuhorsmalahti
Copy link

I also needed a state parameter which is not URI encoded. Perhaps this should be included by default..

Here's my solution (in TypeScript)

    // Define an URL state parameter type which is not URI encoded
    $urlMatcherFactoryProvider.type("nonURIEncoded", {
        encode: (item: any) => item || "",
        decode: (item: any) => item || "",
        // Item is always valid
        is: (item: any) => true
    });

@christian-fei
Copy link

This is awesome, thanks for the solution with the urlMatcher!

@malterb
Copy link

malterb commented Jan 8, 2015

@panuhorsmalahti great, thank you very much!

@martin-brennan-csnet
Copy link

Is this supposed to work with queryString parameters as well? I've tried the custom types with $urlMatcherFactory and it works with parameters in the url e.g. /route/{param:MyType}/etc but not with queryString parameters e.g. /route?{param:MyType}.

@christopherthielen
Copy link
Contributor

@martin-brennan-csnet yes, it is expected to work for query parameters too.

@soarb
Copy link

soarb commented Apr 8, 2015

@christopherthielen I appear to have a similar issue to @martin-brennan-csnet. Registering a custom type for my /route/{url:nonURIEncoded} parameter works a treat, but as a queryString parameter even though a call is made to my custom types 'encode' method, the forward slashes are still being converted to %2F when I call $state.go('state', {url: 'http://someurl/somepath'}) - am I missing something else here? Cheers! Ben

@mismith
Copy link

mismith commented Apr 8, 2015

I still can't get this to work. Am I missing something? Here's a quick plunk showing the problem:
http://plnkr.co/edit/tNlRmadZRUGRPHhrKqTQ?p=preview

nateabele added a commit that referenced this issue Aug 31, 2015
@mismith
Copy link

mismith commented Aug 31, 2015

@nateabele sweet, nicely done. I'm not sure I understand your request however; would you like me to write a test for #2218? I'm not using 1.0 nor am I familiar with TypeScript yet, so I don't know possible that is. Or did you mean I should write an equivalent feature for 0.2.x (including tests)? That I could do!

@nateabele
Copy link
Contributor

[W]ould you like me to write a test for #2218?

Yes.

I'm not using 1.0 nor am I familiar with TypeScript yet, so I don't know possible that is.

The test suite & build setup are identical. You don't need to know anything about TypeScript. Just follow the contributor guidelines and add a failing test for a type with raw: true. Then run grunt integrate.

Let me know if you need help or have other questions.

@sanyam-j
Copy link

sanyam-j commented Jan 6, 2016

It this issue is fixed in latest release. If yes, then how i have to use it in defining ui routes. Bz i am getting the same issue with angular 1.4.7 & ui-router 0.2.15

@drothlis
Copy link

drothlis commented Jan 6, 2016

If you really don't want the slash encoded for you, register a custom type with your regexp and declare item_id to be your custom type, i.e., url: /{item_id:MyType}

Note that since 0.2.15 ui-router provides a type called any that doesn't encode slashes (see 3bfd75a), so you can say url: /{item_id:any}.

@mismith
Copy link

mismith commented Jan 6, 2016

@drothlis Unfortunately using 0.2.15 and any still doesn't fix the issue, at least not on Chrome. See above discussion: #1119 (comment)

Edit: to clarify, this issue was fixed by @nateabele in #2218, but only for v1.0.X. For older versions, i.e. v0.2.X, it remains unresolved. I think this is what @gonzoyumo's commit (gonzoyumo@c7f07e3) aims to resolve, but I suspect his commit won't get merged until proper tests are added.

@drothlis
Copy link

drothlis commented Jan 7, 2016

@mismith I see, there are several subtly different issues here.

  1. Some people want a path component in the URL to contain slashes, and for those slashes to show up in the URL as / not %2F (and certainly not %252F).
  2. Some people want a querystring component in the URL to contain slashes. Are unescaped slashes are allowed here? Would you want them to show up in the URL as / or %2F? I'm not sure. For now, in my app, I've made my peace with them showing up as %2F.
  3. Everybody wants either of the above to survive an encode/decode round trip. That is, if you generate a URL (e.g. by using ui-sref('some-state', {some_param: "with/slashes"}), then when you follow that link you should get the same parameter back from $stateParams ("with/slashes", not "with%2Fslashes").

(3) was broken because slashes were double-encoded in one direction and single-decoded in the other direction. Using the custom type (or any since 0.2.15 or 1.0.0alpha0) fixes this, at least in my use case: setting the parameter with ui-sref and getting it back from $stateParams. I don't use $state.href().

(1) Still happens according to your plunkr. In my use case (any + ui-sref + $stateParams) the URL shows correctly (with / instead of %2F) in the browser URL bar in Firefox and Chrome, but it still shows %2F in the status bar in Chrome (when you hover over the link). I assume that this is because the browser automatically converts %2F to / (but only in path components, not in querystrings). (?)

Honestly I can't tell which of the various github issues is supposed to track which of the above problems, but at least for my use case, I can confirm that any on 0.2.15 and 1.0.0alpha0 fixes (3) for me.

Thanks for the info, the plunkr, and the link to the new raw flag -- it all helped to clarify the above for me.

@sanyam-j
Copy link

sanyam-j commented Jan 7, 2016

@drothlis I am using "url: '/search/*path'". How can i use "any" with dynamic path?

@drothlis
Copy link

drothlis commented Jan 7, 2016

I should add that somewhere between 0.2.13 and 0.2.15, ui-router broke querystring components with slashes. In 0.2.13 you could have a state like this:

url: "path?param1&param2"

In 0.2.15 that will no longer work if the parameter values have slashes in them: the encode/decode round trip will give back a different result than the original value, just like it was already broken for path components in 0.2.13.

In 0.2.15 you will have to use the any type like this:

url: "path?{param1:any}&{param2:any}"

@christopherthielen
Copy link
Contributor

Thanks for your patience. Please build off master and see if this commit 02e9866 has addressed the issue for your apps and use cases.

@moneytree-doug
Copy link

Okay, so my particular case is that I am passing a url for redirect_url in OAuth. This is how it encodes:

https:%252F%252Fstage.example.com%252FHA%252Fapi%252Fcore.php

My current work around is to decode it twice before I do any further processing with it. Here it is after first decode:

https:%2F%2Fstage.example.com%2FHA%2Fapi%2Fcore.php

After the second decode:

https://stage.example.com/HA/api/core.php

@christopherthielen I tried that commit, and it doesn't seem to be different except for the difference using ~2F. I would just expect an url encode resulting in:

https%3A%2F%2Fstage.example.com%2FHA%2Fapi%2Fcore.php

@christopherthielen
Copy link
Contributor

@moneytree-doug urlencoding of the slashes was the root of the problem, which caused edge cases. I switched away from urlencoding slashes to a custom encoding that the browser cannot pre-process without our knowledge.

Since I am not familiar with the OAuth flow, can you explain how your url parameter works through your workflow, and how the fix from 02e9866 is not helping? The goal for ui-router is to allow parameter values including path parameters to have encoded slashes, to allow path parameters to be in the middle of the path, and to be encoded/decoded bi-directionally (allowing a url with slashes in parameters to be bookmarked)

As far as I can tell, we now perform this encoding properly. Slashes should encode to ~2F, and decode back to /. Tildes ~ should encode to ~~ and decode back to ~.

@bettysteger
Copy link

@christopherthielen I just upgraded from 0.2.15 to 0.2.18 and got this problem when using OAuth.. the slashes in the redirectUri parameter should be %252F instead of ~2F

0.2.15 - works!

http://localhost/accounts/test/projects/example-project/connect/github?redirectUri=%252Ftest%252Fexample-project%252Fsetup%252Fgithub

0.2.18

http://localhost/accounts/test/projects/example-project/connect/github?redirectUri=~2Ftest~2Fexample-project~2Fsetup~2Fgithub

this PR #2071 is already in 0.2.18 I think?

I used $state.href for creating the oAuth URL and the redirectUri parameter:

stateParams.redirectUri = $state.href('.setup', {provider: provider});
return API_END_POINT + $state.href('oauth_connect', stateParams);
    .state('oauth_connect', {
      url: 'accounts/:account/projects/:project/connect/:provider?redirectUri'
    })

@moneytree-doug
Copy link

@lpsBetty I had a similar situation. You should expect the tilde after upgrading to 0.2.18. I ran into tons of headaches with this issue in the versions before and I had monkey patches, so I had tests around the encoding part until the fix came out. I am also doing OAuth, and I have migrated it safely.

Your URL in the browser will definitely have a tilde, and this is fine and is expected. However, when you access it in your application code, ui-router will properly decode it in the $stateParams or $state.params, so that there won't be tildes.

Correct me if I misunderstood.

@Hamcker
Copy link

Hamcker commented Apr 25, 2016

thanks all about the comments and patience. I followed this issue to find a way to avoid encoding url but what I got was avoid encoding slashes!!

my problem is the non-Latin chars. they're still being encoded. for example Arabic, Hebrew, Farsi etc.

for example consider I have a HTML like this :

<a ui-sref="someState(Param:'آپارتمانی')"> A localized param </a>

which will be compiled to:

<a href="#!/Procuts/%D8%B2%DB%8C%D8%B1%20%D8%B2%D8%A7%D9%86%D9%88"> A localized param </a>

on StackOverflow:

is it possible to avoid that?

@dkrugman
Copy link

dkrugman commented May 5, 2016

tl;dr

... but I see that there is still some activity here so I'm adding that upgrading from 0.2.10 to anything above 0.2.11 breaks my code, which depends on slashes in the URL.

After upgrading to 0.2.18:
the URL: /browse/Children/Girls/Dresses+&+Skirts
becomes: /browse/Children2FGirls2FDresses+&+Skirts

and I see that in the browser address bar:
screenshot 2016-05-05 18 45 10

So I'm sticking with 0.2.11, but my 2 cents is that whatever happened here over the last 2 years created a significant issue in that I now see the URL get encoded in 0.2.18.

I hope that's helpful in ultimately resolving this issue.

Thanks

@moneytree-doug
Copy link

@dkrugman Why is there no # in your URL?

@perrierism
Copy link

@moneytree-doug he has Html5Mode equal to True https://docs.angularjs.org/api/ng/provider/$locationProvider

ExpFront pushed a commit to ExpFront/ui-router that referenced this issue Jun 23, 2016
@majew7
Copy link

majew7 commented Sep 19, 2016

My issue may have been different, but I was happy to find :any in this discussion. I my code replaced
url: 'products/{slugPath:.*}'
with
url: 'products/{slugPath:any}'

and I had success with finally seeing the forward slash when writing the slugPath rather than ~2F.

@christopherthielen
Copy link
Contributor

Also note we support non-encoded param types in 1.0, via raw: true

Here's the docs ;)

@tuoxiansp
Copy link

@majew7 Thanks!

@olehs1
Copy link

olehs1 commented Apr 3, 2017

@fabiosussetto BIG THANKS MAN!!!!!!

@tanyaburlakova
Copy link

hey @fabiosussetto!

I have another problem when I need to use param as query param.
I can use it like url: '/login?next={nextUrl:nonURIEncoded}',
and I see this login?nextUrl=%2Fisv%2Fedit%2Ftanya-123%2Fpreview

Can u please help to understand what I need to do to fix it?
Or maybe some another way to resolve my task. I need to set param with previous url to link.
Thank u!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests