Skip to content

Commit e79a7ea

Browse files
committed
fix: query string urlencode problem
1 parent 5702bec commit e79a7ea

File tree

11 files changed

+116
-24
lines changed

11 files changed

+116
-24
lines changed

source/controlers/rss.ts

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import twoKeyReply from '../utils/two-key-reply';
44
import errors from '../utils/errors';
55
import { MContext, Next } from '../types/ctx';
66
import { isNone } from '../types/option';
7-
import { decodeUrl } from '../utils/decodeUrl';
7+
import { decodeUrl, encodeUrl } from '../utils/urlencode';
88
import sanitize from '../utils/sanitize';
99

1010
export async function sub(ctx: MContext, next: Next): Promise<void> {
@@ -17,7 +17,9 @@ export async function sub(ctx: MContext, next: Next): Promise<void> {
1717
await ctx.telegram.deleteMessage(ctx.chat.id, ctx.state.processMsgId);
1818
ctx.state.processMsgId = null;
1919
ctx.replyWithMarkdown(`
20-
${i18n[lang]['SUB_SUCCESS']} [${ctx.state.feed.feed_title}](${ctx.state.feedUrl})`);
20+
${i18n[lang]['SUB_SUCCESS']} [${ctx.state.feed.feed_title}](${encodeUrl(
21+
ctx.state.feedUrl
22+
)})`);
2123
} catch (e) {
2224
if (e instanceof errors.ControllableError) throw e;
2325
throw errors.newCtrlErr('DB_ERROR', e);
@@ -37,7 +39,7 @@ export async function unsub(ctx: MContext, next: Next): Promise<void> {
3739
ctx.state.processMsgId = null;
3840
ctx.replyWithMarkdown(
3941
`
40-
${i18n[lang]['UNSUB_SUCCESS']} [${feed.value.feed_title}](${encodeURI(
42+
${i18n[lang]['UNSUB_SUCCESS']} [${feed.value.feed_title}](${encodeUrl(
4143
ctx.state.feedUrl
4244
)})`,
4345
{
@@ -85,15 +87,15 @@ export async function rss(ctx: MContext, next: Next): Promise<void> {
8587
if (raw) {
8688
feeds.forEach((feed) => {
8789
builder.push(
88-
`${sanitize(feed.feed_title)}: <a href="${encodeURI(
90+
`${sanitize(feed.feed_title)}: <a href="${encodeUrl(
8991
feed.url.trim()
9092
)}">${decodeUrl(feed.url.trim())}</a>`
9193
);
9294
});
9395
} else {
9496
feeds.forEach((feed) => {
9597
builder.push(
96-
`<a href="${encodeURI(feed.url.trim())}">${sanitize(
98+
`<a href="${encodeUrl(feed.url.trim())}">${sanitize(
9799
feed.feed_title
98100
)}</a>`
99101
);
@@ -144,7 +146,7 @@ export async function viewAll(ctx: MContext, next: Next): Promise<void> {
144146
const url = feed.url.trim();
145147
const title = sanitize(feed.feed_title);
146148
builder.push(
147-
`<a href="${encodeURI(url)}">${title}</a> ${
149+
`<a href="${encodeUrl(url)}">${title}</a> ${
148150
i18n[lang]['NUMBER_OF_SUBSCRIBER']
149151
}: ${feed.sub_count}`
150152
);

source/index.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ import {
4242
Message
4343
} from './types/message';
4444
import { migrateUser } from './proxies/users';
45+
import { encodeUrl } from './utils/urlencode';
4546

4647
const bot = new Telegraf(token, {
4748
telegram: {
@@ -264,7 +265,7 @@ async function startFetchProcess(restartTime: number): Promise<void> {
264265
const { feed, new_feed } = message;
265266
const builder = [];
266267
builder.push(
267-
`${feed.feed_title}: <a href="${encodeURI(
268+
`${feed.feed_title}: <a href="${encodeUrl(
268269
feed.url
269270
)}"></a> ${i18n[lang]['ERROR_MANY_TIME']}`
270271
); // feed is from database which not urlencoded

source/middlewares/get-url-by-title.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { MContext, Next } from '../types/ctx';
22

33
import { getFeedsByTitle } from '../proxies/rss-feed';
44
import errors from '../utils/errors';
5-
import { decodeUrl } from '../utils/decodeUrl';
5+
import { decodeUrl } from '../utils/urlencode';
66
export default async (ctx: MContext, next: Next): Promise<void> => {
77
const me = await ctx.telegram.getMe();
88
const myId = me.id;

source/middlewares/get-url.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import errors from '../utils/errors';
22
import { getSubscribedFeedsByUserId } from '../proxies/rss-feed';
33
import i18n from '../i18n';
44
import { MContext, Next } from '../types/ctx';
5-
import { decodeUrl } from '../utils/decodeUrl';
5+
import { decodeUrl } from '../utils/urlencode';
66

77
export default async (ctx: MContext, next: Next): Promise<void> => {
88
const { lang } = ctx.state;

source/middlewares/sub-multi-url.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { MContext, Next } from '../types/ctx';
66
import { isSome } from '../types/option';
77
import { Feed } from '../types/feed';
88
import { parseString } from '../parser/parse';
9-
import { decodeUrl } from '../utils/decodeUrl';
9+
import { decodeUrl, encodeUrl } from '../utils/urlencode';
1010

1111
export default async (ctx: MContext, next: Next): Promise<void> => {
1212
const urls = ctx.message.text.match(
@@ -22,7 +22,7 @@ export default async (ctx: MContext, next: Next): Promise<void> => {
2222
return feed.value;
2323
} else {
2424
try {
25-
const res = await got.get(encodeURI(url));
25+
const res = await got.get(encodeUrl(url));
2626
const rssFeed = await parseString(res.body);
2727
// const rssFeed = await parser.parseString(res.body);
2828
return {
@@ -55,7 +55,7 @@ export default async (ctx: MContext, next: Next): Promise<void> => {
5555
}
5656
// encodeURL because it is decoded
5757
builder.push(
58-
`<a href="${encodeURI(feed.url)}">${feed.feed_title}</a>`
58+
`<a href="${encodeUrl(feed.url)}">${feed.feed_title}</a>`
5959
);
6060
});
6161
if (builder.length > 1) {

source/middlewares/test-url.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,10 @@ import { getFeedByUrl } from '../proxies/rss-feed';
66
import { MContext, Next } from '../types/ctx';
77
import { isNone, isSome } from '../types/option';
88
import { parseString } from '../parser/parse';
9-
import { decodeUrl } from '../utils/decodeUrl';
9+
import { decodeUrl, encodeUrl } from '../utils/urlencode';
1010

1111
export default async (ctx: MContext, next: Next): Promise<void> => {
12-
const url = encodeURI(ctx.state.feedUrl);
12+
const url = encodeUrl(ctx.state.feedUrl);
1313
const feedOption = await getFeedByUrl(url);
1414
if (isSome(feedOption)) {
1515
// feed is in database;
@@ -29,7 +29,7 @@ export default async (ctx: MContext, next: Next): Promise<void> => {
2929
case 0:
3030
throw errors.newCtrlErr('FETCH_ERROR');
3131
case 1:
32-
const res = await got(encodeURI(ctx.state.feedUrls[0]));
32+
const res = await got(encodeUrl(ctx.state.feedUrls[0]));
3333
const realFeed = await parseString(res.body);
3434
ctx.state.feed = {
3535
url: ctx.state.feedUrls[0],

source/proxies/rss-feed.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import errors from '../utils/errors';
33
import { Feed } from '../types/feed';
44
import { Subscribe } from '../types/subscribe';
55
import { isSome, Option, Optional, Some } from '../types/option';
6-
import { decodeUrl } from '../utils/decodeUrl';
6+
import { decodeUrl } from '../utils/urlencode';
77

88
export async function sub(
99
userId: number,

source/utils/decodeUrl.ts

Lines changed: 0 additions & 6 deletions
This file was deleted.

source/utils/fetch.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import {
2424
ErrorMaxTimeMessage,
2525
ChangeFeedUrlMessage
2626
} from '../types/message';
27+
import { encodeUrl } from './urlencode';
2728
const { notify_error_count, item_num, concurrency, fetch_gap } = config;
2829

2930
function nextFetchTimeStr(minutes: number) {
@@ -79,7 +80,8 @@ async function fetch(feedModal: Feed): Promise<Option<any[]>> {
7980
const feedUrl = feedModal.url;
8081
try {
8182
logger.debug(`fetching ${feedUrl}`);
82-
const request = got.get(encodeURI(feedUrl), {
83+
const requestUrl = encodeUrl(feedUrl);
84+
const request = got.get(requestUrl, {
8385
headers: {
8486
'If-None-Match': feedModal.etag_header,
8587
'If-Modified-Since': feedModal.last_modified_header
@@ -100,7 +102,7 @@ async function fetch(feedModal: Feed): Promise<Option<any[]>> {
100102
updateFeed(updatedFeedModal);
101103
return none;
102104
}
103-
if (encodeURI(feedUrl) !== res.url && res.statusCode === 301) {
105+
if (requestUrl !== res.url && res.statusCode === 301) {
104106
await handleRedirect(feedUrl, res.url);
105107
}
106108
const feed = await parseString(res.body);

source/utils/urlencode.ts

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
export function decodeUrl(url: string): string {
2+
while (url !== decodeURIComponent(url)) {
3+
url = decodeURIComponent(url);
4+
}
5+
return url;
6+
}
7+
8+
//https://github.com/miniflux/v2/pull/541
9+
export function encodeUrl(url: string): string {
10+
const [first, ...rest] = url.split('?');
11+
const u = new URL(first);
12+
if (rest.length > 0) {
13+
const queryStr = rest.join('?');
14+
const query = new URLSearchParams(queryStr);
15+
query.sort();
16+
const search =
17+
'?' +
18+
[...query.entries()]
19+
.map(([k, v]) => {
20+
k = encodeURIComponent(k);
21+
v = encodeURIComponent(v);
22+
if (v.length === 0) {
23+
return k;
24+
}
25+
return `${k}=${v}`;
26+
})
27+
.join('&');
28+
u.search = search;
29+
}
30+
if (u.pathname === '/') {
31+
u.pathname = '';
32+
}
33+
u.hash = ''; // strip URL fragments
34+
return u.toString();
35+
}

0 commit comments

Comments
 (0)