1
1
/**
2
- * Provides classes for working with [WebSocket](https://developer.mozilla.org/en-US/docs/Web/API/WebSocket) and [ws](https://github.com/websockets/ws).
2
+ * Provides classes for working with [WebSocket](https://developer.mozilla.org/en-US/docs/Web/API/WebSocket), [ws](https://github.com/websockets/ws), and [SockJS](http://sockjs.org ).
3
3
*
4
4
* The model is based on the EventEmitter model, and there is therefore a
5
5
* data-flow step from where a WebSocket event is sent to where the message
@@ -18,26 +18,58 @@ import javascript
18
18
*/
19
19
private string channelName ( ) { result = "message" }
20
20
21
+ /**
22
+ * The names of the libraries modelled in this file.
23
+ */
24
+ private module LibraryNames {
25
+ string sockjs ( ) { result = "SockJS" }
26
+
27
+ string websocket ( ) { result = "WebSocket" }
28
+
29
+ string ws ( ) { result = "ws" }
30
+ }
31
+
32
+ /**
33
+ * Holds if the websocket library named `client` can send a message to the library named `server`.
34
+ * Both `client` and `server` are library names defined in `LibraryNames`.
35
+ */
36
+ private predicate areLibrariesCompatible ( string client , string server ) {
37
+ // sockjs is a WebSocket emulating library, but not actually an implementation of WebSockets.
38
+ client = LibraryNames:: sockjs ( ) and server = LibraryNames:: sockjs ( )
39
+ or
40
+ server = LibraryNames:: ws ( ) and
41
+ ( client = LibraryNames:: ws ( ) or client = LibraryNames:: websocket ( ) )
42
+ }
43
+
21
44
/**
22
45
* Provides classes that model WebSockets clients.
23
46
*/
24
47
module ClientWebSocket {
48
+ private import LibraryNames
49
+
25
50
/**
26
51
* A class that can be used to instantiate a WebSocket instance.
27
52
*/
28
53
class SocketClass extends DataFlow:: SourceNode {
29
- boolean isNode ;
54
+ string library ; // the name of the WebSocket library. Can be one of the libraries defined in `LibraryNames`.
30
55
31
56
SocketClass ( ) {
32
- this = DataFlow:: globalVarRef ( "WebSocket" ) and isNode = false
57
+ this = DataFlow:: globalVarRef ( "WebSocket" ) and library = websocket ( )
58
+ or
59
+ this = DataFlow:: moduleImport ( "ws" ) and library = ws ( )
33
60
or
34
- this = DataFlow:: moduleImport ( "ws" ) and isNode = true
61
+ // the sockjs-client library:https://www.npmjs.com/package/sockjs-client
62
+ library = sockjs ( ) and
63
+ (
64
+ this = DataFlow:: moduleImport ( "sockjs-client" ) or
65
+ this = DataFlow:: globalVarRef ( "SockJS" )
66
+ )
35
67
}
36
68
37
69
/**
38
- * Holds if this class is an import of the "ws" module .
70
+ * Gets the WebSocket library name .
39
71
*/
40
- predicate isNode ( ) { isNode = true }
72
+ string getLibrary ( ) { result = library }
41
73
}
42
74
43
75
/**
@@ -49,11 +81,9 @@ module ClientWebSocket {
49
81
ClientSocket ( ) { this = socketClass .getAnInstantiation ( ) }
50
82
51
83
/**
52
- * Holds if this ClientSocket is created from the "ws" module.
53
- *
54
- * The predicate is used to differentiate where the behavior of the "ws" module differs from the native WebSocket in browsers.
84
+ * Gets the WebSocket library name.
55
85
*/
56
- predicate isNode ( ) { socketClass .isNode ( ) }
86
+ string getLibrary ( ) { result = socketClass .getLibrary ( ) }
57
87
}
58
88
59
89
/**
@@ -68,7 +98,10 @@ module ClientWebSocket {
68
98
69
99
override DataFlow:: Node getSentItem ( int i ) { i = 0 and result = this .getArgument ( 0 ) }
70
100
71
- override ServerWebSocket:: ReceiveNode getAReceiver ( ) { any ( ) }
101
+ override ServerWebSocket:: ReceiveNode getAReceiver ( ) {
102
+ areLibrariesCompatible ( emitter .getLibrary ( ) ,
103
+ result .getEmitter ( ) .( ServerWebSocket:: ServerSocket ) .getLibrary ( ) )
104
+ }
72
105
}
73
106
74
107
/**
@@ -116,7 +149,7 @@ module ClientWebSocket {
116
149
*/
117
150
private class WSReceiveNode extends ClientWebSocket:: ReceiveNode {
118
151
WSReceiveNode ( ) {
119
- emitter .isNode ( ) and
152
+ emitter .getLibrary ( ) = ws ( ) and
120
153
this = getAMessageHandler ( emitter , EventEmitter:: on ( ) )
121
154
}
122
155
@@ -128,21 +161,38 @@ module ClientWebSocket {
128
161
* Provides classes that model WebSocket servers.
129
162
*/
130
163
module ServerWebSocket {
164
+ private import LibraryNames
165
+
166
+ /**
167
+ * Gets a server created by a library named `library`.
168
+ */
169
+ DataFlow:: SourceNode getAServer ( string library ) {
170
+ library = ws ( ) and
171
+ result = DataFlow:: moduleImport ( "ws" ) .getAConstructorInvocation ( "Server" )
172
+ or
173
+ library = sockjs ( ) and
174
+ result = DataFlow:: moduleImport ( "sockjs" ) .getAMemberCall ( "createServer" )
175
+ }
176
+
131
177
/**
132
178
* A server WebSocket instance.
133
179
*/
134
180
class ServerSocket extends EventEmitter:: Range , DataFlow:: SourceNode {
181
+ string library ;
182
+
135
183
ServerSocket ( ) {
136
184
exists ( DataFlow:: CallNode onCall |
137
- onCall =
138
- DataFlow:: moduleImport ( "ws" )
139
- .getAConstructorInvocation ( "Server" )
140
- .getAMemberCall ( EventEmitter:: on ( ) ) and
185
+ onCall = getAServer ( library ) .getAMemberCall ( EventEmitter:: on ( ) ) and
141
186
onCall .getArgument ( 0 ) .mayHaveStringValue ( "connection" )
142
187
|
143
188
this = onCall .getCallback ( 1 ) .getParameter ( 0 )
144
189
)
145
190
}
191
+
192
+ /**
193
+ * Gets the name of the library that created this server socket.
194
+ */
195
+ string getLibrary ( ) { result = library }
146
196
}
147
197
148
198
/**
@@ -151,7 +201,13 @@ module ServerWebSocket {
151
201
class SendNode extends EventDispatch:: Range , DataFlow:: CallNode {
152
202
override ServerSocket emitter ;
153
203
154
- SendNode ( ) { this = emitter .getAMemberCall ( "send" ) }
204
+ SendNode ( ) {
205
+ emitter .getLibrary ( ) = ws ( ) and
206
+ this = emitter .getAMemberCall ( "send" )
207
+ or
208
+ emitter .getLibrary ( ) = sockjs ( ) and
209
+ this = emitter .getAMemberCall ( "write" )
210
+ }
155
211
156
212
override string getChannel ( ) { result = channelName ( ) }
157
213
@@ -160,7 +216,10 @@ module ServerWebSocket {
160
216
result = getArgument ( 0 )
161
217
}
162
218
163
- override ClientWebSocket:: ReceiveNode getAReceiver ( ) { any ( ) }
219
+ override ClientWebSocket:: ReceiveNode getAReceiver ( ) {
220
+ areLibrariesCompatible ( result .getEmitter ( ) .( ClientWebSocket:: ClientSocket ) .getLibrary ( ) ,
221
+ emitter .getLibrary ( ) )
222
+ }
164
223
}
165
224
166
225
/**
@@ -170,8 +229,14 @@ module ServerWebSocket {
170
229
override ServerSocket emitter ;
171
230
172
231
ReceiveNode ( ) {
173
- this = emitter .getAMemberCall ( EventEmitter:: on ( ) ) and
174
- this .getArgument ( 0 ) .mayHaveStringValue ( "message" )
232
+ exists ( string eventName |
233
+ emitter .getLibrary ( ) = ws ( ) and eventName = "message"
234
+ or
235
+ emitter .getLibrary ( ) = sockjs ( ) and eventName = "data"
236
+ |
237
+ this = emitter .getAMemberCall ( EventEmitter:: on ( ) ) and
238
+ this .getArgument ( 0 ) .mayHaveStringValue ( eventName )
239
+ )
175
240
}
176
241
177
242
override string getChannel ( ) { result = channelName ( ) }
0 commit comments