00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034 #include "ncbi_ansi_ext.h"
00035 #include "ncbi_priv.h"
00036 #include <connect/ncbi_connutil.h>
00037 #include <ctype.h>
00038 #include <errno.h>
00039 #include <stdlib.h>
00040
00041 #define NCBI_USE_ERRCODE_X Connect_Util
00042
00043
00044 extern const char* ConnNetInfo_GetValue(const char* service, const char* param,
00045 char* value, size_t value_size,
00046 const char* def_value)
00047 {
00048 char buf[128];
00049 const char* val;
00050 char* s;
00051
00052 if (!value || value_size <= 0)
00053 return 0;
00054 *value = '\0';
00055
00056 if (!param || !*param)
00057 return 0;
00058
00059 if (service && *service) {
00060
00061 size_t slen = strlen(service);
00062 size_t plen = strlen(param) + 1;
00063 if (slen + 1 + sizeof(DEF_CONN_REG_SECTION) + plen > sizeof(buf))
00064 return 0;
00065
00066
00067 s = (char*) memcpy(buf, service, slen) + slen;
00068 *s++ = '_';
00069 memcpy(s, DEF_CONN_REG_SECTION, sizeof(DEF_CONN_REG_SECTION) - 1);
00070 s += sizeof(DEF_CONN_REG_SECTION) - 1;
00071 *s++ = '_';
00072 memcpy(s, param, plen);
00073 if ((val = getenv(buf)) != 0 || (val = getenv(strupr(buf))) != 0)
00074 return strncpy0(value, val, value_size - 1);
00075
00076
00077 buf[slen++] = '\0';
00078 s = buf + slen;
00079 CORE_REG_GET(buf, s, value, value_size, 0);
00080 if (*value)
00081 return value;
00082 } else {
00083
00084 size_t plen = strlen(param) + 1;
00085 if (sizeof(DEF_CONN_REG_SECTION) + plen > sizeof(buf))
00086 return 0;
00087 s = buf;
00088 memcpy(s, DEF_CONN_REG_SECTION, sizeof(DEF_CONN_REG_SECTION) - 1);
00089 s += sizeof(DEF_CONN_REG_SECTION) - 1;
00090 *s++ = '_';
00091 memcpy(s, param, plen);
00092 s = strupr(buf);
00093 }
00094
00095
00096 if ((val = getenv(s)) != 0)
00097 return strncpy0(value, val, value_size - 1);
00098
00099
00100 s += sizeof(DEF_CONN_REG_SECTION);
00101 CORE_REG_GET(DEF_CONN_REG_SECTION, s, value, value_size, def_value);
00102 return value;
00103 }
00104
00105
00106 static EURLScheme s_ParseScheme(const char* str, size_t len)
00107 {
00108 if (len == 5 && strncasecmp(str, "https", len) == 0)
00109 return eURL_Https;
00110 if (len == 4 && strncasecmp(str, "http", len) == 0)
00111 return eURL_Http;
00112 if (len == 4 && strncasecmp(str, "file", len) == 0)
00113 return eURL_File;
00114 if (len == 3 && strncasecmp(str, "ftp", len) == 0)
00115 return eURL_Ftp;
00116 return eURL_Unspec;
00117 }
00118
00119
00120 static const char* s_Scheme(EURLScheme scheme)
00121 {
00122 switch (scheme) {
00123 case eURL_Unspec:
00124 break;
00125 case eURL_Https:
00126 return "https";
00127 case eURL_Http:
00128 return "http";
00129 case eURL_File:
00130 return "file";
00131 case eURL_Ftp:
00132 return "ftp";
00133 }
00134 return 0;
00135 }
00136
00137
00138
00139
00140
00141
00142
00143 extern SConnNetInfo* ConnNetInfo_Create(const char* service)
00144 {
00145 #define REG_VALUE(name, value, def_value) \
00146 ConnNetInfo_GetValue(service, name, value, sizeof(value), def_value)
00147
00148 SConnNetInfo* info = (SConnNetInfo*) malloc(sizeof(*info) +
00149 (service && *service
00150 ? strlen(service) + 1 : 0));
00151 size_t len;
00152
00153 char str[1024];
00154 int val;
00155 double dbl;
00156 char* e;
00157
00158 if (!info)
00159 return 0;
00160
00161
00162 info->client_host[0] = '\0';
00163
00164
00165 REG_VALUE(REG_CONN_SCHEME, str, DEF_CONN_SCHEME);
00166 info->scheme = s_ParseScheme(str, strlen(str));
00167
00168
00169 REG_VALUE(REG_CONN_USER, info->user, DEF_CONN_USER);
00170
00171
00172 REG_VALUE(REG_CONN_PASS, info->pass, DEF_CONN_PASS);
00173
00174
00175 REG_VALUE(REG_CONN_HOST, info->host, DEF_CONN_HOST);
00176
00177
00178 REG_VALUE(REG_CONN_PORT, str, DEF_CONN_PORT);
00179 errno = 0;
00180 if (*str && (val = strtoul(str, &e, 10)) > 0 && !errno
00181 && !*e && val < (1 << 16)) {
00182 info->port = val;
00183 } else
00184 info->port = 0;
00185
00186
00187 REG_VALUE(REG_CONN_PATH, info->path, DEF_CONN_PATH);
00188
00189
00190 REG_VALUE(REG_CONN_ARGS, info->args, DEF_CONN_ARGS);
00191
00192
00193 REG_VALUE(REG_CONN_REQ_METHOD, str, DEF_CONN_REQ_METHOD);
00194 if (!*str || strcasecmp(str, "ANY") == 0)
00195 info->req_method = eReqMethod_Any;
00196 else if (strcasecmp(str, "POST") == 0)
00197 info->req_method = eReqMethod_Post;
00198 else if (strcasecmp(str, "GET") == 0)
00199 info->req_method = eReqMethod_Get;
00200
00201
00202 REG_VALUE(REG_CONN_TIMEOUT, str, 0);
00203 len = strlen(str);
00204 if (len > 2 && len < 9 && strncasecmp(str, "infinite", len) == 0) {
00205 info->timeout = 0;
00206 } else {
00207 info->timeout = &info->tmo;
00208 if (!*str || (dbl = atof(str)) < 0.0)
00209 dbl = DEF_CONN_TIMEOUT;
00210 info->timeout->sec = (unsigned int) dbl;
00211 info->timeout->usec = (unsigned int)
00212 ((dbl - info->timeout->sec) * 1000000.0);
00213 }
00214
00215
00216 REG_VALUE(REG_CONN_MAX_TRY, str, 0);
00217 val = atoi(str);
00218 info->max_try = (unsigned short)(val > 0 ? val : DEF_CONN_MAX_TRY);
00219
00220
00221 REG_VALUE(REG_CONN_HTTP_PROXY_HOST, info->http_proxy_host,
00222 DEF_CONN_HTTP_PROXY_HOST);
00223 if (*info->http_proxy_host) {
00224
00225 REG_VALUE(REG_CONN_HTTP_PROXY_PORT, str, DEF_CONN_HTTP_PROXY_PORT);
00226 errno = 0;
00227 if (*str && (val = strtoul(str, &e, 10)) > 0
00228 && !errno && !*e && val < (1 << 16)) {
00229 info->http_proxy_port = val;
00230 } else
00231 info->http_proxy_port = 0;
00232 } else
00233 info->http_proxy_port = 0;
00234
00235
00236 REG_VALUE(REG_CONN_PROXY_HOST, info->proxy_host, DEF_CONN_PROXY_HOST);
00237
00238
00239 REG_VALUE(REG_CONN_DEBUG_PRINTOUT, str, DEF_CONN_DEBUG_PRINTOUT);
00240 if (*str && (strcmp (str, "1") == 0 ||
00241 strcasecmp(str, "on") == 0 ||
00242 strcasecmp(str, "yes") == 0 ||
00243 strcasecmp(str, "true") == 0 ||
00244 strcasecmp(str, "some") == 0)) {
00245 info->debug_printout = eDebugPrintout_Some;
00246 } else if (*str && (strcasecmp(str, "all") == 0 ||
00247 strcasecmp(str, "data") == 0)) {
00248 info->debug_printout = eDebugPrintout_Data;
00249 } else
00250 info->debug_printout = eDebugPrintout_None;
00251
00252
00253 REG_VALUE(REG_CONN_STATELESS, str, DEF_CONN_STATELESS);
00254 info->stateless = (*str && (strcmp (str, "1") == 0 ||
00255 strcasecmp(str, "on") == 0 ||
00256 strcasecmp(str, "yes") == 0 ||
00257 strcasecmp(str, "true") == 0));
00258
00259
00260 REG_VALUE(REG_CONN_FIREWALL, str, DEF_CONN_FIREWALL);
00261 info->firewall = (*str && (strcmp (str, "1") == 0 ||
00262 strcasecmp(str, "on") == 0 ||
00263 strcasecmp(str, "yes") == 0 ||
00264 strcasecmp(str, "true") == 0));
00265
00266
00267 REG_VALUE(REG_CONN_LB_DISABLE, str, DEF_CONN_LB_DISABLE);
00268 info->lb_disable = (*str && (strcmp (str, "1") == 0 ||
00269 strcasecmp(str, "on" ) == 0 ||
00270 strcasecmp(str, "yes" ) == 0 ||
00271 strcasecmp(str, "true") == 0));
00272
00273
00274 REG_VALUE(REG_CONN_HTTP_USER_HEADER, str, DEF_CONN_HTTP_USER_HEADER);
00275 if (*str) {
00276 size_t len = strlen(str);
00277 if (str[len - 1] != '\n' && len < sizeof(str) - 2) {
00278 str[len++] = '\r';
00279 str[len++] = '\n';
00280 str[len] = '\0';
00281 }
00282 info->http_user_header = strdup(str);
00283 } else
00284 info->http_user_header = 0;
00285
00286
00287 ConnNetInfo_GetValue(0, REG_CONN_HTTP_REFERER, str, sizeof(str),
00288 DEF_CONN_HTTP_REFERER);
00289 info->http_referer = *str ? strdup(str) : 0;
00290
00291
00292 info->http_proxy_adjusted = 0;
00293
00294 info->service = (service && *service
00295 ? strcpy((char*) info + sizeof(*info), service)
00296 : 0);
00297
00298
00299 return info;
00300 #undef REG_VALUE
00301 }
00302
00303
00304 extern int ConnNetInfo_AdjustForHttpProxy(SConnNetInfo* info)
00305 {
00306 char port[10];
00307 size_t hostlen;
00308 size_t portlen;
00309 size_t pathlen;
00310 size_t len;
00311
00312 if (!info)
00313 return 0;
00314
00315 if (!*info->http_proxy_host || info->http_proxy_adjusted)
00316 return 1;
00317
00318 if (info->scheme != eURL_Unspec && info->scheme != eURL_Http) {
00319 CORE_LOGF_X(13, eLOG_Error,
00320 ("[ConnNetInfo_AdjustForHttpProxy] "
00321 " Cannot adjust for scheme \"%s\"",
00322 s_Scheme(info->scheme)));
00323 assert(0);
00324 return 0;
00325 }
00326
00327 hostlen = strlen(info->host);
00328 portlen = info->port ? (size_t) sprintf(port, ":%hu", info->port) : 0;
00329 if (*info->path != '/')
00330 port[portlen++] = '/';
00331 pathlen = strlen(info->path);
00332
00333 len = 7 + hostlen + portlen + pathlen + 1;
00334
00335 if (len >= sizeof(info->path)) {
00336 CORE_LOGF_X(14, eLOG_Error,
00337 ("[ConnNetInfo_AdjustForHttpProxy] "
00338 " Adjusted path too long (%lu)",
00339 (unsigned long) len));
00340 assert(0);
00341 return 0;
00342 }
00343 len -= pathlen + 1;
00344 memmove(info->path + len, info->path, pathlen + 1);
00345 len -= portlen;
00346 memcpy (info->path + len, port, portlen);
00347 assert(len - hostlen == 7);
00348 memcpy (info->path + 7, info->host, hostlen);
00349 memcpy (info->path, "http://", 7);
00350
00351 assert(sizeof(info->host) >= sizeof(info->http_proxy_host));
00352 strncpy0(info->host, info->http_proxy_host, sizeof(info->host) - 1);
00353 info->port = info->http_proxy_port;
00354 info->http_proxy_adjusted = 1;
00355 info->scheme = eURL_Http;
00356 return 1;
00357 }
00358
00359
00360 extern int ConnNetInfo_ParseURL(SConnNetInfo* info, const char* url)
00361 {
00362 const char *s, *a;
00363 size_t len;
00364 char* p;
00365
00366 if (info->http_proxy_adjusted) {
00367
00368 SConnNetInfo* temp = ConnNetInfo_Create(info->service);
00369 if (!ConnNetInfo_ParseURL(temp, info->path)) {
00370 ConnNetInfo_Destroy(temp);
00371 return 0;
00372 }
00373 memcpy(info->host, temp->host, sizeof(info->host));
00374 info->port = temp->port;
00375 memcpy(info->path, temp->path, sizeof(info->path));
00376 ConnNetInfo_Destroy(temp);
00377 info->http_proxy_adjusted = 0;
00378 }
00379
00380
00381 if ((s = strstr(url, "://")) != 0) {
00382 const char* h = s + 3;
00383
00384 len = (size_t)(s - url);
00385 if ((info->scheme = s_ParseScheme(url, len)) == eURL_Unspec)
00386 return 0;
00387
00388
00389 len = strcspn(h, "/?#");
00390 s = h + len;
00391
00392
00393 if (!(a = (const char*) memchr(h, '@', len))) {
00394 info->user[0] = '\0';
00395 info->pass[0] = '\0';
00396 } else {
00397 size_t ulen = (size_t)(a - h);
00398 const char* t = (const char*) memchr(h, ':', ulen);
00399 if (t)
00400 ulen = (size_t)(t - h);
00401 if (ulen < sizeof(info->user)) {
00402 memcpy(info->user, h, ulen);
00403 info->user[ulen] = '\0';
00404 } else {
00405 memcpy(info->user, h, sizeof(info->user) - 1);
00406 info->user[sizeof(info->user) - 1] = '\0';
00407 }
00408 if (t && ulen) {
00409
00410 len = (size_t)(a - ++t);
00411 if (len < sizeof(info->pass)) {
00412 memcpy(info->pass, t, len);
00413 info->pass[len] = '\0';
00414 } else {
00415 memcpy(info->pass, t, sizeof(info->pass) - 1);
00416 info->pass[sizeof(info->pass) - 1] = '\0';
00417 }
00418 } else
00419 info->pass[0] = '\0';
00420 h = ++a;
00421 len = (size_t)(s - h);
00422 }
00423
00424
00425 if (!(a = (const char*) memchr(h, ':', len))) {
00426 info->port = 0;
00427
00428 } else if (isdigit(a[1])) {
00429 unsigned short port;
00430 int n;
00431 if (sscanf(a, ":%hu%n", &port, &n) < 1 || a + n != s || !port)
00432 return 0;
00433 info->port = port;
00434 len = (size_t)(a - h);
00435 } else
00436 return 0;
00437 if (len < sizeof(info->host)) {
00438 memcpy(info->host, h, len);
00439 info->host[len] = '\0';
00440 } else {
00441 memcpy(info->host, h, sizeof(info->host) - 1);
00442 info->host[sizeof(info->host) - 1] = '\0';
00443 }
00444 } else
00445 s = url;
00446
00447 a = s + strcspn(s, "?#");
00448 len = (size_t)(a - s);
00449
00450
00451 if (s != url || *s == '/' || !(p = strrchr(info->path, '/'))) {
00452
00453 p = info->path;
00454 if (!len) {
00455 s = "/";
00456 len = 1;
00457 }
00458 } else
00459 p++;
00460 if (len < sizeof(info->path) - (size_t)(p - info->path)) {
00461 memcpy(p, s, len);
00462 p[len] = '\0';
00463 } else {
00464 memcpy(p, s, sizeof(info->path) - (size_t)(p - info->path) - 1);
00465 info->path[sizeof(info->path) - 1] = '\0';
00466 }
00467
00468
00469 if (*a) {
00470 if (*a == '#') {
00471 len = 0;
00472 s = a;
00473 } else if (!(s = strchr(++a, '#'))) {
00474 len = strlen(a);
00475 s = a + len;
00476 } else
00477 len = (size_t)(s - a);
00478
00479 assert(!*s || *s == '#');
00480 assert(*a != '?');
00481
00482 if (*s) {
00483
00484 if (!s[1]) {
00485
00486 len = (size_t)(s - a);
00487 if (len > sizeof(info->args) - 1)
00488 len = sizeof(info->args) - 1;
00489 } else
00490 len = sizeof(info->args) - 1;
00491 strncpy0(info->args, a, len);
00492 } else if (!(p = strchr(info->args, '#'))
00493 || len >= sizeof(info->args) - 1) {
00494
00495
00496 strncpy0(info->args, a, sizeof(info->args) - 1);
00497 } else {
00498
00499 size_t move = strlen(p);
00500 if (move > sizeof(info->args) - 1 - len)
00501 move = sizeof(info->args) - 1 - len;
00502 memmove(info->args + len, p, move);
00503 memcpy (info->args, a, len);
00504 info->args[len + move] = '\0';
00505 }
00506 } else if ((p = strchr(info->args, '#')) != 0) {
00507
00508 memmove(info->args, p, strlen(p) + 1);
00509 }
00510
00511 return 1;
00512 }
00513
00514
00515 extern int ConnNetInfo_SetUserHeader(SConnNetInfo* info,
00516 const char* user_header)
00517 {
00518 if (info->http_user_header)
00519 free((void*) info->http_user_header);
00520 if (user_header && *user_header) {
00521 info->http_user_header = strdup(user_header);
00522 return info->http_user_header ? 1 : 0;
00523 } else
00524 info->http_user_header = 0;
00525 return 1;
00526 }
00527
00528
00529 extern int ConnNetInfo_AppendUserHeader(SConnNetInfo* info,
00530 const char* user_header)
00531 {
00532 size_t oldlen, newlen;
00533 char* new_header;
00534
00535 if (!info->http_user_header || !(oldlen = strlen(info->http_user_header)))
00536 return ConnNetInfo_SetUserHeader(info, user_header);
00537
00538 if (!user_header || !(newlen = strlen(user_header)))
00539 return 1;
00540
00541 new_header = (char*)
00542 realloc((void*) info->http_user_header, oldlen + newlen + 1);
00543 if (!new_header)
00544 return 0;
00545
00546 memcpy(&new_header[oldlen], user_header, newlen + 1);
00547 info->http_user_header = new_header;
00548 return 1;
00549 }
00550
00551
00552 typedef enum {
00553 eUserHeaderOp_Delete,
00554 eUserHeaderOp_Extend,
00555 eUserHeaderOp_Override
00556 } EUserHeaderOp;
00557
00558
00559 static int s_ModifyUserHeader(SConnNetInfo* info,
00560 const char* user_header,
00561 EUserHeaderOp op)
00562 {
00563 int retval;
00564 char* new_header;
00565 size_t newlinelen;
00566 size_t newhdrlen;
00567 char* newline;
00568 size_t hdrlen;
00569 char* hdr;
00570
00571 if (!user_header || !(newhdrlen = strlen(user_header)))
00572 return 1;
00573
00574 if (!(hdr = (char*) info->http_user_header) || !(hdrlen = strlen(hdr))) {
00575 if (op == eUserHeaderOp_Delete)
00576 return 1;
00577 if (!hdr && !(hdr = strdup("")))
00578 return 0;
00579 hdrlen = 0;
00580 }
00581
00582 if (op != eUserHeaderOp_Delete) {
00583 if (!(new_header = (char*) malloc(newhdrlen + 1)))
00584 return 0;
00585 memcpy(new_header, user_header, newhdrlen + 1);
00586 } else
00587 new_header = (char*) user_header;
00588
00589 retval = 1;
00590 for (newline = new_header; *newline; newline += newlinelen) {
00591 char* eol = strchr(newline, '\n');
00592 char* eot = strchr(newline, ':');
00593 int used = 0;
00594 size_t newtaglen;
00595 char* newtagval;
00596 size_t linelen;
00597 char* line;
00598 size_t len;
00599 size_t l;
00600
00601 newlinelen = (size_t)
00602 (eol ? eol - newline + 1 : new_header + newhdrlen - newline);
00603 if (!eot || eot >= newline + newlinelen ||
00604 !(newtaglen = (size_t)(eot - newline)))
00605 continue;
00606
00607 newtagval = newline + newtaglen + 1;
00608 while (newtagval < newline + newlinelen) {
00609 if (isspace((unsigned char)(*newtagval)))
00610 newtagval++;
00611 else
00612 break;
00613 }
00614 switch (op) {
00615 case eUserHeaderOp_Delete:
00616 len = 0;
00617 break;
00618 case eUserHeaderOp_Extend:
00619 len = newlinelen - (size_t)(newtagval - newline);
00620 break;
00621 case eUserHeaderOp_Override:
00622 len = newtagval < newline + newlinelen ? newlinelen : 0;
00623 break;
00624 default:
00625 assert(0);
00626 retval = 0;
00627 len = 0;
00628 break;
00629 }
00630
00631 for (line = hdr; *line; line += linelen) {
00632 size_t taglen;
00633
00634 eol = strchr(line, '\n');
00635 eot = strchr(line, ':');
00636
00637 linelen = (size_t)(eol ? eol - line + 1 : hdr + hdrlen - line);
00638 if (!eot || eot >= line + linelen)
00639 continue;
00640
00641 taglen = (size_t)(eot - line);
00642 if (newtaglen != taglen || strncasecmp(newline, line, taglen) != 0)
00643 continue;
00644
00645 if (op == eUserHeaderOp_Extend) {
00646 if (linelen - taglen >= len
00647 && strncasecmp(line + linelen - len, newtagval, len) == 0
00648 && (linelen - taglen == len ||
00649 isspace((unsigned char) line[linelen - len - 1]))) {
00650 len = 0;
00651 }
00652 l = linelen + len;
00653 if (len && linelen > 1 && line[linelen - 2] == '\r')
00654 --l;
00655 } else
00656 l = len;
00657 if (l != linelen) {
00658 size_t off = (size_t)(line - hdr);
00659 if (l > linelen) {
00660 char* temp = (char*)realloc(hdr, hdrlen + l - linelen + 1);
00661 if (!temp) {
00662 retval = 0;
00663 continue;
00664 }
00665 hdr = temp;
00666 line = temp + off;
00667 }
00668 hdrlen -= linelen;
00669 memmove(line + l, line + linelen, hdrlen - off + 1);
00670 hdrlen += l;
00671 }
00672
00673 if (len) {
00674 if (op == eUserHeaderOp_Extend) {
00675 char* s = &line[l - len - 1];
00676 *s++ = ' ';
00677 memcpy(s, newtagval, len);
00678 } else
00679 memcpy(line, newline, len);
00680 linelen = l;
00681 used = 1;
00682 } else if (op == eUserHeaderOp_Extend)
00683 used = 1;
00684 }
00685
00686 if (op == eUserHeaderOp_Delete)
00687 continue;
00688
00689 if (used || !len) {
00690 memmove(newline, newline + newlinelen,
00691 newhdrlen - (size_t)(newline-new_header) - newlinelen + 1);
00692 newhdrlen -= newlinelen;
00693 newlinelen = 0;
00694 }
00695 }
00696
00697 info->http_user_header = hdr;
00698 if (op != eUserHeaderOp_Delete) {
00699 if (!ConnNetInfo_AppendUserHeader(info, new_header))
00700 retval = 0;
00701 free(new_header);
00702 }
00703 return retval;
00704 }
00705
00706
00707 extern int ConnNetInfo_OverrideUserHeader(SConnNetInfo* info,
00708 const char* header)
00709 {
00710 return s_ModifyUserHeader(info, header, eUserHeaderOp_Override);
00711 }
00712
00713
00714 extern void ConnNetInfo_DeleteUserHeader(SConnNetInfo* info,
00715 const char* header)
00716 {
00717 verify(s_ModifyUserHeader(info, header, eUserHeaderOp_Delete));
00718 }
00719
00720
00721 extern int ConnNetInfo_ExtendUserHeader(SConnNetInfo* info,
00722 const char* header)
00723 {
00724 return s_ModifyUserHeader(info, header, eUserHeaderOp_Extend);
00725 }
00726
00727
00728 extern int ConnNetInfo_AppendArg(SConnNetInfo* info,
00729 const char* arg,
00730 const char* val)
00731 {
00732 size_t len, used;
00733
00734 if (!arg || !*arg)
00735 return 1;
00736
00737 used = strlen(info->args);
00738 len = strlen(arg);
00739
00740 if (used + (used ? 1 : 0) + len +
00741 (val && *val ? 1 + strlen(val) : 0) >= sizeof(info->args)) {
00742 return 0;
00743 }
00744
00745 if (used)
00746 info->args[used++] = '&';
00747 strcpy(info->args + used, arg);
00748 if (val && *val) {
00749 used += len;
00750 info->args[used++] = '=';
00751 strcpy(info->args + used, val);
00752 }
00753 return 1;
00754 }
00755
00756
00757 extern int ConnNetInfo_PrependArg(SConnNetInfo* info,
00758 const char* arg,
00759 const char* val)
00760 {
00761 size_t len, off, used;
00762
00763 if (!arg || !*arg)
00764 return 1;
00765
00766 used = strlen(info->args);
00767 len = strlen(arg);
00768 off = len + (val && *val ? 1 + strlen(val) : 0) + (used? 1 : 0);
00769
00770 if (off + used >= sizeof(info->args))
00771 return 0;
00772
00773 if (used)
00774 memmove(info->args + off, info->args, used + 1);
00775 strcpy(info->args, arg);
00776 if (val && *val) {
00777 info->args[len++] = '=';
00778 strcpy(info->args + len, val);
00779 }
00780 if (used)
00781 info->args[off - 1] = '&';
00782 return 1;
00783 }
00784
00785
00786 extern void ConnNetInfo_DeleteArg(SConnNetInfo* info,
00787 const char* arg)
00788 {
00789 size_t argnamelen;
00790 size_t arglen;
00791 char* a;
00792
00793 if (!arg || !(argnamelen = strcspn(arg, "=&")))
00794 return;
00795 for (a = info->args; *a; a += arglen) {
00796 if (*a == '&')
00797 a++;
00798 arglen = strcspn(a, "&");
00799 if (arglen < argnamelen || strncasecmp(a, arg, argnamelen) != 0 ||
00800 (a[argnamelen] && a[argnamelen] != '=' && a[argnamelen] != '&'))
00801 continue;
00802 if (a[arglen]) {
00803 arglen++;
00804 memmove(a, a + arglen, strlen(a + arglen) + 1);
00805 } else if (a != info->args) {
00806 *--a = '\0';
00807 } else {
00808 *a = '\0';
00809 }
00810 arglen = 0;
00811 }
00812 }
00813
00814
00815 extern void ConnNetInfo_DeleteAllArgs(SConnNetInfo* info,
00816 const char* args)
00817 {
00818 char* temp;
00819 char* arg;
00820 if (!args || !*args || !(temp = strdup(args))) {
00821 if (args && *args)
00822 *info->args = '\0';
00823 return;
00824 }
00825 arg = temp;
00826 while (*arg) {
00827 char* end = strchr(arg, '&');
00828 if (!end)
00829 end = arg + strlen(arg);
00830 else
00831 *end++ = '\0';
00832 ConnNetInfo_DeleteArg(info, arg);
00833 arg = end;
00834 }
00835 free(temp);
00836 }
00837
00838
00839 extern int ConnNetInfo_PreOverrideArg(SConnNetInfo* info,
00840 const char* arg,
00841 const char* val)
00842 {
00843 if (!arg || !*arg)
00844 return 1;
00845 ConnNetInfo_DeleteAllArgs(info, arg);
00846 return ConnNetInfo_PrependArg(info, arg, val);
00847 }
00848
00849
00850 extern int ConnNetInfo_PostOverrideArg(SConnNetInfo* info,
00851 const char* arg,
00852 const char* val)
00853 {
00854 if (!arg || !*arg)
00855 return 1;
00856 ConnNetInfo_DeleteAllArgs(info, arg);
00857 return ConnNetInfo_AppendArg(info, arg, val);
00858 }
00859
00860
00861 static int s_IsSufficientAddress(const char* addr)
00862 {
00863 const char*c;
00864 return (SOCK_isip(addr) ||
00865 ((c = strchr(addr, '.')) != 0 && c[1] &&
00866 (c = strchr(c + 2, '.')) != 0 && c[1]));
00867 }
00868
00869
00870 static const char* s_ClientAddress(const char* client_host,
00871 int local_host)
00872 {
00873 const char* c = client_host;
00874 unsigned int ip;
00875 char addr[80];
00876 char* s;
00877
00878 assert(client_host);
00879 strncpy0(addr, client_host, sizeof(addr) - 1);
00880 if (UTIL_NcbiLocalHostName(addr) && (s = strdup(addr)) != 0)
00881 client_host = s;
00882 if (s_IsSufficientAddress(client_host) ||
00883 !(ip = *client_host && !local_host
00884 ? SOCK_gethostbyname(client_host)
00885 : SOCK_GetLocalHostAddress(eDefault)) ||
00886 SOCK_ntoa(ip, addr, sizeof(addr)) != 0 ||
00887 !(s = (char*) malloc(strlen(client_host) + strlen(addr) + 3))) {
00888 return client_host;
00889 }
00890 sprintf(s, "%s(%s)", client_host, addr);
00891 if (c != client_host)
00892 free((void*) client_host);
00893 return s;
00894 }
00895
00896
00897 extern int ConnNetInfo_SetupStandardArgs(SConnNetInfo* info,
00898 const char* service)
00899 {
00900 static const char kService[] = "service";
00901 static const char kAddress[] = "address";
00902 static const char kPlatform[] = "platform";
00903 int local_host;
00904 const char* arch;
00905 const char* addr;
00906
00907 if (!info)
00908 return 0;
00909 if (!service || !*service) {
00910 assert(0);
00911 return 0;
00912 }
00913
00914 if (!(arch = CORE_GetPlatform()) || !*arch)
00915 ConnNetInfo_DeleteArg(info, kPlatform);
00916 else
00917 ConnNetInfo_PreOverrideArg(info, kPlatform, arch);
00918 local_host = !info->client_host[0];
00919 if (local_host &&
00920 !SOCK_gethostbyaddr(0, info->client_host, sizeof(info->client_host))) {
00921 SOCK_gethostname(info->client_host, sizeof(info->client_host));
00922 }
00923 if (!(addr = s_ClientAddress(info->client_host, local_host)) || !*addr)
00924 ConnNetInfo_DeleteArg(info, kAddress);
00925 else
00926 ConnNetInfo_PreOverrideArg(info, kAddress, addr);
00927 if (addr != info->client_host)
00928 free((void*) addr);
00929 if (!ConnNetInfo_PreOverrideArg(info, kService, service)) {
00930 ConnNetInfo_DeleteArg(info, kPlatform);
00931 if (!ConnNetInfo_PreOverrideArg(info, kService, service)) {
00932 ConnNetInfo_DeleteArg(info, kAddress);
00933 if (!ConnNetInfo_PreOverrideArg(info, kService, service))
00934 return 0;
00935 }
00936 }
00937 return 1;
00938 }
00939
00940
00941 extern SConnNetInfo* ConnNetInfo_Clone(const SConnNetInfo* info)
00942 {
00943 SConnNetInfo* x_info;
00944 if (!info)
00945 return 0;
00946
00947 x_info = (SConnNetInfo*) malloc(sizeof(SConnNetInfo) +
00948 (info->service
00949 ? strlen(info->service) + 1 : 0));
00950 *x_info = *info;
00951 if (info->timeout && info->timeout != kDefaultTimeout) {
00952 x_info->tmo = *info->timeout;
00953 x_info->timeout = &x_info->tmo;
00954 }
00955 if (info->service) {
00956 char* s = (char*) x_info + sizeof(*x_info);
00957 strcpy(s, info->service);
00958 x_info->service = s;
00959 }
00960 x_info->http_user_header = 0;
00961 ConnNetInfo_SetUserHeader(x_info, info->http_user_header);
00962 x_info->http_referer = info->http_referer ? strdup(info->http_referer) : 0;
00963 return x_info;
00964 }
00965
00966
00967 static const char* s_SchemeStr(EURLScheme scheme, char buf[])
00968 {
00969 switch (scheme) {
00970 case eURL_Ftp:
00971 return "ftp";
00972 case eURL_File:
00973 return "file";
00974 case eURL_Http:
00975 return "http";
00976 case eURL_Https:
00977 return "https";
00978 case eURL_Unspec:
00979 break;
00980 default:
00981 sprintf(buf, "?#0x%08X", (int) scheme);
00982 return buf;
00983 }
00984 return 0;
00985 }
00986
00987 static const char* s_PortStr(unsigned short port, char buf[])
00988 {
00989 if (port) {
00990 sprintf(buf, "%hu", port);
00991 return buf;
00992 }
00993 return "<default>";
00994 }
00995
00996 static void s_SaveStringQuot(char* s, const char* name,
00997 const char* str, int quote)
00998 {
00999 sprintf(s + strlen(s), "%-16.16s: %s%s%s\n", name,
01000 str && quote ? "\"" : "",
01001 str ? str : "NULL",
01002 str && quote ? "\"" : "");
01003 }
01004
01005 static void s_SaveString(char* s, const char* name, const char* str)
01006 {
01007 s_SaveStringQuot(s, name, str, 1);
01008 }
01009
01010 static void s_SaveKeyval(char* s, const char* name, const char* str)
01011 {
01012 s_SaveStringQuot(s, name, str, 0);
01013 }
01014
01015 static void s_SaveULong(char* s, const char* name, unsigned long lll)
01016 {
01017 sprintf(s + strlen(s), "%-16.16s: %lu\n", name, lll);
01018 }
01019
01020 static void s_SaveBool(char* s, const char* name, int bbb)
01021 {
01022 sprintf(s + strlen(s), "%-16.16s: %s\n", name, bbb ? "TRUE" : "FALSE");
01023 }
01024
01025 static void s_SaveUserHeader(char* s, const char* name,
01026 const char* uh, size_t uhlen)
01027 {
01028 s += strlen(s);
01029 s += sprintf(s, "%-16.16s: ", name);
01030 if (uh) {
01031 *s++ = '"';
01032 memcpy(UTIL_PrintableString(uh, uhlen, s, 0), "\"\n", 3);
01033 } else
01034 memcpy(s, "NULL\n", 6);
01035 }
01036
01037 extern void ConnNetInfo_Log(const SConnNetInfo* info, LOG lg)
01038 {
01039 char scheme[32];
01040 char port[16];
01041 size_t uhlen;
01042 char* s;
01043
01044 if (!lg)
01045 return;
01046
01047 if (!info) {
01048 LOG_Write(lg, NCBI_C_ERRCODE_X, 10, eLOG_Trace, 0, 0, 0,
01049 "ConnNetInfo_Log: NULL info", 0, 0);
01050 return;
01051 }
01052
01053 uhlen = info->http_user_header ? strlen(info->http_user_header) : 0;
01054
01055 if (!(s = (char*) malloc(sizeof(*info) + 1024 +
01056 (info->service ? strlen(info->service) : 0) +
01057 UTIL_PrintableStringSize(info->http_user_header,
01058 uhlen) +
01059 (info->http_referer
01060 ? strlen(info->http_referer) : 0)))) {
01061 LOG_WRITE(lg, NCBI_C_ERRCODE_X, 11, eLOG_Error,
01062 "ConnNetInfo_Log: Cannot allocate temporary buffer");
01063 return;
01064 }
01065
01066 strcpy(s, "ConnNetInfo_Log\n"
01067 "#################### [BEGIN] SConnNetInfo:\n");
01068 s_SaveString (s, "service", info->service);
01069 if (*info->client_host)
01070 s_SaveString(s, "client_host", info->client_host);
01071 else
01072 s_SaveKeyval(s, "client_host", "<default>");
01073 s_SaveString (s, "scheme", s_SchemeStr(info->scheme, scheme));
01074 s_SaveString (s, "user", info->user);
01075 s_SaveString (s, "pass", info->pass);
01076 s_SaveString (s, "host", info->host);
01077 s_SaveKeyval (s, "port", s_PortStr(info->port, port));
01078 s_SaveString (s, "path", info->path);
01079 s_SaveString (s, "args", info->args);
01080 s_SaveKeyval (s, "req_method", (info->req_method == eReqMethod_Any
01081 ? "ANY"
01082 : (info->req_method
01083 == eReqMethod_Get
01084 ? "GET"
01085 : (info->req_method
01086 == eReqMethod_Post
01087 ? "POST" : "<unknown>"))));
01088 if (info->timeout) {
01089 s_SaveULong (s, "timeout(sec)", info->timeout->sec);
01090 s_SaveULong (s, "timeout(usec)", info->timeout->usec);
01091 } else
01092 s_SaveKeyval(s, "timeout", "INFINITE");
01093 s_SaveULong (s, "max_try", info->max_try);
01094 s_SaveString (s, "http_proxy_host", info->http_proxy_host);
01095 s_SaveKeyval (s, "http_proxy_port", s_PortStr(info->http_proxy_port,
01096 port));
01097 s_SaveString (s, "proxy_host", info->proxy_host);
01098 s_SaveKeyval (s, "debug_printout", (info->debug_printout
01099 == eDebugPrintout_None
01100 ? "NONE"
01101 : (info->debug_printout
01102 == eDebugPrintout_Some
01103 ? "SOME"
01104 : (info->debug_printout
01105 == eDebugPrintout_Data
01106 ? "DATA" : "<unknown>"))));
01107 s_SaveBool (s, "stateless", info->stateless);
01108 s_SaveBool (s, "firewall", info->firewall);
01109 s_SaveBool (s, "lb_disable", info->lb_disable);
01110 s_SaveUserHeader(s, "http_user_header",info->http_user_header, uhlen);
01111 s_SaveString (s, "http_referer", info->http_referer);
01112 s_SaveBool (s, "proxy_adjusted", info->http_proxy_adjusted);
01113 strcat(s, "#################### [END] SConnNetInfo\n");
01114
01115 LOG_Write(lg, NCBI_C_ERRCODE_X, 12, eLOG_Trace, 0, 0, 0, s, 0, 0);
01116 free(s);
01117 }
01118
01119
01120 extern char* ConnNetInfo_URL(const SConnNetInfo* info)
01121 {
01122 const char* scheme;
01123 size_t len;
01124 char* url;
01125
01126 if (!info || info->scheme == eURL_Unspec
01127 || !(scheme = s_Scheme(info->scheme))) {
01128 return 0;
01129 }
01130
01131 len = strlen(scheme) + 3 + strlen(info->host) +
01132 (info->port ? 6 : 0) +
01133 (info->http_proxy_adjusted ? 2 : 0) +
01134 strlen(info->path) + 1 +
01135 (*info->args ? strlen(info->args) + 2 : 1);
01136 url = (char*) malloc(len);
01137
01138 if (url) {
01139 len = (size_t) sprintf(url, "%s://%s", scheme, info->host);
01140 if (info->port)
01141 len += sprintf(url + len, ":%hu", info->port);
01142 sprintf(url + len, "%s%s%s%s%s", info->http_proxy_adjusted
01143 ? "<" : *info->path != '/' ? "/" : "", info->path,
01144 &"?"[!*info->args || *info->args == '#'], info->args,
01145 ">" + !info->http_proxy_adjusted);
01146 }
01147 return url;
01148 }
01149
01150
01151 extern void ConnNetInfo_Destroy(SConnNetInfo* info)
01152 {
01153 if (!info)
01154 return;
01155 ConnNetInfo_SetUserHeader(info, 0);
01156 if (info->http_referer) {
01157 free((void*) info->http_referer);
01158 info->http_referer = 0;
01159 }
01160 free(info);
01161 }
01162
01163
01164
01165
01166
01167
01168
01169
01170 extern EIO_Status URL_ConnectEx
01171 (const char* host,
01172 unsigned short port,
01173 const char* path,
01174 const char* args,
01175 EReqMethod req_method,
01176 size_t content_length,
01177 const STimeout* c_timeout,
01178 const STimeout* rw_timeout,
01179 const char* user_hdr,
01180 int encode_args,
01181 TSOCK_Flags flags,
01182 SOCK* sock)
01183 {
01184 static const char X_REQ_Q[] = "?";
01185 static const char X_REQ_E[] = " HTTP/1.0\r\n";
01186 static const char X_HOST[] = "Host: ";
01187
01188 EIO_Status st;
01189 BUF buf;
01190 char* header;
01191 size_t hdrsize;
01192 char strbuf[80];
01193 const char* x_args = 0;
01194 size_t x_args_len = args && *args ? strcspn(args, "#") : 0;
01195 size_t user_hdr_len = user_hdr && *user_hdr ? strlen(user_hdr) : 0;
01196 const char* x_req_method;
01197
01198
01199 if (!sock || !host || !*host ||
01200 (user_hdr && *user_hdr && user_hdr[user_hdr_len - 1] != '\n')) {
01201 CORE_LOG_X(2, eLOG_Error, "[URL_Connect] Bad arguments");
01202 assert(0);
01203 return eIO_InvalidArg;
01204 }
01205
01206
01207 if (req_method == eReqMethod_Any) {
01208 req_method = content_length ? eReqMethod_Post : eReqMethod_Get;
01209 } else if (req_method == eReqMethod_Get && content_length) {
01210 CORE_LOG_X(3, eLOG_Warning,
01211 "[URL_Connect] Content length ignored with method GET");
01212 content_length = 0;
01213 }
01214 switch (req_method) {
01215 case eReqMethod_Post:
01216 x_req_method = "POST ";
01217 break;
01218 case eReqMethod_Get:
01219 x_req_method = "GET ";
01220 break;
01221 default:
01222 CORE_LOGF_X(4, eLOG_Error,
01223 ("[URL_Connect] Unrecognized request method (#%u)",
01224 (unsigned int) req_method));
01225 assert(0);
01226 return eIO_InvalidArg;
01227 }
01228
01229
01230 if (x_args_len) {
01231 if ( encode_args ) {
01232 size_t rd_len, wr_len;
01233 size_t size = 3 * x_args_len;
01234 char* xx_args = (char*) malloc(size);
01235 if (!xx_args) {
01236 CORE_LOGF_ERRNO_X(8, eLOG_Error, errno,
01237 ("[URL_Connect] Out of memory (%lu)",
01238 (unsigned long) size));
01239 return eIO_Unknown;
01240 }
01241 URL_Encode(args, x_args_len, &rd_len, xx_args, size, &wr_len);
01242 assert(x_args_len == rd_len);
01243 x_args_len = wr_len;
01244 x_args = xx_args;
01245 } else
01246 x_args = args;
01247 }
01248
01249 buf = 0;
01250 errno = 0;
01251 if (!port) {
01252 *strbuf = '\0';
01253 port = flags & fSOCK_Secure ? 443 : 80;
01254 } else
01255 sprintf(strbuf, ":%hu", port);
01256
01257
01258 if (
01259 !BUF_Write(&buf, x_req_method, strlen(x_req_method)) ||
01260 !BUF_Write(&buf, path, strlen(path)) ||
01261 (x_args_len
01262 && (!BUF_Write(&buf, X_REQ_Q, sizeof(X_REQ_Q) - 1) ||
01263 !BUF_Write(&buf, x_args, x_args_len))) ||
01264 !BUF_Write(&buf, X_REQ_E, sizeof(X_REQ_E) - 1) ||
01265
01266
01267 !BUF_Write(&buf, X_HOST, sizeof(X_HOST) - 1) ||
01268 !BUF_Write(&buf, host, strlen(host)) ||
01269 !BUF_Write(&buf, strbuf, strlen(strbuf)) ||
01270 !BUF_Write(&buf, "\r\n", 2) ||
01271
01272
01273 (user_hdr_len
01274 && !BUF_Write(&buf, user_hdr, user_hdr_len)) ||
01275
01276
01277 (req_method != eReqMethod_Get
01278 && (sprintf(strbuf, "Content-Length: %lu\r\n",
01279 (unsigned long) content_length) <= 0 ||
01280 !BUF_Write(&buf, strbuf, strlen(strbuf)))) ||
01281
01282 !BUF_Write(&buf, "\r\n", 2)) {
01283 int x_errno = errno;
01284 CORE_LOGF_ERRNO_X(5, eLOG_Error, x_errno,
01285 ("[URL_Connect] Error building HTTP header for"
01286 " %s:%hu", host, port));
01287 BUF_Destroy(buf);
01288 if (x_args && x_args != args)
01289 free((void*) x_args);
01290 return eIO_Unknown;
01291 }
01292 if (x_args && x_args != args)
01293 free((void*) x_args);
01294
01295 if (!(header = (char*) malloc(hdrsize = BUF_Size(buf)))
01296 || BUF_Read(buf, header, hdrsize) != hdrsize) {
01297 int x_errno = errno;
01298 CORE_LOGF_ERRNO_X(6, eLOG_Error, x_errno,
01299 ("[URL_Connect] Error storing HTTP header for"
01300 " %s:%hu", host, port));
01301 if (header)
01302 free(header);
01303 BUF_Destroy(buf);
01304 return eIO_Unknown;
01305 }
01306 BUF_Destroy(buf);
01307
01308
01309 st = SOCK_CreateEx(host, port, c_timeout, sock, header, hdrsize, flags);
01310 free(header);
01311 if (st != eIO_Success) {
01312 char temp[80];
01313 assert(!*sock);
01314 if (st == eIO_Timeout && c_timeout) {
01315 sprintf(temp, "[%u.%06u]",
01316 (unsigned int)(c_timeout->sec + c_timeout->usec/1000000),
01317 (unsigned int) (c_timeout->usec%1000000));
01318 } else
01319 *temp = '\0';
01320 CORE_LOGF_X(7, eLOG_Error,
01321 ("[URL_Connect] Socket connect to %s:%hu failed: %s%s",
01322 host, port, IO_StatusStr(st), temp));
01323 } else
01324 verify(SOCK_SetTimeout(*sock, eIO_ReadWrite, rw_timeout)==eIO_Success);
01325 return st;
01326 }
01327
01328
01329 extern SOCK URL_Connect
01330 (const char* host,
01331 unsigned short port,
01332 const char* path,
01333 const char* args,
01334 EReqMethod req_method,
01335 size_t content_length,
01336 const STimeout* c_timeout,
01337 const STimeout* rw_timeout,
01338 const char* user_hdr,
01339 int encode_args,
01340 TSOCK_Flags flags)
01341 {
01342 SOCK sock;
01343 EIO_Status st = URL_ConnectEx(host, port, path, args,
01344 req_method, content_length,
01345 c_timeout, rw_timeout,
01346 user_hdr, encode_args, flags, &sock);
01347 return st == eIO_Success ? sock : 0;
01348 }
01349
01350
01351
01352
01353
01354
01355
01356
01357 typedef EIO_Status (*FDoIO)
01358 (void* stream,
01359 void* buf,
01360 size_t size,
01361 size_t* n_read,
01362 EIO_Event what
01363 );
01364
01365 static EIO_Status s_StripToPattern
01366 (void* stream,
01367 FDoIO io_func,
01368 const void* pattern,
01369 size_t pattern_size,
01370 BUF* buf,
01371 size_t* n_discarded)
01372 {
01373 EIO_Status status;
01374 char* buffer;
01375 size_t buffer_size;
01376 size_t n_read = 0;
01377
01378
01379 if ( n_discarded )
01380 *n_discarded = 0;
01381 if (!stream || (pattern != 0) != (pattern_size != 0))
01382 return eIO_InvalidArg;
01383
01384
01385 buffer_size = 2 * pattern_size;
01386 if (buffer_size < 4096)
01387 buffer_size = 4096;
01388 if ( !(buffer = (char*) malloc(buffer_size)) )
01389 return eIO_Unknown;
01390
01391 if ( !pattern ) {
01392
01393 do {
01394 status = io_func(stream, buffer, buffer_size, &n_read, eIO_Read);
01395 if ( buf )
01396 BUF_Write(buf, buffer, n_read);
01397 if ( n_discarded )
01398 *n_discarded += n_read;
01399 } while (status == eIO_Success);
01400 } else {
01401 for (;;) {
01402
01403 size_t x_read, n_stored;
01404
01405 assert(n_read < pattern_size);
01406 status = io_func(stream, buffer + n_read, buffer_size - n_read,
01407 &x_read, eIO_Read);
01408 if ( !x_read ) {
01409 assert(status != eIO_Success);
01410 break;
01411 }
01412 n_stored = n_read + x_read;
01413
01414 if (n_stored >= pattern_size) {
01415
01416 size_t n_check = n_stored - pattern_size + 1;
01417 const char* b;
01418 for (b = buffer; n_check; b++, n_check--) {
01419 if (*b != *((const char*) pattern))
01420 continue;
01421 if (memcmp(b, pattern, pattern_size) == 0)
01422 break;
01423 }
01424
01425 if ( n_check ) {
01426 size_t x_discarded = (size_t)(b - buffer) + pattern_size;
01427 if ( buf )
01428 BUF_Write(buf, buffer + n_read, x_discarded - n_read);
01429 if ( n_discarded )
01430 *n_discarded += x_discarded;
01431
01432 status = io_func(stream, buffer + x_discarded,
01433 n_stored - x_discarded, 0, eIO_Write);
01434 break;
01435 }
01436 }
01437
01438
01439 if ( buf )
01440 BUF_Write(buf, buffer + n_read, x_read);
01441 if ( n_discarded )
01442 *n_discarded += x_read;
01443 n_read = n_stored;
01444
01445 if (n_read > pattern_size) {
01446 size_t n_cut = n_read - pattern_size + 1;
01447 n_read = pattern_size - 1;
01448 memmove(buffer, buffer + n_cut, n_read);
01449 }
01450 }
01451 }
01452
01453
01454 free(buffer);
01455 return status;
01456 }
01457
01458
01459 static EIO_Status s_CONN_IO
01460 (void* stream,
01461 void* buf,
01462 size_t size,
01463 size_t* n_read,
01464 EIO_Event what)
01465 {
01466 switch (what) {
01467 case eIO_Read:
01468 return CONN_Read((CONN) stream, buf, size, n_read, eIO_ReadPlain);
01469 case eIO_Write:
01470 assert(stream);
01471 return CONN_PushBack((CONN) stream, buf, size);
01472 default:
01473 break;
01474 }
01475 return eIO_InvalidArg;
01476 }
01477
01478 extern EIO_Status CONN_StripToPattern
01479 (CONN conn,
01480 const void* pattern,
01481 size_t pattern_size,
01482 BUF* buf,
01483 size_t* n_discarded)
01484 {
01485 return s_StripToPattern
01486 (conn, s_CONN_IO, pattern, pattern_size, buf, n_discarded);
01487 }
01488
01489
01490 static EIO_Status s_SOCK_IO
01491 (void* stream,
01492 void* buf,
01493 size_t size,
01494 size_t* n_read,
01495 EIO_Event what)
01496 {
01497 switch (what) {
01498 case eIO_Read:
01499 return SOCK_Read((SOCK) stream, buf, size, n_read, eIO_ReadPlain);
01500 case eIO_Write:
01501 return SOCK_PushBack((SOCK) stream, buf, size);
01502 default:
01503 break;
01504 }
01505 return eIO_InvalidArg;
01506 }
01507
01508 extern EIO_Status SOCK_StripToPattern
01509 (SOCK sock,
01510 const void* pattern,
01511 size_t pattern_size,
01512 BUF* buf,
01513 size_t* n_discarded)
01514 {
01515 return s_StripToPattern
01516 (sock, s_SOCK_IO, pattern, pattern_size, buf, n_discarded);
01517 }
01518
01519
01520 static EIO_Status s_BUF_IO
01521 (void* stream,
01522 void* buf,
01523 size_t size,
01524 size_t* n_read,
01525 EIO_Event what)
01526 {
01527 BUF b;
01528 switch (what) {
01529 case eIO_Read:
01530 *n_read = BUF_Read((BUF) stream, buf, size);
01531 return *n_read ? eIO_Success : eIO_Closed;
01532 case eIO_Write:
01533 assert(stream);
01534 b = (BUF) stream;
01535 return BUF_PushBack(&b, buf, size) ? eIO_Success : eIO_Unknown;
01536 default:
01537 break;
01538 }
01539 return eIO_InvalidArg;
01540 }
01541
01542 extern EIO_Status BUF_StripToPattern
01543 (BUF buffer,
01544 const void* pattern,
01545 size_t pattern_size,
01546 BUF* buf,
01547 size_t* n_discarded)
01548 {
01549 return s_StripToPattern
01550 (buffer, s_BUF_IO, pattern, pattern_size, buf, n_discarded);
01551 }
01552
01553
01554
01555
01556
01557
01558
01559
01560
01561
01562
01563
01564 static int s_HexChar(char ch)
01565 {
01566 unsigned int rc = ch - '0';
01567 if (rc <= 9)
01568 return rc;
01569 rc = (ch | ' ') - 'a';
01570 return rc <= 5 ? (int) rc + 10 : -1;
01571 }
01572
01573
01574
01575
01576 static const char s_EncodeTable[256][4] = {
01577 "%00", "%01", "%02", "%03", "%04", "%05", "%06", "%07",
01578 "%08", "%09", "%0A", "%0B", "%0C", "%0D", "%0E", "%0F",
01579 "%10", "%11", "%12", "%13", "%14", "%15", "%16", "%17",
01580 "%18", "%19", "%1A", "%1B", "%1C", "%1D", "%1E", "%1F",
01581 "+", "!", "%22", "%23", "$", "%25", "%26", "'",
01582 "(", ")", "*", "%2B", ",", "-", ".", "%2F",
01583 "0", "1", "2", "3", "4", "5", "6", "7",
01584 "8", "9", "%3A", "%3B", "%3C", "%3D", "%3E", "%3F",
01585 "%40", "A", "B", "C", "D", "E", "F", "G",
01586 "H", "I", "J", "K", "L", "M", "N", "O",
01587 "P", "Q", "R", "S", "T", "U", "V", "W",
01588 "X", "Y", "Z", "%5B", "%5C", "%5D", "%5E", "_",
01589 "%60", "a", "b", "c", "d", "e", "f", "g",
01590 "h", "i", "j", "k", "l", "m", "n", "o",
01591 "p", "q", "r", "s", "t", "u", "v", "w",
01592 "x", "y", "z", "%7B", "%7C", "%7D", "%7E", "%7F",
01593 "%80", "%81", "%82", "%83", "%84", "%85", "%86", "%87",
01594 "%88", "%89", "%8A", "%8B", "%8C", "%8D", "%8E", "%8F",
01595 "%90", "%91", "%92", "%93", "%94", "%95", "%96", "%97",
01596 "%98", "%99", "%9A", "%9B", "%9C", "%9D", "%9E", "%9F",
01597 "%A0", "%A1", "%A2", "%A3", "%A4", "%A5", "%A6", "%A7",
01598 "%A8", "%A9", "%AA", "%AB", "%AC", "%AD", "%AE", "%AF",
01599 "%B0", "%B1", "%B2", "%B3", "%B4", "%B5", "%B6", "%B7",
01600 "%B8", "%B9", "%BA", "%BB", "%BC", "%BD", "%BE", "%BF",
01601 "%C0", "%C1", "%C2", "%C3", "%C4", "%C5", "%C6", "%C7",
01602 "%C8", "%C9", "%CA", "%CB", "%CC", "%CD", "%CE", "%CF",
01603 "%D0", "%D1", "%D2", "%D3", "%D4", "%D5", "%D6", "%D7",
01604 "%D8", "%D9", "%DA", "%DB", "%DC", "%DD", "%DE", "%DF",
01605 "%E0", "%E1", "%E2", "%E3", "%E4", "%E5", "%E6", "%E7",
01606 "%E8", "%E9", "%EA", "%EB", "%EC", "%ED", "%EE", "%EF",
01607 "%F0", "%F1", "%F2", "%F3", "%F4", "%F5", "%F6", "%F7",
01608 "%F8", "%F9", "%FA", "%FB", "%FC", "%FD", "%FE", "%FF"
01609 };
01610
01611 #define VALID_URL_SYMBOL(ch) (s_EncodeTable[(unsigned char)ch][0] != '%')
01612
01613
01614 extern int URL_DecodeEx
01615 (const void* src_buf,
01616 size_t src_size,
01617 size_t* src_read,
01618 void* dst_buf,
01619 size_t dst_size,
01620 size_t* dst_written,
01621 const char* allow_symbols)
01622 {
01623 unsigned char* src = (unsigned char*) src_buf;
01624 unsigned char* dst = (unsigned char*) dst_buf;
01625
01626 *src_read = 0;
01627 *dst_written = 0;
01628 if (!src_size || !dst_size)
01629 return 1;
01630
01631 for ( ; *src_read != src_size && *dst_written != dst_size;
01632 (*src_read)++, (*dst_written)++, src++, dst++) {
01633 switch ( *src ) {
01634 case '%': {
01635 int i1, i2;
01636 if (*src_read + 2 > src_size)
01637 return 1;
01638 if ((i1 = s_HexChar(*(++src))) == -1)
01639 return *dst_written ? 1 : 0;
01640 if (*src_read + 3 > src_size)
01641 return 1;
01642 if ((i2 = s_HexChar(*(++src))) == -1)
01643 return *dst_written ? 1 : 0;
01644
01645 *dst = (unsigned char)((i1 << 4) + i2);
01646 *src_read += 2;
01647 break;
01648 }
01649 case '+': {
01650 *dst = ' ';
01651 break;
01652 }
01653 default: {
01654 if (VALID_URL_SYMBOL(*src) ||
01655 (allow_symbols && strchr(allow_symbols, *src)))
01656 *dst = *src;
01657 else
01658 return *dst_written ? 1 : 0;
01659 }
01660 }
01661 }
01662
01663 assert(src == (unsigned char*) src_buf + *src_read );
01664 assert(dst == (unsigned char*) dst_buf + *dst_written);
01665 return 1;
01666 }
01667
01668
01669 extern int URL_Decode
01670 (const void* src_buf,
01671 size_t src_size,
01672 size_t* src_read,
01673 void* dst_buf,
01674 size_t dst_size,
01675 size_t* dst_written)
01676 {
01677 return URL_DecodeEx
01678 (src_buf, src_size, src_read, dst_buf, dst_size, dst_written, 0);
01679 }
01680
01681
01682 extern void URL_Encode
01683 (const void* src_buf,
01684 size_t src_size,
01685 size_t* src_read,
01686 void* dst_buf,
01687 size_t dst_size,
01688 size_t* dst_written)
01689 {
01690 unsigned char* src = (unsigned char*) src_buf;
01691 unsigned char* dst = (unsigned char*) dst_buf;
01692
01693 *src_read = 0;
01694 *dst_written = 0;
01695 if (!src_size || !dst_size)
01696 return;
01697
01698 for ( ; *src_read != src_size && *dst_written != dst_size;
01699 (*src_read)++, (*dst_written)++, src++, dst++) {
01700 const char* subst = s_EncodeTable[*src];
01701 if (*subst != '%') {
01702 *dst = *subst;
01703 } else if (*dst_written < dst_size - 2) {
01704 *dst = '%';
01705 *(++dst) = *(++subst);
01706 *(++dst) = *(++subst);
01707 *dst_written += 2;
01708 } else {
01709 return;
01710 }
01711 }
01712 assert(src == (unsigned char*) src_buf + *src_read );
01713 assert(dst == (unsigned char*) dst_buf + *dst_written);
01714 }
01715
01716
01717
01718
01719
01720
01721
01722 static const char* s_MIME_Type[eMIME_T_Unknown+1] = {
01723 "x-ncbi-data",
01724 "text",
01725 "application",
01726 "unknown"
01727 };
01728
01729 static const char* s_MIME_SubType[eMIME_Unknown+1] = {
01730 "x-dispatch",
01731 "x-asn-text",
01732 "x-asn-binary",
01733 "x-fasta",
01734 "x-www-form",
01735 "html",
01736 "plain",
01737 "xml",
01738 "xml+soap",
01739 "octet-stream",
01740 "x-unknown"
01741 };
01742
01743 static const char* s_MIME_Encoding[eENCOD_Unknown+1] = {
01744 "",
01745 "urlencoded",
01746 "encoded"
01747 };
01748
01749
01750 extern char* MIME_ComposeContentTypeEx
01751 (EMIME_Type type,
01752 EMIME_SubType subtype,
01753 EMIME_Encoding encoding,
01754 char* buf,
01755 size_t buflen)
01756 {
01757 static const char s_ContentType[] = "Content-Type: ";
01758 const char* x_type;
01759 const char* x_subtype;
01760 const char* x_encoding;
01761 char x_buf[MAX_CONTENT_TYPE_LEN];
01762
01763 assert(buf && buflen);
01764
01765 if (type == eMIME_T_Undefined || subtype == eMIME_Undefined)
01766 return 0;
01767 if (type >= eMIME_T_Unknown)
01768 type = eMIME_T_Unknown;
01769 if (subtype >= eMIME_Unknown)
01770 subtype = eMIME_Unknown;
01771 if (encoding >= eENCOD_Unknown)
01772 encoding = eENCOD_Unknown;
01773
01774 x_type = s_MIME_Type [type];
01775 x_subtype = s_MIME_SubType [subtype];
01776 x_encoding = s_MIME_Encoding[encoding];
01777
01778 if ( *x_encoding ) {
01779 assert(sizeof(s_ContentType) + strlen(x_type) + strlen(x_subtype)
01780 + strlen(x_encoding) + 4 < MAX_CONTENT_TYPE_LEN);
01781 sprintf(x_buf, "%s%s/%s-%s\r\n",
01782 s_ContentType, x_type, x_subtype, x_encoding);
01783 } else {
01784 assert(sizeof(s_ContentType) + strlen(x_type) + strlen(x_subtype)
01785 + 3 < MAX_CONTENT_TYPE_LEN);
01786 sprintf(x_buf, "%s%s/%s\r\n", s_ContentType, x_type, x_subtype);
01787 }
01788 assert(strlen(x_buf) < sizeof(x_buf));
01789 assert(strlen(x_buf) < buflen);
01790 strncpy0(buf, x_buf, buflen - 1);
01791 return buf;
01792 }
01793
01794
01795 extern int MIME_ParseContentTypeEx
01796 (const char* str,
01797 EMIME_Type* type,
01798 EMIME_SubType* subtype,
01799 EMIME_Encoding* encoding)
01800 {
01801 char* x_buf;
01802 size_t x_size;
01803 char* x_type;
01804 char* x_subtype;
01805 int i;
01806
01807 if ( type )
01808 *type = eMIME_T_Undefined;
01809 if ( subtype )
01810 *subtype = eMIME_Undefined;
01811 if ( encoding )
01812 *encoding = eENCOD_None;
01813
01814 x_size = str && *str ? strlen(str) + 1 : 0;
01815 if (!x_size)
01816 return 0;
01817
01818 if (!(x_buf = (char*) malloc(x_size << 1)))
01819 return 0;
01820 x_type = x_buf + x_size;
01821
01822 strlwr(strcpy(x_buf, str));
01823
01824 if ((sscanf(x_buf, " content-type: %s ", x_type) != 1 &&
01825 sscanf(x_buf, " %s ", x_type) != 1) ||
01826 (x_subtype = strchr(x_type, '/')) == 0) {
01827 free(x_buf);
01828 return 0;
01829 }
01830 *x_subtype++ = '\0';
01831 x_size = strlen(x_subtype);
01832
01833 if ( type ) {
01834 for (i = 0; i < (int) eMIME_T_Unknown; i++) {
01835 if (strcmp(x_type, s_MIME_Type[i]) == 0)
01836 break;
01837 }
01838 *type = (EMIME_Type) i;
01839 }
01840
01841 for (i = 1; i <= (int) eENCOD_Unknown; i++) {
01842 size_t len = strlen(s_MIME_Encoding[i]);
01843 if (len < x_size) {
01844 char* x_encoding = x_subtype + x_size - len;
01845 if (x_encoding[-1] == '-'
01846 && strcmp(x_encoding, s_MIME_Encoding[i]) == 0) {
01847 if ( encoding ) {
01848 *encoding = (i == (int) eENCOD_Unknown
01849 ? eENCOD_None : (EMIME_Encoding) i);
01850 }
01851 x_encoding[-1] = '\0';
01852 break;
01853 }
01854 }
01855 }
01856
01857 if ( subtype ) {
01858 for (i = 0; i < (int) eMIME_Unknown; i++) {
01859 if (strcmp(x_subtype, s_MIME_SubType[i]) == 0)
01860 break;
01861 }
01862 *subtype = (EMIME_SubType) i;
01863 }
01864
01865 free(x_buf);
01866 return 1;
01867 }
01868
01869
01870
01871 extern char* MIME_ComposeContentType
01872 (EMIME_SubType subtype,
01873 EMIME_Encoding encoding,
01874 char* buf,
01875 size_t buflen)
01876 {
01877 return MIME_ComposeContentTypeEx(eMIME_T_NcbiData,
01878 subtype, encoding, buf, buflen);
01879 }
01880
01881
01882
01883 extern int MIME_ParseContentType
01884 (const char* str,
01885 EMIME_SubType* subtype,
01886 EMIME_Encoding* encoding)
01887 {
01888 EMIME_Type type;
01889 if ( !MIME_ParseContentTypeEx(str, &type, subtype, encoding) )
01890 return 0;
01891
01892 if (type != eMIME_T_NcbiData) {
01893 if ( subtype )
01894 *subtype = eMIME_Unknown;
01895 if ( encoding )
01896 *encoding = eENCOD_Unknown;
01897 return 0;
01898 }
01899
01900 return 1;
01901 }
01902
01903