1 /*
2 * This file is part of the Sofia-SIP package
3 *
4 * Copyright (C) 2005 Nokia Corporation.
5 *
6 * Contact: Pekka Pessi <pekka.pessi@nokia.com>
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public License
10 * as published by the Free Software Foundation; either version 2.1 of
11 * the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
21 * 02110-1301 USA
22 *
23 */
24
25 /**@file test_nth.c
26 * @brief Tests for nth module
27 *
28 * @author Pekka Pessi <Pekka.Pessi@nokia.com>
29 *
30 * @date Created: Tue Oct 22 20:52:37 2002 ppessi
31 */
32
33 #include "config.h"
34
35 #include <stddef.h>
36 #include <stdlib.h>
37 #include <string.h>
38 #include <stdio.h>
39
40 #include <assert.h>
41
42 #if HAVE_ALARM
43 #include <unistd.h>
44 #include <signal.h>
45 #endif
46
47 typedef struct tester tester_t;
48 typedef struct site site_t;
49 typedef struct client client_t;
50
51 #define SU_ROOT_MAGIC_T tester_t
52
53 #include <sofia-sip/su_tagarg.h>
54 #include <sofia-sip/su_wait.h>
55
56 #define NTH_CLIENT_MAGIC_T client_t
57 #define NTH_SITE_MAGIC_T site_t
58
59 #include "sofia-sip/nth.h"
60 #include <sofia-sip/http_header.h>
61 #include <sofia-sip/msg_mclass.h>
62 #include <sofia-sip/tport_tag.h>
63 #include <sofia-sip/auth_module.h>
64
65 int tstflags = 0;
66
67 #define TSTFLAGS tstflags
68
69 #include <sofia-sip/tstdef.h>
70
71 #if HAVE_FUNC
72 #elif HAVE_FUNCTION
73 #define __func__ __FUNCTION__
74 #else
75 #define __func__ name
76 #endif
77
78 char const name[] = "test_nth";
79
80 static int init_test(tester_t *t);
81 static int deinit_test(tester_t *t);
82 static int test_nth_client_api(tester_t *t);
83 static int test_nth_server_api(tester_t *t);
84 static int init_server(tester_t *t);
85 static int test_requests(tester_t *t);
86 static int init_engine(tester_t *t);
87
88 struct site
89 {
90 site_t *s_next, *s_parent;
91 tester_t *s_tester;
92 url_string_t *s_url;
93 nth_site_t *s_ns;
94 int s_called;
95 int s_status;
96 char const *s_phrase;
97 tagi_t *s_tags;
98 };
99
100 struct client
101 {
102 unsigned c_status;
103 };
104
105 struct tester
106 {
107 su_home_t t_home[1];
108 su_root_t *t_root;
109 msg_mclass_t *t_mclass;
110 url_string_t *t_proxy;
111 nth_engine_t *t_engine;
112
113 char const *t_srcdir;
114 char const *t_pem;
115
116 su_sockaddr_t t_addr[1];
117 socklen_t t_addrlen;
118
119 su_socket_t t_sink;
120 url_string_t *t_sinkuri;
121 su_sockaddr_t t_sinkaddr[1];
122 socklen_t t_sinkaddrlen;
123
124 site_t *t_sites;
125 site_t *t_master;
126 };
127
128 static int test_site(site_t *t,
129 nth_site_t *server,
130 nth_request_t *req,
131 http_t const *http,
132 char const *path);
133
site_create(tester_t * t,site_t * parent,char const * url,int status,char const * phrase,tag_type_t tag,tag_value_t value,...)134 static site_t *site_create(tester_t *t, site_t *parent,
135 char const *url,
136 int status, char const *phrase,
137 tag_type_t tag, tag_value_t value, ...)
138 {
139 nth_site_t *pns = parent ? parent->s_ns : NULL;
140 site_t *s;
141 ta_list ta;
142
143 if (url == NULL)
144 return NULL;
145
146 s = su_zalloc(t->t_home, sizeof *s);
147 if (s == NULL)
148 return NULL;
149
150 s->s_url = URL_STRING_MAKE(url);
151 s->s_tester = t;
152 s->s_next = t->t_sites;
153 s->s_status = status;
154 s->s_phrase = phrase;
155
156 ta_start(ta, tag, value);
157
158 s->s_tags = tl_adup(t->t_home, ta_args(ta));
159 if (s->s_tags)
160 s->s_ns = nth_site_create(pns, test_site, s,
161 (url_string_t *)s->s_url,
162 NTHTAG_ROOT(t->t_root),
163 ta_tags(ta));
164
165 ta_end(ta);
166
167 if (s->s_ns == NULL)
168 return NULL;
169
170 t->t_sites = s;
171
172 return s;
173 }
174
init_test(tester_t * t)175 static int init_test(tester_t *t)
176 {
177 su_socket_t s;
178
179 BEGIN();
180
181 t->t_root = su_root_create(t); TEST_1(t->t_root);
182 t->t_mclass = msg_mclass_clone(http_default_mclass(), 0, 0);
183 TEST_1(t->t_mclass);
184
185 t->t_addr->su_len = (sizeof t->t_addr->su_sin);
186 s = su_socket(t->t_addr->su_family = AF_INET, SOCK_STREAM, 0);
187 TEST_1(s != INVALID_SOCKET);
188 TEST_1(su_inet_pton(AF_INET, "127.0.0.1", &t->t_addr->su_sin.sin_addr) >= 0);
189 TEST_1(bind(s, &t->t_addr->su_sa,
190 t->t_addrlen = (sizeof t->t_addr->su_sin)) != -1);
191 TEST_1(getsockname(s, &t->t_addr->su_sa, &t->t_addrlen) != -1);
192 TEST_1(t->t_addr->su_port != 0);
193 TEST_1(su_close(s) != -1);
194
195 t->t_pem = su_sprintf(t->t_home, "%s/agent.pem", t->t_srcdir);
196
197 END();
198 }
199
deinit_test(tester_t * t)200 static int deinit_test(tester_t *t)
201 {
202 site_t *s, *s_next;
203
204 BEGIN();
205
206 nth_engine_destroy(t->t_engine);
207
208 for (s = t->t_sites; s; s = s_next) {
209 s_next = s->s_next;
210 nth_site_destroy(s->s_ns), s->s_ns = NULL;
211 su_free(t->t_home, s);
212 }
213
214 su_root_destroy(t->t_root);
215
216 su_home_deinit(t->t_home);
217
218 memset(t, 0, sizeof t);
219
220 END();
221 }
222
223
test_nth_client_api(tester_t * t)224 static int test_nth_client_api(tester_t *t)
225 {
226 char const *s;
227
228 BEGIN();
229
230 s = nth_engine_version();
231 TEST_1(s); TEST_1(strlen(s)); TEST_S(s, "sofia-http-client/" NTH_CLIENT_VERSION);
232
233 TEST_1(nth_engine_create(NULL, TAG_END()) == NULL);
234 TEST(errno, EINVAL);
235 TEST_VOID(nth_engine_destroy(NULL));
236 TEST_1(nth_engine_get_params(NULL, TAG_END()) == -1);
237 TEST_1(nth_engine_set_params(NULL, TAG_END()) == -1);
238 TEST_1(!nth_client_tcreate(NULL, NULL, NULL,
239 HTTP_METHOD_OPTIONS,
240 URL_STRING_MAKE("*"),
241 TAG_END()));
242 TEST(nth_client_status(NULL), 400);
243 TEST(nth_client_method(NULL), http_method_invalid);
244 TEST(nth_client_is_streaming(NULL), 0);
245 TEST_P(nth_client_url(NULL), NULL);
246 TEST_P(nth_client_request(NULL), NULL);
247 TEST_P(nth_client_response(NULL), NULL);
248 TEST_VOID(nth_client_destroy(NULL));
249
250 t->t_engine = nth_engine_create(t->t_root,
251 NTHTAG_ERROR_MSG(2),
252 NTHTAG_MCLASS(t->t_mclass),
253 NTHTAG_MFLAGS(MSG_DO_CANONIC|MSG_DO_COMPACT),
254 NTHTAG_STREAMING(0),
255 NTHTAG_PROXY("http://localhost:8888"),
256 TAG_END());
257 TEST_1(t->t_engine);
258
259 {
260 int error_msg = -1;
261 msg_mclass_t const *mclass = (void *)-1;
262 int mflags = -1;
263 unsigned expires = -1;
264 int streaming = -1;
265 url_string_t const *proxy = (void *)-1;
266
267 char *proxy_str;
268
269 TEST(nth_engine_get_params(t->t_engine,
270 NTHTAG_ERROR_MSG_REF(error_msg),
271 NTHTAG_MCLASS_REF(mclass),
272 NTHTAG_MFLAGS_REF(mflags),
273 NTHTAG_EXPIRES_REF(expires),
274 NTHTAG_STREAMING_REF(streaming),
275 NTHTAG_PROXY_REF(proxy),
276 TAG_END()),
277 6);
278
279 TEST(error_msg, 1);
280 TEST_P(mclass, t->t_mclass);
281 TEST(mflags, MSG_DO_CANONIC|MSG_DO_COMPACT);
282 TEST(expires, 32000);
283 TEST(streaming, 0);
284 TEST_1(proxy != NULL);
285 TEST_1(proxy_str = url_as_string(t->t_home, proxy->us_url));
286 TEST_S(proxy_str, "http://localhost:8888");
287
288 proxy = URL_STRING_MAKE("http://127.0.0.1:80");
289
290 TEST(nth_engine_set_params(t->t_engine,
291 NTHTAG_ERROR_MSG(0),
292 NTHTAG_MCLASS(http_default_mclass()),
293 NTHTAG_MFLAGS(0),
294 NTHTAG_EXPIRES(10000),
295 NTHTAG_STREAMING(2),
296 NTHTAG_PROXY(proxy),
297 TAG_END()),
298 6);
299
300 error_msg = -1;
301 mclass = (void *)-1;
302 mflags = -1;
303 expires = (unsigned)-1;
304 streaming = -1;
305 proxy = (void *)-1;
306
307 TEST(nth_engine_get_params(t->t_engine,
308 NTHTAG_ERROR_MSG_REF(error_msg),
309 NTHTAG_MCLASS_REF(mclass),
310 NTHTAG_MFLAGS_REF(mflags),
311 NTHTAG_EXPIRES_REF(expires),
312 NTHTAG_STREAMING_REF(streaming),
313 NTHTAG_PROXY_REF(proxy),
314 TAG_END()),
315 6);
316
317 TEST(error_msg, 0);
318 TEST_P(mclass, NULL);
319 TEST(mflags, 0);
320 TEST(expires, 10000);
321 TEST(streaming, 1);
322 TEST_1(proxy != NULL);
323 TEST_1(proxy_str = url_as_string(t->t_home, proxy->us_url));
324 TEST_S(proxy_str, "http://127.0.0.1:80");
325 }
326
327 TEST_1(nth_engine_get_stats(NULL, TAG_END()) == -1);
328
329 {
330 msg_t *msg;
331 http_t *http;
332
333 TEST_1(nth_engine_msg_create(NULL, -1) == NULL);
334 TEST_1(msg = nth_engine_msg_create(t->t_engine, -1));
335 TEST_1(http = http_object(msg));
336 TEST(http->http_flags, MSG_FLG_USERMASK);
337 msg_destroy(msg);
338
339 /* Use mflags set by set_params (+ streaming flag) */
340 TEST_1(msg = nth_engine_msg_create(t->t_engine, 0));
341 TEST_1(http = http_object(msg));
342 TEST(http->http_flags, MSG_FLG_STREAMING | t->t_mclass->mc_flags);
343 msg_destroy(msg);
344 }
345
346 TEST_VOID(nth_engine_destroy(t->t_engine));
347 t->t_engine = NULL;
348
349 END();
350 }
351
352 static int site_check_all(site_t *t,
353 nth_site_t *server,
354 nth_request_t *req,
355 http_t const *http,
356 char const *path);
357
test_nth_server_api(tester_t * t)358 static int test_nth_server_api(tester_t *t)
359
360 {
361 char const *v;
362 site_t s[1];
363
364 BEGIN();
365
366 memset(s, 0, sizeof s);
367
368 v = nth_site_server_version();
369 TEST_1(v); TEST_1(strlen(v)); TEST_S(v, "nth/" NTH_SERVER_VERSION);
370
371 /* Fails because no parent site, no root */
372 TEST_1(!nth_site_create(NULL, test_site, s,
373 URL_STRING_MAKE("http://127.0.0.1:8888"),
374 TAG_END()));
375
376 /* Fails because url specifies both host and path */
377 TEST_1(!nth_site_create(NULL, site_check_all, s,
378 URL_STRING_MAKE("http://127.0.0.1:8888/foo/"),
379 NTHTAG_ROOT(t->t_root), TAG_END()));
380
381 TEST_VOID(nth_site_destroy(NULL));
382 TEST_P(nth_site_magic(NULL), NULL);
383 TEST_VOID(nth_site_bind(NULL, test_site, s));
384 TEST_1(nth_site_set_params(NULL, TAG_END()) == -1);
385 TEST_1(nth_site_get_params(NULL, TAG_END()) == -1);
386 TEST_1(nth_site_get_stats(NULL, TAG_END()) == -1);
387 TEST(nth_request_status(NULL), 400);
388 TEST(nth_request_method(NULL), http_method_invalid);
389 TEST_P(nth_request_message(NULL), NULL);
390 TEST_1(nth_request_treply(NULL, HTTP_200_OK, TAG_END()) == -1);
391 TEST_VOID(nth_request_destroy(NULL));
392
393 END();
394 }
395
test_site(site_t * s,nth_site_t * ns,nth_request_t * req,http_t const * http,char const * path)396 static int test_site(site_t *s,
397 nth_site_t *ns,
398 nth_request_t *req,
399 http_t const *http,
400 char const *path)
401 {
402 if (s == NULL || ns == NULL || req == NULL)
403 return 500;
404
405 TEST_1(nth_request_treply(req, s->s_status, s->s_phrase,
406 TAG_NEXT(s->s_tags)) != -1);
407
408 TEST_VOID(nth_request_destroy(req));
409
410 return s->s_status;
411 }
412
413
site_check_all(site_t * s,nth_site_t * ns,nth_request_t * req,http_t const * http,char const * path)414 static int site_check_all(site_t *s,
415 nth_site_t *ns,
416 nth_request_t *req,
417 http_t const *http,
418 char const *path)
419 {
420 msg_t *msg;
421 auth_status_t *as;
422
423 TEST_1(s); TEST_1(ns); TEST_1(req); TEST_1(http); TEST_1(path);
424
425 if (s == NULL || ns == NULL || req == NULL)
426 return 500;
427
428 TEST(nth_request_status(req), 0);
429 TEST(nth_request_method(req), http_method_get);
430 TEST_1(msg = nth_request_message(req));
431
432 msg_destroy(msg);
433
434 as = nth_request_auth(req);
435
436 TEST_1(nth_request_treply(req, s->s_status, s->s_phrase,
437 TAG_NEXT(s->s_tags)) != -1);
438
439 TEST_VOID(nth_request_destroy(req));
440
441 return s->s_status;
442 }
443
444 static char passwd_name[] = "tmp_sippasswd.XXXXXX";
445
remove_tmp(void)446 static void remove_tmp(void)
447 {
448 if (passwd_name[0])
449 unlink(passwd_name);
450 }
451
452 static char const passwd[] =
453 "alice:secret:\n"
454 "bob:secret:\n"
455 "charlie:secret:\n";
456
init_server(tester_t * t)457 static int init_server(tester_t *t)
458 {
459 BEGIN();
460
461 site_t *m = t->t_master, *sub2;
462 auth_mod_t *am;
463 int temp;
464
465 TEST_1(t->t_master = m =
466 site_create(t, NULL,
467 su_sprintf(t->t_home, "HTTP://127.0.0.1:%u",
468 htons(t->t_addr->su_port)),
469 HTTP_200_OK,
470 HTTPTAG_CONTENT_TYPE_STR("text/html"),
471 HTTPTAG_PAYLOAD_STR("<html><body>Hello</body></html>\n"),
472 TPTAG_CERTIFICATE(t->t_pem),
473 TAG_END()));
474
475 TEST_1(site_create(t, m, "/sub/sub",
476 HTTP_200_OK,
477 HTTPTAG_CONTENT_TYPE_STR("text/html"),
478 HTTPTAG_PAYLOAD_STR
479 ("<html><body>sub/sub</body></html>\n"),
480 TAG_END()));
481
482 TEST_1(site_create(t, m, "/sub/",
483 HTTP_200_OK,
484 HTTPTAG_CONTENT_TYPE_STR("text/html"),
485 HTTPTAG_PAYLOAD_STR("<html><body>sub/</body></html>\n"),
486 TAG_END()));
487
488 TEST_1(site_create(t, m, "/sub/sub/",
489 HTTP_200_OK,
490 HTTPTAG_CONTENT_TYPE_STR("text/html"),
491 HTTPTAG_PAYLOAD_STR
492 ("<html><body>sub/sub/</body></html>\n"),
493 TAG_END()));
494
495 TEST_1(sub2 =
496 site_create(t, m, "/sub2/",
497 HTTP_200_OK,
498 HTTPTAG_CONTENT_TYPE_STR("text/html"),
499 HTTPTAG_PAYLOAD_STR("<html><body>sub2/</body></html>\n"),
500 TAG_END()));
501
502 TEST_1(site_create(t, sub2, "sub/",
503 HTTP_200_OK,
504 HTTPTAG_CONTENT_TYPE_STR("text/html"),
505 HTTPTAG_PAYLOAD_STR
506 ("<html><body>sub2/sub/</body></html>\n"),
507 TAG_END()));
508
509
510 #ifndef _WIN32
511 temp = mkstemp(passwd_name);
512 #else
513 temp = open(passwd_name, O_WRONLY|O_CREAT|O_TRUNC, 666);
514 #endif
515 TEST_1(temp != -1);
516 atexit(remove_tmp); /* Make sure temp file is unlinked */
517
518 TEST_SIZE(write(temp, passwd, strlen(passwd)), strlen(passwd));
519
520 TEST_1(close(temp) == 0);
521
522 am = auth_mod_create(t->t_root,
523 AUTHTAG_METHOD("Digest"),
524 AUTHTAG_REALM("auth"),
525 AUTHTAG_DB(passwd_name),
526 TAG_END());
527 TEST_1(am);
528
529 TEST_1(site_create(t, m, "auth/",
530 HTTP_200_OK,
531 HTTPTAG_CONTENT_TYPE_STR("text/html"),
532 HTTPTAG_PAYLOAD_STR
533 ("<html><body>auth/</body></html>\n"),
534 NTHTAG_AUTH_MODULE(am),
535 TAG_END()));
536
537 auth_mod_unref(am);
538
539
540 am = auth_mod_create(t->t_root,
541 AUTHTAG_METHOD("Delayed+Basic"),
542 AUTHTAG_REALM("auth2"),
543 AUTHTAG_DB(passwd_name),
544 TAG_END());
545 TEST_1(am);
546
547 TEST_1(site_create(t, m, "auth2/",
548 HTTP_200_OK,
549 HTTPTAG_CONTENT_TYPE_STR("text/html"),
550 HTTPTAG_PAYLOAD_STR
551 ("<html><body>auth/</body></html>\n"),
552 NTHTAG_AUTH_MODULE(am),
553 TAG_END()));
554
555 auth_mod_unref(am);
556
557 END();
558 }
559
send_request(tester_t * t,char const * req,size_t reqlen,int close_socket,char reply[],int rlen,int * return_len)560 static int send_request(tester_t *t, char const *req, size_t reqlen,
561 int close_socket,
562 char reply[], int rlen,
563 int *return_len)
564 {
565 static su_socket_t c = INVALID_SOCKET;
566 int m, r;
567 su_wait_t w[1];
568
569 BEGIN();
570
571 if (c == INVALID_SOCKET) {
572 c = su_socket(t->t_addr->su_family, SOCK_STREAM, 0); TEST_1(c != SOCK_STREAM);
573 TEST_1(su_setblocking(c, 1) != -1);
574 TEST_1(connect(c, &t->t_addr->su_sa, t->t_addrlen) != -1);
575
576 while (su_root_step(t->t_root, 1) == 0);
577 }
578
579 if (reqlen == (size_t)-1)
580 reqlen = strlen(req);
581
582 TEST_SIZE(su_send(c, req, reqlen, 0), reqlen);
583
584 if (close_socket == 1)
585 shutdown(c, 1);
586
587 TEST(su_wait_create(w, c, SU_WAIT_IN), 0);
588
589 while (su_root_step(t->t_root, 1) == 0 || su_wait(w, 1, 0) < 0);
590
591 for (r = 0;;) {
592 TEST_1((m = recv(c, reply, rlen - r - 1, 0)) != -1);
593 r += m;
594 if (m == 0 || r == rlen - 1)
595 break;
596 }
597 reply[r] = '\0';
598
599 if (close_socket != -1)
600 su_close(c), c = -1;
601
602 *return_len = r;
603
604 END();
605 }
606
sspace(char const * buffer)607 int sspace(char const *buffer)
608 {
609 int m = strcspn(buffer, " ");
610
611 if (buffer[m])
612 m += 1 + strcspn(buffer + m + 1, " ");
613
614 return m;
615 }
616
617 #define CRLF "\r\n"
618
test_requests(tester_t * t)619 static int test_requests(tester_t *t)
620 {
621 char buffer[4096 + 1];
622 int m;
623
624 BEGIN();
625
626 {
627 static char const get[] =
628 "GET / HTTP/1.1" CRLF
629 "Host: 127.0.0.1" CRLF
630 "User-Agent: Test-Tool" CRLF
631 "Connection: close" CRLF
632 CRLF;
633
634 TEST(send_request(t, get, -1, 0, buffer, sizeof(buffer), &m), 0);
635
636 m = sspace(buffer); buffer[m] = '\0';
637 TEST_S(buffer, "HTTP/1.1 200");
638 }
639
640 {
641 static char const get[] =
642 "GET / HTTP/1.1" CRLF
643 "Host: 127.0.0.1" CRLF
644 "User-Agent: Test-Tool" CRLF
645 "Connection: close" CRLF
646 CRLF;
647
648 TEST(send_request(t, get, -1, 0, buffer, sizeof(buffer), &m), 0);
649
650 m = strcspn(buffer, CRLF); buffer[m] = '\0';
651 TEST_S(buffer, "HTTP/1.1 200 OK");
652 }
653
654 {
655 static char const request[] =
656 "GET %s HTTP/1.1" CRLF
657 "Host: 127.0.0.1" CRLF
658 "User-Agent: Test-Tool" CRLF
659 "Connection: close" CRLF
660 CRLF;
661 char *get;
662
663 get = su_sprintf(NULL, request, "/sub");
664 TEST(send_request(t, get, -1, 0, buffer, sizeof(buffer), &m), 0);
665 m = sspace(buffer); buffer[m++] = '\0';
666 TEST_S(buffer, "HTTP/1.1 301");
667 m += strcspn(buffer + m, CRLF) + 1;
668 free(get);
669
670 get = su_sprintf(NULL, request, "/sub/");
671 TEST(send_request(t, get, -1, 0, buffer, sizeof(buffer), &m), 0);
672 m = strcspn(buffer, CRLF); buffer[m++] = '\0';
673 TEST_S(buffer, "HTTP/1.1 200 OK");
674 TEST_1(strstr(buffer + m, "<body>sub/</body>"));
675 free(get);
676
677 get = su_sprintf(NULL, request, "/sub2/");
678 TEST(send_request(t, get, -1, 0, buffer, sizeof(buffer), &m), 0);
679 m = strcspn(buffer, CRLF); buffer[m++] = '\0';
680 TEST_S(buffer, "HTTP/1.1 200 OK");
681 TEST_1(strstr(buffer + m, "<body>sub2/</body>"));
682 free(get);
683
684 get = su_sprintf(NULL, request, "/sub2/hub");
685 TEST(send_request(t, get, -1, 0, buffer, sizeof(buffer), &m), 0);
686 m = strcspn(buffer, CRLF); buffer[m++] = '\0';
687 TEST_S(buffer, "HTTP/1.1 200 OK");
688 TEST_1(strstr(buffer + m, "<body>sub2/</body>"));
689 free(get);
690
691 /* Test that absolute path for subdir site is calculated correctly */
692 get = su_sprintf(NULL, request, "/sub2/sub");
693 TEST(send_request(t, get, -1, 0, buffer, sizeof(buffer), &m), 0);
694 m = sspace(buffer); buffer[m++] = '\0';
695 TEST_S(buffer, "HTTP/1.1 301");
696 TEST_1(strstr(buffer + m, "/sub2/sub/" CRLF));
697 free(get);
698
699 get = su_sprintf(NULL, request, "/sub2/sub/");
700 TEST(send_request(t, get, -1, 0, buffer, sizeof(buffer), &m), 0);
701 m = strcspn(buffer, CRLF); buffer[m++] = '\0';
702 TEST_S(buffer, "HTTP/1.1 200 OK");
703 TEST_1(strstr(buffer + m, "<body>sub2/sub/</body>"));
704 free(get);
705
706 get = su_sprintf(NULL, request, "/sub/sub");
707 TEST(send_request(t, get, -1, 0, buffer, sizeof(buffer), &m), 0);
708 m = strcspn(buffer, CRLF); buffer[m++] = '\0';
709 TEST_S(buffer, "HTTP/1.1 200 OK");
710 TEST_1(strstr(buffer + m, "<body>sub/sub</body>"));
711 free(get);
712
713 get = su_sprintf(NULL, request, "/auth/");
714 TEST(send_request(t, get, -1, 0, buffer, sizeof(buffer), &m), 0);
715 m = sspace(buffer); buffer[m++] = '\0';
716 TEST_S(buffer, "HTTP/1.1 401");
717 free(get);
718
719 get = su_sprintf(NULL, request, "/auth2/");
720 TEST(send_request(t, get, -1, 0, buffer, sizeof(buffer), &m), 0);
721 m = sspace(buffer); buffer[m++] = '\0';
722 TEST_S(buffer, "HTTP/1.1 401");
723 free(get);
724 }
725
726 {
727 static char const get[] =
728 "GET /auth2/ HTTP/1.1" CRLF
729 "Host: 127.0.0.1" CRLF
730 "User-Agent: Test-Tool" CRLF
731 "Connection: close" CRLF
732 /* alice:secret in base64 */
733 "Authorization: Basic YWxpY2U6c2VjcmV0" CRLF
734 CRLF;
735
736 TEST(send_request(t, get, -1, 0, buffer, sizeof(buffer), &m), 0);
737 m = sspace(buffer); buffer[m++] = '\0';
738 TEST_S(buffer, "HTTP/1.1 200");
739 }
740
741 {
742 static char const kuik[] =
743 "kuik" CRLF CRLF;
744
745 TEST(send_request(t, kuik, -1, 0, buffer, sizeof(buffer), &m), 0);
746 m = sspace(buffer); buffer[m] = '\0';
747 TEST_S(buffer, "HTTP/1.1 400");
748 }
749
750 {
751 static char const kuik[] =
752 "POST / HTTP/1.1" CRLF
753 "Host: 127.0.0.1" CRLF
754 "Content-Length: 4294967296" CRLF
755 CRLF;
756
757 TEST(send_request(t, kuik, -1, 1, buffer, sizeof(buffer), &m), 0);
758 m = sspace(buffer); buffer[m] = '\0';
759 TEST_S(buffer, "HTTP/1.1 400");
760 }
761
762 {
763 static char const get[] =
764 "GET / HTTP/10.10" CRLF
765 "Host: 127.0.0.1" CRLF
766 "User-Agent: Test-Tool" CRLF
767 "Connection: close" CRLF
768 CRLF;
769
770 TEST(send_request(t, get, -1, 0, buffer, sizeof(buffer), &m), 0);
771
772 m = sspace(buffer); buffer[m] = '\0';
773 TEST_S(buffer, "HTTP/1.1 505");
774 }
775
776 {
777 static char const get[] =
778 "GET /" CRLF;
779
780 TEST(send_request(t, get, -1, 1, buffer, sizeof(buffer) - 1, &m), 0);
781
782 buffer[6] = '\0';
783 TEST_S(buffer, "<html>");
784 }
785
786 if (0)
787 {
788 static char const post[] =
789 "POST /foo HTTP/1.1" CRLF
790 "Host: 127.0.0.1" CRLF
791 "User-Agent: Test-Tool" CRLF
792 "Connection: close" CRLF
793 "Content-Length: 7" CRLF
794 "Expect: 100-continue" CRLF
795 CRLF;
796 static char const body[] =
797 "<html/>";
798
799 TEST(send_request(t, post, -1, -1, buffer, sizeof(buffer) - 1, &m), 0);
800
801 m = sspace(buffer); buffer[m] = '\0';
802 TEST_S(buffer, "HTTP/1.1 100");
803
804 TEST(send_request(t, body, -1, 0, buffer, sizeof(buffer) - 1, &m), 0);
805
806 m = sspace(buffer); buffer[m] = '\0';
807 TEST_S(buffer, "HTTP/1.1 200");
808 }
809
810 END();
811 }
812
813
init_engine(tester_t * t)814 static int init_engine(tester_t *t)
815 {
816 BEGIN();
817 su_socket_t s;
818
819 t->t_engine = nth_engine_create(t->t_root,
820 NTHTAG_STREAMING(0),
821 TAG_END());
822 TEST_1(t->t_engine);
823
824 t->t_sink = s = su_socket(AF_INET, SOCK_STREAM, 0); TEST_1(s != -1);
825 TEST(bind(s, &t->t_sinkaddr->su_sa,
826 t->t_sinkaddrlen = (sizeof t->t_sinkaddr->su_sin)),
827 0);
828 TEST_1(getsockname(s, &t->t_sinkaddr->su_sa, &t->t_sinkaddrlen) != -1);
829 TEST(listen(t->t_sink, 5), 0);
830
831 TEST_1(t->t_sinkuri = (url_string_t *)
832 su_sprintf(t->t_home, "HTTP://127.0.0.1:%u",
833 htons(t->t_sinkaddr->su_port)));
834
835 END();
836 }
837
838
response_to_client(client_t * c,nth_client_t * hc,http_t const * http)839 static int response_to_client(client_t *c,
840 nth_client_t *hc,
841 http_t const *http)
842 {
843 if (http) {
844 c->c_status = http->http_status->st_status;
845 }
846 else {
847 c->c_status = nth_client_status(hc);
848 }
849
850 return 0;
851 }
852
853
test_client(tester_t * t)854 static int test_client(tester_t *t)
855 {
856 BEGIN();
857
858 nth_client_t *hc;
859 char *uri;
860 client_t client[1];
861
862 memset(client, 0, sizeof client);
863
864 TEST_1(uri = su_strcat(NULL, t->t_master->s_url->us_str, "/"));
865 TEST_1(hc = nth_client_tcreate(t->t_engine,
866 response_to_client, client,
867 HTTP_METHOD_GET,
868 URL_STRING_MAKE(uri),
869 TAG_END()));
870 while (client->c_status == 0) su_root_step(t->t_root, 1);
871 TEST(client->c_status, 200);
872 nth_client_destroy(hc);
873 su_free(NULL, uri);
874
875 memset(client, 0, sizeof client);
876
877 TEST_1(hc = nth_client_tcreate(t->t_engine,
878 response_to_client, client,
879 HTTP_METHOD_GET,
880 URL_STRING_MAKE(t->t_sinkuri),
881 NTHTAG_EXPIRES(1000),
882 TAG_END()));
883 while (client->c_status == 0) su_root_step(t->t_root, 1);
884 TEST(client->c_status, 408);
885 nth_client_destroy(hc);
886
887 END();
888 }
889 #if HAVE_ALARM
sig_alarm(int s)890 static RETSIGTYPE sig_alarm(int s)
891 {
892 fprintf(stderr, "%s: FAIL! test timeout!\n", name);
893 exit(1);
894 }
895 #endif
896
usage(int exitcode)897 void usage(int exitcode)
898 {
899 fprintf(stderr, "usage: %s [-v|-q] [-a] [-p proxy-uri]\n", name);
900 exit(exitcode);
901 }
902
main(int argc,char ** argv)903 int main(int argc, char **argv)
904 {
905 int i;
906 int retval = 0;
907 int o_alarm = 1;
908
909 tester_t t[1] = {{{ SU_HOME_INIT(t) }}};
910
911 char const *srcdir = getenv("srcdir");
912
913 if (srcdir == NULL)
914 srcdir = ".";
915
916 for (i = 1; argv[i]; i++) {
917 if (strcmp(argv[i], "-v") == 0)
918 tstflags |= tst_verbatim;
919 else if (strcmp(argv[i], "-a") == 0)
920 tstflags |= tst_abort;
921 else if (strcmp(argv[i], "-q") == 0)
922 tstflags &= ~tst_verbatim;
923 else if (strcmp(argv[i], "-p") == 0 && argv[i + 1])
924 t->t_proxy = (url_string_t *)argv[++i];
925 else if (strcmp(argv[i], "-s") == 0 && argv[i + 1])
926 srcdir = argv[++i];
927 else if (strcmp(argv[i], "--no-alarm") == 0) {
928 o_alarm = 0;
929 }
930 else if (strcmp(argv[i], "-") == 0) {
931 i++; break;
932 }
933 else if (argv[i][0] != '-') {
934 break;
935 }
936 else
937 usage(1);
938 }
939
940 t->t_srcdir = srcdir;
941
942 #if HAVE_ALARM
943 if (o_alarm) {
944 alarm(60);
945 signal(SIGALRM, sig_alarm);
946 }
947 #endif
948
949 su_init();
950
951 retval |= init_test(t);
952 retval |= test_nth_client_api(t);
953 retval |= test_nth_server_api(t);
954 retval |= init_server(t);
955 retval |= test_requests(t);
956 retval |= init_engine(t);
957 retval |= test_client(t);
958 retval |= deinit_test(t);
959
960 su_deinit();
961
962 return retval;
963 }
964