📄 ncbi_connutil.c
字号:
/* * =========================================================================== * PRODUCTION $Log: ncbi_connutil.c,v $ * PRODUCTION Revision 1000.3 2004/04/12 17:06:12 gouriano * PRODUCTION PRODUCTION: UPGRADED [CATCHUP_003] Dev-tree R6.64 * PRODUCTION * =========================================================================== *//* $Id: ncbi_connutil.c,v 1000.3 2004/04/12 17:06:12 gouriano Exp $ * =========================================================================== * * PUBLIC DOMAIN NOTICE * National Center for Biotechnology Information * * This software/database is a "United States Government Work" under the * terms of the United States Copyright Act. It was written as part of * the author's official duties as a United States Government employee and * thus cannot be copyrighted. This software/database is freely available * to the public for use. The National Library of Medicine and the U.S. * Government have not placed any restriction on its use or reproduction. * * Although all reasonable efforts have been taken to ensure the accuracy * and reliability of the software and data, the NLM and the U.S. * Government do not and cannot warrant the performance or results that * may be obtained by using this software or data. The NLM and the U.S. * Government disclaim all warranties, express or implied, including * warranties of performance, merchantability or fitness for any particular * purpose. * * Please cite the author in any work or product based on this material. * * =========================================================================== * * Author: Denis Vakatov, Anton Lavrentiev * * File Description: * Auxiliary API, mostly CONN-, URL-, and MIME-related * (see in "ncbi_connutil.h" for more details). * */#include "ncbi_ansi_ext.h"#include "ncbi_priv.h"#include <connect/ncbi_connutil.h>#include <ctype.h>#include <errno.h>#include <stdlib.h>static const char* s_GetValue(const char* service, const char* param, char* value, size_t value_size, const char* def_value){ char key[250]; char* sec; const char* val; if (!param || !value || value_size <= 0) return 0; *value = '\0'; if (service && *service) { /* Service-specific inquiry */ if (strlen(service) + 1 + sizeof(DEF_CONN_REG_SECTION) + strlen(param) + 1 > sizeof(key)) return 0; /* First, environment search for 'service_CONN_param' */ sprintf(key, "%s_" DEF_CONN_REG_SECTION "_%s", service, param); strupr(key); if ((val = getenv(key)) != 0) return strncpy0(value, val, value_size - 1); /* Next, search for 'CONN_param' in '[service]' registry section */ sprintf(key, DEF_CONN_REG_SECTION "_%s", param); sec = key + strlen(key) + 1; strupr(key); strcpy(sec, service); strupr(sec); CORE_REG_GET(sec, key, value, value_size, 0); if (*value) return value; } else { /* Common case. Form 'CONN_param' */ if (sizeof(DEF_CONN_REG_SECTION) + strlen(param) + 1 > sizeof(key)) return 0; sprintf(key, DEF_CONN_REG_SECTION "_%s", param); strupr(key); } /* Environment search for 'CONN_param' */ if ((val = getenv(key)) != 0) return strncpy0(value, val, value_size - 1); /* Last resort: Search for 'param' in default registry section */ strcpy(key, param); strupr(key); CORE_REG_GET(DEF_CONN_REG_SECTION, key, value, value_size, def_value); return value;}/*********************************************************************** * EXTERNAL ***********************************************************************/extern SConnNetInfo* ConnNetInfo_Create(const char* service){#define REG_VALUE(name, value, def_value) \ s_GetValue(service, name, value, sizeof(value), def_value) SConnNetInfo* info = (SConnNetInfo*) malloc(sizeof(*info) + (service && *service ? strlen(service) + 1 : 0)); /* aux. storage for the string-to-int conversions, etc. */ char str[32]; int val; double dbl; char* s; if (!info) return 0/*failure*/; /* client host */ if (!SOCK_gethostbyaddr(0, info->client_host, sizeof(info->client_host))) SOCK_gethostname(info->client_host, sizeof(info->client_host)); /* dispatcher host name */ REG_VALUE(REG_CONN_HOST, info->host, DEF_CONN_HOST); /* dispatcher port number */ REG_VALUE(REG_CONN_PORT, str, 0); val = atoi(str); info->port = (unsigned short)(val > 0 ? val : DEF_CONN_PORT); /* service path */ REG_VALUE(REG_CONN_PATH, info->path, DEF_CONN_PATH); /* service args */ REG_VALUE(REG_CONN_ARGS, info->args, DEF_CONN_ARGS); /* request method */ REG_VALUE(REG_CONN_REQ_METHOD, str, DEF_CONN_REQ_METHOD); if (!*str || strcasecmp(str, "ANY") == 0) info->req_method = eReqMethod_Any; else if (strcasecmp(str, "POST") == 0) info->req_method = eReqMethod_Post; else if (strcasecmp(str, "GET") == 0) info->req_method = eReqMethod_Get; /* connection timeout */ REG_VALUE(REG_CONN_TIMEOUT, str, 0); if (strlen(str) > 2 && strncasecmp(str, "infinite", strlen(str)) == 0) { info->timeout = 0; } else { info->timeout = &info->tmo; dbl = atof(str); if (dbl <= 0.0) dbl = DEF_CONN_TIMEOUT; info->timeout->sec = (unsigned int) dbl; info->timeout->usec = (unsigned int) ((dbl - info->timeout->sec) * 1000000); } /* max. # of attempts to establish connection */ REG_VALUE(REG_CONN_MAX_TRY, str, 0); val = atoi(str); info->max_try = (unsigned short)(val > 0 ? val : DEF_CONN_MAX_TRY); /* HTTP proxy server? */ REG_VALUE(REG_CONN_HTTP_PROXY_HOST, info->http_proxy_host, DEF_CONN_HTTP_PROXY_HOST); if (*info->http_proxy_host) { /* yes, use the specified HTTP proxy server */ REG_VALUE(REG_CONN_HTTP_PROXY_PORT, str, 0); val = atoi(str); info->http_proxy_port = (unsigned short) (val > 0 ? val : DEF_CONN_HTTP_PROXY_PORT); } else info->http_proxy_port = DEF_CONN_HTTP_PROXY_PORT; /* non-transparent CERN-like firewall proxy server? */ REG_VALUE(REG_CONN_PROXY_HOST, info->proxy_host, DEF_CONN_PROXY_HOST); /* turn on debug printout? */ REG_VALUE(REG_CONN_DEBUG_PRINTOUT, str, DEF_CONN_DEBUG_PRINTOUT); if (*str && (strcmp(str, "1") == 0 || strcasecmp(str, "true") == 0 || strcasecmp(str, "yes" ) == 0 || strcasecmp(str, "some") == 0)) { info->debug_printout = eDebugPrintout_Some; } else if (*str && (strcasecmp(str, "data") == 0 || strcasecmp(str, "all" ) == 0)) { info->debug_printout = eDebugPrintout_Data; } else info->debug_printout = eDebugPrintout_None; /* stateless client? */ REG_VALUE(REG_CONN_STATELESS, str, DEF_CONN_STATELESS); info->stateless = (*str && (strcmp(str, "1") == 0 || strcasecmp(str, "true") == 0 || strcasecmp(str, "yes" ) == 0)); /* firewall mode? */ REG_VALUE(REG_CONN_FIREWALL, str, DEF_CONN_FIREWALL); info->firewall = (*str && (strcmp(str, "1") == 0 || strcasecmp(str, "true") == 0 || strcasecmp(str, "yes" ) == 0)); /* prohibit the use of local load balancer? */ REG_VALUE(REG_CONN_LB_DISABLE, str, DEF_CONN_LB_DISABLE); info->lb_disable = (*str && (strcmp(str, "1") == 0 || strcasecmp(str, "true") == 0 || strcasecmp(str, "yes" ) == 0)); /* has no user header yet... */ info->http_user_header = 0; /* not adjusted yet... */ info->http_proxy_adjusted = 0/*false*/; /* store service name for which this structure has been created */ if (service && *service) { s = (char*) info + sizeof(*info); strcpy(s, service); } else s = 0; info->service = s; /* done */ return info;#undef REG_VALUE}extern int/*bool*/ ConnNetInfo_AdjustForHttpProxy(SConnNetInfo* info){ if (info->http_proxy_adjusted || !*info->http_proxy_host) return 0/*false*/; if (strlen(info->host) + strlen(info->path) + 16 > sizeof(info->path)) { CORE_LOG(eLOG_Error, "[ConnNetInfo_AdjustForHttpProxy] Adjusted path too long"); assert(0); return 0/*false*/; } {{ char x_path[sizeof(info->path)]; sprintf(x_path, "http://%s:%hu%s%s", info->host, info->port, *info->path == '/' ? "" : "/", info->path); assert(strlen(x_path) < sizeof(x_path)); strcpy(info->path, x_path); }} assert(sizeof(info->host) >= sizeof(info->http_proxy_host)); strncpy0(info->host, info->http_proxy_host, sizeof(info->host) - 1); info->port = info->http_proxy_port; info->http_proxy_adjusted = 1/*true*/; return 1/*true*/;}extern int/*bool*/ ConnNetInfo_ParseURL(SConnNetInfo* info, const char* url){ const char *s, *a; char* p; if (info->http_proxy_adjusted) { /* undo proxy adjustment */ SConnNetInfo* temp = ConnNetInfo_Create(info->service); if (!ConnNetInfo_ParseURL(temp, info->path)) { ConnNetInfo_Destroy(temp); return 0/*failure*/; } memcpy(info->host, temp->host, sizeof(info->host)); info->port = temp->port; memcpy(info->path, temp->path, sizeof(info->path)); ConnNetInfo_Destroy(temp); info->http_proxy_adjusted = 0/*false*/; } /* host & port first [both optional] */ if ((s = strstr(url, "://")) != 0) { const char* h = s + 3; /* host starts here */ if (strncasecmp(url, "http://", 7) != 0) return 0/*failure*/; if (!(s = strchr(h, '/'))) s = h + strlen(h); /* host ends at "a" */ if ((a = strchr(h, ':')) != 0 && a < s) { unsigned short port; int n; if (sscanf(a, ":%hu%n", &port, &n) < 1 || a + n != s) return 0/*failure*/; info->port = port; } else a = s; if ((size_t)(a - h) < sizeof(info->host)) { memcpy(info->host, h, (size_t)(a - h)); info->host[(size_t)(a - h)] = '\0'; } else { memcpy(info->host, h, sizeof(info->host) - 1); info->host[sizeof(info->host) - 1] = '\0'; } } else s = url; /* arguments */ if ((a = strchr(s, '?')) != 0) strncpy0(info->args, a + 1, sizeof(info->args) - 1); else a = s + strlen(s); /* path (NB: can be relative) */ if (s != url || *s == '/' || !(p = strrchr(info->path, '/'))) { /* absolute path */ p = info->path; if (!*s) { s = "/"; /* in case of an empty path we take the root '/' */ a = s + 1; } } else p++; if ((size_t)(a - s) < sizeof(info->path) - (size_t)(p - info->path)) { memcpy(p, s, (size_t)(a - s)); p[(size_t)(a - s)] = '\0'; } else { memcpy(p, s, sizeof(info->path) - (size_t)(p - info->path) - 1); info->path[sizeof(info->path) - 1] = '\0'; } return 1/*success*/;}extern int/*bool*/ ConnNetInfo_SetUserHeader(SConnNetInfo* info, const char* user_header){ if (info->http_user_header) free((void*) info->http_user_header); if (user_header && *user_header) { info->http_user_header = strdup(user_header); return info->http_user_header ? 1/*success*/ : 0/*failure*/; } else info->http_user_header = 0; return 1/*success*/;}extern int/*bool*/ ConnNetInfo_AppendUserHeader(SConnNetInfo* info, const char* user_header){ size_t oldlen, newlen; char* new_header; if (!info->http_user_header || !(oldlen = strlen(info->http_user_header))) return ConnNetInfo_SetUserHeader(info, user_header); if (!user_header || !(newlen = strlen(user_header))) return 1/*success*/; new_header = (char*) realloc((void*) info->http_user_header, oldlen + newlen + 1); if (!new_header) return 0/*failure*/; memcpy(&new_header[oldlen], user_header, newlen + 1); info->http_user_header = new_header; return 1/*success*/;}typedef enum { eUserHeaderOp_Delete, eUserHeaderOp_Extend, eUserHeaderOp_Override} EUserHeaderOp;static int/*bool*/ s_ModifyUserHeader(SConnNetInfo* info, const char* user_header, EUserHeaderOp op){ int/*bool*/ retval; char* new_header; size_t newlinelen; size_t newhdrlen; char* newline; size_t hdrlen; char* hdr; if (!user_header || !(newhdrlen = strlen(user_header))) return 1/*success*/; if (!(hdr = (char*) info->http_user_header) || !(hdrlen = strlen(hdr))) { if (op == eUserHeaderOp_Delete) return 1/*success*/; if (!hdr && !(hdr = strdup(""))) return 0/*failure*/; hdrlen = 0; } if (op != eUserHeaderOp_Delete) { if (!(new_header = (char*) malloc(newhdrlen + 1))) return 0/*failure*/; memcpy(new_header, user_header, newhdrlen + 1); } else new_header = (char*) user_header; /* we actually won't modify it! */ retval = 1/*assume best: success*/; for (newline = new_header; *newline; newline += newlinelen) { char* eol = strchr(newline, '\n'); char* eot = strchr(newline, ':'); int/*bool*/ used = 0; size_t newtaglen; char* newtagval; size_t linelen; char* line; size_t len; size_t l; newlinelen = (size_t) (eol ? eol - newline + 1 : new_header + newhdrlen - newline);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -