💾 Archived View for gemini.rmf-dev.com › repo › Vaati › Vgmi › files › ac185490cb1813f428ca96815f92f… captured on 2024-02-05 at 10:01:57. Gemini links have been rewritten to link to archived content
⬅️ Previous capture (2023-12-28)
-=-=-=-=-=-=-
0 /*
1 * ISC License
2 * Copyright (c) 2023 RMF <rawmonk@firemail.cc>
3 */
4 #include <stdio.h>
5 #include <stdlib.h>
6 #include <string.h>
7 struct request;
8 #include "macro.h"
9 #include "gemini.h"
10 #include "client.h"
11 #include "url.h"
12 #include "page.h"
13 #include "request.h"
14 #include "secure.h"
15 #include "memory.h"
16 #include "strlcpy.h"
17 #include "strnstr.h"
18 #include "dns.h"
19 #include "about.h"
20 #include "error.h"
21 #include "parser.h"
22 #include "history.h"
23 #include "xdg.h"
24
25 int request_process(struct request *request, struct secure *secure,
26 const char *url) {
27
28 char buf[MAX_URL + 8];
29 int ret;
30 size_t length;
31
32 /* check if it's an about: page */
33 if (!memcmp(url, V("about:") - 1)) {
34 STRLCPY(request->url, url);
35 if ((ret = about_parse(request))) goto failed;
36 request->state = STATE_COMPLETED;
37 return 0;
38 }
39
40 if ((ret = url_parse(request, url))) goto failed;
41 #ifndef DISABLE_XDG
42 if (xdg_available() && (
43 request->protocol == PROTOCOL_MAIL ||
44 request->protocol == PROTOCOL_HTTP ||
45 request->protocol == PROTOCOL_HTTPS ||
46 request->protocol == PROTOCOL_GOPHER)) {
47 if ((ret = xdg_request(url))) goto failed;
48 request->state = STATE_CANCELED;
49 return 0;
50 }
51 #endif
52 if (request->protocol != PROTOCOL_GEMINI) {
53 ret = ERROR_UNSUPPORTED_PROTOCOL;
54 goto failed;
55 }
56 if ((ret = dns_getip(request->name, &request->addr))) goto failed;
57 if ((ret = secure_connect(secure, *request))) goto failed;
58
59 length = strlcpy(buf, request->url, MAX_URL);
60 length += strlcpy(&buf[length], "\r\n", sizeof(buf) - length);
61
62 if ((ret = secure_send(secure, buf, length))) goto failed;
63 if ((ret = secure_read(secure, &request->data, &request->length)))
64 goto failed;
65 if (parse_request(NULL, request)) goto failed;
66
67 request->state = STATE_COMPLETED;
68 history_add(request->url, request->page.title);
69 return 0;
70 failed:
71 request->state = STATE_FAILED;
72 request->error = ret;
73 return ret;
74 }
75
76 int request_cancel(struct request *request) {
77 /* TODO: mutex lock */
78 switch (request->state) {
79 case STATE_ONGOING:
80 request->state = STATE_CANCELED;
81 break;
82 case STATE_ENDED:
83 case STATE_CANCELED:
84 break;
85 case STATE_COMPLETED:
86 /*request->state = STATE_ENDED;*/
87 break;
88 default:
89 return -1;
90 }
91 return 0;
92 }
93
94 int request_scroll(struct request* req, int scroll, struct rect rect) {
95
96 const int height = rect.h - 2;
97 if (!req) return -1;
98
99 if (0 >= (ssize_t)req->page.length - height) {
100 req->scroll = 0;
101 return 0;
102 }
103
104 req->scroll += scroll;
105 if (req->scroll < 0) req->scroll = 0;
106 else if ((size_t)req->scroll > req->page.length - height)
107 req->scroll = req->page.length - height;
108 return 0;
109 }
110
111 int request_follow(struct request* req, const char *link,
112 char *url, size_t length) {
113
114 const char *end = url + length;
115 char *ptr;
116
117 if (!strncmp(link, ".", length)) {
118 strlcpy(url, req->url, length);
119 ptr = strrchr(url, '/');
120 if (ptr) *(ptr + 1) = '\0';
121 return 0;
122 }
123 if (!strncmp(link, "..", length)) {
124 char *start;
125 strlcpy(url, req->url, length);
126
127 start = strnstr(url, "://", length);
128 if (!start) return 0;
129 start += 3;
130 start = strchr(start, '/');
131 if (!start) return 0;
132
133 ptr = strrchr(url, '/');
134 if (ptr && ptr > start) {
135 *ptr = '\0';
136 ptr = strrchr(url, '/');
137 }
138 if (ptr) *(ptr + 1) = '\0';
139 return 0;
140 }
141 if (!memcmp(link, V("about:") - 1)) {
142 /* only allow "about:*" links on "about:*" pages */
143 if (memcmp(req->url, V("about:") - 1))
144 return ERROR_INVALID_URL;
145 return strlcpy(url, link, length) > length ?
146 ERROR_INVALID_URL : 0;
147 }
148 if (link[0] == '/' && link[1] == '/') {
149 strlcpy(url, &link[2], length);
150 return 0;
151 }
152 if (link[0] == '/') {
153 int i;
154 ptr = strnstr(req->url, "://", sizeof(req->url));
155 if (!ptr) ptr = req->url;
156 else ptr += 4;
157 ptr = strchr(ptr, '/');
158 if (!ptr) ptr = req->url + strnlen(req->url, length);
159 ptr++;
160 strlcpy(url, req->url, ptr - req->url);
161 i = ptr - req->url - 1;
162 i += strlcpy(&url[i], link, length - i);
163 return (size_t)i > length ? ERROR_INVALID_URL : 0;
164 }
165 if (url_is_absolute(link)) {
166 strlcpy(url, link, length);
167 return 0;
168 }
169 strlcpy(url, req->url, length);
170 ptr = strnstr(url, "://", length);
171 if (!ptr) ptr = url;
172 else ptr += 3;
173 ptr = strrchr(ptr, '/');
174 if (!ptr) {
175 ptr = url + strnlen(url, length);
176 *ptr = '/';
177 }
178 ptr++;
179 ptr += strlcpy(ptr, link, end - ptr);
180 return (size_t)(ptr - url) > length ? ERROR_INVALID_URL : 0;
181 }
182
183 int request_free_ref(struct request req) {
184 free_readonly(req.data, req.length);
185 free(req.addr);
186 page_free(req.page);
187 return 0;
188 }
189
190 int request_free(struct request *req) {
191 request_free_ref(*req);
192 free(req);
193 return 0;
194 }
195