~adnano/astronaut

astronaut/errors.go -rw-r--r-- 4.1 KiB
947cfac7Adnan Maolood Update default bindings 17 days ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
package main

import (
	"errors"
	"fmt"
	"strings"

	"git.sr.ht/~adnano/go-gemini"
	"git.sr.ht/~adnano/go-gemini/tofu"
)

var (
	ErrNotTrusted = errors.New("certificate not trusted")
)

type ErrFingerprintMismatch struct {
	Expected tofu.Host
	Got      tofu.Host
}

func (ErrFingerprintMismatch) Title() string {
	return "Fingerprint mismatch!"
}

func (e ErrFingerprintMismatch) Error() string {
	var b strings.Builder
	templates.ExecuteTemplate(&b, "mismatch.tmpl", e)
	return b.String()
}

type ErrTooManyRedirects struct {
	Req *gemini.Request
	Via []*gemini.Request
}

func (ErrTooManyRedirects) Title() string {
	return "Too many redirects"
}

func (e ErrTooManyRedirects) Error() string {
	var b strings.Builder
	templates.ExecuteTemplate(&b, "too-many-redirects.tmpl", e)
	return b.String()
}

type ErrUnsupportedScheme struct{}

func (ErrUnsupportedScheme) Title() string {
	return "Unsupported protocol"
}

func (ErrUnsupportedScheme) Error() string {
	return "The requested protocol is not supported."
}

type ErrUnsupportedCharset string

func (e ErrUnsupportedCharset) Title() string {
	return "Unsupported character encoding"
}

func (e ErrUnsupportedCharset) Error() string {
	return fmt.Sprintf("The character encoding %q is not supported.", string(e))
}

type ErrUnsuccessful struct {
	Status gemini.Status
	Meta   string
}

func (e ErrUnsuccessful) Title() string {
	title, ok := statusTitle[e.Status]
	if !ok {
		title, ok = statusTitle[e.Status.Class()]
	}
	if !ok {
		return "Unknown status code"
	}
	return title
}

func (e ErrUnsuccessful) Error() string {
	const unknownStatus = "The server responded with a status code that is not in the Gemini protocol specification."

	msg, ok := statusMessage[e.Status]
	if !ok {
		msg, ok = statusMessage[e.Status.Class()]
	}
	if !ok {
		return unknownStatus
	}
	if len(e.Meta) != 0 {
		return fmt.Sprintf("%s\n\nServer says:\n> %s\n", msg, e.Meta)
	}
	return msg
}

var statusTitle = map[gemini.Status]string{
	gemini.StatusTemporaryFailure:         "Temporary failure",
	gemini.StatusServerUnavailable:        "Server unavailable",
	gemini.StatusCGIError:                 "CGI error",
	gemini.StatusProxyError:               "Proxy error",
	gemini.StatusSlowDown:                 "Slow down",
	gemini.StatusPermanentFailure:         "Permanent failure",
	gemini.StatusNotFound:                 "Not found",
	gemini.StatusGone:                     "Gone",
	gemini.StatusProxyRequestRefused:      "Proxy request refused",
	gemini.StatusBadRequest:               "Bad request",
	gemini.StatusCertificateRequired:      "Certificate required",
	gemini.StatusCertificateNotAuthorized: "Certificate not authorized",
	gemini.StatusCertificateNotValid:      "Invalid certificate",
}

var statusMessage = map[gemini.Status]string{
	gemini.StatusTemporaryFailure:         "The request failed but may succeed in the future.",
	gemini.StatusServerUnavailable:        "The server is unavailable due to overload or maintenance.",
	gemini.StatusCGIError:                 "Failure during dynamic content generation on the server.",
	gemini.StatusProxyError:               "A proxy request failed because the server was unable to complete a transaction with the remote host.",
	gemini.StatusSlowDown:                 "Rate limiting is in effect.",
	gemini.StatusPermanentFailure:         "The request failed and will not succeed in the future if repeated.",
	gemini.StatusNotFound:                 "The requested resource could not be found but may be available in the future.",
	gemini.StatusGone:                     "The requested resource is no longer available.",
	gemini.StatusProxyRequestRefused:      "The request was for a resource at a domain not served by the server and the server does not accept proxy requests.",
	gemini.StatusBadRequest:               "The server did not understand your request.",
	gemini.StatusCertificateRequired:      "Access to the requested resource requires identification via a client certificate.",
	gemini.StatusCertificateNotAuthorized: "The provided client certificate is valid but is not authorized for accessing the requested resource.",
	gemini.StatusCertificateNotValid:      "The provided client certificate is expired or invalid.",
}