80
80
#endif /* __cplusplus */
83
static char* s_GetArgs(const char* client_host)
85
static const char platform[] = "&platform=";
86
static const char address[] = "address=";
87
size_t nodelen, archlen, buflen;
95
nodelen = strlen(client_host);
96
buflen += sizeof(address) - 1 + nodelen;
97
if (!strchr(client_host, '.') &&
98
(ip = SOCK_gethostbyname(client_host)) != 0 &&
99
SOCK_ntoa(ip, addr, sizeof(addr)) == 0) {
100
buflen += strlen(addr) + 2;
105
if ((arch = CORE_GetPlatform()) != 0 && *arch) {
106
archlen = strlen(arch);
107
buflen += sizeof(platform) - 1 + archlen;
110
if (!buflen || !(p = (char*) malloc(buflen + 1)))
114
strcpy(&p[buflen], address);
115
buflen += sizeof(address) - 1;
116
strcpy(&p[buflen], client_host);
119
buflen += sprintf(&p[buflen], "(%s)", addr);
122
strcpy(&p[buflen], nodelen ? platform : platform + 1);
123
buflen += nodelen ? sizeof(platform) - 1 : sizeof(platform) - 2;
124
strcpy(&p[buflen], arch);
131
83
static int/*bool*/ s_OpenDispatcher(SServiceConnector* uuu)
133
uuu->user_header = 0;
134
85
if (!(uuu->iter = SERV_OpenEx(uuu->service, uuu->types,
135
SERV_LOCALHOST, uuu->net_info, 0, 0)))
86
SERV_LOCALHOST, uuu->net_info, 0, 0))) {
136
87
return 0/*false*/;
141
93
static void s_CloseDispatcher(SServiceConnector* uuu)
143
if (uuu->user_header) {
144
free((void*) uuu->user_header);
145
uuu->user_header = 0;
147
95
SERV_Close(uuu->iter);
155
103
static void s_Reset(SMetaConnector *meta)
157
CONN_SET_METHOD(meta, descr, 0, 0);
158
CONN_SET_METHOD(meta, wait, 0, 0);
159
CONN_SET_METHOD(meta, write, 0, 0);
160
CONN_SET_METHOD(meta, flush, 0, 0);
161
CONN_SET_METHOD(meta, read, 0, 0);
162
CONN_SET_METHOD(meta, status, s_VT_Status, 0);
105
CONN_SET_METHOD(meta, descr, 0, 0);
106
CONN_SET_METHOD(meta, wait, 0, 0);
107
CONN_SET_METHOD(meta, write, 0, 0);
108
CONN_SET_METHOD(meta, flush, 0, 0);
109
CONN_SET_METHOD(meta, read, 0, 0);
110
CONN_SET_METHOD(meta, status, s_VT_Status, 0);
163
111
#ifdef IMPLEMENTED__CONN_WaitAsync
164
CONN_SET_METHOD(meta, wait_async, 0, 0);
112
CONN_SET_METHOD(meta, wait_async, 0, 0);
197
147
/* Special keyword for switching into stateless mode */
198
148
uuu->host = (unsigned int)(-1);
199
149
#if defined(_DEBUG) && !defined(NDEBUG)
200
if (uuu->net_info->debug_printout)
201
CORE_LOG(eLOG_Warning,
150
if (uuu->net_info->debug_printout) {
202
152
"[SERVICE] Fallback to stateless requested");
156
if (sscanf(header, "%u.%u.%u.%u %hu %x",
157
&i1, &i2, &i3, &i4, &uuu->port, &ticket) < 6) {
158
break/*failed - unreadable connection info*/;
160
o1 = i1; o2 = i2; o3 = i3; o4 = i4;
161
sprintf(ipaddr, "%u.%u.%u.%u", o1, o2, o3, o4);
162
if (!(uuu->host = SOCK_gethostbyname(ipaddr)) || !uuu->port)
163
break/*failed - bad host:port in connection info*/;
164
uuu->ticket = SOCK_HostToNetLong(ticket);
206
if (sscanf(header, "%u.%u.%u.%u %hu %x",
207
&i1, &i2, &i3, &i4, &uuu->port, &ticket) < 6)
209
o1 = i1; o2 = i2; o3 = i3; o4 = i4;
210
sprintf(ipaddr, "%u.%u.%u.%u", o1, o2, o3, o4);
211
uuu->host = SOCK_gethostbyname(ipaddr);
212
uuu->ticket = SOCK_htonl(ticket);
215
167
if ((header = strchr(header, '\n')) != 0)
170
if (!header || !*header)
178
static int/*bool*/ s_ContentTypeDefined(const SConnNetInfo* net_info,
180
EMIME_SubType mime_s,
181
EMIME_Encoding mime_e)
186
for (s = net_info->http_user_header; s; s = strchr(s, '\n')) {
187
if (s != net_info->http_user_header)
191
if (strncasecmp(s, "content-type: ", 14) == 0) {
192
#if defined(_DEBUG) && !defined(NDEBUG)
196
char c_t[MAX_CONTENT_TYPE_LEN];
197
if (net_info->debug_printout &&
198
mime_t != SERV_MIME_TYPE_UNDEFINED &&
199
mime_t != eMIME_T_Unknown &&
200
MIME_ParseContentTypeEx(s, &m_t, &m_s, &m_e) &&
202
|| (mime_s != SERV_MIME_SUBTYPE_UNDEFINED &&
203
mime_s != eMIME_Unknown &&
204
m_s != eMIME_Unknown && mime_s != m_s)
205
|| (mime_e != eENCOD_None &&
206
m_e != eENCOD_None && mime_e != m_e))) {
210
for (s += 15; *s; s++) {
211
if (!isspace((unsigned char)(*s)))
214
if (!(c = strchr(s, '\n')))
216
if (c > s && c[-1] == '\r')
218
len = (size_t)(c - s);
219
if ((t = (char*) malloc(len + 1)) != 0) {
223
if (!MIME_ComposeContentTypeEx(mime_t, mime_s, mime_e,
227
CORE_LOGF(eLOG_Warning,
228
("[SERVICE] Content-Type mismatch for \"%s\" "
229
"%s%s%s%s%s", net_info->service,
230
t && *t ? "specified=" : "",
232
t && *t && *c_t ? ", " : "",
233
*c_t ? "configured=" : "",
223
246
static char* s_AdjustNetParams(SConnNetInfo* net_info,
224
247
EReqMethod req_method,
225
const char* cgi_name,
248
const char* cgi_path,
249
const char* cgi_args,
227
250
const char* args,
228
const char* cgi_args,
229
251
const char* static_header,
230
252
EMIME_Type mime_t,
231
253
EMIME_SubType mime_s,
232
254
EMIME_Encoding mime_e,
233
255
char* dynamic_header/*will be freed*/)
235
char content_type[MAX_CONTENT_TYPE_LEN], *retval;
257
char c_t[MAX_CONTENT_TYPE_LEN], *retval;
258
size_t sh_len, dh_len, ct_len;
237
260
net_info->req_method = req_method;
240
strncpy0(net_info->path, cgi_name, sizeof(net_info->path) - 1);
243
strncpy0(net_info->args, cgi_args, sizeof(net_info->args) - 1);
247
ConnNetInfo_AppendArg(net_info, "service", service);
249
ConnNetInfo_PrependArg(net_info, args, 0);
250
if (!ConnNetInfo_PreOverrideArg(net_info, "service", service)) {
251
const char* a = args ? strrchr(args, '&') : 0;
255
ConnNetInfo_DeleteArg(net_info, a + (*a == '&' ? 1 : 0));
256
if (ConnNetInfo_PreOverrideArg(net_info,"service",service))
268
free(dynamic_header);
275
if (mime_t == SERV_MIME_TYPE_UNDEFINED ||
276
mime_s == SERV_MIME_SUBTYPE_UNDEFINED ||
277
!MIME_ComposeContentTypeEx(mime_t, mime_s, mime_e,
278
content_type, sizeof(content_type))) {
281
if ((retval = (char*) malloc((static_header ? strlen(static_header) : 0) +
282
strlen(content_type) + 1/*EOL*/ +
283
(dynamic_header? strlen(dynamic_header) : 0)
285
strcpy(retval, static_header ? static_header : "");
286
strcat(retval, content_type);
287
strcat(retval, dynamic_header ? dynamic_header : "");
263
strncpy0(net_info->path, cgi_path, sizeof(net_info->path) - 1);
266
strncpy0(net_info->args, args, sizeof(net_info->args) - 1);
267
ConnNetInfo_DeleteAllArgs(net_info, cgi_args);
268
if (!ConnNetInfo_PrependArg(net_info, cgi_args, 0)) {
270
free(dynamic_header);
274
sh_len = static_header ? strlen(static_header) : 0;
275
dh_len = dynamic_header ? strlen(dynamic_header) : 0;
276
if (s_ContentTypeDefined(net_info, mime_t, mime_s, mime_e) ||
277
mime_t == SERV_MIME_TYPE_UNDEFINED ||
278
mime_s == SERV_MIME_SUBTYPE_UNDEFINED ||
279
!MIME_ComposeContentTypeEx(mime_t, mime_s, mime_e, c_t, sizeof(c_t))) {
283
ct_len = strlen(c_t);
284
if ((retval = (char*) malloc(sh_len + dh_len +ct_len + 1/*EOL*/)) != 0) {
285
strcpy(retval, static_header ? static_header : "");
286
strcpy(retval + sh_len, dynamic_header ? dynamic_header : "");
287
strcpy(retval + sh_len + dh_len, c_t);
289
289
if (dynamic_header)
290
290
free(dynamic_header);
435
436
if (net_info->stateless) {
436
437
/* Connection request with data */
437
438
user_header = "Connection-Mode: STATELESS\r\n"; /*default*/
438
req_method = eReqMethod_Post;
439
req_method = eReqMethod_Post;
440
441
/* We will wait for conn-info back */
441
442
user_header = "Connection-Mode: STATEFUL\r\n";
442
req_method = eReqMethod_Get;
443
req_method = eReqMethod_Get;
444
445
user_header = s_AdjustNetParams(net_info, req_method,
446
uuu->service, uuu->args,
447
447
SERV_NCBID_ARGS(&info->u.ncbid),
448
user_header, info->mime_t,
448
0, user_header, info->mime_t,
449
449
info->mime_s, info->mime_e, 0);
454
452
case fSERV_HttpGet:
455
453
case fSERV_HttpPost:
456
454
/* Connection directly to CGI */
457
user_header = "Client-Mode: STATELESS_ONLY\r\n"; /*default*/
458
req_method = info->type == fSERV_HttpGet
455
req_method = info->type == fSERV_HttpGet
459
456
? eReqMethod_Get : (info->type == fSERV_HttpPost
460
457
? eReqMethod_Post : eReqMethod_Any);
458
user_header = "Client-Mode: STATELESS_ONLY\r\n"; /*default*/
461
459
user_header = s_AdjustNetParams(net_info, req_method,
462
460
SERV_HTTP_PATH(&info->u.http),
464
461
SERV_HTTP_ARGS(&info->u.http),
465
user_header, info->mime_t,
462
0, user_header, info->mime_t,
466
463
info->mime_s, info->mime_e, 0);
470
465
case fSERV_Standalone:
471
if (net_info->stateless) {
472
/* This will be a pass-thru connection, socket otherwise */
473
user_header = "Client-Mode: STATELESS_ONLY\r\n"; /*default*/
474
user_header = s_AdjustNetParams(net_info, eReqMethod_Post, 0,
475
uuu->service, uuu->args,
476
0, user_header, info->mime_t,
477
info->mime_s, info->mime_e, 0);
466
if (!net_info->stateless) {
467
/* We create SOCKET connector here */
468
return SOCK_CreateConnectorEx(net_info->host,
473
net_info->debug_printout ==
475
? eSCC_DebugPrintout : 0);
477
/* Otherwise, this will be a pass-thru connection */
478
user_header = "Client-Mode: STATELESS_ONLY\r\n"; /*default*/
479
user_header = s_AdjustNetParams(net_info, eReqMethod_Post, 0, 0,
480
0, user_header, info->mime_t,
481
info->mime_s, info->mime_e, 0);
487
488
EMIME_Type mime_t;
511
512
user_header = net_info->stateless
512
513
? "Client-Mode: STATELESS_ONLY\r\n" /*default*/
513
514
: "Client-Mode: STATEFUL_CAPABLE\r\n";
514
user_header = s_AdjustNetParams(net_info, req_method, 0,
515
second_try ? 0 : uuu->service,
516
second_try ? 0 : uuu->args,
515
user_header = s_AdjustNetParams(net_info, req_method,
516
0, 0, 0, user_header,
518
517
mime_t, mime_s, mime_e, 0);
524
/* We create HTTP connector here */
525
char* iter_header = SERV_Print(uuu->iter, uuu->net_info);
527
if (iter_header /*NB: <CR><LF>-terminated*/) {
528
if ((n = strlen(user_header)) > 0) {
529
if ((iter_header = (char*)
530
realloc(iter_header, strlen(iter_header) + n + 1)) != 0)
531
strcat(iter_header, user_header);
532
free((char*) user_header);
522
if ((iter_header = SERV_Print(uuu->iter, uuu->net_info)) != 0) {
524
if ((uh_len = strlen(user_header)) > 0) {
526
size_t ih_len = strlen(iter_header);
527
if ((ih = (char*) realloc(iter_header, ih_len + uh_len + 1)) != 0){
528
strcpy(ih + ih_len, user_header);
534
user_header = iter_header;
535
} else if (!*user_header)
536
user_header = 0; /* special case of assignment of literal "" */
537
if (uuu->user_header) {
538
ConnNetInfo_DeleteUserHeader(net_info, uuu->user_header);
539
free((void*) uuu->user_header);
531
free((char*) user_header);
541
uuu->user_header = user_header;
542
if (!ConnNetInfo_OverrideUserHeader(net_info, user_header))
546
ConnNetInfo_ExtendUserHeader
547
(net_info, "User-Agent: NCBIServiceConnector/"
548
DISP_PROTOCOL_VERSION
533
user_header = iter_header;
534
} else if (!*user_header)
535
user_header = 0; /* special case of assignment of literal "" */
537
if (uuu->user_header) {
538
ConnNetInfo_DeleteUserHeader(net_info, uuu->user_header);
539
free((void*) uuu->user_header);
541
uuu->user_header = user_header;
542
if (!ConnNetInfo_OverrideUserHeader(net_info, user_header))
546
ConnNetInfo_ExtendUserHeader
547
(net_info, "User-Agent: NCBIServiceConnector/"
548
DISP_PROTOCOL_VERSION
549
549
#ifdef NCBI_CXX_TOOLKIT
557
if (!net_info->stateless && (!info ||
558
info->type == fSERV_Firewall ||
559
info->type == fSERV_Ncbid)) {
560
/* HTTP connector is auxiliary only */
564
/* Clear connection info */
568
net_info->max_try = 1;
569
conn = HTTP_CreateConnectorEx(net_info,
570
(uuu->params.flags & fHCC_Flushable)
571
| fHCC_SureFlush/*flags*/,
572
s_ParseHeader, 0/*adj.info*/,
573
uuu/*adj.data*/, 0/*cleanup.data*/);
574
/* Wait for connection info back (error-transparent by DISPD.CGI)*/
575
if (conn && CONN_Create(conn, &c) == eIO_Success) {
576
CONN_SetTimeout(c, eIO_Open, timeout);
577
CONN_SetTimeout(c, eIO_ReadWrite, timeout);
578
CONN_SetTimeout(c, eIO_Close, timeout);
580
/* This also triggers parse header callback */
583
CORE_LOGF(eLOG_Error, ("[SERVICE] Unable to create aux. %s",
584
conn ? "connection" : "connector"));
588
return 0/*failed, no connection info returned*/;
589
if (uuu->host == (unsigned int)(-1)) {
590
/* Firewall mode only in stateful mode, fallback requested */
591
assert((!info || info->type == fSERV_Firewall) && !second_try);
592
/* Try to use stateless mode instead */
593
net_info->stateless = 1/*true*/;
594
return s_Open(uuu, timeout, info, net_info, 1/*second try*/);
596
if (net_info->firewall && *net_info->proxy_host)
597
strcpy(net_info->host, net_info->proxy_host);
599
SOCK_ntoa(uuu->host, net_info->host, sizeof(net_info->host));
600
net_info->port = uuu->port;
601
/* Build and return target SOCKET connector */
602
return SOCK_CreateConnectorEx(net_info->host, net_info->port,
604
&uuu->ticket, sizeof(uuu->ticket),
605
net_info->debug_printout ==
607
? eSCC_DebugPrintout : 0);
609
net_info->max_try = uuu->net_info->max_try;
610
return HTTP_CreateConnectorEx(net_info,
557
if (!net_info->stateless && (!info ||
558
info->type == fSERV_Firewall ||
559
info->type == fSERV_Ncbid)) {
560
/* HTTP connector is auxiliary only */
564
/* Clear connection info */
568
net_info->max_try = 1;
569
conn = HTTP_CreateConnectorEx(net_info,
611
570
(uuu->params.flags & fHCC_Flushable)
612
| fHCC_AutoReconnect/*flags*/,
613
s_ParseHeader, s_AdjustNetInfo,
571
| fHCC_SureFlush/*flags*/,
572
s_ParseHeader, 0/*adj.info*/,
614
573
uuu/*adj.data*/, 0/*cleanup.data*/);
574
/* Wait for connection info back (error-transparent by DISPD.CGI) */
575
if (conn && CONN_Create(conn, &c) == eIO_Success) {
576
CONN_SetTimeout(c, eIO_Open, timeout);
577
CONN_SetTimeout(c, eIO_ReadWrite, timeout);
578
CONN_SetTimeout(c, eIO_Close, timeout);
580
/* This also triggers parse header callback */
583
CORE_LOGF(eLOG_Error, ("[SERVICE] Unable to create aux. %s",
584
conn ? "connection" : "connector"));
588
return 0/*failed, no connection info returned*/;
589
if (uuu->host == (unsigned int)(-1)) {
590
/* Firewall mode only in stateful mode, fallback requested */
591
assert((!info || info->type == fSERV_Firewall) && !second_try);
592
/* Try to use stateless mode instead */
593
net_info->stateless = 1/*true*/;
594
return s_Open(uuu, timeout, info, net_info, 1/*second try*/);
596
if (net_info->firewall && *net_info->proxy_host)
597
strcpy(net_info->host, net_info->proxy_host);
599
SOCK_ntoa(uuu->host, net_info->host, sizeof(net_info->host));
600
net_info->port = uuu->port;
601
/* Build and return target SOCKET connector */
602
return SOCK_CreateConnectorEx(net_info->host,
607
net_info->debug_printout ==
609
? eSCC_DebugPrintout : 0);
616
/* We create SOCKET connector here */
617
return SOCK_CreateConnectorEx(net_info->host, net_info->port,
618
1/*max.try*/, 0/*init.data*/, 0/*data.size*/,
619
net_info->debug_printout ==
620
eDebugPrintout_Data ? eSCC_DebugPrintout :0);
611
return HTTP_CreateConnectorEx(net_info,
612
(uuu->params.flags & fHCC_Flushable)
613
| fHCC_AutoReconnect/*flags*/,
614
s_ParseHeader, s_AdjustNetInfo,
615
uuu/*adj.data*/, 0/*cleanup.data*/);
798
799
SServiceConnector* xxx;
800
SConnNetInfo* x_net_info;
802
801
if (!service || !*service)
806
net_info ? ConnNetInfo_Clone(net_info) : ConnNetInfo_Create(service);
807
x_args = s_GetArgs(x_net_info->client_host);
808
ccc = (SConnector*) malloc(sizeof(SConnector));
809
xxx = (SServiceConnector*) malloc(sizeof(SServiceConnector) +
810
(x_args ? strlen(x_args) : 0));
812
xxx->service = SERV_ServiceName(service);
813
xxx->net_info = x_net_info;
814
if (types & fSERV_StatelessOnly)
804
ccc = (SConnector*) malloc(sizeof(SConnector));
805
xxx = (SServiceConnector*) calloc(1, sizeof(*xxx) + strlen(service));
807
/* initialize connector structures */
811
ccc->setup = s_Setup;
812
ccc->destroy = s_Destroy;
815
xxx->net_info = (net_info
816
? ConnNetInfo_Clone(net_info)
817
: ConnNetInfo_Create(service));
818
if (net_info && xxx->net_info) {
819
xxx->x_service = SERV_ServiceName(service);
820
xxx->net_info->service = xxx->x_service;/*SetupStandardArgs() expects*/
822
if (!ConnNetInfo_SetupStandardArgs(xxx->net_info)) {
827
/* now get ready for first probe dispatching */
828
if (types & fSERV_Stateless)
815
829
xxx->net_info->stateless = 1/*true*/;
816
830
if (types & fSERV_Firewall)
817
831
xxx->net_info->firewall = 1/*true*/;
818
xxx->status = eIO_Success;
821
memset(&xxx->params, 0, sizeof(xxx->params));
822
memset(&xxx->meta, 0, sizeof(xxx->meta));
825
strcpy(xxx->args, x_args);
830
/* initialize connector structure */
834
ccc->setup = s_Setup;
835
ccc->destroy = s_Destroy;
837
/* now make the first probe dispatching */
832
strcpy(xxx->service, service);
838
833
if (!s_OpenDispatcher(xxx)) {
839
s_CloseDispatcher(xxx);