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