Ваш код не free
всех строк, выделенных asprintf
.Учитывая, как вы используете asprintf
для выполнения динамической конкатенации строк, исправление этой проблемы немного обременительно.Обратите внимание, что вы не обрабатываете ошибку выделения памяти.Вы можете использовать asprintf
возвращаемое значение, чтобы обнаружить это и обновить bytes
без необходимости дополнительного strlen()
вызова.
/* return the number of bytes written or -1 in case of error */
int write_response(request *req, response *resp, int socket) {
char *raw_resp, *new_p;
int bytes;
bytes = asprintf(&raw_resp, "HTTP/1.1 %d %s\r\n", resp->code, resp->reason_phrase);
if (bytes < 0)
return -1;
for (int i = 0; i < resp->header_count; i++) {
bytes = asprintf(&new_p, "%s%s", raw_resp, resp->headers[i]);
free(raw_resp);
raw_resp = newp;
if (bytes < 0)
return -1;
}
if (resp->content != NULL) {
bytes = asprintf(&new_p, "%s\r\n", raw_resp);
free(raw_resp);
raw_resp = newp;
if (bytes < 0)
return -1;
new_p = realloc(raw_resp, bytes + resp->content->size);
if (new_p == NULL) {
free(raw_resp);
return -1;
}
raw_resp = new_p;
memcpy(raw_resp + bytes, resp->content->data, resp->content->size);
bytes += resp->content->size;
}
bytes = write(socket, raw_resp, bytes);
free(raw_resp);
return bytes;
}
Примечания:
Использование asprintf
для выполнения конкатенации строк с выделением кажется неэффективным, просто используйте strlen
, realloc
и memcpy
.
asprintf()
не является стандартным, это небыть доступным на всех платформах.
Если вас не попросят сделать один вызов write
, может быть более эффективно написать содержимое отдельно, чтобы избежать дополнительного вызова realloc()
для потенциально большого объема памяти.
Также может быть более эффективно вычислить длину заголовков на начальном этапе с помощью snprintf
и strlen
и выделить пространстводля заголовков непосредственно в полный размер, или даже не выделять, если ниже разумного порога (4K), используя локальный массив.
Вот модифицированная версия:
int write_response(request *req, response *resp, int socket) {
char buffer[4096];
char *raw_resp, *allocated = NULL;
int bytes, pos;
bytes = snprintf(NULL, 0, "HTTP/1.1 %d %s\r\n", resp->code, resp->reason_phrase);
for (int i = 0; i < resp->header_count; i++)
bytes += strlen(resp->headers[i]);
if (resp->content != NULL)
bytes += 2 + resp->content->size;
/* need an extra byte for `snprintf` null terminator
if no headers and no contents */
if (bytes < sizeof(buffer)) {
raw_resp = buffer;
} else {
raw_resp = allocated = malloc(bytes + 1):
if (raw_resp == NULL)
return -1;
}
pos = snprintf(raw_resp, bytes, "HTTP/1.1 %d %s\r\n", resp->code, resp->reason_phrase);
for (int i = 0; i < resp->header_count; i++) {
int len = strlen(resp->headers[i]);
memcpy(raw_resp + pos, resp->headers[i], len);
pos += len;
}
if (resp->content != NULL) {
raw_resp[pos++] = '\r';
raw_resp[pos++] = '\n';
memcpy(raw_resp + pos, resp->content->data, resp->content->size);
pos += resp->content->size;
}
bytes = write(socket, raw_resp, bytes);
free(allocated);
return bytes;
}