LCOV - code coverage report
Current view: top level - src - libhttp.c (source / functions) Hit Total Coverage
Test: mkernel.info Lines: 115 150 76.7 %
Date: 2024-11-20 21:09:21 Functions: 12 12 100.0 %

          Line data    Source code
       1             : /**
       2             :  *    @file  libhttp.c
       3             :  *   @brief  HTTP parsing and building library
       4             :  *
       5             :  *  @author  François Cerbelle (Fanfan), francois@cerbelle.net
       6             :  *
       7             :  *  @internal
       8             :  *       Created:  15/11/2024
       9             :  *      Revision:  none
      10             :  * Last modified:  2024-11-20 20:59
      11             :  *      Compiler:  gcc
      12             :  *  Organization:  Cerbelle.net
      13             :  *     Copyright:  Copyright (c) 2024, François Cerbelle
      14             :  *
      15             :  *  This source code is released for free distribution under the terms of the
      16             :  *  GNU General Public License as published by the Free Software Foundation.
      17             :  */
      18             : 
      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             : 
      28             : typedef struct HTTP_s {
      29             :     sclist_t* headers;
      30             :     char* body;
      31             : } HTTP_t;
      32             : 
      33             : typedef struct HTTPHeader_s {
      34             :     char* name;
      35             :     char* value;
      36             : } HTTPHeader_t;
      37             : 
      38           6 : HTTPHeader_t* HTTPHeader_new(const char* name, const char* value) {
      39             :     HTTPHeader_t* header;
      40             : 
      41           6 :     assert(name);
      42           6 :     assert(value);
      43             : 
      44           6 :     if (NULL==(header=malloc(sizeof(struct HTTPHeader_s)))) {
      45           0 :         perror("HTTPHeader_new");
      46             :     } else {
      47           6 :         header->name = strdup(name);
      48           6 :         header->value = strdup(value);
      49             :     }
      50           6 :     return header;
      51             : }
      52             : 
      53           6 : void          HTTPHeader_del(HTTPHeader_t* header) {
      54           6 :     assert(header);
      55           6 :     assert(header->name);
      56           6 :     assert(header->value);
      57             : 
      58           6 :     free(header->name);
      59           6 :     free(header->value);
      60           6 :     free(header);
      61           6 : }
      62             : 
      63           3 : HTTPHeader_t* HTTPHeader_basicauth(const char* login, const char* pass) {
      64           3 :     assert(login);
      65           3 :     assert(pass);
      66             : 
      67             :     /* Prepare basic authentication */
      68             :     char* auth_encoded;
      69             :     char* auth;
      70             :     {
      71           3 :         if (NULL==(auth=malloc(strlen("Basic ")+strlen(login)+1+strlen(pass)+1))) {
      72           0 :             perror("HTTPHeader_basicauth");
      73           0 :             return NULL;
      74             :         };
      75             :         /* strcpy/strcat expected to be faster than sprintf */
      76           3 :         strcpy(auth,login);
      77           3 :         strcat(auth,":");
      78           3 :         strcat(auth,pass);
      79           3 :         auth_encoded=base64_encode(auth);
      80           3 :         free(auth);
      81             :     }
      82             : 
      83           3 :     if (NULL==(auth=malloc(strlen("Basic ")+strlen(auth_encoded)+1))) {
      84           0 :         perror("HTTPHeader_basicauth");
      85           0 :         free(auth_encoded);
      86           0 :         return NULL;
      87             :     };
      88           3 :     strcpy(auth,"Basic ");
      89           3 :     strcat(auth, auth_encoded);
      90           3 :     return HTTPHeader_new("Authorization",auth);
      91             : }
      92             : 
      93          12 : char*         HTTPHeader_getname(HTTPHeader_t* header) {
      94          12 :     assert(header);
      95          12 :     return header->name;
      96             : }
      97             : 
      98          12 : char*         HTTPHeader_getvalue(HTTPHeader_t* header) {
      99          12 :     assert(header);
     100          12 :     return header->value;
     101             : }
     102             : 
     103           3 : HTTP_t* HTTP_new() {
     104             :     HTTP_t* retval;
     105             : 
     106           3 :     if (NULL==(retval=malloc(sizeof(struct HTTP_s)))) {
     107           0 :         perror("HTTP_new HTTP_s");
     108           0 :         return NULL;
     109             :     }
     110             : 
     111           3 :     if (NULL==(retval->body=malloc(1))) {
     112           0 :         perror("HTTP_new body");
     113           0 :         free(retval);
     114           0 :         return NULL;
     115             :     };
     116           3 :     retval->body[0]=0;
     117             : 
     118           3 :     if (NULL==(retval->headers = sclist_new())) {
     119           0 :         perror("HTTP_new headers");
     120           0 :         free(retval->body);
     121           0 :         free(retval);
     122           0 :         return NULL;
     123             :     }
     124             : 
     125           3 :     return retval;
     126             : }
     127             : 
     128             : 
     129             : 
     130             : 
     131             : 
     132             : 
     133             : 
     134             : 
     135             : typedef struct HTTPHeaders_s {
     136             :     char* name;
     137             :     char* value;
     138             : } HTTPHeaders_t;
     139             : 
     140           3 : void HTTP_del(HTTP_t* http) {
     141             :     sclistrecord_t* current;
     142             : 
     143           3 :     assert(http);
     144           3 :     assert(http->headers);
     145           3 :     assert(http->body);
     146             : 
     147             :     /* Use sclist_remrecord() and sclist_del() */
     148           3 :     current = sclist_firstrecord(http->headers);
     149           6 :     while (current) {
     150           3 :         HTTPHeaders_t* header=sclist_getvalue(current);
     151           3 :         if (header->name)
     152           3 :             free(header->name);
     153           3 :         if (header->value)
     154           3 :             free(header->value);
     155           3 :         current = sclist_nextrecord(current);
     156             :     }
     157             : 
     158           3 :     free(http->body);
     159           3 :     free(http);
     160           3 : }
     161             : 
     162             : 
     163           3 : void HTTP_addheader(HTTP_t* http, const char* name, const char* value) {
     164             :     HTTPHeaders_t* headers;
     165             : 
     166           3 :     assert(http);
     167           3 :     assert(http->headers);
     168           3 :     assert(http->body);
     169             : 
     170           3 :     if (NULL==(headers=malloc(sizeof(struct HTTPHeaders_s)))) {
     171           0 :         perror("HTTP_addheader");
     172           0 :         exit(EXIT_FAILURE);
     173             :     }
     174           3 :     if (NULL==(headers->name=malloc(strlen(name)+1))) {
     175           0 :         perror("HTTP_addheader name malloc");
     176           0 :         exit(EXIT_FAILURE);
     177             :     }
     178           3 :     strcpy(headers->name,name);
     179           3 :     if (NULL==(headers->value=malloc(strlen(value)+1))) {
     180           0 :         perror("HTTP_addheader value malloc");
     181           0 :         exit(EXIT_FAILURE);
     182             :     }
     183           3 :     strcpy(headers->value,value);
     184           3 :     sclist_addrecord(http->headers,headers);
     185           3 : }
     186             : 
     187           3 : char* HTTP_getheaders(const HTTP_t* http) {
     188           3 :     sclistrecord_t* current = NULL;
     189             :     char* retval;
     190             : 
     191           3 :     assert(http);
     192           3 :     assert(http->headers);
     193           3 :     assert(http->body);
     194             : 
     195           3 :     if (NULL==(retval=malloc(1))) {
     196           0 :         perror("HTTP_getheaders initial malloc");
     197           0 :         exit(EXIT_FAILURE);
     198             :     };
     199           3 :     retval[0]=0;
     200             : 
     201           3 :     current = sclist_firstrecord(http->headers);
     202           6 :     while (current) {
     203           3 :         HTTPHeaders_t* header=sclist_getvalue(current);
     204           3 :         if (header->name && header->value) {
     205             :             char* newretval;
     206           3 :             if (NULL==(newretval=realloc(retval,strlen(retval)+strlen(header->name)+2+strlen(header->value)+2+1))) {
     207           0 :                 perror("HTTP_getheaders inner loop");
     208           0 :                 exit(EXIT_FAILURE);
     209             :             }
     210           3 :             retval=newretval;
     211           3 :             strcat(retval,header->name);
     212           3 :             strcat(retval,": ");
     213           3 :             strcat(retval,header->value);
     214           3 :             strcat(retval,"\r\n");
     215             :         }
     216           3 :         current=sclist_nextrecord(current);
     217             :     }
     218           3 :     return retval;
     219             : }
     220             : 
     221           3 : char* HTTP_getrequest(const HTTPMethod_t method, const char* uri, const HTTPVersion_t version) {
     222             :     char* retval;
     223             : 
     224           3 :     assert(method<=HTTPMETHOD_INVALID);
     225           3 :     assert(version<=HTTPVERSION_INVALID);
     226             : 
     227           3 :     if (NULL==(retval=malloc(7+1+strlen(uri)+1+8+1))) {
     228           0 :         perror("HTTP_getrequest");
     229           0 :         exit(EXIT_FAILURE);
     230             :     }
     231           3 :     retval[0]=0;
     232             : 
     233           3 :     switch(method) {
     234           3 :     case HTTPMETHOD_GET:
     235           3 :         strcat(retval, "GET");
     236           3 :         break;;
     237           0 :     case HTTPMETHOD_HEAD:
     238             :     case HTTPMETHOD_POST:
     239             :     case HTTPMETHOD_PUT:
     240             :     case HTTPMETHOD_DELETE:
     241             :     case HTTPMETHOD_CONNECT:
     242             :     case HTTPMETHOD_OPTIONS:
     243             :     case HTTPMETHOD_TRACE:
     244             :     case HTTPMETHOD_PATCH:
     245             :     case HTTPMETHOD_INVALID:
     246             :     default:
     247           0 :         fprintf(stderr,"HTTP method not supported\n");
     248           0 :         exit(EXIT_FAILURE);
     249             :         break;;
     250             :     }
     251           3 :     strcat(retval," ");
     252             : 
     253             :     /* NULL URI allowed, as an empty string */
     254           3 :     if (uri)
     255           3 :         strcat(retval, uri);
     256             : 
     257           3 :     strcat(retval," HTTP/");
     258           3 :     switch(version) {
     259           3 :     case HTTPVERSION_HTTP11:
     260             :     case HTTPVERSION_HTTP11b:
     261           3 :         strcat(retval, "1.1");
     262           3 :         break;;
     263           0 :     case HTTPVERSION_HTTP09:
     264             :     case HTTPVERSION_HTTP10:
     265             :     case HTTPVERSION_HTTP2:
     266             :     case HTTPVERSION_HTTP3:
     267             :     case HTTPVERSION_INVALID:
     268             :     default:
     269           0 :         fprintf(stderr,"HTTP version not supported\n");
     270           0 :         exit(EXIT_FAILURE);
     271             :         break;;
     272             :     }
     273           3 :     strcat(retval, "\r\n");
     274           3 :     return retval;
     275             : }
     276             : 
     277           3 : void HTTP_setbody(HTTP_t* http, const char* body) {
     278             :     char* newbody;
     279             : 
     280           3 :     assert(http);
     281           3 :     assert(http->body);
     282             : 
     283           3 :     if (NULL==(newbody=realloc(http->body,strlen(body)+1))) {
     284           0 :         perror("HTTP_setbody");
     285           0 :         exit(EXIT_FAILURE);
     286             :     }
     287             : 
     288           3 :     http->body = newbody;
     289           3 :     strcpy(http->body, body);
     290           3 : }
     291             : 
     292           3 : char* HTTP_getbody(HTTP_t* http) {
     293           3 :     assert(http);
     294           3 :     assert(http->body);
     295             : 
     296           3 :     return http->body;
     297             : }

Generated by: LCOV version 1.16