|
|
1 //! @file rts-curl.c 2 //! @author J. Marcel van der Veer 3 4 //! @section Copyright 5 //! 6 //! This file is part of Algol68G - an Algol 68 compiler-interpreter. 7 //! Copyright 2001-2026 J. Marcel van der Veer [algol68g@algol68genie.nl]. 8 9 //! @section License 10 //! 11 //! This program is free software; you can redistribute it and/or modify it 12 //! under the terms of the GNU General Public License as published by the 13 //! Free Software Foundation; either version 3 of the License, or 14 //! (at your option) any later version. 15 //! 16 //! This program is distributed in the hope that it will be useful, but 17 //! WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 18 //! or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 19 //! more details. You should have received a copy of the GNU General Public 20 //! License along with this program. If not, see [http://www.gnu.org/licenses/]. 21 22 //! @section Synopsis 23 //! 24 //! HTTP/HTTPS client. 25 26 #include "a68g.h" 27 #include "a68g-genie.h" 28 #include "a68g-prelude.h" 29 #include "a68g-transput.h" 30 31 #if defined (HAVE_CURL) 32 33 #if defined (HAVE_CURL_CURL_H) 34 #include <curl/curl.h> 35 #endif 36 37 typedef struct DATA_T DATA_T; 38 struct DATA_T { 39 char *ref; 40 size_t len; 41 }; 42 43 #define NO_DATA ((DATA_T *) NULL) 44 45 // Below, 0 means default, which are 300 s / endless respectively. 46 47 static INT_T a68g_curl_connecttimeout = 0, a68g_curl_timeout = 0; 48 49 // Callback function concatenating received data. 50 51 static size_t a68g_curl_concat (void *data, size_t len, size_t n, void *buf) 52 { 53 // Sanity checks. 54 if ((char *) data == NO_TEXT || (DATA_T *) buf == NO_DATA) { 55 return 0; 56 } else if (n == 0 || len == 0) { 57 return 0; 58 } 59 ABEND (len >= (2 * A68G_GIGA) / n, ERROR_MEMORY_FULL, NO_TEXT); 60 size_t new_len = n * len; 61 ABEND (new_len + 1 > 2 * A68G_GIGA - ((DATA_T *) buf)->len, ERROR_MEMORY_FULL, NO_TEXT); 62 char *stale = ((DATA_T *) buf)->ref; 63 ((DATA_T *) buf)->ref = malloc (((DATA_T *) buf)->len + new_len + 1); 64 ABEND (((DATA_T *) buf)->ref == NO_TEXT, ERROR_MEMORY_FULL, NO_TEXT); 65 if (stale != NO_TEXT) { 66 MOVE (((DATA_T *) buf)->ref, stale, ((DATA_T *) buf)->len + 1); 67 a68g_free (stale); 68 } 69 MOVE (& (((DATA_T *) buf)->ref[((DATA_T *) buf)->len]), data, new_len); 70 ((DATA_T *) buf)->len += new_len; 71 ((DATA_T *) buf)->ref[((DATA_T *) buf)->len] = NULL_CHAR; 72 return new_len; 73 } 74 75 void genie_curl_content (NODE_T * p, char *protocol) 76 { 77 A68G_REF path_string, domain_string, content_string; 78 A68G_INT port; 79 errno = 0; 80 // Pop arguments. 81 POP_OBJECT (p, &port, A68G_INT); 82 CHECK_INIT (p, INITIALISED (&port), M_INT); // Unused for now. 83 POP_REF (p, &path_string); 84 CHECK_INIT (p, INITIALISED (&path_string), M_STRING); 85 POP_REF (p, &domain_string); 86 CHECK_INIT (p, INITIALISED (&domain_string), M_STRING); 87 POP_REF (p, &content_string); 88 CHECK_REF (p, content_string, M_REF_STRING); 89 *DEREF (A68G_REF, &content_string) = empty_string (p); 90 // Set buffers. 91 reset_transput_buffer (DOMAIN_BUFFER); 92 add_a_string_transput_buffer (p, DOMAIN_BUFFER, (BYTE_T *) & domain_string); 93 reset_transput_buffer (PATH_BUFFER); 94 add_a_string_transput_buffer (p, PATH_BUFFER, (BYTE_T *) & path_string); 95 // Compose request. 96 reset_transput_buffer (REQUEST_BUFFER); 97 if (protocol != NO_TEXT) { 98 add_string_transput_buffer (p, REQUEST_BUFFER, protocol); 99 } 100 add_string_transput_buffer (p, REQUEST_BUFFER, get_transput_buffer (DOMAIN_BUFFER)); 101 add_string_transput_buffer (p, REQUEST_BUFFER, get_transput_buffer (PATH_BUFFER)); 102 // cURL connects to host, negotiates and collects data. 103 DATA_T data = {NO_TEXT, 0}; 104 curl_global_init (CURL_GLOBAL_ALL); 105 CURL *handle = curl_easy_init (); 106 curl_easy_setopt (handle, CURLOPT_URL, get_transput_buffer (REQUEST_BUFFER)); 107 curl_easy_setopt (handle, CURLOPT_WRITEFUNCTION, a68g_curl_concat); 108 curl_easy_setopt (handle, CURLOPT_WRITEDATA, (void *) &data); 109 curl_easy_setopt (handle, CURLOPT_USERAGENT, "libcurl-agent/1.0"); 110 curl_easy_setopt (handle, CURLOPT_CONNECTTIMEOUT, (long) a68g_curl_connecttimeout); 111 curl_easy_setopt (handle, CURLOPT_TIMEOUT, (long) a68g_curl_timeout); 112 CURLcode rc = curl_easy_perform (handle); 113 // Wrap it up. 114 if (rc != CURLE_OK) { 115 errno = rc; 116 } else { 117 *DEREF (A68G_REF, &content_string) = c_to_a_string (p, data.ref, data.len); 118 } 119 if (data.ref != NO_TEXT) { 120 a68g_free (data.ref); 121 } 122 curl_easy_cleanup (handle); 123 curl_global_cleanup (); 124 PUSH_VALUE (p, errno, A68G_INT); 125 } 126 127 //! @brief PROC (INT, INT) VOID http timeout 128 129 void genie_curl_timeout (NODE_T *p) 130 { 131 A68G_INT i, j; 132 POP_OBJECT (p, &j, A68G_INT); 133 POP_OBJECT (p, &i, A68G_INT); 134 a68g_curl_connecttimeout = VALUE (&i); 135 a68g_curl_timeout = VALUE (&j); 136 } 137 138 //! @brief PROC (REF STRING, STRING, STRING, INT) INT http content 139 140 void genie_http_content (NODE_T * p) 141 { 142 genie_curl_content (p, "http://"); 143 } 144 145 //! @brief PROC (REF STRING, STRING, STRING, INT) INT https content 146 147 void genie_https_content (NODE_T * p) 148 { 149 genie_curl_content (p, "https://"); 150 } 151 152 #endif
© 2001-2026 J.M. van der Veer
jmvdveer@algol68genie.nl