Compare commits
2 commits
f63e96f63d
...
f22a523b45
Author | SHA1 | Date | |
---|---|---|---|
f22a523b45 | |||
570da15dab |
6 changed files with 370 additions and 6 deletions
|
@ -38,3 +38,39 @@ HTML_FILE='''example_config/inner.html'''
|
||||||
VAR_FILE='''example_config/var.html'''
|
VAR_FILE='''example_config/var.html'''
|
||||||
|
|
||||||
PATH=/error
|
PATH=/error
|
||||||
|
|
||||||
|
PATH=/inner/further
|
||||||
|
HTML='''
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
color: #FFF;
|
||||||
|
background-color: #333;
|
||||||
|
}
|
||||||
|
a {
|
||||||
|
color: #AAF;
|
||||||
|
}
|
||||||
|
a:link {
|
||||||
|
color: #AAF;
|
||||||
|
}
|
||||||
|
a:visited {
|
||||||
|
color: #88B;
|
||||||
|
}
|
||||||
|
a:focus a:hover {
|
||||||
|
color: #DDF;
|
||||||
|
}
|
||||||
|
a:active {
|
||||||
|
color: #FFF;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>Nested inner: further<h1>
|
||||||
|
{{{VAR}}}
|
||||||
|
<br>
|
||||||
|
<a href="/inner">back</a>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
'''
|
||||||
|
VAR='''yep'''
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
{{{VAR_FILE}}}
|
{{{VAR_FILE}}}
|
||||||
|
|
||||||
<br>
|
<br>
|
||||||
<a href="..">Back.</a>
|
<a href="/inner/further">further</a><br>
|
||||||
|
<a href="/">Back.</a>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
175
src/helpers.c
175
src/helpers.c
|
@ -18,6 +18,109 @@
|
||||||
|
|
||||||
// Standard library includes.
|
// Standard library includes.
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
int c_simple_http_internal_get_string_part_full_size(void *data, void *ud) {
|
||||||
|
C_SIMPLE_HTTP_String_Part *part = data;
|
||||||
|
size_t *count = ud;
|
||||||
|
|
||||||
|
*count += part->size - 1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int c_simple_http_internal_combine_string_parts_from_list(void *data,
|
||||||
|
void *ud) {
|
||||||
|
C_SIMPLE_HTTP_String_Part *part = data;
|
||||||
|
void **ptrs = ud;
|
||||||
|
char *buf = ptrs[0];
|
||||||
|
size_t *current_count = ptrs[1];
|
||||||
|
const size_t *total_count = ptrs[2];
|
||||||
|
|
||||||
|
if (!part->buf || part->size == 0) {
|
||||||
|
// Empty string part, just continue.
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*current_count + part->size - 1 > *total_count) {
|
||||||
|
fprintf(stderr, "ERROR Invalid state combining string parts!\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(buf + *current_count, part->buf, part->size - 1);
|
||||||
|
|
||||||
|
*current_count += part->size - 1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void c_simple_http_cleanup_attr_string_part(C_SIMPLE_HTTP_String_Part **part) {
|
||||||
|
if (part && *part) {
|
||||||
|
if ((*part)->buf) {
|
||||||
|
free((*part)->buf);
|
||||||
|
}
|
||||||
|
free(*part);
|
||||||
|
}
|
||||||
|
*part = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void c_simple_http_cleanup_string_part(void *data) {
|
||||||
|
C_SIMPLE_HTTP_String_Part *part = data;
|
||||||
|
if (part) {
|
||||||
|
if (part->buf) {
|
||||||
|
free(part->buf);
|
||||||
|
}
|
||||||
|
free(part);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void c_simple_http_add_string_part(
|
||||||
|
SDArchiverLinkedList *list, const char *c_string, size_t extra) {
|
||||||
|
C_SIMPLE_HTTP_String_Part *string_part =
|
||||||
|
malloc(sizeof(C_SIMPLE_HTTP_String_Part));
|
||||||
|
|
||||||
|
string_part->size = strlen(c_string) + 1;
|
||||||
|
string_part->buf = malloc(string_part->size);
|
||||||
|
memcpy(string_part->buf, c_string, string_part->size);
|
||||||
|
|
||||||
|
string_part->extra = extra;
|
||||||
|
|
||||||
|
simple_archiver_list_add(
|
||||||
|
list, string_part, c_simple_http_cleanup_string_part);
|
||||||
|
}
|
||||||
|
|
||||||
|
char *c_simple_http_combine_string_parts(const SDArchiverLinkedList *list) {
|
||||||
|
if (!list || list->count == 0) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t count = 0;
|
||||||
|
|
||||||
|
simple_archiver_list_get(
|
||||||
|
list, c_simple_http_internal_get_string_part_full_size, &count);
|
||||||
|
|
||||||
|
char *buf = malloc(count + 1);
|
||||||
|
size_t current_count = 0;
|
||||||
|
|
||||||
|
void **ptrs = malloc(sizeof(void*) * 3);
|
||||||
|
ptrs[0] = buf;
|
||||||
|
ptrs[1] = ¤t_count;
|
||||||
|
ptrs[2] = &count;
|
||||||
|
|
||||||
|
if (simple_archiver_list_get(
|
||||||
|
list, c_simple_http_internal_combine_string_parts_from_list, ptrs)) {
|
||||||
|
free(buf);
|
||||||
|
free(ptrs);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(ptrs);
|
||||||
|
|
||||||
|
buf[count] = 0;
|
||||||
|
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
void c_simple_http_helper_to_lowercase_in_place(char *buf, size_t size) {
|
void c_simple_http_helper_to_lowercase_in_place(char *buf, size_t size) {
|
||||||
for (size_t idx = 0; idx < size; ++idx) {
|
for (size_t idx = 0; idx < size; ++idx) {
|
||||||
|
@ -41,4 +144,76 @@ char *c_simple_http_helper_to_lowercase(const char *buf, size_t size) {
|
||||||
return ret_buf;
|
return ret_buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char c_simple_http_helper_hex_to_value(const char upper, const char lower) {
|
||||||
|
char result = 0;
|
||||||
|
|
||||||
|
if (upper >= '0' && upper <= '9') {
|
||||||
|
result |= (char)(upper - '0') << 4;
|
||||||
|
} else if (upper >= 'a' && upper <= 'f') {
|
||||||
|
result |= (char)(upper - 'a' + 10) << 4;
|
||||||
|
} else if (upper >= 'A' && upper <= 'F') {
|
||||||
|
result |= (char)(upper - 'A' + 10) << 4;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lower >= '0' && lower <= '9') {
|
||||||
|
result |= lower - '0';
|
||||||
|
} else if (lower >= 'a' && lower <= 'f') {
|
||||||
|
result |= lower - 'a' + 10;
|
||||||
|
} else if (lower >= 'A' && lower <= 'F') {
|
||||||
|
result |= lower - 'A' + 10;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *c_simple_http_helper_unescape_uri(const char *uri) {
|
||||||
|
__attribute__((cleanup(simple_archiver_list_free)))
|
||||||
|
SDArchiverLinkedList *parts = simple_archiver_list_init();
|
||||||
|
|
||||||
|
const size_t size = strlen(uri);
|
||||||
|
size_t idx = 0;
|
||||||
|
size_t prev_idx = 0;
|
||||||
|
size_t buf_size;
|
||||||
|
char *buf;
|
||||||
|
|
||||||
|
for (; idx <= size; ++idx) {
|
||||||
|
if (uri[idx] == '%' && idx + 2 < size) {
|
||||||
|
if (idx > prev_idx) {
|
||||||
|
buf_size = idx - prev_idx + 1;
|
||||||
|
buf = malloc(buf_size);
|
||||||
|
memcpy(buf, uri + prev_idx, buf_size - 1);
|
||||||
|
buf[buf_size - 1] = 0;
|
||||||
|
c_simple_http_add_string_part(parts, buf, 0);
|
||||||
|
free(buf);
|
||||||
|
}
|
||||||
|
buf = malloc(2);
|
||||||
|
buf[0] = c_simple_http_helper_hex_to_value(uri[idx + 1], uri[idx + 2]);
|
||||||
|
buf[1] = 0;
|
||||||
|
if (buf[0] == 0) {
|
||||||
|
free(buf);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
c_simple_http_add_string_part(parts, buf, 0);
|
||||||
|
free(buf);
|
||||||
|
prev_idx = idx + 3;
|
||||||
|
idx += 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (idx > prev_idx) {
|
||||||
|
buf_size = idx - prev_idx + 1;
|
||||||
|
buf = malloc(buf_size);
|
||||||
|
memcpy(buf, uri + prev_idx, buf_size - 1);
|
||||||
|
buf[buf_size - 1] = 0;
|
||||||
|
c_simple_http_add_string_part(parts, buf, 0);
|
||||||
|
free(buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
return c_simple_http_combine_string_parts(parts);
|
||||||
|
}
|
||||||
|
|
||||||
// vim: et ts=2 sts=2 sw=2
|
// vim: et ts=2 sts=2 sw=2
|
||||||
|
|
|
@ -20,6 +20,29 @@
|
||||||
// Standard library includes.
|
// Standard library includes.
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
|
||||||
|
// Third-party includes.
|
||||||
|
#include <SimpleArchiver/src/data_structures/linked_list.h>
|
||||||
|
|
||||||
|
typedef struct C_SIMPLE_HTTP_String_Part {
|
||||||
|
char *buf;
|
||||||
|
size_t size;
|
||||||
|
size_t extra;
|
||||||
|
} C_SIMPLE_HTTP_String_Part;
|
||||||
|
|
||||||
|
void c_simple_http_cleanup_attr_string_part(C_SIMPLE_HTTP_String_Part **);
|
||||||
|
|
||||||
|
/// Assumes "data" is a C_SIMPLE_HTTP_String_Part, "data" was malloced, and
|
||||||
|
/// "data->buf" was malloced.
|
||||||
|
void c_simple_http_cleanup_string_part(void *data);
|
||||||
|
|
||||||
|
/// Puts a malloced instance of String_Part into the list.
|
||||||
|
/// The given c_string will be copied into a newly malloced buffer.
|
||||||
|
void c_simple_http_add_string_part(
|
||||||
|
SDArchiverLinkedList *list, const char *c_string, size_t extra);
|
||||||
|
|
||||||
|
/// Combines all String_Parts in the list and returns it as a single buffer.
|
||||||
|
char *c_simple_http_combine_string_parts(const SDArchiverLinkedList *list);
|
||||||
|
|
||||||
/// Modifies "buf" in-place to change all uppercase to lowercase alpha chars.
|
/// Modifies "buf" in-place to change all uppercase to lowercase alpha chars.
|
||||||
void c_simple_http_helper_to_lowercase_in_place(char *buf, size_t size);
|
void c_simple_http_helper_to_lowercase_in_place(char *buf, size_t size);
|
||||||
|
|
||||||
|
@ -27,6 +50,13 @@ void c_simple_http_helper_to_lowercase_in_place(char *buf, size_t size);
|
||||||
/// uppercase to lowercase alpha chars.
|
/// uppercase to lowercase alpha chars.
|
||||||
char *c_simple_http_helper_to_lowercase(const char *buf, size_t size);
|
char *c_simple_http_helper_to_lowercase(const char *buf, size_t size);
|
||||||
|
|
||||||
|
/// Converts two hexadecimal digits into its corresponding value.
|
||||||
|
char c_simple_http_helper_hex_to_value(const char upper, const char lower);
|
||||||
|
|
||||||
|
/// Unescapes percent-encoded parts in the given uri string. If this returns
|
||||||
|
/// non-NULL, it must be free'd.
|
||||||
|
char *c_simple_http_helper_unescape_uri(const char *uri);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// vim: et ts=2 sts=2 sw=2
|
// vim: et ts=2 sts=2 sw=2
|
||||||
|
|
91
src/http.c
91
src/http.c
|
@ -25,7 +25,6 @@
|
||||||
#include <SimpleArchiver/src/helpers.h>
|
#include <SimpleArchiver/src/helpers.h>
|
||||||
|
|
||||||
// Local includes
|
// Local includes
|
||||||
#include "constants.h"
|
|
||||||
#include "http_template.h"
|
#include "http_template.h"
|
||||||
#include "helpers.h"
|
#include "helpers.h"
|
||||||
|
|
||||||
|
@ -111,6 +110,13 @@ char *c_simple_http_request_response(
|
||||||
}
|
}
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
fprintf(stderr, "Parsing request: got path \"%s\"\n", request_path);
|
fprintf(stderr, "Parsing request: got path \"%s\"\n", request_path);
|
||||||
|
#endif
|
||||||
|
__attribute__((cleanup(simple_archiver_helper_cleanup_c_string)))
|
||||||
|
char *request_path_unescaped =
|
||||||
|
c_simple_http_helper_unescape_uri(request_path);
|
||||||
|
#ifndef NDEBUG
|
||||||
|
fprintf(
|
||||||
|
stderr, "Parsing request: unescaped path \"%s\"\n", request_path_unescaped);
|
||||||
#endif
|
#endif
|
||||||
// skip whitespace until next part.
|
// skip whitespace until next part.
|
||||||
for (; idx < size
|
for (; idx < size
|
||||||
|
@ -158,9 +164,9 @@ char *c_simple_http_request_response(
|
||||||
size_t generated_size = 0;
|
size_t generated_size = 0;
|
||||||
__attribute__((cleanup(simple_archiver_helper_cleanup_c_string)))
|
__attribute__((cleanup(simple_archiver_helper_cleanup_c_string)))
|
||||||
char *stripped_path = c_simple_http_strip_path(
|
char *stripped_path = c_simple_http_strip_path(
|
||||||
request_path, request_path_idx);
|
request_path_unescaped, strlen(request_path_unescaped));
|
||||||
char *generated_buf = c_simple_http_path_to_generated(
|
char *generated_buf = c_simple_http_path_to_generated(
|
||||||
stripped_path ? stripped_path : request_path,
|
stripped_path ? stripped_path : request_path_unescaped,
|
||||||
templates,
|
templates,
|
||||||
&generated_size);
|
&generated_size);
|
||||||
|
|
||||||
|
@ -171,8 +177,10 @@ char *c_simple_http_request_response(
|
||||||
if (
|
if (
|
||||||
simple_archiver_hash_map_get(
|
simple_archiver_hash_map_get(
|
||||||
templates->hash_map,
|
templates->hash_map,
|
||||||
stripped_path ? stripped_path : request_path,
|
stripped_path ? stripped_path : request_path_unescaped,
|
||||||
stripped_path ? strlen(stripped_path) + 1 : request_path_idx + 1)
|
stripped_path
|
||||||
|
? strlen(stripped_path) + 1
|
||||||
|
: strlen(request_path_unescaped) + 1)
|
||||||
== NULL) {
|
== NULL) {
|
||||||
*out_response_code = C_SIMPLE_HTTP_Response_404_Not_Found;
|
*out_response_code = C_SIMPLE_HTTP_Response_404_Not_Found;
|
||||||
} else {
|
} else {
|
||||||
|
@ -192,6 +200,14 @@ char *c_simple_http_request_response(
|
||||||
}
|
}
|
||||||
|
|
||||||
char *c_simple_http_strip_path(const char *path, size_t path_size) {
|
char *c_simple_http_strip_path(const char *path, size_t path_size) {
|
||||||
|
if (path_size == 1 && path[0] == '/') {
|
||||||
|
// Edge case: root path.
|
||||||
|
char *buf = malloc(2);
|
||||||
|
buf[0] = '/';
|
||||||
|
buf[1] = 0;
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
size_t idx = 0;
|
size_t idx = 0;
|
||||||
for (; idx < path_size && path[idx] != 0; ++idx) {
|
for (; idx < path_size && path[idx] != 0; ++idx) {
|
||||||
if (path[idx] == '?' || path[idx] == '#') {
|
if (path[idx] == '?' || path[idx] == '#') {
|
||||||
|
@ -203,7 +219,72 @@ char *c_simple_http_strip_path(const char *path, size_t path_size) {
|
||||||
memcpy(stripped_path, path, idx);
|
memcpy(stripped_path, path, idx);
|
||||||
stripped_path[idx] = 0;
|
stripped_path[idx] = 0;
|
||||||
|
|
||||||
|
// Strip multiple '/' into one.
|
||||||
|
__attribute((cleanup(simple_archiver_list_free)))
|
||||||
|
SDArchiverLinkedList *parts = simple_archiver_list_init();
|
||||||
|
|
||||||
|
idx = 0;
|
||||||
|
size_t prev_idx = 0;
|
||||||
|
size_t size;
|
||||||
|
char *buf;
|
||||||
|
uint_fast8_t slash_visited = 0;
|
||||||
|
|
||||||
|
for (; stripped_path[idx] != 0; ++idx) {
|
||||||
|
if (stripped_path[idx] == '/') {
|
||||||
|
if (slash_visited) {
|
||||||
|
// Intentionally left blank.
|
||||||
|
} else {
|
||||||
|
slash_visited = 1;
|
||||||
|
|
||||||
|
if (idx > prev_idx) {
|
||||||
|
size = idx - prev_idx + 1;
|
||||||
|
buf = malloc(size);
|
||||||
|
memcpy(buf, stripped_path + prev_idx, size - 1);
|
||||||
|
buf[size - 1] = 0;
|
||||||
|
|
||||||
|
c_simple_http_add_string_part(parts, buf, 0);
|
||||||
|
free(buf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (slash_visited) {
|
||||||
|
buf = malloc(2);
|
||||||
|
buf[0] = '/';
|
||||||
|
buf[1] = 0;
|
||||||
|
|
||||||
|
c_simple_http_add_string_part(parts, buf, 0);
|
||||||
|
free(buf);
|
||||||
|
|
||||||
|
prev_idx = idx;
|
||||||
|
}
|
||||||
|
|
||||||
|
slash_visited = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!slash_visited && idx > prev_idx) {
|
||||||
|
size = idx - prev_idx + 1;
|
||||||
|
buf = malloc(size);
|
||||||
|
memcpy(buf, stripped_path + prev_idx, size - 1);
|
||||||
|
buf[size - 1] = 0;
|
||||||
|
|
||||||
|
c_simple_http_add_string_part(parts, buf, 0);
|
||||||
|
free(buf);
|
||||||
|
} else if (slash_visited && prev_idx == 0) {
|
||||||
|
buf = malloc(2);
|
||||||
|
buf[0] = '/';
|
||||||
|
buf[1] = 0;
|
||||||
|
|
||||||
|
c_simple_http_add_string_part(parts, buf, 0);
|
||||||
|
free(buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
free(stripped_path);
|
||||||
|
|
||||||
|
stripped_path = c_simple_http_combine_string_parts(parts);
|
||||||
|
|
||||||
// Strip trailing '/'.
|
// Strip trailing '/'.
|
||||||
|
idx = strlen(stripped_path);
|
||||||
while (idx-- > 1) {
|
while (idx-- > 1) {
|
||||||
if (stripped_path[idx] == '/' || stripped_path[idx] == 0) {
|
if (stripped_path[idx] == '/' || stripped_path[idx] == 0) {
|
||||||
stripped_path[idx] = 0;
|
stripped_path[idx] = 0;
|
||||||
|
|
41
src/test.c
41
src/test.c
|
@ -8,6 +8,7 @@
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "http_template.h"
|
#include "http_template.h"
|
||||||
#include "http.h"
|
#include "http.h"
|
||||||
|
#include "helpers.h"
|
||||||
|
|
||||||
// Third party includes.
|
// Third party includes.
|
||||||
#include <SimpleArchiver/src/helpers.h>
|
#include <SimpleArchiver/src/helpers.h>
|
||||||
|
@ -503,6 +504,46 @@ int main(void) {
|
||||||
free(stripped_path_buf);
|
free(stripped_path_buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Test helpers.
|
||||||
|
{
|
||||||
|
__attribute__((cleanup(simple_archiver_list_free)))
|
||||||
|
SDArchiverLinkedList *list = simple_archiver_list_init();
|
||||||
|
|
||||||
|
c_simple_http_add_string_part(list, "one\n", 0);
|
||||||
|
c_simple_http_add_string_part(list, "two\n", 0);
|
||||||
|
c_simple_http_add_string_part(list, "three\n", 0);
|
||||||
|
|
||||||
|
__attribute__((cleanup(simple_archiver_helper_cleanup_c_string)))
|
||||||
|
char *buf = c_simple_http_combine_string_parts(list);
|
||||||
|
ASSERT_TRUE(buf);
|
||||||
|
ASSERT_TRUE(strcmp(buf, "one\ntwo\nthree\n") == 0);
|
||||||
|
free(buf);
|
||||||
|
buf = NULL;
|
||||||
|
|
||||||
|
char hex_result = c_simple_http_helper_hex_to_value('2', 'f');
|
||||||
|
CHECK_TRUE(hex_result == '/');
|
||||||
|
hex_result = c_simple_http_helper_hex_to_value('2', 'F');
|
||||||
|
CHECK_TRUE(hex_result == '/');
|
||||||
|
|
||||||
|
hex_result = c_simple_http_helper_hex_to_value('7', 'a');
|
||||||
|
CHECK_TRUE(hex_result == 'z');
|
||||||
|
hex_result = c_simple_http_helper_hex_to_value('7', 'A');
|
||||||
|
CHECK_TRUE(hex_result == 'z');
|
||||||
|
|
||||||
|
hex_result = c_simple_http_helper_hex_to_value('4', '1');
|
||||||
|
CHECK_TRUE(hex_result == 'A');
|
||||||
|
|
||||||
|
buf = c_simple_http_helper_unescape_uri("%2fderp%2Fdoop%21");
|
||||||
|
CHECK_TRUE(strcmp(buf, "/derp/doop!") == 0);
|
||||||
|
free(buf);
|
||||||
|
buf = NULL;
|
||||||
|
|
||||||
|
buf = c_simple_http_helper_unescape_uri("%41%42%43%25%5A%5a");
|
||||||
|
CHECK_TRUE(strcmp(buf, "ABC%ZZ") == 0);
|
||||||
|
free(buf);
|
||||||
|
buf = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
RETURN()
|
RETURN()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue