mirror of
https://github.com/kuhyx/testsAndMisc.git
synced 2026-07-04 13:23:15 +02:00
feat: fixed most function size lint errors
This commit is contained in:
parent
1d7313690b
commit
d4df42efb5
6
.vscode/tasks.json
vendored
6
.vscode/tasks.json
vendored
@ -48,6 +48,12 @@
|
||||
"command": "python -m pip install -r requirements.txt && pytest -q",
|
||||
"group": "build"
|
||||
},
|
||||
{
|
||||
"label": "pytest quick",
|
||||
"type": "shell",
|
||||
"command": "python -m pip install -r requirements.txt && pytest -q",
|
||||
"group": "build"
|
||||
},
|
||||
{
|
||||
"label": "pytest quick",
|
||||
"type": "shell",
|
||||
|
||||
@ -113,40 +113,55 @@ static int write_file_all(const char* path, const char* data, size_t len) {
|
||||
// removed unused append_file_line (lint)
|
||||
|
||||
// ---- JSON helpers (minimal) ----
|
||||
// NOLINTBEGIN(readability-function-size)
|
||||
static char* json_escape(const char* s) {
|
||||
static size_t json_escaped_len(const char* s) {
|
||||
size_t n = 0;
|
||||
for (const char* p = s; *p; ++p) {
|
||||
if (*p == '"' || *p == '\\' || *p == '\n' || *p == '\r' || *p == '\t') n += 2;
|
||||
else n++;
|
||||
}
|
||||
char* out = malloc(n + 1);
|
||||
if (!out) return NULL;
|
||||
char* w = out;
|
||||
for (const char* p = s; *p; ++p) {
|
||||
if (*p == '"') {
|
||||
*w++ = '\\';
|
||||
*w++ = '"';
|
||||
} else if (*p == '\\') {
|
||||
*w++ = '\\';
|
||||
*w++ = '\\';
|
||||
} else if (*p == '\n') {
|
||||
*w++ = '\\';
|
||||
*w++ = 'n';
|
||||
} else if (*p == '\r') {
|
||||
*w++ = '\\';
|
||||
*w++ = 'r';
|
||||
} else if (*p == '\t') {
|
||||
*w++ = '\\';
|
||||
*w++ = 't';
|
||||
} else {
|
||||
*w++ = *p;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
static inline char* json_append_escaped(char* w, char c) {
|
||||
switch (c) {
|
||||
case '"':
|
||||
*w++ = '\\';
|
||||
*w++ = '"';
|
||||
break;
|
||||
case '\\':
|
||||
*w++ = '\\';
|
||||
*w++ = '\\';
|
||||
break;
|
||||
case '\n':
|
||||
*w++ = '\\';
|
||||
*w++ = 'n';
|
||||
break;
|
||||
case '\r':
|
||||
*w++ = '\\';
|
||||
*w++ = 'r';
|
||||
break;
|
||||
case '\t':
|
||||
*w++ = '\\';
|
||||
*w++ = 't';
|
||||
break;
|
||||
default: *w++ = c; break;
|
||||
}
|
||||
return w;
|
||||
}
|
||||
|
||||
static void json_escape_into(char* out, const char* s) {
|
||||
char* w = out;
|
||||
for (const char* p = s; *p; ++p) w = json_append_escaped(w, *p);
|
||||
*w = '\0';
|
||||
}
|
||||
|
||||
static char* json_escape(const char* s) {
|
||||
size_t n = json_escaped_len(s);
|
||||
char* out = (char*)malloc(n + 1);
|
||||
if (!out) return NULL;
|
||||
json_escape_into(out, s);
|
||||
return out;
|
||||
}
|
||||
// NOLINTEND(readability-function-size)
|
||||
|
||||
static const char* skip_ws_commas(const char* p) {
|
||||
while (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t' || *p == ',') p++;
|
||||
@ -155,30 +170,25 @@ static const char* skip_ws_commas(const char* p) {
|
||||
|
||||
// Parse a JSON string starting at v (after the opening quote).
|
||||
// Returns malloc'd string and sets *after_end to the char after closing quote.
|
||||
// NOLINTBEGIN(readability-function-size)
|
||||
static char* parse_json_string_value(const char* v, const char** after_end) {
|
||||
char* out = malloc(strlen(v) + 1);
|
||||
if (!out) {
|
||||
*after_end = v;
|
||||
return NULL;
|
||||
static inline char json_unescape_char(char c) {
|
||||
switch (c) {
|
||||
case '"':
|
||||
case '\\':
|
||||
case '/': return c;
|
||||
case 'n': return '\n';
|
||||
case 'r': return '\r';
|
||||
case 't': return '\t';
|
||||
default: return c;
|
||||
}
|
||||
size_t w = 0;
|
||||
}
|
||||
|
||||
static void parse_json_string_core(const char* v, char* out, size_t* w, const char** after_end) {
|
||||
bool esc = false;
|
||||
const char* p = v;
|
||||
for (; *p; ++p) {
|
||||
char c = *p;
|
||||
if (esc) {
|
||||
if (c == '"' || c == '\\' || c == '/') {
|
||||
out[w++] = c;
|
||||
} else if (c == 'n') {
|
||||
out[w++] = '\n';
|
||||
} else if (c == 'r') {
|
||||
out[w++] = '\r';
|
||||
} else if (c == 't') {
|
||||
out[w++] = '\t';
|
||||
} else {
|
||||
out[w++] = c;
|
||||
}
|
||||
out[(*w)++] = json_unescape_char(c);
|
||||
esc = false;
|
||||
continue;
|
||||
}
|
||||
@ -187,17 +197,26 @@ static char* parse_json_string_value(const char* v, const char** after_end) {
|
||||
continue;
|
||||
}
|
||||
if (c == '"') {
|
||||
out[w] = '\0';
|
||||
*after_end = p + 1;
|
||||
return out;
|
||||
break;
|
||||
}
|
||||
out[w++] = c;
|
||||
out[(*w)++] = c;
|
||||
}
|
||||
if (!*after_end) *after_end = p;
|
||||
}
|
||||
|
||||
static char* parse_json_string_value(const char* v, const char** after_end) {
|
||||
char* out = (char*)malloc(strlen(v) + 1);
|
||||
if (!out) {
|
||||
*after_end = v;
|
||||
return NULL;
|
||||
}
|
||||
size_t w = 0;
|
||||
*after_end = NULL;
|
||||
parse_json_string_core(v, out, &w, after_end);
|
||||
out[w] = '\0';
|
||||
*after_end = p; // unterminated; best effort
|
||||
return out;
|
||||
}
|
||||
// NOLINTEND(readability-function-size)
|
||||
|
||||
// NOLINTBEGIN(readability-function-size)
|
||||
static const char* ensure_quoted_key(const char* key, char** to_free, size_t* out_len) {
|
||||
@ -765,7 +784,30 @@ static char* ltrim_dup(const char* s) {
|
||||
|
||||
// removed unused list_articles_json (lint)
|
||||
|
||||
// NOLINTBEGIN(readability-function-size)
|
||||
static bool object_id_matches(const char* obj, const char* id) {
|
||||
char* got = json_get_string(obj, "\"id\"");
|
||||
bool ok = got && strcmp(got, id) == 0;
|
||||
free(got);
|
||||
return ok;
|
||||
}
|
||||
|
||||
static char* scan_array_for_id(char* t, const char* id) {
|
||||
size_t len = strlen(t);
|
||||
size_t i = 1;
|
||||
while (1) {
|
||||
char* obj = NULL;
|
||||
int r = find_next_json_object(t, len, &i, &obj);
|
||||
if (r <= 0) break;
|
||||
if (object_id_matches(obj, id)) {
|
||||
free(t);
|
||||
return obj;
|
||||
}
|
||||
free(obj);
|
||||
}
|
||||
free(t);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static char* find_article_by_id(const char* id) {
|
||||
char* file = data_file();
|
||||
if (!file) return NULL;
|
||||
@ -775,48 +817,12 @@ static char* find_article_by_id(const char* id) {
|
||||
if (!content) return NULL;
|
||||
char* t = ltrim_dup(content);
|
||||
free(content);
|
||||
if (!t) return NULL;
|
||||
if (t[0] != '[') {
|
||||
if (!t || t[0] != '[') {
|
||||
free(t);
|
||||
return NULL;
|
||||
}
|
||||
// iterate objects
|
||||
size_t len = strlen(t);
|
||||
size_t i = 1;
|
||||
int depth = 0;
|
||||
size_t start = 0;
|
||||
for (; i < len; ++i) {
|
||||
char c = t[i];
|
||||
if (c == '{') {
|
||||
if (depth == 0) start = i;
|
||||
depth++;
|
||||
} else if (c == '}') {
|
||||
depth--;
|
||||
if (depth == 0) {
|
||||
size_t end = i;
|
||||
size_t obj_len = end - start + 1;
|
||||
char* obj = malloc(obj_len + 1);
|
||||
if (!obj) {
|
||||
free(t);
|
||||
return NULL;
|
||||
}
|
||||
memcpy(obj, t + start, obj_len);
|
||||
obj[obj_len] = '\0';
|
||||
char* got = json_get_string(obj, "\"id\"");
|
||||
int match = got && strcmp(got, id) == 0;
|
||||
free(got);
|
||||
if (match) {
|
||||
free(t);
|
||||
return obj;
|
||||
}
|
||||
free(obj);
|
||||
}
|
||||
}
|
||||
}
|
||||
free(t);
|
||||
return NULL;
|
||||
return scan_array_for_id(t, id);
|
||||
}
|
||||
// NOLINTEND(readability-function-size)
|
||||
|
||||
// NOLINTBEGIN(readability-function-size)
|
||||
static int rewrite_articles_map(char** out_json_updated, const char* match_id,
|
||||
@ -855,8 +861,12 @@ static int rewrite_articles_map(char** out_json_updated, const char* match_id,
|
||||
char* obj = NULL;
|
||||
int r = find_next_json_object(t, len, &i, &obj);
|
||||
if (r < 0) {
|
||||
// free accumulated objs
|
||||
for (size_t z = 0; z < count; ++z) free(objs[z]);
|
||||
free(objs);
|
||||
free(file);
|
||||
free(t);
|
||||
free(updated_copy);
|
||||
return -1;
|
||||
}
|
||||
if (r == 0) break;
|
||||
@ -906,8 +916,11 @@ static int rewrite_articles_map(char** out_json_updated, const char* match_id,
|
||||
if (!(isMatch && is_delete)) {
|
||||
if (push_str(&objs, &cap, &count, obj)) {
|
||||
free(obj);
|
||||
for (size_t z = 0; z < count; ++z) free(objs[z]);
|
||||
free(objs);
|
||||
free(file);
|
||||
free(t);
|
||||
free(updated_copy);
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
@ -955,6 +968,7 @@ static char* create_article_from_body(const char* body_json) {
|
||||
char* out = NULL;
|
||||
size_t w = 0;
|
||||
if (!content || n == 0) {
|
||||
free(content);
|
||||
char* arr_items[1] = {obj};
|
||||
assemble_array(arr_items, 1, &out, &w);
|
||||
} else {
|
||||
@ -969,8 +983,21 @@ static char* create_article_from_body(const char* body_json) {
|
||||
while (1) {
|
||||
char* one = NULL;
|
||||
int r = find_next_json_object(tcontent, len, &i, &one);
|
||||
if (r <= 0) break;
|
||||
push_str(&items, &cap, &cnt, one);
|
||||
if (r <= 0) {
|
||||
// if negative error, free any allocated 'one'
|
||||
if (r < 0) free(one);
|
||||
break;
|
||||
}
|
||||
if (push_str(&items, &cap, &cnt, one)) {
|
||||
free(one);
|
||||
for (size_t z = 0; z < cnt; ++z) free(items[z]);
|
||||
free(items);
|
||||
free(tcontent);
|
||||
free(file);
|
||||
free(id);
|
||||
free(obj);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
assemble_array(items, cnt, &out, &w);
|
||||
for (size_t z = 0; z < cnt; ++z) free(items[z]);
|
||||
@ -1047,23 +1074,27 @@ static char* save_upload(const char* body, size_t blen, const char* ext_hint) {
|
||||
|
||||
// Convert a data: URL into a newly-allocated absolute URL string ("/uploads/...")
|
||||
// Returns NULL on failure.
|
||||
// NOLINTBEGIN(readability-function-size)
|
||||
static char* data_url_to_abs_url(const char* data_url) {
|
||||
static int parse_and_save_data_url(const char* data_url, char** out_saved) {
|
||||
char* mime = NULL;
|
||||
unsigned char* bytes = NULL;
|
||||
size_t bl = 0;
|
||||
if (parse_data_url(data_url, &mime, &bytes, &bl) != 0) {
|
||||
free(mime);
|
||||
free(bytes);
|
||||
return NULL;
|
||||
return -1;
|
||||
}
|
||||
const char* ext = ext_from_mime(mime);
|
||||
char* saved = save_bytes_with_ext(bytes, bl, ext);
|
||||
free(mime);
|
||||
free(bytes);
|
||||
if (!saved) return NULL;
|
||||
if (!saved) return -1;
|
||||
*out_saved = saved;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static char* saved_to_abs_url(char* saved) {
|
||||
size_t L = strlen(saved) + 2;
|
||||
char* url = malloc(L);
|
||||
char* url = (char*)malloc(L);
|
||||
if (!url) {
|
||||
free(saved);
|
||||
return NULL;
|
||||
@ -1072,7 +1103,12 @@ static char* data_url_to_abs_url(const char* data_url) {
|
||||
free(saved);
|
||||
return url;
|
||||
}
|
||||
// NOLINTEND(readability-function-size)
|
||||
|
||||
static char* data_url_to_abs_url(const char* data_url) {
|
||||
char* saved = NULL;
|
||||
if (parse_and_save_data_url(data_url, &saved) != 0) return NULL;
|
||||
return saved_to_abs_url(saved);
|
||||
}
|
||||
|
||||
static int migrate_thumb_if_data_url(char** pthumb) {
|
||||
char* thumb = *pthumb;
|
||||
@ -1162,6 +1198,8 @@ static void api_get_articles_array(int c) {
|
||||
char* obj = NULL;
|
||||
int r = find_next_json_object(t, len, &i, &obj);
|
||||
if (r < 0) {
|
||||
for (size_t z = 0; z < count; ++z) free(objs[z]);
|
||||
free(objs);
|
||||
free(file);
|
||||
free(t);
|
||||
send_response(c, 500, "Internal Server Error", "application/json", "", 0, true);
|
||||
@ -1171,6 +1209,8 @@ static void api_get_articles_array(int c) {
|
||||
obj = migrate_one_obj_if_needed(obj, &changed);
|
||||
if (push_str(&objs, &cap, &count, obj)) {
|
||||
free(obj);
|
||||
for (size_t z = 0; z < count; ++z) free(objs[z]);
|
||||
free(objs);
|
||||
free(file);
|
||||
free(t);
|
||||
send_response(c, 500, "Internal Server Error", "application/json", "", 0, true);
|
||||
@ -1197,72 +1237,77 @@ static void api_get_articles_array(int c) {
|
||||
}
|
||||
// NOLINTEND(readability-function-size)
|
||||
|
||||
// NOLINTBEGIN(readability-function-size)
|
||||
static void persist_article_update(const char* obj, const char* title, const char* author,
|
||||
const char* body_s, const char* thumb, long long createdAt) {
|
||||
char* id_copy = json_get_string(obj, "id");
|
||||
char* updated =
|
||||
build_article_json(id_copy ? id_copy : "", title ? title : "", author ? author : "",
|
||||
body_s ? body_s : "", thumb ? thumb : "", createdAt, 0);
|
||||
if (updated) {
|
||||
rewrite_articles_map(NULL, id_copy, updated, false);
|
||||
free(updated);
|
||||
}
|
||||
free(id_copy);
|
||||
}
|
||||
|
||||
static int migrate_fields_if_needed(char** obj, char** title, char** author, char** body_s,
|
||||
char** thumb, long long createdAt) {
|
||||
int obj_changed = 0;
|
||||
obj_changed |= migrate_thumb_if_data_url(thumb);
|
||||
obj_changed |= migrate_body_inplace(body_s);
|
||||
if (obj_changed) {
|
||||
persist_article_update(*obj, *title, *author, *body_s, *thumb, createdAt);
|
||||
free(*obj);
|
||||
*obj = NULL;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
char* title;
|
||||
char* author;
|
||||
char* body;
|
||||
char* thumb;
|
||||
long long createdAt;
|
||||
} ArticleFields;
|
||||
|
||||
static void load_fields(char* obj, ArticleFields* f) {
|
||||
f->title = json_get_string(obj, "title");
|
||||
f->author = json_get_string(obj, "author");
|
||||
f->body = json_get_string(obj, "body");
|
||||
f->thumb = json_get_string(obj, "thumb");
|
||||
f->createdAt = json_get_number(obj, "\"createdAt\"");
|
||||
}
|
||||
|
||||
static void free_fields(ArticleFields* f) {
|
||||
free(f->title);
|
||||
free(f->author);
|
||||
free(f->body);
|
||||
free(f->thumb);
|
||||
}
|
||||
|
||||
static char* maybe_migrate_and_refresh(const char* id, char* obj) {
|
||||
ArticleFields f;
|
||||
load_fields(obj, &f);
|
||||
if (migrate_fields_if_needed(&obj, &f.title, &f.author, &f.body, &f.thumb, f.createdAt)) {
|
||||
free_fields(&f);
|
||||
return find_article_by_id(id);
|
||||
}
|
||||
free_fields(&f);
|
||||
return obj;
|
||||
}
|
||||
|
||||
static void api_get_article_by_id(int c, const char* id) {
|
||||
char* obj = find_article_by_id(id);
|
||||
if (!obj) {
|
||||
send_response(c, 404, "Not Found", "application/json", "", 0, true);
|
||||
return;
|
||||
}
|
||||
char* title = json_get_string(obj, "title");
|
||||
char* author = json_get_string(obj, "author");
|
||||
char* body_s = json_get_string(obj, "body");
|
||||
char* thumb = json_get_string(obj, "thumb");
|
||||
long long createdAt = json_get_number(obj, "\"createdAt\"");
|
||||
int obj_changed = 0;
|
||||
if (thumb && strncmp(thumb, "data:", 5) == 0) {
|
||||
char* mime = NULL;
|
||||
unsigned char* bytes = NULL;
|
||||
size_t bl2 = 0;
|
||||
if (parse_data_url(thumb, &mime, &bytes, &bl2) == 0) {
|
||||
const char* ext = ext_from_mime(mime);
|
||||
char* saved = save_bytes_with_ext(bytes, bl2, ext);
|
||||
if (saved) {
|
||||
size_t urlL = strlen(saved) + 2;
|
||||
char* newthumb = malloc(urlL);
|
||||
if (newthumb) {
|
||||
snprintf(newthumb, urlL, "/%s", saved);
|
||||
free(thumb);
|
||||
thumb = newthumb;
|
||||
obj_changed = 1;
|
||||
}
|
||||
free(saved);
|
||||
}
|
||||
free(mime);
|
||||
free(bytes);
|
||||
}
|
||||
}
|
||||
bool bchanged = false;
|
||||
char* new_body = migrate_inline_images_in_body(body_s, &bchanged);
|
||||
if (new_body && bchanged) {
|
||||
free(body_s);
|
||||
body_s = new_body;
|
||||
obj_changed = 1;
|
||||
} else {
|
||||
free(new_body);
|
||||
}
|
||||
if (obj_changed) {
|
||||
char* id_copy = json_get_string(obj, "id");
|
||||
char* updated =
|
||||
build_article_json(id_copy ? id_copy : "", title ? title : "", author ? author : "",
|
||||
body_s ? body_s : "", thumb ? thumb : "", createdAt, 0);
|
||||
if (updated) {
|
||||
rewrite_articles_map(NULL, id_copy, updated, false);
|
||||
free(updated);
|
||||
}
|
||||
free(id_copy);
|
||||
free(obj);
|
||||
obj = find_article_by_id(id);
|
||||
}
|
||||
free(title);
|
||||
free(author);
|
||||
free(body_s);
|
||||
free(thumb);
|
||||
size_t L = strlen(obj);
|
||||
send_response(c, 200, "OK", "application/json", obj, L, true);
|
||||
obj = maybe_migrate_and_refresh(id, obj);
|
||||
send_response(c, 200, "OK", "application/json", obj, strlen(obj), true);
|
||||
free(obj);
|
||||
}
|
||||
// NOLINTEND(readability-function-size)
|
||||
|
||||
static void api_post_article(int c, const char* body) {
|
||||
char* obj = create_article_from_body(body ? body : "");
|
||||
@ -1292,27 +1337,18 @@ static void api_delete_article(int c, const char* id) {
|
||||
}
|
||||
}
|
||||
|
||||
// NOLINTBEGIN(readability-function-size)
|
||||
static void api_post_upload(int c, const char* path, const char* body, size_t blen,
|
||||
const char* content_type) {
|
||||
static char* choose_ext_from(const char* path, const char* content_type) {
|
||||
const char* ext_q = get_qparam(path, "ext");
|
||||
const char* ext_from_ct = ext_from_content_type(content_type);
|
||||
const char* ext = ext_from_ct ? ext_from_ct : (ext_q ? ext_q : "bin");
|
||||
size_t elen = 0;
|
||||
while (elen < 4 && ext[elen] && isalnum((unsigned char)ext[elen])) elen++;
|
||||
char* ext_safe = strndup_local(ext, elen ? elen : 3);
|
||||
if (!ext_safe) {
|
||||
send_response(c, 500, "Internal Server Error", "application/json", "", 0, true);
|
||||
return;
|
||||
}
|
||||
char* saved = save_upload(body, blen, ext_safe);
|
||||
free(ext_safe);
|
||||
if (!saved) {
|
||||
send_response(c, 500, "Internal Server Error", "application/json", "", 0, true);
|
||||
return;
|
||||
}
|
||||
return strndup_local(ext, elen ? elen : 3);
|
||||
}
|
||||
|
||||
static void respond_saved_upload(int c, char* saved) {
|
||||
size_t L = strlen(saved) + 20;
|
||||
char* res = malloc(L);
|
||||
char* res = (char*)malloc(L);
|
||||
if (!res) {
|
||||
free(saved);
|
||||
send_response(c, 500, "Internal Server Error", "application/json", "", 0, true);
|
||||
@ -1323,9 +1359,53 @@ static void api_post_upload(int c, const char* path, const char* body, size_t bl
|
||||
free(res);
|
||||
free(saved);
|
||||
}
|
||||
// NOLINTEND(readability-function-size)
|
||||
|
||||
// NOLINTBEGIN(readability-function-size)
|
||||
static void api_post_upload(int c, const char* path, const char* body, size_t blen,
|
||||
const char* content_type) {
|
||||
char* ext_safe = choose_ext_from(path, content_type);
|
||||
if (!ext_safe) {
|
||||
send_response(c, 500, "Internal Server Error", "application/json", "", 0, true);
|
||||
return;
|
||||
}
|
||||
char* saved = save_upload(body, blen, ext_safe);
|
||||
free(ext_safe);
|
||||
if (!saved) {
|
||||
send_response(c, 500, "Internal Server Error", "application/json", "", 0, true);
|
||||
return;
|
||||
}
|
||||
respond_saved_upload(c, saved);
|
||||
}
|
||||
|
||||
static bool path_has_id_suffix(const char* path, size_t base_len) {
|
||||
return path[base_len] == '/' && strlen(path) > base_len + 1;
|
||||
}
|
||||
|
||||
static bool is_method(const char* m, const char* want) { return strcmp(m, want) == 0; }
|
||||
|
||||
static void dispatch_articles_get(int c, const char* path) {
|
||||
const char* base = "/api/articles";
|
||||
size_t bl = strlen(base);
|
||||
if (strcmp(path, base) == 0) api_get_articles_array(c);
|
||||
else if (path_has_id_suffix(path, bl)) api_get_article_by_id(c, path + bl + 1);
|
||||
else send_response(c, 404, "Not Found", "application/json", "", 0, true);
|
||||
}
|
||||
|
||||
static void dispatch_articles_mut(int c, const char* method, const char* path, const char* body) {
|
||||
const char* base = "/api/articles";
|
||||
size_t bl = strlen(base);
|
||||
if (is_method(method, "POST") && strcmp(path, base) == 0) api_post_article(c, body);
|
||||
else if (is_method(method, "PUT") && path_has_id_suffix(path, bl))
|
||||
api_put_article(c, path + bl + 1, body);
|
||||
else if (is_method(method, "DELETE") && path_has_id_suffix(path, bl))
|
||||
api_delete_article(c, path + bl + 1);
|
||||
}
|
||||
|
||||
static void dispatch_upload(int c, const char* method, const char* path, const char* body,
|
||||
size_t blen, const char* content_type) {
|
||||
if (strncmp(path, "/api/upload", 12) != 0) return;
|
||||
if (is_method(method, "POST")) api_post_upload(c, path, body, blen, content_type);
|
||||
}
|
||||
|
||||
static void handle_api(int c, const char* method, const char* path, const char* body, size_t blen,
|
||||
const char* content_type) {
|
||||
if (!strncmp(method, "OPTIONS", 7)) {
|
||||
@ -1334,35 +1414,14 @@ static void handle_api(int c, const char* method, const char* path, const char*
|
||||
}
|
||||
const char* base = "/api/articles";
|
||||
size_t bl = strlen(base);
|
||||
if (!strncmp(path, base, bl)) {
|
||||
if (!strcmp(method, "GET")) {
|
||||
if (!strcmp(path, base)) api_get_articles_array(c);
|
||||
else if (path[bl] == '/' && strlen(path) > bl + 1) api_get_article_by_id(c, path + bl + 1);
|
||||
else send_response(c, 404, "Not Found", "application/json", "", 0, true);
|
||||
return;
|
||||
}
|
||||
if (!strcmp(method, "POST") && !strcmp(path, base)) {
|
||||
api_post_article(c, body);
|
||||
return;
|
||||
}
|
||||
if (!strcmp(method, "PUT") && path[bl] == '/' && strlen(path) > bl + 1) {
|
||||
api_put_article(c, path + bl + 1, body);
|
||||
return;
|
||||
}
|
||||
if (!strcmp(method, "DELETE") && path[bl] == '/' && strlen(path) > bl + 1) {
|
||||
api_delete_article(c, path + bl + 1);
|
||||
return;
|
||||
}
|
||||
if (strncmp(path, base, bl) == 0) {
|
||||
if (is_method(method, "GET")) dispatch_articles_get(c, path);
|
||||
else dispatch_articles_mut(c, method, path, body);
|
||||
}
|
||||
if (!strncmp(path, "/api/upload", 12)) {
|
||||
if (!strcmp(method, "POST")) {
|
||||
api_post_upload(c, path, body, blen, content_type);
|
||||
return;
|
||||
}
|
||||
}
|
||||
send_response(c, 404, "Not Found", "text/plain", "Not Found", 9, true);
|
||||
dispatch_upload(c, method, path, body, blen, content_type);
|
||||
if (strncmp(path, "/api/", 5) == 0)
|
||||
send_response(c, 404, "Not Found", "text/plain", "Not Found", 9, true);
|
||||
}
|
||||
// NOLINTEND(readability-function-size)
|
||||
|
||||
static bool safe_path(const char* p) {
|
||||
if (strstr(p, "..")) return false;
|
||||
@ -1513,23 +1572,9 @@ static void handle_client(int c) {
|
||||
close(c);
|
||||
}
|
||||
|
||||
// NOLINTBEGIN(readability-function-size)
|
||||
int main(int argc, char** argv) {
|
||||
(void)argc;
|
||||
(void)argv;
|
||||
signal(SIGINT, on_sigint);
|
||||
srand((unsigned int)time(NULL));
|
||||
char cwd[SMALL_BUF];
|
||||
if (getcwd(cwd, sizeof(cwd))) DOC_ROOT = strdup(cwd);
|
||||
const char* host = getenv_default("HOST", "127.0.0.1");
|
||||
int port = atoi(getenv_default("PORT", "8000"));
|
||||
if (port <= 0) port = 8000;
|
||||
|
||||
static int server_socket_init(const char* host, int port) {
|
||||
int s = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (s < 0) {
|
||||
perror("socket");
|
||||
return 1;
|
||||
}
|
||||
if (s < 0) return -1;
|
||||
int opt = 1;
|
||||
setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
|
||||
struct sockaddr_in addr = {0};
|
||||
@ -1537,17 +1582,17 @@ int main(int argc, char** argv) {
|
||||
addr.sin_port = htons((uint16_t)port);
|
||||
addr.sin_addr.s_addr = inet_addr(host);
|
||||
if (bind(s, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
|
||||
perror("bind");
|
||||
close(s);
|
||||
return 1;
|
||||
return -1;
|
||||
}
|
||||
if (listen(s, 64) < 0) {
|
||||
perror("listen");
|
||||
close(s);
|
||||
return 1;
|
||||
return -1;
|
||||
}
|
||||
printf("Serving Mini Articles (C) on http://%s:%d\n", host, port);
|
||||
return s;
|
||||
}
|
||||
|
||||
static void server_loop(int s) {
|
||||
while (!g_stop) {
|
||||
struct sockaddr_in ca;
|
||||
socklen_t calen = sizeof(ca);
|
||||
@ -1559,7 +1604,29 @@ int main(int argc, char** argv) {
|
||||
}
|
||||
handle_client(c);
|
||||
}
|
||||
}
|
||||
|
||||
static void init_runtime(void) {
|
||||
signal(SIGINT, on_sigint);
|
||||
srand((unsigned int)time(NULL));
|
||||
char cwd[SMALL_BUF];
|
||||
if (getcwd(cwd, sizeof(cwd))) DOC_ROOT = strdup(cwd);
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
(void)argc;
|
||||
(void)argv;
|
||||
init_runtime();
|
||||
const char* host = getenv_default("HOST", "127.0.0.1");
|
||||
int port = atoi(getenv_default("PORT", "8000"));
|
||||
if (port <= 0) port = 8000;
|
||||
int s = server_socket_init(host, port);
|
||||
if (s < 0) {
|
||||
perror("server");
|
||||
return 1;
|
||||
}
|
||||
printf("Serving Mini Articles (C) on http://%s:%d\n", host, port);
|
||||
server_loop(s);
|
||||
close(s);
|
||||
return 0;
|
||||
}
|
||||
// NOLINTEND(readability-function-size)
|
||||
|
||||
Loading…
Reference in New Issue
Block a user