Single Fetcher.Fetch on the Guard that holds DenyPrefixes. skipTlsVerification is ignored. No 502. keys add writes the secret only to --out. Release binary has no -test-allow-prefix.
191 lines
4.8 KiB
Go
191 lines
4.8 KiB
Go
package converter
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
|
|
"github.com/JohannesKaufmann/dom"
|
|
"golang.org/x/net/html"
|
|
)
|
|
|
|
// func GetValue[K string, V any](ctx context.Context, key K) V {
|
|
// val, _ := ctx.Value(key).(V)
|
|
// return val
|
|
// }
|
|
// func SetValue[K string, V any](ctx context.Context, key K, val V) context.Context {
|
|
// return context.WithValue(ctx, key, val)
|
|
// }
|
|
|
|
type ctxKey string
|
|
|
|
const (
|
|
ctxKeyAssembleAbsoluteURL ctxKey = "AssembleAbsoluteURL"
|
|
ctxKeyDomain ctxKey = "Domain"
|
|
|
|
ctxKeySetState ctxKey = "SetState"
|
|
ctxKeyUpdateState ctxKey = "UpdateState"
|
|
ctxKeyGetState ctxKey = "GetState"
|
|
)
|
|
|
|
func provideDomain(ctx context.Context, domain string) context.Context {
|
|
return context.WithValue(ctx, ctxKeyDomain, domain)
|
|
}
|
|
func GetDomain(ctx context.Context) string {
|
|
domain, ok := ctx.Value(ctxKeyDomain).(string)
|
|
if !ok {
|
|
fmt.Println("[warning] value ctxKeyDomain is different")
|
|
return ""
|
|
}
|
|
|
|
return domain
|
|
}
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - //
|
|
|
|
type AssembleAbsoluteURLFunc func(tagName string, rawURL string, domain string) string
|
|
|
|
func assembleAbsoluteURL(ctx context.Context, tagName string, rawURL string) string {
|
|
domain := GetDomain(ctx)
|
|
|
|
// TODO: since this gets passed down from the converter, it doesn't have to provided from the ctx anymore
|
|
fn, ok := ctx.Value(ctxKeyAssembleAbsoluteURL).(AssembleAbsoluteURLFunc)
|
|
if !ok {
|
|
fmt.Println("[warning] func ctxKeyAssembleAbsoluteURL is different")
|
|
return ""
|
|
}
|
|
|
|
return fn(tagName, rawURL, domain)
|
|
}
|
|
|
|
func provideAssembleAbsoluteURL(ctx context.Context, fn AssembleAbsoluteURLFunc) context.Context {
|
|
return context.WithValue(ctx, ctxKeyAssembleAbsoluteURL, fn)
|
|
}
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - //
|
|
|
|
type SetStateFunc func(key string, val any)
|
|
type UpdateStateFunc func(key string, fn func(any) any)
|
|
type GetStateFunc func(key string) any
|
|
|
|
type globalState struct {
|
|
data map[string]any
|
|
}
|
|
|
|
func newGlobalState() *globalState {
|
|
|
|
return &globalState{
|
|
data: make(map[string]any),
|
|
}
|
|
}
|
|
|
|
func (s *globalState) setState(key string, val any) {
|
|
s.data[key] = val
|
|
}
|
|
func (s *globalState) updateState(key string, fn func(any) any) {
|
|
s.data[key] = fn(s.data[key])
|
|
}
|
|
func (s *globalState) getState(key string) any {
|
|
return s.data[key]
|
|
}
|
|
|
|
func (s *globalState) provideGlobalState(ctx context.Context) context.Context {
|
|
|
|
var setState SetStateFunc = s.setState
|
|
var updateState UpdateStateFunc = s.updateState
|
|
var getState GetStateFunc = s.getState
|
|
|
|
ctx = context.WithValue(ctx, ctxKeySetState, setState)
|
|
ctx = context.WithValue(ctx, ctxKeyUpdateState, updateState)
|
|
ctx = context.WithValue(ctx, ctxKeyGetState, getState)
|
|
|
|
return ctx
|
|
}
|
|
|
|
func GetState[V any](ctx context.Context, key string) V {
|
|
fn := ctx.Value(ctxKeyGetState).(GetStateFunc)
|
|
|
|
val, _ := fn(key).(V)
|
|
|
|
return val
|
|
}
|
|
|
|
func SetState[V any](ctx context.Context, key string, val V) {
|
|
fn := ctx.Value(ctxKeySetState).(SetStateFunc)
|
|
|
|
fn(key, val)
|
|
}
|
|
|
|
func UpdateState[V any](ctx context.Context, key string, fn func(V) V) {
|
|
updater := ctx.Value(ctxKeyUpdateState).(UpdateStateFunc)
|
|
|
|
updater(key, func(val any) any {
|
|
value, ok := val.(V)
|
|
if !ok && val != nil {
|
|
// TODO: slog?
|
|
fmt.Println("[warning] val is different than V in UpdateState")
|
|
}
|
|
|
|
return fn(value)
|
|
})
|
|
}
|
|
|
|
// - - - - - - //
|
|
|
|
// Context extends the normal context.Context with some additional
|
|
// methods useful for the process of converting.
|
|
type Context interface {
|
|
context.Context
|
|
|
|
AssembleAbsoluteURL(ctx Context, tagName string, rawURL string) string
|
|
|
|
GetTagType(tagName string) (tagType, bool)
|
|
|
|
RenderNodes(ctx Context, w Writer, nodes ...*html.Node)
|
|
RenderChildNodes(ctx Context, w Writer, n *html.Node)
|
|
|
|
EscapeContent(content []byte) []byte
|
|
UnEscapeContent(content []byte) []byte
|
|
|
|
WithValue(key any, val any) Context
|
|
}
|
|
|
|
type converterContext struct {
|
|
context.Context
|
|
conv *Converter
|
|
}
|
|
|
|
func newConverterContext(ctx context.Context, conv *Converter) Context {
|
|
return &converterContext{
|
|
Context: ctx,
|
|
conv: conv,
|
|
}
|
|
}
|
|
|
|
func (c *converterContext) AssembleAbsoluteURL(ctx Context, tagName string, rawURL string) string {
|
|
return assembleAbsoluteURL(ctx, tagName, rawURL)
|
|
}
|
|
|
|
func (c *converterContext) RenderNodes(ctx Context, w Writer, nodes ...*html.Node) {
|
|
c.conv.handleRenderNodes(ctx, w, nodes...)
|
|
}
|
|
func (c *converterContext) RenderChildNodes(ctx Context, w Writer, n *html.Node) {
|
|
c.conv.handleRenderNodes(ctx, w, dom.AllChildNodes(n)...)
|
|
}
|
|
|
|
func (c *converterContext) GetTagType(tagName string) (tagType, bool) {
|
|
return c.conv.getTagType(tagName)
|
|
}
|
|
func (c *converterContext) EscapeContent(content []byte) []byte {
|
|
return c.conv.escapeContent(content)
|
|
}
|
|
func (c *converterContext) UnEscapeContent(content []byte) []byte {
|
|
return c.conv.unEscapeContent(content)
|
|
}
|
|
|
|
func (c *converterContext) WithValue(key any, val any) Context {
|
|
return &converterContext{
|
|
Context: context.WithValue(c.Context, key, val),
|
|
conv: c.conv,
|
|
}
|
|
}
|