rsstats 0.0.1
Redis Enterprise Statistic collector
libhttp.c
Go to the documentation of this file.
1
19#ifdef HAVE_CONFIG_H
20#include "config.h"
21#endif
22
23#include "libhttp.h"
24#include "sclist.h"
25#include "base64.h" /* Base64 encoder and decoder */
26
27#include <stdlib.h>
28#include <stdio.h>
29#include <string.h>
30#include <assert.h>
31
32typedef struct HTTP_s {
34 char* body;
36
37typedef struct HTTPHeader_s {
39 char* name;
40 char* value;
42
44 char* newname;
45
46 assert(header);
47 assert(header->name);
48 assert(header->value);
49 assert(name);
50
51 if (name[0]==0) {
52 perror("HTTP_addheader empty name");
53 return NULL;
54 }
55
56 if (NULL==(newname=realloc(header->name,strlen(name)+1))) {
57 perror("HTTPHeader_setname realloc");
58 return NULL;
59 }
60 header->name = newname;
61 strcpy(header->name,name);
62 return header;
63}
64
66 assert(header);
67 assert(header->name);
68 assert(header->value);
69
70 return header->name;
71}
72
73HTTPHeader_t* HTTPHeader_setvalue(HTTPHeader_t* header, const char* value) {
74 char* newvalue;
75
76 assert(header);
77 assert(header->name);
78 assert(header->value);
79 assert(value);
80
81 if (NULL==(newvalue=realloc(header->value,strlen(value)+1))) {
82 perror("HTTPHeader_setvalue realloc");
83 return NULL;
84 }
85 header->value = newvalue;
86 strcpy(header->value,value);
87 return header;
88}
89
91 assert(header);
92 assert(header->name);
93 assert(header->value);
94
95 return header->value;
96}
97
98static HTTPHeader_t* HTTPHeader_new(const char* name, const char* value) {
99 HTTPHeader_t* header;
100
101 assert(name);
102 assert(value);
103
104 if (NULL==(header=malloc(sizeof(struct HTTPHeader_s)))) {
105 perror("HTTPHeader_new");
106 return NULL;
107 }
108 if (NULL==(header->name=strdup(name))) {
109 perror("HTTPHeader_new name");
110 free(header);
111 return NULL;
112 }
113 if (NULL==(header->value=strdup(value))) {
114 perror("HTTPHeader_new value");
115 free(header->name);
116 free(header);
117 return NULL;
118 }
119 header->self = NULL;
120 return header;
121}
122
123static void HTTPHeader_del(HTTPHeader_t* header) {
124 assert(header);
125 assert(header->name);
126 assert(header->value);
127
128 free(header->name);
129 free(header->value);
130 free(header);
131}
132
134 HTTP_t* http;
135
136 if (NULL==(http=malloc(sizeof(struct HTTP_s)))) {
137 perror("HTTP_new HTTP_s");
138 return NULL;
139 }
140
141 if (NULL==(http->body=strdup(""))) {
142 perror("HTTP_new body");
143 free(http);
144 return NULL;
145 };
146
147 if (NULL==(http->headers = sclist_new())) {
148 perror("HTTP_new headers");
149 free(http->body);
150 free(http);
151 return NULL;
152 }
153
154 return http;
155}
156
157void HTTP_del(HTTP_t* http) {
158 sclistrecord_t* headerlst_entry;
159
160 assert(http);
161 assert(http->headers);
162 assert(http->body);
163
164 headerlst_entry = sclist_firstrecord(http->headers);
165 while (headerlst_entry) {
166 HTTPHeader_t* headerlst_value;
167
168 /* Free payload */
169 headerlst_value=sclist_getvalue(headerlst_entry);
170 HTTPHeader_del(headerlst_value);
171
172 /* Remember the entry to delete before moving to the next one */
173 sclistrecord_t* tmp = headerlst_entry;
174 headerlst_entry = sclist_nextrecord(headerlst_entry);
175 sclist_remrecord(http->headers,tmp);
176 }
177
178 free(http->body);
179 free(http);
180}
181
182HTTP_t* HTTP_setbody(HTTP_t* http, const char* body) {
183 char* newbody;
184
185 assert(http);
186 assert(http->headers);
187 assert(http->body);
188 assert(body);
189
190 if (NULL==(newbody=realloc(http->body,strlen(body)+1))) {
191 perror("HTTP_setbody realloc");
192 return NULL;
193 }
194
195 http->body = newbody;
196 strcpy(http->body, body);
197 return http;
198}
199
200char* HTTP_getbody(HTTP_t* http) {
201 assert(http);
202 assert(http->headers);
203 assert(http->body);
204
205 return http->body;
206}
207
208HTTPHeader_t* HTTP_addheader(HTTP_t* http, const char* name, const char* value) {
209 HTTPHeader_t* header;
210
211 assert(http);
212 assert(http->headers);
213 assert(http->body);
214 assert(name);
215 assert(value);
216
217 if (name[0]==0) {
218 perror("HTTP_addheader empty name");
219 return NULL;
220 }
221
222 if (NULL==(header = HTTPHeader_new(name,value))) {
223 perror("HTTP_addheader HTTPHeader_new");
224 return NULL;
225 }
226
227 if (NULL==(header->self=sclist_addrecord(http->headers,header))) {
228 perror("HTTP_addheader");
229 HTTPHeader_del(header);
230 return NULL;
231 }
232 return header;
233}
234
235HTTPHeader_t* HTTP_addbasicauth(HTTP_t* http, const char* login, const char* pass) {
236 char* auth_encoded;
237 char* auth;
238 HTTPHeader_t* header;
239
240 assert(http);
241 assert(http->headers);
242 assert(http->body);
243 assert(login);
244 assert(pass);
245
246 if (NULL==(auth=malloc(strlen(login)+1+strlen(pass)+1))) {
247 perror("HTTP_addbasicauth credentials");
248 return NULL;
249 }
250 /* strcpy/strcat expected to be faster than sprintf */
251 strcpy(auth,login);
252 strcat(auth,":");
253 strcat(auth,pass);
254 auth_encoded=base64_encode(auth);
255 free(auth);
256
257 if (NULL==(auth=malloc(strlen("Basic ")+strlen(auth_encoded)+1))) {
258 perror("HTTP_addbasicauth value");
259 free(auth_encoded);
260 return NULL;
261 }
262 strcpy(auth,"Basic ");
263 strcat(auth, auth_encoded);
264 free(auth_encoded);
265
266 if (NULL==(header=HTTP_addheader(http,"Authorization",auth))) {
267 perror("HTTP_addbasicauth addheader");
268 free(auth);
269 return NULL;
270 }
271 free(auth);
272 return header;
273}
274
276 sclistrecord_t* headerlst_entry;
277
278 assert(http);
279 assert(http->headers);
280 assert(http->body);
281
282 if (NULL==(headerlst_entry=sclist_firstrecord(http->headers)))
283 return NULL;
284 return sclist_getvalue(headerlst_entry);
285}
286
288 sclistrecord_t* headerlst_entry;
289
290 assert(header);
291 assert(header->self);
292 assert(header->name);
293 assert(header->value);
294
295 headerlst_entry = header->self;
296
297 /* EOL reached */
298 if (NULL==(headerlst_entry = sclist_nextrecord(headerlst_entry)))
299 return NULL;
300 else
301 return sclist_getvalue(headerlst_entry);
302}
303
304HTTPHeader_t* HTTP_findheader(const HTTPHeader_t* start, const char* name) {
305 sclistrecord_t* headerlst_entry;
306
307 assert(start);
308 assert(start->self);
309 assert(start->name);
310 assert(start->value);
311 assert(name);
312
313 headerlst_entry = start->self;
314
315 while (headerlst_entry) {
316 HTTPHeader_t* headerlst_value;
317 char* header_name;
318
319 headerlst_value = sclist_getvalue(headerlst_entry);
320 assert(headerlst_value);
321 header_name = HTTPHeader_getname(headerlst_value);
322 if (0==strcmp(header_name,name))
323 break;
324 headerlst_entry=sclist_nextrecord(headerlst_entry);
325 }
326 if (!headerlst_entry)
327 /* Not found */
328 return NULL;
329 else
330 /* Found */
331 return sclist_getvalue(headerlst_entry);
332}
333
334
336 assert(http);
337 assert(http->headers);
338 assert(http->body);
339 assert(header);
340 assert(header->self);
341 assert(header->name);
342 assert(header->value);
343
344 /* Remove from the header list */
345 sclist_remrecord(http->headers, header->self);
347#if 0
348 if (NULL==sclist_remrecord(http->headers, header->sclistrecord)) {
349 perror("HTTP_addheader");
350 return NULL;
351 }
352#endif
356 header->self = NULL;
357 HTTPHeader_del(header);
358
359 return http;
360}
361
362static char* strconcat(char* dst, char* src) {
363 char* newdst;
364
365 assert(dst);
366 assert(src);
367
368 if (NULL==(newdst=realloc(dst,strlen(dst)+strlen(src)+1))) {
369 perror("strconcat");
370 return NULL;
371 }
372 dst = newdst;
373 strcat(dst,src);
374 return dst;
375}
376
377char* HTTP_buildheaders(const HTTP_t* http) {
378 char* headers_str=NULL;
379 sclistrecord_t* headerlst_entry;
380
381 assert(http);
382 assert(http->headers);
383 assert(http->body);
384
385 if (NULL==(headers_str=strdup(""))) {
386 perror("HTTP_buildheaders headers_str");
387 return NULL;
388 }
389 for (headerlst_entry=sclist_firstrecord(http->headers); headerlst_entry; headerlst_entry = sclist_nextrecord(headerlst_entry)) {
390 HTTPHeader_t* headerlst_value;
391
392 headerlst_value = sclist_getvalue(headerlst_entry);
393 assert(headerlst_value);
395 headers_str=strconcat(headers_str,HTTPHeader_getname(headerlst_value));
396 headers_str=strconcat(headers_str,": ");
397 headers_str=strconcat(headers_str,HTTPHeader_getvalue(headerlst_value));
398 headers_str=strconcat(headers_str,"\r\n");
399 }
400
401 return headers_str;
402}
403
404
405
406
407
408
409
410
411
412
413
414
415
416char* HTTP_buildrequest(const HTTPMethod_t method, const char* uri, const HTTPVersion_t version) {
417 char* retval;
418
419 assert(method<=HTTPMETHOD_INVALID);
420 assert(uri);
421 assert(version<=HTTPVERSION_INVALID);
422
423 if (NULL==(retval=malloc(7+1+strlen(uri)+1+8+1))) {
424 perror("HTTP_getrequest");
425 exit(EXIT_FAILURE);
426 }
427 retval[0]=0;
428
429 switch(method) {
430 case HTTPMETHOD_GET:
431 strcat(retval, "GET");
432 break;;
433 case HTTPMETHOD_HEAD:
434 case HTTPMETHOD_POST:
435 case HTTPMETHOD_PUT:
439 case HTTPMETHOD_TRACE:
440 case HTTPMETHOD_PATCH:
442 default:
443 fprintf(stderr,"HTTP method not supported\n");
444 exit(EXIT_FAILURE);
445 break;;
446 }
447
448 if (uri[0]) {
449 strcat(retval," ");
450 strcat(retval, uri);
451 }
452
453 strcat(retval," HTTP/");
454 switch(version) {
457 strcat(retval, "1.1");
458 break;;
464 default:
465 fprintf(stderr,"HTTP version not supported\n");
466 exit(EXIT_FAILURE);
467 break;;
468 }
469 strcat(retval, "\r\n");
470 return retval;
471}
472
char * base64_encode(char *plain)
Encode a zero terminated C string in Base64.
Definition: base64.c:39
Simple Base64 encoding and decoding functions.
const char *const name
Definition: cJSON.h:268
HTTPHeader_t * HTTP_firstheader(const HTTP_t *http)
Definition: libhttp.c:275
char * HTTPHeader_getvalue(HTTPHeader_t *header)
Definition: libhttp.c:90
HTTP_t * HTTP_remheader(HTTP_t *http, HTTPHeader_t *header)
Definition: libhttp.c:335
void HTTP_del(HTTP_t *http)
Definition: libhttp.c:157
char * HTTP_buildheaders(const HTTP_t *http)
Definition: libhttp.c:377
struct HTTP_s HTTP_t
HTTP_t * HTTP_new()
Definition: libhttp.c:133
struct HTTPHeader_s HTTPHeader_t
HTTPHeader_t * HTTP_addbasicauth(HTTP_t *http, const char *login, const char *pass)
Definition: libhttp.c:235
char * HTTP_getbody(HTTP_t *http)
Definition: libhttp.c:200
char * HTTPHeader_getname(HTTPHeader_t *header)
Definition: libhttp.c:65
HTTPHeader_t * HTTPHeader_setname(HTTPHeader_t *header, const char *name)
Definition: libhttp.c:43
HTTPHeader_t * HTTP_findheader(const HTTPHeader_t *start, const char *name)
Definition: libhttp.c:304
HTTP_t * HTTP_setbody(HTTP_t *http, const char *body)
Definition: libhttp.c:182
HTTPHeader_t * HTTP_addheader(HTTP_t *http, const char *name, const char *value)
Definition: libhttp.c:208
char * HTTP_buildrequest(const HTTPMethod_t method, const char *uri, const HTTPVersion_t version)
Definition: libhttp.c:416
HTTPHeader_t * HTTPHeader_setvalue(HTTPHeader_t *header, const char *value)
Definition: libhttp.c:73
HTTPHeader_t * HTTP_nextheader(const HTTPHeader_t *header)
Definition: libhttp.c:287
HTTP parsing and building library.
enum HTTPVersion_e HTTPVersion_t
@ HTTPMETHOD_PUT
Definition: libhttp.h:39
@ HTTPMETHOD_POST
Definition: libhttp.h:38
@ HTTPMETHOD_CONNECT
Definition: libhttp.h:41
@ HTTPMETHOD_TRACE
Definition: libhttp.h:43
@ HTTPMETHOD_PATCH
Definition: libhttp.h:44
@ HTTPMETHOD_DELETE
Definition: libhttp.h:40
@ HTTPMETHOD_OPTIONS
Definition: libhttp.h:42
@ HTTPMETHOD_GET
Definition: libhttp.h:36
@ HTTPMETHOD_INVALID
Definition: libhttp.h:45
@ HTTPMETHOD_HEAD
Definition: libhttp.h:37
@ HTTPVERSION_HTTP11b
Definition: libhttp.h:29
@ HTTPVERSION_INVALID
Definition: libhttp.h:32
@ HTTPVERSION_HTTP09
Definition: libhttp.h:26
@ HTTPVERSION_HTTP2
Definition: libhttp.h:30
@ HTTPVERSION_HTTP10
Definition: libhttp.h:27
@ HTTPVERSION_HTTP3
Definition: libhttp.h:31
@ HTTPVERSION_HTTP11
Definition: libhttp.h:28
enum HTTPMethod_e HTTPMethod_t
#define NULL
Definition: rsstats-opts.c:64
void * sclist_getvalue(sclistrecord_t *record)
Returns the value pointer stored in the record.
Definition: sclist.c:131
sclist_t * sclist_new()
Allocate and initialize the internal list structure.
Definition: sclist.c:43
sclistrecord_t * sclist_nextrecord(const sclistrecord_t *record)
Returns the pointer on the record following the specified one.
Definition: sclist.c:125
sclistrecord_t * sclist_addrecord(sclist_t *sclist, void *value)
Add a value at the end of the list.
Definition: sclist.c:66
sclistrecord_t * sclist_firstrecord(const sclist_t *sclist)
Returns the pointer on the first list record.
Definition: sclist.c:119
void sclist_remrecord(sclist_t *sclist, sclistrecord_t *record)
Remove a record in a list.
Definition: sclist.c:94
Basic single chained generic list.
Definition: libhttp.c:32
char * body
Definition: libhttp.c:34
sclist_t * headers
Definition: libhttp.c:33
char * value
Definition: libhttp.c:40
sclistrecord_t * self
Definition: libhttp.c:38
char * name
Definition: libhttp.c:39
Opaque sclist structure.
Definition: sclist.c:38
Private list record structure.
Definition: sclist.c:31