comparison lib/apic.c @ 19:de4bf839b565

misc: revamp SQL
author David Demelier <markand@malikania.fr>
date Fri, 15 Jul 2022 11:11:48 +0200
parents
children f98ea578b1ef
comparison
equal deleted inserted replaced
18:600204c31bf0 19:de4bf839b565
1 #include <assert.h>
2 #include <errno.h>
3 #include <stdarg.h>
4 #include <stdio.h>
5 #include <string.h>
6
7 #include <curl/curl.h>
8
9 #include "apic.h"
10 #include "util.h"
11
12 struct curlpack {
13 CURL *curl;
14 CURLcode code;
15 struct curl_slist *headers;
16 };
17
18 static size_t
19 writer(char *in, size_t n, size_t w, FILE *fp)
20 {
21 if (fwrite(in, n, w, fp) != w)
22 return 0;
23
24 return w;
25 }
26
27 static inline char *
28 create_url(const char *fmt, va_list args)
29 {
30 static _Thread_local char ret[256];
31 va_list ap;
32
33 ret[0] = 0;
34 va_copy(ap, args);
35 vsnprintf(ret, sizeof (ret), fmt, ap);
36 va_end(ap);
37
38 return ret;
39 }
40
41 static inline FILE *
42 create_file(char **buf, size_t *bufsz)
43 {
44 FILE *fp;
45
46 *buf = NULL;
47 *bufsz = 0;
48
49 if (!(fp = open_memstream(buf, bufsz)))
50 util_die("open_memstream: %s\n", strerror(errno));
51
52 return fp;
53 }
54
55 static struct curlpack
56 create_curl(FILE *fp, const char *body, const char *url)
57 {
58 struct curlpack pack = {0};
59
60 pack.headers = curl_slist_append(pack.headers, "Content-Type: application/json");
61 pack.curl = curl_easy_init();
62 curl_easy_setopt(pack.curl, CURLOPT_HTTPHEADER, pack.headers);
63 curl_easy_setopt(pack.curl, CURLOPT_URL, url);
64 curl_easy_setopt(pack.curl, CURLOPT_FOLLOWLOCATION, 1L);
65 curl_easy_setopt(pack.curl, CURLOPT_TIMEOUT, 3L);
66 curl_easy_setopt(pack.curl, CURLOPT_WRITEFUNCTION, writer);
67 curl_easy_setopt(pack.curl, CURLOPT_WRITEDATA, fp);
68 curl_easy_setopt(pack.curl, CURLOPT_NOSIGNAL, 1L);
69
70 /* Assume POST request if there is a body. */
71 if (body) {
72 curl_easy_setopt(pack.curl, CURLOPT_POSTFIELDS, body);
73 curl_easy_setopt(pack.curl, CURLOPT_POSTFIELDSIZE, strlen(body));
74 }
75
76 pack.code = curl_easy_perform(pack.curl);
77
78 return pack;
79 }
80
81 static int
82 perform(struct apicreq *req, const char *body, const char *fmt, va_list ap)
83 {
84 FILE *fp;
85 char *response, *url;
86 size_t responsesz;
87 json_error_t error;
88 int ret = -1;
89 struct curlpack curl;
90
91 memset(req, 0, sizeof (*req));
92
93 url = create_url(fmt, ap);
94 fp = create_file(&response, &responsesz);
95 curl = create_curl(fp, body, url);
96
97 /* Perform that request now. */
98 fclose(fp);
99
100 if (curl.code != CURLE_OK)
101 snprintf(req->error, sizeof (req->error), "%s", curl_easy_strerror(curl.code));
102 else {
103 curl_easy_getinfo(curl.curl, CURLINFO_RESPONSE_CODE, &req->status);
104
105 if (req->status != 200)
106 snprintf(req->error, sizeof (req->error), "HTTP returned %ld", req->status);
107 if (response[0] && !(req->doc = json_loads(response, 0, &error)))
108 snprintf(req->error, sizeof (req->error), "JSON parse error: %s", error.text);
109 else
110 ret = 0;
111 }
112
113 curl_easy_cleanup(curl.curl);
114 curl_slist_free_all(curl.headers);
115
116 free(response);
117
118 return ret;
119 }
120
121 int
122 apic_get(struct apicreq *req, const char *fmt, ...)
123 {
124 assert(req);
125 assert(fmt);
126
127 va_list ap;
128 int ret;
129
130 va_start(ap, fmt);
131 ret = perform(req, NULL, fmt, ap);
132 va_end(ap);
133
134 return ret;
135 }
136
137 int
138 apic_post(struct apicreq *req, const json_t *doc, const char *fmt, ...)
139 {
140 assert(req);
141 assert(fmt);
142
143 va_list ap;
144 int ret;
145 char *body;
146
147 if (!(body = json_dumps(doc, JSON_COMPACT)))
148 util_die("%s", strerror(ENOMEM));
149
150 va_start(ap, fmt);
151 ret = perform(req, body, fmt, ap);
152 va_end(ap);
153
154 free(body);
155
156 return ret;
157 }