Bug Summary

File:libs/sofia-sip/libsofia-sip-ua/nth/nth_server.c
Location:line 853, column 22
Description:Access to field 'site_url' results in a dereference of a null pointer (loaded from variable 'site')

Annotated Source Code

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/**@internal @file nth_server.c
26 * @brief HTTP server.
27 *
28 * @author Pekka Pessi <Pekka.Pessi@nokia.com>
29 *
30 * @date Created: Sat Oct 19 01:37:36 2002 ppessi
31 */
32
33#include "config.h"
34
35#include <sofia-sip/su_string.h>
36#include <sofia-sip/su.h>
37
38typedef struct server_s server_t;
39
40/** @internal SU timer argument pointer type */
41#define SU_TIMER_ARG_Tserver_t server_t
42
43#include <sofia-sip/http_header.h>
44#include <sofia-sip/http_status.h>
45#include <sofia-sip/http_tag.h>
46
47#include "sofia-sip/nth.h"
48
49#include <sofia-sip/msg_date.h>
50#include <sofia-sip/msg_addr.h>
51#include <sofia-sip/su_tagarg.h>
52
53#include <sofia-sip/hostdomain.h>
54
55/* We are customer of tport_t */
56#define TP_STACK_Tserver_t server_t
57#define TP_MAGIC_Tvoid void
58
59#include <sofia-sip/tport.h>
60#include <sofia-sip/htable.h>
61
62#include <sofia-sip/auth_module.h>
63
64#include <stddef.h>
65#include <stdlib.h>
66#include <stdio.h>
67#include <stdarg.h>
68#include <errno(*__errno_location ()).h>
69#include <assert.h>
70
71#ifndef UINT32_MAX(4294967295U)
72#define UINT32_MAX(4294967295U) (0xffffffffU)
73#endif
74
75enum { SERVER_TICK = 1000 };
76
77#define SERVER_VERSION"nth/" "1.0" "nth/" NTH_VERSION"1.0"
78
79HTABLE_DECLARE(hc_htable, hct, nth_client_t)typedef struct hc_htable_s { unsigned hct_size; unsigned hct_used
; nth_client_t** hct_table; } hc_htable_t
;
80
81struct server_s
82{
83 su_home_t srv_home[1];
84 su_root_t *srv_root;
85
86 su_timer_t *srv_timer;
87 unsigned srv_now;
88
89 msg_mclass_t const*srv_mclass;
90 int srv_mflags; /**< Message flags */
91
92 tport_t *srv_tports;
93 unsigned srv_queuesize; /**< Maximum number of queued responses */
94
95 size_t srv_max_bodylen; /**< Maximum accepted length */
96
97 unsigned srv_persistent:1; /**< Allow persistent connections */
98
99 /** Sites */
100 nth_site_t *srv_sites;
101
102 /* Statistics */
103 struct {
104 uint32_t st_requests; /**< Received requests */
105 uint32_t st_responses; /**< Sent responses */
106 uint32_t st_bad; /**< Bad requests */
107 } srv_stats[1];
108
109 http_server_t *srv_server; /**< Server header */
110};
111
112struct nth_site_s
113{
114 nth_site_t *site_next, **site_prev;
115
116 nth_site_t *site_kids;
117
118 server_t *site_server;
119 auth_mod_t *site_auth;
120
121 url_t *site_url;
122 char const *site_path;
123 size_t site_path_len;
124
125 nth_request_f *site_callback;
126 nth_site_magic_t *site_magic;
127
128 su_time_t site_access; /**< Last request served */
129
130 /** Host header must match with server name */
131 unsigned site_strict : 1;
132 /** Site can have kids */
133 unsigned site_isdir : 1;
134 /** Site does not have domain name */
135 unsigned site_wildcard : 1;
136};
137
138struct nth_request_s
139{
140 server_t *req_server;
141
142 http_method_t req_method;
143 char const *req_method_name;
144 url_t const *req_url; /**< RequestURI */
145 char const *req_version;
146
147 tport_t *req_tport;
148 msg_t *req_request;
149 msg_t *req_response;
150
151 auth_status_t *req_as;
152
153 unsigned short req_status;
154 unsigned req_close : 1; /**< Client asked for close */
155 unsigned req_in_callback : 1;
156 unsigned req_destroyed : 1;
157};
158
159/* ====================================================================== */
160/* Debug log settings */
161
162#define SU_LOGnth_server_log nth_server_log
163
164#ifdef SU_DEBUG_H
165#error <su_debug.h> included directly.
166#endif
167#include <sofia-sip/su_debug.h>
168
169/**Environment variable determining the debug log level for @b nth
170 * module.
171 *
172 * The NTH_DEBUG environment variable is used to determine the debug
173 * logging level for @b nth module. The default level is 1.
174 *
175 * @sa <sofia-sip/su_debug.h>, nth_server_log, SOFIA_DEBUG
176 */
177extern char const NTH_DEBUG[];
178
179#ifndef SU_DEBUG0
180#define SU_DEBUG0 1
181#endif
182
183/**Debug log for @b nth module.
184 *
185 * The nth_server_log is the log object used by @b nth module. The level of
186 * #nth_server_log is set using #NTH_DEBUG environment variable.
187 */
188su_log_t nth_server_log[] = { SU_LOG_INIT("nth", "NTH_DEBUG", SU_DEBUG){ sizeof(su_log_t), "nth", "NTH_DEBUG", 0, SU_LOG_MAX, 0, ((void
*)0), ((void*)0), }
};
189
190#if HAVE_FUNC1
191#elif HAVE_FUNCTION1
192#define __func__ __FUNCTION__
193#else
194static char const __func__[] = "nth";
195#endif
196
197/* ====================================================================== */
198/** Server side
199 */
200static server_t *server_create(url_t const *url,
201 tag_type_t tag, tag_value_t value, ...);
202void server_destroy(server_t *srv);
203static void server_request(server_t *srv, tport_t *tport, msg_t *msg,
204 void *arg, su_time_t now);
205static nth_site_t **site_get_host(nth_site_t **, char const *host, char const *port);
206static nth_site_t **site_get_rslot(nth_site_t *parent, char *path,
207 char **return_rest);
208static nth_site_t *site_get_subdir(nth_site_t *parent, char const *path, char const **res);
209static void server_tport_error(server_t *srv, tport_t *tport,
210 int errcode, char const *remote);
211static msg_t *server_msg_create(server_t *srv, int flags,
212 char const data[], usize_t dlen,
213 tport_t const *tp, tp_client_t *tpc);
214
215static void server_reply(server_t *srv, tport_t *tport,
216 msg_t *request, msg_t *response,
217 int status, char const *phrase);
218
219static
220void nth_site_request(server_t *srv,
221 nth_site_t *site,
222 tport_t *tport,
223 msg_t *request,
224 http_t *http,
225 char const *path,
226 msg_t *response);
227
228/* ----------------------------------------------------------------------
229 * 5) Site functions
230 */
231
232/** Create a http site object.
233 *
234 * The function nth_site_create() allocates and initializes a web site
235 * object. A web site object can be either
236 * - a primary http server (@a parent is NULL),
237 * - a virtual http server (@a address contains hostpart), or
238 * - a site within a server
239 * (@a address does not have hostpart, only path part).
240 *
241 * @param parent pointer to parent site
242 * (NULL when creating a primary server object)
243 * @param callback pointer to callback function called when
244 * a request is received
245 * @param magic application context included in callback parameters
246 * @param address absolute or relative URI specifying the address of
247 * site
248 * @param tag, value, ... list of tagged parameters
249 *
250 * @TAGS
251 * If the @a parent is NULL, the list of tagged parameters must contain
252 * NTHTAG_ROOT() used to create the server engine. Tags supported when @a
253 * parent is NULL are NTHTAG_ROOT(), NTHTAG_MCLASS(), TPTAG_REUSE(),
254 * HTTPTAG_SERVER(), and HTTPTAG_SERVER_STR(). All the tags are passed to
255 * tport_tcreate() and tport_tbind(), too.
256 *
257 * @since Support for multiple sites was added to @VERSION_1_12_4
258 */
259nth_site_t *nth_site_create(nth_site_t *parent,
260 nth_request_f *callback,
261 nth_site_magic_t *magic,
262 url_string_t const *address,
263 tag_type_t tag, tag_value_t value,
264 ...)
265{
266 nth_site_t *site = NULL((void*)0), **prev = NULL((void*)0);
267 su_home_t home[SU_HOME_AUTO_SIZE(256)(((256) + ((sizeof(su_home_t) + 7) & (size_t)~8) + ((3 * sizeof
(void *) + 4 * sizeof(unsigned) + 7 * (sizeof (long) + sizeof
(void *)) + 7) & (size_t)~8)) / sizeof(su_home_t))
];
268 url_t *url, url0[1];
269 server_t *srv = NULL((void*)0);
270 ta_list ta;
271 char *path = NULL((void*)0);
272 size_t usize;
273 int is_host, is_path, wildcard = 0;
274
275 su_home_auto(home, sizeof home);
276
277 if (parent && url_is_string(address)) {
278 char const *s = (char const *)address;
279 size_t sep = strcspn(s, "/:")__extension__ ({ char __r0, __r1, __r2; (__builtin_constant_p
("/:") && ((size_t)(const void *)(("/:") + 1) - (size_t
)(const void *)("/:") == 1) ? ((__builtin_constant_p (s) &&
((size_t)(const void *)((s) + 1) - (size_t)(const void *)(s)
== 1)) ? __builtin_strcspn (s, "/:") : ((__r0 = ((const char
*) ("/:"))[0], __r0 == '\0') ? strlen (s) : ((__r1 = ((const
char *) ("/:"))[1], __r1 == '\0') ? __strcspn_c1 (s, __r0) :
((__r2 = ((const char *) ("/:"))[2], __r2 == '\0') ? __strcspn_c2
(s, __r0, __r1) : (((const char *) ("/:"))[3] == '\0' ? __strcspn_c3
(s, __r0, __r1, __r2) : __builtin_strcspn (s, "/:")))))) : __builtin_strcspn
(s, "/:")); })
;
280
281 if (parent->site_path) {
282 /* subpath */
283 url_init(url0, (enum url_type_e)parent->site_url->url_type);
284 url0->url_path = s;
285 address = (url_string_t*)url0;
286 }
287 else if (s[sep] == ':')
288 /* absolute URL with scheme */;
289 else if (s[sep] == '\0' && strchr(s, '.')(__extension__ (__builtin_constant_p ('.') && !__builtin_constant_p
(s) && ('.') == '\0' ? (char *) __rawmemchr (s, '.')
: __builtin_strchr (s, '.')))
&& host_is_valid(s)) {
290 /* looks like a domain name */;
291 url_init(url0, (enum url_type_e)parent->site_url->url_type);
292 url0->url_host = s;
293 address = (url_string_t*)url0;
294 }
295 else {
296 /* looks like a path */
297 url_init(url0, (enum url_type_e)parent->site_url->url_type);
298 url0->url_path = s;
299 address = (url_string_t*)url0;
300 }
301 }
302
303 url = url_hdup(home, address->us_url);
304
305 if (!url || !callback)
306 return NULL((void*)0);
307
308 is_host = url->url_host != NULL((void*)0);
309 is_path = url->url_path != NULL((void*)0);
310
311 if (is_host && is_path) {
312 SU_DEBUG_3(("nth_site_create(): virtual host and path simultanously\n" VA_NONE))(((nth_server_log != ((void*)0) && nth_server_log->
log_init) == 0 ? 9 : ((nth_server_log != ((void*)0) &&
nth_server_log->log_init > 1) ? nth_server_log->log_level
: su_log_default->log_level)) >= 3 ? (_su_llog(nth_server_log
, 3, "nth_server.c", (const char *)__func__, 312, "nth_site_create(): virtual host and path simultanously\n"
"%s", "")) : (void)0)
;
313 errno(*__errno_location ()) = EINVAL22;
314 goto error;
315 }
316
317 if (!parent && !is_host) {
318 SU_DEBUG_3(("nth_site_create(): host is required\n" VA_NONE))(((nth_server_log != ((void*)0) && nth_server_log->
log_init) == 0 ? 9 : ((nth_server_log != ((void*)0) &&
nth_server_log->log_init > 1) ? nth_server_log->log_level
: su_log_default->log_level)) >= 3 ? (_su_llog(nth_server_log
, 3, "nth_server.c", (const char *)__func__, 318, "nth_site_create(): host is required\n"
"%s", "")) : (void)0)
;
319 errno(*__errno_location ()) = EINVAL22;
320 goto error;
321 }
322
323 if (parent) {
324 if (!parent->site_isdir) {
325 SU_DEBUG_3(("nth_site_create(): invalid parent resource \n" VA_NONE))(((nth_server_log != ((void*)0) && nth_server_log->
log_init) == 0 ? 9 : ((nth_server_log != ((void*)0) &&
nth_server_log->log_init > 1) ? nth_server_log->log_level
: su_log_default->log_level)) >= 3 ? (_su_llog(nth_server_log
, 3, "nth_server.c", (const char *)__func__, 325, "nth_site_create(): invalid parent resource \n"
"%s", "")) : (void)0)
;
326 errno(*__errno_location ()) = EINVAL22;
327 goto error;
328 }
329
330 srv = parent->site_server; assert(srv)((srv) ? (void) (0) : __assert_fail ("srv", "nth_server.c", 330
, __PRETTY_FUNCTION__))
;
331 if (is_host) {
332 prev = site_get_host(&srv->srv_sites, url->url_host, url->url_port);
333
334 if (prev == NULL((void*)0)) {
335 SU_DEBUG_3(("nth_site_create(): host %s:%s already exists\n",(((nth_server_log != ((void*)0) && nth_server_log->
log_init) == 0 ? 9 : ((nth_server_log != ((void*)0) &&
nth_server_log->log_init > 1) ? nth_server_log->log_level
: su_log_default->log_level)) >= 3 ? (_su_llog(nth_server_log
, 3, "nth_server.c", (const char *)__func__, 336, "nth_site_create(): host %s:%s already exists\n"
, url->url_host, url->url_port ? url->url_port : "")
) : (void)0)
336 url->url_host, url->url_port ? url->url_port : ""))(((nth_server_log != ((void*)0) && nth_server_log->
log_init) == 0 ? 9 : ((nth_server_log != ((void*)0) &&
nth_server_log->log_init > 1) ? nth_server_log->log_level
: su_log_default->log_level)) >= 3 ? (_su_llog(nth_server_log
, 3, "nth_server.c", (const char *)__func__, 336, "nth_site_create(): host %s:%s already exists\n"
, url->url_host, url->url_port ? url->url_port : "")
) : (void)0)
;
337 errno(*__errno_location ()) = EEXIST17;
338 goto error;
339 }
340 }
341 else {
342 size_t i, j;
343
344 path = (char *)url->url_path;
345 while (path[0] == '/')
346 path++;
347
348 /* Remove duplicate // */
349 for (i = j = 0; path[i];) {
350 while (path[i] == '/' && path[i + 1] == '/')
351 i++;
352 path[j++] = path[i++];
353 }
354 path[j] = path[i];
355
356 url = url0, *url = *parent->site_url;
357
358 if (url->url_path) {
359 url->url_path = su_strcat(home, url->url_path, path);
360 if (!url->url_path)
361 goto error;
362 path = (char *)url->url_path + strlen(parent->site_url->url_path);
363 }
364 else
365 url->url_path = path;
366
367 prev = site_get_rslot(parent, path, &path);
368
369 if (!prev || path[0] == '\0') {
370 SU_DEBUG_3(("nth_site_create(): directory \"%s\" already exists\n",(((nth_server_log != ((void*)0) && nth_server_log->
log_init) == 0 ? 9 : ((nth_server_log != ((void*)0) &&
nth_server_log->log_init > 1) ? nth_server_log->log_level
: su_log_default->log_level)) >= 3 ? (_su_llog(nth_server_log
, 3, "nth_server.c", (const char *)__func__, 371, "nth_site_create(): directory \"%s\" already exists\n"
, url->url_path)) : (void)0)
371 url->url_path))(((nth_server_log != ((void*)0) && nth_server_log->
log_init) == 0 ? 9 : ((nth_server_log != ((void*)0) &&
nth_server_log->log_init > 1) ? nth_server_log->log_level
: su_log_default->log_level)) >= 3 ? (_su_llog(nth_server_log
, 3, "nth_server.c", (const char *)__func__, 371, "nth_site_create(): directory \"%s\" already exists\n"
, url->url_path)) : (void)0)
;
372 errno(*__errno_location ()) = EEXIST17;
373 goto error;
374 }
375 }
376 }
377
378 if (!parent) {
379 if (strcmp(url->url_host, "*")__extension__ ({ size_t __s1_len, __s2_len; (__builtin_constant_p
(url->url_host) && __builtin_constant_p ("*") &&
(__s1_len = __builtin_strlen (url->url_host), __s2_len = __builtin_strlen
("*"), (!((size_t)(const void *)((url->url_host) + 1) - (
size_t)(const void *)(url->url_host) == 1) || __s1_len >=
4) && (!((size_t)(const void *)(("*") + 1) - (size_t
)(const void *)("*") == 1) || __s2_len >= 4)) ? __builtin_strcmp
(url->url_host, "*") : (__builtin_constant_p (url->url_host
) && ((size_t)(const void *)((url->url_host) + 1) -
(size_t)(const void *)(url->url_host) == 1) && (__s1_len
= __builtin_strlen (url->url_host), __s1_len < 4) ? (__builtin_constant_p
("*") && ((size_t)(const void *)(("*") + 1) - (size_t
)(const void *)("*") == 1) ? __builtin_strcmp (url->url_host
, "*") : (__extension__ ({ const unsigned char *__s2 = (const
unsigned char *) (const char *) ("*"); int __result = (((const
unsigned char *) (const char *) (url->url_host))[0] - __s2
[0]); if (__s1_len > 0 && __result == 0) { __result
= (((const unsigned char *) (const char *) (url->url_host
))[1] - __s2[1]); if (__s1_len > 1 && __result == 0
) { __result = (((const unsigned char *) (const char *) (url->
url_host))[2] - __s2[2]); if (__s1_len > 2 && __result
== 0) __result = (((const unsigned char *) (const char *) (url
->url_host))[3] - __s2[3]); } } __result; }))) : (__builtin_constant_p
("*") && ((size_t)(const void *)(("*") + 1) - (size_t
)(const void *)("*") == 1) && (__s2_len = __builtin_strlen
("*"), __s2_len < 4) ? (__builtin_constant_p (url->url_host
) && ((size_t)(const void *)((url->url_host) + 1) -
(size_t)(const void *)(url->url_host) == 1) ? __builtin_strcmp
(url->url_host, "*") : (- (__extension__ ({ const unsigned
char *__s2 = (const unsigned char *) (const char *) (url->
url_host); int __result = (((const unsigned char *) (const char
*) ("*"))[0] - __s2[0]); if (__s2_len > 0 && __result
== 0) { __result = (((const unsigned char *) (const char *) (
"*"))[1] - __s2[1]); if (__s2_len > 1 && __result ==
0) { __result = (((const unsigned char *) (const char *) ("*"
))[2] - __s2[2]); if (__s2_len > 2 && __result == 0
) __result = (((const unsigned char *) (const char *) ("*"))[
3] - __s2[3]); } } __result; })))) : __builtin_strcmp (url->
url_host, "*")))); })
== 0 ||
380 host_cmp(url->url_host, "0.0.0.0") == 0 ||
381 host_cmp(url->url_host, "::") == 0)
382 wildcard = 1, url->url_host = "*";
383 }
384
385 usize = sizeof(*url) + url_xtra(url);
386
387 ta_start(ta, tag, value)do { tag_type_t ta_start__tag = (tag); tag_value_t ta_start__value
= (value); __builtin_va_start((ta).ap, (value)); while ((ta_start__tag
) == tag_next && (ta_start__value) != 0) { ta_start__tag
= ((tagi_t *)ta_start__value)->t_tag; if (ta_start__tag ==
tag_null || ta_start__tag == ((void*)0)) break; if (ta_start__tag
== tag_next) { ta_start__value = ((tagi_t *)ta_start__value)
->t_value; } else { ta_start__tag = tag_next; break; } } (
ta).tl->t_tag = ta_start__tag; (ta).tl->t_value = ta_start__value
; if (ta_start__tag != ((void*)0) && ta_start__tag !=
tag_null && ta_start__tag != tag_next) { va_list ta_start__ap
; __builtin_va_copy((ta_start__ap), ((ta).ap)); (ta).tl[1].t_tag
= tag_next; (ta).tl[1].t_value = (tag_value_t)tl_vlist(ta_start__ap
); __builtin_va_end(ta_start__ap); } else { (ta).tl[1].t_value
= 0; (ta).tl[1].t_value = (tag_value_t)0; } } while(0)
;
388
389 if (!parent) {
390 srv = server_create(url, ta_tags(ta)(ta).tl[0].t_tag, (ta).tl[0].t_value, (ta).tl[1].t_tag, (ta).
tl[1].t_value
);
391 prev = &srv->srv_sites;
392 }
393
394 if (srv && (site = su_zalloc(srv->srv_home, (sizeof *site) + usize))) {
395 site->site_url = (url_t *)(site + 1);
396 url_dup((void *)(site->site_url + 1), usize - sizeof(*url),
397 site->site_url, url);
398
399 assert(prev)((prev) ? (void) (0) : __assert_fail ("prev", "nth_server.c",
399, __PRETTY_FUNCTION__))
;
400 if ((site->site_next = *prev))
401 site->site_next->site_prev = &site->site_next;
402 *prev = site, site->site_prev = prev;
403 site->site_server = srv;
404
405 if (path) {
406 size_t path_len;
407
408 site->site_path = site->site_url->url_path + (path - url->url_path);
409 path_len = strlen(site->site_path); assert(path_len > 0)((path_len > 0) ? (void) (0) : __assert_fail ("path_len > 0"
, "nth_server.c", 409, __PRETTY_FUNCTION__))
;
410 if (path_len > 0 && site->site_path[path_len - 1] == '/')
411 path_len--, site->site_isdir = 1;
412 site->site_path_len = path_len;
413 }
414 else {
415 site->site_isdir = is_host;
416 site->site_path = "";
417 site->site_path_len = 0;
418 }
419
420 site->site_wildcard = wildcard;
421 site->site_callback = callback;
422 site->site_magic = magic;
423
424 if (parent)
425 site->site_auth = parent->site_auth;
426
427 nth_site_set_params(site, ta_tags(ta)(ta).tl[0].t_tag, (ta).tl[0].t_value, (ta).tl[1].t_tag, (ta).
tl[1].t_value
);
428 }
429
430 ta_end(ta)((((ta).tl[1].t_value) ? (tl_vfree((tagi_t *)((ta).tl[1].t_value
))) : (void)0), (ta).tl[1].t_value = 0, __builtin_va_end((ta)
.ap))
;
431
432 error:
433 su_home_deinit(home);
434 return site;
435}
436
437void nth_site_destroy(nth_site_t *site)
438{
439 if (site == NULL((void*)0))
440 return;
441
442 if (site->site_auth)
443 auth_mod_unref(site->site_auth), site->site_auth = NULL((void*)0);
444
445 if (site->site_server->srv_sites == site) {
446 server_destroy(site->site_server);
447 }
448}
449
450
451nth_site_magic_t *nth_site_magic(nth_site_t const *site)
452{
453 return site ? site->site_magic : NULL((void*)0);
454}
455
456
457void nth_site_bind(nth_site_t *site,
458 nth_request_f *callback,
459 nth_site_magic_t *magic)
460{
461 if (site) {
462 site->site_callback = callback;
463 site->site_magic = magic;
464 }
465}
466
467
468/** Get the site URL. @NEW_1_12_4. */
469url_t const *nth_site_url(nth_site_t const *site)
470{
471 return site ? site->site_url : NULL((void*)0);
472}
473
474/** Return server name and version */
475char const *nth_site_server_version(void)
476{
477 return "nth/" NTH_VERSION"1.0";
478}
479
480/** Get the time last time served. @NEW_1_12_4. */
481su_time_t nth_site_access_time(nth_site_t const *site)
482{
483 su_time_t const never = { 0, 0 };
484
485 return site ? site->site_access : never;
486}
487
488int nth_site_set_params(nth_site_t *site,
489 tag_type_t tag, tag_value_t value, ...)
490{
491 int n;
492 ta_list ta;
493
494 server_t *server;
495 int master;
496 msg_mclass_t const *mclass;
497 int mflags;
498 auth_mod_t *am;
499
500 if (site == NULL((void*)0))
501 return (errno(*__errno_location ()) = EINVAL22), -1;
502
503 server = site->site_server;
504 master = site == server->srv_sites;
505 am = site->site_auth;
506
507 mclass = server->srv_mclass;
508 mflags = server->srv_mflags;
509
510 ta_start(ta, tag, value)do { tag_type_t ta_start__tag = (tag); tag_value_t ta_start__value
= (value); __builtin_va_start((ta).ap, (value)); while ((ta_start__tag
) == tag_next && (ta_start__value) != 0) { ta_start__tag
= ((tagi_t *)ta_start__value)->t_tag; if (ta_start__tag ==
tag_null || ta_start__tag == ((void*)0)) break; if (ta_start__tag
== tag_next) { ta_start__value = ((tagi_t *)ta_start__value)
->t_value; } else { ta_start__tag = tag_next; break; } } (
ta).tl->t_tag = ta_start__tag; (ta).tl->t_value = ta_start__value
; if (ta_start__tag != ((void*)0) && ta_start__tag !=
tag_null && ta_start__tag != tag_next) { va_list ta_start__ap
; __builtin_va_copy((ta_start__ap), ((ta).ap)); (ta).tl[1].t_tag
= tag_next; (ta).tl[1].t_value = (tag_value_t)tl_vlist(ta_start__ap
); __builtin_va_end(ta_start__ap); } else { (ta).tl[1].t_value
= 0; (ta).tl[1].t_value = (tag_value_t)0; } } while(0)
;
511
512 n = tl_gets(ta_args(ta)(ta).tl,
513 TAG_IF(master, NTHTAG_MCLASS_REF(mclass))!(master) ? tag_skip : nthtag_mclass_ref, tag_cptr_vr(&(mclass
), (mclass))
,
514 TAG_IF(master, NTHTAG_MFLAGS_REF(mflags))!(master) ? tag_skip : nthtag_mflags_ref, tag_int_vr(&(mflags
))
,
515 NTHTAG_AUTH_MODULE_REF(am)nthtag_auth_module_ref, tag_ptr_vr(&(am), (am)),
516 TAG_END()(tag_type_t)0, (tag_value_t)0);
517
518 if (n > 0) {
519 if (mclass)
520 server->srv_mclass = mclass;
521 else
522 server->srv_mclass = http_default_mclass();
523 server->srv_mflags = mflags;
524 auth_mod_ref(am), auth_mod_unref(site->site_auth), site->site_auth = am;
525 }
526
527 ta_end(ta)((((ta).tl[1].t_value) ? (tl_vfree((tagi_t *)((ta).tl[1].t_value
))) : (void)0), (ta).tl[1].t_value = 0, __builtin_va_end((ta)
.ap))
;
528
529 return n;
530}
531
532int nth_site_get_params(nth_site_t const *site,
533 tag_type_t tag, tag_value_t value, ...)
534{
535 int n;
536 ta_list ta;
537 server_t *server;
538 int master;
539 msg_mclass_t const *mclass;
540
541 if (site == NULL((void*)0))
542 return (errno(*__errno_location ()) = EINVAL22), -1;
543
544 server = site->site_server;
545 master = site == server->srv_sites;
546
547 if (master && server->srv_mclass != http_default_mclass())
548 mclass = server->srv_mclass;
549 else
550 mclass = NULL((void*)0);
551
552 ta_start(ta, tag, value)do { tag_type_t ta_start__tag = (tag); tag_value_t ta_start__value
= (value); __builtin_va_start((ta).ap, (value)); while ((ta_start__tag
) == tag_next && (ta_start__value) != 0) { ta_start__tag
= ((tagi_t *)ta_start__value)->t_tag; if (ta_start__tag ==
tag_null || ta_start__tag == ((void*)0)) break; if (ta_start__tag
== tag_next) { ta_start__value = ((tagi_t *)ta_start__value)
->t_value; } else { ta_start__tag = tag_next; break; } } (
ta).tl->t_tag = ta_start__tag; (ta).tl->t_value = ta_start__value
; if (ta_start__tag != ((void*)0) && ta_start__tag !=
tag_null && ta_start__tag != tag_next) { va_list ta_start__ap
; __builtin_va_copy((ta_start__ap), ((ta).ap)); (ta).tl[1].t_tag
= tag_next; (ta).tl[1].t_value = (tag_value_t)tl_vlist(ta_start__ap
); __builtin_va_end(ta_start__ap); } else { (ta).tl[1].t_value
= 0; (ta).tl[1].t_value = (tag_value_t)0; } } while(0)
;
553
554 n = tl_tgets(ta_args(ta)(ta).tl,
555 TAG_IF(master, NTHTAG_MCLASS(mclass))!(master) ? tag_skip : nthtag_mclass, tag_cptr_v((mclass)),
556 TAG_IF(master, NTHTAG_MFLAGS(server->srv_mflags))!(master) ? tag_skip : nthtag_mflags, tag_int_v((server->srv_mflags
))
,
557 TAG_END()(tag_type_t)0, (tag_value_t)0);
558
559 ta_end(ta)((((ta).tl[1].t_value) ? (tl_vfree((tagi_t *)((ta).tl[1].t_value
))) : (void)0), (ta).tl[1].t_value = 0, __builtin_va_end((ta)
.ap))
;
560
561 return n;
562}
563
564int nth_site_get_stats(nth_site_t const *site,
565 tag_type_t tag, tag_value_t value, ...)
566{
567 int n;
568 ta_list ta;
569
570 if (site == NULL((void*)0))
571 return (errno(*__errno_location ()) = EINVAL22), -1;
572
573 ta_start(ta, tag, value)do { tag_type_t ta_start__tag = (tag); tag_value_t ta_start__value
= (value); __builtin_va_start((ta).ap, (value)); while ((ta_start__tag
) == tag_next && (ta_start__value) != 0) { ta_start__tag
= ((tagi_t *)ta_start__value)->t_tag; if (ta_start__tag ==
tag_null || ta_start__tag == ((void*)0)) break; if (ta_start__tag
== tag_next) { ta_start__value = ((tagi_t *)ta_start__value)
->t_value; } else { ta_start__tag = tag_next; break; } } (
ta).tl->t_tag = ta_start__tag; (ta).tl->t_value = ta_start__value
; if (ta_start__tag != ((void*)0) && ta_start__tag !=
tag_null && ta_start__tag != tag_next) { va_list ta_start__ap
; __builtin_va_copy((ta_start__ap), ((ta).ap)); (ta).tl[1].t_tag
= tag_next; (ta).tl[1].t_value = (tag_value_t)tl_vlist(ta_start__ap
); __builtin_va_end(ta_start__ap); } else { (ta).tl[1].t_value
= 0; (ta).tl[1].t_value = (tag_value_t)0; } } while(0)
;
574
575 n = tl_tgets(ta_args(ta)(ta).tl,
576 TAG_END()(tag_type_t)0, (tag_value_t)0);
577
578 ta_end(ta)((((ta).tl[1].t_value) ? (tl_vfree((tagi_t *)((ta).tl[1].t_value
))) : (void)0), (ta).tl[1].t_value = 0, __builtin_va_end((ta)
.ap))
;
579
580 return n;
581}
582
583static
584nth_site_t **site_get_host(nth_site_t **list, char const *host, char const *port)
585{
586 nth_site_t *site;
587
588 assert(host)((host) ? (void) (0) : __assert_fail ("host", "nth_server.c",
588, __PRETTY_FUNCTION__))
;
589
590 for (; (site = *list); list = &site->site_next) {
591 if (host_cmp(host, site->site_url->url_host) == 0 &&
592 su_strcmp(port, site->site_url->url_port) == 0) {
593 break;
594 }
595 }
596
597 return list;
598}
599
600/** Find a place to insert site from the hierarchy.
601 *
602 * A resource can be either a 'dir' (name ends with '/') or 'file'.
603 * When a resource
604 */
605static
606nth_site_t **site_get_rslot(nth_site_t *parent, char *path,
607 char **return_rest)
608{
609 nth_site_t *site, **prev;
610 size_t len;
611 int cmp;
612
613 assert(path)((path) ? (void) (0) : __assert_fail ("path", "nth_server.c",
613, __PRETTY_FUNCTION__))
;
614
615 if (path[0] == '\0')
616 return errno(*__errno_location ()) = EEXIST17, NULL((void*)0);
617
618 for (prev = &parent->site_kids; (site = *prev); prev = &site->site_next) {
619 cmp = strncmp(path, site->site_path, len = site->site_path_len)(__extension__ (__builtin_constant_p (len = site->site_path_len
) && ((__builtin_constant_p (path) && strlen (
path) < ((size_t) (len = site->site_path_len))) || (__builtin_constant_p
(site->site_path) && strlen (site->site_path) <
((size_t) (len = site->site_path_len)))) ? __extension__ (
{ size_t __s1_len, __s2_len; (__builtin_constant_p (path) &&
__builtin_constant_p (site->site_path) && (__s1_len
= __builtin_strlen (path), __s2_len = __builtin_strlen (site
->site_path), (!((size_t)(const void *)((path) + 1) - (size_t
)(const void *)(path) == 1) || __s1_len >= 4) && (
!((size_t)(const void *)((site->site_path) + 1) - (size_t)
(const void *)(site->site_path) == 1) || __s2_len >= 4)
) ? __builtin_strcmp (path, site->site_path) : (__builtin_constant_p
(path) && ((size_t)(const void *)((path) + 1) - (size_t
)(const void *)(path) == 1) && (__s1_len = __builtin_strlen
(path), __s1_len < 4) ? (__builtin_constant_p (site->site_path
) && ((size_t)(const void *)((site->site_path) + 1
) - (size_t)(const void *)(site->site_path) == 1) ? __builtin_strcmp
(path, site->site_path) : (__extension__ ({ const unsigned
char *__s2 = (const unsigned char *) (const char *) (site->
site_path); int __result = (((const unsigned char *) (const char
*) (path))[0] - __s2[0]); if (__s1_len > 0 && __result
== 0) { __result = (((const unsigned char *) (const char *) (
path))[1] - __s2[1]); if (__s1_len > 1 && __result
== 0) { __result = (((const unsigned char *) (const char *) (
path))[2] - __s2[2]); if (__s1_len > 2 && __result
== 0) __result = (((const unsigned char *) (const char *) (path
))[3] - __s2[3]); } } __result; }))) : (__builtin_constant_p (
site->site_path) && ((size_t)(const void *)((site->
site_path) + 1) - (size_t)(const void *)(site->site_path) ==
1) && (__s2_len = __builtin_strlen (site->site_path
), __s2_len < 4) ? (__builtin_constant_p (path) &&
((size_t)(const void *)((path) + 1) - (size_t)(const void *)
(path) == 1) ? __builtin_strcmp (path, site->site_path) : (
- (__extension__ ({ const unsigned char *__s2 = (const unsigned
char *) (const char *) (path); int __result = (((const unsigned
char *) (const char *) (site->site_path))[0] - __s2[0]); if
(__s2_len > 0 && __result == 0) { __result = (((const
unsigned char *) (const char *) (site->site_path))[1] - __s2
[1]); if (__s2_len > 1 && __result == 0) { __result
= (((const unsigned char *) (const char *) (site->site_path
))[2] - __s2[2]); if (__s2_len > 2 && __result == 0
) __result = (((const unsigned char *) (const char *) (site->
site_path))[3] - __s2[3]); } } __result; })))) : __builtin_strcmp
(path, site->site_path)))); }) : strncmp (path, site->
site_path, len = site->site_path_len)))
;
620 if (cmp > 0)
621 break;
622 if (cmp < 0)
623 continue;
624 if (path[len] == '\0') {
625 if (site->site_isdir)
626 return *return_rest = path, prev;
627 return errno(*__errno_location ()) = EEXIST17, NULL((void*)0);
628 }
629 if (path[len] != '/' || site->site_path[len] != '/')
630 continue;
631
632 while (path[++len] == '/')
633 ;
634
635 return site_get_rslot(site, path + len, return_rest);
636 }
637
638 *return_rest = path;
639
640 return prev;
641}
642
643static char const site_nodir_match[] = "";
644
645/** Find a subdir from site hierarchy */
646static
647nth_site_t *site_get_subdir(nth_site_t *parent,
648 char const *path,
649 char const **return_rest)
650{
651 nth_site_t *site;
652 size_t len;
653 int cmp;
654
655 assert(path)((path) ? (void) (0) : __assert_fail ("path", "nth_server.c",
655, __PRETTY_FUNCTION__))
;
656
657 while (path[0] == '/') /* Skip multiple slashes */
658 path++;
659
660 if (path[0] == '\0')
661 return *return_rest = path, parent;
662
663 for (site = parent->site_kids; site; site = site->site_next) {
664 cmp = strncmp(path, site->site_path, len = site->site_path_len)(__extension__ (__builtin_constant_p (len = site->site_path_len
) && ((__builtin_constant_p (path) && strlen (
path) < ((size_t) (len = site->site_path_len))) || (__builtin_constant_p
(site->site_path) && strlen (site->site_path) <
((size_t) (len = site->site_path_len)))) ? __extension__ (
{ size_t __s1_len, __s2_len; (__builtin_constant_p (path) &&
__builtin_constant_p (site->site_path) && (__s1_len
= __builtin_strlen (path), __s2_len = __builtin_strlen (site
->site_path), (!((size_t)(const void *)((path) + 1) - (size_t
)(const void *)(path) == 1) || __s1_len >= 4) && (
!((size_t)(const void *)((site->site_path) + 1) - (size_t)
(const void *)(site->site_path) == 1) || __s2_len >= 4)
) ? __builtin_strcmp (path, site->site_path) : (__builtin_constant_p
(path) && ((size_t)(const void *)((path) + 1) - (size_t
)(const void *)(path) == 1) && (__s1_len = __builtin_strlen
(path), __s1_len < 4) ? (__builtin_constant_p (site->site_path
) && ((size_t)(const void *)((site->site_path) + 1
) - (size_t)(const void *)(site->site_path) == 1) ? __builtin_strcmp
(path, site->site_path) : (__extension__ ({ const unsigned
char *__s2 = (const unsigned char *) (const char *) (site->
site_path); int __result = (((const unsigned char *) (const char
*) (path))[0] - __s2[0]); if (__s1_len > 0 && __result
== 0) { __result = (((const unsigned char *) (const char *) (
path))[1] - __s2[1]); if (__s1_len > 1 && __result
== 0) { __result = (((const unsigned char *) (const char *) (
path))[2] - __s2[2]); if (__s1_len > 2 && __result
== 0) __result = (((const unsigned char *) (const char *) (path
))[3] - __s2[3]); } } __result; }))) : (__builtin_constant_p (
site->site_path) && ((size_t)(const void *)((site->
site_path) + 1) - (size_t)(const void *)(site->site_path) ==
1) && (__s2_len = __builtin_strlen (site->site_path
), __s2_len < 4) ? (__builtin_constant_p (path) &&
((size_t)(const void *)((path) + 1) - (size_t)(const void *)
(path) == 1) ? __builtin_strcmp (path, site->site_path) : (
- (__extension__ ({ const unsigned char *__s2 = (const unsigned
char *) (const char *) (path); int __result = (((const unsigned
char *) (const char *) (site->site_path))[0] - __s2[0]); if
(__s2_len > 0 && __result == 0) { __result = (((const
unsigned char *) (const char *) (site->site_path))[1] - __s2
[1]); if (__s2_len > 1 && __result == 0) { __result
= (((const unsigned char *) (const char *) (site->site_path
))[2] - __s2[2]); if (__s2_len > 2 && __result == 0
) __result = (((const unsigned char *) (const char *) (site->
site_path))[3] - __s2[3]); } } __result; })))) : __builtin_strcmp
(path, site->site_path)))); }) : strncmp (path, site->
site_path, len = site->site_path_len)))
;
665 if (cmp > 0)
666 break;
667 if (cmp < 0)
668 continue;
669 if (path[len] == '\0')
670 return *return_rest = site_nodir_match, site;
671 if (site->site_path[len] == '/' && path[len] == '/')
672 return site_get_subdir(site, path + len + 1, return_rest);
673 }
674
675 return *return_rest = path, parent;
676}
677
678
679/* ----------------------------------------------------------------------
680 * Server functions
681 */
682
683static char const * const http_tports[] =
684 {
685 "tcp", "tls", NULL((void*)0)
686 };
687
688static char const * const http_no_tls_tports[] = { "tcp", NULL((void*)0) };
689
690static tp_stack_class_t nth_server_class[1] =
691 {{
692 sizeof(nth_server_class),
693 server_request,
694 server_tport_error,
695 server_msg_create
696 }};
697
698server_t *server_create(url_t const *url,
699 tag_type_t tag, tag_value_t value, ...)
700{
701 server_t *srv;
702 msg_mclass_t const *mclass = NULL((void*)0);
703 tp_name_t tpn[1] = {{ NULL((void*)0) }};
704 su_root_t *root = NULL((void*)0);
705 http_server_t const *server = NULL((void*)0);
706 int persistent = 0;
707 char const *server_str = SERVER_VERSION"nth/" "1.0";
708 ta_list ta;
709
710 ta_start(ta, tag, value)do { tag_type_t ta_start__tag = (tag); tag_value_t ta_start__value
= (value); __builtin_va_start((ta).ap, (value)); while ((ta_start__tag
) == tag_next && (ta_start__value) != 0) { ta_start__tag
= ((tagi_t *)ta_start__value)->t_tag; if (ta_start__tag ==
tag_null || ta_start__tag == ((void*)0)) break; if (ta_start__tag
== tag_next) { ta_start__value = ((tagi_t *)ta_start__value)
->t_value; } else { ta_start__tag = tag_next; break; } } (
ta).tl->t_tag = ta_start__tag; (ta).tl->t_value = ta_start__value
; if (ta_start__tag != ((void*)0) && ta_start__tag !=
tag_null && ta_start__tag != tag_next) { va_list ta_start__ap
; __builtin_va_copy((ta_start__ap), ((ta).ap)); (ta).tl[1].t_tag
= tag_next; (ta).tl[1].t_value = (tag_value_t)tl_vlist(ta_start__ap
); __builtin_va_end(ta_start__ap); } else { (ta).tl[1].t_value
= 0; (ta).tl[1].t_value = (tag_value_t)0; } } while(0)
;
711 tl_gets(ta_args(ta)(ta).tl,
712 NTHTAG_ROOT_REF(root)nthtag_root_ref, tag_ptr_vr(&(root), (root)),
713 NTHTAG_MCLASS_REF(mclass)nthtag_mclass_ref, tag_cptr_vr(&(mclass), (mclass)),
714 TPTAG_REUSE_REF(persistent)tptag_reuse_ref, tag_bool_vr(&(persistent)),
715 HTTPTAG_SERVER_REF(server)httptag_server_ref, httptag_server_vr(&(server)),
716 HTTPTAG_SERVER_STR_REF(server_str)httptag_server_str_ref, tag_str_vr(&(server_str)),
717 TAG_END()(tag_type_t)0, (tag_value_t)0);
718
719 if (!root || !url ||
720 (url->url_type != url_http && url->url_type != url_https)
721 || !(srv = su_home_new(sizeof(*srv)))) {
722 ta_end(ta)((((ta).tl[1].t_value) ? (tl_vfree((tagi_t *)((ta).tl[1].t_value
))) : (void)0), (ta).tl[1].t_value = 0, __builtin_va_end((ta)
.ap))
;
723 return NULL((void*)0);
724 }
725
726 tpn->tpn_proto = url_tport_default((enum url_type_e)url->url_type);
727 tpn->tpn_canon = url->url_host;
728 tpn->tpn_host = url->url_host;
729 tpn->tpn_port = url_port(url);
730
731 srv->srv_tports = tport_tcreate(srv, nth_server_class, root,
732 TPTAG_IDLE(600000)tptag_idle, tag_uint_v((600000)),
733 TPTAG_TIMEOUT(300000)tptag_timeout, tag_uint_v((300000)),
734 ta_tags(ta)(ta).tl[0].t_tag, (ta).tl[0].t_value, (ta).tl[1].t_tag, (ta).
tl[1].t_value
);
735
736 srv->srv_persistent = persistent;
737 srv->srv_max_bodylen = 1 << 30; /* 1 GB */
738
739 if (tport_tbind(srv->srv_tports, tpn, http_tports,
740 TAG_END()(tag_type_t)0, (tag_value_t)0) >= 0 ||
741 tport_tbind(srv->srv_tports, tpn, http_no_tls_tports,
742 TAG_END()(tag_type_t)0, (tag_value_t)0) >= 0) {
743 srv->srv_root = root;
744 srv->srv_mclass = mclass ? mclass : http_default_mclass();
745 srv->srv_mflags = MSG_DO_CANONICMSG_FLG_CANONIC;
746
747 if (server)
748 srv->srv_server = http_server_dup(srv->srv_home, server);
749 else
750 srv->srv_server = http_server_make(srv->srv_home, server_str);
751
752 tport_get_params(srv->srv_tports,
753 TPTAG_QUEUESIZE_REF(srv->srv_queuesize)tptag_queuesize_ref, tag_uint_vr(&(srv->srv_queuesize)
)
,
754 TAG_END()(tag_type_t)0, (tag_value_t)0);
755 }
756 else {
757 SU_DEBUG_1(("nth_server_create: cannot bind transports "(((nth_server_log != ((void*)0) && nth_server_log->
log_init) == 0 ? 9 : ((nth_server_log != ((void*)0) &&
nth_server_log->log_init > 1) ? nth_server_log->log_level
: su_log_default->log_level)) >= 1 ? (_su_llog(nth_server_log
, 1, "nth_server.c", (const char *)__func__, 759, "nth_server_create: cannot bind transports "
"%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s" "\n", (url)->url_scheme
? (url)->url_scheme : "", (url)->url_type != url_any &&
(url)->url_scheme && (url)->url_scheme[0] ? ":"
: "", (url)->url_root && ((url)->url_host || (
url)->url_user) ? "//" : "", (url)->url_user ? (url)->
url_user : "", (url)->url_user && (url)->url_password
? ":" : "", (url)->url_user && (url)->url_password
? (url)->url_password : "", (url)->url_user &&
(url)->url_host ? "@" : "", (url)->url_host ? (url)->
url_host : "", (url)->url_host && (url)->url_port
? ":" : "", (url)->url_host && (url)->url_port
? (url)->url_port : "", (url)->url_root && (url
)->url_path ? "/" : "", (url)->url_path ? (url)->url_path
: "", (url)->url_params ? ";" : "", (url)->url_params ?
(url)->url_params : "", (url)->url_headers ? "?" : "",
(url)->url_headers ? (url)->url_headers : "", (url)->
url_fragment ? "#" : "", (url)->url_fragment ? (url)->url_fragment
: "")) : (void)0)
758 URL_FORMAT_STRING "\n",(((nth_server_log != ((void*)0) && nth_server_log->
log_init) == 0 ? 9 : ((nth_server_log != ((void*)0) &&
nth_server_log->log_init > 1) ? nth_server_log->log_level
: su_log_default->log_level)) >= 1 ? (_su_llog(nth_server_log
, 1, "nth_server.c", (const char *)__func__, 759, "nth_server_create: cannot bind transports "
"%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s" "\n", (url)->url_scheme
? (url)->url_scheme : "", (url)->url_type != url_any &&
(url)->url_scheme && (url)->url_scheme[0] ? ":"
: "", (url)->url_root && ((url)->url_host || (
url)->url_user) ? "//" : "", (url)->url_user ? (url)->
url_user : "", (url)->url_user && (url)->url_password
? ":" : "", (url)->url_user && (url)->url_password
? (url)->url_password : "", (url)->url_user &&
(url)->url_host ? "@" : "", (url)->url_host ? (url)->
url_host : "", (url)->url_host && (url)->url_port
? ":" : "", (url)->url_host && (url)->url_port
? (url)->url_port : "", (url)->url_root && (url
)->url_path ? "/" : "", (url)->url_path ? (url)->url_path
: "", (url)->url_params ? ";" : "", (url)->url_params ?
(url)->url_params : "", (url)->url_headers ? "?" : "",
(url)->url_headers ? (url)->url_headers : "", (url)->
url_fragment ? "#" : "", (url)->url_fragment ? (url)->url_fragment
: "")) : (void)0)
759 URL_PRINT_ARGS(url)))(((nth_server_log != ((void*)0) && nth_server_log->
log_init) == 0 ? 9 : ((nth_server_log != ((void*)0) &&
nth_server_log->log_init > 1) ? nth_server_log->log_level
: su_log_default->log_level)) >= 1 ? (_su_llog(nth_server_log
, 1, "nth_server.c", (const char *)__func__, 759, "nth_server_create: cannot bind transports "
"%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s" "\n", (url)->url_scheme
? (url)->url_scheme : "", (url)->url_type != url_any &&
(url)->url_scheme && (url)->url_scheme[0] ? ":"
: "", (url)->url_root && ((url)->url_host || (
url)->url_user) ? "//" : "", (url)->url_user ? (url)->
url_user : "", (url)->url_user && (url)->url_password
? ":" : "", (url)->url_user && (url)->url_password
? (url)->url_password : "", (url)->url_user &&
(url)->url_host ? "@" : "", (url)->url_host ? (url)->
url_host : "", (url)->url_host && (url)->url_port
? ":" : "", (url)->url_host && (url)->url_port
? (url)->url_port : "", (url)->url_root && (url
)->url_path ? "/" : "", (url)->url_path ? (url)->url_path
: "", (url)->url_params ? ";" : "", (url)->url_params ?
(url)->url_params : "", (url)->url_headers ? "?" : "",
(url)->url_headers ? (url)->url_headers : "", (url)->
url_fragment ? "#" : "", (url)->url_fragment ? (url)->url_fragment
: "")) : (void)0)
;
760 server_destroy(srv), srv = NULL((void*)0);
761 }
762
763 ta_end(ta)((((ta).tl[1].t_value) ? (tl_vfree((tagi_t *)((ta).tl[1].t_value
))) : (void)0), (ta).tl[1].t_value = 0, __builtin_va_end((ta)
.ap))
;
764
765 return srv;
766}
767
768void server_destroy(server_t *srv)
769{
770 tport_destroy(srv->srv_tports);
771 su_timer_destroy(srv->srv_timer);
772 su_home_unref(srv->srv_home);
773}
774
775/** Process incoming request message */
776static
777void server_request(server_t *srv,
778 tport_t *tport,
779 msg_t *request,
780 void *arg,
781 su_time_t now)
782{
783 nth_site_t *site = NULL((void*)0), *subsite = NULL((void*)0);
1
'site' initialized to a null pointer value
784 msg_t *response;
785 http_t *http = http_object(request);
786 http_host_t *h;
787 char const *host, *port, *path, *subpath = NULL((void*)0);
788
789 /* Disable streaming */
790 if (msg_is_streaming(request)) {
2
Taking false branch
791 msg_set_streaming(request, (enum msg_streaming_status)0);
792 return;
793 }
794
795 /* Create a response message */
796 response = server_msg_create(srv, 0, NULL((void*)0), 0, NULL((void*)0), NULL((void*)0));
797 tport_tqueue(tport, response, TAG_END()(tag_type_t)0, (tag_value_t)0);
798
799 if (http && http->http_flags & MSG_FLG_TIMEOUT) {
3
Taking false branch
800 server_reply(srv, tport, request, response, 400, "Request timeout");
801 return;
802 } else if (http && http->http_flags & MSG_FLG_TOOLARGE) {
4
Taking false branch
803 server_reply(srv, tport, request, response, HTTP_413_ENTITY_TOO_LARGE413, http_413_entity_too_large);
804 return;
805 } else if (!http || !http->http_request ||
5
Taking false branch
806 (http->http_flags & MSG_FLG_ERROR)) {
807 server_reply(srv, tport, request, response, HTTP_400_BAD_REQUEST400, http_400_bad_request);
808 return;
809 }
810
811 if (http->http_request->rq_version != http_version_1_0 &&
812 http->http_request->rq_version != http_version_1_1) {
813 server_reply(srv, tport, request, response, HTTP_505_HTTP_VERSION505, http_505_http_version);
814 return;
815 }
816
817 h = http->http_host;
818
819 if (h) {
6
Assuming 'h' is null
7
Taking false branch
820 host = h->h_host, port = h->h_port;
821 }
822 else if (http->http_request->rq_url->url_host) {
8
Taking false branch
823 host = http->http_request->rq_url->url_host;
824 port = http->http_request->rq_url->url_port;
825 }
826 else
827 host = NULL((void*)0), port = NULL((void*)0);
828
829 path = http->http_request->rq_url->url_path;
830
831 if (host)
9
Taking false branch
832 site = *site_get_host(&srv->srv_sites, host, port);
833
834 if (site == NULL((void*)0) && !srv->srv_sites->site_strict)
10
Taking false branch
835 site = srv->srv_sites;
836
837 if (path == NULL((void*)0))
11
Assuming 'path' is not equal to null
12
Taking false branch
838 path = "";
839
840 if (path[0])
13
Taking true branch
841 subsite = site_get_subdir(site, path, &subpath);
842
843 if (subsite)
14
Assuming 'subsite' is non-null
15
Taking true branch
844 subsite->site_access = now;
845 else
846 site->site_access = now;
847
848 if (subsite && subsite->site_isdir && subpath == site_nodir_match) {
16
Taking true branch
849 /* Answer with 301 */
850 http_location_t loc[1];
851 http_location_init(loc);
852
853 *loc->loc_url = *site->site_url;
17
Access to field 'site_url' results in a dereference of a null pointer (loaded from variable 'site')
854
855 if (site->site_wildcard) {
856 if (http->http_host) {
857 loc->loc_url->url_host = http->http_host->h_host;
858 loc->loc_url->url_port = http->http_host->h_port;
859 }
860 else {
861 tp_name_t const *tpn = tport_name(tport); assert(tpn)((tpn) ? (void) (0) : __assert_fail ("tpn", "nth_server.c", 861
, __PRETTY_FUNCTION__))
;
862 loc->loc_url->url_host = tpn->tpn_canon;
863 if (strcmp(url_port_default((enum url_type_e)loc->loc_url->url_type), tpn->tpn_port)__extension__ ({ size_t __s1_len, __s2_len; (__builtin_constant_p
(url_port_default((enum url_type_e)loc->loc_url->url_type
)) && __builtin_constant_p (tpn->tpn_port) &&
(__s1_len = __builtin_strlen (url_port_default((enum url_type_e
)loc->loc_url->url_type)), __s2_len = __builtin_strlen (
tpn->tpn_port), (!((size_t)(const void *)((url_port_default
((enum url_type_e)loc->loc_url->url_type)) + 1) - (size_t
)(const void *)(url_port_default((enum url_type_e)loc->loc_url
->url_type)) == 1) || __s1_len >= 4) && (!((size_t
)(const void *)((tpn->tpn_port) + 1) - (size_t)(const void
*)(tpn->tpn_port) == 1) || __s2_len >= 4)) ? __builtin_strcmp
(url_port_default((enum url_type_e)loc->loc_url->url_type
), tpn->tpn_port) : (__builtin_constant_p (url_port_default
((enum url_type_e)loc->loc_url->url_type)) && (
(size_t)(const void *)((url_port_default((enum url_type_e)loc
->loc_url->url_type)) + 1) - (size_t)(const void *)(url_port_default
((enum url_type_e)loc->loc_url->url_type)) == 1) &&
(__s1_len = __builtin_strlen (url_port_default((enum url_type_e
)loc->loc_url->url_type)), __s1_len < 4) ? (__builtin_constant_p
(tpn->tpn_port) && ((size_t)(const void *)((tpn->
tpn_port) + 1) - (size_t)(const void *)(tpn->tpn_port) == 1
) ? __builtin_strcmp (url_port_default((enum url_type_e)loc->
loc_url->url_type), tpn->tpn_port) : (__extension__ ({ const
unsigned char *__s2 = (const unsigned char *) (const char *)
(tpn->tpn_port); int __result = (((const unsigned char *)
(const char *) (url_port_default((enum url_type_e)loc->loc_url
->url_type)))[0] - __s2[0]); if (__s1_len > 0 &&
__result == 0) { __result = (((const unsigned char *) (const
char *) (url_port_default((enum url_type_e)loc->loc_url->
url_type)))[1] - __s2[1]); if (__s1_len > 1 && __result
== 0) { __result = (((const unsigned char *) (const char *) (
url_port_default((enum url_type_e)loc->loc_url->url_type
)))[2] - __s2[2]); if (__s1_len > 2 && __result ==
0) __result = (((const unsigned char *) (const char *) (url_port_default
((enum url_type_e)loc->loc_url->url_type)))[3] - __s2[3
]); } } __result; }))) : (__builtin_constant_p (tpn->tpn_port
) && ((size_t)(const void *)((tpn->tpn_port) + 1) -
(size_t)(const void *)(tpn->tpn_port) == 1) && (__s2_len
= __builtin_strlen (tpn->tpn_port), __s2_len < 4) ? (__builtin_constant_p
(url_port_default((enum url_type_e)loc->loc_url->url_type
)) && ((size_t)(const void *)((url_port_default((enum
url_type_e)loc->loc_url->url_type)) + 1) - (size_t)(const
void *)(url_port_default((enum url_type_e)loc->loc_url->
url_type)) == 1) ? __builtin_strcmp (url_port_default((enum url_type_e
)loc->loc_url->url_type), tpn->tpn_port) : (- (__extension__
({ const unsigned char *__s2 = (const unsigned char *) (const
char *) (url_port_default((enum url_type_e)loc->loc_url->
url_type)); int __result = (((const unsigned char *) (const char
*) (tpn->tpn_port))[0] - __s2[0]); if (__s2_len > 0 &&
__result == 0) { __result = (((const unsigned char *) (const
char *) (tpn->tpn_port))[1] - __s2[1]); if (__s2_len >
1 && __result == 0) { __result = (((const unsigned char
*) (const char *) (tpn->tpn_port))[2] - __s2[2]); if (__s2_len
> 2 && __result == 0) __result = (((const unsigned
char *) (const char *) (tpn->tpn_port))[3] - __s2[3]); } }
__result; })))) : __builtin_strcmp (url_port_default((enum url_type_e
)loc->loc_url->url_type), tpn->tpn_port)))); })
)
864 loc->loc_url->url_port = tpn->tpn_port;
865 }
866 }
867
868 loc->loc_url->url_root = 1;
869 loc->loc_url->url_path = subsite->site_url->url_path;
870
871 msg_header_add_dup(response, NULL((void*)0), (msg_header_t *)loc);
872
873 server_reply(srv, tport, request, response, HTTP_301_MOVED_PERMANENTLY301, http_301_moved_permanently);
874 }
875 else if (subsite)
876 nth_site_request(srv, subsite, tport, request, http, subpath, response);
877 else if (site)
878 nth_site_request(srv, site, tport, request, http, path, response);
879 else
880 /* Answer with 404 */
881 server_reply(srv, tport, request, response, HTTP_404_NOT_FOUND404, http_404_not_found);
882}
883
884static void server_tport_error(server_t *srv,
885 tport_t *tport,
886 int errcode,
887 char const *remote)
888{
889 su_log("\nth: tport: %s%s%s\n",
890 remote ? remote : "", remote ? ": " : "",
891 su_strerror(errcode));
892}
893
894/** Respond without creating a request structure */
895static void server_reply(server_t *srv, tport_t *tport,
896 msg_t *request, msg_t *response,
897 int status, char const *phrase)
898{
899 http_t *http;
900 http_payload_t *pl;
901 int close;
902 http_status_t st[1];
903 char const *req_version = NULL((void*)0);
904
905 if (status < 200 || status >= 600)
906 status = 500, phrase = http_500_internal_server;
907
908 http = http_object(request);
909
910 if (http && http->http_request)
911 req_version = http->http_request->rq_version;
912
913 close = status >= 200 &&
914 (!srv->srv_persistent
915 || status == 400
916 || (http && http->http_request &&
917 http->http_request->rq_version != http_version_1_1)
918 || (http && http->http_connection &&
919 msg_params_find(http->http_connection->k_items, "close")));
920
921 msg_destroy(request);
922
923 http = http_object(response);
924
925 pl = http_payload_format(msg_home(response)((su_home_t*)(response)),
926 "<html>\n"
927 "<head><title>%u %s</title></head>\n"
928 "<body><h2>%u %s</h2></body>\n"
929 "</html>\n", status, phrase, status, phrase);
930
931 msg_header_insert(response, (msg_pub_t *)http, (msg_header_t *)pl);
932
933 if (req_version != http_version_0_9) {
934 http_status_init(st);
935 st->st_version = http_version_1_1;
936 st->st_status = status;
937 st->st_phrase = phrase;
938
939 http_add_tl(response, http,
940 HTTPTAG_STATUS(st)httptag_status, httptag_status_v(st),
941 HTTPTAG_SERVER(srv->srv_server)httptag_server, httptag_server_v(srv->srv_server),
942 HTTPTAG_CONTENT_TYPE_STR("text/html")httptag_content_type_str, tag_str_v("text/html"),
943 HTTPTAG_SEPARATOR_STR("\r\n")httptag_separator_str, tag_str_v("\r\n"),
944 TAG_IF(close, HTTPTAG_CONNECTION_STR("close"))!(close) ? tag_skip : httptag_connection_str, tag_str_v("close"
)
,
945 TAG_END()(tag_type_t)0, (tag_value_t)0);
946
947 msg_serialize(response, (msg_pub_t *)http);
948 } else {
949 /* Just send the response */
950 *msg_chain_head(response) = (msg_header_t *)pl;
951 close = 1;
952 }
953
954 if (tport_tqsend(tport, response, NULL((void*)0),
955 TPTAG_CLOSE_AFTER(close)tptag_close_after, tag_bool_v((close)),
956 TAG_END()(tag_type_t)0, (tag_value_t)0) == -1) {
957 SU_DEBUG_3(("server_reply(): cannot queue response\n" VA_NONE))(((nth_server_log != ((void*)0) && nth_server_log->
log_init) == 0 ? 9 : ((nth_server_log != ((void*)0) &&
nth_server_log->log_init > 1) ? nth_server_log->log_level
: su_log_default->log_level)) >= 3 ? (_su_llog(nth_server_log
, 3, "nth_server.c", (const char *)__func__, 957, "server_reply(): cannot queue response\n"
"%s", "")) : (void)0)
;
958 tport_shutdown(tport, 2);
959 }
960
961 msg_destroy(response);
962}
963
964/** Create a new message for transport */
965static
966msg_t *server_msg_create(server_t *srv, int flags,
967 char const data[], usize_t dlen,
968 tport_t const *tp, tp_client_t *tpc)
969{
970 msg_t *msg = msg_create(srv->srv_mclass, srv->srv_mflags | flags);
971
972 return msg;
973}
974
975/* ----------------------------------------------------------------------
976 * 6) Server transactions
977 */
978
979struct auth_info
980{
981 nth_site_t *site;
982 nth_request_t *req;
983 http_t const *http;
984 char const *path;
985};
986
987static void nth_authentication_result(void *ai0, auth_status_t *as);
988
989static
990void nth_site_request(server_t *srv,
991 nth_site_t *site,
992 tport_t *tport,
993 msg_t *request,
994 http_t *http,
995 char const *path,
996 msg_t *response)
997{
998 auth_mod_t *am = site->site_auth;
999 nth_request_t *req;
1000 auth_status_t *as;
1001 struct auth_info *ai;
1002 size_t size = (am ? (sizeof *as) + (sizeof *ai) : 0) + (sizeof *req);
1003 int status;
1004
1005 req = su_zalloc(srv->srv_home, size);
1006
1007 if (req == NULL((void*)0)) {
1008 server_reply(srv, tport, request, response, HTTP_500_INTERNAL_SERVER500, http_500_internal_server);
1009 return;
1010 }
1011
1012 if (am)
1013 as = auth_status_init(req + 1, sizeof *as), ai = (void *)(as + 1);
1014 else
1015 as = NULL((void*)0), ai = NULL((void*)0);
1016
1017 req->req_server = srv;
1018 req->req_method = http->http_request->rq_method;
1019 req->req_method_name = http->http_request->rq_method_name;
1020 req->req_url = http->http_request->rq_url;
1021 req->req_version = http->http_request->rq_version;
1022
1023 req->req_tport = tport_incref(tport);
1024 req->req_request = request;
1025 req->req_response = response;
1026
1027 req->req_status = 100;
1028 req->req_close =
1029 !srv->srv_persistent
1030 || http->http_request->rq_version != http_version_1_1
1031 || (http->http_connection &&
1032 msg_params_find(http->http_connection->k_items, "close"));
1033
1034 if (am) {
1035 static auth_challenger_t const http_server_challenger[] =
1036 {{ HTTP_401_UNAUTHORIZED401, http_401_unauthorized, http_www_authenticate_class }};
1037
1038 req->req_as = as;
1039
1040 as->as_method = http->http_request->rq_method_name;
1041 as->as_uri = path;
1042
1043 if (http->http_payload) {
1044 as->as_body = http->http_payload->pl_data;
1045 as->as_bodylen = http->http_payload->pl_len;
1046 }
1047
1048 auth_mod_check_client(am, as,
1049 http->http_authorization,
1050 http_server_challenger);
1051
1052 if (as->as_status == 100) {
1053 /* Stall transport - do not read more requests */
1054 if (tport_queuelen(tport) * 2 >= srv->srv_queuesize)
1055 tport_stall(tport);
1056
1057 as->as_callback = nth_authentication_result;
1058 as->as_magic = ai;
1059 ai->site = site;
1060 ai->req = req;
1061 ai->http = http;
1062 ai->path = path;
1063 return;
1064 }
1065 else if (as->as_status) {
1066 assert(as->as_status >= 200)((as->as_status >= 200) ? (void) (0) : __assert_fail ("as->as_status >= 200"
, "nth_server.c", 1066, __PRETTY_FUNCTION__))
;
1067 nth_request_treply(req, as->as_status, as->as_phrase,
1068 HTTPTAG_HEADER((http_header_t *)as->as_response)httptag_header, httptag_header_v(((http_header_t *)as->as_response
))
,
1069 HTTPTAG_HEADER((http_header_t *)as->as_info)httptag_header, httptag_header_v(((http_header_t *)as->as_info
))
,
1070 TAG_END()(tag_type_t)0, (tag_value_t)0);
1071 nth_request_destroy(req);
1072 return;
1073 }
1074 }
1075
1076 req->req_in_callback = 1;
1077 status = site->site_callback(site->site_magic, site, req, http, path);
1078 req->req_in_callback = 0;
1079
1080 if (status != 0 && (status < 100 || status >= 600))
1081 status = 500;
1082
1083 if (status != 0 && req->req_status < 200) {
1084 nth_request_treply(req, status, NULL((void*)0), TAG_END()(tag_type_t)0, (tag_value_t)0);
1085 }
1086
1087 if (req->req_status < 100) {
1088 /* Stall transport - do not read more requests */
1089 if (tport_queuelen(tport) * 2 >= srv->srv_queuesize)
1090 tport_stall(tport);
1091 }
1092
1093 if (status >= 200 || req->req_destroyed)
1094 nth_request_destroy(req);
1095}
1096
1097static void nth_authentication_result(void *ai0, auth_status_t *as)
1098{
1099 struct auth_info *ai = ai0;
1100 nth_request_t *req = ai->req;
1101 int status;
1102
1103 if (as->as_status != 0) {
1104 assert(as->as_status >= 300)((as->as_status >= 300) ? (void) (0) : __assert_fail ("as->as_status >= 300"
, "nth_server.c", 1104, __PRETTY_FUNCTION__))
;
1105 nth_request_treply(req, status = as->as_status, as->as_phrase,
1106 HTTPTAG_HEADER((http_header_t *)as->as_response)httptag_header, httptag_header_v(((http_header_t *)as->as_response
))
,
1107 TAG_END()(tag_type_t)0, (tag_value_t)0);
1108 }
1109 else {
1110 req->req_in_callback = 1;
1111 status = ai->site->site_callback(ai->site->site_magic,
1112 ai->site,
1113 ai->req,
1114 ai->http,
1115 ai->path);
1116 req->req_in_callback = 0;
1117
1118 if (status != 0 && (status < 100 || status >= 600))
1119 status = 500;
1120
1121 if (status != 0 && req->req_status < 200) {
1122 nth_request_treply(req, status, NULL((void*)0), TAG_END()(tag_type_t)0, (tag_value_t)0);
1123 }
1124 }
1125
1126 if (status >= 200 || req->req_destroyed)
1127 nth_request_destroy(req);
1128}
1129
1130void nth_request_destroy(nth_request_t *req)
1131{
1132 if (req == NULL((void*)0))
1133 return;
1134
1135 if (req->req_status < 200)
1136 nth_request_treply(req, HTTP_500_INTERNAL_SERVER500, http_500_internal_server, TAG_END()(tag_type_t)0, (tag_value_t)0);
1137
1138 req->req_destroyed = 1;
1139
1140 if (req->req_in_callback)
1141 return;
1142
1143 if (req->req_as)
1144 su_home_deinit(req->req_as->as_home);
1145
1146 tport_decref(&req->req_tport), req->req_tport = NULL((void*)0);
1147 msg_destroy(req->req_request), req->req_request = NULL((void*)0);
1148 msg_destroy(req->req_response), req->req_response = NULL((void*)0);
1149 su_free(req->req_server->srv_home, req);
1150}
1151
1152/** Return request authentication status.
1153 *
1154 * @param req pointer to HTTP request object
1155 *
1156 * @retval Status code
1157 *
1158 * @since New in @VERSION_1_12_4
1159 */
1160int nth_request_status(nth_request_t const *req)
1161{
1162 return req ? req->req_status : 400;
1163}
1164
1165/** Return request authentication status.
1166 *
1167 * @param req pointer to HTTP request object
1168 *
1169 * @retval Pointer to authentication status struct
1170 *
1171 * @note The authentication status struct is freed when the #nth_request_t
1172 * object is destroyed.
1173 *
1174 * @since New in @VERSION_1_12_4
1175 *
1176 * @sa AUTH
1177 */
1178auth_status_t *nth_request_auth(nth_request_t const *req)
1179{
1180 return req ? req->req_as : NULL((void*)0);
1181}
1182
1183http_method_t nth_request_method(nth_request_t const *req)
1184{
1185 return req ? req->req_method : http_method_invalid;
1186}
1187
1188msg_t *nth_request_message(nth_request_t *req)
1189{
1190 msg_t *retval = NULL((void*)0);
1191
1192 if (req)
1193 retval = msg_ref_create(req->req_request);
1194
1195 return retval;
1196}
1197
1198int nth_request_treply(nth_request_t *req,
1199 int status, char const *phrase,
1200 tag_type_t tag, tag_value_t value, ...)
1201{
1202 msg_t *response, *next = NULL((void*)0);
1203 http_t *http;
1204 int retval = -1;
1205 int req_close, close;
1206 ta_list ta;
1207 http_header_t const *as_info = NULL((void*)0);
1208
1209 if (req == NULL((void*)0) || status < 100 || status >= 600) {
1210 return -1;
1211 }
1212
1213 response = req->req_response;
1214 http = http_object(response);
1215
1216 if (status >= 200 && req->req_as)
1217 as_info = (http_header_t const *)req->req_as->as_info;
1218
1219 ta_start(ta, tag, value)do { tag_type_t ta_start__tag = (tag); tag_value_t ta_start__value
= (value); __builtin_va_start((ta).ap, (value)); while ((ta_start__tag
) == tag_next && (ta_start__value) != 0) { ta_start__tag
= ((tagi_t *)ta_start__value)->t_tag; if (ta_start__tag ==
tag_null || ta_start__tag == ((void*)0)) break; if (ta_start__tag
== tag_next) { ta_start__value = ((tagi_t *)ta_start__value)
->t_value; } else { ta_start__tag = tag_next; break; } } (
ta).tl->t_tag = ta_start__tag; (ta).tl->t_value = ta_start__value
; if (ta_start__tag != ((void*)0) && ta_start__tag !=
tag_null && ta_start__tag != tag_next) { va_list ta_start__ap
; __builtin_va_copy((ta_start__ap), ((ta).ap)); (ta).tl[1].t_tag
= tag_next; (ta).tl[1].t_value = (tag_value_t)tl_vlist(ta_start__ap
); __builtin_va_end(ta_start__ap); } else { (ta).tl[1].t_value
= 0; (ta).tl[1].t_value = (tag_value_t)0; } } while(0)
;
1220
1221 http_add_tl(response, http,
1222 HTTPTAG_SERVER(req->req_server->srv_server)httptag_server, httptag_server_v(req->req_server->srv_server
)
,
1223 HTTPTAG_HEADER(as_info)httptag_header, httptag_header_v((as_info)),
1224 ta_tags(ta)(ta).tl[0].t_tag, (ta).tl[0].t_value, (ta).tl[1].t_tag, (ta).
tl[1].t_value
);
1225
1226 if (http->http_payload && !http->http_content_length) {
1227 http_content_length_t *l;
1228 http_payload_t *pl;
1229 size_t len = 0;
1230
1231 for (pl = http->http_payload; pl; pl = pl->pl_next)
1232 len += pl->pl_len;
1233
1234 if (len > UINT32_MAX(4294967295U))
1235 goto fail;
1236
1237 l = http_content_length_create(msg_home(response)((su_home_t*)(response)), (uint32_t)len);
1238
1239 msg_header_insert(response, (msg_pub_t *)http, (msg_header_t *)l);
1240 }
1241
1242 if (req->req_method == http_method_head && http->http_payload) {
1243 http_payload_t *pl;
1244
1245 for (pl = http->http_payload; pl; pl = pl->pl_next)
1246 msg_header_remove(response, (msg_pub_t *)http, (msg_header_t *)pl);
1247 }
1248
1249 http_complete_response(response, status, phrase,
1250 http_object(req->req_request));
1251
1252 if (!http->http_date) {
1253 http_date_t date[1];
1254 http_date_init(date)->d_time = msg_now();
1255 msg_header_add_dup(response, (msg_pub_t *)http, (msg_header_t*)date);
1256 }
1257
1258 if (status < 200) {
1259 close = 0;
1260 next = server_msg_create(req->req_server, 0, NULL((void*)0), 0, NULL((void*)0), NULL((void*)0));
1261 }
1262 else {
1263 req_close = req->req_close;
1264
1265 close = (http->http_connection &&
1266 msg_params_find(http->http_connection->k_items, "close"));
1267
1268 if (req_close && !close && status >= 200) {
1269 close = 1;
1270 http_add_tl(response, http, HTTPTAG_CONNECTION_STR("close")httptag_connection_str, tag_str_v("close"), TAG_END()(tag_type_t)0, (tag_value_t)0);
1271 }
1272 }
1273
1274 msg_serialize(response, (msg_pub_t *)http);
1275
1276 retval = tport_tqsend(req->req_tport, response, next,
1277 TAG_IF(close, TPTAG_CLOSE_AFTER(1))!(close) ? tag_skip : tptag_close_after, tag_bool_v((1)),
1278 ta_tags(ta)(ta).tl[0].t_tag, (ta).tl[0].t_value, (ta).tl[1].t_tag, (ta).
tl[1].t_value
);
1279
1280 fail:
1281 ta_end(ta)((((ta).tl[1].t_value) ? (tl_vfree((tagi_t *)((ta).tl[1].t_value
))) : (void)0), (ta).tl[1].t_value = 0, __builtin_va_end((ta)
.ap))
;
1282
1283 if (retval == 0)
1284 req->req_status = status;
1285
1286 return retval;
1287}