Store permanent errors

This commit is contained in:
blank X 2021-08-10 16:07:09 +07:00
parent 34fffa9d37
commit 280703edd8
Signed by: blankie
GPG Key ID: CC15FC822C7F61F5
1 changed files with 99 additions and 0 deletions

99
main.go
View File

@ -9,6 +9,7 @@ import (
"bufio" "bufio"
"errors" "errors"
"context" "context"
"strconv"
"strings" "strings"
"net/url" "net/url"
"crypto/x509" "crypto/x509"
@ -23,6 +24,7 @@ var (
hosts tofu.KnownHosts hosts tofu.KnownHosts
hostsfile *tofu.HostWriter hostsfile *tofu.HostWriter
predirs map[string]*url.URL predirs map[string]*url.URL
perrors map[string]PError
) )
func xdgDataHome() string { func xdgDataHome() string {
@ -48,6 +50,11 @@ func init() {
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }
err = populatePErrors()
if err != nil {
log.Fatal(err)
}
} }
func populatePRedirs() error { func populatePRedirs() error {
@ -114,6 +121,80 @@ func savePRedirs() error {
return writer.Flush() return writer.Flush()
} }
func populatePErrors() error {
file, err := os.OpenFile(filepath.Join(xdgDataHome(), "konbata", "perrors"), os.O_RDONLY|os.O_CREATE, 0600)
if err != nil {
return err
}
defer file.Close()
scanner := bufio.NewScanner(file)
perrors = make(map[string]PError)
unescaper := strings.NewReplacer("\\n", "\n", "\\\\", "\\")
for scanner.Scan() {
values := strings.SplitN(scanner.Text(), " ", 3)
if len(values) != 3 {
continue
}
url, err := url.Parse(values[0])
if err != nil {
continue
}
if url.Scheme != "gemini" {
continue
}
code, err := strconv.Atoi(values[1])
if err != nil {
continue
}
perrors[url.String()] = PError{
code: gemini.Status(code),
message: unescaper.Replace(values[2]),
}
}
return nil
}
func savePErrors() error {
file, err := os.OpenFile(filepath.Join(xdgDataHome(), "konbata", "perrors"), os.O_WRONLY|os.O_CREATE, 0600)
if err != nil {
return err
}
defer file.Close()
err = file.Truncate(0)
if err != nil {
return err
}
writer := bufio.NewWriter(file)
escaper := strings.NewReplacer("\\", "\\\\", "\n", "\\n")
for url, perror := range perrors {
_, err = writer.WriteString(url)
if err != nil {
return err
}
_, err = writer.WriteRune(' ')
if err != nil {
return err
}
_, err = writer.WriteString(strconv.Itoa(int(perror.code)))
if err != nil {
return err
}
_, err = writer.WriteRune(' ')
if err != nil {
return err
}
_, err = escaper.WriteString(writer, perror.message)
if err != nil {
return err
}
_, err = writer.WriteRune('\n')
if err != nil {
return err
}
}
return writer.Flush()
}
func trustCertificate(hostname string, cert *x509.Certificate) error { func trustCertificate(hostname string, cert *x509.Certificate) error {
host := tofu.NewHost(hostname, cert.Raw) host := tofu.NewHost(hostname, cert.Raw)
knownHost, ok := hosts.Lookup(hostname) knownHost, ok := hosts.Lookup(hostname)
@ -141,6 +222,9 @@ func do(client gemini.Client, ctx context.Context, req *gemini.Request, via []*g
redirect.URL = target redirect.URL = target
return do(client, ctx, &redirect, via) return do(client, ctx, &redirect, via)
} }
if perror, exists := perrors[req.URL.String()]; exists {
return nil, req, errors.New(fmt.Sprintf("%d %s", perror.code, perror.message))
}
resp, err := client.Do(ctx, req) resp, err := client.Do(ctx, req)
if err != nil { if err != nil {
return resp, req, err return resp, req, err
@ -161,6 +245,16 @@ func do(client gemini.Client, ctx context.Context, req *gemini.Request, via []*g
return resp, req, err return resp, req, err
} }
} }
if resp.Status.Class() == gemini.StatusPermanentFailure {
perrors[req.URL.String()] = PError{
code: resp.Status,
message: resp.Meta,
}
err = savePErrors()
if err != nil {
return resp, req, err
}
}
if resp.Status.Class() == gemini.StatusRedirect { if resp.Status.Class() == gemini.StatusRedirect {
via = append(via, req) via = append(via, req)
if len(via) > 5 { if len(via) > 5 {
@ -304,6 +398,11 @@ func (a ByTime) Swap(i, j int) {
a[i], a[j] = a[j], a[i] a[i], a[j] = a[j], a[i]
} }
type PError struct {
code gemini.Status
message string
}
type AtomWriter struct { type AtomWriter struct {
Title string Title string
Items []FeedItem Items []FeedItem