├── .github
└── workflows
│ ├── middlewares.yml
│ ├── non-regression.yml
│ └── release.yml
├── .gitignore
├── .golangci.yml
├── .goreleaser.yml
├── .traefik.yml
├── LICENSE
├── Makefile
├── README.md
├── docs
├── esi_1.jpg
└── esi_2.jpg
├── esi.go
├── esi
├── choose.go
├── comment.go
├── errors.go
├── escape.go
├── esi.go
├── esi_test.go
├── include.go
├── remove.go
├── tags.go
├── try.go
├── type.go
├── vars.go
├── vars_test.go
├── when.go
└── when_test.go
├── fixtures
├── alt
├── choose
├── comment
├── escape
├── full.html
├── include
├── remove
├── try
└── vars
├── go.mod
├── middleware
├── caddy
│ ├── .gitignore
│ ├── Caddyfile
│ ├── Makefile
│ ├── esi.go
│ ├── esi_test.go
│ ├── go.mod
│ └── go.sum
├── roadrunner
│ ├── Makefile
│ ├── README.md
│ ├── esi.go
│ ├── esi_test.go
│ ├── examples
│ │ ├── .gitignore
│ │ ├── .rr.yaml
│ │ ├── Dockerfile.test
│ │ ├── composer.json
│ │ ├── composer.lock
│ │ ├── configuration.toml
│ │ ├── docker-compose.yml.test
│ │ └── psr-worker.php
│ ├── go.mod
│ └── go.sum
├── server
│ └── main.go
├── standalone
│ └── main.go
└── traefik
│ ├── Makefile
│ ├── docker-compose.yml
│ ├── esi-configuration.yml
│ ├── esi.go
│ ├── go.mod
│ ├── go.sum
│ ├── traefik.yml
│ └── vendor
│ ├── github.com
│ └── darkweak
│ │ └── go-esi
│ │ ├── LICENSE
│ │ ├── esi
│ │ ├── choose.go
│ │ ├── comment.go
│ │ ├── errors.go
│ │ ├── escape.go
│ │ ├── esi.go
│ │ ├── include.go
│ │ ├── remove.go
│ │ ├── tags.go
│ │ ├── try.go
│ │ ├── type.go
│ │ ├── vars.go
│ │ └── when.go
│ │ └── writer
│ │ └── writer.go
│ └── modules.txt
└── writer
└── writer.go
/.github/workflows/middlewares.yml:
--------------------------------------------------------------------------------
1 | name: Build and validate go-esi as middleware
2 |
3 | on:
4 | - pull_request
5 |
6 | jobs:
7 | build-caddy-validator:
8 | name: Check that go-esi build as caddy module
9 | runs-on: ubuntu-latest
10 | steps:
11 | -
12 | name: Add domain.com host to /etc/hosts
13 | run: |
14 | sudo echo "127.0.0.1 domain.com" | sudo tee -a /etc/hosts
15 | -
16 | name: Install Go
17 | uses: actions/setup-go@v3
18 | with:
19 | go-version: 1.19
20 | -
21 | name: Checkout code
22 | uses: actions/checkout@v3
23 | -
24 | name: Install xcaddy
25 | run: go install github.com/caddyserver/xcaddy/cmd/xcaddy@latest
26 | -
27 | name: Build go-esi as caddy module
28 | run: cd middleware/caddy && xcaddy build --with github.com/darkweak/go-esi/middleware/caddy=./ --with github.com/darkweak/go-esi@latest=../..
29 | -
30 | name: Run Caddy tests
31 | run: cd middleware/caddy && go test -v ./...
32 | -
33 | name: Run detached caddy
34 | run: cd middleware/caddy && ./caddy run &
35 |
36 | build-roadrunner-validator:
37 | name: Check that go-esi build as roadrunner middleware
38 | runs-on: ubuntu-latest
39 | steps:
40 | -
41 | name: Install Go
42 | uses: actions/setup-go@v3
43 | with:
44 | go-version: 1.19
45 | -
46 | name: Checkout code
47 | uses: actions/checkout@v3
48 | -
49 | name: Run Roadrunner tests
50 | run: cd middleware/roadrunner && go test -v ./...
51 |
--------------------------------------------------------------------------------
/.github/workflows/non-regression.yml:
--------------------------------------------------------------------------------
1 | name: Build container and validate lint/tests
2 |
3 | on:
4 | pull_request:
5 | workflow_dispatch:
6 |
7 | jobs:
8 | lint-and-tests:
9 | name: lint and static tests
10 | runs-on: ubuntu-latest
11 | steps:
12 | -
13 | name: Add domain.com host to /etc/hosts
14 | run: |
15 | sudo echo "127.0.0.1 domain.com" | sudo tee -a /etc/hosts
16 | -
17 | name: checkout code
18 | uses: actions/checkout@v3
19 | -
20 | name: install Go
21 | uses: actions/setup-go@v3
22 | with:
23 | go-version: 1.19
24 | -
25 | name: golangci-lint
26 | uses: golangci/golangci-lint-action@v3
27 | -
28 | name: install xcaddy
29 | run: go install github.com/caddyserver/xcaddy/cmd/xcaddy@latest
30 | -
31 | name: build caddy binary
32 | run: cd middleware/caddy && make build && cd -
33 | -
34 | name: run caddy binary as detached mode
35 | run: cd middleware/caddy && make run &
36 | -
37 | name: tests
38 | run: go test -v -race ./...
39 |
--------------------------------------------------------------------------------
/.github/workflows/release.yml:
--------------------------------------------------------------------------------
1 | name: Build container and publish to docker hub
2 |
3 | on:
4 | create:
5 | tags: ["v*"]
6 |
7 | jobs:
8 | generate-artifacts:
9 | name: Deploy to goreleaser
10 | runs-on: ubuntu-latest
11 | steps:
12 | -
13 | name: Set up Go
14 | uses: actions/setup-go@v2
15 | with:
16 | go-version: 1.19
17 | -
18 | name: Checkout
19 | uses: actions/checkout@v2
20 | with:
21 | fetch-depth: 0
22 | -
23 | name: Run GoReleaser
24 | uses: goreleaser/goreleaser-action@v3
25 | with:
26 | version: latest
27 | args: release --rm-dist
28 | workdir: ./middleware/server
29 | env:
30 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
31 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/darkweak/go-esi/dfdfaa8466f9c7cc840040aeb753ee0887c0d431/.gitignore
--------------------------------------------------------------------------------
/.golangci.yml:
--------------------------------------------------------------------------------
1 | run:
2 | timeout: 30s
3 | issues-exit-code: 1
4 |
5 | linters:
6 | enable-all: true
7 | disable:
8 | - bodyclose
9 | - cyclop
10 | - exhaustivestruct
11 | - exhaustruct
12 | - forbidigo
13 | - gochecknoglobals
14 | - gci
15 | - golint
16 | - gomnd
17 | - ifshort
18 | - ireturn
19 | - nestif
20 | - nonamedreturns
21 | - nosnakecase
22 | - revive
23 | - testpackage
24 | - stylecheck
25 | - varnamelen
26 |
--------------------------------------------------------------------------------
/.goreleaser.yml:
--------------------------------------------------------------------------------
1 | before:
2 | hooks:
3 | - go mod download
4 | builds:
5 | - <<: &build_defaults
6 | ldflags:
7 | - -s -w
8 | env:
9 | - CGO_ENABLED=0
10 | goos:
11 | - linux
12 | - darwin
13 | - windows
14 | goarch:
15 | - 386
16 | - amd64
17 | - arm
18 | - arm64
19 | ignore:
20 | - goos: windows
21 | goarch: arm64
22 | archives:
23 | -
24 | replacements:
25 | darwin: Darwin
26 | linux: Linux
27 | windows: Windows
28 | 386: i386
29 | amd64: x86_64
30 | format_overrides:
31 | -
32 | goos: windows
33 | format: zip
34 |
--------------------------------------------------------------------------------
/.traefik.yml:
--------------------------------------------------------------------------------
1 | displayName: ESI
2 | type: middleware
3 | import: github.com/darkweak/go-esi/middleware/traefik
4 | summary: 'Pure implementation of the ESI process'
5 |
6 | testData: {}
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2022 darkweak
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | .PHONY: bump-version lint run-caddy run-roadrunner run-server run-traefik vendor
2 | MIDDLEWARES_LIST=caddy roadrunner server traefik
3 |
4 | bump-version:
5 | test $(from)
6 | test $(to)
7 | sed -i '' 's/version: $(from)/version: $(to)/' README.md
8 | for middleware in $(MIDDLEWARES_LIST) ; do \
9 | sed -i '' 's/github.com\/darkweak\/go-esi $(from)/github.com\/darkweak\/go-esi $(to)/' middleware/$$middleware/go.mod ; \
10 | done
11 |
12 | lint: ## Run golangci-lint to ensure the code quality
13 | docker run --rm -v $(PWD):/app -w /app golangci/golangci-lint golangci-lint run
14 |
15 | run-caddy: ## Build and run caddy binary
16 | cd middleware/caddy && $(MAKE) build && $(MAKE) run
17 |
18 | run-roadrunner: ## Build and run roadrunner
19 | cd middleware/roadrunner && $(MAKE) build && $(MAKE) run
20 |
21 | run-server: ## Run server main.go
22 | go run middleware/server/main.go
23 |
24 | run-traefik: ## Build and run træfik
25 | cd middleware/traefik && $(MAKE) build && $(MAKE) run
26 |
27 | vendor: ## Generate and prepare vendors for each plugin
28 | go mod tidy && go mod download
29 | for middleware in $(MIDDLEWARES_LIST) ; do \
30 | cd middleware/$$middleware && ($(MAKE) build || true) && cd -; done
31 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | go-esi
2 | ------
3 |
4 | go-esi is the implementation of the non-standard ESI (Edge-Side-Include) specification from the w3. With that you'll be able to use the ESI tags and process them in your favorite golang servers.
5 |
6 | ## What are the ESI tags
7 | The ESI tags were introduced by Akamai to add some dynamic tags and only re-render these parts on the server-side.
8 | The goal of that is to render only specific parts. For example, we want to render a full e-commerce webpage but only the cart is user-dependent. So we could render the "static" parts and store with a predefined TTL (e.g. 60 minutes), and only the cart would be requested to render the block.
9 |
10 | There are multiple `esi` tags that we can use but the most used is the `esi:include` because that's the one to request another resource.
11 |
12 | We can have many `esi:include` tags in a single response, and each `esi:include` tags can itself have one or more `esi:include` tags.
13 |
14 | 
15 |
16 | We can have multiple `esi:include` tags in the page to request another resource and add its content to the main page.
17 |
18 | 
19 |
20 | ## References
21 | https://www.w3.org/TR/esi-lang/
22 |
23 | ## Install
24 | ```bash
25 | go get -u github.com/darkweak/go-esi
26 | ```
27 |
28 | ## Usage
29 | ```go
30 | import (
31 | // ...
32 | github.com/darkweak/go-esi/esi
33 | )
34 |
35 | //...
36 |
37 | func functionToParseESITags(b []byte, r *http.Request) []byte {
38 | // Returns the parsed response.
39 | res := esi.Parse(b, r)
40 |
41 | //...
42 | return res
43 | }
44 | ```
45 |
46 | ## Available as middleware
47 | - [x] Caddy
48 | - [x] Træfik
49 | - [x] Roadrunner
50 |
51 | ### Caddy middleware
52 | ```bash
53 | xcaddy build --with github.com/darkweak/go-esi/middleware/caddy
54 | ```
55 | Refer to the [sample Caddyfile](https://github.com/darkweak/go-esi/blob/master/middleware/caddy/Caddyfile) to know how to use that.
56 |
57 | ### Roadrunner middleware
58 | To use the `go-esi` processor as Roadrunner middleware, you just have to follow the steps below.
59 | You have to build your `rr` binary with the `go-esi` dependency.
60 | ```toml
61 | [velox]
62 | build_args = ['-trimpath', '-ldflags', '-s -X github.com/roadrunner-server/roadrunner/v2/internal/meta.version=v2.12.0 -X github.com/roadrunner-server/roadrunner/v2/internal/meta.buildTime=10:00:00']
63 |
64 | [roadrunner]
65 | ref = "v2.12.3"
66 |
67 | [github]
68 | [github.token]
69 | token = "GH_TOKEN"
70 |
71 | [github.plugins]
72 | logger = { ref = "v3.2.0", owner = "roadrunner-server", repository = "logger" }
73 | esi = { ref = "master", owner = "darkweak", repository = "go-esi", folder = "middleware/roadrunner", replace = "/opt/middleware/roadrunner" }
74 | server = { ref = "v3.2.0", owner = "roadrunner-server", repository = "server" }
75 | gzip = { ref = "v3.2.0", owner = "roadrunner-server", repository = "gzip" }
76 | http = { ref = "v3.2.0", owner = "roadrunner-server", repository = "http" }
77 |
78 | [log]
79 | level = "debug"
80 | mode = "development"
81 | ```
82 |
83 | After that, you'll be able to set enable and add the esi processor to the middleware chain.
84 | ```yaml
85 | # .rr.yaml
86 | http:
87 | # Other http sub keys
88 | esi: {}
89 | middleware:
90 | - headers
91 | - gzip
92 | - esi
93 | ```
94 |
95 | ### Træfik middleware
96 | ```yaml
97 | # anywhere/traefik.yml
98 | experimental:
99 | plugins:
100 | souin:
101 | moduleName: github.com/darkweak/go-esi
102 | version: v0.0.6
103 | ```
104 | ```yaml
105 | # anywhere/dynamic-configuration
106 | http:
107 | routers:
108 | whoami:
109 | middlewares:
110 | - esi
111 | service: whoami
112 | rule: Host(`domain.com`)
113 | middlewares:
114 | esi:
115 | plugin:
116 | esi: {}
117 | ```
118 | Refer to the [sample traefik file](https://github.com/darkweak/go-esi/blob/master/middleware/traefik/esi-configuration.yml) to know how to use that.
119 |
120 | ## TODO
121 | - [x] choose tag
122 | - [x] comment tag
123 | - [x] escape tag
124 | - [x] include tag
125 | - [x] remove tag
126 | - [x] otherwise tag
127 | - [ ] try tag
128 | - [x] vars tag
129 | - [x] when tag
--------------------------------------------------------------------------------
/docs/esi_1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/darkweak/go-esi/dfdfaa8466f9c7cc840040aeb753ee0887c0d431/docs/esi_1.jpg
--------------------------------------------------------------------------------
/docs/esi_2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/darkweak/go-esi/dfdfaa8466f9c7cc840040aeb753ee0887c0d431/docs/esi_2.jpg
--------------------------------------------------------------------------------
/esi.go:
--------------------------------------------------------------------------------
1 | package go_esi
2 |
--------------------------------------------------------------------------------
/esi/choose.go:
--------------------------------------------------------------------------------
1 | package esi
2 |
3 | import (
4 | "net/http"
5 | "regexp"
6 | )
7 |
8 | const choose = "choose"
9 |
10 | var (
11 | closeChoose = regexp.MustCompile("")
12 | whenRg = regexp.MustCompile(`(?s)(.+?)`)
13 | otherwiseRg = regexp.MustCompile(`(?s)(.+?)`)
14 | )
15 |
16 | type chooseTag struct {
17 | *baseTag
18 | }
19 |
20 | // Input (e.g.
21 | //
22 | //
23 | //
24 | //
25 | //
26 | //
27 | //
28 | //
29 | //
30 | //
31 | //
32 | //
33 | //
34 | // ).
35 | func (c *chooseTag) Process(b []byte, req *http.Request) ([]byte, int) {
36 | found := closeChoose.FindIndex(b)
37 | if found == nil {
38 | return nil, len(b)
39 | }
40 |
41 | c.length = found[1]
42 | tagIdxs := whenRg.FindAllSubmatch(b, -1)
43 |
44 | var res []byte
45 |
46 | for _, v := range tagIdxs {
47 | if validateTest(v[1], req) {
48 | res = Parse(v[2], req)
49 |
50 | return res, c.length
51 | }
52 | }
53 |
54 | tagIdx := otherwiseRg.FindSubmatch(b)
55 | if tagIdx != nil {
56 | res = Parse(tagIdx[1], req)
57 | }
58 |
59 | return res, c.length
60 | }
61 |
62 | func (*chooseTag) HasClose(b []byte) bool {
63 | return closeChoose.FindIndex(b) != nil
64 | }
65 |
66 | func (*chooseTag) GetClosePosition(b []byte) int {
67 | if idx := closeChoose.FindIndex(b); idx != nil {
68 | return idx[1]
69 | }
70 |
71 | return 0
72 | }
73 |
--------------------------------------------------------------------------------
/esi/comment.go:
--------------------------------------------------------------------------------
1 | package esi
2 |
3 | import (
4 | "net/http"
5 | "regexp"
6 | )
7 |
8 | const comment = "comment"
9 |
10 | var closeComment = regexp.MustCompile("/>((\n| +)+)?")
11 |
12 | type commentTag struct {
13 | *baseTag
14 | }
15 |
16 | // Input (e.g. comment text="This is a comment." />).
17 | func (c *commentTag) Process(b []byte, req *http.Request) ([]byte, int) {
18 | found := closeComment.FindIndex(b)
19 | if found == nil {
20 | return nil, len(b)
21 | }
22 |
23 | return []byte{}, found[1]
24 | }
25 |
26 | func (*commentTag) HasClose(b []byte) bool {
27 | return closeComment.FindIndex(b) != nil
28 | }
29 |
30 | func (*commentTag) GetClosePosition(b []byte) int {
31 | if idx := closeComment.FindIndex(b); idx != nil {
32 | return idx[1]
33 | }
34 |
35 | return 0
36 | }
37 |
--------------------------------------------------------------------------------
/esi/errors.go:
--------------------------------------------------------------------------------
1 | package esi
2 |
3 | import "errors"
4 |
5 | var errNotFound = errors.New("not found")
6 |
--------------------------------------------------------------------------------
/esi/escape.go:
--------------------------------------------------------------------------------
1 | package esi
2 |
3 | import (
4 | "net/http"
5 | "regexp"
6 | )
7 |
8 | const escape = "")
13 | startEscape = regexp.MustCompile("((\n| +)+)?")
14 | )
15 |
16 | type escapeTag struct {
17 | *baseTag
18 | }
19 |
20 | func (e *escapeTag) Process(b []byte, req *http.Request) ([]byte, int) {
21 | closeIdx := closeEscape.FindIndex(b)
22 |
23 | if closeIdx == nil {
24 | return nil, len(b)
25 | }
26 |
27 | startPosition := 0
28 | if startIdx := startEscape.FindIndex(b); startIdx != nil {
29 | startPosition = startIdx[1]
30 | }
31 |
32 | e.length = closeIdx[1]
33 | b = b[startPosition:closeIdx[0]]
34 |
35 | return b, e.length
36 | }
37 |
38 | func (*escapeTag) HasClose(b []byte) bool {
39 | return closeEscape.FindIndex(b) != nil
40 | }
41 |
42 | func (*escapeTag) GetClosePosition(b []byte) int {
43 | if idx := closeEscape.FindIndex(b); idx != nil {
44 | return idx[1]
45 | }
46 |
47 | return 0
48 | }
49 |
--------------------------------------------------------------------------------
/esi/esi.go:
--------------------------------------------------------------------------------
1 | package esi
2 |
3 | import (
4 | "net/http"
5 | )
6 |
7 | func findTagName(b []byte) Tag {
8 | name := tagname.FindSubmatch(b)
9 | if name == nil {
10 | return nil
11 | }
12 |
13 | switch string(name[1]) {
14 | case comment:
15 | return &commentTag{
16 | baseTag: newBaseTag(),
17 | }
18 | case choose:
19 | return &chooseTag{
20 | baseTag: newBaseTag(),
21 | }
22 | case escape:
23 | return &escapeTag{
24 | baseTag: newBaseTag(),
25 | }
26 | case include:
27 | return &includeTag{
28 | baseTag: newBaseTag(),
29 | }
30 | case remove:
31 | return &removeTag{
32 | baseTag: newBaseTag(),
33 | }
34 | case try:
35 | case vars:
36 | return &varsTag{
37 | baseTag: newBaseTag(),
38 | }
39 | default:
40 | return nil
41 | }
42 |
43 | return nil
44 | }
45 |
46 | func HasOpenedTags(b []byte) bool {
47 | return esi.FindIndex(b) != nil || escapeRg.FindIndex(b) != nil
48 | }
49 |
50 | func CanProcess(b []byte) bool {
51 | if tag := findTagName(b); tag != nil {
52 | return tag.HasClose(b)
53 | }
54 |
55 | return false
56 | }
57 |
58 | func ReadToTag(next []byte, pointer int) (startTagPosition, esiPointer int, t Tag) {
59 | var isEscapeTag bool
60 |
61 | tagIdx := esi.FindIndex(next)
62 |
63 | if escIdx := escapeRg.FindIndex(next); escIdx != nil && (tagIdx == nil || escIdx[0] < tagIdx[0]) {
64 | tagIdx = escIdx
65 | tagIdx[1] = escIdx[0]
66 | isEscapeTag = true
67 | }
68 |
69 | if tagIdx == nil {
70 | return len(next), 0, nil
71 | }
72 |
73 | esiPointer = tagIdx[1]
74 | startTagPosition = tagIdx[0]
75 | t = findTagName(next[esiPointer:])
76 |
77 | if isEscapeTag {
78 | esiPointer += 7
79 | }
80 |
81 | return
82 | }
83 |
84 | func Parse(b []byte, req *http.Request) []byte {
85 | pointer := 0
86 |
87 | for pointer < len(b) {
88 | var escapeTag bool
89 |
90 | next := b[pointer:]
91 | tagIdx := esi.FindIndex(next)
92 |
93 | if escIdx := escapeRg.FindIndex(next); escIdx != nil && (tagIdx == nil || escIdx[0] < tagIdx[0]) {
94 | tagIdx = escIdx
95 | tagIdx[1] = escIdx[0]
96 | escapeTag = true
97 | }
98 |
99 | if tagIdx == nil {
100 | break
101 | }
102 |
103 | esiPointer := tagIdx[1]
104 | t := findTagName(next[esiPointer:])
105 |
106 | if escapeTag {
107 | esiPointer += 7
108 | }
109 |
110 | res, p := t.Process(next[esiPointer:], req)
111 | esiPointer += p
112 |
113 | b = append(b[:pointer], append(next[:tagIdx[0]], append(res, next[esiPointer:]...)...)...)
114 | pointer += len(res) + tagIdx[0]
115 | }
116 |
117 | return b
118 | }
119 |
--------------------------------------------------------------------------------
/esi/esi_test.go:
--------------------------------------------------------------------------------
1 | package esi_test
2 |
3 | import (
4 | "net/http"
5 | "net/http/httptest"
6 | "os"
7 | "testing"
8 |
9 | "github.com/darkweak/go-esi/esi"
10 | )
11 |
12 | func loadFromFixtures(name string) []byte {
13 | b, e := os.ReadFile("../fixtures/" + name)
14 | if e != nil {
15 | panic("The file " + name + " doesn't exist.")
16 | }
17 |
18 | return b
19 | }
20 |
21 | func getRequest() *http.Request {
22 | return httptest.NewRequest(http.MethodGet, "http://domain.com:9080", nil)
23 | }
24 |
25 | var expected = map[string]string{
26 | "include": `
CHAINED 2
`,
27 | "comment": `CHAINED 2
`,
28 | "choose": `
29 |
30 |
CHAINED 2
31 |
32 | `,
33 | "full.html": `
34 |
35 | Hello from domain.com:9080
36 |
37 |
38 |
39 |
40 | CHAINED 2
41 | ALTERNATE ESI INCLUDE
42 |
43 |
44 |
ESI INCLUDE
45 |
46 |
47 |
48 |
49 | `,
50 | "escape": `Hello, $(HTTP_COOKIE{name})!
`,
51 | "remove": `CHAINED 2
52 |
53 | CHAINED 2
54 | CHAINED 2
`,
55 | "vars": `
56 |
57 |
58 |
59 |
`,
60 | }
61 |
62 | func verify(t *testing.T, fixture string) {
63 | t.Helper()
64 |
65 | if result := string(esi.Parse(loadFromFixtures(fixture), getRequest())); result != expected[fixture] {
66 | t.Errorf("ESI parsing mismatch from `%s` expected\nExpected:\n%+v\nGiven:\n%+v\n", fixture, expected[fixture], result)
67 | }
68 | }
69 |
70 | func Test_Parse_includeMock(t *testing.T) {
71 | t.Parallel()
72 | verify(t, "include")
73 | }
74 |
75 | func Test_Parse_commentMock(t *testing.T) {
76 | t.Parallel()
77 | verify(t, "comment")
78 | }
79 |
80 | func Test_Parse_chooseMock(t *testing.T) {
81 | t.Parallel()
82 | verify(t, "choose")
83 | }
84 |
85 | func Test_Parse_escapeMock(t *testing.T) {
86 | t.Parallel()
87 | verify(t, "escape")
88 | }
89 |
90 | func Test_Parse_removeMock(t *testing.T) {
91 | t.Parallel()
92 | verify(t, "remove")
93 | }
94 |
95 | func Test_Parse_varsMock(t *testing.T) {
96 | t.Parallel()
97 |
98 | req := httptest.NewRequest(http.MethodGet, "http://domain.com:9080", nil)
99 | req.AddCookie(&http.Cookie{
100 | Name: "type",
101 | Value: "my_value",
102 | })
103 | req.Header.Add("Accept-Language", "en")
104 |
105 | if result := string(esi.Parse(loadFromFixtures("vars"), req)); result != expected["vars"] {
106 | t.Errorf("ESI parsing mismatch from `%s` expected\nExpected:\n%+v\nGiven:\n%+v\n", "vars", expected["vars"], result)
107 | }
108 | }
109 |
110 | func Test_Parse_fullMock(t *testing.T) {
111 | t.Parallel()
112 | verify(t, "full.html")
113 | }
114 |
115 | // Benchmarks.
116 | func BenchmarkInclude(b *testing.B) {
117 | for i := 0; i < b.N; i++ {
118 | esi.Parse(
119 | []byte(
120 | ``,
121 | ),
122 | httptest.NewRequest(http.MethodGet, "http://domain.com:9080", nil),
123 | )
124 | }
125 | }
126 |
127 | var remove = `
128 |
129 | www.example.com
130 |
131 |
132 | `
133 |
134 | func BenchmarkRemove(b *testing.B) {
135 | for i := 0; i < b.N; i++ {
136 | esi.Parse(
137 | []byte(remove),
138 | httptest.NewRequest(http.MethodGet, "http://domain.com:9080", nil),
139 | )
140 | }
141 | }
142 |
143 | const full = `
144 |
145 | Hello from $(HTTP_HOST)
146 |
147 |
148 |
149 |
150 |
151 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 | `
172 |
173 | func BenchmarkFull(b *testing.B) {
174 | for i := 0; i < b.N; i++ {
175 | esi.Parse(
176 | []byte(full),
177 | httptest.NewRequest(http.MethodGet, "http://domain.com:9080", nil),
178 | )
179 | }
180 | }
181 |
--------------------------------------------------------------------------------
/esi/include.go:
--------------------------------------------------------------------------------
1 | package esi
2 |
3 | import (
4 | "bytes"
5 | "context"
6 | "io"
7 | "net/http"
8 | "net/url"
9 | "regexp"
10 | )
11 |
12 | const include = "include"
13 |
14 | var (
15 | closeInclude = regexp.MustCompile("/>")
16 | srcAttribute = regexp.MustCompile(`src="?(.+?)"?( |/>)`)
17 | altAttribute = regexp.MustCompile(`alt="?(.+?)"?( |/>)`)
18 | onErrorAttribute = regexp.MustCompile(`onerror="?(.+?)"?( |/>)`)
19 | )
20 |
21 | // safe to pass to any origin.
22 | var headersSafe = []string{
23 | "Accept",
24 | "Accept-Language",
25 | }
26 |
27 | // safe to pass only to same-origin (same scheme, same host, same port).
28 | var headersUnsafe = []string{
29 | "Cookie",
30 | "Authorization",
31 | }
32 |
33 | type includeTag struct {
34 | *baseTag
35 | silent bool
36 | alt string
37 | src string
38 | }
39 |
40 | func (i *includeTag) loadAttributes(b []byte) error {
41 | src := srcAttribute.FindSubmatch(b)
42 | if src == nil {
43 | return errNotFound
44 | }
45 |
46 | i.src = string(src[1])
47 |
48 | alt := altAttribute.FindSubmatch(b)
49 | if alt != nil {
50 | i.alt = string(alt[1])
51 | }
52 |
53 | onError := onErrorAttribute.FindSubmatch(b)
54 | if onError != nil {
55 | i.silent = string(onError[1]) == "continue"
56 | }
57 |
58 | return nil
59 | }
60 |
61 | func sanitizeURL(u string, reqURL *url.URL) string {
62 | parsed, _ := url.Parse(u)
63 |
64 | return reqURL.ResolveReference(parsed).String()
65 | }
66 |
67 | func addHeaders(headers []string, req *http.Request, rq *http.Request) {
68 | for _, h := range headers {
69 | v := req.Header.Get(h)
70 | if v != "" {
71 | rq.Header.Add(h, v)
72 | }
73 | }
74 | }
75 |
76 | // Input (e.g. include src="https://domain.com/esi-include" alt="https://domain.com/alt-esi-include" />)
77 | // With or without the alt
78 | // With or without a space separator before the closing
79 | // With or without the quotes around the src/alt value.
80 | func (i *includeTag) Process(b []byte, req *http.Request) ([]byte, int) {
81 | closeIdx := closeInclude.FindIndex(b)
82 |
83 | if closeIdx == nil {
84 | return nil, len(b)
85 | }
86 |
87 | i.length = closeIdx[1]
88 | if e := i.loadAttributes(b[8:i.length]); e != nil {
89 | return nil, len(b)
90 | }
91 |
92 | rq, _ := http.NewRequestWithContext(context.Background(), http.MethodGet, sanitizeURL(i.src, req.URL), nil)
93 | addHeaders(headersSafe, req, rq)
94 |
95 | if rq.URL.Scheme == req.URL.Scheme && rq.URL.Host == req.URL.Host {
96 | addHeaders(headersUnsafe, req, rq)
97 | }
98 |
99 | client := &http.Client{}
100 | response, err := client.Do(rq)
101 | req = rq
102 |
103 | if (err != nil || response.StatusCode >= 400) && i.alt != "" {
104 | rq, _ = http.NewRequestWithContext(context.Background(), http.MethodGet, sanitizeURL(i.alt, req.URL), nil)
105 | addHeaders(headersSafe, req, rq)
106 |
107 | if rq.URL.Scheme == req.URL.Scheme && rq.URL.Host == req.URL.Host {
108 | addHeaders(headersUnsafe, req, rq)
109 | }
110 |
111 | response, err = client.Do(rq)
112 | req = rq
113 |
114 | if !i.silent && (err != nil || response.StatusCode >= 400) {
115 | return nil, len(b)
116 | }
117 | }
118 |
119 | if response == nil {
120 | return nil, i.length
121 | }
122 |
123 | var buf bytes.Buffer
124 |
125 | defer response.Body.Close()
126 | _, _ = io.Copy(&buf, response.Body)
127 |
128 | b = Parse(buf.Bytes(), req)
129 |
130 | return b, i.length
131 | }
132 |
133 | func (*includeTag) HasClose(b []byte) bool {
134 | return closeInclude.FindIndex(b) != nil
135 | }
136 |
137 | func (*includeTag) GetClosePosition(b []byte) int {
138 | if idx := closeInclude.FindIndex(b); idx != nil {
139 | return idx[1]
140 | }
141 |
142 | return 0
143 | }
144 |
--------------------------------------------------------------------------------
/esi/remove.go:
--------------------------------------------------------------------------------
1 | package esi
2 |
3 | import (
4 | "net/http"
5 | "regexp"
6 | )
7 |
8 | const remove = "remove"
9 |
10 | var closeRemove = regexp.MustCompile("")
11 |
12 | type removeTag struct {
13 | *baseTag
14 | }
15 |
16 | func (r *removeTag) Process(b []byte, req *http.Request) ([]byte, int) {
17 | closeIdx := closeRemove.FindIndex(b)
18 | if closeIdx == nil {
19 | return []byte{}, len(b)
20 | }
21 |
22 | r.length = closeIdx[1]
23 |
24 | return []byte{}, r.length
25 | }
26 |
27 | func (*removeTag) HasClose(b []byte) bool {
28 | return closeRemove.FindIndex(b) != nil
29 | }
30 |
31 | func (*removeTag) GetClosePosition(b []byte) int {
32 | if idx := closeRemove.FindIndex(b); idx != nil {
33 | return idx[1]
34 | }
35 |
36 | return 0
37 | }
38 |
--------------------------------------------------------------------------------
/esi/tags.go:
--------------------------------------------------------------------------------
1 | package esi
2 |
3 | import "regexp"
4 |
5 | const try = "try"
6 |
7 | var (
8 | esi = regexp.MustCompile("")
26 | )
27 |
28 | func parseVariables(b []byte, req *http.Request) string {
29 | interprets := interpretedVar.FindSubmatch(b)
30 |
31 | if interprets != nil {
32 | switch string(interprets[1]) {
33 | case httpAcceptLanguage:
34 | if strings.Contains(req.Header.Get("Accept-Language"), string(interprets[3])) {
35 | return "true"
36 | } else {
37 | return "false"
38 | }
39 | case httpCookie:
40 | if c, e := req.Cookie(string(interprets[3])); e == nil && c.Value != "" {
41 | return c.Value
42 | }
43 | case httpHost:
44 | return req.Host
45 | case httpReferrer:
46 | return req.Referer()
47 | case httpUserAgent:
48 | return req.UserAgent()
49 | case httpQueryString:
50 | if q := req.URL.Query().Get(string(interprets[3])); q != "" {
51 | return q
52 | }
53 | }
54 |
55 | if len(interprets) > 3 {
56 | defaultValues := defaultExtractor.FindSubmatch(interprets[4])
57 |
58 | if len(defaultValues) > 2 {
59 | return string(defaultValues[2])
60 | }
61 |
62 | return ""
63 | }
64 | } else {
65 | strs := stringExtractor.FindSubmatch(b)
66 |
67 | if len(strs) > 2 {
68 | return string(strs[2])
69 | }
70 | }
71 |
72 | return string(b)
73 | }
74 |
75 | type varsTag struct {
76 | *baseTag
77 | }
78 |
79 | // Input (e.g. comment text="This is a comment." />).
80 | func (c *varsTag) Process(b []byte, req *http.Request) ([]byte, int) {
81 | found := closeVars.FindIndex(b)
82 | if found == nil {
83 | return nil, len(b)
84 | }
85 |
86 | c.length = found[1]
87 |
88 | return interpretedVar.ReplaceAllFunc(b[5:found[0]], func(b []byte) []byte {
89 | return []byte(parseVariables(b, req))
90 | }), c.length
91 | }
92 |
93 | func (*varsTag) HasClose(b []byte) bool {
94 | return closeVars.FindIndex(b) != nil
95 | }
96 |
97 | func (*varsTag) GetClosePosition(b []byte) int {
98 | if idx := closeVars.FindIndex(b); idx != nil {
99 | return idx[1]
100 | }
101 |
102 | return 0
103 | }
104 |
--------------------------------------------------------------------------------
/esi/vars_test.go:
--------------------------------------------------------------------------------
1 | package esi
2 |
3 | import (
4 | "net/http"
5 | "net/http/httptest"
6 | "testing"
7 | )
8 |
9 | func Test_parseVars(t *testing.T) {
10 | t.Parallel()
11 | parseVariables(logicalAndTest, httptest.NewRequest(http.MethodGet, "http://domain.com", nil))
12 | }
13 |
--------------------------------------------------------------------------------
/esi/when.go:
--------------------------------------------------------------------------------
1 | package esi
2 |
3 | import (
4 | "net/http"
5 | "regexp"
6 | "strings"
7 | )
8 |
9 | var (
10 | unaryNegation = regexp.MustCompile(`!\((\$\((.+)\)|(.+))\)`)
11 | comparison = regexp.MustCompile(`(.+)(==|!=|<=|>=|<|>)(.+)`)
12 | logicalAnd = regexp.MustCompile(`\((.+?)\)&\((.+?)\)`)
13 | logicalOr = regexp.MustCompile(`\((.+?)\)\|\((.+?)\)`)
14 | )
15 |
16 | func validateTest(b []byte, req *http.Request) bool {
17 | if r := unaryNegation.FindSubmatch(b); r != nil {
18 | return !validateTest(r[1], req)
19 | } else if r := logicalAnd.FindSubmatch(b); r != nil {
20 | return validateTest(r[1], req) && validateTest(r[2], req)
21 | } else if r := logicalOr.FindSubmatch(b); r != nil {
22 | return validateTest(r[1], req) || validateTest(r[2], req)
23 | } else if r := comparison.FindSubmatch(b); r != nil {
24 | r1 := strings.TrimSpace(parseVariables(r[1], req))
25 | r2 := strings.TrimSpace(parseVariables(r[3], req))
26 | switch string(r[2]) {
27 | case "==":
28 | return r1 == r2
29 | case "!=":
30 | return r1 != r2
31 | case "<":
32 | return r1 < r2
33 | case ">":
34 | return r1 > r2
35 | case "<=":
36 | return r1 <= r2
37 | case ">=":
38 | return r1 >= r2
39 | }
40 | } else {
41 | vars := interpretedVar.FindSubmatch(b)
42 | if vars == nil {
43 | return false
44 | }
45 |
46 | return parseVariables(vars[0], req) == "true"
47 | }
48 |
49 | return false
50 | }
51 |
--------------------------------------------------------------------------------
/esi/when_test.go:
--------------------------------------------------------------------------------
1 | package esi
2 |
3 | import (
4 | "net/http"
5 | "net/http/httptest"
6 | "testing"
7 | )
8 |
9 | var (
10 | unaryNegationTest = []byte("!(1==1)")
11 | comparisonTest = []byte("!('a'<='c')")
12 | logicalOrTest = []byte("(1==1)|('abc'=='def')")
13 | logicalAndTest = []byte("(4!=5)&(4==5)")
14 | complexTest = []byte("$(HTTP_ACCEPT_LANGUAGE{en-gb})")
15 | )
16 |
17 | func Test_validateTest(t *testing.T) {
18 | t.Parallel()
19 |
20 | if validateTest(unaryNegationTest, httptest.NewRequest(http.MethodGet, "http://domain.com", nil)) {
21 | t.Error("The unaryNegationTest must return false because we return the opposite of true (1==1)")
22 | }
23 |
24 | if validateTest(comparisonTest, httptest.NewRequest(http.MethodGet, "http://domain.com", nil)) {
25 | t.Error("The comparisonTest must return false because we return the opposite of true (a < c)")
26 | }
27 |
28 | if !validateTest(logicalOrTest, httptest.NewRequest(http.MethodGet, "http://domain.com", nil)) {
29 | t.Error("The logicalOrTest must return true because we return true or false (1==1)|('abc'=='def')")
30 | }
31 |
32 | if validateTest(logicalAndTest, httptest.NewRequest(http.MethodGet, "http://domain.com", nil)) {
33 | t.Error("The logicalAndTest must return false because we return true and false (4!=5)&(4==5)")
34 | }
35 |
36 | rq := httptest.NewRequest(http.MethodGet, "http://domain.com", nil)
37 | rq.Header.Add("Accept-Language", "en-gb")
38 | rq.Header.Add("Accept-Language", "fr-fr")
39 |
40 | if !validateTest(complexTest, rq) {
41 | t.Error("The complexTest must return true")
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/fixtures/alt:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/fixtures/choose:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/fixtures/comment:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/fixtures/escape:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/fixtures/full.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | Hello from $(HTTP_HOST)
4 |
5 |
6 |
7 |
8 |
9 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/fixtures/include:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/fixtures/remove:
--------------------------------------------------------------------------------
1 |
2 |
3 | www.example.com
4 |
5 |
6 |
--------------------------------------------------------------------------------
/fixtures/try:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | www.example.com
9 |
10 |
--------------------------------------------------------------------------------
/fixtures/vars:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/go.mod:
--------------------------------------------------------------------------------
1 | module github.com/darkweak/go-esi
2 |
3 | go 1.19
4 |
--------------------------------------------------------------------------------
/middleware/caddy/.gitignore:
--------------------------------------------------------------------------------
1 | caddy
--------------------------------------------------------------------------------
/middleware/caddy/Caddyfile:
--------------------------------------------------------------------------------
1 | {
2 | debug
3 | order esi before basicauth
4 | esi
5 | http_port 9080
6 | }
7 |
8 | :9080 {
9 | route /chained-esi-include-1 {
10 | header Content-Type text/html
11 | respond ``
12 | }
13 |
14 | route /chained-esi-include-2 {
15 | header Content-Type text/html
16 | respond "CHAINED 2
"
17 | }
18 |
19 | route /esi-include {
20 | header Content-Type text/html
21 | respond "ESI INCLUDE
"
22 | }
23 |
24 | route /alt-esi-include {
25 | header Content-Type text/html
26 | respond "ALTERNATE ESI INCLUDE
"
27 | }
28 |
29 | route /* {
30 | esi
31 | root * ../../fixtures
32 | file_server
33 | }
34 | }
--------------------------------------------------------------------------------
/middleware/caddy/Makefile:
--------------------------------------------------------------------------------
1 | .PHONY: build run
2 |
3 | build: ## Build caddy binary
4 | go mod tidy
5 | go mod download
6 | xcaddy build --with github.com/darkweak/go-esi@latest=../.. --with github.com/darkweak/go-esi/middleware/caddy=./
7 |
8 | run: ## Run caddy with go-esi
9 | ./caddy run
--------------------------------------------------------------------------------
/middleware/caddy/esi.go:
--------------------------------------------------------------------------------
1 | package caddy_esi
2 |
3 | import (
4 | "bytes"
5 | "net/http"
6 | "sync"
7 |
8 | "github.com/caddyserver/caddy/v2"
9 | "github.com/caddyserver/caddy/v2/caddyconfig/caddyfile"
10 | "github.com/caddyserver/caddy/v2/caddyconfig/httpcaddyfile"
11 | "github.com/caddyserver/caddy/v2/modules/caddyhttp"
12 | "github.com/darkweak/go-esi/writer"
13 | )
14 |
15 | var bufPool *sync.Pool = &sync.Pool{
16 | New: func() any {
17 | return &bytes.Buffer{}
18 | },
19 | }
20 |
21 | func init() {
22 | caddy.RegisterModule(ESI{})
23 | httpcaddyfile.RegisterGlobalOption("esi", func(h *caddyfile.Dispenser, _ interface{}) (interface{}, error) {
24 | return &ESI{}, nil
25 | })
26 | httpcaddyfile.RegisterHandlerDirective("esi", func(h httpcaddyfile.Helper) (caddyhttp.MiddlewareHandler, error) {
27 | return &ESI{}, nil
28 | })
29 | }
30 |
31 | // ESI to handle, process and serve ESI tags.
32 | type ESI struct{}
33 |
34 | // CaddyModule returns the Caddy module information.
35 | func (ESI) CaddyModule() caddy.ModuleInfo {
36 | return caddy.ModuleInfo{
37 | ID: "http.handlers.esi",
38 | New: func() caddy.Module { return new(ESI) },
39 | }
40 | }
41 |
42 | // ServeHTTP implements caddyhttp.MiddlewareHandler
43 | func (e *ESI) ServeHTTP(rw http.ResponseWriter, r *http.Request, next caddyhttp.Handler) error {
44 | buf := bufPool.Get().(*bytes.Buffer)
45 | buf.Reset()
46 | defer bufPool.Put(buf)
47 | cw := writer.NewWriter(buf, rw, r)
48 | go func(w *writer.Writer) {
49 | var i = 0
50 | for {
51 | if len(w.AsyncBuf) <= i {
52 | continue
53 | }
54 | rs := <-w.AsyncBuf[i]
55 | if rs == nil {
56 | w.Done <- true
57 | break
58 | }
59 | _, _ = rw.Write(rs)
60 | i++
61 | }
62 | }(cw)
63 | next.ServeHTTP(cw, r)
64 | cw.Header().Del("Content-Length")
65 | if cw.Rq.ProtoMajor == 1 {
66 | cw.Header().Set("Content-Encoding", "chunked")
67 | }
68 | cw.AsyncBuf = append(cw.AsyncBuf, make(chan []byte))
69 | go func(w *writer.Writer, iteration int) {
70 | w.AsyncBuf[iteration] <- nil
71 | }(cw, cw.Iteration)
72 |
73 | <-cw.Done
74 |
75 | return nil
76 | }
77 |
78 | // Provision implements caddy.Provisioner
79 | func (*ESI) Provision(caddy.Context) error {
80 | return nil
81 | }
82 |
83 | func (s ESI) Start() error { return nil }
84 |
85 | func (s ESI) Stop() error { return nil }
86 |
87 | // Interface guards
88 | var (
89 | _ caddyhttp.MiddlewareHandler = (*ESI)(nil)
90 | _ caddy.Module = (*ESI)(nil)
91 | _ caddy.Provisioner = (*ESI)(nil)
92 | _ caddy.App = (*ESI)(nil)
93 | )
94 |
--------------------------------------------------------------------------------
/middleware/caddy/esi_test.go:
--------------------------------------------------------------------------------
1 | package caddy_esi
2 |
3 | import (
4 | "net/http"
5 | "testing"
6 |
7 | "github.com/caddyserver/caddy/v2/caddytest"
8 | )
9 |
10 | const expectedOutput = `
11 |
12 | Hello from domain.com:9080
13 |
14 |
15 |
16 |
17 | CHAINED 2
18 | ALTERNATE ESI INCLUDE
19 |
20 |
21 |
ESI INCLUDE
22 |
23 |
24 |
25 |
26 | `
27 |
28 | func loadConfiguration(t *testing.T) *caddytest.Tester {
29 | tester := caddytest.NewTester(t)
30 | tester.InitServer(`
31 | {
32 | admin localhost:2999
33 | order esi before basicauth
34 | esi
35 | http_port 9080
36 | }
37 | domain.com:9080 {
38 | route /chained-esi-include-1 {
39 | header Content-Type text/html
40 | respond `+"``"+`
41 | }
42 |
43 | route /chained-esi-include-2 {
44 | header Content-Type text/html
45 | respond "CHAINED 2
"
46 | }
47 |
48 | route /esi-include {
49 | header Content-Type text/html
50 | respond "ESI INCLUDE
"
51 | }
52 |
53 | route /alt-esi-include {
54 | header Content-Type text/html
55 | respond "ALTERNATE ESI INCLUDE
"
56 | }
57 |
58 | route /* {
59 | esi
60 | root * ../../fixtures
61 | file_server
62 | }
63 | }`, "caddyfile")
64 |
65 | return tester
66 | }
67 |
68 | func TestFullHTML(t *testing.T) {
69 | tester := loadConfiguration(t)
70 | _, _ = tester.AssertGetResponse(`http://domain.com:9080/full.html`, http.StatusOK, expectedOutput)
71 | }
72 |
73 | func TestUnitary(t *testing.T) {
74 | tester := loadConfiguration(t)
75 |
76 | _, _ = tester.AssertGetResponse(`http://domain.com:9080/escape`, http.StatusOK, `Hello, $(HTTP_COOKIE{name})!
`)
77 | _, _ = tester.AssertGetResponse(`http://domain.com:9080/include`, http.StatusOK, "CHAINED 2
")
78 | _, _ = tester.AssertGetResponse(`http://domain.com:9080/alt`, http.StatusOK, "ALTERNATE ESI INCLUDE
")
79 | }
80 |
--------------------------------------------------------------------------------
/middleware/caddy/go.mod:
--------------------------------------------------------------------------------
1 | module github.com/darkweak/go-esi/middleware/caddy
2 |
3 | go 1.19
4 |
5 | require (
6 | github.com/caddyserver/caddy/v2 v2.6.4
7 | github.com/darkweak/go-esi v0.0.6
8 | )
9 |
10 | require (
11 | filippo.io/edwards25519 v1.0.0 // indirect
12 | github.com/AndreasBriese/bbloom v0.0.0-20190825152654-46b345b51c96 // indirect
13 | github.com/BurntSushi/toml v1.2.1 // indirect
14 | github.com/Masterminds/goutils v1.1.1 // indirect
15 | github.com/Masterminds/semver/v3 v3.2.0 // indirect
16 | github.com/Masterminds/sprig/v3 v3.2.3 // indirect
17 | github.com/Microsoft/go-winio v0.6.0 // indirect
18 | github.com/alecthomas/chroma/v2 v2.5.0 // indirect
19 | github.com/antlr/antlr4/runtime/Go/antlr v1.4.10 // indirect
20 | github.com/aryann/difflib v0.0.0-20210328193216-ff5ff6dc229b // indirect
21 | github.com/beorn7/perks v1.0.1 // indirect
22 | github.com/caddyserver/certmagic v0.17.2 // indirect
23 | github.com/cenkalti/backoff/v4 v4.1.2 // indirect
24 | github.com/cespare/xxhash v1.1.0 // indirect
25 | github.com/cespare/xxhash/v2 v2.2.0 // indirect
26 | github.com/chzyer/readline v1.5.1 // indirect
27 | github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect
28 | github.com/dgraph-io/badger v1.6.2 // indirect
29 | github.com/dgraph-io/badger/v2 v2.2007.4 // indirect
30 | github.com/dgraph-io/ristretto v0.1.1 // indirect
31 | github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 // indirect
32 | github.com/dlclark/regexp2 v1.7.0 // indirect
33 | github.com/dustin/go-humanize v1.0.1 // indirect
34 | github.com/felixge/httpsnoop v1.0.3 // indirect
35 | github.com/fxamacker/cbor/v2 v2.4.0 // indirect
36 | github.com/go-chi/chi v4.1.2+incompatible // indirect
37 | github.com/go-kit/kit v0.12.0 // indirect
38 | github.com/go-kit/log v0.2.1 // indirect
39 | github.com/go-logfmt/logfmt v0.6.0 // indirect
40 | github.com/go-logr/logr v1.2.3 // indirect
41 | github.com/go-logr/stdr v1.2.2 // indirect
42 | github.com/go-sql-driver/mysql v1.7.0 // indirect
43 | github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 // indirect
44 | github.com/golang/glog v1.1.1 // indirect
45 | github.com/golang/mock v1.6.0 // indirect
46 | github.com/golang/protobuf v1.5.3 // indirect
47 | github.com/golang/snappy v0.0.4 // indirect
48 | github.com/google/cel-go v0.13.0 // indirect
49 | github.com/google/pprof v0.0.0-20230309165930-d61513b1440d // indirect
50 | github.com/google/uuid v1.3.0 // indirect
51 | github.com/grpc-ecosystem/grpc-gateway v1.16.0 // indirect
52 | github.com/huandu/xstrings v1.4.0 // indirect
53 | github.com/imdario/mergo v0.3.14 // indirect
54 | github.com/inconshreveable/mousetrap v1.1.0 // indirect
55 | github.com/jackc/chunkreader/v2 v2.0.1 // indirect
56 | github.com/jackc/pgconn v1.14.0 // indirect
57 | github.com/jackc/pgio v1.0.0 // indirect
58 | github.com/jackc/pgpassfile v1.0.0 // indirect
59 | github.com/jackc/pgproto3/v2 v2.3.2 // indirect
60 | github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect
61 | github.com/jackc/pgtype v1.14.0 // indirect
62 | github.com/jackc/pgx/v4 v4.18.1 // indirect
63 | github.com/klauspost/compress v1.16.3 // indirect
64 | github.com/klauspost/cpuid/v2 v2.2.4 // indirect
65 | github.com/libdns/libdns v0.2.1 // indirect
66 | github.com/manifoldco/promptui v0.9.0 // indirect
67 | github.com/mattn/go-colorable v0.1.13 // indirect
68 | github.com/mattn/go-isatty v0.0.18 // indirect
69 | github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
70 | github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d // indirect
71 | github.com/mholt/acmez v1.1.0 // indirect
72 | github.com/micromdm/scep/v2 v2.1.0 // indirect
73 | github.com/miekg/dns v1.1.52 // indirect
74 | github.com/mitchellh/copystructure v1.2.0 // indirect
75 | github.com/mitchellh/go-ps v1.0.0 // indirect
76 | github.com/mitchellh/reflectwalk v1.0.2 // indirect
77 | github.com/onsi/ginkgo/v2 v2.9.1 // indirect
78 | github.com/pkg/errors v0.9.1 // indirect
79 | github.com/prometheus/client_golang v1.14.0 // indirect
80 | github.com/prometheus/client_model v0.3.0 // indirect
81 | github.com/prometheus/common v0.42.0 // indirect
82 | github.com/prometheus/procfs v0.9.0 // indirect
83 | github.com/quic-go/qpack v0.4.0 // indirect
84 | github.com/quic-go/qtls-go1-19 v0.3.0 // indirect
85 | github.com/quic-go/qtls-go1-20 v0.2.0 // indirect
86 | github.com/quic-go/quic-go v0.33.0 // indirect
87 | github.com/rs/xid v1.4.0 // indirect
88 | github.com/russross/blackfriday/v2 v2.1.0 // indirect
89 | github.com/shopspring/decimal v1.3.1 // indirect
90 | github.com/shurcooL/sanitized_anchor_name v1.0.0 // indirect
91 | github.com/sirupsen/logrus v1.9.0 // indirect
92 | github.com/slackhq/nebula v1.6.1 // indirect
93 | github.com/smallstep/certificates v0.23.2 // indirect
94 | github.com/smallstep/nosql v0.6.0 // indirect
95 | github.com/smallstep/truststore v0.12.1 // indirect
96 | github.com/spf13/cast v1.5.0 // indirect
97 | github.com/spf13/cobra v1.6.1 // indirect
98 | github.com/spf13/pflag v1.0.5 // indirect
99 | github.com/stoewer/go-strcase v1.2.1 // indirect
100 | github.com/tailscale/tscert v0.0.0-20230124224810-c6dc1f4049b2 // indirect
101 | github.com/urfave/cli v1.22.12 // indirect
102 | github.com/x448/float16 v0.8.4 // indirect
103 | github.com/yuin/goldmark v1.5.4 // indirect
104 | github.com/yuin/goldmark-highlighting/v2 v2.0.0-20220924101305-151362477c87 // indirect
105 | go.etcd.io/bbolt v1.3.7 // indirect
106 | go.mozilla.org/pkcs7 v0.0.0-20210826202110-33d05740a352 // indirect
107 | go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.39.0 // indirect
108 | go.opentelemetry.io/otel v1.13.0 // indirect
109 | go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.4.0 // indirect
110 | go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.4.0 // indirect
111 | go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.4.0 // indirect
112 | go.opentelemetry.io/otel/metric v0.36.0 // indirect
113 | go.opentelemetry.io/otel/sdk v1.13.0 // indirect
114 | go.opentelemetry.io/otel/trace v1.13.0 // indirect
115 | go.opentelemetry.io/proto/otlp v0.12.0 // indirect
116 | go.step.sm/cli-utils v0.7.5 // indirect
117 | go.step.sm/crypto v0.27.0 // indirect
118 | go.step.sm/linkedca v0.19.0 // indirect
119 | go.uber.org/atomic v1.10.0 // indirect
120 | go.uber.org/multierr v1.10.0 // indirect
121 | go.uber.org/zap v1.24.0 // indirect
122 | golang.org/x/crypto v0.7.0 // indirect
123 | golang.org/x/exp v0.0.0-20230321023759-10a507213a29 // indirect
124 | golang.org/x/mod v0.9.0 // indirect
125 | golang.org/x/net v0.8.0 // indirect
126 | golang.org/x/sync v0.1.0 // indirect
127 | golang.org/x/sys v0.6.0 // indirect
128 | golang.org/x/term v0.6.0 // indirect
129 | golang.org/x/text v0.8.0 // indirect
130 | golang.org/x/tools v0.7.0 // indirect
131 | google.golang.org/genproto v0.0.0-20230322174352-cde4c949918d // indirect
132 | google.golang.org/grpc v1.54.0 // indirect
133 | google.golang.org/protobuf v1.30.0 // indirect
134 | gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect
135 | gopkg.in/square/go-jose.v2 v2.6.0 // indirect
136 | gopkg.in/yaml.v3 v3.0.1 // indirect
137 | howett.net/plist v1.0.0 // indirect
138 | )
139 |
140 | replace github.com/darkweak/go-esi v0.0.6 => ../..
141 |
--------------------------------------------------------------------------------
/middleware/caddy/go.sum:
--------------------------------------------------------------------------------
1 | cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
2 | cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
3 | cloud.google.com/go v0.110.0 h1:Zc8gqp3+a9/Eyph2KDmcGaPtbKRIoqq4YTlL4NMD0Ys=
4 | cloud.google.com/go/compute v1.18.0 h1:FEigFqoDbys2cvFkZ9Fjq4gnHBP55anJ0yQyau2f9oY=
5 | cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY=
6 | cloud.google.com/go/iam v0.12.0 h1:DRtTY29b75ciH6Ov1PHb4/iat2CLCvrOm40Q0a6DFpE=
7 | cloud.google.com/go/kms v1.9.0 h1:b0votJQa/9DSsxgHwN33/tTLA7ZHVzfWhDCrfiXijSo=
8 | filippo.io/edwards25519 v1.0.0 h1:0wAIcmJUqRdI8IJ/3eGi5/HwXZWPujYXXlkrQogz0Ek=
9 | filippo.io/edwards25519 v1.0.0/go.mod h1:N1IkdkCkiLB6tki+MYJoSx2JTY9NUlxZE7eHn5EwJns=
10 | github.com/AndreasBriese/bbloom v0.0.0-20190825152654-46b345b51c96 h1:cTp8I5+VIoKjsnZuH8vjyaysT/ses3EvZeaV/1UkF2M=
11 | github.com/AndreasBriese/bbloom v0.0.0-20190825152654-46b345b51c96/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8=
12 | github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
13 | github.com/BurntSushi/toml v1.2.1 h1:9F2/+DoOYIOksmaJFPw1tGFy1eDnIJXg+UHjuD8lTak=
14 | github.com/BurntSushi/toml v1.2.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
15 | github.com/Masterminds/goutils v1.1.0/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU=
16 | github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI=
17 | github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU=
18 | github.com/Masterminds/semver/v3 v3.1.0/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs=
19 | github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs=
20 | github.com/Masterminds/semver/v3 v3.2.0 h1:3MEsd0SM6jqZojhjLWWeBY+Kcjy9i6MQAeY7YgDP83g=
21 | github.com/Masterminds/semver/v3 v3.2.0/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ=
22 | github.com/Masterminds/sprig/v3 v3.1.0/go.mod h1:ONGMf7UfYGAbMXCZmQLy8x3lCDIPrEZE/rU8pmrbihA=
23 | github.com/Masterminds/sprig/v3 v3.2.3 h1:eL2fZNezLomi0uOLqjQoN6BfsDD+fyLtgbJMAj9n6YA=
24 | github.com/Masterminds/sprig/v3 v3.2.3/go.mod h1:rXcFaZ2zZbLRJv/xSysmlgIM1u11eBaRMhvYXJNkGuM=
25 | github.com/Microsoft/go-winio v0.6.0 h1:slsWYD/zyx7lCXoZVlvQrj0hPTM1HI4+v1sIda2yDvg=
26 | github.com/Microsoft/go-winio v0.6.0/go.mod h1:cTAf44im0RAYeL23bpB+fzCyDH2MJiz2BO69KH/soAE=
27 | github.com/OneOfOne/xxhash v1.2.2 h1:KMrpdQIwFcEqXDklaen+P1axHaj9BSKzvpUUfnHldSE=
28 | github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
29 | github.com/alecthomas/assert/v2 v2.2.1 h1:XivOgYcduV98QCahG8T5XTezV5bylXe+lBxLG2K2ink=
30 | github.com/alecthomas/chroma/v2 v2.2.0/go.mod h1:vf4zrexSH54oEjJ7EdB65tGNHmH3pGZmVkgTP5RHvAs=
31 | github.com/alecthomas/chroma/v2 v2.5.0 h1:CQCdj1BiBV17sD4Bd32b/Bzuiq/EqoNTrnIhyQAZ+Rk=
32 | github.com/alecthomas/chroma/v2 v2.5.0/go.mod h1:yrkMI9807G1ROx13fhe1v6PN2DDeaR73L3d+1nmYQtw=
33 | github.com/alecthomas/repr v0.0.0-20220113201626-b1b626ac65ae/go.mod h1:2kn6fqh/zIyPLmm3ugklbEi5hg5wS435eygvNfaDQL8=
34 | github.com/alecthomas/repr v0.2.0 h1:HAzS41CIzNW5syS8Mf9UwXhNH1J9aix/BvDRf1Ml2Yk=
35 | github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
36 | github.com/antlr/antlr4/runtime/Go/antlr v1.4.10 h1:yL7+Jz0jTC6yykIK/Wh74gnTJnrGr5AyrNMXuA0gves=
37 | github.com/antlr/antlr4/runtime/Go/antlr v1.4.10/go.mod h1:F7bn7fEU90QkQ3tnmaTx3LTKLEDqnwWODIYppRQ5hnY=
38 | github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
39 | github.com/aryann/difflib v0.0.0-20210328193216-ff5ff6dc229b h1:uUXgbcPDK3KpW29o4iy7GtuappbWT0l5NaMo9H9pJDw=
40 | github.com/aryann/difflib v0.0.0-20210328193216-ff5ff6dc229b/go.mod h1:DAHtR1m6lCRdSC2Tm3DSWRPvIPr6xNKyeHdqDQSQT+A=
41 | github.com/aws/aws-sdk-go v1.44.220 h1:yAj99qAt0Htjle9Up3DglgHfOP77lmFPrElA4jKnrBo=
42 | github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8=
43 | github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
44 | github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
45 | github.com/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx27Ps=
46 | github.com/caddyserver/caddy/v2 v2.6.4 h1:2hwYqiRwk1tf3VruhMpLcYTg+11fCdr8S3jhNAdnPy8=
47 | github.com/caddyserver/caddy/v2 v2.6.4/go.mod h1:p/PqEgaIrg249zmTLdgNMnQO4mBQ8uWYdi+TDOPwejc=
48 | github.com/caddyserver/certmagic v0.17.2 h1:o30seC1T/dBqBCNNGNHWwj2i5/I/FMjBbTAhjADP3nE=
49 | github.com/caddyserver/certmagic v0.17.2/go.mod h1:ouWUuC490GOLJzkyN35eXfV8bSbwMwSf4bdhkIxtdQE=
50 | github.com/cenkalti/backoff/v4 v4.1.2 h1:6Yo7N8UP2K6LWZnW94DLVSSrbobcWdVzAYOisuDPIFo=
51 | github.com/cenkalti/backoff/v4 v4.1.2/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw=
52 | github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
53 | github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
54 | github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
55 | github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
56 | github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
57 | github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
58 | github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
59 | github.com/chzyer/logex v1.2.1 h1:XHDu3E6q+gdHgsdTPH6ImJMIp436vR6MPtH8gP05QzM=
60 | github.com/chzyer/logex v1.2.1/go.mod h1:JLbx6lG2kDbNRFnfkgvh4eRJRPX1QCoOIWomwysCBrQ=
61 | github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
62 | github.com/chzyer/readline v1.5.1 h1:upd/6fQk4src78LMRzh5vItIt361/o4uq553V8B5sGI=
63 | github.com/chzyer/readline v1.5.1/go.mod h1:Eh+b79XXUwfKfcPLepksvw2tcLE/Ct21YObkaSkeBlk=
64 | github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
65 | github.com/chzyer/test v1.0.0 h1:p3BQDXSxOhOG0P9z6/hGnII4LGiEPOYBhs8asl/fC04=
66 | github.com/chzyer/test v1.0.0/go.mod h1:2JlltgoNkt4TW/z9V/IzDdFaMTM2JPIi26O1pF38GC8=
67 | github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
68 | github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
69 | github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
70 | github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI=
71 | github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
72 | github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
73 | github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
74 | github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I=
75 | github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ=
76 | github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
77 | github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk=
78 | github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
79 | github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
80 | github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
81 | github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
82 | github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
83 | github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
84 | github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w=
85 | github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
86 | github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
87 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
88 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
89 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
90 | github.com/dgraph-io/badger v1.6.2 h1:mNw0qs90GVgGGWylh0umH5iag1j6n/PeJtNvL6KY/x8=
91 | github.com/dgraph-io/badger v1.6.2/go.mod h1:JW2yswe3V058sS0kZ2h/AXeDSqFjxnZcRrVH//y2UQE=
92 | github.com/dgraph-io/badger/v2 v2.2007.4 h1:TRWBQg8UrlUhaFdco01nO2uXwzKS7zd+HVdwV/GHc4o=
93 | github.com/dgraph-io/badger/v2 v2.2007.4/go.mod h1:vSw/ax2qojzbN6eXHIx6KPKtCSHJN/Uz0X0VPruTIhk=
94 | github.com/dgraph-io/ristretto v0.0.2/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E=
95 | github.com/dgraph-io/ristretto v0.0.3-0.20200630154024-f66de99634de/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E=
96 | github.com/dgraph-io/ristretto v0.1.1 h1:6CWw5tJNgpegArSHpNHJKldNeq03FQCwYvfMVWajOK8=
97 | github.com/dgraph-io/ristretto v0.1.1/go.mod h1:S1GPSBCYCIhmVNfcth17y2zZtQT6wzkzgwUve0VDWWA=
98 | github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw=
99 | github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 h1:fAjc9m62+UWV/WAFKLNi6ZS0675eEUC9y3AlwSbQu1Y=
100 | github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw=
101 | github.com/dlclark/regexp2 v1.4.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc=
102 | github.com/dlclark/regexp2 v1.7.0 h1:7lJfhqlPssTb1WQx4yvTHN0uElPEv52sbaECrAQxjAo=
103 | github.com/dlclark/regexp2 v1.7.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
104 | github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
105 | github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
106 | github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
107 | github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
108 | github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
109 | github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
110 | github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
111 | github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0=
112 | github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
113 | github.com/felixge/httpsnoop v1.0.3 h1:s/nj+GCswXYzN5v2DpNMuMQYe+0DDwt5WVCU6CWBdXk=
114 | github.com/felixge/httpsnoop v1.0.3/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
115 | github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE=
116 | github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
117 | github.com/fxamacker/cbor/v2 v2.4.0 h1:ri0ArlOR+5XunOP8CRUowT0pSJOwhW098ZCUyskZD88=
118 | github.com/fxamacker/cbor/v2 v2.4.0/go.mod h1:TA1xS00nchWmaBnEIxPSE5oHLuJBAVvqrtAnWBwBCVo=
119 | github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
120 | github.com/go-chi/chi v4.1.2+incompatible h1:fGFk2Gmi/YKXk0OmGfBh0WgmN3XB8lVnEyNz34tQRec=
121 | github.com/go-chi/chi v4.1.2+incompatible/go.mod h1:eB3wogJHnLi3x/kFX2A+IbTBlXxmMeXJVKy9tTv1XzQ=
122 | github.com/go-kit/kit v0.4.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
123 | github.com/go-kit/kit v0.12.0 h1:e4o3o3IsBfAKQh5Qbbiqyfu97Ku7jrO/JbohvztANh4=
124 | github.com/go-kit/kit v0.12.0/go.mod h1:lHd+EkCZPIwYItmGDDRdhinkzX2A1sj+M9biaEaizzs=
125 | github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY=
126 | github.com/go-kit/log v0.2.1 h1:MRVx0/zhvdseW+Gza6N9rVzU/IVzaeE1SFI4raAhmBU=
127 | github.com/go-kit/log v0.2.1/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0=
128 | github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
129 | github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
130 | github.com/go-logfmt/logfmt v0.6.0 h1:wGYYu3uicYdqXVgoYbvnkrPVXkuLM1p1ifugDMEdRi4=
131 | github.com/go-logfmt/logfmt v0.6.0/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs=
132 | github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
133 | github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0=
134 | github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
135 | github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
136 | github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
137 | github.com/go-sql-driver/mysql v1.7.0 h1:ueSltNNllEqE3qcWBTD0iQd3IpL/6U+mJxLkazJ7YPc=
138 | github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=
139 | github.com/go-stack/stack v1.6.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
140 | github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
141 | github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 h1:p104kn46Q8WdvHunIJ9dAyjPVtrBPhSr3KT2yUst43I=
142 | github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
143 | github.com/gofrs/uuid v4.0.0+incompatible h1:1SD/1F5pU8p29ybwgQSwpQk+mwdRrXCYuPhW6m+TnJw=
144 | github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
145 | github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
146 | github.com/golang/glog v1.1.1 h1:jxpi2eWoU84wbX9iIEyAeeoac3FLuifZpY9tcNUD9kw=
147 | github.com/golang/glog v1.1.1/go.mod h1:zR+okUeTbrL6EL3xHUDxZuEtGv04p5shwip1+mL/rLQ=
148 | github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=
149 | github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
150 | github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc=
151 | github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs=
152 | github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
153 | github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
154 | github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
155 | github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
156 | github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk=
157 | github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
158 | github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
159 | github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
160 | github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
161 | github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
162 | github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
163 | github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
164 | github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
165 | github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
166 | github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
167 | github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
168 | github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
169 | github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
170 | github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
171 | github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
172 | github.com/google/cel-go v0.13.0 h1:z+8OBOcmh7IeKyqwT/6IlnMvy621fYUqnTVPEdegGlU=
173 | github.com/google/cel-go v0.13.0/go.mod h1:K2hpQgEjDp18J76a2DKFRlPBPpgRZgi6EbnpDgIhJ8s=
174 | github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
175 | github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
176 | github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
177 | github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
178 | github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
179 | github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
180 | github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
181 | github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE=
182 | github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
183 | github.com/google/pprof v0.0.0-20230309165930-d61513b1440d h1:um9/pc7tKMINFfP1eE7Wv6PRGXlcCSJkVajF7KJw3uQ=
184 | github.com/google/pprof v0.0.0-20230309165930-d61513b1440d/go.mod h1:79YE0hCXdHag9sBkw2o+N/YnZtTkXi0UT9Nnixa5eYk=
185 | github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
186 | github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
187 | github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
188 | github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
189 | github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
190 | github.com/googleapis/enterprise-certificate-proxy v0.2.3 h1:yk9/cqRKtT9wXZSsRH9aurXEpJX+U6FLtpYTdC3R06k=
191 | github.com/googleapis/gax-go/v2 v2.7.1 h1:gF4c0zjUP2H/s/hEGyLA3I0fA2ZWjzYiONAD6cvPr8A=
192 | github.com/gorilla/context v0.0.0-20160226214623-1ea25387ff6f/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
193 | github.com/gorilla/mux v1.4.0/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
194 | github.com/groob/finalizer v0.0.0-20170707115354-4c2ed49aabda/go.mod h1:MyndkAZd5rUMdNogn35MWXBX1UiBigrU8eTj8DoAC2c=
195 | github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo=
196 | github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
197 | github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
198 | github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM=
199 | github.com/huandu/xstrings v1.3.1/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
200 | github.com/huandu/xstrings v1.3.3/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
201 | github.com/huandu/xstrings v1.4.0 h1:D17IlohoQq4UcpqD7fDk80P7l+lwAmlFaBHgOipl2FU=
202 | github.com/huandu/xstrings v1.4.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
203 | github.com/imdario/mergo v0.3.8/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
204 | github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
205 | github.com/imdario/mergo v0.3.14 h1:fOqeC1+nCuuk6PKQdg9YmosXX7Y7mHX6R/0ZldI9iHo=
206 | github.com/imdario/mergo v0.3.14/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY=
207 | github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
208 | github.com/inconshreveable/mousetrap v1.0.1/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
209 | github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
210 | github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
211 | github.com/jackc/chunkreader v1.0.0/go.mod h1:RT6O25fNZIuasFJRyZ4R/Y2BbhasbmZXF9QQ7T3kePo=
212 | github.com/jackc/chunkreader/v2 v2.0.0/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk=
213 | github.com/jackc/chunkreader/v2 v2.0.1 h1:i+RDz65UE+mmpjTfyz0MoVTnzeYxroil2G82ki7MGG8=
214 | github.com/jackc/chunkreader/v2 v2.0.1/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk=
215 | github.com/jackc/pgconn v0.0.0-20190420214824-7e0022ef6ba3/go.mod h1:jkELnwuX+w9qN5YIfX0fl88Ehu4XC3keFuOJJk9pcnA=
216 | github.com/jackc/pgconn v0.0.0-20190824142844-760dd75542eb/go.mod h1:lLjNuW/+OfW9/pnVKPazfWOgNfH2aPem8YQ7ilXGvJE=
217 | github.com/jackc/pgconn v0.0.0-20190831204454-2fabfa3c18b7/go.mod h1:ZJKsE/KZfsUgOEh9hBm+xYTstcNHg7UPMVJqRfQxq4s=
218 | github.com/jackc/pgconn v1.8.0/go.mod h1:1C2Pb36bGIP9QHGBYCjnyhqu7Rv3sGshaQUvmfGIB/o=
219 | github.com/jackc/pgconn v1.9.0/go.mod h1:YctiPyvzfU11JFxoXokUOOKQXQmDMoJL9vJzHH8/2JY=
220 | github.com/jackc/pgconn v1.9.1-0.20210724152538-d89c8390a530/go.mod h1:4z2w8XhRbP1hYxkpTuBjTS3ne3J48K83+u0zoyvg2pI=
221 | github.com/jackc/pgconn v1.14.0 h1:vrbA9Ud87g6JdFWkHTJXppVce58qPIdP7N8y0Ml/A7Q=
222 | github.com/jackc/pgconn v1.14.0/go.mod h1:9mBNlny0UvkgJdCDvdVHYSjI+8tD2rnKK69Wz8ti++E=
223 | github.com/jackc/pgio v1.0.0 h1:g12B9UwVnzGhueNavwioyEEpAmqMe1E/BN9ES+8ovkE=
224 | github.com/jackc/pgio v1.0.0/go.mod h1:oP+2QK2wFfUWgr+gxjoBH9KGBb31Eio69xUb0w5bYf8=
225 | github.com/jackc/pgmock v0.0.0-20190831213851-13a1b77aafa2/go.mod h1:fGZlG77KXmcq05nJLRkk0+p82V8B8Dw8KN2/V9c/OAE=
226 | github.com/jackc/pgmock v0.0.0-20201204152224-4fe30f7445fd/go.mod h1:hrBW0Enj2AZTNpt/7Y5rr2xe/9Mn757Wtb2xeBzPv2c=
227 | github.com/jackc/pgmock v0.0.0-20210724152146-4ad1a8207f65 h1:DadwsjnMwFjfWc9y5Wi/+Zz7xoE5ALHsRQlOctkOiHc=
228 | github.com/jackc/pgmock v0.0.0-20210724152146-4ad1a8207f65/go.mod h1:5R2h2EEX+qri8jOWMbJCtaPWkrrNc7OHwsp2TCqp7ak=
229 | github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
230 | github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
231 | github.com/jackc/pgproto3 v1.1.0/go.mod h1:eR5FA3leWg7p9aeAqi37XOTgTIbkABlvcPB3E5rlc78=
232 | github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190420180111-c116219b62db/go.mod h1:bhq50y+xrl9n5mRYyCBFKkpRVTLYJVWeCc+mEAI3yXA=
233 | github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190609003834-432c2951c711/go.mod h1:uH0AWtUmuShn0bcesswc4aBTWGvw0cAxIJp+6OB//Wg=
234 | github.com/jackc/pgproto3/v2 v2.0.0-rc3/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM=
235 | github.com/jackc/pgproto3/v2 v2.0.0-rc3.0.20190831210041-4c03ce451f29/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM=
236 | github.com/jackc/pgproto3/v2 v2.0.6/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
237 | github.com/jackc/pgproto3/v2 v2.1.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
238 | github.com/jackc/pgproto3/v2 v2.3.2 h1:7eY55bdBeCz1F2fTzSz69QC+pG46jYq9/jtSPiJ5nn0=
239 | github.com/jackc/pgproto3/v2 v2.3.2/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
240 | github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E=
241 | github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a h1:bbPeKD0xmW/Y25WS6cokEszi5g+S0QxI/d45PkRi7Nk=
242 | github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
243 | github.com/jackc/pgtype v0.0.0-20190421001408-4ed0de4755e0/go.mod h1:hdSHsc1V01CGwFsrv11mJRHWJ6aifDLfdV3aVjFF0zg=
244 | github.com/jackc/pgtype v0.0.0-20190824184912-ab885b375b90/go.mod h1:KcahbBH1nCMSo2DXpzsoWOAfFkdEtEJpPbVLq8eE+mc=
245 | github.com/jackc/pgtype v0.0.0-20190828014616-a8802b16cc59/go.mod h1:MWlu30kVJrUS8lot6TQqcg7mtthZ9T0EoIBFiJcmcyw=
246 | github.com/jackc/pgtype v1.8.1-0.20210724151600-32e20a603178/go.mod h1:C516IlIV9NKqfsMCXTdChteoXmwgUceqaLfjg2e3NlM=
247 | github.com/jackc/pgtype v1.14.0 h1:y+xUdabmyMkJLyApYuPj38mW+aAIqCe5uuBB51rH3Vw=
248 | github.com/jackc/pgtype v1.14.0/go.mod h1:LUMuVrfsFfdKGLw+AFFVv6KtHOFMwRgDDzBt76IqCA4=
249 | github.com/jackc/pgx/v4 v4.0.0-20190420224344-cc3461e65d96/go.mod h1:mdxmSJJuR08CZQyj1PVQBHy9XOp5p8/SHH6a0psbY9Y=
250 | github.com/jackc/pgx/v4 v4.0.0-20190421002000-1b8f0016e912/go.mod h1:no/Y67Jkk/9WuGR0JG/JseM9irFbnEPbuWV2EELPNuM=
251 | github.com/jackc/pgx/v4 v4.0.0-pre1.0.20190824185557-6972a5742186/go.mod h1:X+GQnOEnf1dqHGpw7JmHqHc1NxDoalibchSk9/RWuDc=
252 | github.com/jackc/pgx/v4 v4.12.1-0.20210724153913-640aa07df17c/go.mod h1:1QD0+tgSXP7iUjYm9C1NxKhny7lq6ee99u/z+IHFcgs=
253 | github.com/jackc/pgx/v4 v4.18.1 h1:YP7G1KABtKpB5IHrO9vYwSrCOhs7p3uqhvhhQBptya0=
254 | github.com/jackc/pgx/v4 v4.18.1/go.mod h1:FydWkUyadDmdNH/mHnGob881GawxeEm7TcMCzkb+qQE=
255 | github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
256 | github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
257 | github.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
258 | github.com/jackc/puddle v1.3.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
259 | github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
260 | github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg=
261 | github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
262 | github.com/klauspost/compress v1.12.3/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg=
263 | github.com/klauspost/compress v1.16.3 h1:XuJt9zzcnaz6a16/OU53ZjWp/v7/42WcR5t2a0PcNQY=
264 | github.com/klauspost/compress v1.16.3/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
265 | github.com/klauspost/cpuid/v2 v2.2.4 h1:acbojRNwl3o09bUq+yDCtZFc1aiwaAAxtcn8YkZXnvk=
266 | github.com/klauspost/cpuid/v2 v2.2.4/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY=
267 | github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
268 | github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
269 | github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
270 | github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
271 | github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
272 | github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
273 | github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
274 | github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw=
275 | github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
276 | github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
277 | github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
278 | github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
279 | github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
280 | github.com/lib/pq v1.10.2 h1:AqzbZs4ZoCBp+GtejcpCpcxM3zlSMx29dXbUSeVtJb8=
281 | github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
282 | github.com/libdns/libdns v0.2.1 h1:Wu59T7wSHRgtA0cfxC+n1c/e+O3upJGWytknkmFEDis=
283 | github.com/libdns/libdns v0.2.1/go.mod h1:yQCXzk1lEZmmCPa857bnk4TsOiqYasqpyOEeSObbb40=
284 | github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
285 | github.com/manifoldco/promptui v0.9.0 h1:3V4HzJk1TtXW1MTZMP7mdlwbBpIinw3HztaIlYthEiA=
286 | github.com/manifoldco/promptui v0.9.0/go.mod h1:ka04sppxSGFAtxX0qhlYQjISsg9mR4GWtQEhdbn6Pgg=
287 | github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ=
288 | github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
289 | github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
290 | github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
291 | github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
292 | github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
293 | github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
294 | github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
295 | github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE=
296 | github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
297 | github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
298 | github.com/mattn/go-isatty v0.0.18 h1:DOKFKCQ7FNG2L1rbrmstDN4QVRdS89Nkh85u68Uwp98=
299 | github.com/mattn/go-isatty v0.0.18/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
300 | github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo=
301 | github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
302 | github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d h1:5PJl274Y63IEHC+7izoQE9x6ikvDFZS2mDVS3drnohI=
303 | github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=
304 | github.com/mholt/acmez v1.1.0 h1:IQ9CGHKOHokorxnffsqDvmmE30mDenO1lptYZ1AYkHY=
305 | github.com/mholt/acmez v1.1.0/go.mod h1:zwo5+fbLLTowAX8o8ETfQzbDtwGEXnPhkmGdKIP+bgs=
306 | github.com/micromdm/scep/v2 v2.1.0 h1:2fS9Rla7qRR266hvUoEauBJ7J6FhgssEiq2OkSKXmaU=
307 | github.com/micromdm/scep/v2 v2.1.0/go.mod h1:BkF7TkPPhmgJAMtHfP+sFTKXmgzNJgLQlvvGoOExBcc=
308 | github.com/miekg/dns v1.1.52 h1:Bmlc/qsNNULOe6bpXcUTsuOajd0DzRHwup6D9k1An0c=
309 | github.com/miekg/dns v1.1.52/go.mod h1:uInx36IzPl7FYnDcMeVWxj9byh7DutNykX4G9Sj60FY=
310 | github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw=
311 | github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw=
312 | github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s=
313 | github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
314 | github.com/mitchellh/go-ps v1.0.0 h1:i6ampVEEF4wQFF+bkYfwYgY+F/uYJDktmvLPf7qIgjc=
315 | github.com/mitchellh/go-ps v1.0.0/go.mod h1:J4lOc8z8yJs6vUwklHw2XEIiT4z4C40KtWVN3nvg8Pg=
316 | github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
317 | github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
318 | github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ=
319 | github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
320 | github.com/onsi/ginkgo/v2 v2.9.1 h1:zie5Ly042PD3bsCvsSOPvRnFwyo3rKe64TJlD6nu0mk=
321 | github.com/onsi/ginkgo/v2 v2.9.1/go.mod h1:FEcmzVcCHl+4o9bQZVab+4dC9+j+91t2FHSzmGAPfuo=
322 | github.com/onsi/gomega v1.27.3 h1:5VwIwnBY3vbBDOJrNtA4rVdiTZCsq9B5F12pvy1Drmk=
323 | github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
324 | github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
325 | github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
326 | github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
327 | github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
328 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
329 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
330 | github.com/prometheus/client_golang v1.14.0 h1:nJdhIvne2eSX/XRAFV9PcvFFRbrjbcTUj0VP62TMhnw=
331 | github.com/prometheus/client_golang v1.14.0/go.mod h1:8vpkKitgIVNcqrRBWh1C4TIUQgYNtG/XQE4E/Zae36Y=
332 | github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
333 | github.com/prometheus/client_model v0.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4=
334 | github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w=
335 | github.com/prometheus/common v0.42.0 h1:EKsfXEYo4JpWMHH5cg+KOUWeuJSov1Id8zGR8eeI1YM=
336 | github.com/prometheus/common v0.42.0/go.mod h1:xBwqVerjNdUDjgODMpudtOMwlOwf2SaTr1yjz4b7Zbc=
337 | github.com/prometheus/procfs v0.9.0 h1:wzCHvIvM5SxWqYvwgVL7yJY8Lz3PKn49KQtpgMYJfhI=
338 | github.com/prometheus/procfs v0.9.0/go.mod h1:+pB4zwohETzFnmlpe6yd2lSc+0/46IYZRB/chUwxUZY=
339 | github.com/quic-go/qpack v0.4.0 h1:Cr9BXA1sQS2SmDUWjSofMPNKmvF6IiIfDRmgU0w1ZCo=
340 | github.com/quic-go/qpack v0.4.0/go.mod h1:UZVnYIfi5GRk+zI9UMaCPsmZ2xKJP7XBUvVyT1Knj9A=
341 | github.com/quic-go/qtls-go1-19 v0.3.0 h1:aUBoQdpHzUWtPw5tQZbsD2GnrWCNu7/RIX1PtqGeLYY=
342 | github.com/quic-go/qtls-go1-19 v0.3.0/go.mod h1:ySOI96ew8lnoKPtSqx2BlI5wCpUVPT05RMAlajtnyOI=
343 | github.com/quic-go/qtls-go1-20 v0.2.0 h1:jUHn+obJ6WI5JudqBO0Iy1ra5Vh5vsitQ1gXQvkmN+E=
344 | github.com/quic-go/qtls-go1-20 v0.2.0/go.mod h1:JKtK6mjbAVcUTN/9jZpvLbGxvdWIKS8uT7EiStoU1SM=
345 | github.com/quic-go/quic-go v0.33.0 h1:ItNoTDN/Fm/zBlq769lLJc8ECe9gYaW40veHCCco7y0=
346 | github.com/quic-go/quic-go v0.33.0/go.mod h1:YMuhaAV9/jIu0XclDXwZPAsP/2Kgr5yMYhe9oxhhOFA=
347 | github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
348 | github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
349 | github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
350 | github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ=
351 | github.com/rs/xid v1.4.0 h1:qd7wPTDkN6KQx2VmMBLrpHkiyQwgFXRnkOLacUiaSNY=
352 | github.com/rs/xid v1.4.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
353 | github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU=
354 | github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc=
355 | github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
356 | github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
357 | github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
358 | github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
359 | github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
360 | github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4=
361 | github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
362 | github.com/shopspring/decimal v1.3.1 h1:2Usl1nmF/WZucqkFZhnfFYxxxu8LG21F6nPQBE5gKV8=
363 | github.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
364 | github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo=
365 | github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
366 | github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
367 | github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
368 | github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
369 | github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0=
370 | github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
371 | github.com/slackhq/nebula v1.6.1 h1:/OCTR3abj0Sbf2nGoLUrdDXImrCv0ZVFpVPP5qa0DsM=
372 | github.com/slackhq/nebula v1.6.1/go.mod h1:UmkqnXe4O53QwToSl/gG7sM4BroQwAB7dd4hUaT6MlI=
373 | github.com/smallstep/assert v0.0.0-20200723003110-82e2b9b3b262 h1:unQFBIznI+VYD1/1fApl1A+9VcBk+9dcqGfnePY87LY=
374 | github.com/smallstep/assert v0.0.0-20200723003110-82e2b9b3b262/go.mod h1:MyOHs9Po2fbM1LHej6sBUT8ozbxmMOFG+E+rx/GSGuc=
375 | github.com/smallstep/certificates v0.23.2 h1:7KSx9WfZ3CILV0XlsTrl+PK58YE4CHSgqobB6+ieQWs=
376 | github.com/smallstep/certificates v0.23.2/go.mod h1:YuQAlNuYrRA5z+meSH9D0XsUFH45TyAhNgyV5kYuQpQ=
377 | github.com/smallstep/nosql v0.6.0 h1:ur7ysI8s9st0cMXnTvB8tA3+x5Eifmkb6hl4uqNV5jc=
378 | github.com/smallstep/nosql v0.6.0/go.mod h1:jOXwLtockXORUPPZ2MCUcIkGR6w0cN1QGZniY9DITQA=
379 | github.com/smallstep/truststore v0.12.1 h1:guLUKkc1UlsXeS3t6BuVMa4leOOpdiv02PCRTiy1WdY=
380 | github.com/smallstep/truststore v0.12.1/go.mod h1:M4mebeNy28KusGX3lJxpLARIktLcyqBOrj3ZiZ46pqw=
381 | github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
382 | github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI=
383 | github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
384 | github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
385 | github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
386 | github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
387 | github.com/spf13/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w=
388 | github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU=
389 | github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU=
390 | github.com/spf13/cobra v1.6.1 h1:o94oiPyS4KD1mPy2fmcYYHHfCxLqYjJOhGsCHFZtEzA=
391 | github.com/spf13/cobra v1.6.1/go.mod h1:IOw/AERYS7UzyrGinqmz6HLUo219MORXGxhbaJUqzrY=
392 | github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
393 | github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
394 | github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
395 | github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
396 | github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s=
397 | github.com/stoewer/go-strcase v1.2.1 h1:/1JWd+AcWPzkcGLEmjUCka99YqGOtTnp1H/wcP+uap4=
398 | github.com/stoewer/go-strcase v1.2.1/go.mod h1:fAH5hQ5pehh+j3nZfvwdk2RgEgQjAoM8wodgtPmh1xo=
399 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
400 | github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
401 | github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
402 | github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
403 | github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
404 | github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
405 | github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
406 | github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
407 | github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
408 | github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
409 | github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
410 | github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
411 | github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
412 | github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8=
413 | github.com/tailscale/tscert v0.0.0-20230124224810-c6dc1f4049b2 h1:TrgfmCXwtWyFw85UkRGXt9qZRzdzt3nWt2Rerdecn0w=
414 | github.com/tailscale/tscert v0.0.0-20230124224810-c6dc1f4049b2/go.mod h1:kNGUQ3VESx3VZwRwA9MSCUegIl6+saPL8Noq82ozCaU=
415 | github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
416 | github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
417 | github.com/urfave/cli v1.22.12 h1:igJgVw1JdKH+trcLWLeLwZjU9fEfPesQ+9/e4MQ44S8=
418 | github.com/urfave/cli v1.22.12/go.mod h1:sSBEIC79qR6OvcmsD4U3KABeOTxDqQtdDnaFuUN30b8=
419 | github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
420 | github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=
421 | github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
422 | github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
423 | github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
424 | github.com/yuin/goldmark v1.4.15/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
425 | github.com/yuin/goldmark v1.5.4 h1:2uY/xC0roWy8IBEGLgB1ywIoEJFGmRrX21YQcvGZzjU=
426 | github.com/yuin/goldmark v1.5.4/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
427 | github.com/yuin/goldmark-highlighting/v2 v2.0.0-20220924101305-151362477c87 h1:Py16JEzkSdKAtEFJjiaYLYBOWGXc1r/xHj/Q/5lA37k=
428 | github.com/yuin/goldmark-highlighting/v2 v2.0.0-20220924101305-151362477c87/go.mod h1:ovIvrum6DQJA4QsJSovrkC4saKHQVs7TvcaeO8AIl5I=
429 | github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q=
430 | go.etcd.io/bbolt v1.3.7 h1:j+zJOnnEjF/kyHlDDgGnVL/AIqIJPq8UoB2GSNfkUfQ=
431 | go.etcd.io/bbolt v1.3.7/go.mod h1:N9Mkw9X8x5fupy0IKsmuqVtoGDyxsaDlbk4Rd05IAQw=
432 | go.mozilla.org/pkcs7 v0.0.0-20210730143726-725912489c62/go.mod h1:SNgMg+EgDFwmvSmLRTNKC5fegJjB7v23qTQ0XLGUNHk=
433 | go.mozilla.org/pkcs7 v0.0.0-20210826202110-33d05740a352 h1:CCriYyAfq1Br1aIYettdHZTy8mBTIPo7We18TuO/bak=
434 | go.mozilla.org/pkcs7 v0.0.0-20210826202110-33d05740a352/go.mod h1:SNgMg+EgDFwmvSmLRTNKC5fegJjB7v23qTQ0XLGUNHk=
435 | go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0=
436 | go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.39.0 h1:vFEBG7SieZJzvnRWQ81jxpuEqe6J8Ex+hgc9CqOTzHc=
437 | go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.39.0/go.mod h1:9rgTcOKdIhDOC0IcAu8a+R+FChqSUBihKpM1lVNi6T0=
438 | go.opentelemetry.io/otel v1.4.0/go.mod h1:jeAqMFKy2uLIxCtKxoFj0FAL5zAPKQagc3+GtBWakzk=
439 | go.opentelemetry.io/otel v1.13.0 h1:1ZAKnNQKwBBxFtww/GwxNUyTf0AxkZzrukO8MeXqe4Y=
440 | go.opentelemetry.io/otel v1.13.0/go.mod h1:FH3RtdZCzRkJYFTCsAKDy9l/XYjMdNv6QrkFFB8DvVg=
441 | go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.4.0 h1:j7AwzDdAQBJjcqayAaYbvpYeZzII7cEe5qJTu+De6UY=
442 | go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.4.0/go.mod h1:VpP4/RMn8bv8gNo9uK7/IMY4mtWLELsS+JIP0inH0h4=
443 | go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.4.0 h1:lRpP10E8oTGVmY1nVXcwelCT1Z8ca41/l5ce7AqLAss=
444 | go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.4.0/go.mod h1:3oS+j2WUoJVyj6/BzQN/52G17lNJDulngsOxDm1w2PY=
445 | go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.4.0 h1:buSx4AMC/0Z232slPhicN/fU5KIlj0bMngct5pcZhkI=
446 | go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.4.0/go.mod h1:ew1NcwkHo0QFT3uTm3m2IVZMkZdVIpbOYNPasgWwpdk=
447 | go.opentelemetry.io/otel/metric v0.36.0 h1:t0lgGI+L68QWt3QtOIlqM9gXoxqxWLhZ3R/e5oOAY0Q=
448 | go.opentelemetry.io/otel/metric v0.36.0/go.mod h1:wKVw57sd2HdSZAzyfOM9gTqqE8v7CbqWsYL6AyrH9qk=
449 | go.opentelemetry.io/otel/sdk v1.4.0/go.mod h1:71GJPNJh4Qju6zJuYl1CrYtXbrgfau/M9UAggqiy1UE=
450 | go.opentelemetry.io/otel/sdk v1.13.0 h1:BHib5g8MvdqS65yo2vV1s6Le42Hm6rrw08qU6yz5JaM=
451 | go.opentelemetry.io/otel/sdk v1.13.0/go.mod h1:YLKPx5+6Vx/o1TCUYYs+bpymtkmazOMT6zoRrC7AQ7I=
452 | go.opentelemetry.io/otel/trace v1.4.0/go.mod h1:uc3eRsqDfWs9R7b92xbQbU42/eTNz4N+gLP8qJCi4aE=
453 | go.opentelemetry.io/otel/trace v1.13.0 h1:CBgRZ6ntv+Amuj1jDsMhZtlAPT6gbyIRdaIzFhfBSdY=
454 | go.opentelemetry.io/otel/trace v1.13.0/go.mod h1:muCvmmO9KKpvuXSf3KKAXXB2ygNYHQ+ZfI5X08d3tds=
455 | go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
456 | go.opentelemetry.io/proto/otlp v0.12.0 h1:CMJ/3Wp7iOWES+CYLfnBv+DVmPbB+kmy9PJ92XvlR6c=
457 | go.opentelemetry.io/proto/otlp v0.12.0/go.mod h1:TsIjwGWIx5VFYv9KGVlOpxoBl5Dy+63SUguV7GGvlSQ=
458 | go.step.sm/cli-utils v0.7.5 h1:jyp6X8k8mN1B0uWJydTid0C++8tQhm2kaaAdXKQQzdk=
459 | go.step.sm/cli-utils v0.7.5/go.mod h1:taSsY8haLmXoXM3ZkywIyRmVij/4Aj0fQbNTlJvv71I=
460 | go.step.sm/crypto v0.9.0/go.mod h1:+CYG05Mek1YDqi5WK0ERc6cOpKly2i/a5aZmU1sfGj0=
461 | go.step.sm/crypto v0.27.0 h1:MLRvcVCibCMcbcPlj9A6oOteyFqzy6lFfRAcE/ZTAqY=
462 | go.step.sm/crypto v0.27.0/go.mod h1:cee0F+IAmWe7AHIUcEBuOOCltHhcCON3kUSKaYjcn7c=
463 | go.step.sm/linkedca v0.19.0 h1:xuagkR35wrJI2gnu6FAM+q3VmjwsHScvGcJsfZ0GdsI=
464 | go.step.sm/linkedca v0.19.0/go.mod h1:b7vWPrHfYLEOTSUZitFEcztVCpTc+ileIN85CwEAluM=
465 | go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
466 | go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
467 | go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
468 | go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
469 | go.uber.org/atomic v1.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ=
470 | go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
471 | go.uber.org/goleak v1.1.12 h1:gZAh5/EyT/HQwlpkCy6wTpqfH9H8Lz8zbm3dZh+OyzA=
472 | go.uber.org/goleak v1.1.12/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ=
473 | go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
474 | go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4=
475 | go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU=
476 | go.uber.org/multierr v1.10.0 h1:S0h4aNzvfcFsC3dRF1jLoaov7oRaKqRGC/pUEJ2yvPQ=
477 | go.uber.org/multierr v1.10.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
478 | go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=
479 | go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
480 | go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
481 | go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM=
482 | go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60=
483 | go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg=
484 | golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
485 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
486 | golang.org/x/crypto v0.0.0-20190411191339-88737f569e3a/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE=
487 | golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
488 | golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
489 | golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
490 | golang.org/x/crypto v0.0.0-20200414173820-0848c9571904/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
491 | golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
492 | golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
493 | golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
494 | golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
495 | golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
496 | golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
497 | golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
498 | golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58=
499 | golang.org/x/crypto v0.7.0 h1:AvwMYaRytfdeVt3u6mLaxYtErKYjxA2OXjJ1HHq6t3A=
500 | golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU=
501 | golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
502 | golang.org/x/exp v0.0.0-20230321023759-10a507213a29 h1:ooxPy7fPvB4kwsA2h+iBNHkAbp/4JxTSwCmvdjEYmug=
503 | golang.org/x/exp v0.0.0-20230321023759-10a507213a29/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc=
504 | golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
505 | golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
506 | golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
507 | golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
508 | golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
509 | golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
510 | golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
511 | golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
512 | golang.org/x/mod v0.9.0 h1:KENHtAZL2y3NLMYZeHY9DW8HW8V+kQyJsY/V9JlKvCs=
513 | golang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
514 | golang.org/x/net v0.0.0-20170726083632-f5079bd7f6f7/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
515 | golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
516 | golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
517 | golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
518 | golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
519 | golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
520 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
521 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
522 | golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
523 | golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
524 | golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
525 | golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
526 | golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
527 | golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
528 | golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
529 | golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ=
530 | golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
531 | golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
532 | golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
533 | golang.org/x/oauth2 v0.6.0 h1:Lh8GPgSKBfWSwFvtuWOfeI3aAAnbXTSutYxJiOJFgIw=
534 | golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
535 | golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
536 | golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
537 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
538 | golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
539 | golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
540 | golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=
541 | golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
542 | golang.org/x/sys v0.0.0-20170728174421-0f826bdd13b5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
543 | golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
544 | golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
545 | golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
546 | golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
547 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
548 | golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
549 | golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
550 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
551 | golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
552 | golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
553 | golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
554 | golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
555 | golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
556 | golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
557 | golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
558 | golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
559 | golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
560 | golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
561 | golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
562 | golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
563 | golang.org/x/sys v0.0.0-20211031064116-611d5d643895/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
564 | golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
565 | golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
566 | golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
567 | golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
568 | golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
569 | golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
570 | golang.org/x/sys v0.0.0-20221010170243-090e33056c14/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
571 | golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
572 | golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
573 | golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ=
574 | golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
575 | golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
576 | golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
577 | golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
578 | golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
579 | golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
580 | golang.org/x/term v0.6.0 h1:clScbb1cHjoCkyRbWwBEUZ5H/tIFu5TAXIqaZD0Gcjw=
581 | golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U=
582 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
583 | golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
584 | golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
585 | golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
586 | golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
587 | golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
588 | golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
589 | golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
590 | golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68=
591 | golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
592 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
593 | golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
594 | golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
595 | golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
596 | golang.org/x/tools v0.0.0-20190425163242-31fd60d6bfdc/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
597 | golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
598 | golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
599 | golang.org/x/tools v0.0.0-20190823170909-c4a336ef6a2f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
600 | golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
601 | golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
602 | golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
603 | golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
604 | golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
605 | golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
606 | golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
607 | golang.org/x/tools v0.7.0 h1:W4OVu8VVOaIO0yzWMNdepAulS7YfoS3Zabrm8DOXXU4=
608 | golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s=
609 | golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
610 | golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
611 | golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
612 | golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
613 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
614 | golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
615 | google.golang.org/api v0.112.0 h1:iDmzvZ4C086R3+en4nSyIf07HlQKMOX1Xx2dmia/+KQ=
616 | google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
617 | google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
618 | google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c=
619 | google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
620 | google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
621 | google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
622 | google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
623 | google.golang.org/genproto v0.0.0-20230322174352-cde4c949918d h1:OE8TncEeAei3Tehf/P/Jdt/K+8GnTUrRY6wzYpbCes4=
624 | google.golang.org/genproto v0.0.0-20230322174352-cde4c949918d/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s=
625 | google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
626 | google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
627 | google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
628 | google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
629 | google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=
630 | google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
631 | google.golang.org/grpc v1.43.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU=
632 | google.golang.org/grpc v1.44.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU=
633 | google.golang.org/grpc v1.54.0 h1:EhTqbhiYeixwWQtAEZAxmV9MGqcjEU2mFx52xCzNyag=
634 | google.golang.org/grpc v1.54.0/go.mod h1:PUSEXI6iWghWaB6lXM4knEgpJNu2qUcKfDtNci3EC2g=
635 | google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
636 | google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
637 | google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
638 | google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
639 | google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
640 | google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
641 | google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
642 | google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
643 | google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
644 | google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
645 | google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
646 | google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
647 | google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng=
648 | google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
649 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
650 | gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
651 | gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
652 | gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
653 | gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
654 | gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s=
655 | gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc=
656 | gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc=
657 | gopkg.in/square/go-jose.v2 v2.5.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
658 | gopkg.in/square/go-jose.v2 v2.6.0 h1:NGk74WTnPKBNUhNzQX7PYcTLUjoq7mzKk2OKbvwk2iI=
659 | gopkg.in/square/go-jose.v2 v2.6.0/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
660 | gopkg.in/yaml.v1 v1.0.0-20140924161607-9f9df34309c0/go.mod h1:WDnlLJ4WF5VGsH/HVa3CI79GS0ol3YnhVnKP89i0kNg=
661 | gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
662 | gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
663 | gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
664 | gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
665 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
666 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
667 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
668 | honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
669 | honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
670 | honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
671 | howett.net/plist v1.0.0 h1:7CrbWYbPPO/PyNy38b2EB/+gYbjCe2DXBxgtOOZbSQM=
672 | howett.net/plist v1.0.0/go.mod h1:lqaXoTrLY4hg8tnEzNru53gicrbv7rrk+2xJA/7hw9g=
673 |
--------------------------------------------------------------------------------
/middleware/roadrunner/Makefile:
--------------------------------------------------------------------------------
1 | .PHONY: build log run
2 |
3 | build: ## Prepare roadrunner deps
4 | go mod tidy
5 | go mod download
6 |
7 | log: ## Display container logs
8 | cd examples && docker-compose -f docker-compose.yml.test logs -f
9 |
10 | run: ## Run roadrunner with go-esi
11 | cd examples && docker-compose -f docker-compose.yml.test up --remove-orphans --build
12 |
--------------------------------------------------------------------------------
/middleware/roadrunner/README.md:
--------------------------------------------------------------------------------
1 | Roadrunner middleware: Souin
2 | ================================
3 |
4 | This is a distributed HTTP cache module for Roadrunner based on [Souin](https://github.com/darkweak/souin) cache.
5 |
6 | ## Features
7 |
8 | * [RFC 7234](https://httpwg.org/specs/rfc7234.html) compliant HTTP Cache.
9 | * Sets [the `Cache-Status` HTTP Response Header](https://httpwg.org/http-extensions/draft-ietf-httpbis-cache-header.html)
10 | * REST API to purge the cache and list stored resources.
11 | * Builtin support for distributed cache.
12 | * Tag-based invalidation.
13 |
14 | ## Build the roadrunner binary
15 | ```toml
16 | [velox]
17 | build_args = ['-trimpath', '-ldflags', '-s -X github.com/roadrunner-server/roadrunner/v2/internal/meta.version=${VERSION} -X github.com/roadrunner-server/roadrunner/v2/internal/meta.buildTime=${TIME}']
18 |
19 | [roadrunner]
20 | ref = "master"
21 |
22 | [github]
23 | [github.token]
24 | token = "GH_TOKEN"
25 |
26 | [github.plugins]
27 | logger = { ref = "master", owner = "roadrunner-server", repository = "logger" }
28 | cache = { ref = "master", owner = "darkweak", repository = "souin", folder = "/plugins/roadrunner" }
29 | # others ...
30 |
31 | [log]
32 | level = "debug"
33 | mode = "development"
34 | ```
35 |
36 | ## Example configuration
37 | You can set each Souin configuration key under the `http.cache` key. There is a configuration example below.
38 | ```yaml
39 | # .rr.yaml
40 | http:
41 | # Other http sub keys
42 | cache:
43 | api:
44 | basepath: /httpcache_api
45 | prometheus:
46 | basepath: /anything-for-prometheus-metrics
47 | souin: {}
48 | default_cache:
49 | allowed_http_verbs:
50 | - GET
51 | - POST
52 | - HEAD
53 | cdn:
54 | api_key: XXXX
55 | dynamic: true
56 | hostname: XXXX
57 | network: XXXX
58 | provider: fastly
59 | strategy: soft
60 | headers:
61 | - Authorization
62 | regex:
63 | exclude: '/excluded'
64 | timeout:
65 | backend: 5s
66 | cache: 1ms
67 | ttl: 5s
68 | stale: 10s
69 | log_level: debug
70 | ykeys:
71 | The_First_Test:
72 | headers:
73 | Content-Type: '.+'
74 | The_Second_Test:
75 | url: 'the/second/.+'
76 | surrogate_keys:
77 | The_First_Test:
78 | headers:
79 | Content-Type: '.+'
80 | The_Second_Test:
81 | url: 'the/second/.+'
82 | middleware:
83 | - cache
84 | # Other middlewares
85 | ```
86 |
87 |
88 | Other resources
89 | ---------------
90 | You can find an example for a docker-compose stack inside the `examples` folder.
91 | See the [Souin](https://github.com/darkweak/souin) configuration for the full configuration, and its associated [development roadrunner middleware](https://github.com/darkweak/souin/blob/master/plugins/roadrunner)
92 |
93 |
--------------------------------------------------------------------------------
/middleware/roadrunner/esi.go:
--------------------------------------------------------------------------------
1 | package roadrunner_esi
2 |
3 | import (
4 | "bytes"
5 | "net/http"
6 | "sync"
7 |
8 | "github.com/darkweak/go-esi/writer"
9 | "github.com/roadrunner-server/errors"
10 | "go.uber.org/zap"
11 | )
12 |
13 | var bufPool *sync.Pool = &sync.Pool{
14 | New: func() any {
15 | return &bytes.Buffer{}
16 | },
17 | }
18 |
19 | const configurationKey = "http.esi"
20 |
21 | type (
22 | // Configurer interface used to parse yaml configuration.
23 | // Implementation will be provided by the RoadRunner automatically via Init method.
24 | Configurer interface {
25 | // Get used to get config section
26 | Get(name string) any
27 | // Has checks if config section exists.
28 | Has(name string) bool
29 | }
30 |
31 | Plugin struct{}
32 | )
33 |
34 | // Name is the plugin name
35 | func (p *Plugin) Name() string {
36 | return "esi"
37 | }
38 |
39 | // Init allows the user to set up an efficient esi processor.
40 | func (p *Plugin) Init(cfg Configurer, log *zap.Logger) error {
41 | const op = errors.Op("esi_middleware_init")
42 | if !cfg.Has(configurationKey) {
43 | return errors.E(op, errors.Disabled)
44 | }
45 |
46 | return nil
47 | }
48 |
49 | // Middleware is the request entrypoint to catch the response and
50 | // process the esi tags if present.
51 | func (p *Plugin) Middleware(next http.Handler) http.Handler {
52 | return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
53 | buf := bufPool.Get().(*bytes.Buffer)
54 | buf.Reset()
55 | defer bufPool.Put(buf)
56 | cw := writer.NewWriter(buf, rw, r)
57 | go func(w *writer.Writer) {
58 | var i = 0
59 | for {
60 | if len(w.AsyncBuf) <= i {
61 | continue
62 | }
63 | rs := <-w.AsyncBuf[i]
64 | if rs == nil {
65 | w.Done <- true
66 | break
67 | }
68 | _, _ = rw.Write(rs)
69 | i++
70 | }
71 | }(cw)
72 | next.ServeHTTP(cw, r)
73 | cw.Header().Del("Content-Length")
74 | if cw.Rq.ProtoMajor == 1 {
75 | cw.Header().Set("Content-Encoding", "chunked")
76 | }
77 | cw.AsyncBuf = append(cw.AsyncBuf, make(chan []byte))
78 | go func(w *writer.Writer, iteration int) {
79 | w.AsyncBuf[iteration] <- nil
80 | }(cw, cw.Iteration)
81 |
82 | <-cw.Done
83 | })
84 | }
85 |
--------------------------------------------------------------------------------
/middleware/roadrunner/esi_test.go:
--------------------------------------------------------------------------------
1 | package roadrunner_esi
2 |
3 | import (
4 | "io"
5 | "net/http"
6 | "net/http/httptest"
7 | "testing"
8 | )
9 |
10 | type (
11 | configWrapper struct{}
12 | next struct{}
13 | )
14 |
15 | var nextFilter = &next{}
16 |
17 | func (n *next) ServeHTTP(rw http.ResponseWriter, rq *http.Request) {
18 | rw.WriteHeader(http.StatusOK)
19 | if rq.RequestURI == "/esi-include-1" {
20 | _, _ = rw.Write([]byte("Awesome first included ESI tag!"))
21 |
22 | return
23 | }
24 | if rq.RequestURI == "/esi-include-2" {
25 | _, _ = rw.Write([]byte("Another included ESI tag!"))
26 |
27 | return
28 | }
29 | _, _ = rw.Write([]byte(`Hello Roadrunner! `))
30 | }
31 |
32 | func (*configWrapper) Get(name string) any {
33 | return nil
34 | }
35 | func (*configWrapper) Has(name string) bool {
36 | return true
37 | }
38 |
39 | func Test_Plugin_Init(t *testing.T) {
40 | p := &Plugin{}
41 |
42 | if p.Init(&configWrapper{}, nil) != nil {
43 | t.Error("The Init method must not crash if a valid configuration is given.")
44 | }
45 |
46 | defer func() {
47 | if recover() == nil {
48 | t.Error("The Init method must crash if a nil configuration is given.")
49 | }
50 | }()
51 | err := p.Init(nil, nil)
52 | if err != nil {
53 | t.Error(err.Error())
54 | }
55 | }
56 |
57 | func prepare(endpoint string) (req *http.Request, res1 *httptest.ResponseRecorder) {
58 | req = httptest.NewRequest(http.MethodGet, endpoint, nil)
59 | res1 = httptest.NewRecorder()
60 |
61 | return
62 | }
63 |
64 | func Test_Plugin_Middleware(t *testing.T) {
65 | p := &Plugin{}
66 | _ = p.Init(&configWrapper{}, nil)
67 | handler := p.Middleware(nextFilter)
68 | req, res := prepare("http://localhost/handled")
69 | handler.ServeHTTP(res, req)
70 | rs := res.Result()
71 | defer rs.Body.Close()
72 | b, err := io.ReadAll(rs.Body)
73 | if err != nil {
74 | t.Error("body read error")
75 | }
76 |
77 | if string(b) != "Hello Roadrunner! " {
78 | t.Error(`The returned response must be equal to "Hello Roadrunner! " because of non running service.`)
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/middleware/roadrunner/examples/.gitignore:
--------------------------------------------------------------------------------
1 | vendor/
2 | rr
3 |
--------------------------------------------------------------------------------
/middleware/roadrunner/examples/.rr.yaml:
--------------------------------------------------------------------------------
1 | server:
2 | command: "php psr-worker.php"
3 | http:
4 | address: 0.0.0.0:80
5 | pool:
6 | num_workers: 4
7 | esi: {}
8 | middleware: [ "headers", "gzip", "esi" ]
9 |
--------------------------------------------------------------------------------
/middleware/roadrunner/examples/Dockerfile.test:
--------------------------------------------------------------------------------
1 | FROM ghcr.io/roadrunner-server/velox:latest as velox
2 |
3 | ARG CURRENT_SHA
4 | ARG GH_TOKEN
5 | ENV CGO_ENABLED=0
6 | ENV VERSION=v2.12.0
7 | ENV TIME="$(date +%H:%M)"
8 |
9 | RUN apk add git
10 |
11 | COPY . /opt
12 | WORKDIR /opt/middleware/roadrunner
13 | RUN go get -u "github.com/darkweak/go-esi@${CURRENT_SHA}"
14 | WORKDIR /opt/middleware/roadrunner/examples
15 | RUN sed -i "s/GH_TOKEN/${GH_TOKEN}/" configuration.toml
16 | RUN sed -i "s/CURRENT_SHA/${CURRENT_SHA}/" configuration.toml
17 |
18 | RUN vx build -c configuration.toml -o /usr/bin/
19 |
20 | FROM composer:latest AS development-runner
21 | COPY --from=velox /usr/bin/rr /usr/bin/rr
22 |
23 | RUN apk add linux-headers
24 | RUN docker-php-ext-install sockets
25 | RUN composer require spiral/roadrunner nyholm/psr7
26 |
27 | COPY middleware/roadrunner/examples .
28 |
29 | CMD ["/usr/bin/rr", "serve"]
--------------------------------------------------------------------------------
/middleware/roadrunner/examples/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "require": {
3 | "spiral/roadrunner": "^2.10",
4 | "nyholm/psr7": "^1.5"
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/middleware/roadrunner/examples/composer.lock:
--------------------------------------------------------------------------------
1 | {
2 | "_readme": [
3 | "This file locks the dependencies of your project to a known state",
4 | "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
5 | "This file is @generated automatically"
6 | ],
7 | "content-hash": "0941953bf9ca779dea29d031a72ae0f8",
8 | "packages": [
9 | {
10 | "name": "composer/semver",
11 | "version": "3.3.2",
12 | "source": {
13 | "type": "git",
14 | "url": "https://github.com/composer/semver.git",
15 | "reference": "3953f23262f2bff1919fc82183ad9acb13ff62c9"
16 | },
17 | "dist": {
18 | "type": "zip",
19 | "url": "https://api.github.com/repos/composer/semver/zipball/3953f23262f2bff1919fc82183ad9acb13ff62c9",
20 | "reference": "3953f23262f2bff1919fc82183ad9acb13ff62c9",
21 | "shasum": ""
22 | },
23 | "require": {
24 | "php": "^5.3.2 || ^7.0 || ^8.0"
25 | },
26 | "require-dev": {
27 | "phpstan/phpstan": "^1.4",
28 | "symfony/phpunit-bridge": "^4.2 || ^5"
29 | },
30 | "type": "library",
31 | "extra": {
32 | "branch-alias": {
33 | "dev-main": "3.x-dev"
34 | }
35 | },
36 | "autoload": {
37 | "psr-4": {
38 | "Composer\\Semver\\": "src"
39 | }
40 | },
41 | "notification-url": "https://packagist.org/downloads/",
42 | "license": [
43 | "MIT"
44 | ],
45 | "authors": [
46 | {
47 | "name": "Nils Adermann",
48 | "email": "naderman@naderman.de",
49 | "homepage": "http://www.naderman.de"
50 | },
51 | {
52 | "name": "Jordi Boggiano",
53 | "email": "j.boggiano@seld.be",
54 | "homepage": "http://seld.be"
55 | },
56 | {
57 | "name": "Rob Bast",
58 | "email": "rob.bast@gmail.com",
59 | "homepage": "http://robbast.nl"
60 | }
61 | ],
62 | "description": "Semver library that offers utilities, version constraint parsing and validation.",
63 | "keywords": [
64 | "semantic",
65 | "semver",
66 | "validation",
67 | "versioning"
68 | ],
69 | "support": {
70 | "irc": "irc://irc.freenode.org/composer",
71 | "issues": "https://github.com/composer/semver/issues",
72 | "source": "https://github.com/composer/semver/tree/3.3.2"
73 | },
74 | "funding": [
75 | {
76 | "url": "https://packagist.com",
77 | "type": "custom"
78 | },
79 | {
80 | "url": "https://github.com/composer",
81 | "type": "github"
82 | },
83 | {
84 | "url": "https://tidelift.com/funding/github/packagist/composer/composer",
85 | "type": "tidelift"
86 | }
87 | ],
88 | "time": "2022-04-01T19:23:25+00:00"
89 | },
90 | {
91 | "name": "nyholm/psr7",
92 | "version": "1.5.1",
93 | "source": {
94 | "type": "git",
95 | "url": "https://github.com/Nyholm/psr7.git",
96 | "reference": "f734364e38a876a23be4d906a2a089e1315be18a"
97 | },
98 | "dist": {
99 | "type": "zip",
100 | "url": "https://api.github.com/repos/Nyholm/psr7/zipball/f734364e38a876a23be4d906a2a089e1315be18a",
101 | "reference": "f734364e38a876a23be4d906a2a089e1315be18a",
102 | "shasum": ""
103 | },
104 | "require": {
105 | "php": ">=7.1",
106 | "php-http/message-factory": "^1.0",
107 | "psr/http-factory": "^1.0",
108 | "psr/http-message": "^1.0"
109 | },
110 | "provide": {
111 | "psr/http-factory-implementation": "1.0",
112 | "psr/http-message-implementation": "1.0"
113 | },
114 | "require-dev": {
115 | "http-interop/http-factory-tests": "^0.9",
116 | "php-http/psr7-integration-tests": "^1.0",
117 | "phpunit/phpunit": "^7.5 || 8.5 || 9.4",
118 | "symfony/error-handler": "^4.4"
119 | },
120 | "type": "library",
121 | "extra": {
122 | "branch-alias": {
123 | "dev-master": "1.4-dev"
124 | }
125 | },
126 | "autoload": {
127 | "psr-4": {
128 | "Nyholm\\Psr7\\": "src/"
129 | }
130 | },
131 | "notification-url": "https://packagist.org/downloads/",
132 | "license": [
133 | "MIT"
134 | ],
135 | "authors": [
136 | {
137 | "name": "Tobias Nyholm",
138 | "email": "tobias.nyholm@gmail.com"
139 | },
140 | {
141 | "name": "Martijn van der Ven",
142 | "email": "martijn@vanderven.se"
143 | }
144 | ],
145 | "description": "A fast PHP7 implementation of PSR-7",
146 | "homepage": "https://tnyholm.se",
147 | "keywords": [
148 | "psr-17",
149 | "psr-7"
150 | ],
151 | "support": {
152 | "issues": "https://github.com/Nyholm/psr7/issues",
153 | "source": "https://github.com/Nyholm/psr7/tree/1.5.1"
154 | },
155 | "funding": [
156 | {
157 | "url": "https://github.com/Zegnat",
158 | "type": "github"
159 | },
160 | {
161 | "url": "https://github.com/nyholm",
162 | "type": "github"
163 | }
164 | ],
165 | "time": "2022-06-22T07:13:36+00:00"
166 | },
167 | {
168 | "name": "php-http/message-factory",
169 | "version": "v1.0.2",
170 | "source": {
171 | "type": "git",
172 | "url": "https://github.com/php-http/message-factory.git",
173 | "reference": "a478cb11f66a6ac48d8954216cfed9aa06a501a1"
174 | },
175 | "dist": {
176 | "type": "zip",
177 | "url": "https://api.github.com/repos/php-http/message-factory/zipball/a478cb11f66a6ac48d8954216cfed9aa06a501a1",
178 | "reference": "a478cb11f66a6ac48d8954216cfed9aa06a501a1",
179 | "shasum": ""
180 | },
181 | "require": {
182 | "php": ">=5.4",
183 | "psr/http-message": "^1.0"
184 | },
185 | "type": "library",
186 | "extra": {
187 | "branch-alias": {
188 | "dev-master": "1.0-dev"
189 | }
190 | },
191 | "autoload": {
192 | "psr-4": {
193 | "Http\\Message\\": "src/"
194 | }
195 | },
196 | "notification-url": "https://packagist.org/downloads/",
197 | "license": [
198 | "MIT"
199 | ],
200 | "authors": [
201 | {
202 | "name": "Márk Sági-Kazár",
203 | "email": "mark.sagikazar@gmail.com"
204 | }
205 | ],
206 | "description": "Factory interfaces for PSR-7 HTTP Message",
207 | "homepage": "http://php-http.org",
208 | "keywords": [
209 | "factory",
210 | "http",
211 | "message",
212 | "stream",
213 | "uri"
214 | ],
215 | "support": {
216 | "issues": "https://github.com/php-http/message-factory/issues",
217 | "source": "https://github.com/php-http/message-factory/tree/master"
218 | },
219 | "time": "2015-12-19T14:08:53+00:00"
220 | },
221 | {
222 | "name": "psr/container",
223 | "version": "2.0.2",
224 | "source": {
225 | "type": "git",
226 | "url": "https://github.com/php-fig/container.git",
227 | "reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963"
228 | },
229 | "dist": {
230 | "type": "zip",
231 | "url": "https://api.github.com/repos/php-fig/container/zipball/c71ecc56dfe541dbd90c5360474fbc405f8d5963",
232 | "reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963",
233 | "shasum": ""
234 | },
235 | "require": {
236 | "php": ">=7.4.0"
237 | },
238 | "type": "library",
239 | "extra": {
240 | "branch-alias": {
241 | "dev-master": "2.0.x-dev"
242 | }
243 | },
244 | "autoload": {
245 | "psr-4": {
246 | "Psr\\Container\\": "src/"
247 | }
248 | },
249 | "notification-url": "https://packagist.org/downloads/",
250 | "license": [
251 | "MIT"
252 | ],
253 | "authors": [
254 | {
255 | "name": "PHP-FIG",
256 | "homepage": "https://www.php-fig.org/"
257 | }
258 | ],
259 | "description": "Common Container Interface (PHP FIG PSR-11)",
260 | "homepage": "https://github.com/php-fig/container",
261 | "keywords": [
262 | "PSR-11",
263 | "container",
264 | "container-interface",
265 | "container-interop",
266 | "psr"
267 | ],
268 | "support": {
269 | "issues": "https://github.com/php-fig/container/issues",
270 | "source": "https://github.com/php-fig/container/tree/2.0.2"
271 | },
272 | "time": "2021-11-05T16:47:00+00:00"
273 | },
274 | {
275 | "name": "psr/http-factory",
276 | "version": "1.0.1",
277 | "source": {
278 | "type": "git",
279 | "url": "https://github.com/php-fig/http-factory.git",
280 | "reference": "12ac7fcd07e5b077433f5f2bee95b3a771bf61be"
281 | },
282 | "dist": {
283 | "type": "zip",
284 | "url": "https://api.github.com/repos/php-fig/http-factory/zipball/12ac7fcd07e5b077433f5f2bee95b3a771bf61be",
285 | "reference": "12ac7fcd07e5b077433f5f2bee95b3a771bf61be",
286 | "shasum": ""
287 | },
288 | "require": {
289 | "php": ">=7.0.0",
290 | "psr/http-message": "^1.0"
291 | },
292 | "type": "library",
293 | "extra": {
294 | "branch-alias": {
295 | "dev-master": "1.0.x-dev"
296 | }
297 | },
298 | "autoload": {
299 | "psr-4": {
300 | "Psr\\Http\\Message\\": "src/"
301 | }
302 | },
303 | "notification-url": "https://packagist.org/downloads/",
304 | "license": [
305 | "MIT"
306 | ],
307 | "authors": [
308 | {
309 | "name": "PHP-FIG",
310 | "homepage": "http://www.php-fig.org/"
311 | }
312 | ],
313 | "description": "Common interfaces for PSR-7 HTTP message factories",
314 | "keywords": [
315 | "factory",
316 | "http",
317 | "message",
318 | "psr",
319 | "psr-17",
320 | "psr-7",
321 | "request",
322 | "response"
323 | ],
324 | "support": {
325 | "source": "https://github.com/php-fig/http-factory/tree/master"
326 | },
327 | "time": "2019-04-30T12:38:16+00:00"
328 | },
329 | {
330 | "name": "psr/http-message",
331 | "version": "1.0.1",
332 | "source": {
333 | "type": "git",
334 | "url": "https://github.com/php-fig/http-message.git",
335 | "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363"
336 | },
337 | "dist": {
338 | "type": "zip",
339 | "url": "https://api.github.com/repos/php-fig/http-message/zipball/f6561bf28d520154e4b0ec72be95418abe6d9363",
340 | "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363",
341 | "shasum": ""
342 | },
343 | "require": {
344 | "php": ">=5.3.0"
345 | },
346 | "type": "library",
347 | "extra": {
348 | "branch-alias": {
349 | "dev-master": "1.0.x-dev"
350 | }
351 | },
352 | "autoload": {
353 | "psr-4": {
354 | "Psr\\Http\\Message\\": "src/"
355 | }
356 | },
357 | "notification-url": "https://packagist.org/downloads/",
358 | "license": [
359 | "MIT"
360 | ],
361 | "authors": [
362 | {
363 | "name": "PHP-FIG",
364 | "homepage": "http://www.php-fig.org/"
365 | }
366 | ],
367 | "description": "Common interface for HTTP messages",
368 | "homepage": "https://github.com/php-fig/http-message",
369 | "keywords": [
370 | "http",
371 | "http-message",
372 | "psr",
373 | "psr-7",
374 | "request",
375 | "response"
376 | ],
377 | "support": {
378 | "source": "https://github.com/php-fig/http-message/tree/master"
379 | },
380 | "time": "2016-08-06T14:39:51+00:00"
381 | },
382 | {
383 | "name": "psr/log",
384 | "version": "3.0.0",
385 | "source": {
386 | "type": "git",
387 | "url": "https://github.com/php-fig/log.git",
388 | "reference": "fe5ea303b0887d5caefd3d431c3e61ad47037001"
389 | },
390 | "dist": {
391 | "type": "zip",
392 | "url": "https://api.github.com/repos/php-fig/log/zipball/fe5ea303b0887d5caefd3d431c3e61ad47037001",
393 | "reference": "fe5ea303b0887d5caefd3d431c3e61ad47037001",
394 | "shasum": ""
395 | },
396 | "require": {
397 | "php": ">=8.0.0"
398 | },
399 | "type": "library",
400 | "extra": {
401 | "branch-alias": {
402 | "dev-master": "3.x-dev"
403 | }
404 | },
405 | "autoload": {
406 | "psr-4": {
407 | "Psr\\Log\\": "src"
408 | }
409 | },
410 | "notification-url": "https://packagist.org/downloads/",
411 | "license": [
412 | "MIT"
413 | ],
414 | "authors": [
415 | {
416 | "name": "PHP-FIG",
417 | "homepage": "https://www.php-fig.org/"
418 | }
419 | ],
420 | "description": "Common interface for logging libraries",
421 | "homepage": "https://github.com/php-fig/log",
422 | "keywords": [
423 | "log",
424 | "psr",
425 | "psr-3"
426 | ],
427 | "support": {
428 | "source": "https://github.com/php-fig/log/tree/3.0.0"
429 | },
430 | "time": "2021-07-14T16:46:02+00:00"
431 | },
432 | {
433 | "name": "spiral/goridge",
434 | "version": "v3.2.0",
435 | "source": {
436 | "type": "git",
437 | "url": "https://github.com/spiral/goridge-php.git",
438 | "reference": "3d8e97d7d1cc26b6130d233177b23ecb3c7d4efb"
439 | },
440 | "dist": {
441 | "type": "zip",
442 | "url": "https://api.github.com/repos/spiral/goridge-php/zipball/3d8e97d7d1cc26b6130d233177b23ecb3c7d4efb",
443 | "reference": "3d8e97d7d1cc26b6130d233177b23ecb3c7d4efb",
444 | "shasum": ""
445 | },
446 | "require": {
447 | "ext-json": "*",
448 | "ext-sockets": "*",
449 | "php": ">=7.4",
450 | "symfony/polyfill-php80": "^1.22"
451 | },
452 | "require-dev": {
453 | "google/protobuf": "^3.17",
454 | "infection/infection": "^0.26.1",
455 | "jetbrains/phpstorm-attributes": "^1.0",
456 | "phpunit/phpunit": "^9.5",
457 | "rybakit/msgpack": "^0.7",
458 | "vimeo/psalm": "^4.18.1"
459 | },
460 | "suggest": {
461 | "ext-msgpack": "MessagePack codec support",
462 | "ext-protobuf": "Protobuf codec support",
463 | "google/protobuf": "(^3.0) Protobuf codec support",
464 | "rybakit/msgpack": "(^0.7) MessagePack codec support"
465 | },
466 | "type": "goridge",
467 | "extra": {
468 | "branch-alias": {
469 | "dev-master": "3.3.x-dev"
470 | }
471 | },
472 | "autoload": {
473 | "psr-4": {
474 | "Spiral\\Goridge\\": "src"
475 | }
476 | },
477 | "notification-url": "https://packagist.org/downloads/",
478 | "license": [
479 | "MIT"
480 | ],
481 | "authors": [
482 | {
483 | "name": "Anton Titov / Wolfy-J",
484 | "email": "wolfy.jd@gmail.com"
485 | }
486 | ],
487 | "description": "High-performance PHP-to-Golang RPC bridge",
488 | "support": {
489 | "issues": "https://github.com/spiral/goridge-php/issues",
490 | "source": "https://github.com/spiral/goridge-php/tree/v3.2.0"
491 | },
492 | "time": "2022-03-21T20:32:19+00:00"
493 | },
494 | {
495 | "name": "spiral/roadrunner",
496 | "version": "v2.10.7",
497 | "source": {
498 | "type": "git",
499 | "url": "https://github.com/roadrunner-server/roadrunner.git",
500 | "reference": "18a7a98bcb483a680b6ebe7da8bb61e95329daf4"
501 | },
502 | "dist": {
503 | "type": "zip",
504 | "url": "https://api.github.com/repos/roadrunner-server/roadrunner/zipball/18a7a98bcb483a680b6ebe7da8bb61e95329daf4",
505 | "reference": "18a7a98bcb483a680b6ebe7da8bb61e95329daf4",
506 | "shasum": ""
507 | },
508 | "require": {
509 | "spiral/roadrunner-cli": "^2.0",
510 | "spiral/roadrunner-http": "^2.0",
511 | "spiral/roadrunner-worker": "^2.0"
512 | },
513 | "type": "metapackage",
514 | "notification-url": "https://packagist.org/downloads/",
515 | "license": [
516 | "MIT"
517 | ],
518 | "authors": [
519 | {
520 | "name": "Anton Titov / Wolfy-J",
521 | "email": "wolfy.jd@gmail.com"
522 | },
523 | {
524 | "name": "RoadRunner Community",
525 | "homepage": "https://github.com/roadrunner-server/roadrunner/graphs/contributors"
526 | }
527 | ],
528 | "description": "RoadRunner: High-performance PHP application server, load-balancer and process manager written in Golang",
529 | "support": {
530 | "issues": "https://github.com/roadrunner-server/roadrunner/issues",
531 | "source": "https://github.com/roadrunner-server/roadrunner/tree/v2.10.7"
532 | },
533 | "time": "2022-07-14T09:00:44+00:00"
534 | },
535 | {
536 | "name": "spiral/roadrunner-cli",
537 | "version": "v2.2.0",
538 | "source": {
539 | "type": "git",
540 | "url": "https://github.com/spiral/roadrunner-cli.git",
541 | "reference": "d8a224137b1d1ace0aac2308df396403393d63a8"
542 | },
543 | "dist": {
544 | "type": "zip",
545 | "url": "https://api.github.com/repos/spiral/roadrunner-cli/zipball/d8a224137b1d1ace0aac2308df396403393d63a8",
546 | "reference": "d8a224137b1d1ace0aac2308df396403393d63a8",
547 | "shasum": ""
548 | },
549 | "require": {
550 | "composer/semver": "^3.2",
551 | "ext-json": "*",
552 | "php": ">=7.4",
553 | "spiral/roadrunner-worker": ">=2.0.2",
554 | "symfony/console": "^4.4|^5.0|^6.0",
555 | "symfony/http-client": "^4.4|^5.0|^6.0",
556 | "symfony/polyfill-php80": "^1.22"
557 | },
558 | "require-dev": {
559 | "jetbrains/phpstorm-attributes": "^1.0",
560 | "symfony/var-dumper": "^4.4|^5.0",
561 | "vimeo/psalm": "^4.4"
562 | },
563 | "bin": [
564 | "bin/rr"
565 | ],
566 | "type": "library",
567 | "extra": {
568 | "branch-alias": {
569 | "dev-master": "2.1.x-dev"
570 | }
571 | },
572 | "autoload": {
573 | "psr-4": {
574 | "Spiral\\RoadRunner\\Console\\": "src"
575 | }
576 | },
577 | "notification-url": "https://packagist.org/downloads/",
578 | "license": [
579 | "MIT"
580 | ],
581 | "authors": [
582 | {
583 | "name": "Anton Titov (wolfy-j)",
584 | "email": "wolfy-j@spiralscout.com"
585 | },
586 | {
587 | "name": "RoadRunner Community",
588 | "homepage": "https://github.com/spiral/roadrunner/graphs/contributors"
589 | }
590 | ],
591 | "description": "RoadRunner: Command Line Interface",
592 | "support": {
593 | "issues": "https://github.com/spiral/roadrunner-cli/issues",
594 | "source": "https://github.com/spiral/roadrunner-cli/tree/v2.2.0"
595 | },
596 | "time": "2022-05-17T06:44:24+00:00"
597 | },
598 | {
599 | "name": "spiral/roadrunner-http",
600 | "version": "v2.1.0",
601 | "source": {
602 | "type": "git",
603 | "url": "https://github.com/spiral/roadrunner-http.git",
604 | "reference": "3be8bac365d436028a9583e7d438bf6e7183e599"
605 | },
606 | "dist": {
607 | "type": "zip",
608 | "url": "https://api.github.com/repos/spiral/roadrunner-http/zipball/3be8bac365d436028a9583e7d438bf6e7183e599",
609 | "reference": "3be8bac365d436028a9583e7d438bf6e7183e599",
610 | "shasum": ""
611 | },
612 | "require": {
613 | "ext-json": "*",
614 | "php": ">=7.4",
615 | "psr/http-factory": "^1.0.1",
616 | "psr/http-message": "^1.0.1",
617 | "spiral/roadrunner-worker": "^2.2.0"
618 | },
619 | "require-dev": {
620 | "jetbrains/phpstorm-attributes": "^1.0",
621 | "nyholm/psr7": "^1.3",
622 | "phpstan/phpstan": "~0.12",
623 | "phpunit/phpunit": "~8.0",
624 | "symfony/var-dumper": "^5.1",
625 | "vimeo/psalm": "^4.22"
626 | },
627 | "suggest": {
628 | "spiral/roadrunner-cli": "Provides RoadRunner installation and management CLI tools"
629 | },
630 | "type": "library",
631 | "extra": {
632 | "branch-alias": {
633 | "dev-master": "2.2.x-dev"
634 | }
635 | },
636 | "autoload": {
637 | "psr-4": {
638 | "Spiral\\RoadRunner\\Http\\": "src"
639 | }
640 | },
641 | "notification-url": "https://packagist.org/downloads/",
642 | "license": [
643 | "MIT"
644 | ],
645 | "authors": [
646 | {
647 | "name": "Anton Titov / Wolfy-J",
648 | "email": "wolfy.jd@gmail.com"
649 | },
650 | {
651 | "name": "RoadRunner Community",
652 | "homepage": "https://github.com/spiral/roadrunner/graphs/contributors"
653 | }
654 | ],
655 | "description": "RoadRunner: HTTP and PSR-7 worker",
656 | "support": {
657 | "issues": "https://github.com/spiral/roadrunner-http/issues",
658 | "source": "https://github.com/spiral/roadrunner-http/tree/v2.1.0"
659 | },
660 | "time": "2022-03-22T14:48:00+00:00"
661 | },
662 | {
663 | "name": "spiral/roadrunner-worker",
664 | "version": "v2.2.0",
665 | "source": {
666 | "type": "git",
667 | "url": "https://github.com/spiral/roadrunner-worker.git",
668 | "reference": "97399e1f45b188e4288817672df858908b641401"
669 | },
670 | "dist": {
671 | "type": "zip",
672 | "url": "https://api.github.com/repos/spiral/roadrunner-worker/zipball/97399e1f45b188e4288817672df858908b641401",
673 | "reference": "97399e1f45b188e4288817672df858908b641401",
674 | "shasum": ""
675 | },
676 | "require": {
677 | "composer-runtime-api": "^2.0",
678 | "ext-json": "*",
679 | "ext-sockets": "*",
680 | "php": ">=7.4",
681 | "psr/log": "^1.0|^2.0|^3.0",
682 | "spiral/goridge": "^3.2.0",
683 | "symfony/polyfill-php80": "^1.23"
684 | },
685 | "require-dev": {
686 | "jetbrains/phpstorm-attributes": "^1.0",
687 | "symfony/var-dumper": "^5.1",
688 | "vimeo/psalm": "^4.4"
689 | },
690 | "suggest": {
691 | "spiral/roadrunner-cli": "Provides RoadRunner installation and management CLI tools"
692 | },
693 | "type": "library",
694 | "extra": {
695 | "branch-alias": {
696 | "dev-master": "2.3.x-dev"
697 | }
698 | },
699 | "autoload": {
700 | "psr-4": {
701 | "Spiral\\RoadRunner\\": "src"
702 | }
703 | },
704 | "notification-url": "https://packagist.org/downloads/",
705 | "license": [
706 | "MIT"
707 | ],
708 | "authors": [
709 | {
710 | "name": "Anton Titov (wolfy-j)",
711 | "email": "wolfy-j@spiralscout.com"
712 | },
713 | {
714 | "name": "RoadRunner Community",
715 | "homepage": "https://github.com/spiral/roadrunner/graphs/contributors"
716 | }
717 | ],
718 | "description": "RoadRunner: PHP worker",
719 | "support": {
720 | "issues": "https://github.com/spiral/roadrunner-worker/issues",
721 | "source": "https://github.com/spiral/roadrunner-worker/tree/v2.2.0"
722 | },
723 | "time": "2022-03-22T11:03:47+00:00"
724 | },
725 | {
726 | "name": "symfony/console",
727 | "version": "v6.1.2",
728 | "source": {
729 | "type": "git",
730 | "url": "https://github.com/symfony/console.git",
731 | "reference": "7a86c1c42fbcb69b59768504c7bca1d3767760b7"
732 | },
733 | "dist": {
734 | "type": "zip",
735 | "url": "https://api.github.com/repos/symfony/console/zipball/7a86c1c42fbcb69b59768504c7bca1d3767760b7",
736 | "reference": "7a86c1c42fbcb69b59768504c7bca1d3767760b7",
737 | "shasum": ""
738 | },
739 | "require": {
740 | "php": ">=8.1",
741 | "symfony/deprecation-contracts": "^2.1|^3",
742 | "symfony/polyfill-mbstring": "~1.0",
743 | "symfony/service-contracts": "^1.1|^2|^3",
744 | "symfony/string": "^5.4|^6.0"
745 | },
746 | "conflict": {
747 | "symfony/dependency-injection": "<5.4",
748 | "symfony/dotenv": "<5.4",
749 | "symfony/event-dispatcher": "<5.4",
750 | "symfony/lock": "<5.4",
751 | "symfony/process": "<5.4"
752 | },
753 | "provide": {
754 | "psr/log-implementation": "1.0|2.0|3.0"
755 | },
756 | "require-dev": {
757 | "psr/log": "^1|^2|^3",
758 | "symfony/config": "^5.4|^6.0",
759 | "symfony/dependency-injection": "^5.4|^6.0",
760 | "symfony/event-dispatcher": "^5.4|^6.0",
761 | "symfony/lock": "^5.4|^6.0",
762 | "symfony/process": "^5.4|^6.0",
763 | "symfony/var-dumper": "^5.4|^6.0"
764 | },
765 | "suggest": {
766 | "psr/log": "For using the console logger",
767 | "symfony/event-dispatcher": "",
768 | "symfony/lock": "",
769 | "symfony/process": ""
770 | },
771 | "type": "library",
772 | "autoload": {
773 | "psr-4": {
774 | "Symfony\\Component\\Console\\": ""
775 | },
776 | "exclude-from-classmap": [
777 | "/Tests/"
778 | ]
779 | },
780 | "notification-url": "https://packagist.org/downloads/",
781 | "license": [
782 | "MIT"
783 | ],
784 | "authors": [
785 | {
786 | "name": "Fabien Potencier",
787 | "email": "fabien@symfony.com"
788 | },
789 | {
790 | "name": "Symfony Community",
791 | "homepage": "https://symfony.com/contributors"
792 | }
793 | ],
794 | "description": "Eases the creation of beautiful and testable command line interfaces",
795 | "homepage": "https://symfony.com",
796 | "keywords": [
797 | "cli",
798 | "command line",
799 | "console",
800 | "terminal"
801 | ],
802 | "support": {
803 | "source": "https://github.com/symfony/console/tree/v6.1.2"
804 | },
805 | "funding": [
806 | {
807 | "url": "https://symfony.com/sponsor",
808 | "type": "custom"
809 | },
810 | {
811 | "url": "https://github.com/fabpot",
812 | "type": "github"
813 | },
814 | {
815 | "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
816 | "type": "tidelift"
817 | }
818 | ],
819 | "time": "2022-06-26T13:01:30+00:00"
820 | },
821 | {
822 | "name": "symfony/deprecation-contracts",
823 | "version": "v3.1.1",
824 | "source": {
825 | "type": "git",
826 | "url": "https://github.com/symfony/deprecation-contracts.git",
827 | "reference": "07f1b9cc2ffee6aaafcf4b710fbc38ff736bd918"
828 | },
829 | "dist": {
830 | "type": "zip",
831 | "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/07f1b9cc2ffee6aaafcf4b710fbc38ff736bd918",
832 | "reference": "07f1b9cc2ffee6aaafcf4b710fbc38ff736bd918",
833 | "shasum": ""
834 | },
835 | "require": {
836 | "php": ">=8.1"
837 | },
838 | "type": "library",
839 | "extra": {
840 | "branch-alias": {
841 | "dev-main": "3.1-dev"
842 | },
843 | "thanks": {
844 | "name": "symfony/contracts",
845 | "url": "https://github.com/symfony/contracts"
846 | }
847 | },
848 | "autoload": {
849 | "files": [
850 | "function.php"
851 | ]
852 | },
853 | "notification-url": "https://packagist.org/downloads/",
854 | "license": [
855 | "MIT"
856 | ],
857 | "authors": [
858 | {
859 | "name": "Nicolas Grekas",
860 | "email": "p@tchwork.com"
861 | },
862 | {
863 | "name": "Symfony Community",
864 | "homepage": "https://symfony.com/contributors"
865 | }
866 | ],
867 | "description": "A generic function and convention to trigger deprecation notices",
868 | "homepage": "https://symfony.com",
869 | "support": {
870 | "source": "https://github.com/symfony/deprecation-contracts/tree/v3.1.1"
871 | },
872 | "funding": [
873 | {
874 | "url": "https://symfony.com/sponsor",
875 | "type": "custom"
876 | },
877 | {
878 | "url": "https://github.com/fabpot",
879 | "type": "github"
880 | },
881 | {
882 | "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
883 | "type": "tidelift"
884 | }
885 | ],
886 | "time": "2022-02-25T11:15:52+00:00"
887 | },
888 | {
889 | "name": "symfony/http-client",
890 | "version": "v6.1.2",
891 | "source": {
892 | "type": "git",
893 | "url": "https://github.com/symfony/http-client.git",
894 | "reference": "ea1af6c8cc479147d67a3fead457dd7b06261041"
895 | },
896 | "dist": {
897 | "type": "zip",
898 | "url": "https://api.github.com/repos/symfony/http-client/zipball/ea1af6c8cc479147d67a3fead457dd7b06261041",
899 | "reference": "ea1af6c8cc479147d67a3fead457dd7b06261041",
900 | "shasum": ""
901 | },
902 | "require": {
903 | "php": ">=8.1",
904 | "psr/log": "^1|^2|^3",
905 | "symfony/http-client-contracts": "^3",
906 | "symfony/service-contracts": "^1.0|^2|^3"
907 | },
908 | "provide": {
909 | "php-http/async-client-implementation": "*",
910 | "php-http/client-implementation": "*",
911 | "psr/http-client-implementation": "1.0",
912 | "symfony/http-client-implementation": "3.0"
913 | },
914 | "require-dev": {
915 | "amphp/amp": "^2.5",
916 | "amphp/http-client": "^4.2.1",
917 | "amphp/http-tunnel": "^1.0",
918 | "amphp/socket": "^1.1",
919 | "guzzlehttp/promises": "^1.4",
920 | "nyholm/psr7": "^1.0",
921 | "php-http/httplug": "^1.0|^2.0",
922 | "psr/http-client": "^1.0",
923 | "symfony/dependency-injection": "^5.4|^6.0",
924 | "symfony/http-kernel": "^5.4|^6.0",
925 | "symfony/process": "^5.4|^6.0",
926 | "symfony/stopwatch": "^5.4|^6.0"
927 | },
928 | "type": "library",
929 | "autoload": {
930 | "psr-4": {
931 | "Symfony\\Component\\HttpClient\\": ""
932 | },
933 | "exclude-from-classmap": [
934 | "/Tests/"
935 | ]
936 | },
937 | "notification-url": "https://packagist.org/downloads/",
938 | "license": [
939 | "MIT"
940 | ],
941 | "authors": [
942 | {
943 | "name": "Nicolas Grekas",
944 | "email": "p@tchwork.com"
945 | },
946 | {
947 | "name": "Symfony Community",
948 | "homepage": "https://symfony.com/contributors"
949 | }
950 | ],
951 | "description": "Provides powerful methods to fetch HTTP resources synchronously or asynchronously",
952 | "homepage": "https://symfony.com",
953 | "support": {
954 | "source": "https://github.com/symfony/http-client/tree/v6.1.2"
955 | },
956 | "funding": [
957 | {
958 | "url": "https://symfony.com/sponsor",
959 | "type": "custom"
960 | },
961 | {
962 | "url": "https://github.com/fabpot",
963 | "type": "github"
964 | },
965 | {
966 | "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
967 | "type": "tidelift"
968 | }
969 | ],
970 | "time": "2022-06-19T13:02:30+00:00"
971 | },
972 | {
973 | "name": "symfony/http-client-contracts",
974 | "version": "v3.1.1",
975 | "source": {
976 | "type": "git",
977 | "url": "https://github.com/symfony/http-client-contracts.git",
978 | "reference": "fd038f08c623ab5d22b26e9ba35afe8c79071800"
979 | },
980 | "dist": {
981 | "type": "zip",
982 | "url": "https://api.github.com/repos/symfony/http-client-contracts/zipball/fd038f08c623ab5d22b26e9ba35afe8c79071800",
983 | "reference": "fd038f08c623ab5d22b26e9ba35afe8c79071800",
984 | "shasum": ""
985 | },
986 | "require": {
987 | "php": ">=8.1"
988 | },
989 | "suggest": {
990 | "symfony/http-client-implementation": ""
991 | },
992 | "type": "library",
993 | "extra": {
994 | "branch-alias": {
995 | "dev-main": "3.1-dev"
996 | },
997 | "thanks": {
998 | "name": "symfony/contracts",
999 | "url": "https://github.com/symfony/contracts"
1000 | }
1001 | },
1002 | "autoload": {
1003 | "psr-4": {
1004 | "Symfony\\Contracts\\HttpClient\\": ""
1005 | },
1006 | "exclude-from-classmap": [
1007 | "/Test/"
1008 | ]
1009 | },
1010 | "notification-url": "https://packagist.org/downloads/",
1011 | "license": [
1012 | "MIT"
1013 | ],
1014 | "authors": [
1015 | {
1016 | "name": "Nicolas Grekas",
1017 | "email": "p@tchwork.com"
1018 | },
1019 | {
1020 | "name": "Symfony Community",
1021 | "homepage": "https://symfony.com/contributors"
1022 | }
1023 | ],
1024 | "description": "Generic abstractions related to HTTP clients",
1025 | "homepage": "https://symfony.com",
1026 | "keywords": [
1027 | "abstractions",
1028 | "contracts",
1029 | "decoupling",
1030 | "interfaces",
1031 | "interoperability",
1032 | "standards"
1033 | ],
1034 | "support": {
1035 | "source": "https://github.com/symfony/http-client-contracts/tree/v3.1.1"
1036 | },
1037 | "funding": [
1038 | {
1039 | "url": "https://symfony.com/sponsor",
1040 | "type": "custom"
1041 | },
1042 | {
1043 | "url": "https://github.com/fabpot",
1044 | "type": "github"
1045 | },
1046 | {
1047 | "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
1048 | "type": "tidelift"
1049 | }
1050 | ],
1051 | "time": "2022-04-22T07:30:54+00:00"
1052 | },
1053 | {
1054 | "name": "symfony/polyfill-ctype",
1055 | "version": "v1.26.0",
1056 | "source": {
1057 | "type": "git",
1058 | "url": "https://github.com/symfony/polyfill-ctype.git",
1059 | "reference": "6fd1b9a79f6e3cf65f9e679b23af304cd9e010d4"
1060 | },
1061 | "dist": {
1062 | "type": "zip",
1063 | "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/6fd1b9a79f6e3cf65f9e679b23af304cd9e010d4",
1064 | "reference": "6fd1b9a79f6e3cf65f9e679b23af304cd9e010d4",
1065 | "shasum": ""
1066 | },
1067 | "require": {
1068 | "php": ">=7.1"
1069 | },
1070 | "provide": {
1071 | "ext-ctype": "*"
1072 | },
1073 | "suggest": {
1074 | "ext-ctype": "For best performance"
1075 | },
1076 | "type": "library",
1077 | "extra": {
1078 | "branch-alias": {
1079 | "dev-main": "1.26-dev"
1080 | },
1081 | "thanks": {
1082 | "name": "symfony/polyfill",
1083 | "url": "https://github.com/symfony/polyfill"
1084 | }
1085 | },
1086 | "autoload": {
1087 | "files": [
1088 | "bootstrap.php"
1089 | ],
1090 | "psr-4": {
1091 | "Symfony\\Polyfill\\Ctype\\": ""
1092 | }
1093 | },
1094 | "notification-url": "https://packagist.org/downloads/",
1095 | "license": [
1096 | "MIT"
1097 | ],
1098 | "authors": [
1099 | {
1100 | "name": "Gert de Pagter",
1101 | "email": "BackEndTea@gmail.com"
1102 | },
1103 | {
1104 | "name": "Symfony Community",
1105 | "homepage": "https://symfony.com/contributors"
1106 | }
1107 | ],
1108 | "description": "Symfony polyfill for ctype functions",
1109 | "homepage": "https://symfony.com",
1110 | "keywords": [
1111 | "compatibility",
1112 | "ctype",
1113 | "polyfill",
1114 | "portable"
1115 | ],
1116 | "support": {
1117 | "source": "https://github.com/symfony/polyfill-ctype/tree/v1.26.0"
1118 | },
1119 | "funding": [
1120 | {
1121 | "url": "https://symfony.com/sponsor",
1122 | "type": "custom"
1123 | },
1124 | {
1125 | "url": "https://github.com/fabpot",
1126 | "type": "github"
1127 | },
1128 | {
1129 | "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
1130 | "type": "tidelift"
1131 | }
1132 | ],
1133 | "time": "2022-05-24T11:49:31+00:00"
1134 | },
1135 | {
1136 | "name": "symfony/polyfill-intl-grapheme",
1137 | "version": "v1.26.0",
1138 | "source": {
1139 | "type": "git",
1140 | "url": "https://github.com/symfony/polyfill-intl-grapheme.git",
1141 | "reference": "433d05519ce6990bf3530fba6957499d327395c2"
1142 | },
1143 | "dist": {
1144 | "type": "zip",
1145 | "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/433d05519ce6990bf3530fba6957499d327395c2",
1146 | "reference": "433d05519ce6990bf3530fba6957499d327395c2",
1147 | "shasum": ""
1148 | },
1149 | "require": {
1150 | "php": ">=7.1"
1151 | },
1152 | "suggest": {
1153 | "ext-intl": "For best performance"
1154 | },
1155 | "type": "library",
1156 | "extra": {
1157 | "branch-alias": {
1158 | "dev-main": "1.26-dev"
1159 | },
1160 | "thanks": {
1161 | "name": "symfony/polyfill",
1162 | "url": "https://github.com/symfony/polyfill"
1163 | }
1164 | },
1165 | "autoload": {
1166 | "files": [
1167 | "bootstrap.php"
1168 | ],
1169 | "psr-4": {
1170 | "Symfony\\Polyfill\\Intl\\Grapheme\\": ""
1171 | }
1172 | },
1173 | "notification-url": "https://packagist.org/downloads/",
1174 | "license": [
1175 | "MIT"
1176 | ],
1177 | "authors": [
1178 | {
1179 | "name": "Nicolas Grekas",
1180 | "email": "p@tchwork.com"
1181 | },
1182 | {
1183 | "name": "Symfony Community",
1184 | "homepage": "https://symfony.com/contributors"
1185 | }
1186 | ],
1187 | "description": "Symfony polyfill for intl's grapheme_* functions",
1188 | "homepage": "https://symfony.com",
1189 | "keywords": [
1190 | "compatibility",
1191 | "grapheme",
1192 | "intl",
1193 | "polyfill",
1194 | "portable",
1195 | "shim"
1196 | ],
1197 | "support": {
1198 | "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.26.0"
1199 | },
1200 | "funding": [
1201 | {
1202 | "url": "https://symfony.com/sponsor",
1203 | "type": "custom"
1204 | },
1205 | {
1206 | "url": "https://github.com/fabpot",
1207 | "type": "github"
1208 | },
1209 | {
1210 | "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
1211 | "type": "tidelift"
1212 | }
1213 | ],
1214 | "time": "2022-05-24T11:49:31+00:00"
1215 | },
1216 | {
1217 | "name": "symfony/polyfill-intl-normalizer",
1218 | "version": "v1.26.0",
1219 | "source": {
1220 | "type": "git",
1221 | "url": "https://github.com/symfony/polyfill-intl-normalizer.git",
1222 | "reference": "219aa369ceff116e673852dce47c3a41794c14bd"
1223 | },
1224 | "dist": {
1225 | "type": "zip",
1226 | "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/219aa369ceff116e673852dce47c3a41794c14bd",
1227 | "reference": "219aa369ceff116e673852dce47c3a41794c14bd",
1228 | "shasum": ""
1229 | },
1230 | "require": {
1231 | "php": ">=7.1"
1232 | },
1233 | "suggest": {
1234 | "ext-intl": "For best performance"
1235 | },
1236 | "type": "library",
1237 | "extra": {
1238 | "branch-alias": {
1239 | "dev-main": "1.26-dev"
1240 | },
1241 | "thanks": {
1242 | "name": "symfony/polyfill",
1243 | "url": "https://github.com/symfony/polyfill"
1244 | }
1245 | },
1246 | "autoload": {
1247 | "files": [
1248 | "bootstrap.php"
1249 | ],
1250 | "psr-4": {
1251 | "Symfony\\Polyfill\\Intl\\Normalizer\\": ""
1252 | },
1253 | "classmap": [
1254 | "Resources/stubs"
1255 | ]
1256 | },
1257 | "notification-url": "https://packagist.org/downloads/",
1258 | "license": [
1259 | "MIT"
1260 | ],
1261 | "authors": [
1262 | {
1263 | "name": "Nicolas Grekas",
1264 | "email": "p@tchwork.com"
1265 | },
1266 | {
1267 | "name": "Symfony Community",
1268 | "homepage": "https://symfony.com/contributors"
1269 | }
1270 | ],
1271 | "description": "Symfony polyfill for intl's Normalizer class and related functions",
1272 | "homepage": "https://symfony.com",
1273 | "keywords": [
1274 | "compatibility",
1275 | "intl",
1276 | "normalizer",
1277 | "polyfill",
1278 | "portable",
1279 | "shim"
1280 | ],
1281 | "support": {
1282 | "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.26.0"
1283 | },
1284 | "funding": [
1285 | {
1286 | "url": "https://symfony.com/sponsor",
1287 | "type": "custom"
1288 | },
1289 | {
1290 | "url": "https://github.com/fabpot",
1291 | "type": "github"
1292 | },
1293 | {
1294 | "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
1295 | "type": "tidelift"
1296 | }
1297 | ],
1298 | "time": "2022-05-24T11:49:31+00:00"
1299 | },
1300 | {
1301 | "name": "symfony/polyfill-mbstring",
1302 | "version": "v1.26.0",
1303 | "source": {
1304 | "type": "git",
1305 | "url": "https://github.com/symfony/polyfill-mbstring.git",
1306 | "reference": "9344f9cb97f3b19424af1a21a3b0e75b0a7d8d7e"
1307 | },
1308 | "dist": {
1309 | "type": "zip",
1310 | "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/9344f9cb97f3b19424af1a21a3b0e75b0a7d8d7e",
1311 | "reference": "9344f9cb97f3b19424af1a21a3b0e75b0a7d8d7e",
1312 | "shasum": ""
1313 | },
1314 | "require": {
1315 | "php": ">=7.1"
1316 | },
1317 | "provide": {
1318 | "ext-mbstring": "*"
1319 | },
1320 | "suggest": {
1321 | "ext-mbstring": "For best performance"
1322 | },
1323 | "type": "library",
1324 | "extra": {
1325 | "branch-alias": {
1326 | "dev-main": "1.26-dev"
1327 | },
1328 | "thanks": {
1329 | "name": "symfony/polyfill",
1330 | "url": "https://github.com/symfony/polyfill"
1331 | }
1332 | },
1333 | "autoload": {
1334 | "files": [
1335 | "bootstrap.php"
1336 | ],
1337 | "psr-4": {
1338 | "Symfony\\Polyfill\\Mbstring\\": ""
1339 | }
1340 | },
1341 | "notification-url": "https://packagist.org/downloads/",
1342 | "license": [
1343 | "MIT"
1344 | ],
1345 | "authors": [
1346 | {
1347 | "name": "Nicolas Grekas",
1348 | "email": "p@tchwork.com"
1349 | },
1350 | {
1351 | "name": "Symfony Community",
1352 | "homepage": "https://symfony.com/contributors"
1353 | }
1354 | ],
1355 | "description": "Symfony polyfill for the Mbstring extension",
1356 | "homepage": "https://symfony.com",
1357 | "keywords": [
1358 | "compatibility",
1359 | "mbstring",
1360 | "polyfill",
1361 | "portable",
1362 | "shim"
1363 | ],
1364 | "support": {
1365 | "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.26.0"
1366 | },
1367 | "funding": [
1368 | {
1369 | "url": "https://symfony.com/sponsor",
1370 | "type": "custom"
1371 | },
1372 | {
1373 | "url": "https://github.com/fabpot",
1374 | "type": "github"
1375 | },
1376 | {
1377 | "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
1378 | "type": "tidelift"
1379 | }
1380 | ],
1381 | "time": "2022-05-24T11:49:31+00:00"
1382 | },
1383 | {
1384 | "name": "symfony/polyfill-php80",
1385 | "version": "v1.26.0",
1386 | "source": {
1387 | "type": "git",
1388 | "url": "https://github.com/symfony/polyfill-php80.git",
1389 | "reference": "cfa0ae98841b9e461207c13ab093d76b0fa7bace"
1390 | },
1391 | "dist": {
1392 | "type": "zip",
1393 | "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/cfa0ae98841b9e461207c13ab093d76b0fa7bace",
1394 | "reference": "cfa0ae98841b9e461207c13ab093d76b0fa7bace",
1395 | "shasum": ""
1396 | },
1397 | "require": {
1398 | "php": ">=7.1"
1399 | },
1400 | "type": "library",
1401 | "extra": {
1402 | "branch-alias": {
1403 | "dev-main": "1.26-dev"
1404 | },
1405 | "thanks": {
1406 | "name": "symfony/polyfill",
1407 | "url": "https://github.com/symfony/polyfill"
1408 | }
1409 | },
1410 | "autoload": {
1411 | "files": [
1412 | "bootstrap.php"
1413 | ],
1414 | "psr-4": {
1415 | "Symfony\\Polyfill\\Php80\\": ""
1416 | },
1417 | "classmap": [
1418 | "Resources/stubs"
1419 | ]
1420 | },
1421 | "notification-url": "https://packagist.org/downloads/",
1422 | "license": [
1423 | "MIT"
1424 | ],
1425 | "authors": [
1426 | {
1427 | "name": "Ion Bazan",
1428 | "email": "ion.bazan@gmail.com"
1429 | },
1430 | {
1431 | "name": "Nicolas Grekas",
1432 | "email": "p@tchwork.com"
1433 | },
1434 | {
1435 | "name": "Symfony Community",
1436 | "homepage": "https://symfony.com/contributors"
1437 | }
1438 | ],
1439 | "description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions",
1440 | "homepage": "https://symfony.com",
1441 | "keywords": [
1442 | "compatibility",
1443 | "polyfill",
1444 | "portable",
1445 | "shim"
1446 | ],
1447 | "support": {
1448 | "source": "https://github.com/symfony/polyfill-php80/tree/v1.26.0"
1449 | },
1450 | "funding": [
1451 | {
1452 | "url": "https://symfony.com/sponsor",
1453 | "type": "custom"
1454 | },
1455 | {
1456 | "url": "https://github.com/fabpot",
1457 | "type": "github"
1458 | },
1459 | {
1460 | "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
1461 | "type": "tidelift"
1462 | }
1463 | ],
1464 | "time": "2022-05-10T07:21:04+00:00"
1465 | },
1466 | {
1467 | "name": "symfony/service-contracts",
1468 | "version": "v3.1.1",
1469 | "source": {
1470 | "type": "git",
1471 | "url": "https://github.com/symfony/service-contracts.git",
1472 | "reference": "925e713fe8fcacf6bc05e936edd8dd5441a21239"
1473 | },
1474 | "dist": {
1475 | "type": "zip",
1476 | "url": "https://api.github.com/repos/symfony/service-contracts/zipball/925e713fe8fcacf6bc05e936edd8dd5441a21239",
1477 | "reference": "925e713fe8fcacf6bc05e936edd8dd5441a21239",
1478 | "shasum": ""
1479 | },
1480 | "require": {
1481 | "php": ">=8.1",
1482 | "psr/container": "^2.0"
1483 | },
1484 | "conflict": {
1485 | "ext-psr": "<1.1|>=2"
1486 | },
1487 | "suggest": {
1488 | "symfony/service-implementation": ""
1489 | },
1490 | "type": "library",
1491 | "extra": {
1492 | "branch-alias": {
1493 | "dev-main": "3.1-dev"
1494 | },
1495 | "thanks": {
1496 | "name": "symfony/contracts",
1497 | "url": "https://github.com/symfony/contracts"
1498 | }
1499 | },
1500 | "autoload": {
1501 | "psr-4": {
1502 | "Symfony\\Contracts\\Service\\": ""
1503 | },
1504 | "exclude-from-classmap": [
1505 | "/Test/"
1506 | ]
1507 | },
1508 | "notification-url": "https://packagist.org/downloads/",
1509 | "license": [
1510 | "MIT"
1511 | ],
1512 | "authors": [
1513 | {
1514 | "name": "Nicolas Grekas",
1515 | "email": "p@tchwork.com"
1516 | },
1517 | {
1518 | "name": "Symfony Community",
1519 | "homepage": "https://symfony.com/contributors"
1520 | }
1521 | ],
1522 | "description": "Generic abstractions related to writing services",
1523 | "homepage": "https://symfony.com",
1524 | "keywords": [
1525 | "abstractions",
1526 | "contracts",
1527 | "decoupling",
1528 | "interfaces",
1529 | "interoperability",
1530 | "standards"
1531 | ],
1532 | "support": {
1533 | "source": "https://github.com/symfony/service-contracts/tree/v3.1.1"
1534 | },
1535 | "funding": [
1536 | {
1537 | "url": "https://symfony.com/sponsor",
1538 | "type": "custom"
1539 | },
1540 | {
1541 | "url": "https://github.com/fabpot",
1542 | "type": "github"
1543 | },
1544 | {
1545 | "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
1546 | "type": "tidelift"
1547 | }
1548 | ],
1549 | "time": "2022-05-30T19:18:58+00:00"
1550 | },
1551 | {
1552 | "name": "symfony/string",
1553 | "version": "v6.1.2",
1554 | "source": {
1555 | "type": "git",
1556 | "url": "https://github.com/symfony/string.git",
1557 | "reference": "1903f2879875280c5af944625e8246d81c2f0604"
1558 | },
1559 | "dist": {
1560 | "type": "zip",
1561 | "url": "https://api.github.com/repos/symfony/string/zipball/1903f2879875280c5af944625e8246d81c2f0604",
1562 | "reference": "1903f2879875280c5af944625e8246d81c2f0604",
1563 | "shasum": ""
1564 | },
1565 | "require": {
1566 | "php": ">=8.1",
1567 | "symfony/polyfill-ctype": "~1.8",
1568 | "symfony/polyfill-intl-grapheme": "~1.0",
1569 | "symfony/polyfill-intl-normalizer": "~1.0",
1570 | "symfony/polyfill-mbstring": "~1.0"
1571 | },
1572 | "conflict": {
1573 | "symfony/translation-contracts": "<2.0"
1574 | },
1575 | "require-dev": {
1576 | "symfony/error-handler": "^5.4|^6.0",
1577 | "symfony/http-client": "^5.4|^6.0",
1578 | "symfony/translation-contracts": "^2.0|^3.0",
1579 | "symfony/var-exporter": "^5.4|^6.0"
1580 | },
1581 | "type": "library",
1582 | "autoload": {
1583 | "files": [
1584 | "Resources/functions.php"
1585 | ],
1586 | "psr-4": {
1587 | "Symfony\\Component\\String\\": ""
1588 | },
1589 | "exclude-from-classmap": [
1590 | "/Tests/"
1591 | ]
1592 | },
1593 | "notification-url": "https://packagist.org/downloads/",
1594 | "license": [
1595 | "MIT"
1596 | ],
1597 | "authors": [
1598 | {
1599 | "name": "Nicolas Grekas",
1600 | "email": "p@tchwork.com"
1601 | },
1602 | {
1603 | "name": "Symfony Community",
1604 | "homepage": "https://symfony.com/contributors"
1605 | }
1606 | ],
1607 | "description": "Provides an object-oriented API to strings and deals with bytes, UTF-8 code points and grapheme clusters in a unified way",
1608 | "homepage": "https://symfony.com",
1609 | "keywords": [
1610 | "grapheme",
1611 | "i18n",
1612 | "string",
1613 | "unicode",
1614 | "utf-8",
1615 | "utf8"
1616 | ],
1617 | "support": {
1618 | "source": "https://github.com/symfony/string/tree/v6.1.2"
1619 | },
1620 | "funding": [
1621 | {
1622 | "url": "https://symfony.com/sponsor",
1623 | "type": "custom"
1624 | },
1625 | {
1626 | "url": "https://github.com/fabpot",
1627 | "type": "github"
1628 | },
1629 | {
1630 | "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
1631 | "type": "tidelift"
1632 | }
1633 | ],
1634 | "time": "2022-06-26T16:35:04+00:00"
1635 | }
1636 | ],
1637 | "packages-dev": [],
1638 | "aliases": [],
1639 | "minimum-stability": "stable",
1640 | "stability-flags": [],
1641 | "prefer-stable": false,
1642 | "prefer-lowest": false,
1643 | "platform": [],
1644 | "platform-dev": [],
1645 | "plugin-api-version": "2.3.0"
1646 | }
1647 |
--------------------------------------------------------------------------------
/middleware/roadrunner/examples/configuration.toml:
--------------------------------------------------------------------------------
1 | [velox]
2 | build_args = ['-trimpath', '-ldflags', '-s -X github.com/roadrunner-server/roadrunner/v2/internal/meta.version=v2.12.0 -X github.com/roadrunner-server/roadrunner/v2/internal/meta.buildTime=10:00:00']
3 |
4 | [roadrunner]
5 | ref = "v2.12.3"
6 |
7 | [github]
8 | [github.token]
9 | token = "GH_TOKEN"
10 |
11 | [github.plugins]
12 | logger = { ref = "v3.2.0", owner = "roadrunner-server", repository = "logger" }
13 | esi = { ref = "CURRENT_SHA", owner = "darkweak", repository = "go-esi", folder = "middleware/roadrunner", replace = "/opt/middleware/roadrunner" }
14 | server = { ref = "v3.2.0", owner = "roadrunner-server", repository = "server" }
15 | gzip = { ref = "v3.2.0", owner = "roadrunner-server", repository = "gzip" }
16 | http = { ref = "v3.2.0", owner = "roadrunner-server", repository = "http" }
17 |
18 | [log]
19 | level = "debug"
20 | mode = "development"
21 |
--------------------------------------------------------------------------------
/middleware/roadrunner/examples/docker-compose.yml.test:
--------------------------------------------------------------------------------
1 | version: '3.8'
2 |
3 | services:
4 | roadrunner:
5 | build:
6 | context: ../../..
7 | dockerfile: middleware/roadrunner/examples/Dockerfile.test
8 | target: development-runner
9 | args:
10 | GH_TOKEN: ${GH_APP_TOKEN}
11 | CURRENT_SHA: ${CURRENT_SHA}
12 | ports:
13 | - 80:80
14 |
--------------------------------------------------------------------------------
/middleware/roadrunner/examples/psr-worker.php:
--------------------------------------------------------------------------------
1 | waitRequest()) {
18 | try {
19 | $rsp = new Psr7\Response();
20 | if ($_SERVER['REQUEST_URI'] === 'http://localhost/include') {
21 | $rsp->getBody()->write('Include content');
22 | } else {
23 | $rsp->getBody()->write('Hello base uri! !');
24 | }
25 |
26 | $worker->respond($rsp);
27 | } catch (\Throwable $e) {
28 | $worker->getWorker()->error((string)$e);
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/middleware/roadrunner/go.mod:
--------------------------------------------------------------------------------
1 | module github.com/darkweak/go-esi/middleware/roadrunner
2 |
3 | go 1.19
4 |
5 | require (
6 | github.com/darkweak/go-esi v0.0.6
7 | github.com/roadrunner-server/errors v1.2.0
8 | go.uber.org/zap v1.24.0
9 | )
10 |
11 | require (
12 | github.com/pkg/errors v0.9.1 // indirect
13 | github.com/stretchr/testify v1.8.1 // indirect
14 | go.uber.org/atomic v1.10.0 // indirect
15 | go.uber.org/multierr v1.10.0 // indirect
16 | )
17 |
18 | replace github.com/darkweak/go-esi v0.0.6 => ../..
19 |
--------------------------------------------------------------------------------
/middleware/roadrunner/go.sum:
--------------------------------------------------------------------------------
1 | github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8=
2 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
3 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
4 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
5 | github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
6 | github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
7 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
8 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
9 | github.com/roadrunner-server/errors v1.2.0 h1:qBmNXt8Iex9QnYTjCkbJKsBZu2EtYkQCM06GUDcQBbI=
10 | github.com/roadrunner-server/errors v1.2.0/go.mod h1:z0ECxZp/dDa5RahtMcy4mBIavVxiZ9vwE5kByl7kFtY=
11 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
12 | github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
13 | github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
14 | github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
15 | github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
16 | github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
17 | github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
18 | go.uber.org/atomic v1.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ=
19 | go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
20 | go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI=
21 | go.uber.org/multierr v1.10.0 h1:S0h4aNzvfcFsC3dRF1jLoaov7oRaKqRGC/pUEJ2yvPQ=
22 | go.uber.org/multierr v1.10.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
23 | go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60=
24 | go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg=
25 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
26 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
27 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
28 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
29 |
--------------------------------------------------------------------------------
/middleware/server/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "net/http"
5 | "time"
6 | )
7 |
8 | var respond = []byte(`
9 |
10 | Hello from $(HTTP_HOST)
11 |
12 |
13 |
14 |
15 |
16 |
19 |
20 |
21 |
22 |
23 | `)
24 |
25 | func main() {
26 | http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
27 | w.Header().Set("Content-Type", "text/html")
28 | w.WriteHeader(http.StatusOK)
29 | _, _ = w.Write(respond[0:97])
30 | if flusher, ok := w.(http.Flusher); ok {
31 | flusher.Flush()
32 | }
33 | time.Sleep(time.Second)
34 | _, _ = w.Write(respond[97:194])
35 | time.Sleep(time.Second)
36 | _, _ = w.Write(respond[194:291])
37 | time.Sleep(time.Second)
38 | _, _ = w.Write(respond[291:])
39 | })
40 |
41 | server := &http.Server{
42 | Addr: ":81",
43 | ReadHeaderTimeout: 3 * time.Second,
44 | }
45 | _ = server.ListenAndServe()
46 | }
47 |
--------------------------------------------------------------------------------
/middleware/standalone/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "bytes"
5 | "context"
6 | "fmt"
7 | "io"
8 | "net/http"
9 |
10 | "github.com/darkweak/go-esi/esi"
11 | )
12 |
13 | const expected = `
14 |
15 | Hello from domain.com:81
16 |
17 |
18 |
19 |
20 | CHAINED 2
21 | CHAINED 2
22 |
23 |
24 | `
25 |
26 | func main() {
27 | buf := bytes.NewBuffer([]byte{})
28 | ctx := context.Background()
29 | rq, _ := http.NewRequestWithContext(ctx, http.MethodGet, "http://domain.com:81/", nil)
30 |
31 | res, err := http.DefaultClient.Do(rq)
32 | if err != nil {
33 | panic(err)
34 | }
35 |
36 | defer res.Body.Close()
37 | _, _ = io.Copy(buf, res.Body)
38 |
39 | result := buf.String()
40 | parsed := esi.Parse(buf.Bytes(), rq)
41 |
42 | if string(parsed) != expected {
43 | fmt.Printf("Given:\n%+v\nParsed result:\n%+v\n", result, string(parsed))
44 | panic(nil)
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/middleware/traefik/Makefile:
--------------------------------------------------------------------------------
1 | .PHONY: build log run
2 |
3 | build: ## Prepare træfik deps
4 | go mod tidy
5 | go mod download
6 |
7 | log: ## Display container logs
8 | docker-compose logs -f
9 |
10 | run: ## Run træfik with go-esi
11 | docker-compose up --remove-orphans --build
--------------------------------------------------------------------------------
/middleware/traefik/docker-compose.yml:
--------------------------------------------------------------------------------
1 | version: '3.8'
2 |
3 | services:
4 | traefik:
5 | image: traefik:latest
6 | volumes:
7 | - /var/run/docker.sock:/var/run/docker.sock
8 | - ../..:/plugins-local/src/github.com/darkweak/go-esi
9 | - ./traefik.yml:/traefik.yml
10 | - ./esi-configuration.yml:/esi-configuration.yml
11 | environment:
12 | GOPATH: /plugins-local
13 | ports:
14 | - 80:80
15 | - 8080:8080
16 |
17 | whoami:
18 | image: traefik/whoami
19 | labels:
20 | - traefik.http.routers.whoami.rule=Host(`domain.com`)
--------------------------------------------------------------------------------
/middleware/traefik/esi-configuration.yml:
--------------------------------------------------------------------------------
1 | http:
2 | routers:
3 | whoami:
4 | middlewares:
5 | - esi
6 | entrypoints:
7 | - http
8 | service: whoami
9 | rule: Host(`domain.com`)
10 |
11 | services:
12 | whoami:
13 | loadBalancer:
14 | servers:
15 | - url: http://whoami
16 | passHostHeader: false
17 |
18 | middlewares:
19 | esi:
20 | plugin:
21 | esi: {}
--------------------------------------------------------------------------------
/middleware/traefik/esi.go:
--------------------------------------------------------------------------------
1 | package traefik
2 |
3 | import (
4 | "bytes"
5 | "context"
6 | "net/http"
7 | "sync"
8 |
9 | "github.com/darkweak/go-esi/writer"
10 | )
11 |
12 | var bufPool *sync.Pool = &sync.Pool{
13 | New: func() any {
14 | return &bytes.Buffer{}
15 | },
16 | }
17 |
18 | // Config the ESI plugin configuration.
19 | type Config struct{}
20 |
21 | // CreateConfig creates the ESI plugin configuration.
22 | func CreateConfig() *Config {
23 | return &Config{}
24 | }
25 |
26 | // ESI is a plugin that allow users to process the ESI tags.
27 | type ESI struct {
28 | next http.Handler
29 | name string
30 | }
31 |
32 | // New created a new ESI plugin.
33 | func New(ctx context.Context, next http.Handler, config *Config, name string) (http.Handler, error) {
34 | return &ESI{
35 | next: next,
36 | name: name,
37 | }, nil
38 | }
39 |
40 | func (e *ESI) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
41 | buf := bufPool.Get().(*bytes.Buffer)
42 | buf.Reset()
43 | defer bufPool.Put(buf)
44 | cw := writer.NewWriter(buf, rw, req)
45 | go func(w *writer.Writer) {
46 | w.Header().Del("Content-Length")
47 | if w.Rq.ProtoMajor == 1 {
48 | w.Header().Set("Content-Encoding", "chunked")
49 | }
50 | var i = 0
51 | for {
52 | if len(cw.AsyncBuf) <= i {
53 | continue
54 | }
55 | rs := <-cw.AsyncBuf[i]
56 | if rs == nil {
57 | cw.Done <- true
58 | break
59 | }
60 | _, _ = rw.Write(rs)
61 | i++
62 | }
63 | }(cw)
64 | e.next.ServeHTTP(cw, req)
65 | cw.AsyncBuf = append(cw.AsyncBuf, make(chan []byte))
66 | go func(w *writer.Writer, iteration int) {
67 | w.AsyncBuf[iteration] <- nil
68 | }(cw, cw.Iteration)
69 |
70 | <-cw.Done
71 | }
72 |
--------------------------------------------------------------------------------
/middleware/traefik/go.mod:
--------------------------------------------------------------------------------
1 | module github.com/darkweak/go-esi/middleware/traefik
2 |
3 | go 1.19
4 |
5 | require github.com/darkweak/go-esi v0.0.6
6 |
7 | replace github.com/darkweak/go-esi v0.0.6 => ../..
8 |
--------------------------------------------------------------------------------
/middleware/traefik/go.sum:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/darkweak/go-esi/dfdfaa8466f9c7cc840040aeb753ee0887c0d431/middleware/traefik/go.sum
--------------------------------------------------------------------------------
/middleware/traefik/traefik.yml:
--------------------------------------------------------------------------------
1 | providers:
2 | file:
3 | filename: /esi-configuration.yml
4 | watch: true
5 |
6 | api:
7 | dashboard: true
8 | debug: true
9 | insecure: true
10 |
11 | pilot:
12 | token: 12926953-a7d1-4223-a092-d7dd95a91fa3
13 |
14 | experimental:
15 | localPlugins:
16 | esi:
17 | moduleName: github.com/darkweak/go-esi
18 |
19 | log:
20 | level: DEBUG
21 |
22 | accessLog: {}
--------------------------------------------------------------------------------
/middleware/traefik/vendor/github.com/darkweak/go-esi/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2022 darkweak
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
--------------------------------------------------------------------------------
/middleware/traefik/vendor/github.com/darkweak/go-esi/esi/choose.go:
--------------------------------------------------------------------------------
1 | package esi
2 |
3 | import (
4 | "net/http"
5 | "regexp"
6 | )
7 |
8 | const choose = "choose"
9 |
10 | var (
11 | closeChoose = regexp.MustCompile("")
12 | whenRg = regexp.MustCompile(`(?s)(.+?)`)
13 | otherwiseRg = regexp.MustCompile(`(?s)(.+?)`)
14 | )
15 |
16 | type chooseTag struct {
17 | *baseTag
18 | }
19 |
20 | // Input (e.g.
21 | //
22 | //
23 | //
24 | //
25 | //
26 | //
27 | //
28 | //
29 | //
30 | //
31 | //
32 | // ).
33 | func (c *chooseTag) Process(b []byte, req *http.Request) ([]byte, int) {
34 | found := closeChoose.FindIndex(b)
35 | if found == nil {
36 | return nil, len(b)
37 | }
38 |
39 | c.length = found[1]
40 | tagIdxs := whenRg.FindAllSubmatch(b, -1)
41 |
42 | var res []byte
43 |
44 | for _, v := range tagIdxs {
45 | if validateTest(v[1], req) {
46 | res = Parse(v[2], req)
47 |
48 | break
49 | }
50 | }
51 |
52 | tagIdx := otherwiseRg.FindSubmatch(b)
53 | if tagIdx != nil {
54 | res = Parse(tagIdx[1], req)
55 | }
56 |
57 | return res, c.length
58 | }
59 |
60 | func (*chooseTag) HasClose(b []byte) bool {
61 | return closeChoose.FindIndex(b) != nil
62 | }
63 |
64 | func (*chooseTag) GetClosePosition(b []byte) int {
65 | if idx := closeChoose.FindIndex(b); idx != nil {
66 | return idx[1]
67 | }
68 | return 0
69 | }
70 |
--------------------------------------------------------------------------------
/middleware/traefik/vendor/github.com/darkweak/go-esi/esi/comment.go:
--------------------------------------------------------------------------------
1 | package esi
2 |
3 | import (
4 | "net/http"
5 | "regexp"
6 | )
7 |
8 | const comment = "comment"
9 |
10 | var closeComment = regexp.MustCompile("/>")
11 |
12 | type commentTag struct {
13 | *baseTag
14 | }
15 |
16 | // Input (e.g. comment text="This is a comment." />).
17 | func (c *commentTag) Process(b []byte, req *http.Request) ([]byte, int) {
18 | found := closeComment.FindIndex(b)
19 | if found == nil {
20 | return nil, len(b)
21 | }
22 |
23 | return []byte{}, found[1]
24 | }
25 |
26 | func (*commentTag) HasClose(b []byte) bool {
27 | return closeComment.FindIndex(b) != nil
28 | }
29 |
30 | func (*commentTag) GetClosePosition(b []byte) int {
31 | if idx := closeComment.FindIndex(b); idx != nil {
32 | return idx[1]
33 | }
34 | return 0
35 | }
36 |
--------------------------------------------------------------------------------
/middleware/traefik/vendor/github.com/darkweak/go-esi/esi/errors.go:
--------------------------------------------------------------------------------
1 | package esi
2 |
3 | import "errors"
4 |
5 | var errNotFound = errors.New("not found")
6 |
--------------------------------------------------------------------------------
/middleware/traefik/vendor/github.com/darkweak/go-esi/esi/escape.go:
--------------------------------------------------------------------------------
1 | package esi
2 |
3 | import (
4 | "net/http"
5 | "regexp"
6 | )
7 |
8 | const escape = "")
13 | )
14 |
15 | type escapeTag struct {
16 | *baseTag
17 | }
18 |
19 | func (e *escapeTag) Process(b []byte, req *http.Request) ([]byte, int) {
20 | closeIdx := closeEscape.FindIndex(b)
21 |
22 | if closeIdx == nil {
23 | return nil, len(b)
24 | }
25 |
26 | e.length = closeIdx[1]
27 | b = b[:closeIdx[0]]
28 |
29 | return b, e.length
30 | }
31 |
32 | func (*escapeTag) HasClose(b []byte) bool {
33 | return closeEscape.FindIndex(b) != nil
34 | }
35 |
36 | func (*escapeTag) GetClosePosition(b []byte) int {
37 | if idx := closeEscape.FindIndex(b); idx != nil {
38 | return idx[1]
39 | }
40 | return 0
41 | }
42 |
--------------------------------------------------------------------------------
/middleware/traefik/vendor/github.com/darkweak/go-esi/esi/esi.go:
--------------------------------------------------------------------------------
1 | package esi
2 |
3 | import (
4 | "net/http"
5 | )
6 |
7 | func findTagName(b []byte) Tag {
8 | name := tagname.FindSubmatch(b)
9 | if name == nil {
10 | return nil
11 | }
12 |
13 | switch string(name[1]) {
14 | case comment:
15 | return &commentTag{
16 | baseTag: newBaseTag(),
17 | }
18 | case choose:
19 | return &chooseTag{
20 | baseTag: newBaseTag(),
21 | }
22 | case escape:
23 | return &escapeTag{
24 | baseTag: newBaseTag(),
25 | }
26 | case include:
27 | return &includeTag{
28 | baseTag: newBaseTag(),
29 | }
30 | case remove:
31 | return &removeTag{
32 | baseTag: newBaseTag(),
33 | }
34 | case try:
35 | case vars:
36 | return &varsTag{
37 | baseTag: newBaseTag(),
38 | }
39 | default:
40 | return nil
41 | }
42 |
43 | return nil
44 | }
45 |
46 | func HasOpenedTags(b []byte) bool {
47 | return esi.FindIndex(b) != nil || escapeRg.FindIndex(b) != nil
48 | }
49 |
50 | func CanProcess(b []byte) bool {
51 | if tag := findTagName(b); tag != nil {
52 | return tag.HasClose(b)
53 | }
54 |
55 | return false
56 | }
57 |
58 | func ReadToTag(next []byte, pointer int) (startTagPosition, esiPointer int, t Tag) {
59 | tagIdx := esi.FindIndex(next)
60 | var isEscapeTag bool
61 |
62 | if escIdx := escapeRg.FindIndex(next); escIdx != nil && (tagIdx == nil || escIdx[0] < tagIdx[0]) {
63 | tagIdx = escIdx
64 | tagIdx[1] = escIdx[0]
65 | isEscapeTag = true
66 | }
67 |
68 | if tagIdx == nil {
69 | return len(next), 0, nil
70 | }
71 |
72 | esiPointer = tagIdx[1]
73 | startTagPosition = tagIdx[0]
74 | t = findTagName(next[esiPointer:])
75 |
76 | if isEscapeTag {
77 | esiPointer += 7
78 | }
79 |
80 | return
81 | }
82 |
83 | func Parse(b []byte, req *http.Request) []byte {
84 | pointer := 0
85 |
86 | for pointer < len(b) {
87 | var escapeTag bool
88 |
89 | next := b[pointer:]
90 | tagIdx := esi.FindIndex(next)
91 |
92 | if escIdx := escapeRg.FindIndex(next); escIdx != nil && (tagIdx == nil || escIdx[0] < tagIdx[0]) {
93 | tagIdx = escIdx
94 | tagIdx[1] = escIdx[0]
95 | escapeTag = true
96 | }
97 |
98 | if tagIdx == nil {
99 | break
100 | }
101 |
102 | esiPointer := tagIdx[1]
103 | t := findTagName(next[esiPointer:])
104 |
105 | if escapeTag {
106 | esiPointer += 7
107 | }
108 |
109 | res, p := t.Process(next[esiPointer:], req)
110 | esiPointer += p
111 |
112 | b = append(b[:pointer], append(next[:tagIdx[0]], append(res, next[esiPointer:]...)...)...)
113 | pointer += len(res) + tagIdx[0]
114 | }
115 |
116 | return b
117 | }
118 |
--------------------------------------------------------------------------------
/middleware/traefik/vendor/github.com/darkweak/go-esi/esi/include.go:
--------------------------------------------------------------------------------
1 | package esi
2 |
3 | import (
4 | "io"
5 | "net/http"
6 | "regexp"
7 | )
8 |
9 | const include = "include"
10 |
11 | var (
12 | closeInclude = regexp.MustCompile("/>")
13 | srcAttribute = regexp.MustCompile(`src="?(.+?)"?( |/>)`)
14 | altAttribute = regexp.MustCompile(`alt="?(.+?)"?( |/>)`)
15 | )
16 |
17 | type includeTag struct {
18 | *baseTag
19 | src string
20 | alt string
21 | }
22 |
23 | func (i *includeTag) loadAttributes(b []byte) error {
24 | src := srcAttribute.FindSubmatch(b)
25 | if src == nil {
26 | return errNotFound
27 | }
28 |
29 | i.src = string(src[1])
30 |
31 | alt := altAttribute.FindSubmatch(b)
32 | if alt != nil {
33 | i.alt = string(alt[1])
34 | }
35 |
36 | return nil
37 | }
38 |
39 | // Input (e.g. include src="https://domain.com/esi-include" alt="https://domain.com/alt-esi-include" />)
40 | // With or without the alt
41 | // With or without a space separator before the closing
42 | // With or without the quotes around the src/alt value.
43 | func (i *includeTag) Process(b []byte, req *http.Request) ([]byte, int) {
44 | closeIdx := closeInclude.FindIndex(b)
45 |
46 | if closeIdx == nil {
47 | return nil, len(b)
48 | }
49 |
50 | i.length = closeIdx[1]
51 | if e := i.loadAttributes(b[8:i.length]); e != nil {
52 | return nil, len(b)
53 | }
54 |
55 | rq, _ := http.NewRequest(http.MethodGet, i.src, nil)
56 | client := &http.Client{}
57 | response, err := client.Do(rq)
58 |
59 | if err != nil || response.StatusCode >= 400 {
60 | rq, _ = http.NewRequest(http.MethodGet, i.src, nil)
61 | response, err = client.Do(rq)
62 |
63 | if err != nil || response.StatusCode >= 400 {
64 | return nil, len(b)
65 | }
66 | }
67 |
68 | defer response.Body.Close()
69 | x, _ := io.ReadAll(response.Body)
70 | b = Parse(x, req)
71 |
72 | return b, i.length
73 | }
74 |
75 | func (*includeTag) HasClose(b []byte) bool {
76 | return closeInclude.FindIndex(b) != nil
77 | }
78 |
79 | func (*includeTag) GetClosePosition(b []byte) int {
80 | if idx := closeInclude.FindIndex(b); idx != nil {
81 | return idx[1]
82 | }
83 | return 0
84 | }
85 |
--------------------------------------------------------------------------------
/middleware/traefik/vendor/github.com/darkweak/go-esi/esi/remove.go:
--------------------------------------------------------------------------------
1 | package esi
2 |
3 | import (
4 | "net/http"
5 | "regexp"
6 | )
7 |
8 | const remove = "remove"
9 |
10 | var closeRemove = regexp.MustCompile("")
11 |
12 | type removeTag struct {
13 | *baseTag
14 | }
15 |
16 | func (r *removeTag) Process(b []byte, req *http.Request) ([]byte, int) {
17 | closeIdx := closeRemove.FindIndex(b)
18 | if closeIdx == nil {
19 | return []byte{}, len(b)
20 | }
21 |
22 | r.length = closeIdx[1]
23 |
24 | return []byte{}, r.length
25 | }
26 |
27 | func (*removeTag) HasClose(b []byte) bool {
28 | return closeRemove.FindIndex(b) != nil
29 | }
30 |
31 | func (*removeTag) GetClosePosition(b []byte) int {
32 | if idx := closeRemove.FindIndex(b); idx != nil {
33 | return idx[1]
34 | }
35 | return 0
36 | }
37 |
--------------------------------------------------------------------------------
/middleware/traefik/vendor/github.com/darkweak/go-esi/esi/tags.go:
--------------------------------------------------------------------------------
1 | package esi
2 |
3 | import "regexp"
4 |
5 | const (
6 | try = "try"
7 | )
8 |
9 | var (
10 | esi = regexp.MustCompile("").
14 | )
15 |
--------------------------------------------------------------------------------
/middleware/traefik/vendor/github.com/darkweak/go-esi/esi/try.go:
--------------------------------------------------------------------------------
1 | package esi
2 |
--------------------------------------------------------------------------------
/middleware/traefik/vendor/github.com/darkweak/go-esi/esi/type.go:
--------------------------------------------------------------------------------
1 | package esi
2 |
3 | import (
4 | "net/http"
5 | )
6 |
7 | type (
8 | Tag interface {
9 | Process([]byte, *http.Request) ([]byte, int)
10 | HasClose([]byte) bool
11 | GetClosePosition([]byte) int
12 | }
13 |
14 | baseTag struct {
15 | length int
16 | }
17 | )
18 |
19 | func newBaseTag() *baseTag {
20 | return &baseTag{length: 0}
21 | }
22 |
23 | func (b *baseTag) Process(content []byte, _ *http.Request) ([]byte, int) {
24 | return []byte{}, len(content)
25 | }
26 |
--------------------------------------------------------------------------------
/middleware/traefik/vendor/github.com/darkweak/go-esi/esi/vars.go:
--------------------------------------------------------------------------------
1 | package esi
2 |
3 | import (
4 | "net/http"
5 | "regexp"
6 | "strings"
7 | )
8 |
9 | const (
10 | httpAcceptLanguage = "HTTP_ACCEPT_LANGUAGE"
11 | httpCookie = "HTTP_COOKIE"
12 | httpHost = "HTTP_HOST"
13 | httpReferrer = "HTTP_REFERER"
14 | httpUserAgent = "HTTP_USER_AGENT"
15 | httpQueryString = "QUERY_STRING"
16 |
17 | vars = "vars"
18 | )
19 |
20 | var (
21 | interpretedVar = regexp.MustCompile(`\$\((.+?)(\{(.+)\}(.+)?)?\)`)
22 | defaultExtractor = regexp.MustCompile(`\|('|")(.+?)('|")`)
23 | stringExtractor = regexp.MustCompile(`('|")(.+)('|")`)
24 |
25 | closeVars = regexp.MustCompile("")
26 | )
27 |
28 | func parseVariables(b []byte, req *http.Request) string {
29 | interprets := interpretedVar.FindSubmatch(b)
30 |
31 | if interprets != nil {
32 | switch string(interprets[1]) {
33 | case httpAcceptLanguage:
34 | if strings.Contains(req.Header.Get("Accept-Language"), string(interprets[3])) {
35 | return "true"
36 | }
37 | case httpCookie:
38 | if c, e := req.Cookie(string(interprets[3])); e == nil && c.Value != "" {
39 | return c.Value
40 | }
41 | case httpHost:
42 | return req.Host
43 | case httpReferrer:
44 | return req.Referer()
45 | case httpUserAgent:
46 | return req.UserAgent()
47 | case httpQueryString:
48 | if q := req.URL.Query().Get(string(interprets[3])); q != "" {
49 | return q
50 | }
51 | }
52 |
53 | if len(interprets) > 3 {
54 | defaultValues := defaultExtractor.FindSubmatch(interprets[4])
55 |
56 | if len(defaultValues) > 2 {
57 | return string(defaultValues[2])
58 | }
59 |
60 | return ""
61 | }
62 | } else {
63 | strs := stringExtractor.FindSubmatch(b)
64 |
65 | if len(strs) > 2 {
66 | return string(strs[2])
67 | }
68 | }
69 |
70 | return string(b)
71 | }
72 |
73 | type varsTag struct {
74 | *baseTag
75 | }
76 |
77 | // Input (e.g. comment text="This is a comment." />).
78 | func (c *varsTag) Process(b []byte, req *http.Request) ([]byte, int) {
79 | found := closeVars.FindIndex(b)
80 | if found == nil {
81 | return nil, len(b)
82 | }
83 |
84 | c.length = found[1]
85 |
86 | return interpretedVar.ReplaceAllFunc(b[5:found[0]], func(b []byte) []byte {
87 | return []byte(parseVariables(b, req))
88 | }), c.length
89 | }
90 |
91 | func (*varsTag) HasClose(b []byte) bool {
92 | return closeVars.FindIndex(b) != nil
93 | }
94 |
95 | func (*varsTag) GetClosePosition(b []byte) int {
96 | if idx := closeVars.FindIndex(b); idx != nil {
97 | return idx[1]
98 | }
99 | return 0
100 | }
101 |
--------------------------------------------------------------------------------
/middleware/traefik/vendor/github.com/darkweak/go-esi/esi/when.go:
--------------------------------------------------------------------------------
1 | package esi
2 |
3 | import (
4 | "net/http"
5 | "regexp"
6 | "strings"
7 | )
8 |
9 | var (
10 | unaryNegation = regexp.MustCompile(`!\((\$\((.+)\)|(.+))\)`)
11 | comparison = regexp.MustCompile(`(.+)(==|!=|<=|>=|<|>)(.+)`)
12 | logicalAnd = regexp.MustCompile(`\((.+?)\)&\((.+?)\)`)
13 | logicalOr = regexp.MustCompile(`\((.+?)\)\|\((.+?)\)`)
14 | )
15 |
16 | func validateTest(b []byte, req *http.Request) bool {
17 | if r := unaryNegation.FindSubmatch(b); r != nil {
18 | return !validateTest(r[1], req)
19 | } else if r := logicalAnd.FindSubmatch(b); r != nil {
20 | return validateTest(r[1], req) && validateTest(r[2], req)
21 | } else if r := logicalOr.FindSubmatch(b); r != nil {
22 | return validateTest(r[1], req) || validateTest(r[2], req)
23 | } else if r := comparison.FindSubmatch(b); r != nil {
24 | r1 := strings.TrimSpace(parseVariables(r[1], req))
25 | r2 := strings.TrimSpace(parseVariables(r[3], req))
26 | switch string(r[2]) {
27 | case "==":
28 | return r1 == r2
29 | case "!=":
30 | return r1 != r2
31 | case "<":
32 | return r1 < r2
33 | case ">":
34 | return r1 > r2
35 | case "<=":
36 | return r1 <= r2
37 | case ">=":
38 | return r1 >= r2
39 | }
40 | } else {
41 | vars := interpretedVar.FindSubmatch(b)
42 | if vars == nil {
43 | return false
44 | }
45 |
46 | return parseVariables(vars[0], req) == "true"
47 | }
48 |
49 | return false
50 | }
51 |
--------------------------------------------------------------------------------
/middleware/traefik/vendor/github.com/darkweak/go-esi/writer/writer.go:
--------------------------------------------------------------------------------
1 | package writer
2 |
3 | import (
4 | "bytes"
5 | "net/http"
6 |
7 | "github.com/darkweak/go-esi/esi"
8 | )
9 |
10 | type Writer struct {
11 | buf *bytes.Buffer
12 | rw http.ResponseWriter
13 | Rq *http.Request
14 | AsyncBuf []chan []byte
15 | Done chan bool
16 | flushed bool
17 | Iteration int
18 | }
19 |
20 | func NewWriter(buf *bytes.Buffer, rw http.ResponseWriter, rq *http.Request) *Writer {
21 | return &Writer{
22 | buf: buf,
23 | Rq: rq,
24 | rw: rw,
25 | AsyncBuf: make([]chan []byte, 0),
26 | Done: make(chan bool),
27 | }
28 | }
29 |
30 | // Header implements http.ResponseWriter
31 | func (w *Writer) Header() http.Header {
32 | return w.rw.Header()
33 | }
34 |
35 | // WriteHeader implements http.ResponseWriter
36 | func (w *Writer) WriteHeader(statusCode int) {
37 | if statusCode == 0 {
38 | w.rw.WriteHeader(http.StatusOK)
39 | }
40 | }
41 |
42 | // Flush implements http.Flusher
43 | func (w *Writer) Flush() {
44 | if !w.flushed {
45 | w.rw.(http.Flusher).Flush()
46 | w.flushed = true
47 | }
48 | }
49 |
50 | // Write will write the response body
51 | func (w *Writer) Write(b []byte) (int, error) {
52 | buf := append(w.buf.Bytes(), b...)
53 | w.buf.Reset()
54 |
55 | if esi.HasOpenedTags(buf) {
56 | position := 0
57 | for position < len(buf) {
58 | startPos, nextPos, t := esi.ReadToTag(buf[position:], position)
59 |
60 | if startPos != 0 {
61 | w.AsyncBuf = append(w.AsyncBuf, make(chan []byte))
62 | go func(tmpBuf []byte, i int, cw *Writer) {
63 | cw.AsyncBuf[i] <- tmpBuf
64 | }(buf[position:position+startPos], w.Iteration, w)
65 | w.Iteration++
66 | }
67 |
68 | if t == nil {
69 | break
70 | }
71 |
72 | closePosition := t.GetClosePosition(buf[position+startPos:])
73 | if closePosition == 0 {
74 | position += startPos
75 | break
76 | }
77 |
78 | position += nextPos
79 | w.AsyncBuf = append(w.AsyncBuf, make(chan []byte))
80 | go func(currentTag esi.Tag, tmpBuf []byte, cw *Writer, Iteration int) {
81 | p, _ := currentTag.Process(tmpBuf, cw.Rq)
82 | cw.AsyncBuf[Iteration] <- p
83 | }(t, buf[position:(position-nextPos)+startPos+closePosition], w, w.Iteration)
84 | position += startPos + closePosition - nextPos
85 | w.Iteration++
86 | }
87 | w.buf.Write(buf[position:])
88 | return len(b), nil
89 | }
90 |
91 | w.AsyncBuf = append(w.AsyncBuf, make(chan []byte))
92 | w.AsyncBuf[w.Iteration] <- buf
93 | w.Iteration++
94 | return len(b), nil
95 | }
96 |
97 | var _ http.ResponseWriter = (*Writer)(nil)
98 |
--------------------------------------------------------------------------------
/middleware/traefik/vendor/modules.txt:
--------------------------------------------------------------------------------
1 | # github.com/darkweak/go-esi v0.0.5 => ../..
2 | ## explicit; go 1.18
3 | github.com/darkweak/go-esi/esi
4 | github.com/darkweak/go-esi/writer
5 |
--------------------------------------------------------------------------------
/writer/writer.go:
--------------------------------------------------------------------------------
1 | package writer
2 |
3 | import (
4 | "bytes"
5 | "net/http"
6 |
7 | "github.com/darkweak/go-esi/esi"
8 | )
9 |
10 | type Writer struct {
11 | buf *bytes.Buffer
12 | rw http.ResponseWriter
13 | Rq *http.Request
14 | AsyncBuf []chan []byte
15 | Done chan bool
16 | flushed bool
17 | Iteration int
18 | }
19 |
20 | func NewWriter(buf *bytes.Buffer, rw http.ResponseWriter, rq *http.Request) *Writer {
21 | if rq.URL.Scheme == "" {
22 | if rq.TLS != nil {
23 | rq.URL.Scheme = "https"
24 | } else {
25 | rq.URL.Scheme = "http"
26 | }
27 | }
28 |
29 | if rq.URL.Host == "" {
30 | rq.URL.Host = rq.Host
31 | }
32 |
33 | return &Writer{
34 | buf: buf,
35 | Rq: rq,
36 | rw: rw,
37 | AsyncBuf: make([]chan []byte, 0),
38 | Done: make(chan bool),
39 | }
40 | }
41 |
42 | // Header implements http.ResponseWriter.
43 | func (w *Writer) Header() http.Header {
44 | return w.rw.Header()
45 | }
46 |
47 | // WriteHeader implements http.ResponseWriter.
48 | func (w *Writer) WriteHeader(statusCode int) {
49 | if statusCode == 0 {
50 | w.rw.WriteHeader(http.StatusOK)
51 | }
52 | }
53 |
54 | // Flush implements http.Flusher.
55 | func (w *Writer) Flush() {
56 | if !w.flushed {
57 | if flusher, ok := w.rw.(http.Flusher); ok {
58 | flusher.Flush()
59 | }
60 |
61 | w.flushed = true
62 | }
63 | }
64 |
65 | // Write will write the response body.
66 | func (w *Writer) Write(b []byte) (int, error) {
67 | buf := append(w.buf.Bytes(), b...)
68 | w.buf.Reset()
69 |
70 | if esi.HasOpenedTags(buf) {
71 | position := 0
72 | for position < len(buf) {
73 | startPos, nextPos, t := esi.ReadToTag(buf[position:], position)
74 |
75 | if startPos != 0 {
76 | w.AsyncBuf = append(w.AsyncBuf, make(chan []byte))
77 | go func(tmpBuf []byte, i int, cw *Writer) {
78 | cw.AsyncBuf[i] <- tmpBuf
79 | }(buf[position:position+startPos], w.Iteration, w)
80 | w.Iteration++
81 | }
82 |
83 | if t == nil {
84 | break
85 | }
86 |
87 | closePosition := t.GetClosePosition(buf[position+startPos:])
88 | if closePosition == 0 {
89 | position += startPos
90 |
91 | break
92 | }
93 |
94 | position += nextPos
95 |
96 | w.AsyncBuf = append(w.AsyncBuf, make(chan []byte))
97 |
98 | go func(currentTag esi.Tag, tmpBuf []byte, cw *Writer, Iteration int) {
99 | p, _ := currentTag.Process(tmpBuf, cw.Rq)
100 | cw.AsyncBuf[Iteration] <- p
101 | }(t, buf[position:(position-nextPos)+startPos+closePosition], w, w.Iteration)
102 |
103 | position += startPos + closePosition - nextPos
104 | w.Iteration++
105 | }
106 | w.buf.Write(buf[position:])
107 |
108 | return len(b), nil
109 | }
110 |
111 | w.AsyncBuf = append(w.AsyncBuf, make(chan []byte))
112 | w.AsyncBuf[w.Iteration] <- buf
113 | w.Iteration++
114 |
115 | return len(b), nil
116 | }
117 |
118 | var _ http.ResponseWriter = (*Writer)(nil)
119 |
--------------------------------------------------------------------------------