mirror of
https://github.com/rkd77/elinks.git
synced 2024-12-04 14:46:47 -05:00
[gemini] Show error page for some errors.
This commit is contained in:
parent
61247f6a32
commit
391d463a46
@ -26,8 +26,10 @@
|
||||
#endif
|
||||
#include "document/renderer.h"
|
||||
#include "document/view.h"
|
||||
#ifdef CONFIG_ECMASCRIPT
|
||||
#include "ecmascript/ecmascript.h"
|
||||
#include "ecmascript/spidermonkey/document.h"
|
||||
#endif
|
||||
#include "encoding/encoding.h"
|
||||
#include "intl/charsets.h"
|
||||
#include "main/main.h"
|
||||
|
@ -1,6 +1,6 @@
|
||||
top_builddir=../../..
|
||||
include $(top_builddir)/Makefile.config
|
||||
|
||||
OBJS = gemini.o
|
||||
OBJS = codes.o gemini.o
|
||||
|
||||
include $(top_srcdir)/Makefile.lib
|
||||
|
180
src/protocol/gemini/codes.c
Normal file
180
src/protocol/gemini/codes.c
Normal file
@ -0,0 +1,180 @@
|
||||
/* Gemini response codes */
|
||||
|
||||
#ifndef _GNU_SOURCE
|
||||
#define _GNU_SOURCE /* Needed for asprintf() */
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "elinks.h"
|
||||
|
||||
#include "cache/cache.h"
|
||||
#include "intl/gettext/libintl.h"
|
||||
#include "network/connection.h"
|
||||
#include "protocol/gemini/codes.h"
|
||||
#include "protocol/uri.h"
|
||||
#include "session/session.h"
|
||||
#include "session/task.h"
|
||||
#include "terminal/terminal.h"
|
||||
#include "terminal/window.h"
|
||||
#include "util/snprintf.h"
|
||||
#include "viewer/text/draw.h"
|
||||
|
||||
|
||||
struct gemini_code {
|
||||
int num;
|
||||
const char *str;
|
||||
};
|
||||
|
||||
static const struct gemini_code gemini_code[] = {
|
||||
{ 10, "INPUT" },
|
||||
{ 21, "SENSITIVE INPUT" },
|
||||
{ 20, "SUCCESS" },
|
||||
{ 30, "REDIRECT - TEMPORARY" },
|
||||
{ 31, "REDIRECT - PERMANENT" },
|
||||
{ 40, "TEMPORARY FAILURE" },
|
||||
{ 41, "SERVER UNAVAILABLE" },
|
||||
{ 42, "CGI ERROR" },
|
||||
{ 43, "PROXY ERROR" },
|
||||
{ 44, "SLOW DOWN" },
|
||||
{ 50, "PERMANENT FAILURE" },
|
||||
{ 51, "NOT FOUND" },
|
||||
{ 52, "GONE" },
|
||||
{ 53, "PROXY REQUEST REFUSED" },
|
||||
{ 59, "BAD REQUEST" },
|
||||
{ 60, "CLIENT CERTIFICATE REQUIRED" },
|
||||
{ 61, "CERTIFICATE NOT AUTHORISED" },
|
||||
{ 62, "CERTIFICATE NOT VALID" },
|
||||
};
|
||||
|
||||
static int
|
||||
compare_gemini_codes(const void *key, const void *element)
|
||||
{
|
||||
int first = (long) key;
|
||||
int second = ((const struct gemini_code *) element)->num;
|
||||
|
||||
return first - second;
|
||||
}
|
||||
|
||||
static const char *
|
||||
gemini_code_to_string(int code)
|
||||
{
|
||||
const struct gemini_code *element
|
||||
= bsearch((void *) (long) code, gemini_code,
|
||||
sizeof_array(gemini_code),
|
||||
sizeof(*element),
|
||||
compare_gemini_codes);
|
||||
|
||||
if (element) return element->str;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static char *
|
||||
get_gemini_error_document(struct terminal *term, struct uri *uri, int code)
|
||||
{
|
||||
const char *codestr = gemini_code_to_string(code);
|
||||
char *title = asprintfa(_("Gemini error %02d", term), code);
|
||||
struct string string;
|
||||
|
||||
if (!codestr) codestr = "UNKNOWN ERROR";
|
||||
|
||||
if (!init_string(&string)) {
|
||||
mem_free_if(title);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
add_format_to_string(&string,
|
||||
"<html>\n"
|
||||
" <head><title>%s</title></head>\n"
|
||||
" <body>\n"
|
||||
" <h1 align=\"left\">%s: %s</h1>\n"
|
||||
#ifndef CONFIG_SMALL
|
||||
" <hr />\n"
|
||||
" <p>\n"
|
||||
#endif
|
||||
, title, title, codestr);
|
||||
|
||||
#ifndef CONFIG_SMALL
|
||||
add_format_to_string(&string, _(
|
||||
" An error occurred on the server while fetching the document you\n"
|
||||
" requested.\n",
|
||||
term));
|
||||
|
||||
add_format_to_string(&string,
|
||||
" </p>\n"
|
||||
" <p>\n"
|
||||
" URI: <a href=\"%s\">%s</a>\n", struri(uri), struri(uri));
|
||||
#endif
|
||||
add_format_to_string(&string,
|
||||
#ifndef CONFIG_SMALL
|
||||
" </p>\n"
|
||||
" <hr />\n"
|
||||
#endif
|
||||
" </body>\n"
|
||||
"</html>\n");
|
||||
|
||||
mem_free_if(title);
|
||||
|
||||
return string.source;
|
||||
}
|
||||
|
||||
struct gemini_error_info {
|
||||
int code;
|
||||
struct uri *uri;
|
||||
};
|
||||
|
||||
static void
|
||||
show_gemini_error_document(struct session *ses, void *data)
|
||||
{
|
||||
struct gemini_error_info *info = data;
|
||||
struct terminal *term = ses->tab->term;
|
||||
struct cache_entry *cached = find_in_cache(info->uri);
|
||||
struct cache_entry *cache = cached ? cached : get_cache_entry(info->uri);
|
||||
char *str = NULL;
|
||||
|
||||
if (cache) str = get_gemini_error_document(term, info->uri, info->code);
|
||||
|
||||
if (str) {
|
||||
/* The codepage that _("foo", term) used when it was
|
||||
* called by get_gemini_error_document. */
|
||||
const int gettext_codepage = get_terminal_codepage(term);
|
||||
|
||||
if (cached) delete_entry_content(cache);
|
||||
|
||||
/* If we run out of memory here, it's perhaps better
|
||||
* to display a malformatted error message than none
|
||||
* at all. */
|
||||
mem_free_set(&cache->content_type, stracpy("text/html"));
|
||||
mem_free_set(&cache->head,
|
||||
straconcat("\r\nContent-Type: text/html; charset=",
|
||||
get_cp_mime_name(gettext_codepage),
|
||||
"\r\n", (char *) NULL));
|
||||
add_fragment(cache, 0, str, strlen(str));
|
||||
mem_free(str);
|
||||
|
||||
draw_formatted(ses, 1);
|
||||
}
|
||||
|
||||
done_uri(info->uri);
|
||||
mem_free(info);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
gemini_error_document(struct connection *conn, int code)
|
||||
{
|
||||
struct gemini_error_info *info;
|
||||
|
||||
assert(conn && conn->uri);
|
||||
|
||||
info = mem_calloc(1, sizeof(*info));
|
||||
if (!info) return;
|
||||
|
||||
info->code = code;
|
||||
info->uri = get_uri_reference(conn->uri);
|
||||
|
||||
add_questions_entry(show_gemini_error_document, info);
|
||||
}
|
19
src/protocol/gemini/codes.h
Normal file
19
src/protocol/gemini/codes.h
Normal file
@ -0,0 +1,19 @@
|
||||
|
||||
#ifndef EL__PROTOCOL_GEMINI_CODES_H
|
||||
#define EL__PROTOCOL_GEMINI_CODES_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct connection;
|
||||
|
||||
/* Gemini response codes device. */
|
||||
|
||||
void gemini_error_document(struct connection *conn, int code);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* EL__PROTOCOL_HTTP_CODES_H */
|
@ -25,6 +25,7 @@
|
||||
#include "osdep/osdep.h"
|
||||
#include "osdep/sysname.h"
|
||||
#include "protocol/date.h"
|
||||
#include "protocol/gemini/codes.h"
|
||||
#include "protocol/gemini/gemini.h"
|
||||
#include "protocol/header.h"
|
||||
#include "protocol/uri.h"
|
||||
@ -158,18 +159,17 @@ read_gemini_data_done(struct connection *conn)
|
||||
|
||||
/* There's no content but an error so just print
|
||||
* that instead of nothing. */
|
||||
// if (!conn->from) {
|
||||
// if (http->code >= 400) {
|
||||
// http_error_document(conn, http->code);
|
||||
//
|
||||
// } else {
|
||||
// /* This is not an error, thus fine. No need generate any
|
||||
// * document, as this may be empty and it's not a problem.
|
||||
// * In case of 3xx, we're probably just getting kicked to
|
||||
// * another page anyway. And in case of 2xx, the document
|
||||
// * may indeed be empty and thus the user should see it so. */
|
||||
// }
|
||||
// }
|
||||
if (!conn->from) {
|
||||
if (gemini->code >= 40) {
|
||||
gemini_error_document(conn, gemini->code);
|
||||
} else {
|
||||
/* This is not an error, thus fine. No need generate any
|
||||
* document, as this may be empty and it's not a problem.
|
||||
* In case of 3xx, we're probably just getting kicked to
|
||||
* another page anyway. And in case of 2xx, the document
|
||||
* may indeed be empty and thus the user should see it so. */
|
||||
}
|
||||
}
|
||||
|
||||
gemini_end_request(conn, connection_state(S_OK), 0);
|
||||
}
|
||||
@ -271,8 +271,7 @@ gemini_got_header(struct socket *socket, struct read_buffer *rb)
|
||||
struct connection_state state = (!is_in_state(conn->state, S_PROC)
|
||||
? connection_state(S_GETH)
|
||||
: connection_state(S_PROC));
|
||||
int a, h = 20;
|
||||
int cf;
|
||||
int a, h = 40;
|
||||
|
||||
if (socket->state == SOCKET_CLOSED) {
|
||||
retry_connection(conn, connection_state(S_CANT_READ));
|
||||
@ -294,9 +293,12 @@ again:
|
||||
|
||||
if ((a && get_gemini_code(rb, &h))
|
||||
|| ((h >= 40) || h < 10)) {
|
||||
abort_connection(conn, connection_state(S_HTTP_ERROR));
|
||||
gemini->code = h;
|
||||
mem_free_set(&conn->cached->content_type, stracpy("text/html"));
|
||||
read_gemini_data_done(conn);
|
||||
return;
|
||||
}
|
||||
gemini->code = h;
|
||||
|
||||
if (h >= 30 && h < 40) {
|
||||
char *url = memacpy(rb->data + 3, a - 4);
|
||||
@ -313,7 +315,6 @@ again:
|
||||
init_string(&head_string);
|
||||
add_to_string(&head_string, "\nContent-Type:");
|
||||
add_bytes_to_string(&head_string, rb->data + 2, a);
|
||||
gemini->code = h;
|
||||
|
||||
if (!conn->cached) {
|
||||
done_string(&head_string);
|
||||
|
@ -1 +1 @@
|
||||
srcs += files('gemini.c')
|
||||
srcs += files('codes.c', 'gemini.c')
|
||||
|
Loading…
Reference in New Issue
Block a user