1 /* $Id: urlquery.c,v 6.69 2016/10/20 16:25:39 lavr Exp $
2 * ===========================================================================
3 *
4 * PUBLIC DOMAIN NOTICE
5 * National Center for Biotechnology Information (NCBI)
6 *
7 * This software/database is a "United States Government Work" under the
8 * terms of the United States Copyright Act. It was written as part of
9 * the author's official duties as a United States Government employee and
10 * thus cannot be copyrighted. This software/database is freely available
11 * to the public for use. The National Library of Medicine and the U.S.
12 * Government do not place any restriction on its use or reproduction.
13 * We would, however, appreciate having the NCBI and the author cited in
14 * any work or product based on this material
15 *
16 * Although all reasonable efforts have been taken to ensure the accuracy
17 * and reliability of the software and data, the NLM and the U.S.
18 * Government do not and cannot warrant the performance or results that
19 * may be obtained by using this software or data. The NLM and the U.S.
20 * Government disclaim all warranties, express or implied, including
21 * warranties of performance, merchantability or fitness for any particular
22 * purpose.
23 *
24 * ===========================================================================
25 *
26 * File Name: urlquery.c
27 *
28 * Author: Jonathan Kans
29 *
30 * Version Creation Date: 4/16/98
31 *
32 * $Revision: 6.69 $
33 *
34 * File Description:
35 *
36 * Modifications:
37 * --------------------------------------------------------------------------
38 *
39 * ==========================================================================
40 */
41
42 #include "asnbuild.h"
43 #include <urlquery.h>
44
45
46 #ifdef OS_MAC
47 #include <Events.h>
48
QUERY_WaitForNextMacEvent(void)49 NLM_EXTERN void QUERY_WaitForNextMacEvent (void)
50 {
51 EventRecord currEvent;
52
53 WaitNextEvent (0, &currEvent, 0, NULL);
54 }
55 #endif
56
57
58 /* Set HTTP user header */
x_SetupUserHeader(SConnNetInfo * net_info,const char * appName,EMIME_Type type,EMIME_SubType subtype,EMIME_Encoding encoding)59 static void x_SetupUserHeader (
60 SConnNetInfo* net_info,
61 const char* appName,
62 EMIME_Type type,
63 EMIME_SubType subtype,
64 EMIME_Encoding encoding
65 )
66 {
67 const char* userAgentName = NULL;
68 char user_header [MAX_CONTENT_TYPE_LEN + 80];
69
70 /* content-type if specified */
71 if ( MIME_ComposeContentTypeEx (type, subtype, encoding,
72 user_header, MAX_CONTENT_TYPE_LEN) ) {
73 ConnNetInfo_OverrideUserHeader (net_info, user_header);
74 }
75
76 /* allow the user to specify a prog. name, otherwise get it from elsewhere */
77 if (StringHasNoText (appName)) {
78 const char* progName = GetProgramName ();
79 if (StringHasNoText (progName)) {
80 char path [PATH_MAX];
81 Nlm_ProgramPath (path, sizeof (path));
82 userAgentName = StringRChr (path, DIRDELIMCHR);
83 if (userAgentName)
84 ++userAgentName;
85 } else
86 userAgentName = progName;
87 } else
88 userAgentName = appName;
89 if (StringDoesHaveText (userAgentName)) {
90 sprintf (user_header, "User-Agent: %.80s\r\n", userAgentName);
91 ConnNetInfo_ExtendUserHeader (net_info, user_header);
92 }
93 }
94
95
QUERY_OpenUrlQuery(const char * host_machine,Nlm_Uint2 host_port,const char * host_path,const char * arguments,const char * appName,Nlm_Uint4 timeoutsec,EMIME_Type type,EMIME_SubType subtype,EMIME_Encoding encoding,THTTP_Flags flags)96 NLM_EXTERN CONN QUERY_OpenUrlQuery (
97 const char* host_machine,
98 Nlm_Uint2 host_port,
99 const char* host_path,
100 const char* arguments,
101 const char* appName,
102 Nlm_Uint4 timeoutsec,
103 EMIME_Type type,
104 EMIME_SubType subtype,
105 EMIME_Encoding encoding,
106 THTTP_Flags flags
107 )
108 {
109 CONN conn;
110 CONNECTOR connector;
111 SConnNetInfo* net_info;
112 EIO_Status status;
113
114 if (StringHasNoText (host_path))
115 return NULL;
116
117 /* fill in connection info fields and create the connection */
118 net_info = ConnNetInfo_Create (0);
119 ASSERT ( net_info );
120
121 /* explicit setting to https is needed for CCC-23 */
122 net_info->scheme = eURL_Https;
123
124 x_SetupUserHeader (net_info, appName, type, subtype, encoding);
125
126 if (StringDoesHaveText (host_machine)) {
127 StringNCpy_0 (net_info->host, host_machine, sizeof (net_info->host));
128 }
129 if ( host_port ) {
130 net_info->port = host_port;
131 }
132 StringNCpy_0 (net_info->path, host_path, sizeof (net_info->path));
133 if (StringDoesHaveText (arguments)) {
134 StringNCpy_0 (net_info->args, arguments, sizeof (net_info->args));
135 }
136
137 if (timeoutsec == (Nlm_Uint4)(-1L)) {
138 net_info->timeout = kInfiniteTimeout;
139 } else if ( timeoutsec ) {
140 net_info->tmo.sec = timeoutsec;
141 net_info->tmo.usec = 0;
142 net_info->timeout = &net_info->tmo;
143 }
144
145 connector = HTTP_CreateConnector (net_info, NULL, flags);
146
147 ConnNetInfo_Destroy (net_info);
148
149 if (connector == NULL) {
150 ErrPostEx (SEV_ERROR, 0, 0, "QUERY_OpenUrlQuery failed in HTTP_CreateConnector");
151 conn = NULL;
152 } else if ((status = CONN_Create (connector, &conn)) != eIO_Success) {
153 ErrPostEx (SEV_ERROR, 0, 0, "QUERY_OpenUrlQuery failed in CONN_Create: %s",
154 IO_StatusStr (status));
155 ASSERT (conn == NULL);
156 }
157
158 return conn;
159 }
160
161
QUERY_OpenServiceQueryEx(const char * service,const char * parameters,Nlm_Uint4 timeoutsec,const char * arguments)162 NLM_EXTERN CONN QUERY_OpenServiceQueryEx (
163 const char* service,
164 const char* parameters,
165 Nlm_Uint4 timeoutsec,
166 const char* arguments
167 )
168 {
169 CONN conn;
170 CONNECTOR connector;
171 SConnNetInfo* net_info;
172 size_t n_written;
173 EIO_Status status;
174
175 /* fill in connection info fields and create the connection */
176 net_info = ConnNetInfo_Create (service);
177 ASSERT ( net_info );
178
179 /* let the user agent be set with a program name */
180 x_SetupUserHeader (net_info,
181 NULL, eMIME_T_Undefined, eMIME_Undefined, eENCOD_None);
182
183 if (timeoutsec == (Nlm_Uint4)(-1L)) {
184 net_info->timeout = kInfiniteTimeout;
185 } else if ( timeoutsec ) {
186 net_info->tmo.sec = timeoutsec;
187 net_info->tmo.usec = 0;
188 net_info->timeout = &net_info->tmo;
189 }
190
191 ConnNetInfo_PostOverrideArg (net_info, arguments, 0);
192
193 connector = SERVICE_CreateConnectorEx (service, fSERV_Any, net_info, 0);
194
195 ConnNetInfo_Destroy (net_info);
196
197 if (connector == NULL) {
198 ErrPostEx (SEV_ERROR, 0, 0, "QUERY_OpenServiceQuery failed in SERVICE_CreateConnectorEx");
199 conn = NULL;
200 } else if ((status = CONN_Create (connector, &conn)) != eIO_Success) {
201 ErrPostEx (SEV_ERROR, 0, 0, "QUERY_OpenServiceQuery failed in CONN_Create:"
202 " %s", IO_StatusStr (status));
203 ASSERT (conn == NULL);
204 } else if (StringDoesHaveText (parameters)) {
205 status = CONN_Write (conn, parameters, StringLen (parameters),
206 &n_written, eIO_WritePersist);
207 if (status != eIO_Success) {
208 ErrPostEx (SEV_ERROR, 0, 0, "QUERY_OpenServiceQuery failed to write service parameters in CONN_Write: %s", IO_StatusStr (status));
209 CONN_Close (conn);
210 conn = NULL;
211 }
212 }
213
214 return conn;
215 }
216
217
QUERY_OpenServiceQuery(const char * service,const char * parameters,Nlm_Uint4 timeoutsec)218 NLM_EXTERN CONN QUERY_OpenServiceQuery (
219 const char* service,
220 const char* parameters,
221 Nlm_Uint4 timeoutsec
222 )
223 {
224 return QUERY_OpenServiceQueryEx (service, parameters, timeoutsec, 0);
225 }
226
227
QUERY_SendQuery(CONN conn)228 NLM_EXTERN EIO_Status QUERY_SendQuery (
229 CONN conn
230 )
231
232 {
233 static const STimeout kPollTimeout = { 0 };
234 EIO_Status status;
235
236 if (conn == NULL) return eIO_Closed;
237
238 /* flush buffer, sending query, without waiting for response */
239 status = CONN_Wait (conn, eIO_Read, &kPollTimeout);
240 return status == eIO_Timeout ? eIO_Success : status;
241 }
242
243
244 #define URL_QUERY_BUFLEN 4096
245
QUERY_CopyFileToQuery(CONN conn,FILE * fp)246 NLM_EXTERN void QUERY_CopyFileToQuery (
247 CONN conn,
248 FILE *fp
249 )
250 {
251 Char buffer [URL_QUERY_BUFLEN + 4];
252 size_t ct;
253 size_t n_written;
254 EIO_Status status;
255
256 if (conn == NULL || fp == NULL) return;
257
258 while ((ct = FileRead (buffer, 1, URL_QUERY_BUFLEN, fp)) > 0) {
259 status = CONN_Write (conn, (const void *) buffer, ct,
260 &n_written, eIO_WritePersist);
261 if (status != eIO_Success) break;
262 }
263 }
264
265
QUERY_CopyResultsToFile(CONN conn,FILE * fp)266 NLM_EXTERN void QUERY_CopyResultsToFile (
267 CONN conn,
268 FILE *fp
269 )
270 {
271 Char buffer [URL_QUERY_BUFLEN + 4];
272 size_t n_read;
273 EIO_Status status;
274
275 if (conn == NULL || fp == NULL) return;
276
277 do {
278 status = CONN_Read (conn, buffer, URL_QUERY_BUFLEN, &n_read, eIO_ReadPlain);
279 if ( n_read ) {
280 FileWrite (buffer, 1, n_read, fp);
281 }
282 } while (status == eIO_Success);
283 }
284
285
QUERY_CopyResultsToString(CONN conn)286 NLM_EXTERN CharPtr QUERY_CopyResultsToString (
287 CONN conn
288 )
289
290 {
291 Char buffer [URL_QUERY_BUFLEN + 4];
292 ValNodePtr head = NULL, last = NULL, vnp;
293 size_t n_read;
294 EIO_Status status;
295 CharPtr str;
296
297 if (conn == NULL) return NULL;
298
299 do {
300 status = CONN_Read (conn, buffer, URL_QUERY_BUFLEN, &n_read, eIO_ReadPlain);
301 if ( n_read ) {
302 buffer [n_read] = '\0';
303 vnp = ValNodeCopyStr (&last, 0, buffer);
304 if (head == NULL) {
305 head = vnp;
306 }
307 last = vnp;
308 }
309 } while (status == eIO_Success);
310
311 if (head == NULL) return NULL;
312
313 str = ValNodeMergeStrs (head);
314 ValNodeFreeData (head);
315
316 return str;
317 }
318
319
AsnIoConnWrite(Pointer ptr,CharPtr buf,Nlm_Uint2 count)320 static Nlm_Int2 LIBCALL AsnIoConnWrite (
321 Pointer ptr,
322 CharPtr buf,
323 Nlm_Uint2 count
324 )
325 {
326 size_t bytes;
327 AsnIoConnPtr aicp;
328
329 aicp = (AsnIoConnPtr) ptr;
330 if (aicp == NULL || aicp->conn == NULL) return 0;
331 CONN_Write (aicp->conn, buf, (size_t) count, &bytes, eIO_WritePersist);
332 return (Nlm_Int2) bytes;
333 }
334
335
AsnIoConnRead(Pointer ptr,CharPtr buf,Nlm_Uint2 count)336 static Nlm_Int2 LIBCALL AsnIoConnRead (
337 Pointer ptr,
338 CharPtr buf,
339 Nlm_Uint2 count
340 )
341 {
342 size_t bytes;
343 AsnIoConnPtr aicp;
344
345 aicp = (AsnIoConnPtr) ptr;
346 if (aicp == NULL || aicp->conn == NULL) return 0;
347 CONN_Read (aicp->conn, buf, (size_t) count, &bytes, eIO_ReadPlain);
348 return (Nlm_Int2) bytes;
349 }
350
351
QUERY_AsnIoConnOpen(const char * mode,CONN conn)352 NLM_EXTERN AsnIoConnPtr QUERY_AsnIoConnOpen (
353 const char* mode,
354 CONN conn
355 )
356 {
357 Int1 type;
358 AsnIoConnPtr aicp;
359
360 if (strcmp(mode, "r") == 0)
361 type = (ASNIO_IN | ASNIO_TEXT);
362 else if (strcmp(mode, "rb") == 0)
363 type = (ASNIO_IN | ASNIO_BIN);
364 else if (strcmp(mode, "w") == 0)
365 type = (ASNIO_OUT | ASNIO_TEXT);
366 else if (strcmp(mode, "wb") == 0)
367 type = (ASNIO_OUT | ASNIO_BIN);
368 else {
369 AsnIoErrorMsg (NULL, 81, mode);
370 return NULL;
371 }
372
373 aicp = (AsnIoConnPtr) MemNew (sizeof (AsnIoConn));
374 aicp->aip = AsnIoNew (type, NULL, (Pointer) aicp, AsnIoConnRead, AsnIoConnWrite);
375 aicp->conn = conn;
376 return aicp;
377 }
378
379
QUERY_AsnIoConnClose(AsnIoConnPtr aicp)380 NLM_EXTERN AsnIoConnPtr QUERY_AsnIoConnClose (
381 AsnIoConnPtr aicp
382 )
383 {
384 if (aicp == NULL) return NULL;
385 AsnIoClose (aicp->aip);
386 aicp->conn = NULL;
387 return (AsnIoConnPtr) MemFree (aicp);
388 }
389
390
391 typedef struct SQueueTag {
392 CONN conn;
393 QueryResultProc resultproc;
394 Nlm_VoidPtr userdata;
395 Nlm_Boolean closeConn;
396 Nlm_Boolean protect;
397 struct SQueueTag* next;
398 } SConnQueue, PNTR QueuePtr;
399
400
QUERY_AddToQueue(QUEUE * queue,CONN conn,QueryResultProc resultproc,Nlm_VoidPtr userdata,Nlm_Boolean closeConn)401 NLM_EXTERN void QUERY_AddToQueue (
402 QUEUE* queue,
403 CONN conn,
404 QueryResultProc resultproc,
405 Nlm_VoidPtr userdata,
406 Nlm_Boolean closeConn
407 )
408 {
409 QueuePtr cqp;
410 QueuePtr PNTR qptr;
411
412 ASSERT (queue != NULL);
413
414 if (conn == NULL || resultproc == NULL) return;
415
416 /* allocate queue element */
417
418 cqp = (QueuePtr) MemNew (sizeof (SConnQueue));
419 if (cqp == NULL) return;
420
421 cqp->conn = conn;
422 cqp->resultproc = resultproc;
423 cqp->userdata = userdata;
424 cqp->closeConn = closeConn;
425 cqp->protect = FALSE;
426
427 /* add to polling queue */
428
429 for (qptr = (QueuePtr PNTR) queue; *qptr != NULL; qptr = &(*qptr)->next);
430 *qptr = cqp;
431 }
432
433
QUERY_RemoveFromQueue(QUEUE * queue,CONN conn)434 static void QUERY_RemoveFromQueue (
435 QUEUE* queue,
436 CONN conn
437 )
438 {
439 QueuePtr curr;
440 QueuePtr next;
441 QueuePtr PNTR prev;
442 QueuePtr PNTR qptr;
443
444 qptr = (QueuePtr PNTR) queue;
445 if (qptr == NULL || *qptr == NULL || conn == NULL) return;
446
447 prev = qptr;
448 curr = *qptr;
449
450 while (curr != NULL) {
451 next = curr->next;
452 if (curr->conn == conn) {
453 *prev = next;
454 curr->next = NULL;
455 MemFree (curr);
456 } else {
457 prev = &(curr->next);
458 }
459 curr = next;
460 }
461 }
462
463
QUERY_CheckQueue(QUEUE * queue)464 NLM_EXTERN Nlm_Int4 QUERY_CheckQueue (
465 QUEUE* queue
466 )
467 {
468 static const STimeout kPollTimeout = { 0 };
469 Nlm_Int4 count = 0;
470 QueuePtr curr;
471 QueuePtr next;
472 QueuePtr PNTR qptr;
473 EIO_Status status;
474
475 qptr = (QueuePtr PNTR) queue;
476 if (qptr == NULL || *qptr == NULL) return 0;
477
478 curr = *qptr;
479
480 while (curr != NULL) {
481 next = curr->next;
482
483 if (curr->conn != NULL && (! curr->protect)) {
484 status = CONN_Wait (curr->conn, eIO_Read, &kPollTimeout);
485
486 if (status == eIO_Success || status == eIO_Closed) {
487 /* protect against reentrant calls if resultproc is GUI and processes timer */
488 curr->protect = TRUE;
489 if (curr->resultproc != NULL) {
490 /* result could eventually be used to reconnect on timeout */
491 curr->resultproc (curr->conn, curr->userdata, status);
492 }
493 if (curr->closeConn) {
494 CONN_Close (curr->conn);
495 }
496 QUERY_RemoveFromQueue (queue, curr->conn);
497 } else {
498 count++;
499 }
500 }
501
502 curr = next;
503 }
504
505 return count;
506 }
507
508
QUERY_QueueSize(QUEUE queue)509 NLM_EXTERN Nlm_Int4 QUERY_QueueSize (
510 QUEUE queue
511 )
512 {
513 Nlm_Int4 count = 0;
514 QueuePtr qptr;
515
516 for (qptr = (QueuePtr) queue; qptr; qptr = qptr->next) {
517 count++;
518 }
519
520 return count;
521 }
522
523
QUERY_CloseQueue(QUEUE * queue)524 NLM_EXTERN void QUERY_CloseQueue (
525 QUEUE* queue
526 )
527 {
528 QueuePtr curr;
529 QueuePtr next;
530 QueuePtr PNTR qptr;
531
532 qptr = (QueuePtr PNTR) queue;
533 if (qptr == NULL || *qptr == NULL) return;
534
535 curr = *qptr;
536
537 while (curr != NULL) {
538 next = curr->next;
539
540 if (curr->conn != NULL) {
541 CONN_Close (curr->conn);
542 QUERY_RemoveFromQueue (queue, curr->conn);
543 }
544
545 curr = next;
546 }
547 }
548
QUERY_SendSimpleUrlQuery(CharPtr machine,Uint2 port,CharPtr path,CharPtr prefix,CharPtr arguments,CharPtr suffix,CharPtr post)549 static CONN QUERY_SendSimpleUrlQuery (
550 CharPtr machine,
551 Uint2 port,
552 CharPtr path,
553 CharPtr prefix,
554 CharPtr arguments,
555 CharPtr suffix,
556 CharPtr post
557 )
558
559 {
560 Char ch;
561 CONN conn = NULL;
562 size_t len;
563 size_t n_written;
564 CharPtr ptr;
565 CharPtr query = NULL;
566
567 len = StringLen (prefix) + StringLen (arguments) + StringLen (suffix);
568 if (len > 0) {
569 query = (CharPtr) MemNew (len + 2);
570 if (query != NULL) {
571 StringCpy (query, prefix);
572 StringCat (query, arguments);
573 StringCat (query, suffix);
574 ptr = query;
575 ch = *ptr;
576 while (ch != '\0') {
577 if (ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n') {
578 *ptr = '+';
579 }
580 ptr++;
581 ch = *ptr;
582 }
583 }
584 }
585
586 if (StringHasNoText (post)) {
587 post = NULL;
588 }
589
590 if (post != NULL) {
591 conn = QUERY_OpenUrlQuery (machine, port, path, query, NULL, 30,
592 eMIME_T_Application, eMIME_WwwForm, eENCOD_Url,
593 fHTTP_Flushable);
594 } else {
595 conn = QUERY_OpenUrlQuery (machine, port, path, query, NULL, 30,
596 eMIME_T_Undefined, eMIME_Undefined, eENCOD_None,
597 fHTTP_Flushable);
598 }
599
600 MemFree (query);
601
602 if (conn == NULL) return NULL;
603
604 if (post != NULL) {
605 CONN_Write (conn, (const void *) post, StringLen (post), &n_written, eIO_WritePersist);
606 }
607
608 QUERY_SendQuery (conn);
609
610 return conn;
611 }
612
QUERY_UrlSynchronousQuery(CharPtr machine,Uint2 port,CharPtr path,CharPtr prefix,CharPtr arguments,CharPtr suffix,CharPtr post)613 NLM_EXTERN CharPtr QUERY_UrlSynchronousQuery (
614 CharPtr machine,
615 Uint2 port,
616 CharPtr path,
617 CharPtr prefix,
618 CharPtr arguments,
619 CharPtr suffix,
620 CharPtr post
621 )
622
623 {
624 CONN conn;
625 time_t currtime, starttime, max = 0;
626 EIO_Status status;
627 CharPtr str = NULL;
628 STimeout timeout;
629
630 conn = QUERY_SendSimpleUrlQuery (machine, port, path, prefix, arguments, suffix, post);
631
632 if (conn == NULL) return NULL;
633
634 #ifdef OS_MAC
635 timeout.sec = 0;
636 timeout.usec = 1000;
637 #else
638 timeout.sec = 100;
639 timeout.usec = 0;
640 #endif
641
642 starttime = GetSecs ();
643 while (max < 300 && (status = CONN_Wait (conn, eIO_Read, &timeout)) == eIO_Timeout) {
644 currtime = GetSecs ();
645 max = currtime - starttime;
646 }
647
648 if (status == eIO_Success) {
649 str = QUERY_CopyResultsToString (conn);
650 }
651
652 CONN_Close (conn);
653
654 return str;
655 }
656
QUERY_UrlAsynchronousQuery(CharPtr machine,Uint2 port,CharPtr path,CharPtr prefix,CharPtr arguments,CharPtr suffix,CharPtr post,QUEUE * queue,QueryResultProc resultproc,VoidPtr userdata)657 NLM_EXTERN Boolean QUERY_UrlAsynchronousQuery (
658 CharPtr machine,
659 Uint2 port,
660 CharPtr path,
661 CharPtr prefix,
662 CharPtr arguments,
663 CharPtr suffix,
664 CharPtr post,
665 QUEUE* queue,
666 QueryResultProc resultproc,
667 VoidPtr userdata
668 )
669
670 {
671 CONN conn;
672
673 conn = QUERY_SendSimpleUrlQuery (machine, port, path, prefix, arguments, suffix, post);
674
675 if (conn == NULL) return FALSE;
676
677 QUERY_AddToQueue (queue, conn, resultproc, userdata, TRUE);
678
679 return TRUE;
680 }
681
682