Mercurial > sci
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 } |