Skip to content

Commit d32d14f

Browse files
committed
model responseText and responseXml on jqXHR objects
1 parent 26d8e33 commit d32d14f

File tree

3 files changed

+47
-1
lines changed

3 files changed

+47
-1
lines changed

javascript/ql/src/semmle/javascript/frameworks/jQuery.qll

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -291,7 +291,16 @@ private class JQueryAjaxCall extends ClientRequest::Range {
291291
.(DataFlow::FunctionNode)
292292
.getParameter(0)
293293
or
294+
result =
295+
getAResponseNodeFromAnXHRObject(getOptionArgument([0 .. 1],
296+
any(string method | method = "error" or method = "complete"))
297+
.getALocalSource()
298+
.(DataFlow::FunctionNode)
299+
.getParameter(0))
300+
or
294301
result = getAnAjaxCallbackDataNode(this)
302+
or
303+
result = getAResponseNodeFromAnXHRObject(getAnXHRObject(this))
295304
)
296305
}
297306
}
@@ -304,6 +313,25 @@ DataFlow::Node getAnAjaxCallbackDataNode(ClientRequest::Range request) {
304313
request.getAMemberCall(any(string s | s = "done" or s = "then")).getCallback(0).getParameter(0)
305314
}
306315

316+
/**
317+
* Gets the `jqXHR` object from a call to `fail` on the result from an ajax call (`request`).
318+
*/
319+
DataFlow::SourceNode getAnXHRObject(ClientRequest::Range request) {
320+
result = request.getAMemberCall("fail").getCallback(0).getParameter(0)
321+
}
322+
323+
/**
324+
* Gets a node refering to the response contained in an `jqXHR` object (`obj`).
325+
*/
326+
DataFlow::SourceNode getAResponseNodeFromAnXHRObject(DataFlow::SourceNode obj) {
327+
result =
328+
obj
329+
.getAPropertyRead(any(string s |
330+
s = "responseText" or
331+
s = "responseXML"
332+
))
333+
}
334+
307335
/**
308336
* A model of a URL request made using a `jQuery.ajax` shorthand.
309337
* E.g. `jQuery.getJSON`, `jQuery.post` etc.
@@ -360,11 +388,13 @@ private class JQueryAjaxShortHand extends ClientRequest::Range {
360388
not exists(getResponseType()) and responseType = ""
361389
) and
362390
promise = false and
363-
// one of the two last arguments
364391
(
392+
// one of the two last arguments
365393
result = getCallback([getNumArgument() - 2 .. getNumArgument() - 1]).getParameter(0)
366394
or
367395
result = getAnAjaxCallbackDataNode(this)
396+
or
397+
result = getAResponseNodeFromAnXHRObject(getAnXHRObject(this))
368398
)
369399
}
370400
}

javascript/ql/test/library-tests/frameworks/ClientRequests/ClientRequests.expected

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,8 @@ test_ClientRequest
6464
| tst.js:195:2:195:54 | $.get( ... "json") |
6565
| tst.js:197:2:197:45 | $.ajax( ... blob"}) |
6666
| tst.js:200:2:200:21 | $.get("example.php") |
67+
| tst.js:202:5:208:7 | $.ajax( ... }}) |
68+
| tst.js:210:2:210:21 | $.get("example.php") |
6769
test_getADataNode
6870
| tst.js:53:5:53:23 | axios({data: data}) | tst.js:53:18:53:21 | data |
6971
| tst.js:57:5:57:39 | axios.p ... data2}) | tst.js:57:19:57:23 | data1 |
@@ -169,6 +171,8 @@ test_getUrl
169171
| tst.js:195:2:195:54 | $.get( ... "json") | tst.js:195:9:195:24 | "ajax/test.json" |
170172
| tst.js:197:2:197:45 | $.ajax( ... blob"}) | tst.js:197:15:197:25 | "ajax/blob" |
171173
| tst.js:200:2:200:21 | $.get("example.php") | tst.js:200:8:200:20 | "example.php" |
174+
| tst.js:202:5:208:7 | $.ajax( ... }}) | tst.js:203:10:203:22 | "example.php" |
175+
| tst.js:210:2:210:21 | $.get("example.php") | tst.js:210:8:210:20 | "example.php" |
172176
test_getAResponseDataNode
173177
| tst.js:19:5:19:23 | requestPromise(url) | tst.js:19:5:19:23 | requestPromise(url) | text | true |
174178
| tst.js:21:5:21:23 | superagent.get(url) | tst.js:21:5:21:23 | superagent.get(url) | stream | true |
@@ -227,3 +231,5 @@ test_getAResponseDataNode
227231
| tst.js:195:2:195:54 | $.get( ... "json") | tst.js:195:37:195:40 | data | json | false |
228232
| tst.js:197:2:197:45 | $.ajax( ... blob"}) | tst.js:198:23:198:26 | data | blob | false |
229233
| tst.js:200:2:200:21 | $.get("example.php") | tst.js:200:37:200:44 | response | | false |
234+
| tst.js:202:5:208:7 | $.ajax( ... }}) | tst.js:207:21:207:36 | err.responseText | json | false |
235+
| tst.js:210:2:210:21 | $.get("example.php") | tst.js:210:55:210:70 | xhr.responseText | | false |

javascript/ql/test/library-tests/frameworks/ClientRequests/tst.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,4 +198,14 @@ import {ClientRequest, net} from 'electron';
198198
.done(function( data ) {});
199199

200200
$.get("example.php").done(function(response) {})
201+
202+
$.ajax({
203+
url: "example.php",
204+
type: 'POST',
205+
dataType: "json",
206+
error: function (err) {
207+
console.log(err.responseText)
208+
}});
209+
210+
$.get("example.php").fail(function(xhr) {console.log(xhr.responseText)});
201211
});

0 commit comments

Comments
 (0)