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
26 #include "path-priv.h" /* VPathMakeFmt */
27 #include "resolver-priv.h" /* rcResolver */
28
29 #include <klib/log.h> /* klogInt */
30 #include <klib/rc.h> /* RC */
31 #include <klib/text.h> /* string_chr */
32
33 #include <vfs/path.h> /* VPathMakeFmt */
34
_GetAny(const rc_t * rc,const char ** start,const char * end,String * s,bool last)35 static rc_t _GetAny(const rc_t *rc, const char **start,
36 const char *end, String *s, bool last)
37 {
38 assert(rc && start);
39
40 if (*rc != 0) {
41 return *rc;
42 }
43
44 if (!last) {
45 const char *sep = string_chr ( *start, end - *start, '|' );
46 if ( sep == NULL ) {
47 return RC ( rcVFS, rcResolver, rcResolving, rcName, rcNotFound );
48 }
49
50 StringInit(s, *start, sep - *start, ( uint32_t ) ( sep - *start ));
51
52 *start = sep + 1;
53 }
54 else {
55 const char *sep = NULL;
56 for ( sep = end; sep > *start; -- sep ) {
57 switch ( sep [ -1 ] ) {
58 case '\n':
59 case '\r':
60 continue;
61 default:
62 break;
63 }
64 break;
65 }
66
67 StringInit ( s, *start, sep - *start, ( uint32_t ) ( sep - *start ) );
68 }
69
70 return 0;
71 }
72
_Get(const rc_t * rc,const char ** start,const char * end,String * s)73 static rc_t _Get(const rc_t *rc, const char **start,
74 const char *end, String *s)
75 {
76 return _GetAny(rc, start, end, s, false);
77 }
78
_GetLast(const rc_t * rc,const char ** start,const char * end,String * s)79 static rc_t _GetLast(const rc_t *rc, const char **start,
80 const char *end, String *s)
81 {
82 return _GetAny(rc, start, end, s, true);
83 }
84
85 typedef enum {
86 eBadObjectType,
87 eDbgap,
88 eProvisional,
89 eSrapub, /* eSra_run, */
90 eSrapub_files,
91 eSragap, /* eSra_run, */
92 eSra_source,
93 eSra_addon,
94 eRefseq,
95 eWgs,
96 eNa,
97 } EObjectType;
_StringToObjectType(const String * self)98 EObjectType _StringToObjectType(const String *self) {
99 if (self->size == 0) {
100 return eBadObjectType;
101 }
102 else {
103 String dbgap;
104 String provisional;
105 String srapub;
106 String srapub_files;
107 String sragap;
108 String sra_source;
109 String sra_addon;
110 String refseq;
111 String wgs;
112 String na;
113 CONST_STRING(&dbgap, "dbgap");
114 CONST_STRING(&provisional, "provisional");
115 CONST_STRING(&srapub, "srapub");
116 CONST_STRING(&srapub_files, "srapub_files");
117 CONST_STRING(&sragap, "sragap");
118 CONST_STRING(&sra_source, "sra-source");
119 CONST_STRING(&sra_addon, "sra-addon");
120 CONST_STRING(&refseq, "refseq");
121 CONST_STRING(&wgs, "wgs");
122 CONST_STRING(&na, "na");
123 if (StringEqual(self, &dbgap)) {
124 return eDbgap;
125 }
126 else if (StringEqual(self, &provisional)) {
127 return eProvisional;
128 }
129 else if (StringEqual(self, &srapub)) {
130 return eSrapub;
131 }
132 else if (StringEqual(self, &srapub_files)) {
133 return eSrapub_files;
134 }
135 else if (StringEqual(self, &sragap)) {
136 return eSragap;
137 }
138 else if (StringEqual(self, &sra_source)) {
139 return eSra_source;
140 }
141 else if (StringEqual(self, &sra_addon)) {
142 return eSra_addon;
143 }
144 else if (StringEqual(self, &refseq)) {
145 return eRefseq;
146 }
147 else if (StringEqual(self, &wgs)) {
148 return eWgs;
149 }
150 else if (StringEqual(self, &na)) {
151 return eNa;
152 }
153 else {
154 return eBadObjectType;
155 }
156 }
157 }
158
_ProcessCode(EObjectType objectType,const String * object_id,const String * code,const String * download_ticket,const String * url,const String * message,const VPath ** path,const VPath ** mapping,const String * acc,const String * ticket)159 static rc_t _ProcessCode(EObjectType objectType, const String *object_id,
160 const String *code, const String *download_ticket,
161 const String *url, const String *message, const VPath **path,
162 const VPath **mapping, const String *acc, const String *ticket)
163 {
164 rc_t rc = 0;
165 KLogLevel lvl = 0;
166 uint32_t result_code = 0;
167 char *rslt_end = NULL;
168 assert(objectType && object_id && code && download_ticket && url);
169 if (code->size == 0)
170 return RC ( rcVFS, rcResolver, rcResolving, rcMessage, rcCorrupt );
171 result_code = strtoul ( code -> addr, & rslt_end, 10 );
172 if ( ( const char* ) rslt_end - code -> addr != code -> size )
173 return RC ( rcVFS, rcResolver, rcResolving, rcMessage, rcCorrupt );
174 switch ( result_code / 100 ) {
175 case 2: /* successful response but can only handle 200 */
176 if ( result_code == 200 ) { /* normal public response */
177 if (download_ticket->size == 0) {
178 rc = VPathMakeFmt ( ( VPath** ) path, "%S", url );
179 }
180 else { /* protected response */
181 rc = VPathMakeFmt
182 ((VPath**) path, "%S?tic=%S", url, download_ticket);
183 }
184 if ( rc == 0 ) {
185 rc = VPathCheckFromNamesCGI ( * path, ticket, -1, mapping );
186 if ( rc == 0 ) {
187 if ( mapping == NULL )
188 return 0;
189 if (download_ticket->size != 0) {
190 if (object_id->size != 0 && objectType == eSragap) {
191 rc = VPathMakeFmt ( ( VPath** ) mapping,
192 "ncbi-acc:%S?tic=%S",
193 object_id, download_ticket);
194 }
195 else {
196 if (object_id->size == 0)
197 return 0;
198 else
199 rc = VPathMakeFmt ( ( VPath** ) mapping,
200 "ncbi-file:%S?tic=%S",
201 object_id, download_ticket);
202 }
203 }
204 else if (object_id->size != 0 && objectType == eSrapub)
205 {
206 rc = VPathMakeFmt ( ( VPath** ) mapping,
207 "ncbi-acc:%S", object_id );
208 }
209 else {
210 if (object_id->size == 0)
211 return 0;
212 else
213 rc = VPathMakeFmt ( ( VPath** ) mapping,
214 "ncbi-file:%S", object_id );
215 }
216 if ( rc == 0 )
217 return 0;
218 }
219 VPathRelease ( * path );
220 * path = NULL;
221 }
222 return rc;
223 }
224 lvl = klogInt;
225 rc = RC ( rcVFS, rcResolver, rcResolving, rcError, rcUnexpected );
226 break;
227 case 4: /* client error */
228 lvl = klogErr;
229 switch (result_code) {
230 case 400:
231 rc = RC(rcVFS, rcResolver, rcResolving,
232 rcMessage, rcInvalid);
233 break;
234 case 401:
235 case 403:
236 rc = RC( rcVFS, rcResolver, rcResolving,
237 rcQuery, rcUnauthorized);
238 break;
239 case 404: /* 404|no data :
240 If it is a real response then this assession is not found.
241 What if it is a DB failure? Will be retried if configured to do so?*/
242 case 410:
243 rc = RC( rcVFS, rcResolver, rcResolving,
244 rcName, rcNotFound );
245 break;
246 default:
247 rc = RC(rcVFS, rcResolver, rcResolving,
248 rcError, rcUnexpected);
249 }
250 break;
251 case 5: /* server error */
252 lvl = klogSys;
253 switch (result_code) {
254 case 503:
255 rc = RC(rcVFS, rcResolver, rcResolving,
256 rcDatabase, rcNotAvailable);
257 break;
258 case 504:
259 rc = RC(rcVFS, rcResolver, rcResolving,
260 rcTimeout, rcExhausted);
261 break;
262 default:
263 rc = RC(rcVFS, rcResolver, rcResolving,
264 rcError, rcUnexpected);
265 }
266 break;
267 case 1: /* informational response not much we can do here */
268 case 3: /* redirection:
269 currently this is being handled by our request object */
270 default:
271 lvl = klogInt;
272 rc = RC ( rcVFS, rcResolver, rcResolving, rcError, rcUnexpected );
273 break;
274 }
275 /* log message to user */
276 PLOGERR(lvl, (lvl, rc,
277 "failed to resolve accession '$(acc)' - $(msg) ( $(code) )",
278 "acc=%S,msg=%S,code=%u", acc, message, result_code));
279 return rc;
280 }
281
VResolverAlgParseResolverCGIResponse_3_0(const char * astart,size_t asize,const VPath ** path,const VPath ** mapping,const String * acc,const String * ticket)282 rc_t VResolverAlgParseResolverCGIResponse_3_0(const char *astart,
283 size_t asize, const VPath **path, const VPath **mapping,
284 const String *acc, const String *ticket)
285 {
286 const char *start = astart;
287 const char *end = start + asize;
288 String object_type, object_id, size, date,
289 md5, download_ticket, url, code, message;
290 EObjectType objectType = eBadObjectType;
291
292 rc_t rc = 0;
293 rc = _Get (&rc, &start, end, &object_type);
294 rc = _Get (&rc, &start, end, &object_id);
295 rc = _Get (&rc, &start, end, &size);
296 rc = _Get (&rc, &start, end, &date);
297 rc = _Get (&rc, &start, end, &md5);
298 rc = _Get (&rc, &start, end, &download_ticket);
299 rc = _Get (&rc, &start, end, &url);
300 rc = _Get (&rc, &start, end, &code);
301 rc = _GetLast(&rc, &start, end, &message);
302 if (rc != 0) {
303 return rc;
304 }
305
306 objectType = _StringToObjectType(&object_type);
307 if (objectType == eBadObjectType) {
308 return RC ( rcVFS, rcResolver, rcResolving, rcMessage, rcCorrupt );
309 }
310
311 /* compare acc to accession or obj_id */
312 assert(acc);
313 if ( ! StringEqual ( & object_id, acc ) && objectType != eDbgap )
314 return RC ( rcVFS, rcResolver, rcResolving, rcMessage, rcCorrupt );
315
316 /* compare ticket
317 currently this makes sense with 1 request from a known workspace */
318 if (download_ticket.size != 0) {
319 if ( ticket == NULL || ! StringEqual ( & download_ticket, ticket ) )
320 return RC ( rcVFS, rcResolver, rcResolving, rcMessage, rcCorrupt );
321 }
322
323 /* get the result code */
324 return _ProcessCode(objectType, &object_id, &code,
325 &download_ticket, &url, &message, path, mapping, acc, ticket);
326 }
327