chibipub

experimental activitypub node in C
git clone git://jb55.com/chibipub
Log | Files | Refs | README | LICENSE

commit dbb4329b8f450ee3ab74e05b8bb6d8f76edcece6
parent 143e638fc66f14dae4403217e4c3ec7391a74f75
Author: William Casarin <jb55@jb55.com>
Date:   Fri,  8 Oct 2021 19:50:36 -0700

more outbox handling

Diffstat:
Msrc/chibipub.c | 24+++---------------------
Asrc/env.h | 26++++++++++++++++++++++++++
Msrc/outbox.c | 131++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
Msrc/outbox.h | 1+
4 files changed, 160 insertions(+), 22 deletions(-)

diff --git a/src/chibipub.c b/src/chibipub.c @@ -18,6 +18,7 @@ #include "outbox.h" #include "json.h" #include "sigcheck.h" +#include "env.h" #define BUF_SIZE 1048576 #define ARENA_SIZE 134217728 /* 128 MB virtual mem arena */ @@ -37,27 +38,6 @@ static void error(char *msg) exit(1); } -static inline const char *get_hostname() -{ - return getenv("CHIBIPUB_HOST"); -} - -static inline const char *get_pubkey() -{ - return getenv("CHIBIPUB_PUBKEY"); -} - -static inline const char *get_id() -{ - const char *ret; - ret = getenv("CHIBIPUB_ID"); - - if (!ret) - return get_hostname(); - - return ret; -} - #define SCHEMA "https://" @@ -348,6 +328,8 @@ static int handle_request(struct http_req *req, struct cursor *arena) return handle_inbox_request(req, arena); } else if (is_get(req) && patheq(req, "/outbox")) { return handle_outbox_request(req); + } else if (is_get(req) && patheq(req, "/outbox?page=true")) { + return handle_outbox_page_request(req, "outbox.json"); } else if (is_get(req) && is_accept_activity(req) && streq(req->path, "/")) { diff --git a/src/env.h b/src/env.h @@ -0,0 +1,26 @@ + +#pragma once + +#include <stdlib.h> + +static inline const char *get_hostname() +{ + return getenv("CHIBIPUB_HOST"); +} + +static inline const char *get_pubkey() +{ + return getenv("CHIBIPUB_PUBKEY"); +} + +static inline const char *get_id() +{ + const char *ret; + ret = getenv("CHIBIPUB_ID"); + + if (!ret) + return get_hostname(); + + return ret; +} + diff --git a/src/outbox.c b/src/outbox.c @@ -1,8 +1,137 @@ #include "http.h" +#include "env.h" +#include "io.h" + +#include <sys/mman.h> + +/* +{ + "@context": [ + "https://www.w3.org/ns/activitystreams", + "https://gleasonator.com/schemas/litepub-0.1.jsonld", + { + "@language": "und" + } + ], + "first": "https://gleasonator.com/users/alex/outbox?page=true", + "id": "https://gleasonator.com/users/alex/outbox", + "type": "OrderedCollection" +} + */ int handle_outbox_request(struct http_req *req) { - http_write_header(req, "501 Not Implemented"); + const char *hostname = get_hostname(); + + http_write_header(req, "200 OK"); + + fprintf(req->client.socket_file, + "{\"@context\": [\"https://www.w3.org/ns/activitystreams\"]," + " \"first\": \"https://%s/outbox?page=true\"," + " \"id\": \"https://%s/outbox\"," + " \"type\": \"OrderedCollection\"" + " }\r\n", hostname, hostname); + + return 1; +} + +static inline int is_space(char c) +{ + return c == 0x20 || (c >= 0x09 && c <= 0x0d); +} + +static inline int is_linebreak(char c) +{ + return c == '\n' || c == '\r'; +} + +static void consume_space_back(const char *start, const char **cursor) +{ + const char *p = *cursor; + if (p <= start) return; + while (!is_space(*p--) && p > start); + *cursor = p; +} + +static void consume_until_linebreak(const char *start, const char **cursor) +{ + const char *p = *cursor; + if (p <= start) return; + while (!is_linebreak(*p) && --p > start); + *cursor = p == start? start : p+1; +} + +/* +static void tail_data(const char *data, size_t len, FILE *out, int lines) +{ + const char *p = data + len; + const char *line_end; + + line_end = p; + + while (lines-- > 0 && p >= data) { + line_end = p; + consume_space_back(data, &p); + consume_until_linebreak(data, &p); + + fwrite(p, line_end - p, 1, out); + p--; + } +} +*/ + +static void tail_data_array(const char *data, size_t len, FILE *out, int lines) +{ + const char *p = data + len; + const char *line_end; + int first = 1; + + line_end = p; + + while (lines-- > 0 && p >= data) { + line_end = p; + consume_space_back(data, &p); + consume_until_linebreak(data, &p); + + if (!first) + putc(',', out); + first = 0; + + fwrite(p, line_end - p, 1, out); + p--; + } +} + +int handle_outbox_page_request(struct http_req *req, const char *outbox) +{ + unsigned char *data; + const char *hostname; + size_t len; + + hostname = get_hostname(); + + http_write_header(req, "200 OK"); + + fprintf(req->client.socket_file, + "{\"@context\": [\"https://www.w3.org/ns/activitystreams\"]," + " \"id\": \"https://%s/outbox?page=true\"," + " \"partOf\": \"https://%s/outbox\"," + " \"type\": \"OrderedCollectionPage\"," + " \"orderedItems\": [" + , hostname, hostname); + + // technically a 404 but whatevs + if (map_file(outbox, &data, &len)) { + if (len > 0) { + tail_data_array((const char*)data, len, + req->client.socket_file, 20); + } + + munmap(data, len); + } + + fprintf(req->client.socket_file, "]}\r\n"); + return 1; } diff --git a/src/outbox.h b/src/outbox.h @@ -5,5 +5,6 @@ #include "http.h" int handle_outbox_request(struct http_req *); +int handle_outbox_page_request(struct http_req *, const char *outbox); #endif /* CHIBIPUB_OUTBOX */