1 /*===========================================================================
2  *
3  *                            PUBLIC DOMAIN NOTICE
4  *               National Center for Biotechnology Information
5  *
6  *  This software/database is a "United States Government Work" under the
7  *  terms of the United States Copyright Act.  It was written as part of
8  *  the author's official duties as a United States Government employee and
9  *  thus cannot be copyrighted.  This software/database is freely available
10  *  to the public for use. The National Library of Medicine and the U.S.
11  *  Government have not placed any restriction on its use or reproduction.
12  *
13  *  Although all reasonable efforts have been taken to ensure the accuracy
14  *  and reliability of the software and data, the NLM and the U.S.
15  *  Government do not and cannot warrant the performance or results that
16  *  may be obtained by using this software or data. The NLM and the U.S.
17  *  Government disclaim all warranties, express or implied, including
18  *  warranties of performance, merchantability or fitness for any particular
19  *  purpose.
20  *
21  *  Please cite the author in any work or product based on this material.
22  *
23  * ===========================================================================*/
24 
25 #include <vfs/extern.h>
26 
27 #include <cloud/cloud.h> /* CloudRelease */
28 #include <cloud/manager.h> /* CloudMgrRelease */
29 
30 #include <kfs/directory.h> /* KDirectory */
31 #include <kfs/file.h> /* KFileRead */
32 
33 #include <klib/container.h> /* BSTree */
34 #include <klib/debug.h> /* DBGMSG */
35 #include <klib/log.h> /* KLogLevel */
36 #include <klib/out.h> /* KOutMsg */
37 #include <klib/printf.h> /* string_printf */
38 #include <klib/rc.h> /* RC */
39 #include <klib/strings.h> /* KFG_USER_ACCEPT_GCP_CHARGES etc */
40 #include <klib/text.h> /* String */
41 #include <klib/time.h> /* KTime */
42 #include <klib/vector.h> /* Vector */
43 
44 #include <kfg/config.h> /* KConfigRelease */
45 #include <kfg/kart-priv.h> /* KartItemMake2 */
46 #include <kfg/properties.h> /* KConfig_Get_User_Accept_Aws_Charges */
47 #include <kfg/repository.h> /* KRepositoryMgrRelease */
48 
49 #include <kns/http.h> /* KHttpRequest */
50 #include <kns/http-priv.h> /* KClientHttpRequestFormatMsg */
51 #include <kns/kns-mgr-priv.h> /* KNSManagerMakeReliableClientRequest */
52 #include <kns/manager.h> /* KNSManager */
53 #include <kns/stream.h> /* KStreamMakeFromBuffer */
54 
55 #include <kproc/timeout.h> /* TimeoutInit */
56 
57 #include <vdb/vdb-priv.h> /* VDBManagerGetQuality */
58 
59 #include <vfs/manager.h> /* VFSManager */
60 #include <vfs/manager-priv.h> /* VFSManagerMakeFromKfg */
61 #include <vfs/services.h> /* KServiceMake */
62 
63 #include "../kfg/kfg-priv.h" /* KConfigGetNgcFile */
64 #include "../kns/mgr-priv.h" /* KNSManagerGetCloudLocation */
65 #include "json-response.h" /* Response4 */
66 #include "jwt.h" /* JwtKartValidateFile */
67 #include "path-priv.h" /* VPathMakeFmt */
68 #include "resolver-cgi.h" /* RESOLVER_CGI */
69 #include "resolver-priv.h" /* VPathCheckFromNamesCGI */
70 #include "services-cache.h" /* ServicesCacheAddId */
71 #include "services-priv.h"
72 
73 #include <ctype.h> /* isdigit */
74 #include <string.h> /* memset */
75 
76 
77 /******************************************************************************/
78 
79 
80 #define RELEASE(type, obj) do { rc_t rc2 = type##Release(obj); \
81     if (rc2 && !rc) { rc = rc2; } obj = NULL; } while (false)
82 
83 /******************************************************************************/
84 static bool sLogNamesServiceErrors = true;
85 static bool sLogNamesServiceErrorsSet = false;
LogNamesServiceErrorsReset()86 void LogNamesServiceErrorsReset() {
87     sLogNamesServiceErrorsSet = false;
88 }
LogNamesServiceErrorsInit(bool enabled)89 void LogNamesServiceErrorsInit(bool enabled) {
90     if (!sLogNamesServiceErrorsSet)
91         sLogNamesServiceErrors = enabled;
92 }
VFSManagerLogNamesServiceErrors(VFSManager * self,bool enabled)93 LIB_EXPORT rc_t CC VFSManagerLogNamesServiceErrors(VFSManager * self,
94     bool enabled)
95 {
96     sLogNamesServiceErrors = enabled;
97     sLogNamesServiceErrorsSet = true;
98     return 0;
99 }
VFSManagerGetLogNamesServiceErrors(VFSManager * self,bool * enabled)100 LIB_EXPORT rc_t CC VFSManagerGetLogNamesServiceErrors(VFSManager * self,
101     bool * enabled)
102 {
103     if (enabled == NULL)
104         return RC(rcVFS, rcMgr, rcUpdating, rcParam, rcNull);
105     else {
106         *enabled = sLogNamesServiceErrors;
107         return 0;
108     }
109 }
110 /******************************************************************************/
111 
112 /******************************************************************************/
113 /* service type - names of search */
114 typedef enum {
115     eSTnames,
116     eSTsearch,
117 } EServiceType;
118 
119 
120 /* request/response/processing helper objects */
121 typedef struct {
122     const KConfig        * kfg;
123 
124     const KNSManager     * kMgr;
125        /* KNSManagerMakeReliableClientRequest */
126 
127     const KRepositoryMgr * repoMgr;
128        /* KRepositoryMgrGetProtectedRepository */
129 
130     const VFSManager     * vMgr;
131 
132     CloudMgr * cloudMgr;
133     Cloud    * cloud;
134 
135     uint32_t timeoutMs;
136 
137     char * input;
138     size_t inSz;
139 } SHelper;
140 
141 
142 /* raw string text */
143 typedef struct { char * s; } SRaw;
144 
145 
146 /******************************************************************************/
147 /* SERVICE VERSIONS */
148 #define VERSION_1_0 0x01000000
149 #define VERSION_1_1 0x01010000
150 #define VERSION_1_2 0x01020000
151 
152 #define VERSION_2_0 0x02000000
153 
154 /* version in server request / response */
155 typedef ver_t SVersion;
156 
157 /* features that are different for different protocol versions ****************/
SVersionNotExtendedVPaths(const SVersion self)158 static bool SVersionNotExtendedVPaths ( const SVersion  self ) {
159     return self == VERSION_1_0;
160 }
161 
SVersionBefore3_0(const SVersion self)162 static bool SVersionBefore3_0 ( const SVersion  self ) {
163     return self < VERSION_3_0;
164 }
165 
SVersionHasRefseqCtx(const SVersion self)166 static bool SVersionHasRefseqCtx ( const SVersion  self ) {
167     return self < VERSION_3_0;
168 }
169 
SVersionAccInRequest(const SVersion self)170 static bool SVersionAccInRequest ( const SVersion  self ) {
171     return self < VERSION_3_0;
172 }
173 
SVersionSingleUrl(const SVersion self)174 static bool SVersionSingleUrl ( const SVersion  self ) {
175     return self < VERSION_3_0;
176 }
177 
SVersionTypInRequest(const SVersion self)178 static bool SVersionTypInRequest ( const SVersion  self ) {
179     return self == VERSION_3_0;
180 }
181 
SVersionUseObjidAsAcc(const SVersion self)182 static bool SVersionUseObjidAsAcc ( const SVersion  self ) {
183     return self == VERSION_3_0;
184 }
185 
SVersionHasMultpileObjects(const SVersion self,bool sdl)186 static bool SVersionHasMultpileObjects ( const SVersion self, bool sdl ) {
187     return sdl || self >= VERSION_3_0;
188 }
189 
SVersionResponseHasMultipeUrls(const SVersion self)190 static bool SVersionResponseHasMultipeUrls ( const SVersion  self ) {
191     return self >= VERSION_3_0;
192 }
193 
SVersionResponseHasTimestamp(const SVersion self)194 static bool SVersionResponseHasTimestamp ( const SVersion  self ) {
195     return self >= VERSION_3_0;
196 }
197 
SVersionResponseInJson(const SVersion self,bool sdl)198 static bool SVersionResponseInJson ( const SVersion  self, bool sdl ) {
199     return self >= VERSION_4_0 || sdl;
200 }
201 
202 /*static bool SVersionNeedCloudLocation(const SVersion  self, bool sdl) {
203     return !sdl && self == VERSION_4_0;
204 }*/
205 
SVersionNeedCloudEnvironment(const SVersion self,bool sdl)206 static bool SVersionNeedCloudEnvironment(const SVersion  self, bool sdl) {
207     return sdl && self >= VERSION_2_0;
208 }
209 
210 /******************************************************************************/
211 
212 
213 /* server response header */
214 typedef struct {
215     SRaw raw;
216     SVersion version;
217 } SHeader;
218 
219 
220 /* number of fields in different versions of name resolver protocol */
221 #define N_NAMES1_0 5
222 #define N_NAMES1_1 10
223 #define N_NAMES3_0  15
224 
225 /* md5 checksum */
226 typedef struct {
227     uint8_t md5 [ 16 ];
228     bool has_md5;
229 } SMd5;
230 
231 
232 /* response row parsed into named typed fields */
233 typedef struct STyped {
234     bool inited;
235     uint32_t ordId;
236     EObjectType objectType;
237     String accession; /* versios 1.1/1.2 only */
238     String objectId;
239     String name;
240     uint64_t osize;
241     KTime_t date;
242     SMd5 md5;
243     String ticket;
244     String url;
245     String hUrl;
246     String fpUrl;
247     String hsUrl;
248     String flUrl;
249     String s3Url;
250     size_t vdbcacheSize;
251     KTime_t vdbcacheDate;
252     SMd5 vdbcacheMd5;
253     String vdbcacheUrl;
254     String hVdbcacheUrl;
255     String fpVdbcacheUrl;
256     String hsVdbcacheUrl;
257     String flVdbcacheUrl;
258     String s3VdbcacheUrl;
259     KTime_t expiration;
260     uint32_t code;
261     String message;
262 } STyped;
263 
264 
265 /* converter from server response string to a typed object */
266 typedef rc_t TConverter ( void * dest, const String * src );
267 typedef struct { TConverter * f; } SConverter;
268 typedef void * TFieldGetter ( STyped * self, int n );
269 
270 typedef struct {
271     int n;
272     TFieldGetter * get;
273     TConverter ** f;
274 } SConverters;
275 
276 
277 /* response row parsed into array of Strings */
278 typedef struct {
279     int n;
280     String s [ N_NAMES3_0 ];
281 } SOrdered;
282 
283 
284 /* server error row */
285 struct KSrvError {
286     atomic32_t refcount;
287 
288     rc_t rc;
289     uint32_t code;
290     String message;
291 
292     String      objectId;
293     EObjectType objectType;
294 };
295 
296 
297 /* EVPath is defined in ./path-priv.h */
298 
299 
300 /* a response row */
301 typedef struct {
302     SRaw raw;
303     SOrdered ordered;
304     STyped typed;
305     EVPath path;
306     VPathSet * set;
307     char * reqId; /* request id or accession */
308 } SRow;
309 
310 
311 /* timestamp object */
312 typedef struct {
313     SRaw raw;
314     KTime_t time;
315 } STimestamp;
316 
317 
318 /* server timestamp */
319 typedef struct {
320     STimestamp server;
321     STimestamp local;
322 } SServerTimestamp;
323 
324 
325 /* server response = header; vector of response rows; generated objects */
326 typedef struct {
327     EServiceType serviceType;
328     SHeader header;
329     Vector rows;
330     KSrvResponse * list;
331     Kart * kart;
332     SServerTimestamp timestamp;
333     rc_t rc;
334 } SResponse;
335 
336 
337 /* key-value */
338 typedef struct {
339     String k;
340     String v;
341     char n[256];
342 } SKV;
343 
344 
345 /* helper object to add cgi parameters to KHttpRequest */
346 typedef struct {
347     KHttpRequest * httpReq;
348     rc_t rc;
349 } SHttpRequestHelper;
350 
351 
352 /* cgi request info */
353 typedef struct {
354     bool inited;
355     char * cgi;
356 
357     const char * fileKey; /* don't free */
358     const char * fileVal; /* don't free */
359     bool         fileBase64encode;
360 
361     Vector params;
362 } SCgiRequest;
363 
364 
365 /* request object */
366 typedef struct {
367     char * objectId;
368     EObjectType objectType;
369     bool isUri;
370     uint32_t ordId;
371 } SObject;
372 
373 
374 /* service request data ( objects to query ) */
375 typedef struct {
376     SObject * object;
377     size_t allocated;
378     uint32_t objects;
379     bool refseq_ctx;
380 
381     VResolverAppID app;
382     rc_t appRc; /* to record inconsistent app-s when calling revolver-v4 */
383 } SRequestData;
384 
385 
386 typedef struct {
387     BSTNode n;
388     char * ticket;
389     uint32_t project;
390 } BSTItem;
391 
392 
393 /* tickets - access authorization keys */
394 typedef struct {
395     BSTree ticketsToProjects;
396     Vector tickets;
397     KDataBuffer str;
398     size_t size;
399     rc_t rc;
400 } STickets;
401 
402 typedef struct {
403     char * ngcFile;
404     const KNgcObj * ngcObj;
405 } SNgc;
406 
407 /* service request */
408 typedef struct {
409     bool disabled;
410 
411     EServiceType serviceType;
412 
413     SVersion version;
414     bool sdl;
415 
416     SCgiRequest cgiReq;
417     SRequestData request;
418     STickets tickets;
419     int errorsToIgnore;
420     VRemoteProtocols protocols;
421     char * format;
422     char * forced; /* forced SDL>=2 location  */
423     String * jwtKartFile;
424     SNgc _ngc;
425     bool hasQuery;
426 } SRequest;
427 
428 /* service object */
429 struct KService {
430     SHelper helper;
431     SRequest req;
432     SResponse resp;
433 
434     bool resoveOidName;
435     int32_t quality; /* quality type - 0: default, 1: no-qual, 2: full-qual */
436     bool skipLocal;
437     bool skipRemote;
438 };
439 
440 
441 /******************************************************************************/
442 
443 
444 /* SHelper ********************************************************************/
SHelperInit(SHelper * self,const VFSManager * vMgr,const KNSManager * kMgr,const KConfig * kfg)445 static rc_t SHelperInit ( SHelper * self,
446     const VFSManager * vMgr, const KNSManager * kMgr, const KConfig * kfg )
447 {
448     rc_t rc = 0;
449 
450     assert ( self );
451 
452     memset ( self, 0, sizeof * self );
453 
454     /* buffer for names service responses */
455     self -> inSz = 1024;
456     self -> input = (char *) malloc ( self -> inSz );
457 
458     if ( self -> input == NULL )
459         return RC ( rcVFS, rcStorage, rcAllocating, rcMemory, rcExhausted );
460 
461     self -> input [0] = '\0';
462 
463     if ( kMgr == NULL ) {
464         if (vMgr == NULL) {
465             KNSManager * kns = NULL;
466             rc = KNSManagerMake(&kns);
467             kMgr = kns;
468         }
469         else
470             rc = VFSManagerGetKNSMgr(vMgr, (KNSManager **)(&kMgr));
471     }
472     else {
473         rc = KNSManagerAddRef ( kMgr );
474     }
475 
476     if (rc == 0)
477         self->kMgr = kMgr;
478 
479     if (rc == 0 && kfg != NULL) {
480         rc = KConfigAddRef(kfg);
481         if (rc == 0)
482             self->kfg = kfg;
483     }
484 
485     if (rc == 0 && vMgr != NULL) {
486         rc = VFSManagerAddRef(vMgr);
487         if (rc == 0)
488             self->vMgr = vMgr;
489     }
490 
491     self -> timeoutMs = 5000;
492 
493     return rc;
494 }
495 
496 
SHelperFini(SHelper * self)497 static rc_t SHelperFini ( SHelper * self) {
498     rc_t rc = 0;
499 
500     assert ( self );
501 
502     RELEASE ( Cloud         , self -> cloud );
503     RELEASE ( CloudMgr      , self -> cloudMgr );
504     RELEASE ( KConfig       , self -> kfg );
505     RELEASE ( VFSManager    , self -> vMgr );
506     RELEASE ( KNSManager    , self -> kMgr );
507     RELEASE ( KRepositoryMgr, self -> repoMgr );
508 
509     free ( self -> input );
510 
511     memset ( self, 0, sizeof * self );
512 
513     return rc;
514 }
515 
516 
SHelperInitKfg(SHelper * self)517 static rc_t SHelperInitKfg ( SHelper * self ) {
518     rc_t rc = 0;
519 
520     assert ( self );
521 
522     if ( self -> kfg == NULL )
523         rc = KConfigMake ( (KConfig**) & self -> kfg, NULL );
524 
525     return rc;
526 }
527 
528 
SHelperInitRepoMgr(SHelper * self)529 static rc_t SHelperInitRepoMgr ( SHelper * self ) {
530     rc_t rc = 0;
531 
532     assert ( self );
533 
534     if ( self -> repoMgr == NULL ) {
535         rc = SHelperInitKfg ( self );
536         if ( rc != 0 )
537             return rc;
538 
539         rc = KConfigMakeRepositoryMgrRead ( self -> kfg, & self -> repoMgr );
540     }
541 
542     return rc;
543 }
544 
KServiceGetRepoMgr(KService * self,const KRepositoryMgr ** mgr)545 rc_t KServiceGetRepoMgr(KService * self, const KRepositoryMgr ** mgr) {
546     rc_t rc = 0;
547 
548     assert(mgr && self);
549 
550     *mgr = NULL;
551 
552     rc = SHelperInitRepoMgr(&self->helper);
553 
554     if (rc == 0)
555         *mgr = self->helper.repoMgr;
556 
557     return rc;
558 }
559 
560 /* get from kfg, otherwise use hardcoded */
SHelperDefaultProtocols(SHelper * self)561 static VRemoteProtocols SHelperDefaultProtocols ( SHelper * self ) {
562     VRemoteProtocols protocols = DEFAULT_PROTOCOLS;
563 
564     assert ( self );
565 
566     SHelperInitKfg ( self );
567 
568     KConfigReadRemoteProtocols ( self -> kfg, & protocols );
569 
570     return protocols;
571 }
572 
573 /* SRaw ***********************************************************************/
SRawInit(SRaw * self,char * s)574 static void SRawInit(SRaw * self, char * s) {
575     assert(self);
576 
577     self->s = s;
578 }
579 
580 
SRawAlloc(SRaw * self,const char * s,size_t sz)581 static rc_t SRawAlloc(SRaw * self, const char * s, size_t sz) {
582     char * p = NULL;
583 
584     if (sz == 0)
585         p = string_dup_measure(s, NULL);
586     else
587         p = string_dup(s, sz);
588 
589     if (p == NULL)
590         return RC(rcVFS, rcPath, rcAllocating, rcMemory, rcExhausted);
591 
592     SRawInit(self, p);
593 
594     return 0;
595 }
596 
597 
SRawFini(SRaw * self)598 static rc_t SRawFini(SRaw * self) {
599     if (self != NULL) {
600         free(self->s);
601         self->s = NULL;
602     }
603 
604     return 0;
605 }
606 
607 /* cgi supports just 4.9 and doesn't support numeric id-s */
cgiSupportsFullJson(const char * cgi)608 static bool cgiSupportsFullJson(const char * cgi) {
609     assert(cgi);
610 
611     if (cgi[strlen(cgi) - 1] == '/')
612         return true;
613     else
614         return false;
615 }
616 
cgiNotSupportsJson(const char * cgi)617 static bool cgiNotSupportsJson(const char * cgi) {
618     assert(cgi);
619 
620     if (cgi[strlen(cgi) - 1] == 'i')
621         return true;
622     else
623         return false;
624 }
625 
626 /* SVersion *******************************************************************/
SVersionInitFromStr(SVersion * self,bool * sdl,const char * s)627 static rc_t SVersionInitFromStr(SVersion * self, bool * sdl, const char * s) {
628     uint8_t major = 0;
629     uint8_t minor = 0;
630 
631     char * end = NULL;
632     uint64_t l = strtoul(s, &end, 10);
633     if (end == NULL || (*end != '.' && *end != '\0'))
634         return RC(rcVFS, rcQuery, rcResolving, rcMessage, rcCorrupt);
635     major = (uint8_t)l;
636 
637     if (*end != '\0') {
638         s = ++end;
639 
640         l = strtoul(s, &end, 10);
641         if (end == NULL || *end != '\0')
642             return RC(rcVFS, rcQuery, rcResolving, rcMessage, rcCorrupt);
643         minor = (uint8_t)l;
644     }
645 
646     if (sdl != NULL) {
647         *sdl = false;
648 
649         /* NB. I SET THE UPPER BIT(128) OF MAJOR VERSION TO 1
650             TO MARK IT AS SDL VERSION */
651         if (major & 128) {
652             major &= ~128;
653             *sdl = true;
654         }
655     }
656 
657     *self = major << 24 | minor << 16;
658 
659     return 0;
660 }
661 
SVersionInit(SVersion * self,bool * sdl,const char * src,EServiceType serviceType,const String * ticket,SHelper * helper,SRequest * request)662 static rc_t SVersionInit(SVersion * self, bool * sdl, const char * src,
663     EServiceType serviceType, const String * ticket,
664     SHelper * helper, SRequest * request)
665 {
666     rc_t rc = 0;
667     const char * s = src;
668     String * result = NULL;
669     const char * e = NULL;
670 
671 /* TODO: needs investigation: using it makes impossibe to call SDL; names.cgi is always called instead: bool dummy; if (sdl == NULL) sdl = &dummy; */
672 
673     assert(self);
674 
675     *self = 0;
676 
677     e = getenv("NCBI_VDB_REMOTE_VERSION");
678     if (e != NULL)
679         s = e;
680     else if (helper != NULL && serviceType != eSTsearch) {
681         rc_t rc = SHelperInitKfg(helper);
682         if (rc == 0) {
683             rc = KConfigReadString(
684                 helper->kfg, "/repository/remote/version", &result);
685             if (rc == 0) {
686                 assert(result);
687                 s = result->addr;
688             }
689         }
690     }
691 
692     if (s == NULL)
693         return RC(rcVFS, rcQuery, rcExecuting, rcMessage, rcBadVersion);
694 
695     if (*s != '#') {
696         if (serviceType != eSTnames || *s == '\0' || !isdigit(*s))
697             return RC(rcVFS, rcQuery, rcExecuting, rcMessage, rcBadVersion);
698     }
699     else
700         ++s;
701 
702     if (serviceType == eSTsearch) {
703         const char version[] = "version ";
704         size_t sz = sizeof version - 1;
705         if (string_cmp(s, sz, version, sz, (uint32_t)sz) != 0)
706             return RC(rcVFS, rcQuery, rcExecuting, rcMessage, rcBadVersion);
707         s += sz;
708     }
709 
710     if (*s == '\0')
711         return RC(rcVFS, rcQuery, rcExecuting, rcMessage, rcBadVersion);
712 
713     rc = SVersionInitFromStr(self, sdl, s);
714 
715     if (rc == 0 && sdl != NULL && *sdl) {
716         if (ticket != NULL) {
717             if (KConfigGetNgcFile() == NULL)
718                 /* use version 3 when getting dbGaP data without ngc file */
719                 rc = SVersionInitFromStr(self, sdl, "3");
720         }
721         else if (request != NULL
722             && VectorLength(&request->tickets.tickets) > 0
723             && request->request.objects > 0
724             && request->request.object->objectId != NULL
725             && isdigit(request->request.object->objectId[0]))
726         {   /* use version 3 when getting numeric dbGaP data (objectIds) */
727             rc = SVersionInitFromStr(self, sdl, "3");
728         }
729     }
730 
731     free(result);
732 
733     return rc;
734 }
735 
InitVersion(const char * src,const String * ticket)736 ver_t InitVersion(const char * src, const String * ticket) {
737     SVersion self = 0;
738     rc_t rc = SVersionInit(&self, NULL, src, eSTnames, ticket, NULL, NULL);
739     if (rc == 0)
740         return self;
741     else
742         return 0;
743 }
744 
SVersionToString(const SVersion self,char ** s)745 static rc_t SVersionToString(const SVersion  self, char ** s) {
746     size_t num_writ = 0;
747     char tmp[1];
748     assert(self && s);
749     string_printf(tmp, num_writ, &num_writ, "%.2V", self);
750     ++num_writ;
751     *s = (char *)malloc(num_writ);
752     if (*s == NULL)
753         return RC(rcVFS, rcQuery, rcExecuting, rcMemory, rcExhausted);
754     return string_printf(*s, num_writ, &num_writ, "%.2V", self);
755 }
756 
SVersionFini(SVersion * self)757 static rc_t SVersionFini(SVersion * self) {
758     assert(self);
759 
760     *self = 0;
761 
762     return 0;
763 }
764 
765 /* try to get cgi from kfg, otherwise use hardcoded */
766 static
SHelperResolverCgi(SHelper * self,bool aProtected,char * buffer,size_t bsize,const char * aCgi,SRequest * request,bool adjustVersion)767 rc_t SHelperResolverCgi ( SHelper * self, bool aProtected,
768     char * buffer, size_t bsize, const char * aCgi,
769     SRequest * request, bool adjustVersion)
770 {
771     const char man[] = "/repository/remote/main/CGI/resolver-cgi";
772     const char prt[] = "/repository/remote/protected/CGI/resolver-cgi";
773     const char sdl[] = "/repository/remote/main/SDL.2/resolver-cgi";
774     const char cgi[] = RESOLVER_CGI;
775 
776     rc_t rc = 0;
777     const char * path = aProtected ? prt : man;
778     assert( request );
779     assert ( self );
780     rc = SHelperInitKfg ( self );
781     if ( rc == 0 && aCgi == NULL ) {
782         size_t num_read = 0;
783         if (request->sdl) {
784             rc = KConfigRead(self->kfg, sdl, 0, buffer, bsize,
785                 &num_read, NULL);
786             if (rc != 0) {
787                 const char cgi[] = SDL_CGI;
788                 if (buffer == NULL)
789                     return RC(rcVFS, rcQuery, rcExecuting, rcParam, rcNull);
790                 if (bsize < sizeof cgi)
791                     return RC(rcVFS, rcQuery, rcExecuting, rcBuffer,
792                         rcInsufficient);
793                 string_copy(buffer, bsize, cgi, sizeof cgi);
794                 rc = 0;
795             }
796         }
797         else {
798             rc = KConfigRead(self->kfg, path, 0, buffer, bsize,
799                 &num_read, NULL);
800             if (rc != 0) {
801                 if (buffer == NULL)
802                     return RC(rcVFS, rcQuery, rcExecuting, rcParam, rcNull);
803                 if (bsize < sizeof cgi)
804                     return RC(rcVFS, rcQuery, rcExecuting, rcBuffer,
805                         rcInsufficient);
806                 string_copy(buffer, bsize, cgi, sizeof cgi);
807                 rc = 0;
808             }
809         }
810     }
811     else
812         string_copy_measure ( buffer, bsize, aCgi );
813 
814     if (rc == 0 && request->sdl) /* don't auto-correct version and cgi */
815         adjustVersion = false;   /* when calling SDL */
816 
817     if (rc == 0 && adjustVersion) {
818         if (cgiNotSupportsJson(buffer)) { /* cgi supports versions < 4 */
819             if (SVersionResponseInJson(request->version, request->sdl))
820                 /* version >= 4 but cgi does't support 4: use version-3.0 */
821                 request->version = VERSION_3_0;
822         }
823         else { /* cgi supports versions >= 4 */
824             if (request->request.appRc != 0
825                 && SVersionResponseInJson(request->version, request->sdl))
826             {
827                 /* version >= 4
828                 but different acc-s in request:
829                 require to use "filetype=run" (SRR)
830                 and not (not SRR):
831                 call version-3.0 using old cgi */
832                 string_copy(buffer, bsize, cgi, sizeof cgi);
833                 request->version = VERSION_3_0;
834             }
835             else if (!cgiSupportsFullJson(buffer)) {
836                 if (request->request.objects > 0 &&
837                     request->request.object[0].objectId != NULL &&
838                     isdigit(request->request.object[0].objectId[0]) &&
839                     SVersionResponseInJson(request->version, request->sdl))
840                 {
841                     /* version >= 4; request contains numeric kart-ids
842                     but cgi does not support numeric kart-ids:
843                     call version-3.0 using old cgi */
844                     string_copy(buffer, bsize, cgi, sizeof cgi);
845                     request->version = VERSION_3_0;
846                 }
847                 else if (!SVersionResponseInJson(request->version,
848                     request->sdl))
849                 {
850                     /* version < 4; but cgi supports version>=4:
851                     use old cgi */
852                     string_copy(buffer, bsize, cgi, sizeof cgi);
853                 }
854             }
855         }
856     }
857 
858     return rc;
859 }
860 
861 
862 static
SHelperProjectToTicket(SHelper * self,uint32_t projectId,char * buffer,size_t bsize,size_t * ticket_size)863 rc_t SHelperProjectToTicket ( SHelper * self, uint32_t projectId,
864     char * buffer, size_t bsize, size_t * ticket_size )
865 {
866     rc_t rc = 0;
867 
868     const KRepository * repo = NULL;
869 
870     assert ( self );
871 
872     rc = SHelperInitRepoMgr ( self );
873 
874     rc = KRepositoryMgrGetProtectedRepository ( self -> repoMgr, projectId,
875         & repo );
876     if ( rc != 0 )
877         return rc;
878 
879     rc = KRepositoryDownloadTicket ( repo, buffer, bsize, ticket_size );
880 
881     RELEASE ( KRepository, repo );
882 
883     return rc;
884 }
885 
886 
887 /* SHeader ********************************************************************/
SHeaderMake(SHeader * self,const String * src,EServiceType serviceType)888 static rc_t SHeaderMake
889     ( SHeader * self, const String * src, EServiceType serviceType )
890 {
891     rc_t rc = 0;
892 
893     assert ( self && src );
894 
895     memset ( self, 0, sizeof * self );
896 
897     rc = SRawAlloc ( & self -> raw, src -> addr, src -> size );
898 
899     if ( rc == 0 )
900         rc = SVersionInit ( & self -> version, NULL, self -> raw . s, serviceType, NULL, NULL, NULL);
901 
902     return rc;
903 }
904 
905 
SHeaderFini(SHeader * self)906 static rc_t SHeaderFini ( SHeader * self ) {
907     rc_t rc = 0;
908     if ( self != NULL ) {
909         rc_t r2 = SRawFini ( & self -> raw );
910         rc = SVersionFini ( & self -> version );
911         if ( rc == 0 ) {
912             rc = r2;
913         }
914     }
915     return rc;
916 }
917 
918 
919 /* SProtocol ******************************************************************/
920 typedef struct {
921     const char * text;
922     VRemoteProtocols protocol;
923 } SProtocol;
924 
925 
SProtocolGet(const String * url)926 static VRemoteProtocols SProtocolGet ( const String * url ) {
927     size_t i = 0;
928     SProtocol protocols [] = {
929         { "http:", eProtocolHttp },
930         { "fasp:", eProtocolFasp },
931         { "https:",eProtocolHttps},
932         { "file:", eProtocolFile },
933         { "s3:"  , eProtocolS3   },
934         { "gs:"  , eProtocolGS   },
935     };
936     if ( url == NULL || url -> addr == NULL || url -> size == 0 ) {
937         return eProtocolNone;
938     }
939     for ( i = 0; i < sizeof protocols / sizeof protocols [ 0 ]; ++ i ) {
940         uint32_t sz = string_measure ( protocols [ i ] . text, NULL );
941         if ( string_cmp ( url -> addr, sz, protocols [ i ] . text, sz,
942             ( uint32_t ) sz ) == 0 )
943         {
944             return protocols [ i ] . protocol;
945         }
946     }
947     return eProtocolNone;
948 }
949 
950 
951 /* STyped *********************************************************************/
STypedInitUrls(STyped * self)952 static rc_t STypedInitUrls ( STyped * self ) {
953     VRemoteProtocols protocol = eProtocolNone;
954     String * str = NULL;
955     String * dst = NULL;
956     assert ( self );
957     str = & self -> url;
958     while ( str -> size > 0 ) {
959         size_t len = 0;
960         char * n = string_chr ( str -> addr, str -> size, '$' );
961         if ( n != NULL ) {
962             len = n - str -> addr;
963         }
964         else {
965             len = str -> size;
966         }
967         protocol = SProtocolGet ( str );
968         switch ( protocol ) {
969             case eProtocolFasp:
970                 dst = & self -> fpUrl;
971                 break;
972             case eProtocolFile:
973                 dst = & self -> flUrl;
974                 break;
975             case eProtocolHttp:
976                 dst = & self -> hUrl;
977                 break;
978             case eProtocolHttps:
979                 dst = & self -> hsUrl;
980                 break;
981             case eProtocolS3:
982                 dst = & self -> s3Url;
983                 break;
984             default:
985                 return RC ( rcVFS, rcQuery, rcResolving, rcMessage, rcCorrupt );
986         }
987         StringInit ( dst, str -> addr, len, len );
988         if ( n != NULL )
989             ++ len;
990         str -> addr += len;
991         if ( str -> size >= len )
992             str -> size -= len;
993         else
994             str -> size = 0;
995     }
996     str = & self -> vdbcacheUrl;
997     while ( str -> size > 0 ) {
998         size_t len = 0;
999         char * n = string_chr ( str -> addr, str -> size, '$' );
1000         if ( n != NULL ) {
1001             len = n - str -> addr;
1002         }
1003         else {
1004             len = str -> size;
1005         }
1006         protocol = SProtocolGet ( str );
1007         switch ( protocol ) {
1008             case eProtocolFasp:
1009                 dst = & self -> fpVdbcacheUrl;
1010                 break;
1011             case eProtocolFile:
1012                 dst = & self -> flVdbcacheUrl;
1013                 break;
1014             case eProtocolHttp:
1015                 dst = & self -> hVdbcacheUrl;
1016                 break;
1017             case eProtocolHttps:
1018                 dst = & self -> hsVdbcacheUrl;
1019                 break;
1020             case eProtocolS3:
1021                 dst = & self -> s3VdbcacheUrl;
1022                 break;
1023             default:
1024                 return RC ( rcVFS, rcQuery, rcResolving, rcMessage, rcCorrupt );
1025         }
1026         StringInit ( dst, str -> addr, len, len );
1027         if ( n != NULL )
1028             ++ len;
1029         str -> addr += len;
1030         if ( str -> size >= len )
1031             str -> size -= len;
1032         else
1033             str -> size = 0;
1034     }
1035     return 0;
1036 }
1037 
1038 
1039 static
STypedInit(STyped * self,const SOrdered * raw,const SConverters * how,const SVersion version)1040 rc_t STypedInit ( STyped * self, const SOrdered * raw, const SConverters * how,
1041     const SVersion  version )
1042 {
1043     rc_t rc = 0;
1044     int i = 0;
1045     assert ( self && raw && how );
1046     memset ( self, 0, sizeof * self );
1047 
1048     if ( raw -> n != how -> n )                              /* BREAK */
1049         return RC ( rcVFS, rcQuery, rcResolving, rcName, rcUnexpected );
1050 
1051     for ( i = 0; i < raw -> n; ++i ) {
1052         void * dest = how -> get ( self, i );
1053         if ( dest == NULL ) {
1054             rc = RC ( rcVFS, rcQuery, rcResolving, rcMessage, rcCorrupt );
1055             break;
1056         }
1057         {
1058             TConverter * f = how -> f [ i ];
1059             if ( f == NULL ) {
1060                 rc = RC ( rcVFS, rcQuery, rcResolving, rcFunction, rcNotFound );
1061                 break;
1062             }
1063             rc = f ( dest, & raw -> s [ i ] );
1064             if ( rc != 0 )
1065                 break;             /* BREAK */
1066         }
1067     }
1068 
1069     if ( rc == 0 )
1070         if ( SVersionResponseHasMultipeUrls ( version ) )
1071             rc = STypedInitUrls ( self );
1072 
1073     if ( rc == 0 )
1074         self -> inited = true;
1075 
1076     return rc;
1077 }
1078 
1079 
1080 /* CONVERTERS */
1081 /* functions to initialize objects from response row field Strings ************/
1082 static
cmpStringAndObjectType(const String * s,const char * val)1083 bool cmpStringAndObjectType ( const String * s, const char * val )
1084 {
1085     size_t sz = string_size (val );
1086     String v;
1087     StringInit ( & v, val, sz, sz );
1088     return StringCompare ( s, & v ) == 0;
1089 }
1090 
1091 
1092 /* N.B. DO NOT FREE RETURNED STRING !!! */
ObjectTypeToString(EObjectType self)1093 static const char * ObjectTypeToString ( EObjectType self ) {
1094     switch ( self ) {
1095         case eOT_undefined   : return "";
1096         case eOT_dbgap       : return "dbgap";
1097         case eOT_provisional : return "provisional";
1098         case eOT_srapub      : return "srapub";
1099         case eOT_sragap      : return "sragap";
1100         case eOT_srapub_source:return "srapub_source";
1101         case eOT_sragap_source:return "sragap_source";
1102         case eOT_srapub_files: return "srapub_files";
1103         case eOT_sragap_files: return "sragap_files";
1104         case eOT_refseq      : return "refseq";
1105         case eOT_wgs         : return "wgs";
1106         case eOT_na          : return "na";
1107         case eOT_nakmer      : return "nakmer";
1108         default: assert ( 0 ); return "";
1109     }
1110 }
1111 
1112 
StringToObjectType(const String * s)1113 static EObjectType StringToObjectType ( const String * s ) {
1114     if ( cmpStringAndObjectType ( s, "" ) ) {
1115         return eOT_empty;
1116     }
1117     if ( cmpStringAndObjectType ( s, "dbgap" ) ) {
1118         return eOT_dbgap;
1119     }
1120     if ( cmpStringAndObjectType ( s, "provisional" ) ) {
1121         return eOT_provisional;
1122     }
1123     if ( cmpStringAndObjectType ( s, "srapub" ) ) {
1124         return eOT_srapub;
1125     }
1126     if ( cmpStringAndObjectType ( s, "sragap" ) ) {
1127         return eOT_sragap;
1128     }
1129     if ( cmpStringAndObjectType ( s, "srapub_source" ) ) {
1130         return eOT_srapub_source;
1131     }
1132     if ( cmpStringAndObjectType ( s, "srapub_files" ) ) {
1133         return eOT_srapub_files;
1134     }
1135     if ( cmpStringAndObjectType ( s, "sragap_files") ) {
1136         return eOT_sragap_files;
1137     }
1138     if ( cmpStringAndObjectType ( s, "refseq") ) {
1139         return eOT_refseq;
1140     }
1141     if ( cmpStringAndObjectType ( s, "wgs") ) {
1142         return eOT_wgs;
1143     }
1144     if ( cmpStringAndObjectType ( s, "na") ) {
1145         return eOT_na;
1146     }
1147     if ( cmpStringAndObjectType ( s, "nakmer") ) {
1148         return eOT_nakmer;
1149     }
1150     return eOT_undefined;
1151 }
1152 
1153 
EObjectTypeInit(void * p,const String * src)1154 static rc_t EObjectTypeInit ( void * p, const String * src ) {
1155     EObjectType * self = ( EObjectType * ) p;
1156     EObjectType t = StringToObjectType ( src );
1157     if ( t == eOT_undefined ) {
1158         return RC ( rcVFS, rcQuery, rcExecuting, rcType, rcIncorrect );
1159     }
1160     assert ( self );
1161     * self = t;
1162     return 0;
1163 }
1164 
1165 
aStringInit(void * p,const String * src)1166 static rc_t aStringInit ( void * p, const String * src ) {
1167     String * self = ( String * ) p;
1168     assert ( src );
1169     StringInit ( self, src -> addr, src -> size, src -> len );
1170     return 0;
1171 }
1172 
1173 
size_tInit(void * p,const String * src)1174 static rc_t size_tInit ( void * p, const String * src ) {
1175     rc_t rc = 0;
1176     size_t * self = ( size_t * ) p;
1177     size_t s = 0;
1178     if ( src -> size != 0  && src -> len != 0 ) {
1179         s = ( size_t ) StringToU64 ( src, & rc );
1180     }
1181     if ( rc == 0 ) {
1182         assert ( self );
1183         * self = s;
1184     }
1185     return rc;
1186 }
1187 
1188 
uint32_tInit(void * p,const String * src)1189 static rc_t uint32_tInit ( void * p, const String * src ) {
1190     rc_t rc = 0;
1191     uint32_t * self = ( uint32_t * ) p;
1192     uint32_t s = ( uint32_t ) StringToU64 ( src, & rc );
1193     if ( rc == 0 ) {
1194         assert ( self );
1195         * self = s;
1196     }
1197     return rc;
1198 }
1199 
1200 
uint64_tInit(void * p,const String * src)1201 static rc_t uint64_tInit ( void * p, const String * src ) {
1202     rc_t rc = 0;
1203     uint64_t * self = ( uint64_t * ) p;
1204     uint64_t s = 0;
1205     assert ( src && self );
1206     if ( src -> size == 0 )
1207         * self = 0;
1208     else {
1209         s = StringToU64 ( src, & rc );
1210         if ( rc == 0 )
1211             * self = s;
1212     }
1213     return rc;
1214 }
1215 
1216 
KTimeInit(void * p,const String * src)1217 static rc_t KTimeInit ( void * p, const String * src ) {
1218     rc_t rc = 0;
1219 
1220     KTime_t * self = ( KTime_t * ) p;
1221 
1222     assert ( self && src );
1223 
1224     if ( src -> addr != NULL && src -> size > 0 )
1225         * self = StringToU64 ( src, & rc );
1226 
1227     return rc;
1228 }
1229 
1230 
KTimeInitFromIso8601(void * p,const String * src)1231 static rc_t KTimeInitFromIso8601 ( void * p, const String * src ) {
1232     rc_t rc = 0;
1233 
1234     KTime_t * self = ( KTime_t * ) p;
1235 
1236     assert ( self && src );
1237 
1238     if ( src -> addr != NULL && src -> size > 0 ) {
1239         KTime kt;
1240         const KTime * t = KTimeFromIso8601 ( & kt, src -> addr, src -> size );
1241         if ( t == NULL )
1242             return RC ( rcVFS, rcQuery, rcExecuting, rcItem, rcIncorrect );
1243         else
1244             * self = KTimeMakeTime ( & kt );
1245     }
1246 
1247     return rc;
1248 }
1249 
1250 
getDigit(char c,rc_t * rc)1251 static int getDigit ( char c, rc_t * rc ) {
1252     assert ( rc );
1253 
1254     if ( * rc != 0 )
1255         return 0;
1256 
1257     c = tolower ( c );
1258     if ( ! isdigit ( c ) && c < 'a' && c > 'f' ) {
1259         * rc = RC ( rcVFS, rcQuery, rcExecuting, rcItem, rcIncorrect );
1260         return 0;
1261     }
1262 
1263     if ( isdigit ( c ) )
1264         return c - '0';
1265 
1266     return c - 'a' + 10;
1267 }
1268 
1269 
md5Init(void * p,const String * src)1270 static rc_t md5Init ( void * p, const String * src ) {
1271     SMd5 * md5 = (SMd5 *) p;
1272 
1273     assert ( src && src -> addr && md5 );
1274 
1275     md5 -> has_md5 = false;
1276 
1277     switch ( src -> size ) {
1278         case 0:
1279             return 0;
1280         case 32: {
1281             rc_t rc = 0;
1282             int i = 0;
1283             for ( i = 0; i < 16 && rc == 0; ++ i ) {
1284                 md5 -> md5 [ i ]  = getDigit ( src -> addr [ 2 * i     ], & rc )
1285                                     * 16;
1286                 md5 -> md5 [ i ] += getDigit ( src -> addr [ 2 * i + 1 ],
1287                                                                          & rc );
1288             }
1289             md5 -> has_md5 = rc == 0;
1290             return rc;
1291         }
1292         default:
1293             return RC ( rcVFS, rcQuery, rcExecuting, rcItem, rcIncorrect );
1294     }
1295 }
1296 
1297 
1298 /* SConverters ****************************************************************/
1299 /* converter from names-1.0 response row to STyped object  */
STypedGetFieldNames1_0(STyped * self,int n)1300 static void * STypedGetFieldNames1_0 ( STyped * self, int n ) {
1301     assert ( self );
1302     switch ( n ) {
1303         case  0: return & self -> accession;
1304         case  1: return & self -> ticket;
1305         case  2: return & self -> hUrl;
1306         case  3: return & self -> code;
1307         case  4: return & self -> message;
1308     }
1309     return 0;
1310 }
1311 
1312 
SConvertersNames1_0Make(void)1313 static const SConverters * SConvertersNames1_0Make ( void ) {
1314     static TConverter * f [ N_NAMES1_0 + 1 ] = {
1315         aStringInit,
1316         aStringInit,
1317         aStringInit,
1318         uint32_tInit,
1319         aStringInit, NULL };
1320     static const SConverters c = {
1321         N_NAMES1_0,
1322         STypedGetFieldNames1_0, f };
1323     return & c;
1324 }
1325 
1326 
1327 /* converter from names-1.1 response row to STyped object  */
STypedGetFieldNames1_1(STyped * self,int n)1328 static void * STypedGetFieldNames1_1 ( STyped * self, int n ) {
1329     assert ( self);
1330     switch ( n ) {
1331         case  0: return & self -> accession;
1332         case  1: return & self -> objectId;
1333         case  2: return & self -> name;
1334         case  3: return & self -> osize;
1335         case  4: return & self -> date;
1336         case  5: return & self -> md5;
1337         case  6: return & self -> ticket;
1338         case  7: return & self -> hUrl;
1339         case  8: return & self -> code;
1340         case  9: return & self -> message;
1341     }
1342     return 0;
1343 }
1344 
1345 
SConvertersNames1_1Make(void)1346 static const SConverters * SConvertersNames1_1Make ( void ) {
1347     static TConverter * f [ N_NAMES1_1 + 1 ] = {
1348         aStringInit,
1349         aStringInit,
1350         aStringInit,
1351         uint64_tInit,
1352         KTimeInitFromIso8601,
1353         md5Init,
1354         aStringInit,
1355         aStringInit,
1356         uint32_tInit,
1357         aStringInit, NULL };
1358     static const SConverters c = {
1359         N_NAMES1_1,
1360         STypedGetFieldNames1_1, f };
1361     return & c;
1362 }
1363 
1364 
SConvertersNames1_2Make(void)1365 static const SConverters * SConvertersNames1_2Make ( void ) {
1366     static TConverter * f [ N_NAMES1_1 + 1 ] = {
1367         aStringInit,
1368         aStringInit,
1369         aStringInit,
1370         uint64_tInit,
1371         KTimeInitFromIso8601,
1372         md5Init,
1373         aStringInit,
1374         aStringInit,
1375         uint32_tInit,
1376         aStringInit, NULL };
1377     static const SConverters c = {
1378         N_NAMES1_1,
1379         STypedGetFieldNames1_1, f };
1380     return & c;
1381 }
1382 
1383 
1384 /* converter from names-3.0 response row to STyped object  */
STypedGetFieldNames3_0(STyped * self,int n)1385 static void * STypedGetFieldNames3_0 ( STyped * self, int n ) {
1386     assert ( self);
1387     switch ( n ) {
1388         case  0: return & self -> ordId;
1389         case  1: return & self -> objectType;
1390         case  2: return & self -> objectId;
1391         case  3: return & self -> osize;
1392         case  4: return & self -> date;
1393         case  5: return & self -> md5;
1394         case  6: return & self -> ticket;
1395         case  7: return & self -> url;
1396         case  8: return & self -> vdbcacheSize;
1397         case  9: return & self -> vdbcacheDate;
1398         case 10: return & self -> vdbcacheMd5;
1399         case 11: return & self -> vdbcacheUrl;
1400         case 12: return & self -> expiration;
1401         case 13: return & self -> code;
1402         case 14: return & self -> message;
1403     }
1404     return 0;
1405 }
1406 
1407 
SConvertersNames3_0Make(void)1408 static const SConverters * SConvertersNames3_0Make ( void ) {
1409     static TConverter * f [ N_NAMES3_0 + 1 ] = {
1410         uint32_tInit,        /*  0 ord-id */
1411         EObjectTypeInit,     /*  1 object-type */
1412         aStringInit,         /*  2 object-id */
1413         uint64_tInit,        /*  3 osize */
1414         KTimeInitFromIso8601,/*  4 date */
1415         md5Init,             /*  5 md5 */
1416         aStringInit,         /*  6 ticket */
1417         aStringInit,         /*  7 url */
1418         size_tInit,          /*  8 vdbcache-size */
1419         KTimeInitFromIso8601,/*  9 vdbcache-date */
1420         md5Init,             /* 10 vdbcache-md5 */
1421         aStringInit,         /* 11 vdbcache-url */
1422         KTimeInit,           /* 12 expiration */
1423         uint32_tInit,        /* 13 status-code */
1424         aStringInit,         /* 14 message */
1425         NULL };
1426     static const SConverters c = {
1427         N_NAMES3_0,
1428         STypedGetFieldNames3_0, f };
1429     return & c;
1430 }
1431 
1432 
1433 /* converter factory function */
1434 static
SConvertersMake(const SConverters ** self,SHeader * header)1435 rc_t SConvertersMake ( const SConverters ** self, SHeader * header )
1436 {
1437     assert ( self && header );
1438     switch ( header -> version ) {
1439         case VERSION_1_0:
1440             * self = SConvertersNames1_0Make ();
1441             return 0;
1442         case VERSION_1_1:
1443             * self = SConvertersNames1_1Make ();
1444             return 0;
1445         case VERSION_1_2:
1446             * self = SConvertersNames1_2Make ();
1447             return 0;
1448         case VERSION_3_0:
1449             * self = SConvertersNames3_0Make ();
1450             return 0;
1451         default:
1452             * self = NULL;
1453             return RC ( rcVFS, rcQuery, rcExecuting, rcMessage, rcBadVersion );
1454     }
1455 }
1456 
1457 
1458 /* SOrdered *******************************************************************/
1459 static
SOrderedInit(SOrdered * self,const SRaw * raw,int fields)1460 rc_t SOrderedInit ( SOrdered * self, const SRaw * raw, int fields )
1461 {
1462     assert ( self && raw );
1463     memset ( self, 0, sizeof * self );
1464     {
1465         const char * str = raw -> s;
1466         size_t size = string_size ( str );
1467         while ( size > 0 ) {
1468             size_t len = 0;
1469             char * n = string_chr ( str, size, '|' );
1470             if ( n != NULL )
1471                 len = n - str;
1472             else
1473                 len = size;
1474             if ( self -> n >= fields ) {
1475                 return RC ( rcVFS, rcQuery, rcResolving, rcName, rcExcessive );
1476             }
1477             else {
1478                 String * s = & self -> s [ self -> n ++ ];
1479                 StringInit ( s, str, len, len );
1480                 if ( n != NULL )
1481                     ++ len;
1482                 str += len;
1483                 if ( size >= len )
1484                     size -= len;
1485                 else
1486                     size = 0;
1487             }
1488         }
1489     }
1490     return 0;
1491 }
1492 
1493 
1494 /* KSrvError ******************************************************************/
1495 static
KSrvErrorMake(KSrvError ** self,const STyped * src,rc_t aRc)1496 rc_t KSrvErrorMake ( KSrvError ** self,
1497     const STyped * src, rc_t aRc )
1498 {
1499     KSrvError * o = NULL;
1500     assert ( self && aRc );
1501     o = ( KSrvError * ) calloc ( 1, sizeof * o );
1502     if ( o == NULL )
1503         return RC ( rcVFS, rcQuery, rcExecuting, rcMemory, rcExhausted );
1504 
1505     if ( src != NULL ) {
1506         o -> message . addr = string_dup ( src -> message . addr,
1507                                            src -> message . size );
1508         if ( o -> message . addr == NULL )
1509             return RC ( rcVFS, rcQuery, rcExecuting, rcMemory, rcExhausted );
1510         o -> message . size = src -> message . size;
1511         o -> message . len  = src -> message . len;
1512 
1513         if (src->objectId.size > 0) {
1514             o->objectId.addr = string_dup(src->objectId.addr,
1515                 src->objectId.size);
1516             if (o->objectId.addr == NULL)
1517                 return RC(rcVFS, rcQuery, rcExecuting, rcMemory, rcExhausted);
1518             o->objectId.size = src->objectId.size;
1519             o->objectId.len = src->objectId.len;
1520         }
1521 
1522         o -> objectType = src -> objectType;
1523 
1524         o -> code = src -> code;
1525     }
1526 
1527     o -> rc = aRc;
1528 
1529     atomic32_set ( & o -> refcount, 1 );
1530 
1531     * self = o;
1532 
1533     return 0;
1534 }
1535 
KSrvErrorMake4(const struct KSrvError ** self,rc_t aRc,uint32_t code,const char * msg)1536 rc_t KSrvErrorMake4(const struct KSrvError ** self,
1537                     rc_t aRc, uint32_t code, const char * msg)
1538 {
1539     struct KSrvError * e = NULL;
1540     rc_t rc = KSrvErrorMake( & e, NULL, aRc);
1541 
1542     if (rc == 0) {
1543         assert( self );
1544         e ->code = code;
1545         if (msg != NULL) {
1546             e->message.addr = string_dup_measure(msg, &e->message.size);
1547             if (e->message.addr == NULL)
1548                 rc = RC(rcVFS, rcQuery, rcExecuting, rcMemory, rcExhausted);
1549             else
1550                 e->message.len = e->message.size;
1551         }
1552         if (rc == 0)
1553             *self = e;
1554         else
1555             KSrvErrorRelease(e);
1556     }
1557 
1558     return rc;
1559 }
1560 
KSrvErrorAddRef(const KSrvError * cself)1561 rc_t KSrvErrorAddRef ( const KSrvError * cself ) {
1562     KSrvError * self = ( KSrvError * ) cself;
1563     if ( self != NULL )
1564         atomic32_inc ( & ( ( KSrvError * ) self ) -> refcount );
1565 
1566     return 0;
1567 }
1568 
1569 
KSrvErrorRelease(const KSrvError * cself)1570 rc_t KSrvErrorRelease ( const KSrvError * cself ) {
1571     rc_t rc = 0;
1572 
1573     KSrvError * self = ( KSrvError * ) cself;
1574 
1575     if ( self != NULL && atomic32_dec_and_test ( & self -> refcount ) ) {
1576         free ( ( void * ) self -> message  . addr );
1577         free ( ( void * ) self -> objectId . addr );
1578         memset ( self, 0, sizeof * self );
1579         free ( ( void * ) self );
1580     }
1581 
1582     return rc;
1583 }
1584 
1585 
1586 /* Rc - rc code corresponding to this Error */
KSrvErrorRc(const KSrvError * self,rc_t * rc)1587 rc_t KSrvErrorRc      ( const KSrvError * self, rc_t     * rc   ) {
1588     rc_t dummy = 0;
1589     if ( rc == NULL )
1590         rc = & dummy;
1591 
1592     if ( self == NULL )
1593         return RC ( rcVFS, rcQuery, rcExecuting, rcSelf, rcNull );
1594 
1595     * rc = self -> rc;
1596 
1597     return 0;
1598 }
1599 
1600 
1601 /* Code - Status-Code returned by server */
KSrvErrorCode(const KSrvError * self,uint32_t * code)1602 rc_t KSrvErrorCode    ( const KSrvError * self, uint32_t * code ) {
1603     uint32_t dummy = 0;
1604     if ( code == NULL )
1605         code = & dummy;
1606 
1607     if ( self == NULL )
1608         return RC ( rcVFS, rcQuery, rcExecuting, rcSelf, rcNull );
1609 
1610     * code = self -> code;
1611 
1612     return 0;
1613 }
1614 
1615 
1616 /*  returns pointers to internal String data
1617  *  Strings remain valid while "self" is valid */
1618 /* Message - message returned by server */
KSrvErrorMessage(const KSrvError * self,String * message)1619 rc_t KSrvErrorMessage ( const KSrvError * self, String * message ) {
1620     String dummy;
1621     if ( message == NULL )
1622         message = & dummy;
1623 
1624     if ( self == NULL )
1625         return RC ( rcVFS, rcQuery, rcExecuting, rcSelf, rcNull );
1626 
1627     * message = self -> message;
1628 
1629     return 0;
1630 }
1631 
1632 
1633 /* Object - Object-Id/Object-Type that produced this Error */
KSrvErrorObject(const KSrvError * self,String * id,EObjectType * type)1634 rc_t KSrvErrorObject ( const KSrvError * self,
1635     String * id, EObjectType * type )
1636 {
1637     if ( self == NULL )
1638         return RC ( rcVFS, rcQuery, rcExecuting, rcSelf, rcNull );
1639 
1640     if ( id != NULL )
1641         * id = self -> objectId;
1642 
1643     if ( type != NULL )
1644         * type = self -> objectType;
1645 
1646     return 0;
1647 }
1648 
1649 
1650 /* EVPath *********************************************************************/
VPathMakeOrNot(VPath ** new_path,const String * src,const String * ticket,const STyped * typed,bool ext,rc_t * rc,bool useDates)1651 static bool VPathMakeOrNot ( VPath ** new_path, const String * src,
1652     const String * ticket, const STyped * typed, bool ext, rc_t * rc,
1653     bool useDates )
1654 {
1655     String bug;
1656     memset ( & bug, 0, sizeof bug );
1657 
1658     assert ( new_path && src && typed && rc );
1659 
1660     if ( * rc != 0 || src -> len == 0 )
1661         return false;
1662     else {
1663         const String * id = & typed -> objectId;
1664         if ( id -> size == 0 )
1665             id = & typed -> accession;
1666 
1667         if ( id -> size == 0 ) {
1668 /* compensate current names.cgi-v3.0 bug: it does not return id for object-id-s
1669  */
1670             if ( src -> size > 0 &&
1671                  isdigit ( src -> addr [ src -> size - 1 ] ) )
1672             {
1673                 size_t s = 2;
1674                 bug . addr = src -> addr + src -> size - 1;
1675                 bug . size = 1;
1676                 for ( s = 2; s <= src -> size
1677                              && isdigit ( src -> addr [ src -> size - s ] );
1678                     ++ s )
1679                 {
1680                     -- bug . addr;
1681                     ++ bug . size;
1682                 }
1683                 bug . len = bug . size;
1684                 id = & bug;
1685             }
1686         }
1687 
1688         if ( src -> size == 0 )
1689             assert ( src -> addr != NULL );
1690 
1691         * rc = VPathMakeFromUrl ( new_path, src, ticket, ext, id,
1692             typed -> osize,
1693             useDates ? typed -> date : 0,
1694             typed -> md5 . has_md5 ? typed -> md5 . md5 : NULL,
1695             useDates ? typed -> expiration : 0, NULL, NULL, NULL,
1696             false, false, NULL, -1, 0, NULL );
1697         if ( * rc == 0 )
1698             VPathMarkHighReliability ( * new_path, true );
1699 
1700         return true;
1701     }
1702 }
1703 
STypedMakeMapping(const STyped * self,const SVersion version,bool isVdbcache,VPath ** mapping)1704 static rc_t STypedMakeMapping(const STyped * self,
1705     const SVersion version, bool isVdbcache, VPath ** mapping)
1706 {
1707     rc_t rc = 0;
1708 
1709     String empty;
1710     String vdbcache;
1711     memset(&empty, 0, sizeof empty);
1712     CONST_STRING(&vdbcache, ".vdbcache");
1713 
1714     assert(self);
1715 
1716     if (SVersionBefore3_0(version)) {
1717         if (self->ticket.size != 0) {
1718             if (self->accession.size != 0)
1719                 rc = VPathMakeFmt(mapping, "ncbi-acc:%S?tic=%S",
1720                     &self->accession, &self->ticket);
1721             else if (self->name.size == 0)
1722                 return 0;
1723             else
1724                 rc = VPathMakeFmt(mapping,
1725                     "ncbi-file:%S?tic=%S", &self->name, &self->ticket);
1726         }
1727         else if (self->accession.size != 0)
1728             rc = VPathMakeFmt(mapping, "ncbi-acc:%S%S", &self->accession,
1729                 isVdbcache ? &vdbcache : &empty);
1730         else if (self->name.size == 0)
1731             return 0;
1732         else
1733             rc = VPathMakeFmt(mapping, "ncbi-file:%S%S", &self->name,
1734                 isVdbcache ? &vdbcache : &empty);
1735     }
1736     else {
1737         if (self->ticket.size != 0) {
1738             if (self->objectId.size != 0 &&
1739                 self->objectType == eOT_sragap)
1740             {
1741                 rc = VPathMakeFmt(mapping, "ncbi-acc:%S%S?tic=%S",
1742                     &self->objectId,
1743                     isVdbcache ? &vdbcache : &empty,
1744                     &self->ticket);
1745             }
1746             else {
1747                 if (self->objectId.size == 0)
1748                     return 0;
1749                 else
1750                     rc = VPathMakeFmt(mapping, "ncbi-file:%S%S?tic=%S",
1751                         &self->objectId,
1752                         isVdbcache ? &vdbcache : &empty,
1753                         &self->ticket);
1754             }
1755         }
1756         else
1757             if (self->objectId.size != 0 && self->objectType == eOT_sragap)
1758                 rc = VPathMakeFmt(mapping, "ncbi-acc:%S%S", &self->objectId,
1759                     isVdbcache ? &vdbcache : &empty);
1760             else {
1761                 if (self->objectId.size == 0)
1762                     return 0;
1763                 else
1764                     rc = VPathMakeFmt(mapping, "ncbi-file:%S%S",
1765                         &self->objectId,
1766                         isVdbcache ? &vdbcache : &empty);
1767             }
1768     }
1769 
1770     return rc;
1771 }
1772 
EVPathInitMapping(EVPath * self,const STyped * src,const SVersion version)1773 static rc_t EVPathInitMapping
1774     ( EVPath * self, const STyped * src, const SVersion  version )
1775 {
1776     rc_t rc = 0;
1777 
1778     const VPath * vsrc = NULL;
1779 
1780     assert ( self && src );
1781 
1782     if ( self -> https == NULL && self -> http == NULL && self -> fasp == NULL )
1783         return 0;
1784 
1785     vsrc = self -> http ? self -> http
1786         : ( self -> https ? self -> https : self -> fasp );
1787     rc = VPathCheckFromNamesCGI ( vsrc, & src -> ticket, -1,
1788         ( const struct VPath ** ) ( & self -> mapping ) );
1789 
1790     if ( rc == 0) {
1791         rc = STypedMakeMapping(src, version, false, &self->mapping);
1792 
1793         if (rc == 0 && (self->vcHttps != NULL || self->vcHttp != NULL ||
1794             self->vcFasp != NULL))
1795         {
1796             rc = STypedMakeMapping(src, version, true, &self->vcMapping);
1797         }
1798 
1799         if ( rc == 0 )
1800             return 0;
1801 
1802         RELEASE ( VPath, self -> http );
1803         RELEASE ( VPath, self -> fasp );
1804     }
1805 
1806     return rc;
1807 }
1808 
1809 
EVPathInit(EVPath * self,const STyped * src,const SRequest * req,rc_t * r,const char * reqId,const char * respId)1810 static rc_t EVPathInit ( EVPath * self, const STyped * src,
1811     const SRequest * req, rc_t * r, const char * reqId, const char * respId )
1812 {
1813     rc_t rc = 0;
1814     bool made = false;
1815     bool logError = sLogNamesServiceErrors;
1816     KLogLevel lvl = klogInt;
1817     assert ( self && src && r );
1818 
1819     switch ( src -> code / 100 ) {
1820       case 0:
1821         rc = RC ( rcVFS, rcQuery, rcResolving, rcMessage, rcCorrupt );
1822         break;
1823 
1824       case 1:
1825         /* informational response
1826            not much we can do here */
1827         rc = RC ( rcVFS, rcQuery, rcResolving, rcError, rcUnexpected );
1828         break;
1829 
1830       case 2:
1831         /* successful response
1832            but can only handle 200 */
1833         if ( src -> code == 200 ) {
1834             bool ext = true;
1835             assert ( req );
1836             if ( req -> serviceType == eSTnames &&
1837                  SVersionNotExtendedVPaths ( req -> version ) )
1838             {
1839                 ext = false;
1840             }
1841 
1842             made |= VPathMakeOrNot ( & self -> http,
1843                 & src -> hUrl , & src -> ticket, src, ext, & rc, true );
1844             made |= VPathMakeOrNot ( & self -> fasp,
1845                 & src -> fpUrl, & src -> ticket, src, ext, & rc, true );
1846             made |= VPathMakeOrNot ( & self -> https,
1847                 & src -> hsUrl, & src -> ticket, src, ext, & rc, true );
1848             made |= VPathMakeOrNot ( & self -> file,
1849                 & src -> flUrl, & src -> ticket, src, ext, & rc, true );
1850             made |= VPathMakeOrNot ( & self -> s3,
1851                 & src -> s3Url, & src -> ticket, src, ext, & rc, true );
1852             VPathMakeOrNot ( & self -> vcHttp,
1853                 & src -> hVdbcacheUrl, & src -> ticket, src, ext, & rc, false );
1854             VPathMakeOrNot ( & self -> vcFasp,
1855                 & src -> fpVdbcacheUrl,& src -> ticket, src, ext, & rc, false );
1856             VPathMakeOrNot ( & self -> vcHttps,
1857                 & src -> hsVdbcacheUrl,& src -> ticket, src, ext, & rc, false );
1858             VPathMakeOrNot ( & self -> vcFile,
1859                 & src -> flVdbcacheUrl,& src -> ticket, src, ext, & rc, false );
1860             VPathMakeOrNot ( & self -> vcS3,
1861                 & src -> s3VdbcacheUrl,& src -> ticket, src, ext, & rc, false );
1862 
1863             if ( rc == 0 )
1864                 rc = EVPathInitMapping ( self, src,  req -> version );
1865 
1866             if ( rc == 0 && reqId != NULL ) {
1867                 self -> reqId = string_dup_measure ( reqId, NULL );
1868                 if ( self -> reqId == NULL )
1869                     rc = RC ( rcVFS, rcQuery, rcResolving,
1870                                      rcMemory, rcExhausted );
1871             }
1872 
1873             if ( rc == 0 && respId != NULL ) {
1874                 self -> respId = string_dup_measure ( respId, NULL );
1875                 if ( self -> respId == NULL )
1876                     rc = RC ( rcVFS, rcQuery, rcResolving,
1877                                      rcMemory, rcExhausted );
1878             }
1879 
1880             if (rc == 0 && self->https != NULL)
1881                 rc = VPathAttachVdbcache(self->https, self->vcHttps);
1882 
1883             self->osize = src->osize;
1884 
1885             return rc;
1886         }
1887         rc = RC ( rcVFS, rcQuery, rcResolving, rcError, rcUnexpected );
1888         break;
1889 
1890       case 3:
1891         /* redirection
1892            currently this is being handled by our request object */
1893         rc = RC ( rcVFS, rcQuery, rcResolving, rcError, rcUnexpected );
1894         break;
1895       case 4:
1896         /* client error */
1897         lvl = klogErr;
1898         switch ( src -> code )
1899         {
1900         case 400:
1901             rc = RC ( rcVFS, rcQuery, rcResolving, rcMessage, rcInvalid );
1902             break;
1903         case 401:
1904         case 403:
1905             rc = RC ( rcVFS, rcQuery, rcResolving, rcQuery, rcUnauthorized );
1906             break;
1907         case 404: /* 404|no data :
1908           If it is a real response then this accession is not found.
1909           What if it is a DB failure? Will be retried if configured to do so? */
1910             rc = RC ( rcVFS, rcQuery, rcResolving, rcName, rcNotFound );
1911 /*          logError = false; */
1912             break;
1913         case 410:
1914             rc = RC ( rcVFS, rcQuery, rcResolving, rcName, rcNotFound );
1915             break;
1916         default:
1917             rc = RC ( rcVFS, rcQuery, rcResolving, rcError, rcUnexpected );
1918         }
1919         break;
1920       case 5:
1921         /* server error */
1922         lvl = klogSys;
1923         switch ( src -> code )
1924         {
1925         case 503:
1926             rc = RC ( rcVFS, rcQuery, rcResolving, rcDatabase, rcNotAvailable );
1927             break;
1928         case 504:
1929             rc = RC ( rcVFS, rcQuery, rcResolving, rcTimeout, rcExhausted );
1930             break;
1931         default:
1932             rc = RC ( rcVFS, rcQuery, rcResolving, rcError, rcUnexpected );
1933         }
1934         break;
1935       default:
1936         rc = RC ( rcVFS, rcQuery, rcResolving, rcError, rcUnexpected );
1937     }
1938 
1939     /* log message to user */
1940     if ( req -> errorsToIgnore == 0 && logError ) {
1941         if ( src -> objectId . size > 0 )
1942             PLOGERR ( lvl, ( lvl, rc,
1943                 "failed to resolve accession '$(acc)' - $(msg) ( $(code) )",
1944                 "acc=%S,msg=%S,code=%u",
1945                 & src -> objectId, & src -> message, src -> code ) );
1946         else
1947             PLOGERR ( lvl, ( lvl, rc,
1948                 "failed to resolve accession '$(acc)' - $(msg) ( $(code) )",
1949                 "acc=%s,msg=%S,code=%u",
1950                 reqId, & src -> message, src -> code ) );
1951     }
1952     else
1953         -- ( ( SRequest * ) req ) -> errorsToIgnore;
1954 
1955     {
1956         KSrvError * e = NULL;
1957         rc_t r = KSrvErrorMake(&e, src, rc);
1958         if (r == 0)
1959             self->error = e;
1960         return r;
1961     }
1962 }
1963 
1964 
EVPathFini(EVPath * self)1965 static rc_t EVPathFini ( EVPath * self ) {
1966     rc_t rc = 0;
1967 
1968     assert ( self );
1969 
1970     RELEASE ( VPath, self -> mapping );
1971     RELEASE ( VPath, self ->vcMapping);
1972     RELEASE ( VPath, self ->   http  );
1973     RELEASE ( VPath, self ->   fasp  );
1974     RELEASE ( VPath, self ->   https );
1975     RELEASE ( VPath, self ->   file  );
1976     RELEASE ( VPath, self ->   s3    );
1977     RELEASE ( VPath, self -> vcHttp  );
1978     RELEASE ( VPath, self -> vcFasp  );
1979     RELEASE ( VPath, self -> vcHttps );
1980     RELEASE ( VPath, self -> vcFile  );
1981     RELEASE ( VPath, self -> vcS3    );
1982 
1983     RELEASE ( KSrvError, self -> error );
1984 
1985     free ( self -> reqId  );    self -> reqId  = NULL;
1986     free ( self -> respId );    self -> respId = NULL;
1987 
1988     return rc;
1989 }
1990 
1991 
1992 /* SRow ***********************************************************************/
SRowWhack(void * p)1993 static rc_t SRowWhack ( void * p ) {
1994     rc_t rc = 0;
1995     rc_t r2 = 0;
1996     if ( p != NULL ) {
1997         SRow * self = ( SRow * ) p;
1998         r2 = EVPathFini ( & self -> path );
1999         if ( rc == 0) {
2000             rc = r2;
2001         }
2002         r2 = SRawFini ( & self -> raw );
2003         if ( rc == 0) {
2004             rc = r2;
2005         }
2006 
2007         free ( self -> reqId );
2008 
2009         memset ( self, 0, sizeof * self );
2010         free ( self );
2011     }
2012     return rc;
2013 }
2014 
2015 
SRowMake(SRow ** self,const String * src,const SRequest * req,const SConverters * f,const SVersion version)2016 static rc_t SRowMake ( SRow ** self, const String * src, const SRequest * req,
2017     const SConverters * f, const SVersion  version )
2018 {
2019     rc_t rc = 0;
2020     rc_t r2 = 0;
2021 
2022     SRow * p = ( SRow * ) calloc ( 1, sizeof * p );
2023     if ( p == NULL )
2024         return RC ( rcVFS, rcQuery, rcExecuting, rcMemory, rcExhausted );
2025 
2026     assert ( req && src );
2027 
2028     rc = SRawAlloc ( & p -> raw, src -> addr, src -> size );
2029     if ( rc == 0 ) {
2030         assert ( f );
2031         rc = SOrderedInit ( & p -> ordered, & p -> raw, f -> n );
2032     }
2033     if ( rc == 0 ) {
2034         rc = STypedInit ( & p -> typed, & p -> ordered, f, version );
2035     }
2036     if ( rc == 0 /* && p -> typed . code == 200 */ ) {
2037         String acc;
2038         if ( req -> request . objects == 1 ) {
2039 			size_t s = 0;
2040             uint32_t l = string_measure
2041                 ( req -> request . object [ 0 ] . objectId, &s );
2042             StringInit ( & acc,
2043                         req -> request . object [ 0 ] . objectId, s, l );
2044             assert ( acc . size == 0 || acc . addr != NULL );
2045             if ( acc . size > 2 && acc . addr [1] == 'R'
2046                                 && acc . addr [2] == 'R' )
2047             {
2048                 if (SVersionUseObjidAsAcc ( version ) ) {
2049                     if  ( ! StringEqual ( & p -> typed . objectId , & acc ) )
2050                         return RC ( rcVFS, rcQuery, rcResolving,
2051                                     rcMessage, rcCorrupt );
2052                 }
2053                 else if ( ! StringEqual ( & p -> typed . accession, & acc ) )
2054                     return     RC ( rcVFS, rcQuery, rcResolving,
2055                                     rcMessage, rcCorrupt );
2056             }
2057             p -> reqId = string_dup
2058                 ( req -> request . object [ 0 ] . objectId, l );
2059             if ( p -> reqId == NULL )
2060                 return RC ( rcVFS, rcQuery, rcExecuting,
2061                                     rcMemory, rcExhausted );
2062         }
2063         else {
2064             uint32_t i = 0;
2065             for ( i = 0; i < req -> request . objects; ++ i )
2066                 if ( req -> request . object [ i ] . ordId ==
2067                      p -> typed . ordId )
2068                 {
2069 					size_t s = 0;
2070 					uint32_t l = string_measure
2071                         ( req -> request . object [ i ] . objectId, &s );
2072                     StringInit ( & acc,
2073                         req -> request . object [ i ] . objectId, s, l );
2074                     assert ( acc . size == 0 || acc . addr != NULL );
2075                     p -> reqId = string_dup
2076                         ( req -> request . object [ i ] . objectId, l );
2077                     if ( p -> reqId == NULL )
2078                         return RC ( rcVFS, rcQuery, rcExecuting,
2079                                            rcMemory, rcExhausted );
2080                     break;
2081                 }
2082         }
2083     }
2084     if ( rc == 0 ) {
2085         String * s = SVersionUseObjidAsAcc ( version )
2086             ? & p -> typed . objectId : & p -> typed . accession;
2087         char * acc = string_dup ( s -> addr, s -> size );
2088         if ( s -> size != 0 && acc == NULL )
2089             return RC ( rcVFS, rcQuery, rcResolving, rcMemory, rcExhausted );
2090         rc = EVPathInit ( & p -> path, & p -> typed, req, & r2, p -> reqId,
2091                                                                 acc );
2092         if ( rc == 0 )
2093             rc = r2;
2094         free ( acc );
2095     }
2096 
2097 /* compare ticket
2098        currently this makes sense with 1 request from a known workspace *
2099     if ( download_ticket . size != 0 )
2100     {
2101         if ( ticket == NULL || ! StringEqual ( & download_ticket, ticket ) )
2102             return RC ( rcVFS, rcQuery, rcResolving, rcMessage, rcCorrupt );
2103     }
2104 */
2105 
2106     if ( rc == 0 )
2107         rc = VPathSetMake ( & p -> set, & p -> path,
2108                             SVersionSingleUrl ( version ) );
2109     if ( rc == 0 ) {
2110         assert ( self );
2111         * self = p;
2112     }
2113     else
2114         SRowWhack ( p );
2115 
2116     return rc;
2117 }
2118 
2119 
whackSRow(void * self,void * ignore)2120 static void whackSRow ( void * self, void * ignore ) {
2121     SRowWhack ( self);
2122 }
2123 
2124 
2125 /* STimestamp ****************************************************************/
STimestampInit(STimestamp * self,const String * src)2126 static rc_t STimestampInit ( STimestamp * self, const String * src ) {
2127     rc_t rc = 0;
2128 
2129     assert ( self && src );
2130 
2131     rc = SRawAlloc ( & self -> raw, src -> addr, src -> size );
2132 
2133     if ( rc == 0 )
2134         rc = KTimeInit ( & self -> time, src );
2135 
2136     return rc;
2137 }
2138 
2139 
STimestampInitCurrent(STimestamp * self)2140 static rc_t STimestampInitCurrent ( STimestamp * self ) {
2141     assert ( self );
2142 
2143     self -> time = KTimeStamp ();
2144 
2145     if ( self -> time != 0 ) {
2146         const size_t s = 32;
2147         self -> raw . s = (char *) calloc ( 1, s );
2148         if ( self -> raw . s == NULL )
2149             return RC ( rcVFS, rcQuery, rcExecuting, rcMemory, rcExhausted );
2150         else {
2151             size_t sz = KTimeIso8601 ( self -> time, self -> raw . s, s );
2152             if ( sz == 0 )
2153                 return RC ( rcVFS, rcQuery, rcExecuting, rcMemory,
2154                     rcInsufficient );
2155             else
2156                 return 0;
2157         }
2158     }
2159     else
2160         return RC ( rcVFS, rcQuery, rcExecuting, rcItem, rcIncorrect );
2161 }
2162 
2163 
STimestampFini(STimestamp * self)2164 static rc_t STimestampFini ( STimestamp * self ) {
2165     rc_t rc = 0;
2166 
2167     assert ( self );
2168 
2169     rc = SRawFini ( & self -> raw );
2170 
2171     memset ( self, 0, sizeof * self );
2172 
2173     return rc;
2174 }
2175 
2176 
2177 /* SServerTimestamp************************************************************/
2178 static
SServerTimestampInit(SServerTimestamp * self,const String * src)2179 rc_t SServerTimestampInit ( SServerTimestamp * self,
2180                             const String * src )
2181 {
2182     rc_t rc = 0;
2183     rc_t r2 = 0;
2184 
2185     assert ( self );
2186 
2187     rc = STimestampInit ( & self -> server, src );
2188 
2189     r2 = STimestampInitCurrent ( & self -> local );
2190     if ( rc == 0 )
2191         rc = r2;
2192 
2193     return rc;
2194 }
2195 
2196 
SServerTimestampFini(SServerTimestamp * self)2197 static rc_t SServerTimestampFini ( SServerTimestamp * self ) {
2198     rc_t rc = 0;
2199     rc_t r2 = 0;
2200 
2201     assert ( self );
2202     rc = STimestampFini ( & self ->server );
2203 
2204     r2 = STimestampFini ( & self ->local );
2205     if ( rc == 0 )
2206         rc = r2;
2207 
2208     return rc;
2209 }
2210 
2211 
2212 /* SResponse ******************************************************************/
SResponseInit(SResponse * self,rc_t aRc)2213 static rc_t SResponseInit ( SResponse * self, rc_t aRc ) {
2214     rc_t rc = 0;
2215 
2216     assert ( self );
2217 
2218     VectorInit ( & self -> rows, 0, 5 );
2219 
2220     rc = KSrvResponseMake ( & self -> list );
2221 
2222     self->rc = aRc;
2223 
2224     return rc;
2225 }
2226 
2227 
whackKartItem(void * self,void * ignore)2228 static void whackKartItem ( void * self, void * ignore ) {
2229     KartItemRelease ( ( KartItem * ) self);
2230 }
2231 
2232 
SResponseFini(SResponse * self)2233 static rc_t SResponseFini ( SResponse * self ) {
2234     rc_t rc = 0;
2235     rc_t r2 = 0;
2236 
2237     assert ( self );
2238 
2239     {
2240         void ( CC * whack ) ( void *item, void *data ) = NULL;
2241         if ( self -> serviceType == eSTsearch )
2242             whack = whackKartItem;
2243         else
2244             whack = whackSRow;
2245         assert ( whack );
2246         VectorWhack ( & self -> rows, whack, NULL );
2247     }
2248 
2249     rc = SHeaderFini ( & self -> header );
2250 
2251     r2 = KSrvResponseRelease ( self -> list );
2252     if ( r2 != 0 && rc == 0 )
2253         rc = r2;
2254 
2255     r2 = KartRelease ( self -> kart );
2256     if ( r2 != 0 && rc == 0 )
2257         rc = r2;
2258 
2259     r2 = SServerTimestampFini ( & self -> timestamp );
2260     if ( r2 != 0 && rc == 0 )
2261         rc = r2;
2262 
2263     memset ( self, 0, sizeof * self );
2264 
2265     return rc;
2266 }
2267 
2268 
SResponseGetResponse(const SResponse * self,const KSrvResponse ** response)2269 static rc_t SResponseGetResponse
2270     ( const SResponse * self, const KSrvResponse ** response )
2271 {
2272     rc_t rc = 0;
2273     assert ( self );
2274     rc = KSrvResponseAddRef ( self -> list );
2275     if ( rc == 0 ) {
2276         * response = self -> list;
2277     }
2278     return rc;
2279 }
2280 
2281 
2282 /* SKV ************************************************************************/
2283 static
SKVMake(const SKV ** self,const char * k,const char * v)2284 rc_t SKVMake ( const SKV ** self, const char * k, const char * v )
2285 {
2286     assert ( self );
2287     * self = NULL;
2288     if ( k == NULL || * k == '\0' ) {
2289         return RC ( rcVFS, rcQuery, rcExecuting, rcParam, rcNull );
2290     }
2291     else {
2292         rc_t rc = 0;
2293         size_t num_writ = 0;
2294         size_t sk = string_size ( k );
2295         size_t sv = string_size ( v );
2296         size_t s  = sk + sv + 2;
2297         char * p = ( char * ) malloc ( s );
2298         if ( p == NULL ) {
2299             return RC ( rcVFS, rcQuery, rcExecuting, rcMemory, rcExhausted );
2300         }
2301         rc = string_printf ( p, s, & num_writ, "%s=%s", k, v );
2302         assert ( num_writ <= s );
2303         if ( rc != 0 ) {
2304             free ( p );
2305             p = NULL;
2306         }
2307         else {
2308             SKV * kv = ( SKV * ) malloc ( sizeof * kv );
2309             assert ( sk );
2310             if ( kv == NULL ) {
2311                 free ( p );
2312                 p = NULL;
2313                 rc = RC ( rcVFS, rcQuery, rcExecuting, rcMemory, rcExhausted );
2314             }
2315             else {
2316                 StringInit ( & kv -> k, p, sk, sk );
2317                 StringInit ( & kv -> v, p + sk + 1, sv, sv );
2318                 rc = string_printf(kv ->n, sizeof kv->n, &num_writ, "%s", k);
2319                 * self = kv;
2320             }
2321         }
2322         return rc;
2323     }
2324 }
2325 
2326 
2327 static
SKVMakeObj(const SKV ** self,const SObject * obj,const SVersion version)2328 rc_t SKVMakeObj ( const SKV ** self, const SObject * obj,
2329     const SVersion  version )
2330 {
2331     rc_t rc = 0;
2332     size_t sk = 0;
2333     size_t num_writ = 0;
2334     char tmp [] = "";
2335     bool old = SVersionAccInRequest ( version );
2336     char * p = NULL;
2337     const char * k = "object";
2338     if ( old )
2339         k = "acc";
2340 
2341     sk = string_size ( k );
2342 
2343     assert ( self && obj );
2344     * self = NULL;
2345 
2346     if ( old )
2347         rc = string_printf ( tmp, 1, & num_writ, "%s=%s", k,
2348             obj -> objectId );
2349     else
2350         string_printf ( tmp, 1, & num_writ, "%s=%d|%s|%s", k, obj -> ordId,
2351             ObjectTypeToString ( obj -> objectType ), obj -> objectId );
2352 
2353     ++ num_writ;
2354     p = ( char * ) malloc ( num_writ );
2355     if ( p == NULL )
2356         return RC ( rcVFS, rcQuery, rcExecuting, rcMemory, rcExhausted );
2357 
2358     if ( old )
2359         rc = string_printf ( p, num_writ, & num_writ, "%s=%s", k,
2360             obj -> objectId );
2361     else
2362         rc = string_printf ( p, num_writ, & num_writ, "%s=%d|%s|%s", k,
2363             obj -> ordId, ObjectTypeToString ( obj -> objectType ),
2364             obj -> objectId );
2365 
2366     if ( rc != 0 ) {
2367         free ( p );
2368         p = NULL;
2369     }
2370     else {
2371         SKV * kv = ( SKV * ) malloc ( sizeof * kv );
2372         assert ( sk );
2373         if ( kv == NULL ) {
2374             free ( p );
2375             p = NULL;
2376             rc = RC ( rcVFS, rcQuery, rcExecuting, rcMemory, rcExhausted );
2377         }
2378         else {
2379             -- num_writ;
2380             StringInit ( & kv -> k, p, sk, sk );
2381             StringInit ( & kv -> v, p + sk + 1, num_writ, num_writ );
2382             * self = kv;
2383         }
2384     }
2385 
2386     return rc;
2387 }
2388 
2389 
2390 /* SHttpRequestHelper ********************************************************/
SHttpRequestHelperInit(SHttpRequestHelper * self,const KNSManager * kMgr,const char * cgi)2391 static rc_t SHttpRequestHelperInit ( SHttpRequestHelper * self,
2392     const KNSManager * kMgr, const char * cgi )
2393 {
2394     rc_t rc = 0;
2395 
2396     assert ( self );
2397 
2398     memset ( self, 0, sizeof * self );
2399 
2400     rc = KNSManagerMakeReliableClientRequest ( kMgr, & self -> httpReq,
2401         0x01010000, NULL, cgi );
2402 
2403     return rc;
2404 }
2405 
2406 
SHttpRequestHelperFini(SHttpRequestHelper * self)2407 static rc_t SHttpRequestHelperFini ( SHttpRequestHelper * self ) {
2408     rc_t rc = 0;
2409 
2410     assert ( self );
2411 
2412     RELEASE ( KHttpRequest, self -> httpReq );
2413 
2414     return rc;
2415 }
2416 
2417 
2418 static
SHttpRequestHelperAddPostParam(void * item,void * data)2419 void SHttpRequestHelperAddPostParam ( void * item, void * data )
2420 {
2421     const SKV          * kv = ( SKV                * ) item;
2422     SHttpRequestHelper * p  = ( SHttpRequestHelper * ) data;
2423 
2424     rc_t rc = 0;
2425 
2426     assert ( kv && p );
2427 
2428     rc = KHttpRequestAddPostParam ( p -> httpReq, "%s", kv -> k . addr );
2429     if ( p -> rc == 0 )
2430         p -> rc = rc;
2431 }
2432 
2433 static
SHttpRequestHelperAddQueryParam(void * item,void * data)2434 void SHttpRequestHelperAddQueryParam(void * item, void * data)
2435 {
2436     const SKV          * kv = (SKV                *)item;
2437     SHttpRequestHelper * p = (SHttpRequestHelper *)data;
2438 
2439     rc_t rc = 0;
2440 
2441     assert(kv && p);
2442 
2443     rc = KClientHttpRequestAddQueryParam(p->httpReq, kv->n, "%S", &kv->v);
2444     if (p->rc == 0)
2445         p->rc = rc;
2446 }
2447 
2448 
2449 /* SCgiRequest ****************************************************************/
2450 static
SCgiRequestInitCgi(SCgiRequest * self,const char * cgi)2451 rc_t SCgiRequestInitCgi ( SCgiRequest * self, const char * cgi )
2452 {
2453     assert ( self && ! self -> cgi );
2454 
2455     self -> cgi = string_dup_measure ( cgi, NULL );
2456     if ( self -> cgi == NULL )
2457         return RC ( rcVFS, rcQuery, rcExecuting, rcParam, rcNull );
2458 
2459     return 0;
2460 }
2461 
2462 
whackSKV(void * p,void * ignore)2463 static void whackSKV ( void * p, void * ignore ) {
2464     SKV * self = ( SKV * ) p;
2465     assert ( self );
2466     free ( ( void * ) self -> k . addr );
2467     memset ( self, 0, sizeof * self );
2468     free ( self );
2469 }
2470 
2471 
SCgiRequestFini(SCgiRequest * self)2472 static void SCgiRequestFini ( SCgiRequest * self ) {
2473     assert ( self );
2474     free ( self -> cgi );
2475     VectorWhack ( & self -> params, whackSKV, NULL );
2476     memset ( self, 0, sizeof * self );
2477 }
2478 
2479 static
SRequestResponseFromEnv(const SRequest * self,KStream ** stream)2480 bool SRequestResponseFromEnv(const SRequest * self, KStream ** stream)
2481 {
2482     const char * name = NULL;
2483     const char * e = NULL;
2484 
2485     assert(self);
2486 
2487     if (!self->sdl)
2488         return false;
2489 
2490     if (self->request.objects == 1)
2491         name = self->request.object->objectId;
2492     else
2493         name = self->jwtKartFile == NULL ? NULL : self->jwtKartFile->addr;
2494 
2495 
2496     if (name == NULL)
2497         return false;
2498 
2499     e = getenv(name);
2500     if ( e != NULL ) {
2501         KDirectory * dir = NULL;
2502         const KFile * f = NULL;
2503         uint64_t size = 0;
2504         static char b[20000] = ""; /* static for KStreamMakeFromBuffer */
2505         size_t num_read = string_size(e);
2506         char * buffer = b;
2507 
2508         rc_t rc = KDirectoryNativeDir(&dir);
2509 
2510         if (rc == 0)
2511             rc = KDirectoryOpenFileRead(dir, &f, "%s", e);
2512 
2513         if (rc == 0)
2514             rc = KFileSize(f, &size);
2515 
2516         if (rc == 0 && size > sizeof b) {
2517             buffer = calloc(1, size); /* leak */
2518             if (buffer == NULL)
2519                 rc = RC(rcVFS, rcStorage, rcAllocating, rcMemory, rcExhausted);
2520         }
2521 
2522         if (rc == 0)
2523             rc = KFileRead(f, 0, buffer, size, &num_read);
2524 
2525         if (rc == 0) {
2526             DBGMSG(DBG_VFS, DBG_FLAG(DBG_VFS_SERVICE), (
2527               "XXXXX NOT sending HTTP POST request; env file -> resp  XXXX\n"));
2528             e = buffer;
2529         }
2530         else
2531             DBGMSG(DBG_VFS, DBG_FLAG(DBG_VFS_SERVICE), (
2532               "XXXXX NOT sending HTTP POST request; get resp from env XXXX\n"));
2533 
2534         RELEASE(KFile, f);
2535         RELEASE(KDirectory, dir);
2536 
2537         return KStreamMakeFromBuffer ( stream, e, num_read ) == 0;
2538     }
2539 
2540     return false;
2541 }
2542 
SCgiRequestPerform(const SCgiRequest * self,const SHelper * helper,KStream ** stream,const char * expected,KService * service)2543 static rc_t SCgiRequestPerform ( const SCgiRequest * self,
2544     const SHelper * helper, KStream ** stream,
2545     const char * expected, KService * service)
2546 {
2547     rc_t rc = 0, rx = 0;
2548 
2549     assert ( self && helper && stream && service);
2550 
2551     if ( rc == 0 ) {
2552         if ( SRequestResponseFromEnv ( & service -> req, stream ) )
2553             ; /* got response from environment; request was not sent */
2554         else if ( expected == NULL ) {
2555             SHttpRequestHelper h;
2556             rc = SHttpRequestHelperInit(&h, helper->kMgr, self->cgi);
2557 
2558             if (rc == 0) {
2559                 if (self->fileKey != NULL && self->fileVal != NULL) {
2560                     rc = KClientHttpRequestAddPostFileParam(h.httpReq,
2561                         self->fileKey, self->fileVal);
2562                     if (rc == 0) {
2563                         VectorForEach(&self->params, false,
2564                             SHttpRequestHelperAddQueryParam, &h);
2565                         rc = h.rc;
2566                     }
2567                 }
2568                 else {
2569                     VectorForEach(&self->params, false,
2570                         SHttpRequestHelperAddPostParam, &h);
2571                     rc = h.rc;
2572                 }
2573             }
2574 
2575             if (rc == 0) {
2576                 KHttpResult * rslt = NULL;
2577                 DBGMSG ( DBG_VFS, DBG_FLAG ( DBG_VFS_SERVICE ), (
2578             ">>>>>>>>>>>>>>>> sending HTTP POST request >>>>>>>>>>>>>>>>\n" ) );
2579                 rc = KHttpRequestPOST ( h . httpReq, & rslt );
2580                 if ( rc == 0 ) {
2581                     uint32_t code = 0;
2582                     rc = KHttpResultStatus ( rslt, & code, NULL, 0, NULL );
2583                     if ( rc == 0 ) {
2584                         DBGMSG ( DBG_VFS, DBG_FLAG ( DBG_VFS_SERVICE ), (
2585                             "  code=%d\n", code ) );
2586                         switch ( code ) {
2587                           case 200:
2588                             break;
2589                           case 403:
2590                      /* HTTP/1.1 403 Forbidden
2591                       - resolver CGI was called over http insted of https */
2592                             rx = RC ( rcVFS, rcQuery, rcExecuting,
2593                                              rcConnection, rcUnauthorized );
2594                             break;
2595                           case 404:
2596                     /* HTTP/1.1 404 Bad Request - resolver CGI was not found */
2597                             rx = RC ( rcVFS, rcQuery, rcExecuting,
2598                                              rcConnection, rcNotFound );
2599                             break;
2600                           default: /* Something completely unexpected */
2601                             rx = RC ( rcVFS, rcQuery, rcExecuting,
2602                                              rcConnection, rcUnexpected );
2603                             break;
2604                         }
2605                         if (rx != 0) {
2606                             if (SVersionResponseInJson(service->req.version,
2607                                 service->req.sdl))
2608                             {
2609                                 service->resp.rc = rx;
2610                                 rc = KHttpResultGetInputStream(rslt, stream);
2611                             }
2612                             else {
2613                                 rc = rx;
2614                                 if ( stream != NULL )
2615                                     RELEASE(KStream, *stream);
2616                             }
2617                         }
2618                         else
2619                             rc = KHttpResultGetInputStream(rslt, stream);
2620                     }
2621                 }
2622                 RELEASE ( KHttpResult, rslt );
2623             }
2624             {
2625                 rc_t r2 = SHttpRequestHelperFini(&h);
2626                 if (rc == 0)
2627                     rc = r2;
2628             }
2629         }
2630         else {
2631             KStream * strm = NULL;
2632             DBGMSG ( DBG_VFS, DBG_FLAG ( DBG_VFS_SERVICE ), (
2633         "XXXXXXXXXXXX NOT sending HTTP POST request XXXXXXXXXXXXXXXX\n" ) );
2634             rc = KStreamMakeFromBuffer ( &strm, expected,
2635                                         string_size ( expected ) );
2636             if ( rc == 0 )
2637                 * stream = strm;
2638         }
2639     }
2640 
2641     return rc;
2642 }
2643 
2644 
2645 /* SObject ********************************************************************/
SObjectInit(SObject * self,const char * objectId,size_t objSz,EObjectType objectType)2646 static rc_t SObjectInit ( SObject * self,
2647     const char * objectId, size_t objSz, EObjectType objectType )
2648 {
2649     assert ( self );
2650     self -> objectType = objectType;
2651     if ( objectId != NULL && objSz != 0 ) {
2652         self -> objectId = string_dup ( objectId, objSz );
2653         if ( self -> objectId == NULL ) {
2654             return RC ( rcVFS, rcQuery, rcExecuting, rcMemory, rcExhausted );
2655         }
2656     }
2657     return 0;
2658 }
2659 
2660 
SObjectFini(SObject * self)2661 static void SObjectFini ( SObject * self ) {
2662     assert ( self );
2663     free ( self -> objectId );
2664     memset ( self, 0, sizeof * self );
2665 }
2666 
2667 
2668 /* SRequestData ***************************************************************/
SRequestDataInit(SRequestData * self)2669 static rc_t SRequestDataInit ( SRequestData * self ) {
2670     assert ( self );
2671     memset ( self, 0, sizeof * self );
2672 
2673     self -> allocated = 512;
2674 
2675     self->object = (SObject *)calloc(self->allocated, sizeof * self->object);
2676     if ( self -> object == NULL )
2677         return RC ( rcVFS, rcQuery, rcExecuting, rcMemory, rcExhausted );
2678 
2679     return 0;
2680 }
2681 
2682 
SRequestDataFini(SRequestData * self)2683 static void SRequestDataFini ( SRequestData * self ) {
2684     uint32_t i = 0;
2685 
2686     assert ( self );
2687 
2688     for ( i = 0; i < self -> objects; ++i )
2689         SObjectFini ( & self -> object [ i ] );
2690 
2691     free ( self -> object );
2692 
2693     memset ( self, 0, sizeof * self );
2694 }
2695 
2696 
2697 static
SRequestDataAppendObject(SRequestData * self,const char * id,size_t id_sz,EObjectType objectType)2698 rc_t SRequestDataAppendObject ( SRequestData * self, const char * id,
2699     size_t id_sz, EObjectType objectType )
2700 {
2701     rc_t rc = 0;
2702 
2703     VResolverAppID app = appUnknown;
2704 
2705     String accession;
2706 
2707     assert ( self );
2708 
2709     if ( self -> objects > self -> allocated - 1 ) {
2710         size_t n = self -> allocated * 2;
2711         void * t = realloc ( self -> object, n * sizeof * self -> object );
2712         if ( t == NULL )
2713             return RC ( rcVFS, rcQuery, rcExecuting, rcItem, rcExcessive );
2714         else {
2715             self -> object = (SObject *) t;
2716             self -> allocated = n;
2717         }
2718     }
2719 
2720     if ( id == NULL )
2721         return RC ( rcVFS, rcQuery, rcExecuting, rcParam, rcNull );
2722     if ( id [ 0 ] == '\0' )
2723         return RC ( rcVFS, rcQuery, rcExecuting, rcParam, rcEmpty );
2724 
2725     if ( id_sz == 0 )
2726         id_sz = string_measure ( id, NULL );
2727 
2728     StringInitCString(&accession, id);
2729     app = get_accession_app(&accession, false, NULL, NULL, false, NULL,
2730         NULL, -1);
2731     if (self->objects == 0)
2732         self->app = app;
2733     else if (self->app != app && (self->app == appSRA || app == appSRA))
2734         self->appRc = RC(rcVFS, rcQuery, rcExecuting, rcItem, rcInconsistent);
2735 
2736     rc = SObjectInit ( & self -> object [ self -> objects ],
2737                        id, id_sz, objectType );
2738 
2739     if ( rc == 0 ) {
2740         self -> object [ self -> objects ] . ordId = self -> objects;
2741         ++ self -> objects;
2742     }
2743 
2744     return rc;
2745 }
2746 
2747 
2748 /* BSTItem ********************************************************************/
BSTItemCmp(const void * item,const BSTNode * n)2749 static int64_t CC BSTItemCmp ( const void * item, const BSTNode * n ) {
2750     const String * s = (String *) item;
2751     const BSTItem * i = ( BSTItem * ) n;
2752 
2753     assert ( s && i );
2754 
2755     return string_cmp ( s -> addr, s -> size,
2756         i -> ticket, string_measure ( i -> ticket, NULL ), s -> len );
2757 }
2758 
2759 static
BSTreeSort(const BSTNode * item,const BSTNode * n)2760 int64_t CC BSTreeSort ( const BSTNode * item, const BSTNode * n )
2761 {
2762     const BSTItem * i = ( BSTItem * ) item;
2763     String str;
2764     size_t size = 0;
2765     uint32_t len = string_measure ( i -> ticket, & size );
2766     StringInit ( & str, i -> ticket, size, len );
2767     return BSTItemCmp ( & str, n );
2768 }
2769 
BSTItemWhack(BSTNode * n,void * ignore)2770 static void BSTItemWhack ( BSTNode * n, void * ignore ) {
2771     BSTItem * i = ( BSTItem * ) n;
2772     assert ( i );
2773     free ( i -> ticket );
2774     memset ( i, 0, sizeof * i );
2775     free ( i );
2776 }
2777 
2778 /* STickets *******************************************************************/
2779 const uint64_t BICKETS = 1024;
STicketsAppend(STickets * self,uint32_t project,const char * ticket)2780 static rc_t STicketsAppend ( STickets * self, uint32_t project,
2781                              const char * ticket )
2782 {
2783     rc_t rc = 0;
2784 
2785     const char * comma = "";
2786 
2787     assert ( self );
2788 
2789     if ( ticket == NULL )
2790         return 0;
2791 
2792     /* && project>0: dbGaP projectId can be 0*/
2793     if ( rc == 0 && ticket [ 0 ] != '\0' ) {
2794         BSTItem * i = NULL;
2795 
2796         String str;
2797         size_t size = 0;
2798         uint32_t len = string_measure ( ticket, & size );
2799         StringInit ( & str, ticket, size, len );
2800 
2801         i = ( BSTItem * ) BSTreeFind
2802             ( & self -> ticketsToProjects, & str, BSTItemCmp );
2803         if ( i != NULL )
2804             return 0;
2805 
2806         i = (BSTItem *) calloc ( 1, sizeof * i );
2807         if ( i != NULL )
2808             i -> ticket = string_dup_measure ( ticket, NULL );
2809         if ( i == NULL || i -> ticket == NULL ) {
2810             free ( i );
2811             return RC ( rcVFS, rcStorage, rcAllocating, rcMemory, rcExhausted );
2812         }
2813 
2814         i -> project = project;
2815 
2816         rc = BSTreeInsert ( & self -> ticketsToProjects, ( BSTNode * ) i,
2817                             BSTreeSort );
2818     }
2819 
2820     if ( self -> size > 0 )
2821         comma = ",";
2822 
2823     do {
2824         size_t num_writ = 0;
2825         char * p = ( char * ) self -> str . base;
2826         assert ( comma );
2827         rc = string_printf ( p + self -> size,
2828             ( size_t ) self -> str . elem_count - self -> size, & num_writ,
2829             "%s%s", comma, ticket );
2830         if ( rc == 0 ) {
2831             rc_t r2 = 0;
2832             String * s = ( String * ) malloc ( sizeof * s );
2833             if ( s == NULL )
2834                 rc = RC ( rcVFS, rcQuery, rcExecuting, rcMemory, rcExhausted );
2835             else {
2836                 const char * addr = p + self -> size;
2837                 uint32_t len = num_writ;
2838                 if ( comma [ 0 ] != '\0' ) {
2839                     ++ addr;
2840                     -- len;
2841                 }
2842                 StringInit ( s, addr, len, len );
2843                 r2 = VectorAppend ( & self -> tickets, NULL, s );
2844                 if ( r2 != 0 ) {
2845                     rc = r2;
2846                     free ( s );
2847                 }
2848                 self -> size += num_writ;
2849                 break;
2850             }
2851         }
2852         else if ( GetRCState ( rc ) == rcInsufficient
2853             && GetRCObject ( rc ) == ( enum RCObject ) rcBuffer )
2854         {
2855             size_t needed = ( size_t ) BICKETS;
2856             if ( self -> str . elem_count - self -> size + needed < num_writ )
2857                 needed = num_writ;
2858             rc = KDataBufferResize
2859                 ( & self -> str, self -> str . elem_count + needed );
2860         }
2861         else
2862             break;
2863     } while ( rc == 0 );
2864 
2865     return rc;
2866 }
2867 
2868 
STicketsInit(STickets * self)2869 static rc_t STicketsInit ( STickets * self ) {
2870     assert ( self );
2871     memset ( self, 0, sizeof * self );
2872     BSTreeInit ( & self -> ticketsToProjects );
2873     return KDataBufferMakeBytes ( & self -> str, BICKETS );
2874 }
2875 
2876 
whack_free(void * self,void * ignore)2877 static void whack_free ( void * self, void * ignore ) {
2878     if ( self != NULL ) {
2879         memset ( self, 0, sizeof ( * ( char * ) self ) );
2880         free ( self );
2881     }
2882 }
2883 
STicketsFini(STickets * self)2884 static rc_t STicketsFini ( STickets * self ) {
2885     rc_t rc = 0;
2886 
2887     assert ( self );
2888 
2889     rc = KDataBufferWhack ( & self -> str );
2890     VectorWhack ( & self -> tickets, whack_free, NULL );
2891     BSTreeWhack ( & self -> ticketsToProjects, BSTItemWhack, NULL );
2892 
2893     memset ( self, 0 , sizeof * self );
2894 
2895     return rc;
2896 }
2897 
2898 
2899 /* Tickets ********************************************************************/
2900 typedef struct {
2901     Vector * v;
2902     const STickets * r;
2903     rc_t   rc;
2904 } Tickets;
2905 
2906 
TicketsDoAppendTicket(void * item,void * data)2907 static rc_t TicketsDoAppendTicket ( void * item, void * data ) {
2908     const String * ticket = ( String * ) item;
2909     Tickets * t = (Tickets * ) data;
2910     const STickets * r = NULL;
2911     Vector * v = NULL;
2912     const SKV * kv = NULL;
2913     const char * k = "tic";
2914     char * c = string_dup ( ticket -> addr, ticket -> size );
2915     assert(t && t->r && t->v);
2916     r = t->r;
2917     v = t->v;
2918     if ( c == NULL ) {
2919         t -> rc = RC ( rcVFS, rcQuery, rcExecuting, rcMemory, rcExhausted );
2920         return t -> rc;
2921     }
2922     DBGMSG ( DBG_VFS, DBG_FLAG ( DBG_VFS_SERVICE ), ( "  %s=%s\n",
2923         k, c ) );
2924     {
2925         rc_t rc = SKVMake ( & kv, k, c );
2926         free ( c );
2927         if ( rc == 0 ) {
2928             rc = VectorAppend ( v, NULL, kv );
2929             if ( rc != 0 && t -> rc == 0)
2930                 t -> rc = rc;
2931         }
2932     }
2933 
2934     if (t->rc == 0 && VectorLength(&r->tickets) == 1) {
2935         BSTItem * i = (BSTItem *)BSTreeFind
2936             (&r->ticketsToProjects, ticket, BSTItemCmp);
2937         if (i != NULL) {
2938             char c[9] = "";
2939             rc_t rc = 0;
2940             k = "project-id";
2941             rc = string_printf(c, sizeof c, NULL, "%d", i -> project);
2942             if ( rc != 0 )
2943                 t->rc = rc;
2944             else {
2945                 DBGMSG(DBG_VFS, DBG_FLAG(DBG_VFS_SERVICE), ("  %s=%s\n", k, c));
2946                 rc = SKVMake(&kv, k, c);
2947                 if (rc != 0 && t->rc == 0)
2948                     t->rc = rc;
2949                 else {
2950                     rc = VectorAppend(v, NULL, kv);
2951                     if (rc != 0 && t->rc == 0)
2952                         t->rc = rc;
2953                 }
2954             }
2955         }
2956     }
2957 
2958     return t -> rc;
2959 }
2960 
TicketsAppendTicket(void * item,void * data)2961 static void TicketsAppendTicket(void * item, void * data)
2962 {
2963     TicketsDoAppendTicket(item, data);
2964 }
2965 
2966 /* SNgc ***********************************************************************/
2967 
SNgcFini(SNgc * self)2968 static rc_t SNgcFini(SNgc * self) {
2969     rc_t rc = 0;
2970 
2971     assert(self);
2972 
2973     free(self->ngcFile);
2974 
2975     rc = KNgcObjRelease(self->ngcObj);
2976 
2977     memset(self, 0, sizeof * self);
2978 
2979     return rc;
2980 }
2981 
SNgcInit(SNgc * self,const char * path)2982 static rc_t SNgcInit(SNgc * self, const char * path) {
2983     KDirectory * dir = NULL;
2984     rc_t rc = KDirectoryNativeDir(&dir);
2985     const KFile * f = NULL;
2986     rc = KDirectoryOpenFileRead(dir, &f, "%s", path);
2987 
2988     SNgcFini(self);
2989 
2990     if (rc == 0) {
2991         assert(self);
2992 
2993         self->ngcFile = string_dup_measure(path, NULL);
2994         if (self->ngcFile == NULL)
2995             return RC(rcVFS, rcQuery, rcExecuting, rcMemory, rcExhausted);
2996 
2997         rc = KNgcObjMakeFromFile(&self->ngcObj, f);
2998     }
2999 
3000     RELEASE(KFile, f);
3001     RELEASE(KDirectory, dir);
3002 
3003     return rc;
3004 }
3005 
SRequestNgcTicket(const SRequest * self,char * buffer,size_t buffer_size,size_t * written)3006 static rc_t SRequestNgcTicket(const SRequest * self,
3007     char * buffer, size_t buffer_size, size_t * written)
3008 {
3009     assert(self);
3010     return KNgcObjGetTicket(self->_ngc.ngcObj, buffer, buffer_size, written);
3011 }
3012 
SRequestNgcFile(const SRequest * self)3013 const char * SRequestNgcFile(const SRequest * self) {
3014     if (self != NULL && self->_ngc.ngcFile != NULL)
3015         return self->_ngc.ngcFile;
3016 
3017     return NULL;
3018 }
3019 
KServiceGetNgcFile(const KService * self,bool * isProtected)3020 const KNgcObj * KServiceGetNgcFile(const KService * self, bool * isProtected) {
3021     assert(isProtected);
3022 
3023     *isProtected = false;
3024 
3025     if (self != NULL && self->req._ngc.ngcObj != NULL) {
3026         rc_t rc = KNgcObjAddRef(self->req._ngc.ngcObj);
3027         if (rc != 0)
3028             return 0;
3029 
3030         *isProtected = true;
3031         return self->req._ngc.ngcObj;
3032     }
3033 
3034     return NULL;
3035 }
3036 
3037 /* Set ngc file argument in service request */
KServiceSetNgcFile(KService * self,const char * path)3038 rc_t KServiceSetNgcFile(KService * self, const char * path) {
3039     if (self == NULL)
3040         return RC(rcVFS, rcQuery, rcExecuting, rcSelf, rcNull);
3041 
3042     if (path == NULL)
3043         return RC(rcVFS, rcQuery, rcExecuting, rcParam, rcNull);
3044 
3045     return SNgcInit(&self->req._ngc, path);
3046 }
3047 
KServiceCallsSdl(const KService * self)3048 bool KServiceCallsSdl(const KService * self) {
3049     if (self == NULL)
3050         return false;
3051     else
3052         return self->req.sdl;
3053 }
3054 
3055 /* SRequest *******************************************************************/
SRequestInit(SRequest * self)3056 static rc_t SRequestInit ( SRequest * self ) {
3057     rc_t rc = 0;
3058 
3059     assert ( self );
3060 
3061     memset ( self, 0, sizeof * self );
3062 
3063     rc = STicketsInit ( & self -> tickets );
3064 
3065     if ( rc == 0 )
3066         rc = SRequestDataInit ( & self -> request );
3067 
3068     return rc;
3069 }
3070 
3071 
SRequestReset(SRequest * self)3072 static rc_t SRequestReset ( SRequest * self ) {
3073     rc_t rc = 0;
3074     rc_t r2 = 0;
3075 
3076     assert ( self );
3077 
3078     r2 = SVersionFini ( & self -> version );
3079     if ( rc == 0 )
3080         rc = r2;
3081 
3082     SRequestDataFini ( & self -> request );
3083     SCgiRequestFini ( & self -> cgiReq );
3084 
3085     return rc;
3086 }
3087 
3088 
SRequestFini(SRequest * self)3089 static rc_t SRequestFini ( SRequest * self ) {
3090     rc_t r2 = 0;
3091     rc_t rc = SRequestReset ( self );
3092 
3093     assert ( self );
3094 
3095     StringWhack(self->jwtKartFile);
3096     free(self->forced);
3097     free(self->format);
3098 
3099     r2 = SNgcFini(&self->_ngc);
3100     if (rc == 0)
3101         rc = r2;
3102 
3103     r2 = STicketsFini ( & self -> tickets );
3104     if ( rc == 0 )
3105         rc = r2;
3106 
3107     memset ( self, 0, sizeof * self );
3108 
3109     return rc;
3110 }
3111 
3112 
SRequestAddTicket(SRequest * self,uint32_t project,const char * ticket)3113 static rc_t SRequestAddTicket ( SRequest * self, uint32_t project,
3114                                 const char * ticket )
3115 {
3116     assert ( self );
3117     return STicketsAppend ( & self -> tickets, project, ticket );
3118 }
3119 
KServiceGetId(const KService * self,uint32_t idx)3120 const char * KServiceGetId(const KService * self, uint32_t idx) {
3121     assert(self);
3122     if (idx >= self->req.request.objects)
3123         return NULL;
3124     return self->req.request.object[idx].objectId;
3125 }
3126 
SObjectCheckUrl(SObject * self)3127 static rc_t SObjectCheckUrl ( SObject * self ) {
3128     rc_t rc = 0;
3129 
3130     VPath * path = NULL;
3131 
3132     assert ( self && self -> objectId != NULL );
3133 
3134     rc = VPathMake ( & path, self -> objectId );
3135     if ( rc != 0 )
3136         return rc;
3137 
3138     self -> isUri = VPathFromUri ( path );
3139 
3140     RELEASE ( VPath, path );
3141 
3142     return rc;
3143 }
3144 
3145 static
SCgiRequestAddKfgLocation(SCgiRequest * self,SHelper * helper)3146 bool SCgiRequestAddKfgLocation(SCgiRequest * self, SHelper * helper)
3147 {
3148     rc_t rc = SHelperInitKfg(helper);
3149 
3150     assert(helper);
3151 
3152     if (rc == 0) {
3153         char buffer[99] = "";
3154         size_t num_read = 0;
3155         rc = KConfigRead(helper->kfg, "/libs/cloud/location", 0,
3156             buffer, sizeof buffer, &num_read, NULL);
3157         if (rc == 0) {
3158             if (num_read == 0)
3159                 return false;
3160             else {
3161                 const SKV * kv = NULL;
3162                 const char n[] = "location";
3163                 rc = SKVMake(&kv, n, buffer);
3164                 if (rc == 0) {
3165                     DBGMSG(DBG_VFS, DBG_FLAG(DBG_VFS_SERVICE),
3166                         ("  %s=%s\n", n, buffer));
3167                     rc = VectorAppend(&self->params, NULL, kv);
3168                 }
3169             }
3170         }
3171     }
3172 
3173     return rc == 0;
3174 }
3175 
SCgiRequestAddCloudEnvironment(SCgiRequest * self,SHelper * helper)3176 static rc_t SCgiRequestAddCloudEnvironment(
3177     SCgiRequest * self, SHelper * helper)
3178 {
3179     rc_t rc = 0;
3180     CloudProviderId cloud_provider = cloud_provider_none;
3181     bool user_agrees_to_reveal_instance_identity = false;
3182     const String * ce_token = NULL;
3183     assert(helper);
3184     if (helper->cloud == NULL) {
3185         if (helper->cloudMgr == NULL)
3186             rc = CloudMgrMake(&helper->cloudMgr, helper->kfg, helper->kMgr);
3187         if (rc == 0) {
3188             rc = CloudMgrGetCurrentCloud(helper->cloudMgr, &helper->cloud);
3189             if (rc != 0) {
3190                 if (rc != SILENT_RC(
3191                     rcCloud, rcMgr, rcAccessing, rcCloudProvider, rcNotFound))
3192                 {
3193                     LOGERR(klogInt, rc, "cannot get current cloud provider");
3194                 }
3195                 return 0; /* outside of cloud or cannot get cloud */
3196             }
3197         }
3198     }
3199 
3200     if (rc == 0) {
3201         rc = CloudMgrCurrentProvider(helper->cloudMgr, &cloud_provider);
3202         if (rc != 0) {
3203             LOGERR(klogInt, rc, "cannot get current cloud provider");
3204             return 0;
3205         }
3206     }
3207     if (rc == 0) {
3208         rc = SHelperInitKfg(helper);
3209         if (rc == 0)
3210             KConfig_Get_Report_Cloud_Instance_Identity(helper->kfg,
3211                 &user_agrees_to_reveal_instance_identity);
3212     }
3213     if (rc == 0) {
3214         if (user_agrees_to_reveal_instance_identity) {
3215             rc = CloudMakeComputeEnvironmentToken(helper->cloud, &ce_token);
3216             if (rc != 0) {
3217                 LOGERR(klogInt, rc, "cannot Make Compute Environment Token");
3218                 return 0;
3219             }
3220         }
3221         else {
3222             rc = CloudGetLocation(helper->cloud, &ce_token);
3223             if (rc != 0) {
3224                 LOGERR(klogInt, rc, "cannot Get Cloud Location");
3225                 return 0;
3226             }
3227         }
3228     }
3229     if (rc == 0) {
3230         const char * v = NULL;
3231         if (user_agrees_to_reveal_instance_identity) {
3232             if (cloud_provider == cloud_provider_aws)
3233                 v = "aws_pkcs7";
3234             else if (cloud_provider == cloud_provider_gcp)
3235                 v = "gcp_jwt";
3236         }
3237         if (ce_token != NULL) {
3238             if (v != NULL) {
3239                 const SKV * kv = NULL;
3240                 const char n[] = "location-type";
3241                 rc = SKVMake(&kv, n, v);
3242                 if (rc == 0) {
3243                     DBGMSG(DBG_VFS, DBG_FLAG(DBG_VFS_SERVICE),
3244                         ("  %s=%s\n", n, v));
3245                     rc = VectorAppend(&self->params, NULL, kv);
3246                 }
3247                 if (rc != 0)
3248                     return rc;
3249             }
3250             {
3251                 const SKV * kv = NULL;
3252                 const char n[] = "location";
3253                 assert(ce_token);
3254                 rc = SKVMake(&kv, n, ce_token->addr);
3255                 if (rc == 0) {
3256                     DBGMSG(DBG_VFS, DBG_FLAG(DBG_VFS_SERVICE),
3257                         ("  %s=%s\n", n, ce_token->addr));
3258                     rc = VectorAppend(&self->params, NULL, kv);
3259                 }
3260                 StringWhack ( ce_token );
3261                 if (rc != 0)
3262                     return rc;
3263             }
3264         }
3265     }
3266 
3267     return rc;
3268 }
3269 
3270 static
SCgiRequestAddAcceptCharges(SCgiRequest * self,SHelper * helper)3271 rc_t SCgiRequestAddAcceptCharges(SCgiRequest * self, SHelper * helper) {
3272     bool aws = false;
3273     bool gcp = false;
3274 
3275     rc_t rc = SHelperInitKfg(helper);
3276 
3277     if (rc == 0) {
3278         rc = KConfig_Get_User_Accept_Aws_Charges(helper->kfg, &aws);
3279         if (rc != 0)
3280             rc = 0;
3281 
3282         rc = KConfig_Get_User_Accept_Gcp_Charges(helper->kfg, &gcp);
3283         if (rc != 0)
3284             rc = 0;
3285     }
3286 
3287     if (rc == 0) {
3288         const char n[] = "accept-charges";
3289         const char * v = NULL;
3290         if (aws && gcp)
3291             v = "aws,gcp";
3292         else if (aws)
3293             v = "aws";
3294         else if (gcp)
3295             v = "gcp";
3296         if (v != NULL) {
3297             const SKV * kv = NULL;
3298             rc = SKVMake(&kv, n, v);
3299             if (rc == 0) {
3300                 DBGMSG(DBG_VFS, DBG_FLAG(DBG_VFS_SERVICE),
3301                     ("  %s=%s\n", n, v));
3302                 rc = VectorAppend(&self->params, NULL, kv);
3303             }
3304         }
3305     }
3306 
3307     return rc;
3308 }
3309 
SRequestSetDisabled(SRequest * self,SHelper * helper)3310 static rc_t SRequestSetDisabled(SRequest * self, SHelper * helper) {
3311     rc_t rc = 0;
3312 
3313     assert(self && helper);
3314 
3315     rc = SHelperInitKfg(helper);
3316 
3317     if (rc == 0) {
3318         KConfigReadBool(helper->kfg, "/repository/remote/disabled", &self->disabled);
3319         if (self->disabled && VResolverGetRemoteEnable() == vrAlwaysEnable)
3320             self->disabled = false;
3321     }
3322 
3323     return rc;
3324 }
3325 
SRequestAddFile(SRequest * self,const char * key,const char * path,bool base64encode)3326 static rc_t SRequestAddFile(SRequest * self,
3327     const char * key, const char * path, bool base64encode)
3328 {
3329     DBGMSG(DBG_VFS, DBG_FLAG(DBG_VFS_SERVICE), ("  %s=%c%s\n",
3330         key, base64encode ? '@' : '<', path));
3331 
3332     if (key != NULL && path != NULL) {
3333         assert(self);
3334 
3335         self->cgiReq.fileKey = key;
3336         self->cgiReq.fileVal = path;
3337         self->cgiReq.fileBase64encode = base64encode;
3338 
3339         self->hasQuery = true;
3340     }
3341 
3342     return 0;
3343 }
3344 
3345 static
SRequestInitNamesSCgiRequest(SRequest * request,SHelper * helper,VRemoteProtocols protocols,const char * cgi,const char * version,bool aProtected,bool adjustVersion,VQuality quality)3346 rc_t SRequestInitNamesSCgiRequest ( SRequest * request, SHelper * helper,
3347     VRemoteProtocols protocols, const char * cgi, const char * version,
3348     bool aProtected, bool adjustVersion, VQuality quality )
3349 {
3350     SCgiRequest * self = NULL;
3351     rc_t rc = 0;
3352     const SKV * kv = NULL;
3353 
3354     bool fileTypeRun = true;
3355 
3356     assert ( request );
3357 
3358     if ( protocols == eProtocolDefault )
3359         protocols = SHelperDefaultProtocols ( helper );
3360     request -> protocols = protocols;
3361 
3362     self = & request -> cgiReq;
3363 
3364     request -> hasQuery = true;
3365 
3366     DBGMSG ( DBG_VFS, DBG_FLAG ( DBG_VFS_SERVICE ), (
3367         "vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv\n" ) );
3368 
3369     rc = SRequestSetDisabled(request, helper);
3370     if (rc != 0)
3371         return rc;
3372     if (request->disabled) {
3373         request->sdl = true;               /* need to set it to allow to work */
3374         DBGMSG(DBG_VFS, DBG_FLAG(DBG_VFS_SERVICE),     /* without remote repo */
3375             ("remote repo disabled in config\n"));
3376         return rc;
3377     }
3378 
3379     rc = SVersionInit(&request->version, &request->sdl, version, eSTnames,
3380         NULL, helper, request);
3381     if ( rc != 0 )
3382         return rc;
3383 
3384     if ( self -> cgi == NULL ) {
3385         char buffer [ 1024 ] = "";
3386         rc = SHelperResolverCgi ( helper, aProtected,
3387             buffer, sizeof buffer, cgi, request, adjustVersion );
3388         cgi = buffer;
3389         rc = SCgiRequestInitCgi ( self, cgi );
3390     }
3391 
3392     VectorWhack ( & self -> params, whackSKV, NULL );
3393 
3394     VectorInit ( & self -> params, 0, 5 );
3395 
3396     request -> serviceType = eSTnames;
3397     DBGMSG ( DBG_VFS,
3398         DBG_FLAG ( DBG_VFS_SERVICE ), ( "CGI = '%s'\n", self -> cgi ) );
3399     if ( rc == 0 ) {
3400         if (request->sdl)
3401             DBGMSG(DBG_VFS, DBG_FLAG(DBG_VFS_SERVICE), (
3402                 "  not sending version in SDL protocol\n"));
3403         else {
3404             const char name[] = "version";
3405             char * version = NULL;
3406             rc = SVersionToString(request->version, &version);
3407             if (rc != 0) {
3408                 return rc;
3409             }
3410             rc = SKVMake(&kv, name, version);
3411             if (rc == 0) {
3412                 rc = VectorAppend(&self->params, NULL, kv);
3413                 DBGMSG(DBG_VFS, DBG_FLAG(DBG_VFS_SERVICE),
3414                     ("  %s=%s\n", name, version));
3415             }
3416             free(version);
3417             if (rc != 0)
3418                 return rc;
3419         }
3420     }
3421     if ( ! SVersionHasMultpileObjects ( request -> version,
3422         request -> sdl ) )
3423     {
3424         if ( request -> request . object [ 0 ] . objectId == NULL )
3425             return RC ( rcVFS, rcQuery, rcExecuting, rcParam, rcNull );
3426         else {
3427             const char name [] = "acc";
3428             rc = SKVMake
3429                 ( & kv, name, request -> request . object [ 0 ] . objectId );
3430             DBGMSG ( DBG_VFS, DBG_FLAG ( DBG_VFS_SERVICE ), ( "  %s=%s\n",
3431                 name, request -> request . object [ 0 ] . objectId ) );
3432             if ( rc == 0 )
3433                 rc = VectorAppend ( & self -> params, NULL, kv );
3434         }
3435         if ( rc != 0 )
3436             return rc;
3437     }
3438     else {
3439         uint32_t i = 0;
3440         request -> hasQuery = false;
3441         for ( i = 0; i < request -> request . objects; ++i ) {
3442             request -> request . object [ i ] . ordId = i;
3443             rc = SObjectCheckUrl ( & request -> request . object [ i ] );
3444             if ( rc != 0 || ! request -> request . object [ i ] . isUri ) {
3445               if ( SVersionResponseInJson ( request -> version,
3446                   request ->sdl ) )
3447               {
3448                 const char * name = "acc";
3449                 if (request->request.object[i].objectType == eOT_sdlObject)
3450                     name = "object";
3451                 rc = SKVMake ( & kv, name,
3452                                request -> request . object [ i ] . objectId );
3453                 DBGMSG ( DBG_VFS, DBG_FLAG ( DBG_VFS_SERVICE ), ( "  %s=%s\n",
3454                     name, request -> request . object [ i ] . objectId ) );
3455               }
3456               else {
3457                 rc = SKVMakeObj ( & kv, & request -> request . object [ i ],
3458                                    request -> version );
3459                 if ( rc == 0 )
3460                     DBGMSG ( DBG_VFS, DBG_FLAG ( DBG_VFS_SERVICE ),
3461                         ( "  %.*s=%.*s\n", kv -> k . len, kv -> k . addr,
3462                                            kv -> v . len, kv -> v . addr ) );
3463               }
3464               if ( rc == 0 ) {
3465                 rc = VectorAppend ( & self -> params, NULL, kv );
3466                 request -> hasQuery = true;
3467               }
3468             }
3469         }
3470         if ( rc != 0 )
3471             return rc;
3472     }
3473     {
3474         uint32_t i = 0;
3475         const char * prefs [ eProtocolMaxPref ];
3476         const char * seps [ eProtocolMaxPref ];
3477         VRemoteProtocols protos = protocols;
3478 
3479         prefs [ 0 ] = seps [ 0 ] = NULL;
3480         prefs [ 1 ] = seps [ 1 ] = prefs [ 2 ] = seps [ 2 ]
3481                                  = prefs [ 3 ] = seps [ 3 ] = "";
3482 
3483         for ( i = 0; protos != 0 && i < sizeof prefs / sizeof prefs [ 0 ];
3484             protos >>= 3 )
3485         {
3486             /* 1.1 protocols */
3487             switch ( protos & eProtocolMask )
3488             {
3489             case eProtocolHttp:
3490                 prefs [ i ] = "http";
3491                 seps [ i ++ ] = ",";
3492                 break;
3493             case eProtocolFasp:
3494                 prefs [ i ] = "fasp";
3495                 seps [ i ++ ] = ",";
3496                 break;
3497             /* 1.2 protocols */
3498             case eProtocolHttps:
3499                 prefs [ i ] = "https";
3500                 seps [ i ++ ] = ",";
3501                 break;
3502             /* 3.0 protocols */
3503             case eProtocolFile:
3504                 prefs [ i ] = "file";
3505                 seps [ i ++ ] = ",";
3506                 break;
3507             default:
3508                 assert ( 0 );
3509                 break;
3510             }
3511         }
3512         if ( prefs [ 0 ] == NULL )
3513             rc = RC ( rcVFS, rcQuery, rcResolving, rcParam, rcInvalid );
3514         else
3515         {
3516             const char name [] = "accept-proto";
3517             size_t num_writ = 0;
3518             char p [ 512 ] = "";
3519             rc = string_printf ( p, sizeof p, & num_writ, "%s%s%s%s%s%s",
3520                 prefs [ 0 ], seps [ 1 ], prefs [ 1 ], seps [ 2 ], prefs [ 2 ],
3521                                                       seps [ 3 ], prefs [ 3 ] );
3522             rc = SKVMake ( & kv, name, p );
3523             if ( rc == 0 ) {
3524                 DBGMSG ( DBG_VFS, DBG_FLAG ( DBG_VFS_SERVICE ),
3525                     ( "  %s=%s\n", name, p ) );
3526                 rc = VectorAppend ( & self -> params, NULL, kv );
3527             }
3528         }
3529         if ( rc != 0 ) {
3530             return rc;
3531         }
3532     }
3533     if ( SVersionHasRefseqCtx (  request -> version ) &&
3534          request -> request . refseq_ctx )
3535     {
3536         const char name [] = "ctx";
3537         rc = SKVMake ( & kv, name, "refseq" );
3538         if ( rc == 0 ) {
3539                 DBGMSG ( DBG_VFS, DBG_FLAG ( DBG_VFS_SERVICE ),
3540                     ( "  %s=refseq\n", name ) );
3541             rc = VectorAppend ( & self -> params, NULL, kv );
3542         }
3543         if ( rc != 0 ) {
3544             return rc;
3545         }
3546     }
3547     if ( SVersionTypInRequest (  request -> version ) ) {
3548         if ( request -> request . object [ 0 ] . objectType !=
3549             eOT_undefined )
3550         {
3551             const char name [] = "typ";
3552             const char * v = ObjectTypeToString
3553                 ( request -> request . object [ 0 ] . objectType );
3554             rc = SKVMake ( & kv, name, v );
3555             if ( rc == 0 ) {
3556                 DBGMSG ( DBG_VFS, DBG_FLAG ( DBG_VFS_SERVICE ),
3557                     ( "  %s=%s\n", name, v ) );
3558                 rc = VectorAppend ( & self -> params, NULL, kv );
3559             }
3560         }
3561         if ( rc != 0 ) {
3562             return rc;
3563         }
3564     }
3565 
3566     if ( request -> format != NULL ) {
3567         const char * n = "type";
3568         n              = "filetype";
3569         const char * v = request->format;
3570 
3571         String all;
3572         String any;
3573         String format;
3574         CONST_STRING(&all, "all");
3575         CONST_STRING(&any, "any");
3576         StringInitCString(&format, request->format);
3577 
3578         if (!StringEqual(&format, &all) && !StringEqual(&format, &any)) {
3579             rc = SKVMake(&kv, n, v);
3580             if (rc == 0) {
3581                 DBGMSG(DBG_VFS, DBG_FLAG(DBG_VFS_SERVICE),
3582                     ("  %s=%s\n", n, v));
3583                 rc = VectorAppend(&self->params, NULL, kv);
3584             }
3585             if (rc != 0)
3586                 return rc;
3587         }
3588 
3589         fileTypeRun = false;
3590     }
3591 
3592     if (rc == 0 &&
3593         SVersionResponseInJson(request->version, request->sdl))
3594     {
3595         if (request->request.appRc != 0)
3596             /* different query items require to add
3597             and at the same time not to add filetype=run */
3598             return request->request.appRc;
3599         else if (fileTypeRun &&              /* don't add filetype=run
3600                                                 when it was specified already */
3601             ( request->request.app == appSRA /* add it for sra items */
3602                 || ( request->request.app == appUnknown
3603                     && request->jwtKartFile != NULL) )) /* and for jwt carts */
3604         {
3605             const char n[] = "filetype";
3606             if (quality == eQualDefault || quality == eQualFull
3607                 || quality == eQualFullOnly || quality == eQualDblOnly
3608                 || quality >= eQualLast || quality < 0)
3609             {
3610                 const char v[] = "run";
3611                 rc = SKVMake(&kv, n, v);
3612                 if (rc == 0) {
3613                     DBGMSG(DBG_VFS, DBG_FLAG(DBG_VFS_SERVICE),
3614                         ("  %s=%s\n", n, v));
3615                     rc = VectorAppend(&self->params, NULL, kv);
3616                 }
3617                 if (rc != 0)
3618                     return rc;
3619             }
3620             if (quality == eQualDefault || quality == eQualNo
3621                 || quality == eQualDblOnly)
3622             {
3623                 const char v[] = "noqual_run";
3624                 rc = SKVMake(&kv, n, v);
3625                 if (rc == 0) {
3626                     DBGMSG(DBG_VFS, DBG_FLAG(DBG_VFS_SERVICE),
3627                         ("  %s=%s\n", n, v));
3628                     rc = VectorAppend(&self->params, NULL, kv);
3629                 }
3630                 if (rc != 0)
3631                     return rc;
3632             }
3633         }
3634     }
3635 
3636     if (rc == 0) {
3637         if (request->sdl && request->forced != NULL) {
3638             const char name[] = "location";
3639             rc = SKVMake(&kv, name, request->forced);
3640             if (rc == 0) {
3641                 rc = VectorAppend(&self->params, NULL, kv);
3642                 DBGMSG(DBG_VFS, DBG_FLAG(DBG_VFS_SERVICE),
3643                     ("  %s=%s\n", name, request->forced));
3644             }
3645             if (rc == 0) {
3646                 const char name[] = "location-type";
3647                 const char v[] = "forced";
3648                 rc = SKVMake(&kv, name, v);
3649                 if (rc == 0) {
3650                     rc = VectorAppend(&self->params, NULL, kv);
3651                     DBGMSG(DBG_VFS, DBG_FLAG(DBG_VFS_SERVICE),
3652                         ("  %s=%s\n", name, v));
3653                 }
3654             }
3655         }
3656         else if (!SCgiRequestAddKfgLocation(self, helper))
3657             if (SVersionNeedCloudEnvironment(request->version, request->sdl))
3658                 rc = SCgiRequestAddCloudEnvironment(self, helper);
3659     }
3660 
3661     if (rc == 0 && SVersionResponseInJson(request->version, request->sdl))
3662         rc = SCgiRequestAddAcceptCharges(self, helper);
3663 
3664     if (rc == 0) {
3665         if (SRequestNgcFile(request) != NULL)
3666             if (request->sdl)
3667                 rc = SRequestAddFile(request, "ngc", SRequestNgcFile(request),
3668                     true);
3669             else {
3670                 char buffer[256] = "";
3671                 rc = SRequestNgcTicket(request, buffer, sizeof buffer, NULL);
3672                 if (rc == 0) {
3673                     Tickets t = { & self->params, & request -> tickets, 0 };
3674                     String ticket;
3675                     StringInitCString(&ticket, buffer);
3676                     rc = TicketsDoAppendTicket(&ticket, &t);
3677                 }
3678             }
3679         else if ( request -> tickets . size != 0 ) { /* optional */
3680             Tickets t = { & self->params, & request -> tickets, 0 };
3681             VectorForEach ( & request -> tickets .tickets , false,
3682                 TicketsAppendTicket, & t );
3683             rc = t . rc;
3684             if ( rc != 0 )
3685                 return rc;
3686         }
3687     }
3688 
3689     if (rc == 0 && request->sdl && request->jwtKartFile != NULL) {
3690         const char n[] = "cart";
3691         const char * v = request->jwtKartFile->addr;
3692         rc = SKVMake(&kv, n, v);
3693         if (rc == 0) {
3694             DBGMSG(DBG_VFS, DBG_FLAG(DBG_VFS_SERVICE),
3695                 ("  %s=%s\n", n, v));
3696             rc = VectorAppend(&self->params, NULL, kv);
3697         }
3698         if (rc != 0)
3699             return rc;
3700         request->hasQuery = true;
3701     }
3702 
3703     return rc;
3704 }
3705 
3706 
3707 static
SRequestInitSearchSCgiRequest(SRequest * request,const char * cgi,const char * version)3708 rc_t SRequestInitSearchSCgiRequest ( SRequest * request, const char * cgi,
3709     const char * version )
3710 {
3711     SCgiRequest * self = NULL;
3712     rc_t rc = 0;
3713     const SKV * kv = NULL;
3714     assert ( request );
3715     rc = SVersionInit(
3716         &request->version, NULL, version, eSTnames, NULL, NULL, NULL);
3717     if ( rc != 0 )
3718         return rc;
3719     self = & request -> cgiReq;
3720     if ( self -> cgi == NULL ) {
3721         if ( cgi == NULL ) {
3722 /* try to get cgi from kfg, otherwise use hardcoded below */
3723             cgi = "https://trace.ncbi.nlm.nih.gov/Traces/names/search.cgi";
3724         }
3725         rc = SCgiRequestInitCgi ( self, cgi );
3726     }
3727     request -> serviceType = eSTsearch;
3728     VectorInit ( & self -> params, 0, 5 );
3729     DBGMSG ( DBG_VFS,
3730         DBG_FLAG ( DBG_VFS_SERVICE ), ( "CGI = '%s'\n", self -> cgi ) );
3731     if ( rc == 0 ) {
3732         const char name [] = "version";
3733         char * version = NULL;
3734         rc = SVersionToString (  request -> version, & version );
3735         if ( rc != 0 ) {
3736             return rc;
3737         }
3738         rc = SKVMake ( & kv, name, version );
3739         if ( rc == 0 ) {
3740             rc = VectorAppend ( & self -> params, NULL, kv );
3741             DBGMSG ( DBG_VFS, DBG_FLAG ( DBG_VFS_SERVICE ),
3742                 ( "  %s=%s\n", name, version ) );
3743         }
3744         free ( version );
3745         if ( rc != 0 ) {
3746             return rc;
3747         }
3748     }
3749     {
3750         const char name [] = "term";
3751         char * b = NULL;
3752         uint32_t i = 0;
3753         size_t l = 0;
3754         size_t o = 0;
3755         for ( i = 0; i < request -> request . objects; ++i ) {
3756             l += string_measure
3757                 ( request -> request . object [ i ] . objectId, NULL ) + 1;
3758         }
3759         if ( l > 0 ) {
3760             b = ( char * ) malloc ( l );
3761             if ( b == NULL ) {
3762                 return
3763                     RC ( rcVFS, rcQuery, rcExecuting, rcMemory, rcExhausted );
3764             }
3765             for ( i = 0; rc == 0 && i < request -> request . objects;
3766                 ++i )
3767             {
3768                 size_t num_writ = 0;
3769                 rc = string_printf ( b + o, l - o, & num_writ,
3770                     "%s", request -> request . object [ i ] . objectId );
3771                 o += num_writ;
3772                 if ( i + 1 == request -> request . objects ) {
3773                     b [ o ++ ] = '\0';
3774                 }
3775                 else {
3776                     b [ o ++ ] = ',';
3777                 }
3778             }
3779             assert ( o <= l );
3780             rc = SKVMake ( & kv, name, b );
3781             DBGMSG ( DBG_VFS, DBG_FLAG ( DBG_VFS_SERVICE ),
3782                 ( "  %s=%s\n", name, b ) );
3783             if ( rc == 0 ) {
3784                 rc = VectorAppend ( & self -> params, NULL, kv );
3785             }
3786             free ( b );
3787             if ( rc != 0 ) {
3788                 return rc;
3789             }
3790         }
3791     }
3792     return rc;
3793 }
3794 
3795 /* KService *******************************************************************/
KServiceExpectErrors(KService * self,int n)3796 static void KServiceExpectErrors ( KService * self, int n ) {
3797     assert ( self );
3798 
3799     self -> req . errorsToIgnore = n;
3800 }
3801 
3802 
_KServiceAddObject(KService * self,const char * id,size_t id_sz,EObjectType objectType)3803 static rc_t _KServiceAddObject ( KService * self,
3804     const char * id, size_t id_sz, EObjectType objectType )
3805 {
3806     if ( self == NULL )
3807         return RC ( rcVFS, rcQuery, rcExecuting, rcSelf, rcNull );
3808 
3809     return SRequestDataAppendObject
3810         ( & self -> req . request, id, id_sz, objectType );
3811 }
3812 
3813 
3814 /* Add an Id ( Accession or Object-Id ) to service request */
KServiceAddId(KService * self,const char * id)3815 rc_t KServiceAddId ( KService * self, const char * id ) {
3816     return _KServiceAddObject ( self, id, 0, eOT_undefined );
3817 }
3818 
KServiceAddObject(KService * self,const char * id)3819 rc_t KServiceAddObject(KService * self, const char * id) {
3820     return _KServiceAddObject(self, id, 0, eOT_sdlObject);
3821 }
3822 
KServiceAddTicket(KService * self,const char * ticket)3823 static rc_t KServiceAddTicket ( KService * self, const char * ticket ) {
3824     if ( self == NULL )
3825         return RC ( rcVFS, rcQuery, rcExecuting, rcSelf, rcNull );
3826 
3827     if ( ticket == NULL )
3828         return RC ( rcVFS, rcQuery, rcExecuting, rcParam, rcNull );
3829 
3830     return SRequestAddTicket ( & self -> req, 0, ticket );
3831 }
3832 
3833 
3834 /* Add a dbGaP Project to service request */
KServiceAddProject(KService * self,uint32_t project)3835 rc_t KServiceAddProject ( KService * self, uint32_t project ) {
3836     rc_t rc = 0;
3837 
3838     char buffer [ 256 ] = "";
3839     size_t ticket_size = ~0;
3840 
3841     /*  dbGaP projectId can be 0 if ( project == 0 )        return 0; */
3842 
3843     if ( self == NULL )
3844         return RC ( rcVFS, rcQuery, rcExecuting, rcSelf, rcNull );
3845 
3846     rc = SHelperProjectToTicket ( & self -> helper, project,
3847         buffer, sizeof buffer, & ticket_size );
3848     if ( rc != 0 )
3849         return rc;
3850 
3851     assert ( ticket_size <= sizeof buffer );
3852 
3853     return SRequestAddTicket ( & self -> req, project, buffer );
3854 }
3855 
3856 /* Set accept-format-in of service request */
KServiceSetFormat(KService * self,const char * format)3857 rc_t KServiceSetFormat(KService * self, const char * format) {
3858     if (self == NULL)
3859         return RC(rcVFS, rcQuery, rcExecuting, rcSelf, rcNull);
3860 
3861     if (format == NULL)
3862         return RC(rcVFS, rcQuery, rcExecuting, rcParam, rcNull);
3863 
3864     free( self -> req . format );
3865 
3866     self->req.format = NULL;
3867 
3868     self->req.format = string_dup_measure(format, NULL);
3869     if (self->req.format == NULL)
3870         return RC(rcVFS, rcQuery, rcExecuting, rcMemory, rcExhausted);
3871     else
3872         return 0;
3873 }
3874 
3875 /* Set jwt kart argument in service request */
KServiceSetJwtKartFile(KService * self,const char * path)3876 rc_t KServiceSetJwtKartFile(KService * self, const char * path) {
3877     rc_t rc = 0;
3878 
3879     if (self == NULL)
3880         return RC(rcVFS, rcQuery, rcExecuting, rcSelf, rcNull);
3881 
3882     if (path == NULL)
3883         return RC(rcVFS, rcQuery, rcExecuting, rcParam, rcNull);
3884 
3885     StringWhack(self->req.jwtKartFile);
3886     self->req.jwtKartFile = NULL;
3887 
3888     rc = JwtKartValidateFile(path, (const String **)&self->req.jwtKartFile);
3889     if (rc == 0) {
3890         /* remove trailing EOLs; make zero-terminated string */
3891         assert(self->req.jwtKartFile && self->req.jwtKartFile->addr);
3892         ((char*)(self->req.jwtKartFile->addr))[self->req.jwtKartFile->size]
3893             = '\0';
3894     }
3895     return rc;
3896 }
3897 
3898 
3899 /* Set location of data in service request */
KServiceSetLocation(KService * self,const char * location)3900 rc_t KServiceSetLocation(KService * self, const char * location) {
3901     if (self == NULL)
3902         return RC(rcVFS, rcQuery, rcExecuting, rcSelf, rcNull);
3903 
3904     if (location == NULL)
3905         return RC(rcVFS, rcQuery, rcExecuting, rcParam, rcNull);
3906 
3907     free(self->req.forced);
3908 
3909     self->req.forced = NULL;
3910 
3911     self->req.forced = string_dup_measure(location, NULL);
3912     if (self->req.forced == NULL)
3913         return RC(rcVFS, rcQuery, rcExecuting, rcMemory, rcExhausted);
3914     else
3915         return 0;
3916 }
3917 
3918 
3919 static
KServiceInitNamesRequestWithVersion(KService * self,VRemoteProtocols protocols,const char * cgi,const char * version,bool aProtected,bool adjustVersion)3920 rc_t KServiceInitNamesRequestWithVersion ( KService * self,
3921     VRemoteProtocols protocols, const char * cgi, const char * version,
3922     bool aProtected, bool adjustVersion )
3923 {
3924     VQuality quality = eQualDefault;
3925 
3926     assert ( self );
3927 
3928     if (self->quality < 0)
3929         self->quality = VDBManagerGetQuality(0);
3930     if (self->quality >= 0)
3931         quality = self->quality;
3932 
3933     return SRequestInitNamesSCgiRequest ( & self -> req,  & self -> helper,
3934         protocols, cgi, version, aProtected, adjustVersion, quality );
3935 }
3936 
3937 
3938 static
KServiceInitNamesRequest(KService * self,VRemoteProtocols protocols,const char * cgi)3939 rc_t KServiceInitNamesRequest ( KService * self, VRemoteProtocols protocols,
3940     const char * cgi )
3941 {
3942     return KServiceInitNamesRequestWithVersion ( self, protocols, cgi, "#3.0",
3943         false, false );
3944 }
3945 
3946 
3947 static
KServiceInitSearchRequestWithVersion(KService * self,const char * cgi,const char * version)3948 rc_t KServiceInitSearchRequestWithVersion ( KService * self, const char * cgi,
3949     const char * version )
3950 {
3951     assert ( self );
3952 
3953     return SRequestInitSearchSCgiRequest ( & self -> req, cgi, version );
3954 }
3955 
3956 
KServiceInit(KService * self,const VFSManager * vMgr,const KNSManager * mgr,const KConfig * kfg)3957 static rc_t KServiceInit ( KService * self,
3958     const VFSManager * vMgr, const KNSManager * mgr, const KConfig * kfg )
3959 {
3960     rc_t rc = 0;
3961 
3962     assert ( self );
3963     memset ( self, 0, sizeof * self );
3964 
3965     if ( rc == 0 )
3966         rc = SHelperInit ( & self -> helper, vMgr, mgr, kfg );
3967 
3968     if ( rc == 0 )
3969         rc = SResponseInit ( & self ->  resp, 0 );
3970 
3971     if ( rc == 0 )
3972         rc = SRequestInit ( & self -> req );
3973 
3974     self -> resoveOidName = DEFAULT_RESOVE_OID_NAME;
3975     self -> quality = -1; /* not set */
3976 
3977     return rc;
3978 }
3979 
3980 
3981 /* Initialize KService with a single "acc"/"objectType" and optional "ticket"
3982    in Request */
KServiceInitNames1(KService * self,const KNSManager * mgr,const char * cgi,const char * version,const char * acc,size_t acc_sz,const char * ticket,VRemoteProtocols protocols,EObjectType objectType,bool refseq_ctx,bool aProtected)3983 static rc_t KServiceInitNames1 ( KService * self, const KNSManager * mgr,
3984     const char * cgi, const char * version, const char * acc,
3985     size_t acc_sz, const char * ticket, VRemoteProtocols protocols,
3986     EObjectType objectType, bool refseq_ctx, bool aProtected )
3987 {
3988     rc_t rc = 0;
3989 
3990     if ( rc == 0 )
3991         rc = KServiceInit ( self, NULL, mgr, NULL );
3992 
3993     if ( rc == 0 )
3994         rc = _KServiceAddObject ( self, acc, acc_sz, objectType );
3995     if ( rc == 0 )
3996         rc = SRequestAddTicket ( & self -> req, 0, ticket );
3997     if ( rc == 0 )
3998         self -> req . request . refseq_ctx = refseq_ctx;
3999 
4000     if (rc == 0 && SRequestNgcFile(&self->req) == NULL) {
4001         const char * ngc = KConfigGetNgcFile();
4002         if (ngc != NULL)
4003             rc = KServiceSetNgcFile(self, ngc);
4004     }
4005 
4006     if ( rc == 0 )
4007         rc = KServiceInitNamesRequestWithVersion
4008             ( self, protocols, cgi, version, aProtected, true );
4009 
4010     return rc;
4011 }
4012 
4013 
KServiceMakeWithMgr(KService ** self,const VFSManager * vMgr,const KNSManager * mgr,const KConfig * kfg)4014 rc_t KServiceMakeWithMgr ( KService ** self,
4015     const VFSManager * vMgr, const KNSManager * mgr, const KConfig * kfg )
4016 {
4017     rc_t rc = 0;
4018 
4019     KService * p = NULL;
4020 
4021     if ( self == NULL )
4022         return RC ( rcVFS, rcQuery, rcExecuting, rcParam, rcNull );
4023 
4024     p = ( KService * ) calloc ( 1, sizeof * p );
4025     if ( p == NULL )
4026         return RC ( rcVFS, rcQuery, rcExecuting, rcMemory, rcExhausted );
4027 
4028     rc = KServiceInit ( p, vMgr, mgr, kfg );
4029     if ( rc == 0)
4030         * self = p;
4031     else
4032         free ( p );
4033 
4034     return rc;
4035 }
4036 
4037 
4038 /* Make KService object */
KServiceMake(KService ** self)4039 rc_t KServiceMake ( KService ** self) {
4040     return KServiceMakeWithMgr ( self, NULL, NULL, NULL );
4041 }
4042 
4043 
KServiceFini(KService * self)4044 static rc_t KServiceFini ( KService * self ) {
4045     rc_t rc = 0;
4046     rc_t r2 = 0;
4047 
4048     assert ( self );
4049 
4050     r2 = SResponseFini ( & self -> resp );
4051     if ( rc == 0 )
4052         rc = r2;
4053 
4054     r2 = SRequestFini ( & self -> req );
4055     if ( rc == 0 )
4056         rc = r2;
4057 
4058     r2 = SHelperFini ( & self -> helper );
4059     if ( rc == 0 )
4060         rc = r2;
4061 
4062     return rc;
4063 }
4064 
4065 
4066 /* Release KService object */
KServiceRelease(KService * self)4067 rc_t KServiceRelease ( KService * self ) {
4068     rc_t rc = 0;
4069 
4070     if ( self != NULL ) {
4071         rc = KServiceFini ( self );
4072         free ( self );
4073     }
4074 
4075     return rc;
4076 }
4077 
KServiceGetKSrvResponse(KService * self,KSrvResponse ** r)4078 rc_t KServiceGetKSrvResponse( KService * self, KSrvResponse ** r ) {
4079     assert( self && r );
4080 
4081     *r = self->resp.list;
4082 
4083     return 0;
4084 }
4085 
KServiceProcessJson(KService * self)4086 static rc_t KServiceProcessJson ( KService * self ) {
4087     rc_t rc = 0;
4088     rc_t r2 = 0;
4089 
4090     Response4 * r = NULL;
4091 
4092     assert(self);
4093 
4094     if (self->resp.rc != 0)
4095         return self->resp.rc;
4096 
4097     if (self->req.sdl) {
4098         int64_t projectId = -1;
4099         if (self->req._ngc.ngcObj != NULL) {
4100             uint32_t id = 0;
4101             rc = KNgcObjGetProjectId(self->req._ngc.ngcObj, &id);
4102             if (rc == 0)
4103                 projectId = id;
4104         }
4105         if (rc == 0)
4106             rc = Response4MakeSdlExt(&r, self->helper.vMgr, self->helper.kMgr,
4107                 self->helper.kfg, self->helper.input,
4108                 sLogNamesServiceErrors, projectId, self->quality);
4109     }
4110     else
4111         rc = Response4Make4 ( & r, self -> helper . input );
4112 
4113     if ( rc == 0 )
4114         rc = KSrvResponseSetR4 ( self -> resp . list, r );
4115 
4116     if ( rc == 0 )
4117         Response4GetRc ( r, & rc );
4118 
4119     r2 = Response4Release ( r );
4120     if ( r2 != 0 && rc == 0 )
4121         rc = r2;
4122 
4123     return rc;
4124 }
4125 
4126 static
KServiceProcessLine(KService * self,const String * line,bool * end)4127 rc_t KServiceProcessLine ( KService * self,
4128     const String * line, bool * end )
4129 {
4130     rc_t rc = 0;
4131     assert ( self && line && end );
4132     if ( line -> addr [ 0 ] == '$' ) {
4133         * end = true;
4134         if ( SVersionResponseHasTimestamp
4135                 (  self -> resp . header . version )
4136             && line -> size > 2 && line -> len > 2 )
4137         {
4138             String timestamp;
4139             StringInit ( & timestamp, line -> addr + 2, line -> size - 2,
4140                                                         line -> len  - 2 );
4141             rc = SServerTimestampInit ( & self -> resp . timestamp,
4142                                         & timestamp );
4143         }
4144     }
4145     else if ( self -> req . serviceType == eSTsearch ) {
4146         const char str [] = "$end";
4147         size_t sz = sizeof str - 1;
4148         if ( string_cmp ( line -> addr, line -> size, str, sz, ( uint32_t ) sz )
4149             == 0)
4150         {
4151             * end = true;
4152         }
4153         else
4154             rc = KartAddRow ( self -> resp . kart, line -> addr, line -> size );
4155     }
4156     else {
4157         const SConverters * f = NULL;
4158         rc = SConvertersMake ( & f, & self -> resp . header );
4159         if ( rc == 0 ) {
4160             bool append = true;
4161             SRow * row = NULL;
4162             rc_t r2 = SRowMake ( & row, line, & self -> req, f,
4163                  self -> resp . header . version );
4164             uint32_t l = VectorLength ( & self -> resp . rows );
4165             if ( r2 == 0 ) {
4166                 if ( SVersionHasMultpileObjects (
4167                         self -> resp . header . version, false )
4168                     || l == 0 )
4169                 {
4170                     if ( l == 1 &&
4171                          self -> req . request . objects == 1 )
4172                     {
4173 /* SRA-5283 VDB-3423: names.cgi version 3.0 incorrectly returns
4174            2 rows for filtered runs instead of 1: here we compensate this bug */
4175                         const KSrvError * error = NULL;
4176                         SRow * prev
4177                             = (SRow *) VectorGet ( & self -> resp . rows, 0 );
4178                         assert ( prev );
4179                         error = row -> path . error;
4180                         if ( error != NULL &&
4181                              error -> code == 403 &&
4182                              error ->        objectType == eOT_sragap &&
4183                              prev -> typed . objectType == eOT_srapub &&
4184                              row -> typed . ordId == prev -> typed . ordId &&
4185                              StringEqual ( & row  -> typed . objectId,
4186                                            & prev -> typed . objectId ) )
4187                         {
4188                             append = false;
4189                         }
4190                     }
4191                 }
4192                 else {
4193 /* ignore ACC.vdbcache : TODO : search for vdb.cache extension */
4194                     if ( l == 1 && ( row -> typed . objectId . len == 18 ||
4195                                      row -> typed . objectId . len == 19   ) )
4196                     {
4197                         append = false;
4198                     }
4199                 }
4200                 if ( append )
4201                     r2 = VectorAppend ( & self -> resp . rows, NULL, row );
4202                 else {
4203                     r2 = SRowWhack ( row );
4204                     row = NULL;
4205                 }
4206             }
4207             if ( r2 == 0 ) {
4208                 if ( append && ( SVersionHasMultpileObjects
4209                                      ( self -> resp . header . version, false )
4210                           || KSrvResponseLength ( self -> resp . list ) == 0 ) )
4211 
4212                 {
4213                     r2 = KSrvResponseAppend ( self -> resp . list, row -> set );
4214                 }
4215                 else
4216                     assert ( ! row );
4217             }
4218             if ( r2 != 0 && rc == 0 && l != 1 )
4219                 rc = r2;
4220         }
4221     }
4222     return rc;
4223 }
4224 
4225 static
KServiceProcessStreamAll(KService * self,KStream * stream)4226 rc_t KServiceProcessStreamAll ( KService * self, KStream * stream )
4227 {
4228     rc_t rc = 0, rx = 0;
4229     bool start = true;
4230     size_t offW = 0;
4231     size_t num_read = 0;
4232     size_t offR = 0;
4233     size_t sizeR = 0;
4234 
4235     size_t sizeW = 0;
4236     timeout_t tm;
4237 
4238     char * buffer = NULL;
4239 
4240     assert ( self && self -> helper . inSz && self -> helper . input );
4241 
4242     sizeW = self -> helper . inSz;
4243     self -> resp . serviceType = self -> req . serviceType;
4244 
4245     rc = TimeoutInit ( & tm, self -> helper . timeoutMs );
4246     if (rc == 0) {
4247         rx = self->resp.rc;
4248         rc = SResponseFini(&self->resp);
4249     }
4250     if ( rc == 0 )
4251         rc = SResponseInit ( & self -> resp, rx );
4252     if ( rc == 0 && self -> req . serviceType == eSTsearch )
4253         rc = KartMake2 ( & self -> resp . kart );
4254     DBGMSG ( DBG_VFS, DBG_FLAG ( DBG_VFS_SERVICE ), (
4255         "-----------------------------------------------------------\n" ) );
4256     while ( rc == 0 ) {
4257         if ( sizeW == 0 ) {
4258             size_t inSz = self -> helper . inSz;
4259             void * tmp = NULL;
4260             if ( self -> helper . inSz == 0 )  /* buffer for names service */
4261                 self -> helper . inSz  = 1024; /*                 response */
4262             else
4263                 self -> helper . inSz *= 2;
4264             if ( self -> helper . input == NULL )
4265                 tmp = malloc ( self -> helper . inSz );
4266             else
4267                 tmp = realloc ( self -> helper . input, self -> helper . inSz );
4268             if ( tmp == NULL )
4269                 return RC
4270                     ( rcVFS, rcStorage, rcAllocating, rcMemory, rcExhausted );
4271             else
4272                 self -> helper . input = (char *) tmp;
4273             sizeW = self -> helper . inSz - inSz;
4274         }
4275         buffer = self -> helper . input;
4276         rc = KStreamTimedRead ( stream, buffer + offW, sizeW, & num_read,
4277                                 & tm );
4278         if ( rc != 0 || num_read == 0 )
4279             break;
4280         DBGMSG ( DBG_VFS, DBG_FLAG ( DBG_VFS_SERVICE ),
4281             ( "%.*s", ( int ) num_read, buffer + offW ) );
4282         sizeR += num_read;
4283         offW += num_read;
4284         assert ( sizeW >= num_read );
4285         sizeW -= num_read;
4286     }
4287     if ( rc == 0 && sizeR > 0 ) {
4288         if ( sizeW == 0 ) {
4289             void * tmp = NULL;
4290             ++ self -> helper . inSz;
4291             tmp = realloc ( self -> helper . input, self -> helper . inSz );
4292             if ( tmp == NULL )
4293                 return RC
4294                     ( rcVFS, rcStorage, rcAllocating, rcMemory, rcExhausted );
4295             else
4296                 self -> helper . input = (char *) tmp;
4297         }
4298         buffer = self -> helper . input;
4299         buffer [ offW ] = '\0';
4300         if ( self != NULL
4301             && SVersionResponseInJson(self -> req . version, self -> req .sdl)
4302             && offW > 0
4303             && buffer [ 0 ] != '#' )
4304         {
4305             start = false;
4306             rc = KServiceProcessJson ( self );
4307         }
4308         else {
4309             while ( rc == 0 ) {
4310                 char * newline = string_chr ( buffer + offR, sizeR, '\n' );
4311                 if ( newline == NULL ) {
4312                     if ( sizeR != 0 )
4313                         rc = RC ( rcVFS, rcQuery, rcExecuting,
4314                                   rcString, rcInsufficient );
4315                     break;
4316                 }
4317                 else {
4318                     size_t size = newline - ( buffer + offR );
4319                     String s;
4320                     s . addr = buffer + offR;
4321                     s . len = s . size = size;
4322                     if ( start ) {
4323                         if ( size + 1 == num_read )
4324                             DBGMSG ( DBG_VFS, DBG_FLAG ( DBG_VFS_SERVICE ),
4325                                 ( "\n" ) );
4326                         rc = SHeaderMake ( & self -> resp . header,
4327                                            & s, self -> req . serviceType );
4328                         if ( rc != 0 )
4329                             break;
4330                         start = false;
4331                     }
4332                     else {
4333                         bool end = false;
4334                         rc = KServiceProcessLine ( self, & s, & end );
4335                         if ( end || rc != 0 ) {
4336                             DBGMSG ( DBG_VFS, DBG_FLAG ( DBG_VFS_SERVICE ),
4337                                 ( "\n" ) );
4338                             break;
4339                         }
4340                     }
4341                     ++ size;
4342                     offR += size;
4343                     if ( sizeR >= size )
4344                         sizeR -= size;
4345                     else
4346                         sizeR = 0;
4347                     if ( sizeR == 0 && offR == offW ) {
4348                         offR = offW = 0;
4349                         sizeW = sizeof buffer;
4350                     }
4351                 }
4352             }
4353         }
4354     }
4355     if ( start )
4356         rc = RC ( rcVFS, rcQuery, rcExecuting, rcString, rcInsufficient );
4357     DBGMSG ( DBG_VFS, DBG_FLAG ( DBG_VFS_SERVICE ),
4358         ( "^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ "
4359           "rc = %R\n\n", rc ) );
4360     return rc;
4361 }
4362 
KServiceProcessStreamByParts(KService * self,KStream * stream)4363 static rc_t KServiceProcessStreamByParts ( KService * self,
4364                                            KStream * stream )
4365 {
4366     rc_t rc = 0, rx;
4367     bool start = true;
4368     char buffer [ 4096 ] = "";
4369     size_t num_read = 0;
4370     timeout_t tm;
4371     size_t sizeW = sizeof buffer;
4372     size_t sizeR = 0;
4373     size_t offR = 0;
4374     size_t offW = 0;
4375     char * newline = NULL;
4376     assert ( self );
4377     self -> resp . serviceType = self -> req . serviceType;
4378     rc = TimeoutInit ( & tm, self -> helper . timeoutMs );
4379 
4380     if (rc == 0) {
4381         rx = self->resp.rc;
4382         rc = SResponseFini(&self->resp);
4383     }
4384     if ( rc == 0 )
4385         rc = SResponseInit ( & self -> resp, rx );
4386 
4387     if ( rc == 0 && self -> req . serviceType == eSTsearch )
4388         rc = KartMake2 ( & self -> resp . kart );
4389 
4390     DBGMSG ( DBG_VFS, DBG_FLAG ( DBG_VFS_SERVICE ), (
4391         "-----------------------------------------------------------\n" ) );
4392 
4393     while ( rc == 0 ) {
4394         if ( sizeR == 0 ) {
4395             rc = KStreamTimedRead
4396                 ( stream, buffer + offW, sizeW, & num_read, & tm );
4397             if ( rc != 0 || num_read == 0 )
4398                 break;
4399             DBGMSG ( DBG_VFS, DBG_FLAG ( DBG_VFS_SERVICE ),
4400                 ( "%.*s", ( int ) num_read - 1, buffer + offW ) );
4401             sizeR += num_read;
4402             offW += num_read;
4403             if (sizeW >= num_read )
4404                 sizeW -= num_read;
4405             else
4406                 sizeW = 0;
4407         }
4408         newline = string_chr ( buffer + offR, sizeR, '\n' );
4409 /* TODO different conditions: move buffer content; partial read; line > buf size
4410  */
4411         if ( newline == NULL ) {
4412             if ( sizeW == 0 && offR == 0 ) {
4413                 rc = RC
4414                     ( rcVFS, rcQuery, rcExecuting, rcString, rcInsufficient );
4415                 break;
4416             }
4417             else {
4418                 memmove ( buffer, buffer + offR, sizeR );
4419                 if ( sizeR < sizeof buffer )
4420                     buffer [ sizeR ] = '\0';
4421                 sizeW = sizeof buffer - sizeR;
4422                 offR = 0;
4423                 offW = sizeR;
4424             }
4425             rc = KStreamTimedRead
4426                 ( stream, buffer + offW, sizeW, & num_read, & tm );
4427             if ( rc != 0 ) {
4428                 /* TBD - look more closely at rc */
4429                 if ( num_read > 0 )
4430                     rc = 0;
4431                 else
4432                     break;
4433             }
4434             else if ( num_read == 0 ) {
4435                 rc = RC /* stream does not end by '\n' */
4436                     ( rcVFS, rcQuery, rcExecuting, rcString, rcInsufficient );
4437                 break;
4438             }
4439             DBGMSG ( DBG_VFS, DBG_FLAG ( DBG_VFS_SERVICE ),
4440                 ( "%.*s", ( int ) num_read - 1, buffer + offW ) );
4441             sizeR += num_read;
4442             offW += num_read;
4443             if (sizeW >= num_read )
4444                 sizeW -= num_read;
4445             else
4446                 sizeW = 0;
4447         }
4448         else {
4449             size_t size = newline - ( buffer + offR );
4450             String s;
4451             s . addr = buffer + offR;
4452             s . len = s . size = size;
4453             if ( start ) {
4454                 if ( size + 1 == num_read )
4455                     DBGMSG ( DBG_VFS, DBG_FLAG ( DBG_VFS_SERVICE ), ( "\n" ) );
4456                 rc = SHeaderMake
4457                     ( & self -> resp . header, & s, self -> req . serviceType );
4458                 if ( rc != 0 )
4459                     break;
4460                 start = false;
4461             }
4462             else {
4463                 bool end = false;
4464                 rc = KServiceProcessLine ( self, & s, & end );
4465                 if ( end || rc != 0 ) {
4466                     DBGMSG ( DBG_VFS, DBG_FLAG ( DBG_VFS_SERVICE ), ( "\n" ) );
4467                     break;
4468                 }
4469             }
4470             ++ size;
4471             offR += size;
4472             if ( sizeR >= size )
4473                 sizeR -= size;
4474             else
4475                 sizeR = 0;
4476             if ( sizeR == 0 && offR == offW ) {
4477                 offR = offW = 0;
4478                 sizeW = sizeof buffer;
4479             }
4480         }
4481     }
4482     if ( start )
4483         rc = RC ( rcVFS, rcQuery, rcExecuting, rcString, rcInsufficient );
4484     DBGMSG ( DBG_VFS, DBG_FLAG ( DBG_VFS_SERVICE ),
4485         ( "^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ "
4486           "rc = %R\n\n", rc ) );
4487     return rc;
4488 }
4489 
KServiceGetResponse(const KService * self,const KSrvResponse ** response)4490 rc_t KServiceGetResponse(const KService * self,
4491     const KSrvResponse ** response)
4492 {
4493     if (self == NULL)
4494         return RC(rcVFS, rcQuery, rcExecuting, rcSelf, rcNull);
4495 
4496     if (response == NULL)
4497         return RC(rcVFS, rcQuery, rcExecuting, rcParam, rcNull);
4498     else
4499         return SResponseGetResponse(&self->resp, response);
4500 }
4501 
4502 
KServiceGetResponseCStr(const KService * self)4503 const char * KServiceGetResponseCStr(const KService * self) {
4504     if (self == NULL)
4505         return NULL;
4506     else if (self->helper.input[0] == '\0')
4507         return NULL;
4508     else
4509         return self->helper.input;
4510 }
4511 
4512 
StringRelease(const String * self)4513 static rc_t StringRelease(const String *self) {
4514     StringWhack(self);
4515     return 0;
4516 }
4517 
VPathAttachVdbcacheIfEmpty(VPath * self,const VPath * vdbcache)4518 static rc_t VPathAttachVdbcacheIfEmpty(VPath * self, const VPath * vdbcache) {
4519     if (self == NULL || vdbcache == NULL)
4520         return 0;
4521 
4522     else {
4523         const VPath * old = NULL;
4524         rc_t rc = VPathGetVdbcache(self, &old, NULL);
4525         if (rc == 0) {
4526             if (old == NULL)
4527                 rc = VPathAttachVdbcache(self, vdbcache);
4528             else
4529                 RELEASE(VPath, old);
4530         }
4531 
4532         return rc;
4533     }
4534 }
4535 
4536 typedef enum { eNcbi, eS3, eGs, eMaxCloud } EService;
4537 
VPathGetServiceId(const VPath * self,EService * rService,String * service)4538 static rc_t VPathGetServiceId(const VPath * self,
4539     EService * rService, String * service)
4540 {
4541     rc_t rc = 0;
4542 
4543     EService aService = eNcbi;
4544 
4545     String dummy;
4546 
4547     static String gs;
4548     static String s3;
4549     static bool initialized = false;
4550     if (!initialized) {
4551         CONST_STRING(&gs, "gs");
4552         CONST_STRING(&s3, "s3");
4553         initialized = true;
4554     }
4555 
4556     if (service == NULL)
4557         service = &dummy;
4558 
4559     rc = VPathGetService(self, service);
4560     if (rc == 0) {
4561         if (StringCompare(service, &s3) == 0)
4562             aService = eS3;
4563         else if (StringCompare(service, &gs) == 0)
4564             aService = eGs;
4565     }
4566 
4567     assert(rService);
4568     *rService = aService;
4569 
4570     return rc;
4571 }
4572 
KSrvRespObj_AttachVdbcaches(const KSrvRespObj * self)4573 static rc_t KSrvRespObj_AttachVdbcaches(const KSrvRespObj * self) {
4574     rc_t rc = 0, rx = 0;
4575 
4576     KSrvRespObjIterator * it = NULL;
4577     int i = 0, nSrrr = 0, nVdbc = 0;
4578     const String * acc = NULL;
4579     VPath * aSrr = NULL;
4580     const VPath * aVdbc = NULL;
4581     EService aService = eNcbi;
4582 
4583     String sra, vdbcache;
4584 
4585     VPath * srr[eMaxCloud];
4586     const VPath * vdbc[eMaxCloud];
4587     for (i = 0; i < sizeof srr / sizeof srr[0]; ++i)
4588         srr[i] = NULL;
4589     for (i = 0; i < sizeof vdbc / sizeof vdbc[0]; ++i)
4590         vdbc[i] = NULL;
4591 
4592     CONST_STRING(&sra, "sra");
4593     CONST_STRING(&vdbcache, "vdbcache");
4594 
4595     rc = KSrvRespObjGetError(self, &rx, NULL, NULL);
4596 
4597     if (rx == 0)
4598         rc = KSrvRespObjMakeIterator(self, &it);
4599  /* else  error in names service response for this KSrvRespObj: skipping */
4600 
4601     while (rx == 0 && rc == 0) {
4602         KSrvRespFile * file = NULL;
4603         KSrvRespFileIterator * fi = NULL;
4604 
4605         rc = KSrvRespObjIteratorNextFile(it, &file);
4606         if (rc != 0 || file == NULL)
4607             break;
4608 
4609         rc = KSrvRespFileMakeIterator(file, &fi);
4610 
4611         while (rc == 0) {
4612             enum { eOther, eSra, eVdbcache } aType = eOther;
4613 
4614             String id, nameExt, service, type;
4615 
4616             VPath * next = NULL;
4617             rc = KSrvRespFileIteratorNextPath(fi, (const VPath **)& next);
4618             if (rc != 0 || next == NULL)
4619                 break;
4620 
4621             rc = VPathGetId(next, &id);
4622             if (rc == 0)
4623                 rc = VPathGetType(next, &type);
4624             if (rc == 0)
4625                 rc = VPathGetServiceId(next, &aService, &service);
4626 
4627             if (rc == 0) {
4628                 if (acc == NULL)
4629                     rc = StringCopy(&acc, &id);
4630                 else if (StringCompare(acc, &id) != 0)
4631                     PLOGERR(klogFatal, (klogFatal,
4632                         RC(rcVFS, rcQuery, rcExecuting, rcString, rcUnexpected),
4633                         "multiple accessions for the same bundle: "
4634                         "'$(acc1), $(acc2)", "acc1=%S,acc2=%S", acc, &id));
4635             }
4636 
4637             if (rc == 0) {
4638                 if (StringCompare(&type, &sra) == 0) {
4639                     rc = VPathGetNameExt(next, &nameExt);
4640                     if (rc == 0 && nameExt.size == 0)
4641                         aType = eSra;
4642                 }
4643                 else if (StringCompare(&type, &vdbcache) == 0)
4644                     aType = eVdbcache;
4645             }
4646 
4647             switch (aType) {
4648             case eSra:
4649                 ++nSrrr;
4650                 if (aSrr == NULL)
4651                     aSrr = next;
4652                 if (srr[aService] == NULL)
4653                     srr[aService] = next;
4654                 else
4655                 {
4656                     PLOGERR(klogFatal, (klogFatal,
4657                         RC(rcVFS, rcQuery, rcExecuting, rcString, rcUnexpected),
4658                         "multiple response SRR URLs for the same service "
4659                         "'$(service)'", "service=%S", &service));
4660                     VPathRelease ( next );
4661                 }
4662                 break;
4663             case eVdbcache:
4664                 ++nVdbc;
4665                 if (aVdbc == NULL)
4666                     aVdbc = next;
4667                 if (vdbc[aService] == NULL)
4668                     vdbc[aService] = next;
4669                 else
4670                 {
4671                     PLOGERR(klogFatal, (klogFatal,
4672                         RC(rcVFS, rcQuery, rcExecuting, rcString, rcUnexpected),
4673                         "multiple response VDBCACHE URLs for the same service "
4674                         "'$(service)", "service=%S", &service));
4675                     VPathRelease ( next );
4676                 }
4677                 break;
4678             case eOther:
4679                 VPathRelease ( next );
4680                 break;
4681             default:
4682                 assert(0);
4683                 break;
4684             }
4685         }
4686 
4687         RELEASE(KSrvRespFile, file);
4688         RELEASE(KSrvRespFileIterator, fi);
4689     }
4690     RELEASE(String, acc);
4691     RELEASE(KSrvRespObjIterator, it);
4692 
4693     if (nVdbc > 0) {
4694         if (nVdbc == 1) {
4695             if (nSrrr == 1)
4696                 rc = VPathAttachVdbcacheIfEmpty(aSrr, aVdbc);
4697             else
4698                 for (i = 0; rc == 0 && i < sizeof srr / sizeof srr[0]; ++i)
4699                     rc = VPathAttachVdbcacheIfEmpty(srr[i], aVdbc);
4700         }
4701         else if (nSrrr == 1)
4702             for (i = 0; rc == 0 && i < sizeof vdbc / sizeof vdbc[0]; ++i)
4703                 rc = VPathAttachVdbcacheIfEmpty(aSrr, vdbc[i]);
4704         else
4705             for (i = 0; rc == 0 && i < sizeof srr / sizeof srr[0]; ++i)
4706                 if (srr[i] != NULL) {
4707                     const VPath * v = NULL;
4708                     switch (i) {
4709                     case eNcbi:
4710                         if (vdbc[eNcbi] != NULL)
4711                             v = vdbc[eNcbi];
4712                         else if (vdbc[eS3] != NULL)
4713                             v = vdbc[eS3];
4714                         else
4715                             v = vdbc[eGs];
4716                         break;
4717                     case eS3:
4718                         if (vdbc[eS3] != NULL)
4719                             v = vdbc[eS3];
4720                         else if (vdbc[eNcbi] != NULL)
4721                             v = vdbc[eNcbi];
4722                         else
4723                             v = vdbc[eGs];
4724                         break;
4725                     case eGs:
4726                         if (vdbc[eGs] != NULL)
4727                             v = vdbc[eGs];
4728                         else if (vdbc[eNcbi] != NULL)
4729                             v = vdbc[eNcbi];
4730                         else
4731                             v = vdbc[eS3];
4732                         break;
4733                     default:
4734                         assert(0);
4735                         break;
4736                     }
4737                     rc = VPathAttachVdbcacheIfEmpty(srr[i], v);
4738                 }
4739     }
4740     else
4741         if (nSrrr == 1)
4742             rc = VPathAttachVdbcache(aSrr, NULL);
4743         else
4744             for (i = 0; rc == 0 && i < sizeof srr / sizeof srr[0]; ++i)
4745                 if (srr[i] != NULL)
4746                     rc = VPathAttachVdbcache(srr[i], NULL);
4747 
4748     for (i = 0; i < sizeof srr / sizeof srr[0]; ++i)
4749         RELEASE(VPath, srr[i]);
4750     for (i = 0; i < sizeof vdbc / sizeof vdbc[0]; ++i)
4751         RELEASE(VPath, vdbc[i]);
4752 
4753     return rc;
4754 }
4755 
KServiceAddIdToCache(KService * self,const char * objId)4756 static rc_t KServiceAddIdToCache(KService * self, const char * objId) {
4757     rc_t rc = 0;
4758     ServicesCache * cache = NULL;
4759     int32_t q = -1;
4760     KServiceGetQuality(self, &q);
4761     if (q >= eQualLast || q < 0)
4762         return 0;
4763     if (!KServiceCallsSdl(self))
4764         return 0;
4765     rc = KServiceGetServiceCache(self, &cache);
4766     if (rc == 0)
4767         rc = ServicesCacheAddId(cache, objId);
4768     return rc;
4769 }
4770 
4771 static
KServiceProcessStream(KService * self,KStream * stream)4772 rc_t KServiceProcessStream ( KService * self, KStream * stream )
4773 {
4774     rc_t rc = 0;
4775 
4776     uint32_t i = 0;
4777 
4778     Response4 * r4 = NULL;
4779 
4780     const char * magic = getenv(ENV_MAGIC_REMOTE);
4781     const char * objectId = NULL;
4782 
4783     assert ( self );
4784 
4785     if (magic != NULL) {
4786         if (self->req.request.objects != 1) {
4787             DBGMSG(DBG_VFS, DBG_FLAG(DBG_VFS_PATH), ("%s: '%s' magic ignored "
4788                 "when multiple objects in query\n",
4789                 __func__, ENV_MAGIC_REMOTE));
4790             magic = NULL;
4791         }
4792         else {
4793             const char * o = self->req.request.object[0].objectId;
4794             objectId = o;
4795             if (o != NULL && o[0] != '\0' && o[1] != 'R' && o[2] != 'R') {
4796                 DBGMSG(DBG_VFS, DBG_FLAG(DBG_VFS_PATH), ("%s: '%s' magic "
4797                     "ignored for non-runs\n", __func__, ENV_MAGIC_REMOTE));
4798                 magic = NULL;
4799             }
4800         }
4801     }
4802 
4803     if ( self -> req . request. objects == 0 && self->req.jwtKartFile == NULL )
4804         return RC ( rcVFS, rcQuery, rcExecuting, rcString, rcInsufficient );
4805     else if ( self -> req . hasQuery
4806            || self -> req . serviceType == eSTsearch )
4807     {
4808         if (magic != NULL)
4809             rc = KServiceAddIdToCache(self, objectId);
4810         else if ( SVersionResponseInJson (self -> req . version,
4811             self -> req . sdl) )
4812         {
4813             rc = KServiceProcessStreamAll     ( self, stream );
4814         }
4815         else
4816             rc = KServiceProcessStreamByParts ( self, stream );
4817     }
4818 
4819     if ( rc == 0 )
4820         rc = KSrvResponseGetR4 ( self -> resp .list, & r4 );
4821 
4822     if (rc == 0 && r4 == NULL)
4823         rc = Response4MakeEmpty(&r4, NULL, NULL, NULL,
4824             sLogNamesServiceErrors, -1, 0);
4825 
4826     for ( i = 0; rc == 0 && i < self -> req . request . objects; ++ i )
4827         if ( self -> req . request . object [ i ] . isUri )
4828             rc = Response4AppendUrl ( r4,
4829                 self -> req . request . object [ i ] . objectId );
4830 
4831     if (rc == 0) {
4832         uint32_t i = 0;
4833         if (SVersionResponseInJson(self->req.version, self->req.sdl)) {
4834             uint32_t l = 0;
4835             /* attach vdbcache */
4836             const KSrvResponse * response = NULL;
4837             if (rc == 0)
4838                 rc = KServiceGetResponse(self, &response);
4839             if (rc == 0)
4840                 l = KSrvResponseLength(response);
4841             for (i = 0; rc == 0 && i < l; ++i) {
4842                 const KSrvRespObj * obj = NULL;
4843                 rc = KSrvResponseGetObjByIdx(response, i, &obj);
4844                 if (rc == 0)
4845                     rc = KSrvRespObj_AttachVdbcaches(obj);
4846                 RELEASE(KSrvRespObj, obj);
4847             }
4848             RELEASE(KSrvResponse, response);
4849         }
4850 
4851         else {
4852             uint32_t l = KSrvResponseLength(self->resp.list);
4853             for (i = 0; rc == 0 && i < l; ++i) {
4854                 Container * box = NULL;
4855                 Item * file = NULL;
4856                 const char * reqId = NULL;
4857                 const char * respId = NULL;
4858                 VRemoteProtocols pp[]
4859                     = { eProtocolHttp, eProtocolFasp, eProtocolHttps };
4860                 uint32_t p = 0;
4861                 const VPath * mapping = NULL;
4862                 const VPath * vdbcacheMapping = NULL;
4863                 rc = KSrvResponseGetIds(self->resp.list, i, &reqId,
4864                     &respId);
4865                 if (rc == 0)
4866                     rc = Response4AddAccOrId(r4, reqId, -1, &box);
4867                 if (rc == 0)
4868                     ContainerAdd(box, respId, -1, &file, NULL);
4869                 if (rc != 0)
4870                     break;
4871                 if (rc == 0)
4872                     rc = KSrvResponseGetMapping(
4873                         self->resp.list, i, &mapping, &vdbcacheMapping);
4874                 for (p = 0; rc == 0 && p < sizeof pp / sizeof pp[0]; ++p) {
4875                     const VPath * path = NULL;
4876                     const VPath * vdbcache = NULL;
4877                     const KSrvError * error = NULL;
4878                     uint64_t osize = 0;
4879                     rc = KSrvResponseGetPath(self->resp.list, i, pp[p],
4880                         &path, &vdbcache, &error);
4881                     if (rc == 0)
4882                         rc = KSrvResponseGetOSize(self->resp.list, i, &osize);
4883                     if (rc == 0) {
4884                         if (path != NULL) {
4885                             String ticket;
4886                             rc_t r = 0;
4887                             memset(&ticket, 0, sizeof ticket);
4888                             r = VPathGetTicket(path, &ticket);
4889                             if (r == 0)
4890                                 rc = ItemSetTicket(file, &ticket);
4891                             if (rc == 0)
4892                                 rc = ItemAddVPath(file, "sra", path,
4893                                     mapping, true, osize);
4894                             RELEASE(VPath, path);
4895                             if (rc != 0)
4896                                 break;
4897                         }
4898                         if (rc == 0 && vdbcache != NULL) {
4899                             rc = ItemAddVPath(file, "vdbcache", vdbcache,
4900                                 vdbcacheMapping, true, 0);
4901                             RELEASE(VPath, vdbcache);
4902                             if (rc != 0)
4903                                 break;
4904                         }
4905                     }
4906 
4907                     RELEASE(VPath, path);
4908                     RELEASE(VPath, vdbcache);
4909                     RELEASE(KSrvError, error);
4910                     RELEASE(VPath, mapping);
4911 
4912                     if (rc != 0)
4913                     {
4914                         break;
4915                     }
4916 
4917                 }
4918                 RELEASE(VPath, mapping);
4919                 RELEASE(VPath, vdbcacheMapping);
4920             }
4921         }
4922     }
4923 
4924     if (rc == 0)
4925         rc = KSrvResponseSetR4(self->resp.list, r4);
4926 
4927     RELEASE(Response4, r4);
4928 
4929     return rc;
4930 }
4931 
KServiceGetServiceCache(KService * self,struct ServicesCache ** cache)4932 rc_t KServiceGetServiceCache(KService * self,
4933     struct ServicesCache ** cache)
4934 {
4935     rc_t rc = 0;
4936     Response4 * r4 = NULL;
4937     assert(self);
4938     rc = KSrvResponseGetR4(self->resp.list, &r4);
4939     if (rc == 0 && r4 == NULL) {
4940         rc = Response4MakeEmpty(&r4, self->helper.vMgr, self->helper.kMgr,
4941             self->helper.kfg, sLogNamesServiceErrors, -1, self->quality);
4942         if (rc == 0)
4943             rc = KSrvResponseSetR4(self->resp.list, r4);
4944     }
4945     if (rc == 0)
4946         rc = KSrvResponseGetServiceCache(self->resp.list, cache);
4947     RELEASE(Response4, r4);
4948     return rc;
4949 }
4950 
KServiceAddLocalAndCacheToResponse(KService * self,const char * acc,const VPathSet * vps)4951 rc_t KServiceAddLocalAndCacheToResponse(KService * self,
4952     const char * acc, const VPathSet * vps)
4953 {
4954     rc_t rc = 0;
4955 
4956     Response4 * r4 = NULL;
4957 
4958     assert(self);
4959 
4960     rc = KSrvResponseGetR4(self->resp.list, &r4);
4961 
4962     if (rc == 0 && r4 == NULL)
4963         rc = Response4MakeEmpty(&r4, self->helper.vMgr, self->helper.kMgr,
4964             self->helper.kfg, sLogNamesServiceErrors, -1, self->quality);
4965 
4966     if (rc == 0) {
4967         const VFSManager * mgr = NULL;
4968         rc = KServiceGetVFSManager(self, &mgr);
4969         if (rc == 0)
4970             rc = Response4AppendLocalAndCache(r4, acc, vps, mgr);
4971         RELEASE(VFSManager, mgr);
4972     }
4973 
4974     if (rc == 0)
4975         rc = KSrvResponseSetR4(self->resp.list, r4);
4976 
4977     RELEASE(Response4, r4);
4978 
4979     return rc;
4980 }
4981 
KServiceSetQuality(KService * self,VQuality quality)4982 rc_t KServiceSetQuality(KService * self, VQuality quality) {
4983     assert(self);
4984     self->quality = quality;
4985     return 0;
4986 }
4987 
KServiceGetQuality(const KService * self,int32_t * quality)4988 rc_t KServiceGetQuality(const KService * self, int32_t * quality) {
4989     assert(quality);
4990 
4991     *quality = -1;
4992 
4993     if (self == NULL)
4994         return RC(rcVFS, rcQuery, rcExecuting, rcSelf, rcNull);
4995 
4996     *quality = self->quality;
4997     return 0;
4998 }
4999 
KServiceGetConfig(struct KService * self,const KConfig ** kfg)5000 rc_t KServiceGetConfig ( struct KService * self, const KConfig ** kfg) {
5001     rc_t rc = 0;
5002 
5003     if ( self == NULL )
5004         return RC ( rcVFS, rcQuery, rcExecuting, rcSelf, rcNull );
5005     if ( kfg == NULL )
5006         return RC ( rcVFS, rcQuery, rcExecuting, rcParam, rcNull );
5007 
5008     rc = SHelperInitKfg ( & self -> helper );
5009     if ( rc == 0 )
5010         rc = KConfigAddRef ( self -> helper . kfg );
5011 
5012     if ( rc == 0 )
5013         * kfg = self -> helper . kfg;
5014 
5015     return rc;
5016 }
5017 
KServiceGetResolverForProject(KService * self,uint32_t project,VResolver ** resolver)5018 rc_t KServiceGetResolverForProject(KService * self, uint32_t project,
5019     VResolver ** resolver)
5020 {
5021     rc_t rc = 0;
5022     const KRepository * r = NULL;
5023 
5024     assert(self);
5025 
5026     rc = SHelperInitRepoMgr(&self->helper);
5027     if (rc != 0)
5028         return rc;
5029 
5030     rc = KRepositoryMgrGetProtectedRepository(
5031         self->helper.repoMgr, project, &r);
5032     if (rc != 0)
5033         return rc;
5034 
5035     rc = KRepositoryMakeResolver(r, resolver, self->helper.kfg);
5036 
5037     RELEASE(KRepository, r);
5038 
5039     return rc;
5040 }
5041 
KServiceGetVFSManager(const KService * self,const VFSManager ** mgr)5042 rc_t KServiceGetVFSManager(const KService * self,
5043     const VFSManager ** mgr)
5044 {
5045     rc_t rc = 0;
5046 
5047     if (self == NULL)
5048         return RC(rcVFS, rcQuery, rcExecuting, rcSelf, rcNull);
5049     if (mgr == NULL)
5050         return RC(rcVFS, rcQuery, rcExecuting, rcParam, rcNull);
5051 
5052     if (self->helper.vMgr == NULL)
5053         rc = VFSManagerMakeFromKns((VFSManager**)(&self->helper.vMgr),
5054             (KConfig*)self->helper.kfg, (KNSManager*)self->helper.kMgr);
5055 
5056     if (rc == 0)
5057         rc = VFSManagerAddRef(self->helper.vMgr);
5058 
5059     if (rc == 0)
5060         * mgr = self->helper.vMgr;
5061 
5062     return rc;
5063 }
5064 
KServiceGetResolver(KService * self,const String * ticket,VResolver ** resolver)5065 rc_t KServiceGetResolver ( KService * self, const String * ticket,
5066                            VResolver ** resolver )
5067 {
5068     uint32_t project = 0;
5069 
5070     if ( self == NULL || ticket == NULL || ticket -> addr == NULL
5071                       || ticket -> size == 0 || resolver == NULL)
5072     {
5073         return 0;
5074     }
5075     else {
5076         const BSTItem * i = ( BSTItem * ) BSTreeFind
5077             ( & self -> req . tickets . ticketsToProjects, ticket, BSTItemCmp );
5078         if ( i == NULL )
5079             return 0;
5080 
5081         project = i -> project;
5082     }
5083 
5084     * resolver = NULL;
5085 
5086     if ( project != 0 ) {
5087         const KRepository * r = NULL;
5088         rc_t rc = SHelperInitRepoMgr ( & self -> helper );
5089         if ( rc != 0 )
5090             return rc;
5091 
5092         rc = KRepositoryMgrGetProtectedRepository
5093             ( self -> helper . repoMgr,  project, & r );
5094         if ( rc != 0 )
5095             return rc;
5096 
5097         rc = KRepositoryMakeResolver ( r, resolver, self -> helper . kfg );
5098 
5099         RELEASE ( KRepository, r );
5100 
5101         return rc;
5102     }
5103 
5104     return 0;
5105 }
5106 
5107 
KServiceResolve(KService * self,bool local,bool remote)5108 rc_t KServiceResolve(KService * self, bool local, bool remote) {
5109     assert(self);
5110 
5111     self->skipLocal = !local;
5112     self->skipRemote = !remote;
5113 
5114     return 0;
5115 }
5116 
KServiceSkipLocal(const KService * self)5117 bool KServiceSkipLocal(const KService * self) {
5118     assert(self);
5119     return self->skipLocal;
5120 }
5121 
KServiceNamesExecuteExtImpl(KService * self,VRemoteProtocols protocols,const char * cgi,const char * version,const KSrvResponse ** response,const char * expected)5122 rc_t KServiceNamesExecuteExtImpl ( KService * self, VRemoteProtocols protocols,
5123     const char * cgi, const char * version,
5124     const KSrvResponse ** response, const char * expected )
5125 {
5126     rc_t rc = 0;
5127 
5128     KStream * stream = NULL;
5129 
5130     if ( self == NULL )
5131         return RC ( rcVFS, rcQuery, rcExecuting, rcSelf, rcNull );
5132 
5133     if ( response == NULL )
5134         return RC ( rcVFS, rcQuery, rcExecuting, rcParam, rcNull );
5135 
5136     if ( version == NULL )
5137         version = "130";
5138 
5139     rc = KServiceInitNamesRequestWithVersion ( self, protocols, cgi, version,
5140         false, expected == NULL );
5141 
5142     if (rc == 0 && self->req.disabled) {
5143         DBGMSG(DBG_VFS, DBG_FLAG(DBG_VFS_SERVICE), (
5144             "XXXXXXXXXXXX NOT sending HTTP request XXXXXXXXXXXXXXXXXXXXX\n"));
5145         return RC(rcVFS, rcQuery, rcResolving, rcName, rcNotFound);
5146     }
5147 
5148     if (rc == 0 && self->req.hasQuery)
5149         rc = SCgiRequestPerform(&self->req.cgiReq, &self->helper,
5150             &stream, expected, self);
5151 
5152     if ( rc == 0 )
5153         rc = KServiceProcessStream ( self, stream );
5154 
5155     if ( rc == 0 )
5156         rc = KServiceGetResponse ( self, response );
5157 
5158     RELEASE ( KStream, stream );
5159 
5160     return rc;
5161 }
5162 
5163 
5164 /* Emulate Names Service Call :
5165    - prepare the request;
5166    - use "expected" instead of calling "cgi"
5167    - parse "expected" as "cgi" response */
KServiceTestNamesExecuteExt(KService * self,VRemoteProtocols protocols,const char * cgi,const char * version,const struct KSrvResponse ** response,const char * expected)5168 rc_t KServiceTestNamesExecuteExt ( KService * self, VRemoteProtocols protocols,
5169     const char * cgi, const char * version,
5170     const struct KSrvResponse ** response, const char * expected )
5171 {
5172     return KServiceNamesExecuteExtImpl ( self, protocols, cgi, version,
5173         response, expected );
5174 }
5175 
5176 
5177 /* Execute Names Service Call : extended version */
KServiceNamesExecuteExt(KService * self,VRemoteProtocols protocols,const char * cgi,const char * version,const KSrvResponse ** response)5178 rc_t KServiceNamesExecuteExt ( KService * self, VRemoteProtocols protocols,
5179     const char * cgi, const char * version,
5180     const KSrvResponse ** response )
5181 {
5182     return KServiceNamesExecuteExtImpl ( self, protocols, cgi, version,
5183         response, NULL );
5184 }
5185 
5186 
5187 /* Execute Names Service Call using current default protocol version;
5188    get KSrvResponse */
KServiceNamesExecute(KService * self,VRemoteProtocols protocols,const KSrvResponse ** response)5189 rc_t KServiceNamesExecute ( KService * self, VRemoteProtocols protocols,
5190     const KSrvResponse ** response )
5191 {
5192     return KServiceNamesExecuteExt ( self, protocols, NULL, NULL, response );
5193 }
5194 
5195 
KService1NameWithVersionAndType(const KNSManager * mgr,const char * url,const char * acc,size_t acc_sz,const char * ticket,VRemoteProtocols protocols,const VPath ** remote,const VPath ** mapping,bool refseq_ctx,const char * version,EObjectType objectType,bool aProtected)5196 static rc_t KService1NameWithVersionAndType ( const KNSManager * mgr,
5197     const char * url, const char * acc, size_t acc_sz, const char * ticket,
5198     VRemoteProtocols protocols, const VPath ** remote,  const VPath ** mapping,
5199     bool refseq_ctx, const char * version, EObjectType objectType,
5200     bool aProtected )
5201 {
5202     rc_t rc = 0;
5203 
5204     KStream * stream = NULL;
5205 
5206     KService service;
5207 
5208     if ( acc == NULL || remote == NULL )
5209         return RC ( rcVFS, rcQuery, rcExecuting, rcParam, rcNull );
5210 
5211     rc = KServiceInitNames1 ( & service, mgr, url, version,
5212         acc, acc_sz, ticket, protocols, objectType, refseq_ctx, aProtected );
5213 
5214     protocols = service . req . protocols;
5215 
5216     if (rc == 0) {
5217         rc_t rx = 0;
5218         rc = SCgiRequestPerform(&service.req.cgiReq, &service.helper,
5219             &stream, NULL, &service);
5220         if (rc == 0)
5221             service.resp.rc = rx;
5222     }
5223 
5224     if ( rc == 0 )
5225         rc = KServiceProcessStream ( & service, stream );
5226 
5227     if ( rc == 0 ) {
5228         if ( SVersionResponseInJson ( service . req . version,
5229             service . req . sdl ) )
5230         {
5231             uint32_t n = 0;
5232             const KSrvResponse * response = NULL;
5233             const KSrvRespObj * obj = NULL;
5234             KSrvRespObjIterator * it = NULL;
5235             KSrvRespFile * file = NULL;
5236             KSrvRespFileIterator * fi = NULL;
5237             bool ok = false;
5238             String vdbcache;
5239             CONST_STRING(&vdbcache, "vdbcache");
5240             assert(remote);
5241             *remote = NULL;
5242             rc = KServiceGetResponse ( & service, & response );
5243             if ( rc == 0 ) {
5244                 n = KSrvResponseLength  ( response );
5245                 if ( n != 1 )
5246                     rc = RC ( rcVFS, rcQuery, rcExecuting, rcRow, rcIncorrect );
5247             }
5248             if ( rc == 0 )
5249                 rc = KSrvResponseGetObjByIdx ( response, 0, & obj );
5250             if ( rc == 0 )
5251                 rc = KSrvRespObjMakeIterator ( obj, & it );
5252             while (rc == 0 && !ok) {
5253                 rc = KSrvRespObjIteratorNextFile(it, &file);
5254                 if (rc == 0 && file != NULL)
5255                     rc = KSrvRespFileMakeIterator(file, &fi);
5256                 if (rc == 0) {
5257                     const VPath * tmp = NULL;
5258                     String type;
5259                     rc = KSrvRespFileIteratorNextPath(fi, &tmp);
5260                     if (rc == 0 && tmp != NULL) {
5261                         rc = VPathGetType(tmp, &type);
5262                         if (rc == 0)
5263                             if (!StringEqual(&type, &vdbcache))
5264                                 ok = true;
5265                     }
5266                     if (*remote == NULL)
5267                         *remote = tmp;
5268                     else if (ok) {
5269                         if (*remote != tmp)
5270                             RELEASE(VPath, *remote);
5271                         *remote = tmp;
5272                     }
5273                     else
5274                         RELEASE(VPath, tmp);
5275                 }
5276             }
5277             if ( rc == 0 && mapping != NULL )
5278                 rc = KSrvRespFileGetMapping ( file, mapping );
5279             RELEASE ( KSrvRespFileIterator, fi );
5280             RELEASE ( KSrvRespFile, file );
5281             RELEASE ( KSrvRespObjIterator, it );
5282             RELEASE ( KSrvRespObj, obj );
5283             RELEASE ( KSrvResponse, response );
5284         }
5285         else if ( VectorLength ( & service . resp . rows ) != 1 )
5286             rc = RC ( rcVFS, rcQuery, rcExecuting, rcRow, rcIncorrect );
5287         else {
5288             uint32_t l = KSrvResponseLength ( service . resp . list );
5289             if ( rc == 0 ) {
5290                 if ( l != 1 )
5291                     rc = RC ( rcVFS, rcQuery, rcExecuting, rcRow, rcIncorrect );
5292                 else {
5293                     const KSrvError * error = NULL;
5294                     rc = KSrvResponseGetPath ( service . resp . list, 0,
5295                         protocols, NULL, NULL, & error );
5296                     if ( rc == 0 && error != NULL ) {
5297                         KSrvErrorRc ( error, & rc );
5298                         KSrvErrorRelease ( error );
5299                     }
5300                     else {
5301                         const SRow * r =
5302                             ( SRow * ) VectorGet ( & service . resp . rows, 0 );
5303                         if ( r == NULL)
5304                             rc = RC
5305                                 ( rcVFS, rcQuery, rcExecuting, rcRow, rcNull );
5306                         else {
5307                             const VPath * path = NULL;
5308                             VRemoteProtocols protos = protocols;
5309                             int i = 0;
5310                             for ( i = 0; protos != 0 && i < eProtocolMaxPref;
5311                                   protos >>= 3, ++ i )
5312                             {
5313                                 switch ( protos & eProtocolMask ) {
5314                                     case eProtocolHttp:
5315                                         path = r -> path . http;
5316                                         break;
5317                                     case eProtocolFasp:
5318                                         path = r -> path . fasp;
5319                                         break;
5320                                     case eProtocolHttps:
5321                                         path = r -> path . https;
5322                                         break;
5323                                 }
5324                                 if ( path != NULL )
5325                                     break;
5326                             }
5327 
5328               /* in early versions of protocol only http path was initialized */
5329                             if ( path == NULL )
5330                                 path = r -> path . http;
5331 
5332                             rc = VPathAddRef ( path );
5333                             if ( rc == 0 )
5334                                 * remote = path;
5335                             if ( mapping ) {
5336                                 path = r -> path . mapping;
5337                                 rc = VPathAddRef ( path );
5338                                 if ( rc == 0 )
5339                                     * mapping = path;
5340                             }
5341                         }
5342                     }
5343                 }
5344             }
5345         }
5346     }
5347 
5348     if ( rc == 0 &&
5349         ! SVersionResponseInJson(service . req . version, service . req . sdl) )
5350     {
5351         uint32_t l = KSrvResponseLength ( service . resp . list );
5352         if ( l != 1)
5353             rc = RC ( rcVFS, rcQuery, rcResolving, rcQuery, rcUnauthorized );
5354         else {
5355             const VPathSet * s = NULL;
5356             rc = KSrvResponseGet ( service . resp . list, 0, & s );
5357             if ( rc != 0 ) {
5358             }
5359             else if ( s == NULL )
5360                 rc = RC ( rcVFS, rcQuery, rcExecuting, rcRow, rcIncorrect );
5361             else {
5362                 const VPath * path = NULL;
5363                 const VPath * cache = NULL;
5364                 rc = VPathSetGet ( s, protocols, & path, & cache );
5365                 if ( rc == 0 ) {
5366                     int notequal = ~ 0;
5367                     assert ( remote );
5368                     rc = VPathEqual ( * remote, path, & notequal );
5369                     if ( rc == 0 )
5370                         rc = notequal;
5371                     RELEASE ( VPath, cache );
5372                     RELEASE ( VPath, path );
5373                 }
5374             }
5375             RELEASE ( VPathSet, s );
5376         }
5377     }
5378 
5379     {
5380         rc_t r2 = KServiceFini ( & service );
5381         if ( rc == 0 )
5382             rc = r2;
5383     }
5384 
5385     RELEASE ( KStream, stream );
5386 
5387     return rc;
5388 }
5389 
5390 
5391 /* make name service call : request: 1 object, response: 1 object */
5392 LIB_EXPORT
KService1NameWithVersion(const KNSManager * mgr,const char * url,const char * acc,size_t acc_sz,const char * ticket,VRemoteProtocols protocols,const VPath ** remote,const VPath ** mapping,bool refseq_ctx,const char * version,bool aProtected)5393 rc_t CC KService1NameWithVersion ( const KNSManager * mgr, const char * url,
5394     const char * acc, size_t acc_sz, const char * ticket,
5395     VRemoteProtocols protocols, const VPath ** remote, const VPath ** mapping,
5396     bool refseq_ctx, const char * version, bool aProtected )
5397 {
5398     if ( version == NULL )
5399         return RC ( rcVFS, rcQuery, rcExecuting, rcParam, rcNull );
5400 
5401     return KService1NameWithVersionAndType ( mgr, url, acc, acc_sz, ticket,
5402         protocols, remote, mapping, refseq_ctx, version, eOT_undefined,
5403         aProtected );
5404 }
5405 
5406 
5407 /* Execute Search Service Call : extended version */
KServiceSearchExecuteExt(KService * self,const char * cgi,const char * version,const Kart ** result)5408 rc_t KServiceSearchExecuteExt ( KService * self, const char * cgi,
5409     const char * version, const Kart ** result )
5410 {
5411     rc_t rc = 0;
5412 
5413     KStream * stream = NULL;
5414 
5415     if ( self == NULL )
5416         return RC ( rcVFS, rcQuery, rcExecuting, rcSelf, rcNull );
5417 
5418     if ( result == NULL )
5419         return RC ( rcVFS, rcQuery, rcExecuting, rcParam, rcNull );
5420 
5421     if ( version == NULL )
5422         version = "1";
5423 
5424     rc = KServiceInitSearchRequestWithVersion ( self, cgi, version );
5425 
5426     if (rc == 0) {
5427         rc_t rx = 0;
5428         rc = SCgiRequestPerform(&self->req.cgiReq, &self->helper,
5429             &stream, NULL, self);
5430         if (rc == 0)
5431             self->resp.rc = rx;
5432     }
5433 
5434     if ( rc == 0 )
5435         rc = KServiceProcessStream ( self, stream );
5436 
5437     if ( rc == 0 ) {
5438         rc = KartAddRef ( self -> resp . kart );
5439         if ( rc == 0 )
5440             * result = self -> resp . kart;
5441     }
5442 
5443     RELEASE ( KStream, stream );
5444 
5445     return rc;
5446 }
5447 
5448 
5449 /* Execute Search Service Call; get Kart response */
KServiceSearchExecute(KService * self,const Kart ** response)5450 rc_t KServiceSearchExecute ( KService * self, const Kart ** response ) {
5451     return KServiceSearchExecuteExt ( self, NULL, NULL, response );
5452 }
5453 
5454 
5455 /* Execute a simple ( one accession in request ) Search Service Call;
5456    get Kart response */
KService1Search(const KNSManager * mgr,const char * cgi,const char * acc,const Kart ** result)5457 rc_t KService1Search ( const KNSManager * mgr, const char * cgi,
5458     const char * acc, const Kart ** result )
5459 {
5460     rc_t rc = 0;
5461 
5462     KService service;
5463 
5464     rc = KServiceInit ( & service, NULL, mgr, NULL );
5465 
5466     if ( rc == 0 )
5467         rc = KServiceAddId ( & service, acc );
5468 
5469     if ( rc == 0 )
5470         rc = KServiceSearchExecute ( & service, result );
5471 
5472     {
5473         rc_t r2 = KServiceFini ( & service );
5474         if ( rc == 0 )
5475             rc = r2;
5476     }
5477     return rc;
5478 }
5479 
5480 /* resolve mapping id -> file nime inside of VFS */
KServiceResolveName(KService * self,int resolve)5481 rc_t KServiceResolveName ( KService * self, int resolve ) {
5482     if ( self == NULL )
5483         return RC ( rcVFS, rcResolver, rcUpdating, rcSelf, rcNull );
5484 
5485     switch ( resolve ) {
5486         case 0 : self -> resoveOidName = DEFAULT_RESOVE_OID_NAME; break;
5487         case 1 : self -> resoveOidName = true                   ; break;
5488         default: self -> resoveOidName = false                  ; break;
5489     }
5490     return 0;
5491 }
5492 
KServiceGetResolveName(const KService * self)5493 int KServiceGetResolveName ( const KService * self ) {
5494     if ( self == NULL )
5495         return DEFAULT_RESOVE_OID_NAME;
5496     if ( self -> resoveOidName )
5497         return 1;
5498     else
5499         return 2;
5500 }
5501 
5502 /* TESTS **********************************************************************/
5503 typedef struct {
5504     rc_t passed;
5505     const char * acc;
5506     const char * version;
5507     VRemoteProtocols protocols;
5508 } SKVCheck;
5509 
SCgiRequestCheck(void * item,void * data)5510 static void SCgiRequestCheck ( void * item, void * data ) {
5511  /* const SKV * kv = ( SKV      * ) item; */
5512     SKVCheck  * p  = ( SKVCheck * ) data;
5513     assert ( p );
5514     p -> passed = 0;
5515 }
5516 
SKVCheckInit(SKVCheck * self,const char * acc,const char * version,VRemoteProtocols protocols)5517 static void SKVCheckInit ( SKVCheck * self, const char * acc,
5518     const char * version, VRemoteProtocols protocols )
5519 {
5520     assert ( self );
5521     memset ( self, 0, sizeof * self );
5522     self -> acc = acc;
5523     self -> version = version;
5524     self -> protocols = protocols;
5525     self -> passed = -1;
5526 }
5527 
KServiceRequestTestNames1(const KNSManager * mgr,const char * cgi,const char * version,const char * acc,size_t acc_sz,const char * ticket,VRemoteProtocols protocols,EObjectType objectType)5528 rc_t KServiceRequestTestNames1 ( const KNSManager * mgr,
5529     const char * cgi, const char * version, const char * acc, size_t acc_sz,
5530     const char * ticket, VRemoteProtocols protocols,
5531     EObjectType objectType )
5532 {
5533     KService service;
5534     rc_t rc = KServiceInitNames1 ( & service, mgr, cgi, version,
5535         acc, acc_sz,  ticket, protocols, objectType, false, false );
5536     if ( rc == 0 ) {
5537         SKVCheck c;
5538         SKVCheckInit ( & c, acc, version, protocols );
5539         VectorForEach
5540             ( & service . req . cgiReq . params, false, SCgiRequestCheck, & c );
5541         rc = c . passed;
5542     }
5543     {
5544         rc_t r2 = KServiceFini ( & service );
5545         if ( rc == 0 ) {
5546             rc = r2;
5547         }
5548     }
5549     return rc;
5550 }
5551 
KServiceNamesRequestTest(const KNSManager * mgr,const char * b,const char * cgi,VRemoteProtocols protocols,const SServiceRequestTestData * d,...)5552 rc_t KServiceNamesRequestTest ( const KNSManager * mgr, const char * b,
5553     const char * cgi, VRemoteProtocols protocols,
5554     const SServiceRequestTestData * d, ... )
5555 {
5556     va_list args;
5557     KService * service = NULL;
5558     KStream * stream = NULL;
5559     rc_t rc = KServiceMakeWithMgr ( & service, NULL, mgr, NULL );
5560     va_start ( args, d );
5561     while ( rc == 0 && d != NULL ) {
5562         if ( d -> id != NULL ) {
5563             rc = _KServiceAddObject ( service, d -> id, 0, d -> type );
5564         }
5565         if ( rc == 0 && d -> ticket != NULL ) {
5566             rc = KServiceAddTicket ( service, d -> ticket );
5567         }
5568         d = va_arg ( args, const SServiceRequestTestData * );
5569     }
5570     if ( rc == 0 ) {
5571         rc = KServiceInitNamesRequest ( service, protocols, cgi );
5572     }
5573     if ( rc == 0 ) {
5574         SKVCheck c;
5575     /*SKVCheckInit ( & c, acc, service -> req . version .raw . s, protocols );*/
5576         VectorForEach (
5577             & service -> req . cgiReq . params, false, SCgiRequestCheck, & c );
5578         rc = c . passed;
5579     }
5580     if ( rc == 0 ) {
5581         rc = KStreamMakeFromBuffer ( & stream, b, string_size ( b ) );
5582     }
5583     if ( rc == 0 ) {
5584         rc = KServiceProcessStream ( service, stream );
5585     }
5586     if ( rc == 0 ) {
5587         const KSrvResponse * l = NULL;
5588         rc = KServiceGetResponse ( service, & l );
5589         if ( rc == 0 ) {
5590             uint32_t i = 0;
5591             uint32_t n = KSrvResponseLength ( l );
5592             for ( i = 0; rc == 0 && i < n; ++i ) {
5593                 const VPathSet * s = NULL;
5594                 rc = KSrvResponseGet ( l, i, & s );
5595                 RELEASE ( VPathSet, s );
5596             }
5597         }
5598         RELEASE ( KSrvResponse, l );
5599     }
5600     RELEASE ( KStream, stream );
5601     RELEASE ( KService, service );
5602     return rc;
5603 }
5604 
KServiceFuserTest(const KNSManager * mgr,const char * ticket,const char * acc,...)5605 rc_t KServiceFuserTest ( const KNSManager * mgr,  const char * ticket,
5606     const char * acc, ... )
5607 {
5608     va_list args;
5609     KService * service = NULL;
5610     const KSrvResponse * response = NULL;
5611     rc_t rc = KServiceMake ( & service);
5612     va_start ( args, acc );
5613     while ( rc == 0 && acc != NULL ) {
5614         rc = KServiceAddId ( service, acc );
5615         acc = va_arg ( args, const char * );
5616     }
5617     if ( rc == 0 ) {
5618         rc = KServiceNamesQuery ( service, eProtocolDefault, & response );
5619     }
5620     if ( rc == 0 ) {
5621         uint32_t i = 0;
5622         for ( i = 0; rc == 0 && i < KSrvResponseLength ( response ); ++i ) {
5623             const VPath * path = NULL;
5624             rc = KSrvResponseGetPath ( response, i, 0, & path, NULL, NULL );
5625             if ( rc == 0 ) {
5626                 rc_t r2;
5627 /*KTime_t mod = VPathGetModDate ( path );size_t size = VPathGetSize ( path );*/
5628                 String id;
5629                 memset ( & id, 0, sizeof id );
5630                 r2 = VPathGetId ( path, & id );
5631                 if ( rc == 0 )
5632                     rc = r2;
5633             }
5634             RELEASE ( VPath, path );
5635         }
5636     }
5637     RELEASE ( KSrvResponse, response );
5638     RELEASE ( KService, service );
5639     return rc;
5640 }
5641 
SCgiRequestPerformTestNames1(const KNSManager * mgr,const char * cgi,const char * version,const char * acc,const char * ticket,VRemoteProtocols protocols,EObjectType objectType)5642 rc_t SCgiRequestPerformTestNames1 ( const KNSManager * mgr, const char * cgi,
5643     const char * version, const char * acc, const char * ticket,
5644     VRemoteProtocols protocols, EObjectType objectType )
5645 {
5646     KService service;
5647 
5648     rc_t rc = KServiceInitNames1 ( & service, mgr, cgi, version, acc,
5649         string_measure ( acc, NULL ), ticket, protocols, objectType, false,
5650         false );
5651 
5652     if ( rc == 0 ) {
5653         KStream * response = NULL;
5654         rc = SCgiRequestPerform ( & service . req . cgiReq, & service . helper,
5655                                   & response, NULL, & service );
5656         RELEASE ( KStream, response );
5657     }
5658 
5659     {
5660         rc_t r2 = KServiceFini ( & service );
5661         if ( rc == 0 )
5662             rc = r2;
5663     }
5664 
5665     return rc;
5666 }
5667 
KServiceProcessStreamTestNames1(const KNSManager * mgr,const char * b,const char * version,const char * acc,const VPath * exp,const char * ticket,const VPath * ex2,int errors)5668 rc_t KServiceProcessStreamTestNames1 ( const KNSManager * mgr,
5669     const char * b, const char * version, const char * acc,
5670     const VPath * exp, const char * ticket, const VPath * ex2,
5671     int errors )
5672 {
5673     KService service;
5674     KStream * stream = NULL;
5675     rc_t rc = 0;
5676     if ( rc == 0 )
5677         rc = KServiceInitNames1 ( & service, mgr, "", version, acc,
5678             string_measure ( acc, NULL ), ticket, eProtocolHttps,
5679             eOT_undefined, false, false );
5680     if ( rc == 0 ) {
5681         DBGMSG ( DBG_VFS, DBG_FLAG ( DBG_VFS_SERVICE ), (
5682             "XXXXXXXXXXXX NOT sending HTTP POST request XXXXXXXXXXXXXXXX\n" ) );
5683         rc = KStreamMakeFromBuffer ( & stream, b, string_size ( b ) );
5684     }
5685     if ( rc == 0 )
5686         KServiceExpectErrors ( & service, errors );
5687     if ( rc == 0 )
5688         rc = KServiceProcessStream ( & service, stream );
5689     if ( rc == 0 ) {
5690         if ( VectorLength ( & service . resp . rows ) != 1 )
5691             rc = RC ( rcVFS, rcQuery, rcExecuting, rcRow, rcExcessive );
5692         else {
5693             const VPath * path = NULL;
5694             const SRow * r
5695                 = ( SRow * ) VectorGet ( & service . resp . rows, 0 );
5696             if ( r == NULL)
5697                 rc = RC ( rcVFS, rcQuery, rcExecuting, rcVector, rcEmpty );
5698             else
5699                 if ( r -> path . error != NULL )
5700                     rc = r -> path . error -> rc;
5701                 else
5702                     path = r -> path . http;
5703             if ( exp != NULL && rc == 0 ) {
5704                 int notequal = ~ 0;
5705                 rc = VPathEqual ( path, exp, & notequal );
5706                 if ( rc == 0 )
5707                     rc = notequal;
5708             }
5709             if ( ex2 != NULL && rc == 0 ) {
5710                 int notequal = ~ 0;
5711                 rc = VPathEqual ( path, ex2, & notequal );
5712                 if ( rc == 0 )
5713                     rc = notequal;
5714             }
5715         }
5716     }
5717     {
5718         rc_t r2 = KServiceFini ( & service );
5719         if ( rc == 0 ) {
5720             rc = r2;
5721         }
5722     }
5723     RELEASE ( KStream, stream );
5724     return rc;
5725 }
5726 
5727 
5728 /* Parse "buffer" as names-3.0 response.
5729    Do not log "errorsToIgnore" messages during response processing */
KServiceNames3_0StreamTestMany(const char * buffer,const KSrvResponse ** response,int errorsToIgnore,int itemsInRequest)5730 rc_t KServiceNames3_0StreamTestMany ( const char * buffer,
5731     const KSrvResponse ** response, int errorsToIgnore,
5732     int itemsInRequest )
5733 {
5734     rc_t rc = 0;
5735     rc_t r2 = 0;
5736 
5737     KStream * stream = NULL;
5738 
5739     KService service;
5740 
5741     if ( rc == 0 )
5742         rc = KServiceInit ( & service, NULL, NULL, NULL );
5743     if ( rc == 0 )
5744         KServiceExpectErrors ( & service, errorsToIgnore );
5745 
5746     if ( rc == 0 )
5747         rc = KStreamMakeFromBuffer ( & stream, buffer, string_size ( buffer ) );
5748 
5749     if ( rc == 0 ) {
5750         int i = 0;
5751         for ( i = 0; i < itemsInRequest; ++ i ) {
5752             char id [ 99 ] = "";
5753             string_printf ( id, sizeof id, NULL,
5754                             "Fake_KServiceNames3_0StreamTest_ID_%d", i + 1 );
5755             KServiceAddId ( & service, id );
5756         }
5757         service . req . hasQuery = true;
5758         rc = KServiceProcessStream ( & service, stream );
5759     }
5760 
5761     if ( rc == 0 )
5762         rc = KServiceGetResponse ( & service , response );
5763 
5764     r2 = KServiceFini ( & service );
5765     if ( rc == 0 )
5766         rc = r2;
5767 
5768     RELEASE ( KStream, stream );
5769 
5770     return rc;
5771 }
5772 
KServiceNames3_0StreamTest(const char * buffer,const KSrvResponse ** response,int errorsToIgnore)5773 rc_t KServiceNames3_0StreamTest ( const char * buffer,
5774     const KSrvResponse ** response, int errorsToIgnore )
5775 {
5776     return ( KServiceNames3_0StreamTestMany ( buffer, response,
5777                                               errorsToIgnore, 1 ) );
5778 }
5779 
KServiceCgiTest1(const KNSManager * mgr,const char * cgi,const char * version,const char * acc,const char * ticket,VRemoteProtocols protocols,EObjectType objectType,const VPath * exp,const VPath * ex2)5780 rc_t KServiceCgiTest1 ( const KNSManager * mgr, const char * cgi,
5781     const char * version, const char * acc, const char * ticket,
5782     VRemoteProtocols protocols, EObjectType objectType,
5783     const VPath * exp, const VPath * ex2 )
5784 {
5785     const VPath * path = NULL;
5786     rc_t rc = KService1NameWithVersionAndType ( mgr, cgi, acc,
5787         string_measure ( acc, NULL ), ticket, protocols,
5788         & path, NULL, false, version, objectType, false );
5789     if ( rc == 0 ) {
5790         if ( exp != NULL && rc == 0 ) {
5791             int notequal = ~ 0;
5792             rc = VPathEqual ( path, exp, & notequal );
5793             if ( rc == 0 ) {
5794                 rc = notequal;
5795             }
5796         }
5797         if ( ex2 != NULL && rc == 0 ) {
5798             int notequal = ~ 0;
5799             rc = VPathEqual ( path, ex2, & notequal );
5800             if ( rc == 0 ) {
5801                 rc = notequal;
5802             }
5803         }
5804     }
5805     RELEASE ( VPath, path );
5806     return rc;
5807 }
5808 
KServiceSearchTest1(const KNSManager * mgr,const char * cgi,const char * acc)5809 rc_t KServiceSearchTest1
5810     ( const KNSManager * mgr, const char * cgi, const char * acc )
5811 {
5812     rc_t rc = 0;
5813     KService service;
5814     const Kart * result = NULL;
5815     rc = KServiceInit ( & service, NULL, mgr, NULL );
5816     if ( rc == 0 ) {
5817         rc = KServiceAddId ( & service, acc );
5818     }
5819     if ( rc == 0 )
5820         rc = KServiceSearchExecute ( & service, & result );
5821     {
5822         rc_t r2 = KServiceFini ( & service );
5823         if ( rc == 0 )
5824             rc = r2;
5825     }
5826     RELEASE ( Kart, result );
5827     return rc;
5828 }
5829 
KServiceSearchTest(const KNSManager * mgr,const char * cgi,const char * acc,...)5830 rc_t KServiceSearchTest (
5831     const KNSManager * mgr, const char * cgi, const char * acc, ... )
5832 {
5833     va_list args;
5834     rc_t rc = 0;
5835     KStream * stream = NULL;
5836     const Kart * result = NULL;
5837     KService service;
5838     rc = KServiceInit ( & service, NULL, mgr, NULL );
5839     va_start ( args, acc );
5840     while ( rc == 0 && acc != NULL ) {
5841         rc = _KServiceAddObject ( & service, acc, 0, eOT_undefined);
5842         acc = va_arg ( args, const char * );
5843     }
5844     if ( rc == 0 ) {
5845         rc = KServiceSearchExecuteExt ( & service, cgi, NULL, & result );
5846     }
5847     {
5848         rc_t r2 = KartRelease ( result );
5849         if ( rc == 0 ) {
5850             rc = r2;
5851         }
5852     }
5853     {
5854         rc_t r2 = KServiceFini ( & service );
5855         if ( rc == 0 ) {
5856             rc = r2;
5857         }
5858     }
5859     RELEASE ( KStream, stream );
5860     return rc;
5861 }
5862 /******************************************************************************/
5863