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

Fix handling of urlencoded '+' #168

Merged
merged 1 commit into from
Jun 30, 2015

Conversation

sprohaska
Copy link
Contributor

Previously, '%2B' was incorrectly converted to space. The reason was
that page.js's Context() calls decodeURLEncodedURIComponent() when
initializing pathname and Route.match() calls
decodeURLEncodedURIComponent() again on the matched params after
splitting pathname. Since decodeURLEncodedURIComponent() replaces
plus with space and the path is already decoded when calling it on the
params, pluses were incorrectly converted to spaces.

page's Route.match() calls decodeURIComponent() to decode pathname
before applying the path regex, so there is no need to decode the entire
path when initializing the Context().

page.js's behavior seems odd. But I haven't fully understood whether it
is a bug, so this fixes it by disabling page.js's
decodeURLEncodedURIComponent() via the config object.

The tests are updated to exercise the param matching with a few
urlencoded special characters.

rendered++;
}
});

FlowRouter.go(pathDef, {key: "abc"});
FlowRouter.go(pathDef, {key: "abc%20%2B%40%25"});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why you need put encoded string here? I think that should be done by the router.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you are right that the router should encode it. See longer comment below.

@arunoda
Copy link
Contributor

arunoda commented Jun 17, 2015

I'm quite not sure about here. Need some voice from others as well. @elidoran @delgermurun

@delgermurun
Copy link
Contributor

What is the problem? What is exact behavior?

@elidoran
Copy link
Contributor

pagejs appears to decode twice as @sprohaska describes. See pagejs line 491 and line 497.

I don't know why they would decode it twice. The first time always happens and the second happens unless you disable it. The second one also explicitly changes pluses to spaces before decoding (here).

I'm curious to know why they do that. Perhaps raise this issue with pagejs and see what they have to say?

It seems like outright disabling it would alter behavior and possibly break backwards compatibility. How about providing a way for a user to specify FlowRouter should disable the extra decoding, and leave it enabled by default.

Also, when I do the calls listed below I get an error: URIError: URI malformed. Should it encode it for us?

  • FlowRouter.go('/app/abc +@%')
  • FlowRouter.go('/app/abc%20%2B%40%25')
  • FlowRouter.go('/app/:param', {param:'abc%20%2B%40%25'})
  • FlowRouter.go('/app/home?test=abc +@%')

Without the % and %25 they work fine and all return abc @ (plus sign is replaced with a space).

When I do FlowRouter.go('/app/home?test=abc%20%2B%40%25') it works and the browser shows the encoded version. FlowRouter.getQueryParam('test') returns the decoded version "abc +@%".

So, this seems to require some review to determine what the behavior should actually be.

@sprohaska
Copy link
Contributor Author

I agree that a good solution may require clarification of the behavior in pagejs.

I'm a bit unsure what I'd exactly expect from flow router. It seems reasonable that whatever I type in the browser's address field should be put into the params as urldecoded strings and I can just use them without any further decoding.

I'm less sure what I'd expect from FlowRouter.go(). One option would be that FlowRouter.go(path) behaves as if I typed path into the browser's address field, which means that it would not urlencode path. But for symmetry with route matching, FlowRouter.go('/app/:param', {param: String}), should probably urlencode the String, since it places decoded strings into params when matching a path, so it should encode them when constructing a path. In combination it would mean that flow router would not encode any direct path argument (assuming that it is already encoded) but would encode strings that are passed as params. I'm unsure whether this is a sensible choice.

Any thoughts?

Previously, '%2B' (aka '+') was incorrectly converted to space.  Other
urlencoded characters where affected, too.  The reason was that pagejs's
`Context()` calls `decodeURLEncodedURIComponent()` when initializing
`pathname` and `Route.match()` calls `decodeURLEncodedURIComponent()`
again on the matched `params` after splitting `pathname`.  Since
`decodeURLEncodedURIComponent()` replaces plus with space and the path
is already decoded when calling it on the `params`, pluses were
incorrectly converted to spaces; other urlencoded values were effected
if the second urldecoding was not idempotent.

pagejs's `Route.match()` calls `decodeURIComponent()` to decode
`pathname` before applying the path regex, so there is no need to decode
the entire path when initializing the `Context()`.  pagejs's behavior
seems odd at least; maybe it is a bug.

This commit fixes the problem by disabling pagejs's
`decodeURLEncodedURIComponent()` via the config object.  There is no
reasonable scenario in which the old behavior was correct and is
modified by fixing the duplicate decoding.  params are now correctly
handled, and `FlowRouter` uses `qs.parse()` to handle query strings,
which handles urldecoding, so pagejs should leave the query string
alone.

The semantic of `FlowRouter.path(pathDef, params, queryParams)` is
clarified to urlencode `params` and `queryParams`, but not the
`pathDef`.

The tests are updated to exercise the encoding by using a few special
characters.
@sprohaska
Copy link
Contributor Author

I've updated the commit to implement the urlencoding in FlowRouter.path() as described in my previous comment.

@sprohaska
Copy link
Contributor Author

Note that encoding of params may be unintuitive for tail params as in /:foo/:bar+. :bar captures all tail directory levels, so /a/b/c/d is matched with :bar = b/c/d. FlowRouter.path('/:foo/:bar+', {foo: 'x', bar: 'b/c/d'}) will not return the original path but /x/b%2Fc%2Fd, which is correct but looks a bit odd.

I'm unsure whether this is acceptable. I'm not fully convinced, but also do not yet have a better proposal.

@arunoda arunoda merged commit 4a792fd into kadirahq:master Jun 30, 2015
arunoda added a commit that referenced this pull request Jun 30, 2015
@arunoda
Copy link
Contributor

arunoda commented Jun 30, 2015

I had to do add a few modifications to this.
See this: 750321c

@sprohaska
Copy link
Contributor Author

It looks correct and works, but it creates ugly URLs. I'm wondering whether flow router could provide an opt-in option to disable page.js URL encoding. It would preserve backward compatibility but also provide nicer URLs by avoiding the page.js weirdness.

I haven't thought about it in more detail. Maybe I propose something when I find more time.

@sprohaska sprohaska deleted the fix-urlencoded-plus branch July 1, 2015 14:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants