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