rsstats 0.0.1
Redis Enterprise Statistic collector
libhttp.c
Go to the documentation of this file.
1
19#include "libhttp.h"
20#include "sclist.h"
21#include "base64.h" /* Base64 encoder and decoder */
22
23#include <stdlib.h>
24#include <stdio.h>
25#include <string.h>
26#include <assert.h>
27
28typedef struct HTTP_s {
30 char* body;
32
33typedef struct HTTPHeader_s {
35 char* name;
36 char* value;
38
39HTTPHeader_t* HTTPHeader_new(const char* name, const char* value) {
40 HTTPHeader_t* header;
41
42 assert(name);
43 assert(value);
44
45 if (NULL==(header=malloc(sizeof(struct HTTPHeader_s)))) {
46 perror("HTTPHeader_new");
47 return NULL;
48 }
49 if (NULL==(header->name = strdup(name))) {
50 perror("HTTPHeader_new name");
51 free(header);
52 return NULL;
53 }
54 if (NULL==(header->value = strdup(value))) {
55 perror("HTTPHeader_new value");
56 free(header->name);
57 free(header);
58 return NULL;
59 }
60 header->sclistrecord = NULL;
61 return header;
62}
63
65 assert(header);
66 assert(header->name);
67 assert(header->value);
68
69 free(header->name);
70 free(header->value);
71 free(header);
72}
73
74HTTPHeader_t* HTTPHeader_basicauth(const char* login, const char* pass) {
75 char* auth_encoded;
76 char* auth;
77
78 assert(login);
79 assert(pass);
80
81 if (NULL==(auth=malloc(strlen("Basic ")+strlen(login)+1+strlen(pass)+1))) {
82 perror("HTTPHeader_basicauth");
83 return NULL;
84 }
85 /* strcpy/strcat expected to be faster than sprintf */
86 strcpy(auth,login);
87 strcat(auth,":");
88 strcat(auth,pass);
89 auth_encoded=base64_encode(auth);
90 free(auth);
91
92 if (NULL==(auth=malloc(strlen("Basic ")+strlen(auth_encoded)+1))) {
93 perror("HTTPHeader_basicauth");
94 free(auth_encoded);
95 return NULL;
96 }
97 strcpy(auth,"Basic ");
98 strcat(auth, auth_encoded);
99
100 return HTTPHeader_new("Authorization",auth);
101}
102
104 assert(header);
105 return header->name;
106}
107
109 assert(header);
110 return header->value;
111}
112
114 HTTP_t* retval;
115
116 if (NULL==(retval=malloc(sizeof(struct HTTP_s)))) {
117 perror("HTTP_new HTTP_s");
118 return NULL;
119 }
120
121 if (NULL==(retval->body=malloc(1))) {
122 perror("HTTP_new body");
123 free(retval);
124 return NULL;
125 };
126 retval->body[0]=0;
127
128 if (NULL==(retval->headers = sclist_new())) {
129 perror("HTTP_new headers");
130 free(retval->body);
131 free(retval);
132 return NULL;
133 }
134
135 return retval;
136}
137
138void HTTP_del(HTTP_t* http) {
139 sclistrecord_t* current;
140
141 assert(http);
142 assert(http->headers);
143 assert(http->body);
144
145 current = sclist_firstrecord(http->headers);
146 while (current) {
147 HTTPHeader_t* header=sclist_getvalue(current);
148 if (header->name)
149 free(header->name);
150 if (header->value)
151 free(header->value);
152 sclistrecord_t* tmp = current;
153 current = sclist_nextrecord(current);
154 sclist_remrecord(http->headers,tmp);
155 }
156
157 free(http->body);
158 free(http);
159}
160
161char* HTTP_setbody(HTTP_t* http, const char* body) {
162 char* newbody;
163
164 assert(http);
165 assert(body);
166 assert(http->body);
167
168 if (NULL==(newbody=realloc(http->body,strlen(body)+1))) {
169 perror("HTTP_setbody");
170 return NULL;
171 }
172
173 http->body = newbody;
174 strcpy(http->body, body);
175 return http->body;
176}
177
178char* HTTP_getbody(HTTP_t* http) {
179 assert(http);
180 assert(http->body);
181
182 return http->body;
183}
184
186 assert(http);
187 assert(http->headers);
188 assert(http->body);
189 assert(header);
190
191 /* Header already belonging to an header list */
192 if (header->sclistrecord) {
193 perror("HTTP_addheader, header already in a list");
194 return NULL;
195 }
196
197 if (NULL==(header->sclistrecord=sclist_addrecord(http->headers,header))) {
198 perror("HTTP_addheader");
199 return NULL;
200 }
201 return http;
202}
203
205 assert(http);
206 assert(http->headers);
207 sclistrecord_t* header_item=sclist_firstrecord(http->headers);
208 if (!header_item)
209 return NULL;
210 return sclist_getvalue(header_item);
211}
212
214 sclistrecord_t* list_it;
215
216 assert(header);
217
218 list_it = header->sclistrecord;
219
220 /* EOL reached */
221 if (NULL==(list_it = sclist_nextrecord(list_it)))
222 return NULL;
223 else
224 return sclist_getvalue(list_it);
225}
226
227HTTPHeader_t* HTTP_findheader(const HTTPHeader_t* start, const char* name, const char* value) {
228 sclistrecord_t* header_it;
229
230 assert(start);
231 assert(start->sclistrecord);
232 assert(name);
233 /* value can be null for "any" */
234
235 header_it = start->sclistrecord;
236
237 /* Find the record pointer in the list */
238 for (; header_it; header_it=sclist_nextrecord(header_it)) {
239 HTTPHeader_t* header_ptr = sclist_getvalue(header_it);
240 assert(header_ptr);
241 char* header_name = HTTPHeader_getname(header_ptr);
242 if (0==strcmp(header_name,name)) {
243 if (NULL==value)
244 break;
245 char* header_value = HTTPHeader_getvalue(header_ptr);
246 assert(header_value);
247 if (0==strcmp(header_value,value))
248 break;
249 }
250 }
251 if (!header_it)
252 return NULL;
253 else
254 return sclist_getvalue(header_it);
255}
256
258 assert(http);
259 assert(http->headers);
260 assert(http->body);
261 assert(header);
262
263 /* Calling function has the header pointer, can and need to free it */
264 sclist_remrecord(http->headers, header->sclistrecord);
266#if 0
267 if (NULL==sclist_remrecord(http->headers, header->sclistrecord)) {
268 perror("HTTP_addheader");
269 return NULL;
270 }
271#endif
272 header->sclistrecord = NULL;
273
274 return http;
275}
276
277char* HTTP_buildrequest(const HTTPMethod_t method, const char* uri, const HTTPVersion_t version) {
278 char* retval;
279
280 assert(method<=HTTPMETHOD_INVALID);
281 assert(version<=HTTPVERSION_INVALID);
282
283 /* NULL URI allowed, as an empty string */
284 if (NULL==(retval=malloc(7+1+(uri?strlen(uri)+1:0)+8+1))) {
285 perror("HTTP_getrequest");
286 exit(EXIT_FAILURE);
287 }
288 retval[0]=0;
289
290 switch(method) {
291 case HTTPMETHOD_GET:
292 strcat(retval, "GET");
293 break;;
294 case HTTPMETHOD_HEAD:
295 case HTTPMETHOD_POST:
296 case HTTPMETHOD_PUT:
300 case HTTPMETHOD_TRACE:
301 case HTTPMETHOD_PATCH:
303 default:
304 fprintf(stderr,"HTTP method not supported\n");
305 exit(EXIT_FAILURE);
306 break;;
307 }
308
309 /* NULL URI allowed, as an empty string */
310 if (uri) {
311 strcat(retval," ");
312 strcat(retval, uri);
313 }
314
315 strcat(retval," HTTP/");
316 switch(version) {
319 strcat(retval, "1.1");
320 break;;
326 default:
327 fprintf(stderr,"HTTP version not supported\n");
328 exit(EXIT_FAILURE);
329 break;;
330 }
331 strcat(retval, "\r\n");
332 return retval;
333}
334
335static char* strconcat(char* dst, char* src) {
336 char* newdst;
337
338 assert(dst);
339 assert(src);
340
341 if (NULL==(newdst=realloc(dst,strlen(dst)+strlen(src)+1))) {
342 perror("strconcat");
343 return NULL;
344 }
345 dst = newdst;
346 strcat(dst,src);
347 return dst;
348}
349
350char* HTTP_buildheaders(const HTTP_t* http) {
351 char* headers=NULL;
352 sclistrecord_t* sclistrecord;
353 HTTPHeader_t* header;
354
355 assert(http);
356 assert(http->headers);
357 assert(http->body);
358
359 if (NULL==(headers=strdup(""))) {
360 perror("HTTP_buildheaders headers");
361 return NULL;
362 }
363 for (sclistrecord=sclist_firstrecord(http->headers); sclistrecord; sclistrecord = sclist_nextrecord(sclistrecord)) {
364 header = sclist_getvalue(sclistrecord);
365 assert(header);
367 headers=strconcat(headers,HTTPHeader_getname(header));
368 headers=strconcat(headers,": ");
369 headers=strconcat(headers,HTTPHeader_getvalue(header));
370 headers=strconcat(headers,"\r\n");
371 }
372
373
374 return headers;
375}
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:204
char * HTTP_setbody(HTTP_t *http, const char *body)
Definition: libhttp.c:161
char * HTTPHeader_getvalue(HTTPHeader_t *header)
Definition: libhttp.c:108
void HTTPHeader_del(HTTPHeader_t *header)
Definition: libhttp.c:64
void HTTP_del(HTTP_t *http)
Definition: libhttp.c:138
HTTP_t * HTTP_addheader(HTTP_t *http, HTTPHeader_t *header)
Definition: libhttp.c:185
char * HTTP_buildheaders(const HTTP_t *http)
Definition: libhttp.c:350
struct HTTP_s HTTP_t
HTTP_t * HTTP_new()
Definition: libhttp.c:113
HTTPHeader_t * HTTPHeader_basicauth(const char *login, const char *pass)
Definition: libhttp.c:74
struct HTTPHeader_s HTTPHeader_t
char * HTTP_getbody(HTTP_t *http)
Definition: libhttp.c:178
HTTPHeader_t * HTTPHeader_new(const char *name, const char *value)
Definition: libhttp.c:39
char * HTTPHeader_getname(HTTPHeader_t *header)
Definition: libhttp.c:103
char * HTTP_buildrequest(const HTTPMethod_t method, const char *uri, const HTTPVersion_t version)
Definition: libhttp.c:277
HTTP_t * HTTP_delheader(HTTP_t *http, HTTPHeader_t *header)
Definition: libhttp.c:257
HTTPHeader_t * HTTP_nextheader(const HTTPHeader_t *header)
Definition: libhttp.c:213
HTTPHeader_t * HTTP_findheader(const HTTPHeader_t *start, const char *name, const char *value)
Definition: libhttp.c:227
HTTP parsing and building library.
enum HTTPVersion_e HTTPVersion_t
@ HTTPMETHOD_PUT
Definition: libhttp.h:38
@ HTTPMETHOD_POST
Definition: libhttp.h:37
@ HTTPMETHOD_CONNECT
Definition: libhttp.h:40
@ HTTPMETHOD_TRACE
Definition: libhttp.h:42
@ HTTPMETHOD_PATCH
Definition: libhttp.h:43
@ HTTPMETHOD_DELETE
Definition: libhttp.h:39
@ HTTPMETHOD_OPTIONS
Definition: libhttp.h:41
@ HTTPMETHOD_GET
Definition: libhttp.h:35
@ HTTPMETHOD_INVALID
Definition: libhttp.h:44
@ HTTPMETHOD_HEAD
Definition: libhttp.h:36
@ HTTPVERSION_HTTP11b
Definition: libhttp.h:28
@ HTTPVERSION_INVALID
Definition: libhttp.h:31
@ HTTPVERSION_HTTP09
Definition: libhttp.h:25
@ HTTPVERSION_HTTP2
Definition: libhttp.h:29
@ HTTPVERSION_HTTP10
Definition: libhttp.h:26
@ HTTPVERSION_HTTP3
Definition: libhttp.h:30
@ HTTPVERSION_HTTP11
Definition: libhttp.h:27
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:127
sclist_t * sclist_new()
Allocate and initialize the internal list structure.
Definition: sclist.c:39
sclistrecord_t * sclist_nextrecord(const sclistrecord_t *record)
Returns the pointer on the record following the specified one.
Definition: sclist.c:121
sclistrecord_t * sclist_addrecord(sclist_t *sclist, void *value)
Add a value at the end of the list.
Definition: sclist.c:62
sclistrecord_t * sclist_firstrecord(const sclist_t *sclist)
Returns the pointer on the first list record.
Definition: sclist.c:115
void sclist_remrecord(sclist_t *sclist, sclistrecord_t *record)
Remove a record in a list.
Definition: sclist.c:90
Basic single chained generic list.
Definition: libhttp.c:28
char * body
Definition: libhttp.c:30
sclist_t * headers
Definition: libhttp.c:29
char * value
Definition: libhttp.c:36
sclistrecord_t * sclistrecord
Definition: libhttp.c:34
char * name
Definition: libhttp.c:35
Opaque sclist structure.
Definition: sclist.c:34
Private list record structure.
Definition: sclist.c:27