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
353 header->self = NULL;
354 HTTPHeader_del(header);
355
356 return http;
357}
358
359static char* strconcat(char* dst, char* src) {
360 char* newdst;
361
362 assert(dst);
363 assert(src);
364
365 if (NULL==(newdst=realloc(dst,strlen(dst)+strlen(src)+1))) {
366 perror("strconcat");
367 return NULL;
368 }
369 dst = newdst;
370 strcat(dst,src);
371 return dst;
372}
373
374char* HTTP_buildheaders(const HTTP_t* http) {
375 char* headers_str=NULL;
376 sclistrecord_t* headerlst_entry;
377
378 assert(http);
379 assert(http->headers);
380 assert(http->body);
381
382 if (NULL==(headers_str=strdup(""))) {
383 perror("HTTP_buildheaders headers_str");
384 return NULL;
385 }
386 for (headerlst_entry=sclist_firstrecord(http->headers); headerlst_entry; headerlst_entry = sclist_nextrecord(headerlst_entry)) {
387 HTTPHeader_t* headerlst_value;
388
389 headerlst_value = sclist_getvalue(headerlst_entry);
390 assert(headerlst_value);
392 headers_str=strconcat(headers_str,HTTPHeader_getname(headerlst_value));
393 headers_str=strconcat(headers_str,": ");
394 headers_str=strconcat(headers_str,HTTPHeader_getvalue(headerlst_value));
395 headers_str=strconcat(headers_str,"\r\n");
396 }
397
398 return headers_str;
399}
400
401
402
403
404
405
406
407
408
409
410
411
412
413char* HTTP_buildrequest(const HTTPMethod_t method, const char* uri, const HTTPVersion_t version) {
414 char* retval;
415
416 assert(method<=HTTPMETHOD_INVALID);
417 assert(uri);
418 assert(version<=HTTPVERSION_INVALID);
419
420 if (NULL==(retval=malloc(7+1+strlen(uri)+1+8+1))) {
421 perror("HTTP_getrequest");
422 exit(EXIT_FAILURE);
423 }
424 retval[0]=0;
425
426 switch(method) {
427 case HTTPMETHOD_GET:
428 strcat(retval, "GET");
429 break;;
430 case HTTPMETHOD_HEAD:
431 case HTTPMETHOD_POST:
432 case HTTPMETHOD_PUT:
436 case HTTPMETHOD_TRACE:
437 case HTTPMETHOD_PATCH:
439 default:
440 fprintf(stderr,"HTTP method not supported\n");
441 exit(EXIT_FAILURE);
442 break;;
443 }
444
445 if (uri[0]) {
446 strcat(retval," ");
447 strcat(retval, uri);
448 }
449
450 strcat(retval," HTTP/");
451 switch(version) {
454 strcat(retval, "1.1");
455 break;;
461 default:
462 fprintf(stderr,"HTTP version not supported\n");
463 exit(EXIT_FAILURE);
464 break;;
465 }
466 strcat(retval, "\r\n");
467 return retval;
468}
469
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:374
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:413
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