💾 Archived View for gemini.rmf-dev.com › repo › Vaati › Vgmi › files › 57995ab6cf5ae658b1dd22a329bf8… captured on 2023-12-28 at 15:44:09. Gemini links have been rewritten to link to archived content
-=-=-=-=-=-=-
0 /*
1 * ISC License
2 * Copyright (c) 2023 RMF <rawmonk@firemail.cc>
3 */
4 #ifdef __linux__
5 #define _DEFAULT_SOURCE
6 #include <syscall.h>
7 #endif
8 #include <unistd.h>
9 #include <pthread.h>
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <stdint.h>
13 #include <string.h>
14 #include "macro.h"
15 #include "error.h"
16 #include "sandbox.h"
17 #include "proc.h"
18 #include "url.h"
19 #include "page.h"
20 #include "gemini.h"
21 #include "request.h"
22 #include "strlcpy.h"
23 #include "strnstr.h"
24 #include "memory.h"
25 #define PARSER_INTERNAL
26 #include "parser.h"
27
28 struct parser {
29 int in;
30 int out;
31 pthread_mutex_t mutex;
32 };
33 struct parser request_parser;
34 struct parser page_parser;
35
36 void parser_request(int in, int out);
37
38 int parse_request(struct parser *parser, struct request *request) {
39
40 int ret, gemtext;
41 if (!parser) parser = &request_parser;
42
43 pthread_mutex_lock(&parser->mutex);
44
45 write(parser->out, P(request->length));
46 write(parser->out, request->data, request->length);
47
48 if ((ret = vread(parser->in, P(request->status)))) goto fail;
49 if (request->status == -1) {
50 int error;
51 if ((ret = vread(parser->in, P(error)))) goto fail;
52 ret = error;
53 goto fail;
54 }
55 if ((ret = vread(parser->in, V(request->meta)))) goto fail;
56 if ((ret = vread(parser->in, P(request->page.mime)))) goto fail;
57 if ((ret = vread(parser->in, P(request->page.offset)))) goto fail;
58
59 gemtext = request->status == GMI_SUCCESS &&
60 is_gemtext(V(request->meta));
61 request->page.links_count = 0;
62 request->page.links = NULL;
63 ret = 0;
64 while (gemtext) {
65
66 size_t length = 0;
67 char url[MAX_URL] = {0};
68 void *tmp;
69 char *ptr;
70
71 if (vread(parser->in, P(length))) {
72 ret = -1;
73 break;
74 }
75 if (length == (size_t)-1) break;
76 if (!length || vread(parser->in, url, length)) {
77 ret = -1;
78 break;
79 }
80
81 length++;
82 if ((ret = readonly(url, length, &ptr))) break;
83
84 tmp = realloc(request->page.links,
85 sizeof(char*) * (request->page.links_count + 1));
86 if (!tmp) {
87 ret = ERROR_MEMORY_FAILURE;
88 break;
89 }
90 request->page.links = tmp;
91 request->page.links[request->page.links_count] = ptr;
92 request->page.links_count++;
93 }
94
95 if (gemtext && (ret = vread(parser->in, V(request->page.title))))
96 goto fail;
97 if (!gemtext || !request->page.title[0])
98 STRLCPY(request->page.title, request->url);
99 fail:
100 pthread_mutex_unlock(&parser->mutex);
101 return ret;
102 }
103
104 void parser_page(int in, int out) {
105 char *data = NULL;
106 parser_sandbox(out, "vgmi [page]");
107 while (1) { /* TODO: send error code */
108
109 int ret;
110 size_t length;
111 int width;
112 int mime;
113
114 if (vread(in, &length, sizeof(length))) break;
115 if (vread(in, &width, sizeof(width))) break;
116 if (vread(in, &mime, sizeof(mime))) break;
117
118 switch (mime) {
119 case MIME_GEMTEXT:
120 ret = parse_gemtext(in, length, width, out);
121 break;
122 case MIME_PLAIN:
123 ret = parse_plain(in, length, width, out);
124 break;
125 default:
126 ret = parse_binary(in, length, width, out);
127 break;
128 }
129
130 if (ret) break;
131
132 free(data);
133 data = NULL;
134 }
135 free(data);
136 }
137
138 int parse_page(struct parser *parser, struct request *request, int width) {
139
140 int ret;
141 size_t length;
142 if (!parser) parser = &page_parser;
143
144 pthread_mutex_lock(&parser->mutex);
145
146 length = request->length - request->page.offset;
147 write(parser->out, P(length));
148 write(parser->out, P(width));
149 write(parser->out, P(request->page.mime));
150
151 request->page.width = width;
152 ret = page_update(parser->in, parser->out,
153 &request->data[request->page.offset],
154 length, &request->page);
155
156 pthread_mutex_unlock(&parser->mutex);
157 return ret;
158 }
159
160 int parser_create(struct parser *parser, int type) {
161 switch (type) {
162 case PARSER_GEMTEXT:
163 proc_fork("--page", &parser->in, &parser->out);
164 break;
165 case PARSER_REQUEST:
166 proc_fork("--request", &parser->in, &parser->out);
167 break;
168 }
169 return 0;
170 }
171
172 int parser_request_create() {
173 return parser_create(&request_parser, PARSER_REQUEST);
174 }
175
176 int parser_page_create() {
177 return parser_create(&page_parser, PARSER_GEMTEXT);
178 }
179
180 int parser_sandbox(int out, const char *title) {
181 uint8_t byte;
182 sandbox_set_name(title);
183 if (sandbox_isolate()) return -1;
184 byte = 0;
185 write(out, &byte, 1);
186 return 0;
187 }
188