blob: 9194f2bb7b3050e397400de6f57d178f54546114 [file] [log] [blame]
Sauw Mingd8435e62010-02-04 18:29:16 +00001/* $Id$ */
2/*
3 * Copyright (C) 2008-2010 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;
Benny Prijonod62947c2010-08-06 08:40:55 +000067 char *pkt = (char*)pj_pool_alloc(pool, srv->buf_size);
Benny Prijono29580612010-08-11 06:03:47 +000068 pj_sock_t newsock = PJ_INVALID_SOCKET;
Sauw Mingd8435e62010-02-04 18:29:16 +000069
70 while (!thread_quit) {
Sauw Mingd8435e62010-02-04 18:29:16 +000071 pj_ssize_t pkt_len;
72 int rc;
73 pj_fd_set_t rset;
Benny Prijonod62947c2010-08-06 08:40:55 +000074 pj_time_val timeout = {0, 500};
Sauw Mingd8435e62010-02-04 18:29:16 +000075
Benny Prijonod62947c2010-08-06 08:40:55 +000076 while (!thread_quit) {
77 PJ_FD_ZERO(&rset);
78 PJ_FD_SET(srv->sock, &rset);
79 rc = pj_sock_select(srv->sock+1, &rset, NULL, NULL, &timeout);
80 if (rc != 1) {
81 continue;
82 }
Sauw Mingd8435e62010-02-04 18:29:16 +000083
Benny Prijonod62947c2010-08-06 08:40:55 +000084 rc = pj_sock_accept(srv->sock, &newsock, NULL, NULL);
85 if (rc == PJ_SUCCESS) {
86 break;
87 }
88 }
Sauw Mingd8435e62010-02-04 18:29:16 +000089
Benny Prijonod62947c2010-08-06 08:40:55 +000090 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(newsock+1, &rset, NULL, NULL, &timeout);
97 if (rc != 1) {
98 PJ_LOG(3,("http test", "client timeout"));
Sauw Mingd8435e62010-02-04 18:29:16 +000099 continue;
100 }
Benny Prijonod62947c2010-08-06 08:40:55 +0000101
102 pkt_len = srv->buf_size;
103 rc = pj_sock_recv(newsock, pkt, &pkt_len, 0);
104 if (rc == PJ_SUCCESS) {
Sauw Mingd8435e62010-02-04 18:29:16 +0000105 break;
Benny Prijonod62947c2010-08-06 08:40:55 +0000106 }
107 }
108
109 if (thread_quit)
110 break;
Sauw Mingd8435e62010-02-04 18:29:16 +0000111
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 unsigned send_size = 0, ctr = 0;
119 pj_ansi_sprintf(pkt, "HTTP/1.0 200 OK\r\n");
120 if (srv->send_content_length) {
121 pj_ansi_sprintf(pkt + pj_ansi_strlen(pkt),
122 "Content-Length: %d\r\n",
123 srv->data_size);
124 }
125 pj_ansi_sprintf(pkt + pj_ansi_strlen(pkt), "\r\n");
126 pkt_len = pj_ansi_strlen(pkt);
Benny Prijonod62947c2010-08-06 08:40:55 +0000127 rc = pj_sock_send(newsock, pkt, &pkt_len, 0);
128 if (rc != PJ_SUCCESS) {
129 pj_sock_close(newsock);
130 continue;
131 }
Sauw Mingd8435e62010-02-04 18:29:16 +0000132 while (send_size < srv->data_size) {
133 pkt_len = srv->data_size - send_size;
134 if (pkt_len > (signed)srv->buf_size)
135 pkt_len = srv->buf_size;
136 send_size += pkt_len;
137 pj_create_random_string(pkt, pkt_len);
138 pj_ansi_sprintf(pkt, "\nPacket: %d", ++ctr);
139 pkt[pj_ansi_strlen(pkt)] = '\n';
Benny Prijonod62947c2010-08-06 08:40:55 +0000140 rc = pj_sock_send(newsock, pkt, &pkt_len, 0);
141 if (rc != PJ_SUCCESS)
142 break;
Sauw Mingd8435e62010-02-04 18:29:16 +0000143 }
144 pj_sock_close(newsock);
145 }
146 }
147
148 return 0;
149}
150
151static void on_data_read(pj_http_req *hreq, void *data, pj_size_t size)
152{
153 PJ_UNUSED_ARG(hreq);
154 PJ_UNUSED_ARG(data);
155
Sauw Ming63236bb2010-02-05 16:03:29 +0000156 PJ_LOG(5, (THIS_FILE, "\nData received: %d bytes", size));
Sauw Mingd8435e62010-02-04 18:29:16 +0000157 if (size > 0) {
158#ifdef VERBOSE
159 printf("%.*s\n", (int)size, (char *)data);
160#endif
161 }
162}
163
164static void on_send_data(pj_http_req *hreq,
165 void **data, pj_size_t *size)
166{
167 char *sdata;
168 pj_size_t sendsz = 8397;
169
170 PJ_UNUSED_ARG(hreq);
171
172 if (send_size + sendsz > total_size) {
173 sendsz = total_size - send_size;
174 }
175 send_size += sendsz;
176
Benny Prijono990f6e92010-02-10 10:45:07 +0000177 sdata = (char*)pj_pool_alloc(pool, sendsz);
Sauw Mingd8435e62010-02-04 18:29:16 +0000178 pj_create_random_string(sdata, sendsz);
179 pj_ansi_sprintf(sdata, "\nSegment #%d\n", ++counter);
180 *data = sdata;
181 *size = sendsz;
182
Sauw Ming63236bb2010-02-05 16:03:29 +0000183 PJ_LOG(5, (THIS_FILE, "\nSending data progress: %d out of %d bytes",
Sauw Mingd8435e62010-02-04 18:29:16 +0000184 send_size, total_size));
185}
186
187
188static void on_complete(pj_http_req *hreq, pj_status_t status,
189 const pj_http_resp *resp)
190{
191 PJ_UNUSED_ARG(hreq);
192
193 if (status == PJ_ECANCELLED) {
Sauw Ming63236bb2010-02-05 16:03:29 +0000194 PJ_LOG(5, (THIS_FILE, "Request cancelled"));
Sauw Mingd8435e62010-02-04 18:29:16 +0000195 return;
196 } else if (status == PJ_ETIMEDOUT) {
Sauw Ming63236bb2010-02-05 16:03:29 +0000197 PJ_LOG(5, (THIS_FILE, "Request timed out!"));
Sauw Mingd8435e62010-02-04 18:29:16 +0000198 return;
Sauw Ming63236bb2010-02-05 16:03:29 +0000199 } else if (status != PJ_SUCCESS) {
200 PJ_LOG(3, (THIS_FILE, "Error %d", status));
Sauw Mingd8435e62010-02-04 18:29:16 +0000201 return;
202 }
Sauw Ming63236bb2010-02-05 16:03:29 +0000203 PJ_LOG(5, (THIS_FILE, "\nData completed: %d bytes", resp->size));
Sauw Mingd8435e62010-02-04 18:29:16 +0000204 if (resp->size > 0 && resp->data) {
205#ifdef VERBOSE
206 printf("%.*s\n", (int)resp->size, (char *)resp->data);
207#endif
208 }
209}
210
211static void on_response(pj_http_req *hreq, const pj_http_resp *resp)
212{
213 pj_size_t i;
214
215 PJ_UNUSED_ARG(hreq);
216 PJ_UNUSED_ARG(resp);
217 PJ_UNUSED_ARG(i);
218
219#ifdef VERBOSE
Sauw Ming63236bb2010-02-05 16:03:29 +0000220 printf("%.*s, %d, %.*s\n", STR_PREC(resp->version),
221 resp->status_code, STR_PREC(resp->reason));
Sauw Mingd8435e62010-02-04 18:29:16 +0000222 for (i = 0; i < resp->headers.count; i++) {
223 printf("%.*s : %.*s\n",
224 STR_PREC(resp->headers.header[i].name),
225 STR_PREC(resp->headers.header[i].value));
226 }
227#endif
228
229 if (test_cancel) {
Benny Prijonod62947c2010-08-06 08:40:55 +0000230 /* Need to delay closing the client socket here, otherwise the
231 * server will get SIGPIPE when sending response.
232 */
233 pj_thread_sleep(100);
Sauw Mingd8435e62010-02-04 18:29:16 +0000234 pj_http_req_cancel(hreq, PJ_TRUE);
235 test_cancel = PJ_FALSE;
236 }
237}
238
239
Benny Prijono00f88272010-09-27 08:35:08 +0000240pj_status_t parse_url(const char *url, pj_http_url *hurl)
Sauw Mingd8435e62010-02-04 18:29:16 +0000241{
242 pj_str_t surl;
Sauw Mingd8435e62010-02-04 18:29:16 +0000243 pj_status_t status;
244
245 pj_cstr(&surl, url);
Benny Prijono00f88272010-09-27 08:35:08 +0000246 status = pj_http_req_parse_url(&surl, hurl);
Sauw Mingd8435e62010-02-04 18:29:16 +0000247#ifdef VERBOSE
248 if (!status) {
249 printf("URL: %s\nProtocol: %.*s\nHost: %.*s\nPort: %d\nPath: %.*s\n\n",
Benny Prijono00f88272010-09-27 08:35:08 +0000250 url, STR_PREC(hurl->protocol), STR_PREC(hurl->host),
251 hurl->port, STR_PREC(hurl->path));
Sauw Mingd8435e62010-02-04 18:29:16 +0000252 } else {
253 }
254#endif
255 return status;
256}
257
Benny Prijono00f88272010-09-27 08:35:08 +0000258static int parse_url_test()
Sauw Mingd8435e62010-02-04 18:29:16 +0000259{
Benny Prijono00f88272010-09-27 08:35:08 +0000260 struct test_data
261 {
262 char *url;
263 pj_status_t result;
264 const char *username;
265 const char *passwd;
266 const char *host;
267 int port;
268 const char *path;
269 } test_data[] =
270 {
271 /* Simple URL without '/' in the end */
272 {"http://www.pjsip.org", PJ_SUCCESS, "", "", "www.pjsip.org", 80, "/"},
273
274 /* Simple URL with port number but without '/' in the end */
275 {"http://pjsip.org:8080", PJ_SUCCESS, "", "", "pjsip.org", 8080, "/"},
276
277 /* URL with path */
278 {"http://127.0.0.1:280/Joomla/index.php?option=com_content&task=view&id=5&Itemid=6",
279 PJ_SUCCESS, "", "", "127.0.0.1", 280,
280 "/Joomla/index.php?option=com_content&task=view&id=5&Itemid=6"},
281
282 /* URL with port and path */
283 {"http://pjsip.org:81/about-us/", PJ_SUCCESS, "", "", "pjsip.org", 81, "/about-us/"},
284
285 /* unsupported protocol */
286 {"ftp://www.pjsip.org", PJ_ENOTSUP, "", "", "", 80, ""},
287
288 /* invalid format */
289 {"http:/pjsip.org/about-us/", PJLIB_UTIL_EHTTPINURL, "", "", "", 80, ""},
290
291 /* invalid port number */
292 {"http://pjsip.org:xyz/", PJLIB_UTIL_EHTTPINPORT, "", "", "", 80, ""},
293
294 /* with username and password */
295 {"http://user:pass@pjsip.org", PJ_SUCCESS, "user", "pass", "pjsip.org", 80, "/"},
296
297 /* password only*/
298 {"http://:pass@pjsip.org", PJ_SUCCESS, "", "pass", "pjsip.org", 80, "/"},
299
300 /* user only*/
301 {"http://user:@pjsip.org", PJ_SUCCESS, "user", "", "pjsip.org", 80, "/"},
302
303 /* empty username and passwd*/
304 {"http://:@pjsip.org", PJ_SUCCESS, "", "", "pjsip.org", 80, "/"},
305
Benny Prijono064d2352010-10-01 06:43:17 +0000306 /* '@' character in username and path */
307 {"http://user@pjsip.org/@", PJ_SUCCESS, "user", "", "pjsip.org", 80, "/@"},
308
309 /* '@' character in path */
310 {"http://pjsip.org/@", PJ_SUCCESS, "", "", "pjsip.org", 80, "/@"},
311
312 /* '@' character in path */
313 {"http://pjsip.org/one@", PJ_SUCCESS, "", "", "pjsip.org", 80, "/one@"},
314
Benny Prijono00f88272010-09-27 08:35:08 +0000315 /* Invalid URL */
316 {"http://:", PJ_EINVAL, "", "", "", 0, ""},
317
318 /* Invalid URL */
319 {"http://@", PJ_EINVAL, "", "", "", 0, ""},
320
321 /* Invalid URL */
322 {"http", PJ_EINVAL, "", "", "", 0, ""},
323
324 /* Invalid URL */
325 {"http:/", PJ_EINVAL, "", "", "", 0, ""},
326
327 /* Invalid URL */
328 {"http://", PJ_EINVAL, "", "", "", 0, ""},
329
330 /* Invalid URL */
331 {"http:///", PJ_EINVAL, "", "", "", 0, ""},
332
333 /* Invalid URL */
334 {"http://@/", PJ_EINVAL, "", "", "", 0, ""},
335
336 /* Invalid URL */
Benny Prijono064d2352010-10-01 06:43:17 +0000337 {"http:///@", PJ_EINVAL, "", "", "", 0, ""},
338
339 /* Invalid URL */
Benny Prijono00f88272010-09-27 08:35:08 +0000340 {"http://:::", PJ_EINVAL, "", "", "", 0, ""},
341 };
342 unsigned i;
343
344 for (i=0; i<PJ_ARRAY_SIZE(test_data); ++i) {
345 struct test_data *ptd;
346 pj_http_url hurl;
347 pj_status_t status;
348
349 ptd = &test_data[i];
350
351 PJ_LOG(3, (THIS_FILE, ".. %s", ptd->url));
352 status = parse_url(ptd->url, &hurl);
353
354 if (status != ptd->result) {
355 PJ_LOG(3,(THIS_FILE, "%d", status));
356 return -11;
357 }
358 if (status != PJ_SUCCESS)
359 continue;
360 if (pj_strcmp2(&hurl.username, ptd->username))
361 return -12;
362 if (pj_strcmp2(&hurl.passwd, ptd->passwd))
363 return -13;
364 if (pj_strcmp2(&hurl.host, ptd->host))
365 return -14;
366 if (hurl.port != ptd->port)
367 return -15;
368 if (pj_strcmp2(&hurl.path, ptd->path))
369 return -16;
370 }
Sauw Mingd8435e62010-02-04 18:29:16 +0000371
372 return 0;
373}
374
375/*
376 * GET request scenario 1: using on_response() and on_data_read()
377 * Server replies with content-length. Application cancels the
378 * request upon receiving the response, then start it again.
379 */
380int http_client_test1()
381{
382 pj_str_t url;
383 pj_http_req_callback hcb;
384 pj_http_req_param param;
Benny Prijono2ee684b2010-04-27 08:31:08 +0000385 char urlbuf[80];
Sauw Mingd8435e62010-02-04 18:29:16 +0000386
387 pj_bzero(&hcb, sizeof(hcb));
388 hcb.on_complete = &on_complete;
389 hcb.on_data_read = &on_data_read;
390 hcb.on_response = &on_response;
391 pj_http_req_param_default(&param);
392
393 /* Create pool, timer, and ioqueue */
394 pool = pj_pool_create(mem, NULL, 8192, 4096, NULL);
395 if (pj_timer_heap_create(pool, 16, &timer_heap))
396 return -31;
397 if (pj_ioqueue_create(pool, 16, &ioqueue))
398 return -32;
399
400#ifdef USE_LOCAL_SERVER
401
Sauw Mingd8435e62010-02-04 18:29:16 +0000402 thread_quit = PJ_FALSE;
403 g_server.action = ACTION_REPLY;
404 g_server.send_content_length = PJ_TRUE;
405 g_server.data_size = 2970;
Sauw Mingd8435e62010-02-04 18:29:16 +0000406 g_server.buf_size = 1024;
407
408 sstatus = pj_sock_socket(pj_AF_INET(), pj_SOCK_STREAM(), 0,
409 &g_server.sock);
410 if (sstatus != PJ_SUCCESS)
411 return -41;
412
Benny Prijono2ee684b2010-04-27 08:31:08 +0000413 pj_sockaddr_in_init(&addr, NULL, 0);
Sauw Mingd8435e62010-02-04 18:29:16 +0000414
415 sstatus = pj_sock_bind(g_server.sock, &addr, sizeof(addr));
416 if (sstatus != PJ_SUCCESS)
417 return -43;
418
Benny Prijono2ee684b2010-04-27 08:31:08 +0000419 {
420 pj_sockaddr_in addr;
421 int addr_len = sizeof(addr);
422 sstatus = pj_sock_getsockname(g_server.sock, &addr, &addr_len);
423 if (sstatus != PJ_SUCCESS)
424 return -44;
425 g_server.port = pj_sockaddr_in_get_port(&addr);
426 pj_ansi_snprintf(urlbuf, sizeof(urlbuf),
427 "http://127.0.0.1:%d/about-us/",
428 g_server.port);
429 url = pj_str(urlbuf);
430 }
431
Sauw Mingd8435e62010-02-04 18:29:16 +0000432 sstatus = pj_sock_listen(g_server.sock, 8);
433 if (sstatus != PJ_SUCCESS)
434 return -45;
435
436 sstatus = pj_thread_create(pool, NULL, &server_thread, &g_server,
437 0, 0, &g_server.thread);
438 if (sstatus != PJ_SUCCESS)
439 return -47;
440
441#else
442 pj_cstr(&url, "http://www.teluu.com/about-us/");
443#endif
444
445 if (pj_http_req_create(pool, &url, timer_heap, ioqueue,
446 &param, &hcb, &http_req))
447 return -33;
448
449 test_cancel = PJ_TRUE;
450 if (pj_http_req_start(http_req))
451 return -35;
452
453 while (pj_http_req_is_running(http_req)) {
454 pj_time_val delay = {0, 50};
455 pj_ioqueue_poll(ioqueue, &delay);
456 pj_timer_heap_poll(timer_heap, NULL);
457 }
458
459 if (pj_http_req_start(http_req))
460 return -37;
461
462 while (pj_http_req_is_running(http_req)) {
463 pj_time_val delay = {0, 50};
464 pj_ioqueue_poll(ioqueue, &delay);
465 pj_timer_heap_poll(timer_heap, NULL);
466 }
467
468#ifdef USE_LOCAL_SERVER
469 thread_quit = PJ_TRUE;
Benny Prijonod62947c2010-08-06 08:40:55 +0000470 pj_thread_join(g_server.thread);
Sauw Mingd8435e62010-02-04 18:29:16 +0000471 pj_sock_close(g_server.sock);
472#endif
473
474 pj_http_req_destroy(http_req);
475 pj_ioqueue_destroy(ioqueue);
476 pj_timer_heap_destroy(timer_heap);
477 pj_pool_release(pool);
478
479 return PJ_SUCCESS;
480}
481
482/*
483 * GET request scenario 2: using on_complete() to get the
484 * complete data. Server does not reply with content-length.
485 * Request timed out, application sets a longer timeout, then
486 * then restart the request.
487 */
488int http_client_test2()
489{
490 pj_str_t url;
491 pj_http_req_callback hcb;
492 pj_http_req_param param;
493 pj_time_val timeout;
Benny Prijono2ee684b2010-04-27 08:31:08 +0000494 char urlbuf[80];
Sauw Mingd8435e62010-02-04 18:29:16 +0000495
496 pj_bzero(&hcb, sizeof(hcb));
497 hcb.on_complete = &on_complete;
498 hcb.on_response = &on_response;
499 pj_http_req_param_default(&param);
500
501 /* Create pool, timer, and ioqueue */
502 pool = pj_pool_create(mem, NULL, 8192, 4096, NULL);
503 if (pj_timer_heap_create(pool, 16, &timer_heap))
504 return -41;
505 if (pj_ioqueue_create(pool, 16, &ioqueue))
506 return -42;
507
508#ifdef USE_LOCAL_SERVER
509
510 pj_cstr(&url, "http://127.0.0.1:380");
511 param.timeout.sec = 0;
512 param.timeout.msec = 2000;
513
514 thread_quit = PJ_FALSE;
515 g_server.action = ACTION_IGNORE;
516 g_server.send_content_length = PJ_FALSE;
517 g_server.data_size = 4173;
Sauw Mingd8435e62010-02-04 18:29:16 +0000518 g_server.buf_size = 1024;
519
520 sstatus = pj_sock_socket(pj_AF_INET(), pj_SOCK_STREAM(), 0,
521 &g_server.sock);
522 if (sstatus != PJ_SUCCESS)
523 return -41;
524
Benny Prijono2ee684b2010-04-27 08:31:08 +0000525 pj_sockaddr_in_init(&addr, NULL, 0);
Sauw Mingd8435e62010-02-04 18:29:16 +0000526
527 sstatus = pj_sock_bind(g_server.sock, &addr, sizeof(addr));
528 if (sstatus != PJ_SUCCESS)
529 return -43;
530
Benny Prijono2ee684b2010-04-27 08:31:08 +0000531 {
532 pj_sockaddr_in addr;
533 int addr_len = sizeof(addr);
534 sstatus = pj_sock_getsockname(g_server.sock, &addr, &addr_len);
535 if (sstatus != PJ_SUCCESS)
536 return -44;
537 g_server.port = pj_sockaddr_in_get_port(&addr);
538 pj_ansi_snprintf(urlbuf, sizeof(urlbuf),
539 "http://127.0.0.1:%d",
540 g_server.port);
541 url = pj_str(urlbuf);
542 }
543
Sauw Mingd8435e62010-02-04 18:29:16 +0000544 sstatus = pj_sock_listen(g_server.sock, 8);
545 if (sstatus != PJ_SUCCESS)
546 return -45;
547
548 sstatus = pj_thread_create(pool, NULL, &server_thread, &g_server,
549 0, 0, &g_server.thread);
550 if (sstatus != PJ_SUCCESS)
551 return -47;
552
553#else
554 pj_cstr(&url, "http://www.google.com.sg");
555 param.timeout.sec = 0;
556 param.timeout.msec = 50;
557#endif
558
Benny Prijono990f6e92010-02-10 10:45:07 +0000559 pj_http_headers_add_elmt2(&param.headers, (char*)"Accept",
560 (char*)"image/gif, image/x-xbitmap, image/jpeg, "
561 "image/pjpeg, application/x-ms-application,"
562 " application/vnd.ms-xpsdocument, "
563 "application/xaml+xml, "
564 "application/x-ms-xbap, "
565 "application/x-shockwave-flash, "
566 "application/vnd.ms-excel, "
567 "application/vnd.ms-powerpoint, "
568 "application/msword, */*");
569 pj_http_headers_add_elmt2(&param.headers, (char*)"Accept-Language",
570 (char*)"en-sg");
571 pj_http_headers_add_elmt2(&param.headers, (char*)"User-Agent",
572 (char*)"Mozilla/4.0 (compatible; MSIE 7.0; "
573 "Windows NT 6.0; SLCC1; "
574 ".NET CLR 2.0.50727; "
575 ".NET CLR 3.0.04506)");
Sauw Mingd8435e62010-02-04 18:29:16 +0000576 if (pj_http_req_create(pool, &url, timer_heap, ioqueue,
577 &param, &hcb, &http_req))
578 return -43;
579
580 if (pj_http_req_start(http_req))
581 return -45;
582
583 while (pj_http_req_is_running(http_req)) {
584 pj_time_val delay = {0, 50};
585 pj_ioqueue_poll(ioqueue, &delay);
586 pj_timer_heap_poll(timer_heap, NULL);
587 }
588
589#ifdef USE_LOCAL_SERVER
590 g_server.action = ACTION_REPLY;
591#endif
592
593 timeout.sec = 0; timeout.msec = 10000;
594 pj_http_req_set_timeout(http_req, &timeout);
595 if (pj_http_req_start(http_req))
596 return -47;
597
598 while (pj_http_req_is_running(http_req)) {
599 pj_time_val delay = {0, 50};
600 pj_ioqueue_poll(ioqueue, &delay);
601 pj_timer_heap_poll(timer_heap, NULL);
602 }
603
604#ifdef USE_LOCAL_SERVER
605 thread_quit = PJ_TRUE;
Benny Prijonod62947c2010-08-06 08:40:55 +0000606 pj_thread_join(g_server.thread);
Sauw Mingd8435e62010-02-04 18:29:16 +0000607 pj_sock_close(g_server.sock);
608#endif
609
610 pj_http_req_destroy(http_req);
611 pj_ioqueue_destroy(ioqueue);
612 pj_timer_heap_destroy(timer_heap);
613 pj_pool_release(pool);
614
615 return PJ_SUCCESS;
616}
617
618/*
619 * PUT request scenario 1: sending the whole data at once
620 */
621int http_client_test_put1()
622{
623 pj_str_t url;
624 pj_http_req_callback hcb;
625 pj_http_req_param param;
626 char *data;
627 int length = 3875;
Benny Prijono2ee684b2010-04-27 08:31:08 +0000628 char urlbuf[80];
Sauw Mingd8435e62010-02-04 18:29:16 +0000629
630 pj_bzero(&hcb, sizeof(hcb));
631 hcb.on_complete = &on_complete;
632 hcb.on_data_read = &on_data_read;
633 hcb.on_response = &on_response;
634
635 /* Create pool, timer, and ioqueue */
636 pool = pj_pool_create(mem, NULL, 8192, 4096, NULL);
637 if (pj_timer_heap_create(pool, 16, &timer_heap))
638 return -51;
639 if (pj_ioqueue_create(pool, 16, &ioqueue))
640 return -52;
641
642#ifdef USE_LOCAL_SERVER
Sauw Mingd8435e62010-02-04 18:29:16 +0000643 thread_quit = PJ_FALSE;
644 g_server.action = ACTION_REPLY;
645 g_server.send_content_length = PJ_TRUE;
646 g_server.data_size = 0;
Sauw Mingd8435e62010-02-04 18:29:16 +0000647 g_server.buf_size = 4096;
648
649 sstatus = pj_sock_socket(pj_AF_INET(), pj_SOCK_STREAM(), 0,
650 &g_server.sock);
651 if (sstatus != PJ_SUCCESS)
652 return -41;
653
Benny Prijono2ee684b2010-04-27 08:31:08 +0000654 pj_sockaddr_in_init(&addr, NULL, 0);
Sauw Mingd8435e62010-02-04 18:29:16 +0000655
656 sstatus = pj_sock_bind(g_server.sock, &addr, sizeof(addr));
657 if (sstatus != PJ_SUCCESS)
658 return -43;
659
Benny Prijono2ee684b2010-04-27 08:31:08 +0000660 {
661 pj_sockaddr_in addr;
662 int addr_len = sizeof(addr);
663 sstatus = pj_sock_getsockname(g_server.sock, &addr, &addr_len);
664 if (sstatus != PJ_SUCCESS)
665 return -44;
666 g_server.port = pj_sockaddr_in_get_port(&addr);
667 pj_ansi_snprintf(urlbuf, sizeof(urlbuf),
668 "http://127.0.0.1:%d/test/test.txt",
669 g_server.port);
670 url = pj_str(urlbuf);
671 }
672
Sauw Mingd8435e62010-02-04 18:29:16 +0000673 sstatus = pj_sock_listen(g_server.sock, 8);
674 if (sstatus != PJ_SUCCESS)
675 return -45;
676
677 sstatus = pj_thread_create(pool, NULL, &server_thread, &g_server,
678 0, 0, &g_server.thread);
679 if (sstatus != PJ_SUCCESS)
680 return -47;
681
682#else
683 pj_cstr(&url, "http://127.0.0.1:280/test/test.txt");
684
685#endif
686
687 pj_http_req_param_default(&param);
Benny Prijono990f6e92010-02-10 10:45:07 +0000688 pj_strset2(&param.method, (char*)"PUT");
689 data = (char*)pj_pool_alloc(pool, length);
Sauw Mingd8435e62010-02-04 18:29:16 +0000690 pj_create_random_string(data, length);
691 pj_ansi_sprintf(data, "PUT test\n");
692 param.reqdata.data = data;
693 param.reqdata.size = length;
694 if (pj_http_req_create(pool, &url, timer_heap, ioqueue,
695 &param, &hcb, &http_req))
696 return -53;
697
698 if (pj_http_req_start(http_req))
699 return -55;
700
701 while (pj_http_req_is_running(http_req)) {
702 pj_time_val delay = {0, 50};
703 pj_ioqueue_poll(ioqueue, &delay);
704 pj_timer_heap_poll(timer_heap, NULL);
705 }
706
707#ifdef USE_LOCAL_SERVER
708 thread_quit = PJ_TRUE;
Benny Prijonod62947c2010-08-06 08:40:55 +0000709 pj_thread_join(g_server.thread);
Sauw Mingd8435e62010-02-04 18:29:16 +0000710 pj_sock_close(g_server.sock);
711#endif
712
713 pj_http_req_destroy(http_req);
714 pj_ioqueue_destroy(ioqueue);
715 pj_timer_heap_destroy(timer_heap);
716 pj_pool_release(pool);
717
718 return PJ_SUCCESS;
719}
720
721/*
722 * PUT request scenario 2: using on_send_data() callback to
723 * sending the data in chunks
724 */
725int http_client_test_put2()
726{
727 pj_str_t url;
728 pj_http_req_callback hcb;
729 pj_http_req_param param;
Benny Prijono2ee684b2010-04-27 08:31:08 +0000730 char urlbuf[80];
Sauw Mingd8435e62010-02-04 18:29:16 +0000731
732 pj_bzero(&hcb, sizeof(hcb));
733 hcb.on_complete = &on_complete;
734 hcb.on_send_data = &on_send_data;
735 hcb.on_data_read = &on_data_read;
736 hcb.on_response = &on_response;
737
738 /* Create pool, timer, and ioqueue */
739 pool = pj_pool_create(mem, NULL, 8192, 4096, NULL);
740 if (pj_timer_heap_create(pool, 16, &timer_heap))
741 return -51;
742 if (pj_ioqueue_create(pool, 16, &ioqueue))
743 return -52;
744
745#ifdef USE_LOCAL_SERVER
Sauw Mingd8435e62010-02-04 18:29:16 +0000746 thread_quit = PJ_FALSE;
747 g_server.action = ACTION_REPLY;
748 g_server.send_content_length = PJ_TRUE;
749 g_server.data_size = 0;
Sauw Mingd8435e62010-02-04 18:29:16 +0000750 g_server.buf_size = 16384;
751
752 sstatus = pj_sock_socket(pj_AF_INET(), pj_SOCK_STREAM(), 0,
753 &g_server.sock);
754 if (sstatus != PJ_SUCCESS)
755 return -41;
756
Benny Prijono2ee684b2010-04-27 08:31:08 +0000757 pj_sockaddr_in_init(&addr, NULL, 0);
Sauw Mingd8435e62010-02-04 18:29:16 +0000758
759 sstatus = pj_sock_bind(g_server.sock, &addr, sizeof(addr));
760 if (sstatus != PJ_SUCCESS)
761 return -43;
762
Benny Prijono2ee684b2010-04-27 08:31:08 +0000763 {
764 pj_sockaddr_in addr;
765 int addr_len = sizeof(addr);
766 sstatus = pj_sock_getsockname(g_server.sock, &addr, &addr_len);
767 if (sstatus != PJ_SUCCESS)
768 return -44;
769 g_server.port = pj_sockaddr_in_get_port(&addr);
770 pj_ansi_snprintf(urlbuf, sizeof(urlbuf),
771 "http://127.0.0.1:%d/test/test2.txt",
772 g_server.port);
773 url = pj_str(urlbuf);
774 }
775
Sauw Mingd8435e62010-02-04 18:29:16 +0000776 sstatus = pj_sock_listen(g_server.sock, 8);
777 if (sstatus != PJ_SUCCESS)
778 return -45;
779
780 sstatus = pj_thread_create(pool, NULL, &server_thread, &g_server,
781 0, 0, &g_server.thread);
782 if (sstatus != PJ_SUCCESS)
783 return -47;
784
785#else
786 pj_cstr(&url, "http://127.0.0.1:280/test/test2.txt");
787
788#endif
789
790 pj_http_req_param_default(&param);
Benny Prijono990f6e92010-02-10 10:45:07 +0000791 pj_strset2(&param.method, (char*)"PUT");
Sauw Mingd8435e62010-02-04 18:29:16 +0000792 total_size = 15383;
793 send_size = 0;
794 param.reqdata.total_size = total_size;
795 if (pj_http_req_create(pool, &url, timer_heap, ioqueue,
796 &param, &hcb, &http_req))
797 return -53;
798
799 if (pj_http_req_start(http_req))
800 return -55;
801
802 while (pj_http_req_is_running(http_req)) {
803 pj_time_val delay = {0, 50};
804 pj_ioqueue_poll(ioqueue, &delay);
805 pj_timer_heap_poll(timer_heap, NULL);
806 }
807
808#ifdef USE_LOCAL_SERVER
809 thread_quit = PJ_TRUE;
Benny Prijonod62947c2010-08-06 08:40:55 +0000810 pj_thread_join(g_server.thread);
Sauw Mingd8435e62010-02-04 18:29:16 +0000811 pj_sock_close(g_server.sock);
812#endif
813
814 pj_http_req_destroy(http_req);
815 pj_ioqueue_destroy(ioqueue);
816 pj_timer_heap_destroy(timer_heap);
817 pj_pool_release(pool);
818
819 return PJ_SUCCESS;
820}
821
822int http_client_test_delete()
823{
824 pj_str_t url;
825 pj_http_req_callback hcb;
826 pj_http_req_param param;
Benny Prijono2ee684b2010-04-27 08:31:08 +0000827 char urlbuf[80];
Sauw Mingd8435e62010-02-04 18:29:16 +0000828
829 pj_bzero(&hcb, sizeof(hcb));
830 hcb.on_complete = &on_complete;
831 hcb.on_response = &on_response;
832
833 /* Create pool, timer, and ioqueue */
834 pool = pj_pool_create(mem, NULL, 8192, 4096, NULL);
835 if (pj_timer_heap_create(pool, 16, &timer_heap))
836 return -61;
837 if (pj_ioqueue_create(pool, 16, &ioqueue))
838 return -62;
839
840#ifdef USE_LOCAL_SERVER
Sauw Mingd8435e62010-02-04 18:29:16 +0000841 thread_quit = PJ_FALSE;
842 g_server.action = ACTION_REPLY;
843 g_server.send_content_length = PJ_TRUE;
844 g_server.data_size = 0;
Sauw Mingd8435e62010-02-04 18:29:16 +0000845 g_server.buf_size = 1024;
846
847 sstatus = pj_sock_socket(pj_AF_INET(), pj_SOCK_STREAM(), 0,
848 &g_server.sock);
849 if (sstatus != PJ_SUCCESS)
850 return -41;
851
Benny Prijono2ee684b2010-04-27 08:31:08 +0000852 pj_sockaddr_in_init(&addr, NULL, 0);
Sauw Mingd8435e62010-02-04 18:29:16 +0000853
854 sstatus = pj_sock_bind(g_server.sock, &addr, sizeof(addr));
855 if (sstatus != PJ_SUCCESS)
856 return -43;
857
Benny Prijono2ee684b2010-04-27 08:31:08 +0000858 {
859 pj_sockaddr_in addr;
860 int addr_len = sizeof(addr);
861 sstatus = pj_sock_getsockname(g_server.sock, &addr, &addr_len);
862 if (sstatus != PJ_SUCCESS)
863 return -44;
864 g_server.port = pj_sockaddr_in_get_port(&addr);
865 pj_ansi_snprintf(urlbuf, sizeof(urlbuf),
866 "http://127.0.0.1:%d/test/test2.txt",
867 g_server.port);
868 url = pj_str(urlbuf);
869 }
870
Sauw Mingd8435e62010-02-04 18:29:16 +0000871 sstatus = pj_sock_listen(g_server.sock, 8);
872 if (sstatus != PJ_SUCCESS)
873 return -45;
874
875 sstatus = pj_thread_create(pool, NULL, &server_thread, &g_server,
876 0, 0, &g_server.thread);
877 if (sstatus != PJ_SUCCESS)
878 return -47;
879
880#else
881 pj_cstr(&url, "http://127.0.0.1:280/test/test2.txt");
882#endif
883
884 pj_http_req_param_default(&param);
Benny Prijono990f6e92010-02-10 10:45:07 +0000885 pj_strset2(&param.method, (char*)"DELETE");
Sauw Mingd8435e62010-02-04 18:29:16 +0000886 if (pj_http_req_create(pool, &url, timer_heap, ioqueue,
887 &param, &hcb, &http_req))
888 return -63;
889
890 if (pj_http_req_start(http_req))
891 return -65;
892
893 while (pj_http_req_is_running(http_req)) {
894 pj_time_val delay = {0, 50};
895 pj_ioqueue_poll(ioqueue, &delay);
896 pj_timer_heap_poll(timer_heap, NULL);
897 }
898
899#ifdef USE_LOCAL_SERVER
900 thread_quit = PJ_TRUE;
Benny Prijonod62947c2010-08-06 08:40:55 +0000901 pj_thread_join(g_server.thread);
Sauw Mingd8435e62010-02-04 18:29:16 +0000902 pj_sock_close(g_server.sock);
903#endif
904
905 pj_http_req_destroy(http_req);
906 pj_ioqueue_destroy(ioqueue);
907 pj_timer_heap_destroy(timer_heap);
908 pj_pool_release(pool);
909
910 return PJ_SUCCESS;
911}
912
913int http_client_test()
914{
915 int rc;
916
917 PJ_LOG(3, (THIS_FILE, "..Testing URL parsing"));
918 rc = parse_url_test();
919 if (rc)
920 return rc;
921
922 PJ_LOG(3, (THIS_FILE, "..Testing GET request scenario 1"));
923 rc = http_client_test1();
924 if (rc)
925 return rc;
926
927 PJ_LOG(3, (THIS_FILE, "..Testing GET request scenario 2"));
928 rc = http_client_test2();
929 if (rc)
930 return rc;
931
932 PJ_LOG(3, (THIS_FILE, "..Testing PUT request scenario 1"));
933 rc = http_client_test_put1();
934 if (rc)
935 return rc;
936
937 PJ_LOG(3, (THIS_FILE, "..Testing PUT request scenario 2"));
938 rc = http_client_test_put2();
939 if (rc)
940 return rc;
941
942 PJ_LOG(3, (THIS_FILE, "..Testing DELETE request"));
943 rc = http_client_test_delete();
944 if (rc)
945 return rc;
946
947 return PJ_SUCCESS;
948}
949
950#else
951/* To prevent warning about "translation unit is empty"
952 * when this test is disabled.
953 */
954int dummy_http_client_test;
955#endif /* INCLUDE_HTTP_CLIENT_TEST */