summaryrefslogtreecommitdiff
path: root/src/gmrequest.c
diff options
context:
space:
mode:
authorJaakko Keränen <jaakko.keranen@iki.fi>2020-08-08 22:02:14 +0300
committerJaakko Keränen <jaakko.keranen@iki.fi>2020-08-08 22:02:58 +0300
commit496122b446d2084f6117e2b8704d7c9ec6706422 (patch)
treeb379efe7f6a2ed530ec9a9bc982e7f48cbd3a29a /src/gmrequest.c
parent7b98d7af353c31706d5d6b20ff7d65272f8b7445 (diff)
Handling "about:home"; GmRequest decoupling
GmRequest is given a pointer to the GmCerts to use. Also, timeouts are handled via a posted command so they get processed in the main thread.
Diffstat (limited to 'src/gmrequest.c')
-rw-r--r--src/gmrequest.c82
1 files changed, 61 insertions, 21 deletions
diff --git a/src/gmrequest.c b/src/gmrequest.c
index 7cc8b897..1a6476ba 100644
--- a/src/gmrequest.c
+++ b/src/gmrequest.c
@@ -1,11 +1,12 @@
1#include "gmrequest.h" 1#include "gmrequest.h"
2#include "gmutil.h" 2#include "gmutil.h"
3#include "gmcerts.h" 3#include "gmcerts.h"
4#include "app.h" 4#include "app.h" /* dataDir_App() */
5 5
6#include <the_Foundation/file.h> 6#include <the_Foundation/file.h>
7#include <the_Foundation/tlsrequest.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 10
10#include <SDL_timer.h> 11#include <SDL_timer.h>
11 12
@@ -62,30 +63,35 @@ enum iGmRequestState {
62}; 63};
63 64
64struct Impl_GmRequest { 65struct Impl_GmRequest {
65 iObject object; 66 iObject object;
66 iMutex mutex; 67 iMutex mutex;
67 enum iGmRequestState state; 68 iGmCerts * certs; /* not owned */
68 iString url; 69 enum iGmRequestState state;
69 iTlsRequest *req; 70 iString url;
70 iGmResponse resp; 71 iTlsRequest * req;
71 uint32_t timeoutId; /* in case server doesn't close the connection */ 72 iGmResponse resp;
72 iAudience *updated; 73 uint32_t timeoutId; /* in case server doesn't close the connection */
73 iAudience *finished; 74 iAudience * updated;
75 iAudience * timeout;
76 iAudience * finished;
74}; 77};
75 78
76iDefineObjectConstruction(GmRequest) 79iDefineObjectConstructionArgs(GmRequest, (iGmCerts *certs), certs)
77iDefineAudienceGetter(GmRequest, updated) 80iDefineAudienceGetter(GmRequest, updated)
81iDefineAudienceGetter(GmRequest, timeout)
78iDefineAudienceGetter(GmRequest, finished) 82iDefineAudienceGetter(GmRequest, finished)
79 83
80void init_GmRequest(iGmRequest *d) { 84void init_GmRequest(iGmRequest *d, iGmCerts *certs) {
81 init_Mutex(&d->mutex); 85 init_Mutex(&d->mutex);
82 d->state = initialized_GmRequestState;
83 init_GmResponse(&d->resp); 86 init_GmResponse(&d->resp);
84 init_String(&d->url); 87 init_String(&d->url);
85 d->req = NULL; 88 d->certs = certs;
86 d->timeoutId = 0; 89 d->timeoutId = 0;
87 d->updated = NULL; 90 d->req = NULL;
88 d->finished = NULL; 91 d->state = initialized_GmRequestState;
92 d->updated = NULL;
93 d->timeout = NULL;
94 d->finished = NULL;
89} 95}
90 96
91void deinit_GmRequest(iGmRequest *d) { 97void deinit_GmRequest(iGmRequest *d) {
@@ -107,6 +113,7 @@ void deinit_GmRequest(iGmRequest *d) {
107 } 113 }
108 iRelease(d->req); 114 iRelease(d->req);
109 d->req = NULL; 115 d->req = NULL;
116 delete_Audience(d->timeout);
110 delete_Audience(d->finished); 117 delete_Audience(d->finished);
111 delete_Audience(d->updated); 118 delete_Audience(d->updated);
112 deinit_GmResponse(&d->resp); 119 deinit_GmResponse(&d->resp);
@@ -121,7 +128,9 @@ void setUrl_GmRequest(iGmRequest *d, const iString *url) {
121 128
122static uint32_t timedOutWhileReceivingBody_GmRequest_(uint32_t interval, void *obj) { 129static uint32_t timedOutWhileReceivingBody_GmRequest_(uint32_t interval, void *obj) {
123 /* Note: Called from SDL's timer thread. */ 130 /* Note: Called from SDL's timer thread. */
124 postCommandf_App("gmrequest.timeout request:%p", obj); 131 iGmRequest *d = obj;
132 //postCommandf_App("gmrequest.timeout request:%p", obj);
133 iNotifyAudience(d, timeout, GmRequestTimeout);
125 iUnused(interval); 134 iUnused(interval);
126 return 0; 135 return 0;
127} 136}
@@ -142,7 +151,6 @@ static void checkServerCertificate_GmRequest_(iGmRequest *d) {
142 const iTlsCertificate *cert = serverCertificate_TlsRequest(d->req); 151 const iTlsCertificate *cert = serverCertificate_TlsRequest(d->req);
143 d->resp.certFlags = 0; 152 d->resp.certFlags = 0;
144 if (cert) { 153 if (cert) {
145 iGmCerts * certDb = certs_App();
146 const iRangecc domain = urlHost_String(&d->url); 154 const iRangecc domain = urlHost_String(&d->url);
147 d->resp.certFlags |= available_GmCertFlag; 155 d->resp.certFlags |= available_GmCertFlag;
148 if (!isExpired_TlsCertificate(cert)) { 156 if (!isExpired_TlsCertificate(cert)) {
@@ -151,7 +159,7 @@ static void checkServerCertificate_GmRequest_(iGmRequest *d) {
151 if (verifyDomain_TlsCertificate(cert, domain)) { 159 if (verifyDomain_TlsCertificate(cert, domain)) {
152 d->resp.certFlags |= domainVerified_GmCertFlag; 160 d->resp.certFlags |= domainVerified_GmCertFlag;
153 } 161 }
154 if (checkTrust_GmCerts(certDb, domain, cert)) { 162 if (checkTrust_GmCerts(d->certs, domain, cert)) {
155 d->resp.certFlags |= trusted_GmCertFlag; 163 d->resp.certFlags |= trusted_GmCertFlag;
156 } 164 }
157 validUntil_TlsCertificate(cert, &d->resp.certValidUntil); 165 validUntil_TlsCertificate(cert, &d->resp.certValidUntil);
@@ -243,7 +251,39 @@ void submit_GmRequest(iGmRequest *d) {
243 clear_GmResponse(&d->resp); 251 clear_GmResponse(&d->resp);
244 iUrl url; 252 iUrl url;
245 init_Url(&url, &d->url); 253 init_Url(&url, &d->url);
246 if (equalCase_Rangecc(&url.protocol, "file")) { 254 /* Check for special protocols. */
255 /* TODO: If this were a library, these could be handled via callbacks. */
256 if (equalCase_Rangecc(&url.protocol, "about")) {
257 if (equalCase_Rangecc(&url.path, "home")) {
258 d->resp.statusCode = success_GmStatusCode;
259 setCStr_String(&d->resp.meta, "text/gemini; charset=utf-8");
260 setCStr_Block(&d->resp.body,
261"```\n"
262"ooooo \n"
263"`888' \n"
264" 888 .oooo. .oooooooo oooo d8b .oooo. ooo. .oo. .oooooooo .ooooo. \n"
265" 888 `P )88b 888' `88b `888\"\"8P `P )88b `888P\"Y88b 888' `88b d88' `88b \n"
266" 888 .oP\"888 888 888 888 .oP\"888 888 888 888 888 888ooo888 \n"
267" 888 o d8( 888 `88bod8P' 888 d8( 888 888 888 `88bod8P' 888 .o \n"
268"o888ooooood8 `Y888\"\"8o `8oooooo. d888b `Y888\"\"8o o888o o888o `8oooooo. `Y8bod8P' \n"
269" d\" YD d\" YD \n"
270" \"Y88888P' \"Y88888P' \n"
271"```\n"
272"# A Beautiful Gemini Browser\n"
273"## Version " LAGRANGE_APP_VERSION "\n\n"
274"=> https://skyjake.fi/@jk by Jaakko Keränen <code@iki.fi>\n"
275"Crafted with \u2615 in Finland\n");
276 d->state = receivingBody_GmRequestState;
277 iNotifyAudience(d, updated, GmRequestUpdated);
278 }
279 else {
280 d->resp.statusCode = invalidLocalResource_GmStatusCode;
281 }
282 d->state = finished_GmRequestState;
283 iNotifyAudience(d, finished, GmRequestFinished);
284 return;
285 }
286 else if (equalCase_Rangecc(&url.protocol, "file")) {
247 iString *path = collect_String(urlDecode_String(collect_String(newRange_String(url.path)))); 287 iString *path = collect_String(urlDecode_String(collect_String(newRange_String(url.path))));
248 iFile * f = new_File(path); 288 iFile * f = new_File(path);
249 if (open_File(f, readOnly_FileMode)) { 289 if (open_File(f, readOnly_FileMode)) {