http_client.c 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966
  1. /*
  2. * Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
  3. *
  4. * This program is free software; you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License as published by
  6. * the Free Software Foundation; either version 2 of the License, or
  7. * (at your option) any later version.
  8. *
  9. * This program is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this program; if not, write to the Free Software
  16. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  17. */
  18. #include "test.h"
  19. #if INCLUDE_HTTP_CLIENT_TEST
  20. #define THIS_FILE "test_http"
  21. //#define VERBOSE
  22. #define STR_PREC(s) (int)s.slen, s.ptr
  23. #define USE_LOCAL_SERVER
  24. #include <pjlib.h>
  25. #include <pjlib-util.h>
  26. #define ACTION_REPLY 0
  27. #define ACTION_IGNORE -1
  28. static struct server_t
  29. {
  30. pj_sock_t sock;
  31. pj_uint16_t port;
  32. pj_thread_t *thread;
  33. /* Action:
  34. * 0: reply with the response in resp.
  35. * -1: ignore query (to simulate timeout).
  36. * other: reply with that error
  37. */
  38. int action;
  39. pj_bool_t send_content_length;
  40. unsigned data_size;
  41. unsigned buf_size;
  42. } g_server;
  43. static pj_bool_t thread_quit;
  44. static pj_timer_heap_t *timer_heap;
  45. static pj_ioqueue_t *ioqueue;
  46. static pj_pool_t *pool;
  47. static pj_http_req *http_req;
  48. static pj_bool_t test_cancel = PJ_FALSE;
  49. static pj_size_t total_size;
  50. static pj_size_t send_size = 0;
  51. static pj_status_t sstatus;
  52. static pj_sockaddr_in addr;
  53. static int counter = 0;
  54. static int server_thread(void *p)
  55. {
  56. struct server_t *srv = (struct server_t*)p;
  57. char *pkt = (char*)pj_pool_alloc(pool, srv->buf_size);
  58. pj_sock_t newsock = PJ_INVALID_SOCKET;
  59. while (!thread_quit) {
  60. pj_ssize_t pkt_len;
  61. int rc;
  62. pj_fd_set_t rset;
  63. pj_time_val timeout = {0, 500};
  64. while (!thread_quit) {
  65. PJ_FD_ZERO(&rset);
  66. PJ_FD_SET(srv->sock, &rset);
  67. rc = pj_sock_select((int)srv->sock+1, &rset, NULL, NULL, &timeout);
  68. if (rc != 1) {
  69. continue;
  70. }
  71. rc = pj_sock_accept(srv->sock, &newsock, NULL, NULL);
  72. if (rc == PJ_SUCCESS) {
  73. break;
  74. }
  75. }
  76. if (thread_quit)
  77. break;
  78. while (!thread_quit) {
  79. PJ_FD_ZERO(&rset);
  80. PJ_FD_SET(newsock, &rset);
  81. rc = pj_sock_select((int)newsock+1, &rset, NULL, NULL, &timeout);
  82. if (rc != 1) {
  83. PJ_LOG(3,("http test", "client timeout"));
  84. continue;
  85. }
  86. pkt_len = srv->buf_size;
  87. rc = pj_sock_recv(newsock, pkt, &pkt_len, 0);
  88. if (rc == PJ_SUCCESS) {
  89. break;
  90. }
  91. }
  92. if (thread_quit)
  93. break;
  94. /* Simulate network RTT */
  95. pj_thread_sleep(50);
  96. if (srv->action == ACTION_IGNORE) {
  97. continue;
  98. } else if (srv->action == ACTION_REPLY) {
  99. pj_size_t send_len = 0;
  100. unsigned ctr = 0;
  101. pkt_len = pj_ansi_snprintf(pkt, srv->buf_size,
  102. "HTTP/1.0 200 OK\r\n");
  103. PJ_ASSERT_ON_FAIL(pkt_len>0, {
  104. PJ_PERROR(2, (THIS_FILE, -pkt_len, "Error creating response"));
  105. pj_sock_close(newsock);
  106. continue;
  107. })
  108. if (srv->send_content_length) {
  109. pj_ansi_snprintf(pkt + pkt_len, srv->buf_size - pkt_len,
  110. "Content-Length: %d\r\n",
  111. srv->data_size);
  112. }
  113. pkt_len = pj_ansi_strxcat(pkt, "\r\n", srv->buf_size);
  114. if (pkt_len < 0) {
  115. PJ_PERROR(2, (THIS_FILE, -pkt_len, "Error creating response"));
  116. pj_sock_close(newsock);
  117. continue;
  118. }
  119. rc = pj_sock_send(newsock, pkt, &pkt_len, 0);
  120. if (rc != PJ_SUCCESS) {
  121. pj_sock_close(newsock);
  122. continue;
  123. }
  124. while (send_len < srv->data_size) {
  125. pkt_len = srv->data_size - send_len;
  126. if (pkt_len > (signed)srv->buf_size)
  127. pkt_len = srv->buf_size;
  128. send_len += pkt_len;
  129. pj_create_random_string(pkt, pkt_len);
  130. pj_ansi_snprintf(pkt, srv->buf_size, "\nPacket: %d", ++ctr);
  131. pkt[pj_ansi_strlen(pkt)] = '\n';
  132. rc = pj_sock_send(newsock, pkt, &pkt_len, 0);
  133. if (rc != PJ_SUCCESS)
  134. break;
  135. }
  136. pj_sock_close(newsock);
  137. }
  138. }
  139. return 0;
  140. }
  141. static void on_data_read(pj_http_req *hreq, void *data, pj_size_t size)
  142. {
  143. PJ_UNUSED_ARG(hreq);
  144. PJ_UNUSED_ARG(data);
  145. PJ_LOG(5, (THIS_FILE, "\nData received: %lu bytes", (unsigned long)size));
  146. if (size > 0) {
  147. #ifdef VERBOSE
  148. printf("%.*s\n", (int)size, (char *)data);
  149. #endif
  150. }
  151. }
  152. static void on_send_data(pj_http_req *hreq,
  153. void **data, pj_size_t *size)
  154. {
  155. char *sdata;
  156. pj_size_t sendsz = 8397;
  157. PJ_UNUSED_ARG(hreq);
  158. if (send_size + sendsz > total_size) {
  159. sendsz = total_size - send_size;
  160. }
  161. send_size += sendsz;
  162. sdata = (char*)pj_pool_alloc(pool, sendsz);
  163. pj_create_random_string(sdata, sendsz);
  164. pj_ansi_snprintf(sdata, sendsz, "\nSegment #%d\n", ++counter);
  165. *data = sdata;
  166. *size = sendsz;
  167. PJ_LOG(5, (THIS_FILE, "\nSending data progress: %lu out of %lu bytes",
  168. (unsigned long)send_size, (unsigned long)total_size));
  169. }
  170. static void on_complete(pj_http_req *hreq, pj_status_t status,
  171. const pj_http_resp *resp)
  172. {
  173. PJ_UNUSED_ARG(hreq);
  174. if (status == PJ_ECANCELLED) {
  175. PJ_LOG(5, (THIS_FILE, "Request cancelled"));
  176. return;
  177. } else if (status == PJ_ETIMEDOUT) {
  178. PJ_LOG(5, (THIS_FILE, "Request timed out!"));
  179. return;
  180. } else if (status != PJ_SUCCESS) {
  181. PJ_LOG(3, (THIS_FILE, "Error %d", status));
  182. return;
  183. }
  184. PJ_LOG(5, (THIS_FILE, "\nData completed: %lu bytes",
  185. (unsigned long)resp->size));
  186. if (resp->size > 0 && resp->data) {
  187. #ifdef VERBOSE
  188. printf("%.*s\n", (int)resp->size, (char *)resp->data);
  189. #endif
  190. }
  191. }
  192. static void on_response(pj_http_req *hreq, const pj_http_resp *resp)
  193. {
  194. pj_size_t i;
  195. PJ_UNUSED_ARG(hreq);
  196. PJ_UNUSED_ARG(resp);
  197. PJ_UNUSED_ARG(i);
  198. #ifdef VERBOSE
  199. printf("%.*s, %d, %.*s\n", STR_PREC(resp->version),
  200. resp->status_code, STR_PREC(resp->reason));
  201. for (i = 0; i < resp->headers.count; i++) {
  202. printf("%.*s : %.*s\n",
  203. STR_PREC(resp->headers.header[i].name),
  204. STR_PREC(resp->headers.header[i].value));
  205. }
  206. #endif
  207. if (test_cancel) {
  208. /* Need to delay closing the client socket here, otherwise the
  209. * server will get SIGPIPE when sending response.
  210. */
  211. pj_thread_sleep(100);
  212. pj_http_req_cancel(hreq, PJ_TRUE);
  213. test_cancel = PJ_FALSE;
  214. }
  215. }
  216. pj_status_t parse_url(const char *url, pj_http_url *hurl)
  217. {
  218. pj_str_t surl;
  219. pj_status_t status;
  220. pj_cstr(&surl, url);
  221. status = pj_http_req_parse_url(&surl, hurl);
  222. #ifdef VERBOSE
  223. if (!status) {
  224. printf("URL: %s\nProtocol: %.*s\nHost: %.*s\nPort: %d\nPath: %.*s\n\n",
  225. url, STR_PREC(hurl->protocol), STR_PREC(hurl->host),
  226. hurl->port, STR_PREC(hurl->path));
  227. } else {
  228. }
  229. #endif
  230. return status;
  231. }
  232. static int parse_url_test()
  233. {
  234. struct test_data
  235. {
  236. char *url;
  237. pj_status_t result;
  238. const char *username;
  239. const char *passwd;
  240. const char *host;
  241. int port;
  242. const char *path;
  243. } test_data[] =
  244. {
  245. /* Simple URL without '/' in the end */
  246. {"http://www.pjsip.org", PJ_SUCCESS, "", "", "www.pjsip.org", 80, "/"},
  247. /* Simple URL with port number but without '/' in the end */
  248. {"http://pjsip.org:8080", PJ_SUCCESS, "", "", "pjsip.org", 8080, "/"},
  249. /* URL with path */
  250. {"http://127.0.0.1:280/Joomla/index.php?option=com_content&task=view&id=5&Itemid=6",
  251. PJ_SUCCESS, "", "", "127.0.0.1", 280,
  252. "/Joomla/index.php?option=com_content&task=view&id=5&Itemid=6"},
  253. /* URL with port and path */
  254. {"http://pjsip.org:81/about-us/", PJ_SUCCESS, "", "", "pjsip.org", 81, "/about-us/"},
  255. /* unsupported protocol */
  256. {"ftp://www.pjsip.org", PJ_ENOTSUP, "", "", "", 80, ""},
  257. /* invalid format */
  258. {"http:/pjsip.org/about-us/", PJLIB_UTIL_EHTTPINURL, "", "", "", 80, ""},
  259. /* invalid port number */
  260. {"http://pjsip.org:xyz/", PJLIB_UTIL_EHTTPINPORT, "", "", "", 80, ""},
  261. /* with username and password */
  262. {"http://user:pass@pjsip.org", PJ_SUCCESS, "user", "pass", "pjsip.org", 80, "/"},
  263. /* password only*/
  264. {"http://:pass@pjsip.org", PJ_SUCCESS, "", "pass", "pjsip.org", 80, "/"},
  265. /* user only*/
  266. {"http://user:@pjsip.org", PJ_SUCCESS, "user", "", "pjsip.org", 80, "/"},
  267. /* empty username and passwd*/
  268. {"http://:@pjsip.org", PJ_SUCCESS, "", "", "pjsip.org", 80, "/"},
  269. /* '@' character in username and path */
  270. {"http://user@pjsip.org/@", PJ_SUCCESS, "user", "", "pjsip.org", 80, "/@"},
  271. /* '@' character in path */
  272. {"http://pjsip.org/@", PJ_SUCCESS, "", "", "pjsip.org", 80, "/@"},
  273. /* '@' character in path */
  274. {"http://pjsip.org/one@", PJ_SUCCESS, "", "", "pjsip.org", 80, "/one@"},
  275. /* Invalid URL */
  276. {"http://:", PJ_EINVAL, "", "", "", 0, ""},
  277. /* Invalid URL */
  278. {"http://@", PJ_EINVAL, "", "", "", 0, ""},
  279. /* Invalid URL */
  280. {"http", PJ_EINVAL, "", "", "", 0, ""},
  281. /* Invalid URL */
  282. {"http:/", PJ_EINVAL, "", "", "", 0, ""},
  283. /* Invalid URL */
  284. {"http://", PJ_EINVAL, "", "", "", 0, ""},
  285. /* Invalid URL */
  286. {"http:///", PJ_EINVAL, "", "", "", 0, ""},
  287. /* Invalid URL */
  288. {"http://@/", PJ_EINVAL, "", "", "", 0, ""},
  289. /* Invalid URL */
  290. {"http:///@", PJ_EINVAL, "", "", "", 0, ""},
  291. /* Invalid URL */
  292. {"http://:::", PJ_EINVAL, "", "", "", 0, ""},
  293. };
  294. unsigned i;
  295. for (i=0; i<PJ_ARRAY_SIZE(test_data); ++i) {
  296. struct test_data *ptd;
  297. pj_http_url hurl;
  298. pj_status_t status;
  299. ptd = &test_data[i];
  300. PJ_LOG(3, (THIS_FILE, ".. %s", ptd->url));
  301. status = parse_url(ptd->url, &hurl);
  302. if (status != ptd->result) {
  303. PJ_LOG(3,(THIS_FILE, "%d", status));
  304. return -11;
  305. }
  306. if (status != PJ_SUCCESS)
  307. continue;
  308. if (pj_strcmp2(&hurl.username, ptd->username))
  309. return -12;
  310. if (pj_strcmp2(&hurl.passwd, ptd->passwd))
  311. return -13;
  312. if (pj_strcmp2(&hurl.host, ptd->host))
  313. return -14;
  314. if (hurl.port != ptd->port)
  315. return -15;
  316. if (pj_strcmp2(&hurl.path, ptd->path))
  317. return -16;
  318. }
  319. return 0;
  320. }
  321. /*
  322. * GET request scenario 1: using on_response() and on_data_read()
  323. * Server replies with content-length. Application cancels the
  324. * request upon receiving the response, then start it again.
  325. */
  326. int http_client_test1()
  327. {
  328. pj_str_t url;
  329. pj_http_req_callback hcb;
  330. pj_http_req_param param;
  331. char urlbuf[80];
  332. pj_bzero(&hcb, sizeof(hcb));
  333. hcb.on_complete = &on_complete;
  334. hcb.on_data_read = &on_data_read;
  335. hcb.on_response = &on_response;
  336. pj_http_req_param_default(&param);
  337. /* Create pool, timer, and ioqueue */
  338. pool = pj_pool_create(mem, NULL, 8192, 4096, NULL);
  339. if (pj_timer_heap_create(pool, 16, &timer_heap))
  340. return -31;
  341. if (pj_ioqueue_create(pool, 16, &ioqueue))
  342. return -32;
  343. #ifdef USE_LOCAL_SERVER
  344. thread_quit = PJ_FALSE;
  345. g_server.action = ACTION_REPLY;
  346. g_server.send_content_length = PJ_TRUE;
  347. g_server.data_size = 2970;
  348. g_server.buf_size = 1024;
  349. sstatus = pj_sock_socket(pj_AF_INET(), pj_SOCK_STREAM(), 0,
  350. &g_server.sock);
  351. if (sstatus != PJ_SUCCESS)
  352. return -41;
  353. pj_sockaddr_in_init(&addr, NULL, 0);
  354. sstatus = pj_sock_bind(g_server.sock, &addr, sizeof(addr));
  355. if (sstatus != PJ_SUCCESS)
  356. return -43;
  357. {
  358. pj_sockaddr_in addr2;
  359. int addr_len = sizeof(addr2);
  360. sstatus = pj_sock_getsockname(g_server.sock, &addr2, &addr_len);
  361. if (sstatus != PJ_SUCCESS)
  362. return -44;
  363. g_server.port = pj_sockaddr_in_get_port(&addr2);
  364. pj_ansi_snprintf(urlbuf, sizeof(urlbuf),
  365. "http://127.0.0.1:%d/about-us/",
  366. g_server.port);
  367. url = pj_str(urlbuf);
  368. }
  369. sstatus = pj_sock_listen(g_server.sock, 8);
  370. if (sstatus != PJ_SUCCESS)
  371. return -45;
  372. sstatus = pj_thread_create(pool, NULL, &server_thread, &g_server,
  373. 0, 0, &g_server.thread);
  374. if (sstatus != PJ_SUCCESS)
  375. return -47;
  376. #else
  377. pj_cstr(&url, "http://www.teluu.com/about-us/");
  378. #endif
  379. if (pj_http_req_create(pool, &url, timer_heap, ioqueue,
  380. &param, &hcb, &http_req))
  381. return -33;
  382. test_cancel = PJ_TRUE;
  383. if (pj_http_req_start(http_req))
  384. return -35;
  385. while (pj_http_req_is_running(http_req)) {
  386. pj_time_val delay = {0, 50};
  387. pj_ioqueue_poll(ioqueue, &delay);
  388. pj_timer_heap_poll(timer_heap, NULL);
  389. }
  390. if (pj_http_req_start(http_req))
  391. return -37;
  392. while (pj_http_req_is_running(http_req)) {
  393. pj_time_val delay = {0, 50};
  394. pj_ioqueue_poll(ioqueue, &delay);
  395. pj_timer_heap_poll(timer_heap, NULL);
  396. }
  397. #ifdef USE_LOCAL_SERVER
  398. thread_quit = PJ_TRUE;
  399. pj_thread_join(g_server.thread);
  400. pj_sock_close(g_server.sock);
  401. #endif
  402. pj_http_req_destroy(http_req);
  403. pj_ioqueue_destroy(ioqueue);
  404. pj_timer_heap_destroy(timer_heap);
  405. pj_pool_release(pool);
  406. return PJ_SUCCESS;
  407. }
  408. /*
  409. * GET request scenario 2: using on_complete() to get the
  410. * complete data. Server does not reply with content-length.
  411. * Request timed out, application sets a longer timeout, then
  412. * then restart the request.
  413. */
  414. int http_client_test2()
  415. {
  416. pj_str_t url;
  417. pj_http_req_callback hcb;
  418. pj_http_req_param param;
  419. pj_time_val timeout;
  420. char urlbuf[80];
  421. pj_bzero(&hcb, sizeof(hcb));
  422. hcb.on_complete = &on_complete;
  423. hcb.on_response = &on_response;
  424. pj_http_req_param_default(&param);
  425. /* Create pool, timer, and ioqueue */
  426. pool = pj_pool_create(mem, NULL, 8192, 4096, NULL);
  427. if (pj_timer_heap_create(pool, 16, &timer_heap))
  428. return -41;
  429. if (pj_ioqueue_create(pool, 16, &ioqueue))
  430. return -42;
  431. #ifdef USE_LOCAL_SERVER
  432. pj_cstr(&url, "http://127.0.0.1:380");
  433. param.timeout.sec = 0;
  434. param.timeout.msec = 2000;
  435. thread_quit = PJ_FALSE;
  436. g_server.action = ACTION_IGNORE;
  437. g_server.send_content_length = PJ_FALSE;
  438. g_server.data_size = 4173;
  439. g_server.buf_size = 1024;
  440. sstatus = pj_sock_socket(pj_AF_INET(), pj_SOCK_STREAM(), 0,
  441. &g_server.sock);
  442. if (sstatus != PJ_SUCCESS)
  443. return -41;
  444. pj_sockaddr_in_init(&addr, NULL, 0);
  445. sstatus = pj_sock_bind(g_server.sock, &addr, sizeof(addr));
  446. if (sstatus != PJ_SUCCESS)
  447. return -43;
  448. {
  449. pj_sockaddr_in addr2;
  450. int addr_len = sizeof(addr2);
  451. sstatus = pj_sock_getsockname(g_server.sock, &addr2, &addr_len);
  452. if (sstatus != PJ_SUCCESS)
  453. return -44;
  454. g_server.port = pj_sockaddr_in_get_port(&addr2);
  455. pj_ansi_snprintf(urlbuf, sizeof(urlbuf),
  456. "http://127.0.0.1:%d",
  457. g_server.port);
  458. url = pj_str(urlbuf);
  459. }
  460. sstatus = pj_sock_listen(g_server.sock, 8);
  461. if (sstatus != PJ_SUCCESS)
  462. return -45;
  463. sstatus = pj_thread_create(pool, NULL, &server_thread, &g_server,
  464. 0, 0, &g_server.thread);
  465. if (sstatus != PJ_SUCCESS)
  466. return -47;
  467. #else
  468. pj_cstr(&url, "http://www.google.com.sg");
  469. param.timeout.sec = 0;
  470. param.timeout.msec = 50;
  471. #endif
  472. pj_http_headers_add_elmt2(&param.headers, (char*)"Accept",
  473. (char*)"image/gif, image/x-xbitmap, image/jpeg, "
  474. "image/pjpeg, application/x-ms-application,"
  475. " application/vnd.ms-xpsdocument, "
  476. "application/xaml+xml, "
  477. "application/x-ms-xbap, "
  478. "application/x-shockwave-flash, "
  479. "application/vnd.ms-excel, "
  480. "application/vnd.ms-powerpoint, "
  481. "application/msword, */*");
  482. pj_http_headers_add_elmt2(&param.headers, (char*)"Accept-Language",
  483. (char*)"en-sg");
  484. pj_http_headers_add_elmt2(&param.headers, (char*)"User-Agent",
  485. (char*)"Mozilla/4.0 (compatible; MSIE 7.0; "
  486. "Windows NT 6.0; SLCC1; "
  487. ".NET CLR 2.0.50727; "
  488. ".NET CLR 3.0.04506)");
  489. if (pj_http_req_create(pool, &url, timer_heap, ioqueue,
  490. &param, &hcb, &http_req))
  491. return -43;
  492. if (pj_http_req_start(http_req))
  493. return -45;
  494. while (pj_http_req_is_running(http_req)) {
  495. pj_time_val delay = {0, 50};
  496. pj_ioqueue_poll(ioqueue, &delay);
  497. pj_timer_heap_poll(timer_heap, NULL);
  498. }
  499. #ifdef USE_LOCAL_SERVER
  500. g_server.action = ACTION_REPLY;
  501. #endif
  502. timeout.sec = 0; timeout.msec = 10000;
  503. pj_http_req_set_timeout(http_req, &timeout);
  504. if (pj_http_req_start(http_req))
  505. return -47;
  506. while (pj_http_req_is_running(http_req)) {
  507. pj_time_val delay = {0, 50};
  508. pj_ioqueue_poll(ioqueue, &delay);
  509. pj_timer_heap_poll(timer_heap, NULL);
  510. }
  511. #ifdef USE_LOCAL_SERVER
  512. thread_quit = PJ_TRUE;
  513. pj_thread_join(g_server.thread);
  514. pj_sock_close(g_server.sock);
  515. #endif
  516. pj_http_req_destroy(http_req);
  517. pj_ioqueue_destroy(ioqueue);
  518. pj_timer_heap_destroy(timer_heap);
  519. pj_pool_release(pool);
  520. return PJ_SUCCESS;
  521. }
  522. /*
  523. * PUT request scenario 1: sending the whole data at once
  524. */
  525. int http_client_test_put1()
  526. {
  527. pj_str_t url;
  528. pj_http_req_callback hcb;
  529. pj_http_req_param param;
  530. char *data;
  531. int length = 3875;
  532. char urlbuf[80];
  533. pj_bzero(&hcb, sizeof(hcb));
  534. hcb.on_complete = &on_complete;
  535. hcb.on_data_read = &on_data_read;
  536. hcb.on_response = &on_response;
  537. /* Create pool, timer, and ioqueue */
  538. pool = pj_pool_create(mem, NULL, 8192, 4096, NULL);
  539. if (pj_timer_heap_create(pool, 16, &timer_heap))
  540. return -51;
  541. if (pj_ioqueue_create(pool, 16, &ioqueue))
  542. return -52;
  543. #ifdef USE_LOCAL_SERVER
  544. thread_quit = PJ_FALSE;
  545. g_server.action = ACTION_REPLY;
  546. g_server.send_content_length = PJ_TRUE;
  547. g_server.data_size = 0;
  548. g_server.buf_size = 4096;
  549. sstatus = pj_sock_socket(pj_AF_INET(), pj_SOCK_STREAM(), 0,
  550. &g_server.sock);
  551. if (sstatus != PJ_SUCCESS)
  552. return -41;
  553. pj_sockaddr_in_init(&addr, NULL, 0);
  554. sstatus = pj_sock_bind(g_server.sock, &addr, sizeof(addr));
  555. if (sstatus != PJ_SUCCESS)
  556. return -43;
  557. {
  558. pj_sockaddr_in addr2;
  559. int addr_len = sizeof(addr2);
  560. sstatus = pj_sock_getsockname(g_server.sock, &addr2, &addr_len);
  561. if (sstatus != PJ_SUCCESS)
  562. return -44;
  563. g_server.port = pj_sockaddr_in_get_port(&addr2);
  564. pj_ansi_snprintf(urlbuf, sizeof(urlbuf),
  565. "http://127.0.0.1:%d/test/test.txt",
  566. g_server.port);
  567. url = pj_str(urlbuf);
  568. }
  569. sstatus = pj_sock_listen(g_server.sock, 8);
  570. if (sstatus != PJ_SUCCESS)
  571. return -45;
  572. sstatus = pj_thread_create(pool, NULL, &server_thread, &g_server,
  573. 0, 0, &g_server.thread);
  574. if (sstatus != PJ_SUCCESS)
  575. return -47;
  576. #else
  577. pj_cstr(&url, "http://127.0.0.1:280/test/test.txt");
  578. #endif
  579. pj_http_req_param_default(&param);
  580. pj_strset2(&param.method, (char*)"PUT");
  581. data = (char*)pj_pool_alloc(pool, length);
  582. pj_create_random_string(data, length);
  583. pj_ansi_snprintf(data, length, "PUT test\n");
  584. param.reqdata.data = data;
  585. param.reqdata.size = length;
  586. if (pj_http_req_create(pool, &url, timer_heap, ioqueue,
  587. &param, &hcb, &http_req))
  588. return -53;
  589. if (pj_http_req_start(http_req))
  590. return -55;
  591. while (pj_http_req_is_running(http_req)) {
  592. pj_time_val delay = {0, 50};
  593. pj_ioqueue_poll(ioqueue, &delay);
  594. pj_timer_heap_poll(timer_heap, NULL);
  595. }
  596. #ifdef USE_LOCAL_SERVER
  597. thread_quit = PJ_TRUE;
  598. pj_thread_join(g_server.thread);
  599. pj_sock_close(g_server.sock);
  600. #endif
  601. pj_http_req_destroy(http_req);
  602. pj_ioqueue_destroy(ioqueue);
  603. pj_timer_heap_destroy(timer_heap);
  604. pj_pool_release(pool);
  605. return PJ_SUCCESS;
  606. }
  607. /*
  608. * PUT request scenario 2: using on_send_data() callback to
  609. * sending the data in chunks
  610. */
  611. int http_client_test_put2()
  612. {
  613. pj_str_t url;
  614. pj_http_req_callback hcb;
  615. pj_http_req_param param;
  616. char urlbuf[80];
  617. pj_bzero(&hcb, sizeof(hcb));
  618. hcb.on_complete = &on_complete;
  619. hcb.on_send_data = &on_send_data;
  620. hcb.on_data_read = &on_data_read;
  621. hcb.on_response = &on_response;
  622. /* Create pool, timer, and ioqueue */
  623. pool = pj_pool_create(mem, NULL, 8192, 4096, NULL);
  624. if (pj_timer_heap_create(pool, 16, &timer_heap))
  625. return -51;
  626. if (pj_ioqueue_create(pool, 16, &ioqueue))
  627. return -52;
  628. #ifdef USE_LOCAL_SERVER
  629. thread_quit = PJ_FALSE;
  630. g_server.action = ACTION_REPLY;
  631. g_server.send_content_length = PJ_TRUE;
  632. g_server.data_size = 0;
  633. g_server.buf_size = 16384;
  634. sstatus = pj_sock_socket(pj_AF_INET(), pj_SOCK_STREAM(), 0,
  635. &g_server.sock);
  636. if (sstatus != PJ_SUCCESS)
  637. return -41;
  638. pj_sockaddr_in_init(&addr, NULL, 0);
  639. sstatus = pj_sock_bind(g_server.sock, &addr, sizeof(addr));
  640. if (sstatus != PJ_SUCCESS)
  641. return -43;
  642. {
  643. pj_sockaddr_in addr2;
  644. int addr_len = sizeof(addr2);
  645. sstatus = pj_sock_getsockname(g_server.sock, &addr2, &addr_len);
  646. if (sstatus != PJ_SUCCESS)
  647. return -44;
  648. g_server.port = pj_sockaddr_in_get_port(&addr2);
  649. pj_ansi_snprintf(urlbuf, sizeof(urlbuf),
  650. "http://127.0.0.1:%d/test/test2.txt",
  651. g_server.port);
  652. url = pj_str(urlbuf);
  653. }
  654. sstatus = pj_sock_listen(g_server.sock, 8);
  655. if (sstatus != PJ_SUCCESS)
  656. return -45;
  657. sstatus = pj_thread_create(pool, NULL, &server_thread, &g_server,
  658. 0, 0, &g_server.thread);
  659. if (sstatus != PJ_SUCCESS)
  660. return -47;
  661. #else
  662. pj_cstr(&url, "http://127.0.0.1:280/test/test2.txt");
  663. #endif
  664. pj_http_req_param_default(&param);
  665. pj_strset2(&param.method, (char*)"PUT");
  666. total_size = 15383;
  667. send_size = 0;
  668. param.reqdata.total_size = total_size;
  669. if (pj_http_req_create(pool, &url, timer_heap, ioqueue,
  670. &param, &hcb, &http_req))
  671. return -53;
  672. if (pj_http_req_start(http_req))
  673. return -55;
  674. while (pj_http_req_is_running(http_req)) {
  675. pj_time_val delay = {0, 50};
  676. pj_ioqueue_poll(ioqueue, &delay);
  677. pj_timer_heap_poll(timer_heap, NULL);
  678. }
  679. #ifdef USE_LOCAL_SERVER
  680. thread_quit = PJ_TRUE;
  681. pj_thread_join(g_server.thread);
  682. pj_sock_close(g_server.sock);
  683. #endif
  684. pj_http_req_destroy(http_req);
  685. pj_ioqueue_destroy(ioqueue);
  686. pj_timer_heap_destroy(timer_heap);
  687. pj_pool_release(pool);
  688. return PJ_SUCCESS;
  689. }
  690. int http_client_test_delete()
  691. {
  692. pj_str_t url;
  693. pj_http_req_callback hcb;
  694. pj_http_req_param param;
  695. char urlbuf[80];
  696. pj_bzero(&hcb, sizeof(hcb));
  697. hcb.on_complete = &on_complete;
  698. hcb.on_response = &on_response;
  699. /* Create pool, timer, and ioqueue */
  700. pool = pj_pool_create(mem, NULL, 8192, 4096, NULL);
  701. if (pj_timer_heap_create(pool, 16, &timer_heap))
  702. return -61;
  703. if (pj_ioqueue_create(pool, 16, &ioqueue))
  704. return -62;
  705. #ifdef USE_LOCAL_SERVER
  706. thread_quit = PJ_FALSE;
  707. g_server.action = ACTION_REPLY;
  708. g_server.send_content_length = PJ_TRUE;
  709. g_server.data_size = 0;
  710. g_server.buf_size = 1024;
  711. sstatus = pj_sock_socket(pj_AF_INET(), pj_SOCK_STREAM(), 0,
  712. &g_server.sock);
  713. if (sstatus != PJ_SUCCESS)
  714. return -41;
  715. pj_sockaddr_in_init(&addr, NULL, 0);
  716. sstatus = pj_sock_bind(g_server.sock, &addr, sizeof(addr));
  717. if (sstatus != PJ_SUCCESS)
  718. return -43;
  719. {
  720. pj_sockaddr_in addr2;
  721. int addr_len = sizeof(addr2);
  722. sstatus = pj_sock_getsockname(g_server.sock, &addr2, &addr_len);
  723. if (sstatus != PJ_SUCCESS)
  724. return -44;
  725. g_server.port = pj_sockaddr_in_get_port(&addr2);
  726. pj_ansi_snprintf(urlbuf, sizeof(urlbuf),
  727. "http://127.0.0.1:%d/test/test2.txt",
  728. g_server.port);
  729. url = pj_str(urlbuf);
  730. }
  731. sstatus = pj_sock_listen(g_server.sock, 8);
  732. if (sstatus != PJ_SUCCESS)
  733. return -45;
  734. sstatus = pj_thread_create(pool, NULL, &server_thread, &g_server,
  735. 0, 0, &g_server.thread);
  736. if (sstatus != PJ_SUCCESS)
  737. return -47;
  738. #else
  739. pj_cstr(&url, "http://127.0.0.1:280/test/test2.txt");
  740. #endif
  741. pj_http_req_param_default(&param);
  742. pj_strset2(&param.method, (char*)"DELETE");
  743. if (pj_http_req_create(pool, &url, timer_heap, ioqueue,
  744. &param, &hcb, &http_req))
  745. return -63;
  746. if (pj_http_req_start(http_req))
  747. return -65;
  748. while (pj_http_req_is_running(http_req)) {
  749. pj_time_val delay = {0, 50};
  750. pj_ioqueue_poll(ioqueue, &delay);
  751. pj_timer_heap_poll(timer_heap, NULL);
  752. }
  753. #ifdef USE_LOCAL_SERVER
  754. thread_quit = PJ_TRUE;
  755. pj_thread_join(g_server.thread);
  756. pj_sock_close(g_server.sock);
  757. #endif
  758. pj_http_req_destroy(http_req);
  759. pj_ioqueue_destroy(ioqueue);
  760. pj_timer_heap_destroy(timer_heap);
  761. pj_pool_release(pool);
  762. return PJ_SUCCESS;
  763. }
  764. int http_client_test()
  765. {
  766. int rc;
  767. PJ_LOG(3, (THIS_FILE, "..Testing URL parsing"));
  768. rc = parse_url_test();
  769. if (rc)
  770. return rc;
  771. PJ_LOG(3, (THIS_FILE, "..Testing GET request scenario 1"));
  772. rc = http_client_test1();
  773. if (rc)
  774. return rc;
  775. PJ_LOG(3, (THIS_FILE, "..Testing GET request scenario 2"));
  776. rc = http_client_test2();
  777. if (rc)
  778. return rc;
  779. PJ_LOG(3, (THIS_FILE, "..Testing PUT request scenario 1"));
  780. rc = http_client_test_put1();
  781. if (rc)
  782. return rc;
  783. PJ_LOG(3, (THIS_FILE, "..Testing PUT request scenario 2"));
  784. rc = http_client_test_put2();
  785. if (rc)
  786. return rc;
  787. PJ_LOG(3, (THIS_FILE, "..Testing DELETE request"));
  788. rc = http_client_test_delete();
  789. if (rc)
  790. return rc;
  791. return PJ_SUCCESS;
  792. }
  793. #else
  794. /* To prevent warning about "translation unit is empty"
  795. * when this test is disabled.
  796. */
  797. int dummy_http_client_test;
  798. #endif /* INCLUDE_HTTP_CLIENT_TEST */