|
|
|
/* SPDX-License-Identifier: GPL-3.0-or-later */
|
|
|
|
/* Copyright 2022 Ivan Polyakov */
|
|
|
|
|
|
|
|
#include "response.h"
|
|
|
|
#include <assert.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
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);
|
|
|
|
}
|