test-lib-http2.cc 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616
  1. #include "gtest/gtest.h"
  2. #include <cstring>
  3. #include <fcntl.h>
  4. #include <iostream>
  5. #include <poll.h>
  6. #include <set>
  7. #include <string>
  8. #include <sys/socket.h>
  9. #include <thread>
  10. #include <unistd.h>
  11. #include <vector>
  12. #include "smartdns/http2.h"
  13. class LIBHTTP2 : public ::testing::Test
  14. {
  15. protected:
  16. void SetUp() override
  17. {
  18. // Create socketpair for communication
  19. if (socketpair(AF_UNIX, SOCK_STREAM, 0, socks) < 0) {
  20. perror("socketpair");
  21. FAIL() << "Failed to create socketpair";
  22. }
  23. client_sock = socks[0];
  24. server_sock = socks[1];
  25. // Set non-blocking
  26. fcntl(client_sock, F_SETFL, O_NONBLOCK);
  27. fcntl(server_sock, F_SETFL, O_NONBLOCK);
  28. }
  29. void TearDown() override
  30. {
  31. if (client_sock != -1)
  32. close(client_sock);
  33. if (server_sock != -1)
  34. close(server_sock);
  35. }
  36. int socks[2];
  37. int client_sock = -1;
  38. int server_sock = -1;
  39. // BIO callbacks
  40. static int bio_read(void *private_data, uint8_t *buf, int len)
  41. {
  42. int fd = *(int *)private_data;
  43. int ret = read(fd, buf, len);
  44. if (ret < 0 && (errno == EAGAIN || errno == EWOULDBLOCK)) {
  45. errno = EAGAIN;
  46. return -1;
  47. }
  48. return ret;
  49. }
  50. static int bio_write(void *private_data, const uint8_t *buf, int len)
  51. {
  52. int fd = *(int *)private_data;
  53. int ret = write(fd, buf, len);
  54. if (ret < 0 && (errno == EAGAIN || errno == EWOULDBLOCK)) {
  55. errno = EAGAIN;
  56. return -1;
  57. }
  58. return ret;
  59. }
  60. };
  61. TEST_F(LIBHTTP2, Integrated)
  62. {
  63. std::thread server_thread([this]() {
  64. // Server logic
  65. struct http2_ctx *ctx = http2_ctx_server_new("test-server", bio_read, bio_write, &server_sock, NULL);
  66. ASSERT_NE(ctx, nullptr);
  67. // Handshake
  68. int handshake_attempts = 200;
  69. int ret = 0;
  70. while (handshake_attempts-- > 0) {
  71. struct pollfd pfd = {server_sock, POLLIN, 0};
  72. int poll_ret = poll(&pfd, 1, 10);
  73. if (poll_ret == 0) {
  74. continue;
  75. }
  76. ret = http2_ctx_handshake(ctx);
  77. if (ret == 1)
  78. break;
  79. if (ret < 0)
  80. break;
  81. }
  82. ASSERT_EQ(ret, 1) << "Server handshake failed";
  83. // Accept stream
  84. struct http2_stream *stream = nullptr;
  85. int max_attempts = 200;
  86. while (max_attempts-- > 0 && !stream) {
  87. struct pollfd pfd = {server_sock, POLLIN, 0};
  88. poll(&pfd, 1, 100);
  89. struct http2_poll_item items[10];
  90. int count = 0;
  91. http2_ctx_poll(ctx, items, 10, &count);
  92. for (int i = 0; i < count; i++) {
  93. if (items[i].stream == nullptr && items[i].readable) {
  94. stream = http2_ctx_accept_stream(ctx);
  95. if (stream)
  96. break;
  97. }
  98. }
  99. usleep(20000);
  100. }
  101. if (!stream) {
  102. std::cout << "Server failed to accept stream after timeout" << std::endl;
  103. }
  104. ASSERT_NE(stream, nullptr) << "Server failed to accept stream";
  105. // Read request body
  106. uint8_t request_body[4096];
  107. int request_body_len = 0;
  108. while (!http2_stream_is_end(stream) && request_body_len < (int)sizeof(request_body)) {
  109. int read_len = http2_stream_read_body(stream, request_body + request_body_len,
  110. sizeof(request_body) - request_body_len);
  111. if (read_len > 0) {
  112. request_body_len += read_len;
  113. } else {
  114. usleep(10000);
  115. }
  116. }
  117. // Send response
  118. char response[8192];
  119. int response_len = snprintf(response, sizeof(response), "Echo Response: %.*s", request_body_len, request_body);
  120. char content_length[32];
  121. snprintf(content_length, sizeof(content_length), "%d", response_len);
  122. struct http2_header_pair headers[] = {{"content-type", "text/plain"}, {"content-length", content_length}};
  123. http2_stream_set_response(stream, 200, headers, 2);
  124. http2_stream_write_body(stream, (const uint8_t *)response, response_len, 1);
  125. usleep(100000);
  126. http2_ctx_free(ctx);
  127. });
  128. std::thread client_thread([this]() {
  129. usleep(500000); // Wait for server start
  130. struct http2_ctx *ctx = http2_ctx_client_new("test-client", bio_read, bio_write, &client_sock, NULL);
  131. ASSERT_NE(ctx, nullptr);
  132. // Handshake
  133. int handshake_attempts = 200;
  134. int ret = 0;
  135. while (handshake_attempts-- > 0) {
  136. struct pollfd pfd = {client_sock, POLLIN, 0};
  137. poll(&pfd, 1, 10);
  138. ret = http2_ctx_handshake(ctx);
  139. if (ret == 1)
  140. break;
  141. if (ret < 0)
  142. break;
  143. }
  144. ASSERT_EQ(ret, 1) << "Client handshake failed";
  145. // Create stream
  146. struct http2_stream *stream = http2_stream_new(ctx);
  147. ASSERT_NE(stream, nullptr);
  148. // Send request
  149. struct http2_header_pair headers[] = {
  150. {"content-type", "application/json"}, {"content-length", "27"}, {NULL, NULL}};
  151. http2_stream_set_request(stream, "POST", "/echo", headers);
  152. const char *request_body = "{\"message\":\"Hello Echo!\"}";
  153. http2_stream_write_body(stream, (const uint8_t *)request_body, strlen(request_body), 1);
  154. // Wait for response
  155. int max_attempts = 200;
  156. while (max_attempts-- > 0) {
  157. struct pollfd pfd = {client_sock, POLLIN, 0};
  158. poll(&pfd, 1, 100);
  159. struct http2_poll_item items[10];
  160. int count = 0;
  161. http2_ctx_poll(ctx, items, 10, &count);
  162. if (http2_stream_get_status(stream) > 0)
  163. break;
  164. usleep(20000);
  165. }
  166. EXPECT_EQ(http2_stream_get_status(stream), 200);
  167. // Read response
  168. uint8_t response_body[4096];
  169. int response_body_len = 0;
  170. while (!http2_stream_is_end(stream) && response_body_len < (int)sizeof(response_body)) {
  171. int read_len = http2_stream_read_body(stream, response_body + response_body_len,
  172. sizeof(response_body) - response_body_len);
  173. if (read_len > 0) {
  174. response_body_len += read_len;
  175. } else {
  176. usleep(10000);
  177. }
  178. }
  179. std::string resp((char *)response_body, response_body_len);
  180. EXPECT_NE(resp.find("Echo Response"), std::string::npos);
  181. http2_stream_put(stream);
  182. http2_ctx_free(ctx);
  183. });
  184. server_thread.join();
  185. client_thread.join();
  186. }
  187. TEST_F(LIBHTTP2, MultiStream)
  188. {
  189. const int NUM_STREAMS = 3;
  190. std::thread server_thread([this, NUM_STREAMS]() {
  191. struct http2_ctx *ctx = http2_ctx_server_new("test-server", bio_read, bio_write, &server_sock, NULL);
  192. ASSERT_NE(ctx, nullptr);
  193. // Handshake
  194. int handshake_attempts = 200;
  195. int ret = 0;
  196. while (handshake_attempts-- > 0) {
  197. struct pollfd pfd = {server_sock, POLLIN, 0};
  198. poll(&pfd, 1, 10);
  199. ret = http2_ctx_handshake(ctx);
  200. if (ret == 1)
  201. break;
  202. if (ret < 0)
  203. break;
  204. }
  205. ASSERT_EQ(ret, 1) << "Server handshake failed";
  206. int streams_completed = 0;
  207. int max_iterations = 500;
  208. while (streams_completed < NUM_STREAMS && max_iterations-- > 0) {
  209. struct pollfd pfd = {server_sock, POLLIN, 0};
  210. poll(&pfd, 1, 100);
  211. struct http2_poll_item items[10];
  212. int count = 0;
  213. http2_ctx_poll(ctx, items, 10, &count);
  214. for (int i = 0; i < count; i++) {
  215. if (items[i].stream == nullptr && items[i].readable) {
  216. http2_ctx_accept_stream(ctx);
  217. } else if (items[i].stream && items[i].readable) {
  218. struct http2_stream *stream = items[i].stream;
  219. uint8_t buf[1024];
  220. http2_stream_read_body(stream, buf, sizeof(buf));
  221. if (http2_stream_is_end(stream)) {
  222. char response[256];
  223. int response_len =
  224. snprintf(response, sizeof(response), "Echo from stream %d", http2_stream_get_id(stream));
  225. char content_length[32];
  226. snprintf(content_length, sizeof(content_length), "%d", response_len);
  227. struct http2_header_pair headers[] = {{"content-type", "text/plain"},
  228. {"content-length", content_length}};
  229. http2_stream_set_response(stream, 200, headers, 2);
  230. http2_stream_write_body(stream, (const uint8_t *)response, response_len, 1);
  231. streams_completed++;
  232. }
  233. }
  234. }
  235. usleep(2000);
  236. }
  237. usleep(100000);
  238. http2_ctx_free(ctx);
  239. });
  240. std::thread client_thread([this, NUM_STREAMS]() {
  241. usleep(50000);
  242. struct http2_ctx *ctx = http2_ctx_client_new("test-client", bio_read, bio_write, &client_sock, NULL);
  243. ASSERT_NE(ctx, nullptr);
  244. // Handshake
  245. int handshake_attempts = 200;
  246. int ret = 0;
  247. while (handshake_attempts-- > 0) {
  248. struct pollfd pfd = {client_sock, POLLIN, 0};
  249. poll(&pfd, 1, 10);
  250. ret = http2_ctx_handshake(ctx);
  251. if (ret == 1)
  252. break;
  253. if (ret < 0)
  254. break;
  255. }
  256. ASSERT_EQ(ret, 1) << "Client handshake failed";
  257. struct http2_stream *streams[NUM_STREAMS];
  258. for (int i = 0; i < NUM_STREAMS; i++) {
  259. streams[i] = http2_stream_new(ctx);
  260. ASSERT_NE(streams[i], nullptr);
  261. char path[64];
  262. snprintf(path, sizeof(path), "/stream%d", i);
  263. char body[128];
  264. int body_len = snprintf(body, sizeof(body), "Request from stream %d", i);
  265. char content_length[32];
  266. snprintf(content_length, sizeof(content_length), "%d", body_len);
  267. struct http2_header_pair headers[] = {
  268. {"content-type", "text/plain"}, {"content-length", content_length}, {NULL, NULL}};
  269. http2_stream_set_request(streams[i], "POST", path, headers);
  270. http2_stream_write_body(streams[i], (const uint8_t *)body, body_len, 1);
  271. }
  272. int streams_completed = 0;
  273. int max_iterations = 500;
  274. std::set<int> completed_stream_ids;
  275. while (streams_completed < NUM_STREAMS && max_iterations-- > 0) {
  276. struct pollfd pfd = {client_sock, POLLIN, 0};
  277. poll(&pfd, 1, 100);
  278. struct http2_poll_item items[10];
  279. int count = 0;
  280. http2_ctx_poll(ctx, items, 10, &count);
  281. for (int i = 0; i < count; i++) {
  282. if (items[i].stream && items[i].readable) {
  283. struct http2_stream *stream = items[i].stream;
  284. uint8_t buf[1024];
  285. http2_stream_read_body(stream, buf, sizeof(buf));
  286. if (http2_stream_is_end(stream)) {
  287. int stream_id = http2_stream_get_id(stream);
  288. if (completed_stream_ids.find(stream_id) == completed_stream_ids.end()) {
  289. completed_stream_ids.insert(stream_id);
  290. streams_completed++;
  291. }
  292. }
  293. }
  294. }
  295. usleep(2000);
  296. }
  297. EXPECT_EQ(streams_completed, NUM_STREAMS);
  298. for (int i = 0; i < NUM_STREAMS; i++) {
  299. http2_stream_put(streams[i]);
  300. }
  301. http2_ctx_free(ctx);
  302. });
  303. server_thread.join();
  304. client_thread.join();
  305. }
  306. TEST_F(LIBHTTP2, EarlyStreamCreation)
  307. {
  308. std::thread server_thread([this]() {
  309. // Server logic
  310. struct http2_ctx *ctx = http2_ctx_server_new("test-server", bio_read, bio_write, &server_sock, NULL);
  311. ASSERT_NE(ctx, nullptr);
  312. // Handshake
  313. int handshake_attempts = 200;
  314. int ret = 0;
  315. while (handshake_attempts-- > 0) {
  316. struct pollfd pfd = {server_sock, POLLIN, 0};
  317. int poll_ret = poll(&pfd, 1, 10);
  318. if (poll_ret == 0) {
  319. continue;
  320. }
  321. ret = http2_ctx_handshake(ctx);
  322. if (ret == 1)
  323. break;
  324. if (ret < 0)
  325. break;
  326. }
  327. ASSERT_EQ(ret, 1) << "Server handshake failed";
  328. // Accept stream
  329. struct http2_stream *stream = nullptr;
  330. int max_attempts = 200;
  331. while (max_attempts-- > 0 && !stream) {
  332. struct pollfd pfd = {server_sock, POLLIN, 0};
  333. poll(&pfd, 1, 100);
  334. struct http2_poll_item items[10];
  335. int count = 0;
  336. http2_ctx_poll(ctx, items, 10, &count);
  337. for (int i = 0; i < count; i++) {
  338. if (items[i].stream == nullptr && items[i].readable) {
  339. stream = http2_ctx_accept_stream(ctx);
  340. if (stream)
  341. break;
  342. }
  343. }
  344. usleep(20000);
  345. }
  346. ASSERT_NE(stream, nullptr) << "Server failed to accept stream";
  347. // Verify we received the request
  348. const char *method = http2_stream_get_method(stream);
  349. const char *path = http2_stream_get_path(stream);
  350. EXPECT_STREQ(method, "POST");
  351. EXPECT_STREQ(path, "/early-test");
  352. // Read request body (should be empty for GET)
  353. uint8_t request_body[4096];
  354. int request_body_len = 0;
  355. while (!http2_stream_is_end(stream) && request_body_len < (int)sizeof(request_body)) {
  356. int read_len = http2_stream_read_body(stream, request_body + request_body_len,
  357. sizeof(request_body) - request_body_len);
  358. if (read_len > 0) {
  359. request_body_len += read_len;
  360. } else {
  361. usleep(10000);
  362. }
  363. }
  364. // Send response
  365. char response[8192];
  366. int response_len = snprintf(response, sizeof(response), "Echo Response: %.*s", request_body_len, request_body);
  367. char content_length[32];
  368. snprintf(content_length, sizeof(content_length), "%d", response_len);
  369. struct http2_header_pair headers[] = {
  370. {"content-type", "text/plain"}, {"content-length", content_length}, {NULL, NULL}};
  371. http2_stream_set_response(stream, 200, headers, 2);
  372. http2_stream_write_body(stream, (const uint8_t *)response, response_len, 1);
  373. usleep(100000);
  374. http2_ctx_free(ctx);
  375. });
  376. std::thread client_thread([this]() {
  377. usleep(50000); // Wait for server start
  378. // Create client context
  379. struct http2_ctx *ctx = http2_ctx_client_new("test-client", bio_read, bio_write, &client_sock, NULL);
  380. ASSERT_NE(ctx, nullptr);
  381. // IMPORTANT: Create stream and send request BEFORE handshake completes
  382. // This tests that the HEADERS frame is buffered and sent after handshake
  383. struct http2_stream *stream = http2_stream_new(ctx);
  384. ASSERT_NE(stream, nullptr);
  385. // Send request immediately (before handshake)
  386. struct http2_header_pair headers[] = {{"user-agent", "test-client"}, {NULL, NULL}};
  387. int ret = http2_stream_set_request(stream, "POST", "/early-test", headers);
  388. EXPECT_EQ(ret, 0) << "Failed to set request";
  389. const char *request_body = "test echo";
  390. http2_stream_write_body(stream, (const uint8_t *)request_body, strlen(request_body), 1);
  391. // Now complete handshake
  392. int handshake_attempts = 200;
  393. ret = 0;
  394. while (handshake_attempts-- > 0) {
  395. struct pollfd pfd = {client_sock, POLLIN, 0};
  396. poll(&pfd, 1, 10);
  397. ret = http2_ctx_handshake(ctx);
  398. if (ret == 1)
  399. break;
  400. if (ret < 0)
  401. break;
  402. }
  403. ASSERT_EQ(ret, 1) << "Client handshake failed";
  404. // Wait for response
  405. int max_attempts = 200;
  406. while (max_attempts-- > 0) {
  407. struct pollfd pfd = {client_sock, POLLIN, 0};
  408. poll(&pfd, 1, 100);
  409. struct http2_poll_item items[10];
  410. int count = 0;
  411. http2_ctx_poll(ctx, items, 10, &count);
  412. if (http2_stream_get_status(stream) > 0)
  413. break;
  414. usleep(20000);
  415. }
  416. EXPECT_EQ(http2_stream_get_status(stream), 200);
  417. // Read response
  418. uint8_t response_body[4096];
  419. int response_body_len = 0;
  420. while (!http2_stream_is_end(stream) && response_body_len < (int)sizeof(response_body)) {
  421. int read_len = http2_stream_read_body(stream, response_body + response_body_len,
  422. sizeof(response_body) - response_body_len);
  423. if (read_len > 0) {
  424. response_body_len += read_len;
  425. } else {
  426. usleep(10000);
  427. }
  428. }
  429. std::string resp((char *)response_body, response_body_len);
  430. EXPECT_NE(resp.find("Echo Response"), std::string::npos);
  431. EXPECT_NE(resp.find("test echo"), std::string::npos);
  432. http2_stream_put(stream);
  433. http2_ctx_free(ctx);
  434. });
  435. server_thread.join();
  436. client_thread.join();
  437. }
  438. TEST_F(LIBHTTP2, ServerLoopTerminationOnDisconnect)
  439. {
  440. std::thread server_thread([this]() {
  441. struct http2_ctx *ctx = http2_ctx_server_new("test-server", bio_read, bio_write, &server_sock, NULL);
  442. ASSERT_NE(ctx, nullptr);
  443. // Handshake
  444. int handshake_attempts = 200;
  445. int ret = 0;
  446. while (handshake_attempts-- > 0) {
  447. struct pollfd pfd = {server_sock, POLLIN, 0};
  448. int poll_ret = poll(&pfd, 1, 10);
  449. if (poll_ret == 0) {
  450. continue;
  451. }
  452. ret = http2_ctx_handshake(ctx);
  453. if (ret == 1)
  454. break;
  455. if (ret < 0)
  456. break;
  457. }
  458. ASSERT_EQ(ret, 1) << "Server handshake failed";
  459. // Accept stream
  460. struct http2_stream *stream = nullptr;
  461. int max_attempts = 200;
  462. while (max_attempts-- > 0 && !stream) {
  463. struct pollfd pfd = {server_sock, POLLIN, 0};
  464. poll(&pfd, 1, 100);
  465. struct http2_poll_item items[10];
  466. int count = 0;
  467. http2_ctx_poll(ctx, items, 10, &count);
  468. for (int i = 0; i < count; i++) {
  469. if (items[i].stream == nullptr && items[i].readable) {
  470. stream = http2_ctx_accept_stream(ctx);
  471. if (stream)
  472. break;
  473. }
  474. }
  475. usleep(20000);
  476. }
  477. ASSERT_NE(stream, nullptr) << "Server failed to accept stream";
  478. // Read request body until EOF
  479. uint8_t buf[1024];
  480. int loop_count = 0;
  481. while (loop_count++ < 100) {
  482. struct http2_poll_item items[10];
  483. int count = 0;
  484. http2_ctx_poll(ctx, items, 10, &count);
  485. int data_read = 0;
  486. for (int i = 0; i < count; i++) {
  487. if (items[i].stream == stream && items[i].readable) {
  488. int ret = http2_stream_read_body(stream, buf, sizeof(buf));
  489. if (ret > 0) {
  490. data_read = 1;
  491. } else if (ret == 0) {
  492. // EOF received
  493. data_read = 1;
  494. }
  495. }
  496. }
  497. if (!data_read && http2_stream_is_end(stream)) {
  498. // If we are here, it means poll returned 0 items (or stream not readable),
  499. // which is correct behavior after EOF is consumed.
  500. // If the bug exists, poll would keep returning readable stream, and we would keep reading 0 bytes.
  501. break;
  502. }
  503. usleep(10000);
  504. }
  505. EXPECT_LT(loop_count, 100) << "Server loop did not terminate (infinite loop detected)";
  506. http2_ctx_free(ctx);
  507. });
  508. std::thread client_thread([this]() {
  509. usleep(50000);
  510. struct http2_ctx *ctx = http2_ctx_client_new("test-client", bio_read, bio_write, &client_sock, NULL);
  511. ASSERT_NE(ctx, nullptr);
  512. int handshake_attempts = 200;
  513. int ret = 0;
  514. while (handshake_attempts-- > 0) {
  515. struct pollfd pfd = {client_sock, POLLIN, 0};
  516. poll(&pfd, 1, 10);
  517. ret = http2_ctx_handshake(ctx);
  518. if (ret == 1) break;
  519. if (ret < 0) break;
  520. }
  521. ASSERT_EQ(ret, 1);
  522. struct http2_stream *stream = http2_stream_new(ctx);
  523. ASSERT_NE(stream, nullptr);
  524. struct http2_header_pair headers[] = {{"content-type", "text/plain"}, {NULL, NULL}};
  525. http2_stream_set_request(stream, "POST", "/test", headers);
  526. http2_stream_write_body(stream, (const uint8_t *)"test", 4, 1);
  527. usleep(200000); // Wait for server to process
  528. http2_stream_put(stream);
  529. http2_ctx_free(ctx);
  530. });
  531. server_thread.join();
  532. client_thread.join();
  533. }