Pretty path parsing

Introduces a new path parser that uses the : token to represent a variable. It isn't fully featured but is just capable enough to work for ratFE

FossilOrigin-Name: f7646dd5278f3c509d96307e45dc216522f81d9b93eb6b17125dc1b1892b1eee
This commit is contained in:
me@ow.nekobit.net 2022-02-10 20:32:18 +00:00
parent 1a31ca43ba
commit 8dbeb095f1
12 changed files with 132 additions and 81 deletions

View file

@ -2,7 +2,7 @@ CC ?= cc
GIT ?= git
MASTODONT_DIR = mastodont-c/
MASTODONT = $(MASTODONT_DIR)libmastodont.a
CFLAGS = -Wall -I $(MASTODONT_DIR)include/
CFLAGS += -Wall -I $(MASTODONT_DIR)include/
LDFLAGS = -L$(MASTODONT_DIR) -lcurl -lmastodont -lcjson
SRC = $(wildcard src/*.c)
OBJ = $(patsubst %.c,%.o,$(SRC))

View file

@ -22,7 +22,6 @@
#include "../config.h"
#include "account.h"
#include "easprintf.h"
#include "uri.h"
// Files
#include "../static/index.chtml"
@ -51,25 +50,23 @@ char* construct_account_page(struct mstdnt_account* acct, size_t* res_size)
return result;
}
void content_account(mastodont_t* api)
void content_account(mastodont_t* api, char** data, size_t size)
{
int cleanup = 0;
char* account_page;
struct mstdnt_account acct;
struct mstdnt_storage storage;
char uri[MSTDNT_URISIZE];
if (parse_uri(uri, MSTDNT_URISIZE, getenv("PATH_INFO")+2))
{
return;
}
if (mastodont_account(api, MSTDNT_LOOKUP_ACCT, uri,
if (mastodont_account(api, MSTDNT_LOOKUP_ACCT, data[0],
&acct, &storage, NULL))
account_page = "An error occured";
account_page = "Couldn't load account info";
else
{
cleanup = 1;
account_page = construct_account_page(&acct, NULL);
if (!account_page)
account_page = "Malloc error";
if (!account_page)
account_page = "Malloc error";
}
struct base_page b = {
.locale = L10N_EN_US,
@ -82,5 +79,5 @@ void content_account(mastodont_t* api)
/* Cleanup */
mastodont_storage_cleanup(&storage);
free(account_page);
if (cleanup) free(account_page);
}

View file

@ -18,9 +18,10 @@
#ifndef ACCOUNT_H
#define ACCOUNT_H
#include <stddef.h>
#include <mastodont.h>
char* construct_account_page(struct mstdnt_account* acct, size_t* res_size);
void content_account(mastodont_t* api);
void content_account(mastodont_t* api, char** data, size_t data_size);
#endif // ACCOUNT_H

View file

@ -28,16 +28,23 @@
void content_index(mastodont_t* api)
{
int cleanup = 0;
size_t status_count, statuses_html_count;
struct mstdnt_status* statuses;
struct mstdnt_storage storage;
char* status_format;
mastodont_timeline_public(api, NULL, &storage, &statuses, &status_count);
/* Construct statuses into HTML */
status_format = construct_statuses(statuses, status_count, &statuses_html_count);
if (status_format == NULL)
status_format = "Error in malloc!";
if (mastodont_timeline_public(api, NULL, &storage, &statuses, &status_count))
{
status_format = "An error occured loading the timeline";
}
else
{
/* Construct statuses into HTML */
status_format = construct_statuses(statuses, status_count, &statuses_html_count);
if (status_format == NULL)
status_format = "Error in malloc!";
cleanup = 1;
}
struct base_page b = {
.locale = L10N_EN_US,
@ -50,5 +57,5 @@ void content_index(mastodont_t* api)
/* Cleanup */
mastodont_storage_cleanup(&storage);
free(status_format);
if (cleanup) free(status_format);
}

View file

@ -23,6 +23,7 @@
#include "index.h"
#include "page_config.h"
#include "path.h"
#include "account.h"
int main(void)
{
@ -41,7 +42,8 @@ int main(void)
* Path handling *
******************/
struct path_info paths[] = {
{ "/config", content_config }
{ "/config", content_config },
{ "/@:", content_account },
};
handle_paths(&api, paths, sizeof(paths)/sizeof(paths[0]));

View file

@ -20,6 +20,7 @@
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include "base_page.h"
#include "../config.h"
#include "page_config.h"
#include "query.h"
@ -28,17 +29,13 @@
#include "../static/index.chtml"
#include "../static/config.chtml"
void content_config(mastodont_t* api)
void content_config(mastodont_t* api, char** data, size_t size)
{
(void)api; // No need to use this
char* request_method = getenv("REQUEST_METHOD");
char* post_query, * p_query_read;
struct http_query_info info;
// Output
printf("Content-Length: %ld\r\n\r\n",
data_index_html_size + data_config_html_size);
// Handle POST
if (request_method && (strcmp("POST", request_method) == 0))
@ -71,5 +68,13 @@ void content_config(mastodont_t* api)
free(post_query);
}
struct base_page b = {
.locale = L10N_EN_US,
.content = data_config_html,
.sidebar_right = NULL
};
render_base_page(&b);
printf(data_index_html, config_canonical_name, data_config_html);
}

View file

@ -18,8 +18,9 @@
#ifndef PAGE_CONFIG_H
#define PAGE_CONFIG_H
#include <stddef.h>
#include <mastodont.h>
void content_config(mastodont_t* api);
void content_config(mastodont_t* api, char** data, size_t data_size);
#endif // PAGE_CONFIG_H

View file

@ -22,6 +22,91 @@
#include "index.h"
#include "account.h"
enum path_state
{
PARSE_NEUTRAL,
PARSE_READ,
};
void parse_path(mastodont_t* api, struct path_info* path_info)
{
int fail = 0, fin = 0;
enum path_state state = PARSE_NEUTRAL;
char* p = path_info->path + 1;
char* p2 = getenv("PATH_INFO") + 1;
// Stored into data
int str_size = 0;
char* tmp = NULL;
char** data = NULL;
size_t size = 0;
for (int i = 0, j = 0;;)
{
switch (p[j])
{
case '\0':
fin = 1;
// fall
case '/':
if (state == PARSE_READ)
{
state = PARSE_NEUTRAL;
// Set value and move on
data = realloc(data, ++size * sizeof(tmp));
data[size-1] = tmp;
tmp = NULL;
str_size = 0;
}
if (fin) goto breakpt;
break;
case ':':
state = PARSE_READ;
// fall
default:
if (state == PARSE_NEUTRAL)
{
if (p[j] == p2[i])
break;
else {
fail = 1;
goto breakpt;
}
}
else {
// Don't realloc, we already have a space for our final character
if (p2[i] == '\0')
{
tmp[str_size] = '\0';
++j;
}
tmp = realloc(tmp, ++str_size + 1);
tmp[str_size-1] = p2[i];
}
break;
}
if (state == PARSE_NEUTRAL) ++j; // Used for p
++i; // Used for p2
}
breakpt:
if (fail)
return;
path_info->callback(api, data, size);
// Cleanup
for (size_t i = 0; i < size; ++i)
{
free(data[i]);
}
if (data) free(data);
}
void handle_paths(mastodont_t* api, struct path_info* paths, size_t paths_len)
{
char* path = getenv("PATH_INFO");
@ -30,16 +115,10 @@ void handle_paths(mastodont_t* api, struct path_info* paths, size_t paths_len)
{
content_index(api);
}
else if (path[1] == '@')
{ // Account path
content_account(api);
}
else
{ // Generic path
else { // Generic path
for (size_t i = 0; i < paths_len; ++i)
{
if (strcmp(path, paths[i].path) == 0)
paths[i].callback(api);
parse_path(api, paths + i);
}
}
}

View file

@ -24,9 +24,10 @@
struct path_info
{
char* path;
void (*callback)(mastodont_t*);
void (*callback)(mastodont_t*, char**, size_t);
};
void handle_paths(mastodont_t* api, struct path_info* paths, size_t paths_len);
void parse_path(mastodont_t* api, struct path_info* path_info);
#endif // PATH_H

View file

@ -1,17 +0,0 @@
#include <string.h>
#include "uri.h"
int parse_uri(char* dest, size_t dest_max_n, char* src)
{
strncpy(dest, src, dest_max_n);
char* delim = strchr(dest, '/');
int xp = delim != NULL; /* Expression */
if (xp || dest[strlen(dest)] == '\0')
{
/* Incase the second expression didn't match, check xp again */
if (xp) *delim = '\0';
return 0;
}
return 1;
}

View file

@ -1,25 +0,0 @@
/*
* RatFE - Lightweight frontend for Pleroma
* Copyright (C) 2022 Nekobit
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef URI_H
#define URI_H
#include <stddef.h>
int parse_uri(char* dest, size_t dest_max_n, char* src);
#endif // URI_H

View file

@ -1,5 +1,5 @@
<div id="config-page">
<form action="/config" method="post">
<form action="config" method="post">
<h1>General</h1>
<h3>JavaScript</h3>
<ul>