summaryrefslogtreecommitdiff
path: root/src/gmrequest.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/gmrequest.c')
-rw-r--r--src/gmrequest.c80
1 files changed, 51 insertions, 29 deletions
diff --git a/src/gmrequest.c b/src/gmrequest.c
index 996c77ea..2b6ee9f9 100644
--- a/src/gmrequest.c
+++ b/src/gmrequest.c
@@ -2,11 +2,13 @@
2#include "gmutil.h" 2#include "gmutil.h"
3#include "gmcerts.h" 3#include "gmcerts.h"
4#include "app.h" /* dataDir_App() */ 4#include "app.h" /* dataDir_App() */
5#include "embedded.h"
5 6
6#include <the_Foundation/file.h> 7#include <the_Foundation/file.h>
7#include <the_Foundation/tlsrequest.h>
8#include <the_Foundation/mutex.h> 8#include <the_Foundation/mutex.h>
9#include <the_Foundation/path.h> 9#include <the_Foundation/path.h>
10#include <the_Foundation/regexp.h>
11#include <the_Foundation/tlsrequest.h>
10 12
11#include <SDL_timer.h> 13#include <SDL_timer.h>
12 14
@@ -81,17 +83,17 @@ enum iGmRequestState {
81}; 83};
82 84
83struct Impl_GmRequest { 85struct Impl_GmRequest {
84 iObject object; 86 iObject object;
85 iMutex mutex; 87 iMutex mutex;
86 iGmCerts * certs; /* not owned */ 88 iGmCerts * certs; /* not owned */
87 enum iGmRequestState state; 89 enum iGmRequestState state;
88 iString url; 90 iString url;
89 iTlsRequest * req; 91 iTlsRequest * req;
90 iGmResponse resp; 92 iGmResponse resp;
91 uint32_t timeoutId; /* in case server doesn't close the connection */ 93 uint32_t timeoutId; /* in case server doesn't close the connection */
92 iAudience * updated; 94 iAudience * updated;
93 iAudience * timeout; 95 iAudience * timeout;
94 iAudience * finished; 96 iAudience * finished;
95}; 97};
96 98
97iDefineObjectConstructionArgs(GmRequest, (iGmCerts *certs), certs) 99iDefineObjectConstructionArgs(GmRequest, (iGmCerts *certs), certs)
@@ -261,6 +263,40 @@ static void requestFinished_GmRequest_(iAnyObject *obj) {
261 iNotifyAudience(d, finished, GmRequestFinished); 263 iNotifyAudience(d, finished, GmRequestFinished);
262} 264}
263 265
266static const iBlock *aboutPageSource_(iRangecc path) {
267 const iBlock *src = NULL;
268 if (equalCase_Rangecc(&path, "lagrange")) {
269 return &blobAbout_Embedded;
270 }
271 if (equalCase_Rangecc(&path, "help")) {
272 return &blobHelp_Embedded;
273 }
274 if (equalCase_Rangecc(&path, "version")) {
275 return &blobVersion_Embedded;
276 }
277 return src;
278}
279
280static const iBlock *replaceVariables_(const iBlock *block) {
281 iRegExp *var = new_RegExp("\\$\\{([A-Z_]+)\\}", 0);
282 iRegExpMatch m;
283 if (matchRange_RegExp(var, range_Block(block), &m)) {
284 iBlock *replaced = collect_Block(copy_Block(block));
285 do {
286 const iRangei span = m.range;
287 remove_Block(replaced, span.start, size_Range(&span));
288 const iRangecc name = capturedRange_RegExpMatch(&m, 1);
289 if (equal_Rangecc(&name, "APP_VERSION")) {
290 insertData_Block(replaced, span.start,
291 LAGRANGE_APP_VERSION, strlen(LAGRANGE_APP_VERSION));
292 }
293 } while (matchRange_RegExp(var, range_Block(replaced), &m));
294 block = replaced;
295 }
296 iRelease(var);
297 return block;
298}
299
264void submit_GmRequest(iGmRequest *d) { 300void submit_GmRequest(iGmRequest *d) {
265 iAssert(d->state == initialized_GmRequestState); 301 iAssert(d->state == initialized_GmRequestState);
266 if (d->state != initialized_GmRequestState) { 302 if (d->state != initialized_GmRequestState) {
@@ -272,25 +308,11 @@ void submit_GmRequest(iGmRequest *d) {
272 /* Check for special protocols. */ 308 /* Check for special protocols. */
273 /* TODO: If this were a library, these could be handled via callbacks. */ 309 /* TODO: If this were a library, these could be handled via callbacks. */
274 if (equalCase_Rangecc(&url.protocol, "about")) { 310 if (equalCase_Rangecc(&url.protocol, "about")) {
275 if (equalCase_Rangecc(&url.path, "home")) { 311 const iBlock *src = aboutPageSource_(url.path);
312 if (src) {
276 d->resp.statusCode = success_GmStatusCode; 313 d->resp.statusCode = success_GmStatusCode;
277 setCStr_String(&d->resp.meta, "text/gemini; charset=utf-8"); 314 setCStr_String(&d->resp.meta, "text/gemini; charset=utf-8");
278 setCStr_Block(&d->resp.body, 315 set_Block(&d->resp.body, replaceVariables_(src));
279"```\n"
280"ooooo\n"
281"`888'\n"
282" 888 .oooo. .oooooooo oooo d8b .oooo. ooo. .oo. .oooooooo .ooooo. \n"
283" 888 `P )88b 888' `88b `888\"\"8P `P )88b `888P\"Y88b 888' `88b d88' `88b \n"
284" 888 .oP\"888 888 888 888 .oP\"888 888 888 888 888 888ooo888 \n"
285" 888 o d8( 888 `88bod8P' 888 d8( 888 888 888 `88bod8P' 888 .o \n"
286"o888ooooood8 `Y888\"\"8o `8oooooo. d888b `Y888\"\"8o o888o o888o `8oooooo. `Y8bod8P' \n"
287" d\" YD d\" YD\n"
288" \"Y88888P' \"Y88888P'\n"
289"```\n"
290"# A Beautiful Gemini Client\n"
291"## Version " LAGRANGE_APP_VERSION "\n\n"
292"=> https://skyjake.fi/@jk by Jaakko Keränen <code@iki.fi>\n"
293"Crafted with \u2615 in Finland\n");
294 d->state = receivingBody_GmRequestState; 316 d->state = receivingBody_GmRequestState;
295 iNotifyAudience(d, updated, GmRequestUpdated); 317 iNotifyAudience(d, updated, GmRequestUpdated);
296 } 318 }