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