Skip to content

Commit 85fc229

Browse files
committed
fix(realtime): compatible extractNoteIdFromSocket failed
fixed url parsed method and add testcase for extractNoteIdFromSocket Signed-off-by: BoHong Li <[email protected]>
1 parent bfb0a66 commit 85fc229

File tree

2 files changed

+146
-13
lines changed

2 files changed

+146
-13
lines changed

lib/realtime.js

Lines changed: 42 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ var Chance = require('chance')
1010
var chance = new Chance()
1111
var moment = require('moment')
1212

13+
const get = require('lodash/get')
14+
1315
// core
1416
var config = require('./config')
1517
var logger = require('./logger')
@@ -271,25 +273,51 @@ function isReady () {
271273
disconnectSocketQueue.length === 0 && !isDisconnectBusy
272274
}
273275

276+
function parseUrl (data) {
277+
try {
278+
if (url.URL) {
279+
return new url.URL(data)
280+
} else {
281+
// fallback legacy api
282+
// eslint-disable-next-line
283+
return url.parse(data)
284+
}
285+
} catch (e) {
286+
}
287+
return null
288+
}
289+
274290
function extractNoteIdFromSocket (socket) {
291+
function extractNoteIdFromReferer (referer) {
292+
if (referer) {
293+
const hostUrl = parseUrl(referer)
294+
if (!hostUrl) {
295+
return false
296+
}
297+
if (config.urlPath) {
298+
return hostUrl.pathname.slice(config.urlPath.length + 1, hostUrl.pathname.length).split('/')[1]
299+
}
300+
return hostUrl.pathname.split('/')[1]
301+
}
302+
return false
303+
}
304+
275305
if (!socket || !socket.handshake) {
276306
return false
277307
}
278-
if (socket.handshake.query && socket.handshake.query.noteId) {
279-
return socket.handshake.query.noteId
280-
} else if (socket.handshake.headers) {
308+
309+
if (get(socket, 'handshake.query.noteId')) {
310+
return decodeURIComponent(socket.handshake.query.noteId)
311+
}
312+
313+
const referer = get(socket, 'handshake.headers.referer')
314+
if (referer) {
281315
// this part is only for backward compatibility only; current code
282316
// should be using noteId query parameter instead.
283-
var referer = socket.handshake.headers.referer
284-
if (!referer) {
285-
return false
286-
}
287-
var hostUrl = url.URL.parse(referer)
288-
var noteId = config.urlPath ? hostUrl.pathname.slice(config.urlPath.length + 1, hostUrl.pathname.length).split('/')[1] : hostUrl.pathname.split('/')[1]
289-
return noteId
290-
} else {
291-
return false
317+
return extractNoteIdFromReferer(referer)
292318
}
319+
320+
return false
293321
}
294322

295323
function parseNoteIdFromSocket (socket, callback) {
@@ -933,4 +961,5 @@ function connection (socket) {
933961
})
934962
}
935963

936-
module.exports = realtime
964+
exports = module.exports = realtime
965+
exports.extractNoteIdFromSocket = extractNoteIdFromSocket

test/realtime.test.js

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
'use strict'
2+
3+
/* eslint-env node, mocha */
4+
5+
const io = require('socket.io-client')
6+
const http = require('http')
7+
8+
const mock = require('mock-require')
9+
const assert = require('assert')
10+
11+
function makeMockSocket (headers, query) {
12+
return {
13+
handshake: {
14+
headers: Object.assign({}, headers),
15+
query: Object.assign({}, query)
16+
}
17+
}
18+
}
19+
20+
describe('realtime', function () {
21+
describe('extractNoteIdFromSocket', function () {
22+
beforeEach(() => {
23+
mock('../lib/logger', {})
24+
mock('../lib/history', {})
25+
mock('../lib/models', {})
26+
})
27+
28+
afterEach(() => {
29+
delete require.cache[require.resolve('../lib/realtime')]
30+
mock.stopAll()
31+
})
32+
33+
describe('urlPath not set', function () {
34+
beforeEach(() => {
35+
mock('../lib/config', {})
36+
realtime = require('../lib/realtime')
37+
})
38+
39+
let realtime
40+
41+
it('return false if socket or socket.handshake not exists', function () {
42+
let noteId = realtime.extractNoteIdFromSocket()
43+
assert.strictEqual(false, noteId)
44+
45+
noteId = realtime.extractNoteIdFromSocket({})
46+
assert.strictEqual(false, noteId)
47+
})
48+
49+
it('return false if query not set and referer not set', function () {
50+
let noteId = realtime.extractNoteIdFromSocket(makeMockSocket({
51+
otherHeader: 1
52+
}, {
53+
otherQuery: 1
54+
}))
55+
assert.strictEqual(false, noteId)
56+
})
57+
58+
it('return noteId from query', function () {
59+
// Arrange
60+
const incomingNoteId = 'myNoteId'
61+
const incomingSocket = makeMockSocket(undefined, { noteId: incomingNoteId })
62+
63+
// Act
64+
const noteId = realtime.extractNoteIdFromSocket(incomingSocket)
65+
// Assert
66+
assert.strictEqual(noteId, incomingNoteId)
67+
})
68+
69+
it('return noteId from old method (referer)', function () {
70+
// Arrange
71+
const incomingNoteId = 'myNoteId'
72+
const incomingSocket = makeMockSocket({
73+
referer: `https://localhost:3000/${incomingNoteId}`
74+
})
75+
76+
// Act
77+
const noteId = realtime.extractNoteIdFromSocket(incomingSocket)
78+
// Assert
79+
assert.strictEqual(noteId, incomingNoteId)
80+
})
81+
})
82+
83+
describe('urlPath is set', function () {
84+
let realtime
85+
it('return noteId from old method (referer) and urlPath set', function () {
86+
// Arrange
87+
const urlPath = 'hello'
88+
mock('../lib/config', {
89+
urlPath: urlPath
90+
})
91+
realtime = require('../lib/realtime')
92+
const incomingNoteId = 'myNoteId'
93+
const incomingSocket = makeMockSocket({
94+
referer: `https://localhost:3000/${urlPath}/${incomingNoteId}`
95+
})
96+
97+
// Act
98+
const noteId = realtime.extractNoteIdFromSocket(incomingSocket)
99+
// Assert
100+
assert.strictEqual(noteId, incomingNoteId)
101+
})
102+
})
103+
})
104+
})

0 commit comments

Comments
 (0)