chibipub

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

outbox.c (2794B)


      1 
      2 #include "http.h"
      3 #include "env.h"
      4 #include "io.h"
      5 
      6 #include <sys/mman.h>
      7 
      8 /*
      9 {
     10   "@context": [
     11     "https://www.w3.org/ns/activitystreams",
     12     "https://gleasonator.com/schemas/litepub-0.1.jsonld",
     13     {
     14       "@language": "und"
     15     }
     16   ],
     17   "first": "https://gleasonator.com/users/alex/outbox?page=true",
     18   "id": "https://gleasonator.com/users/alex/outbox",
     19   "type": "OrderedCollection"
     20 }
     21  */
     22 
     23 int handle_outbox_request(struct http_req *req)
     24 {
     25 	const char *hostname = get_hostname();
     26 
     27 	http_write_header(req, "200 OK");
     28 
     29 	fprintf(req->client.socket_file,
     30 	  "{\"@context\": [\"https://www.w3.org/ns/activitystreams\"],"
     31 	  " \"first\": \"https://%s/outbox?page=true\","
     32 	  " \"id\": \"https://%s/outbox\","
     33 	  " \"type\": \"OrderedCollection\""
     34 	  " }\r\n", hostname, hostname);
     35 
     36 	return 1;
     37 }
     38 
     39 static inline int is_space(char c)
     40 {
     41 	return c == 0x20 || (c >= 0x09 && c <= 0x0d);
     42 }
     43 
     44 static inline int is_linebreak(char c)
     45 {
     46 	return c == '\n' || c == '\r';
     47 }
     48 
     49 static void consume_space_back(const char *start, const char **cursor)
     50 {
     51 	const char *p = *cursor;
     52 	if (p <= start) return;
     53 	while (!is_space(*p--) && p > start);
     54 	*cursor = p;
     55 }
     56 
     57 static void consume_until_linebreak(const char *start, const char **cursor)
     58 {
     59 	const char *p = *cursor;
     60 	if (p <= start) return;
     61 	while (!is_linebreak(*p) && --p > start);
     62 	*cursor = p == start? start : p+1;
     63 }
     64 
     65 /*
     66 static void tail_data(const char *data, size_t len, FILE *out, int lines)
     67 {
     68 	const char *p = data + len;
     69 	const char *line_end;
     70 
     71 	line_end = p;
     72 
     73 	while (lines-- > 0 && p >= data) {
     74 		line_end = p;
     75 		consume_space_back(data, &p);
     76 		consume_until_linebreak(data, &p);
     77 
     78 		fwrite(p, line_end - p, 1, out);
     79 		p--;
     80 	}
     81 }
     82 */
     83 
     84 static void tail_data_array(const char *data, size_t len, FILE *out, int lines)
     85 {
     86 	const char *p = data + len;
     87 	const char *line_end;
     88 	int first = 1;
     89 
     90 	line_end = p;
     91 
     92 	while (lines-- > 0 && p >= data) {
     93 		line_end = p;
     94 		consume_space_back(data, &p);
     95 		consume_until_linebreak(data, &p);
     96 
     97 		if (!first)
     98 			putc(',', out);
     99 		first = 0;
    100 
    101 		fwrite(p, line_end - p, 1, out);
    102 		p--;
    103 	}
    104 }
    105 
    106 int handle_outbox_page_request(struct http_req *req, const char *outbox)
    107 {
    108 	unsigned char *data;
    109 	const char *hostname;
    110 	size_t len;
    111 
    112 	hostname = get_hostname();
    113 
    114 	http_write_header(req, "200 OK");
    115 
    116 	fprintf(req->client.socket_file,
    117 	  "{\"@context\": [\"https://www.w3.org/ns/activitystreams\"],"
    118 	  " \"id\": \"https://%s/outbox?page=true\","
    119 	  " \"partOf\": \"https://%s/outbox\","
    120 	  " \"type\": \"OrderedCollectionPage\","
    121 	  " \"orderedItems\": ["
    122 	, hostname, hostname);
    123 
    124 	// technically a 404 but whatevs
    125 	if (map_file(outbox, &data, &len)) {
    126 		if (len > 0) {
    127 			tail_data_array((const char*)data, len,
    128 				  req->client.socket_file, 20);
    129 		}
    130 
    131 		munmap(data, len);
    132 	}
    133 
    134 	fprintf(req->client.socket_file, "]}\r\n");
    135 
    136 	return 1;
    137 }