rts-curl.c
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-2024 J. Marcel van der Veer [algol68g@xs4all.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 // Callback function concatenating received data.
46
47 static size_t a68_curl_concat (void *data, size_t len, size_t n, void *buf)
48 {
49 // Sanity checks.
50 if ((char *) data == NO_TEXT || (DATA_T *) buf == NO_DATA) {
51 return 0;
52 } else if (n == 0 || len == 0) {
53 return 0;
54 }
55 ABEND (len >= (2 * GIGABYTE) / n, ERROR_OUT_OF_CORE, NO_TEXT);
56 size_t new_len = n * len;
57 ABEND (new_len + 1 > 2 * GIGABYTE - ((DATA_T *) buf)->len, ERROR_OUT_OF_CORE, NO_TEXT);
58 char *stale = ((DATA_T *) buf)->ref;
59 ((DATA_T *) buf)->ref = malloc (((DATA_T *) buf)->len + new_len + 1);
60 ABEND (((DATA_T *) buf)->ref == NO_TEXT, ERROR_OUT_OF_CORE, NO_TEXT);
61 if (stale != NO_TEXT) {
62 MOVE (((DATA_T *) buf)->ref, stale, ((DATA_T *) buf)->len + 1);
63 free (stale);
64 }
65 MOVE (& (((DATA_T *) buf)->ref[((DATA_T *) buf)->len]), data, new_len);
66 ((DATA_T *) buf)->len += new_len;
67 ((DATA_T *) buf)->ref[((DATA_T *) buf)->len] = NULL_CHAR;
68 return new_len;
69 }
70
71 void genie_curl_content (NODE_T * p, char *protocol)
72 {
73 A68_REF path_string, domain_string, content_string;
74 A68_INT port;
75 errno = 0;
76 // Pop arguments.
77 POP_OBJECT (p, &port, A68_INT);
78 CHECK_INIT (p, INITIALISED (&port), M_INT); // Unused for now.
79 POP_REF (p, &path_string);
80 CHECK_INIT (p, INITIALISED (&path_string), M_STRING);
81 POP_REF (p, &domain_string);
82 CHECK_INIT (p, INITIALISED (&domain_string), M_STRING);
83 POP_REF (p, &content_string);
84 CHECK_REF (p, content_string, M_REF_STRING);
85 *DEREF (A68_REF, &content_string) = empty_string (p);
86 // Set buffers.
87 reset_transput_buffer (DOMAIN_BUFFER);
88 add_a_string_transput_buffer (p, DOMAIN_BUFFER, (BYTE_T *) & domain_string);
89 reset_transput_buffer (PATH_BUFFER);
90 add_a_string_transput_buffer (p, PATH_BUFFER, (BYTE_T *) & path_string);
91 // Compose request.
92 reset_transput_buffer (REQUEST_BUFFER);
93 if (protocol != NO_TEXT) {
94 add_string_transput_buffer (p, REQUEST_BUFFER, protocol);
95 }
96 add_string_transput_buffer (p, REQUEST_BUFFER, get_transput_buffer (DOMAIN_BUFFER));
97 add_string_transput_buffer (p, REQUEST_BUFFER, get_transput_buffer (PATH_BUFFER));
98 // cURL connects to host, negotiates and collects data.
99 DATA_T data = {NO_TEXT, 0};
100 curl_global_init (CURL_GLOBAL_ALL);
101 CURL *handle = curl_easy_init ();
102 curl_easy_setopt (handle, CURLOPT_URL, get_transput_buffer (REQUEST_BUFFER));
103 curl_easy_setopt (handle, CURLOPT_WRITEFUNCTION, a68_curl_concat);
104 curl_easy_setopt (handle, CURLOPT_WRITEDATA, (void *) &data);
105 curl_easy_setopt (handle, CURLOPT_USERAGENT, "libcurl-agent/1.0");
106 CURLcode rc = curl_easy_perform (handle);
107 // Wrap it up.
108 if (rc != CURLE_OK) {
109 errno = rc;
110 } else {
111 *DEREF (A68_REF, &content_string) = c_to_a_string (p, data.ref, data.len);
112 }
113 if (data.ref != NO_TEXT) {
114 free (data.ref);
115 }
116 curl_easy_cleanup (handle);
117 curl_global_cleanup ();
118 PUSH_VALUE (p, errno, A68_INT);
119 }
120
121 //! @brief PROC (REF STRING, STRING, STRING, INT) INT http content
122
123 void genie_http_content (NODE_T * p)
124 {
125 genie_curl_content (p, "http://");
126 }
127
128 //! @brief PROC (REF STRING, STRING, STRING, INT) INT https content
129
130 void genie_https_content (NODE_T * p)
131 {
132 genie_curl_content (p, "https://");
133 }
134
135 #endif
© 2002-2024 J.M. van der Veer (jmvdveer@xs4all.nl)
|