summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJaakko Keränen <jaakko.keranen@iki.fi>2020-08-01 22:50:07 +0300
committerJaakko Keränen <jaakko.keranen@iki.fi>2020-08-01 22:50:07 +0300
commit5fb32fcfca41d2e1b6eaaacaa6b6b37fc9e6d0b1 (patch)
tree2e01c7226a558bb51d8c4e82c46600e57d74f3cb
parenta05d181c72df33256e603f2e4543ee73665b242c (diff)
Handling status codes by class
-rw-r--r--src/gemini.h4
-rw-r--r--src/gmutil.c198
-rw-r--r--src/ui/documentwidget.c42
-rw-r--r--src/ui/window.c5
4 files changed, 140 insertions, 109 deletions
diff --git a/src/gemini.h b/src/gemini.h
index 863e27f7..564de65b 100644
--- a/src/gemini.h
+++ b/src/gemini.h
@@ -9,6 +9,7 @@ enum iGmStatusCode {
9 invalidHeader_GmStatusCode, 9 invalidHeader_GmStatusCode,
10 unsupportedMimeType_GmStatusCode, 10 unsupportedMimeType_GmStatusCode,
11 failedToOpenFile_GmStatusCode, 11 failedToOpenFile_GmStatusCode,
12 unknownStatusCode_GmStatusCode,
12 none_GmStatusCode = 0, 13 none_GmStatusCode = 0,
13 input_GmStatusCode = 10, 14 input_GmStatusCode = 10,
14 sensitiveInput_GmStatusCode = 11, 15 sensitiveInput_GmStatusCode = 11,
@@ -38,4 +39,5 @@ struct Impl_GmError {
38 const char *info; 39 const char *info;
39}; 40};
40 41
41const iGmError * get_GmError (enum iGmStatusCode code); 42iBool isDefined_GmError (enum iGmStatusCode code);
43const iGmError * get_GmError (enum iGmStatusCode code);
diff --git a/src/gmutil.c b/src/gmutil.c
index 2008ea36..bf08e960 100644
--- a/src/gmutil.c
+++ b/src/gmutil.c
@@ -146,97 +146,117 @@ void urlEncodeSpaces_String(iString *d) {
146 } 146 }
147} 147}
148 148
149static const struct {
150 enum iGmStatusCode code;
151 iGmError err;
152} errors_[] = {
153 { unknownStatusCode_GmStatusCode, /* keep this as the first one (fallback return value) */
154 { 0x1f4ab, /* dizzy */
155 "Unknown Status Code",
156 "The server responded with a status code that is not specified in the Gemini "
157 "protocol as known to this client. Maybe the server is from the future? Or "
158 "just malfunctioning."} },
159 { failedToOpenFile_GmStatusCode,
160 { 0x1f4c1, /* file folder */
161 "Failed to Open File",
162 "The requested file does not exist or is inaccessible. "
163 "Please check the file path." } },
164 { unsupportedMimeType_GmStatusCode,
165 { 0x1f47d, /* alien */
166 "Unsupported MIME Type",
167 "The received content is in an unsupported format and cannot be viewed with "
168 "this application." } },
169 { invalidHeader_GmStatusCode,
170 { 0x1f4a9, /* pile of poo */
171 "Invalid Header",
172 "The received header did not conform to the Gemini specification. "
173 "Perhaps the server is malfunctioning or you tried to contact a "
174 "non-Gemini server." } },
175 { invalidRedirect_GmStatusCode,
176 { 0, /* */
177 "Invalid Redirect",
178 "The server responded with a redirect but did not provide a valid destination URL. "
179 "Perhaps the server is malfunctioning." } },
180 { temporaryFailure_GmStatusCode,
181 { 0x1f50c, /* electric plug */
182 "Temporary Failure",
183 "The request has failed, but may succeed if you try again in the future." } },
184 { serverUnavailable_GmStatusCode,
185 { 0x1f525, /* fire */
186 "Server Unavailable",
187 "The server is unavailable due to overload or maintenance. Check back later." } },
188 { cgiError_GmStatusCode,
189 { 0x1f4a5, /* collision */
190 "CGI Error",
191 "Failure during dynamic content generation on the server. This may be due "
192 "to buggy serverside software." } },
193 { proxyError_GmStatusCode,
194 { 0x1f310, /* globe */
195 "Proxy Error",
196 "A proxy request failed because the server was unable to successfully "
197 "complete a transaction with the remote host. Perhaps there are difficulties "
198 "with network connectivity." } },
199 { slowDown_GmStatusCode,
200 { 0x1f40c, /* snail */
201 "Slow Down",
202 "The server is rate limiting requests. Please wait..." } },
203 { permanentFailure_GmStatusCode,
204 { 0x1f6ab, /* no entry */
205 "Permanent Failure",
206 "Your request has failed and will fail in the future as well if repeated." } },
207 { notFound_GmStatusCode,
208 { 0x1f50d, /* magnifying glass */
209 "Not Found",
210 "The requested resource could not be found at this time." } },
211 { gone_GmStatusCode,
212 { 0x1f47b, /* ghost */
213 "Gone",
214 "The resource requested is no longer available and will not be available again." } },
215 { proxyRequestRefused_GmStatusCode,
216 { 0x1f6c2, /* passport control */
217 "Proxy Request Refused",
218 "The request was for a resource at a domain not served by the server and the "
219 "server does not accept proxy requests." } },
220 { badRequest_GmStatusCode,
221 { 0x1f44e, /* thumbs down */
222 "Bad Request",
223 "The server was unable to parse your request, presumably due to the "
224 "request being malformed. Likely a bug in Lagrange." } },
225 { clientCertificateRequired_GmStatusCode,
226 { 0x1f511, /* key */
227 "Certificate Required",
228 "Access to the requested resource requires identification via "
229 "a client certificate." } },
230 { certificateNotAuthorized_GmStatusCode,
231 { 0x1f512, /* lock */
232 "Certificate Not Authorized",
233 "The provided client certificate is valid but is not authorized for accessing "
234 "the requested resource. " } },
235 { certificateNotValid_GmStatusCode,
236 { 0x1f6a8, /* revolving light */
237 "Invalid Certificate",
238 "The provided client certificate is expired or invalid." } },
239};
240
241iBool isDefined_GmError(enum iGmStatusCode code) {
242 iForIndices(i, errors_) {
243 if (errors_[i].code == code) {
244 return iTrue;
245 }
246 }
247 return iFalse;
248}
249
149const iGmError *get_GmError(enum iGmStatusCode code) { 250const iGmError *get_GmError(enum iGmStatusCode code) {
150 static const iGmError none = { 0, "", "" }; 251 static const iGmError none = { 0, "", "" };
151 static const struct { 252 if (code == 0) {
152 enum iGmStatusCode code; 253 return &none;
153 iGmError err; 254 }
154 } errors[] = { 255 iForIndices(i, errors_) {
155 { failedToOpenFile_GmStatusCode, 256 if (errors_[i].code == code) {
156 { 0x1f4c1, /* file folder */ 257 return &errors_[i].err;
157 "Failed to Open File",
158 "The requested file does not exist or is inaccessible. "
159 "Please check the file path." } },
160 { unsupportedMimeType_GmStatusCode,
161 { 0x1f47d, /* alien */
162 "Unsupported MIME Type",
163 "The received content is in an unsupported format and cannot be viewed with "
164 "this application." } },
165 { invalidHeader_GmStatusCode,
166 { 0x1f4a9, /* pile of poo */
167 "Invalid Header",
168 "The received header did not conform to the Gemini specification. "
169 "Perhaps the server is malfunctioning or you tried to contact a "
170 "non-Gemini server." } },
171 { invalidRedirect_GmStatusCode,
172 { 0, /* */
173 "Invalid Redirect",
174 "The server responded with a redirect but did not provide a valid destination URL. "
175 "Perhaps the server is malfunctioning." } },
176 { temporaryFailure_GmStatusCode,
177 { 0x1f50c, /* electric plug */
178 "Temporary Failure",
179 "The request has failed, but may succeed if you try again in the future." } },
180 { serverUnavailable_GmStatusCode,
181 { 0x1f525, /* fire */
182 "Server Unavailable",
183 "The server is unavailable due to overload or maintenance. Check back later." } },
184 { cgiError_GmStatusCode,
185 { 0x1f4a5, /* collision */
186 "CGI Error",
187 "Failure during dynamic content generation on the server. This may be due "
188 "to buggy serverside software." } },
189 { proxyError_GmStatusCode,
190 { 0x1f310, /* globe */
191 "Proxy Error",
192 "A proxy request failed because the server was unable to successfully "
193 "complete a transaction with the remote host. Perhaps there are difficulties "
194 "with network connectivity." } },
195 { slowDown_GmStatusCode,
196 { 0x1f40c, /* snail */
197 "Slow Down",
198 "The server is rate limiting requests. Please wait..." } },
199 { permanentFailure_GmStatusCode,
200 { 0x1f6ab, /* no entry */
201 "Permanent Failure",
202 "Your request has failed and will fail in the future as well if repeated." } },
203 { notFound_GmStatusCode,
204 { 0x1f50d, /* magnifying glass */
205 "Not Found",
206 "The requested resource could not be found at this time." } },
207 { gone_GmStatusCode,
208 { 0x1f47b, /* ghost */
209 "Gone",
210 "The resource requested is no longer available and will not be available again." } },
211 { proxyRequestRefused_GmStatusCode,
212 { 0x1f6c2, /* passport control */
213 "Proxy Request Refused",
214 "The request was for a resource at a domain not served by the server and the "
215 "server does not accept proxy requests." } },
216 { badRequest_GmStatusCode,
217 { 0x1f44e, /* thumbs down */
218 "Bad Request",
219 "The server was unable to parse your request, presumably due to the "
220 "request being malformed. Likely a bug in Lagrange." } },
221 { clientCertificateRequired_GmStatusCode,
222 { 0x1f511, /* key */
223 "Certificate Required",
224 "Access to the requested resource requires identification via "
225 "a client certificate." } },
226 { certificateNotAuthorized_GmStatusCode,
227 { 0x1f512, /* lock */
228 "Certificate Not Authorized",
229 "The provided client certificate is valid but is not authorized for accessing "
230 "the requested resource. " } },
231 { certificateNotValid_GmStatusCode,
232 { 0x1f6a8, /* revolving light */
233 "Invalid Certificate",
234 "The provided client certificate is expired or invalid." } },
235 };
236 iForIndices(i, errors) {
237 if (errors[i].code == code) {
238 return &errors[i].err;
239 } 258 }
240 } 259 }
241 return &none; 260 iAssert(errors_[0].code == unknownStatusCode_GmStatusCode);
261 return &errors_[0].err; /* unknown */
242} 262}
diff --git a/src/ui/documentwidget.c b/src/ui/documentwidget.c
index 3b8c468b..c8755fd2 100644
--- a/src/ui/documentwidget.c
+++ b/src/ui/documentwidget.c
@@ -419,26 +419,19 @@ static void checkResponseCode_DocumentWidget_(iDocumentWidget *d) {
419 enum iGmStatusCode statusCode = status_GmRequest(d->request); 419 enum iGmStatusCode statusCode = status_GmRequest(d->request);
420 if (d->state == fetching_DocumentState) { 420 if (d->state == fetching_DocumentState) {
421 d->state = receivedPartialResponse_DocumentState; 421 d->state = receivedPartialResponse_DocumentState;
422 switch (statusCode) { 422 switch (statusCode / 10) {
423 case none_GmStatusCode: 423 case 1: /* input required */ {
424 case success_GmStatusCode:
425 d->scrollY = 0;
426 reset_GmDocument(d->doc); /* new content incoming */
427 updateSource_DocumentWidget_(d);
428 break;
429 case input_GmStatusCode:
430 case sensitiveInput_GmStatusCode: {
431 iUrl parts; 424 iUrl parts;
432 init_Url(&parts, d->url); 425 init_Url(&parts, d->url);
426 printf("%s\n", cstr_String(meta_GmRequest(d->request)));
433 iWidget *dlg = makeValueInput_Widget( 427 iWidget *dlg = makeValueInput_Widget(
434 as_Widget(d), 428 as_Widget(d),
435 NULL, 429 NULL,
436 format_CStr(cyan_ColorEscape "%s", 430 format_CStr(cyan_ColorEscape "%s",
437 cstr_String(collect_String(newRange_String(parts.host)))), 431 cstr_String(collect_String(newRange_String(parts.host)))),
438 isEmpty_String(meta_GmRequest(d->request)) 432 isEmpty_String(meta_GmRequest(d->request))
439 ? format_CStr( 433 ? format_CStr("Please enter input for %s:",
440 "Please enter input for %s:", 434 cstr_String(collect_String(newRange_String(parts.path))))
441 cstr_String(collect_String(newRange_String(parts.path))))
442 : cstr_String(meta_GmRequest(d->request)), 435 : cstr_String(meta_GmRequest(d->request)),
443 orange_ColorEscape "Send \u21d2", 436 orange_ColorEscape "Send \u21d2",
444 "document.input.submit"); 437 "document.input.submit");
@@ -446,19 +439,32 @@ static void checkResponseCode_DocumentWidget_(iDocumentWidget *d) {
446 statusCode == sensitiveInput_GmStatusCode); 439 statusCode == sensitiveInput_GmStatusCode);
447 break; 440 break;
448 } 441 }
449 case redirectTemporary_GmStatusCode: 442 case 2: /* success */
450 case redirectPermanent_GmStatusCode: 443 d->scrollY = 0;
444 reset_GmDocument(d->doc); /* new content incoming */
445 updateSource_DocumentWidget_(d);
446 break;
447 case 3: /* redirect */
451 if (isEmpty_String(meta_GmRequest(d->request))) { 448 if (isEmpty_String(meta_GmRequest(d->request))) {
452 showErrorPage_DocumentWidget_(d, invalidRedirect_GmStatusCode); 449 showErrorPage_DocumentWidget_(d, invalidRedirect_GmStatusCode);
453 } 450 }
454 else { 451 else {
455 postCommandf_App("open redirect:1 url:%s", 452 postCommandf_App(
456 cstr_String(meta_GmRequest(d->request))); 453 "open redirect:1 url:%s",
454 cstr_String(absoluteUrl_String(d->url, meta_GmRequest(d->request))));
457 iReleasePtr(&d->request); 455 iReleasePtr(&d->request);
458 } 456 }
459 break; 457 break;
460 default: 458 default:
461 showErrorPage_DocumentWidget_(d, statusCode); 459 if (isDefined_GmError(statusCode)) {
460 showErrorPage_DocumentWidget_(d, statusCode);
461 }
462 else if (statusCode / 10 == 4) {
463 showErrorPage_DocumentWidget_(d, temporaryFailure_GmStatusCode);
464 }
465 else if (statusCode / 10 == 5) {
466 showErrorPage_DocumentWidget_(d, permanentFailure_GmStatusCode);
467 }
462 break; 468 break;
463 } 469 }
464 } 470 }
diff --git a/src/ui/window.c b/src/ui/window.c
index 83c3d5a3..b438c301 100644
--- a/src/ui/window.c
+++ b/src/ui/window.c
@@ -9,6 +9,7 @@
9#include "labelwidget.h" 9#include "labelwidget.h"
10#include "inputwidget.h" 10#include "inputwidget.h"
11#include "documentwidget.h" 11#include "documentwidget.h"
12#include "gmutil.h"
12#if defined (iPlatformMsys) 13#if defined (iPlatformMsys)
13# include "../win32.h" 14# include "../win32.h"
14#endif 15#endif
@@ -81,7 +82,9 @@ static iBool handleNavBarCommands_(iWidget *navBar, const char *cmd) {
81 if (equal_Command(cmd, "input.ended")) { 82 if (equal_Command(cmd, "input.ended")) {
82 iInputWidget *url = findChild_Widget(navBar, "url"); 83 iInputWidget *url = findChild_Widget(navBar, "url");
83 if (arg_Command(cmd) && pointer_Command(cmd) == url) { 84 if (arg_Command(cmd) && pointer_Command(cmd) == url) {
84 postCommandf_App("open url:%s", cstr_String(text_InputWidget(url))); 85 postCommandf_App(
86 "open url:%s",
87 cstr_String(absoluteUrl_String(&iStringLiteral(""), text_InputWidget(url))));
85 return iTrue; 88 return iTrue;
86 } 89 }
87 } 90 }