diff options
author | Jaakko Keränen <jaakko.keranen@iki.fi> | 2020-08-01 22:50:07 +0300 |
---|---|---|
committer | Jaakko Keränen <jaakko.keranen@iki.fi> | 2020-08-01 22:50:07 +0300 |
commit | 5fb32fcfca41d2e1b6eaaacaa6b6b37fc9e6d0b1 (patch) | |
tree | 2e01c7226a558bb51d8c4e82c46600e57d74f3cb | |
parent | a05d181c72df33256e603f2e4543ee73665b242c (diff) |
Handling status codes by class
-rw-r--r-- | src/gemini.h | 4 | ||||
-rw-r--r-- | src/gmutil.c | 198 | ||||
-rw-r--r-- | src/ui/documentwidget.c | 42 | ||||
-rw-r--r-- | src/ui/window.c | 5 |
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 | ||
41 | const iGmError * get_GmError (enum iGmStatusCode code); | 42 | iBool isDefined_GmError (enum iGmStatusCode code); |
43 | const 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 | ||
149 | static 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 | |||
241 | iBool 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 | |||
149 | const iGmError *get_GmError(enum iGmStatusCode code) { | 250 | const 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 | } |