aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJeremias Stotter <jeremias@stotter.eu>2021-10-26 21:39:26 +0200
committerJeremias Stotter <jeremias@stotter.eu>2021-10-26 21:39:26 +0200
commita7186b411a899dc471fd4e1f71b7f7aabe575153 (patch)
treeb4b53d407615743c13add766f7f25cb9759eeb54
parent29653bc81226dcc51bcd7316296efbe3bdc7bc3a (diff)
downloadJBlog-a7186b411a899dc471fd4e1f71b7f7aabe575153.tar.gz
JBlog-a7186b411a899dc471fd4e1f71b7f7aabe575153.tar.bz2
JBlog-a7186b411a899dc471fd4e1f71b7f7aabe575153.zip
Primitive memory caching is now implemented
It doesn't have a size limit, so if you ever have so many blog files that they don't fit into memory you might be screwed. I'll implement that later
-rw-r--r--cache.h29
-rw-r--r--jblog.c123
-rw-r--r--md.c11
3 files changed, 130 insertions, 33 deletions
diff --git a/cache.h b/cache.h
new file mode 100644
index 0000000..98f3621
--- /dev/null
+++ b/cache.h
@@ -0,0 +1,29 @@
+#ifndef JCACHE
+#define JCACHE
+#include <stdio.h>
+#include <stdlib.h>
+#include <search.h>
+
+struct tree_entry {
+ int hash;
+ char* content;
+};
+
+int compute_hash(char* input) {
+ int h = 5381;
+ for(int c = *input++; c != '\0'; c=*input++) {
+ h = (h << 5) + h + c;
+ }
+ return h;
+}
+
+int compare(const void* a, const void* b) {
+ struct tree_entry* ea = (struct tree_entry*)a;
+ struct tree_entry* eb = (struct tree_entry*)b;
+ if(ea != NULL && eb != NULL) {
+ return (ea->hash > eb->hash) - (ea->hash < eb->hash);
+ } else {
+ return 0;
+ }
+}
+#endif
diff --git a/jblog.c b/jblog.c
index e5d9f0b..4cb2a35 100644
--- a/jblog.c
+++ b/jblog.c
@@ -35,6 +35,8 @@
// Call program like this
// jblog <UNIX socket> <html pattern> <directory with blog files>
+#include "cache.h"
+
#define HTML_ERROR(error_code) "<html><body><h1>Error " #error_code "</h1>\n<h2>JBLOG</h2></body></html>"
// 108 is the maximum path length allowed for sockets on Linux
@@ -42,6 +44,7 @@
#define UN_MAX_LEN 108
// This is the part of the pattern where the dynamic content is insertet
#define BLOGMARK "\n$BLOG$"
+#define TITLEMARK "\n$TITLE$"
// Actually we are not gonna have quite as much usable
#define MAX_REPLY 8096
@@ -51,6 +54,9 @@
int sockfd;
+// Root of the search tree used for caching
+void* tree_root = NULL;
+
void sigint_catch(int signo) {
if(shutdown(sockfd, SHUT_RDWR) != 0) {
perror("Could not shutdown socket");
@@ -66,13 +72,15 @@ char* trim_whitespace(char** str) {
return *str;
}
-char* blog_head;
+char* blog_head_pretitle;
+char* blog_head_postitle;
char* blog_foot;
char* base_path;
int pattern_type = 0;
int handle_request(int socket);
-int create_html(char* content, size_t content_length, char request_uri[1024], char request_method[64], char* buffer, size_t buffer_size, size_t* reply_size);
+int create_html(char* content, size_t content_length, char request_uri[1024], char request_method[64], char** buffer, size_t* reply_size);
+int seperate_string(char* input, char* seperator, char** out_pre, char** out_post);
int main(int argc, char* argv[]) {
// Signal handling
@@ -98,11 +106,10 @@ int main(int argc, char* argv[]) {
fprintf(stderr, "ERROR: The blog directory may path may only be %d characters long\n", PATH_MAX);
return -1;
}
-
+
char* un_path = argv[1];
char* pattern_path = argv[2];
base_path = argv[3];
-
// read in the html pattern to memory
int patternfd = open(pattern_path, O_RDONLY);
if(patternfd < 0) {
@@ -138,18 +145,17 @@ int main(int argc, char* argv[]) {
}
// The pattern should contain a line starting with $BLOG$ at which the whole blog HTML code will be insertet
- // Find the Blog
- char* blog_start = strstr(pattern, BLOGMARK);
- if(blog_start == NULL) {
+ // Find the Title
+ if(seperate_string(pattern, TITLEMARK, &blog_head_pretitle, &blog_head_postitle) != 0) {
+ fprintf(stderr, "Missing title marker in pattern (%s)\n", TITLEMARK);
+ }
+ if(seperate_string(blog_head_postitle, BLOGMARK, &blog_head_postitle, &blog_foot) != 0) {
fprintf(stderr, "Missing blog marker in pattern (%s)\n", BLOGMARK);
- return -1;
}
- int blogmark_len = strlen(BLOGMARK);
- blog_foot = blog_start + blogmark_len;
- *blog_start = '\0';
- blog_head = pattern;
+ //
+
// Set up the socket to listen to
sockfd = socket(AF_LOCAL, SOCK_STREAM, 0);
@@ -275,10 +281,14 @@ int handle_request(int socket) {
}
}
// Create and return the html
- char html[MAX_REPLY] = "";
+ char* html;
char http_response[MAX_REPLY] = "";
size_t reply_size = 0;
- int status_code = create_html(content, content_length, request_uri, request_method, html, MAX_REPLY, &reply_size);
+ int status_code = create_html(content, content_length, request_uri, request_method, &html, &reply_size);
+ if(status_code > 299 || status_code < 200) {
+ free(html);
+ }
+
char pattern_media_type[128] = "";
if(pattern_type == XHTML_ID) {
@@ -305,7 +315,7 @@ int handle_request(int socket) {
}
// Maybe put the patterns in some sort of in memory cache
-char* read_jblog_file(char* file_name, int* error_code) {
+char* read_jblog_file(char* file_name, int* error_code, char* title_buffer, size_t title_buffer_size) {
int blog_fd = open(file_name, O_RDONLY);
if(blog_fd < 0) {
*error_code = 404;
@@ -400,7 +410,7 @@ char* read_jblog_file(char* file_name, int* error_code) {
return NULL;
}
snprintf(html, MAX_REPLY + 1, "<div class=\"jblog\">"
- "<h2>%s</h2>"
+ "<h1>%s</h1>"
"%s"
"<h4>Written by %s</h4>"
"<h4>Published on %s</h4>"
@@ -408,37 +418,100 @@ char* read_jblog_file(char* file_name, int* error_code) {
} else if(strcmp(type_str, "Index") == 0) {
}
+ strncpy(title_buffer, title, title_buffer_size-1);
+
free(original_blog_content);
return html;
}
// This will create the html in buffer and return a http status code
-int create_html(char* content, size_t content_length, char request_uri[1024], char request_method[64], char* buffer, size_t buffer_size, size_t* reply_size) {
+// It will also alocate the buffer itself
+// The buffer should only be freed by the caller in case the return isn't in the 200-299 success range
+int create_html(char* content, size_t content_length, char request_uri[1024], char request_method[64], char** buffer, size_t* reply_size) {
+
+ *buffer = malloc(MAX_REPLY);
+ if(buffer == NULL) {
+ perror("malloc error");
+ return -1;
+ }
- char path[PATH_MAX + 1] = "";
- if(snprintf(path, PATH_MAX + 1, "%s/.%s", base_path, request_uri) > PATH_MAX) {
- strcpy(buffer, HTML_ERROR(431));
+ char path[PATH_MAX] = "";
+ if(snprintf(path, PATH_MAX, "%s/.%s", base_path, request_uri) > PATH_MAX) {
+ strcpy(*buffer, HTML_ERROR(431));
return 431;
}
+ char canonicalized_path[PATH_MAX] = {'\0'};
+
+ if(realpath(path, canonicalized_path) == NULL) {
+ strcpy(*buffer, HTML_ERROR(400));
+ return 400;
+ }
+
+ struct tree_entry* in_entry = malloc(sizeof(struct tree_entry));
+ in_entry->hash = compute_hash(canonicalized_path);
+
+ struct tree_entry** found_entry = tfind(in_entry, &tree_root, compare);
+ if(found_entry != NULL) {
+ free(*buffer);
+ *buffer = (*found_entry)->content;
+ return 200;
+ }
+
int error_code = 0;
- char* dyn_content = read_jblog_file(path, &error_code);
+ char title[128] = {'\0'};
+ char* dyn_content = read_jblog_file(path, &error_code, title, 128);
if(dyn_content == NULL) {
- sprintf(buffer, HTML_ERROR(%d), error_code);
+ sprintf(*buffer, HTML_ERROR(%d), error_code);
return error_code;
}
- *reply_size = snprintf(buffer, buffer_size, "%s\n%s\n%s", blog_head, dyn_content, blog_foot);
+ *reply_size = snprintf(*buffer, MAX_REPLY, "%s\n<title>%s</title>\n%s\n%s\n%s", blog_head_pretitle, title, blog_head_postitle, dyn_content, blog_foot);
// The response was too big
- if(*reply_size >= buffer_size) {
- strcpy(buffer, HTML_ERROR(500));
+ if(*reply_size >= MAX_REPLY) {
+ strcpy(*buffer, HTML_ERROR(500));
+ free(dyn_content);
+ return 500;
+ }
+ *buffer = realloc(*buffer, *reply_size + 1);
+
+ if(buffer == NULL) {
+ perror("realloc error");
+ strcpy(*buffer, HTML_ERROR(500));
free(dyn_content);
return 500;
}
+
+ in_entry->content = *buffer;
+
+ // Add the entry in
+ found_entry = tsearch(in_entry, &tree_root, compare);
+
+ if(found_entry == NULL) {
+ perror("tsearch error");
+ strcpy(*buffer, HTML_ERROR(500));
+ free(dyn_content);
+ return 500;
+ }
+
+ memcpy(*found_entry, in_entry, sizeof(struct tree_entry));
// @todo handle all the different inputs
free(dyn_content);
return 200;
}
+
+int seperate_string(char* input, char* seperator, char** out_pre, char** out_post) {
+ char* seperator_start= strstr(input, seperator);
+ if(seperator_start == NULL) {
+ return -1;
+ }
+ int seperator_len = strlen(seperator);
+
+ *out_post = seperator_start + seperator_len;
+ *seperator_start = '\0';
+ *out_pre = input;
+ return 0;
+}
diff --git a/md.c b/md.c
index a723af9..73ddc9c 100644
--- a/md.c
+++ b/md.c
@@ -71,7 +71,6 @@ size_t prepend(char* in_dest, char* in_src) {
// free the returned pointers yourself
char* get_link_components(char* start, char** out_text, char** out_loc, size_t* out_len) {
// Search for the next closing bracket
- bool no_link = false;
char* closing_sqr_bracket = strchr(start, ']');
if(closing_sqr_bracket == NULL) {
return NULL;
@@ -106,8 +105,6 @@ char* get_link_components(char* start, char** out_text, char** out_loc, size_t*
// @todo NEXT
// The program needs to loop through the loop again to cose all the open things at the end, THIS NEEDS TO BE IMPLEMENTED for xhtml
int parse_markdown(char* input, char* buffer, size_t buffer_size) {
- char* parsed_text = NULL;
- size_t text_length = 0;
bool empty_line_carry = true;
bool spaced_codeblock = false;
bool in_paragraph = false;
@@ -121,7 +118,6 @@ int parse_markdown(char* input, char* buffer, size_t buffer_size) {
// Different indicators for all the inline things
// How strongly are we currently emphasized? * = 1; ** = 2; *** = 3
int strength_level = 0;
- int inline_code_level = 0;
bool in_mono = false;
bool in_cut = false;
bool in_quotes = false;
@@ -140,7 +136,6 @@ int parse_markdown(char* input, char* buffer, size_t buffer_size) {
}
}
size_t line_length = 0;
- size_t line_offset = 0;
char line_buffer[LINE_MAX] = {'\0'};
bool no_special = true;
// The pre_line_buffer contains html headers that are needed before content of the current line
@@ -213,8 +208,9 @@ int parse_markdown(char* input, char* buffer, size_t buffer_size) {
// Unordered Lists ------------------------------------------------
if(spaces_skipped < 4 + list_spaces && *trimmed_line == '*' && *(trimmed_line + 1) == ' ') {
+ line_length = prepend(line_buffer, "<li>");
if(!in_list) {
- strncat(pre_line_buffer, "<ul>", LINE_MAX-1);
+ line_length = prepend(line_buffer, "<ul>");
in_list = true;
} else {
strncat(pre_line_buffer, "</li>\n", LINE_MAX-1);
@@ -226,12 +222,11 @@ int parse_markdown(char* input, char* buffer, size_t buffer_size) {
}
} else if(spaces_skipped > list_spaces) {
for(int i = (spaces_skipped - list_spaces) >> 1; i > 0; i--) {
- strncat(pre_line_buffer, "<ul>", LINE_MAX-1);
+ line_length = prepend(line_buffer, "<ul>");
list_level++;
}
}
- strncat(pre_line_buffer, "<li>", LINE_MAX-1);
trimmed_line = trimmed_line + 2;
list_spaces = spaces_skipped;
} else if(in_list && empty_line) {
Jeremias Stotters git repositories generated by CGIT