Skip to content

Commit 5de79b4

Browse files
committed
Python: Add HTTP::Client::Request concept
Taken from Ruby, except that `getURL` member predicate was changed to `getUrl` to keep consistency with the rest of our concepts, and stick to our naming convention.
1 parent a636021 commit 5de79b4

File tree

2 files changed

+88
-0
lines changed

2 files changed

+88
-0
lines changed

python/ql/lib/semmle/python/Concepts.qll

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -812,6 +812,77 @@ module HTTP {
812812
}
813813
}
814814
}
815+
816+
/** Provides classes for modeling HTTP clients. */
817+
module Client {
818+
/**
819+
* A method call that makes an outgoing HTTP request.
820+
*
821+
* Extend this class to refine existing API models. If you want to model new APIs,
822+
* extend `Request::Range` instead.
823+
*/
824+
class Request extends DataFlow::Node instanceof Request::Range {
825+
/** Gets a node which returns the body of the response */
826+
DataFlow::Node getResponseBody() { result = super.getResponseBody() }
827+
828+
/**
829+
* Gets a node that contributes to the URL of the request.
830+
* Depending on the framework, a request may have multiple nodes which contribute to the URL.
831+
*/
832+
DataFlow::Node getUrl() { result = super.getUrl() }
833+
834+
/** Gets a string that identifies the framework used for this request. */
835+
string getFramework() { result = super.getFramework() }
836+
837+
/**
838+
* Holds if this request is made using a mode that disables SSL/TLS
839+
* certificate validation, where `disablingNode` represents the point at
840+
* which the validation was disabled.
841+
*/
842+
predicate disablesCertificateValidation(DataFlow::Node disablingNode) {
843+
super.disablesCertificateValidation(disablingNode)
844+
}
845+
}
846+
847+
/** Provides a class for modeling new HTTP requests. */
848+
module Request {
849+
/**
850+
* A method call that makes an outgoing HTTP request.
851+
*
852+
* Extend this class to model new APIs. If you want to refine existing API models,
853+
* extend `Request` instead.
854+
*/
855+
abstract class Range extends DataFlow::Node {
856+
/** Gets a node which returns the body of the response */
857+
abstract DataFlow::Node getResponseBody();
858+
859+
/**
860+
* Gets a node that contributes to the URL of the request.
861+
* Depending on the framework, a request may have multiple nodes which contribute to the URL.
862+
*/
863+
abstract DataFlow::Node getUrl();
864+
865+
/** Gets a string that identifies the framework used for this request. */
866+
abstract string getFramework();
867+
868+
/**
869+
* Holds if this request is made using a mode that disables SSL/TLS
870+
* certificate validation, where `disablingNode` represents the point at
871+
* which the validation was disabled.
872+
*/
873+
abstract predicate disablesCertificateValidation(DataFlow::Node disablingNode);
874+
}
875+
}
876+
877+
/** The response body from an outgoing HTTP request, considered as a remote flow source */
878+
private class RequestResponseBody extends RemoteFlowSource::Range, DataFlow::Node {
879+
Request request;
880+
881+
RequestResponseBody() { this = request.getResponseBody() }
882+
883+
override string getSourceType() { result = request.getFramework() }
884+
}
885+
}
815886
}
816887

817888
/**

python/ql/test/experimental/meta/ConceptsTest.qll

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -475,3 +475,20 @@ class CryptographicOperationTest extends InlineExpectationsTest {
475475
)
476476
}
477477
}
478+
479+
class HttpClientRequestTest extends InlineExpectationsTest {
480+
HttpClientRequestTest() { this = "HttpClientRequestTest" }
481+
482+
override string getARelevantTag() { result = "clientRequestUrl" }
483+
484+
override predicate hasActualResult(Location location, string element, string tag, string value) {
485+
exists(location.getFile().getRelativePath()) and
486+
exists(HTTP::Client::Request req, DataFlow::Node url |
487+
url = req.getUrl() and
488+
location = url.getLocation() and
489+
element = url.toString() and
490+
value = prettyNodeForInlineTest(url) and
491+
tag = "clientRequestUrl"
492+
)
493+
}
494+
}

0 commit comments

Comments
 (0)