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