client/general: improve URL escaping
Specifically, cater for /, + and % in URL components.
This commit is contained in:
parent
a22fe306d1
commit
7fa8593b0a
15 changed files with 39 additions and 26 deletions
|
@ -151,6 +151,7 @@ the one in the `config.yaml`, so that client knows how to access the backend!
|
|||
server {
|
||||
listen 80;
|
||||
server_name great.dude;
|
||||
merge_slashes off; # to support post tags such as ///
|
||||
|
||||
location ~ ^/api$ {
|
||||
return 302 /api/;
|
||||
|
|
|
@ -63,12 +63,15 @@ class Api extends events.EventTarget {
|
|||
|
||||
_process(url, requestFactory, data, files, options) {
|
||||
options = options || {};
|
||||
const fullUrl = this._getFullUrl(url);
|
||||
const [fullUrl, query] = this._getFullUrl(url);
|
||||
return new Promise((resolve, reject) => {
|
||||
if (!options.noProgress) {
|
||||
nprogress.start();
|
||||
}
|
||||
let req = requestFactory(fullUrl);
|
||||
if (query) {
|
||||
req.query(query);
|
||||
}
|
||||
if (data) {
|
||||
req.attach('metadata', new Blob([JSON.stringify(data)]));
|
||||
}
|
||||
|
@ -176,8 +179,12 @@ class Api extends events.EventTarget {
|
|||
}
|
||||
|
||||
_getFullUrl(url) {
|
||||
return (config.apiUrl + '/' + encodeURI(url))
|
||||
.replace(/([^:])\/+/g, '$1/');
|
||||
const fullUrl =
|
||||
(config.apiUrl + '/' + url).replace(/([^:])\/+/g, '$1/');
|
||||
const matches = fullUrl.match(/^([^?]*)\??(.*)$/);
|
||||
const baseUrl = matches[1];
|
||||
const request = matches[2];
|
||||
return [baseUrl, request];
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -32,7 +32,7 @@ class CommentsController {
|
|||
},
|
||||
requestPage: page => {
|
||||
return PostList.search(
|
||||
'sort:comment-date+comment-count-min:1', page, 10, fields);
|
||||
'sort:comment-date comment-count-min:1', page, 10, fields);
|
||||
},
|
||||
pageRenderer: pageCtx => {
|
||||
Object.assign(pageCtx, {
|
||||
|
|
|
@ -255,7 +255,7 @@ class PostController {
|
|||
}
|
||||
|
||||
module.exports = router => {
|
||||
router.enter('/post/:id/edit/:parameters?',
|
||||
router.enter('/post/:id/edit/:parameters(.*)?',
|
||||
(ctx, next) => { misc.parseUrlParametersRoute(ctx, next); },
|
||||
(ctx, next) => {
|
||||
// restore parameters from history state
|
||||
|
@ -265,7 +265,7 @@ module.exports = router => {
|
|||
ctx.controller = new PostController(ctx.parameters.id, true, ctx);
|
||||
});
|
||||
router.enter(
|
||||
'/post/:id/:parameters?',
|
||||
'/post/:id/:parameters(.*)?',
|
||||
(ctx, next) => { misc.parseUrlParametersRoute(ctx, next); },
|
||||
(ctx, next) => {
|
||||
// restore parameters from history state
|
||||
|
|
|
@ -120,7 +120,7 @@ class PostListController {
|
|||
|
||||
module.exports = router => {
|
||||
router.enter(
|
||||
'/posts/:parameters?',
|
||||
'/posts/:parameters(.*)?',
|
||||
(ctx, next) => { misc.parseUrlParametersRoute(ctx, next); },
|
||||
(ctx, next) => { ctx.controller = new PostListController(ctx); });
|
||||
};
|
||||
|
|
|
@ -121,16 +121,16 @@ class TagController {
|
|||
}
|
||||
|
||||
module.exports = router => {
|
||||
router.enter('/tag/:name', (ctx, next) => {
|
||||
ctx.controller = new TagController(ctx, 'summary');
|
||||
});
|
||||
router.enter('/tag/:name/edit', (ctx, next) => {
|
||||
router.enter('/tag/:name(.+?)/edit', (ctx, next) => {
|
||||
ctx.controller = new TagController(ctx, 'edit');
|
||||
});
|
||||
router.enter('/tag/:name/merge', (ctx, next) => {
|
||||
router.enter('/tag/:name(.+?)/merge', (ctx, next) => {
|
||||
ctx.controller = new TagController(ctx, 'merge');
|
||||
});
|
||||
router.enter('/tag/:name/delete', (ctx, next) => {
|
||||
router.enter('/tag/:name(.+?)/delete', (ctx, next) => {
|
||||
ctx.controller = new TagController(ctx, 'delete');
|
||||
});
|
||||
router.enter('/tag/:name(.+)', (ctx, next) => {
|
||||
ctx.controller = new TagController(ctx, 'summary');
|
||||
});
|
||||
};
|
||||
|
|
|
@ -75,7 +75,7 @@ class TagListController {
|
|||
|
||||
module.exports = router => {
|
||||
router.enter(
|
||||
'/tags/:parameters?',
|
||||
'/tags/:parameters(.*)?',
|
||||
(ctx, next) => { misc.parseUrlParametersRoute(ctx, next); },
|
||||
(ctx, next) => { ctx.controller = new TagListController(ctx); });
|
||||
};
|
||||
|
|
|
@ -69,7 +69,7 @@ class UserListController {
|
|||
|
||||
module.exports = router => {
|
||||
router.enter(
|
||||
'/users/:parameters?',
|
||||
'/users/:parameters(.*)?',
|
||||
(ctx, next) => { misc.parseUrlParametersRoute(ctx, next); },
|
||||
(ctx, next) => { ctx.controller = new UserListController(ctx); });
|
||||
};
|
||||
|
|
|
@ -6,7 +6,10 @@ const Post = require('./post.js');
|
|||
|
||||
class PostList extends AbstractList {
|
||||
static getAround(id, searchQuery) {
|
||||
return api.get(`/post/${id}/around?fields=id&query=${searchQuery}`)
|
||||
const url =
|
||||
`/post/${id}/around?fields=id` +
|
||||
`&query=${encodeURIComponent(searchQuery)}`;
|
||||
return api.get(url)
|
||||
.then(response => {
|
||||
return Promise.resolve(response);
|
||||
}).catch(response => {
|
||||
|
@ -16,7 +19,7 @@ class PostList extends AbstractList {
|
|||
|
||||
static search(text, page, pageSize, fields) {
|
||||
const url =
|
||||
`/posts/?query=${text}` +
|
||||
`/posts/?query=${encodeURIComponent(text)}` +
|
||||
`&page=${page}` +
|
||||
`&pageSize=${pageSize}` +
|
||||
`&fields=${fields.join(',')}`;
|
||||
|
|
|
@ -7,7 +7,7 @@ const Snapshot = require('./snapshot.js');
|
|||
class SnapshotList extends AbstractList {
|
||||
static search(text, page, pageSize) {
|
||||
const url =
|
||||
`/snapshots/?query=${text}` +
|
||||
`/snapshots/?query=${encodeURIComponent(text)}` +
|
||||
`&page=${page}` +
|
||||
`&pageSize=${pageSize}`;
|
||||
return api.get(url).then(response => {
|
||||
|
|
|
@ -7,7 +7,7 @@ const Tag = require('./tag.js');
|
|||
class TagList extends AbstractList {
|
||||
static search(text, page, pageSize, fields) {
|
||||
const url =
|
||||
`/tags/?query=${text}` +
|
||||
`/tags/?query=${encodeURIComponent(text)}` +
|
||||
`&page=${page}` +
|
||||
`&pageSize=${pageSize}` +
|
||||
`&fields=${fields.join(',')}`;
|
||||
|
|
|
@ -6,7 +6,9 @@ const User = require('./user.js');
|
|||
|
||||
class UserList extends AbstractList {
|
||||
static search(text, page) {
|
||||
const url = `/users/?query=${text}&page=${page}&pageSize=30`;
|
||||
const url =
|
||||
`/users/?query=${encodeURIComponent(text)}` +
|
||||
`&page=${page}&pageSize=30`;
|
||||
return api.get(url).then(response => {
|
||||
return Promise.resolve(Object.assign(
|
||||
{},
|
||||
|
|
|
@ -75,7 +75,7 @@ class Route {
|
|||
const keys = this.keys;
|
||||
const qsIndex = path.indexOf('?');
|
||||
const pathname = ~qsIndex ? path.slice(0, qsIndex) : path;
|
||||
const m = this.regexp.exec(decodeURIComponent(pathname));
|
||||
const m = this.regexp.exec(pathname);
|
||||
|
||||
if (!m) {
|
||||
return false;
|
||||
|
|
|
@ -165,7 +165,7 @@ function formatUrlParameters(dict) {
|
|||
continue;
|
||||
}
|
||||
if (value) {
|
||||
result.push(`${key}=${value}`);
|
||||
result.push(`${key}=${encodeURIComponent(value)}`);
|
||||
}
|
||||
}
|
||||
return result.join(';');
|
||||
|
|
|
@ -56,14 +56,14 @@ def create_tag(ctx, _params=None):
|
|||
return _serialize(ctx, tag)
|
||||
|
||||
|
||||
@routes.get('/tag/(?P<tag_name>[^/]+)/?')
|
||||
@routes.get('/tag/(?P<tag_name>.+)')
|
||||
def get_tag(ctx, params):
|
||||
auth.verify_privilege(ctx.user, 'tags:view')
|
||||
tag = tags.get_tag_by_name(params['tag_name'])
|
||||
return _serialize(ctx, tag)
|
||||
|
||||
|
||||
@routes.put('/tag/(?P<tag_name>[^/]+)/?')
|
||||
@routes.put('/tag/(?P<tag_name>.+)')
|
||||
def update_tag(ctx, params):
|
||||
tag = tags.get_tag_by_name(params['tag_name'])
|
||||
versions.verify_version(tag, ctx)
|
||||
|
@ -97,7 +97,7 @@ def update_tag(ctx, params):
|
|||
return _serialize(ctx, tag)
|
||||
|
||||
|
||||
@routes.delete('/tag/(?P<tag_name>[^/]+)/?')
|
||||
@routes.delete('/tag/(?P<tag_name>.+)')
|
||||
def delete_tag(ctx, params):
|
||||
tag = tags.get_tag_by_name(params['tag_name'])
|
||||
versions.verify_version(tag, ctx)
|
||||
|
@ -126,7 +126,7 @@ def merge_tags(ctx, _params=None):
|
|||
return _serialize(ctx, target_tag)
|
||||
|
||||
|
||||
@routes.get('/tag-siblings/(?P<tag_name>[^/]+)/?')
|
||||
@routes.get('/tag-siblings/(?P<tag_name>.+)')
|
||||
def get_tag_siblings(ctx, params):
|
||||
auth.verify_privilege(ctx.user, 'tags:view')
|
||||
tag = tags.get_tag_by_name(params['tag_name'])
|
||||
|
|
Loading…
Reference in a new issue