/* SPDX-License-Identifier: GPL-3.0-or-later */ /* Copyright 2022 Ivan Polyakov */ #include "response.h" #include #include #include #include static size_t calc_res_status_len(const rpd_res *res); static size_t calc_res_headers_len(const rpd_keyval *res); void rpd_res_init(rpd_res *dest) { dest->status = rpd_res_st_ok; dest->body = NULL; rpd_keyval_init(&dest->headers, 5); dest->headers.unique = 0; } int rpd_res_headers_str(char **dest, const rpd_res *src) { size_t len, i = 0; char *ptr; len = calc_res_headers_len(&src->headers); *dest = (char *) malloc(sizeof(char) * (len + 1)); if (!*dest) { perror("malloc"); return 1; } ptr = *dest; while (i < src->headers.size) { ptr += sprintf( ptr, "%s: %s\r\n", src->headers.items[i].key, src->headers.items[i].val); i++; } return 0; } int rpd_res_str(char **dest, const rpd_res *res) { size_t headers_len, len; char *ptr, *headers; len = headers_len = calc_res_headers_len(&res->headers); len += calc_res_status_len(res); len += 2; /* CRLF */ if (res->body) len += strlen(res->body); *dest = (char *) malloc(sizeof(char) * (len + 1)); if (!*dest) { perror("malloc"); return 1; } /* Status header */ ptr = *dest; ptr += sprintf(ptr, "Status: %d\r\n", res->status); /* Headers */ if (rpd_res_headers_str(&headers, res)) { return 1; } memcpy(ptr, headers, headers_len); free(headers); ptr += headers_len; /* CRLF */ memcpy(ptr, "\r\n", 2); ptr += 2; /* Content */ if (res->body) { int bodylen = strlen(res->body); memcpy(ptr, res->body, bodylen); ptr += bodylen; } (*dest)[len] = *ptr = '\0'; return 0; } static size_t calc_res_status_len(const rpd_res *res) { return strlen("Status: 000\r\n"); } static size_t calc_res_headers_len(const rpd_keyval *headers) { size_t size = 0, i = 0; while (i < headers->size) { size += strlen(headers->items[i].key); size += 2; /* plus ": " */ size += strlen(headers->items[i].val); size += 2; /* plus CRLF */ i++; } return size; } void rpd_res_cleanup(rpd_res *res) { res->status = rpd_res_st_ok; if (res->body) { free(res->body); res->body = NULL; } rpd_keyval_cleanup(&res->headers); } void rpd_res_free(rpd_res *res) { rpd_res_cleanup(res); rpd_keyval_free(&res->headers); }