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 fprintf(stderr,"ERROR: HTTP_setname empty name\n");
53 return NULL;
54 }
55
56 if (NULL==(newname=realloc(header->name,strlen(name)+1))) {
57 perror("ERROR: 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("ERROR: 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("ERROR: HTTPHeader_new");
106 return NULL;
107 }
108 if (NULL==(header->name=strdup(name))) {
109 perror("ERROR: HTTPHeader_new name");
110 free(header);
111 return NULL;
112 }
113 if (NULL==(header->value=strdup(value))) {
114 perror("ERROR: 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("ERROR: HTTP_new HTTP_s");
138 return NULL;
139 }
140
141 if (NULL==(http->body=strdup(""))) {
142 perror("ERROR: HTTP_new body");
143 free(http);
144 return NULL;
145 };
146
147 if (NULL==(http->headers = sclist_new())) {
148 fprintf(stderr,"ERROR: HTTP_new headers\n");
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 sclist_del(http->headers);
178
179 free(http->body);
180 free(http);
181}
182
183HTTP_t* HTTP_setbody(HTTP_t* http, const char* body) {
184 char* newbody;
185
186 assert(http);
187 assert(http->headers);
188 assert(http->body);
189 assert(body);
190
191 if (NULL==(newbody=realloc(http->body,strlen(body)+1))) {
192 perror("ERROR: HTTP_setbody realloc");
193 return NULL;
194 }
195
196 http->body = newbody;
197 strcpy(http->body, body);
198 return http;
199}
200
201char* HTTP_getbody(HTTP_t* http) {
202 assert(http);
203 assert(http->headers);
204 assert(http->body);
205
206 return http->body;
207}
208
209HTTPHeader_t* HTTP_addheader(HTTP_t* http, const char* name, const char* value) {
210 HTTPHeader_t* header;
211
212 assert(http);
213 assert(http->headers);
214 assert(http->body);
215 assert(name);
216 assert(value);
217
218 if (name[0]==0) {
219 fprintf(stderr,"ERROR: HTTP_addheader empty name\n");
220 return NULL;
221 }
222
223 if (NULL==(header = HTTPHeader_new(name,value))) {
224 fprintf(stderr,"ERROR: HTTP_addheader HTTPHeader_new\n");
225 return NULL;
226 }
227
228 if (NULL==(header->self=sclist_addrecord(http->headers,header))) {
229 fprintf(stderr,"ERROR: HTTP_addheader\n");
230 HTTPHeader_del(header);
231 return NULL;
232 }
233 return header;
234}
235
236HTTPHeader_t* HTTP_addbasicauth(HTTP_t* http, const char* login, const char* pass) {
237 char* auth_encoded;
238 char* auth;
239 HTTPHeader_t* header;
240
241 assert(http);
242 assert(http->headers);
243 assert(http->body);
244 assert(login);
245 assert(pass);
246
247 if (NULL==(auth=malloc(strlen(login)+1+strlen(pass)+1))) {
248 perror("ERROR: HTTP_addbasicauth credentials");
249 return NULL;
250 }
251 /* strcpy/strcat expected to be faster than sprintf */
252 strcpy(auth,login);
253 strcat(auth,":");
254 strcat(auth,pass);
255 auth_encoded=base64_encode(auth);
256 free(auth);
257
258 if (NULL==(auth=malloc(strlen("Basic ")+strlen(auth_encoded)+1))) {
259 perror("ERROR: HTTP_addbasicauth value");
260 free(auth_encoded);
261 return NULL;
262 }
263 strcpy(auth,"Basic ");
264 strcat(auth, auth_encoded);
265 free(auth_encoded);
266
267 if (NULL==(header=HTTP_addheader(http,"Authorization",auth))) {
268 fprintf(stderr,"ERROR: HTTP_addbasicauth addheader\n");
269 free(auth);
270 return NULL;
271 }
272 free(auth);
273 return header;
274}
275
277 sclistrecord_t* headerlst_entry;
278
279 assert(http);
280 assert(http->headers);
281 assert(http->body);
282
283 if (NULL==(headerlst_entry=sclist_firstrecord(http->headers)))
284 return NULL;
285 return sclist_getvalue(headerlst_entry);
286}
287
289 sclistrecord_t* headerlst_entry;
290
291 assert(header);
292 assert(header->self);
293 assert(header->name);
294 assert(header->value);
295
296 headerlst_entry = header->self;
297
298 /* EOL reached */
299 if (NULL==(headerlst_entry = sclist_nextrecord(headerlst_entry)))
300 return NULL;
301 else
302 return sclist_getvalue(headerlst_entry);
303}
304
305HTTPHeader_t* HTTP_findheader(const HTTPHeader_t* start, const char* name) {
306 sclistrecord_t* headerlst_entry;
307
308 assert(start);
309 assert(start->self);
310 assert(start->name);
311 assert(start->value);
312 assert(name);
313
314 headerlst_entry = start->self;
315
316 while (headerlst_entry) {
317 HTTPHeader_t* headerlst_value;
318 char* header_name;
319
320 headerlst_value = sclist_getvalue(headerlst_entry);
321 assert(headerlst_value);
322 header_name = HTTPHeader_getname(headerlst_value);
323 if (0==strcmp(header_name,name))
324 break;
325 headerlst_entry=sclist_nextrecord(headerlst_entry);
326 }
327 if (!headerlst_entry)
328 /* Not found */
329 return NULL;
330 else
331 /* Found */
332 return sclist_getvalue(headerlst_entry);
333}
334
335
337 assert(http);
338 assert(http->headers);
339 assert(http->body);
340 assert(header);
341 assert(header->self);
342 assert(header->name);
343 assert(header->value);
344
345 /* Remove from the header list */
346 if (NULL==sclist_remrecord(http->headers, header->self)) {
347 fprintf(stderr,"ERROR: HTTP_remheader not found\n");
348 return NULL;
349 }
350 header->self = NULL;
351 HTTPHeader_del(header);
352
353 return http;
354}
355
356static char* strconcat(char* dst, const char* src) {
357 char* newdst;
358
359 assert(dst);
360 assert(src);
361
362 if (NULL==(newdst=realloc(dst,strlen(dst)+strlen(src)+1))) {
363 perror("ERROR: strconcat");
364 return NULL;
365 }
366 dst = newdst;
367 strcat(dst,src);
368 return dst;
369}
370
371char* HTTP_buildheaders(const HTTP_t* http) {
372 char* headers_str=NULL;
373 sclistrecord_t* headerlst_entry;
374
375 assert(http);
376 assert(http->headers);
377 assert(http->body);
378
379 if (NULL==(headers_str=strdup(""))) {
380 perror("ERROR: HTTP_buildheaders headers_str");
381 return NULL;
382 }
383 for (
384 headerlst_entry=sclist_firstrecord(http->headers);
385 headerlst_entry;
386 headerlst_entry = sclist_nextrecord(headerlst_entry)
387 ) {
388 HTTPHeader_t* headerlst_value;
389
390 headerlst_value = sclist_getvalue(headerlst_entry);
391 assert(headerlst_value);
393 headers_str=strconcat(headers_str,HTTPHeader_getname(headerlst_value));
394 headers_str=strconcat(headers_str,": ");
395 headers_str=strconcat(headers_str,HTTPHeader_getvalue(headerlst_value));
396 headers_str=strconcat(headers_str,"\r\n");
397 }
398
399 return headers_str;
400}
401
402
403
404
405
406
407
408
409
410
411
412
413/* @todo redesign headers and implementation to identify different errors */
414char* HTTP_buildrequest(const HTTP_t* http, const HTTPMethod_t method, const char* uri, const HTTPVersion_t version) {
415 char* request;
416 char* newrequest;
417 char* headers;
418
419 assert(method<=HTTPMETHOD_INVALID);
420 assert(uri);
421 assert(version<=HTTPVERSION_INVALID);
422
423 if (NULL==(request=strdup(""))) {
424 perror("ERROR: HTTP_getrequest strdup");
425 return NULL;
426 }
427
428 switch(method) {
429 case HTTPMETHOD_GET:
430 if (NULL==(newrequest=strconcat(request, "GET"))) {
431 fprintf(stderr,"ERROR: HTTP_buildrequest method\n");
432 free(request);
433 return NULL;
434 }
435 break;;
436 case HTTPMETHOD_HEAD:
437 case HTTPMETHOD_POST:
438 case HTTPMETHOD_PUT:
442 case HTTPMETHOD_TRACE:
443 case HTTPMETHOD_PATCH:
445 default:
446 fprintf(stderr,"ERROR: HTTP method not supported\n");
447 free(request);
448 return NULL;
449 break;;
450 }
451
452 if (uri[0]) {
453 if (NULL==(newrequest=strconcat(request, " "))) {
454 fprintf(stderr,"ERROR: HTTP_buildrequest uri\n");
455 free(request);
456 return NULL;
457 }
458 request = newrequest;
459 if (NULL==(newrequest=strconcat(request, uri))) {
460 fprintf(stderr,"ERROR: HTTP_buildrequest uri\n");
461 free(request);
462 return NULL;
463 }
464 request = newrequest;
465 }
466
467 if (NULL==(newrequest=strconcat(request, " HTTP/"))) {
468 fprintf(stderr,"ERROR: HTTP_buildrequest HTTP\n");
469 free(request);
470 return NULL;
471 }
472 request = newrequest;
473 switch(version) {
476 if (NULL==(newrequest=strconcat(request, "1.1"))) {
477 fprintf(stderr,"ERROR: HTTP_buildrequest Version\n");
478 free(request);
479 return NULL;
480 }
481 request = newrequest;
482 break;;
488 default:
489 fprintf(stderr,"PANIC: HTTP version not supported\n");
490 free(request);
491 return NULL;
492 break;;
493 }
494 if (NULL==(newrequest=strconcat(request, "\r\n"))) {
495 fprintf(stderr,"ERROR: HTTP_buildrequest Version\n");
496 free(request);
497 return NULL;
498 }
499 request = newrequest;
500
501 if (NULL==(headers=HTTP_buildheaders(http))) {
502 fprintf(stderr,"ERROR: HTTP_buildrequest buildheaders\n");
503 free(request);
504 return NULL;
505 }
506
507 if (NULL==(newrequest=strconcat(request, headers))) {
508 fprintf(stderr,"ERROR: HTTP_buildrequest header separator\n");
509 free(request);
510 return NULL;
511 }
512 request = newrequest;
513 free(headers);
514
515 if (NULL==(newrequest=strconcat(request, "\r\n"))) {
516 fprintf(stderr,"ERROR: HTTP_buildrequest header separator\n");
517 free(request);
518 return NULL;
519 }
520 request = newrequest;
521
522 if (NULL==(newrequest=strconcat(request, http->body))) {
523 fprintf(stderr,"ERROR: HTTP_buildrequest body\n");
524 free(request);
525 return NULL;
526 }
527 request = newrequest;
528
529 return request;
530}
531
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:276
char * HTTPHeader_getvalue(HTTPHeader_t *header)
Definition: libhttp.c:90
HTTP_t * HTTP_remheader(HTTP_t *http, HTTPHeader_t *header)
Definition: libhttp.c:336
void HTTP_del(HTTP_t *http)
Definition: libhttp.c:157
char * HTTP_buildheaders(const HTTP_t *http)
Definition: libhttp.c:371
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:236
char * HTTP_getbody(HTTP_t *http)
Definition: libhttp.c:201
char * HTTP_buildrequest(const HTTP_t *http, const HTTPMethod_t method, const char *uri, const HTTPVersion_t version)
Definition: libhttp.c:414
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:305
HTTP_t * HTTP_setbody(HTTP_t *http, const char *body)
Definition: libhttp.c:183
HTTPHeader_t * HTTP_addheader(HTTP_t *http, const char *name, const char *value)
Definition: libhttp.c:209
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:288
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:132
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:126
void sclist_del(sclist_t *sclist)
Free all the list structure but not the values.
Definition: sclist.c:55
sclist_t * sclist_remrecord(sclist_t *sclist, sclistrecord_t *record)
Remove a record in a list.
Definition: sclist.c:94
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:120
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