diff --git a/trunk/doc/CHANGELOG.md b/trunk/doc/CHANGELOG.md
index 2eb333f41..16599decf 100644
--- a/trunk/doc/CHANGELOG.md
+++ b/trunk/doc/CHANGELOG.md
@@ -7,6 +7,7 @@ The changelog for SRS.
## SRS 7.0 Changelog
+* v7.0, 2025-11-18, AI: API: Change pagination default count to 10, minimum 1. v7.0.128
* v7.0, 2025-11-14, AI: Fix race condition causing immediate deletion of new sources. v7.0.127 (#4449)
* v7.0, 2025-11-11, AI: WebRTC: Support optional msid attribute per RFC 8830. v7.0.126 (#4570)
* v7.0, 2025-11-11, AI: SRT: Stop TS parsing after codec detection. v7.0.125 (#4569)
diff --git a/trunk/src/app/srs_app_http_api.cpp b/trunk/src/app/srs_app_http_api.cpp
index 72f414b15..e2d7e1c5b 100644
--- a/trunk/src/app/srs_app_http_api.cpp
+++ b/trunk/src/app/srs_app_http_api.cpp
@@ -147,6 +147,18 @@ srs_error_t srs_api_response_code(ISrsHttpResponseWriter *w, ISrsHttpMessage *r,
return srs_api_response_jsonp_code(w, callback, code);
}
+void srs_api_parse_pagination(ISrsHttpMessage *r, int &start, int &count)
+{
+ std::string rstart = r->query_get("start");
+ std::string rcount = r->query_get("count");
+
+ // Parse start parameter, default to 0, minimum 0.
+ start = srs_max(0, atoi(rstart.c_str()));
+
+ // Parse count parameter, default to 10, minimum 1.
+ count = rcount.empty() ? 10 : srs_max(1, atoi(rcount.c_str()));
+}
+
// @remark we will free the code.
srs_error_t srs_api_response_code(ISrsHttpResponseWriter *w, ISrsHttpMessage *r, srs_error_t code)
{
@@ -794,10 +806,8 @@ srs_error_t SrsGoApiStreams::serve_http(ISrsHttpResponseWriter *w, ISrsHttpMessa
SrsJsonArray *data = SrsJsonAny::array();
obj->set("streams", data);
- std::string rstart = r->query_get("start");
- std::string rcount = r->query_get("count");
- int start = srs_max(0, atoi(rstart.c_str()));
- int count = srs_max(1, atoi(rcount.c_str()));
+ int start, count;
+ srs_api_parse_pagination(r, start, count);
if ((err = stat_->dumps_streams(data, start, count)) != srs_success) {
int code = srs_error_code(err);
srs_freep(err);
@@ -866,10 +876,8 @@ srs_error_t SrsGoApiClients::serve_http(ISrsHttpResponseWriter *w, ISrsHttpMessa
SrsJsonArray *data = SrsJsonAny::array();
obj->set("clients", data);
- std::string rstart = r->query_get("start");
- std::string rcount = r->query_get("count");
- int start = srs_max(0, atoi(rstart.c_str()));
- int count = srs_max(1, atoi(rcount.c_str()));
+ int start, count;
+ srs_api_parse_pagination(r, start, count);
if ((err = stat_->dumps_clients(data, start, count)) != srs_success) {
int code = srs_error_code(err);
srs_freep(err);
diff --git a/trunk/src/app/srs_app_http_api.hpp b/trunk/src/app/srs_app_http_api.hpp
index b986141fb..98bc446e9 100644
--- a/trunk/src/app/srs_app_http_api.hpp
+++ b/trunk/src/app/srs_app_http_api.hpp
@@ -35,6 +35,12 @@ extern srs_error_t srs_api_response(ISrsHttpResponseWriter *w, ISrsHttpMessage *
extern srs_error_t srs_api_response_code(ISrsHttpResponseWriter *w, ISrsHttpMessage *r, int code);
extern srs_error_t srs_api_response_code(ISrsHttpResponseWriter *w, ISrsHttpMessage *r, srs_error_t code);
+// Parse pagination parameters from HTTP request query string.
+// @param r The HTTP request message.
+// @param start Output parameter for start index, defaults to 0, minimum 0.
+// @param count Output parameter for count, defaults to 10, minimum 1.
+extern void srs_api_parse_pagination(ISrsHttpMessage *r, int &start, int &count);
+
// For http root.
class SrsGoApiRoot : public ISrsHttpHandler
{
diff --git a/trunk/src/core/srs_core_version7.hpp b/trunk/src/core/srs_core_version7.hpp
index 65afefc46..0940d73d3 100644
--- a/trunk/src/core/srs_core_version7.hpp
+++ b/trunk/src/core/srs_core_version7.hpp
@@ -9,6 +9,6 @@
#define VERSION_MAJOR 7
#define VERSION_MINOR 0
-#define VERSION_REVISION 127
+#define VERSION_REVISION 128
#endif
\ No newline at end of file
diff --git a/trunk/src/utest/srs_utest_ai24.cpp b/trunk/src/utest/srs_utest_ai24.cpp
index 6f03e2614..7d6736f92 100644
--- a/trunk/src/utest/srs_utest_ai24.cpp
+++ b/trunk/src/utest/srs_utest_ai24.cpp
@@ -8,6 +8,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -21,6 +22,7 @@
#include
#include
#include
+#include
#ifdef SRS_FFMPEG_FIT
#include
@@ -1311,3 +1313,106 @@ VOID TEST(SdpTest, ParseLibdatachannelSdpFromIssue4570)
}
EXPECT_TRUE(found_audio_ssrc);
}
+
+// Test: srs_api_parse_pagination with various input scenarios
+VOID TEST(HttpApiPaginationTest, ParsePagination)
+{
+ int start, count;
+
+ // Test 1: Default values (no query parameters)
+ if (true) {
+ MockHttpMessageForApiResponse mock_msg;
+ srs_api_parse_pagination(&mock_msg, start, count);
+ EXPECT_EQ(0, start);
+ EXPECT_EQ(10, count);
+ }
+
+ // Test 2: Valid start and count
+ if (true) {
+ MockHttpMessageForApiResponse mock_msg;
+ mock_msg.query_params_["start"] = "5";
+ mock_msg.query_params_["count"] = "20";
+ srs_api_parse_pagination(&mock_msg, start, count);
+ EXPECT_EQ(5, start);
+ EXPECT_EQ(20, count);
+ }
+
+ // Test 3: Zero count (should use minimum 1)
+ if (true) {
+ MockHttpMessageForApiResponse mock_msg;
+ mock_msg.query_params_["start"] = "0";
+ mock_msg.query_params_["count"] = "0";
+ srs_api_parse_pagination(&mock_msg, start, count);
+ EXPECT_EQ(0, start);
+ EXPECT_EQ(1, count);
+ }
+
+ // Test 4: Negative start (should use minimum 0)
+ if (true) {
+ MockHttpMessageForApiResponse mock_msg;
+ mock_msg.query_params_["start"] = "-10";
+ mock_msg.query_params_["count"] = "5";
+ srs_api_parse_pagination(&mock_msg, start, count);
+ EXPECT_EQ(0, start);
+ EXPECT_EQ(5, count);
+ }
+
+ // Test 5: Negative count (should use minimum 1)
+ if (true) {
+ MockHttpMessageForApiResponse mock_msg;
+ mock_msg.query_params_["start"] = "10";
+ mock_msg.query_params_["count"] = "-5";
+ srs_api_parse_pagination(&mock_msg, start, count);
+ EXPECT_EQ(10, start);
+ EXPECT_EQ(1, count);
+ }
+
+ // Test 6: Empty count string (should use default 10)
+ if (true) {
+ MockHttpMessageForApiResponse mock_msg;
+ mock_msg.query_params_["start"] = "5";
+ mock_msg.query_params_["count"] = "";
+ srs_api_parse_pagination(&mock_msg, start, count);
+ EXPECT_EQ(5, start);
+ EXPECT_EQ(10, count);
+ }
+
+ // Test 7: Only start parameter
+ if (true) {
+ MockHttpMessageForApiResponse mock_msg;
+ mock_msg.query_params_["start"] = "15";
+ srs_api_parse_pagination(&mock_msg, start, count);
+ EXPECT_EQ(15, start);
+ EXPECT_EQ(10, count);
+ }
+
+ // Test 8: Only count parameter
+ if (true) {
+ MockHttpMessageForApiResponse mock_msg;
+ mock_msg.query_params_["count"] = "25";
+ srs_api_parse_pagination(&mock_msg, start, count);
+ EXPECT_EQ(0, start);
+ EXPECT_EQ(25, count);
+ }
+
+ // Test 9: Invalid (non-numeric) values
+ if (true) {
+ MockHttpMessageForApiResponse mock_msg;
+ mock_msg.query_params_["start"] = "abc";
+ mock_msg.query_params_["count"] = "xyz";
+ srs_api_parse_pagination(&mock_msg, start, count);
+ // atoi returns 0 for invalid strings
+ EXPECT_EQ(0, start);
+ EXPECT_EQ(1, count); // minimum enforced since atoi returns 0
+ }
+
+ // Test 10: Large values
+ if (true) {
+ MockHttpMessageForApiResponse mock_msg;
+ mock_msg.query_params_["start"] = "1000000";
+ mock_msg.query_params_["count"] = "500";
+ srs_api_parse_pagination(&mock_msg, start, count);
+ EXPECT_EQ(1000000, start);
+ EXPECT_EQ(500, count);
+ }
+}