NCBI C++ ToolKit
ncbi_connutil.c
Go to the documentation of this file.

Go to the SVN repository for this file.

1 /* $Id: ncbi_connutil.c 102053 2024-03-23 01:53:27Z lavr $
2  * ===========================================================================
3  *
4  * PUBLIC DOMAIN NOTICE
5  * National Center for Biotechnology Information
6  *
7  * This software/database is a "United States Government Work" under the
8  * terms of the United States Copyright Act. It was written as part of
9  * the author's official duties as a United States Government employee and
10  * thus cannot be copyrighted. This software/database is freely available
11  * to the public for use. The National Library of Medicine and the U.S.
12  * Government have not placed any restriction on its use or reproduction.
13  *
14  * Although all reasonable efforts have been taken to ensure the accuracy
15  * and reliability of the software and data, the NLM and the U.S.
16  * Government do not and cannot warrant the performance or results that
17  * may be obtained by using this software or data. The NLM and the U.S.
18  * Government disclaim all warranties, express or implied, including
19  * warranties of performance, merchantability or fitness for any particular
20  * purpose.
21  *
22  * Please cite the author in any work or product based on this material.
23  *
24  * ===========================================================================
25  *
26  * Author: Denis Vakatov, Anton Lavrentiev
27  *
28  * File Description:
29  * Auxiliary API, mostly CONN-, URL-, and MIME-related
30  * (see in "ncbi_connutil.h" for more details).
31  *
32  */
33 
34 #include "ncbi_ansi_ext.h"
35 #include "ncbi_connssl.h"
36 #include "ncbi_once.h"
37 #include "ncbi_servicep.h"
38 #include <connect/ncbi_connutil.h>
39 #include <ctype.h>
40 #include <errno.h>
41 #include <stdlib.h>
42 
43 #define NCBI_USE_ERRCODE_X Connect_Util
44 
45 
46 #define CONN_NET_INFO_MAGIC 0x600DCAFE
47 
48 #define SizeOf(arr) (sizeof(arr) / sizeof((arr)[0]))
49 
50 
51 static const char kDigits[] = "0123456789";
52 
53 
55  (unsigned int)
57  (unsigned int)
58  ((DEF_CONN_TIMEOUT - (unsigned int) DEF_CONN_TIMEOUT) * 1.0e6)
59 };
60 
61 
62 static TNCBI_BigCount s_FWPorts[1024 / sizeof(TNCBI_BigCount)] = { 0 };
63 
64 
65 #if 0
66 static char* x_getenv(const char* name)
67 {
68  char* env = getenv(name);
69  CORE_TRACEF(("getenv(\"%s\") = %s%s%s", name,
70  &"\""[!env], env ? env : "NULL", &"\""[!env]));
71  return env;
72 }
73 #else
74 # define x_getenv getenv
75 #endif
76 
77 
78 
79 /****************************************************************************
80  * ConnNetInfo API
81  */
82 
83 
84 static int/*bool*/ x_StrcatCRLF(char** dstp, const char* src, int/*bool*/ pre)
85 {
86  char* dst = *dstp;
87  size_t dstlen = dst && *dst ? strlen(dst) : 0;
88  size_t srclen = src && *src ? strlen(src) : 0;
89  if (dstlen && dst[dstlen - 1] == '\n') {
90  if (--dstlen && dst[dstlen - 1] == '\r')
91  --dstlen;
92  }
93  while (srclen) {
94  if (!isspace((unsigned char)(*src)))
95  break;
96  --srclen;
97  ++src;
98  }
99  while (srclen) {
100  if (!isspace((unsigned char) src[srclen - 1]))
101  break;
102  --srclen;
103  }
104  if (dstlen | srclen) {
105  size_t len;
106  char* temp;
107  len = (dstlen ? dstlen + 2 : 0) + (srclen ? srclen + 2 : 0) + 1;
108  if (!(temp = (char*)(dst ? realloc(dst, len) : malloc (len))))
109  return 0/*failure*/;
110  dst = temp;
111  if (srclen && pre) {
112  memmove(dst + srclen + 2, dst, dstlen);
113  memcpy(temp, src, srclen);
114  temp += srclen;
115  memcpy(temp, "\r\n", 2 + !dstlen);
116  temp += 2;
117  }
118  if (dstlen) {
119  temp += dstlen;
120  memcpy(temp, "\r\n", 3);
121  temp += 2;
122  }
123  if (srclen && !pre) {
124  memcpy(temp, src, srclen);
125  temp += srclen;
126  memcpy(temp, "\r\n", 3);
127  }
128  }
129  *dstp = dst;
130  return 1/*success*/;
131 }
132 
133 
134 static const char* x_strncpy0(char* dst, const char* src, size_t dst_size)
135 {
136  size_t src_len = strlen(src);
137  const char* retval = dst;
138  assert(dst_size);
139  if (src_len >= dst_size) {
140  src_len = dst_size - 1;
141  retval = 0;
142  }
143  strncpy0(dst, src, src_len);
144  return retval;
145 }
146 
147 
148 /* Replace any non-alpha / non-digit with '_' */
149 static int/*bool*/ x_mkenv(char* str, size_t len)
150 {
151  int/*bool*/ made = 0/*false*/;
152  const char* end = str + len;
153  while (str != end) {
154  unsigned char c = (unsigned char)(*str);
155  assert(!isspace(c));
156  if (!isalpha(c) && !isdigit(c) && !(c == '_')) {
157  made = 1/*true*/;
158  *str = '_';
159  }
160  ++str;
161  }
162  return made;
163 }
164 
165 
166 /* Either strncasecmp() or strncmp() */
167 typedef int (*FStrNCmp)(const char* s1, const char* s2, size_t n);
168 
169 /* The "*generic" parameter:
170  * [in]
171  * if "svclen" == 0: ignored;
172  * if "svclen" != 0, is a boolean "service_only" (if non-zero then no
173  * fallback to generic search in the "CONN_param" environment, or the
174  * "[CONN]param" registry entry, gets performed);
175  * [out]
176  * 0 if the search ended up with a service-specific value returned (always
177  * so if the [in] value was non-zero);
178  * 1 if the search ended up looking at the "CONN_param" enviroment or the
179  * "[CONN]param" registry entry (always so if "svclen" == 0).
180  *
181  * The "strncompar" parameter:
182  * if strncmp()'s address is passed in, "param" is assumed all-CAPS and is
183  * not uppercased unnecessarily (compared to when strncasecmp() passed in).
184  */
185 static const char* x_GetValue(const char* svc/*ign if !svclen*/, size_t svclen,
186  const char* param, char* value,
187  size_t value_size, const char* def_value,
188  int* /*bool*/ generic, FStrNCmp strncompar)
189 {
190  const char* val, *rv;
191  char buf[128];
192  size_t parlen;
193  char* s;
194 
195  assert(!svclen || (svclen == strlen(svc)));
196  assert(value && value_size && !*value);
197  assert(param && *param);
198  assert(generic);
199 
200  parlen = strlen(param) + 1;
201  if (svclen) {
202  /* Service-specific inquiry */
203  size_t len = svclen + 1 + parlen;
204  char tmp[sizeof(buf)];
205  int/*bool*/ end, e;
206 
207  if (strncompar(param, DEF_CONN_REG_SECTION "_",
208  sizeof(DEF_CONN_REG_SECTION)) != 0) {
209  len += sizeof(DEF_CONN_REG_SECTION);
210  end = 0/*false*/;
211  } else
212  end = 1/*true*/;
213  if (len > sizeof(buf))
214  return 0;
215 
216  /* First, search the environment for 'service_CONN_param' */
217  s = (char*) memcpy(buf, svc, svclen) + svclen;
218  e = x_mkenv(buf, svclen);
219  memcpy(tmp, buf, svclen);
220  *s = '\0';
221  strupr(buf);
222  *s++ = '_';
223  if (!end) {
224  memcpy(s, DEF_CONN_REG_SECTION, sizeof(DEF_CONN_REG_SECTION) - 1);
225  s += sizeof(DEF_CONN_REG_SECTION) - 1;
226  *s++ = '_';
227  end = *generic;
228  }
229  *generic = 0/*false*/;
230  memcpy(s, param, parlen);
231  if (strncompar != strncmp)
232  strupr(s);
234  if ((val = x_getenv(buf)) != 0
235  || (memcmp(buf, tmp, svclen) != 0
236  && (val = x_getenv((char*) memcpy(buf, tmp, svclen))) != 0)){
237  rv = x_strncpy0(value, val, value_size);
238  CORE_UNLOCK;
239  return rv;
240  }
241  CORE_UNLOCK;
242  assert(memcmp(buf, tmp, svclen) == 0);
243 
244  /* Next, search for 'CONN_param' in '[service]' registry section */
245  if (e)
246  memcpy(buf, svc, svclen); /* re-copy */
247  buf[svclen++] = '\0';
248  s = buf + svclen;
249  rv = CORE_REG_GET(buf, s, value, value_size, end ? def_value : 0);
250  if (*value || end)
251  return rv;
252  *generic = 1/*true*/;
253  } else {
254  *generic = 1/*true*/;
255  /* Common case. Form 'CONN_param' */
256  if (strncompar(param, DEF_CONN_REG_SECTION "_",
257  sizeof(DEF_CONN_REG_SECTION)) != 0) {
258  if (sizeof(DEF_CONN_REG_SECTION) + parlen > sizeof(buf))
259  return 0;
260  s = buf;
261  memcpy(s, DEF_CONN_REG_SECTION, sizeof(DEF_CONN_REG_SECTION) - 1);
262  s += sizeof(DEF_CONN_REG_SECTION) - 1;
263  *s++ = '_';
264  } else if (strncompar != strncmp) {
265  if (parlen > sizeof(buf))
266  return 0;
267  s = buf;
268  } else
269  s = (char*) param; /*NB: "s" is "const char*" from this point on*/
270  if (s != param) {
271  memcpy(s, param, parlen);
272  if (strncompar != strncmp)
273  strupr(s);
274  s = buf;
275  }
276  }
277 
278  /* Environment search for 'CONN_param' */
280  if ((val = x_getenv(s)) != 0) {
281  rv = x_strncpy0(value, val, value_size);
282  CORE_UNLOCK;
283  return rv;
284  }
285  CORE_UNLOCK;
286 
287  /* Last resort: Search for 'param' in default registry section [CONN] */
288  s += sizeof(DEF_CONN_REG_SECTION);
289  return CORE_REG_GET(DEF_CONN_REG_SECTION, s, value, value_size, def_value);
290 }
291 
292 
293 /* Trim leading and trailing spaces first, then drop enveloping quotes, if any.
294  * Do not trim any spaces within the quotes, though. */
295 static void x_Trim(char* str)
296 {
297  size_t len;
298  char* ptr = str;
299  /* surrounding whitespace first */
300  while (*ptr && isspace((unsigned char)(*ptr)))
301  ++ptr;
302  len = strlen(ptr);
303  while (len && isspace((unsigned char) ptr[len - 1]))
304  --len;
305  assert(!*ptr == !len);
306  /* then strip enveloping quotes, if any */
307  if (len > 1 && (*ptr == '"' || *ptr == '\'') && ptr[len - 1] == *ptr)
308  len -= 2, ++ptr;
309  if (ptr != str && len)
310  memmove(str, ptr, len);
311  str[len] = '\0';
312 }
313 
314 
315 static const char* s_GetValue(const char* svc, size_t svclen,
316  const char* param, char* value,
317  size_t value_size, const char* def_value,
318  int* /*bool*/ generic, FStrNCmp strncompar)
319 {
320  const char* retval = x_GetValue(svc, svclen, param, value,
321  value_size, def_value, generic,strncompar);
322  assert(!retval || retval == value);
323  if (retval) {
324  assert(value == retval);
325  if (*value)
326  x_Trim(value);
327  }
328  if (*value) {
329  CORE_TRACEF(("ConnNetInfo(%s%.*s%s%s=\"%s\"): %s%s%s", &"\""[!svclen],
330  (int) svclen, svc, svclen ? "\", " : "", param, value,
331  &"\""[!retval], retval ? retval : "NULL",
332  &"\""[!retval]));
333  }
334  return retval;
335 }
336 
337 
338 const char* ConnNetInfo_GetValueInternal(const char* service,const char* param,
339  char* value, size_t value_size,
340  const char* def_value)
341 {
342  int/*bool*/ service_only = 0/*false*/;
343  assert(!service || (!NCBI_HasSpaces(service, strlen(service))
344  && !strpbrk(service, "?*[")));
345  assert(param && *param && !NCBI_HasSpaces(param, strlen(param)));
346  assert(value && value_size);
347  *value = '\0';
348  return s_GetValue(service, service && *service ? strlen(service) : 0,
349  param, value, value_size, def_value,
350  &service_only, strncmp);
351 }
352 
353 
354 /* No "CONN_param" environment or "[CONN]param" registry fallbacks */
355 const char* ConnNetInfo_GetValueService(const char* service, const char* param,
356  char* value, size_t value_size,
357  const char* def_value)
358 {
359  const char* retval;
360  int/*bool*/ service_only = 1/*true*/;
361  assert(service && *service && !NCBI_HasSpaces(service, strlen(service))
362  && !strpbrk(service, "?*["));
363  assert(param && *param && !NCBI_HasSpaces(param, strlen(param)));
364  assert(value && value_size);
365  *value = '\0';
366  retval = s_GetValue(service, strlen(service),
367  param, value, value_size, def_value,
368  &service_only, strncmp);
369  assert(!service_only);
370  return retval;
371 }
372 
373 
374 extern const char* ConnNetInfo_GetValue(const char* service, const char* param,
375  char* value, size_t value_size,
376  const char* def_value)
377 {
378  int/*bool*/ service_only;
379  const char* retval;
380  size_t svclen;
381 
382  if (!value || !value_size)
383  return 0;
384  *value = '\0';
385  if (!param || !*param || NCBI_HasSpaces(param, strlen(param)))
386  return 0;
387 
388  if (service) {
389  if (!*service || strpbrk(service, "?*["))
390  svclen = 0;
391  else if (!(service = SERV_ServiceName(service)))
392  return 0;
393  else
394  verify((svclen = strlen(service)) != 0);
395  } else
396  svclen = 0;
397 
398  service_only = 0/*false*/;
399  retval = s_GetValue(service, svclen,
400  param, value, value_size, def_value,
401  &service_only, strncasecmp);
402  if (svclen)
403  free((void*) service);
404  return retval;
405 }
406 
407 
408 extern int/*bool*/ ConnNetInfo_Boolean(const char* str)
409 {
410  char c;
411  switch (!str ? 6 : !*str ? 0 : strnlen(str, 6)) {
412  case 0:
413  return 0/*false*/;
414  case 1:
415  if (*str == '1')
416  return 1/*true*/;
417  if (*str == '0')
418  return 0/*false*/;
419  c = toupper((unsigned char)(*str));
420  if (c == 'Y' || c == 'T')
421  return 1/*true*/;
422  if (c == 'N' || c == 'F')
423  return 0/*false*/;
424  break;
425  case 2:
426  if (strcasecmp(str, "ON") == 0)
427  return 1/*true*/;
428  if (strcasecmp(str, "NO") == 0)
429  return 0/*false*/;
430  break;
431  case 3:
432  if (strcasecmp(str, "YES") == 0)
433  return 1/*true*/;
434  if (strcasecmp(str, "OFF") == 0)
435  return 0/*false*/;
436  break;
437  case 4:
438  if (strcasecmp(str, "TRUE") == 0)
439  return 1/*true*/;
440  break;
441  case 5:
442  if (strcasecmp(str, "FALSE") == 0)
443  return 0/*false*/;
444  break;
445  default:
446  break;
447  }
448 #if defined(_DEBUG) && !defined(NDEBUG)
450  ("Unrecognized boolean value %s%s%s treated as FALSE",
451  &"\""[!str], str ? str : "NULL", &"\""[!str]));
452 #endif /*_DEBUG && !NDEBUG*/
453  return 0/*false*/;
454 }
455 
456 
457 static EURLScheme x_ParseScheme(const char* str, size_t len)
458 {
459  assert(str && (!str[len] || str[len] == ':'));
460  switch (len) {
461  case 5:
462  if (strncasecmp(str, "https", len) == 0)
463  return eURL_Https;
464  break;
465  case 4:
466  if (strncasecmp(str, "http", len) == 0)
467  return eURL_Http;
468  if (strncasecmp(str, "file", len) == 0)
469  return eURL_File;
470  break;
471  case 3:
472  if (strncasecmp(str, "ftp", len) == 0)
473  return eURL_Ftp;
474  break;
475  default:
476  break;
477  }
478  return eURL_Unspec;
479 }
480 
481 
482 static EFWMode x_ParseFirewall(const char* str, int/*bool*/ generic)
483 {
484  const char* ptr;
485  if (!*str) /*NB: not actually necessary but faster*/
486  return eFWMode_Legacy;
487  if (strcasecmp(str, "adaptive") == 0)
488  return eFWMode_Adaptive;
489  if (strcasecmp(str, "firewall") == 0)
490  return eFWMode_Firewall;
491  if (strcasecmp(str, "fallback") == 0)
492  return eFWMode_Fallback;
493  ptr = str;
494  for (;;) {
495  int n;
496  unsigned short port;
497  if (sscanf(ptr, "%hu%n", &port, &n) < 1 || port < 2)
498  break;
499  if (generic)
500  SERV_AddFirewallPort(port);
501  ptr += n;
502  if (!*(ptr += strspn(ptr, " \t")))
503  return eFWMode_Fallback;
504  }
506 }
507 
508 
509 static const char* x_ProxyStr(EBProxyType proxy)
510 {
511  switch (proxy) {
512  case fProxy_None:
513  break;
514  case fProxy_Http:
515  return "HTTP";
516  case fProxy_Https:
517  return "HTTPS";
519  return "HTTP(S)";
520  default:
521  assert(0);
522  break;
523  }
524  return "NONE";
525 }
526 
527 
528 /* Return -1 if nothing to do; 0 if failed; 1 if succeeded.
529  * NB: This call must be service-agnostic as the result gets cached for all. */
530 static int/*tri-state*/ x_SetupHttpProxy(SConnNetInfo* info,
531  const char* env, EBProxyType proxy)
532 {
533  SConnNetInfo* x_info;
534  const char* val;
535  int parsed;
536 
537  assert(env && *env && proxy && !(info->http_proxy_mask & proxy));
538 
540  if (!(val = x_getenv(env)) || !*val
541  || strcmp(val, "''") == 0 || strcmp(val, "\"\"") == 0) {
542  CORE_UNLOCK;
543  return -1/*noop*/;
544  }
545  if (!(val = strdup(val))) {
546  CORE_UNLOCK;
547  return 0/*failure*/;
548  }
549  CORE_UNLOCK;
550 
551  if (!(x_info = ConnNetInfo_CloneInternal(info))) {
552  free((void*) val);
553  return 0/*failure*/;
554  }
555  if (*val == '"' || *val == '\'') {
556  /* strip enveloping quotes, if any: note that '' and "" have already
557  * been excluded, so the resulting string is always non-empty... */
558  size_t len = strlen(val);
559  assert(len);
560  if (val[--len] == *val) {
561  memmove((char*) val, val + 1, --len);
562  ((char*) val)[len] = '\0';
563  assert(len);
564  }
565  }
566 
567  x_info->req_method = eReqMethod_Any;
568  x_info->scheme = eURL_Unspec;
569  x_info->user[0] = '\0';
570  x_info->pass[0] = '\0';
571  x_info->host[0] = '\0';
572  x_info->port = 0;
573  x_info->path[0] = '\0';
574  parsed = ConnNetInfo_ParseURL(x_info, val);
575  assert(!(parsed & ~1)); /*0|1*/
576 
577  if (parsed
578  && (!x_info->host[0] || !x_info->port
579  || (x_info->path[0]
580  && (x_info->path[0] != '/' || x_info->path[1])))) {
581  parsed = 0/*failure*/;
582  }
583  if (parsed
584  && (!x_info->scheme/*eURL_Unspec*/ || x_info->scheme == eURL_Http)){
585  assert(!NCBI_HasSpaces(x_info->host, strlen(x_info->host)));
586  if (!info->http_proxy_mask) {
587  /* first time here, just save */
588  info->http_proxy_port = x_info->port;
589  strcpy(info->http_proxy_host, x_info->host);
590  strcpy(info->http_proxy_user, x_info->user);
591  strcpy(info->http_proxy_pass, x_info->pass);
592  } else if (info->http_proxy_port != x_info->port ||
593  strcasecmp(info->http_proxy_host, x_info->host) != 0 ||
594  strcmp (info->http_proxy_user, x_info->user) != 0 ||
595  strcmp (info->http_proxy_pass, x_info->pass) != 0) {
597  ("ConnNetInfo($%s): Non-identical proxy setting"
598  " \"%s\" compared to %s", env, val,
599  x_ProxyStr(info->http_proxy_mask)));
600  parsed = 0/*failure*/;
601  }
602  if (parsed) {
603  info->http_proxy_mask |= proxy;
604  CORE_TRACEF(("ConnNetInfo($%s): \"%s\" [%s]->[%s]", env, val,
605  x_ProxyStr(proxy),
606  x_ProxyStr(info->http_proxy_mask)));
607  }
608  } else {
609  if (parsed
610  && (proxy != fProxy_Https || x_info->scheme != eURL_Https)) {
611  assert(x_info->scheme && x_info->scheme != eURL_Http);
612  parsed = 0/*failure*/;
613  }
614  CORE_LOGF_X(parsed ? 15 : 10, eLOG_Error,
615  ("ConnNetInfo($%s): %s \"%s\"", env, parsed
616  ? "Unable to utilize secure HTTPS proxy"
617  : "Unrecognized HTTP proxy specification", val));
618  parsed = 0/*failure*/;
619  }
620  ConnNetInfo_Destroy(x_info);
621  free((void*) val);
622  return parsed;
623 }
624 
625 
626 /* -1: not set; 0: error; 1: set okay */
627 static int/*tri-state*/ x_SetupSystemHttpProxy(SConnNetInfo* info)
628 {
629  static volatile int s_ProxySet = 0/*-1:err; 0:not yet set; 1:set*/;
630  static EProxyType s_ProxyMask = 0/*!=0 when set non-empty*/;
631  static char s_ProxyHost[sizeof(info->http_proxy_host)];
632  static unsigned short s_ProxyPort;
633  static char s_ProxyUser[sizeof(info->http_proxy_user)];
634  static char s_ProxyPass[sizeof(info->http_proxy_pass)];
635  int rv;
636 
637  if (!info) {
638  /* A special "reset" entry point for testing */
640  s_ProxyPass[0] = '\0';
641  s_ProxyUser[0] = '\0';
642  s_ProxyPort = 0;
643  s_ProxyHost[0] = '\0';
644  s_ProxyMask = 0;
645  s_ProxySet = 0;
646  CORE_UNLOCK;
647  return 0;
648  }
649 
650  assert(!info->http_proxy_mask &&
651  !info->http_proxy_port &&
652  !info->http_proxy_host[0]);
653  if (info->http_proxy_skip)
654  return -1/*noop*/;
655 
657  if (s_ProxySet) {
658  if (s_ProxySet < 0)
659  rv = !info->http_proxy_leak ? 0/*error*/ : -1/*noop*/;
660  else if (!s_ProxyMask)
661  rv = -1/*noop*/;
662  else {
663  rv = 1/*okay*/;
664  info->http_proxy_mask = s_ProxyMask;
665  info->http_proxy_port = s_ProxyPort;
666  strcpy(info->http_proxy_host, s_ProxyHost);
667  strcpy(info->http_proxy_user, s_ProxyUser);
668  strcpy(info->http_proxy_pass, s_ProxyPass);
669  }
670  CORE_UNLOCK;
671  return rv;
672  }
673  CORE_UNLOCK;
674 
675  rv = x_SetupHttpProxy(info, "http_proxy", fProxy_Http);
676  assert(!(rv <= 0) ^ !info->http_proxy_mask);
677  if (rv) {
678  int rvs = x_SetupHttpProxy(info, "https_proxy", fProxy_Https);
679  if (0 <= rvs)
680  rv = rvs;
681  }
682 
684  if (!s_ProxySet) {
685  if (!rv)
686  s_ProxySet = -1/*error*/;
687  else {
688  if (rv > 0) {
689  strcpy(s_ProxyPass, info->http_proxy_pass);
690  strcpy(s_ProxyUser, info->http_proxy_user);
691  strcpy(s_ProxyHost, info->http_proxy_host);
692  s_ProxyPort = info->http_proxy_port;
693  s_ProxyMask = info->http_proxy_mask;
694  assert(s_ProxyMask);
695  } else
696  assert(!s_ProxyMask);
697  s_ProxySet = 1/*set (incl.none)*/;
698  }
699  }
700  CORE_UNLOCK;
701 
702  return rv || !info->http_proxy_leak ? rv : -1/*noop*/;
703 }
704 
705 
706 static const char* x_GetReferer(char* str, size_t size)
707 {
708  int generic;
709  if (g_CORE_GetReferer) {
710  const char* referer = g_CORE_GetReferer();
711  assert(!referer || *referer);
712  if (referer)
713  return referer;
714  }
715  /* default referer ([in] "generic" irrelevant), all error(s) ignored */
716  *str = '\0';
717  generic = 0;
719  DEF_CONN_HTTP_REFERER, &generic, strncmp);
720  assert(generic);
721  return *str ? strdup(str) : 0;
722 }
723 
724 
725 static void x_DestroyNetInfo(SConnNetInfo* info, unsigned int magic)
726 {
727  assert(info);
728  /* do not free() fields if there's a version skew (offsets maybe off) */
729  if (magic == CONN_NET_INFO_MAGIC) {
730  if (info->http_user_header) {
731  free((void*) info->http_user_header);
732  info->http_user_header = 0;
733  }
734  if (info->http_referer) {
735  free((void*) info->http_referer);
736  info->http_referer = 0;
737  }
738  info->magic++;
739  }
740  free(info);
741 }
742 
743 
744 #ifdef __GNUC__
745 inline
746 #endif /*__GNUC__*/
747 static int/*bool*/ s_InfoIsValid(const SConnNetInfo* info)
748 {
749  if (!info)
750  return 0/*false*/;
751  assert(info->magic == CONN_NET_INFO_MAGIC);
752  return info->magic == CONN_NET_INFO_MAGIC ? 1/*true*/ : 0/*false*/;
753 }
754 
755 
756 /*fwdecl*/
757 static int/*bool*/ x_SetArgs(SConnNetInfo* info, const char* args);
758 
759 /* Note that all PARAMS are all-CAPS here */
761 {
762 #define REG_VALUE(name, value, def_value) \
763  generic = 0; \
764  *value = '\0'; \
765  if (!s_GetValue(service, len, \
766  name, value, sizeof(value), def_value, \
767  &generic, strncmp)) \
768  goto err/*memory or truncation error*/
769 
770  char str[(CONN_PATH_LEN + 1)/2];
771  int/*bool*/ generic;
773  size_t len;
774  long val;
775  double dbl;
776  char* e;
777 
778  len = service && *service ? strlen(service) : 0;
779  assert(!len || (!NCBI_HasSpaces(service, len)
780  && !strpbrk(service, "?*[")));
781 
782  /* NB: created *NOT* cleared up with all 0s */
783  if (!(info = (SConnNetInfo*) malloc(sizeof(*info) + len)))
784  return 0/*failure*/;
785  info->magic = 0;
786  info->unused = 0/*MBZ*/;
787  info->reserved = 0/*MBZ*/;
788  info->http_referer = 0;
789  info->http_user_header = 0;
790 
791  /* store the service name, which this structure is being created for */
792  memcpy((char*) info->svc, service ? service : "", len + 1);
793 
794  /* client host: default */
795  info->client_host[0] = '\0';
796 
797  /* request method */
799  if (!*str || strcasecmp(str, "ANY") == 0)
800  info->req_method = eReqMethod_Any;
801  else if (strcasecmp(str, "POST") == 0)
802  info->req_method = eReqMethod_Post;
803  else if (strcasecmp(str, "GET") == 0)
804  info->req_method = eReqMethod_Get;
805  else /* NB: HEAD, CONNECT, etc not allowed here */
806  goto err;
807 
808  /* scheme */
809  info->scheme = eURL_Unspec;
810 
811  /* external mode */
813  info->external = ConnNetInfo_Boolean(str) ? 1 : 0;
814 
815  /* firewall mode */
817  info->firewall = x_ParseFirewall(str, generic);
818 
819  /* stateless client */
821  info->stateless = ConnNetInfo_Boolean(str) ? 1 : 0;
822 
823  /* prohibit use of the local load balancer */
825  info->lb_disable = ConnNetInfo_Boolean(str) ? 1 : 0;
826 
827  /* HTTP version */
829  info->http_version = *str && atoi(str) == 1 ? 1 : 0;
830 
831  /* level of debug printout */
833  if (!*str)
834  info->debug_printout = eDebugPrintout_None;
835  else if (strcasecmp(str, "SOME") == 0)
836  info->debug_printout = eDebugPrintout_Some;
837  else if (strcasecmp(str, "DATA") == 0 || strcasecmp(str, "ALL") == 0)
838  info->debug_printout = eDebugPrintout_Data;
839  else {
840  info->debug_printout = ConnNetInfo_Boolean(str)
843  }
844 
845  /* push HTTP auth tags */
847  info->http_push_auth = ConnNetInfo_Boolean(str) ? 1 : 0;
848 
849  /* HTTP proxy leakout */
851  info->http_proxy_leak = ConnNetInfo_Boolean(str) ? 1 : 0;
852 
853  /* HTTP proxy skip */
855  info->http_proxy_skip = ConnNetInfo_Boolean(str) ? 1 : 0;
856 
857  /* Which of "$http_proxy" / "$https_proxy" was loaded */
858  info->http_proxy_mask = fProxy_None/*0*/;
859 
860  /* username */
862 
863  /* password */
865 
866  /* hostname */
868  if (NCBI_HasSpaces(info->host, strlen(info->host))) {
870  ("[ConnNetInfo_Create%s%s%s] Invalid host specification"
871  " \"%s\"", *info->svc ? "(\"" : "",
872  info->svc, *info->svc ? "\")" : "", info->host));
873  goto err;
874  }
875 
876  /* port # */
878  errno = 0;
879  if (*str && (val = (long) strtoul(str, &e, 10)) > 0 && !errno
880  && !*e && val < (1 << 16)) {
881  info->port = (unsigned short) val;
882  } else
883  info->port = 0/*default*/;
884 
885  /* path */
887 
888  /* HTTP proxy server: set all blank for now */
889  info->http_proxy_host[0] = '\0';
890  info->http_proxy_port = 0;
891  info->http_proxy_user[0] = '\0';
892  info->http_proxy_pass[0] = '\0';
893 
894  /* max. # of attempts to establish connection */
896  val = atoi(str);
897  info->max_try = (unsigned short)(val > 0 ? val : DEF_CONN_MAX_TRY);
898 
899  /* connection timeout */
900  info->tmo = g_NcbiDefConnTimeout;
902  val = *str ? (long) strlen(str) : 0;
903  if (val < 3 || 8 < val
904  || strncasecmp(str, "infinite", (size_t) val) != 0) {
905  if (*str && (dbl = NCBI_simple_atof(str, &e)) >= 0.0 && !errno && !*e){
906  info->tmo.sec = (unsigned int) dbl;
907  info->tmo.usec = (unsigned int)((dbl - info->tmo.sec) * 1.0e6);
908  if (dbl && !(info->tmo.sec | info->tmo.usec))
909  info->tmo.usec = 1/*protect from underflow*/;
910  }
911  info->timeout = &info->tmo;
912  } else
913  info->timeout = kInfiniteTimeout/*0*/;
914 
915  /* HTTP user header */
917  if (!x_StrcatCRLF((char**) &info->http_user_header, str, 0))
918  goto err;
919 
920  /* HTTP referer */
921  info->http_referer = x_GetReferer(str, sizeof(str));
922 
923  /* credentials */
924  info->credentials = 0;
925 
926  /* magic: the "info" is fully inited and ready to use */
927  info->magic = CONN_NET_INFO_MAGIC;
928 
929  /* args */
931  if (!x_SetArgs(info, str))
932  goto err;
933 
934  /* HTTP proxy from process environment */
935  if (!(val = x_SetupSystemHttpProxy(info)))
936  goto err;
937  if (val < 0) {
938  /* proxy wasn't defined; try loading it from the registry */
939  assert(!info->http_proxy_mask &&
940  !info->http_proxy_port &&
941  !info->http_proxy_host[0]);
942 
943  /* HTTP proxy from legacy settings */
944  REG_VALUE(REG_CONN_HTTP_PROXY_HOST, info->http_proxy_host,
946  if (NCBI_HasSpaces(info->http_proxy_host,
947  strlen(info->http_proxy_host))){
948  CORE_LOGF_X(12, info->http_proxy_leak ? eLOG_Warning : eLOG_Error,
949  ("[ConnNetInfo_Create%s%s%s] Invalid HTTP proxy"
950  " host specification \"%s\"",
951  *info->svc ? "(\"" : "", info->svc,
952  *info->svc ? "\")" : "", info->http_proxy_host));
953  if (!info->http_proxy_leak)
954  goto err;
955  info->http_proxy_host[0] = '\0';
956  }
957  if (info->http_proxy_host[0]) {
959  errno = 0;
960  if (*str && (val = (long) strtoul(str, &e, 10)) > 0
961  && !errno && !*e && val < (1 << 16)) {
962  info->http_proxy_port = (unsigned short) val;
963  } else
964  info->http_proxy_port = 0/*none*/;
965  /* HTTP proxy username */
966  REG_VALUE(REG_CONN_HTTP_PROXY_USER, info->http_proxy_user,
968  /* HTTP proxy password */
969  REG_VALUE(REG_CONN_HTTP_PROXY_PASS, info->http_proxy_pass,
971  }
972  } else
973  assert(info->http_proxy_mask);
974  return info;
975 
976  err:
978  return 0;
979 #undef REG_VALUE
980 }
981 
982 
984 {
986 }
987 
988 
989 extern SConnNetInfo* ConnNetInfo_Create(const char* service)
990 {
991  const char* x_service;
992  SConnNetInfo* retval;
993 
994  if (service && *service && !strpbrk(service, "?*[")) {
995  if (!(x_service = SERV_ServiceName(service)))
996  return 0;
997  assert(*x_service);
998  } else
999  x_service = 0;
1000 
1001  retval = ConnNetInfo_CreateInternal(x_service);
1002 
1003  if (x_service)
1004  free((void*) x_service);
1005  return retval;
1006 }
1007 
1008 
1010  const char* user_header)
1011 {
1012  if (!s_InfoIsValid(info))
1013  return 0/*failure*/;
1014 
1015  if (info->http_user_header) {
1016  free((void*) info->http_user_header);
1017  info->http_user_header = 0;
1018  }
1019  return x_StrcatCRLF((char**) &info->http_user_header, user_header, 0);
1020 }
1021 
1022 
1024  const char* user_header)
1025 {
1026  if (!s_InfoIsValid(info))
1027  return 0/*failure*/;
1028  return x_StrcatCRLF((char**) &info->http_user_header, user_header, 0);
1029 }
1030 
1031 
1033  const char* user_header)
1034 {
1035  if (!s_InfoIsValid(info))
1036  return 0/*failure*/;
1037  return x_StrcatCRLF((char**) &info->http_user_header, user_header, 1);
1038 }
1039 
1040 
1041 static int/*bool*/ x_TagValueMatches(const char* oldval, size_t oldvallen,
1042  const char* newval, size_t newvallen)
1043 {
1044  assert(newvallen > 0);
1045  while (oldvallen > 0) {
1046  do {
1047  if (!isspace((unsigned char)(*oldval)))
1048  break;
1049  ++oldval;
1050  } while (--oldvallen > 0);
1051  if (oldvallen < newvallen)
1052  break;
1053  if (strncasecmp(oldval, newval, newvallen) == 0
1054  && (oldvallen == newvallen
1055  || isspace((unsigned char) oldval[newvallen]))) {
1056  return 1/*true*/;
1057  }
1058  assert(oldvallen > 0);
1059  do {
1060  if ( isspace((unsigned char)(*oldval)))
1061  break;
1062  ++oldval;
1063  } while (--oldvallen > 0);
1064  }
1065  return 0/*false*/;
1066 }
1067 
1068 
1074 };
1075 
1076 
1078  const char* user_header,
1079  enum EUserHeaderOp op)
1080 {
1081  int/*bool*/ retval;
1082  size_t newlinelen;
1083  size_t newhdrlen;
1084  char* newline;
1085  char* newhdr;
1086  size_t hdrlen;
1087  char* hdr;
1088 
1089  if (!s_InfoIsValid(info))
1090  return 0/*failure*/;
1091 
1092  if (!user_header || !(newhdrlen = strlen(user_header)))
1093  return 1/*success*/;
1094 
1095  if (!(hdr = (char*) info->http_user_header) || !(hdrlen = strlen(hdr))) {
1096  if (op == eUserHeaderOp_Delete)
1097  return 1/*success*/;
1098  if (!hdr && !(hdr = strdup("")))
1099  return 0/*failure*/;
1100  hdrlen = 0;
1101  }
1102  assert(hdr);
1103 
1104  /* NB: "user_header" can be part of "info->user_header",
1105  * so create a copy of it even for delete operations! */
1106  if (!(newhdr = (char*) malloc(newhdrlen + 1))) {
1107  retval = 0/*failure*/;
1108  goto out;
1109  }
1110  memcpy(newhdr, user_header, newhdrlen + 1);
1111 
1112  retval = 1/*assume best: success*/;
1113  for (newline = newhdr; *newline; newline += newlinelen) {
1114  char* eol = strchr(newline, '\n');
1115  char* eot = strchr(newline, ':');
1116  size_t newtaglen;
1117  char* newtagval;
1118  size_t linelen;
1119  size_t newlen;
1120  char* line;
1121  size_t off;
1122 
1123  /* line (tag) & taglen */
1124  newlinelen = (size_t)
1125  (eol ? eol - newline + 1 : newhdr + newhdrlen - newline);
1126  if (!eot || eot >= newline + newlinelen) {
1127  if (op != eUserHeaderOp_Delete)
1128  goto ignore;
1129  if (eol) {
1130  eot = eol;
1131  if (eot > newline && eot[-1] == '\r')
1132  eot--;
1133  } else
1134  eot = newhdr + newhdrlen;
1135  }
1136  if (!(newtaglen = (size_t)(eot - newline)))
1137  goto ignore;
1138 
1139  /* tag value */
1140  newtagval = newline + newtaglen;
1141  if (op != eUserHeaderOp_Delete) {
1142  assert(*newtagval == ':');
1143  while (++newtagval < newline + newlinelen) {
1144  if (!isspace((unsigned char)(*newtagval)))
1145  break;
1146  }
1147  switch (op) {
1150  newlen = newtagval < newline + newlinelen ? newlinelen : 0;
1151  break;
1152  case eUserHeaderOp_Extend:
1153  /* NB: how much _additional_ space would be required */
1154  if (!(newlen = newlinelen - (size_t)(newtagval - newline)))
1155  goto ignore;
1156  break;
1157  default:
1158  retval = 0/*failure*/;
1159  assert(0);
1160  goto out;
1161  }
1162  if (newlen && eol) {
1163  if (eol[-1] == '\r')
1164  newlen -= 2;
1165  else
1166  newlen--;
1167  assert(newlen);
1168  }
1169  } else
1170  newlen = 0;
1171 
1172  for (line = hdr; *line; line += linelen) {
1173  size_t taglen;
1174  char* temp;
1175  size_t len;
1176 
1177  eol = strchr(line, '\n');
1178  eot = strchr(line, ':');
1179 
1180  linelen = (size_t)(eol ? eol - line + 1 : hdr + hdrlen - line);
1181  if (!eot || eot >= line + linelen)
1182  continue;
1183 
1184  taglen = (size_t)(eot - line);
1185  if (newtaglen != taglen || strncasecmp(newline, line, taglen) != 0)
1186  continue;
1187  assert(0 < taglen && taglen <= linelen);
1188 
1189  if (newlen) {
1191  off = !eol ? 0 : eol[-1] != '\r' ? 1 : 2;
1192  if (op == eUserHeaderOp_Extend) {
1193  assert(line[taglen] == ':');
1194  taglen++;
1195  if (x_TagValueMatches(line + taglen, linelen-off - taglen,
1196  newtagval, newlen)) {
1197  goto ignore;
1198  }
1199  line += linelen - off;
1200  linelen = off;
1201  newlen++;
1202  len = 0;
1203  } else
1204  len = linelen - off;
1205  } else
1206  len = 0/*==newlen*/;
1207 
1208  off = (size_t)(line - hdr);
1209  if (len < newlen) {
1211  len = newlen - len;
1212  if (!(temp = (char*) realloc(hdr, hdrlen + len + 1))) {
1213  retval = 0/*failure*/;
1214  goto ignore;
1215  }
1216  hdr = temp;
1217  line = temp + off;
1218  memmove(line + len, line, hdrlen - off + 1);
1219  hdrlen += len;
1220  linelen += len;
1221  if (op == eUserHeaderOp_Extend) {
1222  memcpy(line + 1, newtagval, newlen - 1);
1223  *line = ' ';
1224  newlen = 0;
1225  break;
1226  }
1227  } else if (len > newlen) {
1229  hdrlen -= len;
1230  memmove(line + newlen, line + len, hdrlen - off + 1);
1231  hdrlen += newlen;
1232  }
1233  if (newlen) {
1235  memcpy(line, newline, newlen);
1236  newlen = 0;
1237  continue;
1238  }
1239 
1240  hdrlen -= linelen;
1241  memmove(line, line + linelen, hdrlen - off + 1);
1242  linelen = 0;
1243  }
1244 
1245  if (!newlen) {
1246  ignore:
1247  if (op == eUserHeaderOp_Delete)
1248  continue;
1249  off = (size_t)(newline - newhdr);
1250  newhdrlen -= newlinelen;
1251  memmove(newline, newline + newlinelen, newhdrlen - off + 1);
1252  newlinelen = 0;
1253  }
1254  }
1255 
1256  out:
1257  if (!*hdr) {
1258  assert(!hdrlen);
1259  free(hdr);
1260  hdr = 0;
1261  }
1262  info->http_user_header = hdr;
1263  if (retval && op != eUserHeaderOp_Delete) {
1264  retval = (op != eUserHeaderOp_PreOverride
1266  : ConnNetInfo_PrependUserHeader)(info, newhdr);
1267  }
1268  if (newhdr)
1269  free(newhdr);
1270 
1271  return retval;
1272 }
1273 
1274 
1276  const char* header)
1277 {
1279 }
1280 
1281 
1283  const char* header)
1284 {
1286 }
1287 
1288 
1290  const char* header)
1291 {
1292  return s_ModifyUserHeader(info, header, eUserHeaderOp_Extend);
1293 }
1294 
1295 
1297  const char* header)
1298 {
1300 }
1301 
1302 
1303 extern int/*bool*/ ConnNetInfo_ParseURL(SConnNetInfo* info, const char* url)
1304 {
1305  /* URL elements and their parsed lengths as passed */
1306  const char *user, *pass, *host, *path, *args;
1307  size_t userlen, passlen, hostlen, pathlen, argslen;
1308  EURLScheme scheme;
1309  const char* s;
1310  size_t len;
1311  long port;
1312  char* p;
1313 
1314  if (!s_InfoIsValid(info) || !url)
1315  return 0/*failure*/;
1316 
1317  if (!*url)
1318  return 1/*success*/;
1319 
1320  if ((info->req_method & ~eReqMethod_v1) == eReqMethod_Connect) {
1321  len = strlen(url);
1322  s = (const char*) memchr(url, ':', len);
1323  if (s) {
1324  if (!isdigit((unsigned char) s[1]) || s[1] == '0')
1325  return 0/*failure*/;
1326  len = (size_t)(s - url);
1327  }
1328  if (len >= sizeof(info->host))
1329  return 0/*failure*/;
1330  if (NCBI_HasSpaces(url, len))
1331  return 0/*false*/;
1332  if (s) {
1333  errno = 0;
1334  port = strtol(++s, &p, 10);
1335  if (errno || s == p || *p)
1336  return 0/*failure*/;
1337  if (!port || port ^ (port & 0xFFFF))
1338  return 0/*failure*/;
1339  info->port = (unsigned short) port;
1340  }
1341  if (len) {
1342  memcpy(info->host, url, len);
1343  info->host[len] = '\0';
1344  }
1345  return 1/*success*/;
1346  }
1347 
1348  /* "scheme://user:pass@host:port" first [any optional] */
1349  if ((s = strstr(url, "//")) != 0) {
1350  /* the authority portion is present */
1351  port = -1L/*unassigned*/;
1352  if (s != url) {
1353  if (*--s != ':')
1354  return 0/*failure*/;
1355  len = (size_t)(s++ - url);
1356  if ((scheme = x_ParseScheme(url, len)) == eURL_Unspec)
1357  return 0/*failure*/;
1358  } else
1359  scheme = (EURLScheme) info->scheme;
1360  host = s + 2/*"//"*/;
1361  hostlen = strcspn(host, "/?#");
1362  if (NCBI_HasSpaces(host, hostlen))
1363  return 0/*failure*/;
1364  path = host + hostlen;
1365 
1366  /* username:password */
1367  if (!hostlen) {
1368  user = pass = host = (scheme == eURL_File ? "" : 0);
1369  userlen = passlen = 0;
1370  } else {
1371  if (!(s = (const char*) memrchr(host, '@', hostlen))) {
1372  user = pass = "";
1373  userlen = passlen = 0;
1374  } else {
1375  user = host;
1376  userlen = (size_t)(s - user);
1377  host = ++s;
1378  hostlen = (size_t)(path - s);
1379  if (!hostlen)
1380  return 0/*failure*/;
1381  if (!(s = (const char*) memchr(user, ':', userlen))) {
1382  pass = "";
1383  passlen = 0;
1384  } else {
1385  userlen = (size_t)(s++ - user);
1386  pass = s++;
1387  passlen = (size_t)(host - s);
1388  }
1389  }
1390 
1391  /* port, if any */
1392  if ((s = (const char*) memchr(host, ':', hostlen)) != 0) {
1393  hostlen = (size_t)(s - host);
1394  if (!hostlen || !isdigit((unsigned char)s[1]) || s[1]=='0')
1395  return 0/*failure*/;
1396  errno = 0;
1397  port = strtol(++s, &p, 10);
1398  if (errno || s == p || p != path)
1399  return 0/*failure*/;
1400  if (!port || port ^ (port & 0xFFFF))
1401  return 0/*failure*/;
1402  } else
1403  port = 0/*default*/;
1404 
1405  if (userlen >= sizeof(info->user) ||
1406  passlen >= sizeof(info->pass) ||
1407  hostlen >= sizeof(info->host)) {
1408  return 0/*failure*/;
1409  }
1410  }
1411  } else {
1412  /* the authority portion is not present */
1413  s = (const char*) strchr(url, ':');
1414  if (s && s != url &&
1415  (scheme = x_ParseScheme(url, (size_t)(s - url))) != eURL_Unspec) {
1416  url = ++s;
1417  s = 0;
1418  } else
1419  scheme = (EURLScheme) info->scheme;
1420  /* Check for special case: host:port[/path[...]] (see CXX-11455) */
1421  if (s && s != url
1422  && *++s != '0' && (hostlen/*NB:portlen*/ = strspn(s, kDigits))
1423  && memchr("/?#", s[hostlen/*NB:portlen*/], 4)
1424  && (errno = 0, (port = strtol(s, &p, 10)) != 0) && !errno
1425  && p == s + hostlen && !(port ^ (port & 0xFFFF))
1426  && !NCBI_HasSpaces(url, hostlen = (size_t)(--s - url))) {
1427  user = pass = "";
1428  host = url;
1429  assert(hostlen);
1430  path = p;
1431  } else {
1432  user = pass = 0;
1433  host = 0;
1434  hostlen = 0;
1435  port = -1L/*unassigned*/;
1436  path = url;
1437  }
1438  userlen = passlen = 0;
1439  }
1440  assert(!hostlen || host);
1441  if (hostlen && hostlen == strlen(info->host)
1442  && strncasecmp(host, info->host, hostlen) == 0) {
1443  host = 0;
1444  }
1445 
1446  pathlen = (scheme == eURL_Https || scheme == eURL_Http
1447  ? strcspn(path, "?#") : strlen(path));
1448  args = path + pathlen;
1449 
1450  if ((!pathlen && !*args) || (pathlen && *path == '/')) {
1451  /* absolute path */
1452  p = info->path;
1453  len = 0;
1454  if (!pathlen) {
1455  path = "/";
1456  pathlen = 1;
1457  }
1458  } else {
1459  /* relative path */
1460  len = (scheme == eURL_Https || scheme == eURL_Http
1461  ? strcspn(info->path, "?#") : strlen(info->path));
1462  if (!pathlen) {
1463  p = info->path + len;
1464  path = 0;
1465  } else if (!(p = (char*) memrchr(info->path, '/', len))) {
1466  p = info->path;
1467  len = 0;
1468  } else
1469  len = (size_t)(++p - info->path);
1470  }
1471  if (len + pathlen >= sizeof(info->path))
1472  return 0/*failure*/;
1473 
1474  /* arguments and fragment */
1475  if (*args) {
1476  const char* frag;
1477  assert(scheme == eURL_Https || scheme == eURL_Http);
1478  argslen = strlen(args);
1479  if (*args == '#')
1480  frag = args;
1481  else if (!(frag = strchr(args + 1/*NB: args[0]=='?'*/, '#')))
1482  frag = args + argslen;
1483  assert(!*frag || *frag == '#');
1484 
1485  if (*frag) {
1486  /* if there is a new fragment, the entire args get overridden */
1487  if (!frag[1])
1488  --argslen; /* although, don't store the empty fragment # */
1489  if ((size_t)(p - info->path)
1490  + pathlen + argslen >= sizeof(info->path)) {
1491  return 0/*failure*/;
1492  }
1493  len = 0;
1494  } else if ((frag = strchr(info->path, '#')) != 0) {
1495  /* there is no new fragment, but there was the old one: keep it */
1496  len = strlen(frag);
1497  if ((size_t)(p - info->path)
1498  + pathlen + argslen + len >= sizeof(info->path)) {
1499  return 0/*failure*/;
1500  }
1501  memmove(p + pathlen + argslen, frag, len);
1502  } else {
1503  if ((size_t)(p - info->path)
1504  + pathlen + argslen >= sizeof(info->path)) {
1505  return 0/*failure*/;
1506  }
1507  len = 0;
1508  }
1509  memcpy(p + pathlen, args, argslen);
1510  p[pathlen + argslen + len] = '\0';
1511  } else if ((scheme == eURL_Https || scheme == eURL_Http)
1512  && (args = strchr(info->path, '#'))) {
1513  /* keep the old fragment, if any, but drop all args */
1514  memmove(p + pathlen, args, strlen(args) + 1/*EOL*/);
1515  } else
1516  p[pathlen] = '\0';
1517  if (path)
1518  memcpy(p, path, pathlen);
1519  if (user && (*user || host)) {
1520  assert(pass);
1521  memcpy(info->user, user, userlen);
1522  info->user[userlen] = '\0';
1523  memcpy(info->pass, pass, passlen);
1524  info->pass[passlen] = '\0';
1525  }
1526  if (port >= 0 || scheme == eURL_File)
1527  info->port = (unsigned short)(port < 0 ? 0 : port);
1528  if (host) {
1529  assert(!hostlen || !NCBI_HasSpaces(host, hostlen));
1530  memcpy(info->host, host, hostlen);
1531  info->host[hostlen] = '\0';
1532  }
1533  info->scheme = scheme;
1534  return 1/*success*/;
1535 }
1536 
1537 
1538 static const char* x_SepAndLen(const char* str, const char* sep, size_t* len)
1539 {
1540  size_t m = 0;
1541  while (*sep) {
1542  size_t n = strcspn(str, sep);
1543  if (!str[n]) {
1544  *len = m + n;
1545  return sep;
1546  }
1547  sep += (size_t)(strchr(sep, str[n++]) - sep) + 1;
1548  str += n;
1549  m += n;
1550  }
1551  *len = m + strlen(str);
1552  return sep/*NB:""*/;
1553 }
1554 
1555 
1556 extern int/*bool*/ ConnNetInfo_SetPath(SConnNetInfo* info, const char* path)
1557 {
1558  size_t plen, x_alen;
1559  const char* frag;
1560  const char* sep;
1561  char* x_args;
1562 
1563  if (!s_InfoIsValid(info))
1564  return 0/*failure*/;
1565 
1566  if (!path) {
1567  info->path[0] = '\0';
1568  return 1/*success: all deleted*/;
1569  }
1570 
1571  sep = x_SepAndLen(path, "?#", &plen);
1572 
1573  x_args = info->path + strcspn(info->path, sep);
1574 
1575  if (!plen) {
1576  if (!*x_args)
1577  info->path[0] = '\0';
1578  else if (x_args != info->path)
1579  memmove(info->path, x_args, strlen(x_args) + 1/*EOL*/);
1580  return 1/*success: deleted*/;
1581  }
1582 
1583  x_alen = strlen(x_args);
1584  if ((frag = (const char*) memchr(path, '#', plen)) != 0 && !frag[1])
1585  --plen;
1586  if (plen + x_alen >= sizeof(info->path))
1587  return 0/*failure: too long*/;
1588 
1589  memmove(info->path + plen, x_args, x_alen + 1/*EOL*/);
1590  memcpy(info->path, path, plen);
1591  return 1/*success*/;
1592 }
1593 
1594 
1595 extern int/*bool*/ ConnNetInfo_AddPath(SConnNetInfo* info, const char* path)
1596 {
1597  size_t plen, x_alen;
1598  const char* sep;
1599  char* x_path;
1600  char* x_args;
1601 
1602  if (!s_InfoIsValid(info))
1603  return 0/*failure*/;
1604 
1605  if (!path || !*path)
1606  return 1/*success: nothing to do*/;
1607 
1608  sep = x_SepAndLen(path, "?#", &plen);
1609  assert(plen);
1610 
1611  x_args = info->path + strcspn(info->path, sep);
1612  x_alen = strlen(x_args);
1613 
1614  if (*path == '?' || *path == '#') {
1615  x_path = (char*) memchr (info->path,
1616  *path, (size_t)(x_args - info->path));
1617  if (!x_path)
1618  x_path = x_args;
1619  if (*path == '#' && !path[1])
1620  --plen;
1621  } else if (*path != '/') {
1622  x_path = (char*) memrchr(info->path,
1623  '/', (size_t)(x_args - info->path));
1624  if (!x_path)
1625  x_path = info->path;
1626  else
1627  x_path++;
1628  } else {
1629  x_path = info->path + strcspn(info->path, "?#");
1630  if (x_path != info->path && x_path[-1] == '/')
1631  x_path--;
1632  }
1633  if ((size_t)(x_path - info->path) + plen + x_alen >= sizeof(info->path))
1634  return 0/*failure: too long*/;
1635 
1636  memmove(x_path + plen, x_args, x_alen + 1/*EOL*/);
1637  memcpy(x_path, path, plen);
1638  return 1/*success*/;
1639 }
1640 
1641 
1642 static int/*bool*/ x_SetArgs(SConnNetInfo* info, const char* args)
1643 {
1644  size_t alen, x_flen, room;
1645  const char *x_frag;
1646  const char* frag;
1647  char* x_args;
1648 
1650 
1651  alen = args ? strlen(args) : 0;
1652 
1653  x_args = info->path + strcspn(info->path, "?#");
1654  if (!alen) {
1655  if (!args) {
1656  *x_args = '\0';
1657  return 1/*success: all deleted*/;
1658  }
1659  if (*x_args == '?') {
1660  x_frag = (x_args + 1) + strcspn(x_args + 1, "#");
1661  if (!*x_frag)
1662  *x_args = '\0';
1663  else
1664  memmove(x_args, x_frag, strlen(x_frag) + 1/*EOL*/);
1665  }
1666  return 1/*success: deleted*/;
1667  }
1668 
1669  if (!(frag = (const char*) memchr(args, '#', alen))) {
1670  /* preserve frag, if any */
1671  x_frag = x_args + strcspn(x_args, "#");
1672  x_flen = strlen(x_frag);
1673  } else {
1674  if (!frag[1])
1675  --alen;
1676  x_frag = ""; /*NB: unused*/
1677  x_flen = 0;
1678  }
1679  room = !(*args == '#') + alen;
1680  if ((size_t)(x_args - info->path) + room + x_flen >= sizeof(info->path))
1681  return 0/*failure: too long*/;
1682 
1683  if (x_flen)
1684  memmove(x_args + room, x_frag, x_flen + 1/*EOL*/);
1685  if (!(*args == '#'))
1686  *x_args++ = '?';
1687  memcpy(x_args, args, alen);
1688  if (!x_flen)
1689  x_args[alen] = '\0';
1690  return 1/*success*/;
1691 }
1692 
1693 
1694 extern int/*bool*/ ConnNetInfo_SetArgs(SConnNetInfo* info, const char* args)
1695 {
1696  return s_InfoIsValid(info) ? x_SetArgs(info, args) : 0/*failure*/;
1697 }
1698 
1699 
1700 extern int/*bool*/ ConnNetInfo_SetFrag(SConnNetInfo* info, const char* frag)
1701 {
1702  char* x_frag;
1703  size_t flen;
1704 
1705  if (!s_InfoIsValid(info))
1706  return 0/*failure*/;
1707 
1708  flen = frag ? strlen(frag += !(*frag != '#')) : 0;
1709 
1710  x_frag = info->path + strcspn(info->path, "#");
1711  if (!flen) {
1712  *x_frag = '\0';
1713  return 1/*success: deleted*/;
1714  }
1715  ++flen;
1716  if ((size_t)(x_frag - info->path) + flen >= sizeof(info->path))
1717  return 0/*failure: too long*/;
1718 
1719  *x_frag++ = '#';
1720  memcpy(x_frag, frag, flen/*EOL incl'd*/);
1721  return 1/*success*/;
1722 }
1723 
1724 
1725 extern const char* ConnNetInfo_GetArgs(const SConnNetInfo* info)
1726 {
1727  const char* args;
1728 
1729  if (!s_InfoIsValid(info))
1730  return 0/*failure*/;
1731 
1732  args = info->path + strcspn(info->path, "?#");
1733  if (*args == '?')
1734  ++args;
1735  return args;
1736 }
1737 
1738 
1739 static int/*bool*/ x_AppendArg(SConnNetInfo* info,
1740  const char* arg,
1741  const char* val)
1742 {
1743  size_t alen, vlen, x_alen, x_flen, room;
1744  char* x_args, *x_frag;
1745 
1747 
1748  if (!arg || !(alen = strcspn(arg, "#")))
1749  return 1/*success*/;
1750  vlen = val ? 1/*'='*/ + strcspn(val, "#") : 0;
1751 
1752  x_args = info->path + strcspn(info->path, "?#");
1753  x_alen = strlen(x_args);
1754 
1755  if (*x_args == '?') {
1756  x_frag = (x_args + 1) + strcspn(x_args + 1, "#");
1757  x_flen = x_alen - (size_t)(x_frag - x_args);
1758  x_alen -= x_flen;
1759  } else {
1760  x_frag = x_args;
1761  x_flen = x_alen;
1762  x_alen = 0;
1763  }
1764  room = (x_alen == 1 ? 0 : x_alen) + 1/*'?'|'&'*/ + (alen + vlen);
1765  if ((size_t)(x_args - info->path) + room + x_flen >= sizeof(info->path))
1766  return 0/*failure: too long*/;
1767 
1768  assert(!x_flen || *x_frag == '#');
1769  if (x_flen)
1770  memmove(x_args + room, x_frag, x_flen + 1/*EOL*/);
1771  if (x_alen > 1) {
1772  assert(*x_args == '?');
1773  x_args += x_alen;
1774  *x_args++ = '&';
1775  } else
1776  *x_args++ = '?';
1777  memcpy(x_args, arg, alen);
1778  x_args += alen;
1779  if (vlen--) {
1780  *x_args++ = '=';
1781  memcpy(x_args, val, vlen);
1782  x_args += vlen;
1783  }
1784  if (!x_flen)
1785  *x_args = '\0';
1786  return 1/*success*/;
1787 }
1788 
1789 
1791  const char* arg,
1792  const char* val)
1793 {
1794  return s_InfoIsValid(info) ? x_AppendArg(info, arg, val) : 0/*failure*/;
1795 }
1796 
1797 
1798 static int/*bool*/ x_PrependArg(SConnNetInfo* info,
1799  const char* arg,
1800  const char* val)
1801 {
1802  size_t alen, vlen, x_alen, room;
1803  char* x_args, *xx_args;
1804 
1806 
1807  if (!arg || !(alen = strcspn(arg, "#")))
1808  return 1/*success*/;
1809  vlen = val ? 1/*'='*/ + strcspn(val, "#") : 0;
1810 
1811  x_args = info->path + strcspn(info->path, "?#");
1812  x_alen = strlen(x_args);
1813 
1814  xx_args = x_args;
1815  if (*xx_args == '?' && (!xx_args[1] || xx_args[1] == '#')) {
1816  ++xx_args;
1817  --x_alen;
1818  room = 0;
1819  } else
1820  room = 1/*'?'|'&'*/;
1821  room += alen + vlen;
1822  if ((size_t)(x_args - info->path) + room + x_alen >= sizeof(info->path))
1823  return 0/*failure: too long*/;
1824 
1825  if (x_alen) {
1826  if (*xx_args == '?')
1827  *xx_args = '&';
1828  memmove(xx_args + room, xx_args, x_alen + 1/*EOL*/);
1829  }
1830  *x_args++ = '?';
1831  memcpy(x_args, arg, alen);
1832  x_args += alen;
1833  if (vlen--) {
1834  *x_args++ = '=';
1835  memcpy(x_args, val, vlen);
1836  x_args += vlen;
1837  }
1838  if (!x_alen)
1839  *x_args = '\0';
1840  return 1/*success*/;
1841 }
1842 
1843 
1845  const char* arg,
1846  const char* val)
1847 {
1848  return s_InfoIsValid(info) ? x_PrependArg(info, arg, val) : 0/*failure*/;
1849 }
1850 
1851 
1852 static int/*bool*/ x_DeleteArg(SConnNetInfo* info,
1853  const char* arg)
1854 {
1855  int/*bool*/ deleted;
1856  size_t alen, x_alen;
1857  char* x_args, *x_a;
1858 
1860 
1861  if (!arg || !(alen = strcspn(arg, "=&#")))
1862  return 0/*failure*/;
1863 
1864  deleted = 0/*false*/;
1865  x_args = info->path + strcspn(info->path, "?#");
1866  for (x_a = x_args; *x_a && *x_a != '#'; x_a += x_alen) {
1867  if (x_a == x_args || *x_a == '&')
1868  ++x_a;
1869  x_alen = strcspn(x_a, "&#");
1870  if (x_alen < alen || strncasecmp(x_a, arg, alen) != 0 ||
1871  (x_a[alen] &&
1872  x_a[alen] != '=' && x_a[alen] != '&' && x_a[alen] != '#')) {
1873  continue;
1874  }
1875  if (x_a[x_alen] == '&')
1876  ++x_alen; /* inner arg: eat the following '&' */
1877  else
1878  ++x_alen, --x_a; /* last arg: remove preceding '?' / '&' */
1879  memmove(x_a, x_a + x_alen, strlen(x_a + x_alen) + 1/*EOL*/);
1880  deleted = 1/*true*/;
1881  x_alen = 0;
1882  }
1883  return deleted;
1884 }
1885 
1886 
1888  const char* arg)
1889 {
1890  return s_InfoIsValid(info) ? x_DeleteArg(info, arg) : 0/*failure*/;
1891 }
1892 
1893 
1895  const char* args)
1896 {
1897  assert(s_InfoIsValid(info) && args && *args);
1898 
1899  while (*args && *args != '#') {
1900  size_t alen = strcspn(args, "&#");
1901  if (alen)
1902  x_DeleteArg(info, args);
1903  if (args[alen] == '&')
1904  ++args;
1905  args += alen;
1906  }
1907 }
1908 
1909 
1911  const char* args)
1912 {
1913  if (s_InfoIsValid(info) && args && *args)
1914  x_DeleteAllArgs(info, args);
1915 }
1916 
1917 
1919  const char* arg,
1920  const char* val)
1921 {
1922  if (!s_InfoIsValid(info))
1923  return 0/*failure*/;
1924 
1925  if (!arg || !*arg)
1926  return 1/*success*/;
1927 
1928  x_DeleteAllArgs(info, arg);
1929  return x_PrependArg(info, arg, val);
1930 }
1931 
1932 
1934  const char* arg,
1935  const char* val)
1936 {
1937  if (!s_InfoIsValid(info))
1938  return 0/*failure*/;
1939 
1940  if (!arg || !*arg)
1941  return 1/*success*/;
1942 
1943  x_DeleteAllArgs(info, arg);
1944  return x_AppendArg(info, arg, val);
1945 }
1946 
1947 
1948 static int/*bool*/ x_IsSufficientAddress(const char* addr)
1949 {
1950  const char* c;
1951  return !strchr(addr, ' ')
1952  && (SOCK_isip(addr)
1953  || ((c = strchr(addr, '.')) != 0 && c[1] &&
1954  (c = strchr(c + 2, '.')) != 0 && c[1]));
1955 }
1956 
1957 
1958 static const char* x_ClientAddress(const char* client_host,
1959  int/*bool*/ local_host)
1960 {
1961  const char* c = client_host;
1962  unsigned int ip;
1963  char addr[80];
1964  char* s;
1965 
1966  assert(client_host);
1967  strncpy0(addr, client_host, sizeof(addr) - 1);
1968  if (UTIL_NcbiLocalHostName(addr) && (s = strdup(addr)) != 0)
1969  client_host = s; /*NB: this usually makes client_host insufficient*/
1970 
1971  if ((client_host == c && x_IsSufficientAddress(client_host))
1972  || !(ip = (*c && !local_host
1973  ? SOCK_gethostbyname(c)
1975  || SOCK_ntoa(ip, addr, sizeof(addr)) != 0
1976  || !(s = (char*) malloc(strlen(client_host) + strlen(addr) + 3))) {
1977  return client_host/*least we can do :-/*/;
1978  }
1979 
1980  sprintf(s, "%s(%s)", client_host, addr);
1981  if (client_host != c)
1982  free((void*) client_host);
1983  for (client_host = s; *s; ++s) {
1984  if (*s == ' ')
1985  *s = '+';
1986  }
1987  return client_host;
1988 }
1989 
1990 
1992  const char* service)
1993 {
1994  static const char kService[] = "service";
1995  static const char kAddress[] = "address";
1996  static const char kPlatform[] = "platform";
1997  int/*bool*/ local_host;
1998  const char* s;
1999 
2000  if (!s_InfoIsValid(info))
2001  return 0/*failed*/;
2002 
2003  s = CORE_GetAppName();
2004  if (s && *s) {
2005  char ua[16 + 80];
2006  sprintf(ua, "User-Agent: %.80s", s);
2008  }
2009 
2010  /* Dispatcher CGI args (may sacrifice some if they don't fit altogether) */
2011  if (!(s = CORE_GetPlatform()) || !*s)
2012  ConnNetInfo_DeleteArg(info, kPlatform);
2013  else
2014  ConnNetInfo_PreOverrideArg(info, kPlatform, s);
2015  local_host = !info->client_host[0];
2016  if (local_host &&
2017  !SOCK_gethostbyaddr(0, info->client_host, sizeof(info->client_host))) {
2018  SOCK_gethostname(info->client_host, sizeof(info->client_host));
2019  }
2020  if (!(s = x_ClientAddress(info->client_host, local_host)) || !*s)
2021  ConnNetInfo_DeleteArg(info, kAddress);
2022  else
2023  ConnNetInfo_PreOverrideArg(info, kAddress, s);
2024  if (s != info->client_host)
2025  free((void*) s);
2026  if (service) {
2027  if (!*service)
2028  ConnNetInfo_DeleteArg(info, kService);
2029  else if (!ConnNetInfo_PreOverrideArg(info, kService, service)) {
2030  ConnNetInfo_DeleteArg(info, kPlatform);
2031  if (!ConnNetInfo_PreOverrideArg(info, kService, service)) {
2032  ConnNetInfo_DeleteArg(info, kAddress);
2033  if (!ConnNetInfo_PreOverrideArg(info, kService, service))
2034  return 0/*failed*/;
2035  }
2036  }
2037  }
2038  return 1/*succeeded*/;
2039 }
2040 
2041 
2043 {
2044  SConnNetInfo* x_info;
2045  size_t svclen;
2046 
2047  if (!s_InfoIsValid(info))
2048  return 0;
2049 
2050  svclen = strlen(info->svc);
2051  if (!(x_info = (SConnNetInfo*) malloc(sizeof(*info) + svclen)))
2052  return 0;
2053 
2054  strcpy(x_info->client_host, info->client_host);
2055  x_info->req_method = info->req_method;
2056  x_info->scheme = info->scheme;
2057  x_info->external = info->external;
2058  x_info->firewall = info->firewall;
2059  x_info->stateless = info->stateless;
2060  x_info->lb_disable = info->lb_disable;
2061  x_info->http_version = info->http_version;
2062  x_info->debug_printout = info->debug_printout;
2063  x_info->http_push_auth = info->http_push_auth;
2064  x_info->http_proxy_leak = info->http_proxy_leak;
2065  x_info->http_proxy_skip = info->http_proxy_skip;
2066  x_info->http_proxy_mask = info->http_proxy_mask;
2067  x_info->reserved = info->reserved;
2068  strcpy(x_info->user, info->user);
2069  strcpy(x_info->pass, info->pass);
2070  strcpy(x_info->host, info->host);
2071  x_info->port = info->port;
2072  strcpy(x_info->path, info->path);
2073  strcpy(x_info->http_proxy_host, info->http_proxy_host);
2074  x_info->http_proxy_port = info->http_proxy_port;
2075  strcpy(x_info->http_proxy_user, info->http_proxy_user);
2076  strcpy(x_info->http_proxy_pass, info->http_proxy_pass);
2077  x_info->max_try = info->max_try;
2078  x_info->unused = info->unused;
2079  x_info->http_user_header = 0;
2080  x_info->http_referer = 0;
2081  x_info->credentials = info->credentials;
2082 
2083  x_info->tmo = info->timeout ? *info->timeout : info->tmo;
2084  x_info->timeout = info->timeout ? &x_info->tmo : 0;
2085  memcpy((char*) x_info->svc, info->svc, svclen + 1);
2086 
2087  x_info->magic = CONN_NET_INFO_MAGIC;
2088  return x_info;
2089 }
2090 
2091 
2093 {
2095  if (!x_info)
2096  return 0;
2097  assert(s_InfoIsValid(x_info));
2098 
2099  if (info->http_user_header && *info->http_user_header
2100  && !(x_info->http_user_header = strdup(info->http_user_header))) {
2101  goto err;
2102  }
2103  if (info->http_referer && *info->http_referer
2104  && !(x_info->http_referer = strdup(info->http_referer))) {
2105  goto err;
2106  }
2107  return x_info;
2108 
2109  err:
2110  ConnNetInfo_Destroy(x_info);
2111  return 0;
2112 }
2113 
2114 
2115 static const char* x_BadMagic(unsigned int magic, char buf[])
2116 {
2117  sprintf(buf, "0x%08lX (INVALID != 0x%08lX)",
2118  (unsigned long) magic, (unsigned long) CONN_NET_INFO_MAGIC);
2119  return buf;
2120 }
2121 
2122 
2123 static const char* x_Num(unsigned int num, char buf[])
2124 {
2125  sprintf(buf, "(#%u)", num);
2126  return buf;
2127 }
2128 
2129 
2130 static const char* x_Scheme(EURLScheme scheme, char buf[])
2131 {
2132  switch (scheme) {
2133  case eURL_Unspec:
2134  return "";
2135  case eURL_Https:
2136  return "HTTPS";
2137  case eURL_Http:
2138  return "HTTP";
2139  case eURL_File:
2140  return "FILE";
2141  case eURL_Ftp:
2142  return "FTP";
2143  default:
2144  break;
2145  }
2146  return buf ? x_Num(scheme, buf) : 0;
2147 }
2148 
2149 
2150 static const char* x_Port(unsigned short port, char buf[])
2151 {
2152  assert(port);
2153  sprintf(buf, "%hu", port);
2154  return buf;
2155 }
2156 
2157 
2158 static const char* x_ReqMethod(TReqMethod req_method, char buf[])
2159 {
2160  int/*bool*/ v1 = req_method & eReqMethod_v1 ? 1/*true*/ : 0/*false*/;
2161  req_method &= (TReqMethod)(~eReqMethod_v1);
2162  switch (req_method) {
2163  case eReqMethod_Any:
2164  return v1 ? "ANY/1.1" : "ANY";
2165  case eReqMethod_Get:
2166  return v1 ? "GET/1.1" : "GET";
2167  case eReqMethod_Post:
2168  return v1 ? "POST/1.1" : "POST";
2169  case eReqMethod_Head:
2170  return v1 ? "HEAD/1.1" : "HEAD";
2171  case eReqMethod_Connect:
2172  return v1 ? "CONNECT/1.1" : "CONNECT";
2173  case eReqMethod_Put:
2174  return "PUT";
2175  case eReqMethod_Patch:
2176  return "PATCH";
2177  case eReqMethod_Trace:
2178  return "TRACE";
2179  case eReqMethod_Delete:
2180  return "DELETE";
2181  case eReqMethod_Options:
2182  return "OPTIONS";
2183  default:
2184  break;
2185  }
2186  return buf ? x_Num(req_method, buf) : 0;
2187 }
2188 
2189 
2190 static const char* x_Firewall(unsigned int firewall)
2191 {
2192  switch ((EFWMode) firewall) {
2193  case eFWMode_Adaptive:
2194  return "TRUE";
2195  case eFWMode_Firewall:
2196  return "FIREWALL";
2197  case eFWMode_Fallback:
2198  return "FALLBACK";
2199  default:
2200  assert(!firewall);
2201  break;
2202  }
2203  return "NONE";
2204 }
2205 
2206 
2207 static const char* x_CredInfo(NCBI_CRED cred, char buf[])
2208 {
2209  unsigned int who, what;
2210  if (!cred)
2211  return "NONE";
2212  who = cred->type / 100;
2213  what = cred->type % 100;
2214  switch (who) {
2215  case eNcbiCred_GnuTls / 100:
2216  switch (what) {
2217  case 0:
2218  return "(GNUTLS X.509 Cert Cred)";
2219  default:
2220  sprintf(buf, "(GNUTLS/%u)", what);
2221  return buf;
2222  }
2223  case eNcbiCred_MbedTls / 100:
2224  switch (what) {
2225  case 0:
2226  return "(MBEDTLS X.509 Cert & PK)";
2227  default:
2228  sprintf(buf, "(MBEDTLS/%u)", what);
2229  return buf;
2230  }
2231  default:
2232  break;
2233  }
2234  sprintf(buf, "(TLS 0x%08X/%u)", cred->type, what);
2235  return buf;
2236 }
2237 
2238 
2239 static void s_SaveStringQuot(char* s, const char* name,
2240  const char* str, int/*bool*/ quote)
2241 {
2242  sprintf(s + strlen(s), "%-16.16s: %s%s%s\n", name,
2243  str && quote ? "\"" : "",
2244  str ? str : "NULL",
2245  str && quote ? "\"" : "");
2246 }
2247 
2248 static void s_SaveString(char* s, const char* name, const char* str)
2249 {
2250  s_SaveStringQuot(s, name, str, 1);
2251 }
2252 
2253 static void s_SaveKeyval(char* s, const char* name, const char* str)
2254 {
2255  assert(str && *str);
2256  s_SaveStringQuot(s, name, str, 0);
2257 }
2258 
2259 static void s_SaveBool(char* s, const char* name, unsigned int/*bool*/ bbb)
2260 {
2261  s_SaveKeyval(s, name, bbb ? "TRUE" : "FALSE");
2262 }
2263 
2264 static void s_SaveULong(char* s, const char* name, unsigned long lll)
2265 {
2266  sprintf(s + strlen(s), "%-16.16s: %lu\n", name, lll);
2267 }
2268 
2269 static void s_SaveUserHeader(char* s, const char* name,
2270  const char* uh, size_t uhlen)
2271 {
2272  s += strlen(s);
2273  s += sprintf(s, "%-16.16s: ", name);
2274  if (uh) {
2275  *s++ = '"';
2276  memcpy(UTIL_PrintableString(uh, uhlen, s, 0/*reduce*/), "\"\n", 3);
2277  } else
2278  memcpy(s, "NULL\n", 6);
2279 }
2280 
2281 
2282 extern void ConnNetInfo_Log(const SConnNetInfo* info, ELOG_Level sev, LOG lg)
2283 {
2284  char buf[80];
2285  size_t uhlen;
2286  size_t len;
2287  char* s;
2288 
2289  if (!info) {
2290  LOG_Write(lg, NCBI_C_ERRCODE_X, 10, sev, 0, 0, 0, 0,
2291  "ConnNetInfo_Log: NULL", 0, 0);
2292  return;
2293  }
2294 
2295  uhlen = info->http_user_header ? strlen(info->http_user_header) : 0;
2296 
2297  len = sizeof(*info) + 1024/*slack for all labels & keywords*/
2298  + UTIL_PrintableStringSize(info->http_user_header, uhlen)
2299  + (info->http_referer ? strlen(info->http_referer) : 0)
2300  + strlen(info->svc);
2301 
2302  if (!(s = (char*) malloc(len))) {
2303  LOG_WRITE(lg, NCBI_C_ERRCODE_X, 11,
2304  sev == eLOG_Fatal ? eLOG_Fatal : eLOG_Error,
2305  "ConnNetInfo_Log: Cannot allocate memory");
2306  return;
2307  }
2308 
2309  strcpy(s, "ConnNetInfo_Log\n"
2310  "#################### [BEGIN] SConnNetInfo:\n");
2311  if (!s_InfoIsValid(info))
2312  s_SaveKeyval(s, "magic", x_BadMagic(info->magic, buf));
2313  if (*info->svc)
2314  s_SaveString(s, "service", info->svc);
2315  else
2316  s_SaveKeyval(s, "service", "NONE");
2317  if (*info->client_host)
2318  s_SaveString(s, "client_host", info->client_host);
2319  else
2320  s_SaveKeyval(s, "client_host", "(default)");
2321  s_SaveKeyval (s, "req_method", x_ReqMethod((TReqMethod)
2322  (info->req_method
2323  | (info->http_version
2324  ? eReqMethod_v1
2325  : 0)), buf));
2326  s_SaveKeyval (s, "scheme", (info->scheme
2327  ? x_Scheme((EURLScheme)
2328  info->scheme, buf)
2329  : "(unspec)"));
2330 #if defined(_DEBUG) && !defined(NDEBUG)
2331  s_SaveString (s, "user", info->user);
2332 #else
2333  s_SaveKeyval (s, "user", *info->user ? "(set)" : "\"\"");
2334 #endif /*_DEBUG && !NDEBUG*/
2335  if (*info->pass)
2336  s_SaveKeyval(s, "pass", *info->user ? "(set)" : "(ignored)");
2337  else
2338  s_SaveString(s, "pass", info->pass);
2339  s_SaveString (s, "host", info->host);
2340  s_SaveKeyval (s, "port", (info->port
2341  ? x_Port(info->port, buf)
2342  : *info->host
2343  ? "(default)"
2344  : "(none"));
2345  s_SaveString (s, "path", info->path);
2346  s_SaveString (s, "http_proxy_host", info->http_proxy_host);
2347  s_SaveKeyval (s, "http_proxy_port",(info->http_proxy_port
2348  ? x_Port(info->http_proxy_port, buf)
2349  : "(none)"));
2350 #if defined(_DEBUG) && !defined(NDEBUG)
2351  s_SaveString (s, "http_proxy_user", info->http_proxy_user);
2352 #else
2353  s_SaveKeyval (s, "http_proxy_user",(info->http_proxy_user[0]
2354  ? "(set)" : "\"\""));
2355 #endif /*_DEBUG && !NDEBUG*/
2356  if (*info->http_proxy_pass) {
2357  s_SaveKeyval(s, "http_proxy_pass",(info->http_proxy_user[0]
2358  ? "(set)" : "(ignored)"));
2359  } else
2360  s_SaveString(s, "http_proxy_pass", info->http_proxy_pass);
2361  s_SaveBool (s, "http_proxy_leak", info->http_proxy_leak);
2362  s_SaveBool (s, "http_proxy_skip", info->http_proxy_skip);
2363  s_SaveKeyval (s, "http_proxy_mask", x_ProxyStr(info->http_proxy_mask));
2364  s_SaveULong (s, "max_try", info->max_try);
2365  if (info->timeout) {
2366  s_SaveULong (s, "timeout(sec)", info->timeout->sec);
2367  s_SaveULong (s, "timeout(usec)", info->timeout->usec);
2368  } else
2369  s_SaveKeyval(s, "timeout", "INFINITE");
2370  s_SaveBool (s, "external", info->external);
2371  s_SaveKeyval (s, "firewall", x_Firewall(info->firewall));
2372  s_SaveBool (s, "stateless", info->stateless);
2373  s_SaveBool (s, "lb_disable", info->lb_disable);
2374  s_SaveKeyval (s, "debug_printout", (info->debug_printout
2376  ? "NONE"
2377  : info->debug_printout
2379  ? "SOME"
2380  : info->debug_printout
2382  ? "DATA"
2383  : x_Num(info->debug_printout,buf)));
2384  s_SaveBool (s, "http_push_auth", info->http_push_auth);
2385  s_SaveUserHeader(s, "http_user_header",info->http_user_header, uhlen);
2386  s_SaveString (s, "http_referer", info->http_referer);
2387  if (info->credentials)
2388  s_SaveKeyval(s, "credentials", x_CredInfo(info->credentials, buf));
2389  strcat(s,
2390  "#################### [_END_] SConnNetInfo\n");
2391 
2392  assert(strlen(s) < len);
2393  LOG_Write(lg, NCBI_C_ERRCODE_X, 12, sev, 0, 0, 0, 0, s, 0, 0);
2394  free(s);
2395 }
2396 
2397 
2398 extern char* ConnNetInfo_URL(const SConnNetInfo* info)
2399 {
2400  TReqMethod req_method;
2401  const char* scheme;
2402  size_t schlen;
2403  const char* path;
2404  size_t len;
2405  char* url;
2406 
2407  if (!s_InfoIsValid(info))
2408  return 0/*failed*/;
2409 
2410  req_method = info->req_method & (TReqMethod)(~eReqMethod_v1);
2411  if (!(scheme = x_Scheme((EURLScheme) info->scheme, 0)))
2412  return 0/*failed*/;
2413 
2414  if (req_method == eReqMethod_Connect) {
2415  scheme = "";
2416  schlen = 0;
2417  path = 0;
2418  len = 0;
2419  } else {
2420  schlen = strlen(scheme);
2421  path = info->path;
2422  len = schlen + 4/*"://",'/'*/ + strlen(path);
2423  }
2424  len += strlen(info->host) + 7/*:port\0*/;
2425 
2426  url = (char*) malloc(len);
2427  if (url) {
2428  strlwr((char*) memcpy(url, scheme, schlen + 1));
2429  len = schlen;
2430  len += sprintf(url + len,
2431  &"://%s"[schlen ? 0 : path ? 1 : 3], info->host);
2432  if (info->port || !path/*req_method == eReqMethod_Connect*/)
2433  len += sprintf(url + len, ":%hu", info->port);
2434  sprintf(url + len,
2435  "%s%s", &"/"[!(path && *path != '/')], path ? path : "");
2436  }
2437  assert(!url || *url);
2438  return url;
2439 }
2440 
2441 
2443  const STimeout* timeout)
2444 {
2445  if (!s_InfoIsValid(info) || timeout == kDefaultTimeout)
2446  return 0/*failed*/;
2447  if (timeout) {
2448  info->tmo = *timeout;
2449  info->timeout = &info->tmo;
2450  } else
2451  info->timeout = kInfiniteTimeout/*0,==timeout*/;
2452  return 1/*succeeded*/;
2453 }
2454 
2455 
2457 {
2458  if (info)
2459  x_DestroyNetInfo(info, info->magic);
2460 }
2461 
2462 
2463 
2464 /****************************************************************************
2465  * URL_Connect
2466  */
2467 
2468 
2470 {
2471  if (sock) {
2472  SOCK_Abort(sock);
2473  SOCK_Close(sock);
2474  }
2475  return status;
2476 }
2477 
2478 
2480 (const char* host,
2481  unsigned short port,
2482  const char* path,
2483  const char* args,
2484  TReqMethod req_method,
2485  size_t content_length,
2486  const STimeout* o_timeout,
2487  const STimeout* rw_timeout,
2488  const char* user_hdr,
2489  SURLExtra* extra,
2491  SOCK* sock)
2492 {
2493  static const char kHttp[][12] = { " HTTP/1.0\r\n",
2494  " HTTP/1.1\r\n" };
2495  SOCK s;
2496  BUF buf;
2497  char* hdr;
2498  const char* str;
2499  SSOCK_Init init;
2500  const char* http;
2501  int/*bool*/ x_c_l;
2502  EIO_Status status;
2503  size_t hdr_len;
2504  size_t path_len;
2505  size_t args_len;
2506  char temp[80];
2507  unsigned short x_port;
2508  EReqMethod x_req_meth;
2509  size_t user_hdr_len = user_hdr && *user_hdr ? strlen(user_hdr) : 0;
2510 
2511  x_req_meth = (EReqMethod)(req_method & (TReqMethod)(~eReqMethod_v1));
2512  http = kHttp[!(req_method < eReqMethod_v1)];
2513  args_len = strcspn(path, "?#")/*temp!*/;
2514  path_len = path
2515  ? (x_req_meth != eReqMethod_Connect && !args
2516  ? args_len
2517  : strlen(path))
2518  : 0;
2519 
2520  /* sanity checks */
2521  if (!sock || !host || !*host || !path_len || args_len < path_len) {
2522  CORE_LOG_X(2, eLOG_Critical, "[URL_Connect] Bad argument(s)");
2523  if (sock) {
2524  s = *sock;
2525  *sock = 0;
2526  } else
2527  s = 0;
2529  }
2530  s = *sock;
2531  *sock = 0;
2532 
2533  if (path[path_len]/*NB: '?'/'#' && !args*/)
2534  args = &path[path_len] + !(path[path_len] != '?');
2535 
2536  /* trim user_hdr */
2537  while (user_hdr_len) {
2538  if (!isspace((unsigned char) user_hdr[0]))
2539  break;
2540  --user_hdr_len;
2541  ++user_hdr;
2542  }
2543  while (user_hdr_len) {
2544  if (!isspace((unsigned char) user_hdr[user_hdr_len - 1]))
2545  break;
2546  --user_hdr_len;
2547  }
2548 
2549  /* check C-L, select request method and its verbal representation */
2550  x_c_l = content_length && content_length != (size_t)(-1L) ? 1 : 0;
2551  if (x_req_meth == eReqMethod_Any)
2552  x_req_meth = content_length ? eReqMethod_Post : eReqMethod_Get;
2553  else if (x_c_l && (x_req_meth == eReqMethod_Head ||
2554  x_req_meth == eReqMethod_Get)) {
2555  if (port)
2556  sprintf(temp, ":%hu", port);
2557  else
2558  *temp = '\0';
2560  ("[URL_Connect; http%s://%s%s%s%.*s] "
2561  " Content-Length (%lu) is ignored with request method %s",
2562  &"s"[!(flags & fSOCK_Secure)], host, temp,
2563  &"/"[path_len && *path == '/'], (int) path_len, path,
2564  (unsigned long) content_length,
2565  x_req_meth == eReqMethod_Get ? "GET" : "HEAD"));
2566  content_length = (size_t)(-1L);
2567  }
2568  if (content_length != (size_t)(-1L) && x_req_meth != eReqMethod_Connect){
2569  /* RFC7230 3.3.2 */
2570  x_c_l = content_length
2571  || x_req_meth == eReqMethod_Put
2572  || x_req_meth == eReqMethod_Post ? 1/*true*/ : 0/*false*/;
2573  } else
2574  x_c_l = 0/*false*/;
2575 
2576  if (!(str = x_ReqMethod(x_req_meth, 0))) {
2577  char tmp[40];
2578  if (port)
2579  sprintf(temp, ":%hu", port);
2580  else
2581  *temp = '\0';
2583  ("[URL_Connect; http%s://%s%s%s%.*s] "
2584  " Unsupported request method %s",
2585  &"s"[!(flags & fSOCK_Secure)], host, temp,
2586  &"/"[path_len && *path == '/'], (int) path_len, path,
2587  x_ReqMethod(req_method, tmp)));
2588  assert(0);
2590  }
2591 
2592  x_port = port;
2593  if (x_req_meth != eReqMethod_Connect) {
2594  if (!x_port)
2596  args_len = args ? strcspn(args, "#") : 0;
2597  } else
2598  args_len = 0;
2599 
2600  buf = 0;
2601  errno = 0;
2602  /* compose HTTP header */
2603  if (/* METHOD <path>[?<args>] HTTP/1.x\r\n */
2604  !BUF_Write(&buf, str, strlen(str)) ||
2605  !BUF_Write(&buf, " ", 1) ||
2606  !BUF_Write(&buf, path, path_len) ||
2607  (args_len
2608  && (!BUF_Write(&buf, "?", 1) ||
2609  !BUF_Write(&buf, args, args_len))) ||
2610  !BUF_Write (&buf, http, sizeof(kHttp[0]) - 1) ||
2611 
2612  /* Content-Length: <content_length>\r\n */
2613  (x_c_l
2614  && !BUF_Write(&buf, temp, (size_t)
2615  sprintf(temp, "Content-Length: %lu\r\n",
2616  (unsigned long) content_length))) ||
2617 
2618  /* <user_header> */
2619  (user_hdr_len
2620  && !BUF_Write(&buf, user_hdr, user_hdr_len)) ||
2621 
2622  /* header separator */
2623  !BUF_Write(&buf, "\r\n\r\n", user_hdr_len ? 4 : 2) ||
2624 
2625  /* tunneled data */
2626  (x_req_meth == eReqMethod_Connect
2627  && content_length && content_length != (size_t)(-1L)
2628  && !BUF_Write(&buf, args, content_length))) {
2629  int x_errno = errno;
2630  if (port)
2631  sprintf(temp, ":%hu", port);
2632  else
2633  *temp = '\0';
2634  CORE_LOGF_ERRNO_X(5, eLOG_Error, x_errno,
2635  ("[URL_Connect; http%s://%s%s%s%.*s%s%.*s] "
2636  " Cannot build HTTP header",
2637  &"s"[!(flags & fSOCK_Secure)], host, temp,
2638  &"/"[path_len && *path == '/'], (int)path_len, path,
2639  &"?"[!args_len], (int) args_len, args));
2640  BUF_Destroy(buf);
2642  }
2643 
2644  if (!(hdr = (char*) malloc(hdr_len = BUF_Size(buf)))
2645  || BUF_Read(buf, hdr, hdr_len) != hdr_len) {
2646  int x_errno = errno;
2647  if (port)
2648  sprintf(temp, ":%hu", port);
2649  else
2650  *temp = '\0';
2651  CORE_LOGF_ERRNO_X(6, eLOG_Error, x_errno,
2652  ("[URL_Connect; http%s://%s%s%s%.*s%s%.*s] "
2653  " Cannot maintain HTTP header (%lu byte%s)",
2654  &"s"[!(flags & fSOCK_Secure)], host, temp,
2655  &"/"[path_len && *path == '/'], (int)path_len, path,
2656  &"?"[!args_len], (int) args_len, args,
2657  (unsigned long) hdr_len, &"s"[hdr_len == 1]));
2658  if (hdr)
2659  free(hdr);
2660  BUF_Destroy(buf);
2662  }
2663  BUF_Destroy(buf);
2664 
2665  memset(&init, 0, sizeof(init));
2666  init.data = hdr;
2667  init.size = hdr_len;
2668  if (extra) {
2669  init.cred = extra->cred;
2670  init.host = extra->host;
2671  }
2672 
2673  if (s) {
2674  /* re-use existing connection */
2675  status = SOCK_CreateOnTopInternal(s/*old*/, 0, sock/*new*/,
2676  &init, flags);
2677  SOCK_Destroy(s);
2678  } else {
2679  /* connect to HTTPD */
2680  status = SOCK_CreateInternal(host, x_port, o_timeout, sock/*new*/,
2681  &init, flags);
2682  if (*sock)
2683  SOCK_DisableOSSendDelay(*sock, 1/*yes,disable*/);
2684  }
2685  free(hdr);
2686 
2687  if (status != eIO_Success) {
2688  char timeout[40];
2689  assert(!*sock);
2690  if (status == eIO_Timeout && o_timeout) {
2691  sprintf(timeout, "[%u.%06u]",
2692  o_timeout->usec / 1000000 + o_timeout->sec,
2693  o_timeout->usec % 1000000);
2694  } else
2695  *timeout = '\0';
2696  if (port)
2697  sprintf(temp, ":%hu", port);
2698  else
2699  *temp = '\0';
2701  ("[URL_Connect; http%s://%s%s%s%.*s%s%.*s] "
2702  " Failed to %s: %s%s",
2703  &"s"[!(flags & fSOCK_Secure)], host, temp,
2704  &"/"[path_len && *path == '/'], (int) path_len, path,
2705  &"?"[!args_len], (int) args_len, args,
2706  s ? "use connection" : "connect",
2707  IO_StatusStr(status), timeout));
2708  } else
2709  verify(SOCK_SetTimeout(*sock, eIO_ReadWrite, rw_timeout)==eIO_Success);
2710  return status;
2711 }
2712 
2713 
2715 (const char* host,
2716  unsigned short port,
2717  const char* path,
2718  const char* args,
2719  EReqMethod req_method,
2720  size_t content_length,
2721  const STimeout* o_timeout,
2722  const STimeout* rw_timeout,
2723  const char* user_hdr,
2724  int/*bool*/ encode_args,
2726 {
2727  static const char kHost[] = "Host: ";
2728  const char* x_hdr = user_hdr;
2729  static void* s_Once = 0;
2730  char* x_args = 0;
2731  SOCK sock;
2732 
2733  if (!CORE_Once(&s_Once)) {
2734  CORE_LOG(eLOG_Warning, "[URL_Connect] "
2735  " *DEPRECATED*!!! DON'T USE IT!! Update your code please!");
2736  }
2737  if (req_method >= eReqMethod_v1) {
2739  "[URL_Connect] Unsupported version of HTTP protocol");
2740  return 0;
2741  }
2742 
2743  if (req_method != eReqMethod_Connect) {
2744  size_t x_add = 1/*true*/;
2745  while (x_hdr && *x_hdr) {
2746  if (x_hdr != user_hdr)
2747  x_hdr++;
2748  if (strncasecmp(x_hdr, kHost, sizeof(kHost) - 2) == 0) {
2749  x_add = 0/*false*/;
2750  break;
2751  }
2752  x_hdr = strchr(x_hdr, '\n');
2753  }
2754  if (x_add) {
2755  size_t x_len = host && *host ? strlen(host) : 0;
2756  char* x_host = x_len ? (char*) malloc(x_len + sizeof(kHost)+6) : 0;
2757  if (x_host) {
2758  memcpy(x_host, kHost, sizeof(kHost) - 1);
2759  memcpy(x_host + sizeof(kHost) - 1, host, x_len);
2760  x_len += sizeof(kHost) - 1;
2761  if (port)
2762  sprintf(x_host + x_len, ":%hu", port);
2763  else
2764  x_host[x_len] = '\0';
2765  if (!x_StrcatCRLF(&x_host, user_hdr, 1)) {
2766  x_hdr = user_hdr;
2767  free(x_host);
2768  } else
2769  x_hdr = x_host;
2770  } else
2771  x_hdr = user_hdr;
2772  } else
2773  x_hdr = user_hdr;
2774 
2775  if (args && encode_args && (x_add = strcspn(args, "#")) > 0) {
2776  /* URL-encode "args", if any specified */
2777  size_t size = 3 * x_add;
2778  size_t rd_len, wr_len;
2779  if (!(x_args = (char*) malloc(size + 1))) {
2780  CORE_LOGF_ERRNO_X(8, eLOG_Error, errno,
2781  ("[URL_Connect] Out of memory (%lu)",
2782  (unsigned long)(size + 1)));
2783  if (x_hdr != user_hdr)
2784  free((void*) x_hdr);
2785  return 0;
2786  }
2787  URL_Encode(args, x_add, &rd_len, x_args, size, &wr_len);
2788  assert(rd_len == x_add);
2789  assert(wr_len <= size);
2790  x_args[wr_len] = '\0';
2791  args = x_args;
2792  }
2793  }
2794 
2795  sock = 0;
2796  verify(URL_ConnectEx(host, port, path, args,
2797  req_method, content_length,
2798  o_timeout, rw_timeout,
2799  x_hdr, 0/*cred*/, flags, &sock) == eIO_Success
2800  || !sock);
2801 
2802  if (x_args)
2803  free(x_args);
2804  if (x_hdr != user_hdr)
2805  free((void*) x_hdr);
2806  return sock;
2807 }
2808 
2809 
2810 
2811 /****************************************************************************
2812  * StripToPattern()
2813  */
2814 
2815 
2816 typedef EIO_Status (*FDoIO)
2817 (void* stream,
2818  void* buf,
2819  size_t size,
2820  size_t* n_read,
2821  EIO_Event what /* eIO_Read | eIO_Write (to pushback) */
2822  );
2823 
2825 (void* stream,
2826  FDoIO io_func,
2827  const void* pattern,
2828  size_t pattern_size,
2829  BUF* discard,
2830  size_t* n_discarded)
2831 {
2832  char* buf;
2833  size_t n_read;
2834  size_t buf_size;
2835  char x_buf[4096];
2836  EIO_Status retval, status;
2837 
2838  /* check args */
2839  if ( n_discarded )
2840  *n_discarded = 0;
2841  if (!stream)
2842  return eIO_InvalidArg;
2843 
2844  if (!pattern_size) {
2845  pattern = 0;
2846  buf_size = sizeof(x_buf);
2847  } else
2848  buf_size = pattern ? pattern_size << 1 : pattern_size;
2849 
2850  /* allocate a temporary read buffer */
2851  if (buf_size <= sizeof(x_buf) && pattern) {
2852  buf_size = sizeof(x_buf);
2853  buf = x_buf;
2854  } else if (!(buf = (char*) malloc(buf_size)))
2855  return eIO_Unknown;
2856 
2857  retval = eIO_Success;
2858  if (!pattern) {
2859  /* read/discard the specified # of bytes or until EOF */
2860  char* xx_buf = buf;
2861  for (;;) {
2862  status = io_func(stream, xx_buf, buf_size, &n_read, eIO_Read);
2863  assert(buf_size && n_read <= buf_size);
2864  if (!n_read) {
2865  assert(status != eIO_Success);
2866  retval = status;
2867  break;
2868  }
2869  if (discard) {
2870  if (xx_buf == buf) {
2871  /* enqueue the entire buffer when new */
2872  if (BUF_AppendEx(discard, buf, buf_size, xx_buf, n_read))
2873  buf = 0/*mark it not to be free()'d at the end*/;
2874  else
2875  retval = status = eIO_Unknown;
2876  } else /*NB:zero-copy,can't fail!*/
2877  verify(BUF_Write(discard, xx_buf, n_read));
2878  }
2879  if ( n_discarded )
2880  *n_discarded += n_read;
2881  if (!(buf_size -= n_read)) {
2882  if (pattern_size)
2883  break;
2884  if (status != eIO_Success) {
2885  retval = status;
2886  break;
2887  }
2888  buf_size = sizeof(x_buf);
2889  if (!buf && !(buf = (char*) malloc(buf_size))) {
2890  retval = eIO_Unknown;
2891  break;
2892  }
2893  xx_buf = buf;
2894  continue;
2895  }
2896  if (status != eIO_Success) {
2897  retval = status;
2898  break;
2899  } else
2900  xx_buf += n_read;
2901  }
2902  } else {
2903  /* pattern search case */
2904  assert(pattern_size);
2905  --pattern_size;
2906  n_read = 0;
2907  for (;;) {
2908  /* read; search for the pattern; store/count the discarded data */
2909  size_t x_read, n_stored;
2910 
2911  assert(n_read <= pattern_size && n_read < buf_size);
2912  status = io_func(stream, buf + n_read, buf_size - n_read,
2913  &x_read, eIO_Read);
2914  assert(x_read <= buf_size - n_read);
2915  if (!x_read) {
2916  assert(status != eIO_Success);
2917  retval = status;
2918  break;
2919  }
2920  n_stored = n_read + x_read;
2921 
2922  if (n_stored > pattern_size) {
2923  /* search for the pattern */
2924  size_t n_check;
2925  const char* b = buf;
2926  for (n_check = n_stored - pattern_size; n_check; --n_check) {
2927  if (*b++ != *((const char*)pattern))
2928  continue;
2929  if (!pattern_size)
2930  break; /*found*/
2931  if (memcmp(b, (const char*)pattern + 1, pattern_size) == 0)
2932  break; /*found*/
2933  }
2934  if ( n_check ) {
2935  /* pattern found */
2936  size_t x_discarded = (size_t)(b - buf) + pattern_size;
2937  if (discard && !BUF_Write(discard, buf + n_read,
2938  x_discarded - n_read)) {
2939  retval = status = eIO_Unknown;
2940  }
2941  if ( n_discarded )
2942  *n_discarded += x_discarded - n_read;
2943  /* return the unused portion to the stream */
2944  status = io_func(stream, buf + x_discarded,
2945  n_stored - x_discarded, 0, eIO_Write);
2946  if (retval == eIO_Success)
2947  retval = status;
2948  break;
2949  }
2950  }
2951 
2952  /* pattern still not found */
2953  if ( n_discarded )
2954  *n_discarded += x_read;
2955  if (discard && !BUF_Write(discard, buf + n_read, x_read)) {
2956  retval = eIO_Unknown;
2957  break;
2958  }
2959  if (status != eIO_Success) {
2960  retval = status;
2961  break;
2962  }
2963  if (n_stored > pattern_size) {
2964  n_read = pattern_size;
2965  memmove(buf, buf + n_stored - n_read, n_read);
2966  } else
2967  n_read = n_stored;
2968  }
2969  }
2970 
2971  /* cleanup & exit */
2972  if (buf && buf != x_buf)
2973  free(buf);
2974  return retval;
2975 }
2976 
2977 
2979 (void* stream,
2980  void* buf,
2981  size_t size,
2982  size_t* n_read,
2983  EIO_Event what)
2984 {
2985  switch (what) {
2986  case eIO_Read:
2987  return CONN_Read((CONN) stream, buf, size, n_read, eIO_ReadPlain);
2988  case eIO_Write:
2989  return CONN_Pushback((CONN) stream, buf, size);
2990  default:
2991  assert(0);
2992  break;
2993  }
2994  return eIO_InvalidArg;
2995 }
2996 
2998 (CONN conn,
2999  const void* pattern,
3000  size_t pattern_size,
3001  BUF* discard,
3002  size_t* n_discarded)
3003 {
3004  return s_StripToPattern
3005  (conn, s_CONN_IO, pattern, pattern_size, discard, n_discarded);
3006 }
3007 
3008 
3010 (void* stream,
3011  void* buf,
3012  size_t size,
3013  size_t* n_read,
3014  EIO_Event what)
3015 {
3016  switch (what) {
3017  case eIO_Read:
3018  return SOCK_Read((SOCK) stream, buf, size, n_read, eIO_ReadPlain);
3019  case eIO_Write:
3020  return SOCK_Pushback((SOCK) stream, buf, size);
3021  default:
3022  assert(0);
3023  break;
3024  }
3025  return eIO_InvalidArg;
3026 }
3027 
3029 (SOCK sock,
3030  const void* pattern,
3031  size_t pattern_size,
3032  BUF* discard,
3033  size_t* n_discarded)
3034 {
3035  return s_StripToPattern
3036  (sock, s_SOCK_IO, pattern, pattern_size, discard, n_discarded);
3037 }
3038 
3039 
3041 (void* stream,
3042  void* buf,
3043  size_t size,
3044  size_t* n_read,
3045  EIO_Event what)
3046 {
3047  BUF b;
3048  switch (what) {
3049  case eIO_Read:
3050  *n_read = BUF_Read((BUF) stream, buf, size);
3051  return *n_read || !size ? eIO_Success : eIO_Closed;
3052  case eIO_Write:
3053  assert(stream);
3054  b = (BUF) stream;
3055  return BUF_Pushback(&b, buf, size) ? eIO_Success : eIO_Unknown;
3056  default:
3057  assert(0);
3058  break;
3059  }
3060  return eIO_InvalidArg;
3061 }
3062 
3064 (BUF buffer,
3065  const void* pattern,
3066  size_t pattern_size,
3067  BUF* discard,
3068  size_t* n_discarded)
3069 {
3070  return s_StripToPattern
3071  (buffer, s_BUF_IO, pattern, pattern_size, discard, n_discarded);
3072 }
3073 
3074 
3075 
3076 /****************************************************************************
3077  * URL- Encoding/Decoding
3078  */
3079 
3080 
3081 /* Return integer (0..15) corresponding to the "ch" as a hex digit.
3082  * Return -1 on error.
3083  */
3084 static int s_HexChar(char ch)
3085 {
3086  unsigned int rc = (unsigned int)(ch - '0');
3087  if (rc <= 9)
3088  return (int) rc;
3089  rc = (unsigned int)((ch | ' ') - 'a');
3090  return rc <= 5 ? (int)(rc + 10) : -1;
3091 }
3092 
3093 
3094 /* The URL-encoding table
3095  */
3096 static const char s_EncodeTable[256][4] = {
3097  "%00", "%01", "%02", "%03", "%04", "%05", "%06", "%07",
3098  "%08", "%09", "%0A", "%0B", "%0C", "%0D", "%0E", "%0F",
3099  "%10", "%11", "%12", "%13", "%14", "%15", "%16", "%17",
3100  "%18", "%19", "%1A", "%1B", "%1C", "%1D", "%1E", "%1F",
3101  "+", "!", "%22", "%23", "$", "%25", "%26", "'",
3102  "(", ")", "*", "%2B", ",", "-", ".", "%2F",
3103  "0", "1", "2", "3", "4", "5", "6", "7",
3104  "8", "9", "%3A", "%3B", "%3C", "%3D", "%3E", "%3F",
3105  "%40", "A", "B", "C", "D", "E", "F", "G",
3106  "H", "I", "J", "K", "L", "M", "N", "O",
3107  "P", "Q", "R", "S", "T", "U", "V", "W",
3108  "X", "Y", "Z", "%5B", "%5C", "%5D", "%5E", "_",
3109  "%60", "a", "b", "c", "d", "e", "f", "g",
3110  "h", "i", "j", "k", "l", "m", "n", "o",
3111  "p", "q", "r", "s", "t", "u", "v", "w",
3112  "x", "y", "z", "%7B", "%7C", "%7D", "%7E", "%7F",
3113  "%80", "%81", "%82", "%83", "%84", "%85", "%86", "%87",
3114  "%88", "%89", "%8A", "%8B", "%8C", "%8D", "%8E", "%8F",
3115  "%90", "%91", "%92", "%93", "%94", "%95", "%96", "%97",
3116  "%98", "%99", "%9A", "%9B", "%9C", "%9D", "%9E", "%9F",
3117  "%A0", "%A1", "%A2", "%A3", "%A4", "%A5", "%A6", "%A7",
3118  "%A8", "%A9", "%AA", "%AB", "%AC", "%AD", "%AE", "%AF",
3119  "%B0", "%B1", "%B2", "%B3", "%B4", "%B5", "%B6", "%B7",
3120  "%B8", "%B9", "%BA", "%BB", "%BC", "%BD", "%BE", "%BF",
3121  "%C0", "%C1", "%C2", "%C3", "%C4", "%C5", "%C6", "%C7",
3122  "%C8", "%C9", "%CA", "%CB", "%CC", "%CD", "%CE", "%CF",
3123  "%D0", "%D1", "%D2", "%D3", "%D4", "%D5", "%D6", "%D7",
3124  "%D8", "%D9", "%DA", "%DB", "%DC", "%DD", "%DE", "%DF",
3125  "%E0", "%E1", "%E2", "%E3", "%E4", "%E5", "%E6", "%E7",
3126  "%E8", "%E9", "%EA", "%EB", "%EC", "%ED", "%EE", "%EF",
3127  "%F0", "%F1", "%F2", "%F3", "%F4", "%F5", "%F6", "%F7",
3128  "%F8", "%F9", "%FA", "%FB", "%FC", "%FD", "%FE", "%FF"
3129 };
3130 
3131 #define VALID_URL_SYMBOL(ch) (s_EncodeTable[(unsigned char)ch][0] != '%')
3132 
3133 
3134 extern int/*bool*/ URL_DecodeEx
3135 (const void* src_buf,
3136  size_t src_size,
3137  size_t* src_read,
3138  void* dst_buf,
3139  size_t dst_size,
3140  size_t* dst_written,
3141  const char* allow_symbols)
3142 {
3143  const char* src = (char* const) src_buf;
3144  char* dst = (char*) dst_buf;
3145 
3146  *src_read = 0;
3147  *dst_written = 0;
3148  if (!src_size || !dst_size)
3149  return 1/*true*/;
3150  if (!src || !dst)
3151  return 0/*false*/;
3152 
3153  for ( ; *src_read != src_size && *dst_written != dst_size;
3154  ++(*src_read), ++(*dst_written), ++src, ++dst) {
3155  switch ( *src ) {
3156  case '+':
3157  *dst = ' ';
3158  break;
3159  case '%':
3160  if (*src_read + 2 < src_size) {
3161  int i1, i2;
3162  if ((i1 = s_HexChar(src[1])) != -1 &&
3163  (i2 = s_HexChar(src[2])) != -1) {
3164  *dst = (char)((i1 << 4) + i2);
3165  *src_read += 2;
3166  src += 2;
3167  break;
3168  }
3169  } else if (src != src_buf) {
3170  assert(*dst_written);
3171  return 1/*true*/;
3172  }
3173  if (!allow_symbols || *allow_symbols)
3174  return *dst_written ? 1/*true*/ : 0/*false*/;
3175  /*FALLTHRU*/
3176  default:
3177  if (VALID_URL_SYMBOL(*src)
3178  || (allow_symbols && (!*allow_symbols
3179  || strchr(allow_symbols, *src)))) {
3180  *dst = *src;
3181  } else
3182  return *dst_written ? 1/*true*/ : 0/*false*/;
3183  }
3184  }
3185 
3186  assert(src == (const char*) src_buf + *src_read );
3187  assert(dst == (char*) dst_buf + *dst_written);
3188  assert(*src_read && *dst_written);
3189  return 1/*true*/;
3190 }
3191 
3192 
3193 extern int/*bool*/ URL_Decode
3194 (const void* src_buf,
3195  size_t src_size,
3196  size_t* src_read,
3197  void* dst_buf,
3198  size_t dst_size,
3199  size_t* dst_written)
3200 {
3201  return URL_DecodeEx
3202  (src_buf, src_size, src_read, dst_buf, dst_size, dst_written, 0);
3203 }
3204 
3205 
3206 extern void URL_EncodeEx
3207 (const void* src_buf,
3208  size_t src_size,
3209  size_t* src_read,
3210  void* dst_buf,
3211  size_t dst_size,
3212  size_t* dst_written,
3213  const char* allow_symbols)
3214 {
3215  const char* src = (const char*) src_buf;
3216  char* dst = (char*) dst_buf;
3217 
3218  *src_read = 0;
3219  *dst_written = 0;
3220  if (!src_size || !dst_size || !dst || !src)
3221  return;
3222 
3223  for ( ; *src_read != src_size && *dst_written != dst_size;
3224  ++(*src_read), ++(*dst_written), ++src, ++dst) {
3225  const char* subst = allow_symbols ? strchr(allow_symbols, *src) : 0;
3226  if (subst) {
3227  *dst = *subst;
3228  continue;
3229  }
3230  subst = s_EncodeTable[*((unsigned char*) src)];
3231  if (*subst != '%') {
3232  *dst = *subst;
3233  } else if (*dst_written < dst_size - 2) {
3234  *dst = '%';
3235  *(++dst) = *(++subst);
3236  *(++dst) = *(++subst);
3237  *dst_written += 2;
3238  } else
3239  break;
3240  }
3241  assert(src == (const char*) src_buf + *src_read );
3242  assert(dst == (char*) dst_buf + *dst_written);
3243 }
3244 
3245 
3246 extern void URL_Encode
3247 (const void* src_buf,
3248  size_t src_size,
3249  size_t* src_read,
3250  void* dst_buf,
3251  size_t dst_size,
3252  size_t* dst_written)
3253 {
3254  URL_EncodeEx
3255  (src_buf, src_size, src_read, dst_buf, dst_size, dst_written, 0);
3256 }
3257 
3258 
3259 
3260 /****************************************************************************
3261  * NCBI-specific MIME content type and sub-types
3262  */
3263 
3264 
3265 static const char* kMIME_Type[eMIME_T_Unknown+1] = {
3266  "x-ncbi-data",
3267  "text",
3268  "application",
3269  "unknown"
3270 };
3271 
3272 static const char* kMIME_SubType[eMIME_Unknown+1] = {
3273  "x-dispatch",
3274  "x-asn-text",
3275  "x-asn-binary",
3276  "x-fasta",
3277  "x-www-form",
3278  "html",
3279  "plain",
3280  "xml",
3281  "xml+soap",
3282  "octet-stream",
3283  "x-unknown"
3284 };
3285 
3286 static const char* kMIME_Encoding[eENCOD_Unknown+1] = {
3287  "",
3288  "urlencoded",
3289  "encoded"
3290 };
3291 
3292 
3294 (EMIME_Type type,
3295  EMIME_SubType subtype,
3296  EMIME_Encoding encoding,
3297  char* buf,
3298  size_t bufsize)
3299 {
3300  static const char kContentType[] = "Content-Type: ";
3301  const char* x_type, *x_subtype, *x_encoding;
3302  char x_buf[CONN_CONTENT_TYPE_LEN+1];
3303  size_t len;
3304  char* rv;
3305 
3306  assert(buf && bufsize);
3307 
3308  *buf = '\0';
3309  if (type == eMIME_T_Undefined || subtype == eMIME_Undefined)
3310  return 0;
3311 
3312  if (type >= eMIME_T_Unknown)
3314  if (subtype >= eMIME_Unknown)
3315  subtype = eMIME_Unknown;
3316  if (encoding >= eENCOD_Unknown)
3317  encoding = eENCOD_Unknown;
3318 
3319  x_type = kMIME_Type [type];
3320  x_subtype = kMIME_SubType [subtype];
3321  x_encoding = kMIME_Encoding[encoding];
3322 
3323  if ( *x_encoding ) {
3324  assert(sizeof(kContentType) + strlen(x_type) + strlen(x_subtype)
3325  + strlen(x_encoding) + 4 < sizeof(x_buf));
3326  sprintf(x_buf, "%s%s/%s-%s\r\n",
3327  kContentType, x_type, x_subtype, x_encoding);
3328  } else {
3329  assert(sizeof(kContentType) + strlen(x_type) + strlen(x_subtype)
3330  + 3 < sizeof(x_buf));
3331  sprintf(x_buf, "%s%s/%s\r\n", kContentType, x_type, x_subtype);
3332  }
3333  len = strlen(x_buf);
3334  assert(len < sizeof(x_buf));
3335  if (len >= bufsize) {
3336  len = bufsize - 1;
3337  rv = 0;
3338  } else
3339  rv = buf;
3340  strncpy0(buf, x_buf, len);
3341  return rv;
3342 }
3343 
3344 
3345 extern int/*bool*/ MIME_ParseContentTypeEx
3346 (const char* str,
3347  EMIME_Type* type,
3348  EMIME_SubType* subtype,
3349  EMIME_Encoding* encoding)
3350 {
3351  char* x_buf;
3352  size_t x_size;
3353  char* x_type;
3354  char* x_subtype;
3355  int i;
3356 
3357  if ( type )
3359  if ( subtype )
3360  *subtype = eMIME_Undefined;
3361  if ( encoding )
3362  *encoding = eENCOD_None;
3363 
3364  x_size = str && *str ? strlen(str) + 1 : 0;
3365  if (!x_size)
3366  return 0/*failure*/;
3367 
3368  if (!(x_buf = (char*) malloc(x_size << 1)))
3369  return 0/*failure*/;
3370  x_type = x_buf + x_size;
3371 
3372  strlwr(strcpy(x_buf, str));
3373 
3374  if ((sscanf(x_buf, " content-type: %s ", x_type) != 1 &&
3375  sscanf(x_buf, " %s ", x_type) != 1)
3376  || !(x_subtype = strchr(x_type, '/'))) {
3377  free(x_buf);
3378  return 0/*failure*/;
3379  }
3380  *x_subtype++ = '\0';
3381  x_size = strlen(x_subtype);
3382 
3383  if ( type ) {
3384  for (i = 0; i < (int) eMIME_T_Unknown; ++i) {
3385  if (strcmp(x_type, kMIME_Type[i]) == 0)
3386  break;
3387  }
3388  *type = (EMIME_Type) i;
3389  }
3390 
3391  for (i = 1; i <= (int) eENCOD_Unknown; ++i) {
3392  size_t len = strlen(kMIME_Encoding[i]);
3393  if (len < x_size) {
3394  char* x_encoding = x_subtype + x_size - len;
3395  if (x_encoding[-1] == '-'
3396  && strcmp(x_encoding, kMIME_Encoding[i]) == 0) {
3397  if ( encoding ) {
3398  *encoding = (i == (int) eENCOD_Unknown
3399  ? eENCOD_None : (EMIME_Encoding) i);
3400  }
3401  x_encoding[-1] = '\0';
3402  break;
3403  }
3404  }
3405  }
3406 
3407  if ( subtype ) {
3408  for (i = 0; i < (int) eMIME_Unknown; ++i) {
3409  if (strcmp(x_subtype, kMIME_SubType[i]) == 0)
3410  break;
3411  }
3412  *subtype = (EMIME_SubType) i;
3413  }
3414 
3415  free(x_buf);
3416  return 1/*success*/;
3417 }
3418 
3419 
3421 {
3422  memset(s_FWPorts, 0, sizeof(s_FWPorts));
3423 }
3424 
3425 
3426 int/*bool*/ SERV_AddFirewallPort(unsigned short port)
3427 {
3428  unsigned int n, m;
3429  if (!port--)
3430  return 0/*false*/;
3431  n = port / (sizeof(s_FWPorts[0]) << 3);
3432  m = port % (sizeof(s_FWPorts[0]) << 3);
3433  if ((size_t) n < SizeOf(s_FWPorts)) {
3434  s_FWPorts[n] |= (TNCBI_BigCount) 1 << m;
3435  return 1/*true*/;
3436  }
3437  return 0/*false*/;
3438 }
3439 
3440 
3441 int/*bool*/ SERV_IsFirewallPort(unsigned short port)
3442 {
3443  unsigned int n, m;
3444  if (!port--)
3445  return 0/*false*/;
3446  n = port / (sizeof(s_FWPorts[0]) << 3);
3447  m = port % (sizeof(s_FWPorts[0]) << 3);
3448  if ((size_t) n < SizeOf(s_FWPorts) &&
3449  s_FWPorts[n] & ((TNCBI_BigCount) 1 << m)) {
3450  return 1/*true*/;
3451  }
3452  return 0/*false*/;
3453 }
3454 
3455 
3457 {
3458  unsigned short m;
3459  size_t len, n;
3460 
3461  assert(buf && bufsize > 1);
3462  switch (mode) {
3463  case eFWMode_Legacy:
3464  *buf = '\0';
3465  return;
3466  case eFWMode_Firewall:
3467  memcpy(buf, "0", 2);
3468  return;
3469  default:
3470  break;
3471  }
3472  m = 0;
3473  len = 0;
3474  for (n = 0; n < SizeOf(s_FWPorts); ++n) {
3475  unsigned short p;
3477  for (p = (unsigned short)(m + 1); mask; ++p, mask >>= 1) {
3478  if (mask & 1) {
3479  char port[10];
3480  size_t k = (size_t) sprintf(port, &" %hu"[!len], p);
3481  if (len + k < bufsize) {
3482  memcpy(buf + len, port, k);
3483  len += k;
3484  }
3485  }
3486  }
3487  m = (unsigned short)(m + (sizeof(s_FWPorts[0]) << 3));
3488  }
3489  buf[len] = '\0';
3490 }
ncbi::TMaskedQueryRegions mask
static const char * kContentType
static uch flags
static const char ip[]
Definition: des.c:75
std::ofstream out("events_result.xml")
main entry point for tests
const char * kHost
static CS_CONNECTION * conn
Definition: ct_dynamic.c:25
#define strcat(s, k)
static void DLIST_NAME() init(DLIST_LIST_TYPE *list)
Definition: dlist.tmpl.h:40
static int type
Definition: getdata.c:31
static const char * str(char *buf, int n)
Definition: stats.c:84
static HENV env
Definition: transaction2.c:38
static char tmp[3200]
Definition: utf8.c:42
@ eDefault
Definition: ncbi_types.h:112
int BUF_Write(BUF *pBuf, const void *data, size_t size)
Definition: ncbi_buffer.c:224
size_t BUF_Size(BUF buf)
Definition: ncbi_buffer.c:84
struct SNcbiBuf * BUF
handle of a buffer
Definition: ncbi_buffer.h:72
int BUF_Pushback(BUF *pBuf, const void *data, size_t size)
Definition: ncbi_buffer.c:285
int BUF_AppendEx(BUF *pBuf, void *base, size_t alloc_size, void *data, size_t size)
Definition: ncbi_buffer.c:138
size_t BUF_Read(BUF buf, void *data, size_t size)
Definition: ncbi_buffer.c:414
void BUF_Destroy(BUF buf)
Definition: ncbi_buffer.c:500
EIO_Status CONN_Read(CONN conn, void *buf, size_t size, size_t *n_read, EIO_ReadMethod how)
const STimeout g_NcbiDefConnTimeout
DEF_CONN_TIMEOUT as STimeout.
Definition: ncbi_connutil.c:54
EIO_Status CONN_Pushback(CONN conn, const void *data, size_t size)
Push "size" bytes from the buffer "data" back into connection.
EIO_Status SOCK_SetTimeout(SOCK sock, EIO_Event event, const STimeout *timeout)
Specify timeout for the connection I/O (see SOCK_[Read|Write|Close]()).
Definition: ncbi_socket.c:7194
void SOCK_DisableOSSendDelay(SOCK sock, int on_off)
Control OS-defined send strategy by disabling/enabling the TCP Nagle algorithm (which is on by defaul...
Definition: ncbi_socket.c:7815
#define SOCK_Destroy(s)
Definition: ncbi_socket.h:875
EIO_Status SOCK_Close(SOCK sock)
Close the SOCK handle, and destroy all relevant internal data.
Definition: ncbi_socket.c:6851
EIO_Status SOCK_Read(SOCK sock, void *buf, size_t size, size_t *n_read, EIO_ReadMethod how)
Read/peek up to "size" bytes from "sock" to a buffer pointed to by "buf".
Definition: ncbi_socket.c:7270
int SOCK_gethostname(char *name, size_t namelen)
Same as SOCK_gethostnameEx(,,<current API data logging>)
Definition: ncbi_socket.c:8774
unsigned int SOCK_gethostbyname(const char *hostname)
Same as SOCK_gethostbynameEx(,<current API data logging>)
Definition: ncbi_socket.c:8790
EIO_Status SOCK_Pushback(SOCK sock, const void *data, size_t size)
Push the specified data back to the socket's input queue (in the socket's internal read buffer).
Definition: ncbi_socket.c:7439
EIO_Status SOCK_Abort(SOCK sock)
If there is outstanding connection or output data pending, cancel it.
Definition: ncbi_socket.c:7557
int SOCK_ntoa(unsigned int addr, char *buf, size_t bufsize)
Convert IP address to a string in dotted notation.
Definition: ncbi_socket.c:8661
unsigned int SOCK_GetLocalHostAddress(ESwitch reget)
Get (and cache for faster follow-up retrievals) IPv4 address of local host.
Definition: ncbi_socket.c:8827
const char * SOCK_gethostbyaddr(unsigned int addr, char *name, size_t namelen)
Same as SOCK_gethostbyaddrEx(,,<current API data logging>)
Definition: ncbi_socket.c:8813
int SOCK_isip(const char *host)
Equivalent of SOCK_isip(host, 0)
Definition: ncbi_socket.c:8712
unsigned int TSOCK_Flags
bitwise "OR" of ESOCK_Flags
Definition: ncbi_socket.h:503
@ fSOCK_Secure
subsumes CloseOnExec regardless of Keep
Definition: ncbi_socket.h:497
#define DEF_CONN_HOST
#define LOG_WRITE(lg, code, subcode, level, message)
Auxiliary plain macros to write message (maybe, with raw data) to the log.
Definition: ncbi_util.h:136
#define DEF_CONN_PASS
ELOG_Level
Log severity level.
Definition: ncbi_core.h:292
TReqMethod req_method
unsigned EBProxyType
#define REG_CONN_ARGS
#define REG_CONN_HTTP_VERSION
#define DEF_CONN_HTTP_PROXY_SKIP
EURLScheme
unsigned external
char http_proxy_host[255+1]
unsigned lb_disable
EBFWMode firewall
int ConnNetInfo_ExtendUserHeader(SConnNetInfo *info, const char *header)
const char * host
SSL host id (aka SNI) (if differs from "host")
unsigned TReqMethod
EIO_Status URL_ConnectEx(const char *host, unsigned short port, const char *path, const char *args, TReqMethod req_method, size_t content_length, const STimeout *o_timeout, const STimeout *rw_timeout, const char *user_hdr, SURLExtra *extra, TSOCK_Flags flags, SOCK *sock)
#define DEF_CONN_USER
#define REG_CONN_HOST
int ConnNetInfo_AddPath(SConnNetInfo *info, const char *path)
int ConnNetInfo_SetupStandardArgs(SConnNetInfo *info, const char *service)
#define REG_CONN_PATH
#define UTIL_PrintableString(d, s, b, f)
Same as UTIL_PrintableStringEx(..., 0) – i.e.
Definition: ncbi_util.h:781
char http_proxy_user[63+1]
unsigned short http_proxy_port
#define DEF_CONN_HTTP_PROXY_HOST
#define kInfiniteTimeout
Definition: ncbi_types.h:82
#define REG_CONN_HTTP_PROXY_PORT
unsigned short unused
int ConnNetInfo_SetTimeout(SConnNetInfo *info, const STimeout *timeout)
int ConnNetInfo_OverrideUserHeader(SConnNetInfo *info, const char *header)
void ConnNetInfo_DeleteAllArgs(SConnNetInfo *info, const char *args)
int ConnNetInfo_PreOverrideUserHeader(SConnNetInfo *info, const char *header)
const STimeout * timeout
unsigned short port
int ConnNetInfo_ParseURL(SConnNetInfo *info, const char *url)
#define DEF_CONN_PATH
unsigned http_push_auth
STimeout tmo
char * MIME_ComposeContentTypeEx(EMIME_Type type, EMIME_SubType subtype, EMIME_Encoding encoding, char *buf, size_t bufsize)
int ConnNetInfo_SetArgs(SConnNetInfo *info, const char *args)
EMIME_Type
EMIME_SubType
int ConnNetInfo_AppendUserHeader(SConnNetInfo *info, const char *user_header)
SConnNetInfo * ConnNetInfo_Clone(const SConnNetInfo *info)
int ConnNetInfo_AppendArg(SConnNetInfo *info, const char *arg, const char *val)
#define REG_CONN_HTTP_PROXY_USER
#define REG_CONN_DEBUG_PRINTOUT
char user[63+1]
#define REG_CONN_HTTP_USER_HEADER
const char * ConnNetInfo_GetValue(const char *service, const char *param, char *value, size_t value_size, const char *def_value)
#define DEF_CONN_LB_DISABLE
#define DEF_CONN_HTTP_PUSH_AUTH
EIO_Status
I/O status.
Definition: ncbi_core.h:132
#define REG_CONN_TIMEOUT
#define REG_CONN_STATELESS
EIO_Status CONN_StripToPattern(CONN conn, const void *pattern, size_t pattern_size, BUF *discard, size_t *n_discarded)
Discard all input data before (and including) the first occurrence of a "pattern".
#define REG_CONN_HTTP_PUSH_AUTH
unsigned reserved
unsigned int usec
microseconds (modulo 1,000,000)
Definition: ncbi_types.h:78
#define REG_CONN_LB_DISABLE
int URL_Decode(const void *src_buf, size_t src_size, size_t *src_read, void *dst_buf, size_t dst_size, size_t *dst_written)
#define CONN_CONTENT_TYPE_LEN
char http_proxy_pass[63+1]
#define DEF_CONN_FIREWALL
const char * ConnNetInfo_GetArgs(const SConnNetInfo *info)
EMIME_Encoding
int ConnNetInfo_PreOverrideArg(SConnNetInfo *info, const char *arg, const char *val)
#define DEF_CONN_REQ_METHOD
#define REG_CONN_FIREWALL
#define REG_CONN_HTTP_PROXY_LEAK
unsigned http_proxy_leak
EReqMethod
unsigned stateless
SOCK URL_Connect(const char *host, unsigned short port, const char *path, const char *args, EReqMethod req_method, size_t content_length, const STimeout *o_timeout, const STimeout *rw_timeout, const char *user_hdr, int encode_args, TSOCK_Flags flags)
#define DEF_CONN_HTTP_PROXY_LEAK
EProxyType
const char svc[1]
#define DEF_CONN_STATELESS
EFWMode
#define DEF_CONN_HTTP_PROXY_PASS
char * ConnNetInfo_URL(const SConnNetInfo *info)
#define DEF_CONN_DEBUG_PRINTOUT
const char * IO_StatusStr(EIO_Status status)
Get the text form of an enum status value.
Definition: ncbi_core.c:56
#define REG_CONN_PORT
const char * CORE_GetAppName(void)
Obtain current application name (toolkit dependent).
Definition: ncbi_util.c:716
int ConnNetInfo_PostOverrideArg(SConnNetInfo *info, const char *arg, const char *val)
int ConnNetInfo_PrependUserHeader(SConnNetInfo *info, const char *user_header)
void LOG_Write(LOG lg, int code, int subcode, ELOG_Level level, const char *module, const char *func, const char *file, int line, const char *message, const void *raw_data, size_t raw_size)
Upon having filled SLOG_Message data from parameters, write a message (perhaps with raw data attached...
Definition: ncbi_core.c:424
int ConnNetInfo_SetUserHeader(SConnNetInfo *info, const char *user_header)
#define DEF_CONN_PORT
int MIME_ParseContentTypeEx(const char *str, EMIME_Type *type, EMIME_SubType *subtype, EMIME_Encoding *encoding)
void ConnNetInfo_DeleteUserHeader(SConnNetInfo *info, const char *header)
#define DEF_CONN_HTTP_PROXY_USER
#define REG_CONN_HTTP_REFERER
void URL_EncodeEx(const void *src_buf, size_t src_size, size_t *src_read, void *dst_buf, size_t dst_size, size_t *dst_written, const char *allow_symbols)
#define DEF_CONN_HTTP_REFERER
NCBI_CRED cred
SSL credentials (if any)
unsigned http_proxy_skip
#define REG_CONN_USER
#define REG_CONN_EXTERNAL
void ConnNetInfo_Log(const SConnNetInfo *info, ELOG_Level sev, LOG lg)
#define REG_CONN_REQ_METHOD
EBURLScheme scheme
const char * http_user_header
size_t UTIL_PrintableStringSize(const char *data, size_t size)
Calculate size of buffer needed to store printable representation of the block of data of the specifi...
Definition: ncbi_util.c:198
#define DEF_CONN_REG_SECTION
EBProxyType http_proxy_mask
unsigned short max_try
int ConnNetInfo_DeleteArg(SConnNetInfo *info, const char *arg)
#define REG_CONN_HTTP_PROXY_SKIP
unsigned int sec
seconds
Definition: ncbi_types.h:77
NCBI_CRED credentials
#define REG_CONN_MAX_TRY
char * UTIL_NcbiLocalHostName(char *hostname)
Cut off well-known NCBI domain suffix out of the passed "hostname".
Definition: ncbi_util.c:1384
char pass[63+1]
EIO_Status SOCK_StripToPattern(SOCK sock, const void *pattern, size_t pattern_size, BUF *discard, size_t *n_discarded)
SConnNetInfo * ConnNetInfo_Create(const char *service)
#define REG_CONN_HTTP_PROXY_HOST
int ConnNetInfo_PrependArg(SConnNetInfo *info, const char *arg, const char *val)
#define DEF_CONN_HTTP_USER_HEADER
unsigned http_version
EIO_Event
I/O event (or direction).
Definition: ncbi_core.h:118
unsigned int magic
#define DEF_CONN_HTTP_VERSION
void URL_Encode(const void *src_buf, size_t src_size, size_t *src_read, void *dst_buf, size_t dst_size, size_t *dst_written)
#define DEF_CONN_HTTP_PROXY_PORT
#define DEF_CONN_ARGS
char host[255+1]
int ConnNetInfo_Boolean(const char *str)
char client_host[255+1]
#define DEF_CONN_EXTERNAL
#define REG_CONN_PASS
#define kDefaultTimeout
Definition: ncbi_types.h:81
char path[4095+1]
const char * CORE_GetPlatform(void)
Return NCBI platrofm ID (if known).
Definition: ncbi_util.c:769
EBDebugPrintout debug_printout
#define DEF_CONN_MAX_TRY
#define DEF_CONN_TIMEOUT
int URL_DecodeEx(const void *src_buf, size_t src_size, size_t *src_read, void *dst_buf, size_t dst_size, size_t *dst_written, const char *allow_symbols)
int ConnNetInfo_SetPath(SConnNetInfo *info, const char *path)
const char * http_referer
void ConnNetInfo_Destroy(SConnNetInfo *info)
int ConnNetInfo_SetFrag(SConnNetInfo *info, const char *frag)
uint64_t TNCBI_BigCount
Big unsigned integer for file size and position.
Definition: ncbi_types.h:164
EIO_Status BUF_StripToPattern(BUF buffer, const void *pattern, size_t pattern_size, BUF *discard, size_t *n_discarded)
#define REG_CONN_HTTP_PROXY_PASS
@ eLOG_Critical
Definition: ncbi_core.h:298
@ eLOG_Error
Definition: ncbi_core.h:297
@ eLOG_Warning
Definition: ncbi_core.h:296
@ eLOG_Fatal
Definition: ncbi_core.h:299
@ eURL_Ftp
@ eURL_Unspec
@ eURL_Http
@ eURL_Https
@ eURL_File
@ eMIME_T_Undefined
@ eMIME_T_Unknown
@ eMIME_Undefined
@ eMIME_Unknown
@ eIO_Timeout
timeout expired before any I/O succeeded
Definition: ncbi_core.h:134
@ eIO_NotSupported
operation is not supported or is not available
Definition: ncbi_core.h:138
@ eIO_Success
everything is fine, no error occurred
Definition: ncbi_core.h:133
@ eIO_Unknown
unknown I/O error (likely fatal but can retry)
Definition: ncbi_core.h:139
@ eIO_InvalidArg
bad argument / parameter value(s) supplied
Definition: ncbi_core.h:137
@ eENCOD_None
@ eENCOD_Unknown
@ eReqMethod_Options
@ eReqMethod_Trace
@ eReqMethod_Any
@ eReqMethod_v1
@ eReqMethod_Put
@ eReqMethod_Delete
@ eReqMethod_Patch
@ eReqMethod_Get
@ eReqMethod_Connect
@ eReqMethod_Head
@ eReqMethod_Post
@ fProxy_None
No $http_proxy / $https_proxy used.
@ fProxy_Http
$http_proxy used
@ fProxy_Https
$https_proxy used
@ eFWMode_Legacy
Relay, no firewall.
@ eFWMode_Firewall
Regular firewall ports only, no fallback.
@ eFWMode_Adaptive
Regular firewall ports first, then fallback.
@ eFWMode_Fallback
Fallback ports only (w/o trying any regular)
@ eDebugPrintout_Some
@ eDebugPrintout_None
@ eDebugPrintout_Data
@ eIO_ReadPlain
read readily available data only, wait if none
Definition: ncbi_core.h:90
@ eIO_Write
write
Definition: ncbi_core.h:121
@ eIO_ReadWrite
eIO_Read | eIO_Write (also, eCONN_OnFlush)
Definition: ncbi_core.h:122
@ eIO_Read
read
Definition: ncbi_core.h:120
unsigned int
A callback function used to compare two keys in a database.
Definition: types.hpp:1210
char * buf
int i
if(yy_accept[yy_current_state])
yy_size_t n
int len
static MDB_envinfo info
Definition: mdb_load.c:37
mdb_mode_t mode
Definition: lmdb++.h:38
const struct ncbi::grid::netcache::search::fields::SIZE size
const GenericPointer< typename T::ValueType > T2 value
Definition: pointer.h:1227
int strncmp(const char *str1, const char *str2, size_t count)
Definition: odbc_utils.hpp:133
int strcmp(const char *str1, const char *str2)
Definition: odbc_utils.hpp:160
int NCBI_HasSpaces(const char *s, size_t n)
Return non-zero(true) if a block of memory based at "s" and of size "n" has any space characters (as ...
double NCBI_simple_atof(const char *s, char **t)
Locale-independent ASCII-to-double conversion of string "s".
char * strncpy0(char *s1, const char *s2, size_t n)
Copy not more than "n" characters from string "s2" into "s1", and return the result,...
#define memrchr
#define strnlen
Definition: ncbi_ansi_ext.h:53
#define strdup
Definition: ncbi_ansi_ext.h:70
#define strlwr
#define strncasecmp
#define strcasecmp
#define strupr
#define verify(expr)
Definition: ncbi_assert.h:51
@ eNcbiCred_MbedTls
Definition: ncbi_connssl.h:48
@ eNcbiCred_GnuTls
Definition: ncbi_connssl.h:47
static void x_DestroyNetInfo(SConnNetInfo *info, unsigned int magic)
static void s_SaveKeyval(char *s, const char *name, const char *str)
static const char * x_BadMagic(unsigned int magic, char buf[])
static int x_PrependArg(SConnNetInfo *info, const char *arg, const char *val)
static void s_SaveString(char *s, const char *name, const char *str)
static int x_SetArgs(SConnNetInfo *info, const char *args)
static EIO_Status s_CONN_IO(void *stream, void *buf, size_t size, size_t *n_read, EIO_Event what)
static const char * x_ReqMethod(TReqMethod req_method, char buf[])
static int x_mkenv(char *str, size_t len)
SConnNetInfo * ConnNetInfo_CloneInternal(const SConnNetInfo *info)
#define REG_VALUE(name, value, def_value)
const char * ConnNetInfo_GetValueService(const char *service, const char *param, char *value, size_t value_size, const char *def_value)
static const char s_EncodeTable[256][4]
#define CONN_NET_INFO_MAGIC
Definition: ncbi_connutil.c:46
static const char * kMIME_Encoding[eENCOD_Unknown+1]
static int x_TagValueMatches(const char *oldval, size_t oldvallen, const char *newval, size_t newvallen)
static void s_SaveStringQuot(char *s, const char *name, const char *str, int quote)
static void x_Trim(char *str)
const char * ConnNetInfo_GetValueInternal(const char *service, const char *param, char *value, size_t value_size, const char *def_value)
static TNCBI_BigCount s_FWPorts[1024/sizeof(TNCBI_BigCount)]
Definition: ncbi_connutil.c:62
static EIO_Status s_SOCK_IO(void *stream, void *buf, size_t size, size_t *n_read, EIO_Event what)
static const char * x_ClientAddress(const char *client_host, int local_host)
static const char * x_SepAndLen(const char *str, const char *sep, size_t *len)
static void x_DeleteAllArgs(SConnNetInfo *info, const char *args)
static const char * x_strncpy0(char *dst, const char *src, size_t dst_size)
EIO_Status(* FDoIO)(void *stream, void *buf, size_t size, size_t *n_read, EIO_Event what)
static const char * x_Firewall(unsigned int firewall)
static EIO_Status x_URLConnectErrorReturn(SOCK sock, EIO_Status status)
void SERV_PrintFirewallPorts(char *buf, size_t bufsize, EFWMode mode)
static int x_SetupSystemHttpProxy(SConnNetInfo *info)
static void s_SaveULong(char *s, const char *name, unsigned long lll)
static int x_SetupHttpProxy(SConnNetInfo *info, const char *env, EBProxyType proxy)
static const char * s_GetValue(const char *svc, size_t svclen, const char *param, char *value, size_t value_size, const char *def_value, int *generic, FStrNCmp strncompar)
static int s_InfoIsValid(const SConnNetInfo *info)
static const char * x_Num(unsigned int num, char buf[])
void SERV_InitFirewallPorts(void)
static void s_SaveUserHeader(char *s, const char *name, const char *uh, size_t uhlen)
int SERV_IsFirewallPort(unsigned short port)
static int x_StrcatCRLF(char **dstp, const char *src, int pre)
Definition: ncbi_connutil.c:84
static EFWMode x_ParseFirewall(const char *str, int generic)
#define VALID_URL_SYMBOL(ch)
static const char * x_GetValue(const char *svc, size_t svclen, const char *param, char *value, size_t value_size, const char *def_value, int *generic, FStrNCmp strncompar)
static const char * x_ProxyStr(EBProxyType proxy)
#define SizeOf(arr)
Definition: ncbi_connutil.c:48
static int s_HexChar(char ch)
static EURLScheme x_ParseScheme(const char *str, size_t len)
static const char * kMIME_Type[eMIME_T_Unknown+1]
#define x_getenv
Definition: ncbi_connutil.c:74
static int x_DeleteArg(SConnNetInfo *info, const char *arg)
SConnNetInfo * ConnNetInfo_CreateInternal(const char *service)
static const char * x_GetReferer(char *str, size_t size)
static const char * x_Port(unsigned short port, char buf[])
int SERV_AddFirewallPort(unsigned short port)
static const char * x_Scheme(EURLScheme scheme, char buf[])
static const char * x_CredInfo(NCBI_CRED cred, char buf[])
void ConnNetInfo_ResetHttpProxyInternal(void)
EUserHeaderOp
@ eUserHeaderOp_Override
@ eUserHeaderOp_Extend
@ eUserHeaderOp_PreOverride
@ eUserHeaderOp_Delete
int(* FStrNCmp)(const char *s1, const char *s2, size_t n)
static int x_IsSufficientAddress(const char *addr)
static EIO_Status s_StripToPattern(void *stream, FDoIO io_func, const void *pattern, size_t pattern_size, BUF *discard, size_t *n_discarded)
static int s_ModifyUserHeader(SConnNetInfo *info, const char *user_header, enum EUserHeaderOp op)
static const char kDigits[]
Definition: ncbi_connutil.c:51
static EIO_Status s_BUF_IO(void *stream, void *buf, size_t size, size_t *n_read, EIO_Event what)
static void s_SaveBool(char *s, const char *name, unsigned int bbb)
static const char * kMIME_SubType[eMIME_Unknown+1]
static int x_AppendArg(SConnNetInfo *info, const char *arg, const char *val)
#define CONN_PATH_LEN
#define CONN_PORT_HTTP
Definition: ncbi_connutil.h:95
#define CONN_PORT_HTTPS
Definition: ncbi_connutil.h:96
static size_t x_size(const char *dst, size_t len, const char *ptr)
Definition: ncbi_iprange.c:138
#define CORE_Once(once)
Return non-zero (true) if "*once" had a value of NULL, and set the value to non-NULL regardless (best...
Definition: ncbi_once.h:47
FNcbiGetReferer g_CORE_GetReferer
Definition: ncbi_priv.c:53
#define CORE_REG_GET(section, name, value, value_size, def_value)
Definition: ncbi_priv.h:297
#define NCBI_C_ERRCODE_X
Return currently set default error code.
Definition: ncbi_priv.h:126
#define CORE_LOGF_X(subcode, level, fmt_args)
Definition: ncbi_priv.h:150
#define CORE_LOCK_WRITE
Definition: ncbi_priv.h:269
#define CORE_LOGF_ERRNO_X(subcode, level, error, fmt_args)
Definition: ncbi_priv.h:166
#define CORE_TRACEF(fmt_args)
Definition: ncbi_priv.h:138
#define CORE_UNLOCK
Definition: ncbi_priv.h:273
#define CORE_LOG_X(subcode, level, message)
Definition: ncbi_priv.h:146
#define CORE_LOCK_READ
Definition: ncbi_priv.h:271
#define CORE_LOG(level, message)
Definition: ncbi_priv.h:154
char * SERV_ServiceName(const char *service)
Definition: ncbi_service.c:186
EIO_Status SOCK_CreateOnTopInternal(const void *handle, size_t handle_size, SOCK *sock, const SSOCK_Init *init, TSOCK_Flags flags)
Definition: ncbi_socket.c:6700
EIO_Status SOCK_CreateInternal(const char *host, unsigned short port, const STimeout *timeout, SOCK *sock, const SSOCK_Init *init, TSOCK_Flags flags)
Definition: ncbi_socket.c:6631
int isalpha(Uchar c)
Definition: ncbictype.hpp:61
int isspace(Uchar c)
Definition: ncbictype.hpp:69
int isdigit(Uchar c)
Definition: ncbictype.hpp:64
int toupper(Uchar c)
Definition: ncbictype.hpp:73
#define memmove(a, b, c)
static int bufsize
Definition: pcregrep.c:162
static char * newline
Definition: pcregrep.c:151
static pcre_uint8 * buffer
Definition: pcretest.c:1051
#define assert(x)
Definition: srv_diag.hpp:58
ENcbiCred type
Definition: ncbi_connssl.h:53
Timeout structure.
Definition: ncbi_types.h:76
Extra URL_ConnectEx() parameters.
Definition: type.c:6
void free(voidpf ptr)
voidp malloc(uInt size)
Modified on Sat May 25 14:19:08 2024 by modify_doxy.py rev. 669887