Move RnD sample programs to examples dir, rename test_data to example_data, add stubs for server and client
This commit is contained in:
56
Makefile
56
Makefile
@@ -2,10 +2,17 @@
|
|||||||
|
|
||||||
GOOPTS=CGO_ENABLED=0
|
GOOPTS=CGO_ENABLED=0
|
||||||
BUILDOPTS=-ldflags="-s -w" -a -gcflags=all=-l -trimpath -buildvcs=false
|
BUILDOPTS=-ldflags="-s -w" -a -gcflags=all=-l -trimpath -buildvcs=false
|
||||||
MYNAME=doll
|
MYNAME1=doll
|
||||||
BINARY=${MYNAME}
|
MYNAME2=doll-master
|
||||||
UNIX_BINARY=${MYNAME}
|
BINARY1=${MYNAME1}
|
||||||
WINDOWS_BINARY=${MYNAME}.exe
|
BINARY2=${MYNAME2}
|
||||||
|
UNIX_BINARY1=${MYNAME1}
|
||||||
|
UNIX_BINARY2=${MYNAME2}
|
||||||
|
WINDOWS_BINARY1=${MYNAME1}.exe
|
||||||
|
WINDOWS_BINARY2=${MYNAME2}.exe
|
||||||
|
EXAMPLE01=01-LoadJsonFile
|
||||||
|
EXAMPLE02=02-TestLuaScript
|
||||||
|
|
||||||
RMCMD=rm -rf
|
RMCMD=rm -rf
|
||||||
|
|
||||||
# На windows имя бинарника может зависеть не только от платформы, но и от выбранной цели, для linux-а суффикс .exe
|
# На windows имя бинарника может зависеть не только от платформы, но и от выбранной цели, для linux-а суффикс .exe
|
||||||
@@ -13,12 +20,15 @@ RMCMD=rm -rf
|
|||||||
ifeq ($(OS),Windows_NT)
|
ifeq ($(OS),Windows_NT)
|
||||||
ifdef GOOS
|
ifdef GOOS
|
||||||
ifeq ($(GOOS),windows)
|
ifeq ($(GOOS),windows)
|
||||||
BINARY=${WINDOWS_BINARY}
|
BINARY1=${WINDOWS_BINARY1}
|
||||||
|
BINARY2=${WINDOWS_BINARY2}
|
||||||
else # not ifeq ($(GOOS),windows)
|
else # not ifeq ($(GOOS),windows)
|
||||||
BINARY=${MYNAME}
|
BINARY1=${MYNAME1}
|
||||||
|
BINARY2=${MYNAME2}
|
||||||
endif # ifeq ($(GOOS),windows)
|
endif # ifeq ($(GOOS),windows)
|
||||||
else # not ifdef GOOS
|
else # not ifdef GOOS
|
||||||
BINARY=${WINDOWS_BINARY}
|
BINARY1=${WINDOWS_BINARY1}
|
||||||
|
BINARY2=${WINDOWS_BINARY2}
|
||||||
endif # ifdef GOOS
|
endif # ifdef GOOS
|
||||||
ifeq ($(SHELL), sh.exe)
|
ifeq ($(SHELL), sh.exe)
|
||||||
RMCMD=DEL /Q /F
|
RMCMD=DEL /Q /F
|
||||||
@@ -40,17 +50,20 @@ ifeq ($(OS),Windows_NT)
|
|||||||
ifeq ($(SHELL), sh.exe)
|
ifeq ($(SHELL), sh.exe)
|
||||||
# # Vanilla cmd.exe / powershell.
|
# # Vanilla cmd.exe / powershell.
|
||||||
SET "CGO_ENABLED=0"
|
SET "CGO_ENABLED=0"
|
||||||
go build ${BUILDOPTS} -o ${BINARY} ./cmd/${MYNAME}
|
go build ${BUILDOPTS} -o ${BINARY1} ./cmd/${MYNAME1}
|
||||||
|
go build ${BUILDOPTS} -o ${BINARY2} ./cmd/${MYNAME2}
|
||||||
else ifeq (,$(findstring(Git/usr/bin/sh.exe, $(SHELL))))
|
else ifeq (,$(findstring(Git/usr/bin/sh.exe, $(SHELL))))
|
||||||
# # git-bash
|
# # git-bash
|
||||||
CGO_ENABLED=0 go build ${BUILDOPTS} -o ${BINARY} ./cmd/${MYNAME}
|
CGO_ENABLED=0 go build ${BUILDOPTS} -o ${BINARY1} ./cmd/${MYNAME1}
|
||||||
|
CGO_ENABLED=0 go build ${BUILDOPTS} -o ${BINARY2} ./cmd/${MYNAME2}
|
||||||
else # not ifeq (,$(findstring(Git/usr/bin/sh.exe, $(SHELL))))
|
else # not ifeq (,$(findstring(Git/usr/bin/sh.exe, $(SHELL))))
|
||||||
# # Some other shell.
|
# # Some other shell.
|
||||||
# # TODO: handle it.
|
# # TODO: handle it.
|
||||||
$(info "-- Dunno how to handle this shell: ${SHELL}")
|
$(info "-- Dunno how to handle this shell: ${SHELL}")
|
||||||
endif # ifeq (,$(findstring(Git/usr/bin/sh.exe, $(SHELL))))
|
endif # ifeq (,$(findstring(Git/usr/bin/sh.exe, $(SHELL))))
|
||||||
else # not ($(OS),Windows_NT)
|
else # not ($(OS),Windows_NT)
|
||||||
CGO_ENABLED=0 go build ${BUILDOPTS} -o ${BINARY} ./cmd/${MYNAME}
|
CGO_ENABLED=0 go build ${BUILDOPTS} -o ${BINARY1} ./cmd/${MYNAME1}
|
||||||
|
CGO_ENABLED=0 go build ${BUILDOPTS} -o ${BINARY2} ./cmd/${MYNAME2}
|
||||||
endif # ifeq ($(OS),Windows_NT)
|
endif # ifeq ($(OS),Windows_NT)
|
||||||
|
|
||||||
|
|
||||||
@@ -58,17 +71,27 @@ clean:
|
|||||||
ifeq ($(OS),Windows_NT)
|
ifeq ($(OS),Windows_NT)
|
||||||
ifeq ($(SHELL),sh.exe)
|
ifeq ($(SHELL),sh.exe)
|
||||||
# # Vanilla cmd.exe / powershell.
|
# # Vanilla cmd.exe / powershell.
|
||||||
|
if exist 01-LoadJsonFile.exe ${RMCMD} ${WINDOWS_BINARY1}
|
||||||
|
if exist 01-LoadJsonFile.exe ${RMCMD} ${UNIX_BINARY1}
|
||||||
|
if exist 01-LoadJsonFile.exe ${RMCMD} ${WINDOWS_BINARY2}
|
||||||
|
if exist 01-LoadJsonFile.exe ${RMCMD} ${UNIX_BINARY2}
|
||||||
if exist 01-LoadJsonFile.exe ${RMCMD} 01-LoadJsonFile.exe
|
if exist 01-LoadJsonFile.exe ${RMCMD} 01-LoadJsonFile.exe
|
||||||
if exist 01-LoadJsonFile ${RMCMD} 01-LoadJsonFile
|
if exist 01-LoadJsonFile ${RMCMD} 01-LoadJsonFile
|
||||||
if exist 02-TestLuaScript.exe ${RMCMD} 02-TestLuaScript.exe
|
if exist 02-TestLuaScript.exe ${RMCMD} 02-TestLuaScript.exe
|
||||||
if exist 02-TestLuaScript ${RMCMD} 02-TestLuaScript
|
if exist 02-TestLuaScript ${RMCMD} 02-TestLuaScript
|
||||||
else # not ifeq ($(SHELL),sh.exe)
|
else # not ifeq ($(SHELL),sh.exe)
|
||||||
|
${RMCMD} ${WINDOWS_BINARY1}
|
||||||
|
${RMCMD} ${UNIX_BINARY1}
|
||||||
|
${RMCMD} ${WINDOWS_BINARY2}
|
||||||
|
${RMCMD} ${UNIX_BINARY2}
|
||||||
${RMCMD} ./01-LoadJsonFile.exe
|
${RMCMD} ./01-LoadJsonFile.exe
|
||||||
${RMCMD} ./01-LoadJsonFile
|
${RMCMD} ./01-LoadJsonFile
|
||||||
${RMCMD} ./02-TestLuaScript.exe
|
${RMCMD} ./02-TestLuaScript.exe
|
||||||
${RMCMD} ./02-TestLuaScript
|
${RMCMD} ./02-TestLuaScript
|
||||||
endif # ifeq ($(SHELL),sh.exe)
|
endif # ifeq ($(SHELL),sh.exe)
|
||||||
else # not ifeq ($(OS),Windows_NT)
|
else # not ifeq ($(OS),Windows_NT)
|
||||||
|
${RMCMD} ${BINARY1}
|
||||||
|
${RMCMD} ${BINARY2}
|
||||||
${RMCMD} ./01-LoadJsonFile
|
${RMCMD} ./01-LoadJsonFile
|
||||||
${RMCMD} ./02-TestLuaScript
|
${RMCMD} ./02-TestLuaScript
|
||||||
endif
|
endif
|
||||||
@@ -86,17 +109,17 @@ ifeq ($(OS),Windows_NT)
|
|||||||
ifeq ($(SHELL), sh.exe)
|
ifeq ($(SHELL), sh.exe)
|
||||||
# # Vanilla cmd.exe / powershell.
|
# # Vanilla cmd.exe / powershell.
|
||||||
SET "CGO_ENABLED=0"
|
SET "CGO_ENABLED=0"
|
||||||
go build ${BUILDOPTS} -o 01-LoadJsonFile.exe ./cmd/01-LoadJsonFile
|
go build ${BUILDOPTS} -o ${EXAMPLE01}.exe ./examples/${EXAMPLE01}
|
||||||
else ifeq (,$(findstring(Git/usr/bin/sh.exe, $(SHELL))))
|
else ifeq (,$(findstring(Git/usr/bin/sh.exe, $(SHELL))))
|
||||||
# # git-bash
|
# # git-bash
|
||||||
CGO_ENABLED=0 go build ${BUILDOPTS} -o 01-LoadJsonFile.exe ./cmd/01-LoadJsonFile
|
CGO_ENABLED=0 go build ${BUILDOPTS} -o ${EXAMPLE01}.exe ./examples/${EXAMPLE01}
|
||||||
else # not ifeq (,$(findstring(Git/usr/bin/sh.exe, $(SHELL))))
|
else # not ifeq (,$(findstring(Git/usr/bin/sh.exe, $(SHELL))))
|
||||||
# # Some other shell.
|
# # Some other shell.
|
||||||
# # TODO: handle it.
|
# # TODO: handle it.
|
||||||
$(info "-- Dunno how to handle this shell: ${SHELL}")
|
$(info "-- Dunno how to handle this shell: ${SHELL}")
|
||||||
endif # ifeq (,$(findstring(Git/usr/bin/sh.exe, $(SHELL))))
|
endif # ifeq (,$(findstring(Git/usr/bin/sh.exe, $(SHELL))))
|
||||||
else # not ($(OS),Windows_NT)
|
else # not ($(OS),Windows_NT)
|
||||||
CGO_ENABLED=0 go build ${BUILDOPTS} -o 01-LoadJsonFile ./cmd/01-LoadJsonFile
|
CGO_ENABLED=0 go build ${BUILDOPTS} -o ${EXAMPLE01} ./examples/${EXAMPLE01}
|
||||||
endif # ifeq ($(OS),Windows_NT)
|
endif # ifeq ($(OS),Windows_NT)
|
||||||
|
|
||||||
|
|
||||||
@@ -106,17 +129,18 @@ ifeq ($(OS),Windows_NT)
|
|||||||
ifeq ($(SHELL), sh.exe)
|
ifeq ($(SHELL), sh.exe)
|
||||||
# # Vanilla cmd.exe / powershell.
|
# # Vanilla cmd.exe / powershell.
|
||||||
SET "CGO_ENABLED=0"
|
SET "CGO_ENABLED=0"
|
||||||
go build ${BUILDOPTS} -o 02-TestLuaScript.exe ./cmd/02-TestLuaScript
|
go build ${BUILDOPTS} -o ${EXAMPLE02}.exe ./examples/${EXAMPLE02}
|
||||||
else ifeq (,$(findstring(Git/usr/bin/sh.exe, $(SHELL))))
|
else ifeq (,$(findstring(Git/usr/bin/sh.exe, $(SHELL))))
|
||||||
# # git-bash
|
# # git-bash
|
||||||
CGO_ENABLED=0 go build ${BUILDOPTS} -o 02-TestLuaScript.exe ./cmd/02-TestLuaScript
|
CGO_ENABLED=0 go build ${BUILDOPTS} -o ${EXAMPLE02}.exe ./examples/${EXAMPLE02}
|
||||||
else # not ifeq (,$(findstring(Git/usr/bin/sh.exe, $(SHELL))))
|
else # not ifeq (,$(findstring(Git/usr/bin/sh.exe, $(SHELL))))
|
||||||
# # Some other shell.
|
# # Some other shell.
|
||||||
# # TODO: handle it.
|
# # TODO: handle it.
|
||||||
$(info "-- Dunno how to handle this shell: ${SHELL}")
|
$(info "-- Dunno how to handle this shell: ${SHELL}")
|
||||||
endif # ifeq (,$(findstring(Git/usr/bin/sh.exe, $(SHELL))))
|
endif # ifeq (,$(findstring(Git/usr/bin/sh.exe, $(SHELL))))
|
||||||
else # not ($(OS),Windows_NT)
|
else # not ($(OS),Windows_NT)
|
||||||
CGO_ENABLED=0 go build ${BUILDOPTS} -o 02-TestLuaScript ./cmd/02-TestLuaScript
|
CGO_ENABLED=0 go build ${BUILDOPTS} -o ${EXAMPLE02} ./examples/${EXAMPLE02}
|
||||||
endif # ifeq ($(OS),Windows_NT)
|
endif # ifeq ($(OS),Windows_NT)
|
||||||
|
|
||||||
|
|
||||||
# vim: set ft=make noet ai ts=4 sw=4 sts=4:
|
# vim: set ft=make noet ai ts=4 sw=4 sts=4:
|
||||||
23
cmd/doll-master/main.go
Normal file
23
cmd/doll-master/main.go
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"doll/internal/log"
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
// Register http-request handler.
|
||||||
|
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
fmt.Fprintf(w, "Doll-master here!")
|
||||||
|
})
|
||||||
|
|
||||||
|
// And run server on 8240 port.
|
||||||
|
log.Info("Starting server at port 8240")
|
||||||
|
|
||||||
|
if err := http.ListenAndServe(":8240", nil); err != nil {
|
||||||
|
log.Fatalf("Error starting the server: %s", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* vim: set ft=go noet ai ts=4 sw=4 sts=4: */
|
||||||
26
cmd/doll/main.go
Normal file
26
cmd/doll/main.go
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"doll/internal/log"
|
||||||
|
|
||||||
|
"github.com/carlmjohnson/requests"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
var (
|
||||||
|
ctx = context.Background()
|
||||||
|
body string
|
||||||
|
userAgent = "doll"
|
||||||
|
url = "http://localhost:8240/"
|
||||||
|
err error
|
||||||
|
)
|
||||||
|
|
||||||
|
if err = requests.URL(url).UserAgent(userAgent).ToString(&body).Fetch(ctx); err != nil {
|
||||||
|
log.Fatalf("unable to GET %s: %s", url, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Infof("Response is: %s", body)
|
||||||
|
}
|
||||||
|
|
||||||
|
/* vim: set ft=go noet ai ts=4 sw=4 sts=4: */
|
||||||
@@ -9,12 +9,15 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
file := "example_data/01-config.json"
|
||||||
|
|
||||||
log.Init("info", os.Stderr)
|
log.Init("info", os.Stderr)
|
||||||
log.Info("loading 01-config.json")
|
log.Infof("loading %s", file)
|
||||||
|
|
||||||
data := doll.LoadJsonFile("test_data/01-config.json")
|
data := doll.LoadJsonFile(file)
|
||||||
|
|
||||||
|
log.Infof("data from %s", file)
|
||||||
|
|
||||||
log.Info("data from 01-config.json is")
|
|
||||||
spew.Dump(data)
|
spew.Dump(data)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -8,20 +8,21 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
file := "example_data/02-test.lua"
|
||||||
log.Init("info", os.Stderr)
|
log.Init("info", os.Stderr)
|
||||||
|
|
||||||
L := lua.NewState()
|
L := lua.NewState()
|
||||||
defer L.Close()
|
defer L.Close()
|
||||||
|
|
||||||
// Load the Lua script file.
|
// Load the Lua script file.
|
||||||
log.Info("Loading ./test_data/02-test.lua")
|
log.Infof("Loading %s", file)
|
||||||
|
|
||||||
// We can execute script directly via L.DoFile("./test_data/02-test.lua") but in practice we'll get scripts as
|
// We can execute script directly via L.DoFile("./example_data/02-test.lua") but in practice we'll get scripts as
|
||||||
// strings - snippets from templates - so, testing/checking how it works is not use for project.
|
// strings - snippets from templates - so, testing/checking how it works is not use for project.
|
||||||
luaCode, err := os.ReadFile("./test_data/02-test.lua")
|
luaCode, err := os.ReadFile(file)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("Error reading Lua file: %s", err)
|
log.Errorf("Error reading Lua file %s: %s", file, err)
|
||||||
|
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
3
go.mod
3
go.mod
@@ -3,7 +3,10 @@ module doll
|
|||||||
go 1.25.3
|
go 1.25.3
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
github.com/carlmjohnson/requests v0.25.1
|
||||||
github.com/davecgh/go-spew v1.1.1
|
github.com/davecgh/go-spew v1.1.1
|
||||||
github.com/hjson/hjson-go/v4 v4.5.0
|
github.com/hjson/hjson-go/v4 v4.5.0
|
||||||
github.com/yuin/gopher-lua v1.1.1
|
github.com/yuin/gopher-lua v1.1.1
|
||||||
)
|
)
|
||||||
|
|
||||||
|
require golang.org/x/net v0.38.0 // indirect
|
||||||
|
|||||||
4
go.sum
4
go.sum
@@ -1,6 +1,10 @@
|
|||||||
|
github.com/carlmjohnson/requests v0.25.1 h1:17zNRLecxtAjhtdEIV+F+wrYfe+AGZUjWJtpndcOUYA=
|
||||||
|
github.com/carlmjohnson/requests v0.25.1/go.mod h1:z3UEf8IE4sZxZ78spW6/tLdqBkfCu1Fn4RaYMnZ8SRM=
|
||||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/hjson/hjson-go/v4 v4.5.0 h1:ZHLiZ+HaGqPOtEe8T6qY8QHnoEsAeBv8wqxniQAp+CY=
|
github.com/hjson/hjson-go/v4 v4.5.0 h1:ZHLiZ+HaGqPOtEe8T6qY8QHnoEsAeBv8wqxniQAp+CY=
|
||||||
github.com/hjson/hjson-go/v4 v4.5.0/go.mod h1:4zx6c7Y0vWcm8IRyVoQJUHAPJLXLvbG6X8nk1RLigSo=
|
github.com/hjson/hjson-go/v4 v4.5.0/go.mod h1:4zx6c7Y0vWcm8IRyVoQJUHAPJLXLvbG6X8nk1RLigSo=
|
||||||
github.com/yuin/gopher-lua v1.1.1 h1:kYKnWBjvbNP4XLT3+bPEwAXJx262OhaHDWDVOPjL46M=
|
github.com/yuin/gopher-lua v1.1.1 h1:kYKnWBjvbNP4XLT3+bPEwAXJx262OhaHDWDVOPjL46M=
|
||||||
github.com/yuin/gopher-lua v1.1.1/go.mod h1:GBR0iDaNXjAgGg9zfCvksxSRnQx76gclCIb7kdAd1Pw=
|
github.com/yuin/gopher-lua v1.1.1/go.mod h1:GBR0iDaNXjAgGg9zfCvksxSRnQx76gclCIb7kdAd1Pw=
|
||||||
|
golang.org/x/net v0.38.0 h1:vRMAPTMaeGqVhG5QyLJHqNDwecKTomGeqbnfZyKlBI8=
|
||||||
|
golang.org/x/net v0.38.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8=
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
package serverSonfig
|
package serverConfig
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
|||||||
1
vendor/github.com/carlmjohnson/requests/.gitignore
generated
vendored
Normal file
1
vendor/github.com/carlmjohnson/requests/.gitignore
generated
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
img/
|
||||||
21
vendor/github.com/carlmjohnson/requests/LICENSE
generated
vendored
Normal file
21
vendor/github.com/carlmjohnson/requests/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2021 Carl Johnson
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
314
vendor/github.com/carlmjohnson/requests/README.md
generated
vendored
Normal file
314
vendor/github.com/carlmjohnson/requests/README.md
generated
vendored
Normal file
@@ -0,0 +1,314 @@
|
|||||||
|
# Requests [](https://godoc.org/github.com/carlmjohnson/requests) [](https://goreportcard.com/report/github.com/carlmjohnson/requests) [](https://coveralls.io/github/earthboundkid/requests) [](https://github.com/avelino/awesome-go)
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
## _HTTP requests for Gophers._
|
||||||
|
|
||||||
|
**The problem**: Go's net/http is powerful and versatile, but using it correctly for client requests can be extremely verbose.
|
||||||
|
|
||||||
|
**The solution**: The requests.Builder type is a convenient way to build, send, and handle HTTP requests. Builder has a fluent API with methods returning a pointer to the same struct, which allows for declaratively describing a request by method chaining.
|
||||||
|
|
||||||
|
Requests also comes with tools for building custom http transports, include a request recorder and replayer for testing.
|
||||||
|
|
||||||
|
*[See this note on the canonical project URL.](https://gist.github.com/earthboundkid/8915002ae0e531cecdfc58bc6453ac80)*
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
- Simplifies HTTP client usage compared to net/http
|
||||||
|
- Can't forget to close response body
|
||||||
|
- Checks status codes by default
|
||||||
|
- Supports context.Context
|
||||||
|
- JSON serialization and deserialization helpers
|
||||||
|
- Easily manipulate URLs and query parameters
|
||||||
|
- Request recording and replaying for tests
|
||||||
|
- Customizable transports and validators that are compatible with the standard library and third party libraries
|
||||||
|
- No third party dependencies
|
||||||
|
- Good test coverage
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
### Simple GET into a string
|
||||||
|
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th><strong>code with net/http</strong></th>
|
||||||
|
<th><strong>code with requests</strong></th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
|
||||||
|
```go
|
||||||
|
req, err := http.NewRequestWithContext(ctx,
|
||||||
|
http.MethodGet, "http://example.com", nil)
|
||||||
|
if err != nil {
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
res, err := http.DefaultClient.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
defer res.Body.Close()
|
||||||
|
b, err := io.ReadAll(res.Body)
|
||||||
|
if err != nil {
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
s := string(b)
|
||||||
|
```
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
|
||||||
|
```go
|
||||||
|
var s string
|
||||||
|
err := requests.
|
||||||
|
URL("http://example.com").
|
||||||
|
ToString(&s).
|
||||||
|
Fetch(ctx)
|
||||||
|
```
|
||||||
|
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr><td>11+ lines</td><td>5 lines</td></tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
|
||||||
|
### POST a raw body
|
||||||
|
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th><strong>code with net/http</strong></th>
|
||||||
|
<th><strong>code with requests</strong></th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
|
||||||
|
```go
|
||||||
|
body := bytes.NewReader(([]byte(`hello, world`))
|
||||||
|
req, err := http.NewRequestWithContext(ctx, http.MethodPost,
|
||||||
|
"https://postman-echo.com/post", body)
|
||||||
|
if err != nil {
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
req.Header.Set("Content-Type", "text/plain")
|
||||||
|
res, err := http.DefaultClient.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
defer res.Body.Close()
|
||||||
|
_, err := io.ReadAll(res.Body)
|
||||||
|
if err != nil {
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
|
||||||
|
```go
|
||||||
|
err := requests.
|
||||||
|
URL("https://postman-echo.com/post").
|
||||||
|
BodyBytes([]byte(`hello, world`)).
|
||||||
|
ContentType("text/plain").
|
||||||
|
Fetch(ctx)
|
||||||
|
```
|
||||||
|
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr><td>12+ lines</td><td>5 lines</td></tr></tbody></table>
|
||||||
|
|
||||||
|
### GET a JSON object
|
||||||
|
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th><strong>code with net/http</strong></th>
|
||||||
|
<th><strong>code with requests</strong></th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
|
||||||
|
```go
|
||||||
|
var post placeholder
|
||||||
|
u, err := url.Parse("https://jsonplaceholder.typicode.com")
|
||||||
|
if err != nil {
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
u.Path = fmt.Sprintf("/posts/%d", 1)
|
||||||
|
req, err := http.NewRequestWithContext(ctx,
|
||||||
|
http.MethodGet, u.String(), nil)
|
||||||
|
if err != nil {
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
res, err := http.DefaultClient.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
defer res.Body.Close()
|
||||||
|
b, err := io.ReadAll(res.Body)
|
||||||
|
if err != nil {
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
err := json.Unmarshal(b, &post)
|
||||||
|
if err != nil {
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
</td><td>
|
||||||
|
|
||||||
|
```go
|
||||||
|
var post placeholder
|
||||||
|
err := requests.
|
||||||
|
URL("https://jsonplaceholder.typicode.com").
|
||||||
|
Pathf("/posts/%d", 1).
|
||||||
|
ToJSON(&post).
|
||||||
|
Fetch(ctx)
|
||||||
|
```
|
||||||
|
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr><td>18+ lines</td><td>7 lines</td></tr></tbody></table>
|
||||||
|
|
||||||
|
### POST a JSON object and parse the response
|
||||||
|
|
||||||
|
```go
|
||||||
|
var res placeholder
|
||||||
|
req := placeholder{
|
||||||
|
Title: "foo",
|
||||||
|
Body: "baz",
|
||||||
|
UserID: 1,
|
||||||
|
}
|
||||||
|
err := requests.
|
||||||
|
URL("/posts").
|
||||||
|
Host("jsonplaceholder.typicode.com").
|
||||||
|
BodyJSON(&req).
|
||||||
|
ToJSON(&res).
|
||||||
|
Fetch(ctx)
|
||||||
|
// net/http equivalent left as an exercise for the reader
|
||||||
|
```
|
||||||
|
|
||||||
|
### Set custom headers for a request
|
||||||
|
|
||||||
|
```go
|
||||||
|
// Set headers
|
||||||
|
var headers postman
|
||||||
|
err := requests.
|
||||||
|
URL("https://postman-echo.com/get").
|
||||||
|
UserAgent("bond/james-bond").
|
||||||
|
ContentType("secret").
|
||||||
|
Header("martini", "shaken").
|
||||||
|
Fetch(ctx)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Easily manipulate URLs and query parameters
|
||||||
|
|
||||||
|
```go
|
||||||
|
u, err := requests.
|
||||||
|
URL("https://prod.example.com/get?a=1&b=2").
|
||||||
|
Hostf("%s.example.com", "dev1").
|
||||||
|
Param("b", "3").
|
||||||
|
ParamInt("c", 4).
|
||||||
|
URL()
|
||||||
|
if err != nil { /* ... */ }
|
||||||
|
fmt.Println(u.String()) // https://dev1.example.com/get?a=1&b=3&c=4
|
||||||
|
```
|
||||||
|
|
||||||
|
### Record and replay responses
|
||||||
|
|
||||||
|
```go
|
||||||
|
// record a request to the file system
|
||||||
|
var s1, s2 string
|
||||||
|
err := requests.URL("http://example.com").
|
||||||
|
Transport(reqtest.Record(nil, "somedir")).
|
||||||
|
ToString(&s1).
|
||||||
|
Fetch(ctx)
|
||||||
|
check(err)
|
||||||
|
|
||||||
|
// now replay the request in tests
|
||||||
|
err = requests.URL("http://example.com").
|
||||||
|
Transport(reqtest.Replay("somedir")).
|
||||||
|
ToString(&s2).
|
||||||
|
Fetch(ctx)
|
||||||
|
check(err)
|
||||||
|
assert(s1 == s2) // true
|
||||||
|
```
|
||||||
|
|
||||||
|
## FAQs
|
||||||
|
|
||||||
|
[See wiki](https://github.com/earthboundkid/requests/wiki) for more details.
|
||||||
|
|
||||||
|
### Why not just use the standard library HTTP client?
|
||||||
|
|
||||||
|
Brad Fitzpatrick, long time maintainer of the net/http package, [wrote an extensive list of problems with the standard library HTTP client](https://github.com/bradfitz/exp-httpclient/blob/master/problems.md). His four main points (ignoring issues that can't be resolved by a wrapper around the standard library) are:
|
||||||
|
|
||||||
|
> - Too easy to not call Response.Body.Close.
|
||||||
|
> - Too easy to not check return status codes
|
||||||
|
> - Context support is oddly bolted on
|
||||||
|
> - Proper usage is too many lines of boilerplate
|
||||||
|
|
||||||
|
Requests solves these issues by always closing the response body, checking status codes by default, always requiring a `context.Context`, and simplifying the boilerplate with a descriptive UI based on fluent method chaining.
|
||||||
|
|
||||||
|
### Why requests and not some other helper library?
|
||||||
|
|
||||||
|
There are two major flaws in other libraries as I see it. One is that in other libraries support for `context.Context` tends to be bolted on if it exists at all. Two, many hide the underlying `http.Client` in such a way that it is difficult or impossible to replace or mock out. Beyond that, I believe that none have achieved the same core simplicity that the requests library has.
|
||||||
|
|
||||||
|
### How do I just get some JSON?
|
||||||
|
|
||||||
|
```go
|
||||||
|
var data SomeDataType
|
||||||
|
err := requests.
|
||||||
|
URL("https://example.com/my-json").
|
||||||
|
ToJSON(&data).
|
||||||
|
Fetch(ctx)
|
||||||
|
```
|
||||||
|
|
||||||
|
### How do I post JSON and read the response JSON?
|
||||||
|
|
||||||
|
```go
|
||||||
|
body := MyRequestType{}
|
||||||
|
var resp MyResponseType
|
||||||
|
err := requests.
|
||||||
|
URL("https://example.com/my-json").
|
||||||
|
BodyJSON(&body).
|
||||||
|
ToJSON(&resp).
|
||||||
|
Fetch(ctx)
|
||||||
|
```
|
||||||
|
|
||||||
|
### How do I just save a file to disk?
|
||||||
|
|
||||||
|
It depends on exactly what you need in terms of file atomicity and buffering, but this will work for most cases:
|
||||||
|
|
||||||
|
```go
|
||||||
|
err := requests.
|
||||||
|
URL("http://example.com").
|
||||||
|
ToFile("myfile.txt").
|
||||||
|
Fetch(ctx)
|
||||||
|
```
|
||||||
|
|
||||||
|
For more advanced use case, use `ToWriter`.
|
||||||
|
|
||||||
|
### How do I save a response to a string?
|
||||||
|
|
||||||
|
```go
|
||||||
|
var s string
|
||||||
|
err := requests.
|
||||||
|
URL("http://example.com").
|
||||||
|
ToString(&s).
|
||||||
|
Fetch(ctx)
|
||||||
|
```
|
||||||
|
|
||||||
|
### How do I validate the response status?
|
||||||
|
|
||||||
|
By default, if no other validators are added to a builder, requests will check that the response is in the 2XX range. If you add another validator, you can add `builder.CheckStatus(200)` or `builder.AddValidator(requests.DefaultValidator)` to the validation stack.
|
||||||
|
|
||||||
|
To disable all response validation, run `builder.AddValidator(nil)`.
|
||||||
|
|
||||||
|
## Contributing
|
||||||
|
|
||||||
|
Please [create a discussion](https://github.com/earthboundkid/requests/discussions) before submitting a pull request for a new feature.
|
||||||
9
vendor/github.com/carlmjohnson/requests/SECURITY.md
generated
vendored
Normal file
9
vendor/github.com/carlmjohnson/requests/SECURITY.md
generated
vendored
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
# Security Policy
|
||||||
|
|
||||||
|
## Supported Versions
|
||||||
|
|
||||||
|
Only the most recently tagged version of this repository is supported.
|
||||||
|
|
||||||
|
## Reporting a Vulnerability
|
||||||
|
|
||||||
|
Email me@carlmjohnson.net with any security concerns or vulnerabilities.
|
||||||
77
vendor/github.com/carlmjohnson/requests/body.go
generated
vendored
Normal file
77
vendor/github.com/carlmjohnson/requests/body.go
generated
vendored
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
package requests
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"io"
|
||||||
|
"net/url"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// BodyGetter provides a Builder with a source for a request body.
|
||||||
|
type BodyGetter = func() (io.ReadCloser, error)
|
||||||
|
|
||||||
|
// BodyReader is a BodyGetter that returns an io.Reader.
|
||||||
|
func BodyReader(r io.Reader) BodyGetter {
|
||||||
|
return func() (io.ReadCloser, error) {
|
||||||
|
if rc, ok := r.(io.ReadCloser); ok {
|
||||||
|
return rc, nil
|
||||||
|
}
|
||||||
|
return rc(r), nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// BodyWriter is a BodyGetter that pipes writes into a request body.
|
||||||
|
func BodyWriter(f func(w io.Writer) error) BodyGetter {
|
||||||
|
return func() (io.ReadCloser, error) {
|
||||||
|
r, w := io.Pipe()
|
||||||
|
go func() {
|
||||||
|
var err error
|
||||||
|
defer func() {
|
||||||
|
w.CloseWithError(err)
|
||||||
|
}()
|
||||||
|
err = f(w)
|
||||||
|
}()
|
||||||
|
return r, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// BodyBytes is a BodyGetter that returns the provided raw bytes.
|
||||||
|
func BodyBytes(b []byte) BodyGetter {
|
||||||
|
return func() (io.ReadCloser, error) {
|
||||||
|
return rc(bytes.NewReader(b)), nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// BodySerializer is a BodyGetter
|
||||||
|
// that uses the provided [Serializer]
|
||||||
|
// to build the body of a request from v.
|
||||||
|
func BodySerializer(s Serializer, v any) BodyGetter {
|
||||||
|
return func() (io.ReadCloser, error) {
|
||||||
|
b, err := s(v)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return rc(bytes.NewReader(b)), nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// BodyJSON is a [BodySerializer]
|
||||||
|
// that uses [JSONSerializer] to marshal the object.
|
||||||
|
func BodyJSON(v any) BodyGetter {
|
||||||
|
return BodySerializer(JSONSerializer, v)
|
||||||
|
}
|
||||||
|
|
||||||
|
// BodyForm is a BodyGetter that builds an encoded form body.
|
||||||
|
func BodyForm(data url.Values) BodyGetter {
|
||||||
|
return func() (r io.ReadCloser, err error) {
|
||||||
|
return rc(strings.NewReader(data.Encode())), nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// BodyFile is a BodyGetter that reads the provided file path.
|
||||||
|
func BodyFile(name string) BodyGetter {
|
||||||
|
return func() (r io.ReadCloser, err error) {
|
||||||
|
return os.Open(name)
|
||||||
|
}
|
||||||
|
}
|
||||||
281
vendor/github.com/carlmjohnson/requests/builder_core.go
generated
vendored
Normal file
281
vendor/github.com/carlmjohnson/requests/builder_core.go
generated
vendored
Normal file
@@ -0,0 +1,281 @@
|
|||||||
|
package requests
|
||||||
|
|
||||||
|
import (
|
||||||
|
"cmp"
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"slices"
|
||||||
|
|
||||||
|
"github.com/carlmjohnson/requests/internal/minitrue"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Builder is a convenient way to build, send, and handle HTTP requests.
|
||||||
|
// Builder has a fluent API with methods returning a pointer to the same
|
||||||
|
// struct, which allows for declaratively describing a request by method chaining.
|
||||||
|
//
|
||||||
|
// Builder can build a url.URL,
|
||||||
|
// build an http.Request,
|
||||||
|
// or handle a full http.Client request and response with validation.
|
||||||
|
//
|
||||||
|
// # Build a url.URL with Builder.URL
|
||||||
|
//
|
||||||
|
// Set the base URL by creating a new Builder with [requests.URL]
|
||||||
|
// or by calling [Builder.BaseURL]
|
||||||
|
// then customize it with
|
||||||
|
// [Builder.Scheme], [Builder.Host], [Builder.Hostf], [Builder.Path],
|
||||||
|
// [Builder.Pathf], [Builder.Param], and [Builder.ParamInt].
|
||||||
|
// [Builder.ParamOptional] can be used to add a query parameter
|
||||||
|
// only if it has not been otherwise set.
|
||||||
|
//
|
||||||
|
// # Build an http.Request with Builder.Request
|
||||||
|
//
|
||||||
|
// Set the method for a request with [Builder.Method]
|
||||||
|
// or use the [Builder.Delete], [Builder.Head], [Builder.Patch], [Builder.Post], and [Builder.Put] methods.
|
||||||
|
// By default, requests without a body are GET,
|
||||||
|
// and those with a body are POST.
|
||||||
|
//
|
||||||
|
// Set headers with [Builder.Header]
|
||||||
|
// or set conventional header keys with
|
||||||
|
// [Builder.Accept], [Builder.BasicAuth], [Builder.Bearer], [Builder.CacheControl],
|
||||||
|
// [Builder.ContentType], [Builder.Cookie], and [Builder.UserAgent].
|
||||||
|
// [Builder.HeaderOptional] can be used to add a header
|
||||||
|
// only if it has not been otherwise set.
|
||||||
|
//
|
||||||
|
// Set the body of the request, if any, with [Builder.Body]
|
||||||
|
// or use built in [Builder.BodyBytes], [Builder.BodyFile], [Builder.BodyForm],
|
||||||
|
// [Builder.BodyJSON], [Builder.BodyReader], or [Builder.BodyWriter].
|
||||||
|
//
|
||||||
|
// # Handle a request and response with Builder.Do or Builder.Fetch
|
||||||
|
//
|
||||||
|
// Set the http.Client to use for a request with [Builder.Client]
|
||||||
|
// and/or set an http.RoundTripper with [Builder.Transport].
|
||||||
|
//
|
||||||
|
// Add a response validator to the Builder with [Builder.AddValidator]
|
||||||
|
// or use the built in [Builder.CheckStatus], [Builder.CheckContentType],
|
||||||
|
// [Builder.CheckPeek], [Builder.CopyHeaders], and [Builder.ErrorJSON].
|
||||||
|
// If no validator has been added, Builder will use [DefaultValidator].
|
||||||
|
//
|
||||||
|
// Set a handler for a response with [Builder.Handle]
|
||||||
|
// or use the built in [Builder.ToHeaders], [Builder.ToJSON], [Builder.ToString],
|
||||||
|
// [Builder.ToBytesBuffer], or [Builder.ToWriter].
|
||||||
|
//
|
||||||
|
// [Builder.Fetch] creates an http.Request with [Builder.Request]
|
||||||
|
// and validates and handles it with [Builder.Do].
|
||||||
|
//
|
||||||
|
// # Other methods
|
||||||
|
//
|
||||||
|
// [Builder.Config] can be used to set several options on a Builder at once.
|
||||||
|
// [New] creates a new Builder and applies [Config] options to it.
|
||||||
|
//
|
||||||
|
// In many cases, it will be possible to set most options for an API endpoint
|
||||||
|
// in a Builder at the package or struct level
|
||||||
|
// and then call [Builder.Clone] in a function
|
||||||
|
// to add request specific details for the URL, parameters, headers, body, or handler.
|
||||||
|
//
|
||||||
|
// Errors returned by Builder methods will have an [ErrorKind] indicating their origin.
|
||||||
|
//
|
||||||
|
// The zero value of Builder is usable.
|
||||||
|
type Builder struct {
|
||||||
|
ub urlBuilder
|
||||||
|
rb requestBuilder
|
||||||
|
cl *http.Client
|
||||||
|
rt http.RoundTripper
|
||||||
|
validators []ResponseHandler
|
||||||
|
handler ResponseHandler
|
||||||
|
}
|
||||||
|
|
||||||
|
// BaseURL sets the base URL that other URL methods modify.
|
||||||
|
// It is usually more convenient to use [URL] instead.
|
||||||
|
func (rb *Builder) BaseURL(baseurl string) *Builder {
|
||||||
|
rb.ub.BaseURL(baseurl)
|
||||||
|
return rb
|
||||||
|
}
|
||||||
|
|
||||||
|
// Scheme sets the scheme for a Builder's URL.
|
||||||
|
// It overrides the scheme set by BaseURL.
|
||||||
|
func (rb *Builder) Scheme(scheme string) *Builder {
|
||||||
|
rb.ub.Scheme(scheme)
|
||||||
|
return rb
|
||||||
|
}
|
||||||
|
|
||||||
|
// Host sets the host for a Builder's URL.
|
||||||
|
// It overrides the host set by BaseURL.
|
||||||
|
func (rb *Builder) Host(host string) *Builder {
|
||||||
|
rb.ub.Host(host)
|
||||||
|
return rb
|
||||||
|
}
|
||||||
|
|
||||||
|
// Path joins a path to a Builder's URL per the path joining rules of RFC 3986.
|
||||||
|
// If the path begins with /, it overrides any existing path.
|
||||||
|
// If the path begins with ./ or ../, the final path will be rewritten in its absolute form when creating a request.
|
||||||
|
func (rb *Builder) Path(path string) *Builder {
|
||||||
|
rb.ub.Path(path)
|
||||||
|
return rb
|
||||||
|
}
|
||||||
|
|
||||||
|
// Param sets a query parameter on a Builder's URL.
|
||||||
|
// It overwrites the existing values of a key.
|
||||||
|
func (rb *Builder) Param(key string, values ...string) *Builder {
|
||||||
|
rb.ub.Param(key, values...)
|
||||||
|
return rb
|
||||||
|
}
|
||||||
|
|
||||||
|
// ParamOptional sets a query parameter on a Builder's URL
|
||||||
|
// only if it is not set by some other call to Param or ParamOptional
|
||||||
|
// and one of the values is a non-blank string.
|
||||||
|
func (rb *Builder) ParamOptional(key string, values ...string) *Builder {
|
||||||
|
rb.ub.ParamOptional(key, values...)
|
||||||
|
return rb
|
||||||
|
}
|
||||||
|
|
||||||
|
// Header sets a header on a request. It overwrites the existing values of a key.
|
||||||
|
func (rb *Builder) Header(key string, values ...string) *Builder {
|
||||||
|
rb.rb.Header(key, values...)
|
||||||
|
return rb
|
||||||
|
}
|
||||||
|
|
||||||
|
// HeaderOptional sets a header on a request
|
||||||
|
// only if it has not already been set by another call to Header or HeaderOptional
|
||||||
|
// and one of the values is a non-blank string.
|
||||||
|
func (rb *Builder) HeaderOptional(key string, values ...string) *Builder {
|
||||||
|
rb.rb.HeaderOptional(key, values...)
|
||||||
|
return rb
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cookie adds a cookie to a request.
|
||||||
|
// Unlike other headers, adding a cookie does not overwrite existing values.
|
||||||
|
func (rb *Builder) Cookie(name, value string) *Builder {
|
||||||
|
rb.rb.Cookie(name, value)
|
||||||
|
return rb
|
||||||
|
}
|
||||||
|
|
||||||
|
// Method sets the HTTP method for a request.
|
||||||
|
// By default, requests without a body are GET,
|
||||||
|
// and those with a body are POST.
|
||||||
|
func (rb *Builder) Method(method string) *Builder {
|
||||||
|
rb.rb.Method(method)
|
||||||
|
return rb
|
||||||
|
}
|
||||||
|
|
||||||
|
// Body sets the BodyGetter to use to build the body of a request.
|
||||||
|
// The provided BodyGetter is used as an http.Request.GetBody func.
|
||||||
|
// It implicitly sets method to POST.
|
||||||
|
func (rb *Builder) Body(src BodyGetter) *Builder {
|
||||||
|
rb.rb.Body(src)
|
||||||
|
return rb
|
||||||
|
}
|
||||||
|
|
||||||
|
// Client sets the http.Client to use for requests. If nil, it uses http.DefaultClient.
|
||||||
|
func (rb *Builder) Client(cl *http.Client) *Builder {
|
||||||
|
rb.cl = cl
|
||||||
|
return rb
|
||||||
|
}
|
||||||
|
|
||||||
|
// Transport sets the http.RoundTripper to use for requests.
|
||||||
|
// If set, it makes a shallow copy of the http.Client before modifying it.
|
||||||
|
func (rb *Builder) Transport(rt http.RoundTripper) *Builder {
|
||||||
|
rb.rt = rt
|
||||||
|
return rb
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddValidator adds a response validator to the Builder.
|
||||||
|
// Adding a validator disables DefaultValidator.
|
||||||
|
// To disable all validation, just add nil.
|
||||||
|
func (rb *Builder) AddValidator(h ResponseHandler) *Builder {
|
||||||
|
rb.validators = append(rb.validators, h)
|
||||||
|
return rb
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle sets the response handler for a Builder.
|
||||||
|
// To use multiple handlers, use ChainHandlers.
|
||||||
|
func (rb *Builder) Handle(h ResponseHandler) *Builder {
|
||||||
|
rb.handler = h
|
||||||
|
return rb
|
||||||
|
}
|
||||||
|
|
||||||
|
// Config allows Builder to be extended by functions that set several options at once.
|
||||||
|
func (rb *Builder) Config(cfgs ...Config) *Builder {
|
||||||
|
for _, cfg := range cfgs {
|
||||||
|
cfg(rb)
|
||||||
|
}
|
||||||
|
return rb
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clone creates a new Builder suitable for independent mutation.
|
||||||
|
func (rb *Builder) Clone() *Builder {
|
||||||
|
rb2 := *rb
|
||||||
|
rb2.ub = *rb.ub.Clone()
|
||||||
|
rb2.rb = *rb.rb.Clone()
|
||||||
|
rb2.validators = slices.Clip(rb2.validators)
|
||||||
|
return &rb2
|
||||||
|
}
|
||||||
|
|
||||||
|
func joinerrs(a, b error) error {
|
||||||
|
return fmt.Errorf("%w: %w", a, b)
|
||||||
|
}
|
||||||
|
|
||||||
|
// URL builds a *url.URL from the base URL and options set on the Builder.
|
||||||
|
// If a valid url.URL cannot be built,
|
||||||
|
// URL() nevertheless returns a new url.URL,
|
||||||
|
// so it is always safe to call u.String().
|
||||||
|
func (rb *Builder) URL() (u *url.URL, err error) {
|
||||||
|
u, err = rb.ub.URL()
|
||||||
|
if err != nil {
|
||||||
|
return u, joinerrs(ErrURL, err)
|
||||||
|
}
|
||||||
|
return u, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Request builds a new http.Request with its context set.
|
||||||
|
func (rb *Builder) Request(ctx context.Context) (req *http.Request, err error) {
|
||||||
|
u, err := rb.URL()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
req, err = rb.rb.Request(ctx, u)
|
||||||
|
if err != nil {
|
||||||
|
return nil, joinerrs(ErrRequest, err)
|
||||||
|
}
|
||||||
|
return req, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Do calls the underlying http.Client and validates and handles any resulting response. The response body is closed after all validators and the handler run.
|
||||||
|
func (rb *Builder) Do(req *http.Request) (err error) {
|
||||||
|
cl := cmp.Or(rb.cl, http.DefaultClient)
|
||||||
|
if rb.rt != nil {
|
||||||
|
cl2 := *cl
|
||||||
|
cl2.Transport = rb.rt
|
||||||
|
cl = &cl2
|
||||||
|
}
|
||||||
|
validators := rb.validators
|
||||||
|
if len(validators) == 0 {
|
||||||
|
validators = []ResponseHandler{DefaultValidator}
|
||||||
|
}
|
||||||
|
h := minitrue.Cond(rb.handler != nil,
|
||||||
|
rb.handler,
|
||||||
|
consumeBody)
|
||||||
|
|
||||||
|
code, err := do(cl, req, validators, h)
|
||||||
|
switch code {
|
||||||
|
case doOK:
|
||||||
|
return nil
|
||||||
|
case doConnect:
|
||||||
|
err = joinerrs(ErrTransport, err)
|
||||||
|
case doValidate:
|
||||||
|
err = joinerrs(ErrValidator, err)
|
||||||
|
case doHandle:
|
||||||
|
err = joinerrs(ErrHandler, err)
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fetch builds a request, sends it, and handles the response.
|
||||||
|
func (rb *Builder) Fetch(ctx context.Context) (err error) {
|
||||||
|
req, err := rb.Request(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return rb.Do(req)
|
||||||
|
}
|
||||||
239
vendor/github.com/carlmjohnson/requests/builder_extras.go
generated
vendored
Normal file
239
vendor/github.com/carlmjohnson/requests/builder_extras.go
generated
vendored
Normal file
@@ -0,0 +1,239 @@
|
|||||||
|
package requests
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/base64"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"strconv"
|
||||||
|
)
|
||||||
|
|
||||||
|
// URL creates a new Builder suitable for method chaining.
|
||||||
|
// It is equivalent to calling BaseURL on an empty Builder.
|
||||||
|
func URL(baseurl string) *Builder {
|
||||||
|
return (&Builder{}).BaseURL(baseurl)
|
||||||
|
}
|
||||||
|
|
||||||
|
// New creates a new Builder suitable for method chaining by applying the specified Configs.
|
||||||
|
// It is equivalent to calling Config on an empty Builder.
|
||||||
|
// The zero value of Builder is usable,
|
||||||
|
// so it is not necessary to call New
|
||||||
|
// when you do not have any Configs to apply.
|
||||||
|
func New(cfgs ...Config) *Builder {
|
||||||
|
return (&Builder{}).Config(cfgs...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Head sets HTTP method to HEAD.
|
||||||
|
func (rb *Builder) Head() *Builder {
|
||||||
|
return rb.Method(http.MethodHead)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Post sets HTTP method to POST.
|
||||||
|
//
|
||||||
|
// Note that setting a Body causes a request to be POST by default.
|
||||||
|
func (rb *Builder) Post() *Builder {
|
||||||
|
return rb.Method(http.MethodPost)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Put sets HTTP method to PUT.
|
||||||
|
func (rb *Builder) Put() *Builder {
|
||||||
|
return rb.Method(http.MethodPut)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Patch sets HTTP method to PATCH.
|
||||||
|
func (rb *Builder) Patch() *Builder {
|
||||||
|
return rb.Method(http.MethodPatch)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete sets HTTP method to DELETE.
|
||||||
|
func (rb *Builder) Delete() *Builder {
|
||||||
|
return rb.Method(http.MethodDelete)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hostf calls Host with fmt.Sprintf.
|
||||||
|
func (rb *Builder) Hostf(format string, a ...any) *Builder {
|
||||||
|
return rb.Host(fmt.Sprintf(format, a...))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pathf calls Path with fmt.Sprintf.
|
||||||
|
//
|
||||||
|
// Note that for security reasons, you must not use %s
|
||||||
|
// with a user provided string!
|
||||||
|
func (rb *Builder) Pathf(format string, a ...any) *Builder {
|
||||||
|
return rb.Path(fmt.Sprintf(format, a...))
|
||||||
|
}
|
||||||
|
|
||||||
|
// ParamInt converts value to a string and calls Param.
|
||||||
|
func (rb *Builder) ParamInt(key string, value int) *Builder {
|
||||||
|
return rb.Param(key, strconv.Itoa(value))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Params calls Param with all the members of m.
|
||||||
|
func (rb *Builder) Params(m map[string][]string) *Builder {
|
||||||
|
for k, vv := range m {
|
||||||
|
rb.Param(k, vv...)
|
||||||
|
}
|
||||||
|
return rb
|
||||||
|
}
|
||||||
|
|
||||||
|
// Headers calls Header with all the members of m.
|
||||||
|
func (rb *Builder) Headers(m map[string][]string) *Builder {
|
||||||
|
for k, vv := range m {
|
||||||
|
rb.Header(k, vv...)
|
||||||
|
}
|
||||||
|
return rb
|
||||||
|
}
|
||||||
|
|
||||||
|
// Accept sets the Accept header for a request.
|
||||||
|
func (rb *Builder) Accept(contentTypes string) *Builder {
|
||||||
|
return rb.Header("Accept", contentTypes)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CacheControl sets the client-side Cache-Control directive for a request.
|
||||||
|
func (rb *Builder) CacheControl(directive string) *Builder {
|
||||||
|
return rb.Header("Cache-Control", directive)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ContentType sets the Content-Type header on a request.
|
||||||
|
func (rb *Builder) ContentType(ct string) *Builder {
|
||||||
|
return rb.Header("Content-Type", ct)
|
||||||
|
}
|
||||||
|
|
||||||
|
// UserAgent sets the User-Agent header.
|
||||||
|
func (rb *Builder) UserAgent(s string) *Builder {
|
||||||
|
return rb.Header("User-Agent", s)
|
||||||
|
}
|
||||||
|
|
||||||
|
// BasicAuth sets the Authorization header to a basic auth credential.
|
||||||
|
func (rb *Builder) BasicAuth(username, password string) *Builder {
|
||||||
|
auth := username + ":" + password
|
||||||
|
v := base64.StdEncoding.EncodeToString([]byte(auth))
|
||||||
|
return rb.Header("Authorization", "Basic "+v)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bearer sets the Authorization header to a bearer token.
|
||||||
|
func (rb *Builder) Bearer(token string) *Builder {
|
||||||
|
return rb.Header("Authorization", "Bearer "+token)
|
||||||
|
}
|
||||||
|
|
||||||
|
// BodyReader sets the Builder's request body to r.
|
||||||
|
func (rb *Builder) BodyReader(r io.Reader) *Builder {
|
||||||
|
return rb.Body(BodyReader(r))
|
||||||
|
}
|
||||||
|
|
||||||
|
// BodyWriter pipes writes from w to the Builder's request body.
|
||||||
|
func (rb *Builder) BodyWriter(f func(w io.Writer) error) *Builder {
|
||||||
|
return rb.Body(BodyWriter(f))
|
||||||
|
}
|
||||||
|
|
||||||
|
// BodyBytes sets the Builder's request body to b.
|
||||||
|
func (rb *Builder) BodyBytes(b []byte) *Builder {
|
||||||
|
return rb.Body(BodyBytes(b))
|
||||||
|
}
|
||||||
|
|
||||||
|
// BodySerializer sets the Builder's request body
|
||||||
|
// to the serialized object.
|
||||||
|
func (rb *Builder) BodySerializer(s Serializer, v any) *Builder {
|
||||||
|
return rb.
|
||||||
|
Body(BodySerializer(s, v))
|
||||||
|
}
|
||||||
|
|
||||||
|
// BodyJSON sets the Builder's request body to the marshaled JSON.
|
||||||
|
// It uses [JSONSerializer] to marshal the object.
|
||||||
|
// It also sets ContentType to "application/json"
|
||||||
|
// if it is not otherwise set.
|
||||||
|
func (rb *Builder) BodyJSON(v any) *Builder {
|
||||||
|
return rb.
|
||||||
|
Body(BodyJSON(v)).
|
||||||
|
HeaderOptional("Content-Type", "application/json")
|
||||||
|
}
|
||||||
|
|
||||||
|
// BodyForm sets the Builder's request body to the encoded form.
|
||||||
|
// It also sets the ContentType to "application/x-www-form-urlencoded".
|
||||||
|
func (rb *Builder) BodyForm(data url.Values) *Builder {
|
||||||
|
return rb.
|
||||||
|
Body(BodyForm(data)).
|
||||||
|
ContentType("application/x-www-form-urlencoded")
|
||||||
|
}
|
||||||
|
|
||||||
|
// BodyFile sets the Builder's request body to read from the given file path.
|
||||||
|
func (rb *Builder) BodyFile(name string) *Builder {
|
||||||
|
return rb.Body(BodyFile(name))
|
||||||
|
}
|
||||||
|
|
||||||
|
// CheckStatus adds a validator for status code of a response.
|
||||||
|
func (rb *Builder) CheckStatus(acceptStatuses ...int) *Builder {
|
||||||
|
return rb.AddValidator(CheckStatus(acceptStatuses...))
|
||||||
|
}
|
||||||
|
|
||||||
|
// CheckContentType adds a validator for the content type header of a response.
|
||||||
|
func (rb *Builder) CheckContentType(cts ...string) *Builder {
|
||||||
|
return rb.AddValidator(CheckContentType(cts...))
|
||||||
|
}
|
||||||
|
|
||||||
|
// CheckPeek adds a validator that peeks at the first n bytes of a response body.
|
||||||
|
func (rb *Builder) CheckPeek(n int, f func([]byte) error) *Builder {
|
||||||
|
return rb.AddValidator(CheckPeek(n, f))
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToDeserializer sets the Builder to decode a response into v
|
||||||
|
// using a [Deserializer].
|
||||||
|
func (rb *Builder) ToDeserializer(d Deserializer, v any) *Builder {
|
||||||
|
return rb.
|
||||||
|
Handle(ToDeserializer(d, v))
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToJSON sets the Builder to decode a response as a JSON object.
|
||||||
|
//
|
||||||
|
// It uses [JSONDeserializer] to unmarshal the object.
|
||||||
|
func (rb *Builder) ToJSON(v any) *Builder {
|
||||||
|
return rb.Handle(ToJSON(v))
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToString sets the Builder to write the response body to the provided string pointer.
|
||||||
|
func (rb *Builder) ToString(sp *string) *Builder {
|
||||||
|
return rb.Handle(ToString(sp))
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToBytesBuffer sets the Builder to write the response body to the provided bytes.Buffer.
|
||||||
|
func (rb *Builder) ToBytesBuffer(buf *bytes.Buffer) *Builder {
|
||||||
|
return rb.Handle(ToBytesBuffer(buf))
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToWriter sets the Builder to copy the response body into w.
|
||||||
|
func (rb *Builder) ToWriter(w io.Writer) *Builder {
|
||||||
|
return rb.Handle(ToWriter(w))
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToFile sets the Builder to write the response body to the given file name.
|
||||||
|
// The file and its parent directories are created automatically.
|
||||||
|
// For more advanced use cases, use ToWriter.
|
||||||
|
func (rb *Builder) ToFile(name string) *Builder {
|
||||||
|
return rb.Handle(ToFile(name))
|
||||||
|
}
|
||||||
|
|
||||||
|
// CopyHeaders adds a validator which copies the response headers to h.
|
||||||
|
// Note that because CopyHeaders adds a validator,
|
||||||
|
// the DefaultValidator is disabled and must be added back manually
|
||||||
|
// if status code validation is desired.
|
||||||
|
func (rb *Builder) CopyHeaders(h map[string][]string) *Builder {
|
||||||
|
return rb.
|
||||||
|
AddValidator(CopyHeaders(h))
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToHeaders sets the method to HEAD and adds a handler which copies the response headers to h.
|
||||||
|
// To just copy headers, see Builder.CopyHeaders.
|
||||||
|
func (rb *Builder) ToHeaders(h map[string][]string) *Builder {
|
||||||
|
return rb.
|
||||||
|
Head().
|
||||||
|
Handle(ChainHandlers(CopyHeaders(h), consumeBody))
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrorJSON adds a validator that applies DefaultValidator
|
||||||
|
// and decodes the response as a JSON object
|
||||||
|
// if the DefaultValidator check fails.
|
||||||
|
func (rb *Builder) ErrorJSON(v any) *Builder {
|
||||||
|
return rb.AddValidator(ErrorJSON(v))
|
||||||
|
}
|
||||||
77
vendor/github.com/carlmjohnson/requests/config.go
generated
vendored
Normal file
77
vendor/github.com/carlmjohnson/requests/config.go
generated
vendored
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
package requests
|
||||||
|
|
||||||
|
import (
|
||||||
|
"compress/gzip"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"mime/multipart"
|
||||||
|
"net/http/httptest"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Config allows Builder to be extended by setting several options at once.
|
||||||
|
// For example, a Config might set a Body and its ContentType.
|
||||||
|
type Config = func(rb *Builder)
|
||||||
|
|
||||||
|
// GzipConfig writes a gzip stream to its request body using a callback.
|
||||||
|
// It also sets the appropriate Content-Encoding header and automatically
|
||||||
|
// closes and the stream when the callback returns.
|
||||||
|
func GzipConfig(level int, h func(gw *gzip.Writer) error) Config {
|
||||||
|
return func(rb *Builder) {
|
||||||
|
rb.
|
||||||
|
Header("Content-Encoding", "gzip").
|
||||||
|
BodyWriter(func(w io.Writer) error {
|
||||||
|
gw, err := gzip.NewWriterLevel(w, level)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err = h(gw); err != nil {
|
||||||
|
gw.Close()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return gw.Close()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestServerConfig returns a Config
|
||||||
|
// which sets the Builder's BaseURL to s.URL
|
||||||
|
// and the Builder's Client to s.Client().
|
||||||
|
//
|
||||||
|
// Deprecated: Use reqtest.Server.
|
||||||
|
func TestServerConfig(s *httptest.Server) Config {
|
||||||
|
return func(rb *Builder) {
|
||||||
|
rb.
|
||||||
|
BaseURL(s.URL).
|
||||||
|
Client(s.Client())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// BodyMultipart returns a Config
|
||||||
|
// that uses a multipart.Writer for the request body.
|
||||||
|
// If boundary is "", a multipart boundary is chosen at random.
|
||||||
|
// The content type of the request is set to multipart/form-data
|
||||||
|
// with the correct boundary.
|
||||||
|
// The multipart.Writer is automatically closed if the callback succeeds.
|
||||||
|
func BodyMultipart(boundary string, h func(multi *multipart.Writer) error) Config {
|
||||||
|
return func(rb *Builder) {
|
||||||
|
if boundary == "" {
|
||||||
|
multi := multipart.NewWriter(nil)
|
||||||
|
boundary = multi.Boundary()
|
||||||
|
}
|
||||||
|
rb.
|
||||||
|
ContentType("multipart/form-data; boundary=" + boundary).
|
||||||
|
BodyWriter(func(w io.Writer) error {
|
||||||
|
multi := multipart.NewWriter(w)
|
||||||
|
if err := multi.SetBoundary(boundary); err != nil {
|
||||||
|
return fmt.Errorf("setting boundary: %w", err)
|
||||||
|
}
|
||||||
|
if err := h(multi); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := multi.Close(); err != nil {
|
||||||
|
return fmt.Errorf("closing multipart writer: %w", err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
18
vendor/github.com/carlmjohnson/requests/cookies.go
generated
vendored
Normal file
18
vendor/github.com/carlmjohnson/requests/cookies.go
generated
vendored
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
package requests
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
"net/http/cookiejar"
|
||||||
|
|
||||||
|
"golang.org/x/net/publicsuffix"
|
||||||
|
)
|
||||||
|
|
||||||
|
// NewCookieJar returns a cookie jar using the standard public suffix list.
|
||||||
|
func NewCookieJar() http.CookieJar {
|
||||||
|
jar, err := cookiejar.New(&cookiejar.Options{PublicSuffixList: publicsuffix.List})
|
||||||
|
// As of Go 1.16, cookiejar.New err is hardcoded nil
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
return jar
|
||||||
|
}
|
||||||
36
vendor/github.com/carlmjohnson/requests/core_do.go
generated
vendored
Normal file
36
vendor/github.com/carlmjohnson/requests/core_do.go
generated
vendored
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
package requests
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
type doResponse int
|
||||||
|
|
||||||
|
const (
|
||||||
|
doOK doResponse = iota
|
||||||
|
doConnect
|
||||||
|
doValidate
|
||||||
|
doHandle
|
||||||
|
)
|
||||||
|
|
||||||
|
func do(cl *http.Client, req *http.Request, validators []ResponseHandler, h ResponseHandler) (doResponse, error) {
|
||||||
|
res, err := cl.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return doConnect, err
|
||||||
|
}
|
||||||
|
defer res.Body.Close()
|
||||||
|
|
||||||
|
for _, v := range validators {
|
||||||
|
if v == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if err = v(res); err != nil {
|
||||||
|
return doValidate, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if err = h(res); err != nil {
|
||||||
|
return doHandle, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return doOK, nil
|
||||||
|
}
|
||||||
106
vendor/github.com/carlmjohnson/requests/core_req.go
generated
vendored
Normal file
106
vendor/github.com/carlmjohnson/requests/core_req.go
generated
vendored
Normal file
@@ -0,0 +1,106 @@
|
|||||||
|
package requests
|
||||||
|
|
||||||
|
import (
|
||||||
|
"cmp"
|
||||||
|
"context"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"slices"
|
||||||
|
|
||||||
|
"github.com/carlmjohnson/requests/internal/minitrue"
|
||||||
|
)
|
||||||
|
|
||||||
|
// nopCloser is like io.NopCloser(),
|
||||||
|
// but it is a concrete type so we can strip it out
|
||||||
|
// before setting a body on a request.
|
||||||
|
// See https://github.com/carlmjohnson/requests/discussions/49
|
||||||
|
type nopCloser struct {
|
||||||
|
io.Reader
|
||||||
|
}
|
||||||
|
|
||||||
|
func rc(r io.Reader) nopCloser {
|
||||||
|
return nopCloser{r}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (nopCloser) Close() error { return nil }
|
||||||
|
|
||||||
|
var _ io.ReadCloser = nopCloser{}
|
||||||
|
|
||||||
|
type requestBuilder struct {
|
||||||
|
headers []multimap
|
||||||
|
cookies []kvpair
|
||||||
|
getBody BodyGetter
|
||||||
|
method string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rb *requestBuilder) Header(key string, values ...string) {
|
||||||
|
rb.headers = append(rb.headers, multimap{key, values, false})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rb *requestBuilder) HeaderOptional(key string, values ...string) {
|
||||||
|
rb.headers = append(rb.headers, multimap{key, values, true})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rb *requestBuilder) Cookie(name, value string) {
|
||||||
|
rb.cookies = append(rb.cookies, kvpair{name, value})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rb *requestBuilder) Method(method string) {
|
||||||
|
rb.method = method
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rb *requestBuilder) Body(src BodyGetter) {
|
||||||
|
rb.getBody = src
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clone creates a new Builder suitable for independent mutation.
|
||||||
|
func (rb *requestBuilder) Clone() *requestBuilder {
|
||||||
|
rb2 := *rb
|
||||||
|
rb2.headers = slices.Clip(rb2.headers)
|
||||||
|
rb2.cookies = slices.Clip(rb2.cookies)
|
||||||
|
return &rb2
|
||||||
|
}
|
||||||
|
|
||||||
|
// Request builds a new http.Request with its context set.
|
||||||
|
func (rb *requestBuilder) Request(ctx context.Context, u *url.URL) (req *http.Request, err error) {
|
||||||
|
var body io.Reader
|
||||||
|
if rb.getBody != nil {
|
||||||
|
if body, err = rb.getBody(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if nopper, ok := body.(nopCloser); ok {
|
||||||
|
body = nopper.Reader
|
||||||
|
}
|
||||||
|
}
|
||||||
|
method := cmp.Or(rb.method,
|
||||||
|
minitrue.Cond(rb.getBody == nil,
|
||||||
|
http.MethodGet,
|
||||||
|
http.MethodPost))
|
||||||
|
|
||||||
|
req, err = http.NewRequestWithContext(ctx, method, u.String(), body)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
req.GetBody = rb.getBody
|
||||||
|
|
||||||
|
for _, kv := range rb.headers {
|
||||||
|
if !kv.optional {
|
||||||
|
req.Header[http.CanonicalHeaderKey(kv.key)] = kv.values
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, kv := range rb.headers {
|
||||||
|
if kv.optional &&
|
||||||
|
req.Header.Get(kv.key) == "" &&
|
||||||
|
cmp.Or(kv.values...) != "" {
|
||||||
|
req.Header[http.CanonicalHeaderKey(kv.key)] = kv.values
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, kv := range rb.cookies {
|
||||||
|
req.AddCookie(&http.Cookie{
|
||||||
|
Name: kv.key,
|
||||||
|
Value: kv.value,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return req, nil
|
||||||
|
}
|
||||||
94
vendor/github.com/carlmjohnson/requests/core_url.go
generated
vendored
Normal file
94
vendor/github.com/carlmjohnson/requests/core_url.go
generated
vendored
Normal file
@@ -0,0 +1,94 @@
|
|||||||
|
package requests
|
||||||
|
|
||||||
|
import (
|
||||||
|
"cmp"
|
||||||
|
"net/url"
|
||||||
|
"slices"
|
||||||
|
)
|
||||||
|
|
||||||
|
type multimap struct {
|
||||||
|
key string
|
||||||
|
values []string
|
||||||
|
optional bool
|
||||||
|
}
|
||||||
|
|
||||||
|
type kvpair struct {
|
||||||
|
key, value string
|
||||||
|
}
|
||||||
|
|
||||||
|
type urlBuilder struct {
|
||||||
|
baseurl string
|
||||||
|
scheme, host string
|
||||||
|
paths []string
|
||||||
|
params []multimap
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ub *urlBuilder) BaseURL(baseurl string) {
|
||||||
|
ub.baseurl = baseurl
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ub *urlBuilder) Scheme(scheme string) {
|
||||||
|
ub.scheme = scheme
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ub *urlBuilder) Host(host string) {
|
||||||
|
ub.host = host
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ub *urlBuilder) Path(path string) {
|
||||||
|
ub.paths = append(ub.paths, path)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ub *urlBuilder) Param(key string, values ...string) {
|
||||||
|
ub.params = append(ub.params, multimap{key, values, false})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ub *urlBuilder) ParamOptional(key string, values ...string) {
|
||||||
|
ub.params = append(ub.params, multimap{key, values, true})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ub *urlBuilder) Clone() *urlBuilder {
|
||||||
|
ub2 := *ub
|
||||||
|
ub2.paths = slices.Clip(ub2.paths)
|
||||||
|
ub2.params = slices.Clip(ub2.params)
|
||||||
|
return &ub2
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ub *urlBuilder) URL() (u *url.URL, err error) {
|
||||||
|
u, err = url.Parse(ub.baseurl)
|
||||||
|
if err != nil {
|
||||||
|
return new(url.URL), err
|
||||||
|
}
|
||||||
|
u.Scheme = cmp.Or(
|
||||||
|
ub.scheme,
|
||||||
|
u.Scheme,
|
||||||
|
"https",
|
||||||
|
)
|
||||||
|
u.Host = cmp.Or(ub.host, u.Host)
|
||||||
|
for _, p := range ub.paths {
|
||||||
|
u.Path = u.ResolveReference(&url.URL{Path: p}).Path
|
||||||
|
}
|
||||||
|
if len(ub.params) > 0 {
|
||||||
|
q := u.Query()
|
||||||
|
for _, kv := range ub.params {
|
||||||
|
if !kv.optional {
|
||||||
|
q[kv.key] = kv.values
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, kv := range ub.params {
|
||||||
|
if kv.optional &&
|
||||||
|
q.Get(kv.key) == "" &&
|
||||||
|
cmp.Or(kv.values...) != "" {
|
||||||
|
q[kv.key] = kv.values
|
||||||
|
}
|
||||||
|
}
|
||||||
|
u.RawQuery = q.Encode()
|
||||||
|
}
|
||||||
|
// Reparsing, in case the path rewriting broke the URL
|
||||||
|
u, err = url.Parse(u.String())
|
||||||
|
if err != nil {
|
||||||
|
return new(url.URL), err
|
||||||
|
}
|
||||||
|
return u, nil
|
||||||
|
}
|
||||||
3
vendor/github.com/carlmjohnson/requests/doc.go
generated
vendored
Normal file
3
vendor/github.com/carlmjohnson/requests/doc.go
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
// Package requests is a convenience wrapper around net/http to make it faster
|
||||||
|
// and easier to build requests and custom transports.
|
||||||
|
package requests
|
||||||
20
vendor/github.com/carlmjohnson/requests/errorkind.go
generated
vendored
Normal file
20
vendor/github.com/carlmjohnson/requests/errorkind.go
generated
vendored
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
package requests
|
||||||
|
|
||||||
|
// ErrorKind indicates where an error was returned in the process of building, validating, and handling a request.
|
||||||
|
// Errors returned by Builder can be tested for their ErrorKind using errors.Is or errors.As.
|
||||||
|
type ErrorKind int8
|
||||||
|
|
||||||
|
//go:generate stringer -type=ErrorKind
|
||||||
|
|
||||||
|
// Enum values for type ErrorKind
|
||||||
|
const (
|
||||||
|
ErrURL ErrorKind = iota // error building URL
|
||||||
|
ErrRequest // error building the request
|
||||||
|
ErrTransport // error connecting
|
||||||
|
ErrValidator // validator error
|
||||||
|
ErrHandler // handler error
|
||||||
|
)
|
||||||
|
|
||||||
|
func (ek ErrorKind) Error() string {
|
||||||
|
return ek.String()
|
||||||
|
}
|
||||||
27
vendor/github.com/carlmjohnson/requests/errorkind_string.go
generated
vendored
Normal file
27
vendor/github.com/carlmjohnson/requests/errorkind_string.go
generated
vendored
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
// Code generated by "stringer -type=ErrorKind"; DO NOT EDIT.
|
||||||
|
|
||||||
|
package requests
|
||||||
|
|
||||||
|
import "strconv"
|
||||||
|
|
||||||
|
func _() {
|
||||||
|
// An "invalid array index" compiler error signifies that the constant values have changed.
|
||||||
|
// Re-run the stringer command to generate them again.
|
||||||
|
var x [1]struct{}
|
||||||
|
_ = x[ErrURL-0]
|
||||||
|
_ = x[ErrRequest-1]
|
||||||
|
_ = x[ErrTransport-2]
|
||||||
|
_ = x[ErrValidator-3]
|
||||||
|
_ = x[ErrHandler-4]
|
||||||
|
}
|
||||||
|
|
||||||
|
const _ErrorKind_name = "ErrURLErrRequestErrTransportErrValidatorErrHandler"
|
||||||
|
|
||||||
|
var _ErrorKind_index = [...]uint8{0, 6, 16, 28, 40, 50}
|
||||||
|
|
||||||
|
func (i ErrorKind) String() string {
|
||||||
|
if i < 0 || i >= ErrorKind(len(_ErrorKind_index)-1) {
|
||||||
|
return "ErrorKind(" + strconv.FormatInt(int64(i), 10) + ")"
|
||||||
|
}
|
||||||
|
return _ErrorKind_name[_ErrorKind_index[i]:_ErrorKind_index[i+1]]
|
||||||
|
}
|
||||||
139
vendor/github.com/carlmjohnson/requests/handler.go
generated
vendored
Normal file
139
vendor/github.com/carlmjohnson/requests/handler.go
generated
vendored
Normal file
@@ -0,0 +1,139 @@
|
|||||||
|
package requests
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"bytes"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"golang.org/x/net/html"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ResponseHandler is used to validate or handle the response to a request.
|
||||||
|
type ResponseHandler = func(*http.Response) error
|
||||||
|
|
||||||
|
// ChainHandlers allows for the composing of validators or response handlers.
|
||||||
|
func ChainHandlers(handlers ...ResponseHandler) ResponseHandler {
|
||||||
|
return func(r *http.Response) error {
|
||||||
|
for _, h := range handlers {
|
||||||
|
if h == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if err := h(r); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func consumeBody(res *http.Response) (err error) {
|
||||||
|
const maxDiscardSize = 640 * 1 << 10
|
||||||
|
if _, err = io.CopyN(io.Discard, res.Body, maxDiscardSize); err == io.EOF {
|
||||||
|
err = nil
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToDeserializer decodes a response into v using a [Deserializer].
|
||||||
|
func ToDeserializer(d Deserializer, v any) ResponseHandler {
|
||||||
|
return func(res *http.Response) error {
|
||||||
|
data, err := io.ReadAll(res.Body)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err = d(data, v); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToJSON decodes a response as a JSON object.
|
||||||
|
//
|
||||||
|
// It uses [JSONDeserializer] to unmarshal the object.
|
||||||
|
func ToJSON(v any) ResponseHandler {
|
||||||
|
return ToDeserializer(JSONDeserializer, v)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToString writes the response body to the provided string pointer.
|
||||||
|
func ToString(sp *string) ResponseHandler {
|
||||||
|
return func(res *http.Response) error {
|
||||||
|
var buf strings.Builder
|
||||||
|
_, err := io.Copy(&buf, res.Body)
|
||||||
|
if err == nil {
|
||||||
|
*sp = buf.String()
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToBytesBuffer writes the response body to the provided bytes.Buffer.
|
||||||
|
func ToBytesBuffer(buf *bytes.Buffer) ResponseHandler {
|
||||||
|
return func(res *http.Response) error {
|
||||||
|
_, err := io.Copy(buf, res.Body)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToBufioReader takes a callback which wraps the response body in a bufio.Reader.
|
||||||
|
func ToBufioReader(f func(r *bufio.Reader) error) ResponseHandler {
|
||||||
|
return func(res *http.Response) error {
|
||||||
|
return f(bufio.NewReader(res.Body))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToBufioScanner takes a callback which wraps the response body in a bufio.Scanner.
|
||||||
|
func ToBufioScanner(f func(r *bufio.Scanner) error) ResponseHandler {
|
||||||
|
return func(res *http.Response) error {
|
||||||
|
return f(bufio.NewScanner(res.Body))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToHTML parses the page with x/net/html.Parse.
|
||||||
|
//
|
||||||
|
// Deprecated: Use reqhtml.To.
|
||||||
|
func ToHTML(n *html.Node) ResponseHandler {
|
||||||
|
return ToBufioReader(func(r *bufio.Reader) error {
|
||||||
|
n2, err := html.Parse(r)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
*n = *n2
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToWriter copies the response body to w.
|
||||||
|
func ToWriter(w io.Writer) ResponseHandler {
|
||||||
|
return ToBufioReader(func(r *bufio.Reader) error {
|
||||||
|
_, err := io.Copy(w, r)
|
||||||
|
|
||||||
|
return err
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToFile writes the response body at the provided file path.
|
||||||
|
// The file and its parent directories are created automatically.
|
||||||
|
func ToFile(name string) ResponseHandler {
|
||||||
|
return func(res *http.Response) error {
|
||||||
|
_ = os.MkdirAll(filepath.Dir(name), 0777)
|
||||||
|
|
||||||
|
f, err := os.Create(name)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
|
||||||
|
_, err = io.Copy(f, res.Body)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToHeaders is an alias for backwards compatibility.
|
||||||
|
//
|
||||||
|
// Deprecated: Use CopyHeaders
|
||||||
|
var ToHeaders = CopyHeaders
|
||||||
9
vendor/github.com/carlmjohnson/requests/internal/minitrue/minitrue.go
generated
vendored
Normal file
9
vendor/github.com/carlmjohnson/requests/internal/minitrue/minitrue.go
generated
vendored
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
// Package minitrue - Whatever the Package holds to be the truth, is truth.
|
||||||
|
package minitrue
|
||||||
|
|
||||||
|
func Cond[T any](val bool, a, b T) T {
|
||||||
|
if val {
|
||||||
|
return a
|
||||||
|
}
|
||||||
|
return b
|
||||||
|
}
|
||||||
131
vendor/github.com/carlmjohnson/requests/recorder.go
generated
vendored
Normal file
131
vendor/github.com/carlmjohnson/requests/recorder.go
generated
vendored
Normal file
@@ -0,0 +1,131 @@
|
|||||||
|
package requests
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"bytes"
|
||||||
|
"crypto/md5"
|
||||||
|
"encoding/base64"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io/fs"
|
||||||
|
"net/http"
|
||||||
|
"net/http/httputil"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Record returns an http.RoundTripper that writes out its
|
||||||
|
// requests and their responses to text files in basepath.
|
||||||
|
// Requests are named according to a hash of their contents.
|
||||||
|
// Responses are named according to the request that made them.
|
||||||
|
//
|
||||||
|
// Deprecated: Use reqtest.Record.
|
||||||
|
func Record(rt http.RoundTripper, basepath string) Transport {
|
||||||
|
if rt == nil {
|
||||||
|
rt = http.DefaultTransport
|
||||||
|
}
|
||||||
|
return RoundTripFunc(func(req *http.Request) (res *http.Response, err error) {
|
||||||
|
defer func() {
|
||||||
|
if err != nil {
|
||||||
|
err = fmt.Errorf("problem while recording transport: %w", err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
_ = os.MkdirAll(basepath, 0755)
|
||||||
|
b, err := httputil.DumpRequest(req, true)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
reqname, resname := buildName(b)
|
||||||
|
name := filepath.Join(basepath, reqname)
|
||||||
|
if err = os.WriteFile(name, b, 0644); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if res, err = rt.RoundTrip(req); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
b, err = httputil.DumpResponse(res, true)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
name = filepath.Join(basepath, resname)
|
||||||
|
if err = os.WriteFile(name, b, 0644); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Replay returns an http.RoundTripper that reads its
|
||||||
|
// responses from text files in basepath.
|
||||||
|
// Responses are looked up according to a hash of the request.
|
||||||
|
//
|
||||||
|
// Deprecated: Use reqtest.Replay.
|
||||||
|
func Replay(basepath string) Transport {
|
||||||
|
return ReplayFS(os.DirFS(basepath))
|
||||||
|
}
|
||||||
|
|
||||||
|
var errNotFound = errors.New("response not found")
|
||||||
|
|
||||||
|
// ReplayFS returns an http.RoundTripper that reads its
|
||||||
|
// responses from text files in the fs.FS.
|
||||||
|
// Responses are looked up according to a hash of the request.
|
||||||
|
// Response file names may optionally be prefixed with comments for better human organization.
|
||||||
|
//
|
||||||
|
// Deprecated: Use reqtest.ReplayFS.
|
||||||
|
func ReplayFS(fsys fs.FS) Transport {
|
||||||
|
return RoundTripFunc(func(req *http.Request) (res *http.Response, err error) {
|
||||||
|
defer func() {
|
||||||
|
if err != nil {
|
||||||
|
err = fmt.Errorf("problem while replaying transport: %w", err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
b, err := httputil.DumpRequest(req, true)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
_, name := buildName(b)
|
||||||
|
glob := "*" + name
|
||||||
|
matches, err := fs.Glob(fsys, glob)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if len(matches) == 0 {
|
||||||
|
return nil, fmt.Errorf("%w: no replay file matches %q", errNotFound, glob)
|
||||||
|
}
|
||||||
|
if len(matches) > 1 {
|
||||||
|
return nil, fmt.Errorf("ambiguous response: multiple replay files match %q", glob)
|
||||||
|
}
|
||||||
|
b, err = fs.ReadFile(fsys, matches[0])
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
r := bufio.NewReader(bytes.NewReader(b))
|
||||||
|
return http.ReadResponse(r, req)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func buildName(b []byte) (reqname, resname string) {
|
||||||
|
h := md5.New()
|
||||||
|
h.Write(b)
|
||||||
|
s := base64.URLEncoding.EncodeToString(h.Sum(nil))
|
||||||
|
return s[:8] + ".req.txt", s[:8] + ".res.txt"
|
||||||
|
}
|
||||||
|
|
||||||
|
// Caching returns an http.RoundTripper that attempts to read its
|
||||||
|
// responses from text files in basepath. If the response is absent,
|
||||||
|
// it caches the result of issuing the request with rt in basepath.
|
||||||
|
// Requests are named according to a hash of their contents.
|
||||||
|
// Responses are named according to the request that made them.
|
||||||
|
//
|
||||||
|
// Deprecated: Use reqtest.Caching.
|
||||||
|
func Caching(rt http.RoundTripper, basepath string) Transport {
|
||||||
|
replay := Replay(basepath).RoundTrip
|
||||||
|
record := Record(rt, basepath).RoundTrip
|
||||||
|
return RoundTripFunc(func(req *http.Request) (res *http.Response, err error) {
|
||||||
|
res, err = replay(req)
|
||||||
|
if errors.Is(err, errNotFound) {
|
||||||
|
res, err = record(req)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
})
|
||||||
|
}
|
||||||
19
vendor/github.com/carlmjohnson/requests/redirects.go
generated
vendored
Normal file
19
vendor/github.com/carlmjohnson/requests/redirects.go
generated
vendored
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
package requests
|
||||||
|
|
||||||
|
import "net/http"
|
||||||
|
|
||||||
|
// CheckRedirectPolicy is a function suitable for use as CheckRedirect on an http.Client.
|
||||||
|
type CheckRedirectPolicy = func(req *http.Request, via []*http.Request) error
|
||||||
|
|
||||||
|
// MaxFollow returns a CheckRedirectPolicy that follows a maximum of n redirects.
|
||||||
|
func MaxFollow(n int) CheckRedirectPolicy {
|
||||||
|
return func(req *http.Request, via []*http.Request) error {
|
||||||
|
if len(via) > n {
|
||||||
|
return http.ErrUseLastResponse
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NoFollow is a CheckRedirectPolicy that does not follow redirects.
|
||||||
|
var NoFollow CheckRedirectPolicy = MaxFollow(0)
|
||||||
24
vendor/github.com/carlmjohnson/requests/serializer.go
generated
vendored
Normal file
24
vendor/github.com/carlmjohnson/requests/serializer.go
generated
vendored
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
package requests
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Serializer is a function
|
||||||
|
// that can convert arbitrary data
|
||||||
|
// to bytes in some format.
|
||||||
|
type Serializer = func(v any) ([]byte, error)
|
||||||
|
|
||||||
|
// Deserializer is a function
|
||||||
|
// that can read data in some format
|
||||||
|
// and store the result in v.
|
||||||
|
type Deserializer = func(data []byte, v any) error
|
||||||
|
|
||||||
|
var (
|
||||||
|
// JSONSerializer is used by BodyJSON and Builder.BodyJSON.
|
||||||
|
// The default serializer may be changed in a future version of requests.
|
||||||
|
JSONSerializer Serializer = json.Marshal
|
||||||
|
// JSONDeserializer is used by ToJSON and Builder.ToJSON.
|
||||||
|
// The default deserializer may be changed in a future version of requests.
|
||||||
|
JSONDeserializer Deserializer = json.Unmarshal
|
||||||
|
)
|
||||||
128
vendor/github.com/carlmjohnson/requests/transport.go
generated
vendored
Normal file
128
vendor/github.com/carlmjohnson/requests/transport.go
generated
vendored
Normal file
@@ -0,0 +1,128 @@
|
|||||||
|
package requests
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"regexp"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Transport is an alias of http.RoundTripper for documentation purposes.
|
||||||
|
type Transport = http.RoundTripper
|
||||||
|
|
||||||
|
// RoundTripFunc is an adaptor to use a function as an http.RoundTripper.
|
||||||
|
type RoundTripFunc func(req *http.Request) (res *http.Response, err error)
|
||||||
|
|
||||||
|
// RoundTrip implements http.RoundTripper.
|
||||||
|
func (rtf RoundTripFunc) RoundTrip(r *http.Request) (*http.Response, error) {
|
||||||
|
return rtf(r)
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ Transport = RoundTripFunc(nil)
|
||||||
|
|
||||||
|
// ReplayString returns an http.RoundTripper that always responds with a
|
||||||
|
// request built from rawResponse. It is intended for use in one-off tests.
|
||||||
|
//
|
||||||
|
// Deprecated: Use reqtest.ReplayString.
|
||||||
|
func ReplayString(rawResponse string) Transport {
|
||||||
|
return RoundTripFunc(func(req *http.Request) (res *http.Response, err error) {
|
||||||
|
r := bufio.NewReader(strings.NewReader(rawResponse))
|
||||||
|
res, err = http.ReadResponse(r, req)
|
||||||
|
return
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// UserAgentTransport returns a wrapped http.RoundTripper that sets the User-Agent header on requests to s.
|
||||||
|
func UserAgentTransport(rt http.RoundTripper, s string) Transport {
|
||||||
|
if rt == nil {
|
||||||
|
rt = http.DefaultTransport
|
||||||
|
}
|
||||||
|
return RoundTripFunc(func(req *http.Request) (res *http.Response, err error) {
|
||||||
|
r2 := *req
|
||||||
|
r2.Header = r2.Header.Clone()
|
||||||
|
r2.Header.Set("User-Agent", s)
|
||||||
|
return rt.RoundTrip(&r2)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// PermitURLTransport returns a wrapped http.RoundTripper that rejects any requests whose URL doesn't match the provided regular expression string.
|
||||||
|
//
|
||||||
|
// PermitURLTransport will panic if the regexp does not compile.
|
||||||
|
func PermitURLTransport(rt http.RoundTripper, regex string) Transport {
|
||||||
|
if rt == nil {
|
||||||
|
rt = http.DefaultTransport
|
||||||
|
}
|
||||||
|
re := regexp.MustCompile(regex)
|
||||||
|
reErr := fmt.Errorf("requested URL not permitted by regexp: %s", regex)
|
||||||
|
return RoundTripFunc(func(req *http.Request) (res *http.Response, err error) {
|
||||||
|
if u := req.URL.String(); !re.MatchString(u) {
|
||||||
|
return nil, reErr
|
||||||
|
}
|
||||||
|
return rt.RoundTrip(req)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// LogTransport returns a wrapped http.RoundTripper
|
||||||
|
// that calls fn with details when a response has finished.
|
||||||
|
// A response is considered finished
|
||||||
|
// when the wrapper http.RoundTripper returns an error
|
||||||
|
// or the Response.Body is closed,
|
||||||
|
// whichever comes first.
|
||||||
|
// To simplify logging code,
|
||||||
|
// a nil *http.Response is replaced with a new http.Response.
|
||||||
|
func LogTransport(rt http.RoundTripper, fn func(req *http.Request, res *http.Response, err error, duration time.Duration)) Transport {
|
||||||
|
if rt == nil {
|
||||||
|
rt = http.DefaultTransport
|
||||||
|
}
|
||||||
|
return RoundTripFunc(func(req *http.Request) (res *http.Response, err error) {
|
||||||
|
start := time.Now()
|
||||||
|
res, err = rt.RoundTrip(req)
|
||||||
|
if err != nil {
|
||||||
|
res2 := res
|
||||||
|
if res == nil {
|
||||||
|
res2 = new(http.Response)
|
||||||
|
}
|
||||||
|
fn(req, res2, err, time.Since(start))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
res.Body = closeLogger{res.Body, func() {
|
||||||
|
fn(req, res, err, time.Since(start))
|
||||||
|
}}
|
||||||
|
return
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
type closeLogger struct {
|
||||||
|
io.ReadCloser
|
||||||
|
fn func()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cl closeLogger) Close() error {
|
||||||
|
cl.fn()
|
||||||
|
return cl.ReadCloser.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
// DoerTransport converts a Doer into a Transport.
|
||||||
|
// It exists for compatibility with other libraries.
|
||||||
|
// A Doer is an interface with a Do method.
|
||||||
|
// Users should prefer Transport,
|
||||||
|
// because Do is the interface of http.Client
|
||||||
|
// which has higher level concerns.
|
||||||
|
func DoerTransport(cl interface {
|
||||||
|
Do(req *http.Request) (*http.Response, error)
|
||||||
|
}) Transport {
|
||||||
|
return RoundTripFunc(cl.Do)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrorTransport always returns the specified error instead of connecting.
|
||||||
|
// It is intended for use in testing
|
||||||
|
// or to prevent accidental use of http.DefaultClient.
|
||||||
|
func ErrorTransport(err error) Transport {
|
||||||
|
return RoundTripFunc(func(req *http.Request) (*http.Response, error) {
|
||||||
|
return nil, err
|
||||||
|
})
|
||||||
|
}
|
||||||
102
vendor/github.com/carlmjohnson/requests/validator.go
generated
vendored
Normal file
102
vendor/github.com/carlmjohnson/requests/validator.go
generated
vendored
Normal file
@@ -0,0 +1,102 @@
|
|||||||
|
package requests
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"maps"
|
||||||
|
"mime"
|
||||||
|
"net/http"
|
||||||
|
"slices"
|
||||||
|
)
|
||||||
|
|
||||||
|
// DefaultValidator is the validator applied by Builder unless otherwise specified.
|
||||||
|
var DefaultValidator ResponseHandler = CheckStatus(
|
||||||
|
http.StatusOK,
|
||||||
|
http.StatusCreated,
|
||||||
|
http.StatusAccepted,
|
||||||
|
http.StatusNonAuthoritativeInfo,
|
||||||
|
http.StatusNoContent,
|
||||||
|
)
|
||||||
|
|
||||||
|
// ResponseError is the error type produced by CheckStatus and CheckContentType.
|
||||||
|
type ResponseError http.Response
|
||||||
|
|
||||||
|
// Error fulfills the error interface.
|
||||||
|
func (se *ResponseError) Error() string {
|
||||||
|
return fmt.Sprintf("response error for %s", se.Request.URL.Redacted())
|
||||||
|
}
|
||||||
|
|
||||||
|
// CheckStatus validates the response has an acceptable status code.
|
||||||
|
func CheckStatus(acceptStatuses ...int) ResponseHandler {
|
||||||
|
return func(res *http.Response) error {
|
||||||
|
if slices.Contains(acceptStatuses, res.StatusCode) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return fmt.Errorf("%w: unexpected status: %d",
|
||||||
|
(*ResponseError)(res), res.StatusCode)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// HasStatusErr returns true if err is a ResponseError caused by any of the codes given.
|
||||||
|
func HasStatusErr(err error, codes ...int) bool {
|
||||||
|
if err == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if se := new(ResponseError); errors.As(err, &se) {
|
||||||
|
return slices.Contains(codes, se.StatusCode)
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// CheckContentType validates that a response has one of the given content type headers.
|
||||||
|
func CheckContentType(cts ...string) ResponseHandler {
|
||||||
|
return func(res *http.Response) error {
|
||||||
|
mt, _, err := mime.ParseMediaType(res.Header.Get("Content-Type"))
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("%w: problem matching Content-Type",
|
||||||
|
(*ResponseError)(res))
|
||||||
|
}
|
||||||
|
if slices.Contains(cts, mt) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return fmt.Errorf("%w: unexpected Content-Type: %s",
|
||||||
|
(*ResponseError)(res), mt)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type bufioCloser struct {
|
||||||
|
*bufio.Reader
|
||||||
|
io.Closer
|
||||||
|
}
|
||||||
|
|
||||||
|
// CheckPeek wraps the body of a response in a bufio.Reader and
|
||||||
|
// gives f a peek at the first n bytes for validation.
|
||||||
|
func CheckPeek(n int, f func([]byte) error) ResponseHandler {
|
||||||
|
return func(res *http.Response) error {
|
||||||
|
// ensure buffer is at least minimum size
|
||||||
|
buf := bufio.NewReader(res.Body)
|
||||||
|
// ensure large peeks will fit in the buffer
|
||||||
|
buf = bufio.NewReaderSize(buf, n)
|
||||||
|
res.Body = &bufioCloser{
|
||||||
|
buf,
|
||||||
|
res.Body,
|
||||||
|
}
|
||||||
|
b, err := buf.Peek(n)
|
||||||
|
if err != nil && err != io.EOF {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return f(b)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// CopyHeaders copies the response headers to h.
|
||||||
|
func CopyHeaders(h map[string][]string) ResponseHandler {
|
||||||
|
return func(res *http.Response) error {
|
||||||
|
maps.Copy(h, res.Header)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
34
vendor/github.com/carlmjohnson/requests/validator_handler.go
generated
vendored
Normal file
34
vendor/github.com/carlmjohnson/requests/validator_handler.go
generated
vendored
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
package requests
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ValidatorHandler composes a Validator and a Handler.
|
||||||
|
// If the validation check fails, it triggers the handler.
|
||||||
|
// Any errors from validator or handler will be joined to the error returned.
|
||||||
|
// If the handler succeeds, the error will matching ErrInvalidHandled.
|
||||||
|
func ValidatorHandler(v, h ResponseHandler) ResponseHandler {
|
||||||
|
return func(res *http.Response) error {
|
||||||
|
err1 := v(res)
|
||||||
|
if err1 == nil { // passes validation
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
err2 := h(res)
|
||||||
|
if err2 == nil { // successfully handled
|
||||||
|
return fmt.Errorf("%w: %w", ErrInvalidHandled, err1)
|
||||||
|
}
|
||||||
|
return errors.Join(err1, err2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var ErrInvalidHandled = errors.New("handled recovery from invalid response")
|
||||||
|
|
||||||
|
// ErrorJSON is a ValidatorHandler that applies DefaultValidator
|
||||||
|
// and decodes the response as a JSON object
|
||||||
|
// if the DefaultValidator check fails.
|
||||||
|
func ErrorJSON(v any) ResponseHandler {
|
||||||
|
return ValidatorHandler(DefaultValidator, ToJSON(v))
|
||||||
|
}
|
||||||
27
vendor/golang.org/x/net/LICENSE
generated
vendored
Normal file
27
vendor/golang.org/x/net/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
Copyright 2009 The Go Authors.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are
|
||||||
|
met:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
* Redistributions in binary form must reproduce the above
|
||||||
|
copyright notice, this list of conditions and the following disclaimer
|
||||||
|
in the documentation and/or other materials provided with the
|
||||||
|
distribution.
|
||||||
|
* Neither the name of Google LLC nor the names of its
|
||||||
|
contributors may be used to endorse or promote products derived from
|
||||||
|
this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
22
vendor/golang.org/x/net/PATENTS
generated
vendored
Normal file
22
vendor/golang.org/x/net/PATENTS
generated
vendored
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
Additional IP Rights Grant (Patents)
|
||||||
|
|
||||||
|
"This implementation" means the copyrightable works distributed by
|
||||||
|
Google as part of the Go project.
|
||||||
|
|
||||||
|
Google hereby grants to You a perpetual, worldwide, non-exclusive,
|
||||||
|
no-charge, royalty-free, irrevocable (except as stated in this section)
|
||||||
|
patent license to make, have made, use, offer to sell, sell, import,
|
||||||
|
transfer and otherwise run, modify and propagate the contents of this
|
||||||
|
implementation of Go, where such license applies only to those patent
|
||||||
|
claims, both currently owned or controlled by Google and acquired in
|
||||||
|
the future, licensable by Google that are necessarily infringed by this
|
||||||
|
implementation of Go. This grant does not include claims that would be
|
||||||
|
infringed only as a consequence of further modification of this
|
||||||
|
implementation. If you or your agent or exclusive licensee institute or
|
||||||
|
order or agree to the institution of patent litigation against any
|
||||||
|
entity (including a cross-claim or counterclaim in a lawsuit) alleging
|
||||||
|
that this implementation of Go or any code incorporated within this
|
||||||
|
implementation of Go constitutes direct or contributory patent
|
||||||
|
infringement, or inducement of patent infringement, then any patent
|
||||||
|
rights granted to you under this License for this implementation of Go
|
||||||
|
shall terminate as of the date such litigation is filed.
|
||||||
78
vendor/golang.org/x/net/html/atom/atom.go
generated
vendored
Normal file
78
vendor/golang.org/x/net/html/atom/atom.go
generated
vendored
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
// Copyright 2012 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// Package atom provides integer codes (also known as atoms) for a fixed set of
|
||||||
|
// frequently occurring HTML strings: tag names and attribute keys such as "p"
|
||||||
|
// and "id".
|
||||||
|
//
|
||||||
|
// Sharing an atom's name between all elements with the same tag can result in
|
||||||
|
// fewer string allocations when tokenizing and parsing HTML. Integer
|
||||||
|
// comparisons are also generally faster than string comparisons.
|
||||||
|
//
|
||||||
|
// The value of an atom's particular code is not guaranteed to stay the same
|
||||||
|
// between versions of this package. Neither is any ordering guaranteed:
|
||||||
|
// whether atom.H1 < atom.H2 may also change. The codes are not guaranteed to
|
||||||
|
// be dense. The only guarantees are that e.g. looking up "div" will yield
|
||||||
|
// atom.Div, calling atom.Div.String will return "div", and atom.Div != 0.
|
||||||
|
package atom // import "golang.org/x/net/html/atom"
|
||||||
|
|
||||||
|
// Atom is an integer code for a string. The zero value maps to "".
|
||||||
|
type Atom uint32
|
||||||
|
|
||||||
|
// String returns the atom's name.
|
||||||
|
func (a Atom) String() string {
|
||||||
|
start := uint32(a >> 8)
|
||||||
|
n := uint32(a & 0xff)
|
||||||
|
if start+n > uint32(len(atomText)) {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return atomText[start : start+n]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a Atom) string() string {
|
||||||
|
return atomText[a>>8 : a>>8+a&0xff]
|
||||||
|
}
|
||||||
|
|
||||||
|
// fnv computes the FNV hash with an arbitrary starting value h.
|
||||||
|
func fnv(h uint32, s []byte) uint32 {
|
||||||
|
for i := range s {
|
||||||
|
h ^= uint32(s[i])
|
||||||
|
h *= 16777619
|
||||||
|
}
|
||||||
|
return h
|
||||||
|
}
|
||||||
|
|
||||||
|
func match(s string, t []byte) bool {
|
||||||
|
for i, c := range t {
|
||||||
|
if s[i] != c {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Lookup returns the atom whose name is s. It returns zero if there is no
|
||||||
|
// such atom. The lookup is case sensitive.
|
||||||
|
func Lookup(s []byte) Atom {
|
||||||
|
if len(s) == 0 || len(s) > maxAtomLen {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
h := fnv(hash0, s)
|
||||||
|
if a := table[h&uint32(len(table)-1)]; int(a&0xff) == len(s) && match(a.string(), s) {
|
||||||
|
return a
|
||||||
|
}
|
||||||
|
if a := table[(h>>16)&uint32(len(table)-1)]; int(a&0xff) == len(s) && match(a.string(), s) {
|
||||||
|
return a
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// String returns a string whose contents are equal to s. In that sense, it is
|
||||||
|
// equivalent to string(s) but may be more efficient.
|
||||||
|
func String(s []byte) string {
|
||||||
|
if a := Lookup(s); a != 0 {
|
||||||
|
return a.String()
|
||||||
|
}
|
||||||
|
return string(s)
|
||||||
|
}
|
||||||
785
vendor/golang.org/x/net/html/atom/table.go
generated
vendored
Normal file
785
vendor/golang.org/x/net/html/atom/table.go
generated
vendored
Normal file
@@ -0,0 +1,785 @@
|
|||||||
|
// Code generated by go generate gen.go; DO NOT EDIT.
|
||||||
|
|
||||||
|
//go:generate go run gen.go
|
||||||
|
|
||||||
|
package atom
|
||||||
|
|
||||||
|
const (
|
||||||
|
A Atom = 0x1
|
||||||
|
Abbr Atom = 0x4
|
||||||
|
Accept Atom = 0x1a06
|
||||||
|
AcceptCharset Atom = 0x1a0e
|
||||||
|
Accesskey Atom = 0x2c09
|
||||||
|
Acronym Atom = 0xaa07
|
||||||
|
Action Atom = 0x26506
|
||||||
|
Address Atom = 0x6f107
|
||||||
|
Align Atom = 0xb105
|
||||||
|
Allowfullscreen Atom = 0x3280f
|
||||||
|
Allowpaymentrequest Atom = 0xc113
|
||||||
|
Allowusermedia Atom = 0xdd0e
|
||||||
|
Alt Atom = 0xf303
|
||||||
|
Annotation Atom = 0x1c90a
|
||||||
|
AnnotationXml Atom = 0x1c90e
|
||||||
|
Applet Atom = 0x30806
|
||||||
|
Area Atom = 0x35004
|
||||||
|
Article Atom = 0x3f607
|
||||||
|
As Atom = 0x3c02
|
||||||
|
Aside Atom = 0x10705
|
||||||
|
Async Atom = 0xff05
|
||||||
|
Audio Atom = 0x11505
|
||||||
|
Autocomplete Atom = 0x26b0c
|
||||||
|
Autofocus Atom = 0x12109
|
||||||
|
Autoplay Atom = 0x13c08
|
||||||
|
B Atom = 0x101
|
||||||
|
Base Atom = 0x3b04
|
||||||
|
Basefont Atom = 0x3b08
|
||||||
|
Bdi Atom = 0xba03
|
||||||
|
Bdo Atom = 0x14b03
|
||||||
|
Bgsound Atom = 0x15e07
|
||||||
|
Big Atom = 0x17003
|
||||||
|
Blink Atom = 0x17305
|
||||||
|
Blockquote Atom = 0x1870a
|
||||||
|
Body Atom = 0x2804
|
||||||
|
Br Atom = 0x202
|
||||||
|
Button Atom = 0x19106
|
||||||
|
Canvas Atom = 0x10306
|
||||||
|
Caption Atom = 0x22407
|
||||||
|
Center Atom = 0x21306
|
||||||
|
Challenge Atom = 0x28e09
|
||||||
|
Charset Atom = 0x2107
|
||||||
|
Checked Atom = 0x5b507
|
||||||
|
Cite Atom = 0x19c04
|
||||||
|
Class Atom = 0x55805
|
||||||
|
Code Atom = 0x5ee04
|
||||||
|
Col Atom = 0x1ab03
|
||||||
|
Colgroup Atom = 0x1ab08
|
||||||
|
Color Atom = 0x1bf05
|
||||||
|
Cols Atom = 0x1c404
|
||||||
|
Colspan Atom = 0x1c407
|
||||||
|
Command Atom = 0x1d707
|
||||||
|
Content Atom = 0x57b07
|
||||||
|
Contenteditable Atom = 0x57b0f
|
||||||
|
Contextmenu Atom = 0x37a0b
|
||||||
|
Controls Atom = 0x1de08
|
||||||
|
Coords Atom = 0x1f006
|
||||||
|
Crossorigin Atom = 0x1fa0b
|
||||||
|
Data Atom = 0x49904
|
||||||
|
Datalist Atom = 0x49908
|
||||||
|
Datetime Atom = 0x2ab08
|
||||||
|
Dd Atom = 0x2bf02
|
||||||
|
Default Atom = 0x10a07
|
||||||
|
Defer Atom = 0x5f005
|
||||||
|
Del Atom = 0x44c03
|
||||||
|
Desc Atom = 0x55504
|
||||||
|
Details Atom = 0x7207
|
||||||
|
Dfn Atom = 0x8703
|
||||||
|
Dialog Atom = 0xbb06
|
||||||
|
Dir Atom = 0x9303
|
||||||
|
Dirname Atom = 0x9307
|
||||||
|
Disabled Atom = 0x16408
|
||||||
|
Div Atom = 0x16b03
|
||||||
|
Dl Atom = 0x5d602
|
||||||
|
Download Atom = 0x45d08
|
||||||
|
Draggable Atom = 0x17a09
|
||||||
|
Dropzone Atom = 0x3ff08
|
||||||
|
Dt Atom = 0x64002
|
||||||
|
Em Atom = 0x6e02
|
||||||
|
Embed Atom = 0x6e05
|
||||||
|
Enctype Atom = 0x28007
|
||||||
|
Face Atom = 0x21104
|
||||||
|
Fieldset Atom = 0x21908
|
||||||
|
Figcaption Atom = 0x2210a
|
||||||
|
Figure Atom = 0x23b06
|
||||||
|
Font Atom = 0x3f04
|
||||||
|
Footer Atom = 0xf606
|
||||||
|
For Atom = 0x24703
|
||||||
|
ForeignObject Atom = 0x2470d
|
||||||
|
Foreignobject Atom = 0x2540d
|
||||||
|
Form Atom = 0x26104
|
||||||
|
Formaction Atom = 0x2610a
|
||||||
|
Formenctype Atom = 0x27c0b
|
||||||
|
Formmethod Atom = 0x2970a
|
||||||
|
Formnovalidate Atom = 0x2a10e
|
||||||
|
Formtarget Atom = 0x2b30a
|
||||||
|
Frame Atom = 0x8b05
|
||||||
|
Frameset Atom = 0x8b08
|
||||||
|
H1 Atom = 0x15c02
|
||||||
|
H2 Atom = 0x56102
|
||||||
|
H3 Atom = 0x2cd02
|
||||||
|
H4 Atom = 0x2fc02
|
||||||
|
H5 Atom = 0x33f02
|
||||||
|
H6 Atom = 0x34902
|
||||||
|
Head Atom = 0x32004
|
||||||
|
Header Atom = 0x32006
|
||||||
|
Headers Atom = 0x32007
|
||||||
|
Height Atom = 0x5206
|
||||||
|
Hgroup Atom = 0x64206
|
||||||
|
Hidden Atom = 0x2bd06
|
||||||
|
High Atom = 0x2ca04
|
||||||
|
Hr Atom = 0x15702
|
||||||
|
Href Atom = 0x2cf04
|
||||||
|
Hreflang Atom = 0x2cf08
|
||||||
|
Html Atom = 0x5604
|
||||||
|
HttpEquiv Atom = 0x2d70a
|
||||||
|
I Atom = 0x601
|
||||||
|
Icon Atom = 0x57a04
|
||||||
|
Id Atom = 0x10902
|
||||||
|
Iframe Atom = 0x2eb06
|
||||||
|
Image Atom = 0x2f105
|
||||||
|
Img Atom = 0x2f603
|
||||||
|
Input Atom = 0x44505
|
||||||
|
Inputmode Atom = 0x44509
|
||||||
|
Ins Atom = 0x20303
|
||||||
|
Integrity Atom = 0x23209
|
||||||
|
Is Atom = 0x16502
|
||||||
|
Isindex Atom = 0x2fe07
|
||||||
|
Ismap Atom = 0x30505
|
||||||
|
Itemid Atom = 0x38506
|
||||||
|
Itemprop Atom = 0x19d08
|
||||||
|
Itemref Atom = 0x3c707
|
||||||
|
Itemscope Atom = 0x66f09
|
||||||
|
Itemtype Atom = 0x30e08
|
||||||
|
Kbd Atom = 0xb903
|
||||||
|
Keygen Atom = 0x3206
|
||||||
|
Keytype Atom = 0xd607
|
||||||
|
Kind Atom = 0x17704
|
||||||
|
Label Atom = 0x5905
|
||||||
|
Lang Atom = 0x2d304
|
||||||
|
Legend Atom = 0x18106
|
||||||
|
Li Atom = 0xb202
|
||||||
|
Link Atom = 0x17404
|
||||||
|
List Atom = 0x49d04
|
||||||
|
Listing Atom = 0x49d07
|
||||||
|
Loop Atom = 0x5d04
|
||||||
|
Low Atom = 0xc303
|
||||||
|
Main Atom = 0x1004
|
||||||
|
Malignmark Atom = 0xb00a
|
||||||
|
Manifest Atom = 0x6d508
|
||||||
|
Map Atom = 0x30703
|
||||||
|
Mark Atom = 0xb604
|
||||||
|
Marquee Atom = 0x31607
|
||||||
|
Math Atom = 0x31d04
|
||||||
|
Max Atom = 0x33703
|
||||||
|
Maxlength Atom = 0x33709
|
||||||
|
Media Atom = 0xe605
|
||||||
|
Mediagroup Atom = 0xe60a
|
||||||
|
Menu Atom = 0x38104
|
||||||
|
Menuitem Atom = 0x38108
|
||||||
|
Meta Atom = 0x4ac04
|
||||||
|
Meter Atom = 0x9805
|
||||||
|
Method Atom = 0x29b06
|
||||||
|
Mglyph Atom = 0x2f706
|
||||||
|
Mi Atom = 0x34102
|
||||||
|
Min Atom = 0x34103
|
||||||
|
Minlength Atom = 0x34109
|
||||||
|
Mn Atom = 0x2a402
|
||||||
|
Mo Atom = 0xa402
|
||||||
|
Ms Atom = 0x67202
|
||||||
|
Mtext Atom = 0x34b05
|
||||||
|
Multiple Atom = 0x35908
|
||||||
|
Muted Atom = 0x36105
|
||||||
|
Name Atom = 0x9604
|
||||||
|
Nav Atom = 0x1303
|
||||||
|
Nobr Atom = 0x3704
|
||||||
|
Noembed Atom = 0x6c07
|
||||||
|
Noframes Atom = 0x8908
|
||||||
|
Nomodule Atom = 0xa208
|
||||||
|
Nonce Atom = 0x1a605
|
||||||
|
Noscript Atom = 0x2c208
|
||||||
|
Novalidate Atom = 0x2a50a
|
||||||
|
Object Atom = 0x25b06
|
||||||
|
Ol Atom = 0x13702
|
||||||
|
Onabort Atom = 0x19507
|
||||||
|
Onafterprint Atom = 0x2290c
|
||||||
|
Onautocomplete Atom = 0x2690e
|
||||||
|
Onautocompleteerror Atom = 0x26913
|
||||||
|
Onauxclick Atom = 0x6140a
|
||||||
|
Onbeforeprint Atom = 0x69c0d
|
||||||
|
Onbeforeunload Atom = 0x6e50e
|
||||||
|
Onblur Atom = 0x1ea06
|
||||||
|
Oncancel Atom = 0x11908
|
||||||
|
Oncanplay Atom = 0x14d09
|
||||||
|
Oncanplaythrough Atom = 0x14d10
|
||||||
|
Onchange Atom = 0x41508
|
||||||
|
Onclick Atom = 0x2e407
|
||||||
|
Onclose Atom = 0x36607
|
||||||
|
Oncontextmenu Atom = 0x3780d
|
||||||
|
Oncopy Atom = 0x38b06
|
||||||
|
Oncuechange Atom = 0x3910b
|
||||||
|
Oncut Atom = 0x39c05
|
||||||
|
Ondblclick Atom = 0x3a10a
|
||||||
|
Ondrag Atom = 0x3ab06
|
||||||
|
Ondragend Atom = 0x3ab09
|
||||||
|
Ondragenter Atom = 0x3b40b
|
||||||
|
Ondragexit Atom = 0x3bf0a
|
||||||
|
Ondragleave Atom = 0x3d90b
|
||||||
|
Ondragover Atom = 0x3e40a
|
||||||
|
Ondragstart Atom = 0x3ee0b
|
||||||
|
Ondrop Atom = 0x3fd06
|
||||||
|
Ondurationchange Atom = 0x40d10
|
||||||
|
Onemptied Atom = 0x40409
|
||||||
|
Onended Atom = 0x41d07
|
||||||
|
Onerror Atom = 0x42407
|
||||||
|
Onfocus Atom = 0x42b07
|
||||||
|
Onhashchange Atom = 0x4370c
|
||||||
|
Oninput Atom = 0x44307
|
||||||
|
Oninvalid Atom = 0x44f09
|
||||||
|
Onkeydown Atom = 0x45809
|
||||||
|
Onkeypress Atom = 0x4650a
|
||||||
|
Onkeyup Atom = 0x47407
|
||||||
|
Onlanguagechange Atom = 0x48110
|
||||||
|
Onload Atom = 0x49106
|
||||||
|
Onloadeddata Atom = 0x4910c
|
||||||
|
Onloadedmetadata Atom = 0x4a410
|
||||||
|
Onloadend Atom = 0x4ba09
|
||||||
|
Onloadstart Atom = 0x4c30b
|
||||||
|
Onmessage Atom = 0x4ce09
|
||||||
|
Onmessageerror Atom = 0x4ce0e
|
||||||
|
Onmousedown Atom = 0x4dc0b
|
||||||
|
Onmouseenter Atom = 0x4e70c
|
||||||
|
Onmouseleave Atom = 0x4f30c
|
||||||
|
Onmousemove Atom = 0x4ff0b
|
||||||
|
Onmouseout Atom = 0x50a0a
|
||||||
|
Onmouseover Atom = 0x5170b
|
||||||
|
Onmouseup Atom = 0x52209
|
||||||
|
Onmousewheel Atom = 0x5300c
|
||||||
|
Onoffline Atom = 0x53c09
|
||||||
|
Ononline Atom = 0x54508
|
||||||
|
Onpagehide Atom = 0x54d0a
|
||||||
|
Onpageshow Atom = 0x5630a
|
||||||
|
Onpaste Atom = 0x56f07
|
||||||
|
Onpause Atom = 0x58a07
|
||||||
|
Onplay Atom = 0x59406
|
||||||
|
Onplaying Atom = 0x59409
|
||||||
|
Onpopstate Atom = 0x59d0a
|
||||||
|
Onprogress Atom = 0x5a70a
|
||||||
|
Onratechange Atom = 0x5bc0c
|
||||||
|
Onrejectionhandled Atom = 0x5c812
|
||||||
|
Onreset Atom = 0x5da07
|
||||||
|
Onresize Atom = 0x5e108
|
||||||
|
Onscroll Atom = 0x5f508
|
||||||
|
Onsecuritypolicyviolation Atom = 0x5fd19
|
||||||
|
Onseeked Atom = 0x61e08
|
||||||
|
Onseeking Atom = 0x62609
|
||||||
|
Onselect Atom = 0x62f08
|
||||||
|
Onshow Atom = 0x63906
|
||||||
|
Onsort Atom = 0x64d06
|
||||||
|
Onstalled Atom = 0x65709
|
||||||
|
Onstorage Atom = 0x66009
|
||||||
|
Onsubmit Atom = 0x66908
|
||||||
|
Onsuspend Atom = 0x67909
|
||||||
|
Ontimeupdate Atom = 0x400c
|
||||||
|
Ontoggle Atom = 0x68208
|
||||||
|
Onunhandledrejection Atom = 0x68a14
|
||||||
|
Onunload Atom = 0x6a908
|
||||||
|
Onvolumechange Atom = 0x6b10e
|
||||||
|
Onwaiting Atom = 0x6bf09
|
||||||
|
Onwheel Atom = 0x6c807
|
||||||
|
Open Atom = 0x1a304
|
||||||
|
Optgroup Atom = 0x5f08
|
||||||
|
Optimum Atom = 0x6cf07
|
||||||
|
Option Atom = 0x6e106
|
||||||
|
Output Atom = 0x51106
|
||||||
|
P Atom = 0xc01
|
||||||
|
Param Atom = 0xc05
|
||||||
|
Pattern Atom = 0x6607
|
||||||
|
Picture Atom = 0x7b07
|
||||||
|
Ping Atom = 0xef04
|
||||||
|
Placeholder Atom = 0x1310b
|
||||||
|
Plaintext Atom = 0x1b209
|
||||||
|
Playsinline Atom = 0x1400b
|
||||||
|
Poster Atom = 0x64706
|
||||||
|
Pre Atom = 0x46a03
|
||||||
|
Preload Atom = 0x47a07
|
||||||
|
Progress Atom = 0x5a908
|
||||||
|
Prompt Atom = 0x52a06
|
||||||
|
Public Atom = 0x57606
|
||||||
|
Q Atom = 0xcf01
|
||||||
|
Radiogroup Atom = 0x30a
|
||||||
|
Rb Atom = 0x3a02
|
||||||
|
Readonly Atom = 0x35108
|
||||||
|
Referrerpolicy Atom = 0x3cb0e
|
||||||
|
Rel Atom = 0x47b03
|
||||||
|
Required Atom = 0x23f08
|
||||||
|
Reversed Atom = 0x8008
|
||||||
|
Rows Atom = 0x9c04
|
||||||
|
Rowspan Atom = 0x9c07
|
||||||
|
Rp Atom = 0x22f02
|
||||||
|
Rt Atom = 0x19a02
|
||||||
|
Rtc Atom = 0x19a03
|
||||||
|
Ruby Atom = 0xfb04
|
||||||
|
S Atom = 0x2501
|
||||||
|
Samp Atom = 0x7804
|
||||||
|
Sandbox Atom = 0x12907
|
||||||
|
Scope Atom = 0x67305
|
||||||
|
Scoped Atom = 0x67306
|
||||||
|
Script Atom = 0x2c406
|
||||||
|
Seamless Atom = 0x36b08
|
||||||
|
Search Atom = 0x55c06
|
||||||
|
Section Atom = 0x1e507
|
||||||
|
Select Atom = 0x63106
|
||||||
|
Selected Atom = 0x63108
|
||||||
|
Shape Atom = 0x1f505
|
||||||
|
Size Atom = 0x5e504
|
||||||
|
Sizes Atom = 0x5e505
|
||||||
|
Slot Atom = 0x20504
|
||||||
|
Small Atom = 0x32605
|
||||||
|
Sortable Atom = 0x64f08
|
||||||
|
Sorted Atom = 0x37206
|
||||||
|
Source Atom = 0x43106
|
||||||
|
Spacer Atom = 0x46e06
|
||||||
|
Span Atom = 0x9f04
|
||||||
|
Spellcheck Atom = 0x5b00a
|
||||||
|
Src Atom = 0x5e903
|
||||||
|
Srcdoc Atom = 0x5e906
|
||||||
|
Srclang Atom = 0x6f707
|
||||||
|
Srcset Atom = 0x6fe06
|
||||||
|
Start Atom = 0x3f405
|
||||||
|
Step Atom = 0x57304
|
||||||
|
Strike Atom = 0xd206
|
||||||
|
Strong Atom = 0x6db06
|
||||||
|
Style Atom = 0x70405
|
||||||
|
Sub Atom = 0x66b03
|
||||||
|
Summary Atom = 0x70907
|
||||||
|
Sup Atom = 0x71003
|
||||||
|
Svg Atom = 0x71303
|
||||||
|
System Atom = 0x71606
|
||||||
|
Tabindex Atom = 0x4b208
|
||||||
|
Table Atom = 0x58505
|
||||||
|
Target Atom = 0x2b706
|
||||||
|
Tbody Atom = 0x2705
|
||||||
|
Td Atom = 0x9202
|
||||||
|
Template Atom = 0x71908
|
||||||
|
Textarea Atom = 0x34c08
|
||||||
|
Tfoot Atom = 0xf505
|
||||||
|
Th Atom = 0x15602
|
||||||
|
Thead Atom = 0x31f05
|
||||||
|
Time Atom = 0x4204
|
||||||
|
Title Atom = 0x11005
|
||||||
|
Tr Atom = 0xcc02
|
||||||
|
Track Atom = 0x1ba05
|
||||||
|
Translate Atom = 0x20809
|
||||||
|
Tt Atom = 0x6802
|
||||||
|
Type Atom = 0xd904
|
||||||
|
Typemustmatch Atom = 0x2830d
|
||||||
|
U Atom = 0xb01
|
||||||
|
Ul Atom = 0xa702
|
||||||
|
Updateviacache Atom = 0x460e
|
||||||
|
Usemap Atom = 0x58e06
|
||||||
|
Value Atom = 0x1505
|
||||||
|
Var Atom = 0x16d03
|
||||||
|
Video Atom = 0x2e005
|
||||||
|
Wbr Atom = 0x56c03
|
||||||
|
Width Atom = 0x63e05
|
||||||
|
Workertype Atom = 0x7210a
|
||||||
|
Wrap Atom = 0x72b04
|
||||||
|
Xmp Atom = 0x12f03
|
||||||
|
)
|
||||||
|
|
||||||
|
const hash0 = 0x84f70e16
|
||||||
|
|
||||||
|
const maxAtomLen = 25
|
||||||
|
|
||||||
|
var table = [1 << 9]Atom{
|
||||||
|
0x1: 0x3ff08, // dropzone
|
||||||
|
0x2: 0x3b08, // basefont
|
||||||
|
0x3: 0x23209, // integrity
|
||||||
|
0x4: 0x43106, // source
|
||||||
|
0x5: 0x2c09, // accesskey
|
||||||
|
0x6: 0x1a06, // accept
|
||||||
|
0x7: 0x6c807, // onwheel
|
||||||
|
0xb: 0x47407, // onkeyup
|
||||||
|
0xc: 0x32007, // headers
|
||||||
|
0xd: 0x67306, // scoped
|
||||||
|
0xe: 0x67909, // onsuspend
|
||||||
|
0xf: 0x8908, // noframes
|
||||||
|
0x10: 0x1fa0b, // crossorigin
|
||||||
|
0x11: 0x2e407, // onclick
|
||||||
|
0x12: 0x3f405, // start
|
||||||
|
0x13: 0x37a0b, // contextmenu
|
||||||
|
0x14: 0x5e903, // src
|
||||||
|
0x15: 0x1c404, // cols
|
||||||
|
0x16: 0xbb06, // dialog
|
||||||
|
0x17: 0x47a07, // preload
|
||||||
|
0x18: 0x3c707, // itemref
|
||||||
|
0x1b: 0x2f105, // image
|
||||||
|
0x1d: 0x4ba09, // onloadend
|
||||||
|
0x1e: 0x45d08, // download
|
||||||
|
0x1f: 0x46a03, // pre
|
||||||
|
0x23: 0x2970a, // formmethod
|
||||||
|
0x24: 0x71303, // svg
|
||||||
|
0x25: 0xcf01, // q
|
||||||
|
0x26: 0x64002, // dt
|
||||||
|
0x27: 0x1de08, // controls
|
||||||
|
0x2a: 0x2804, // body
|
||||||
|
0x2b: 0xd206, // strike
|
||||||
|
0x2c: 0x3910b, // oncuechange
|
||||||
|
0x2d: 0x4c30b, // onloadstart
|
||||||
|
0x2e: 0x2fe07, // isindex
|
||||||
|
0x2f: 0xb202, // li
|
||||||
|
0x30: 0x1400b, // playsinline
|
||||||
|
0x31: 0x34102, // mi
|
||||||
|
0x32: 0x30806, // applet
|
||||||
|
0x33: 0x4ce09, // onmessage
|
||||||
|
0x35: 0x13702, // ol
|
||||||
|
0x36: 0x1a304, // open
|
||||||
|
0x39: 0x14d09, // oncanplay
|
||||||
|
0x3a: 0x6bf09, // onwaiting
|
||||||
|
0x3b: 0x11908, // oncancel
|
||||||
|
0x3c: 0x6a908, // onunload
|
||||||
|
0x3e: 0x53c09, // onoffline
|
||||||
|
0x3f: 0x1a0e, // accept-charset
|
||||||
|
0x40: 0x32004, // head
|
||||||
|
0x42: 0x3ab09, // ondragend
|
||||||
|
0x43: 0x1310b, // placeholder
|
||||||
|
0x44: 0x2b30a, // formtarget
|
||||||
|
0x45: 0x2540d, // foreignobject
|
||||||
|
0x47: 0x400c, // ontimeupdate
|
||||||
|
0x48: 0xdd0e, // allowusermedia
|
||||||
|
0x4a: 0x69c0d, // onbeforeprint
|
||||||
|
0x4b: 0x5604, // html
|
||||||
|
0x4c: 0x9f04, // span
|
||||||
|
0x4d: 0x64206, // hgroup
|
||||||
|
0x4e: 0x16408, // disabled
|
||||||
|
0x4f: 0x4204, // time
|
||||||
|
0x51: 0x42b07, // onfocus
|
||||||
|
0x53: 0xb00a, // malignmark
|
||||||
|
0x55: 0x4650a, // onkeypress
|
||||||
|
0x56: 0x55805, // class
|
||||||
|
0x57: 0x1ab08, // colgroup
|
||||||
|
0x58: 0x33709, // maxlength
|
||||||
|
0x59: 0x5a908, // progress
|
||||||
|
0x5b: 0x70405, // style
|
||||||
|
0x5c: 0x2a10e, // formnovalidate
|
||||||
|
0x5e: 0x38b06, // oncopy
|
||||||
|
0x60: 0x26104, // form
|
||||||
|
0x61: 0xf606, // footer
|
||||||
|
0x64: 0x30a, // radiogroup
|
||||||
|
0x66: 0xfb04, // ruby
|
||||||
|
0x67: 0x4ff0b, // onmousemove
|
||||||
|
0x68: 0x19d08, // itemprop
|
||||||
|
0x69: 0x2d70a, // http-equiv
|
||||||
|
0x6a: 0x15602, // th
|
||||||
|
0x6c: 0x6e02, // em
|
||||||
|
0x6d: 0x38108, // menuitem
|
||||||
|
0x6e: 0x63106, // select
|
||||||
|
0x6f: 0x48110, // onlanguagechange
|
||||||
|
0x70: 0x31f05, // thead
|
||||||
|
0x71: 0x15c02, // h1
|
||||||
|
0x72: 0x5e906, // srcdoc
|
||||||
|
0x75: 0x9604, // name
|
||||||
|
0x76: 0x19106, // button
|
||||||
|
0x77: 0x55504, // desc
|
||||||
|
0x78: 0x17704, // kind
|
||||||
|
0x79: 0x1bf05, // color
|
||||||
|
0x7c: 0x58e06, // usemap
|
||||||
|
0x7d: 0x30e08, // itemtype
|
||||||
|
0x7f: 0x6d508, // manifest
|
||||||
|
0x81: 0x5300c, // onmousewheel
|
||||||
|
0x82: 0x4dc0b, // onmousedown
|
||||||
|
0x84: 0xc05, // param
|
||||||
|
0x85: 0x2e005, // video
|
||||||
|
0x86: 0x4910c, // onloadeddata
|
||||||
|
0x87: 0x6f107, // address
|
||||||
|
0x8c: 0xef04, // ping
|
||||||
|
0x8d: 0x24703, // for
|
||||||
|
0x8f: 0x62f08, // onselect
|
||||||
|
0x90: 0x30703, // map
|
||||||
|
0x92: 0xc01, // p
|
||||||
|
0x93: 0x8008, // reversed
|
||||||
|
0x94: 0x54d0a, // onpagehide
|
||||||
|
0x95: 0x3206, // keygen
|
||||||
|
0x96: 0x34109, // minlength
|
||||||
|
0x97: 0x3e40a, // ondragover
|
||||||
|
0x98: 0x42407, // onerror
|
||||||
|
0x9a: 0x2107, // charset
|
||||||
|
0x9b: 0x29b06, // method
|
||||||
|
0x9c: 0x101, // b
|
||||||
|
0x9d: 0x68208, // ontoggle
|
||||||
|
0x9e: 0x2bd06, // hidden
|
||||||
|
0xa0: 0x3f607, // article
|
||||||
|
0xa2: 0x63906, // onshow
|
||||||
|
0xa3: 0x64d06, // onsort
|
||||||
|
0xa5: 0x57b0f, // contenteditable
|
||||||
|
0xa6: 0x66908, // onsubmit
|
||||||
|
0xa8: 0x44f09, // oninvalid
|
||||||
|
0xaa: 0x202, // br
|
||||||
|
0xab: 0x10902, // id
|
||||||
|
0xac: 0x5d04, // loop
|
||||||
|
0xad: 0x5630a, // onpageshow
|
||||||
|
0xb0: 0x2cf04, // href
|
||||||
|
0xb2: 0x2210a, // figcaption
|
||||||
|
0xb3: 0x2690e, // onautocomplete
|
||||||
|
0xb4: 0x49106, // onload
|
||||||
|
0xb6: 0x9c04, // rows
|
||||||
|
0xb7: 0x1a605, // nonce
|
||||||
|
0xb8: 0x68a14, // onunhandledrejection
|
||||||
|
0xbb: 0x21306, // center
|
||||||
|
0xbc: 0x59406, // onplay
|
||||||
|
0xbd: 0x33f02, // h5
|
||||||
|
0xbe: 0x49d07, // listing
|
||||||
|
0xbf: 0x57606, // public
|
||||||
|
0xc2: 0x23b06, // figure
|
||||||
|
0xc3: 0x57a04, // icon
|
||||||
|
0xc4: 0x1ab03, // col
|
||||||
|
0xc5: 0x47b03, // rel
|
||||||
|
0xc6: 0xe605, // media
|
||||||
|
0xc7: 0x12109, // autofocus
|
||||||
|
0xc8: 0x19a02, // rt
|
||||||
|
0xca: 0x2d304, // lang
|
||||||
|
0xcc: 0x49908, // datalist
|
||||||
|
0xce: 0x2eb06, // iframe
|
||||||
|
0xcf: 0x36105, // muted
|
||||||
|
0xd0: 0x6140a, // onauxclick
|
||||||
|
0xd2: 0x3c02, // as
|
||||||
|
0xd6: 0x3fd06, // ondrop
|
||||||
|
0xd7: 0x1c90a, // annotation
|
||||||
|
0xd8: 0x21908, // fieldset
|
||||||
|
0xdb: 0x2cf08, // hreflang
|
||||||
|
0xdc: 0x4e70c, // onmouseenter
|
||||||
|
0xdd: 0x2a402, // mn
|
||||||
|
0xde: 0xe60a, // mediagroup
|
||||||
|
0xdf: 0x9805, // meter
|
||||||
|
0xe0: 0x56c03, // wbr
|
||||||
|
0xe2: 0x63e05, // width
|
||||||
|
0xe3: 0x2290c, // onafterprint
|
||||||
|
0xe4: 0x30505, // ismap
|
||||||
|
0xe5: 0x1505, // value
|
||||||
|
0xe7: 0x1303, // nav
|
||||||
|
0xe8: 0x54508, // ononline
|
||||||
|
0xe9: 0xb604, // mark
|
||||||
|
0xea: 0xc303, // low
|
||||||
|
0xeb: 0x3ee0b, // ondragstart
|
||||||
|
0xef: 0x12f03, // xmp
|
||||||
|
0xf0: 0x22407, // caption
|
||||||
|
0xf1: 0xd904, // type
|
||||||
|
0xf2: 0x70907, // summary
|
||||||
|
0xf3: 0x6802, // tt
|
||||||
|
0xf4: 0x20809, // translate
|
||||||
|
0xf5: 0x1870a, // blockquote
|
||||||
|
0xf8: 0x15702, // hr
|
||||||
|
0xfa: 0x2705, // tbody
|
||||||
|
0xfc: 0x7b07, // picture
|
||||||
|
0xfd: 0x5206, // height
|
||||||
|
0xfe: 0x19c04, // cite
|
||||||
|
0xff: 0x2501, // s
|
||||||
|
0x101: 0xff05, // async
|
||||||
|
0x102: 0x56f07, // onpaste
|
||||||
|
0x103: 0x19507, // onabort
|
||||||
|
0x104: 0x2b706, // target
|
||||||
|
0x105: 0x14b03, // bdo
|
||||||
|
0x106: 0x1f006, // coords
|
||||||
|
0x107: 0x5e108, // onresize
|
||||||
|
0x108: 0x71908, // template
|
||||||
|
0x10a: 0x3a02, // rb
|
||||||
|
0x10b: 0x2a50a, // novalidate
|
||||||
|
0x10c: 0x460e, // updateviacache
|
||||||
|
0x10d: 0x71003, // sup
|
||||||
|
0x10e: 0x6c07, // noembed
|
||||||
|
0x10f: 0x16b03, // div
|
||||||
|
0x110: 0x6f707, // srclang
|
||||||
|
0x111: 0x17a09, // draggable
|
||||||
|
0x112: 0x67305, // scope
|
||||||
|
0x113: 0x5905, // label
|
||||||
|
0x114: 0x22f02, // rp
|
||||||
|
0x115: 0x23f08, // required
|
||||||
|
0x116: 0x3780d, // oncontextmenu
|
||||||
|
0x117: 0x5e504, // size
|
||||||
|
0x118: 0x5b00a, // spellcheck
|
||||||
|
0x119: 0x3f04, // font
|
||||||
|
0x11a: 0x9c07, // rowspan
|
||||||
|
0x11b: 0x10a07, // default
|
||||||
|
0x11d: 0x44307, // oninput
|
||||||
|
0x11e: 0x38506, // itemid
|
||||||
|
0x11f: 0x5ee04, // code
|
||||||
|
0x120: 0xaa07, // acronym
|
||||||
|
0x121: 0x3b04, // base
|
||||||
|
0x125: 0x2470d, // foreignObject
|
||||||
|
0x126: 0x2ca04, // high
|
||||||
|
0x127: 0x3cb0e, // referrerpolicy
|
||||||
|
0x128: 0x33703, // max
|
||||||
|
0x129: 0x59d0a, // onpopstate
|
||||||
|
0x12a: 0x2fc02, // h4
|
||||||
|
0x12b: 0x4ac04, // meta
|
||||||
|
0x12c: 0x17305, // blink
|
||||||
|
0x12e: 0x5f508, // onscroll
|
||||||
|
0x12f: 0x59409, // onplaying
|
||||||
|
0x130: 0xc113, // allowpaymentrequest
|
||||||
|
0x131: 0x19a03, // rtc
|
||||||
|
0x132: 0x72b04, // wrap
|
||||||
|
0x134: 0x8b08, // frameset
|
||||||
|
0x135: 0x32605, // small
|
||||||
|
0x137: 0x32006, // header
|
||||||
|
0x138: 0x40409, // onemptied
|
||||||
|
0x139: 0x34902, // h6
|
||||||
|
0x13a: 0x35908, // multiple
|
||||||
|
0x13c: 0x52a06, // prompt
|
||||||
|
0x13f: 0x28e09, // challenge
|
||||||
|
0x141: 0x4370c, // onhashchange
|
||||||
|
0x142: 0x57b07, // content
|
||||||
|
0x143: 0x1c90e, // annotation-xml
|
||||||
|
0x144: 0x36607, // onclose
|
||||||
|
0x145: 0x14d10, // oncanplaythrough
|
||||||
|
0x148: 0x5170b, // onmouseover
|
||||||
|
0x149: 0x64f08, // sortable
|
||||||
|
0x14a: 0xa402, // mo
|
||||||
|
0x14b: 0x2cd02, // h3
|
||||||
|
0x14c: 0x2c406, // script
|
||||||
|
0x14d: 0x41d07, // onended
|
||||||
|
0x14f: 0x64706, // poster
|
||||||
|
0x150: 0x7210a, // workertype
|
||||||
|
0x153: 0x1f505, // shape
|
||||||
|
0x154: 0x4, // abbr
|
||||||
|
0x155: 0x1, // a
|
||||||
|
0x156: 0x2bf02, // dd
|
||||||
|
0x157: 0x71606, // system
|
||||||
|
0x158: 0x4ce0e, // onmessageerror
|
||||||
|
0x159: 0x36b08, // seamless
|
||||||
|
0x15a: 0x2610a, // formaction
|
||||||
|
0x15b: 0x6e106, // option
|
||||||
|
0x15c: 0x31d04, // math
|
||||||
|
0x15d: 0x62609, // onseeking
|
||||||
|
0x15e: 0x39c05, // oncut
|
||||||
|
0x15f: 0x44c03, // del
|
||||||
|
0x160: 0x11005, // title
|
||||||
|
0x161: 0x11505, // audio
|
||||||
|
0x162: 0x63108, // selected
|
||||||
|
0x165: 0x3b40b, // ondragenter
|
||||||
|
0x166: 0x46e06, // spacer
|
||||||
|
0x167: 0x4a410, // onloadedmetadata
|
||||||
|
0x168: 0x44505, // input
|
||||||
|
0x16a: 0x58505, // table
|
||||||
|
0x16b: 0x41508, // onchange
|
||||||
|
0x16e: 0x5f005, // defer
|
||||||
|
0x171: 0x50a0a, // onmouseout
|
||||||
|
0x172: 0x20504, // slot
|
||||||
|
0x175: 0x3704, // nobr
|
||||||
|
0x177: 0x1d707, // command
|
||||||
|
0x17a: 0x7207, // details
|
||||||
|
0x17b: 0x38104, // menu
|
||||||
|
0x17c: 0xb903, // kbd
|
||||||
|
0x17d: 0x57304, // step
|
||||||
|
0x17e: 0x20303, // ins
|
||||||
|
0x17f: 0x13c08, // autoplay
|
||||||
|
0x182: 0x34103, // min
|
||||||
|
0x183: 0x17404, // link
|
||||||
|
0x185: 0x40d10, // ondurationchange
|
||||||
|
0x186: 0x9202, // td
|
||||||
|
0x187: 0x8b05, // frame
|
||||||
|
0x18a: 0x2ab08, // datetime
|
||||||
|
0x18b: 0x44509, // inputmode
|
||||||
|
0x18c: 0x35108, // readonly
|
||||||
|
0x18d: 0x21104, // face
|
||||||
|
0x18f: 0x5e505, // sizes
|
||||||
|
0x191: 0x4b208, // tabindex
|
||||||
|
0x192: 0x6db06, // strong
|
||||||
|
0x193: 0xba03, // bdi
|
||||||
|
0x194: 0x6fe06, // srcset
|
||||||
|
0x196: 0x67202, // ms
|
||||||
|
0x197: 0x5b507, // checked
|
||||||
|
0x198: 0xb105, // align
|
||||||
|
0x199: 0x1e507, // section
|
||||||
|
0x19b: 0x6e05, // embed
|
||||||
|
0x19d: 0x15e07, // bgsound
|
||||||
|
0x1a2: 0x49d04, // list
|
||||||
|
0x1a3: 0x61e08, // onseeked
|
||||||
|
0x1a4: 0x66009, // onstorage
|
||||||
|
0x1a5: 0x2f603, // img
|
||||||
|
0x1a6: 0xf505, // tfoot
|
||||||
|
0x1a9: 0x26913, // onautocompleteerror
|
||||||
|
0x1aa: 0x5fd19, // onsecuritypolicyviolation
|
||||||
|
0x1ad: 0x9303, // dir
|
||||||
|
0x1ae: 0x9307, // dirname
|
||||||
|
0x1b0: 0x5a70a, // onprogress
|
||||||
|
0x1b2: 0x65709, // onstalled
|
||||||
|
0x1b5: 0x66f09, // itemscope
|
||||||
|
0x1b6: 0x49904, // data
|
||||||
|
0x1b7: 0x3d90b, // ondragleave
|
||||||
|
0x1b8: 0x56102, // h2
|
||||||
|
0x1b9: 0x2f706, // mglyph
|
||||||
|
0x1ba: 0x16502, // is
|
||||||
|
0x1bb: 0x6e50e, // onbeforeunload
|
||||||
|
0x1bc: 0x2830d, // typemustmatch
|
||||||
|
0x1bd: 0x3ab06, // ondrag
|
||||||
|
0x1be: 0x5da07, // onreset
|
||||||
|
0x1c0: 0x51106, // output
|
||||||
|
0x1c1: 0x12907, // sandbox
|
||||||
|
0x1c2: 0x1b209, // plaintext
|
||||||
|
0x1c4: 0x34c08, // textarea
|
||||||
|
0x1c7: 0xd607, // keytype
|
||||||
|
0x1c8: 0x34b05, // mtext
|
||||||
|
0x1c9: 0x6b10e, // onvolumechange
|
||||||
|
0x1ca: 0x1ea06, // onblur
|
||||||
|
0x1cb: 0x58a07, // onpause
|
||||||
|
0x1cd: 0x5bc0c, // onratechange
|
||||||
|
0x1ce: 0x10705, // aside
|
||||||
|
0x1cf: 0x6cf07, // optimum
|
||||||
|
0x1d1: 0x45809, // onkeydown
|
||||||
|
0x1d2: 0x1c407, // colspan
|
||||||
|
0x1d3: 0x1004, // main
|
||||||
|
0x1d4: 0x66b03, // sub
|
||||||
|
0x1d5: 0x25b06, // object
|
||||||
|
0x1d6: 0x55c06, // search
|
||||||
|
0x1d7: 0x37206, // sorted
|
||||||
|
0x1d8: 0x17003, // big
|
||||||
|
0x1d9: 0xb01, // u
|
||||||
|
0x1db: 0x26b0c, // autocomplete
|
||||||
|
0x1dc: 0xcc02, // tr
|
||||||
|
0x1dd: 0xf303, // alt
|
||||||
|
0x1df: 0x7804, // samp
|
||||||
|
0x1e0: 0x5c812, // onrejectionhandled
|
||||||
|
0x1e1: 0x4f30c, // onmouseleave
|
||||||
|
0x1e2: 0x28007, // enctype
|
||||||
|
0x1e3: 0xa208, // nomodule
|
||||||
|
0x1e5: 0x3280f, // allowfullscreen
|
||||||
|
0x1e6: 0x5f08, // optgroup
|
||||||
|
0x1e8: 0x27c0b, // formenctype
|
||||||
|
0x1e9: 0x18106, // legend
|
||||||
|
0x1ea: 0x10306, // canvas
|
||||||
|
0x1eb: 0x6607, // pattern
|
||||||
|
0x1ec: 0x2c208, // noscript
|
||||||
|
0x1ed: 0x601, // i
|
||||||
|
0x1ee: 0x5d602, // dl
|
||||||
|
0x1ef: 0xa702, // ul
|
||||||
|
0x1f2: 0x52209, // onmouseup
|
||||||
|
0x1f4: 0x1ba05, // track
|
||||||
|
0x1f7: 0x3a10a, // ondblclick
|
||||||
|
0x1f8: 0x3bf0a, // ondragexit
|
||||||
|
0x1fa: 0x8703, // dfn
|
||||||
|
0x1fc: 0x26506, // action
|
||||||
|
0x1fd: 0x35004, // area
|
||||||
|
0x1fe: 0x31607, // marquee
|
||||||
|
0x1ff: 0x16d03, // var
|
||||||
|
}
|
||||||
|
|
||||||
|
const atomText = "abbradiogrouparamainavalueaccept-charsetbodyaccesskeygenobrb" +
|
||||||
|
"asefontimeupdateviacacheightmlabelooptgroupatternoembedetail" +
|
||||||
|
"sampictureversedfnoframesetdirnameterowspanomoduleacronymali" +
|
||||||
|
"gnmarkbdialogallowpaymentrequestrikeytypeallowusermediagroup" +
|
||||||
|
"ingaltfooterubyasyncanvasidefaultitleaudioncancelautofocusan" +
|
||||||
|
"dboxmplaceholderautoplaysinlinebdoncanplaythrough1bgsoundisa" +
|
||||||
|
"bledivarbigblinkindraggablegendblockquotebuttonabortcitempro" +
|
||||||
|
"penoncecolgrouplaintextrackcolorcolspannotation-xmlcommandco" +
|
||||||
|
"ntrolsectionblurcoordshapecrossoriginslotranslatefacenterfie" +
|
||||||
|
"ldsetfigcaptionafterprintegrityfigurequiredforeignObjectfore" +
|
||||||
|
"ignobjectformactionautocompleteerrorformenctypemustmatchalle" +
|
||||||
|
"ngeformmethodformnovalidatetimeformtargethiddenoscripthigh3h" +
|
||||||
|
"reflanghttp-equivideonclickiframeimageimglyph4isindexismappl" +
|
||||||
|
"etitemtypemarqueematheadersmallowfullscreenmaxlength5minleng" +
|
||||||
|
"th6mtextareadonlymultiplemutedoncloseamlessortedoncontextmen" +
|
||||||
|
"uitemidoncopyoncuechangeoncutondblclickondragendondragentero" +
|
||||||
|
"ndragexitemreferrerpolicyondragleaveondragoverondragstarticl" +
|
||||||
|
"eondropzonemptiedondurationchangeonendedonerroronfocusourceo" +
|
||||||
|
"nhashchangeoninputmodeloninvalidonkeydownloadonkeypresspacer" +
|
||||||
|
"onkeyupreloadonlanguagechangeonloadeddatalistingonloadedmeta" +
|
||||||
|
"databindexonloadendonloadstartonmessageerroronmousedownonmou" +
|
||||||
|
"seenteronmouseleaveonmousemoveonmouseoutputonmouseoveronmous" +
|
||||||
|
"eupromptonmousewheelonofflineononlineonpagehidesclassearch2o" +
|
||||||
|
"npageshowbronpastepublicontenteditableonpausemaponplayingonp" +
|
||||||
|
"opstateonprogresspellcheckedonratechangeonrejectionhandledon" +
|
||||||
|
"resetonresizesrcdocodeferonscrollonsecuritypolicyviolationau" +
|
||||||
|
"xclickonseekedonseekingonselectedonshowidthgrouposteronsorta" +
|
||||||
|
"bleonstalledonstorageonsubmitemscopedonsuspendontoggleonunha" +
|
||||||
|
"ndledrejectionbeforeprintonunloadonvolumechangeonwaitingonwh" +
|
||||||
|
"eeloptimumanifestrongoptionbeforeunloaddressrclangsrcsetstyl" +
|
||||||
|
"esummarysupsvgsystemplateworkertypewrap"
|
||||||
111
vendor/golang.org/x/net/html/const.go
generated
vendored
Normal file
111
vendor/golang.org/x/net/html/const.go
generated
vendored
Normal file
@@ -0,0 +1,111 @@
|
|||||||
|
// Copyright 2011 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package html
|
||||||
|
|
||||||
|
// Section 12.2.4.2 of the HTML5 specification says "The following elements
|
||||||
|
// have varying levels of special parsing rules".
|
||||||
|
// https://html.spec.whatwg.org/multipage/syntax.html#the-stack-of-open-elements
|
||||||
|
var isSpecialElementMap = map[string]bool{
|
||||||
|
"address": true,
|
||||||
|
"applet": true,
|
||||||
|
"area": true,
|
||||||
|
"article": true,
|
||||||
|
"aside": true,
|
||||||
|
"base": true,
|
||||||
|
"basefont": true,
|
||||||
|
"bgsound": true,
|
||||||
|
"blockquote": true,
|
||||||
|
"body": true,
|
||||||
|
"br": true,
|
||||||
|
"button": true,
|
||||||
|
"caption": true,
|
||||||
|
"center": true,
|
||||||
|
"col": true,
|
||||||
|
"colgroup": true,
|
||||||
|
"dd": true,
|
||||||
|
"details": true,
|
||||||
|
"dir": true,
|
||||||
|
"div": true,
|
||||||
|
"dl": true,
|
||||||
|
"dt": true,
|
||||||
|
"embed": true,
|
||||||
|
"fieldset": true,
|
||||||
|
"figcaption": true,
|
||||||
|
"figure": true,
|
||||||
|
"footer": true,
|
||||||
|
"form": true,
|
||||||
|
"frame": true,
|
||||||
|
"frameset": true,
|
||||||
|
"h1": true,
|
||||||
|
"h2": true,
|
||||||
|
"h3": true,
|
||||||
|
"h4": true,
|
||||||
|
"h5": true,
|
||||||
|
"h6": true,
|
||||||
|
"head": true,
|
||||||
|
"header": true,
|
||||||
|
"hgroup": true,
|
||||||
|
"hr": true,
|
||||||
|
"html": true,
|
||||||
|
"iframe": true,
|
||||||
|
"img": true,
|
||||||
|
"input": true,
|
||||||
|
"keygen": true, // "keygen" has been removed from the spec, but are kept here for backwards compatibility.
|
||||||
|
"li": true,
|
||||||
|
"link": true,
|
||||||
|
"listing": true,
|
||||||
|
"main": true,
|
||||||
|
"marquee": true,
|
||||||
|
"menu": true,
|
||||||
|
"meta": true,
|
||||||
|
"nav": true,
|
||||||
|
"noembed": true,
|
||||||
|
"noframes": true,
|
||||||
|
"noscript": true,
|
||||||
|
"object": true,
|
||||||
|
"ol": true,
|
||||||
|
"p": true,
|
||||||
|
"param": true,
|
||||||
|
"plaintext": true,
|
||||||
|
"pre": true,
|
||||||
|
"script": true,
|
||||||
|
"section": true,
|
||||||
|
"select": true,
|
||||||
|
"source": true,
|
||||||
|
"style": true,
|
||||||
|
"summary": true,
|
||||||
|
"table": true,
|
||||||
|
"tbody": true,
|
||||||
|
"td": true,
|
||||||
|
"template": true,
|
||||||
|
"textarea": true,
|
||||||
|
"tfoot": true,
|
||||||
|
"th": true,
|
||||||
|
"thead": true,
|
||||||
|
"title": true,
|
||||||
|
"tr": true,
|
||||||
|
"track": true,
|
||||||
|
"ul": true,
|
||||||
|
"wbr": true,
|
||||||
|
"xmp": true,
|
||||||
|
}
|
||||||
|
|
||||||
|
func isSpecialElement(element *Node) bool {
|
||||||
|
switch element.Namespace {
|
||||||
|
case "", "html":
|
||||||
|
return isSpecialElementMap[element.Data]
|
||||||
|
case "math":
|
||||||
|
switch element.Data {
|
||||||
|
case "mi", "mo", "mn", "ms", "mtext", "annotation-xml":
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
case "svg":
|
||||||
|
switch element.Data {
|
||||||
|
case "foreignObject", "desc", "title":
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
122
vendor/golang.org/x/net/html/doc.go
generated
vendored
Normal file
122
vendor/golang.org/x/net/html/doc.go
generated
vendored
Normal file
@@ -0,0 +1,122 @@
|
|||||||
|
// Copyright 2010 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
/*
|
||||||
|
Package html implements an HTML5-compliant tokenizer and parser.
|
||||||
|
|
||||||
|
Tokenization is done by creating a Tokenizer for an io.Reader r. It is the
|
||||||
|
caller's responsibility to ensure that r provides UTF-8 encoded HTML.
|
||||||
|
|
||||||
|
z := html.NewTokenizer(r)
|
||||||
|
|
||||||
|
Given a Tokenizer z, the HTML is tokenized by repeatedly calling z.Next(),
|
||||||
|
which parses the next token and returns its type, or an error:
|
||||||
|
|
||||||
|
for {
|
||||||
|
tt := z.Next()
|
||||||
|
if tt == html.ErrorToken {
|
||||||
|
// ...
|
||||||
|
return ...
|
||||||
|
}
|
||||||
|
// Process the current token.
|
||||||
|
}
|
||||||
|
|
||||||
|
There are two APIs for retrieving the current token. The high-level API is to
|
||||||
|
call Token; the low-level API is to call Text or TagName / TagAttr. Both APIs
|
||||||
|
allow optionally calling Raw after Next but before Token, Text, TagName, or
|
||||||
|
TagAttr. In EBNF notation, the valid call sequence per token is:
|
||||||
|
|
||||||
|
Next {Raw} [ Token | Text | TagName {TagAttr} ]
|
||||||
|
|
||||||
|
Token returns an independent data structure that completely describes a token.
|
||||||
|
Entities (such as "<") are unescaped, tag names and attribute keys are
|
||||||
|
lower-cased, and attributes are collected into a []Attribute. For example:
|
||||||
|
|
||||||
|
for {
|
||||||
|
if z.Next() == html.ErrorToken {
|
||||||
|
// Returning io.EOF indicates success.
|
||||||
|
return z.Err()
|
||||||
|
}
|
||||||
|
emitToken(z.Token())
|
||||||
|
}
|
||||||
|
|
||||||
|
The low-level API performs fewer allocations and copies, but the contents of
|
||||||
|
the []byte values returned by Text, TagName and TagAttr may change on the next
|
||||||
|
call to Next. For example, to extract an HTML page's anchor text:
|
||||||
|
|
||||||
|
depth := 0
|
||||||
|
for {
|
||||||
|
tt := z.Next()
|
||||||
|
switch tt {
|
||||||
|
case html.ErrorToken:
|
||||||
|
return z.Err()
|
||||||
|
case html.TextToken:
|
||||||
|
if depth > 0 {
|
||||||
|
// emitBytes should copy the []byte it receives,
|
||||||
|
// if it doesn't process it immediately.
|
||||||
|
emitBytes(z.Text())
|
||||||
|
}
|
||||||
|
case html.StartTagToken, html.EndTagToken:
|
||||||
|
tn, _ := z.TagName()
|
||||||
|
if len(tn) == 1 && tn[0] == 'a' {
|
||||||
|
if tt == html.StartTagToken {
|
||||||
|
depth++
|
||||||
|
} else {
|
||||||
|
depth--
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Parsing is done by calling Parse with an io.Reader, which returns the root of
|
||||||
|
the parse tree (the document element) as a *Node. It is the caller's
|
||||||
|
responsibility to ensure that the Reader provides UTF-8 encoded HTML. For
|
||||||
|
example, to process each anchor node in depth-first order:
|
||||||
|
|
||||||
|
doc, err := html.Parse(r)
|
||||||
|
if err != nil {
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
for n := range doc.Descendants() {
|
||||||
|
if n.Type == html.ElementNode && n.Data == "a" {
|
||||||
|
// Do something with n...
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
The relevant specifications include:
|
||||||
|
https://html.spec.whatwg.org/multipage/syntax.html and
|
||||||
|
https://html.spec.whatwg.org/multipage/syntax.html#tokenization
|
||||||
|
|
||||||
|
# Security Considerations
|
||||||
|
|
||||||
|
Care should be taken when parsing and interpreting HTML, whether full documents
|
||||||
|
or fragments, within the framework of the HTML specification, especially with
|
||||||
|
regard to untrusted inputs.
|
||||||
|
|
||||||
|
This package provides both a tokenizer and a parser, which implement the
|
||||||
|
tokenization, and tokenization and tree construction stages of the WHATWG HTML
|
||||||
|
parsing specification respectively. While the tokenizer parses and normalizes
|
||||||
|
individual HTML tokens, only the parser constructs the DOM tree from the
|
||||||
|
tokenized HTML, as described in the tree construction stage of the
|
||||||
|
specification, dynamically modifying or extending the document's DOM tree.
|
||||||
|
|
||||||
|
If your use case requires semantically well-formed HTML documents, as defined by
|
||||||
|
the WHATWG specification, the parser should be used rather than the tokenizer.
|
||||||
|
|
||||||
|
In security contexts, if trust decisions are being made using the tokenized or
|
||||||
|
parsed content, the input must be re-serialized (for instance by using Render or
|
||||||
|
Token.String) in order for those trust decisions to hold, as the process of
|
||||||
|
tokenization or parsing may alter the content.
|
||||||
|
*/
|
||||||
|
package html // import "golang.org/x/net/html"
|
||||||
|
|
||||||
|
// The tokenization algorithm implemented by this package is not a line-by-line
|
||||||
|
// transliteration of the relatively verbose state-machine in the WHATWG
|
||||||
|
// specification. A more direct approach is used instead, where the program
|
||||||
|
// counter implies the state, such as whether it is tokenizing a tag or a text
|
||||||
|
// node. Specification compliance is verified by checking expected and actual
|
||||||
|
// outputs over a test suite rather than aiming for algorithmic fidelity.
|
||||||
|
|
||||||
|
// TODO(nigeltao): Does a DOM API belong in this package or a separate one?
|
||||||
|
// TODO(nigeltao): How does parsing interact with a JavaScript engine?
|
||||||
156
vendor/golang.org/x/net/html/doctype.go
generated
vendored
Normal file
156
vendor/golang.org/x/net/html/doctype.go
generated
vendored
Normal file
@@ -0,0 +1,156 @@
|
|||||||
|
// Copyright 2011 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package html
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// parseDoctype parses the data from a DoctypeToken into a name,
|
||||||
|
// public identifier, and system identifier. It returns a Node whose Type
|
||||||
|
// is DoctypeNode, whose Data is the name, and which has attributes
|
||||||
|
// named "system" and "public" for the two identifiers if they were present.
|
||||||
|
// quirks is whether the document should be parsed in "quirks mode".
|
||||||
|
func parseDoctype(s string) (n *Node, quirks bool) {
|
||||||
|
n = &Node{Type: DoctypeNode}
|
||||||
|
|
||||||
|
// Find the name.
|
||||||
|
space := strings.IndexAny(s, whitespace)
|
||||||
|
if space == -1 {
|
||||||
|
space = len(s)
|
||||||
|
}
|
||||||
|
n.Data = s[:space]
|
||||||
|
// The comparison to "html" is case-sensitive.
|
||||||
|
if n.Data != "html" {
|
||||||
|
quirks = true
|
||||||
|
}
|
||||||
|
n.Data = strings.ToLower(n.Data)
|
||||||
|
s = strings.TrimLeft(s[space:], whitespace)
|
||||||
|
|
||||||
|
if len(s) < 6 {
|
||||||
|
// It can't start with "PUBLIC" or "SYSTEM".
|
||||||
|
// Ignore the rest of the string.
|
||||||
|
return n, quirks || s != ""
|
||||||
|
}
|
||||||
|
|
||||||
|
key := strings.ToLower(s[:6])
|
||||||
|
s = s[6:]
|
||||||
|
for key == "public" || key == "system" {
|
||||||
|
s = strings.TrimLeft(s, whitespace)
|
||||||
|
if s == "" {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
quote := s[0]
|
||||||
|
if quote != '"' && quote != '\'' {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
s = s[1:]
|
||||||
|
q := strings.IndexRune(s, rune(quote))
|
||||||
|
var id string
|
||||||
|
if q == -1 {
|
||||||
|
id = s
|
||||||
|
s = ""
|
||||||
|
} else {
|
||||||
|
id = s[:q]
|
||||||
|
s = s[q+1:]
|
||||||
|
}
|
||||||
|
n.Attr = append(n.Attr, Attribute{Key: key, Val: id})
|
||||||
|
if key == "public" {
|
||||||
|
key = "system"
|
||||||
|
} else {
|
||||||
|
key = ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if key != "" || s != "" {
|
||||||
|
quirks = true
|
||||||
|
} else if len(n.Attr) > 0 {
|
||||||
|
if n.Attr[0].Key == "public" {
|
||||||
|
public := strings.ToLower(n.Attr[0].Val)
|
||||||
|
switch public {
|
||||||
|
case "-//w3o//dtd w3 html strict 3.0//en//", "-/w3d/dtd html 4.0 transitional/en", "html":
|
||||||
|
quirks = true
|
||||||
|
default:
|
||||||
|
for _, q := range quirkyIDs {
|
||||||
|
if strings.HasPrefix(public, q) {
|
||||||
|
quirks = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// The following two public IDs only cause quirks mode if there is no system ID.
|
||||||
|
if len(n.Attr) == 1 && (strings.HasPrefix(public, "-//w3c//dtd html 4.01 frameset//") ||
|
||||||
|
strings.HasPrefix(public, "-//w3c//dtd html 4.01 transitional//")) {
|
||||||
|
quirks = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if lastAttr := n.Attr[len(n.Attr)-1]; lastAttr.Key == "system" &&
|
||||||
|
strings.EqualFold(lastAttr.Val, "http://www.ibm.com/data/dtd/v11/ibmxhtml1-transitional.dtd") {
|
||||||
|
quirks = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return n, quirks
|
||||||
|
}
|
||||||
|
|
||||||
|
// quirkyIDs is a list of public doctype identifiers that cause a document
|
||||||
|
// to be interpreted in quirks mode. The identifiers should be in lower case.
|
||||||
|
var quirkyIDs = []string{
|
||||||
|
"+//silmaril//dtd html pro v0r11 19970101//",
|
||||||
|
"-//advasoft ltd//dtd html 3.0 aswedit + extensions//",
|
||||||
|
"-//as//dtd html 3.0 aswedit + extensions//",
|
||||||
|
"-//ietf//dtd html 2.0 level 1//",
|
||||||
|
"-//ietf//dtd html 2.0 level 2//",
|
||||||
|
"-//ietf//dtd html 2.0 strict level 1//",
|
||||||
|
"-//ietf//dtd html 2.0 strict level 2//",
|
||||||
|
"-//ietf//dtd html 2.0 strict//",
|
||||||
|
"-//ietf//dtd html 2.0//",
|
||||||
|
"-//ietf//dtd html 2.1e//",
|
||||||
|
"-//ietf//dtd html 3.0//",
|
||||||
|
"-//ietf//dtd html 3.2 final//",
|
||||||
|
"-//ietf//dtd html 3.2//",
|
||||||
|
"-//ietf//dtd html 3//",
|
||||||
|
"-//ietf//dtd html level 0//",
|
||||||
|
"-//ietf//dtd html level 1//",
|
||||||
|
"-//ietf//dtd html level 2//",
|
||||||
|
"-//ietf//dtd html level 3//",
|
||||||
|
"-//ietf//dtd html strict level 0//",
|
||||||
|
"-//ietf//dtd html strict level 1//",
|
||||||
|
"-//ietf//dtd html strict level 2//",
|
||||||
|
"-//ietf//dtd html strict level 3//",
|
||||||
|
"-//ietf//dtd html strict//",
|
||||||
|
"-//ietf//dtd html//",
|
||||||
|
"-//metrius//dtd metrius presentational//",
|
||||||
|
"-//microsoft//dtd internet explorer 2.0 html strict//",
|
||||||
|
"-//microsoft//dtd internet explorer 2.0 html//",
|
||||||
|
"-//microsoft//dtd internet explorer 2.0 tables//",
|
||||||
|
"-//microsoft//dtd internet explorer 3.0 html strict//",
|
||||||
|
"-//microsoft//dtd internet explorer 3.0 html//",
|
||||||
|
"-//microsoft//dtd internet explorer 3.0 tables//",
|
||||||
|
"-//netscape comm. corp.//dtd html//",
|
||||||
|
"-//netscape comm. corp.//dtd strict html//",
|
||||||
|
"-//o'reilly and associates//dtd html 2.0//",
|
||||||
|
"-//o'reilly and associates//dtd html extended 1.0//",
|
||||||
|
"-//o'reilly and associates//dtd html extended relaxed 1.0//",
|
||||||
|
"-//softquad software//dtd hotmetal pro 6.0::19990601::extensions to html 4.0//",
|
||||||
|
"-//softquad//dtd hotmetal pro 4.0::19971010::extensions to html 4.0//",
|
||||||
|
"-//spyglass//dtd html 2.0 extended//",
|
||||||
|
"-//sq//dtd html 2.0 hotmetal + extensions//",
|
||||||
|
"-//sun microsystems corp.//dtd hotjava html//",
|
||||||
|
"-//sun microsystems corp.//dtd hotjava strict html//",
|
||||||
|
"-//w3c//dtd html 3 1995-03-24//",
|
||||||
|
"-//w3c//dtd html 3.2 draft//",
|
||||||
|
"-//w3c//dtd html 3.2 final//",
|
||||||
|
"-//w3c//dtd html 3.2//",
|
||||||
|
"-//w3c//dtd html 3.2s draft//",
|
||||||
|
"-//w3c//dtd html 4.0 frameset//",
|
||||||
|
"-//w3c//dtd html 4.0 transitional//",
|
||||||
|
"-//w3c//dtd html experimental 19960712//",
|
||||||
|
"-//w3c//dtd html experimental 970421//",
|
||||||
|
"-//w3c//dtd w3 html//",
|
||||||
|
"-//w3o//dtd w3 html 3.0//",
|
||||||
|
"-//webtechs//dtd mozilla html 2.0//",
|
||||||
|
"-//webtechs//dtd mozilla html//",
|
||||||
|
}
|
||||||
2253
vendor/golang.org/x/net/html/entity.go
generated
vendored
Normal file
2253
vendor/golang.org/x/net/html/entity.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
339
vendor/golang.org/x/net/html/escape.go
generated
vendored
Normal file
339
vendor/golang.org/x/net/html/escape.go
generated
vendored
Normal file
@@ -0,0 +1,339 @@
|
|||||||
|
// Copyright 2010 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package html
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"strings"
|
||||||
|
"unicode/utf8"
|
||||||
|
)
|
||||||
|
|
||||||
|
// These replacements permit compatibility with old numeric entities that
|
||||||
|
// assumed Windows-1252 encoding.
|
||||||
|
// https://html.spec.whatwg.org/multipage/syntax.html#consume-a-character-reference
|
||||||
|
var replacementTable = [...]rune{
|
||||||
|
'\u20AC', // First entry is what 0x80 should be replaced with.
|
||||||
|
'\u0081',
|
||||||
|
'\u201A',
|
||||||
|
'\u0192',
|
||||||
|
'\u201E',
|
||||||
|
'\u2026',
|
||||||
|
'\u2020',
|
||||||
|
'\u2021',
|
||||||
|
'\u02C6',
|
||||||
|
'\u2030',
|
||||||
|
'\u0160',
|
||||||
|
'\u2039',
|
||||||
|
'\u0152',
|
||||||
|
'\u008D',
|
||||||
|
'\u017D',
|
||||||
|
'\u008F',
|
||||||
|
'\u0090',
|
||||||
|
'\u2018',
|
||||||
|
'\u2019',
|
||||||
|
'\u201C',
|
||||||
|
'\u201D',
|
||||||
|
'\u2022',
|
||||||
|
'\u2013',
|
||||||
|
'\u2014',
|
||||||
|
'\u02DC',
|
||||||
|
'\u2122',
|
||||||
|
'\u0161',
|
||||||
|
'\u203A',
|
||||||
|
'\u0153',
|
||||||
|
'\u009D',
|
||||||
|
'\u017E',
|
||||||
|
'\u0178', // Last entry is 0x9F.
|
||||||
|
// 0x00->'\uFFFD' is handled programmatically.
|
||||||
|
// 0x0D->'\u000D' is a no-op.
|
||||||
|
}
|
||||||
|
|
||||||
|
// unescapeEntity reads an entity like "<" from b[src:] and writes the
|
||||||
|
// corresponding "<" to b[dst:], returning the incremented dst and src cursors.
|
||||||
|
// Precondition: b[src] == '&' && dst <= src.
|
||||||
|
// attribute should be true if parsing an attribute value.
|
||||||
|
func unescapeEntity(b []byte, dst, src int, attribute bool) (dst1, src1 int) {
|
||||||
|
// https://html.spec.whatwg.org/multipage/syntax.html#consume-a-character-reference
|
||||||
|
|
||||||
|
// i starts at 1 because we already know that s[0] == '&'.
|
||||||
|
i, s := 1, b[src:]
|
||||||
|
|
||||||
|
if len(s) <= 1 {
|
||||||
|
b[dst] = b[src]
|
||||||
|
return dst + 1, src + 1
|
||||||
|
}
|
||||||
|
|
||||||
|
if s[i] == '#' {
|
||||||
|
if len(s) <= 3 { // We need to have at least "&#.".
|
||||||
|
b[dst] = b[src]
|
||||||
|
return dst + 1, src + 1
|
||||||
|
}
|
||||||
|
i++
|
||||||
|
c := s[i]
|
||||||
|
hex := false
|
||||||
|
if c == 'x' || c == 'X' {
|
||||||
|
hex = true
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
|
||||||
|
x := '\x00'
|
||||||
|
for i < len(s) {
|
||||||
|
c = s[i]
|
||||||
|
i++
|
||||||
|
if hex {
|
||||||
|
if '0' <= c && c <= '9' {
|
||||||
|
x = 16*x + rune(c) - '0'
|
||||||
|
continue
|
||||||
|
} else if 'a' <= c && c <= 'f' {
|
||||||
|
x = 16*x + rune(c) - 'a' + 10
|
||||||
|
continue
|
||||||
|
} else if 'A' <= c && c <= 'F' {
|
||||||
|
x = 16*x + rune(c) - 'A' + 10
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
} else if '0' <= c && c <= '9' {
|
||||||
|
x = 10*x + rune(c) - '0'
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if c != ';' {
|
||||||
|
i--
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
if i <= 3 { // No characters matched.
|
||||||
|
b[dst] = b[src]
|
||||||
|
return dst + 1, src + 1
|
||||||
|
}
|
||||||
|
|
||||||
|
if 0x80 <= x && x <= 0x9F {
|
||||||
|
// Replace characters from Windows-1252 with UTF-8 equivalents.
|
||||||
|
x = replacementTable[x-0x80]
|
||||||
|
} else if x == 0 || (0xD800 <= x && x <= 0xDFFF) || x > 0x10FFFF {
|
||||||
|
// Replace invalid characters with the replacement character.
|
||||||
|
x = '\uFFFD'
|
||||||
|
}
|
||||||
|
|
||||||
|
return dst + utf8.EncodeRune(b[dst:], x), src + i
|
||||||
|
}
|
||||||
|
|
||||||
|
// Consume the maximum number of characters possible, with the
|
||||||
|
// consumed characters matching one of the named references.
|
||||||
|
|
||||||
|
for i < len(s) {
|
||||||
|
c := s[i]
|
||||||
|
i++
|
||||||
|
// Lower-cased characters are more common in entities, so we check for them first.
|
||||||
|
if 'a' <= c && c <= 'z' || 'A' <= c && c <= 'Z' || '0' <= c && c <= '9' {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if c != ';' {
|
||||||
|
i--
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
entityName := string(s[1:i])
|
||||||
|
if entityName == "" {
|
||||||
|
// No-op.
|
||||||
|
} else if attribute && entityName[len(entityName)-1] != ';' && len(s) > i && s[i] == '=' {
|
||||||
|
// No-op.
|
||||||
|
} else if x := entity[entityName]; x != 0 {
|
||||||
|
return dst + utf8.EncodeRune(b[dst:], x), src + i
|
||||||
|
} else if x := entity2[entityName]; x[0] != 0 {
|
||||||
|
dst1 := dst + utf8.EncodeRune(b[dst:], x[0])
|
||||||
|
return dst1 + utf8.EncodeRune(b[dst1:], x[1]), src + i
|
||||||
|
} else if !attribute {
|
||||||
|
maxLen := len(entityName) - 1
|
||||||
|
if maxLen > longestEntityWithoutSemicolon {
|
||||||
|
maxLen = longestEntityWithoutSemicolon
|
||||||
|
}
|
||||||
|
for j := maxLen; j > 1; j-- {
|
||||||
|
if x := entity[entityName[:j]]; x != 0 {
|
||||||
|
return dst + utf8.EncodeRune(b[dst:], x), src + j + 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dst1, src1 = dst+i, src+i
|
||||||
|
copy(b[dst:dst1], b[src:src1])
|
||||||
|
return dst1, src1
|
||||||
|
}
|
||||||
|
|
||||||
|
// unescape unescapes b's entities in-place, so that "a<b" becomes "a<b".
|
||||||
|
// attribute should be true if parsing an attribute value.
|
||||||
|
func unescape(b []byte, attribute bool) []byte {
|
||||||
|
for i, c := range b {
|
||||||
|
if c == '&' {
|
||||||
|
dst, src := unescapeEntity(b, i, i, attribute)
|
||||||
|
for src < len(b) {
|
||||||
|
c := b[src]
|
||||||
|
if c == '&' {
|
||||||
|
dst, src = unescapeEntity(b, dst, src, attribute)
|
||||||
|
} else {
|
||||||
|
b[dst] = c
|
||||||
|
dst, src = dst+1, src+1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return b[0:dst]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
// lower lower-cases the A-Z bytes in b in-place, so that "aBc" becomes "abc".
|
||||||
|
func lower(b []byte) []byte {
|
||||||
|
for i, c := range b {
|
||||||
|
if 'A' <= c && c <= 'Z' {
|
||||||
|
b[i] = c + 'a' - 'A'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
// escapeComment is like func escape but escapes its input bytes less often.
|
||||||
|
// Per https://github.com/golang/go/issues/58246 some HTML comments are (1)
|
||||||
|
// meaningful and (2) contain angle brackets that we'd like to avoid escaping
|
||||||
|
// unless we have to.
|
||||||
|
//
|
||||||
|
// "We have to" includes the '&' byte, since that introduces other escapes.
|
||||||
|
//
|
||||||
|
// It also includes those bytes (not including EOF) that would otherwise end
|
||||||
|
// the comment. Per the summary table at the bottom of comment_test.go, this is
|
||||||
|
// the '>' byte that, per above, we'd like to avoid escaping unless we have to.
|
||||||
|
//
|
||||||
|
// Studying the summary table (and T actions in its '>' column) closely, we
|
||||||
|
// only need to escape in states 43, 44, 49, 51 and 52. State 43 is at the
|
||||||
|
// start of the comment data. State 52 is after a '!'. The other three states
|
||||||
|
// are after a '-'.
|
||||||
|
//
|
||||||
|
// Our algorithm is thus to escape every '&' and to escape '>' if and only if:
|
||||||
|
// - The '>' is after a '!' or '-' (in the unescaped data) or
|
||||||
|
// - The '>' is at the start of the comment data (after the opening "<!--").
|
||||||
|
func escapeComment(w writer, s string) error {
|
||||||
|
// When modifying this function, consider manually increasing the
|
||||||
|
// maxSuffixLen constant in func TestComments, from 6 to e.g. 9 or more.
|
||||||
|
// That increase should only be temporary, not committed, as it
|
||||||
|
// exponentially affects the test running time.
|
||||||
|
|
||||||
|
if len(s) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Loop:
|
||||||
|
// - Grow j such that s[i:j] does not need escaping.
|
||||||
|
// - If s[j] does need escaping, output s[i:j] and an escaped s[j],
|
||||||
|
// resetting i and j to point past that s[j] byte.
|
||||||
|
i := 0
|
||||||
|
for j := 0; j < len(s); j++ {
|
||||||
|
escaped := ""
|
||||||
|
switch s[j] {
|
||||||
|
case '&':
|
||||||
|
escaped = "&"
|
||||||
|
|
||||||
|
case '>':
|
||||||
|
if j > 0 {
|
||||||
|
if prev := s[j-1]; (prev != '!') && (prev != '-') {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
escaped = ">"
|
||||||
|
|
||||||
|
default:
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if i < j {
|
||||||
|
if _, err := w.WriteString(s[i:j]); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if _, err := w.WriteString(escaped); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
i = j + 1
|
||||||
|
}
|
||||||
|
|
||||||
|
if i < len(s) {
|
||||||
|
if _, err := w.WriteString(s[i:]); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// escapeCommentString is to EscapeString as escapeComment is to escape.
|
||||||
|
func escapeCommentString(s string) string {
|
||||||
|
if strings.IndexAny(s, "&>") == -1 {
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
var buf bytes.Buffer
|
||||||
|
escapeComment(&buf, s)
|
||||||
|
return buf.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
const escapedChars = "&'<>\"\r"
|
||||||
|
|
||||||
|
func escape(w writer, s string) error {
|
||||||
|
i := strings.IndexAny(s, escapedChars)
|
||||||
|
for i != -1 {
|
||||||
|
if _, err := w.WriteString(s[:i]); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
var esc string
|
||||||
|
switch s[i] {
|
||||||
|
case '&':
|
||||||
|
esc = "&"
|
||||||
|
case '\'':
|
||||||
|
// "'" is shorter than "'" and apos was not in HTML until HTML5.
|
||||||
|
esc = "'"
|
||||||
|
case '<':
|
||||||
|
esc = "<"
|
||||||
|
case '>':
|
||||||
|
esc = ">"
|
||||||
|
case '"':
|
||||||
|
// """ is shorter than """.
|
||||||
|
esc = """
|
||||||
|
case '\r':
|
||||||
|
esc = " "
|
||||||
|
default:
|
||||||
|
panic("unrecognized escape character")
|
||||||
|
}
|
||||||
|
s = s[i+1:]
|
||||||
|
if _, err := w.WriteString(esc); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
i = strings.IndexAny(s, escapedChars)
|
||||||
|
}
|
||||||
|
_, err := w.WriteString(s)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// EscapeString escapes special characters like "<" to become "<". It
|
||||||
|
// escapes only five such characters: <, >, &, ' and ".
|
||||||
|
// UnescapeString(EscapeString(s)) == s always holds, but the converse isn't
|
||||||
|
// always true.
|
||||||
|
func EscapeString(s string) string {
|
||||||
|
if strings.IndexAny(s, escapedChars) == -1 {
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
var buf bytes.Buffer
|
||||||
|
escape(&buf, s)
|
||||||
|
return buf.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnescapeString unescapes entities like "<" to become "<". It unescapes a
|
||||||
|
// larger range of entities than EscapeString escapes. For example, "á"
|
||||||
|
// unescapes to "á", as does "á" and "&xE1;".
|
||||||
|
// UnescapeString(EscapeString(s)) == s always holds, but the converse isn't
|
||||||
|
// always true.
|
||||||
|
func UnescapeString(s string) string {
|
||||||
|
for _, c := range s {
|
||||||
|
if c == '&' {
|
||||||
|
return string(unescape([]byte(s), false))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return s
|
||||||
|
}
|
||||||
221
vendor/golang.org/x/net/html/foreign.go
generated
vendored
Normal file
221
vendor/golang.org/x/net/html/foreign.go
generated
vendored
Normal file
@@ -0,0 +1,221 @@
|
|||||||
|
// Copyright 2011 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package html
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
func adjustAttributeNames(aa []Attribute, nameMap map[string]string) {
|
||||||
|
for i := range aa {
|
||||||
|
if newName, ok := nameMap[aa[i].Key]; ok {
|
||||||
|
aa[i].Key = newName
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func adjustForeignAttributes(aa []Attribute) {
|
||||||
|
for i, a := range aa {
|
||||||
|
if a.Key == "" || a.Key[0] != 'x' {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
switch a.Key {
|
||||||
|
case "xlink:actuate", "xlink:arcrole", "xlink:href", "xlink:role", "xlink:show",
|
||||||
|
"xlink:title", "xlink:type", "xml:base", "xml:lang", "xml:space", "xmlns:xlink":
|
||||||
|
j := strings.Index(a.Key, ":")
|
||||||
|
aa[i].Namespace = a.Key[:j]
|
||||||
|
aa[i].Key = a.Key[j+1:]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func htmlIntegrationPoint(n *Node) bool {
|
||||||
|
if n.Type != ElementNode {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
switch n.Namespace {
|
||||||
|
case "math":
|
||||||
|
if n.Data == "annotation-xml" {
|
||||||
|
for _, a := range n.Attr {
|
||||||
|
if a.Key == "encoding" {
|
||||||
|
if strings.EqualFold(a.Val, "text/html") || strings.EqualFold(a.Val, "application/xhtml+xml") {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case "svg":
|
||||||
|
switch n.Data {
|
||||||
|
case "desc", "foreignObject", "title":
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func mathMLTextIntegrationPoint(n *Node) bool {
|
||||||
|
if n.Namespace != "math" {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
switch n.Data {
|
||||||
|
case "mi", "mo", "mn", "ms", "mtext":
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// Section 12.2.6.5.
|
||||||
|
var breakout = map[string]bool{
|
||||||
|
"b": true,
|
||||||
|
"big": true,
|
||||||
|
"blockquote": true,
|
||||||
|
"body": true,
|
||||||
|
"br": true,
|
||||||
|
"center": true,
|
||||||
|
"code": true,
|
||||||
|
"dd": true,
|
||||||
|
"div": true,
|
||||||
|
"dl": true,
|
||||||
|
"dt": true,
|
||||||
|
"em": true,
|
||||||
|
"embed": true,
|
||||||
|
"h1": true,
|
||||||
|
"h2": true,
|
||||||
|
"h3": true,
|
||||||
|
"h4": true,
|
||||||
|
"h5": true,
|
||||||
|
"h6": true,
|
||||||
|
"head": true,
|
||||||
|
"hr": true,
|
||||||
|
"i": true,
|
||||||
|
"img": true,
|
||||||
|
"li": true,
|
||||||
|
"listing": true,
|
||||||
|
"menu": true,
|
||||||
|
"meta": true,
|
||||||
|
"nobr": true,
|
||||||
|
"ol": true,
|
||||||
|
"p": true,
|
||||||
|
"pre": true,
|
||||||
|
"ruby": true,
|
||||||
|
"s": true,
|
||||||
|
"small": true,
|
||||||
|
"span": true,
|
||||||
|
"strong": true,
|
||||||
|
"strike": true,
|
||||||
|
"sub": true,
|
||||||
|
"sup": true,
|
||||||
|
"table": true,
|
||||||
|
"tt": true,
|
||||||
|
"u": true,
|
||||||
|
"ul": true,
|
||||||
|
"var": true,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Section 12.2.6.5.
|
||||||
|
var svgTagNameAdjustments = map[string]string{
|
||||||
|
"altglyph": "altGlyph",
|
||||||
|
"altglyphdef": "altGlyphDef",
|
||||||
|
"altglyphitem": "altGlyphItem",
|
||||||
|
"animatecolor": "animateColor",
|
||||||
|
"animatemotion": "animateMotion",
|
||||||
|
"animatetransform": "animateTransform",
|
||||||
|
"clippath": "clipPath",
|
||||||
|
"feblend": "feBlend",
|
||||||
|
"fecolormatrix": "feColorMatrix",
|
||||||
|
"fecomponenttransfer": "feComponentTransfer",
|
||||||
|
"fecomposite": "feComposite",
|
||||||
|
"feconvolvematrix": "feConvolveMatrix",
|
||||||
|
"fediffuselighting": "feDiffuseLighting",
|
||||||
|
"fedisplacementmap": "feDisplacementMap",
|
||||||
|
"fedistantlight": "feDistantLight",
|
||||||
|
"feflood": "feFlood",
|
||||||
|
"fefunca": "feFuncA",
|
||||||
|
"fefuncb": "feFuncB",
|
||||||
|
"fefuncg": "feFuncG",
|
||||||
|
"fefuncr": "feFuncR",
|
||||||
|
"fegaussianblur": "feGaussianBlur",
|
||||||
|
"feimage": "feImage",
|
||||||
|
"femerge": "feMerge",
|
||||||
|
"femergenode": "feMergeNode",
|
||||||
|
"femorphology": "feMorphology",
|
||||||
|
"feoffset": "feOffset",
|
||||||
|
"fepointlight": "fePointLight",
|
||||||
|
"fespecularlighting": "feSpecularLighting",
|
||||||
|
"fespotlight": "feSpotLight",
|
||||||
|
"fetile": "feTile",
|
||||||
|
"feturbulence": "feTurbulence",
|
||||||
|
"foreignobject": "foreignObject",
|
||||||
|
"glyphref": "glyphRef",
|
||||||
|
"lineargradient": "linearGradient",
|
||||||
|
"radialgradient": "radialGradient",
|
||||||
|
"textpath": "textPath",
|
||||||
|
}
|
||||||
|
|
||||||
|
// Section 12.2.6.1
|
||||||
|
var mathMLAttributeAdjustments = map[string]string{
|
||||||
|
"definitionurl": "definitionURL",
|
||||||
|
}
|
||||||
|
|
||||||
|
var svgAttributeAdjustments = map[string]string{
|
||||||
|
"attributename": "attributeName",
|
||||||
|
"attributetype": "attributeType",
|
||||||
|
"basefrequency": "baseFrequency",
|
||||||
|
"baseprofile": "baseProfile",
|
||||||
|
"calcmode": "calcMode",
|
||||||
|
"clippathunits": "clipPathUnits",
|
||||||
|
"diffuseconstant": "diffuseConstant",
|
||||||
|
"edgemode": "edgeMode",
|
||||||
|
"filterunits": "filterUnits",
|
||||||
|
"glyphref": "glyphRef",
|
||||||
|
"gradienttransform": "gradientTransform",
|
||||||
|
"gradientunits": "gradientUnits",
|
||||||
|
"kernelmatrix": "kernelMatrix",
|
||||||
|
"kernelunitlength": "kernelUnitLength",
|
||||||
|
"keypoints": "keyPoints",
|
||||||
|
"keysplines": "keySplines",
|
||||||
|
"keytimes": "keyTimes",
|
||||||
|
"lengthadjust": "lengthAdjust",
|
||||||
|
"limitingconeangle": "limitingConeAngle",
|
||||||
|
"markerheight": "markerHeight",
|
||||||
|
"markerunits": "markerUnits",
|
||||||
|
"markerwidth": "markerWidth",
|
||||||
|
"maskcontentunits": "maskContentUnits",
|
||||||
|
"maskunits": "maskUnits",
|
||||||
|
"numoctaves": "numOctaves",
|
||||||
|
"pathlength": "pathLength",
|
||||||
|
"patterncontentunits": "patternContentUnits",
|
||||||
|
"patterntransform": "patternTransform",
|
||||||
|
"patternunits": "patternUnits",
|
||||||
|
"pointsatx": "pointsAtX",
|
||||||
|
"pointsaty": "pointsAtY",
|
||||||
|
"pointsatz": "pointsAtZ",
|
||||||
|
"preservealpha": "preserveAlpha",
|
||||||
|
"preserveaspectratio": "preserveAspectRatio",
|
||||||
|
"primitiveunits": "primitiveUnits",
|
||||||
|
"refx": "refX",
|
||||||
|
"refy": "refY",
|
||||||
|
"repeatcount": "repeatCount",
|
||||||
|
"repeatdur": "repeatDur",
|
||||||
|
"requiredextensions": "requiredExtensions",
|
||||||
|
"requiredfeatures": "requiredFeatures",
|
||||||
|
"specularconstant": "specularConstant",
|
||||||
|
"specularexponent": "specularExponent",
|
||||||
|
"spreadmethod": "spreadMethod",
|
||||||
|
"startoffset": "startOffset",
|
||||||
|
"stddeviation": "stdDeviation",
|
||||||
|
"stitchtiles": "stitchTiles",
|
||||||
|
"surfacescale": "surfaceScale",
|
||||||
|
"systemlanguage": "systemLanguage",
|
||||||
|
"tablevalues": "tableValues",
|
||||||
|
"targetx": "targetX",
|
||||||
|
"targety": "targetY",
|
||||||
|
"textlength": "textLength",
|
||||||
|
"viewbox": "viewBox",
|
||||||
|
"viewtarget": "viewTarget",
|
||||||
|
"xchannelselector": "xChannelSelector",
|
||||||
|
"ychannelselector": "yChannelSelector",
|
||||||
|
"zoomandpan": "zoomAndPan",
|
||||||
|
}
|
||||||
56
vendor/golang.org/x/net/html/iter.go
generated
vendored
Normal file
56
vendor/golang.org/x/net/html/iter.go
generated
vendored
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
// Copyright 2024 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
//go:build go1.23
|
||||||
|
|
||||||
|
package html
|
||||||
|
|
||||||
|
import "iter"
|
||||||
|
|
||||||
|
// Ancestors returns an iterator over the ancestors of n, starting with n.Parent.
|
||||||
|
//
|
||||||
|
// Mutating a Node or its parents while iterating may have unexpected results.
|
||||||
|
func (n *Node) Ancestors() iter.Seq[*Node] {
|
||||||
|
_ = n.Parent // eager nil check
|
||||||
|
|
||||||
|
return func(yield func(*Node) bool) {
|
||||||
|
for p := n.Parent; p != nil && yield(p); p = p.Parent {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ChildNodes returns an iterator over the immediate children of n,
|
||||||
|
// starting with n.FirstChild.
|
||||||
|
//
|
||||||
|
// Mutating a Node or its children while iterating may have unexpected results.
|
||||||
|
func (n *Node) ChildNodes() iter.Seq[*Node] {
|
||||||
|
_ = n.FirstChild // eager nil check
|
||||||
|
|
||||||
|
return func(yield func(*Node) bool) {
|
||||||
|
for c := n.FirstChild; c != nil && yield(c); c = c.NextSibling {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Descendants returns an iterator over all nodes recursively beneath
|
||||||
|
// n, excluding n itself. Nodes are visited in depth-first preorder.
|
||||||
|
//
|
||||||
|
// Mutating a Node or its descendants while iterating may have unexpected results.
|
||||||
|
func (n *Node) Descendants() iter.Seq[*Node] {
|
||||||
|
_ = n.FirstChild // eager nil check
|
||||||
|
|
||||||
|
return func(yield func(*Node) bool) {
|
||||||
|
n.descendants(yield)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *Node) descendants(yield func(*Node) bool) bool {
|
||||||
|
for c := range n.ChildNodes() {
|
||||||
|
if !yield(c) || !c.descendants(yield) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
229
vendor/golang.org/x/net/html/node.go
generated
vendored
Normal file
229
vendor/golang.org/x/net/html/node.go
generated
vendored
Normal file
@@ -0,0 +1,229 @@
|
|||||||
|
// Copyright 2011 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package html
|
||||||
|
|
||||||
|
import (
|
||||||
|
"golang.org/x/net/html/atom"
|
||||||
|
)
|
||||||
|
|
||||||
|
// A NodeType is the type of a Node.
|
||||||
|
type NodeType uint32
|
||||||
|
|
||||||
|
const (
|
||||||
|
ErrorNode NodeType = iota
|
||||||
|
TextNode
|
||||||
|
DocumentNode
|
||||||
|
ElementNode
|
||||||
|
CommentNode
|
||||||
|
DoctypeNode
|
||||||
|
// RawNode nodes are not returned by the parser, but can be part of the
|
||||||
|
// Node tree passed to func Render to insert raw HTML (without escaping).
|
||||||
|
// If so, this package makes no guarantee that the rendered HTML is secure
|
||||||
|
// (from e.g. Cross Site Scripting attacks) or well-formed.
|
||||||
|
RawNode
|
||||||
|
scopeMarkerNode
|
||||||
|
)
|
||||||
|
|
||||||
|
// Section 12.2.4.3 says "The markers are inserted when entering applet,
|
||||||
|
// object, marquee, template, td, th, and caption elements, and are used
|
||||||
|
// to prevent formatting from "leaking" into applet, object, marquee,
|
||||||
|
// template, td, th, and caption elements".
|
||||||
|
var scopeMarker = Node{Type: scopeMarkerNode}
|
||||||
|
|
||||||
|
// A Node consists of a NodeType and some Data (tag name for element nodes,
|
||||||
|
// content for text) and are part of a tree of Nodes. Element nodes may also
|
||||||
|
// have a Namespace and contain a slice of Attributes. Data is unescaped, so
|
||||||
|
// that it looks like "a<b" rather than "a<b". For element nodes, DataAtom
|
||||||
|
// is the atom for Data, or zero if Data is not a known tag name.
|
||||||
|
//
|
||||||
|
// Node trees may be navigated using the link fields (Parent,
|
||||||
|
// FirstChild, and so on) or a range loop over iterators such as
|
||||||
|
// [Node.Descendants].
|
||||||
|
//
|
||||||
|
// An empty Namespace implies a "http://www.w3.org/1999/xhtml" namespace.
|
||||||
|
// Similarly, "math" is short for "http://www.w3.org/1998/Math/MathML", and
|
||||||
|
// "svg" is short for "http://www.w3.org/2000/svg".
|
||||||
|
type Node struct {
|
||||||
|
Parent, FirstChild, LastChild, PrevSibling, NextSibling *Node
|
||||||
|
|
||||||
|
Type NodeType
|
||||||
|
DataAtom atom.Atom
|
||||||
|
Data string
|
||||||
|
Namespace string
|
||||||
|
Attr []Attribute
|
||||||
|
}
|
||||||
|
|
||||||
|
// InsertBefore inserts newChild as a child of n, immediately before oldChild
|
||||||
|
// in the sequence of n's children. oldChild may be nil, in which case newChild
|
||||||
|
// is appended to the end of n's children.
|
||||||
|
//
|
||||||
|
// It will panic if newChild already has a parent or siblings.
|
||||||
|
func (n *Node) InsertBefore(newChild, oldChild *Node) {
|
||||||
|
if newChild.Parent != nil || newChild.PrevSibling != nil || newChild.NextSibling != nil {
|
||||||
|
panic("html: InsertBefore called for an attached child Node")
|
||||||
|
}
|
||||||
|
var prev, next *Node
|
||||||
|
if oldChild != nil {
|
||||||
|
prev, next = oldChild.PrevSibling, oldChild
|
||||||
|
} else {
|
||||||
|
prev = n.LastChild
|
||||||
|
}
|
||||||
|
if prev != nil {
|
||||||
|
prev.NextSibling = newChild
|
||||||
|
} else {
|
||||||
|
n.FirstChild = newChild
|
||||||
|
}
|
||||||
|
if next != nil {
|
||||||
|
next.PrevSibling = newChild
|
||||||
|
} else {
|
||||||
|
n.LastChild = newChild
|
||||||
|
}
|
||||||
|
newChild.Parent = n
|
||||||
|
newChild.PrevSibling = prev
|
||||||
|
newChild.NextSibling = next
|
||||||
|
}
|
||||||
|
|
||||||
|
// AppendChild adds a node c as a child of n.
|
||||||
|
//
|
||||||
|
// It will panic if c already has a parent or siblings.
|
||||||
|
func (n *Node) AppendChild(c *Node) {
|
||||||
|
if c.Parent != nil || c.PrevSibling != nil || c.NextSibling != nil {
|
||||||
|
panic("html: AppendChild called for an attached child Node")
|
||||||
|
}
|
||||||
|
last := n.LastChild
|
||||||
|
if last != nil {
|
||||||
|
last.NextSibling = c
|
||||||
|
} else {
|
||||||
|
n.FirstChild = c
|
||||||
|
}
|
||||||
|
n.LastChild = c
|
||||||
|
c.Parent = n
|
||||||
|
c.PrevSibling = last
|
||||||
|
}
|
||||||
|
|
||||||
|
// RemoveChild removes a node c that is a child of n. Afterwards, c will have
|
||||||
|
// no parent and no siblings.
|
||||||
|
//
|
||||||
|
// It will panic if c's parent is not n.
|
||||||
|
func (n *Node) RemoveChild(c *Node) {
|
||||||
|
if c.Parent != n {
|
||||||
|
panic("html: RemoveChild called for a non-child Node")
|
||||||
|
}
|
||||||
|
if n.FirstChild == c {
|
||||||
|
n.FirstChild = c.NextSibling
|
||||||
|
}
|
||||||
|
if c.NextSibling != nil {
|
||||||
|
c.NextSibling.PrevSibling = c.PrevSibling
|
||||||
|
}
|
||||||
|
if n.LastChild == c {
|
||||||
|
n.LastChild = c.PrevSibling
|
||||||
|
}
|
||||||
|
if c.PrevSibling != nil {
|
||||||
|
c.PrevSibling.NextSibling = c.NextSibling
|
||||||
|
}
|
||||||
|
c.Parent = nil
|
||||||
|
c.PrevSibling = nil
|
||||||
|
c.NextSibling = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// reparentChildren reparents all of src's child nodes to dst.
|
||||||
|
func reparentChildren(dst, src *Node) {
|
||||||
|
for {
|
||||||
|
child := src.FirstChild
|
||||||
|
if child == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
src.RemoveChild(child)
|
||||||
|
dst.AppendChild(child)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// clone returns a new node with the same type, data and attributes.
|
||||||
|
// The clone has no parent, no siblings and no children.
|
||||||
|
func (n *Node) clone() *Node {
|
||||||
|
m := &Node{
|
||||||
|
Type: n.Type,
|
||||||
|
DataAtom: n.DataAtom,
|
||||||
|
Data: n.Data,
|
||||||
|
Attr: make([]Attribute, len(n.Attr)),
|
||||||
|
}
|
||||||
|
copy(m.Attr, n.Attr)
|
||||||
|
return m
|
||||||
|
}
|
||||||
|
|
||||||
|
// nodeStack is a stack of nodes.
|
||||||
|
type nodeStack []*Node
|
||||||
|
|
||||||
|
// pop pops the stack. It will panic if s is empty.
|
||||||
|
func (s *nodeStack) pop() *Node {
|
||||||
|
i := len(*s)
|
||||||
|
n := (*s)[i-1]
|
||||||
|
*s = (*s)[:i-1]
|
||||||
|
return n
|
||||||
|
}
|
||||||
|
|
||||||
|
// top returns the most recently pushed node, or nil if s is empty.
|
||||||
|
func (s *nodeStack) top() *Node {
|
||||||
|
if i := len(*s); i > 0 {
|
||||||
|
return (*s)[i-1]
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// index returns the index of the top-most occurrence of n in the stack, or -1
|
||||||
|
// if n is not present.
|
||||||
|
func (s *nodeStack) index(n *Node) int {
|
||||||
|
for i := len(*s) - 1; i >= 0; i-- {
|
||||||
|
if (*s)[i] == n {
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
|
||||||
|
// contains returns whether a is within s.
|
||||||
|
func (s *nodeStack) contains(a atom.Atom) bool {
|
||||||
|
for _, n := range *s {
|
||||||
|
if n.DataAtom == a && n.Namespace == "" {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// insert inserts a node at the given index.
|
||||||
|
func (s *nodeStack) insert(i int, n *Node) {
|
||||||
|
(*s) = append(*s, nil)
|
||||||
|
copy((*s)[i+1:], (*s)[i:])
|
||||||
|
(*s)[i] = n
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove removes a node from the stack. It is a no-op if n is not present.
|
||||||
|
func (s *nodeStack) remove(n *Node) {
|
||||||
|
i := s.index(n)
|
||||||
|
if i == -1 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
copy((*s)[i:], (*s)[i+1:])
|
||||||
|
j := len(*s) - 1
|
||||||
|
(*s)[j] = nil
|
||||||
|
*s = (*s)[:j]
|
||||||
|
}
|
||||||
|
|
||||||
|
type insertionModeStack []insertionMode
|
||||||
|
|
||||||
|
func (s *insertionModeStack) pop() (im insertionMode) {
|
||||||
|
i := len(*s)
|
||||||
|
im = (*s)[i-1]
|
||||||
|
*s = (*s)[:i-1]
|
||||||
|
return im
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *insertionModeStack) top() insertionMode {
|
||||||
|
if i := len(*s); i > 0 {
|
||||||
|
return (*s)[i-1]
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
2464
vendor/golang.org/x/net/html/parse.go
generated
vendored
Normal file
2464
vendor/golang.org/x/net/html/parse.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
293
vendor/golang.org/x/net/html/render.go
generated
vendored
Normal file
293
vendor/golang.org/x/net/html/render.go
generated
vendored
Normal file
@@ -0,0 +1,293 @@
|
|||||||
|
// Copyright 2011 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package html
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
type writer interface {
|
||||||
|
io.Writer
|
||||||
|
io.ByteWriter
|
||||||
|
WriteString(string) (int, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Render renders the parse tree n to the given writer.
|
||||||
|
//
|
||||||
|
// Rendering is done on a 'best effort' basis: calling Parse on the output of
|
||||||
|
// Render will always result in something similar to the original tree, but it
|
||||||
|
// is not necessarily an exact clone unless the original tree was 'well-formed'.
|
||||||
|
// 'Well-formed' is not easily specified; the HTML5 specification is
|
||||||
|
// complicated.
|
||||||
|
//
|
||||||
|
// Calling Parse on arbitrary input typically results in a 'well-formed' parse
|
||||||
|
// tree. However, it is possible for Parse to yield a 'badly-formed' parse tree.
|
||||||
|
// For example, in a 'well-formed' parse tree, no <a> element is a child of
|
||||||
|
// another <a> element: parsing "<a><a>" results in two sibling elements.
|
||||||
|
// Similarly, in a 'well-formed' parse tree, no <a> element is a child of a
|
||||||
|
// <table> element: parsing "<p><table><a>" results in a <p> with two sibling
|
||||||
|
// children; the <a> is reparented to the <table>'s parent. However, calling
|
||||||
|
// Parse on "<a><table><a>" does not return an error, but the result has an <a>
|
||||||
|
// element with an <a> child, and is therefore not 'well-formed'.
|
||||||
|
//
|
||||||
|
// Programmatically constructed trees are typically also 'well-formed', but it
|
||||||
|
// is possible to construct a tree that looks innocuous but, when rendered and
|
||||||
|
// re-parsed, results in a different tree. A simple example is that a solitary
|
||||||
|
// text node would become a tree containing <html>, <head> and <body> elements.
|
||||||
|
// Another example is that the programmatic equivalent of "a<head>b</head>c"
|
||||||
|
// becomes "<html><head><head/><body>abc</body></html>".
|
||||||
|
func Render(w io.Writer, n *Node) error {
|
||||||
|
if x, ok := w.(writer); ok {
|
||||||
|
return render(x, n)
|
||||||
|
}
|
||||||
|
buf := bufio.NewWriter(w)
|
||||||
|
if err := render(buf, n); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return buf.Flush()
|
||||||
|
}
|
||||||
|
|
||||||
|
// plaintextAbort is returned from render1 when a <plaintext> element
|
||||||
|
// has been rendered. No more end tags should be rendered after that.
|
||||||
|
var plaintextAbort = errors.New("html: internal error (plaintext abort)")
|
||||||
|
|
||||||
|
func render(w writer, n *Node) error {
|
||||||
|
err := render1(w, n)
|
||||||
|
if err == plaintextAbort {
|
||||||
|
err = nil
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func render1(w writer, n *Node) error {
|
||||||
|
// Render non-element nodes; these are the easy cases.
|
||||||
|
switch n.Type {
|
||||||
|
case ErrorNode:
|
||||||
|
return errors.New("html: cannot render an ErrorNode node")
|
||||||
|
case TextNode:
|
||||||
|
return escape(w, n.Data)
|
||||||
|
case DocumentNode:
|
||||||
|
for c := n.FirstChild; c != nil; c = c.NextSibling {
|
||||||
|
if err := render1(w, c); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
case ElementNode:
|
||||||
|
// No-op.
|
||||||
|
case CommentNode:
|
||||||
|
if _, err := w.WriteString("<!--"); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := escapeComment(w, n.Data); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if _, err := w.WriteString("-->"); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
case DoctypeNode:
|
||||||
|
if _, err := w.WriteString("<!DOCTYPE "); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := escape(w, n.Data); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if n.Attr != nil {
|
||||||
|
var p, s string
|
||||||
|
for _, a := range n.Attr {
|
||||||
|
switch a.Key {
|
||||||
|
case "public":
|
||||||
|
p = a.Val
|
||||||
|
case "system":
|
||||||
|
s = a.Val
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if p != "" {
|
||||||
|
if _, err := w.WriteString(" PUBLIC "); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := writeQuoted(w, p); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if s != "" {
|
||||||
|
if err := w.WriteByte(' '); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := writeQuoted(w, s); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if s != "" {
|
||||||
|
if _, err := w.WriteString(" SYSTEM "); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := writeQuoted(w, s); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return w.WriteByte('>')
|
||||||
|
case RawNode:
|
||||||
|
_, err := w.WriteString(n.Data)
|
||||||
|
return err
|
||||||
|
default:
|
||||||
|
return errors.New("html: unknown node type")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Render the <xxx> opening tag.
|
||||||
|
if err := w.WriteByte('<'); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if _, err := w.WriteString(n.Data); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
for _, a := range n.Attr {
|
||||||
|
if err := w.WriteByte(' '); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if a.Namespace != "" {
|
||||||
|
if _, err := w.WriteString(a.Namespace); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := w.WriteByte(':'); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if _, err := w.WriteString(a.Key); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if _, err := w.WriteString(`="`); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := escape(w, a.Val); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := w.WriteByte('"'); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if voidElements[n.Data] {
|
||||||
|
if n.FirstChild != nil {
|
||||||
|
return fmt.Errorf("html: void element <%s> has child nodes", n.Data)
|
||||||
|
}
|
||||||
|
_, err := w.WriteString("/>")
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := w.WriteByte('>'); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add initial newline where there is danger of a newline beging ignored.
|
||||||
|
if c := n.FirstChild; c != nil && c.Type == TextNode && strings.HasPrefix(c.Data, "\n") {
|
||||||
|
switch n.Data {
|
||||||
|
case "pre", "listing", "textarea":
|
||||||
|
if err := w.WriteByte('\n'); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Render any child nodes
|
||||||
|
if childTextNodesAreLiteral(n) {
|
||||||
|
for c := n.FirstChild; c != nil; c = c.NextSibling {
|
||||||
|
if c.Type == TextNode {
|
||||||
|
if _, err := w.WriteString(c.Data); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if err := render1(w, c); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if n.Data == "plaintext" {
|
||||||
|
// Don't render anything else. <plaintext> must be the
|
||||||
|
// last element in the file, with no closing tag.
|
||||||
|
return plaintextAbort
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for c := n.FirstChild; c != nil; c = c.NextSibling {
|
||||||
|
if err := render1(w, c); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Render the </xxx> closing tag.
|
||||||
|
if _, err := w.WriteString("</"); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if _, err := w.WriteString(n.Data); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return w.WriteByte('>')
|
||||||
|
}
|
||||||
|
|
||||||
|
func childTextNodesAreLiteral(n *Node) bool {
|
||||||
|
// Per WHATWG HTML 13.3, if the parent of the current node is a style,
|
||||||
|
// script, xmp, iframe, noembed, noframes, or plaintext element, and the
|
||||||
|
// current node is a text node, append the value of the node's data
|
||||||
|
// literally. The specification is not explicit about it, but we only
|
||||||
|
// enforce this if we are in the HTML namespace (i.e. when the namespace is
|
||||||
|
// "").
|
||||||
|
// NOTE: we also always include noscript elements, although the
|
||||||
|
// specification states that they should only be rendered as such if
|
||||||
|
// scripting is enabled for the node (which is not something we track).
|
||||||
|
if n.Namespace != "" {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
switch n.Data {
|
||||||
|
case "iframe", "noembed", "noframes", "noscript", "plaintext", "script", "style", "xmp":
|
||||||
|
return true
|
||||||
|
default:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// writeQuoted writes s to w surrounded by quotes. Normally it will use double
|
||||||
|
// quotes, but if s contains a double quote, it will use single quotes.
|
||||||
|
// It is used for writing the identifiers in a doctype declaration.
|
||||||
|
// In valid HTML, they can't contain both types of quotes.
|
||||||
|
func writeQuoted(w writer, s string) error {
|
||||||
|
var q byte = '"'
|
||||||
|
if strings.Contains(s, `"`) {
|
||||||
|
q = '\''
|
||||||
|
}
|
||||||
|
if err := w.WriteByte(q); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if _, err := w.WriteString(s); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := w.WriteByte(q); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Section 12.1.2, "Elements", gives this list of void elements. Void elements
|
||||||
|
// are those that can't have any contents.
|
||||||
|
var voidElements = map[string]bool{
|
||||||
|
"area": true,
|
||||||
|
"base": true,
|
||||||
|
"br": true,
|
||||||
|
"col": true,
|
||||||
|
"embed": true,
|
||||||
|
"hr": true,
|
||||||
|
"img": true,
|
||||||
|
"input": true,
|
||||||
|
"keygen": true, // "keygen" has been removed from the spec, but are kept here for backwards compatibility.
|
||||||
|
"link": true,
|
||||||
|
"meta": true,
|
||||||
|
"param": true,
|
||||||
|
"source": true,
|
||||||
|
"track": true,
|
||||||
|
"wbr": true,
|
||||||
|
}
|
||||||
1286
vendor/golang.org/x/net/html/token.go
generated
vendored
Normal file
1286
vendor/golang.org/x/net/html/token.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
BIN
vendor/golang.org/x/net/publicsuffix/data/children
generated
vendored
Normal file
BIN
vendor/golang.org/x/net/publicsuffix/data/children
generated
vendored
Normal file
Binary file not shown.
BIN
vendor/golang.org/x/net/publicsuffix/data/nodes
generated
vendored
Normal file
BIN
vendor/golang.org/x/net/publicsuffix/data/nodes
generated
vendored
Normal file
Binary file not shown.
1
vendor/golang.org/x/net/publicsuffix/data/text
generated
vendored
Normal file
1
vendor/golang.org/x/net/publicsuffix/data/text
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
205
vendor/golang.org/x/net/publicsuffix/list.go
generated
vendored
Normal file
205
vendor/golang.org/x/net/publicsuffix/list.go
generated
vendored
Normal file
@@ -0,0 +1,205 @@
|
|||||||
|
// Copyright 2012 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
//go:generate go run gen.go
|
||||||
|
|
||||||
|
// Package publicsuffix provides a public suffix list based on data from
|
||||||
|
// https://publicsuffix.org/
|
||||||
|
//
|
||||||
|
// A public suffix is one under which Internet users can directly register
|
||||||
|
// names. It is related to, but different from, a TLD (top level domain).
|
||||||
|
//
|
||||||
|
// "com" is a TLD (top level domain). Top level means it has no dots.
|
||||||
|
//
|
||||||
|
// "com" is also a public suffix. Amazon and Google have registered different
|
||||||
|
// siblings under that domain: "amazon.com" and "google.com".
|
||||||
|
//
|
||||||
|
// "au" is another TLD, again because it has no dots. But it's not "amazon.au".
|
||||||
|
// Instead, it's "amazon.com.au".
|
||||||
|
//
|
||||||
|
// "com.au" isn't an actual TLD, because it's not at the top level (it has
|
||||||
|
// dots). But it is an eTLD (effective TLD), because that's the branching point
|
||||||
|
// for domain name registrars.
|
||||||
|
//
|
||||||
|
// Another name for "an eTLD" is "a public suffix". Often, what's more of
|
||||||
|
// interest is the eTLD+1, or one more label than the public suffix. For
|
||||||
|
// example, browsers partition read/write access to HTTP cookies according to
|
||||||
|
// the eTLD+1. Web pages served from "amazon.com.au" can't read cookies from
|
||||||
|
// "google.com.au", but web pages served from "maps.google.com" can share
|
||||||
|
// cookies from "www.google.com", so you don't have to sign into Google Maps
|
||||||
|
// separately from signing into Google Web Search. Note that all four of those
|
||||||
|
// domains have 3 labels and 2 dots. The first two domains are each an eTLD+1,
|
||||||
|
// the last two are not (but share the same eTLD+1: "google.com").
|
||||||
|
//
|
||||||
|
// All of these domains have the same eTLD+1:
|
||||||
|
// - "www.books.amazon.co.uk"
|
||||||
|
// - "books.amazon.co.uk"
|
||||||
|
// - "amazon.co.uk"
|
||||||
|
//
|
||||||
|
// Specifically, the eTLD+1 is "amazon.co.uk", because the eTLD is "co.uk".
|
||||||
|
//
|
||||||
|
// There is no closed form algorithm to calculate the eTLD of a domain.
|
||||||
|
// Instead, the calculation is data driven. This package provides a
|
||||||
|
// pre-compiled snapshot of Mozilla's PSL (Public Suffix List) data at
|
||||||
|
// https://publicsuffix.org/
|
||||||
|
package publicsuffix // import "golang.org/x/net/publicsuffix"
|
||||||
|
|
||||||
|
// TODO: specify case sensitivity and leading/trailing dot behavior for
|
||||||
|
// func PublicSuffix and func EffectiveTLDPlusOne.
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/http/cookiejar"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// List implements the cookiejar.PublicSuffixList interface by calling the
|
||||||
|
// PublicSuffix function.
|
||||||
|
var List cookiejar.PublicSuffixList = list{}
|
||||||
|
|
||||||
|
type list struct{}
|
||||||
|
|
||||||
|
func (list) PublicSuffix(domain string) string {
|
||||||
|
ps, _ := PublicSuffix(domain)
|
||||||
|
return ps
|
||||||
|
}
|
||||||
|
|
||||||
|
func (list) String() string {
|
||||||
|
return version
|
||||||
|
}
|
||||||
|
|
||||||
|
// PublicSuffix returns the public suffix of the domain using a copy of the
|
||||||
|
// publicsuffix.org database compiled into the library.
|
||||||
|
//
|
||||||
|
// icann is whether the public suffix is managed by the Internet Corporation
|
||||||
|
// for Assigned Names and Numbers. If not, the public suffix is either a
|
||||||
|
// privately managed domain (and in practice, not a top level domain) or an
|
||||||
|
// unmanaged top level domain (and not explicitly mentioned in the
|
||||||
|
// publicsuffix.org list). For example, "foo.org" and "foo.co.uk" are ICANN
|
||||||
|
// domains, "foo.dyndns.org" is a private domain and
|
||||||
|
// "cromulent" is an unmanaged top level domain.
|
||||||
|
//
|
||||||
|
// Use cases for distinguishing ICANN domains like "foo.com" from private
|
||||||
|
// domains like "foo.appspot.com" can be found at
|
||||||
|
// https://wiki.mozilla.org/Public_Suffix_List/Use_Cases
|
||||||
|
func PublicSuffix(domain string) (publicSuffix string, icann bool) {
|
||||||
|
lo, hi := uint32(0), uint32(numTLD)
|
||||||
|
s, suffix, icannNode, wildcard := domain, len(domain), false, false
|
||||||
|
loop:
|
||||||
|
for {
|
||||||
|
dot := strings.LastIndexByte(s, '.')
|
||||||
|
if wildcard {
|
||||||
|
icann = icannNode
|
||||||
|
suffix = 1 + dot
|
||||||
|
}
|
||||||
|
if lo == hi {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
f := find(s[1+dot:], lo, hi)
|
||||||
|
if f == notFound {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
u := uint32(nodes.get(f) >> (nodesBitsTextOffset + nodesBitsTextLength))
|
||||||
|
icannNode = u&(1<<nodesBitsICANN-1) != 0
|
||||||
|
u >>= nodesBitsICANN
|
||||||
|
u = children.get(u & (1<<nodesBitsChildren - 1))
|
||||||
|
lo = u & (1<<childrenBitsLo - 1)
|
||||||
|
u >>= childrenBitsLo
|
||||||
|
hi = u & (1<<childrenBitsHi - 1)
|
||||||
|
u >>= childrenBitsHi
|
||||||
|
switch u & (1<<childrenBitsNodeType - 1) {
|
||||||
|
case nodeTypeNormal:
|
||||||
|
suffix = 1 + dot
|
||||||
|
case nodeTypeException:
|
||||||
|
suffix = 1 + len(s)
|
||||||
|
break loop
|
||||||
|
}
|
||||||
|
u >>= childrenBitsNodeType
|
||||||
|
wildcard = u&(1<<childrenBitsWildcard-1) != 0
|
||||||
|
if !wildcard {
|
||||||
|
icann = icannNode
|
||||||
|
}
|
||||||
|
|
||||||
|
if dot == -1 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
s = s[:dot]
|
||||||
|
}
|
||||||
|
if suffix == len(domain) {
|
||||||
|
// If no rules match, the prevailing rule is "*".
|
||||||
|
return domain[1+strings.LastIndexByte(domain, '.'):], icann
|
||||||
|
}
|
||||||
|
return domain[suffix:], icann
|
||||||
|
}
|
||||||
|
|
||||||
|
const notFound uint32 = 1<<32 - 1
|
||||||
|
|
||||||
|
// find returns the index of the node in the range [lo, hi) whose label equals
|
||||||
|
// label, or notFound if there is no such node. The range is assumed to be in
|
||||||
|
// strictly increasing node label order.
|
||||||
|
func find(label string, lo, hi uint32) uint32 {
|
||||||
|
for lo < hi {
|
||||||
|
mid := lo + (hi-lo)/2
|
||||||
|
s := nodeLabel(mid)
|
||||||
|
if s < label {
|
||||||
|
lo = mid + 1
|
||||||
|
} else if s == label {
|
||||||
|
return mid
|
||||||
|
} else {
|
||||||
|
hi = mid
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return notFound
|
||||||
|
}
|
||||||
|
|
||||||
|
// nodeLabel returns the label for the i'th node.
|
||||||
|
func nodeLabel(i uint32) string {
|
||||||
|
x := nodes.get(i)
|
||||||
|
length := x & (1<<nodesBitsTextLength - 1)
|
||||||
|
x >>= nodesBitsTextLength
|
||||||
|
offset := x & (1<<nodesBitsTextOffset - 1)
|
||||||
|
return text[offset : offset+length]
|
||||||
|
}
|
||||||
|
|
||||||
|
// EffectiveTLDPlusOne returns the effective top level domain plus one more
|
||||||
|
// label. For example, the eTLD+1 for "foo.bar.golang.org" is "golang.org".
|
||||||
|
func EffectiveTLDPlusOne(domain string) (string, error) {
|
||||||
|
if strings.HasPrefix(domain, ".") || strings.HasSuffix(domain, ".") || strings.Contains(domain, "..") {
|
||||||
|
return "", fmt.Errorf("publicsuffix: empty label in domain %q", domain)
|
||||||
|
}
|
||||||
|
|
||||||
|
suffix, _ := PublicSuffix(domain)
|
||||||
|
if len(domain) <= len(suffix) {
|
||||||
|
return "", fmt.Errorf("publicsuffix: cannot derive eTLD+1 for domain %q", domain)
|
||||||
|
}
|
||||||
|
i := len(domain) - len(suffix) - 1
|
||||||
|
if domain[i] != '.' {
|
||||||
|
return "", fmt.Errorf("publicsuffix: invalid public suffix %q for domain %q", suffix, domain)
|
||||||
|
}
|
||||||
|
return domain[1+strings.LastIndexByte(domain[:i], '.'):], nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type uint32String string
|
||||||
|
|
||||||
|
func (u uint32String) get(i uint32) uint32 {
|
||||||
|
off := i * 4
|
||||||
|
u = u[off:] // help the compiler reduce bounds checks
|
||||||
|
return uint32(u[3]) |
|
||||||
|
uint32(u[2])<<8 |
|
||||||
|
uint32(u[1])<<16 |
|
||||||
|
uint32(u[0])<<24
|
||||||
|
}
|
||||||
|
|
||||||
|
type uint40String string
|
||||||
|
|
||||||
|
func (u uint40String) get(i uint32) uint64 {
|
||||||
|
off := uint64(i * (nodesBits / 8))
|
||||||
|
u = u[off:] // help the compiler reduce bounds checks
|
||||||
|
return uint64(u[4]) |
|
||||||
|
uint64(u[3])<<8 |
|
||||||
|
uint64(u[2])<<16 |
|
||||||
|
uint64(u[1])<<24 |
|
||||||
|
uint64(u[0])<<32
|
||||||
|
}
|
||||||
70
vendor/golang.org/x/net/publicsuffix/table.go
generated
vendored
Normal file
70
vendor/golang.org/x/net/publicsuffix/table.go
generated
vendored
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
// generated by go run gen.go; DO NOT EDIT
|
||||||
|
|
||||||
|
package publicsuffix
|
||||||
|
|
||||||
|
import _ "embed"
|
||||||
|
|
||||||
|
const version = "publicsuffix.org's public_suffix_list.dat, git revision 2c960dac3d39ba521eb5db9da192968f5be0aded (2025-03-18T07:22:13Z)"
|
||||||
|
|
||||||
|
const (
|
||||||
|
nodesBits = 40
|
||||||
|
nodesBitsChildren = 10
|
||||||
|
nodesBitsICANN = 1
|
||||||
|
nodesBitsTextOffset = 16
|
||||||
|
nodesBitsTextLength = 6
|
||||||
|
|
||||||
|
childrenBitsWildcard = 1
|
||||||
|
childrenBitsNodeType = 2
|
||||||
|
childrenBitsHi = 14
|
||||||
|
childrenBitsLo = 14
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
nodeTypeNormal = 0
|
||||||
|
nodeTypeException = 1
|
||||||
|
nodeTypeParentOnly = 2
|
||||||
|
)
|
||||||
|
|
||||||
|
// numTLD is the number of top level domains.
|
||||||
|
const numTLD = 1454
|
||||||
|
|
||||||
|
// text is the combined text of all labels.
|
||||||
|
//
|
||||||
|
//go:embed data/text
|
||||||
|
var text string
|
||||||
|
|
||||||
|
// nodes is the list of nodes. Each node is represented as a 40-bit integer,
|
||||||
|
// which encodes the node's children, wildcard bit and node type (as an index
|
||||||
|
// into the children array), ICANN bit and text.
|
||||||
|
//
|
||||||
|
// The layout within the node, from MSB to LSB, is:
|
||||||
|
//
|
||||||
|
// [ 7 bits] unused
|
||||||
|
// [10 bits] children index
|
||||||
|
// [ 1 bits] ICANN bit
|
||||||
|
// [16 bits] text index
|
||||||
|
// [ 6 bits] text length
|
||||||
|
//
|
||||||
|
//go:embed data/nodes
|
||||||
|
var nodes uint40String
|
||||||
|
|
||||||
|
// children is the list of nodes' children, the parent's wildcard bit and the
|
||||||
|
// parent's node type. If a node has no children then their children index
|
||||||
|
// will be in the range [0, 6), depending on the wildcard bit and node type.
|
||||||
|
//
|
||||||
|
// The layout within the uint32, from MSB to LSB, is:
|
||||||
|
//
|
||||||
|
// [ 1 bits] unused
|
||||||
|
// [ 1 bits] wildcard bit
|
||||||
|
// [ 2 bits] node type
|
||||||
|
// [14 bits] high nodes index (exclusive) of children
|
||||||
|
// [14 bits] low nodes index (inclusive) of children
|
||||||
|
//
|
||||||
|
//go:embed data/children
|
||||||
|
var children uint32String
|
||||||
|
|
||||||
|
// max children 870 (capacity 1023)
|
||||||
|
// max text offset 31785 (capacity 65535)
|
||||||
|
// max text length 31 (capacity 63)
|
||||||
|
// max hi 10100 (capacity 16383)
|
||||||
|
// max lo 10095 (capacity 16383)
|
||||||
9
vendor/modules.txt
vendored
9
vendor/modules.txt
vendored
@@ -1,3 +1,7 @@
|
|||||||
|
# github.com/carlmjohnson/requests v0.25.1
|
||||||
|
## explicit; go 1.23.0
|
||||||
|
github.com/carlmjohnson/requests
|
||||||
|
github.com/carlmjohnson/requests/internal/minitrue
|
||||||
# github.com/davecgh/go-spew v1.1.1
|
# github.com/davecgh/go-spew v1.1.1
|
||||||
## explicit
|
## explicit
|
||||||
github.com/davecgh/go-spew/spew
|
github.com/davecgh/go-spew/spew
|
||||||
@@ -10,3 +14,8 @@ github.com/yuin/gopher-lua
|
|||||||
github.com/yuin/gopher-lua/ast
|
github.com/yuin/gopher-lua/ast
|
||||||
github.com/yuin/gopher-lua/parse
|
github.com/yuin/gopher-lua/parse
|
||||||
github.com/yuin/gopher-lua/pm
|
github.com/yuin/gopher-lua/pm
|
||||||
|
# golang.org/x/net v0.38.0
|
||||||
|
## explicit; go 1.23.0
|
||||||
|
golang.org/x/net/html
|
||||||
|
golang.org/x/net/html/atom
|
||||||
|
golang.org/x/net/publicsuffix
|
||||||
|
|||||||
Reference in New Issue
Block a user